From 982a96021b9128d5a5b1fff1a1cc58f2ed842f51 Mon Sep 17 00:00:00 2001 From: Cam Stevenson Date: Sun, 15 Oct 2017 17:25:09 -0400 Subject: [PATCH 1/4] Checkpoint: OPML import --- manuskript/import_export/__init__.py | 0 manuskript/import_export/opml.py | 44 ++++++++++++++++++++++++++++ manuskript/mainWindow.py | 12 ++++++-- manuskript/ui/mainWindow.py | 5 ++++ 4 files changed, 58 insertions(+), 3 deletions(-) create mode 100644 manuskript/import_export/__init__.py create mode 100644 manuskript/import_export/opml.py diff --git a/manuskript/import_export/__init__.py b/manuskript/import_export/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/manuskript/import_export/opml.py b/manuskript/import_export/opml.py new file mode 100644 index 00000000..77e6d311 --- /dev/null +++ b/manuskript/import_export/opml.py @@ -0,0 +1,44 @@ +#!/usr/bin/env python +# --!-- coding: utf8 --!-- + +# Import/export outline cards in OPML format + +from manuskript.models.outlineModel import outlineItem +from manuskript.enums import Outline +import xmltodict +from manuskript.functions import mainWindow +import xml.etree.ElementTree as ET + + +def handleCard(_, card): + print(card['title']) + + +def exportOpml(): + return True + + +def importOpml(opmlFilePath): + with open(opmlFilePath, 'r') as opmlFile: + opmlContent = opmlFile.read() + + mw = mainWindow() + mdl = mw.mdlOutline + + dict = xmltodict.parse(opmlContent, item_callback=handleCard) + + opmlNode = dict['opml'] + bodyNode = opmlNode['body'] + + outline = bodyNode['outline'] + + for element in outline: + if '@text' in element: + card = outlineItem(parent=mdl.rootItem) + card.title = element['@text'] + card.ID = card.title + card.path = '' + if '@_note' in element: + card.setData(Outline.text.value, element['@_note']) + + return True diff --git a/manuskript/mainWindow.py b/manuskript/mainWindow.py index 3ab3b18c..67d178b7 100644 --- a/manuskript/mainWindow.py +++ b/manuskript/mainWindow.py @@ -26,6 +26,7 @@ from manuskript.ui.mainWindow import Ui_MainWindow from manuskript.ui.tools.frequencyAnalyzer import frequencyAnalyzer from manuskript.ui.views.outlineDelegates import outlineCharacterDelegate from manuskript.ui.views.plotDelegate import plotDelegate +from manuskript.import_export import opml as opmlInputExport # Spellcheck support from manuskript.ui.views.textEditView import textEditView @@ -94,13 +95,14 @@ class MainWindow(QMainWindow, Ui_MainWindow): self.cmbSummary.currentIndexChanged.emit(0) # Main Menu - for i in [self.actSave, self.actSaveAs, self.actCloseProject, + for i in [self.actSave, self.actSaveAs, self.actImport, self.actCloseProject, self.menuEdit, self.menuView, self.menuTools, self.menuHelp]: i.setEnabled(False) self.actOpen.triggered.connect(self.welcome.openFile) self.actSave.triggered.connect(self.saveDatas) self.actSaveAs.triggered.connect(self.welcome.saveAsFile) + self.actImport.triggered.connect(self.importOutline) self.actCompile.triggered.connect(self.doCompile) self.actLabels.triggered.connect(self.settingsLabel) self.actStatus.triggered.connect(self.settingsStatus) @@ -386,7 +388,7 @@ class MainWindow(QMainWindow, Ui_MainWindow): # UI for i in [self.actOpen, self.menuRecents]: i.setEnabled(False) - for i in [self.actSave, self.actSaveAs, self.actCloseProject, + for i in [self.actSave, self.actSaveAs, self.actImport, self.actCloseProject, self.menuEdit, self.menuView, self.menuTools, self.menuHelp]: i.setEnabled(True) @@ -429,7 +431,7 @@ class MainWindow(QMainWindow, Ui_MainWindow): # UI for i in [self.actOpen, self.menuRecents]: i.setEnabled(True) - for i in [self.actSave, self.actSaveAs, self.actCloseProject, + for i in [self.actSave, self.actSaveAs, self.actImport, self.actCloseProject, self.menuEdit, self.menuView, self.menuTools, self.menuHelp]: i.setEnabled(False) @@ -548,6 +550,10 @@ class MainWindow(QMainWindow, Ui_MainWindow): self.statusBar().showMessage( self.tr("Project {} loaded with some errors.").format(project), 5000) + def importOutline(self, project): + opmlInputExport.importOpml('/home/cstevenson/End Plan 2.opml') + return True + ############################################################################### # MAIN CONNECTIONS ############################################################################### diff --git a/manuskript/ui/mainWindow.py b/manuskript/ui/mainWindow.py index 9c13e469..8b4ef492 100644 --- a/manuskript/ui/mainWindow.py +++ b/manuskript/ui/mainWindow.py @@ -1123,6 +1123,9 @@ class Ui_MainWindow(object): self.actSaveAs.setObjectName("actSaveAs") self.actQuit = QtWidgets.QAction(MainWindow) icon = QtGui.QIcon.fromTheme("application-exit") + self.actImport = QtWidgets.QAction(MainWindow) + self.actImport.setIcon(icon) + self.actImport.setObjectName("actImport") self.actQuit.setIcon(icon) self.actQuit.setObjectName("actQuit") self.actShowHelp = QtWidgets.QAction(MainWindow) @@ -1175,6 +1178,7 @@ class Ui_MainWindow(object): self.menuFile.addAction(self.menuRecents.menuAction()) self.menuFile.addAction(self.actSave) self.menuFile.addAction(self.actSaveAs) + self.menuFile.addAction(self.actImport) self.menuFile.addAction(self.actCloseProject) self.menuFile.addSeparator() self.menuFile.addAction(self.actCompile) @@ -1316,6 +1320,7 @@ class Ui_MainWindow(object): self.actSave.setShortcut(_translate("MainWindow", "Ctrl+S")) self.actSaveAs.setText(_translate("MainWindow", "Sa&ve as...")) self.actSaveAs.setShortcut(_translate("MainWindow", "Ctrl+Shift+S")) + self.actImport.setText("Import") self.actQuit.setText(_translate("MainWindow", "&Quit")) self.actQuit.setShortcut(_translate("MainWindow", "Ctrl+Q")) self.actShowHelp.setText(_translate("MainWindow", "&Show help texts")) From bdc6a096f2c1267b9703f0397aaee2d1e792eb40 Mon Sep 17 00:00:00 2001 From: Cam Stevenson Date: Sat, 21 Oct 2017 16:29:17 -0400 Subject: [PATCH 2/4] Checkpoint: OPML import --- manuskript/import_export/opml.py | 49 +++++++++++++++++++++++++------- 1 file changed, 39 insertions(+), 10 deletions(-) diff --git a/manuskript/import_export/opml.py b/manuskript/import_export/opml.py index 77e6d311..fe90fc6e 100644 --- a/manuskript/import_export/opml.py +++ b/manuskript/import_export/opml.py @@ -7,7 +7,6 @@ from manuskript.models.outlineModel import outlineItem from manuskript.enums import Outline import xmltodict from manuskript.functions import mainWindow -import xml.etree.ElementTree as ET def handleCard(_, card): @@ -20,12 +19,12 @@ def exportOpml(): def importOpml(opmlFilePath): with open(opmlFilePath, 'r') as opmlFile: - opmlContent = opmlFile.read() + opmlContent = saveNewlines(opmlFile.read()) mw = mainWindow() mdl = mw.mdlOutline - dict = xmltodict.parse(opmlContent, item_callback=handleCard) + dict = xmltodict.parse(opmlContent, strip_whitespace=False) opmlNode = dict['opml'] bodyNode = opmlNode['body'] @@ -33,12 +32,42 @@ def importOpml(opmlFilePath): outline = bodyNode['outline'] for element in outline: - if '@text' in element: - card = outlineItem(parent=mdl.rootItem) - card.title = element['@text'] - card.ID = card.title - card.path = '' - if '@_note' in element: - card.setData(Outline.text.value, element['@_note']) + parseItems(underElement=element, parentItem=mdl.rootItem) return True + +def parseItems(underElement, parentItem): + if '@text' in underElement: + card = outlineItem(parent=parentItem, title=underElement['@text']) + + text = "" + summary = "" + if '@_note' in underElement: + text = restoreNewLines(underElement['@_note']) + summary = text[0:128] + + card.setData(Outline.summaryFull.value, summary) + + if 'outline' in underElement: + elements = underElement['outline'] + + for el in elements: + parseItems(el, card) + else: + card.setData(Outline.type.value, 'md') + card.setData(Outline.text.value, text) + + # I assume I don't have to do the following + # parentItem.appendChild(card) + + return + +def saveNewlines(inString): + inString = inString.replace("\r\n", "\n") + inString = inString.replace("\n", "{{lf}}") + + return inString + +def restoreNewLines(inString): + return inString.replace("{{lf}}", "\n") + From 44db1a59893d8a0f5baa7b3682fa9618ce4ed795 Mon Sep 17 00:00:00 2001 From: Cam Stevenson Date: Sun, 22 Oct 2017 10:21:39 -0400 Subject: [PATCH 3/4] Checkpoint: functional OPML import --- manuskript/import_export/opml.py | 14 +++++++++----- manuskript/mainWindow.py | 6 +++--- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/manuskript/import_export/opml.py b/manuskript/import_export/opml.py index fe90fc6e..e178ddc3 100644 --- a/manuskript/import_export/opml.py +++ b/manuskript/import_export/opml.py @@ -7,10 +7,7 @@ from manuskript.models.outlineModel import outlineItem from manuskript.enums import Outline import xmltodict from manuskript.functions import mainWindow - - -def handleCard(_, card): - print(card['title']) +from PyQt5.QtCore import QModelIndex def exportOpml(): @@ -32,10 +29,15 @@ def importOpml(opmlFilePath): outline = bodyNode['outline'] for element in outline: - parseItems(underElement=element, parentItem=mdl.rootItem) + parseItems(element, mdl.rootItem) + + mdl.layoutChanged.emit() + + mw.treeRedacOutline.viewport().update() return True + def parseItems(underElement, parentItem): if '@text' in underElement: card = outlineItem(parent=parentItem, title=underElement['@text']) @@ -62,12 +64,14 @@ def parseItems(underElement, parentItem): return + def saveNewlines(inString): inString = inString.replace("\r\n", "\n") inString = inString.replace("\n", "{{lf}}") return inString + def restoreNewLines(inString): return inString.replace("{{lf}}", "\n") diff --git a/manuskript/mainWindow.py b/manuskript/mainWindow.py index 9401c614..92850ff8 100644 --- a/manuskript/mainWindow.py +++ b/manuskript/mainWindow.py @@ -98,7 +98,7 @@ class MainWindow(QMainWindow, Ui_MainWindow): # Main Menu for i in [self.actSave, self.actSaveAs, self.actCloseProject, self.menuEdit, self.menuView, self.menuTools, self.menuHelp, - self.actCompile, self.actSettings]: + self.actCompile, self.actImport, self.actSettings]: i.setEnabled(False) self.actOpen.triggered.connect(self.welcome.openFile) @@ -447,7 +447,7 @@ class MainWindow(QMainWindow, Ui_MainWindow): i.setEnabled(False) for i in [self.actSave, self.actSaveAs, self.actCloseProject, self.menuEdit, self.menuView, self.menuTools, self.menuHelp, - self.actCompile, self.actSettings]: + self.actCompile, self.actImport, self.actSettings]: i.setEnabled(True) # Add project name to Window's name @@ -491,7 +491,7 @@ class MainWindow(QMainWindow, Ui_MainWindow): i.setEnabled(True) for i in [self.actSave, self.actSaveAs, self.actCloseProject, self.menuEdit, self.menuView, self.menuTools, self.menuHelp, - self.actCompile, self.actSettings]: + self.actCompile, self.actImport, self.actSettings]: i.setEnabled(False) # Set Window's name - no project loaded From 1fa86ddd73959cc6fb958ba8c462a33333b90744 Mon Sep 17 00:00:00 2001 From: Cam Stevenson Date: Sun, 29 Oct 2017 11:26:43 -0400 Subject: [PATCH 4/4] Finish OPML Import --- manuskript/import_export/opml.py | 125 ++++++++++++++++++------- manuskript/mainWindow.py | 12 +-- manuskript/ui/editors/mainEditor.py | 20 ++++ manuskript/ui/editors/mainEditor_ui.py | 10 ++ manuskript/ui/editors/mainEditor_ui.ui | 17 ++++ manuskript/ui/mainWindow.py | 5 - 6 files changed, 142 insertions(+), 47 deletions(-) diff --git a/manuskript/import_export/opml.py b/manuskript/import_export/opml.py index e178ddc3..9dc63277 100644 --- a/manuskript/import_export/opml.py +++ b/manuskript/import_export/opml.py @@ -2,69 +2,112 @@ # --!-- 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 -import xmltodict +from lxml import etree as ET from manuskript.functions import mainWindow -from PyQt5.QtCore import QModelIndex -def exportOpml(): - return True - - -def importOpml(opmlFilePath): - with open(opmlFilePath, 'r') as opmlFile: - opmlContent = saveNewlines(opmlFile.read()) - +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 - dict = xmltodict.parse(opmlContent, strip_whitespace=False) + if idx.internalPointer() is not None: + parentItem = idx.internalPointer() + else: + parentItem = mdl.rootItem - opmlNode = dict['opml'] - bodyNode = opmlNode['body'] + try: + parsed = ET.fromstring(bytes(opmlContent, 'utf-8')) - outline = bodyNode['outline'] + opmlNode = parsed + bodyNode = opmlNode.find("body") - for element in outline: - parseItems(element, mdl.rootItem) + if bodyNode is not None: + outlineEls = bodyNode.findall("outline") - mdl.layoutChanged.emit() + if outlineEls is not None: + for element in outlineEls: + parseItems(element, parentItem) - mw.treeRedacOutline.viewport().update() + mdl.layoutChanged.emit() + mw.treeRedacOutline.viewport().update() + ret = True + except: + pass - return True + # 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): - if '@text' in underElement: - card = outlineItem(parent=parentItem, title=underElement['@text']) + 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 += '...' - text = "" + card = outlineItem(parent=parentItem, title=title) + + body = "" summary = "" - if '@_note' in underElement: - text = restoreNewLines(underElement['@_note']) - summary = text[0:128] + 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 'outline' in underElement: - elements = underElement['outline'] - - for el in elements: + 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, text) + card.setData(Outline.text.value, body) - # I assume I don't have to do the following - # parentItem.appendChild(card) + # 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}}") @@ -72,6 +115,22 @@ def saveNewlines(inString): 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 diff --git a/manuskript/mainWindow.py b/manuskript/mainWindow.py index 92850ff8..36d40e17 100644 --- a/manuskript/mainWindow.py +++ b/manuskript/mainWindow.py @@ -27,7 +27,6 @@ from manuskript.ui.mainWindow import Ui_MainWindow from manuskript.ui.tools.frequencyAnalyzer import frequencyAnalyzer from manuskript.ui.views.outlineDelegates import outlineCharacterDelegate from manuskript.ui.views.plotDelegate import plotDelegate -from manuskript.import_export import opml as opmlInputExport # Spellcheck support from manuskript.ui.views.textEditView import textEditView @@ -98,13 +97,12 @@ class MainWindow(QMainWindow, Ui_MainWindow): # Main Menu for i in [self.actSave, self.actSaveAs, self.actCloseProject, self.menuEdit, self.menuView, self.menuTools, self.menuHelp, - self.actCompile, self.actImport, self.actSettings]: + self.actCompile, self.actSettings]: i.setEnabled(False) self.actOpen.triggered.connect(self.welcome.openFile) self.actSave.triggered.connect(self.saveDatas) self.actSaveAs.triggered.connect(self.welcome.saveAsFile) - self.actImport.triggered.connect(self.importOutline) self.actCompile.triggered.connect(self.doCompile) self.actLabels.triggered.connect(self.settingsLabel) self.actStatus.triggered.connect(self.settingsStatus) @@ -447,7 +445,7 @@ class MainWindow(QMainWindow, Ui_MainWindow): i.setEnabled(False) for i in [self.actSave, self.actSaveAs, self.actCloseProject, self.menuEdit, self.menuView, self.menuTools, self.menuHelp, - self.actCompile, self.actImport, self.actSettings]: + self.actCompile, self.actSettings]: i.setEnabled(True) # Add project name to Window's name @@ -491,7 +489,7 @@ class MainWindow(QMainWindow, Ui_MainWindow): i.setEnabled(True) for i in [self.actSave, self.actSaveAs, self.actCloseProject, self.menuEdit, self.menuView, self.menuTools, self.menuHelp, - self.actCompile, self.actImport, self.actSettings]: + self.actCompile, self.actSettings]: i.setEnabled(False) # Set Window's name - no project loaded @@ -627,10 +625,6 @@ class MainWindow(QMainWindow, Ui_MainWindow): self.statusBar().showMessage( self.tr("Project {} loaded with some errors.").format(project), 5000) - def importOutline(self, project): - opmlInputExport.importOpml('/home/cstevenson/End Plan 2.opml') - return True - ############################################################################### # MAIN CONNECTIONS ############################################################################### diff --git a/manuskript/ui/editors/mainEditor.py b/manuskript/ui/editors/mainEditor.py index ab5c1b60..71571e7d 100644 --- a/manuskript/ui/editors/mainEditor.py +++ b/manuskript/ui/editors/mainEditor.py @@ -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, '') @@ -44,6 +45,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. @@ -217,6 +222,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) @@ -296,6 +302,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 ############################################################################### diff --git a/manuskript/ui/editors/mainEditor_ui.py b/manuskript/ui/editors/mainEditor_ui.py index 269f0fc1..22fd1f0c 100644 --- a/manuskript/ui/editors/mainEditor_ui.py +++ b/manuskript/ui/editors/mainEditor_ui.py @@ -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 diff --git a/manuskript/ui/editors/mainEditor_ui.ui b/manuskript/ui/editors/mainEditor_ui.ui index 68a3a68f..ce73c973 100644 --- a/manuskript/ui/editors/mainEditor_ui.ui +++ b/manuskript/ui/editors/mainEditor_ui.ui @@ -111,6 +111,23 @@ + + + + + Import items from an OPML file into the current folder + + + + + + + + + true + + + diff --git a/manuskript/ui/mainWindow.py b/manuskript/ui/mainWindow.py index ad5d0933..a2a9a74e 100644 --- a/manuskript/ui/mainWindow.py +++ b/manuskript/ui/mainWindow.py @@ -1123,9 +1123,6 @@ class Ui_MainWindow(object): self.actSaveAs.setObjectName("actSaveAs") self.actQuit = QtWidgets.QAction(MainWindow) icon = QtGui.QIcon.fromTheme("application-exit") - self.actImport = QtWidgets.QAction(MainWindow) - self.actImport.setIcon(icon) - self.actImport.setObjectName("actImport") self.actQuit.setIcon(icon) self.actQuit.setObjectName("actQuit") self.actShowHelp = QtWidgets.QAction(MainWindow) @@ -1186,7 +1183,6 @@ class Ui_MainWindow(object): self.menuFile.addAction(self.menuRecents.menuAction()) self.menuFile.addAction(self.actSave) self.menuFile.addAction(self.actSaveAs) - self.menuFile.addAction(self.actImport) self.menuFile.addAction(self.actCloseProject) self.menuFile.addSeparator() self.menuFile.addAction(self.actCompile) @@ -1328,7 +1324,6 @@ class Ui_MainWindow(object): self.actSave.setShortcut(_translate("MainWindow", "Ctrl+S")) self.actSaveAs.setText(_translate("MainWindow", "Sa&ve as...")) self.actSaveAs.setShortcut(_translate("MainWindow", "Ctrl+Shift+S")) - self.actImport.setText("Import") self.actQuit.setText(_translate("MainWindow", "&Quit")) self.actQuit.setShortcut(_translate("MainWindow", "Ctrl+Q")) self.actShowHelp.setText(_translate("MainWindow", "&Show help texts"))