mirror of
https://github.com/olivierkes/manuskript.git
synced 2024-06-08 22:14:33 +12:00
Adds: split dialog, split at cursor
This commit is contained in:
parent
3b17c4e2b4
commit
a153606811
|
@ -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")
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
###############################################################################
|
###############################################################################
|
||||||
|
|
|
@ -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"]
|
||||||
|
|
|
@ -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")
|
||||||
|
|
|
@ -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")
|
||||||
|
|
||||||
|
|
55
manuskript/ui/tools/splitDialog.py
Normal file
55
manuskript/ui/tools/splitDialog.py
Normal 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)
|
|
@ -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))
|
||||||
|
|
|
@ -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):
|
||||||
|
|
Loading…
Reference in a new issue