mirror of
https://github.com/olivierkes/manuskript.git
synced 2024-05-11 00:12:24 +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>>"
|
||||
icon = ""
|
||||
|
||||
@classmethod
|
||||
def startImport(cls, filePath):
|
||||
def startImport(self, filePath, settingsWidget):
|
||||
"""
|
||||
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
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#!/usr/bin/env python
|
||||
# --!-- coding: utf8 --!--
|
||||
|
||||
from PyQt5.QtWidgets import QMessageBox
|
||||
from PyQt5.QtWidgets import qApp, QMessageBox
|
||||
from manuskript.models.outlineModel import outlineItem
|
||||
from manuskript.enums import Outline
|
||||
from lxml import etree as ET
|
||||
|
@ -15,9 +15,56 @@ class opmlImporter(abstractImporter):
|
|||
fileFormat = "OPML Files (*.opml)"
|
||||
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):
|
||||
"""
|
||||
Import/export outline cards in OPML format.
|
||||
#FIXME: delete me when done with startImport
|
||||
"""
|
||||
ret = False
|
||||
mw = mainWindow()
|
||||
|
@ -26,7 +73,6 @@ class opmlImporter(abstractImporter):
|
|||
with open(opmlFilePath, 'r') as opmlFile:
|
||||
opmlContent = saveNewlines(opmlFile.read())
|
||||
except:
|
||||
# TODO: Translation
|
||||
QMessageBox.critical(mw, mw.tr("OPML Import"),
|
||||
mw.tr("File open failed."))
|
||||
return False
|
||||
|
@ -67,48 +113,30 @@ class opmlImporter(abstractImporter):
|
|||
|
||||
return ret
|
||||
|
||||
|
||||
def parseItems(underElement, parentItem):
|
||||
text = underElement.get('text')
|
||||
if text 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 += '...'
|
||||
@classmethod
|
||||
def parseItems(cls, underElement, parentItem=None):
|
||||
title = underElement.get('text')
|
||||
if title is not None:
|
||||
|
||||
card = outlineItem(parent=parentItem, title=title)
|
||||
|
||||
body = ""
|
||||
summary = ""
|
||||
note = underElement.get('_note')
|
||||
if note is not None and not isWhitespaceOnly(note):
|
||||
body = 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)
|
||||
if note is not None and not cls.isWhitespaceOnly(note):
|
||||
body = cls.restoreNewLines(note)
|
||||
|
||||
children = underElement.findall('outline')
|
||||
if children is not None and len(children) > 0:
|
||||
for el in children:
|
||||
parseItems(el, card)
|
||||
cls.parseItems(el, card)
|
||||
else:
|
||||
card.setData(Outline.type.value, 'md')
|
||||
card.setData(Outline.text.value, body)
|
||||
|
||||
# I assume I don't have to do the following
|
||||
# parentItem.appendChild(card)
|
||||
return card
|
||||
|
||||
return
|
||||
|
||||
def saveNewlines(inString):
|
||||
@classmethod
|
||||
def saveNewlines(cls, inString):
|
||||
"""
|
||||
Since XML parsers are notorious for stripping out significant newlines,
|
||||
save them in a form we can restore after the parse.
|
||||
|
@ -118,17 +146,19 @@ class opmlImporter(abstractImporter):
|
|||
|
||||
return inString
|
||||
|
||||
def restoreNewLines(inString):
|
||||
@classmethod
|
||||
def restoreNewLines(cls, inString):
|
||||
"""
|
||||
Restore any significant newlines
|
||||
"""
|
||||
return inString.replace("{{lf}}", "\n")
|
||||
|
||||
def isWhitespaceOnly(inString):
|
||||
@classmethod
|
||||
def isWhitespaceOnly(cls, inString):
|
||||
"""
|
||||
Determine whether or not a string only contains whitespace.
|
||||
"""
|
||||
str = restoreNewLines(inString)
|
||||
str = ''.join(str.split())
|
||||
s = cls.restoreNewLines(inString)
|
||||
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.setObjectName("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.toolBox.addItem(self.general, "")
|
||||
self.verticalLayout_2.addWidget(self.toolBox)
|
||||
|
@ -63,5 +66,6 @@ class Ui_generalSettings(object):
|
|||
generalSettings.setWindowTitle(_translate("generalSettings", "Form"))
|
||||
self.chkGeneralParent.setText(_translate("generalSettings", "Import under:"))
|
||||
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"))
|
||||
|
||||
|
|
|
@ -90,6 +90,13 @@ QToolBox::tab:selected, QToolBox::tab:hover{
|
|||
</property>
|
||||
</widget>
|
||||
</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>
|
||||
</item>
|
||||
</layout>
|
||||
|
|
|
@ -157,5 +157,30 @@ class importerDialog(QWidget, Ui_importer):
|
|||
############################################################################
|
||||
|
||||
def preview(self):
|
||||
# TODO
|
||||
|
||||
# We find the current selected format
|
||||
F = self.currentFormat()
|
||||
|
||||
# Temporary outlineModel
|
||||
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.setOrientation(QtCore.Qt.Horizontal)
|
||||
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.editor = mainEditor(self.splitter_2)
|
||||
self.editor.setObjectName("editor")
|
||||
|
@ -102,4 +104,3 @@ class Ui_importer(object):
|
|||
self.grpPreview.setTitle(_translate("importer", "Preview"))
|
||||
|
||||
from manuskript.ui.editors.mainEditor import mainEditor
|
||||
from manuskript.ui.views.treeView import treeView
|
||||
|
|
|
@ -178,7 +178,14 @@
|
|||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</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>
|
||||
</item>
|
||||
|
@ -189,11 +196,6 @@
|
|||
</layout>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
<class>treeView</class>
|
||||
<extends>QTreeView</extends>
|
||||
<header>manuskript.ui.views.treeView.h</header>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
<class>mainEditor</class>
|
||||
<extends>QWidget</extends>
|
||||
|
|
Loading…
Reference in a new issue