Commit f967b58e authored by Nikolai Kosjar's avatar Nikolai Kosjar

EditorManager: Warn before opening big text files

...since these might lead to out of memory situations and thus to
crashes. The warning and the file size limited is configurable in
Environment > General.

Task-number: QTCREATORBUG-14390
Change-Id: I868ceca0bee5551ed55f0df990ed334a8b539a7d
Reviewed-by: default avatarDavid Schulz <david.schulz@theqtcompany.com>
Reviewed-by: default avatarEike Ziller <eike.ziller@theqtcompany.com>
parent c82d287c
......@@ -65,6 +65,7 @@
#include <extensionsystem/pluginmanager.h>
#include <utils/algorithm.h>
#include <utils/checkablemessagebox.h>
#include <utils/executeondestruction.h>
#include <utils/fileutils.h>
#include <utils/hostosinfo.h>
......@@ -107,6 +108,8 @@ static const char documentStatesKey[] = "EditorManager/DocumentStates";
static const char reloadBehaviorKey[] = "EditorManager/ReloadBehavior";
static const char autoSaveEnabledKey[] = "EditorManager/AutoSaveEnabled";
static const char autoSaveIntervalKey[] = "EditorManager/AutoSaveInterval";
static const char warnBeforeOpeningBigTextFilesKey[] = "EditorManager/WarnBeforeOpeningBigTextFiles";
static const char bigTextFileSizeLimitKey[] = "EditorManager/BigTextFileSizeLimitInMB";
static const char scratchBufferKey[] = "_q_emScratchBuffer";
......@@ -280,7 +283,9 @@ EditorManagerPrivate::EditorManagerPrivate(QObject *parent) :
m_coreListener(0),
m_reloadSetting(IDocument::AlwaysAsk),
m_autoSaveEnabled(true),
m_autoSaveInterval(5)
m_autoSaveInterval(5),
m_warnBeforeOpeningBigFilesEnabled(true),
m_bigFileSizeLimitInMB(5)
{
d = this;
}
......@@ -544,6 +549,47 @@ EditorArea *EditorManagerPrivate::mainEditorArea()
return d->m_editorAreas.at(0);
}
bool EditorManagerPrivate::skipOpeningBigTextFile(const QString &filePath)
{
if (!d->m_warnBeforeOpeningBigFilesEnabled)
return false;
const QFileInfo fileInfo(filePath);
if (!fileInfo.exists(filePath))
return false;
Utils::MimeDatabase mdb;
Utils::MimeType mimeType = mdb.mimeTypeForFile(filePath);
if (!mimeType.inherits(QLatin1String("text/plain")))
return false;
const double fileSizeInMB = fileInfo.size() / 1000.0 / 1000.0;
if (fileSizeInMB > d->m_bigFileSizeLimitInMB) {
const QString title = EditorManager::tr("Continue Opening Huge Text File?");
const QString text = EditorManager::tr(
"The text file \"%1\" has the size %2MB and might take more memory to open"
" and process than available.\n"
"\n"
"Continue?")
.arg(fileInfo.fileName())
.arg(fileSizeInMB, 0, 'f', 2);
CheckableMessageBox messageBox(ICore::mainWindow());
messageBox.setWindowTitle(title);
messageBox.setText(text);
messageBox.setStandardButtons(QDialogButtonBox::Yes|QDialogButtonBox::No);
messageBox.setDefaultButton(QDialogButtonBox::No);
messageBox.setIconPixmap(QMessageBox::standardIcon(QMessageBox::Question));
messageBox.setCheckBoxVisible(true);
messageBox.setCheckBoxText(CheckableMessageBox::msgDoNotAskAgain());
messageBox.exec();
d->setWarnBeforeOpeningBigFilesEnabled(!messageBox.isChecked());
return messageBox.clickedStandardButton() != QDialogButtonBox::Yes;
}
return false;
}
IEditor *EditorManagerPrivate::openEditor(EditorView *view, const QString &fileName, Id editorId,
EditorManager::OpenEditorFlags flags, bool *newEditor)
{
......@@ -960,6 +1006,11 @@ void EditorManagerPrivate::saveSettings()
settings->setValue(QLatin1String(autoSaveEnabledKey), d->m_autoSaveEnabled);
settings->setValue(QLatin1String(autoSaveIntervalKey), d->m_autoSaveInterval);
settings->endTransaction();
QSettings *qsettings = ICore::settings();
qsettings->setValue(QLatin1String(warnBeforeOpeningBigTextFilesKey),
d->m_warnBeforeOpeningBigFilesEnabled);
qsettings->setValue(QLatin1String(bigTextFileSizeLimitKey), d->m_bigFileSizeLimitInMB);
}
void EditorManagerPrivate::readSettings()
......@@ -973,6 +1024,12 @@ void EditorManagerPrivate::readSettings()
qs->remove(QLatin1String(documentStatesKey));
}
if (qs->contains(QLatin1String(warnBeforeOpeningBigTextFilesKey))) {
d->m_warnBeforeOpeningBigFilesEnabled
= qs->value(QLatin1String(warnBeforeOpeningBigTextFilesKey)).toBool();
d->m_bigFileSizeLimitInMB = qs->value(QLatin1String(bigTextFileSizeLimitKey)).toInt();
}
SettingsDatabase *settings = ICore::settingsDatabase();
if (settings->contains(QLatin1String(documentStatesKey)))
d->m_editorStates = settings->value(QLatin1String(documentStatesKey))
......@@ -1010,6 +1067,26 @@ int EditorManagerPrivate::autoSaveInterval()
return d->m_autoSaveInterval;
}
bool EditorManagerPrivate::warnBeforeOpeningBigFilesEnabled()
{
return d->m_warnBeforeOpeningBigFilesEnabled;
}
void EditorManagerPrivate::setWarnBeforeOpeningBigFilesEnabled(bool enabled)
{
d->m_warnBeforeOpeningBigFilesEnabled = enabled;
}
int EditorManagerPrivate::bigFileSizeLimit()
{
return d->m_bigFileSizeLimitInMB;
}
void EditorManagerPrivate::setBigFileSizeLimit(int limitInMB)
{
d->m_bigFileSizeLimitInMB = limitInMB;
}
EditorManager::EditorFactoryList EditorManagerPrivate::findFactories(Id editorId, const QString &fileName)
{
if (debugEditorManager)
......@@ -2451,6 +2528,9 @@ EditorManager::ExternalEditorList
IEditor *EditorManager::openEditor(const QString &fileName, Id editorId,
OpenEditorFlags flags, bool *newEditor)
{
if (EditorManagerPrivate::skipOpeningBigTextFile(fileName))
return 0;
if (flags & EditorManager::OpenInOtherSplit)
EditorManager::gotoOtherSplit();
......@@ -2461,6 +2541,9 @@ IEditor *EditorManager::openEditor(const QString &fileName, Id editorId,
IEditor *EditorManager::openEditorAt(const QString &fileName, int line, int column,
Id editorId, OpenEditorFlags flags, bool *newEditor)
{
if (EditorManagerPrivate::skipOpeningBigTextFile(fileName))
return 0;
if (flags & EditorManager::OpenInOtherSplit)
EditorManager::gotoOtherSplit();
......
......@@ -111,6 +111,10 @@ public:
static bool autoSaveEnabled();
static void setAutoSaveInterval(int interval);
static int autoSaveInterval();
static void setWarnBeforeOpeningBigFilesEnabled(bool enabled);
static bool warnBeforeOpeningBigFilesEnabled();
static void setBigFileSizeLimit(int limitInMB);
static int bigFileSizeLimit();
static void splitNewWindow(Internal::EditorView *view);
static void closeView(Internal::EditorView *view);
......@@ -188,6 +192,7 @@ private:
static void setupSaveActions(IDocument *document, QAction *saveAction,
QAction *saveAsAction, QAction *revertToSavedAction);
static void updateWindowTitle();
static bool skipOpeningBigTextFile(const QString &filePath);
private:
explicit EditorManagerPrivate(QObject *parent);
......@@ -251,6 +256,9 @@ private:
bool m_autoSaveEnabled;
int m_autoSaveInterval;
bool m_warnBeforeOpeningBigFilesEnabled;
int m_bigFileSizeLimitInMB;
QString m_placeholderText;
};
......
......@@ -144,8 +144,10 @@ QWidget *GeneralSettings::widget()
m_page->patchChooser->setPath(PatchTool::patchCommand());
m_page->autoSaveCheckBox->setChecked(EditorManagerPrivate::autoSaveEnabled());
m_page->autoSaveInterval->setValue(EditorManagerPrivate::autoSaveInterval());
m_page->resetWarningsButton->setEnabled(InfoBar::anyGloballySuppressed()
|| CheckableMessageBox::hasSuppressedQuestions(ICore::settings()));
m_page->warnBeforeOpeningBigFiles->setChecked(
EditorManagerPrivate::warnBeforeOpeningBigFilesEnabled());
m_page->bigFilesLimitSpinBox->setValue(EditorManagerPrivate::bigFileSizeLimit());
m_page->resetWarningsButton->setEnabled(canResetWarnings());
connect(m_page->resetColorButton, SIGNAL(clicked()),
this, SLOT(resetInterfaceColor()));
......@@ -188,6 +190,9 @@ void GeneralSettings::apply()
PatchTool::setPatchCommand(m_page->patchChooser->path());
EditorManagerPrivate::setAutoSaveEnabled(m_page->autoSaveCheckBox->isChecked());
EditorManagerPrivate::setAutoSaveInterval(m_page->autoSaveInterval->value());
EditorManagerPrivate::setWarnBeforeOpeningBigFilesEnabled(
m_page->warnBeforeOpeningBigFiles->isChecked());
EditorManagerPrivate::setBigFileSizeLimit(m_page->bigFilesLimitSpinBox->value());
m_page->themeWidget->apply();
}
......@@ -207,6 +212,7 @@ void GeneralSettings::resetWarnings()
{
InfoBar::clearGloballySuppressed();
CheckableMessageBox::resetAllDoNotAskAgainQuestions(ICore::settings());
m_page->warnBeforeOpeningBigFiles->setChecked(true);
m_page->resetWarningsButton->setEnabled(false);
}
......@@ -230,6 +236,13 @@ void GeneralSettings::updatePath()
m_page->patchChooser->setEnvironment(env);
}
bool GeneralSettings::canResetWarnings() const
{
return InfoBar::anyGloballySuppressed()
|| CheckableMessageBox::hasSuppressedQuestions(ICore::settings())
|| !EditorManagerPrivate::warnBeforeOpeningBigFilesEnabled();
}
void GeneralSettings::variableHelpDialogCreator(const QString &helpText)
{
if (m_dialog) {
......
......@@ -64,6 +64,7 @@ private slots:
void updatePath();
private:
bool canResetWarnings() const;
void variableHelpDialogCreator(const QString &helpText);
void fillLanguageBox() const;
QString language() const;
......
......@@ -7,7 +7,7 @@
<x>0</x>
<y>0</y>
<width>527</width>
<height>359</height>
<height>366</height>
</rect>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
......@@ -310,6 +310,49 @@
</item>
</layout>
</item>
<item row="5" column="0" colspan="4">
<layout class="QHBoxLayout" name="horizontalLayout_4">
<item>
<widget class="QCheckBox" name="warnBeforeOpeningBigFiles">
<property name="text">
<string>Warn before opening text files greater than</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QSpinBox" name="bigFilesLimitSpinBox">
<property name="suffix">
<string>MB</string>
</property>
<property name="minimum">
<number>1</number>
</property>
<property name="maximum">
<number>500</number>
</property>
<property name="value">
<number>5</number>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_4">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
</layout>
</widget>
</item>
......@@ -362,12 +405,28 @@
<slot>setEnabled(bool)</slot>
<hints>
<hint type="sourcelabel">
<x>161</x>
<y>262</y>
<x>181</x>
<y>310</y>
</hint>
<hint type="destinationlabel">
<x>340</x>
<y>311</y>
</hint>
</hints>
</connection>
<connection>
<sender>warnBeforeOpeningBigFiles</sender>
<signal>toggled(bool)</signal>
<receiver>bigFilesLimitSpinBox</receiver>
<slot>setEnabled(bool)</slot>
<hints>
<hint type="sourcelabel">
<x>124</x>
<y>330</y>
</hint>
<hint type="destinationlabel">
<x>342</x>
<y>263</y>
<x>305</x>
<y>332</y>
</hint>
</hints>
</connection>
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment