Allow the user to save as files with different extensions.

There is still an open issue in this fix since the new extension might be of a different mime type (and our editors are attached to it currently).
More details documented in the code.

Task-number: QTCREATORBUG-2094
Reviewed-by: Thorbjorn Lindeijer
This commit is contained in:
Leandro Melo
2010-09-07 11:55:52 +02:00
parent f7b555b785
commit bcb3bb0fba
5 changed files with 98 additions and 55 deletions

View File

@@ -246,6 +246,8 @@ const char * const SETTINGS_CATEGORY_CORE_ICON = ":/core/images/category_core.pn
const char * const SETTINGS_TR_CATEGORY_CORE = QT_TRANSLATE_NOOP("Core", "Environment"); const char * const SETTINGS_TR_CATEGORY_CORE = QT_TRANSLATE_NOOP("Core", "Environment");
const char * const SETTINGS_ID_ENVIRONMENT = "A.General"; const char * const SETTINGS_ID_ENVIRONMENT = "A.General";
const char * const ALL_FILES_FILTER = QT_TRANSLATE_NOOP("Core", "All Files (*)");
const int TARGET_ICON_SIZE = 32; const int TARGET_ICON_SIZE = 32;
} // namespace Constants } // namespace Constants

View File

@@ -264,8 +264,7 @@ void ShortcutSettings::exportAction()
QString fileName = ICore::instance()->fileManager()->getSaveFileNameWithExtension( QString fileName = ICore::instance()->fileManager()->getSaveFileNameWithExtension(
tr("Export Keyboard Mapping Scheme"), tr("Export Keyboard Mapping Scheme"),
ICore::instance()->resourcePath() + "/schemes/", ICore::instance()->resourcePath() + "/schemes/",
tr("Keyboard Mapping Scheme (*.kms)"), tr("Keyboard Mapping Scheme (*.kms)"));
".kms");
if (!fileName.isEmpty()) { if (!fileName.isEmpty()) {
CommandsFile cf(fileName); CommandsFile cf(fileName);
cf.exportCommands(m_scitems); cf.exportCommands(m_scitems);

View File

@@ -77,6 +77,8 @@
#include <QtGui/QSplitter> #include <QtGui/QSplitter>
#include <QtGui/QStackedLayout> #include <QtGui/QStackedLayout>
#include <algorithm>
Q_DECLARE_METATYPE(Core::IEditor*) Q_DECLARE_METATYPE(Core::IEditor*)
enum { debugEditorManager=0 }; enum { debugEditorManager=0 };
@@ -208,9 +210,6 @@ struct EditorManagerPrivate {
QMap<QString, QVariant> m_editorStates; QMap<QString, QVariant> m_editorStates;
Internal::OpenEditorsViewFactory *m_openEditorsFactory; Internal::OpenEditorsViewFactory *m_openEditorsFactory;
QString fileFilters;
QString selectedFilter;
OpenEditorsModel *m_editorModel; OpenEditorsModel *m_editorModel;
QString m_externalEditor; QString m_externalEditor;
@@ -1152,33 +1151,28 @@ QString EditorManager::getOpenWithEditorId(const QString &fileName,
return selectedId; return selectedId;
} }
static QString formatFileFilters(const Core::ICore *core, QString *selectedFilter) static QString formatFileFilters(const Core::ICore *core, QString *selectedFilter = 0)
{ {
QString rc; if (selectedFilter)
selectedFilter->clear();
// Compile list of filter strings // Compile list of filter strings, sort, and remove duplicates (different mime types might
// generate the same filter).
QStringList filters = core->mimeDatabase()->filterStrings(); QStringList filters = core->mimeDatabase()->filterStrings();
filters.sort();
selectedFilter->clear();
if (filters.empty()) if (filters.empty())
return rc; return QString();
filters.sort();
filters.erase(std::unique(filters.begin(), filters.end()), filters.end());
const QString filterSeparator = QLatin1String(";;"); static const QString allFilesFilter =
foreach (const QString &filterString, filters) { QCoreApplication::translate("Core", Constants::ALL_FILES_FILTER);
if (!rc.isEmpty()) if (selectedFilter)
rc += filterSeparator; *selectedFilter = allFilesFilter;
rc += filterString;
}
// prepend all files filter // Prepend all files filter (instead of appending to work around a bug in Qt/Mac).
// prepending instead of appending to work around a bug in Qt/Mac filters.prepend(allFilesFilter);
QString allFilesFilter = EditorManager::tr("All Files (*)");
if (!rc.isEmpty())
allFilesFilter += filterSeparator;
rc.prepend(allFilesFilter);
*selectedFilter = allFilesFilter;
return rc; return filters.join(QLatin1String(";;"));
} }
IEditor *EditorManager::openEditor(const QString &fileName, const QString &editorId, IEditor *EditorManager::openEditor(const QString &fileName, const QString &editorId,
@@ -1244,10 +1238,10 @@ bool EditorManager::openExternalEditor(const QString &fileName, const QString &e
QStringList EditorManager::getOpenFileNames() const QStringList EditorManager::getOpenFileNames() const
{ {
if (m_d->fileFilters.isEmpty()) QString selectedFilter;
m_d->fileFilters = formatFileFilters(m_d->m_core, &m_d->selectedFilter); const QString &fileFilters = formatFileFilters(m_d->m_core, &selectedFilter);
return ICore::instance()->fileManager()->getOpenFileNames(m_d->fileFilters, return ICore::instance()->fileManager()->getOpenFileNames(fileFilters,
QString(), &m_d->selectedFilter); QString(), &selectedFilter);
} }
@@ -1475,23 +1469,35 @@ bool EditorManager::saveFileAs(IEditor *editor)
if (!editor) if (!editor)
return false; return false;
QString absoluteFilePath = m_d->m_core->fileManager()->getSaveAsFileName(editor->file()); IFile *file = editor->file();
const QString &filter = formatFileFilters(m_d->m_core);
QString selectedFilter =
m_d->m_core->mimeDatabase()->findByFile(QFileInfo(file->fileName())).filterString();
const QString &absoluteFilePath =
m_d->m_core->fileManager()->getSaveAsFileName(file, filter, &selectedFilter);
if (absoluteFilePath.isEmpty()) if (absoluteFilePath.isEmpty())
return false; return false;
if (absoluteFilePath != editor->file()->fileName()) { if (absoluteFilePath != file->fileName()) {
const QList<IEditor *> existList = editorsForFileName(absoluteFilePath); const QList<IEditor *> existList = editorsForFileName(absoluteFilePath);
if (!existList.isEmpty()) { if (!existList.isEmpty()) {
closeEditors(existList, false); closeEditors(existList, false);
} }
} }
m_d->m_core->fileManager()->blockFileChange(editor->file()); m_d->m_core->fileManager()->blockFileChange(file);
const bool success = editor->file()->save(absoluteFilePath); const bool success = file->save(absoluteFilePath);
m_d->m_core->fileManager()->unblockFileChange(editor->file()); m_d->m_core->fileManager()->unblockFileChange(file);
editor->file()->checkPermissions(); file->checkPermissions();
// @todo: There is an issue to be treated here. The new file might be of a different mime
// type than the original and thus require a different editor. An alternative strategy
// would be to close the current editor and open a new appropriate one, but this is not
// a good way out either (also the undo stack would be lost). Perhaps the best is to
// re-think part of the editors design.
if (success && !editor->isTemporary()) if (success && !editor->isTemporary())
m_d->m_core->fileManager()->addToRecentFiles(editor->file()->fileName()); m_d->m_core->fileManager()->addToRecentFiles(file->fileName());
updateActions(); updateActions();
return success; return success;

View File

@@ -37,6 +37,7 @@
#include "mimedatabase.h" #include "mimedatabase.h"
#include "saveitemsdialog.h" #include "saveitemsdialog.h"
#include "vcsmanager.h" #include "vcsmanager.h"
#include "coreconstants.h"
#include <utils/qtcassert.h> #include <utils/qtcassert.h>
#include <utils/pathchooser.h> #include <utils/pathchooser.h>
@@ -689,22 +690,45 @@ QList<IFile *> FileManager::saveModifiedFiles(const QList<IFile *> &files,
return notSaved; return notSaved;
} }
QString FileManager::getSaveFileNameWithExtension(const QString &title, const QString &pathIn, QString FileManager::getSaveFileName(const QString &title, const QString &pathIn,
const QString &fileFilter, const QString &extension) const QString &filter, QString *selectedFilter)
{ {
const QString &path = pathIn.isEmpty() ? fileDialogInitialDirectory() : pathIn;
QString fileName; QString fileName;
bool repeat; bool repeat;
do { do {
repeat = false; repeat = false;
const QString path = pathIn.isEmpty() ? fileDialogInitialDirectory() : pathIn; fileName = QFileDialog::getSaveFileName(
fileName = QFileDialog::getSaveFileName(d->m_mainWindow, title, path, fileFilter); d->m_mainWindow, title, path, filter, selectedFilter, QFileDialog::DontConfirmOverwrite);
if (!fileName.isEmpty() && !extension.isEmpty() && !fileName.endsWith(extension)) { if (!fileName.isEmpty()) {
fileName.append(extension); // If the selected filter is All Files (*) we leave the name exactly as the user
// specified. Otherwise the suffix must be one available in the selected filter. If
// the name already ends with such suffix nothing needs to be done. But if not, the
// first one from the filter is appended.
if (selectedFilter && *selectedFilter != QCoreApplication::translate(
"Core", Constants::ALL_FILES_FILTER)) {
// Mime database creates filter strings like this: Anything here (*.foo *.bar)
QRegExp regExp(".*\\s+\\((.*)\\)$");
const int index = regExp.lastIndexIn(*selectedFilter);
bool suffixOk = false;
if (index != -1) {
const QStringList &suffixes = regExp.cap(1).remove('*').split(' ');
foreach (const QString &suffix, suffixes)
if (fileName.endsWith(suffix)) {
suffixOk = true;
break;
}
if (!suffixOk && !suffixes.isEmpty())
fileName.append(suffixes.at(0));
}
}
if (QFile::exists(fileName)) { if (QFile::exists(fileName)) {
if (QMessageBox::warning(d->m_mainWindow, tr("Overwrite?"), if (QMessageBox::warning(d->m_mainWindow, tr("Overwrite?"),
tr("An item named '%1' already exists at this location. Do you want to overwrite it?").arg(fileName), tr("An item named '%1' already exists at this location. "
QMessageBox::Yes | QMessageBox::No) == QMessageBox::No) "Do you want to overwrite it?").arg(fileName),
QMessageBox::Yes | QMessageBox::No) == QMessageBox::No) {
repeat = true; repeat = true;
}
} }
} }
} while (repeat); } while (repeat);
@@ -713,12 +737,19 @@ QString FileManager::getSaveFileNameWithExtension(const QString &title, const QS
return fileName; return fileName;
} }
QString FileManager::getSaveFileNameWithExtension(const QString &title, const QString &pathIn,
const QString &filter)
{
QString selected = filter;
return getSaveFileName(title, pathIn, filter, &selected);
}
/*! /*!
\fn QString FileManager::getSaveAsFileName(IFile *file) \fn QString FileManager::getSaveAsFileName(IFile *file)
Asks the user for a new file name (Save File As) for /arg file. Asks the user for a new file name (Save File As) for /arg file.
*/ */
QString FileManager::getSaveAsFileName(IFile *file) QString FileManager::getSaveAsFileName(IFile *file, const QString &filter, QString *selectedFilter)
{ {
if (!file) if (!file)
return QLatin1String(""); return QLatin1String("");
@@ -732,17 +763,20 @@ QString FileManager::getSaveAsFileName(IFile *file)
if (!defaultPath.isEmpty()) if (!defaultPath.isEmpty())
path = defaultPath; path = defaultPath;
} }
QString filterString; QString filterString;
QString preferredSuffix; if (filter.isEmpty()) {
if (const MimeType mt = Core::ICore::instance()->mimeDatabase()->findByFile(fi)) { if (const MimeType &mt = Core::ICore::instance()->mimeDatabase()->findByFile(fi))
filterString = mt.filterString(); filterString = mt.filterString();
preferredSuffix = mt.preferredSuffix(); selectedFilter = &filterString;
} else {
filterString = filter;
} }
absoluteFilePath = getSaveFileNameWithExtension(tr("Save File As"), absoluteFilePath = getSaveFileName(tr("Save File As"),
path + QDir::separator() + fileName, path + QDir::separator() + fileName,
filterString, filterString,
preferredSuffix); selectedFilter);
return absoluteFilePath; return absoluteFilePath;
} }

View File

@@ -87,10 +87,12 @@ public:
QStringList getOpenFileNames(const QString &filters, QStringList getOpenFileNames(const QString &filters,
const QString path = QString(), const QString path = QString(),
QString *selectedFilter = 0); QString *selectedFilter = 0);
QString getSaveFileName(const QString &title, const QString &pathIn,
QString getSaveFileNameWithExtension(const QString &title, const QString &path, const QString &filter = QString(), QString *selectedFilter = 0);
const QString &fileFilter, const QString &extension); QString getSaveFileNameWithExtension(const QString &title, const QString &pathIn,
QString getSaveAsFileName(IFile *file); const QString &filter);
QString getSaveAsFileName(IFile *file, const QString &filter = QString(),
QString *selectedFilter = 0);
QList<IFile *> saveModifiedFilesSilently(const QList<IFile *> &files); QList<IFile *> saveModifiedFilesSilently(const QList<IFile *> &files);
QList<IFile *> saveModifiedFiles(const QList<IFile *> &files, QList<IFile *> saveModifiedFiles(const QList<IFile *> &files,