manuskript/manuskript/ui/editors/mainEditor.py

370 lines
14 KiB
Python
Raw Normal View History

2015-06-28 00:06:35 +12:00
#!/usr/bin/env python
2016-02-07 00:34:22 +13:00
# --!-- coding: utf8 --!--
2015-06-30 04:51:20 +12:00
import locale
2016-02-07 00:34:22 +13:00
from PyQt5.QtCore import QModelIndex, QRect, QPoint
from PyQt5.QtCore import Qt
2016-04-11 17:13:09 +12:00
from PyQt5.QtGui import QPixmap, QPainter, QIcon
from PyQt5.QtWidgets import QWidget, qApp
2016-02-07 00:34:22 +13:00
from manuskript import settings
from manuskript.enums import Outline
2016-04-12 09:54:47 +12:00
from manuskript.functions import AUC, mainWindow, drawProgress, appPath
from manuskript.ui import style
2016-02-07 00:34:22 +13:00
from manuskript.ui.editors.editorWidget import editorWidget
from manuskript.ui.editors.fullScreenEditor import fullScreenEditor
from manuskript.ui.editors.mainEditor_ui import Ui_mainEditor
try:
locale.setlocale(locale.LC_ALL, '')
except:
pass
2015-06-28 00:06:35 +12:00
class mainEditor(QWidget, Ui_mainEditor):
"""
`mainEditor` is responsible for opening `outlineItem`s and offering informations
and commands about those `outlineItem`s to the used.
It contains two main elements:
1. A `tabSplitter`, which can open any numer of `outlineItem`s either in tabs
(in `QTabWidget`) and/or in splitted views (children `tabSplitter`s).
2. An horizontal layout contain a number of buttons and informations:
- Go up button
- Select folder view: either "text", "cork" or "outline" (see `editorWidget`)
- Zoom slider for "cork" view
- Label showing stats about displayed `outlineItem`
- Fullscreen button
`mainEditor` is responsible for opening indexes, propagating event to relevent
views, opening and closing tabs, etc.
+---------------------------| mainEditor |--------------------------------+
| |
| +--------| tabSplitter |----------------------------------------------+ |
| | +----------| tabSplitter |---------+ | |
| | | | | |
| | +-----| editorWidget |----+ | +-------| editorWidget |-----+ | | |
| | | | | | | | | |
| | +-------------------------+ | +----------------------------+ | | |
| | | | | |
| | +-----| editorWidget |----+ | +-------| editorWidget |-----+ | | |
| | | | | | | | | |
| | +-------------------------+ | +----------------------------+ | | |
| | +----------------------------------+ | |
| +---------------------------------------------------------------------+ |
| |
+-------------------------------------------------------------------------+
| ## ## ## ## toolbar ## ## |
+-------------------------------------------------------------------------+
"""
2015-06-28 00:06:35 +12:00
def __init__(self, parent=None):
QWidget.__init__(self, parent)
self.setupUi(self)
2015-06-30 00:21:57 +12:00
self._updating = False
2016-02-07 00:34:22 +13:00
2015-06-28 00:06:35 +12:00
self.mw = mainWindow()
2016-02-08 21:04:24 +13:00
2015-06-28 23:03:57 +12:00
# Connections --------------------------------------------------------
2016-02-07 00:34:22 +13:00
2017-10-15 08:39:16 +13:00
self.btnGoUp.clicked.connect(self.goToParentItem)
2015-06-28 00:06:35 +12:00
self.sldCorkSizeFactor.valueChanged.connect(
2016-02-07 00:34:22 +13:00
self.setCorkSizeFactor, AUC)
2015-06-28 00:06:35 +12:00
self.btnRedacFolderCork.toggled.connect(
2016-04-11 03:29:27 +12:00
self.sldCorkSizeFactor.setVisible, AUC
)
2015-06-28 00:06:35 +12:00
self.btnRedacFolderText.clicked.connect(
2016-02-07 00:34:22 +13:00
lambda v: self.setFolderView("text"), AUC)
2015-06-28 00:06:35 +12:00
self.btnRedacFolderCork.clicked.connect(
2016-02-07 00:34:22 +13:00
lambda v: self.setFolderView("cork"), AUC)
2015-06-28 00:06:35 +12:00
self.btnRedacFolderOutline.clicked.connect(
2016-02-07 00:34:22 +13:00
lambda v: self.setFolderView("outline"), AUC)
2015-06-28 00:06:35 +12:00
self.btnRedacFullscreen.clicked.connect(
2016-02-07 00:34:22 +13:00
self.showFullScreen, AUC)
2016-04-11 03:29:27 +12:00
# self.tab.setDocumentMode(False)
2016-04-12 01:14:24 +12:00
# Bug in Qt < 5.5: doesn't always load icons from custom theme.
# Cf. https://github.com/qtproject/qtbase/commit/a8621a3f85e64f1252a80ae81a6e22554f7b3f44
# Since those are important, we provide fallback.
self.btnRedacFolderCork.setIcon(QIcon.fromTheme("view-cards",
2016-04-12 09:54:47 +12:00
QIcon(appPath("icons/NumixMsk/256x256/actions/view-cards.svg"))))
2016-04-12 01:14:24 +12:00
self.btnRedacFolderOutline.setIcon(QIcon.fromTheme("view-outline",
2016-04-12 09:54:47 +12:00
QIcon(appPath("icons/NumixMsk/256x256/actions/view-outline.svg"))))
2016-04-12 01:14:24 +12:00
self.btnRedacFolderText.setIcon(QIcon.fromTheme("view-text",
2016-04-12 09:54:47 +12:00
QIcon(appPath("icons/NumixMsk/256x256/actions/view-text.svg"))))
2016-04-11 17:13:09 +12:00
for btn in [self.btnRedacFolderCork, self.btnRedacFolderText, self.btnRedacFolderOutline]:
btn.setToolTip(btn.text())
btn.setText("")
2016-04-09 01:23:20 +12:00
2016-02-07 00:34:22 +13:00
###############################################################################
# TABS
###############################################################################
2016-04-11 03:29:27 +12:00
def currentTabWidget(self):
"""Returns the tabSplitter that has focus."""
ts = self.tabSplitter
while ts:
if ts.focusTab == 1:
return ts.tab
else:
ts = ts.secondTab
# No tabSplitter has focus, something is strange.
# But probably not important.
# Let's return self.tabSplitter.tab anyway.
return self.tabSplitter.tab
2016-04-12 01:14:24 +12:00
def currentEditor(self, tabWidget=None):
if tabWidget is None:
tabWidget = self.currentTabWidget()
return tabWidget.currentWidget()
2016-04-11 03:29:27 +12:00
# return self.tab.currentWidget()
2016-02-07 00:34:22 +13:00
2016-04-11 03:29:27 +12:00
def tabChanged(self, index=QModelIndex()):
2015-06-30 00:21:57 +12:00
if self.currentEditor():
index = self.currentEditor().currentIndex
view = self.currentEditor().folderView
self.updateFolderViewButtons(view)
else:
index = QModelIndex()
2016-02-07 00:34:22 +13:00
2016-04-12 01:14:24 +12:00
self.updateMainTreeView(index)
2016-02-07 00:34:22 +13:00
2015-06-30 00:33:30 +12:00
self.updateStats()
2015-07-02 09:15:35 +12:00
self.updateThingsVisible(index)
2016-02-07 00:34:22 +13:00
2016-04-12 01:14:24 +12:00
def updateMainTreeView(self, index):
self._updating = True
self.mw.treeRedacOutline.setCurrentIndex(index)
self._updating = False
def closeAllTabs(self):
2016-04-11 03:29:27 +12:00
for ts in self.allTabSplitters():
while(ts.tab.count()):
ts.closeTab(0)
for ts in reversed(self.allTabSplitters()):
ts.closeSplit()
def allTabs(self, tabWidget=None):
"""Returns all the tabs from the given tabWidget. If tabWidget is None, from the current tabWidget."""
if tabWidget is None:
tabWidget = self.currentTabWidget()
return [tabWidget.widget(i) for i in range(tabWidget.count())]
def allAllTabs(self):
"""Returns a list of all tabs, from all tabWidgets."""
r = []
for ts in self.allTabSplitters():
r.extend(self.allTabs(ts.tab))
return r
def allTabSplitters(self):
r = []
ts = self.tabSplitter
while ts:
r.append(ts)
ts = ts.secondTab
return r
2016-02-07 00:34:22 +13:00
###############################################################################
# SELECTION AND UPDATES
###############################################################################
2015-06-28 00:06:35 +12:00
def selectionChanged(self):
2015-06-30 00:21:57 +12:00
if self._updating:
return
2016-02-07 00:34:22 +13:00
# This might be called during a drag n drop operation, or while deleting
# items. If so, we don't want to do anything.
if not self.mw.mdlOutline._removingRows:
if len(self.mw.treeRedacOutline.selectionModel().
selection().indexes()) == 0:
idx = QModelIndex()
else:
idx = self.mw.treeRedacOutline.currentIndex()
2015-06-28 00:06:35 +12:00
self.setCurrentModelIndex(idx)
self.updateThingsVisible(idx)
2016-02-07 00:34:22 +13:00
2015-06-30 00:21:57 +12:00
def openIndexes(self, indexes, newTab=False):
for i in indexes:
self.setCurrentModelIndex(i, newTab)
2017-10-15 08:39:16 +13:00
def goToParentItem(self):
idx = self.currentEditor().currentIndex
self.mw.treeRedacOutline.setCurrentIndex(idx.parent())
2016-02-07 00:34:22 +13:00
2016-04-12 01:14:24 +12:00
def setCurrentModelIndex(self, index, newTab=False, tabWidget=None):
2016-02-07 00:34:22 +13:00
2016-04-12 01:14:24 +12:00
title = self.getIndexTitle(index)
if tabWidget is None:
tabWidget = self.currentTabWidget()
2016-02-07 00:34:22 +13:00
2015-06-30 00:21:57 +12:00
# Checking if tab is already openned
2016-04-12 01:14:24 +12:00
for w in self.allTabs(tabWidget):
2015-06-30 00:21:57 +12:00
if w.currentIndex == index:
2016-04-12 01:14:24 +12:00
tabWidget.setCurrentWidget(w)
2015-06-30 00:21:57 +12:00
return
2016-02-07 00:34:22 +13:00
2015-06-30 00:21:57 +12:00
if qApp.keyboardModifiers() & Qt.ControlModifier:
newTab = True
2016-02-07 00:34:22 +13:00
if newTab or not tabWidget.count():
2015-06-30 00:21:57 +12:00
editor = editorWidget(self)
editor.setCurrentModelIndex(index)
editor._tabWidget = tabWidget
i = tabWidget.addTab(editor, editor.ellidedTitle(title))
tabWidget.setTabToolTip(i, title)
tabWidget.setCurrentIndex(tabWidget.count() - 1)
2015-06-30 00:21:57 +12:00
else:
2016-04-12 01:14:24 +12:00
self.currentEditor(tabWidget).setCurrentModelIndex(index)
#tabWidget.setTabText(tabWidget.currentIndex(), title)
2016-04-12 01:14:24 +12:00
def updateTargets(self):
"""Updates all tabSplitter that are targets. This is called from editorWidget."""
index = self.sender().currentIndex()
for ts in self.allTabSplitters():
if ts.isTarget:
self.updateMainTreeView(index)
self.setCurrentModelIndex(index, tabWidget=ts.tab)
self.updateThingsVisible(index)
def getIndexTitle(self, index):
if not index.isValid():
title = self.tr("Root")
else:
title = index.internalPointer().title()
return title
2016-02-07 00:34:22 +13:00
###############################################################################
# FUNCTIONS FOR MENU ACCESS
###############################################################################
def copy(self): self.currentEditor().copy()
def cut(self): self.currentEditor().cut()
def paste(self): self.currentEditor().paste()
def duplicate(self): self.currentEditor().duplicate()
def delete(self): self.currentEditor().delete()
def moveUp(self): self.currentEditor().moveUp()
def moveDown(self): self.currentEditor().moveDown()
2017-11-11 04:26:23 +13:00
def splitDialog(self): self.currentEditor().splitDialog()
def splitCursor(self): self.currentEditor().splitCursor()
2017-11-11 05:21:02 +13:00
def merge(self): self.currentEditor().merge()
2016-02-07 00:34:22 +13:00
###############################################################################
# UI
###############################################################################
2015-07-02 09:15:35 +12:00
def updateThingsVisible(self, index):
if index.isValid():
visible = index.internalPointer().isFolder()
else:
visible = True
2016-02-07 00:34:22 +13:00
2015-07-02 09:15:35 +12:00
# Hides / show textFormat
self.textFormat.updateFromIndex(index)
2016-02-07 00:34:22 +13:00
2015-07-02 09:15:35 +12:00
self.btnRedacFolderText.setVisible(visible)
self.btnRedacFolderCork.setVisible(visible)
self.btnRedacFolderOutline.setVisible(visible)
2016-04-11 03:29:27 +12:00
self.sldCorkSizeFactor.setVisible(visible and self.btnRedacFolderCork.isChecked())
2015-07-02 09:15:35 +12:00
self.btnRedacFullscreen.setVisible(not visible)
2016-02-07 00:34:22 +13:00
2015-06-30 00:21:57 +12:00
def updateFolderViewButtons(self, view):
if view == "text":
self.btnRedacFolderText.setChecked(True)
elif view == "cork":
self.btnRedacFolderCork.setChecked(True)
elif view == "outline":
self.btnRedacFolderOutline.setChecked(True)
2016-02-07 00:34:22 +13:00
2015-06-30 00:33:30 +12:00
def updateStats(self):
2016-02-07 00:34:22 +13:00
2015-06-30 00:33:30 +12:00
if not self.currentEditor():
return
2016-02-07 00:34:22 +13:00
2015-06-30 00:33:30 +12:00
index = self.currentEditor().currentIndex
if index.isValid():
2015-06-28 00:06:35 +12:00
item = index.internalPointer()
else:
2015-06-30 00:21:57 +12:00
item = self.mw.mdlOutline.rootItem
2016-02-07 00:34:22 +13:00
2015-06-28 00:06:35 +12:00
if not item:
2015-06-30 00:21:57 +12:00
item = self.mw.mdlOutline.rootItem
2016-02-07 00:34:22 +13:00
2015-06-28 00:06:35 +12:00
wc = item.data(Outline.wordCount.value)
goal = item.data(Outline.goal.value)
progress = item.data(Outline.goalPercentage.value)
2016-02-07 00:34:22 +13:00
# mw = qApp.activeWindow()
2015-06-28 00:06:35 +12:00
if not wc:
wc = 0
if goal:
self.lblRedacProgress.show()
rect = self.lblRedacProgress.geometry()
rect = QRect(QPoint(0, 0), rect.size())
self.px = QPixmap(rect.size())
self.px.fill(Qt.transparent)
p = QPainter(self.px)
drawProgress(p, rect, progress, 2)
del p
self.lblRedacProgress.setPixmap(self.px)
2017-11-14 22:36:57 +13:00
self.lblRedacWC.setText(self.tr("{} words / {} ").format(
2016-02-07 00:34:22 +13:00
locale.format("%d", wc, grouping=True),
locale.format("%d", goal, grouping=True)))
2015-06-28 00:06:35 +12:00
else:
self.lblRedacProgress.hide()
2017-11-14 22:36:57 +13:00
self.lblRedacWC.setText(self.tr("{} words ").format(
2016-02-07 00:34:22 +13:00
locale.format("%d", wc, grouping=True)))
###############################################################################
# VIEWS
###############################################################################
2015-06-28 00:06:35 +12:00
def setFolderView(self, view):
if self.currentEditor():
self.currentEditor().setFolderView(view)
2016-02-07 00:34:22 +13:00
2015-06-28 00:06:35 +12:00
def setCorkSizeFactor(self, val):
2016-04-11 03:29:27 +12:00
for w in self.allAllTabs():
2015-06-30 00:33:30 +12:00
w.setCorkSizeFactor(val)
2015-06-30 09:41:13 +12:00
settings.corkSizeFactor = val
2016-02-07 00:34:22 +13:00
2015-06-28 00:06:35 +12:00
def updateCorkView(self):
2016-04-11 03:29:27 +12:00
for w in self.allAllTabs():
2015-06-30 00:33:30 +12:00
w.corkView.viewport().update()
2016-02-07 00:34:22 +13:00
2015-06-28 00:06:35 +12:00
def updateCorkBackground(self):
2016-04-11 03:29:27 +12:00
for w in self.allAllTabs():
2015-06-30 00:33:30 +12:00
w.corkView.updateBackground()
2016-02-07 00:34:22 +13:00
2015-06-28 00:06:35 +12:00
def updateTreeView(self):
2016-04-11 03:29:27 +12:00
for w in self.allAllTabs():
2016-02-05 05:48:35 +13:00
w.outlineView.viewport().update()
2016-02-07 00:34:22 +13:00
2015-06-28 00:06:35 +12:00
def showFullScreen(self):
2015-06-30 04:46:16 +12:00
if self.currentEditor():
self._fullScreen = fullScreenEditor(self.currentEditor().currentIndex)
2016-02-07 00:34:22 +13:00
###############################################################################
# DICT AND STUFF LIKE THAT
###############################################################################
2015-06-28 00:06:35 +12:00
def setDict(self, dict):
2015-06-30 00:21:57 +12:00
print(dict)
2016-04-11 03:29:27 +12:00
for w in self.allAllTabs():
2015-06-30 00:21:57 +12:00
w.setDict(dict)
2016-02-07 00:34:22 +13:00
2015-06-28 00:06:35 +12:00
def toggleSpellcheck(self, val):
2016-04-11 03:29:27 +12:00
for w in self.allAllTabs():
2015-06-30 00:21:57 +12:00
w.toggleSpellcheck(val)