Adds: split dialog, split at cursor

This commit is contained in:
Olivier Keshavjee 2017-11-10 16:26:23 +01:00
parent 3b17c4e2b4
commit a153606811
8 changed files with 206 additions and 21 deletions

View file

@ -439,23 +439,42 @@ class MainWindow(QMainWindow, Ui_MainWindow):
# mainEditor). So we just pass along the signal. # mainEditor). So we just pass along the signal.
def documentsCopy(self): def documentsCopy(self):
"Copy selected item(s)."
if self._lastFocus: self._lastFocus.copy() if self._lastFocus: self._lastFocus.copy()
def documentsCut(self): def documentsCut(self):
"Cut selected item(s)."
if self._lastFocus: self._lastFocus.cut() if self._lastFocus: self._lastFocus.cut()
def documentsPaste(self): def documentsPaste(self):
"Paste clipboard item(s) into selected item."
if self._lastFocus: self._lastFocus.paste() if self._lastFocus: self._lastFocus.paste()
def documentsDuplicate(self): def documentsDuplicate(self):
"Duplicate selected item(s)."
if self._lastFocus: self._lastFocus.duplicate() if self._lastFocus: self._lastFocus.duplicate()
def documentsDelete(self): def documentsDelete(self):
"Delete selected item(s)."
if self._lastFocus: self._lastFocus.delete() if self._lastFocus: self._lastFocus.delete()
def documentsMoveUp(self): def documentsMoveUp(self):
"Move up selected item(s)."
if self._lastFocus: self._lastFocus.moveUp() if self._lastFocus: self._lastFocus.moveUp()
def documentsMoveDown(self): def documentsMoveDown(self):
"Move Down selected item(s)."
if self._lastFocus: self._lastFocus.moveDown() if self._lastFocus: self._lastFocus.moveDown()
def documentsSplitDialog(self): def documentsSplitDialog(self):
print("documentsSplitDialog::FIXME") "Opens a dialog to split selected items."
if self._lastFocus: self._lastFocus.splitDialog()
# current items or selected items?
pass
# use outlineBasics, to do that on all selected items.
# use editorWidget to do that on selected text.
def documentsSplitCursor(self): def documentsSplitCursor(self):
print("documentsSplitCursor::FIXME") """
Split current item (open in text editor) at cursor position. If there is
a text selection, that selection becomes the title of the new scene.
"""
if self._lastFocus and self._lastFocus == self.mainEditor:
self.mainEditor.splitCursor()
def documentsMerge(self): def documentsMerge(self):
print("documentsMerge::FIXME") print("documentsMerge::FIXME")

View file

@ -652,6 +652,7 @@ class outlineItem():
if column == Outline.text.value: if column == Outline.text.value:
wc = wordCount(data) wc = wordCount(data)
self.setData(Outline.wordCount.value, wc) self.setData(Outline.wordCount.value, wc)
self.emitDataChanged(cols=[Outline.text.value]) # new in 0.5.0
if column == Outline.compile.value: if column == Outline.compile.value:
self.emitDataChanged(cols=[Outline.title.value, Outline.compile.value], recursive=True) self.emitDataChanged(cols=[Outline.title.value, Outline.compile.value], recursive=True)
@ -894,9 +895,39 @@ class outlineItem():
item.setData(Outline.text.value, subTxt) item.setData(Outline.text.value, subTxt)
# Inserting item # Inserting item
self.parent().insertChild(self.row()+k, item) #self.parent().insertChild(self.row()+k, item)
self._model.insertItem(item, self.row()+k, self.parent().index())
k += 1 k += 1
def splitAt(self, position, length=0):
"""
Splits note at position p.
If length is bigger than 0, it describes the length of the title, made
from the character following position.
"""
txt = self.text()
# Stores the new text
self.setData(Outline.text.value, txt[:position])
# Create a copy
item = self.copy()
# Update title
if length > 0:
title = txt[position:position+length].replace("\n", "")
else:
title = "{}_{}".format(item.title(), 2)
item.setData(Outline.title.value, title)
# Set text
item.setData(Outline.text.value, txt[position+length:])
# Inserting item using the model to signal views
self._model.insertItem(item, self.row()+1, self.parent().index())
############################################################################### ###############################################################################
# XML # XML
############################################################################### ###############################################################################

View file

@ -96,13 +96,14 @@ frequencyAnalyzer = {
viewMode = "fiction" # simple, fiction viewMode = "fiction" # simple, fiction
saveToZip = True saveToZip = True
dontShowDeleteWarning = False
def save(filename=None, protocol=None): def save(filename=None, protocol=None):
global spellcheck, dict, corkSliderFactor, viewSettings, corkSizeFactor, folderView, lastTab, openIndexes, \ global spellcheck, dict, corkSliderFactor, viewSettings, corkSizeFactor, folderView, lastTab, openIndexes, \
autoSave, autoSaveDelay, saveOnQuit, autoSaveNoChanges, autoSaveNoChangesDelay, outlineViewColumns, \ autoSave, autoSaveDelay, saveOnQuit, autoSaveNoChanges, autoSaveNoChangesDelay, outlineViewColumns, \
corkBackground, corkStyle, fullScreenTheme, defaultTextType, textEditor, revisions, frequencyAnalyzer, viewMode, \ corkBackground, corkStyle, fullScreenTheme, defaultTextType, textEditor, revisions, frequencyAnalyzer, viewMode, \
saveToZip saveToZip, dontShowDeleteWarning
allSettings = { allSettings = {
"viewSettings": viewSettings, "viewSettings": viewSettings,
@ -127,6 +128,7 @@ def save(filename=None, protocol=None):
"frequencyAnalyzer": frequencyAnalyzer, "frequencyAnalyzer": frequencyAnalyzer,
"viewMode": viewMode, "viewMode": viewMode,
"saveToZip": saveToZip, "saveToZip": saveToZip,
"dontShowDeleteWarning": dontShowDeleteWarning,
} }
#pp=pprint.PrettyPrinter(indent=4, compact=False) #pp=pprint.PrettyPrinter(indent=4, compact=False)
@ -294,3 +296,7 @@ def load(string, fromString=False, protocol=None):
if "saveToZip" in allSettings: if "saveToZip" in allSettings:
global saveToZip global saveToZip
saveToZip = allSettings["saveToZip"] saveToZip = allSettings["saveToZip"]
if "dontShowDeleteWarning" in allSettings:
global dontShowDeleteWarning
dontShowDeleteWarning = allSettings["dontShowDeleteWarning"]

View file

@ -8,6 +8,7 @@ from manuskript import settings
from manuskript.functions import AUC, mainWindow from manuskript.functions import AUC, mainWindow
from manuskript.ui.editors.editorWidget_ui import Ui_editorWidget_ui from manuskript.ui.editors.editorWidget_ui import Ui_editorWidget_ui
from manuskript.ui.views.textEditView import textEditView from manuskript.ui.views.textEditView import textEditView
from manuskript.ui.tools.splitDialog import splitDialog
class editorWidget(QWidget, Ui_editorWidget_ui): class editorWidget(QWidget, Ui_editorWidget_ui):
@ -330,7 +331,9 @@ class editorWidget(QWidget, Ui_editorWidget_ui):
############################################################################### ###############################################################################
def getCurrentItemView(self): def getCurrentItemView(self):
if self.folderView == "outline": if self.stack.currentIndex() == 0:
return self.txtRedacText
elif self.folderView == "outline":
return self.outlineView return self.outlineView
elif self.folderView == "cork": elif self.folderView == "cork":
return self.corkView return self.corkView
@ -351,9 +354,46 @@ class editorWidget(QWidget, Ui_editorWidget_ui):
if self.getCurrentItemView(): self.getCurrentItemView().moveUp() if self.getCurrentItemView(): self.getCurrentItemView().moveUp()
def moveDown(self): def moveDown(self):
if self.getCurrentItemView(): self.getCurrentItemView().moveDown() if self.getCurrentItemView(): self.getCurrentItemView().moveDown()
def documentsSplitDialog(self):
print("documentsSplitDialog::FIXME") def splitDialog(self):
def documentsSplitCursor(self): """
print("documentsSplitCursor::FIXME") Opens a dialog to split selected items.
"""
if self.getCurrentItemView() == self.txtRedacText:
# Text editor
if not self.currentIndex.isValid():
return
sel = self.txtRedacText.textCursor().selectedText()
# selectedText uses \u2029 instead of \n, no idea why.
sel = sel.replace("\u2029", "\n")
splitDialog(self, [self.currentIndex], mark=sel)
elif self.getCurrentItemView():
# One of the view
self.getCurrentItemView().splitDialog()
def splitCursor(self):
"""
Splits items at cursor position. If there is a selection, that selection
becomes the new item's title.
Call context: Only works when editing a file.
"""
if not self.currentIndex.isValid():
return
if self.getCurrentItemView() == self.txtRedacText:
c = self.txtRedacText.textCursor()
title = c.selectedText()
# selection can be backward
pos = min(c.selectionStart(), c.selectionEnd())
item = self.currentIndex.internalPointer()
item.splitAt(pos, len(title))
def documentsMerge(self): def documentsMerge(self):
print("documentsMerge::FIXME") print("documentsMerge::FIXME")

View file

@ -255,10 +255,8 @@ class mainEditor(QWidget, Ui_mainEditor):
def delete(self): self.currentEditor().delete() def delete(self): self.currentEditor().delete()
def moveUp(self): self.currentEditor().moveUp() def moveUp(self): self.currentEditor().moveUp()
def moveDown(self): self.currentEditor().moveDown() def moveDown(self): self.currentEditor().moveDown()
def documentsSplitDialog(self): def splitDialog(self): self.currentEditor().splitDialog()
print("documentsSplitDialog::FIXME") def splitCursor(self): self.currentEditor().splitCursor()
def documentsSplitCursor(self):
print("documentsSplitCursor::FIXME")
def documentsMerge(self): def documentsMerge(self):
print("documentsMerge::FIXME") print("documentsMerge::FIXME")

View file

@ -0,0 +1,55 @@
#!/usr/bin/env python
# --!-- coding: utf8 --!--
from PyQt5.QtWidgets import QInputDialog
class splitDialog(QInputDialog):
"""
Opens a dialog to split indexes.
"""
def __init__(self, parent, indexes, mark=None):
"""
@param parent: a QWidget, for the dialog.
@param indexes: a list of QModelIndex in the outlineModel
@param default: the default split mark
"""
QInputDialog.__init__(self, parent)
description = self.tr("""
<p>Split selected item(s) at the given mark.</p>
<p>If one of the selected item is a folder, it will be applied
recursively to <i>all</i> of it's children items.</p>
<p>The split mark can contain folling escret ape sequences:
<ul>
<li><b><code>\\n</code></b>: line break</li>
<li><b><code>\\t</code></b>: tab</li>
</ul>
</p>
<p><b>Mark:</b></p>
""")
if not mark:
mark = "\\n---\\n"
mark = mark.replace("\n", "\\n")
mark = mark.replace("\t", "\\t")
self.setLabelText(description)
self.setTextValue(mark)
self.setWindowTitle(self.tr("Split item(s)"))
r = self.exec()
mark = self.textValue()
if r and mark:
mark = mark.replace("\\n", "\n")
mark = mark.replace("\\t", "\t")
for idx in indexes:
if idx.isValid():
item = idx.internalPointer()
item.split(mark)

View file

@ -2,14 +2,16 @@
# --!-- coding: utf8 --!-- # --!-- coding: utf8 --!--
from PyQt5.QtCore import Qt, QSignalMapper, QSize from PyQt5.QtCore import Qt, QSignalMapper, QSize
from PyQt5.QtGui import QIcon, QCursor from PyQt5.QtGui import QIcon, QCursor
from PyQt5.QtWidgets import QAbstractItemView, qApp, QMenu, QAction from PyQt5.QtWidgets import QAbstractItemView, qApp, QMenu, QAction, \
from PyQt5.QtWidgets import QListWidget, QWidgetAction, QListWidgetItem, QLineEdit QListWidget, QWidgetAction, QListWidgetItem, \
QLineEdit, QInputDialog, QMessageBox, QCheckBox
from manuskript import settings from manuskript import settings
from manuskript.enums import Outline from manuskript.enums import Outline
from manuskript.functions import mainWindow from manuskript.functions import mainWindow
from manuskript.functions import toInt, customIcons from manuskript.functions import toInt, customIcons
from manuskript.models.outlineModel import outlineItem from manuskript.models.outlineModel import outlineItem
from manuskript.ui.tools.splitDialog import splitDialog
class outlineBasics(QAbstractItemView): class outlineBasics(QAbstractItemView):
@ -53,7 +55,7 @@ class outlineBasics(QAbstractItemView):
title = mouseIndex.internalPointer().title() title = mouseIndex.internalPointer().title()
else: else:
title = self.tr("Root") title = qApp.translate("outlineBasics", "Root")
if len(title) > 25: if len(title) > 25:
title = title[:25] + "" title = title[:25] + ""
@ -67,10 +69,10 @@ class outlineBasics(QAbstractItemView):
# Open item(s) in new tab # Open item(s) in new tab
if mouseIndex in sel and len(sel) > 1: if mouseIndex in sel and len(sel) > 1:
actionTitle = self.tr("Open {} items in new tabs").format(len(sel)) actionTitle = qApp.translate("outlineBasics", "Open {} items in new tabs").format(len(sel))
self._indexesToOpen = sel self._indexesToOpen = sel
else: else:
actionTitle = self.tr("Open {} in a new tab").format(title) actionTitle = qApp.translate("outlineBasics", "Open {} in a new tab").format(title)
self._indexesToOpen = [mouseIndex] self._indexesToOpen = [mouseIndex]
self.actNewTab = QAction(QIcon.fromTheme("go-right"), actionTitle, menu) self.actNewTab = QAction(QIcon.fromTheme("go-right"), actionTitle, menu)
@ -284,6 +286,27 @@ class outlineBasics(QAbstractItemView):
self.delete() self.delete()
def delete(self): def delete(self):
"""
Shows a warning, and then deletes currently selected indexes.
"""
if not settings.dontShowDeleteWarning:
msg = QMessageBox(QMessageBox.Warning,
qApp.translate("outlineBasics", "About to remove"),
qApp.translate("outlineBasics",
"<p><b>You're about to delete {} item(s).</b></p><p>Are you sure?</p>"
).format(len(self.getSelection())),
QMessageBox.Yes | QMessageBox.Cancel)
chk = QCheckBox("&Don't show this warning in the future.")
msg.setCheckBox(chk)
ret = msg.exec()
if ret == QMessageBox.Cancel:
return
if chk.isChecked():
settings.dontShowDeleteWarning = True
self.model().removeIndexes(self.getSelection()) self.model().removeIndexes(self.getSelection())
def duplicate(self): def duplicate(self):
@ -295,7 +318,7 @@ class outlineBasics(QAbstractItemView):
Move selected items up or down. Move selected items up or down.
""" """
# we store selected indexes # we store selected indexesret
currentID = self.model().ID(self.currentIndex()) currentID = self.model().ID(self.currentIndex())
selIDs = [self.model().ID(i) for i in self.selectedIndexes()] selIDs = [self.model().ID(i) for i in self.selectedIndexes()]
@ -316,7 +339,7 @@ class outlineBasics(QAbstractItemView):
sm.clear() sm.clear()
[sm.select(idx, sm.Select) for idx in selIdx] [sm.select(idx, sm.Select) for idx in selIdx]
sm.setCurrentIndex(self.model().getIndexByID(currentID), sm.Select) sm.setCurrentIndex(self.model().getIndexByID(currentID), sm.Select)
#self.setSelectionModel(sm) #self.setSmsgBoxelectionModel(sm)
# Unblock signals # Unblock signals
self.blockSignals(False) self.blockSignals(False)
@ -342,6 +365,19 @@ class outlineBasics(QAbstractItemView):
def moveUp(self): self.move(-1) def moveUp(self): self.move(-1)
def moveDown(self): self.move(+1) def moveDown(self): self.move(+1)
def splitDialog(self):
"""
Opens a dialog to split selected items.
Call context: if at least one index is selected. Folder or text.
"""
indexes = self.getSelection()
if len(indexes) == 0:
return
splitDialog(self, indexes)
def setPOV(self, POV): def setPOV(self, POV):
for i in self.getSelection(): for i in self.getSelection():
self.model().setData(i.sibling(i.row(), Outline.POV.value), str(POV)) self.model().setData(i.sibling(i.row(), Outline.POV.value), str(POV))

View file

@ -93,7 +93,7 @@ class textEditView(QTextEdit):
default_locale = QLocale.system().name() default_locale = QLocale.system().name()
if default_locale is None: if default_locale is None:
default_locale = enchant.list_dicts()[0][0] default_locale = enchant.list_dicts()[0][0]
return default_locale return default_locale
def setModel(self, model): def setModel(self, model):