manuskript/manuskript/mainWindow.py

1204 lines
48 KiB
Python
Raw Normal View History

2015-05-28 13:32:09 +12:00
#!/usr/bin/env python
2016-02-06 00:25:25 +13:00
# --!-- coding: utf8 --!--
import imp
2016-02-07 00:34:22 +13:00
import os
2016-02-07 06:36:02 +13:00
from PyQt5.QtCore import pyqtSignal, QSignalMapper, QTimer, QSettings, Qt, QRegExp, QUrl, QSize
2016-04-09 06:09:41 +12:00
from PyQt5.QtGui import QStandardItemModel, QIcon, QColor
2016-02-07 06:36:02 +13:00
from PyQt5.QtWidgets import QMainWindow, QHeaderView, qApp, QMenu, QActionGroup, QAction, QStyle, QListWidgetItem, \
QLabel
2016-02-07 00:34:22 +13:00
from manuskript import settings
2016-03-25 01:42:47 +13:00
from manuskript.enums import Character, PlotStep, Plot, World, Outline
from manuskript.functions import AUC, wordCount, appPath, findWidgetsOfClass
from manuskript import loadSave
from manuskript.models.characterModel import characterModel
2016-02-07 00:34:22 +13:00
from manuskript.models.outlineModel import outlineModel
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.about import aboutDialog
2016-02-07 00:34:22 +13:00
from manuskript.ui.collapsibleDockWidgets import collapsibleDockWidgets
2016-04-02 06:01:27 +13:00
from manuskript.ui.exporters.exporter import exporterDialog
2016-02-07 00:34:22 +13:00
from manuskript.ui.helpLabel import helpLabel
from manuskript.ui.mainWindow import Ui_MainWindow
2016-02-09 01:50:35 +13:00
from manuskript.ui.tools.frequencyAnalyzer import frequencyAnalyzer
from manuskript.ui.views.outlineDelegates import outlineCharacterDelegate
2016-02-07 00:34:22 +13:00
from manuskript.ui.views.plotDelegate import plotDelegate
2015-05-28 13:32:09 +12:00
# Spellcheck support
2016-02-07 00:34:22 +13:00
from manuskript.ui.views.textEditView import textEditView
2015-06-07 05:10:44 +12:00
try:
import enchant
except ImportError:
enchant = None
2015-06-23 07:34:11 +12:00
2015-05-28 13:32:09 +12:00
class MainWindow(QMainWindow, Ui_MainWindow):
2015-06-08 08:06:57 +12:00
dictChanged = pyqtSignal(str)
2016-02-06 00:25:25 +13:00
2015-07-10 01:30:59 +12:00
# Tab indexes
2015-07-10 01:01:07 +12:00
TabInfos = 0
TabSummary = 1
TabPersos = 2
TabPlots = 3
TabWorld = 4
TabOutline = 5
TabRedac = 6
2015-05-28 13:32:09 +12:00
def __init__(self):
QMainWindow.__init__(self)
self.setupUi(self)
2015-06-23 10:19:40 +12:00
self.currentProject = None
2015-07-02 20:08:20 +12:00
2015-05-31 16:03:07 +12:00
self.readSettings()
2015-06-23 07:34:11 +12:00
2015-05-29 05:15:57 +12:00
# UI
2015-06-04 05:25:03 +12:00
self.setupMoreUi()
2015-07-02 20:08:20 +12:00
2015-06-23 10:19:40 +12:00
# Welcome
2015-06-24 04:22:39 +12:00
self.welcome.updateValues()
self.stack.setCurrentIndex(0)
2015-07-02 20:08:20 +12:00
2015-05-31 16:03:07 +12:00
# Word count
self.mprWordCount = QSignalMapper(self)
2015-05-28 13:32:09 +12:00
for t, i in [
(self.txtSummarySentence, 0),
2015-05-28 13:32:09 +12:00
(self.txtSummaryPara, 1),
(self.txtSummaryPage, 2),
(self.txtSummaryFull, 3)
2016-02-06 00:25:25 +13:00
]:
2015-05-31 16:03:07 +12:00
t.textChanged.connect(self.mprWordCount.map)
self.mprWordCount.setMapping(t, i)
self.mprWordCount.mapped.connect(self.wordCount)
2015-06-23 07:34:11 +12:00
2015-05-28 13:32:09 +12:00
# Snowflake Method Cycle
self.mapperCycle = QSignalMapper(self)
for t, i in [
2016-02-06 00:25:25 +13:00
(self.btnStepTwo, 0),
2015-05-28 13:32:09 +12:00
(self.btnStepThree, 1),
2016-02-06 00:25:25 +13:00
(self.btnStepFour, 2),
(self.btnStepFive, 3),
(self.btnStepSix, 4),
2015-05-28 13:32:09 +12:00
(self.btnStepSeven, 5),
(self.btnStepEight, 6)
2016-02-06 00:25:25 +13:00
]:
2015-05-28 13:32:09 +12:00
t.clicked.connect(self.mapperCycle.map)
self.mapperCycle.setMapping(t, i)
2015-06-23 07:34:11 +12:00
2015-05-28 13:32:09 +12:00
self.mapperCycle.mapped.connect(self.clickCycle)
2015-06-21 21:29:35 +12:00
self.cmbSummary.currentIndexChanged.connect(self.summaryPageChanged)
self.cmbSummary.setCurrentIndex(0)
self.cmbSummary.currentIndexChanged.emit(0)
2015-06-23 07:34:11 +12:00
# Main Menu
2015-06-23 10:19:40 +12:00
for i in [self.actSave, self.actSaveAs, self.actCloseProject,
2016-03-25 01:42:47 +13:00
self.menuEdit, self.menuView, self.menuTools, self.menuHelp]:
2015-06-23 10:19:40 +12:00
i.setEnabled(False)
2015-07-02 20:08:20 +12:00
2015-06-24 04:22:39 +12:00
self.actOpen.triggered.connect(self.welcome.openFile)
2015-06-17 22:00:03 +12:00
self.actSave.triggered.connect(self.saveDatas)
2015-06-24 04:22:39 +12:00
self.actSaveAs.triggered.connect(self.welcome.saveAsFile)
2015-07-01 23:14:03 +12:00
self.actCompile.triggered.connect(self.doCompile)
self.actLabels.triggered.connect(self.settingsLabel)
self.actStatus.triggered.connect(self.settingsStatus)
self.actSettings.triggered.connect(self.settingsWindow)
2015-06-24 04:22:39 +12:00
self.actCloseProject.triggered.connect(self.closeProject)
self.actQuit.triggered.connect(self.close)
2016-02-09 01:50:35 +13:00
self.actToolFrequency.triggered.connect(self.frequencyAnalyzer)
self.actAbout.triggered.connect(self.about)
self.generateViewMenu()
2015-07-02 20:08:20 +12:00
2016-03-25 01:42:47 +13:00
self.actModeGroup = QActionGroup(self)
self.actModeSimple.setActionGroup(self.actModeGroup)
self.actModeFiction.setActionGroup(self.actModeGroup)
self.actModeSnowflake.setActionGroup(self.actModeGroup)
self.actModeSimple.triggered.connect(self.setViewModeSimple)
self.actModeFiction.triggered.connect(self.setViewModeFiction)
self.actModeSnowflake.setEnabled(False)
self.makeUIConnections()
2015-07-02 20:08:20 +12:00
2016-02-06 00:25:25 +13:00
# self.loadProject(os.path.join(appPath(), "test_project.zip"))
2015-06-23 07:34:11 +12:00
2016-02-06 00:25:25 +13:00
###############################################################################
# SUMMARY
###############################################################################
2015-06-23 07:34:11 +12:00
2015-06-21 21:29:35 +12:00
def summaryPageChanged(self, index):
fractalButtons = [
self.btnStepTwo,
self.btnStepThree,
self.btnStepFive,
self.btnStepSeven,
2016-02-06 00:25:25 +13:00
]
2015-06-21 21:29:35 +12:00
for b in fractalButtons:
b.setVisible(fractalButtons.index(b) == index)
2015-06-23 07:34:11 +12:00
2016-02-06 00:25:25 +13:00
###############################################################################
# OUTLINE
###############################################################################
2015-06-23 07:34:11 +12:00
def outlineRemoveItemsRedac(self):
self.treeRedacOutline.delete()
2016-02-06 00:25:25 +13:00
def outlineRemoveItemsOutline(self):
self.treeOutlineOutline.delete()
2016-02-06 00:25:25 +13:00
###############################################################################
2016-03-24 23:17:48 +13:00
# CHARACTERS
2016-02-06 00:25:25 +13:00
###############################################################################
2015-06-01 08:41:32 +12:00
def changeCurrentCharacter(self, trash=None):
"""
2015-06-23 07:34:11 +12:00
@return:
"""
c = self.lstCharacters.currentCharacter()
if not c:
self.tabPersos.setEnabled(False)
2015-06-29 09:46:51 +12:00
return
2015-06-23 07:34:11 +12:00
2015-06-29 09:46:51 +12:00
self.tabPersos.setEnabled(True)
index = c.index()
2015-07-02 20:08:20 +12:00
2015-06-29 20:22:18 +12:00
for w in [
self.txtPersoName,
self.sldPersoImportance,
self.txtPersoMotivation,
self.txtPersoGoal,
self.txtPersoConflict,
self.txtPersoEpiphany,
self.txtPersoSummarySentence,
2015-06-29 20:22:18 +12:00
self.txtPersoSummaryPara,
self.txtPersoSummaryFull,
self.txtPersoNotes,
2016-02-06 00:25:25 +13:00
]:
2015-06-29 20:22:18 +12:00
w.setCurrentModelIndex(index)
2015-07-02 20:08:20 +12:00
2015-06-29 21:28:34 +12:00
# Button color
self.updateCharacterColor(c.ID())
2015-07-02 20:08:20 +12:00
# Slider importance
self.updateCharacterImportance(c.ID())
# Character Infos
2015-06-29 21:28:34 +12:00
self.tblPersoInfos.setRootIndex(index)
2015-07-02 20:08:20 +12:00
if self.mdlCharacter.rowCount(index):
2015-06-29 21:28:34 +12:00
self.updatePersoInfoView()
2015-07-02 20:08:20 +12:00
2015-06-29 21:28:34 +12:00
def updatePersoInfoView(self):
self.tblPersoInfos.horizontalHeader().setSectionResizeMode(0, QHeaderView.ResizeToContents)
self.tblPersoInfos.horizontalHeader().setSectionResizeMode(1, QHeaderView.Stretch)
2015-06-29 21:28:34 +12:00
self.tblPersoInfos.verticalHeader().hide()
def updateCharacterColor(self, ID):
c = self.mdlCharacter.getCharacterByID(ID)
color = c.color().name()
self.btnPersoColor.setStyleSheet("background:{};".format(color))
def updateCharacterImportance(self, ID):
c = self.mdlCharacter.getCharacterByID(ID)
self.sldPersoImportance.setValue(int(c.importance()))
2016-02-06 00:25:25 +13:00
###############################################################################
# PLOTS
###############################################################################
2015-06-22 23:11:45 +12:00
def changeCurrentPlot(self):
2015-06-23 06:30:43 +12:00
index = self.lstPlots.currentPlotIndex()
2015-06-23 07:34:11 +12:00
2015-06-22 23:11:45 +12:00
if not index.isValid():
self.tabPlot.setEnabled(False)
return
2015-06-23 07:34:11 +12:00
2015-06-22 23:11:45 +12:00
self.tabPlot.setEnabled(True)
self.txtPlotName.setCurrentModelIndex(index)
self.txtPlotDescription.setCurrentModelIndex(index)
self.txtPlotResult.setCurrentModelIndex(index)
self.sldPlotImportance.setCurrentModelIndex(index)
2015-06-23 07:34:11 +12:00
self.lstPlotPerso.setRootIndex(index.sibling(index.row(),
Plot.characters.value))
# Slider importance
self.updatePlotImportance(index.row())
2016-03-07 04:10:25 +13:00
subplotindex = index.sibling(index.row(), Plot.steps.value)
2015-07-07 01:00:22 +12:00
self.lstSubPlots.setRootIndex(subplotindex)
if self.mdlPlots.rowCount(subplotindex):
self.updateSubPlotView()
2015-06-23 07:34:11 +12:00
2016-02-06 00:25:25 +13:00
# self.txtSubPlotSummary.setCurrentModelIndex(QModelIndex())
2015-06-22 23:11:45 +12:00
self.txtSubPlotSummary.setEnabled(False)
2015-06-23 07:07:38 +12:00
self._updatingSubPlot = True
2015-06-22 23:11:45 +12:00
self.txtSubPlotSummary.setPlainText("")
2015-06-23 07:07:38 +12:00
self._updatingSubPlot = False
2015-07-06 20:07:05 +12:00
self.lstPlotPerso.selectionModel().clear()
2015-06-23 07:34:11 +12:00
2015-07-07 01:00:22 +12:00
def updateSubPlotView(self):
# Hide columns
for i in range(self.mdlPlots.columnCount()):
self.lstSubPlots.hideColumn(i)
2016-03-07 04:10:25 +13:00
self.lstSubPlots.showColumn(PlotStep.name.value)
self.lstSubPlots.showColumn(PlotStep.meta.value)
2015-07-07 01:00:22 +12:00
self.lstSubPlots.horizontalHeader().setSectionResizeMode(
2016-03-07 04:10:25 +13:00
PlotStep.name.value, QHeaderView.Stretch)
2015-07-07 01:00:22 +12:00
self.lstSubPlots.horizontalHeader().setSectionResizeMode(
2016-03-07 04:10:25 +13:00
PlotStep.meta.value, QHeaderView.ResizeToContents)
2015-07-07 01:00:22 +12:00
self.lstSubPlots.verticalHeader().hide()
2016-02-06 00:25:25 +13:00
def updatePlotImportance(self, ID):
imp = self.mdlPlots.getPlotImportanceByID(ID)
self.sldPlotImportance.setValue(int(imp))
2015-06-22 23:11:45 +12:00
def changeCurrentSubPlot(self, index):
2015-06-23 07:34:11 +12:00
# Got segfaults when using textEditView model system, so ad hoc stuff.
2016-03-07 04:10:25 +13:00
index = index.sibling(index.row(), PlotStep.summary.value)
2015-06-22 23:11:45 +12:00
item = self.mdlPlots.itemFromIndex(index)
if not item:
self.txtSubPlotSummary.setEnabled(False)
return
self.txtSubPlotSummary.setEnabled(True)
txt = item.text()
self._updatingSubPlot = True
self.txtSubPlotSummary.setPlainText(txt)
self._updatingSubPlot = False
2015-06-23 07:34:11 +12:00
2015-06-22 23:11:45 +12:00
def updateSubPlotSummary(self):
if self._updatingSubPlot:
return
2015-06-23 07:34:11 +12:00
2015-06-22 23:11:45 +12:00
index = self.lstSubPlots.currentIndex()
if not index.isValid():
return
2016-03-07 04:10:25 +13:00
index = index.sibling(index.row(), PlotStep.summary.value)
2015-06-22 23:11:45 +12:00
item = self.mdlPlots.itemFromIndex(index)
2015-06-23 07:34:11 +12:00
2015-06-22 23:11:45 +12:00
self._updatingSubPlot = True
item.setText(self.txtSubPlotSummary.toPlainText())
self._updatingSubPlot = False
2016-02-06 00:25:25 +13:00
2015-07-06 20:07:05 +12:00
def plotPersoSelectionChanged(self):
"Enables or disables remove plot perso button."
self.btnRmPlotPerso.setEnabled(
2016-02-06 00:25:25 +13:00
len(self.lstPlotPerso.selectedIndexes()) != 0)
2015-06-23 07:34:11 +12:00
2016-02-06 00:25:25 +13:00
###############################################################################
# WORLD
###############################################################################
def changeCurrentWorld(self):
index = self.mdlWorld.selectedIndex()
if not index.isValid():
self.tabWorld.setEnabled(False)
return
self.tabWorld.setEnabled(True)
self.txtWorldName.setCurrentModelIndex(index)
self.txtWorldDescription.setCurrentModelIndex(index)
self.txtWorldPassion.setCurrentModelIndex(index)
self.txtWorldConflict.setCurrentModelIndex(index)
2016-03-24 23:17:48 +13:00
# ###############################################################################
# # LOAD AND SAVE
# ###############################################################################
2015-06-23 07:34:11 +12:00
2015-06-24 04:22:39 +12:00
def loadProject(self, project, loadFromFile=True):
"""Loads the project ``project``.
2015-07-02 20:08:20 +12:00
2015-06-24 04:22:39 +12:00
If ``loadFromFile`` is False, then it does not load datas from file.
It assumes that the datas have been populated in a different way."""
if loadFromFile and not os.path.exists(project):
print(self.tr("The file {} does not exist. Try again.").format(project))
self.statusBar().showMessage(
2016-02-06 00:25:25 +13:00
self.tr("The file {} does not exist. Try again.").format(project),
5000)
2015-06-24 04:22:39 +12:00
return
2015-07-02 20:08:20 +12:00
2015-06-24 04:22:39 +12:00
if loadFromFile:
2015-06-25 20:01:28 +12:00
# Load empty settings
2015-07-02 20:08:20 +12:00
imp.reload(settings)
# Load data
2015-06-24 04:22:39 +12:00
self.loadEmptyDatas()
2015-07-07 01:00:22 +12:00
self.loadDatas(project)
2015-07-02 20:08:20 +12:00
self.makeConnections()
2015-06-23 07:34:11 +12:00
2015-06-17 22:00:03 +12:00
# Load settings
2016-04-11 03:29:27 +12:00
if settings.openIndexes:
self.mainEditor.tabSplitter.restoreOpenIndexes(settings.openIndexes)
self.generateViewMenu()
2015-06-28 00:06:35 +12:00
self.mainEditor.sldCorkSizeFactor.setValue(settings.corkSizeFactor)
self.actSpellcheck.setChecked(settings.spellcheck)
2015-06-30 00:21:57 +12:00
self.toggleSpellcheck(settings.spellcheck)
self.updateMenuDict()
self.setDictionary()
2015-07-02 20:08:20 +12:00
2015-06-28 00:06:35 +12:00
self.mainEditor.setFolderView(settings.folderView)
2015-06-30 00:21:57 +12:00
self.mainEditor.updateFolderViewButtons(settings.folderView)
2016-04-12 01:14:24 +12:00
self.mainEditor.tabSplitter.updateStyleSheet()
2015-06-16 06:30:18 +12:00
self.tabMain.setCurrentIndex(settings.lastTab)
# We force to emit even if it opens on the current tab
self.tabMain.currentChanged.emit(settings.lastTab)
2015-06-28 00:06:35 +12:00
self.mainEditor.updateCorkBackground()
2016-03-25 01:42:47 +13:00
if settings.viewMode == "simple":
self.setViewModeSimple()
else:
self.setViewModeFiction()
2015-06-23 07:34:11 +12:00
2015-06-17 22:00:03 +12:00
# Set autosave
2015-06-18 04:40:55 +12:00
self.saveTimer = QTimer()
self.saveTimer.setInterval(settings.autoSaveDelay * 60 * 1000)
self.saveTimer.setSingleShot(False)
self.saveTimer.timeout.connect(self.saveDatas)
2015-06-17 22:00:03 +12:00
if settings.autoSave:
self.saveTimer.start()
2015-06-23 07:34:11 +12:00
2015-06-18 04:40:55 +12:00
# Set autosave if no changes
self.saveTimerNoChanges = QTimer()
2016-02-06 00:25:25 +13:00
self.saveTimerNoChanges.setInterval(settings.autoSaveNoChangesDelay * 1000)
2015-06-18 04:40:55 +12:00
self.saveTimerNoChanges.setSingleShot(True)
2015-06-24 04:22:39 +12:00
self.mdlFlatData.dataChanged.connect(self.startTimerNoChanges)
2015-06-18 04:40:55 +12:00
self.mdlOutline.dataChanged.connect(self.startTimerNoChanges)
self.mdlCharacter.dataChanged.connect(self.startTimerNoChanges)
2015-07-03 03:45:27 +12:00
self.mdlPlots.dataChanged.connect(self.startTimerNoChanges)
self.mdlWorld.dataChanged.connect(self.startTimerNoChanges)
2016-02-06 00:25:25 +13:00
# self.mdlPersosInfos.dataChanged.connect(self.startTimerNoChanges)
2015-06-18 06:48:20 +12:00
self.mdlStatus.dataChanged.connect(self.startTimerNoChanges)
self.mdlLabels.dataChanged.connect(self.startTimerNoChanges)
2015-06-23 07:34:11 +12:00
2015-06-18 04:40:55 +12:00
self.saveTimerNoChanges.timeout.connect(self.saveDatas)
self.saveTimerNoChanges.stop()
2015-06-23 07:34:11 +12:00
2015-06-17 22:00:03 +12:00
# UI
for i in [self.actOpen, self.menuRecents]:
i.setEnabled(False)
2015-06-23 10:19:40 +12:00
for i in [self.actSave, self.actSaveAs, self.actCloseProject,
2016-03-25 01:42:47 +13:00
self.menuEdit, self.menuView, self.menuTools, self.menuHelp]:
2015-06-23 10:19:40 +12:00
i.setEnabled(True)
2017-05-23 04:48:20 +12:00
# Add project name to Window's name
pName = os.path.split(project)[1]
if pName.endswith('.msk'):
pName=pName[:-4]
self.setWindowTitle(pName + " - " + self.tr("Manuskript"))
2015-06-23 07:34:11 +12:00
2015-06-01 08:41:32 +12:00
# Stuff
2016-02-06 00:25:25 +13:00
# self.checkPersosID() # Should'n be necessary any longer
2015-07-02 20:08:20 +12:00
2015-07-07 01:00:22 +12:00
self.currentProject = project
QSettings().setValue("lastProject", project)
2015-06-24 04:22:39 +12:00
# Show main Window
self.stack.setCurrentIndex(1)
2015-07-02 20:08:20 +12:00
2015-06-24 04:22:39 +12:00
def closeProject(self):
2016-03-31 21:50:20 +13:00
if not self.currentProject:
return
# Close open tabs in editor
self.mainEditor.closeAllTabs()
2015-06-24 04:22:39 +12:00
# Save datas
self.saveDatas()
2015-07-02 20:08:20 +12:00
2015-06-24 04:22:39 +12:00
self.currentProject = None
QSettings().setValue("lastProject", "")
2015-07-02 20:08:20 +12:00
2015-06-24 04:22:39 +12:00
# Clear datas
self.loadEmptyDatas()
self.saveTimer.stop()
loadSave.clearSaveCache()
2015-07-02 20:08:20 +12:00
self.breakConnections()
2015-06-24 04:22:39 +12:00
# UI
for i in [self.actOpen, self.menuRecents]:
i.setEnabled(True)
2015-06-24 04:22:39 +12:00
for i in [self.actSave, self.actSaveAs, self.actCloseProject,
2016-03-25 01:42:47 +13:00
self.menuEdit, self.menuView, self.menuTools, self.menuHelp]:
2015-06-24 04:22:39 +12:00
i.setEnabled(False)
2015-07-02 20:08:20 +12:00
2017-05-23 04:48:20 +12:00
# Set Window's name - no project loaded
self.setWindowTitle(self.tr("Manuskript"))
2015-06-24 04:22:39 +12:00
# Reload recent files
self.welcome.updateValues()
2015-07-02 20:08:20 +12:00
2015-06-24 04:22:39 +12:00
# Show welcome dialog
self.stack.setCurrentIndex(0)
2015-06-23 07:34:11 +12:00
2015-06-24 04:22:39 +12:00
def readSettings(self):
# Load State and geometry
sttgns = QSettings(qApp.organizationName(), qApp.applicationName())
if sttgns.contains("geometry"):
self.restoreGeometry(sttgns.value("geometry"))
if sttgns.contains("windowState"):
self.restoreState(sttgns.value("windowState"))
else:
self.dckCheatSheet.hide()
self.dckSearch.hide()
2015-07-04 19:59:35 +12:00
if sttgns.contains("metadataState"):
state = [False if v == "false" else True for v in sttgns.value("metadataState")]
self.redacMetadata.restoreState(state)
if sttgns.contains("revisionsState"):
state = [False if v == "false" else True for v in sttgns.value("revisionsState")]
self.redacMetadata.revisions.restoreState(state)
if sttgns.contains("splitterRedacH"):
self.splitterRedacH.restoreState(sttgns.value("splitterRedacH"))
if sttgns.contains("splitterRedacV"):
self.splitterRedacV.restoreState(sttgns.value("splitterRedacV"))
if sttgns.contains("toolbar"):
# self.toolbar is not initialized yet, so we just store balue
self._toolbarState = sttgns.value("toolbar")
else:
self._toolbarState = ""
2016-02-06 00:25:25 +13:00
2015-06-24 04:22:39 +12:00
def closeEvent(self, event):
2015-07-04 19:59:35 +12:00
# Save State and geometry and other things
2015-06-24 04:22:39 +12:00
sttgns = QSettings(qApp.organizationName(), qApp.applicationName())
sttgns.setValue("geometry", self.saveGeometry())
sttgns.setValue("windowState", self.saveState())
2015-07-04 19:59:35 +12:00
sttgns.setValue("metadataState", self.redacMetadata.saveState())
sttgns.setValue("revisionsState", self.redacMetadata.revisions.saveState())
sttgns.setValue("splitterRedacH", self.splitterRedacH.saveState())
sttgns.setValue("splitterRedacV", self.splitterRedacV.saveState())
sttgns.setValue("toolbar", self.toolbar.saveState())
2016-02-06 00:25:25 +13:00
2015-06-24 04:22:39 +12:00
# Specific settings to save before quitting
settings.lastTab = self.tabMain.currentIndex()
2015-07-02 20:08:20 +12:00
2015-06-24 04:22:39 +12:00
if self.currentProject:
# Remembering the current items (stores outlineItem's ID)
2016-04-11 03:29:27 +12:00
settings.openIndexes = self.mainEditor.tabSplitter.openIndexes()
2015-06-24 04:22:39 +12:00
# Save data from models
if self.currentProject and settings.saveOnQuit:
self.saveDatas()
2016-02-06 00:25:25 +13:00
# closeEvent
# QMainWindow.closeEvent(self, event) # Causin segfaults?
2015-06-24 04:22:39 +12:00
def startTimerNoChanges(self):
if settings.autoSaveNoChanges:
self.saveTimerNoChanges.start()
def saveDatas(self, projectName=None):
"""Saves the current project (in self.currentProject).
2015-07-02 20:08:20 +12:00
2015-06-24 04:22:39 +12:00
If ``projectName`` is given, currentProject becomes projectName.
In other words, it "saves as...".
"""
2015-07-02 20:08:20 +12:00
2015-06-24 04:22:39 +12:00
if projectName:
self.currentProject = projectName
QSettings().setValue("lastProject", projectName)
2015-07-02 20:08:20 +12:00
r = loadSave.saveProject() # version=0
self.saveTimerNoChanges.stop()
if r:
feedback = self.tr("Project {} saved.").format(self.currentProject)
else:
feedback = self.tr("WARNING: Project {} not saved.").format(self.currentProject)
2015-06-24 04:22:39 +12:00
# Giving some feedback
print(feedback)
self.statusBar().showMessage(feedback, 5000)
2015-06-24 04:22:39 +12:00
def loadEmptyDatas(self):
self.mdlFlatData = QStandardItemModel(self)
self.mdlCharacter = characterModel(self)
2016-02-06 00:25:25 +13:00
# self.mdlPersosProxy = persosProxyModel(self)
# self.mdlPersosInfos = QStandardItemModel(self)
self.mdlLabels = QStandardItemModel(self)
self.mdlStatus = QStandardItemModel(self)
self.mdlPlots = plotModel(self)
self.mdlOutline = outlineModel(self)
self.mdlWorld = worldModel(self)
2015-06-24 04:22:39 +12:00
2015-07-07 01:00:22 +12:00
def loadDatas(self, project):
2015-06-24 04:22:39 +12:00
errors = loadSave.loadProject(project)
2015-07-02 20:08:20 +12:00
2015-06-24 04:22:39 +12:00
# Giving some feedback
if not errors:
2015-07-07 01:00:22 +12:00
print(self.tr("Project {} loaded.").format(project))
2015-06-24 04:22:39 +12:00
self.statusBar().showMessage(
2016-02-06 00:25:25 +13:00
self.tr("Project {} loaded.").format(project), 5000)
2015-06-24 04:22:39 +12:00
else:
2015-07-07 01:00:22 +12:00
print(self.tr("Project {} loaded with some errors:").format(project))
2015-06-24 04:22:39 +12:00
for e in errors:
print(self.tr(" * {} wasn't found in project file.").format(e))
self.statusBar().showMessage(
2016-02-06 00:25:25 +13:00
self.tr("Project {} loaded with some errors.").format(project), 5000)
2015-06-24 04:22:39 +12:00
2016-02-06 00:25:25 +13:00
###############################################################################
# MAIN CONNECTIONS
###############################################################################
def makeUIConnections(self):
2016-03-24 23:17:48 +13:00
"Connections that have to be made once only, even when a new project is loaded."
self.lstCharacters.currentItemChanged.connect(self.changeCurrentCharacter, AUC)
2015-07-02 20:08:20 +12:00
self.txtPlotFilter.textChanged.connect(self.lstPlots.setFilter, AUC)
self.lstPlots.currentItemChanged.connect(self.changeCurrentPlot, AUC)
self.txtSubPlotSummary.document().contentsChanged.connect(
2016-02-06 00:25:25 +13:00
self.updateSubPlotSummary, AUC)
2017-03-24 23:30:54 +13:00
self.lstSubPlots.clicked.connect(self.changeCurrentSubPlot, AUC)
2015-07-02 20:08:20 +12:00
self.btnRedacAddFolder.clicked.connect(self.treeRedacOutline.addFolder, AUC)
self.btnOutlineAddFolder.clicked.connect(self.treeOutlineOutline.addFolder, AUC)
self.btnRedacAddText.clicked.connect(self.treeRedacOutline.addText, AUC)
self.btnOutlineAddText.clicked.connect(self.treeOutlineOutline.addText, AUC)
self.btnRedacRemoveItem.clicked.connect(self.outlineRemoveItemsRedac, AUC)
self.btnOutlineRemoveItem.clicked.connect(self.outlineRemoveItemsOutline, AUC)
2015-07-02 20:08:20 +12:00
2015-07-10 01:01:07 +12:00
self.tabMain.currentChanged.connect(self.toolbar.setCurrentGroup)
def makeConnections(self):
2015-06-23 07:34:11 +12:00
# Flat datas (Summary and general infos)
for widget, col in [
(self.txtSummarySituation, 0),
(self.txtSummarySentence, 1),
(self.txtSummarySentence_2, 1),
(self.txtSummaryPara, 2),
(self.txtSummaryPara_2, 2),
(self.txtPlotSummaryPara, 2),
(self.txtSummaryPage, 3),
(self.txtSummaryPage_2, 3),
(self.txtPlotSummaryPage, 3),
(self.txtSummaryFull, 4),
(self.txtPlotSummaryFull, 4),
2016-02-06 00:25:25 +13:00
]:
widget.setModel(self.mdlFlatData)
widget.setColumn(col)
widget.setCurrentModelIndex(self.mdlFlatData.index(1, col))
2015-06-23 07:34:11 +12:00
for widget, col in [
(self.txtGeneralTitle, 0),
(self.txtGeneralSubtitle, 1),
(self.txtGeneralSerie, 2),
(self.txtGeneralVolume, 3),
(self.txtGeneralGenre, 4),
(self.txtGeneralLicense, 5),
(self.txtGeneralAuthor, 6),
(self.txtGeneralEmail, 7),
2016-02-06 00:25:25 +13:00
]:
widget.setModel(self.mdlFlatData)
widget.setColumn(col)
widget.setCurrentModelIndex(self.mdlFlatData.index(0, col))
2015-06-23 07:34:11 +12:00
2016-03-24 23:17:48 +13:00
# Characters
self.lstCharacters.setCharactersModel(self.mdlCharacter)
self.tblPersoInfos.setModel(self.mdlCharacter)
2015-07-02 20:08:20 +12:00
self.btnAddPerso.clicked.connect(self.mdlCharacter.addCharacter, AUC)
2016-03-10 05:38:12 +13:00
try:
self.btnRmPerso.clicked.connect(self.lstCharacters.removeCharacter, AUC)
self.btnPersoColor.clicked.connect(self.lstCharacters.choseCharacterColor, AUC)
self.btnPersoAddInfo.clicked.connect(self.lstCharacters.addCharacterInfo, AUC)
self.btnPersoRmInfo.clicked.connect(self.lstCharacters.removeCharacterInfo, AUC)
except TypeError:
# Connection has already been made
pass
2015-07-02 20:08:20 +12:00
2015-06-29 20:22:18 +12:00
for w, c in [
(self.txtPersoName, Character.name.value),
(self.sldPersoImportance, Character.importance.value),
(self.txtPersoMotivation, Character.motivation.value),
(self.txtPersoGoal, Character.goal.value),
(self.txtPersoConflict, Character.conflict.value),
(self.txtPersoEpiphany, Character.epiphany.value),
(self.txtPersoSummarySentence, Character.summarySentence.value),
(self.txtPersoSummaryPara, Character.summaryPara.value),
(self.txtPersoSummaryFull, Character.summaryFull.value),
(self.txtPersoNotes, Character.notes.value)
2016-02-06 00:25:25 +13:00
]:
w.setModel(self.mdlCharacter)
2015-06-29 20:22:18 +12:00
w.setColumn(c)
self.tabPersos.setEnabled(False)
2015-07-02 20:08:20 +12:00
# Plots
2015-06-22 23:11:45 +12:00
self.lstPlots.setPlotModel(self.mdlPlots)
self.lstPlotPerso.setModel(self.mdlPlots)
self.lstSubPlots.setModel(self.mdlPlots)
2015-06-23 07:07:38 +12:00
self._updatingSubPlot = False
self.btnAddPlot.clicked.connect(self.mdlPlots.addPlot, AUC)
2015-06-23 07:34:11 +12:00
self.btnRmPlot.clicked.connect(lambda:
2016-02-06 00:25:25 +13:00
self.mdlPlots.removePlot(self.lstPlots.currentPlotIndex()), AUC)
self.btnAddSubPlot.clicked.connect(self.mdlPlots.addSubPlot, AUC)
2017-03-24 23:30:54 +13:00
self.btnAddSubPlot.clicked.connect(self.updateSubPlotView, AUC)
self.btnRmSubPlot.clicked.connect(self.mdlPlots.removeSubPlot, AUC)
2015-07-06 20:07:05 +12:00
self.lstPlotPerso.selectionModel().selectionChanged.connect(self.plotPersoSelectionChanged)
self.btnRmPlotPerso.clicked.connect(self.mdlPlots.removePlotPerso, AUC)
2015-06-23 07:34:11 +12:00
for w, c in [
(self.txtPlotName, Plot.name.value),
(self.txtPlotDescription, Plot.description.value),
(self.txtPlotResult, Plot.result.value),
(self.sldPlotImportance, Plot.importance.value),
2016-02-06 00:25:25 +13:00
]:
w.setModel(self.mdlPlots)
w.setColumn(c)
2015-06-23 07:34:11 +12:00
self.tabPlot.setEnabled(False)
2015-06-29 20:22:18 +12:00
self.mdlPlots.updatePlotPersoButton()
self.mdlCharacter.dataChanged.connect(self.mdlPlots.updatePlotPersoButton)
2015-06-23 06:30:43 +12:00
self.lstOutlinePlots.setPlotModel(self.mdlPlots)
self.lstOutlinePlots.setShowSubPlot(True)
2016-03-06 21:21:10 +13:00
self.plotCharacterDelegate = outlineCharacterDelegate(self.mdlCharacter, self)
self.lstPlotPerso.setItemDelegate(self.plotCharacterDelegate)
2015-07-07 01:00:22 +12:00
self.plotDelegate = plotDelegate(self)
2016-03-07 04:10:25 +13:00
self.lstSubPlots.setItemDelegateForColumn(PlotStep.meta.value, self.plotDelegate)
2015-06-23 07:34:11 +12:00
# World
self.treeWorld.setModel(self.mdlWorld)
for i in range(self.mdlWorld.columnCount()):
self.treeWorld.hideColumn(i)
self.treeWorld.showColumn(0)
self.btnWorldEmptyData.setMenu(self.mdlWorld.emptyDataMenu())
self.treeWorld.selectionModel().selectionChanged.connect(self.changeCurrentWorld, AUC)
self.btnAddWorld.clicked.connect(self.mdlWorld.addItem, AUC)
self.btnRmWorld.clicked.connect(self.mdlWorld.removeItem, AUC)
for w, c in [
(self.txtWorldName, World.name.value),
(self.txtWorldDescription, World.description.value),
(self.txtWorldPassion, World.passion.value),
(self.txtWorldConflict, World.conflict.value),
2016-02-06 00:25:25 +13:00
]:
w.setModel(self.mdlWorld)
w.setColumn(c)
self.tabWorld.setEnabled(False)
self.treeWorld.expandAll()
2016-02-06 00:25:25 +13:00
# Outline
self.treeRedacOutline.setModel(self.mdlOutline)
self.treeOutlineOutline.setModelCharacters(self.mdlCharacter)
self.treeOutlineOutline.setModelLabels(self.mdlLabels)
self.treeOutlineOutline.setModelStatus(self.mdlStatus)
2015-06-23 07:34:11 +12:00
self.redacMetadata.setModels(self.mdlOutline, self.mdlCharacter,
2015-06-23 07:34:11 +12:00
self.mdlLabels, self.mdlStatus)
self.outlineItemEditor.setModels(self.mdlOutline, self.mdlCharacter,
2015-06-23 07:34:11 +12:00
self.mdlLabels, self.mdlStatus)
self.treeOutlineOutline.setModel(self.mdlOutline)
2016-02-06 00:25:25 +13:00
# self.redacEditor.setModel(self.mdlOutline)
self.storylineView.setModels(self.mdlOutline, self.mdlCharacter, self.mdlPlots)
2015-06-23 07:34:11 +12:00
2016-04-12 01:14:24 +12:00
self.treeOutlineOutline.selectionModel().selectionChanged.connect(self.outlineItemEditor.selectionChanged, AUC)
self.treeOutlineOutline.clicked.connect(self.outlineItemEditor.selectionChanged, AUC)
2015-07-02 20:08:20 +12:00
2015-06-30 00:21:57 +12:00
# Sync selection
2016-04-12 01:14:24 +12:00
self.treeRedacOutline.selectionModel().selectionChanged.connect(self.redacMetadata.selectionChanged, AUC)
self.treeRedacOutline.clicked.connect(self.redacMetadata.selectionChanged, AUC)
2015-06-23 07:34:11 +12:00
2015-06-28 00:06:35 +12:00
self.treeRedacOutline.selectionModel().selectionChanged.connect(self.mainEditor.selectionChanged, AUC)
2015-07-02 20:08:20 +12:00
2015-06-30 22:27:43 +12:00
# Cheat Sheet
self.cheatSheet.setModels()
2015-07-02 20:08:20 +12:00
2016-02-06 00:25:25 +13:00
# Debug
2015-06-24 04:22:39 +12:00
self.mdlFlatData.setVerticalHeaderLabels(["Infos générales", "Summary"])
self.tblDebugFlatData.setModel(self.mdlFlatData)
self.tblDebugPersos.setModel(self.mdlCharacter)
self.tblDebugPersosInfos.setModel(self.mdlCharacter)
2015-06-29 21:28:34 +12:00
self.tblDebugPersos.selectionModel().currentChanged.connect(
lambda: self.tblDebugPersosInfos.setRootIndex(self.mdlCharacter.index(
2016-02-06 00:25:25 +13:00
self.tblDebugPersos.selectionModel().currentIndex().row(),
2016-03-04 06:48:45 +13:00
Character.name.value)), AUC)
2015-07-02 20:08:20 +12:00
2015-06-24 04:22:39 +12:00
self.tblDebugPlots.setModel(self.mdlPlots)
self.tblDebugPlotsPersos.setModel(self.mdlPlots)
self.tblDebugSubPlots.setModel(self.mdlPlots)
self.tblDebugPlots.selectionModel().currentChanged.connect(
2016-02-06 00:25:25 +13:00
lambda: self.tblDebugPlotsPersos.setRootIndex(self.mdlPlots.index(
self.tblDebugPlots.selectionModel().currentIndex().row(),
Plot.characters.value)), AUC)
2015-06-24 04:22:39 +12:00
self.tblDebugPlots.selectionModel().currentChanged.connect(
2016-02-06 00:25:25 +13:00
lambda: self.tblDebugSubPlots.setRootIndex(self.mdlPlots.index(
self.tblDebugPlots.selectionModel().currentIndex().row(),
2016-03-07 04:10:25 +13:00
Plot.steps.value)), AUC)
self.treeDebugWorld.setModel(self.mdlWorld)
2015-06-24 04:22:39 +12:00
self.treeDebugOutline.setModel(self.mdlOutline)
self.lstDebugLabels.setModel(self.mdlLabels)
self.lstDebugStatus.setModel(self.mdlStatus)
2015-07-02 20:08:20 +12:00
def disconnectAll(self, signal, oldHandler=None):
# Disconnect all "oldHandler" slot connections for a signal
#
# Ref: PyQt Widget connect() and disconnect()
# https://stackoverflow.com/questions/21586643/pyqt-widget-connect-and-disconnect
#
# The loop is needed for safely disconnecting a specific handler,
# because it may have been connected multiple times, and
# disconnect only removes one connection at a time.
while True:
try:
if oldHandler is not None:
signal.disconnect(oldHandler)
else:
signal.disconnect()
except TypeError:
break
def breakConnections(self):
# Break connections for UI elements that were connected in makeConnections()
# Characters
self.disconnectAll(self.btnAddPerso.clicked, self.mdlCharacter.addCharacter)
self.disconnectAll(self.btnRmPerso.clicked, self.lstCharacters.removeCharacter)
self.disconnectAll(self.btnPersoColor.clicked, self.lstCharacters.choseCharacterColor)
self.disconnectAll(self.btnPersoAddInfo.clicked, self.lstCharacters.addCharacterInfo)
self.disconnectAll(self.btnPersoRmInfo.clicked, self.lstCharacters.removeCharacterInfo)
# Plots
self._updatingSubPlot = False
self.disconnectAll(self.btnAddPlot.clicked, self.mdlPlots.addPlot)
self.disconnectAll(self.btnRmPlot.clicked, lambda:
self.mdlPlots.removePlot(self.lstPlots.currentPlotIndex()))
self.disconnectAll(self.btnAddSubPlot.clicked, self.mdlPlots.addSubPlot)
self.disconnectAll(self.btnAddSubPlot.clicked, self.updateSubPlotView)
self.disconnectAll(self.btnRmSubPlot.clicked, self.mdlPlots.removeSubPlot)
self.disconnectAll(self.lstPlotPerso.selectionModel().selectionChanged, self.plotPersoSelectionChanged)
self.disconnectAll(self.btnRmPlotPerso.clicked, self.mdlPlots.removePlotPerso)
self.disconnectAll(self.mdlCharacter.dataChanged, self.mdlPlots.updatePlotPersoButton)
# World
self.disconnectAll(self.treeWorld.selectionModel().selectionChanged, self.changeCurrentWorld)
self.disconnectAll(self.btnAddWorld.clicked, self.mdlWorld.addItem)
self.disconnectAll(self.btnRmWorld.clicked, self.mdlWorld.removeItem)
# Outline
self.disconnectAll(self.treeOutlineOutline.selectionModel().selectionChanged, self.outlineItemEditor.selectionChanged)
self.disconnectAll(self.treeOutlineOutline.clicked, self.outlineItemEditor.selectionChanged)
# Sync selection
self.disconnectAll(self.treeRedacOutline.selectionModel().selectionChanged, self.redacMetadata.selectionChanged)
self.disconnectAll(self.treeRedacOutline.clicked, self.redacMetadata.selectionChanged)
self.disconnectAll(self.treeRedacOutline.selectionModel().selectionChanged, self.mainEditor.selectionChanged)
# Debug
self.disconnectAll(self.tblDebugPersos.selectionModel().currentChanged,
lambda: self.tblDebugPersosInfos.setRootIndex(self.mdlCharacter.index(
self.tblDebugPersos.selectionModel().currentIndex().row(),
Character.name.value)))
self.disconnectAll(self.tblDebugPlots.selectionModel().currentChanged,
lambda: self.tblDebugPlotsPersos.setRootIndex(self.mdlPlots.index(
self.tblDebugPlots.selectionModel().currentIndex().row(),
Plot.characters.value)))
self.disconnectAll(self.tblDebugPlots.selectionModel().currentChanged,
lambda: self.tblDebugSubPlots.setRootIndex(self.mdlPlots.index(
self.tblDebugPlots.selectionModel().currentIndex().row(),
Plot.steps.value)))
2016-02-06 00:25:25 +13:00
###############################################################################
# HELP
###############################################################################
def about(self):
self.dialog = aboutDialog(mw=self)
self.dialog.setFixedSize(self.dialog.size())
self.dialog.show()
# Center about dialog
r = self.dialog.geometry()
r2 = self.geometry()
self.dialog.move(r2.center() - r.center())
###############################################################################
2016-02-06 00:25:25 +13:00
# GENERAL AKA UNSORTED
###############################################################################
2015-06-23 07:34:11 +12:00
2015-05-28 13:32:09 +12:00
def clickCycle(self, i):
2015-06-23 07:34:11 +12:00
if i == 0: # step 2 - paragraph summary
2015-07-10 01:01:07 +12:00
self.tabMain.setCurrentIndex(self.TabSummary)
2015-05-28 13:32:09 +12:00
self.tabSummary.setCurrentIndex(1)
2015-06-23 07:34:11 +12:00
if i == 1: # step 3 - characters summary
2015-07-10 01:01:07 +12:00
self.tabMain.setCurrentIndex(self.TabPersos)
2015-05-28 13:32:09 +12:00
self.tabPersos.setCurrentIndex(0)
2015-06-23 07:34:11 +12:00
if i == 2: # step 4 - page summary
2015-07-10 01:01:07 +12:00
self.tabMain.setCurrentIndex(self.TabSummary)
2015-05-28 13:32:09 +12:00
self.tabSummary.setCurrentIndex(2)
2015-06-23 07:34:11 +12:00
if i == 3: # step 5 - characters description
2015-07-10 01:01:07 +12:00
self.tabMain.setCurrentIndex(self.TabPersos)
2015-05-28 13:32:09 +12:00
self.tabPersos.setCurrentIndex(1)
2015-06-23 07:34:11 +12:00
if i == 4: # step 6 - four page synopsis
2015-07-10 01:01:07 +12:00
self.tabMain.setCurrentIndex(self.TabSummary)
2015-05-28 13:32:09 +12:00
self.tabSummary.setCurrentIndex(3)
2015-06-23 07:34:11 +12:00
if i == 5: # step 7 - full character charts
2015-07-10 01:01:07 +12:00
self.tabMain.setCurrentIndex(self.TabPersos)
2015-05-28 13:32:09 +12:00
self.tabPersos.setCurrentIndex(2)
2015-06-23 07:34:11 +12:00
if i == 6: # step 8 - scene list
2015-07-10 01:01:07 +12:00
self.tabMain.setCurrentIndex(self.TabPlots)
2015-06-23 07:34:11 +12:00
2015-05-31 16:03:07 +12:00
def wordCount(self, i):
2015-06-23 07:34:11 +12:00
src = {
0: self.txtSummarySentence,
2015-06-23 07:34:11 +12:00
1: self.txtSummaryPara,
2: self.txtSummaryPage,
3: self.txtSummaryFull
2016-02-06 00:25:25 +13:00
}[i]
2015-06-23 07:34:11 +12:00
2015-05-28 13:32:09 +12:00
lbl = {
0: self.lblSummaryWCSentence,
2015-06-23 07:34:11 +12:00
1: self.lblSummaryWCPara,
2: self.lblSummaryWCPage,
3: self.lblSummaryWCFull
2016-02-06 00:25:25 +13:00
}[i]
2015-06-23 07:34:11 +12:00
2015-06-05 06:22:37 +12:00
wc = wordCount(src.toPlainText())
2015-06-23 07:34:11 +12:00
if i in [2, 3]:
pages = self.tr(" (~{} pages)").format(int(wc / 25) / 10.)
else:
pages = ""
2015-06-08 22:01:45 +12:00
lbl.setText(self.tr("Words: {}{}").format(wc, pages))
2015-06-23 07:34:11 +12:00
2015-06-04 05:25:03 +12:00
def setupMoreUi(self):
2016-02-06 00:25:25 +13:00
style.styleMainWindow(self)
2015-07-10 01:01:07 +12:00
# Tool bar on the right
self.toolbar = collapsibleDockWidgets(Qt.RightDockWidgetArea, self)
self.toolbar.addCustomWidget(self.tr("Book summary"), self.grpPlotSummary, self.TabPlots)
self.toolbar.addCustomWidget(self.tr("Project tree"), self.treeRedacWidget, self.TabRedac)
self.toolbar.addCustomWidget(self.tr("Metadata"), self.redacMetadata, self.TabRedac)
self.toolbar.addCustomWidget(self.tr("Story line"), self.storylineView, self.TabRedac)
if self._toolbarState:
self.toolbar.restoreState(self._toolbarState)
2016-02-06 00:25:25 +13:00
2016-02-07 06:36:02 +13:00
# Custom "tab" bar on the left
self.lstTabs.setIconSize(QSize(48, 48))
for i in range(self.tabMain.count()):
icons = ["general-128px.png",
"summary-128px.png",
"characters-128px.png",
"plot-128px.png",
"world-128px.png",
"outline-128px.png",
"redaction-128px.png",
""
]
self.tabMain.setTabIcon(i, QIcon(appPath("icons/Custom/Tabs/{}".format(icons[i]))))
item = QListWidgetItem(self.tabMain.tabIcon(i),
self.tabMain.tabText(i))
item.setSizeHint(QSize(item.sizeHint().width(), 64))
item.setTextAlignment(Qt.AlignCenter)
self.lstTabs.addItem(item)
self.tabMain.tabBar().hide()
self.lstTabs.currentRowChanged.connect(self.tabMain.setCurrentIndex)
self.tabMain.currentChanged.connect(self.lstTabs.setCurrentRow)
2015-06-04 05:25:03 +12:00
# Splitters
self.splitterPersos.setStretchFactor(0, 25)
self.splitterPersos.setStretchFactor(1, 75)
2015-06-23 07:34:11 +12:00
2015-06-04 05:25:03 +12:00
self.splitterPlot.setStretchFactor(0, 20)
2015-06-05 06:22:37 +12:00
self.splitterPlot.setStretchFactor(1, 60)
self.splitterPlot.setStretchFactor(2, 30)
2016-02-06 00:25:25 +13:00
self.splitterWorld.setStretchFactor(0, 25)
self.splitterWorld.setStretchFactor(1, 75)
2015-06-23 07:34:11 +12:00
2015-06-05 06:22:37 +12:00
self.splitterOutlineH.setStretchFactor(0, 25)
self.splitterOutlineH.setStretchFactor(1, 75)
self.splitterOutlineV.setStretchFactor(0, 75)
self.splitterOutlineV.setStretchFactor(1, 25)
2015-06-23 07:34:11 +12:00
self.splitterRedacV.setStretchFactor(0, 75)
self.splitterRedacV.setStretchFactor(1, 25)
self.splitterRedacH.setStretchFactor(0, 30)
self.splitterRedacH.setStretchFactor(1, 40)
self.splitterRedacH.setStretchFactor(2, 30)
2016-02-06 00:25:25 +13:00
# QFormLayout stretch
for w in [self.txtWorldDescription, self.txtWorldPassion, self.txtWorldConflict]:
s = w.sizePolicy()
s.setVerticalStretch(1)
w.setSizePolicy(s)
2016-02-06 00:25:25 +13:00
2015-06-04 05:25:03 +12:00
# Help box
references = [
(self.lytTabOverview,
2015-06-21 21:29:35 +12:00
self.tr("Enter infos about your book, and yourself."),
0),
(self.lytSituation,
2016-02-06 00:25:25 +13:00
self.tr(
"""The basic situation, in the form of a 'What if...?' question. Ex: 'What if the most dangerous
evil wizard could wasn't abled to kill a baby?' (Harry Potter)"""),
2015-06-21 21:29:35 +12:00
1),
(self.lytSummary,
2016-02-06 00:25:25 +13:00
self.tr(
"""Take time to think about a one sentence (~50 words) summary of your book. Then expand it to
2016-02-06 00:25:25 +13:00
a paragraph, then to a page, then to a full summary."""),
2015-06-21 21:29:35 +12:00
1),
2015-06-04 05:25:03 +12:00
(self.lytTabPersos,
2015-06-21 21:29:35 +12:00
self.tr("Create your characters."),
0),
2015-06-04 05:25:03 +12:00
(self.lytTabPlot,
2015-06-21 21:29:35 +12:00
self.tr("Develop plots."),
0),
2017-09-24 07:53:18 +13:00
(self.lytTabContext,
self.tr("Build worlds. Create hierarchy of broad categories down to specific details."),
0),
2015-06-04 05:25:03 +12:00
(self.lytTabOutline,
2015-06-21 21:29:35 +12:00
self.tr("Create the outline of your masterpiece."),
0),
2015-06-04 05:25:03 +12:00
(self.lytTabRedac,
2015-06-21 21:29:35 +12:00
self.tr("Write."),
0),
2015-06-04 05:25:03 +12:00
(self.lytTabDebug,
2015-06-21 21:29:35 +12:00
self.tr("Debug infos. Sometimes useful."),
0)
2016-02-06 00:25:25 +13:00
]
2015-06-04 05:25:03 +12:00
2015-06-21 21:29:35 +12:00
for widget, text, pos in references:
label = helpLabel(text, self)
self.actShowHelp.toggled.connect(label.setVisible, AUC)
2015-06-21 21:29:35 +12:00
widget.layout().insertWidget(pos, label)
2015-06-23 07:34:11 +12:00
2015-06-07 05:10:44 +12:00
self.actShowHelp.setChecked(False)
2015-06-23 07:34:11 +12:00
2015-06-07 05:10:44 +12:00
# Spellcheck
if enchant:
2015-06-08 22:01:45 +12:00
self.menuDict = QMenu(self.tr("Dictionary"))
2015-06-07 05:10:44 +12:00
self.menuDictGroup = QActionGroup(self)
self.updateMenuDict()
2015-06-07 05:10:44 +12:00
self.menuTools.addMenu(self.menuDict)
2015-06-23 07:34:11 +12:00
self.actSpellcheck.toggled.connect(self.toggleSpellcheck, AUC)
2015-06-28 00:06:35 +12:00
self.dictChanged.connect(self.mainEditor.setDict, AUC)
self.dictChanged.connect(self.redacMetadata.setDict, AUC)
self.dictChanged.connect(self.outlineItemEditor.setDict, AUC)
2015-06-23 07:34:11 +12:00
2015-06-07 05:10:44 +12:00
else:
# No Spell check support
self.actSpellcheck.setVisible(False)
2015-06-08 22:01:45 +12:00
a = QAction(self.tr("Install PyEnchant to use spellcheck"), self)
2015-06-07 05:10:44 +12:00
a.setIcon(self.style().standardIcon(QStyle.SP_MessageBoxWarning))
a.triggered.connect(self.openPyEnchantWebPage, AUC)
2015-06-07 05:10:44 +12:00
self.menuTools.addAction(a)
2015-06-23 07:34:11 +12:00
2016-02-06 00:25:25 +13:00
###############################################################################
# SPELLCHECK
###############################################################################
2015-06-24 04:22:39 +12:00
def updateMenuDict(self):
2015-06-23 07:34:11 +12:00
2015-06-16 18:15:24 +12:00
if not enchant:
return
2015-06-23 07:34:11 +12:00
self.menuDict.clear()
for i in enchant.list_dicts():
a = QAction(str(i[0]), self)
a.setCheckable(True)
2015-06-23 07:34:11 +12:00
if settings.dict is None:
settings.dict = enchant.get_default_language()
if str(i[0]) == settings.dict:
a.setChecked(True)
2015-06-30 00:21:57 +12:00
a.triggered.connect(self.setDictionary, AUC)
self.menuDictGroup.addAction(a)
self.menuDict.addAction(a)
2015-06-23 07:34:11 +12:00
2015-06-07 05:10:44 +12:00
def setDictionary(self):
2015-06-16 18:15:24 +12:00
if not enchant:
return
2015-06-23 07:34:11 +12:00
2015-06-07 05:10:44 +12:00
for i in self.menuDictGroup.actions():
if i.isChecked():
2016-02-06 00:25:25 +13:00
# self.dictChanged.emit(i.text().replace("&", ""))
settings.dict = i.text().replace("&", "")
2015-06-23 07:34:11 +12:00
# Find all textEditView from self, and toggle spellcheck
2015-06-23 07:34:11 +12:00
for w in self.findChildren(textEditView, QRegExp(".*"),
Qt.FindChildrenRecursively):
w.setDict(settings.dict)
2015-06-07 05:10:44 +12:00
def openPyEnchantWebPage(self):
2016-02-07 00:34:22 +13:00
from PyQt5.QtGui import QDesktopServices
QDesktopServices.openUrl(QUrl("http://pythonhosted.org/pyenchant/"))
2015-06-23 07:34:11 +12:00
def toggleSpellcheck(self, val):
settings.spellcheck = val
2015-06-23 07:34:11 +12:00
# Find all textEditView from self, and toggle spellcheck
2015-06-23 07:34:11 +12:00
for w in self.findChildren(textEditView, QRegExp(".*"),
Qt.FindChildrenRecursively):
w.toggleSpellcheck(val)
2015-06-23 07:34:11 +12:00
2016-02-06 00:25:25 +13:00
###############################################################################
# SETTINGS
###############################################################################
def settingsLabel(self):
2015-07-04 09:00:54 +12:00
self.settingsWindow(3)
2015-06-23 07:34:11 +12:00
def settingsStatus(self):
2015-07-04 09:00:54 +12:00
self.settingsWindow(4)
2015-06-23 07:34:11 +12:00
def settingsWindow(self, tab=None):
self.sw = settingsWindow(self)
self.sw.hide()
self.sw.setWindowModality(Qt.ApplicationModal)
self.sw.setWindowFlags(Qt.Dialog)
r = self.sw.geometry()
r2 = self.geometry()
self.sw.move(r2.center() - r.center())
if tab:
2015-06-18 06:45:24 +12:00
self.sw.setTab(tab)
self.sw.show()
2015-06-23 07:34:11 +12:00
2016-02-09 01:50:35 +13:00
###############################################################################
# TOOLS
###############################################################################
def frequencyAnalyzer(self):
self.fw = frequencyAnalyzer(self)
self.fw.show()
2016-02-06 00:25:25 +13:00
###############################################################################
# VIEW MENU
###############################################################################
2015-06-23 07:34:11 +12:00
def generateViewMenu(self):
values = [
2016-02-06 00:25:25 +13:00
(self.tr("Nothing"), "Nothing"),
(self.tr("POV"), "POV"),
(self.tr("Label"), "Label"),
(self.tr("Progress"), "Progress"),
(self.tr("Compile"), "Compile"),
]
2015-06-23 07:34:11 +12:00
menus = [
(self.tr("Tree"), "Tree"),
(self.tr("Index cards"), "Cork"),
(self.tr("Outline"), "Outline")
2016-02-06 00:25:25 +13:00
]
2015-06-23 07:34:11 +12:00
submenus = {
"Tree": [
(self.tr("Icon color"), "Icon"),
(self.tr("Text color"), "Text"),
(self.tr("Background color"), "Background"),
2016-02-06 00:25:25 +13:00
],
"Cork": [
(self.tr("Icon"), "Icon"),
(self.tr("Text"), "Text"),
(self.tr("Background"), "Background"),
(self.tr("Border"), "Border"),
(self.tr("Corner"), "Corner"),
2016-02-06 00:25:25 +13:00
],
"Outline": [
(self.tr("Icon color"), "Icon"),
(self.tr("Text color"), "Text"),
(self.tr("Background color"), "Background"),
2016-02-06 00:25:25 +13:00
],
}
2015-06-23 07:34:11 +12:00
self.menuView.clear()
2016-03-25 01:42:47 +13:00
self.menuView.addMenu(self.menuMode)
self.menuView.addSeparator()
2015-06-23 07:34:11 +12:00
2016-02-06 00:25:25 +13:00
# print("Generating menus with", settings.viewSettings)
2015-06-23 07:34:11 +12:00
for mnu, mnud in menus:
m = QMenu(mnu, self.menuView)
for s, sd in submenus[mnud]:
m2 = QMenu(s, m)
agp = QActionGroup(m2)
for v, vd in values:
a = QAction(v, m)
a.setCheckable(True)
a.setData("{},{},{}".format(mnud, sd, vd))
if settings.viewSettings[mnud][sd] == vd:
a.setChecked(True)
a.triggered.connect(self.setViewSettingsAction, AUC)
agp.addAction(a)
m2.addAction(a)
m.addMenu(m2)
self.menuView.addMenu(m)
2015-06-23 07:34:11 +12:00
2015-06-18 04:40:55 +12:00
def setViewSettingsAction(self):
action = self.sender()
item, part, element = action.data().split(",")
2015-06-18 04:40:55 +12:00
self.setViewSettings(item, part, element)
2015-06-23 07:34:11 +12:00
2015-06-18 04:40:55 +12:00
def setViewSettings(self, item, part, element):
2015-06-16 09:15:10 +12:00
settings.viewSettings[item][part] = element
if item == "Cork":
2015-06-28 00:06:35 +12:00
self.mainEditor.updateCorkView()
2015-06-18 03:15:13 +12:00
if item == "Outline":
2015-06-28 00:06:35 +12:00
self.mainEditor.updateTreeView()
self.treeOutlineOutline.viewport().update()
2015-06-18 03:15:13 +12:00
if item == "Tree":
2015-07-01 23:14:03 +12:00
self.treeRedacOutline.viewport().update()
2015-07-02 20:08:20 +12:00
2016-03-25 01:42:47 +13:00
###############################################################################
# VIEW MODES
###############################################################################
def setViewModeSimple(self):
settings.viewMode = "simple"
self.tabMain.setCurrentIndex(self.TabRedac)
self.viewModeFictionVisibilitySwitch(False)
self.actModeSimple.setChecked(True)
def setViewModeFiction(self):
settings.viewMode = "fiction"
self.viewModeFictionVisibilitySwitch(True)
self.actModeFiction.setChecked(True)
def viewModeFictionVisibilitySwitch(self, val):
"""
Swtiches the visibility of some UI components useful for fiction only
@param val: sets visibility to val
"""
# Menu navigation & boutton in toolbar
self.toolbar.setDockVisibility(self.dckNavigation, val)
# POV in metadatas
from manuskript.ui.views.propertiesView import propertiesView
for w in findWidgetsOfClass(propertiesView):
w.lblPOV.setVisible(val)
w.cmbPOV.setVisible(val)
# POV in outline view
if Outline.POV.value in settings.outlineViewColumns:
settings.outlineViewColumns.remove(Outline.POV.value)
from manuskript.ui.views.outlineView import outlineView
for w in findWidgetsOfClass(outlineView):
w.hideColumns()
# TODO: clean up all other fiction things in non-fiction view mode
# Character in search widget
# POV in settings / views
2016-02-06 00:25:25 +13:00
###############################################################################
# COMPILE
###############################################################################
2015-07-01 23:14:03 +12:00
def doCompile(self):
2016-04-05 06:00:19 +12:00
self.dialog = exporterDialog(mw=self)
2016-04-02 06:01:27 +13:00
self.dialog.show()
r = self.dialog.geometry()
r2 = self.geometry()
self.dialog.move(r2.center() - r.center())