2012-10-02 09:12:39 +02:00
|
|
|
/****************************************************************************
|
2008-12-02 12:01:29 +01:00
|
|
|
**
|
2014-01-07 13:27:11 +01:00
|
|
|
** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
|
2012-10-02 09:12:39 +02:00
|
|
|
** Contact: http://www.qt-project.org/legal
|
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
|
|
|
|
** a written agreement between you and Digia. For licensing terms and
|
|
|
|
** conditions see http://qt.digia.com/licensing. For further information
|
|
|
|
** use the contact form at http://qt.digia.com/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
|
|
|
|
** General Public License version 2.1 as published by the Free Software
|
|
|
|
** Foundation and appearing in the file LICENSE.LGPL included in the
|
|
|
|
** packaging of this file. Please review the following information to
|
|
|
|
** ensure the GNU Lesser General Public License version 2.1 requirements
|
|
|
|
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
|
|
|
**
|
|
|
|
** In addition, as a special exception, Digia gives you certain additional
|
|
|
|
** rights. These rights are described in the Digia Qt 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"
|
2009-01-23 13:03:36 +01:00
|
|
|
#include "mimedatabase.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>
|
|
|
|
#include <coreplugin/editormanager/ieditor.h>
|
|
|
|
#include <coreplugin/editormanager/ieditorfactory.h>
|
|
|
|
#include <coreplugin/editormanager/iexternaleditor.h>
|
2012-10-15 11:53:22 +02:00
|
|
|
|
2012-08-23 15:53:58 +02:00
|
|
|
#include <utils/hostosinfo.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
|
|
|
|
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 {
|
|
|
|
|
2011-12-09 11:09:59 +01:00
|
|
|
struct OpenWithEntry
|
|
|
|
{
|
|
|
|
OpenWithEntry() : editorFactory(0), externalEditor(0) {}
|
|
|
|
IEditorFactory *editorFactory;
|
|
|
|
IExternalEditor *externalEditor;
|
|
|
|
QString fileName;
|
|
|
|
};
|
|
|
|
|
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;
|
|
|
|
|
|
|
|
QString m_currentFile;
|
|
|
|
|
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;
|
|
|
|
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;
|
|
|
|
static Internal::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
|
|
|
{
|
2012-08-23 15:53:58 +02:00
|
|
|
if (Utils::HostOsInfo::isAnyUnixHost()) {
|
|
|
|
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()),
|
2012-08-23 15:53:58 +02:00
|
|
|
m_useProjectsDirectory(Utils::HostOsInfo::isMacHost()), // Creator is in bizarre places when launched via finder.
|
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
|
|
|
|
|
|
|
|
Q_DECLARE_METATYPE(Core::Internal::OpenWithEntry)
|
|
|
|
|
|
|
|
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-05-07 19:03:22 +02:00
|
|
|
connect(ICore::instance(), SIGNAL(contextChanged(QList<Core::IContext*>,Core::Context)),
|
|
|
|
this, SLOT(syncWithEditor(QList<Core::IContext*>)));
|
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;
|
|
|
|
}
|
|
|
|
|
2013-08-29 17:56:28 +02:00
|
|
|
QObject *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();
|
|
|
|
if (!watcher->files().contains(fileName))
|
|
|
|
watcher->addPath(fileName);
|
|
|
|
|
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
|
|
|
{
|
2013-07-04 13:30:26 +02:00
|
|
|
const QString fixedName = DocumentManager::fixFileName(document->filePath(), DocumentManager::KeepLinks);
|
|
|
|
const QString fixedResolvedName = DocumentManager::fixFileName(document->filePath(), 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*)));
|
2013-07-04 13:30:26 +02:00
|
|
|
connect(document, SIGNAL(filePathChanged(QString,QString)), m_instance, SLOT(filePathChanged(QString,QString)));
|
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*)));
|
2013-07-04 13:30:26 +02:00
|
|
|
connect(document, SIGNAL(filePathChanged(QString,QString)), m_instance, SLOT(filePathChanged(QString,QString)));
|
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);
|
2013-07-04 13:30:26 +02:00
|
|
|
document->setFilePath(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
|
|
|
|
2013-07-04 13:30:26 +02:00
|
|
|
void DocumentManager::filePathChanged(const QString &oldName, const QString &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;
|
|
|
|
emit m_instance->documentRenamed(doc, oldName, newName);
|
|
|
|
}
|
|
|
|
|
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);
|
2012-08-23 15:53:58 +02:00
|
|
|
if (Utils::HostOsInfo::isWindowsHost())
|
|
|
|
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()) {
|
2013-07-04 13:30:26 +02:00
|
|
|
QString name = document->filePath();
|
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"));
|
|
|
|
if (roDialog.exec() == Core::Internal::ReadOnlyFilesDialog::RO_Cancel) {
|
|
|
|
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) {
|
2013-08-29 15:46:04 +02:00
|
|
|
if (!EditorManager::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;
|
2013-07-04 13:30:26 +02:00
|
|
|
QString effName = fileName.isEmpty() ? document->filePath() : 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);
|
|
|
|
bool suffixOk = false;
|
|
|
|
if (index != -1) {
|
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?"),
|
2010-09-07 11:55:52 +02:00
|
|
|
tr("An item named '%1' already exists at this location. "
|
|
|
|
"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("");
|
2013-07-04 13:30:26 +02:00
|
|
|
QString absoluteFilePath = document->filePath();
|
2008-12-02 12:01:29 +01:00
|
|
|
const QFileInfo fi(absoluteFilePath);
|
|
|
|
QString fileName = fi.fileName();
|
|
|
|
QString path = fi.absolutePath();
|
|
|
|
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;
|
|
|
|
}
|
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()) {
|
2013-08-30 16:38:57 +02:00
|
|
|
if (const MimeType &mt = MimeDatabase::findByFile(fi))
|
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"),
|
2008-12-02 12:01:29 +01:00
|
|
|
path + QDir::separator() + fileName,
|
|
|
|
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,
|
2009-11-26 18:03:16 +01:00
|
|
|
const QString pathIn,
|
|
|
|
QString *selectedFilter)
|
|
|
|
{
|
2010-07-13 15:27:08 +02:00
|
|
|
QString path = pathIn;
|
|
|
|
if (path.isEmpty()) {
|
|
|
|
if (!d->m_currentFile.isEmpty())
|
|
|
|
path = QFileInfo(d->m_currentFile).absoluteFilePath();
|
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-03-14 13:03:42 +01:00
|
|
|
if (QApplication::activeModalWidget()) { // a modal dialog, recheck later
|
|
|
|
QTimer::singleShot(200, this, SLOT(checkForReload()));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2010-01-22 16:49:57 +01:00
|
|
|
if (d->m_blockActivated)
|
|
|
|
return;
|
|
|
|
|
|
|
|
d->m_blockActivated = true;
|
|
|
|
|
2013-08-29 15:46:04 +02:00
|
|
|
IDocument::ReloadSetting defaultBehavior = EditorManager::reloadSetting();
|
2013-09-06 11:01:37 +02:00
|
|
|
Utils::ReloadPromptAnswer previousReloadAnswer = Utils::ReloadCurrent;
|
|
|
|
Utils::FileDeletedPromptAnswer previousDeletedAnswer = Utils::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
|
|
|
|
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
|
2013-09-06 11:01:37 +02:00
|
|
|
if (previousReloadAnswer == Utils::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);
|
2013-09-06 11:01:37 +02:00
|
|
|
} else if (previousReloadAnswer == Utils::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
|
2014-01-03 14:43:29 +01:00
|
|
|
previousReloadAnswer = Utils::reloadPrompt(document->filePath(), document->isModified(),
|
|
|
|
ICore::dialogParent());
|
2013-09-06 11:01:37 +02:00
|
|
|
switch (previousReloadAnswer) {
|
2010-11-23 12:47:45 +01:00
|
|
|
case Utils::ReloadAll:
|
|
|
|
case Utils::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;
|
|
|
|
case Utils::ReloadSkipCurrent:
|
|
|
|
case Utils::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;
|
2012-09-28 14:35:32 +02:00
|
|
|
case Utils::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) {
|
2013-09-06 11:01:37 +02:00
|
|
|
if (previousDeletedAnswer != Utils::FileDeletedCloseAll) {
|
|
|
|
previousDeletedAnswer =
|
|
|
|
Utils::fileDeletedPrompt(document->filePath(),
|
|
|
|
trigger == IDocument::TriggerExternal,
|
|
|
|
QApplication::activeWindow());
|
|
|
|
}
|
|
|
|
switch (previousDeletedAnswer) {
|
2010-11-23 12:47:45 +01:00
|
|
|
case Utils::FileDeletedSave:
|
2013-07-04 13:30:26 +02:00
|
|
|
documentsToSave.insert(document, document->filePath());
|
2010-11-23 12:47:45 +01:00
|
|
|
unhandled = false;
|
|
|
|
break;
|
|
|
|
case Utils::FileDeletedSaveAs:
|
|
|
|
{
|
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;
|
|
|
|
}
|
|
|
|
case Utils::FileDeletedClose:
|
2013-09-06 11:01:37 +02:00
|
|
|
case Utils::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())
|
2013-07-04 13:30:26 +02:00
|
|
|
errorStrings << tr("Cannot reload %1").arg(QDir::toNativeSeparators(document->filePath()));
|
2011-04-04 15:24:13 +02:00
|
|
|
else
|
|
|
|
errorStrings << errorString;
|
|
|
|
}
|
2010-03-19 10:28:05 +01:00
|
|
|
|
2010-11-23 12:47:45 +01:00
|
|
|
// update file info, also handling if e.g. link target has changed
|
2012-02-14 16:43:51 +01:00
|
|
|
removeFileInfo(document);
|
|
|
|
addFileInfo(document);
|
|
|
|
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"),
|
2011-04-04 15:24:13 +02:00
|
|
|
errorStrings.join(QLatin1String("\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
|
|
|
}
|
|
|
|
|
2013-05-07 19:03:22 +02:00
|
|
|
void DocumentManager::syncWithEditor(const QList<Core::IContext *> &context)
|
2008-12-02 12:01:29 +01:00
|
|
|
{
|
2013-05-07 19:03:22 +02:00
|
|
|
if (context.isEmpty())
|
2008-12-02 12:01:29 +01:00
|
|
|
return;
|
|
|
|
|
2012-05-08 09:43:14 +02:00
|
|
|
Core::IEditor *editor = Core::EditorManager::currentEditor();
|
2013-07-12 15:36:29 +02:00
|
|
|
if (!editor || editor->document()->isTemporary())
|
2013-05-07 19:03:22 +02:00
|
|
|
return;
|
|
|
|
foreach (IContext *c, context) {
|
|
|
|
if (editor->widget() == c->widget()) {
|
2013-07-04 13:30:26 +02:00
|
|
|
setCurrentFile(editor->document()->filePath());
|
2013-05-07 19:03:22 +02:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
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
|
|
|
*/
|
2012-02-14 16:43:51 +01:00
|
|
|
void DocumentManager::addToRecentFiles(const QString &fileName, const 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
|
|
|
}
|
|
|
|
|
2012-01-24 15:36:40 +01:00
|
|
|
QSettings *s = Core::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
|
|
|
{
|
2012-01-24 15:36:40 +01:00
|
|
|
QSettings *s = Core::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
|
2010-10-19 11:07:20 +02:00
|
|
|
d->m_projectsDirectory = Utils::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
|
|
|
}
|
|
|
|
|
2008-12-02 12:01:29 +01:00
|
|
|
/*!
|
|
|
|
|
2013-09-06 16:38:53 +02:00
|
|
|
The current file is the file currently opened when an editor is active,
|
|
|
|
or the selected file in case a Project Explorer is active.
|
2008-12-02 12:01:29 +01:00
|
|
|
|
2009-04-24 16:00:19 +02:00
|
|
|
\sa currentFile
|
2008-12-02 12:01:29 +01:00
|
|
|
*/
|
2012-02-14 16:43:51 +01:00
|
|
|
void DocumentManager::setCurrentFile(const QString &filePath)
|
2008-12-02 12:01:29 +01:00
|
|
|
{
|
2009-11-25 10:09:45 +01:00
|
|
|
if (d->m_currentFile == filePath)
|
2008-12-02 12:01:29 +01:00
|
|
|
return;
|
2009-11-25 10:09:45 +01:00
|
|
|
d->m_currentFile = filePath;
|
2012-01-19 23:23:43 +01:00
|
|
|
emit m_instance->currentFileChanged(d->m_currentFile);
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
2013-09-06 16:38:53 +02:00
|
|
|
Returns the absolute path of the current file.
|
2008-12-02 12:01:29 +01:00
|
|
|
|
2013-09-06 16:38:53 +02:00
|
|
|
The current file is the file currently opened when an editor is active,
|
|
|
|
or the selected file in case a Project Explorer is active.
|
2008-12-02 12:01:29 +01:00
|
|
|
|
2009-04-24 16:00:19 +02:00
|
|
|
\sa setCurrentFile
|
2008-12-02 12:01:29 +01:00
|
|
|
*/
|
2012-02-14 16:43:51 +01:00
|
|
|
QString DocumentManager::currentFile()
|
2008-12-02 12:01:29 +01:00
|
|
|
{
|
2009-11-25 10:09:45 +01:00
|
|
|
return d->m_currentFile;
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
2009-11-26 18:03:16 +01:00
|
|
|
/*!
|
|
|
|
|
|
|
|
Returns the initial directory for a new file dialog. If there is
|
2013-09-06 16:38:53 +02:00
|
|
|
a current file, uses that, otherwise uses the last visited directory.
|
2009-11-26 18:03:16 +01:00
|
|
|
|
|
|
|
\sa setFileDialogLastVisitedDirectory
|
|
|
|
*/
|
|
|
|
|
2012-02-14 16:43:51 +01:00
|
|
|
QString DocumentManager::fileDialogInitialDirectory()
|
2009-11-26 18:03:16 +01:00
|
|
|
{
|
|
|
|
if (!d->m_currentFile.isEmpty())
|
2010-07-13 14:23:10 +02:00
|
|
|
return QFileInfo(d->m_currentFile).absolutePath();
|
2009-11-26 18:03:16 +01:00
|
|
|
return d->m_lastVisitedDirectory;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
|
|
|
|
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
|
|
|
}
|
|
|
|
|
2012-02-14 16:43:51 +01:00
|
|
|
void DocumentManager::populateOpenWithMenu(QMenu *menu, const QString &fileName)
|
2011-12-09 10:45:17 +01:00
|
|
|
{
|
|
|
|
typedef QList<IEditorFactory*> EditorFactoryList;
|
|
|
|
typedef QList<IExternalEditor*> ExternalEditorList;
|
|
|
|
|
|
|
|
menu->clear();
|
|
|
|
|
|
|
|
bool anyMatches = false;
|
|
|
|
|
2013-08-30 16:38:57 +02:00
|
|
|
if (const MimeType mt = MimeDatabase::findByFile(QFileInfo(fileName))) {
|
2012-05-08 09:43:14 +02:00
|
|
|
const EditorFactoryList factories = EditorManager::editorFactories(mt, false);
|
|
|
|
const ExternalEditorList externalEditors = EditorManager::externalEditors(mt, false);
|
2011-12-09 10:45:17 +01:00
|
|
|
anyMatches = !factories.empty() || !externalEditors.empty();
|
|
|
|
if (anyMatches) {
|
|
|
|
// Add all suitable editors
|
|
|
|
foreach (IEditorFactory *editorFactory, factories) {
|
|
|
|
// Add action to open with this very editor factory
|
|
|
|
QString const actionTitle = editorFactory->displayName();
|
|
|
|
QAction * const action = menu->addAction(actionTitle);
|
2012-01-19 23:23:43 +01:00
|
|
|
OpenWithEntry entry;
|
2011-12-09 11:09:59 +01:00
|
|
|
entry.editorFactory = editorFactory;
|
|
|
|
entry.fileName = fileName;
|
|
|
|
action->setData(qVariantFromValue(entry));
|
2011-12-09 10:45:17 +01:00
|
|
|
}
|
|
|
|
// Add all suitable external editors
|
|
|
|
foreach (IExternalEditor *externalEditor, externalEditors) {
|
|
|
|
QAction * const action = menu->addAction(externalEditor->displayName());
|
2012-01-19 23:23:43 +01:00
|
|
|
OpenWithEntry entry;
|
2011-12-09 11:09:59 +01:00
|
|
|
entry.externalEditor = externalEditor;
|
|
|
|
entry.fileName = fileName;
|
|
|
|
action->setData(qVariantFromValue(entry));
|
2011-12-09 10:45:17 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
menu->setEnabled(anyMatches);
|
|
|
|
}
|
|
|
|
|
2012-02-14 16:43:51 +01:00
|
|
|
void DocumentManager::executeOpenWithMenuAction(QAction *action)
|
2011-12-09 10:45:17 +01:00
|
|
|
{
|
2011-12-09 12:23:46 +01:00
|
|
|
QTC_ASSERT(action, return);
|
2011-12-09 10:45:17 +01:00
|
|
|
const QVariant data = action->data();
|
2012-09-18 17:18:37 +02:00
|
|
|
OpenWithEntry entry = qvariant_cast<OpenWithEntry>(data);
|
2011-12-09 11:09:59 +01:00
|
|
|
if (entry.editorFactory) {
|
2011-12-09 10:45:17 +01:00
|
|
|
// close any open editors that have this file open, but have a different type.
|
2013-07-18 12:26:23 +02:00
|
|
|
QList<IEditor *> editorsOpenForFile
|
|
|
|
= EditorManager::documentModel()->editorsForFilePath(entry.fileName);
|
2011-12-09 10:45:17 +01:00
|
|
|
if (!editorsOpenForFile.isEmpty()) {
|
|
|
|
foreach (IEditor *openEditor, editorsOpenForFile) {
|
2014-03-05 15:58:12 +01:00
|
|
|
if (entry.editorFactory->id() == openEditor->document()->id())
|
2011-12-09 10:45:17 +01:00
|
|
|
editorsOpenForFile.removeAll(openEditor);
|
|
|
|
}
|
2013-08-29 15:46:04 +02:00
|
|
|
if (!EditorManager::closeEditors(editorsOpenForFile)) // don't open if cancel was pressed
|
2011-12-09 10:45:17 +01:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2013-05-31 12:52:53 +02:00
|
|
|
EditorManager::openEditor(entry.fileName, entry.editorFactory->id());
|
2011-12-09 10:45:17 +01:00
|
|
|
return;
|
|
|
|
}
|
2011-12-09 11:09:59 +01:00
|
|
|
if (entry.externalEditor)
|
2012-05-08 09:43:14 +02:00
|
|
|
EditorManager::openExternalEditor(entry.fileName, entry.externalEditor->id());
|
2011-12-09 10:45:17 +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
|