2012-10-02 09:12:39 +02:00
|
|
|
/****************************************************************************
|
2008-12-02 12:01:29 +01:00
|
|
|
**
|
2015-01-14 18:07:15 +01:00
|
|
|
** Copyright (C) 2015 The Qt Company Ltd.
|
|
|
|
** Contact: http://www.qt.io/licensing
|
2008-12-02 12:01:29 +01:00
|
|
|
**
|
2012-10-02 09:12:39 +02:00
|
|
|
** This file is part of Qt Creator.
|
2008-12-02 12:01:29 +01:00
|
|
|
**
|
2012-10-02 09:12:39 +02:00
|
|
|
** Commercial License Usage
|
|
|
|
** Licensees holding valid commercial Qt licenses may use this file in
|
|
|
|
** accordance with the commercial license agreement provided with the
|
|
|
|
** Software or, alternatively, in accordance with the terms contained in
|
2015-01-14 18:07:15 +01:00
|
|
|
** a written agreement between you and The Qt Company. For licensing terms and
|
|
|
|
** conditions see http://www.qt.io/terms-conditions. For further information
|
2014-10-01 13:21:18 +02:00
|
|
|
** use the contact form at http://www.qt.io/contact-us.
|
2008-12-02 14:17:16 +01:00
|
|
|
**
|
2009-02-25 09:15:00 +01:00
|
|
|
** GNU Lesser General Public License Usage
|
2012-10-02 09:12:39 +02:00
|
|
|
** Alternatively, this file may be used under the terms of the GNU Lesser
|
2014-10-01 13:21:18 +02:00
|
|
|
** General Public License version 2.1 or version 3 as published by the Free
|
|
|
|
** Software Foundation and appearing in the file LICENSE.LGPLv21 and
|
|
|
|
** LICENSE.LGPLv3 included in the packaging of this file. Please review the
|
|
|
|
** following information to ensure the GNU Lesser General Public License
|
|
|
|
** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
|
|
|
|
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
2012-10-02 09:12:39 +02:00
|
|
|
**
|
2015-01-14 18:07:15 +01:00
|
|
|
** In addition, as a special exception, The Qt Company gives you certain additional
|
|
|
|
** rights. These rights are described in The Qt Company LGPL Exception
|
2010-12-17 16:01:08 +01:00
|
|
|
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
|
|
|
**
|
2012-10-02 09:12:39 +02:00
|
|
|
****************************************************************************/
|
2008-12-02 14:09:21 +01:00
|
|
|
|
2012-02-14 16:43:51 +01:00
|
|
|
#include "documentmanager.h"
|
2008-12-09 15:25:01 +01:00
|
|
|
|
2009-01-23 13:03:36 +01:00
|
|
|
#include "icore.h"
|
2012-02-14 16:43:51 +01:00
|
|
|
#include "idocument.h"
|
2010-09-07 11:55:52 +02:00
|
|
|
#include "coreconstants.h"
|
2008-12-02 12:01:29 +01:00
|
|
|
|
2013-08-29 16:36:42 +02:00
|
|
|
#include <coreplugin/dialogs/readonlyfilesdialog.h>
|
|
|
|
#include <coreplugin/dialogs/saveitemsdialog.h>
|
|
|
|
#include <coreplugin/editormanager/editormanager.h>
|
2014-07-18 17:11:57 +02:00
|
|
|
#include <coreplugin/editormanager/editormanager_p.h>
|
2014-07-02 16:53:17 +02:00
|
|
|
#include <coreplugin/editormanager/editorview.h>
|
2013-08-29 16:36:42 +02:00
|
|
|
#include <coreplugin/editormanager/ieditor.h>
|
|
|
|
#include <coreplugin/editormanager/ieditorfactory.h>
|
|
|
|
#include <coreplugin/editormanager/iexternaleditor.h>
|
2012-10-15 11:53:22 +02:00
|
|
|
|
2014-12-21 21:54:30 +02:00
|
|
|
#include <utils/fileutils.h>
|
2012-08-23 15:53:58 +02:00
|
|
|
#include <utils/hostosinfo.h>
|
2015-02-04 09:32:46 +01:00
|
|
|
#include <utils/mimetypes/mimedatabase.h>
|
2008-12-09 15:25:01 +01:00
|
|
|
#include <utils/qtcassert.h>
|
2009-11-26 18:03:16 +01:00
|
|
|
#include <utils/pathchooser.h>
|
2010-03-19 10:28:05 +01:00
|
|
|
#include <utils/reloadpromptutils.h>
|
2008-12-09 15:25:01 +01:00
|
|
|
|
2013-03-27 08:29:38 +01:00
|
|
|
#include <QStringList>
|
2012-02-15 10:42:41 +01:00
|
|
|
#include <QDateTime>
|
|
|
|
#include <QDir>
|
|
|
|
#include <QFile>
|
|
|
|
#include <QFileInfo>
|
|
|
|
#include <QFileSystemWatcher>
|
|
|
|
#include <QSettings>
|
|
|
|
#include <QTimer>
|
|
|
|
#include <QAction>
|
|
|
|
#include <QFileDialog>
|
|
|
|
#include <QMainWindow>
|
|
|
|
#include <QMenu>
|
|
|
|
#include <QMessageBox>
|
2008-12-02 12:01:29 +01:00
|
|
|
|
|
|
|
/*!
|
2012-02-14 16:43:51 +01:00
|
|
|
\class Core::DocumentManager
|
2008-12-02 12:01:29 +01:00
|
|
|
\mainclass
|
2012-02-14 16:43:51 +01:00
|
|
|
\inheaderfile documentmanager.h
|
2013-06-05 14:29:24 +02:00
|
|
|
\brief The DocumentManager class manages a set of IDocument objects.
|
2008-12-02 12:01:29 +01:00
|
|
|
|
2013-09-06 16:38:53 +02:00
|
|
|
The DocumentManager service monitors a set of IDocument objects. Plugins
|
|
|
|
should register files they work with at the service. The files the IDocument
|
|
|
|
objects point to will be monitored at filesystem level. If a file changes,
|
|
|
|
the status of the IDocument object
|
2008-12-02 12:01:29 +01:00
|
|
|
will be adjusted accordingly. Furthermore, on application exit the user will
|
|
|
|
be asked to save all modified files.
|
|
|
|
|
2012-02-14 16:43:51 +01:00
|
|
|
Different IDocument objects in the set can point to the same file in the
|
2013-09-06 16:38:53 +02:00
|
|
|
filesystem. The monitoring for an IDocument can be blocked by
|
|
|
|
\c blockFileChange(), and enabled again by \c unblockFileChange().
|
2008-12-02 12:01:29 +01:00
|
|
|
|
2013-09-06 16:38:53 +02:00
|
|
|
The functions \c expectFileChange() and \c unexpectFileChange() mark a file change
|
2012-02-14 16:43:51 +01:00
|
|
|
as expected. On expected file changes all IDocument objects are notified to reload
|
2010-01-22 16:49:57 +01:00
|
|
|
themselves.
|
|
|
|
|
2013-10-07 13:34:40 +02:00
|
|
|
The DocumentManager service also provides two convenience functions for saving
|
2013-09-06 16:38:53 +02:00
|
|
|
files: \c saveModifiedFiles() and \c saveModifiedFilesSilently(). Both take a list
|
2008-12-02 12:01:29 +01:00
|
|
|
of FileInterfaces as an argument, and return the list of files which were
|
|
|
|
_not_ saved.
|
|
|
|
|
2013-09-06 16:38:53 +02:00
|
|
|
The service also manages the list of recent files to be shown to the user.
|
|
|
|
|
|
|
|
\sa addToRecentFiles(), recentFiles()
|
2008-12-02 12:01:29 +01:00
|
|
|
*/
|
|
|
|
|
2011-05-10 15:19:38 +02:00
|
|
|
static const char settingsGroupC[] = "RecentFiles";
|
|
|
|
static const char filesKeyC[] = "Files";
|
|
|
|
static const char editorsKeyC[] = "EditorIds";
|
2009-11-26 18:03:16 +01:00
|
|
|
|
2011-05-10 15:19:38 +02:00
|
|
|
static const char directoryGroupC[] = "Directories";
|
|
|
|
static const char projectDirectoryKeyC[] = "Projects";
|
|
|
|
static const char useProjectDirectoryKeyC[] = "UseProjectsDirectory";
|
2012-12-05 14:50:08 +01:00
|
|
|
static const char buildDirectoryKeyC[] = "BuildDirectory.Template";
|
2011-12-09 10:45:17 +01:00
|
|
|
|
2015-02-11 08:44:31 +02:00
|
|
|
using namespace Utils;
|
|
|
|
|
2009-11-25 10:09:45 +01:00
|
|
|
namespace Core {
|
2012-01-19 23:23:43 +01:00
|
|
|
|
|
|
|
static void readSettings();
|
|
|
|
|
2014-01-21 13:25:19 +01:00
|
|
|
static bool saveModifiedFilesHelper(const QList<IDocument *> &documents,
|
|
|
|
const QString &message,
|
|
|
|
bool *cancelled, bool silently,
|
|
|
|
const QString &alwaysSaveMessage,
|
|
|
|
bool *alwaysSave, QList<IDocument *> *failedToSave);
|
2012-01-19 23:23:43 +01:00
|
|
|
|
2009-11-25 10:09:45 +01:00
|
|
|
namespace Internal {
|
|
|
|
|
2010-01-22 16:49:57 +01:00
|
|
|
struct FileStateItem
|
2009-11-25 10:09:45 +01:00
|
|
|
{
|
|
|
|
QDateTime modified;
|
|
|
|
QFile::Permissions permissions;
|
|
|
|
};
|
|
|
|
|
2010-01-22 16:49:57 +01:00
|
|
|
struct FileState
|
|
|
|
{
|
2012-02-14 16:43:51 +01:00
|
|
|
QMap<IDocument *, FileStateItem> lastUpdatedState;
|
2010-01-22 16:49:57 +01:00
|
|
|
FileStateItem expected;
|
|
|
|
};
|
|
|
|
|
2010-03-05 13:55:47 +01:00
|
|
|
|
2012-02-14 16:43:51 +01:00
|
|
|
struct DocumentManagerPrivate
|
2012-01-19 23:23:43 +01:00
|
|
|
{
|
2014-01-06 10:56:30 +01:00
|
|
|
DocumentManagerPrivate();
|
2011-04-28 13:13:51 +02:00
|
|
|
QFileSystemWatcher *fileWatcher();
|
|
|
|
QFileSystemWatcher *linkWatcher();
|
2009-11-25 10:09:45 +01:00
|
|
|
|
2010-03-05 13:55:47 +01:00
|
|
|
QMap<QString, FileState> m_states;
|
2011-04-15 15:06:00 +02:00
|
|
|
QSet<QString> m_changedFiles;
|
2012-02-14 16:43:51 +01:00
|
|
|
QList<IDocument *> m_documentsWithoutWatch;
|
|
|
|
QMap<IDocument *, QStringList> m_documentsWithWatch;
|
2010-12-13 17:35:40 +01:00
|
|
|
QSet<QString> m_expectedFileNames;
|
2009-11-25 10:09:45 +01:00
|
|
|
|
2012-02-14 16:43:51 +01:00
|
|
|
QList<DocumentManager::RecentFile> m_recentFiles;
|
2009-11-25 10:09:45 +01:00
|
|
|
static const int m_maxRecentFiles = 7;
|
|
|
|
|
2011-04-28 13:13:51 +02:00
|
|
|
QFileSystemWatcher *m_fileWatcher; // Delayed creation.
|
2011-04-14 16:57:40 +02:00
|
|
|
QFileSystemWatcher *m_linkWatcher; // Delayed creation (only UNIX/if a link is seen).
|
2009-11-25 10:09:45 +01:00
|
|
|
bool m_blockActivated;
|
2009-11-26 18:03:16 +01:00
|
|
|
QString m_lastVisitedDirectory;
|
2015-01-16 17:47:11 +01:00
|
|
|
QString m_defaultLocationForNewFiles;
|
2009-11-26 18:03:16 +01:00
|
|
|
QString m_projectsDirectory;
|
|
|
|
bool m_useProjectsDirectory;
|
2012-10-05 21:34:09 +10:00
|
|
|
QString m_buildDirectory;
|
2013-09-06 16:38:53 +02:00
|
|
|
// When we are calling into an IDocument
|
2010-05-11 14:13:38 +02:00
|
|
|
// we don't want to receive a changed()
|
|
|
|
// signal
|
|
|
|
// That makes the code easier
|
2012-02-14 16:43:51 +01:00
|
|
|
IDocument *m_blockedIDocument;
|
2009-11-25 10:09:45 +01:00
|
|
|
};
|
|
|
|
|
2012-02-14 16:43:51 +01:00
|
|
|
static DocumentManager *m_instance;
|
2015-02-03 23:48:19 +02:00
|
|
|
static DocumentManagerPrivate *d;
|
2012-01-19 23:23:43 +01:00
|
|
|
|
2012-02-14 16:43:51 +01:00
|
|
|
QFileSystemWatcher *DocumentManagerPrivate::fileWatcher()
|
2011-04-14 16:57:40 +02:00
|
|
|
{
|
|
|
|
if (!m_fileWatcher) {
|
2011-04-28 13:13:51 +02:00
|
|
|
m_fileWatcher= new QFileSystemWatcher(m_instance);
|
2011-04-14 16:57:40 +02:00
|
|
|
QObject::connect(m_fileWatcher, SIGNAL(fileChanged(QString)),
|
|
|
|
m_instance, SLOT(changedFile(QString)));
|
|
|
|
}
|
2011-04-28 13:13:51 +02:00
|
|
|
return m_fileWatcher;
|
2011-04-14 16:57:40 +02:00
|
|
|
}
|
|
|
|
|
2012-02-14 16:43:51 +01:00
|
|
|
QFileSystemWatcher *DocumentManagerPrivate::linkWatcher()
|
2011-04-14 16:57:40 +02:00
|
|
|
{
|
2015-02-11 08:44:31 +02:00
|
|
|
if (HostOsInfo::isAnyUnixHost()) {
|
2012-08-23 15:53:58 +02:00
|
|
|
if (!m_linkWatcher) {
|
|
|
|
m_linkWatcher = new QFileSystemWatcher(m_instance);
|
|
|
|
m_linkWatcher->setObjectName(QLatin1String("_qt_autotest_force_engine_poller"));
|
|
|
|
QObject::connect(m_linkWatcher, SIGNAL(fileChanged(QString)),
|
|
|
|
m_instance, SLOT(changedFile(QString)));
|
|
|
|
}
|
|
|
|
return m_linkWatcher;
|
2011-04-14 16:57:40 +02:00
|
|
|
}
|
2012-08-23 15:53:58 +02:00
|
|
|
|
2011-04-28 13:13:51 +02:00
|
|
|
return fileWatcher();
|
2011-04-14 16:57:40 +02:00
|
|
|
}
|
|
|
|
|
2014-01-06 10:56:30 +01:00
|
|
|
DocumentManagerPrivate::DocumentManagerPrivate() :
|
2011-04-14 16:57:40 +02:00
|
|
|
m_fileWatcher(0),
|
|
|
|
m_linkWatcher(0),
|
2009-11-26 18:03:16 +01:00
|
|
|
m_blockActivated(false),
|
|
|
|
m_lastVisitedDirectory(QDir::currentPath()),
|
2014-11-10 13:56:38 +01:00
|
|
|
m_useProjectsDirectory(true),
|
2012-02-14 16:43:51 +01:00
|
|
|
m_blockedIDocument(0)
|
2008-12-02 12:01:29 +01:00
|
|
|
{
|
2009-11-25 10:09:45 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
} // namespace Internal
|
2011-12-09 11:09:59 +01:00
|
|
|
} // namespace Core
|
|
|
|
|
|
|
|
namespace Core {
|
2009-11-25 10:09:45 +01:00
|
|
|
|
2012-01-19 23:23:43 +01:00
|
|
|
using namespace Internal;
|
|
|
|
|
2014-01-06 10:56:30 +01:00
|
|
|
DocumentManager::DocumentManager(QObject *parent)
|
|
|
|
: QObject(parent)
|
2009-11-25 10:09:45 +01:00
|
|
|
{
|
2014-01-06 10:56:30 +01:00
|
|
|
d = new DocumentManagerPrivate;
|
2012-01-19 23:23:43 +01:00
|
|
|
m_instance = this;
|
2013-06-10 15:28:26 +02:00
|
|
|
qApp->installEventFilter(this);
|
2008-12-02 12:01:29 +01:00
|
|
|
|
2010-10-19 11:07:20 +02:00
|
|
|
readSettings();
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
2012-02-14 16:43:51 +01:00
|
|
|
DocumentManager::~DocumentManager()
|
2009-11-25 10:09:45 +01:00
|
|
|
{
|
|
|
|
delete d;
|
|
|
|
}
|
|
|
|
|
2014-09-04 14:59:50 +02:00
|
|
|
DocumentManager *DocumentManager::instance()
|
2010-11-26 16:01:34 +01:00
|
|
|
{
|
2012-01-19 23:23:43 +01:00
|
|
|
return m_instance;
|
|
|
|
}
|
|
|
|
|
2012-02-14 16:43:51 +01:00
|
|
|
/* only called from addFileInfo(IDocument *) */
|
|
|
|
static void addFileInfo(const QString &fileName, IDocument *document, bool isLink)
|
2012-01-19 23:23:43 +01:00
|
|
|
{
|
|
|
|
FileStateItem state;
|
|
|
|
if (!fileName.isEmpty()) {
|
|
|
|
const QFileInfo fi(fileName);
|
|
|
|
state.modified = fi.lastModified();
|
|
|
|
state.permissions = fi.permissions();
|
|
|
|
// Add watcher if we don't have that already
|
Remove braces for single lines of conditions
#!/usr/bin/env ruby
Dir.glob('**/*.cpp') { |file|
# skip ast (excluding paste, astpath, and canv'ast'imer)
next if file =~ /ast[^eip]|keywords\.|qualifiers|preprocessor|names.cpp/i
s = File.read(file)
next if s.include?('qlalr')
orig = s.dup
s.gsub!(/\n *if [^\n]*{\n[^\n]*\n\s+}(\s+else if [^\n]* {\n[^\n]*\n\s+})*(\s+else {\n[^\n]*\n\s+})?\n/m) { |m|
res = $&
if res =~ /^\s*(\/\/|[A-Z_]{3,})/ # C++ comment or macro (Q_UNUSED, SDEBUG), do not touch braces
res
else
res.gsub!('} else', 'else')
res.gsub!(/\n +} *\n/m, "\n")
res.gsub(/ *{$/, '')
end
}
s.gsub!(/ *$/, '')
File.open(file, 'wb').write(s) if s != orig
}
Change-Id: I3b30ee60df0986f66c02132c65fc38a3fbb6bbdc
Reviewed-by: hjk <qthjk@ovi.com>
2013-01-08 03:32:53 +02:00
|
|
|
if (!d->m_states.contains(fileName))
|
2012-01-19 23:23:43 +01:00
|
|
|
d->m_states.insert(fileName, FileState());
|
|
|
|
|
|
|
|
QFileSystemWatcher *watcher = 0;
|
|
|
|
if (isLink)
|
|
|
|
watcher = d->linkWatcher();
|
|
|
|
else
|
|
|
|
watcher = d->fileWatcher();
|
2015-07-06 11:27:34 +02:00
|
|
|
if (!watcher->files().contains(fileName))
|
|
|
|
watcher->addPath(fileName);
|
2012-01-19 23:23:43 +01:00
|
|
|
|
2012-02-14 16:43:51 +01:00
|
|
|
d->m_states[fileName].lastUpdatedState.insert(document, state);
|
2012-01-19 23:23:43 +01:00
|
|
|
}
|
2012-02-14 16:43:51 +01:00
|
|
|
d->m_documentsWithWatch[document].append(fileName); // inserts a new QStringList if not already there
|
2012-01-19 23:23:43 +01:00
|
|
|
}
|
|
|
|
|
2012-02-14 16:43:51 +01:00
|
|
|
/* Adds the IDocument's file and possibly it's final link target to both m_states
|
2012-01-19 23:23:43 +01:00
|
|
|
(if it's file name is not empty), and the m_filesWithWatch list,
|
|
|
|
and adds a file watcher for each if not already done.
|
|
|
|
(The added file names are guaranteed to be absolute and cleaned.) */
|
2012-02-14 16:43:51 +01:00
|
|
|
static void addFileInfo(IDocument *document)
|
2012-01-19 23:23:43 +01:00
|
|
|
{
|
2014-12-21 21:54:30 +02:00
|
|
|
const QString fixedName = DocumentManager::fixFileName(document->filePath().toString(), DocumentManager::KeepLinks);
|
|
|
|
const QString fixedResolvedName = DocumentManager::fixFileName(document->filePath().toString(), DocumentManager::ResolveLinks);
|
2012-02-14 16:43:51 +01:00
|
|
|
addFileInfo(fixedResolvedName, document, false);
|
2012-01-19 23:23:43 +01:00
|
|
|
if (fixedName != fixedResolvedName)
|
2012-02-14 16:43:51 +01:00
|
|
|
addFileInfo(fixedName, document, true);
|
2010-11-26 16:01:34 +01:00
|
|
|
}
|
|
|
|
|
2008-12-02 12:01:29 +01:00
|
|
|
/*!
|
2012-02-14 16:43:51 +01:00
|
|
|
Adds a list of IDocument's to the collection. If \a addWatcher is true (the default),
|
2010-07-12 16:53:07 +02:00
|
|
|
the files are added to a file system watcher that notifies the file manager
|
|
|
|
about file changes.
|
2008-12-02 12:01:29 +01:00
|
|
|
*/
|
2012-02-14 16:43:51 +01:00
|
|
|
void DocumentManager::addDocuments(const QList<IDocument *> &documents, bool addWatcher)
|
2008-12-02 12:01:29 +01:00
|
|
|
{
|
2010-03-05 13:55:47 +01:00
|
|
|
if (!addWatcher) {
|
|
|
|
// We keep those in a separate list
|
|
|
|
|
2012-02-14 16:43:51 +01:00
|
|
|
foreach (IDocument *document, documents) {
|
|
|
|
if (document && !d->m_documentsWithoutWatch.contains(document)) {
|
2012-03-05 22:30:59 +01:00
|
|
|
connect(document, SIGNAL(destroyed(QObject*)), m_instance, SLOT(documentDestroyed(QObject*)));
|
2014-12-21 21:54:30 +02:00
|
|
|
connect(document, &IDocument::filePathChanged,
|
|
|
|
m_instance, &DocumentManager::filePathChanged);
|
2012-02-14 16:43:51 +01:00
|
|
|
d->m_documentsWithoutWatch.append(document);
|
2010-11-23 12:47:45 +01:00
|
|
|
}
|
|
|
|
}
|
2010-11-18 18:11:15 +01:00
|
|
|
return;
|
2010-03-05 13:55:47 +01:00
|
|
|
}
|
|
|
|
|
2012-02-14 16:43:51 +01:00
|
|
|
foreach (IDocument *document, documents) {
|
|
|
|
if (document && !d->m_documentsWithWatch.contains(document)) {
|
|
|
|
connect(document, SIGNAL(changed()), m_instance, SLOT(checkForNewFileName()));
|
2012-03-05 22:30:59 +01:00
|
|
|
connect(document, SIGNAL(destroyed(QObject*)), m_instance, SLOT(documentDestroyed(QObject*)));
|
2014-12-21 21:54:30 +02:00
|
|
|
connect(document, &IDocument::filePathChanged, m_instance, &DocumentManager::filePathChanged);
|
2012-02-14 16:43:51 +01:00
|
|
|
addFileInfo(document);
|
2010-11-23 12:47:45 +01:00
|
|
|
}
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-01-22 16:49:57 +01:00
|
|
|
|
2012-02-14 16:43:51 +01:00
|
|
|
/* Removes all occurrences of the IDocument from m_filesWithWatch and m_states.
|
|
|
|
If that results in a file no longer being referenced by any IDocument, this
|
2012-01-19 23:23:43 +01:00
|
|
|
also removes the file watcher.
|
|
|
|
*/
|
2012-02-14 16:43:51 +01:00
|
|
|
static void removeFileInfo(IDocument *document)
|
2010-11-23 12:47:45 +01:00
|
|
|
{
|
2012-02-14 16:43:51 +01:00
|
|
|
if (!d->m_documentsWithWatch.contains(document))
|
2012-01-19 23:23:43 +01:00
|
|
|
return;
|
2012-02-14 16:43:51 +01:00
|
|
|
foreach (const QString &fileName, d->m_documentsWithWatch.value(document)) {
|
2012-01-19 23:23:43 +01:00
|
|
|
if (!d->m_states.contains(fileName))
|
|
|
|
continue;
|
2012-02-14 16:43:51 +01:00
|
|
|
d->m_states[fileName].lastUpdatedState.remove(document);
|
2012-01-19 23:23:43 +01:00
|
|
|
if (d->m_states.value(fileName).lastUpdatedState.isEmpty()) {
|
|
|
|
if (d->m_fileWatcher && d->m_fileWatcher->files().contains(fileName))
|
|
|
|
d->m_fileWatcher->removePath(fileName);
|
|
|
|
if (d->m_linkWatcher && d->m_linkWatcher->files().contains(fileName))
|
|
|
|
d->m_linkWatcher->removePath(fileName);
|
|
|
|
d->m_states.remove(fileName);
|
2010-03-19 10:28:05 +01:00
|
|
|
}
|
2010-01-22 16:49:57 +01:00
|
|
|
}
|
2012-02-14 16:43:51 +01:00
|
|
|
d->m_documentsWithWatch.remove(document);
|
2010-01-22 16:49:57 +01:00
|
|
|
}
|
|
|
|
|
2010-05-11 14:13:38 +02:00
|
|
|
/// Dumps the state of the file manager's map
|
|
|
|
/// For debugging purposes
|
2012-01-19 23:23:43 +01:00
|
|
|
/*
|
|
|
|
static void dump()
|
2010-05-11 14:13:38 +02:00
|
|
|
{
|
2010-11-23 12:47:45 +01:00
|
|
|
qDebug() << "======== dumping state map";
|
2012-01-19 23:23:43 +01:00
|
|
|
QMap<QString, FileState>::const_iterator it, end;
|
2010-05-11 14:13:38 +02:00
|
|
|
it = d->m_states.constBegin();
|
|
|
|
end = d->m_states.constEnd();
|
|
|
|
for (; it != end; ++it) {
|
|
|
|
qDebug() << it.key();
|
2010-11-23 12:47:45 +01:00
|
|
|
qDebug() << " expected:" << it.value().expected.modified;
|
2010-05-11 14:13:38 +02:00
|
|
|
|
2012-02-14 16:43:51 +01:00
|
|
|
QMap<IDocument *, FileStateItem>::const_iterator jt, jend;
|
2010-05-11 14:13:38 +02:00
|
|
|
jt = it.value().lastUpdatedState.constBegin();
|
|
|
|
jend = it.value().lastUpdatedState.constEnd();
|
|
|
|
for (; jt != jend; ++jt) {
|
2010-11-23 12:47:45 +01:00
|
|
|
qDebug() << " " << jt.key()->fileName() << jt.value().modified;
|
2010-05-11 14:13:38 +02:00
|
|
|
}
|
|
|
|
}
|
2010-11-23 12:47:45 +01:00
|
|
|
qDebug() << "------- dumping files with watch list";
|
2012-02-14 16:43:51 +01:00
|
|
|
foreach (IDocument *key, d->m_filesWithWatch.keys()) {
|
2010-11-23 12:47:45 +01:00
|
|
|
qDebug() << key->fileName() << d->m_filesWithWatch.value(key);
|
|
|
|
}
|
|
|
|
qDebug() << "------- dumping watch list";
|
2011-04-14 16:57:40 +02:00
|
|
|
if (d->m_fileWatcher)
|
|
|
|
qDebug() << d->m_fileWatcher->files();
|
2010-11-23 12:47:45 +01:00
|
|
|
qDebug() << "------- dumping link watch list";
|
2011-04-14 16:57:40 +02:00
|
|
|
if (d->m_linkWatcher)
|
|
|
|
qDebug() << d->m_linkWatcher->files();
|
2010-05-11 14:13:38 +02:00
|
|
|
}
|
2012-01-19 23:23:43 +01:00
|
|
|
*/
|
2010-05-11 14:13:38 +02:00
|
|
|
|
2010-11-23 12:47:45 +01:00
|
|
|
/*!
|
2013-09-06 16:38:53 +02:00
|
|
|
Tells the file manager that a file has been renamed on disk from within \QC.
|
2010-11-23 12:47:45 +01:00
|
|
|
|
2013-09-06 16:38:53 +02:00
|
|
|
Needs to be called right after the actual renaming on disk (that is, before
|
|
|
|
the file system
|
2010-11-23 12:47:45 +01:00
|
|
|
watcher can report the event during the next event loop run). \a from needs to be an absolute file path.
|
2012-02-14 16:43:51 +01:00
|
|
|
This will notify all IDocument objects pointing to that file of the rename
|
2013-09-06 16:38:53 +02:00
|
|
|
by calling \c IDocument::rename(), and update the cached time and permission
|
2010-11-23 12:47:45 +01:00
|
|
|
information to avoid annoying the user with "file has been removed"
|
|
|
|
popups.
|
|
|
|
*/
|
2012-02-14 16:43:51 +01:00
|
|
|
void DocumentManager::renamedFile(const QString &from, const QString &to)
|
2010-05-11 14:13:38 +02:00
|
|
|
{
|
2010-11-23 12:47:45 +01:00
|
|
|
const QString &fixedFrom = fixFileName(from, KeepLinks);
|
2010-05-11 14:13:38 +02:00
|
|
|
|
2012-02-14 16:43:51 +01:00
|
|
|
// gather the list of IDocuments
|
|
|
|
QList<IDocument *> documentsToRename;
|
|
|
|
QMapIterator<IDocument *, QStringList> it(d->m_documentsWithWatch);
|
2010-11-23 12:47:45 +01:00
|
|
|
while (it.hasNext()) {
|
|
|
|
it.next();
|
|
|
|
if (it.value().contains(fixedFrom))
|
2012-02-14 16:43:51 +01:00
|
|
|
documentsToRename.append(it.key());
|
2010-01-22 16:49:57 +01:00
|
|
|
}
|
|
|
|
|
2012-02-14 16:43:51 +01:00
|
|
|
// rename the IDocuments
|
|
|
|
foreach (IDocument *document, documentsToRename) {
|
|
|
|
d->m_blockedIDocument = document;
|
|
|
|
removeFileInfo(document);
|
2015-02-11 08:44:31 +02:00
|
|
|
document->setFilePath(FileName::fromString(to));
|
2012-02-14 16:43:51 +01:00
|
|
|
addFileInfo(document);
|
|
|
|
d->m_blockedIDocument = 0;
|
2010-11-23 12:47:45 +01:00
|
|
|
}
|
2012-03-12 16:56:25 +01:00
|
|
|
emit m_instance->allDocumentsRenamed(from, to);
|
2010-01-22 16:49:57 +01:00
|
|
|
}
|
2012-03-12 16:56:25 +01:00
|
|
|
|
2015-02-11 08:44:31 +02:00
|
|
|
void DocumentManager::filePathChanged(const FileName &oldName, const FileName &newName)
|
2012-03-12 16:56:25 +01:00
|
|
|
{
|
|
|
|
IDocument *doc = qobject_cast<IDocument *>(sender());
|
|
|
|
QTC_ASSERT(doc, return);
|
|
|
|
if (doc == d->m_blockedIDocument)
|
|
|
|
return;
|
2014-12-21 21:54:30 +02:00
|
|
|
emit m_instance->documentRenamed(doc, oldName.toString(), newName.toString());
|
2012-03-12 16:56:25 +01:00
|
|
|
}
|
|
|
|
|
2008-12-02 12:01:29 +01:00
|
|
|
/*!
|
2013-09-06 16:38:53 +02:00
|
|
|
Adds an IDocument object to the collection. If \a addWatcher is \c true
|
|
|
|
(the default),
|
2010-07-12 16:53:07 +02:00
|
|
|
the file is added to a file system watcher that notifies the file manager
|
|
|
|
about file changes.
|
2008-12-02 12:01:29 +01:00
|
|
|
*/
|
2012-02-14 16:43:51 +01:00
|
|
|
void DocumentManager::addDocument(IDocument *document, bool addWatcher)
|
2008-12-02 12:01:29 +01:00
|
|
|
{
|
2012-02-14 16:43:51 +01:00
|
|
|
addDocuments(QList<IDocument *>() << document, addWatcher);
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
2012-02-14 16:43:51 +01:00
|
|
|
void DocumentManager::documentDestroyed(QObject *obj)
|
2008-12-02 12:01:29 +01:00
|
|
|
{
|
2012-02-14 16:43:51 +01:00
|
|
|
IDocument *document = static_cast<IDocument*>(obj);
|
2010-03-05 13:55:47 +01:00
|
|
|
// Check the special unwatched first:
|
2012-02-14 16:43:51 +01:00
|
|
|
if (!d->m_documentsWithoutWatch.removeOne(document))
|
|
|
|
removeFileInfo(document);
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
2013-09-06 16:38:53 +02:00
|
|
|
Removes an IDocument object from the collection.
|
2008-12-02 12:01:29 +01:00
|
|
|
|
2013-09-06 16:38:53 +02:00
|
|
|
Returns \c true if the file specified by \a document had the \a addWatcher
|
|
|
|
argument to \a addDocument() set.
|
2008-12-02 12:01:29 +01:00
|
|
|
*/
|
2012-02-14 16:43:51 +01:00
|
|
|
bool DocumentManager::removeDocument(IDocument *document)
|
2008-12-02 12:01:29 +01:00
|
|
|
{
|
2012-02-14 16:43:51 +01:00
|
|
|
QTC_ASSERT(document, return false);
|
2008-12-02 12:01:29 +01:00
|
|
|
|
2011-04-15 21:23:21 +02:00
|
|
|
bool addWatcher = false;
|
2010-03-05 13:55:47 +01:00
|
|
|
// Special casing unwatched files
|
2012-02-14 16:43:51 +01:00
|
|
|
if (!d->m_documentsWithoutWatch.removeOne(document)) {
|
2011-04-15 21:23:21 +02:00
|
|
|
addWatcher = true;
|
2012-02-14 16:43:51 +01:00
|
|
|
removeFileInfo(document);
|
|
|
|
disconnect(document, SIGNAL(changed()), m_instance, SLOT(checkForNewFileName()));
|
2010-03-05 13:55:47 +01:00
|
|
|
}
|
2012-03-05 22:30:59 +01:00
|
|
|
disconnect(document, SIGNAL(destroyed(QObject*)), m_instance, SLOT(documentDestroyed(QObject*)));
|
2011-04-15 21:23:21 +02:00
|
|
|
return addWatcher;
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
2012-02-14 16:43:51 +01:00
|
|
|
/* Slot reacting on IDocument::changed. We need to check if the signal was sent
|
2010-11-23 12:47:45 +01:00
|
|
|
because the file was saved under different name. */
|
2012-02-14 16:43:51 +01:00
|
|
|
void DocumentManager::checkForNewFileName()
|
2008-12-02 12:01:29 +01:00
|
|
|
{
|
2012-02-14 16:43:51 +01:00
|
|
|
IDocument *document = qobject_cast<IDocument *>(sender());
|
|
|
|
// We modified the IDocument
|
2010-05-11 14:13:38 +02:00
|
|
|
// Trust the other code to also update the m_states map
|
2012-02-14 16:43:51 +01:00
|
|
|
if (document == d->m_blockedIDocument)
|
2010-05-11 14:13:38 +02:00
|
|
|
return;
|
2012-02-14 16:43:51 +01:00
|
|
|
QTC_ASSERT(document, return);
|
|
|
|
QTC_ASSERT(d->m_documentsWithWatch.contains(document), return);
|
2010-01-22 16:49:57 +01:00
|
|
|
|
2010-11-23 12:47:45 +01:00
|
|
|
// Maybe the name has changed or file has been deleted and created again ...
|
2010-01-22 16:49:57 +01:00
|
|
|
// This also updates the state to the on disk state
|
2012-02-14 16:43:51 +01:00
|
|
|
removeFileInfo(document);
|
|
|
|
addFileInfo(document);
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
2010-11-23 12:47:45 +01:00
|
|
|
/*!
|
|
|
|
Returns a guaranteed cleaned path in native form. If the file exists,
|
|
|
|
it will either be a cleaned absolute file path (fixmode == KeepLinks), or
|
|
|
|
a cleaned canonical file path (fixmode == ResolveLinks).
|
|
|
|
*/
|
2012-02-14 16:43:51 +01:00
|
|
|
QString DocumentManager::fixFileName(const QString &fileName, FixMode fixmode)
|
2008-12-02 12:01:29 +01:00
|
|
|
{
|
|
|
|
QString s = fileName;
|
2010-03-23 16:33:21 +01:00
|
|
|
QFileInfo fi(s);
|
2010-11-23 12:47:45 +01:00
|
|
|
if (fi.exists()) {
|
|
|
|
if (fixmode == ResolveLinks)
|
|
|
|
s = fi.canonicalFilePath();
|
|
|
|
else
|
|
|
|
s = QDir::cleanPath(fi.absoluteFilePath());
|
|
|
|
} else {
|
|
|
|
s = QDir::cleanPath(s);
|
|
|
|
}
|
|
|
|
s = QDir::toNativeSeparators(s);
|
2015-02-11 08:44:31 +02:00
|
|
|
if (HostOsInfo::fileNameCaseSensitivity() == Qt::CaseInsensitive)
|
2012-08-23 15:53:58 +02:00
|
|
|
s = s.toLower();
|
2010-03-23 16:33:21 +01:00
|
|
|
return s;
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
2013-09-06 16:38:53 +02:00
|
|
|
Returns the list of IDocuments that have been modified.
|
2008-12-02 12:01:29 +01:00
|
|
|
*/
|
2012-02-14 16:43:51 +01:00
|
|
|
QList<IDocument *> DocumentManager::modifiedDocuments()
|
2008-12-02 12:01:29 +01:00
|
|
|
{
|
2012-02-14 16:43:51 +01:00
|
|
|
QList<IDocument *> modified;
|
2008-12-02 12:01:29 +01:00
|
|
|
|
2012-02-14 16:43:51 +01:00
|
|
|
foreach (IDocument *document, d->m_documentsWithWatch.keys()) {
|
|
|
|
if (document->isModified())
|
|
|
|
modified << document;
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
2010-11-23 12:47:45 +01:00
|
|
|
|
2012-02-14 16:43:51 +01:00
|
|
|
foreach (IDocument *document, d->m_documentsWithoutWatch) {
|
|
|
|
if (document->isModified())
|
|
|
|
modified << document;
|
2010-03-05 13:55:47 +01:00
|
|
|
}
|
|
|
|
|
2012-02-14 16:43:51 +01:00
|
|
|
return modified;
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
2010-01-22 16:49:57 +01:00
|
|
|
/*!
|
2013-09-06 16:38:53 +02:00
|
|
|
Any subsequent change to \a fileName is treated as an expected file change.
|
2010-01-22 16:49:57 +01:00
|
|
|
|
2012-02-14 16:43:51 +01:00
|
|
|
\see DocumentManager::unexpectFileChange(const QString &fileName)
|
2010-01-22 16:49:57 +01:00
|
|
|
*/
|
2012-02-14 16:43:51 +01:00
|
|
|
void DocumentManager::expectFileChange(const QString &fileName)
|
2008-12-02 12:01:29 +01:00
|
|
|
{
|
2010-12-13 17:35:40 +01:00
|
|
|
if (fileName.isEmpty())
|
|
|
|
return;
|
|
|
|
d->m_expectedFileNames.insert(fileName);
|
2010-01-22 16:49:57 +01:00
|
|
|
}
|
|
|
|
|
2013-10-07 13:34:40 +02:00
|
|
|
/* only called from unblock and unexpect file change functions */
|
2012-01-19 23:23:43 +01:00
|
|
|
static void updateExpectedState(const QString &fileName)
|
|
|
|
{
|
|
|
|
if (fileName.isEmpty())
|
|
|
|
return;
|
|
|
|
if (d->m_states.contains(fileName)) {
|
|
|
|
QFileInfo fi(fileName);
|
|
|
|
d->m_states[fileName].expected.modified = fi.lastModified();
|
|
|
|
d->m_states[fileName].expected.permissions = fi.permissions();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-01-22 16:49:57 +01:00
|
|
|
/*!
|
2013-09-06 16:38:53 +02:00
|
|
|
Any changes to \a fileName are unexpected again.
|
2010-01-22 16:49:57 +01:00
|
|
|
|
2012-02-14 16:43:51 +01:00
|
|
|
\see DocumentManager::expectFileChange(const QString &fileName)
|
2010-01-22 16:49:57 +01:00
|
|
|
*/
|
2012-02-14 16:43:51 +01:00
|
|
|
void DocumentManager::unexpectFileChange(const QString &fileName)
|
2010-01-22 16:49:57 +01:00
|
|
|
{
|
|
|
|
// We are updating the expected time of the file
|
|
|
|
// And in changedFile we'll check if the modification time
|
|
|
|
// is the same as the saved one here
|
|
|
|
// If so then it's a expected change
|
|
|
|
|
2010-11-23 12:47:45 +01:00
|
|
|
if (fileName.isEmpty())
|
|
|
|
return;
|
2010-12-13 17:35:40 +01:00
|
|
|
d->m_expectedFileNames.remove(fileName);
|
2010-11-23 12:47:45 +01:00
|
|
|
const QString fixedName = fixFileName(fileName, KeepLinks);
|
|
|
|
updateExpectedState(fixedName);
|
|
|
|
const QString fixedResolvedName = fixFileName(fileName, ResolveLinks);
|
|
|
|
if (fixedName != fixedResolvedName)
|
|
|
|
updateExpectedState(fixedResolvedName);
|
2010-01-22 16:49:57 +01:00
|
|
|
}
|
|
|
|
|
2014-01-21 13:25:19 +01:00
|
|
|
static bool saveModifiedFilesHelper(const QList<IDocument *> &documents,
|
|
|
|
const QString &message, bool *cancelled, bool silently,
|
|
|
|
const QString &alwaysSaveMessage, bool *alwaysSave,
|
|
|
|
QList<IDocument *> *failedToSave)
|
2008-12-02 12:01:29 +01:00
|
|
|
{
|
|
|
|
if (cancelled)
|
|
|
|
(*cancelled) = false;
|
|
|
|
|
2012-02-14 16:43:51 +01:00
|
|
|
QList<IDocument *> notSaved;
|
|
|
|
QMap<IDocument *, QString> modifiedDocumentsMap;
|
|
|
|
QList<IDocument *> modifiedDocuments;
|
2008-12-02 12:01:29 +01:00
|
|
|
|
2012-02-14 16:43:51 +01:00
|
|
|
foreach (IDocument *document, documents) {
|
2014-01-21 13:13:44 +01:00
|
|
|
if (document && document->isModified()) {
|
2014-12-21 21:54:30 +02:00
|
|
|
QString name = document->filePath().toString();
|
2008-12-02 12:01:29 +01:00
|
|
|
if (name.isEmpty())
|
2012-02-14 16:43:51 +01:00
|
|
|
name = document->suggestedFileName();
|
2008-12-02 12:01:29 +01:00
|
|
|
|
2012-02-14 16:43:51 +01:00
|
|
|
// There can be several IDocuments pointing to the same file
|
2012-02-14 12:10:29 +01:00
|
|
|
// Prefer one that is not readonly
|
2012-02-14 16:43:51 +01:00
|
|
|
// (even though it *should* not happen that the IDocuments are inconsistent with readonly)
|
|
|
|
if (!modifiedDocumentsMap.key(name, 0) || !document->isFileReadOnly())
|
|
|
|
modifiedDocumentsMap.insert(document, name);
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
}
|
2012-02-14 16:43:51 +01:00
|
|
|
modifiedDocuments = modifiedDocumentsMap.keys();
|
|
|
|
if (!modifiedDocuments.isEmpty()) {
|
|
|
|
QList<IDocument *> documentsToSave;
|
2008-12-02 12:01:29 +01:00
|
|
|
if (silently) {
|
2012-02-14 16:43:51 +01:00
|
|
|
documentsToSave = modifiedDocuments;
|
2008-12-02 12:01:29 +01:00
|
|
|
} else {
|
2014-01-06 10:56:30 +01:00
|
|
|
SaveItemsDialog dia(ICore::dialogParent(), modifiedDocuments);
|
2008-12-02 12:01:29 +01:00
|
|
|
if (!message.isEmpty())
|
|
|
|
dia.setMessage(message);
|
2009-05-06 11:55:21 +02:00
|
|
|
if (!alwaysSaveMessage.isNull())
|
|
|
|
dia.setAlwaysSaveMessage(alwaysSaveMessage);
|
2008-12-02 12:01:29 +01:00
|
|
|
if (dia.exec() != QDialog::Accepted) {
|
|
|
|
if (cancelled)
|
|
|
|
(*cancelled) = true;
|
2009-05-06 11:55:21 +02:00
|
|
|
if (alwaysSave)
|
2014-01-21 13:25:19 +01:00
|
|
|
(*alwaysSave) = dia.alwaysSaveChecked();
|
|
|
|
if (failedToSave)
|
|
|
|
(*failedToSave) = modifiedDocuments;
|
|
|
|
return false;
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
2009-05-06 11:55:21 +02:00
|
|
|
if (alwaysSave)
|
|
|
|
*alwaysSave = dia.alwaysSaveChecked();
|
2012-02-14 16:43:51 +01:00
|
|
|
documentsToSave = dia.itemsToSave();
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
2012-10-15 11:53:22 +02:00
|
|
|
// Check for files without write permissions.
|
|
|
|
QList<IDocument *> roDocuments;
|
|
|
|
foreach (IDocument *document, documentsToSave) {
|
|
|
|
if (document->isFileReadOnly())
|
|
|
|
roDocuments << document;
|
|
|
|
}
|
|
|
|
if (!roDocuments.isEmpty()) {
|
2014-01-06 10:56:30 +01:00
|
|
|
ReadOnlyFilesDialog roDialog(roDocuments, ICore::dialogParent());
|
2013-04-15 13:43:16 +02:00
|
|
|
roDialog.setShowFailWarning(true, DocumentManager::tr(
|
2012-10-15 11:53:22 +02:00
|
|
|
"Could not save the files.",
|
|
|
|
"error message"));
|
2014-09-20 21:52:56 +02:00
|
|
|
if (roDialog.exec() == ReadOnlyFilesDialog::RO_Cancel) {
|
2012-10-15 11:53:22 +02:00
|
|
|
if (cancelled)
|
|
|
|
(*cancelled) = true;
|
2014-01-21 13:25:19 +01:00
|
|
|
if (failedToSave)
|
|
|
|
(*failedToSave) = modifiedDocuments;
|
|
|
|
return false;
|
2012-10-15 11:53:22 +02:00
|
|
|
}
|
|
|
|
}
|
2012-02-14 16:43:51 +01:00
|
|
|
foreach (IDocument *document, documentsToSave) {
|
2014-07-18 17:11:57 +02:00
|
|
|
if (!EditorManagerPrivate::saveDocument(document)) {
|
2010-12-01 13:10:08 +01:00
|
|
|
if (cancelled)
|
|
|
|
*cancelled = true;
|
2012-02-14 16:43:51 +01:00
|
|
|
notSaved.append(document);
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2014-01-21 13:25:19 +01:00
|
|
|
if (failedToSave)
|
|
|
|
(*failedToSave) = notSaved;
|
|
|
|
return notSaved.isEmpty();
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
2012-02-14 16:43:51 +01:00
|
|
|
bool DocumentManager::saveDocument(IDocument *document, const QString &fileName, bool *isReadOnly)
|
2011-03-30 12:38:12 +02:00
|
|
|
{
|
2011-04-15 21:23:21 +02:00
|
|
|
bool ret = true;
|
2014-12-21 21:54:30 +02:00
|
|
|
QString effName = fileName.isEmpty() ? document->filePath().toString() : fileName;
|
2012-02-14 16:43:51 +01:00
|
|
|
expectFileChange(effName); // This only matters to other IDocuments which refer to this file
|
|
|
|
bool addWatcher = removeDocument(document); // So that our own IDocument gets no notification at all
|
2011-04-15 21:23:21 +02:00
|
|
|
|
2011-03-30 13:45:16 +02:00
|
|
|
QString errorString;
|
2012-02-14 16:43:51 +01:00
|
|
|
if (!document->save(&errorString, fileName, false)) {
|
2011-03-30 13:45:16 +02:00
|
|
|
if (isReadOnly) {
|
|
|
|
QFile ofi(effName);
|
|
|
|
// Check whether the existing file is writable
|
2011-08-01 14:58:33 +02:00
|
|
|
if (!ofi.open(QIODevice::ReadWrite) && ofi.open(QIODevice::ReadOnly)) {
|
2011-03-30 13:45:16 +02:00
|
|
|
*isReadOnly = true;
|
2011-04-15 21:23:21 +02:00
|
|
|
goto out;
|
2011-03-30 13:45:16 +02:00
|
|
|
}
|
|
|
|
*isReadOnly = false;
|
|
|
|
}
|
2014-01-06 10:56:30 +01:00
|
|
|
QMessageBox::critical(ICore::dialogParent(), tr("File Error"),
|
2012-03-08 08:42:29 +01:00
|
|
|
tr("Error while saving file: %1").arg(errorString));
|
2011-04-15 21:23:21 +02:00
|
|
|
out:
|
|
|
|
ret = false;
|
2011-03-30 13:45:16 +02:00
|
|
|
}
|
2011-03-30 12:38:12 +02:00
|
|
|
|
2012-02-14 16:43:51 +01:00
|
|
|
addDocument(document, addWatcher);
|
2011-04-15 21:23:21 +02:00
|
|
|
unexpectFileChange(effName);
|
|
|
|
return ret;
|
2011-03-30 12:38:12 +02:00
|
|
|
}
|
|
|
|
|
2012-02-14 16:43:51 +01:00
|
|
|
QString DocumentManager::getSaveFileName(const QString &title, const QString &pathIn,
|
2010-09-07 11:55:52 +02:00
|
|
|
const QString &filter, QString *selectedFilter)
|
2008-12-02 12:01:29 +01:00
|
|
|
{
|
2010-09-07 11:55:52 +02:00
|
|
|
const QString &path = pathIn.isEmpty() ? fileDialogInitialDirectory() : pathIn;
|
2008-12-02 12:01:29 +01:00
|
|
|
QString fileName;
|
|
|
|
bool repeat;
|
|
|
|
do {
|
|
|
|
repeat = false;
|
2010-09-07 11:55:52 +02:00
|
|
|
fileName = QFileDialog::getSaveFileName(
|
2014-01-06 10:56:30 +01:00
|
|
|
ICore::dialogParent(), title, path, filter, selectedFilter, QFileDialog::DontConfirmOverwrite);
|
2010-09-07 11:55:52 +02:00
|
|
|
if (!fileName.isEmpty()) {
|
|
|
|
// 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)
|
2011-12-22 14:44:14 +01:00
|
|
|
QRegExp regExp(QLatin1String(".*\\s+\\((.*)\\)$"));
|
2010-09-07 11:55:52 +02:00
|
|
|
const int index = regExp.lastIndexIn(*selectedFilter);
|
|
|
|
if (index != -1) {
|
2014-08-04 14:02:17 +02:00
|
|
|
bool suffixOk = false;
|
2011-12-22 14:44:14 +01:00
|
|
|
const QStringList &suffixes = regExp.cap(1).remove(QLatin1Char('*')).split(QLatin1Char(' '));
|
2010-09-07 11:55:52 +02:00
|
|
|
foreach (const QString &suffix, suffixes)
|
|
|
|
if (fileName.endsWith(suffix)) {
|
|
|
|
suffixOk = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (!suffixOk && !suffixes.isEmpty())
|
|
|
|
fileName.append(suffixes.at(0));
|
|
|
|
}
|
|
|
|
}
|
2008-12-02 12:01:29 +01:00
|
|
|
if (QFile::exists(fileName)) {
|
2014-01-06 10:56:30 +01:00
|
|
|
if (QMessageBox::warning(ICore::dialogParent(), tr("Overwrite?"),
|
2014-04-17 14:09:47 +02:00
|
|
|
tr("An item named \"%1\" already exists at this location. "
|
2010-09-07 11:55:52 +02:00
|
|
|
"Do you want to overwrite it?").arg(fileName),
|
|
|
|
QMessageBox::Yes | QMessageBox::No) == QMessageBox::No) {
|
2008-12-02 12:01:29 +01:00
|
|
|
repeat = true;
|
2010-09-07 11:55:52 +02:00
|
|
|
}
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
} while (repeat);
|
2009-11-26 18:03:16 +01:00
|
|
|
if (!fileName.isEmpty())
|
|
|
|
setFileDialogLastVisitedDirectory(QFileInfo(fileName).absolutePath());
|
2008-12-02 12:01:29 +01:00
|
|
|
return fileName;
|
|
|
|
}
|
|
|
|
|
2012-02-14 16:43:51 +01:00
|
|
|
QString DocumentManager::getSaveFileNameWithExtension(const QString &title, const QString &pathIn,
|
2010-09-07 11:55:52 +02:00
|
|
|
const QString &filter)
|
|
|
|
{
|
|
|
|
QString selected = filter;
|
|
|
|
return getSaveFileName(title, pathIn, filter, &selected);
|
|
|
|
}
|
|
|
|
|
2008-12-02 12:01:29 +01:00
|
|
|
/*!
|
2013-09-06 16:38:53 +02:00
|
|
|
Asks the user for a new file name (\gui {Save File As}) for \a document.
|
2008-12-02 12:01:29 +01:00
|
|
|
*/
|
2012-10-15 11:53:22 +02:00
|
|
|
QString DocumentManager::getSaveAsFileName(const IDocument *document, const QString &filter, QString *selectedFilter)
|
2008-12-02 12:01:29 +01:00
|
|
|
{
|
2012-02-14 16:43:51 +01:00
|
|
|
if (!document)
|
2008-12-02 12:01:29 +01:00
|
|
|
return QLatin1String("");
|
2014-12-21 21:54:30 +02:00
|
|
|
QString absoluteFilePath = document->filePath().toString();
|
2008-12-02 12:01:29 +01:00
|
|
|
const QFileInfo fi(absoluteFilePath);
|
2014-11-12 15:07:44 +01:00
|
|
|
QString path;
|
|
|
|
QString fileName;
|
2008-12-02 12:01:29 +01:00
|
|
|
if (absoluteFilePath.isEmpty()) {
|
2012-02-14 16:43:51 +01:00
|
|
|
fileName = document->suggestedFileName();
|
|
|
|
const QString defaultPath = document->defaultPath();
|
2008-12-02 12:01:29 +01:00
|
|
|
if (!defaultPath.isEmpty())
|
|
|
|
path = defaultPath;
|
2014-11-12 15:07:44 +01:00
|
|
|
} else {
|
|
|
|
path = fi.absolutePath();
|
|
|
|
fileName = fi.fileName();
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
2010-09-07 11:55:52 +02:00
|
|
|
|
2008-12-02 12:01:29 +01:00
|
|
|
QString filterString;
|
2010-09-07 11:55:52 +02:00
|
|
|
if (filter.isEmpty()) {
|
2015-02-04 09:32:46 +01:00
|
|
|
Utils::MimeDatabase mdb;
|
|
|
|
const Utils::MimeType &mt = mdb.mimeTypeForFile(fi);
|
|
|
|
if (mt.isValid())
|
2010-09-07 11:55:52 +02:00
|
|
|
filterString = mt.filterString();
|
|
|
|
selectedFilter = &filterString;
|
|
|
|
} else {
|
|
|
|
filterString = filter;
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
2010-09-07 11:55:52 +02:00
|
|
|
absoluteFilePath = getSaveFileName(tr("Save File As"),
|
2015-01-31 22:11:11 +02:00
|
|
|
path + QLatin1Char('/') + fileName,
|
2008-12-02 12:01:29 +01:00
|
|
|
filterString,
|
2010-09-07 11:55:52 +02:00
|
|
|
selectedFilter);
|
2008-12-02 12:01:29 +01:00
|
|
|
return absoluteFilePath;
|
|
|
|
}
|
|
|
|
|
2014-01-21 13:25:19 +01:00
|
|
|
/*!
|
|
|
|
Silently saves all documents and will return true if all modified documents were saved
|
|
|
|
successfully.
|
|
|
|
|
|
|
|
This method will try to avoid showing dialogs to the user, but can do so anyway (e.g. if
|
|
|
|
a file is not writeable).
|
|
|
|
|
|
|
|
\a Canceled will be set if the user canceled any of the dialogs that he interacted with.
|
|
|
|
\a FailedToClose will contain a list of documents that could not be saved if passed into the
|
|
|
|
method.
|
|
|
|
*/
|
|
|
|
bool DocumentManager::saveAllModifiedDocumentsSilently(bool *canceled,
|
|
|
|
QList<IDocument *> *failedToClose)
|
|
|
|
{
|
|
|
|
return saveModifiedDocumentsSilently(modifiedDocuments(), canceled, failedToClose);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
Silently saves \a documents and will return true if all of them were saved successfully.
|
|
|
|
|
|
|
|
This method will try to avoid showing dialogs to the user, but can do so anyway (e.g. if
|
|
|
|
a file is not writeable).
|
|
|
|
|
|
|
|
\a Canceled will be set if the user canceled any of the dialogs that he interacted with.
|
|
|
|
\a FailedToClose will contain a list of documents that could not be saved if passed into the
|
|
|
|
method.
|
|
|
|
*/
|
|
|
|
bool DocumentManager::saveModifiedDocumentsSilently(const QList<IDocument *> &documents, bool *canceled,
|
|
|
|
QList<IDocument *> *failedToClose)
|
|
|
|
{
|
|
|
|
return saveModifiedFilesHelper(documents, QString(), canceled, true, QString(), 0, failedToClose);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
Silently saves a \a document and will return true if it was saved successfully.
|
|
|
|
|
|
|
|
This method will try to avoid showing dialogs to the user, but can do so anyway (e.g. if
|
|
|
|
a file is not writeable).
|
|
|
|
|
|
|
|
\a Canceled will be set if the user canceled any of the dialogs that he interacted with.
|
|
|
|
\a FailedToClose will contain a list of documents that could not be saved if passed into the
|
|
|
|
method.
|
|
|
|
*/
|
|
|
|
bool DocumentManager::saveModifiedDocumentSilently(IDocument *document, bool *canceled,
|
|
|
|
QList<IDocument *> *failedToClose)
|
|
|
|
{
|
|
|
|
return saveModifiedDocumentsSilently(QList<IDocument *>() << document, canceled, failedToClose);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
Presents a dialog with all modified documents to the user and will ask him which of these
|
|
|
|
should be saved.
|
|
|
|
|
|
|
|
This method may show additional dialogs to the user, e.g. if a file is not writeable).
|
|
|
|
|
|
|
|
The dialog text can be set using \a message. \a Canceled will be set if the user canceled any
|
|
|
|
of the dialogs that he interacted with (the method will also return false in this case).
|
|
|
|
The \a alwaysSaveMessage will show an additional checkbox asking in the dialog. The state of
|
|
|
|
this checkbox will be written into \a alwaysSave if set.
|
|
|
|
\a FailedToClose will contain a list of documents that could not be saved if passed into the
|
|
|
|
method.
|
|
|
|
*/
|
|
|
|
bool DocumentManager::saveAllModifiedDocuments(const QString &message, bool *canceled,
|
|
|
|
const QString &alwaysSaveMessage, bool *alwaysSave,
|
|
|
|
QList<IDocument *> *failedToClose)
|
|
|
|
{
|
|
|
|
return saveModifiedDocuments(modifiedDocuments(), message, canceled,
|
|
|
|
alwaysSaveMessage, alwaysSave, failedToClose);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
Presents a dialog with \a documents to the user and will ask him which of these should be saved.
|
|
|
|
|
|
|
|
This method may show additional dialogs to the user, e.g. if a file is not writeable).
|
|
|
|
|
|
|
|
The dialog text can be set using \a message. \a Canceled will be set if the user canceled any
|
|
|
|
of the dialogs that he interacted with (the method will also return false in this case).
|
|
|
|
The \a alwaysSaveMessage will show an additional checkbox asking in the dialog. The state of
|
|
|
|
this checkbox will be written into \a alwaysSave if set.
|
|
|
|
\a FailedToClose will contain a list of documents that could not be saved if passed into the
|
|
|
|
method.
|
|
|
|
*/
|
|
|
|
bool DocumentManager::saveModifiedDocuments(const QList<IDocument *> &documents,
|
|
|
|
const QString &message, bool *canceled,
|
|
|
|
const QString &alwaysSaveMessage, bool *alwaysSave,
|
|
|
|
QList<IDocument *> *failedToClose)
|
|
|
|
{
|
|
|
|
return saveModifiedFilesHelper(documents, message, canceled, false,
|
|
|
|
alwaysSaveMessage, alwaysSave, failedToClose);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
Presents a dialog with the one \a document to the user and will ask him whether he wants it
|
|
|
|
saved.
|
|
|
|
|
|
|
|
This method may show additional dialogs to the user, e.g. if the file is not writeable).
|
|
|
|
|
|
|
|
The dialog text can be set using \a message. \a Canceled will be set if the user canceled any
|
|
|
|
of the dialogs that he interacted with (the method will also return false in this case).
|
|
|
|
The \a alwaysSaveMessage will show an additional checkbox asking in the dialog. The state of
|
|
|
|
this checkbox will be written into \a alwaysSave if set.
|
|
|
|
\a FailedToClose will contain a list of documents that could not be saved if passed into the
|
|
|
|
method.
|
|
|
|
*/
|
|
|
|
bool DocumentManager::saveModifiedDocument(IDocument *document, const QString &message, bool *canceled,
|
|
|
|
const QString &alwaysSaveMessage, bool *alwaysSave,
|
|
|
|
QList<IDocument *> *failedToClose)
|
|
|
|
{
|
|
|
|
return saveModifiedDocuments(QList<IDocument *>() << document, message, canceled,
|
|
|
|
alwaysSaveMessage, alwaysSave, failedToClose);
|
|
|
|
}
|
|
|
|
|
2009-11-26 18:03:16 +01:00
|
|
|
/*!
|
2010-07-12 16:53:07 +02:00
|
|
|
Asks the user for a set of file names to be opened. The \a filters
|
2013-09-06 16:38:53 +02:00
|
|
|
and \a selectedFilter arguments are interpreted like in
|
|
|
|
\c QFileDialog::getOpenFileNames(). \a pathIn specifies a path to open the
|
|
|
|
dialog in if that is not overridden by the user's policy.
|
2009-11-26 18:03:16 +01:00
|
|
|
*/
|
|
|
|
|
2012-02-14 16:43:51 +01:00
|
|
|
QStringList DocumentManager::getOpenFileNames(const QString &filters,
|
2014-05-20 08:58:08 +03:00
|
|
|
const QString &pathIn,
|
|
|
|
QString *selectedFilter)
|
2009-11-26 18:03:16 +01:00
|
|
|
{
|
2010-07-13 15:27:08 +02:00
|
|
|
QString path = pathIn;
|
|
|
|
if (path.isEmpty()) {
|
2015-01-16 17:45:06 +01:00
|
|
|
if (EditorManager::currentDocument() && !EditorManager::currentDocument()->isTemporary())
|
|
|
|
path = EditorManager::currentDocument()->filePath().toString();
|
2010-11-01 14:29:25 +01:00
|
|
|
if (path.isEmpty() && useProjectsDirectory())
|
|
|
|
path = projectsDirectory();
|
2010-07-13 15:27:08 +02:00
|
|
|
}
|
2014-01-06 10:56:30 +01:00
|
|
|
const QStringList files = QFileDialog::getOpenFileNames(ICore::dialogParent(),
|
2009-11-26 18:03:16 +01:00
|
|
|
tr("Open File"),
|
|
|
|
path, filters,
|
|
|
|
selectedFilter);
|
|
|
|
if (!files.isEmpty())
|
|
|
|
setFileDialogLastVisitedDirectory(QFileInfo(files.front()).absolutePath());
|
|
|
|
return files;
|
|
|
|
}
|
|
|
|
|
2012-02-14 16:43:51 +01:00
|
|
|
void DocumentManager::changedFile(const QString &fileName)
|
2008-12-02 12:01:29 +01:00
|
|
|
{
|
2009-11-25 10:09:45 +01:00
|
|
|
const bool wasempty = d->m_changedFiles.isEmpty();
|
2010-01-22 16:49:57 +01:00
|
|
|
|
2011-04-15 15:06:00 +02:00
|
|
|
if (d->m_states.contains(fileName))
|
|
|
|
d->m_changedFiles.insert(fileName);
|
2010-01-22 16:49:57 +01:00
|
|
|
|
Remove braces for single lines of conditions
#!/usr/bin/env ruby
Dir.glob('**/*.cpp') { |file|
# skip ast (excluding paste, astpath, and canv'ast'imer)
next if file =~ /ast[^eip]|keywords\.|qualifiers|preprocessor|names.cpp/i
s = File.read(file)
next if s.include?('qlalr')
orig = s.dup
s.gsub!(/\n *if [^\n]*{\n[^\n]*\n\s+}(\s+else if [^\n]* {\n[^\n]*\n\s+})*(\s+else {\n[^\n]*\n\s+})?\n/m) { |m|
res = $&
if res =~ /^\s*(\/\/|[A-Z_]{3,})/ # C++ comment or macro (Q_UNUSED, SDEBUG), do not touch braces
res
else
res.gsub!('} else', 'else')
res.gsub!(/\n +} *\n/m, "\n")
res.gsub(/ *{$/, '')
end
}
s.gsub!(/ *$/, '')
File.open(file, 'wb').write(s) if s != orig
}
Change-Id: I3b30ee60df0986f66c02132c65fc38a3fbb6bbdc
Reviewed-by: hjk <qthjk@ovi.com>
2013-01-08 03:32:53 +02:00
|
|
|
if (wasempty && !d->m_changedFiles.isEmpty())
|
2009-04-15 16:06:49 +02:00
|
|
|
QTimer::singleShot(200, this, SLOT(checkForReload()));
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
2012-02-14 16:43:51 +01:00
|
|
|
void DocumentManager::checkForReload()
|
2008-12-02 12:01:29 +01:00
|
|
|
{
|
2010-11-23 12:47:45 +01:00
|
|
|
if (d->m_changedFiles.isEmpty())
|
|
|
|
return;
|
2014-03-14 13:03:42 +01:00
|
|
|
if (!QApplication::activeWindow())
|
2010-01-22 16:49:57 +01:00
|
|
|
return;
|
2008-12-02 12:01:29 +01:00
|
|
|
|
2014-11-13 14:38:58 +01:00
|
|
|
if (QApplication::activeModalWidget() || d->m_blockActivated) {
|
|
|
|
// We do not want to prompt for modified file if we currently have some modal dialog open.
|
|
|
|
// If d->m_blockActivated is true, then it means that the event processing of either the
|
|
|
|
// file modified dialog, or of loading large files, has delivered a file change event from
|
|
|
|
// a watcher *and* the timer triggered. We may never end up here in a nested way, so
|
|
|
|
// recheck later.
|
2014-03-14 13:03:42 +01:00
|
|
|
QTimer::singleShot(200, this, SLOT(checkForReload()));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2010-01-22 16:49:57 +01:00
|
|
|
d->m_blockActivated = true;
|
|
|
|
|
2015-05-13 16:12:45 +02:00
|
|
|
IDocument::ReloadSetting defaultBehavior = EditorManager::reloadSetting();
|
2015-02-11 08:44:31 +02:00
|
|
|
ReloadPromptAnswer previousReloadAnswer = ReloadCurrent;
|
|
|
|
FileDeletedPromptAnswer previousDeletedAnswer = FileDeletedSave;
|
2010-01-22 16:49:57 +01:00
|
|
|
|
2013-07-12 16:38:37 +02:00
|
|
|
QList<IDocument *> documentsToClose;
|
2012-02-14 16:43:51 +01:00
|
|
|
QMap<IDocument*, QString> documentsToSave;
|
2010-11-23 12:47:45 +01:00
|
|
|
|
|
|
|
// collect file information
|
2012-01-19 23:23:43 +01:00
|
|
|
QMap<QString, FileStateItem> currentStates;
|
2012-02-14 16:43:51 +01:00
|
|
|
QMap<QString, IDocument::ChangeType> changeTypes;
|
|
|
|
QSet<IDocument *> changedIDocuments;
|
2010-03-19 10:28:05 +01:00
|
|
|
foreach (const QString &fileName, d->m_changedFiles) {
|
2012-02-14 16:43:51 +01:00
|
|
|
IDocument::ChangeType type = IDocument::TypeContents;
|
2012-01-19 23:23:43 +01:00
|
|
|
FileStateItem state;
|
2010-01-22 16:49:57 +01:00
|
|
|
QFileInfo fi(fileName);
|
2010-03-19 10:28:05 +01:00
|
|
|
if (!fi.exists()) {
|
2012-02-14 16:43:51 +01:00
|
|
|
type = IDocument::TypeRemoved;
|
2010-03-19 10:28:05 +01:00
|
|
|
} else {
|
2010-11-23 12:47:45 +01:00
|
|
|
state.modified = fi.lastModified();
|
|
|
|
state.permissions = fi.permissions();
|
2010-01-22 16:49:57 +01:00
|
|
|
}
|
2010-11-23 12:47:45 +01:00
|
|
|
currentStates.insert(fileName, state);
|
|
|
|
changeTypes.insert(fileName, type);
|
2012-02-14 16:43:51 +01:00
|
|
|
foreach (IDocument *document, d->m_states.value(fileName).lastUpdatedState.keys())
|
|
|
|
changedIDocuments.insert(document);
|
2010-11-23 12:47:45 +01:00
|
|
|
}
|
|
|
|
|
2011-04-14 21:07:13 +02:00
|
|
|
// clean up. do this before we may enter the main loop, otherwise we would
|
|
|
|
// lose consecutive notifications.
|
|
|
|
d->m_changedFiles.clear();
|
|
|
|
|
2010-12-13 17:35:40 +01:00
|
|
|
// collect information about "expected" file names
|
|
|
|
// we can't do the "resolving" already in expectFileChange, because
|
|
|
|
// if the resolved names are different when unexpectFileChange is called
|
|
|
|
// we would end up with never-unexpected file names
|
|
|
|
QSet<QString> expectedFileNames;
|
|
|
|
foreach (const QString &fileName, d->m_expectedFileNames) {
|
|
|
|
const QString fixedName = fixFileName(fileName, KeepLinks);
|
|
|
|
expectedFileNames.insert(fixedName);
|
|
|
|
const QString fixedResolvedName = fixFileName(fileName, ResolveLinks);
|
|
|
|
if (fixedName != fixedResolvedName)
|
|
|
|
expectedFileNames.insert(fixedResolvedName);
|
|
|
|
}
|
|
|
|
|
2012-02-14 16:43:51 +01:00
|
|
|
// handle the IDocuments
|
2011-04-04 15:24:13 +02:00
|
|
|
QStringList errorStrings;
|
2012-02-14 16:43:51 +01:00
|
|
|
foreach (IDocument *document, changedIDocuments) {
|
|
|
|
IDocument::ChangeTrigger trigger = IDocument::TriggerInternal;
|
|
|
|
IDocument::ChangeType type = IDocument::TypePermissions;
|
2010-11-23 12:47:45 +01:00
|
|
|
bool changed = false;
|
|
|
|
// find out the type & behavior from the two possible files
|
|
|
|
// behavior is internal if all changes are expected (and none removed)
|
|
|
|
// type is "max" of both types (remove > contents > permissions)
|
2012-02-14 16:43:51 +01:00
|
|
|
foreach (const QString & fileName, d->m_documentsWithWatch.value(document)) {
|
2010-11-23 12:47:45 +01:00
|
|
|
// was the file reported?
|
|
|
|
if (!currentStates.contains(fileName))
|
|
|
|
continue;
|
2010-01-22 16:49:57 +01:00
|
|
|
|
2012-01-19 23:23:43 +01:00
|
|
|
FileStateItem currentState = currentStates.value(fileName);
|
|
|
|
FileStateItem expectedState = d->m_states.value(fileName).expected;
|
2012-02-14 16:43:51 +01:00
|
|
|
FileStateItem lastState = d->m_states.value(fileName).lastUpdatedState.value(document);
|
2011-04-15 11:19:16 +02:00
|
|
|
|
2010-11-23 12:47:45 +01:00
|
|
|
// did the file actually change?
|
|
|
|
if (lastState.modified == currentState.modified && lastState.permissions == currentState.permissions)
|
2010-03-19 10:28:05 +01:00
|
|
|
continue;
|
2010-11-23 12:47:45 +01:00
|
|
|
changed = true;
|
|
|
|
|
|
|
|
// was it only a permission change?
|
|
|
|
if (lastState.modified == currentState.modified)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
// was the change unexpected?
|
2013-06-19 08:37:21 +03:00
|
|
|
if ((currentState.modified != expectedState.modified || currentState.permissions != expectedState.permissions)
|
2010-12-13 17:35:40 +01:00
|
|
|
&& !expectedFileNames.contains(fileName)) {
|
2013-06-19 08:37:21 +03:00
|
|
|
trigger = IDocument::TriggerExternal;
|
2010-03-19 10:28:05 +01:00
|
|
|
}
|
2010-11-23 12:47:45 +01:00
|
|
|
|
|
|
|
// find out the type
|
2012-02-14 16:43:51 +01:00
|
|
|
IDocument::ChangeType fileChange = changeTypes.value(fileName);
|
Remove braces for single lines of conditions
#!/usr/bin/env ruby
Dir.glob('**/*.cpp') { |file|
# skip ast (excluding paste, astpath, and canv'ast'imer)
next if file =~ /ast[^eip]|keywords\.|qualifiers|preprocessor|names.cpp/i
s = File.read(file)
next if s.include?('qlalr')
orig = s.dup
s.gsub!(/\n *if [^\n]*{\n[^\n]*\n\s+}(\s+else if [^\n]* {\n[^\n]*\n\s+})*(\s+else {\n[^\n]*\n\s+})?\n/m) { |m|
res = $&
if res =~ /^\s*(\/\/|[A-Z_]{3,})/ # C++ comment or macro (Q_UNUSED, SDEBUG), do not touch braces
res
else
res.gsub!('} else', 'else')
res.gsub!(/\n +} *\n/m, "\n")
res.gsub(/ *{$/, '')
end
}
s.gsub!(/ *$/, '')
File.open(file, 'wb').write(s) if s != orig
}
Change-Id: I3b30ee60df0986f66c02132c65fc38a3fbb6bbdc
Reviewed-by: hjk <qthjk@ovi.com>
2013-01-08 03:32:53 +02:00
|
|
|
if (fileChange == IDocument::TypeRemoved)
|
2012-02-14 16:43:51 +01:00
|
|
|
type = IDocument::TypeRemoved;
|
Remove braces for single lines of conditions
#!/usr/bin/env ruby
Dir.glob('**/*.cpp') { |file|
# skip ast (excluding paste, astpath, and canv'ast'imer)
next if file =~ /ast[^eip]|keywords\.|qualifiers|preprocessor|names.cpp/i
s = File.read(file)
next if s.include?('qlalr')
orig = s.dup
s.gsub!(/\n *if [^\n]*{\n[^\n]*\n\s+}(\s+else if [^\n]* {\n[^\n]*\n\s+})*(\s+else {\n[^\n]*\n\s+})?\n/m) { |m|
res = $&
if res =~ /^\s*(\/\/|[A-Z_]{3,})/ # C++ comment or macro (Q_UNUSED, SDEBUG), do not touch braces
res
else
res.gsub!('} else', 'else')
res.gsub!(/\n +} *\n/m, "\n")
res.gsub(/ *{$/, '')
end
}
s.gsub!(/ *$/, '')
File.open(file, 'wb').write(s) if s != orig
}
Change-Id: I3b30ee60df0986f66c02132c65fc38a3fbb6bbdc
Reviewed-by: hjk <qthjk@ovi.com>
2013-01-08 03:32:53 +02:00
|
|
|
else if (fileChange == IDocument::TypeContents && type == IDocument::TypePermissions)
|
2012-02-14 16:43:51 +01:00
|
|
|
type = IDocument::TypeContents;
|
2010-11-23 12:47:45 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!changed) // probably because the change was blocked with (un)blockFileChange
|
|
|
|
continue;
|
|
|
|
|
|
|
|
// handle it!
|
2012-02-14 16:43:51 +01:00
|
|
|
d->m_blockedIDocument = document;
|
2010-11-23 12:47:45 +01:00
|
|
|
|
2014-11-13 14:38:58 +01:00
|
|
|
// Update file info, also handling if e.g. link target has changed.
|
|
|
|
// We need to do that before the file is reloaded, because removing the watcher will
|
|
|
|
// loose any pending change events. Loosing change events *before* the file is reloaded
|
|
|
|
// doesn't matter, because in that case we then reload the new version of the file already
|
|
|
|
// anyhow.
|
|
|
|
removeFileInfo(document);
|
|
|
|
addFileInfo(document);
|
|
|
|
|
2011-04-04 15:24:13 +02:00
|
|
|
bool success = true;
|
|
|
|
QString errorString;
|
2010-11-23 12:47:45 +01:00
|
|
|
// we've got some modification
|
|
|
|
// check if it's contents or permissions:
|
2012-02-14 16:43:51 +01:00
|
|
|
if (type == IDocument::TypePermissions) {
|
2010-11-23 12:47:45 +01:00
|
|
|
// Only permission change
|
2012-02-14 16:43:51 +01:00
|
|
|
success = document->reload(&errorString, IDocument::FlagReload, IDocument::TypePermissions);
|
2010-11-23 12:47:45 +01:00
|
|
|
// now we know it's a content change or file was removed
|
2012-02-14 16:43:51 +01:00
|
|
|
} else if (defaultBehavior == IDocument::ReloadUnmodified
|
|
|
|
&& type == IDocument::TypeContents && !document->isModified()) {
|
2010-11-23 12:47:45 +01:00
|
|
|
// content change, but unmodified (and settings say to reload in this case)
|
2012-02-14 16:43:51 +01:00
|
|
|
success = document->reload(&errorString, IDocument::FlagReload, type);
|
2010-11-23 12:47:45 +01:00
|
|
|
// file was removed or it's a content change and the default behavior for
|
|
|
|
// unmodified files didn't kick in
|
2012-02-14 16:43:51 +01:00
|
|
|
} else if (defaultBehavior == IDocument::ReloadUnmodified
|
|
|
|
&& type == IDocument::TypeRemoved && !document->isModified()) {
|
2011-04-27 15:52:24 +02:00
|
|
|
// file removed, but unmodified files should be reloaded
|
|
|
|
// so we close the file
|
2013-07-12 16:38:37 +02:00
|
|
|
documentsToClose << document;
|
2012-02-14 16:43:51 +01:00
|
|
|
} else if (defaultBehavior == IDocument::IgnoreAll) {
|
2010-11-23 12:47:45 +01:00
|
|
|
// content change or removed, but settings say ignore
|
2012-02-14 16:43:51 +01:00
|
|
|
success = document->reload(&errorString, IDocument::FlagIgnore, type);
|
2010-11-23 12:47:45 +01:00
|
|
|
// either the default behavior is to always ask,
|
|
|
|
// or the ReloadUnmodified default behavior didn't kick in,
|
2012-02-14 16:43:51 +01:00
|
|
|
// so do whatever the IDocument wants us to do
|
2010-11-23 12:47:45 +01:00
|
|
|
} else {
|
2012-02-14 16:43:51 +01:00
|
|
|
// check if IDocument wants us to ask
|
|
|
|
if (document->reloadBehavior(trigger, type) == IDocument::BehaviorSilent) {
|
|
|
|
// content change or removed, IDocument wants silent handling
|
2012-03-08 08:42:29 +01:00
|
|
|
if (type == IDocument::TypeRemoved)
|
2013-07-12 16:38:37 +02:00
|
|
|
documentsToClose << document;
|
2012-03-08 08:42:29 +01:00
|
|
|
else
|
|
|
|
success = document->reload(&errorString, IDocument::FlagReload, type);
|
2012-02-14 16:43:51 +01:00
|
|
|
// IDocument wants us to ask
|
|
|
|
} else if (type == IDocument::TypeContents) {
|
|
|
|
// content change, IDocument wants to ask user
|
2015-02-11 08:44:31 +02:00
|
|
|
if (previousReloadAnswer == ReloadNone) {
|
2010-11-23 12:47:45 +01:00
|
|
|
// answer already given, ignore
|
2012-02-14 16:43:51 +01:00
|
|
|
success = document->reload(&errorString, IDocument::FlagIgnore, IDocument::TypeContents);
|
2015-02-11 08:44:31 +02:00
|
|
|
} else if (previousReloadAnswer == ReloadAll) {
|
2010-11-23 12:47:45 +01:00
|
|
|
// answer already given, reload
|
2012-02-14 16:43:51 +01:00
|
|
|
success = document->reload(&errorString, IDocument::FlagReload, IDocument::TypeContents);
|
2010-11-23 12:47:45 +01:00
|
|
|
} else {
|
|
|
|
// Ask about content change
|
2015-02-11 08:44:31 +02:00
|
|
|
previousReloadAnswer = reloadPrompt(document->filePath(), document->isModified(),
|
2014-01-03 14:43:29 +01:00
|
|
|
ICore::dialogParent());
|
2013-09-06 11:01:37 +02:00
|
|
|
switch (previousReloadAnswer) {
|
2015-02-11 08:44:31 +02:00
|
|
|
case ReloadAll:
|
|
|
|
case ReloadCurrent:
|
2012-02-14 16:43:51 +01:00
|
|
|
success = document->reload(&errorString, IDocument::FlagReload, IDocument::TypeContents);
|
2010-11-23 12:47:45 +01:00
|
|
|
break;
|
2015-02-11 08:44:31 +02:00
|
|
|
case ReloadSkipCurrent:
|
|
|
|
case ReloadNone:
|
2012-02-14 16:43:51 +01:00
|
|
|
success = document->reload(&errorString, IDocument::FlagIgnore, IDocument::TypeContents);
|
2010-11-23 12:47:45 +01:00
|
|
|
break;
|
2015-02-11 08:44:31 +02:00
|
|
|
case CloseCurrent:
|
2013-07-12 16:38:37 +02:00
|
|
|
documentsToClose << document;
|
2012-09-28 14:35:32 +02:00
|
|
|
break;
|
2010-03-19 10:28:05 +01:00
|
|
|
}
|
2010-11-23 12:47:45 +01:00
|
|
|
}
|
2012-02-14 16:43:51 +01:00
|
|
|
// IDocument wants us to ask, and it's the TypeRemoved case
|
2010-11-23 12:47:45 +01:00
|
|
|
} else {
|
|
|
|
// Ask about removed file
|
|
|
|
bool unhandled = true;
|
|
|
|
while (unhandled) {
|
2015-02-11 08:44:31 +02:00
|
|
|
if (previousDeletedAnswer != FileDeletedCloseAll) {
|
2013-09-06 11:01:37 +02:00
|
|
|
previousDeletedAnswer =
|
2015-02-11 08:44:31 +02:00
|
|
|
fileDeletedPrompt(document->filePath().toString(),
|
2013-09-06 11:01:37 +02:00
|
|
|
trigger == IDocument::TriggerExternal,
|
|
|
|
QApplication::activeWindow());
|
|
|
|
}
|
|
|
|
switch (previousDeletedAnswer) {
|
2015-02-11 08:44:31 +02:00
|
|
|
case FileDeletedSave:
|
2014-12-21 21:54:30 +02:00
|
|
|
documentsToSave.insert(document, document->filePath().toString());
|
2010-11-23 12:47:45 +01:00
|
|
|
unhandled = false;
|
|
|
|
break;
|
2015-02-11 08:44:31 +02:00
|
|
|
case FileDeletedSaveAs:
|
2010-11-23 12:47:45 +01:00
|
|
|
{
|
2012-02-14 16:43:51 +01:00
|
|
|
const QString &saveFileName = getSaveAsFileName(document);
|
2010-11-23 12:47:45 +01:00
|
|
|
if (!saveFileName.isEmpty()) {
|
2012-02-14 16:43:51 +01:00
|
|
|
documentsToSave.insert(document, saveFileName);
|
2010-03-19 10:28:05 +01:00
|
|
|
unhandled = false;
|
|
|
|
}
|
2010-11-23 12:47:45 +01:00
|
|
|
break;
|
|
|
|
}
|
2015-02-11 08:44:31 +02:00
|
|
|
case FileDeletedClose:
|
|
|
|
case FileDeletedCloseAll:
|
2013-07-12 16:38:37 +02:00
|
|
|
documentsToClose << document;
|
2010-11-23 12:47:45 +01:00
|
|
|
unhandled = false;
|
|
|
|
break;
|
2010-01-22 16:49:57 +01:00
|
|
|
}
|
|
|
|
}
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
}
|
2011-04-04 15:24:13 +02:00
|
|
|
if (!success) {
|
|
|
|
if (errorString.isEmpty())
|
2014-12-21 21:54:30 +02:00
|
|
|
errorStrings << tr("Cannot reload %1").arg(document->filePath().toUserOutput());
|
2011-04-04 15:24:13 +02:00
|
|
|
else
|
|
|
|
errorStrings << errorString;
|
|
|
|
}
|
2010-03-19 10:28:05 +01:00
|
|
|
|
2012-02-14 16:43:51 +01:00
|
|
|
d->m_blockedIDocument = 0;
|
2010-03-05 12:55:04 +01:00
|
|
|
}
|
2011-04-04 15:24:13 +02:00
|
|
|
if (!errorStrings.isEmpty())
|
2014-01-06 10:56:30 +01:00
|
|
|
QMessageBox::critical(ICore::dialogParent(), tr("File Error"),
|
2014-08-23 01:19:53 +02:00
|
|
|
errorStrings.join(QLatin1Char('\n')));
|
2010-11-23 12:47:45 +01:00
|
|
|
|
2010-03-19 10:28:05 +01:00
|
|
|
// handle deleted files
|
2013-07-12 16:38:37 +02:00
|
|
|
EditorManager::closeDocuments(documentsToClose, false);
|
2012-02-14 16:43:51 +01:00
|
|
|
QMapIterator<IDocument *, QString> it(documentsToSave);
|
2010-03-19 10:28:05 +01:00
|
|
|
while (it.hasNext()) {
|
|
|
|
it.next();
|
2012-02-14 16:43:51 +01:00
|
|
|
saveDocument(it.key(), it.value());
|
2010-04-08 16:07:23 +02:00
|
|
|
it.key()->checkPermissions();
|
2010-03-19 10:28:05 +01:00
|
|
|
}
|
|
|
|
|
2010-01-22 16:49:57 +01:00
|
|
|
d->m_blockActivated = false;
|
2010-11-23 12:47:45 +01:00
|
|
|
|
|
|
|
// dump();
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
2010-12-09 11:37:58 +01:00
|
|
|
Adds the \a fileName to the list of recent files. Associates the file to
|
2013-09-06 16:38:53 +02:00
|
|
|
be reopened with the editor that has the specified \a editorId, if possible.
|
|
|
|
\a editorId defaults to the empty id, which lets \QC figure out
|
2010-12-09 11:37:58 +01:00
|
|
|
the best editor itself.
|
2008-12-02 12:01:29 +01:00
|
|
|
*/
|
2014-07-01 11:08:26 +02:00
|
|
|
void DocumentManager::addToRecentFiles(const QString &fileName, Id editorId)
|
2008-12-02 12:01:29 +01:00
|
|
|
{
|
|
|
|
if (fileName.isEmpty())
|
|
|
|
return;
|
2010-11-23 12:47:45 +01:00
|
|
|
QString unifiedForm(fixFileName(fileName, KeepLinks));
|
2010-12-09 11:37:58 +01:00
|
|
|
QMutableListIterator<RecentFile > it(d->m_recentFiles);
|
2010-10-19 11:07:20 +02:00
|
|
|
while (it.hasNext()) {
|
2010-12-09 11:37:58 +01:00
|
|
|
RecentFile file = it.next();
|
2012-02-14 16:43:51 +01:00
|
|
|
QString recentUnifiedForm(fixFileName(file.first, DocumentManager::KeepLinks));
|
2010-10-19 11:07:20 +02:00
|
|
|
if (unifiedForm == recentUnifiedForm)
|
|
|
|
it.remove();
|
|
|
|
}
|
2009-11-25 10:09:45 +01:00
|
|
|
if (d->m_recentFiles.count() > d->m_maxRecentFiles)
|
|
|
|
d->m_recentFiles.removeLast();
|
2010-12-09 11:37:58 +01:00
|
|
|
d->m_recentFiles.prepend(RecentFile(fileName, editorId));
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
2011-06-20 11:01:23 +02:00
|
|
|
/*!
|
|
|
|
Clears the list of recent files. Should only be called by
|
2013-09-06 16:38:53 +02:00
|
|
|
the core plugin when the user chooses to clear the list.
|
2011-06-20 11:01:23 +02:00
|
|
|
*/
|
2012-02-14 16:43:51 +01:00
|
|
|
void DocumentManager::clearRecentFiles()
|
2011-06-20 11:01:23 +02:00
|
|
|
{
|
|
|
|
d->m_recentFiles.clear();
|
|
|
|
}
|
|
|
|
|
2008-12-02 12:01:29 +01:00
|
|
|
/*!
|
|
|
|
Returns the list of recent files.
|
|
|
|
*/
|
2012-02-14 16:43:51 +01:00
|
|
|
QList<DocumentManager::RecentFile> DocumentManager::recentFiles()
|
2008-12-02 12:01:29 +01:00
|
|
|
{
|
2009-11-25 10:09:45 +01:00
|
|
|
return d->m_recentFiles;
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
2012-02-14 16:43:51 +01:00
|
|
|
void DocumentManager::saveSettings()
|
2008-12-02 12:01:29 +01:00
|
|
|
{
|
2010-12-09 11:37:58 +01:00
|
|
|
QStringList recentFiles;
|
|
|
|
QStringList recentEditorIds;
|
|
|
|
foreach (const RecentFile &file, d->m_recentFiles) {
|
|
|
|
recentFiles.append(file.first);
|
2011-11-10 11:36:51 +01:00
|
|
|
recentEditorIds.append(file.second.toString());
|
2010-12-09 11:37:58 +01:00
|
|
|
}
|
|
|
|
|
2014-11-16 10:52:41 +02:00
|
|
|
QSettings *s = ICore::settings();
|
2009-11-26 18:03:16 +01:00
|
|
|
s->beginGroup(QLatin1String(settingsGroupC));
|
2010-12-09 11:37:58 +01:00
|
|
|
s->setValue(QLatin1String(filesKeyC), recentFiles);
|
|
|
|
s->setValue(QLatin1String(editorsKeyC), recentEditorIds);
|
2009-11-26 18:03:16 +01:00
|
|
|
s->endGroup();
|
|
|
|
s->beginGroup(QLatin1String(directoryGroupC));
|
|
|
|
s->setValue(QLatin1String(projectDirectoryKeyC), d->m_projectsDirectory);
|
|
|
|
s->setValue(QLatin1String(useProjectDirectoryKeyC), d->m_useProjectsDirectory);
|
2012-10-05 21:34:09 +10:00
|
|
|
s->setValue(QLatin1String(buildDirectoryKeyC), d->m_buildDirectory);
|
2008-12-02 12:01:29 +01:00
|
|
|
s->endGroup();
|
|
|
|
}
|
|
|
|
|
2012-01-19 23:23:43 +01:00
|
|
|
void readSettings()
|
2010-10-19 11:07:20 +02:00
|
|
|
{
|
2014-11-16 10:52:41 +02:00
|
|
|
QSettings *s = ICore::settings();
|
2010-10-19 11:07:20 +02:00
|
|
|
d->m_recentFiles.clear();
|
2010-12-09 11:37:58 +01:00
|
|
|
s->beginGroup(QLatin1String(settingsGroupC));
|
|
|
|
QStringList recentFiles = s->value(QLatin1String(filesKeyC)).toStringList();
|
|
|
|
QStringList recentEditorIds = s->value(QLatin1String(editorsKeyC)).toStringList();
|
|
|
|
s->endGroup();
|
2010-10-19 11:07:20 +02:00
|
|
|
// clean non-existing files
|
2010-12-09 11:37:58 +01:00
|
|
|
QStringListIterator ids(recentEditorIds);
|
|
|
|
foreach (const QString &fileName, recentFiles) {
|
|
|
|
QString editorId;
|
|
|
|
if (ids.hasNext()) // guard against old or weird settings
|
|
|
|
editorId = ids.next();
|
|
|
|
if (QFileInfo(fileName).isFile())
|
2012-02-14 16:43:51 +01:00
|
|
|
d->m_recentFiles.append(DocumentManager::RecentFile(QDir::fromNativeSeparators(fileName), // from native to guard against old settings
|
2013-01-15 13:28:17 +01:00
|
|
|
Id::fromString(editorId)));
|
2010-10-19 11:07:20 +02:00
|
|
|
}
|
|
|
|
|
2010-12-09 11:37:58 +01:00
|
|
|
s->beginGroup(QLatin1String(directoryGroupC));
|
|
|
|
const QString settingsProjectDir = s->value(QLatin1String(projectDirectoryKeyC),
|
|
|
|
QString()).toString();
|
2012-11-16 19:11:36 +01:00
|
|
|
if (!settingsProjectDir.isEmpty() && QFileInfo(settingsProjectDir).isDir())
|
2010-10-19 11:07:20 +02:00
|
|
|
d->m_projectsDirectory = settingsProjectDir;
|
2012-11-16 19:11:36 +01:00
|
|
|
else
|
2015-02-11 08:44:31 +02:00
|
|
|
d->m_projectsDirectory = PathChooser::homePath();
|
2010-12-09 11:37:58 +01:00
|
|
|
d->m_useProjectsDirectory = s->value(QLatin1String(useProjectDirectoryKeyC),
|
2010-10-19 11:07:20 +02:00
|
|
|
d->m_useProjectsDirectory).toBool();
|
2012-10-05 21:34:09 +10:00
|
|
|
|
|
|
|
const QString settingsShadowDir = s->value(QLatin1String(buildDirectoryKeyC),
|
|
|
|
QString()).toString();
|
2012-11-16 19:11:36 +01:00
|
|
|
if (!settingsShadowDir.isEmpty())
|
2012-10-05 21:34:09 +10:00
|
|
|
d->m_buildDirectory = settingsShadowDir;
|
|
|
|
else
|
2012-11-16 19:11:36 +01:00
|
|
|
d->m_buildDirectory = QLatin1String(Constants::DEFAULT_BUILD_DIRECTORY);
|
2012-10-05 21:34:09 +10:00
|
|
|
|
2010-12-09 11:37:58 +01:00
|
|
|
s->endGroup();
|
2010-10-19 11:07:20 +02:00
|
|
|
}
|
|
|
|
|
2009-11-26 18:03:16 +01:00
|
|
|
/*!
|
|
|
|
|
|
|
|
Returns the initial directory for a new file dialog. If there is
|
2015-01-16 17:47:11 +01:00
|
|
|
a current file, uses that, otherwise if there is a default location for
|
|
|
|
new files, uses that, otherwise uses the last visited directory.
|
2009-11-26 18:03:16 +01:00
|
|
|
|
|
|
|
\sa setFileDialogLastVisitedDirectory
|
2015-01-16 17:47:11 +01:00
|
|
|
\sa setDefaultLocationForNewFiles
|
2009-11-26 18:03:16 +01:00
|
|
|
*/
|
|
|
|
|
2012-02-14 16:43:51 +01:00
|
|
|
QString DocumentManager::fileDialogInitialDirectory()
|
2009-11-26 18:03:16 +01:00
|
|
|
{
|
2015-03-16 14:06:37 +01:00
|
|
|
IDocument *doc = EditorManager::currentDocument();
|
|
|
|
if (doc && !doc->isTemporary() && !doc->filePath().isEmpty())
|
|
|
|
return doc->filePath().toFileInfo().absolutePath();
|
2015-01-16 17:47:11 +01:00
|
|
|
if (!d->m_defaultLocationForNewFiles.isEmpty())
|
|
|
|
return d->m_defaultLocationForNewFiles;
|
2009-11-26 18:03:16 +01:00
|
|
|
return d->m_lastVisitedDirectory;
|
|
|
|
}
|
|
|
|
|
2015-01-16 17:47:11 +01:00
|
|
|
/*!
|
|
|
|
|
|
|
|
Sets the default location for new files
|
|
|
|
|
|
|
|
\sa fileDialogInitialDirectory
|
|
|
|
*/
|
|
|
|
QString DocumentManager::defaultLocationForNewFiles()
|
|
|
|
{
|
|
|
|
return d->m_defaultLocationForNewFiles;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
Returns the default location for new files
|
|
|
|
*/
|
|
|
|
void DocumentManager::setDefaultLocationForNewFiles(const QString &location)
|
|
|
|
{
|
|
|
|
d->m_defaultLocationForNewFiles = location;
|
|
|
|
}
|
|
|
|
|
2009-11-26 18:03:16 +01:00
|
|
|
/*!
|
|
|
|
|
|
|
|
Returns the directory for projects. Defaults to HOME.
|
|
|
|
|
|
|
|
\sa setProjectsDirectory, setUseProjectsDirectory
|
|
|
|
*/
|
|
|
|
|
2012-02-14 16:43:51 +01:00
|
|
|
QString DocumentManager::projectsDirectory()
|
2009-11-26 18:03:16 +01:00
|
|
|
{
|
|
|
|
return d->m_projectsDirectory;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
|
2013-09-06 16:38:53 +02:00
|
|
|
Sets the directory for projects.
|
2009-11-26 18:03:16 +01:00
|
|
|
|
|
|
|
\sa projectsDirectory, useProjectsDirectory
|
|
|
|
*/
|
|
|
|
|
2012-02-14 16:43:51 +01:00
|
|
|
void DocumentManager::setProjectsDirectory(const QString &dir)
|
2009-11-26 18:03:16 +01:00
|
|
|
{
|
|
|
|
d->m_projectsDirectory = dir;
|
|
|
|
}
|
|
|
|
|
2012-10-05 21:34:09 +10:00
|
|
|
/*!
|
2012-11-16 19:11:36 +01:00
|
|
|
Returns the default build directory.
|
2012-10-05 21:34:09 +10:00
|
|
|
|
2012-11-16 19:11:36 +01:00
|
|
|
\sa setBuildDirectory
|
2012-10-05 21:34:09 +10:00
|
|
|
*/
|
|
|
|
QString DocumentManager::buildDirectory()
|
|
|
|
{
|
|
|
|
return d->m_buildDirectory;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
Sets the shadow build directory to \a directory.
|
|
|
|
|
2012-11-16 19:11:36 +01:00
|
|
|
\sa buildDirectory
|
2012-10-05 21:34:09 +10:00
|
|
|
*/
|
|
|
|
void DocumentManager::setBuildDirectory(const QString &directory)
|
|
|
|
{
|
|
|
|
d->m_buildDirectory = directory;
|
|
|
|
}
|
|
|
|
|
2009-11-26 18:03:16 +01:00
|
|
|
/*!
|
|
|
|
|
2013-09-06 16:38:53 +02:00
|
|
|
Returns whether the directory for projects is to be used or whether the user
|
|
|
|
chose to use the current directory.
|
2009-11-26 18:03:16 +01:00
|
|
|
|
|
|
|
\sa setProjectsDirectory, setUseProjectsDirectory
|
|
|
|
*/
|
|
|
|
|
2012-02-14 16:43:51 +01:00
|
|
|
bool DocumentManager::useProjectsDirectory()
|
2009-11-26 18:03:16 +01:00
|
|
|
{
|
|
|
|
return d->m_useProjectsDirectory;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
|
|
|
|
Sets whether the directory for projects is to be used.
|
|
|
|
|
|
|
|
\sa projectsDirectory, useProjectsDirectory
|
|
|
|
*/
|
|
|
|
|
2012-02-14 16:43:51 +01:00
|
|
|
void DocumentManager::setUseProjectsDirectory(bool useProjectsDirectory)
|
2009-11-26 18:03:16 +01:00
|
|
|
{
|
|
|
|
d->m_useProjectsDirectory = useProjectsDirectory;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
|
2013-09-06 16:38:53 +02:00
|
|
|
Returns the last visited directory of a file dialog.
|
2009-11-26 18:03:16 +01:00
|
|
|
|
|
|
|
\sa setFileDialogLastVisitedDirectory, fileDialogInitialDirectory
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
2012-02-14 16:43:51 +01:00
|
|
|
QString DocumentManager::fileDialogLastVisitedDirectory()
|
2009-11-26 18:03:16 +01:00
|
|
|
{
|
|
|
|
return d->m_lastVisitedDirectory;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
|
2013-09-06 16:38:53 +02:00
|
|
|
Sets the last visited directory of a file dialog that will be remembered
|
2009-11-26 18:03:16 +01:00
|
|
|
for the next one.
|
|
|
|
|
|
|
|
\sa fileDialogLastVisitedDirectory, fileDialogInitialDirectory
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
2012-02-14 16:43:51 +01:00
|
|
|
void DocumentManager::setFileDialogLastVisitedDirectory(const QString &directory)
|
2009-11-26 18:03:16 +01:00
|
|
|
{
|
|
|
|
d->m_lastVisitedDirectory = directory;
|
|
|
|
}
|
|
|
|
|
2012-02-14 16:43:51 +01:00
|
|
|
void DocumentManager::notifyFilesChangedInternally(const QStringList &files)
|
2009-12-21 11:08:20 +01:00
|
|
|
{
|
2012-01-19 23:23:43 +01:00
|
|
|
emit m_instance->filesChangedInternally(files);
|
2009-12-21 11:08:20 +01:00
|
|
|
}
|
|
|
|
|
2013-06-10 15:28:26 +02:00
|
|
|
bool DocumentManager::eventFilter(QObject *obj, QEvent *e)
|
|
|
|
{
|
|
|
|
if (obj == qApp && e->type() == QEvent::ApplicationActivate) {
|
|
|
|
// activeWindow is not necessarily set yet, do checkForReload asynchronously
|
|
|
|
QTimer::singleShot(0, this, SLOT(checkForReload()));
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2009-11-26 18:03:16 +01:00
|
|
|
// -------------- FileChangeBlocker
|
|
|
|
|
2009-06-18 14:30:04 +02:00
|
|
|
FileChangeBlocker::FileChangeBlocker(const QString &fileName)
|
2010-01-22 16:49:57 +01:00
|
|
|
: m_fileName(fileName)
|
2009-06-18 14:30:04 +02:00
|
|
|
{
|
2012-02-14 16:43:51 +01:00
|
|
|
DocumentManager::expectFileChange(fileName);
|
2009-06-18 14:30:04 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
FileChangeBlocker::~FileChangeBlocker()
|
|
|
|
{
|
2012-02-14 16:43:51 +01:00
|
|
|
DocumentManager::unexpectFileChange(m_fileName);
|
2009-06-18 14:30:04 +02:00
|
|
|
}
|
2009-11-25 10:09:45 +01:00
|
|
|
|
|
|
|
} // namespace Core
|