Checkpoint: opml import can be previewed in tree view

This commit is contained in:
Olivier Keshavjee 2017-11-07 12:50:40 +01:00
parent d51233ebba
commit 316651245c
7 changed files with 117 additions and 47 deletions

View file

@ -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

View file

@ -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

View file

@ -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"))

View file

@ -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 (&gt; 32 chars)</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>

View file

@ -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()

View file

@ -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

View file

@ -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>