mirror of
https://github.com/olivierkes/manuskript.git
synced 2024-05-21 05:12:27 +12:00
Checkpoint: opml import can be previewed in tree view
This commit is contained in:
parent
d51233ebba
commit
316651245c
|
@ -22,10 +22,11 @@ class abstractImporter:
|
||||||
# For folder, use "<<folder>>"
|
# For folder, use "<<folder>>"
|
||||||
icon = ""
|
icon = ""
|
||||||
|
|
||||||
@classmethod
|
def startImport(self, filePath, settingsWidget):
|
||||||
def startImport(cls, filePath):
|
|
||||||
"""
|
"""
|
||||||
Takes a str path to the file/folder to import, and return `outlineItem`s.
|
Takes a str path to the file/folder to import, and the settingsWidget
|
||||||
|
returnend by `self.settingsWidget()` containing the user set settings,
|
||||||
|
and return `outlineItem`s.
|
||||||
"""
|
"""
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
#!/usr/bin/env python
|
#!/usr/bin/env python
|
||||||
# --!-- coding: utf8 --!--
|
# --!-- coding: utf8 --!--
|
||||||
|
|
||||||
from PyQt5.QtWidgets import QMessageBox
|
from PyQt5.QtWidgets import qApp, QMessageBox
|
||||||
from manuskript.models.outlineModel import outlineItem
|
from manuskript.models.outlineModel import outlineItem
|
||||||
from manuskript.enums import Outline
|
from manuskript.enums import Outline
|
||||||
from lxml import etree as ET
|
from lxml import etree as ET
|
||||||
|
@ -15,9 +15,56 @@ class opmlImporter(abstractImporter):
|
||||||
fileFormat = "OPML Files (*.opml)"
|
fileFormat = "OPML Files (*.opml)"
|
||||||
icon = "text-x-opml+xml"
|
icon = "text-x-opml+xml"
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def startImport(cls, filePath, parentItem, settingsWidget):
|
||||||
|
"""
|
||||||
|
Import/export outline cards in OPML format.
|
||||||
|
"""
|
||||||
|
ret = False
|
||||||
|
|
||||||
|
try:
|
||||||
|
with open(filePath, 'r') as opmlFile:
|
||||||
|
opmlContent = cls.saveNewlines(opmlFile.read())
|
||||||
|
except:
|
||||||
|
QMessageBox.critical(settingsWidget,
|
||||||
|
qApp.translate("Import", "OPML Import"),
|
||||||
|
qApp.translate("Import", "File open failed."))
|
||||||
|
return None
|
||||||
|
|
||||||
|
parsed = ET.fromstring(bytes(opmlContent, 'utf-8'))
|
||||||
|
|
||||||
|
opmlNode = parsed
|
||||||
|
bodyNode = opmlNode.find("body")
|
||||||
|
items = []
|
||||||
|
|
||||||
|
if bodyNode is not None:
|
||||||
|
outlineEls = bodyNode.findall("outline")
|
||||||
|
|
||||||
|
if outlineEls is not None:
|
||||||
|
for element in outlineEls:
|
||||||
|
items.append(cls.parseItems(element, parentItem))
|
||||||
|
ret = True
|
||||||
|
|
||||||
|
if ret:
|
||||||
|
#QMessageBox.information(
|
||||||
|
#settingsWidget,
|
||||||
|
#qApp.translate("Import", "OPML Import"),
|
||||||
|
#qApp.translate("Import", "Import Complete."))
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
QMessageBox.critical(
|
||||||
|
settingsWidget,
|
||||||
|
qApp.translate("Import", "OPML Import"),
|
||||||
|
qApp.translate("Import", "This does not appear to be a valid OPML file."))
|
||||||
|
|
||||||
|
return None
|
||||||
|
|
||||||
|
return items
|
||||||
|
|
||||||
def importOpml(opmlFilePath, idx):
|
def importOpml(opmlFilePath, idx):
|
||||||
"""
|
"""
|
||||||
Import/export outline cards in OPML format.
|
Import/export outline cards in OPML format.
|
||||||
|
#FIXME: delete me when done with startImport
|
||||||
"""
|
"""
|
||||||
ret = False
|
ret = False
|
||||||
mw = mainWindow()
|
mw = mainWindow()
|
||||||
|
@ -26,7 +73,6 @@ class opmlImporter(abstractImporter):
|
||||||
with open(opmlFilePath, 'r') as opmlFile:
|
with open(opmlFilePath, 'r') as opmlFile:
|
||||||
opmlContent = saveNewlines(opmlFile.read())
|
opmlContent = saveNewlines(opmlFile.read())
|
||||||
except:
|
except:
|
||||||
# TODO: Translation
|
|
||||||
QMessageBox.critical(mw, mw.tr("OPML Import"),
|
QMessageBox.critical(mw, mw.tr("OPML Import"),
|
||||||
mw.tr("File open failed."))
|
mw.tr("File open failed."))
|
||||||
return False
|
return False
|
||||||
|
@ -67,48 +113,30 @@ class opmlImporter(abstractImporter):
|
||||||
|
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
|
@classmethod
|
||||||
def parseItems(underElement, parentItem):
|
def parseItems(cls, underElement, parentItem=None):
|
||||||
text = underElement.get('text')
|
title = underElement.get('text')
|
||||||
if text is not None:
|
if title is not None:
|
||||||
|
|
||||||
# In the case where the title is exceptionally long, trim it so it isn't
|
|
||||||
# distracting in the tab label
|
|
||||||
title = text[0:32]
|
|
||||||
if len(title) < len(text):
|
|
||||||
title += '...'
|
|
||||||
|
|
||||||
card = outlineItem(parent=parentItem, title=title)
|
card = outlineItem(parent=parentItem, title=title)
|
||||||
|
|
||||||
body = ""
|
body = ""
|
||||||
summary = ""
|
|
||||||
note = underElement.get('_note')
|
note = underElement.get('_note')
|
||||||
if note is not None and not isWhitespaceOnly(note):
|
if note is not None and not cls.isWhitespaceOnly(note):
|
||||||
body = restoreNewLines(note)
|
body = cls.restoreNewLines(note)
|
||||||
summary = body[0:128]
|
|
||||||
else:
|
|
||||||
|
|
||||||
# There's no note (body), but there is a title. Fill the
|
|
||||||
# body with the title to support cards that consist only
|
|
||||||
# of a title.
|
|
||||||
body = text
|
|
||||||
|
|
||||||
card.setData(Outline.summaryFull.value, summary)
|
|
||||||
|
|
||||||
children = underElement.findall('outline')
|
children = underElement.findall('outline')
|
||||||
if children is not None and len(children) > 0:
|
if children is not None and len(children) > 0:
|
||||||
for el in children:
|
for el in children:
|
||||||
parseItems(el, card)
|
cls.parseItems(el, card)
|
||||||
else:
|
else:
|
||||||
card.setData(Outline.type.value, 'md')
|
card.setData(Outline.type.value, 'md')
|
||||||
card.setData(Outline.text.value, body)
|
card.setData(Outline.text.value, body)
|
||||||
|
|
||||||
# I assume I don't have to do the following
|
return card
|
||||||
# parentItem.appendChild(card)
|
|
||||||
|
|
||||||
return
|
@classmethod
|
||||||
|
def saveNewlines(cls, inString):
|
||||||
def saveNewlines(inString):
|
|
||||||
"""
|
"""
|
||||||
Since XML parsers are notorious for stripping out significant newlines,
|
Since XML parsers are notorious for stripping out significant newlines,
|
||||||
save them in a form we can restore after the parse.
|
save them in a form we can restore after the parse.
|
||||||
|
@ -118,17 +146,19 @@ class opmlImporter(abstractImporter):
|
||||||
|
|
||||||
return inString
|
return inString
|
||||||
|
|
||||||
def restoreNewLines(inString):
|
@classmethod
|
||||||
|
def restoreNewLines(cls, inString):
|
||||||
"""
|
"""
|
||||||
Restore any significant newlines
|
Restore any significant newlines
|
||||||
"""
|
"""
|
||||||
return inString.replace("{{lf}}", "\n")
|
return inString.replace("{{lf}}", "\n")
|
||||||
|
|
||||||
def isWhitespaceOnly(inString):
|
@classmethod
|
||||||
|
def isWhitespaceOnly(cls, inString):
|
||||||
"""
|
"""
|
||||||
Determine whether or not a string only contains whitespace.
|
Determine whether or not a string only contains whitespace.
|
||||||
"""
|
"""
|
||||||
str = restoreNewLines(inString)
|
s = cls.restoreNewLines(inString)
|
||||||
str = ''.join(str.split())
|
s = ''.join(s.split())
|
||||||
|
|
||||||
return len(str) is 0
|
return len(s) is 0
|
||||||
|
|
|
@ -49,6 +49,9 @@ class Ui_generalSettings(object):
|
||||||
self.treeGeneralParent.setHeaderHidden(True)
|
self.treeGeneralParent.setHeaderHidden(True)
|
||||||
self.treeGeneralParent.setObjectName("treeGeneralParent")
|
self.treeGeneralParent.setObjectName("treeGeneralParent")
|
||||||
self.formLayout_4.setWidget(0, QtWidgets.QFormLayout.FieldRole, self.treeGeneralParent)
|
self.formLayout_4.setWidget(0, QtWidgets.QFormLayout.FieldRole, self.treeGeneralParent)
|
||||||
|
self.chkGeneralTrimTitles = QtWidgets.QCheckBox(self.general)
|
||||||
|
self.chkGeneralTrimTitles.setObjectName("chkGeneralTrimTitles")
|
||||||
|
self.formLayout_4.setWidget(2, QtWidgets.QFormLayout.SpanningRole, self.chkGeneralTrimTitles)
|
||||||
self.verticalLayout_5.addLayout(self.formLayout_4)
|
self.verticalLayout_5.addLayout(self.formLayout_4)
|
||||||
self.toolBox.addItem(self.general, "")
|
self.toolBox.addItem(self.general, "")
|
||||||
self.verticalLayout_2.addWidget(self.toolBox)
|
self.verticalLayout_2.addWidget(self.toolBox)
|
||||||
|
@ -63,5 +66,6 @@ class Ui_generalSettings(object):
|
||||||
generalSettings.setWindowTitle(_translate("generalSettings", "Form"))
|
generalSettings.setWindowTitle(_translate("generalSettings", "Form"))
|
||||||
self.chkGeneralParent.setText(_translate("generalSettings", "Import under:"))
|
self.chkGeneralParent.setText(_translate("generalSettings", "Import under:"))
|
||||||
self.chkGeneralSplitScenes.setText(_translate("generalSettings", "Split scenes at:"))
|
self.chkGeneralSplitScenes.setText(_translate("generalSettings", "Split scenes at:"))
|
||||||
|
self.chkGeneralTrimTitles.setText(_translate("generalSettings", "Trim long titles (> 32 chars)"))
|
||||||
self.toolBox.setItemText(self.toolBox.indexOf(self.general), _translate("generalSettings", "General"))
|
self.toolBox.setItemText(self.toolBox.indexOf(self.general), _translate("generalSettings", "General"))
|
||||||
|
|
||||||
|
|
|
@ -90,6 +90,13 @@ QToolBox::tab:selected, QToolBox::tab:hover{
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
<item row="2" column="0" colspan="2">
|
||||||
|
<widget class="QCheckBox" name="chkGeneralTrimTitles">
|
||||||
|
<property name="text">
|
||||||
|
<string>Trim long titles (> 32 chars)</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</item>
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
|
|
|
@ -157,5 +157,30 @@ class importerDialog(QWidget, Ui_importer):
|
||||||
############################################################################
|
############################################################################
|
||||||
|
|
||||||
def preview(self):
|
def preview(self):
|
||||||
# TODO
|
|
||||||
|
# We find the current selected format
|
||||||
|
F = self.currentFormat()
|
||||||
|
|
||||||
|
# Temporary outlineModel
|
||||||
previewModel = outlineModel(self)
|
previewModel = outlineModel(self)
|
||||||
|
|
||||||
|
# Calling the importer in a temporary model
|
||||||
|
items = F.startImport(self.fileName,
|
||||||
|
previewModel.rootItem,
|
||||||
|
self.settingsWidget)
|
||||||
|
|
||||||
|
# Do transformations
|
||||||
|
# TODO
|
||||||
|
|
||||||
|
if items:
|
||||||
|
self.tree.setModel(previewModel)
|
||||||
|
for i in range(1, previewModel.columnCount()):
|
||||||
|
self.tree.hideColumn(i)
|
||||||
|
|
||||||
|
def startImport(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
# Note: dont forget to emit: mdl.layoutChanged.emit()
|
||||||
|
# Maybe: mw.treeRedacOutline.viewport().update()
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -80,7 +80,9 @@ class Ui_importer(object):
|
||||||
self.splitter_2 = QtWidgets.QSplitter(self.grpPreview)
|
self.splitter_2 = QtWidgets.QSplitter(self.grpPreview)
|
||||||
self.splitter_2.setOrientation(QtCore.Qt.Horizontal)
|
self.splitter_2.setOrientation(QtCore.Qt.Horizontal)
|
||||||
self.splitter_2.setObjectName("splitter_2")
|
self.splitter_2.setObjectName("splitter_2")
|
||||||
self.tree = treeView(self.splitter_2)
|
self.tree = QtWidgets.QTreeView(self.splitter_2)
|
||||||
|
self.tree.setEditTriggers(QtWidgets.QAbstractItemView.NoEditTriggers)
|
||||||
|
self.tree.setHeaderHidden(True)
|
||||||
self.tree.setObjectName("tree")
|
self.tree.setObjectName("tree")
|
||||||
self.editor = mainEditor(self.splitter_2)
|
self.editor = mainEditor(self.splitter_2)
|
||||||
self.editor.setObjectName("editor")
|
self.editor.setObjectName("editor")
|
||||||
|
@ -102,4 +104,3 @@ class Ui_importer(object):
|
||||||
self.grpPreview.setTitle(_translate("importer", "Preview"))
|
self.grpPreview.setTitle(_translate("importer", "Preview"))
|
||||||
|
|
||||||
from manuskript.ui.editors.mainEditor import mainEditor
|
from manuskript.ui.editors.mainEditor import mainEditor
|
||||||
from manuskript.ui.views.treeView import treeView
|
|
||||||
|
|
|
@ -178,7 +178,14 @@
|
||||||
<property name="orientation">
|
<property name="orientation">
|
||||||
<enum>Qt::Horizontal</enum>
|
<enum>Qt::Horizontal</enum>
|
||||||
</property>
|
</property>
|
||||||
<widget class="treeView" name="tree"/>
|
<widget class="QTreeView" name="tree">
|
||||||
|
<property name="editTriggers">
|
||||||
|
<set>QAbstractItemView::NoEditTriggers</set>
|
||||||
|
</property>
|
||||||
|
<property name="headerHidden">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
<widget class="mainEditor" name="editor" native="true"/>
|
<widget class="mainEditor" name="editor" native="true"/>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
@ -189,11 +196,6 @@
|
||||||
</layout>
|
</layout>
|
||||||
</widget>
|
</widget>
|
||||||
<customwidgets>
|
<customwidgets>
|
||||||
<customwidget>
|
|
||||||
<class>treeView</class>
|
|
||||||
<extends>QTreeView</extends>
|
|
||||||
<header>manuskript.ui.views.treeView.h</header>
|
|
||||||
</customwidget>
|
|
||||||
<customwidget>
|
<customwidget>
|
||||||
<class>mainEditor</class>
|
<class>mainEditor</class>
|
||||||
<extends>QWidget</extends>
|
<extends>QWidget</extends>
|
||||||
|
|
Loading…
Reference in a new issue