Commit f1f9904d authored by Oswald Buddenhagen's avatar Oswald Buddenhagen

add errorString output argument to IFile::save()

this centralizes error reporting (in fact, in most cases it adds any in
the first place).

Task-number: QTCREATORBUG-1619
parent 469199e7
......@@ -35,6 +35,7 @@
#include <texteditor/fontsettings.h>
#include <texteditor/texteditorconstants.h>
#include <coreplugin/editormanager/ieditor.h>
#include <utils/fileutils.h>
#include <QtCore/QByteArrayMatcher>
#include <QtCore/QDebug>
......@@ -337,7 +338,7 @@ bool BinEditor::isReadOnly() const
return m_readOnly;
}
bool BinEditor::save(const QString &oldFileName, const QString &newFileName)
bool BinEditor::save(QString *errorString, const QString &oldFileName, const QString &newFileName)
{
if (oldFileName != newFileName) {
QString tmpName;
......@@ -354,21 +355,26 @@ bool BinEditor::save(const QString &oldFileName, const QString &newFileName)
if (!QFile::rename(tmpName, newFileName))
return false;
}
QFile output(newFileName);
if (!output.open(QIODevice::ReadWrite)) // QtBug: WriteOnly truncates.
return false;
const qint64 size = output.size();
for (BlockMap::const_iterator it = m_modifiedData.constBegin();
it != m_modifiedData.constEnd(); ++it) {
if (!output.seek(it.key() * m_blockSize))
return false;
if (output.write(it.value()) < m_blockSize)
return false;
}
Utils::FileSaver saver(newFileName, QIODevice::ReadWrite); // QtBug: WriteOnly truncates.
if (!saver.hasError()) {
QFile *output = saver.file();
const qint64 size = output->size();
for (BlockMap::const_iterator it = m_modifiedData.constBegin();
it != m_modifiedData.constEnd(); ++it) {
if (!saver.setResult(output->seek(it.key() * m_blockSize)))
break;
if (!saver.write(it.value()))
break;
if (!saver.setResult(output->flush()))
break;
}
// We may have padded the displayed data, so we have to make sure
// changes to that area are not actually written back to disk.
if (!output.resize(size))
// We may have padded the displayed data, so we have to make sure
// changes to that area are not actually written back to disk.
if (!saver.hasError())
saver.setResult(output->resize(size));
}
if (!saver.finalize(errorString))
return false;
setModified(false);
......
......@@ -72,7 +72,7 @@ public:
Q_INVOKABLE void addData(quint64 block, const QByteArray &data);
Q_INVOKABLE void setNewWindowRequestAllowed();
Q_INVOKABLE void updateContents();
bool save(const QString &oldFileName, const QString &newFileName);
bool save(QString *errorString, const QString &oldFileName, const QString &newFileName);
void zoomIn(int range = 1);
void zoomOut(int range = 1);
......
......@@ -199,10 +199,11 @@ public:
return QLatin1String(Constants::C_BINEDITOR_MIMETYPE);
}
bool save(const QString &fileName = QString()) {
bool save(QString *errorString, const QString &fileName = QString())
{
const QString fileNameToUse
= fileName.isEmpty() ? m_fileName : fileName;
if (m_editor->save(m_fileName, fileNameToUse)) {
if (m_editor->save(errorString, m_fileName, fileNameToUse)) {
m_fileName = fileNameToUse;
m_editor->editor()->setDisplayName(QFileInfo(fileNameToUse).fileName());
emit changed();
......
......@@ -735,10 +735,11 @@ CMakeFile::CMakeFile(CMakeProject *parent, QString fileName)
}
bool CMakeFile::save(const QString &fileName)
bool CMakeFile::save(QString *errorString, const QString &fileName)
{
// Once we have an texteditor open for this file, we probably do
// need to implement this, don't we.
Q_UNUSED(errorString)
Q_UNUSED(fileName)
return false;
}
......
......@@ -199,7 +199,7 @@ class CMakeFile : public Core::IFile
public:
CMakeFile(CMakeProject *parent, QString fileName);
bool save(const QString &fileName = QString());
bool save(QString *errorString, const QString &fileName = QString());
QString fileName() const;
QString defaultPath() const;
......
......@@ -1373,11 +1373,12 @@ bool EditorManager::saveFile(IFile *fileParam)
return saveFileAs(file);
bool success = false;
bool isReadOnly;
// try saving, no matter what isReadOnly tells us
success = m_d->m_core->fileManager()->saveFile(file);
success = m_d->m_core->fileManager()->saveFile(file, QString(), &isReadOnly);
if (!success) {
if (!success && isReadOnly) {
MakeWritableResult answer =
makeFileWritable(file);
if (answer == Failed)
......
......@@ -638,9 +638,24 @@ QList<IFile *> FileManager::saveModifiedFiles(const QList<IFile *> &files,
return notSaved;
}
bool FileManager::saveFile(IFile *file, const QString &fileName)
bool FileManager::saveFile(IFile *file, const QString &fileName, bool *isReadOnly)
{
const bool success = file->save(fileName);
QString effName = fileName.isEmpty() ? file->fileName() : fileName;
QString errorString;
if (!file->save(&errorString, fileName)) {
if (isReadOnly) {
QFile ofi(effName);
// Check whether the existing file is writable
if (ofi.exists() && !ofi.open(QIODevice::ReadWrite)
&& ofi.error() == QFile::PermissionsError) {
*isReadOnly = true;
return false;
}
*isReadOnly = false;
}
QMessageBox::critical(d->m_mainWindow, tr("File Error"), errorString);
return false;
}
// We are updating the lastUpdated time to the current modification time
// in changedFile we'll compare the modification time with the last updated
......@@ -655,7 +670,7 @@ bool FileManager::saveFile(IFile *file, const QString &fileName)
foreach (const QString &fileName, d->m_filesWithWatch.value(file))
updateExpectedState(fileName);
return success;
return true;
}
QString FileManager::getSaveFileName(const QString &title, const QString &pathIn,
......
......@@ -94,7 +94,7 @@ public:
// helper methods
static QString fixFileName(const QString &fileName, FixMode fixmode);
bool saveFile(IFile *file, const QString &fileName = QString());
bool saveFile(IFile *file, const QString &fileName = QString(), bool *isReadOnly = 0);
QStringList getOpenFileNames(const QString &filters,
const QString path = QString(),
......
......@@ -83,7 +83,7 @@ public:
IFile(QObject *parent = 0) : QObject(parent) {}
virtual ~IFile() {}
virtual bool save(const QString &fileName = QString()) = 0;
virtual bool save(QString *errorString, const QString &fileName = QString()) = 0;
virtual QString fileName() const = 0;
virtual QString defaultPath() const = 0;
......
......@@ -35,6 +35,7 @@
#include <coreplugin/icore.h>
#include <utils/reloadpromptutils.h>
#include <utils/fileutils.h>
#include <utils/qtcassert.h>
#include <QtDesigner/QDesignerFormWindowInterface>
......@@ -62,7 +63,7 @@ FormWindowFile::FormWindowFile(QDesignerFormWindowInterface *form, QObject *pare
this, SLOT(slotFormWindowRemoved(QDesignerFormWindowInterface*)));
}
bool FormWindowFile::save(const QString &name /* = QString() */)
bool FormWindowFile::save(QString *errorString, const QString &name /* = QString() */)
{
const QString actualName = name.isEmpty() ? fileName() : name;
......@@ -79,12 +80,10 @@ bool FormWindowFile::save(const QString &name /* = QString() */)
const QString formName = fi.absoluteFilePath();
m_formWindow->setFileName(formName);
QString errorString;
const bool warningsEnabled = qdesigner_internal::QSimpleResource::setWarningsEnabled(false);
const bool writeOK = writeFile(actualName, errorString);
qdesigner_internal::QSimpleResource::setWarningsEnabled(warningsEnabled);
if (!writeOK) {
QMessageBox::critical(0, tr("Error saving %1").arg(formName), errorString);
m_formWindow->setFileName(oldFormName);
return false;
}
......@@ -178,29 +177,14 @@ QString FormWindowFile::mimeType() const
return m_mimeType;
}
bool FormWindowFile::writeFile(const QString &fileName, QString &errorString) const
bool FormWindowFile::writeFile(const QString &fileName, QString *errorString) const
{
if (Designer::Constants::Internal::debug)
qDebug() << Q_FUNC_INFO << m_fileName << fileName;
QFile file(fileName);
if (!file.open(QIODevice::WriteOnly | QIODevice::Text | QIODevice::Truncate)) {
errorString = tr("Unable to open %1: %2").arg(fileName, file.errorString());
return false;
}
const bool rc = writeFile(file, errorString);
file.close();
return rc;
}
bool FormWindowFile::writeFile(QFile &file, QString &errorString) const
{
const QByteArray content = m_formWindow->contents().toUtf8();
if (!file.write(content)) {
errorString = tr("Unable to write to %1: %2").arg(file.fileName(), file.errorString());
return false;
}
return true;
Utils::FileSaver saver(fileName, QIODevice::Text);
saver.write(m_formWindow->contents().toUtf8());
return saver.finalize(errorString);
}
void FormWindowFile::setFileName(const QString &fname)
......
......@@ -53,7 +53,7 @@ public:
explicit FormWindowFile(QDesignerFormWindowInterface *form, QObject *parent = 0);
// IFile
virtual bool save(const QString &fileName = QString());
virtual bool save(QString *errorString, const QString &fileName = QString());
virtual QString fileName() const;
virtual bool isModified() const;
virtual bool isReadOnly() const;
......@@ -68,8 +68,7 @@ public:
// Internal
void setSuggestedFileName(const QString &fileName);
bool writeFile(const QString &fileName, QString &errorString) const;
bool writeFile(QFile &file, QString &errorString) const;
bool writeFile(const QString &fileName, QString *errorString) const;
QDesignerFormWindowInterface *formWindow() const;
......
......@@ -565,7 +565,7 @@ GenericProjectFile::GenericProjectFile(GenericProject *parent, QString fileName)
GenericProjectFile::~GenericProjectFile()
{ }
bool GenericProjectFile::save(const QString &)
bool GenericProjectFile::save(QString *, const QString &)
{
return false;
}
......
......@@ -159,7 +159,7 @@ public:
GenericProjectFile(GenericProject *parent, QString fileName);
virtual ~GenericProjectFile();
virtual bool save(const QString &fileName = QString());
virtual bool save(QString *errorString, const QString &fileName = QString());
virtual QString fileName() const;
virtual QString defaultPath() const;
......
......@@ -173,9 +173,9 @@ ProjectFilesDocument::ProjectFilesDocument(Manager *manager)
ProjectFilesDocument::~ProjectFilesDocument()
{ }
bool ProjectFilesDocument::save(const QString &name)
bool ProjectFilesDocument::save(QString *errorString, const QString &name)
{
if (! BaseTextDocument::save(name))
if (! BaseTextDocument::save(errorString, name))
return false;
m_manager->notifyChanged(name);
......
......@@ -113,7 +113,7 @@ public:
ProjectFilesDocument(Manager *manager);
virtual ~ProjectFilesDocument();
virtual bool save(const QString &name);
virtual bool save(QString *errorString, const QString &name);
private:
Manager *m_manager;
......
......@@ -86,8 +86,9 @@ void ImageViewerFile::reload(Core::IFile::ReloadFlag flag,
}
}
bool ImageViewerFile::save(const QString &fileName)
bool ImageViewerFile::save(QString *errorString, const QString &fileName)
{
Q_UNUSED(errorString)
Q_UNUSED(fileName);
return false;
}
......
......@@ -49,7 +49,7 @@ public:
explicit ImageViewerFile(ImageViewer *parent = 0);
~ImageViewerFile();
bool save(const QString &fileName = QString());
bool save(QString *errorString, const QString &fileName = QString());
void rename(const QString &newName);
QString fileName() const;
......
......@@ -46,7 +46,7 @@ QmlProjectFile::QmlProjectFile(QmlProject *parent, QString fileName)
QmlProjectFile::~QmlProjectFile()
{ }
bool QmlProjectFile::save(const QString &)
bool QmlProjectFile::save(QString *, const QString &)
{
return false;
}
......
......@@ -49,7 +49,7 @@ public:
QmlProjectFile(QmlProject *parent, QString fileName);
virtual ~QmlProjectFile();
virtual bool save(const QString &fileName = QString());
virtual bool save(QString *errorString, const QString &fileName = QString());
virtual QString fileName() const;
virtual void rename(const QString &newName);
......
......@@ -175,8 +175,9 @@ Qt4PriFile::Qt4PriFile(Qt4PriFileNode *qt4PriFile)
}
bool Qt4PriFile::save(const QString &fileName)
bool Qt4PriFile::save(QString *errorString, const QString &fileName)
{
Q_UNUSED(errorString);
Q_UNUSED(fileName);
return false;
}
......
......@@ -115,7 +115,7 @@ class Qt4PriFile : public Core::IFile
Q_OBJECT
public:
Qt4PriFile(Qt4PriFileNode *qt4PriFile);
virtual bool save(const QString &fileName = QString());
virtual bool save(QString *errorString, const QString &fileName = QString());
virtual QString fileName() const;
virtual void rename(const QString &newName);
......
......@@ -182,7 +182,7 @@ Qt4ProjectFile::Qt4ProjectFile(Qt4Project *project, const QString &filePath, QOb
{
}
bool Qt4ProjectFile::save(const QString &)
bool Qt4ProjectFile::save(QString *, const QString &)
{
// This is never used
return false;
......
......@@ -79,7 +79,7 @@ class Qt4ProjectFile : public Core::IFile
public:
Qt4ProjectFile(Qt4Project *project, const QString &filePath, QObject *parent = 0);
bool save(const QString &fileName = QString());
bool save(QString *errorString, const QString &fileName = QString());
QString fileName() const;
virtual void rename(const QString &newName);
......
......@@ -138,7 +138,7 @@ bool ResourceEditorW::open(const QString &fileName /* = QString() */)
return true;
}
bool ResourceEditorFile::save(const QString &name /* = QString() */)
bool ResourceEditorFile::save(QString *errorString, const QString &name /* = QString() */)
{
if (debugResourceEditorW)
qDebug(">ResourceEditorW::save: %s", qPrintable(name));
......@@ -150,6 +150,7 @@ bool ResourceEditorFile::save(const QString &name /* = QString() */)
m_parent->m_resourceEditor->setFileName(actualName);
if (!m_parent->m_resourceEditor->save()) {
*errorString = m_parent->m_resourceEditor->errorMessage();
m_parent->m_resourceEditor->setFileName(oldFileName);
return false;
}
......
......@@ -57,7 +57,7 @@ public:
ResourceEditorFile(ResourceEditorW *parent = 0);
//IFile
bool save(const QString &fileName = QString());
bool save(QString *errorString, const QString &fileName = QString());
QString fileName() const;
bool isModified() const;
bool isReadOnly() const;
......
......@@ -48,8 +48,9 @@ TaskFile::TaskFile(QObject *parent) : Core::IFile(parent),
TaskFile::~TaskFile()
{ }
bool TaskFile::save(const QString &fileName)
bool TaskFile::save(QString *errorString, const QString &fileName)
{
Q_UNUSED(errorString)
Q_UNUSED(fileName);
return false;
}
......
......@@ -48,7 +48,7 @@ public:
TaskFile(QObject *parent);
~TaskFile();
bool save(const QString &fileName = QString());
bool save(QString *errorString, const QString &fileName = QString());
QString fileName() const;
QString defaultPath() const;
......
......@@ -55,6 +55,7 @@
#include <coreplugin/icore.h>
#include <coreplugin/progressmanager/progressmanager.h>
#include <utils/qtcassert.h>
#include <utils/fileutils.h>
#include <utils/reloadpromptutils.h>
namespace {
......@@ -362,7 +363,7 @@ ITextMarkable *BaseTextDocument::documentMarker() const
return d->m_documentMarker;
}
bool BaseTextDocument::save(const QString &fileName)
bool BaseTextDocument::save(QString *errorString, const QString &fileName)
{
QTextCursor cursor(d->m_document);
......@@ -386,26 +387,24 @@ bool BaseTextDocument::save(const QString &fileName)
if (!fileName.isEmpty())
fName = fileName;
QFile file(fName);
if (!file.open(QIODevice::WriteOnly | QIODevice::Truncate))
return false;
Utils::FileSaver saver(fName);
if (!saver.hasError()) {
QString plainText = d->m_document->toPlainText();
QString plainText = d->m_document->toPlainText();
if (d->m_lineTerminatorMode == BaseTextDocumentPrivate::CRLFLineTerminator)
plainText.replace(QLatin1Char('\n'), QLatin1String("\r\n"));
if (d->m_lineTerminatorMode == BaseTextDocumentPrivate::CRLFLineTerminator)
plainText.replace(QLatin1Char('\n'), QLatin1String("\r\n"));
if (d->m_codec->name() == "UTF-8"
&& (d->m_extraEncodingSettings.m_utf8BomSetting == ExtraEncodingSettings::AlwaysAdd
|| (d->m_extraEncodingSettings.m_utf8BomSetting == ExtraEncodingSettings::OnlyKeep
&& d->m_fileHasUtf8Bom))) {
saver.write("\xef\xbb\xbf", 3);
}
if (d->m_codec->name() == "UTF-8"
&& (d->m_extraEncodingSettings.m_utf8BomSetting == ExtraEncodingSettings::AlwaysAdd
|| (d->m_extraEncodingSettings.m_utf8BomSetting == ExtraEncodingSettings::OnlyKeep
&& d->m_fileHasUtf8Bom))) {
file.write("\xef\xbb\xbf", 3);
saver.write(d->m_codec->fromUnicode(plainText));
}
file.write(d->m_codec->fromUnicode(plainText));
if (!file.flush())
if (!saver.finalize(errorString))
return false;
file.close();
const QFileInfo fi(fName);
d->m_fileName = QDir::cleanPath(fi.absoluteFilePath());
......
......@@ -70,7 +70,7 @@ public:
ITextMarkable *documentMarker() const;
// IFile implementation.
virtual bool save(const QString &fileName = QString());
virtual bool save(QString *errorString, const QString &fileName = QString());
virtual QString fileName() const;
virtual bool isReadOnly() const;
virtual bool isModified() const;
......
......@@ -69,9 +69,9 @@ void SubmitEditorFile::setModified(bool modified)
emit changed();
}
bool SubmitEditorFile::save(const QString &fileName)
bool SubmitEditorFile::save(QString *errorString, const QString &fileName)
{
emit saveMe(fileName);
emit saveMe(errorString, fileName);
emit changed();
return true;
}
......
......@@ -53,7 +53,7 @@ public:
virtual QString mimeType() const;
bool isReadOnly() const { return false; }
bool isSaveAsAllowed() const { return false; }
bool save(const QString &fileName);
bool save(QString *errorString, const QString &fileName);
ReloadBehavior reloadBehavior(ChangeTrigger state, ChangeType type) const;
void reload(ReloadFlag flag, ChangeType type);
void rename(const QString &newName);
......@@ -62,7 +62,7 @@ public:
void setModified(bool modified = true);
signals:
void saveMe(const QString &fileName);
void saveMe(QString *errorString, const QString &fileName);
private:
const QString m_mimeType;
......
......@@ -48,6 +48,7 @@
#include <utils/checkablemessagebox.h>
#include <utils/synchronousprocess.h>
#include <utils/submitfieldwidget.h>
#include <utils/fileutils.h>
#include <find/basetextfind.h>
#include <texteditor/fontsettings.h>
#include <texteditor/texteditorsettings.h>
......@@ -164,7 +165,7 @@ VCSBaseSubmitEditor::VCSBaseSubmitEditor(const VCSBaseSubmitEditorParameters *pa
m_d->m_file->setModified(false);
// We are always clean to prevent the editor manager from asking to save.
connect(m_d->m_file, SIGNAL(saveMe(QString)), this, SLOT(save(QString)));
connect(m_d->m_file, SIGNAL(saveMe(QString*, QString)), this, SLOT(save(QString*, QString)));
connect(m_d->m_widget, SIGNAL(diffSelected(QStringList)), this, SLOT(slotDiffSelectedVCSFiles(QStringList)));
connect(m_d->m_widget->descriptionEdit(), SIGNAL(textChanged()), this, SLOT(slotDescriptionChanged()));
......@@ -457,18 +458,13 @@ void VCSBaseSubmitEditor::slotDiffSelectedVCSFiles(const QStringList &rawList)
emit diffSelectedFiles(rawList);
}
bool VCSBaseSubmitEditor::save(const QString &fileName)
bool VCSBaseSubmitEditor::save(QString *errorString, const QString &fileName)
{
const QString fName = fileName.isEmpty() ? m_d->m_file->fileName() : fileName;
QFile file(fName);
if (!file.open(QIODevice::WriteOnly | QIODevice::Truncate | QIODevice::Text)) {
qWarning("Unable to open %s: %s", qPrintable(fName), qPrintable(file.errorString()));
Utils::FileSaver saver(fName, QIODevice::WriteOnly | QIODevice::Truncate | QIODevice::Text);
saver.write(fileContents().toLocal8Bit());
if (!saver.finalize(errorString))
return false;
}
file.write(fileContents().toLocal8Bit());
if (!file.flush())
return false;
file.close();
const QFileInfo fi(fName);
m_d->m_file->setFileName(fi.absoluteFilePath());
m_d->m_file->setModified(false);
......
......@@ -159,7 +159,7 @@ signals:
private slots:
void slotDiffSelectedVCSFiles(const QStringList &rawList);
bool save(const QString &fileName);
bool save(QString *errorString, const QString &fileName);
void slotDescriptionChanged();
void slotCheckSubmitMessage();
void slotInsertNickName();
......
......@@ -50,6 +50,7 @@ public:
bool load(const QString &fileName);
bool save();
QString errorMessage() const { return m_treeview->errorMessage(); }
bool isDirty();
void setDirty(bool dirty);
......
......@@ -200,7 +200,13 @@ bool ResourceFile::save()
QTextStream stream(&file);
doc.save(stream, 4);
#if QT_VERSION >= QT_VERSION_CHECK(4, 8, 0)
stream.flush();
if (stream.status() != QTextStream::Ok) {
m_error_message = QCoreApplication::translate("Designer", "Cannot write file. Disk full?");
return false;
}
#endif
return true;
}
......