2017-11-07 23:25:19 +13:00
|
|
|
#!/usr/bin/env python
|
|
|
|
# --!-- coding: utf8 --!--
|
|
|
|
|
2017-11-08 00:50:40 +13:00
|
|
|
from PyQt5.QtWidgets import qApp, QMessageBox
|
2017-11-07 23:25:19 +13:00
|
|
|
from manuskript.models.outlineModel import outlineItem
|
|
|
|
from manuskript.enums import Outline
|
|
|
|
from lxml import etree as ET
|
|
|
|
from manuskript.functions import mainWindow
|
|
|
|
from manuskript.importer.abstractImporter import abstractImporter
|
|
|
|
|
|
|
|
class opmlImporter(abstractImporter):
|
|
|
|
|
|
|
|
name = "OPML"
|
|
|
|
description = ""
|
|
|
|
fileFormat = "OPML Files (*.opml)"
|
|
|
|
icon = "text-x-opml+xml"
|
|
|
|
|
2017-11-08 00:50:40 +13:00
|
|
|
@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
|
|
|
|
|
2017-11-07 23:25:19 +13:00
|
|
|
def importOpml(opmlFilePath, idx):
|
|
|
|
"""
|
|
|
|
Import/export outline cards in OPML format.
|
2017-11-08 00:50:40 +13:00
|
|
|
#FIXME: delete me when done with startImport
|
2017-11-07 23:25:19 +13:00
|
|
|
"""
|
|
|
|
ret = False
|
|
|
|
mw = mainWindow()
|
|
|
|
|
|
|
|
try:
|
|
|
|
with open(opmlFilePath, 'r') as opmlFile:
|
|
|
|
opmlContent = saveNewlines(opmlFile.read())
|
|
|
|
except:
|
|
|
|
QMessageBox.critical(mw, mw.tr("OPML Import"),
|
|
|
|
mw.tr("File open failed."))
|
|
|
|
return False
|
|
|
|
|
|
|
|
mdl = mw.mdlOutline
|
|
|
|
|
|
|
|
if idx.internalPointer() is not None:
|
|
|
|
parentItem = idx.internalPointer()
|
|
|
|
else:
|
|
|
|
parentItem = mdl.rootItem
|
|
|
|
|
|
|
|
try:
|
|
|
|
parsed = ET.fromstring(bytes(opmlContent, 'utf-8'))
|
|
|
|
|
|
|
|
opmlNode = parsed
|
|
|
|
bodyNode = opmlNode.find("body")
|
|
|
|
|
|
|
|
if bodyNode is not None:
|
|
|
|
outlineEls = bodyNode.findall("outline")
|
|
|
|
|
|
|
|
if outlineEls is not None:
|
|
|
|
for element in outlineEls:
|
|
|
|
parseItems(element, parentItem)
|
|
|
|
|
|
|
|
mdl.layoutChanged.emit()
|
|
|
|
mw.treeRedacOutline.viewport().update()
|
|
|
|
ret = True
|
|
|
|
except:
|
|
|
|
pass
|
|
|
|
|
|
|
|
# TODO: Translation
|
|
|
|
if ret:
|
|
|
|
QMessageBox.information(mw, mw.tr("OPML Import"),
|
|
|
|
mw.tr("Import Complete."))
|
|
|
|
else:
|
|
|
|
QMessageBox.critical(mw, mw.tr("OPML Import"),
|
|
|
|
mw.tr("This does not appear to be a valid OPML file."))
|
|
|
|
|
|
|
|
return ret
|
|
|
|
|
2017-11-08 00:50:40 +13:00
|
|
|
@classmethod
|
|
|
|
def parseItems(cls, underElement, parentItem=None):
|
|
|
|
title = underElement.get('text')
|
|
|
|
if title is not None:
|
2017-11-07 23:25:19 +13:00
|
|
|
|
|
|
|
card = outlineItem(parent=parentItem, title=title)
|
|
|
|
|
|
|
|
body = ""
|
|
|
|
note = underElement.get('_note')
|
2017-11-08 00:50:40 +13:00
|
|
|
if note is not None and not cls.isWhitespaceOnly(note):
|
|
|
|
body = cls.restoreNewLines(note)
|
2017-11-07 23:25:19 +13:00
|
|
|
|
|
|
|
children = underElement.findall('outline')
|
|
|
|
if children is not None and len(children) > 0:
|
|
|
|
for el in children:
|
2017-11-08 00:50:40 +13:00
|
|
|
cls.parseItems(el, card)
|
2017-11-07 23:25:19 +13:00
|
|
|
else:
|
|
|
|
card.setData(Outline.type.value, 'md')
|
|
|
|
card.setData(Outline.text.value, body)
|
|
|
|
|
2017-11-08 00:50:40 +13:00
|
|
|
return card
|
2017-11-07 23:25:19 +13:00
|
|
|
|
2017-11-08 00:50:40 +13:00
|
|
|
@classmethod
|
|
|
|
def saveNewlines(cls, inString):
|
2017-11-07 23:25:19 +13:00
|
|
|
"""
|
|
|
|
Since XML parsers are notorious for stripping out significant newlines,
|
|
|
|
save them in a form we can restore after the parse.
|
|
|
|
"""
|
|
|
|
inString = inString.replace("\r\n", "\n")
|
|
|
|
inString = inString.replace("\n", "{{lf}}")
|
|
|
|
|
|
|
|
return inString
|
|
|
|
|
2017-11-08 00:50:40 +13:00
|
|
|
@classmethod
|
|
|
|
def restoreNewLines(cls, inString):
|
2017-11-07 23:25:19 +13:00
|
|
|
"""
|
|
|
|
Restore any significant newlines
|
|
|
|
"""
|
|
|
|
return inString.replace("{{lf}}", "\n")
|
|
|
|
|
2017-11-08 00:50:40 +13:00
|
|
|
@classmethod
|
|
|
|
def isWhitespaceOnly(cls, inString):
|
2017-11-07 23:25:19 +13:00
|
|
|
"""
|
|
|
|
Determine whether or not a string only contains whitespace.
|
|
|
|
"""
|
2017-11-08 00:50:40 +13:00
|
|
|
s = cls.restoreNewLines(inString)
|
|
|
|
s = ''.join(s.split())
|
2017-11-07 23:25:19 +13:00
|
|
|
|
2017-11-08 00:50:40 +13:00
|
|
|
return len(s) is 0
|