Merge pull request #192 from camstevenson/import-export

Adds: Import OPML
This commit is contained in:
Olivier 2017-11-06 08:21:06 +01:00 committed by GitHub
commit 1f04bf6f54
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 183 additions and 0 deletions

View file

View file

@ -0,0 +1,136 @@
#!/usr/bin/env python
# --!-- coding: utf8 --!--
# Import/export outline cards in OPML format
from PyQt5.QtWidgets import QMessageBox
from manuskript.models.outlineModel import outlineItem
from manuskript.enums import Outline
from lxml import etree as ET
from manuskript.functions import mainWindow
def importOpml(opmlFilePath, idx):
ret = False
mw = mainWindow()
try:
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
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
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 += '...'
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)
children = underElement.findall('outline')
if children is not None and len(children) > 0:
for el in children:
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
"""
Since XML parsers are notorious for stripping out significant newlines,
save them in a form we can restore after the parse.
"""
def saveNewlines(inString):
inString = inString.replace("\r\n", "\n")
inString = inString.replace("\n", "{{lf}}")
return inString
"""
Restore any significant newlines
"""
def restoreNewLines(inString):
return inString.replace("{{lf}}", "\n")
"""
Determine whether or not a string only contains whitespace.
"""
def isWhitespaceOnly(inString):
str = restoreNewLines(inString)
str = ''.join(str.split())
return len(str) is 0

View file

@ -14,6 +14,7 @@ from manuskript.ui import style
from manuskript.ui.editors.editorWidget import editorWidget
from manuskript.ui.editors.fullScreenEditor import fullScreenEditor
from manuskript.ui.editors.mainEditor_ui import Ui_mainEditor
from manuskript.import_export import opml as opmlInputExport
locale.setlocale(locale.LC_ALL, '')
@ -83,6 +84,10 @@ class mainEditor(QWidget, Ui_mainEditor):
self.btnRedacFullscreen.clicked.connect(
self.showFullScreen, AUC)
self.btnImport.clicked.connect(
lambda v: self.importOPML()
)
# self.tab.setDocumentMode(False)
# Bug in Qt < 5.5: doesn't always load icons from custom theme.
@ -259,6 +264,7 @@ class mainEditor(QWidget, Ui_mainEditor):
self.btnRedacFolderText.setVisible(visible)
self.btnRedacFolderCork.setVisible(visible)
self.btnRedacFolderOutline.setVisible(visible)
self.btnImport.setVisible(visible)
self.sldCorkSizeFactor.setVisible(visible and self.btnRedacFolderCork.isChecked())
self.btnRedacFullscreen.setVisible(not visible)
@ -338,6 +344,20 @@ class mainEditor(QWidget, Ui_mainEditor):
if self.currentEditor():
self._fullScreen = fullScreenEditor(self.currentEditor().currentIndex)
def importOPML(self):
from PyQt5.QtWidgets import QFileDialog
options = QFileDialog.Options()
options |= QFileDialog.DontUseNativeDialog
fileName, _ = QFileDialog.getOpenFileName(self, "Import OPML", "",
"OPML Files (*.opml)", options=options)
if fileName:
if len(self.mw.treeRedacOutline.selectionModel().
selection().indexes()) == 0:
idx = QModelIndex()
else:
idx = self.mw.treeRedacOutline.currentIndex()
opmlInputExport.importOpml(fileName, idx)
###############################################################################
# DICT AND STUFF LIKE THAT
###############################################################################

View file

@ -55,6 +55,14 @@ class Ui_mainEditor(object):
self.btnRedacFolderOutline.setObjectName("btnRedacFolderOutline")
self.buttonGroup.addButton(self.btnRedacFolderOutline)
self.horizontalLayout_19.addWidget(self.btnRedacFolderOutline)
self.btnImport = QtWidgets.QPushButton(mainEditor)
self.btnImport.setText("")
icon = QtGui.QIcon.fromTheme("document-open")
self.btnImport.setIcon(icon)
self.btnImport.setFlat(True)
self.btnImport.setObjectName("btnImport")
self.buttonGroup.addButton(self.btnImport)
self.horizontalLayout_19.addWidget(self.btnImport)
self.sldCorkSizeFactor = QtWidgets.QSlider(mainEditor)
self.sldCorkSizeFactor.setMinimumSize(QtCore.QSize(100, 0))
self.sldCorkSizeFactor.setMaximumSize(QtCore.QSize(200, 16777215))
@ -109,6 +117,8 @@ class Ui_mainEditor(object):
self.btnRedacFolderCork.setText(_translate("mainEditor", "Index cards"))
self.btnRedacFolderOutline.setText(_translate("mainEditor", "Outline"))
self.btnRedacFullscreen.setShortcut(_translate("mainEditor", "F11"))
# TODO: Translation
self.btnImport.setToolTip(_translate("mainEditor", "Import items from an OPML file into the current folder"))
from manuskript.ui.editors.tabSplitter import tabSplitter
from manuskript.ui.editors.textFormat import textFormat

View file

@ -111,6 +111,23 @@
</attribute>
</widget>
</item>
<item>
<widget class="QPushButton" name="btnImport">
<property name="toolTip">
<!-- TODO: Translation -->
<string>Import items from an OPML file into the current folder</string>
</property>
<property name="text">
<string/>
</property>
<property name="icon">
<iconset theme="document-open"/>
</property>
<property name="flat">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QSlider" name="sldCorkSizeFactor">
<property name="minimumSize">