Do not reinvent QFileDialog's default suffix

According to issue #608 we were silently overwriting files when there
was a suffix being generated for a chosen export filename when one was
missing to begin with. Unfortunately, this helpful feature avoids all
the conveniences offered by QFileDialog in regards to alerting the user
to overwriting an existing file. Worse still, this feature already
exists in QFileDialog and the native APIs it can rely on.

This patch reimplements QFileDialog.getSaveFileName to allow the use of
the default suffix feature as functions.getSaveFileNameWithSuffix and
removes most of the magic involved with the old solution.
This commit is contained in:
Jan Wester 2019-08-09 00:16:02 +02:00 committed by Curtis Gedak
parent bcf749d165
commit 9317dc97d8
10 changed files with 42 additions and 20 deletions

View file

@ -21,6 +21,7 @@ class HTML(markdown):
exportVarName = "lastManuskriptHTML"
exportFilter = "HTML files (*.html);; Any files (*)"
exportDefaultSuffix = ".html"
def isValid(self):
return MD is not None

View file

@ -16,6 +16,7 @@ class markdown(plainText):
exportVarName = "lastManuskriptMarkdown"
exportFilter = "Markdown files (*.md);; Any files (*)"
exportDefaultSuffix = ".md"
icon = "text-x-markdown"
def settingsWidget(self):

View file

@ -5,7 +5,7 @@ from PyQt5.QtGui import QFont, QTextCharFormat
from PyQt5.QtWidgets import QPlainTextEdit, qApp, QFrame, QFileDialog, QMessageBox
from manuskript.exporter.basic import basicFormat
from manuskript.functions import mainWindow
from manuskript.functions import mainWindow, getSaveFileNameWithSuffix
from manuskript.models import outlineItem
from manuskript.ui.exporters.manuskript.plainTextSettings import exporterSettings
import codecs
@ -24,6 +24,7 @@ class plainText(basicFormat):
# Default settings used in self.getExportFilename. For easy subclassing when exporting plaintext.
exportVarName = "lastPlainText"
exportFilter = "Text files (*.txt);; Any files (*)"
exportDefaultSuffix = ".txt" # qt ignores the period, but it is clearer in our code to have it
def __init__(self):
pass
@ -64,28 +65,16 @@ class plainText(basicFormat):
else:
filename = ""
filename, filter = QFileDialog.getSaveFileName(settingsWidget.parent(),
caption=qApp.translate("Export", "Choose output file…"),
filter=filter,
directory=filename)
filename, filter = getSaveFileNameWithSuffix(settingsWidget.parent(),
caption=qApp.translate("Export", "Choose output file…"),
filter=filter,
directory=filename,
defaultSuffix=self.exportDefaultSuffix)
if filename:
s[varName] = filename
settingsWidget.settings["Output"] = s
# Auto adds extension if necessary
try:
# Extract the extension from "Some name (*.ext)"
ext = filter.split("(")[1].split(")")[0]
ext = ext.split(".")[1]
if " " in ext: # In case there are multiple extensions: "Images (*.png *.jpg)"
ext = ext.split(" ")[0]
except:
ext = ""
if ext and filename[-len(ext)-1:] != ".{}".format(ext):
filename += "." + ext
# Save settings
settingsWidget.writeSettings()

View file

@ -16,6 +16,7 @@ class HTML(abstractPlainText):
exportVarName = "lastPandocHTML"
toFormat = "html"
exportFilter = "HTML files (*.html);; Any files (*)"
exportDefaultSuffix = ".html"
requires = {
"Settings": True,
"Preview": True,

View file

@ -23,6 +23,7 @@ class PDF(abstractOutput):
exportVarName = "lastPandocPDF"
toFormat = "pdf"
exportFilter = "PDF files (*.pdf);; Any files (*)"
exportDefaultSuffix = ".pdf"
requires = {
"Settings": True,
"Preview": True,

View file

@ -10,6 +10,7 @@ class abstractOutput(abstractPlainText):
toFormat = "SUBCLASSME"
icon = "SUBCLASSME"
exportFilter = "SUBCLASSME"
exportDefaultSuffix = ".SUBCLASSME"
requires = {
"Settings": True,
"Preview": False,

View file

@ -16,6 +16,7 @@ class abstractPlainText(markdown):
toFormat = "SUBCLASSME"
icon = "SUBCLASSME"
exportFilter = "SUBCLASSME"
exportDefaultSuffix = ".SUBCLASSME"
def __init__(self, exporter):
self.exporter = exporter

View file

@ -13,6 +13,7 @@ class ePub(abstractOutput):
exportVarName = "lastPandocePub"
toFormat = "epub"
exportFilter = "ePub files (*.epub);; Any files (*)"
exportDefaultSuffix = ".epub"
class OpenDocument(abstractOutput):
@ -23,6 +24,7 @@ class OpenDocument(abstractOutput):
toFormat = "odt"
icon = "application-vnd.oasis.opendocument.text"
exportFilter = "OpenDocument files (*.odt);; Any files (*)"
exportDefaultSuffix = ".odt"
class DocX(abstractOutput):
@ -33,4 +35,5 @@ class DocX(abstractOutput):
toFormat = "docx"
icon = "application-vnd.openxmlformats-officedocument.wordprocessingml.document"
exportFilter = "DocX files (*.docx);; Any files (*)"
exportDefaultSuffix = ".docx"

View file

@ -14,6 +14,7 @@ class markdown(abstractPlainText):
exportVarName = "lastPandocMarkdown"
toFormat = "markdown"
exportFilter = "Markdown files (*.md);; Any files (*)"
exportDefaultSuffix = ".md"
class reST(abstractPlainText):
@ -24,6 +25,7 @@ class reST(abstractPlainText):
toFormat = "rst"
icon = "text-plain"
exportFilter = "reST files (*.rst);; Any files (*)"
exportDefaultSuffix = ".rst"
class latex(abstractPlainText):
@ -35,6 +37,7 @@ class latex(abstractPlainText):
toFormat = "latex"
icon = "text-x-tex"
exportFilter = "Tex files (*.tex);; Any files (*)"
exportDefaultSuffix = ".tex"
class OPML(abstractPlainText):
@ -47,5 +50,5 @@ class OPML(abstractPlainText):
toFormat = "opml"
icon = "text-x-opml+xml"
exportFilter = "OPML files (*.opml);; Any files (*)"
exportDefaultSuffix = ".opml"

View file

@ -9,7 +9,7 @@ from PyQt5.QtCore import Qt, QRect, QStandardPaths, QObject, QRegExp, QDir
from PyQt5.QtCore import QUrl, QTimer
from PyQt5.QtGui import QBrush, QIcon, QPainter, QColor, QImage, QPixmap
from PyQt5.QtGui import QDesktopServices
from PyQt5.QtWidgets import qApp, QTextEdit
from PyQt5.QtWidgets import qApp, QFileDialog, QTextEdit
from manuskript.enums import Outline
@ -386,6 +386,27 @@ def openURL(url):
"""
QDesktopServices.openUrl(QUrl(url))
def getSaveFileNameWithSuffix(parent, caption, directory, filter, options=None, selectedFilter=None, defaultSuffix=None):
"""
A reimplemented version of QFileDialog.getSaveFileName() because we would like to make use
of the QFileDialog.defaultSuffix property that getSaveFileName() does not let us adjust.
Note: knowing the selected filter is not an invitation to change the chosen filename later.
"""
dialog = QFileDialog(parent=parent, caption=caption, directory=directory, filter=filter)
if options:
dialog.setOptions(options)
if defaultSuffix:
dialog.setDefaultSuffix(defaultSuffix)
dialog.setFileMode(QFileDialog.AnyFile)
dialog.setSupportedSchemes(("file",))
dialog.setAcceptMode(QFileDialog.AcceptSave)
if selectedFilter:
dialog.selectNameFilter(selectedFilter)
if (dialog.exec() == QFileDialog.Accepted):
return dialog.selectedFiles()[0], dialog.selectedNameFilter()
return None, None
def inspect():
"""
Debugging tool. Call it to see a stack of calls up to that point.