2009-02-25 09:15:00 +01:00
|
|
|
/**************************************************************************
|
2008-12-02 12:01:29 +01:00
|
|
|
**
|
|
|
|
** This file is part of Qt Creator
|
|
|
|
**
|
2010-03-05 11:25:49 +01:00
|
|
|
** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
|
2008-12-02 12:01:29 +01:00
|
|
|
**
|
2009-06-17 00:01:27 +10:00
|
|
|
** Contact: Nokia Corporation (qt-info@nokia.com)
|
2008-12-02 12:01:29 +01:00
|
|
|
**
|
2009-02-25 09:15:00 +01:00
|
|
|
** Commercial Usage
|
2008-12-02 14:17:16 +01:00
|
|
|
**
|
2009-02-25 09:15:00 +01:00
|
|
|
** Licensees holding valid Qt Commercial licenses may use this file in
|
|
|
|
** accordance with the Qt Commercial License Agreement provided with the
|
|
|
|
** Software or, alternatively, in accordance with the terms contained in
|
|
|
|
** a written agreement between you and Nokia.
|
2008-12-02 14:17:16 +01:00
|
|
|
**
|
2009-02-25 09:15:00 +01:00
|
|
|
** GNU Lesser General Public License Usage
|
2008-12-02 14:17:16 +01:00
|
|
|
**
|
2009-02-25 09:15:00 +01: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.
|
2008-12-02 14:17:16 +01:00
|
|
|
**
|
2009-02-25 09:15:00 +01:00
|
|
|
** If you are unsure which license is appropriate for your use, please
|
2009-08-14 09:30:56 +02:00
|
|
|
** contact the sales department at http://qt.nokia.com/contact.
|
2008-12-02 12:01:29 +01:00
|
|
|
**
|
2009-02-25 09:15:00 +01:00
|
|
|
**************************************************************************/
|
2008-12-02 14:09:21 +01:00
|
|
|
|
2008-12-02 12:01:29 +01:00
|
|
|
#include "filemanager.h"
|
2008-12-09 15:25:01 +01:00
|
|
|
|
2009-01-23 13:03:36 +01:00
|
|
|
#include "editormanager.h"
|
2009-10-01 16:38:08 +02:00
|
|
|
#include "ieditor.h"
|
2009-01-23 13:03:36 +01:00
|
|
|
#include "icore.h"
|
2008-12-02 12:01:29 +01:00
|
|
|
#include "ifile.h"
|
2009-01-23 13:03:36 +01:00
|
|
|
#include "iversioncontrol.h"
|
|
|
|
#include "mimedatabase.h"
|
2008-12-02 12:01:29 +01:00
|
|
|
#include "saveitemsdialog.h"
|
|
|
|
#include "vcsmanager.h"
|
2010-09-07 11:55:52 +02:00
|
|
|
#include "coreconstants.h"
|
2008-12-02 12:01:29 +01:00
|
|
|
|
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
|
|
|
|
2008-12-02 12:01:29 +01:00
|
|
|
#include <QtCore/QSettings>
|
|
|
|
#include <QtCore/QFileInfo>
|
|
|
|
#include <QtCore/QFile>
|
|
|
|
#include <QtCore/QDir>
|
|
|
|
#include <QtCore/QTimer>
|
|
|
|
#include <QtCore/QFileSystemWatcher>
|
2009-11-25 10:09:45 +01:00
|
|
|
#include <QtCore/QDateTime>
|
2008-12-02 12:01:29 +01:00
|
|
|
#include <QtGui/QFileDialog>
|
|
|
|
#include <QtGui/QMessageBox>
|
2009-11-25 10:09:45 +01:00
|
|
|
#include <QtGui/QMainWindow>
|
2010-11-26 16:01:34 +01:00
|
|
|
#include <QtGui/QPushButton>
|
2008-12-02 12:01:29 +01:00
|
|
|
|
|
|
|
/*!
|
2010-07-12 16:53:07 +02:00
|
|
|
\class Core::FileManager
|
2008-12-02 12:01:29 +01:00
|
|
|
\mainclass
|
|
|
|
\inheaderfile filemanager.h
|
|
|
|
\brief Manages a set of IFile objects.
|
|
|
|
|
|
|
|
The FileManager service monitors a set of IFile's. Plugins should register
|
|
|
|
files they work with at the service. The files the IFile's point to will be
|
|
|
|
monitored at filesystem level. If a file changes, the status of the IFile's
|
|
|
|
will be adjusted accordingly. Furthermore, on application exit the user will
|
|
|
|
be asked to save all modified files.
|
|
|
|
|
|
|
|
Different IFile objects in the set can point to the same file in the
|
2010-01-22 16:49:57 +01:00
|
|
|
filesystem. The monitoring for a IFile can be blocked by blockFileChange(), and
|
2008-12-02 12:01:29 +01:00
|
|
|
enabled again by unblockFileChange().
|
|
|
|
|
2010-01-22 16:49:57 +01:00
|
|
|
The functions expectFileChange() and unexpectFileChange() mark a file change
|
|
|
|
as expected. On expected file changes all IFile objects are notified to reload
|
|
|
|
themselves.
|
|
|
|
|
2008-12-02 12:01:29 +01:00
|
|
|
The FileManager service also provides two convenience methods for saving
|
|
|
|
files: saveModifiedFiles() and saveModifiedFilesSilently(). Both take a list
|
|
|
|
of FileInterfaces as an argument, and return the list of files which were
|
|
|
|
_not_ saved.
|
|
|
|
|
|
|
|
The service also manages the list of recent files to be shown to the user
|
|
|
|
(see addToRecentFiles() and recentFiles()).
|
|
|
|
*/
|
|
|
|
|
2009-11-26 18:03:16 +01:00
|
|
|
static const char settingsGroupC[] = "RecentFiles";
|
|
|
|
static const char filesKeyC[] = "Files";
|
|
|
|
|
|
|
|
static const char directoryGroupC[] = "Directories";
|
|
|
|
static const char projectDirectoryKeyC[] = "Projects";
|
|
|
|
static const char useProjectDirectoryKeyC[] = "UseProjectsDirectory";
|
2008-12-02 12:01:29 +01:00
|
|
|
|
2009-11-25 10:09:45 +01:00
|
|
|
namespace Core {
|
|
|
|
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
|
|
|
|
{
|
|
|
|
QMap<IFile *, FileStateItem> lastUpdatedState;
|
|
|
|
FileStateItem expected;
|
|
|
|
};
|
|
|
|
|
2010-03-05 13:55:47 +01:00
|
|
|
|
2009-11-25 10:09:45 +01:00
|
|
|
struct FileManagerPrivate {
|
2010-11-26 16:01:34 +01:00
|
|
|
explicit FileManagerPrivate(FileManager *q, QMainWindow *mw);
|
2009-11-25 10:09:45 +01:00
|
|
|
|
2010-11-26 16:01:34 +01:00
|
|
|
static FileManager *m_instance;
|
2010-03-05 13:55:47 +01:00
|
|
|
QMap<QString, FileState> m_states;
|
2010-01-22 16:49:57 +01:00
|
|
|
QStringList m_changedFiles;
|
2010-03-05 13:55:47 +01:00
|
|
|
QList<IFile *> m_filesWithoutWatch;
|
2010-11-23 12:47:45 +01:00
|
|
|
QMap<IFile *, QStringList> m_filesWithWatch;
|
2009-11-25 10:09:45 +01:00
|
|
|
|
|
|
|
QStringList m_recentFiles;
|
|
|
|
static const int m_maxRecentFiles = 7;
|
|
|
|
|
|
|
|
QString m_currentFile;
|
|
|
|
|
|
|
|
QMainWindow *m_mainWindow;
|
|
|
|
QFileSystemWatcher *m_fileWatcher;
|
2010-11-23 12:47:45 +01:00
|
|
|
QFileSystemWatcher *m_linkWatcher;
|
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;
|
2010-05-11 14:13:38 +02:00
|
|
|
// When we are callling into a IFile
|
|
|
|
// we don't want to receive a changed()
|
|
|
|
// signal
|
|
|
|
// That makes the code easier
|
|
|
|
IFile *m_blockedIFile;
|
2009-11-25 10:09:45 +01:00
|
|
|
};
|
|
|
|
|
2010-11-26 16:01:34 +01:00
|
|
|
FileManager *FileManagerPrivate::m_instance = 0;
|
|
|
|
|
|
|
|
FileManagerPrivate::FileManagerPrivate(FileManager *q, QMainWindow *mw) :
|
2008-12-02 12:01:29 +01:00
|
|
|
m_mainWindow(mw),
|
2009-11-25 10:09:45 +01:00
|
|
|
m_fileWatcher(new QFileSystemWatcher(q)),
|
2009-11-26 18:03:16 +01:00
|
|
|
m_blockActivated(false),
|
|
|
|
m_lastVisitedDirectory(QDir::currentPath()),
|
|
|
|
#ifdef Q_OS_MAC // Creator is in bizarre places when launched via finder.
|
2010-05-11 14:13:38 +02:00
|
|
|
m_useProjectsDirectory(true),
|
2009-11-26 18:03:16 +01:00
|
|
|
#else
|
2010-05-11 14:13:38 +02:00
|
|
|
m_useProjectsDirectory(false),
|
2009-11-26 18:03:16 +01:00
|
|
|
#endif
|
2010-05-11 14:13:38 +02:00
|
|
|
m_blockedIFile(0)
|
2008-12-02 12:01:29 +01:00
|
|
|
{
|
2010-11-26 16:01:34 +01:00
|
|
|
m_instance = q;
|
2010-11-23 12:47:45 +01:00
|
|
|
q->connect(m_fileWatcher, SIGNAL(fileChanged(QString)),
|
|
|
|
q, SLOT(changedFile(QString)));
|
|
|
|
#ifdef Q_OS_UNIX
|
|
|
|
m_linkWatcher = new QFileSystemWatcher(q);
|
|
|
|
m_linkWatcher->setObjectName(QLatin1String("_qt_autotest_force_engine_poller"));
|
|
|
|
q->connect(m_linkWatcher, SIGNAL(fileChanged(QString)),
|
|
|
|
q, SLOT(changedFile(QString)));
|
|
|
|
#else
|
|
|
|
m_linkWatcher = m_fileWatcher;
|
|
|
|
#endif
|
2009-11-25 10:09:45 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
} // namespace Internal
|
|
|
|
|
|
|
|
FileManager::FileManager(QMainWindow *mw)
|
|
|
|
: QObject(mw),
|
|
|
|
d(new Internal::FileManagerPrivate(this, mw))
|
|
|
|
{
|
|
|
|
Core::ICore *core = Core::ICore::instance();
|
|
|
|
connect(d->m_mainWindow, SIGNAL(windowActivated()),
|
2008-12-02 12:01:29 +01:00
|
|
|
this, SLOT(mainWindowActivated()));
|
2010-06-25 13:12:50 +02:00
|
|
|
connect(core, SIGNAL(contextChanged(Core::IContext*,Core::Context)),
|
2008-12-02 12:01:29 +01:00
|
|
|
this, SLOT(syncWithEditor(Core::IContext*)));
|
|
|
|
|
2010-10-19 11:07:20 +02:00
|
|
|
readSettings();
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
2009-11-25 10:09:45 +01:00
|
|
|
FileManager::~FileManager()
|
|
|
|
{
|
|
|
|
delete d;
|
|
|
|
}
|
|
|
|
|
2010-11-26 16:01:34 +01:00
|
|
|
FileManager *FileManager::instance()
|
|
|
|
{
|
|
|
|
return Internal::FileManagerPrivate::m_instance;
|
|
|
|
}
|
|
|
|
|
2008-12-02 12:01:29 +01:00
|
|
|
/*!
|
2010-07-12 16:53:07 +02:00
|
|
|
\fn bool FileManager::addFiles(const QList<IFile *> &files, bool addWatcher)
|
2008-12-02 12:01:29 +01:00
|
|
|
|
2010-07-12 16:53:07 +02:00
|
|
|
Adds a list of IFile's to the collection. If \a addWatcher is true (the default),
|
|
|
|
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
|
|
|
*/
|
2010-11-18 18:11:15 +01:00
|
|
|
void FileManager::addFiles(const QList<IFile *> &files, 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
|
|
|
|
|
2010-11-26 16:01:34 +01:00
|
|
|
foreach (IFile *file, files) {
|
2010-11-23 12:47:45 +01:00
|
|
|
if (file && !d->m_filesWithoutWatch.contains(file)) {
|
|
|
|
connect(file, SIGNAL(destroyed(QObject *)), this, SLOT(fileDestroyed(QObject *)));
|
|
|
|
d->m_filesWithoutWatch.append(file);
|
|
|
|
}
|
|
|
|
}
|
2010-11-18 18:11:15 +01:00
|
|
|
return;
|
2010-03-05 13:55:47 +01:00
|
|
|
}
|
|
|
|
|
2008-12-02 12:01:29 +01:00
|
|
|
foreach (IFile *file, files) {
|
2010-11-23 12:47:45 +01:00
|
|
|
if (file && !d->m_filesWithWatch.contains(file)) {
|
|
|
|
connect(file, SIGNAL(changed()), this, SLOT(checkForNewFileName()));
|
|
|
|
connect(file, SIGNAL(destroyed(QObject *)), this, SLOT(fileDestroyed(QObject *)));
|
|
|
|
addFileInfo(file);
|
|
|
|
}
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-11-23 12:47:45 +01:00
|
|
|
/* Adds the IFile's file and possibly it's final link target to both m_states
|
|
|
|
(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.) */
|
2010-03-05 13:55:47 +01:00
|
|
|
void FileManager::addFileInfo(IFile *file)
|
2010-01-22 16:49:57 +01:00
|
|
|
{
|
2010-11-23 12:47:45 +01:00
|
|
|
const QString fixedName = fixFileName(file->fileName(), KeepLinks);
|
|
|
|
const QString fixedResolvedName = fixFileName(file->fileName(), ResolveLinks);
|
|
|
|
addFileInfo(fixedResolvedName, file, false);
|
|
|
|
if (fixedName != fixedResolvedName)
|
|
|
|
addFileInfo(fixedName, file, true);
|
|
|
|
}
|
2010-01-22 16:49:57 +01:00
|
|
|
|
2010-11-23 12:47:45 +01:00
|
|
|
/* only called from addFileInfo(IFile *) */
|
|
|
|
void FileManager::addFileInfo(const QString &fileName, IFile *file, bool isLink)
|
|
|
|
{
|
|
|
|
Internal::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
|
|
|
|
if (!d->m_states.contains(fileName)) {
|
|
|
|
d->m_states.insert(fileName, Internal::FileState());
|
|
|
|
|
|
|
|
if (isLink)
|
|
|
|
d->m_linkWatcher->addPath(fileName);
|
|
|
|
else
|
|
|
|
d->m_fileWatcher->addPath(fileName);
|
2010-03-19 10:28:05 +01:00
|
|
|
}
|
2010-11-23 12:47:45 +01:00
|
|
|
d->m_states[fileName].lastUpdatedState.insert(file, state);
|
2010-01-22 16:49:57 +01:00
|
|
|
}
|
2010-11-23 12:47:45 +01:00
|
|
|
d->m_filesWithWatch[file].append(fileName); // inserts a new QStringList if not already there
|
2010-01-22 16:49:57 +01:00
|
|
|
}
|
|
|
|
|
2010-11-23 12:47:45 +01:00
|
|
|
/* Updates the time stamp and permission information of the files
|
|
|
|
registered for this IFile (in m_filesWithWatch; can be the IFile's file + final link target) */
|
2010-01-22 16:49:57 +01:00
|
|
|
void FileManager::updateFileInfo(IFile *file)
|
|
|
|
{
|
2010-11-23 12:47:45 +01:00
|
|
|
foreach (const QString &fileName, d->m_filesWithWatch.value(file)) {
|
|
|
|
// If the filename is empty there's nothing to do
|
|
|
|
if (fileName.isEmpty())
|
|
|
|
continue;
|
|
|
|
const QFileInfo fi(fileName);
|
|
|
|
Internal::FileStateItem item;
|
|
|
|
item.modified = fi.lastModified();
|
|
|
|
item.permissions = fi.permissions();
|
|
|
|
QTC_ASSERT(d->m_states.contains(fileName), continue);
|
|
|
|
QTC_ASSERT(d->m_states.value(fileName).lastUpdatedState.contains(file), continue);
|
|
|
|
d->m_states[fileName].lastUpdatedState.insert(file, item);
|
|
|
|
}
|
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
|
|
|
|
void FileManager::dump()
|
|
|
|
{
|
2010-11-23 12:47:45 +01:00
|
|
|
qDebug() << "======== dumping state map";
|
2010-05-11 14:13:38 +02:00
|
|
|
QMap<QString, Internal::FileState>::const_iterator it, end;
|
|
|
|
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
|
|
|
|
|
|
|
QMap<IFile *, Internal::FileStateItem>::const_iterator jt, jend;
|
|
|
|
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";
|
|
|
|
foreach (IFile *key, d->m_filesWithWatch.keys()) {
|
|
|
|
qDebug() << key->fileName() << d->m_filesWithWatch.value(key);
|
|
|
|
}
|
|
|
|
qDebug() << "------- dumping watch list";
|
|
|
|
qDebug() << d->m_fileWatcher->files();
|
|
|
|
qDebug() << "------- dumping link watch list";
|
|
|
|
qDebug() << d->m_linkWatcher->files();
|
2010-05-11 14:13:38 +02:00
|
|
|
}
|
|
|
|
|
2010-11-23 12:47:45 +01:00
|
|
|
/*!
|
|
|
|
\fn void FileManager::renamedFile(const QString &from, QString &to)
|
|
|
|
\brief Tells the file manager that a file has been renamed on disk from within Qt Creator.
|
|
|
|
|
|
|
|
Needs to be called right after the actual renaming on disk (i.e. before the file system
|
|
|
|
watcher can report the event during the next event loop run). \a from needs to be an absolute file path.
|
|
|
|
This will notify all IFile objects pointing to that file of the rename
|
|
|
|
by calling IFile::rename, and update the cached time and permission
|
|
|
|
information to avoid annoying the user with "file has been removed"
|
|
|
|
popups.
|
|
|
|
*/
|
2010-11-26 16:01:34 +01:00
|
|
|
void FileManager::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
|
|
|
|
2010-11-23 12:47:45 +01:00
|
|
|
// gather the list of IFiles
|
|
|
|
QList<IFile *> filesToRename;
|
|
|
|
QMapIterator<IFile *, QStringList> it(d->m_filesWithWatch);
|
|
|
|
while (it.hasNext()) {
|
|
|
|
it.next();
|
|
|
|
if (it.value().contains(fixedFrom))
|
|
|
|
filesToRename.append(it.key());
|
2010-01-22 16:49:57 +01:00
|
|
|
}
|
|
|
|
|
2010-11-23 12:47:45 +01:00
|
|
|
// rename the IFiles
|
|
|
|
foreach (IFile *file, filesToRename) {
|
|
|
|
d->m_blockedIFile = file;
|
|
|
|
removeFileInfo(file);
|
|
|
|
file->rename(to);
|
|
|
|
addFileInfo(file);
|
|
|
|
d->m_blockedIFile = 0;
|
|
|
|
}
|
2010-01-22 16:49:57 +01:00
|
|
|
}
|
|
|
|
|
2010-11-23 12:47:45 +01:00
|
|
|
/* Removes all occurrances of the IFile from m_filesWithWatch and m_states.
|
|
|
|
If that results in a file no longer being referenced by any IFile, this
|
|
|
|
also removes the file watcher.
|
|
|
|
*/
|
|
|
|
void FileManager::removeFileInfo(IFile *file)
|
2010-01-22 16:49:57 +01:00
|
|
|
{
|
2010-11-23 12:47:45 +01:00
|
|
|
if (!d->m_filesWithWatch.contains(file))
|
|
|
|
return;
|
|
|
|
foreach (const QString &fileName, d->m_filesWithWatch.value(file)) {
|
|
|
|
if (!d->m_states.contains(fileName))
|
|
|
|
continue;
|
|
|
|
d->m_states[fileName].lastUpdatedState.remove(file);
|
|
|
|
if (d->m_states.value(fileName).lastUpdatedState.isEmpty()) {
|
|
|
|
if (d->m_fileWatcher->files().contains(fileName))
|
|
|
|
d->m_fileWatcher->removePath(fileName);
|
|
|
|
if (d->m_linkWatcher->files().contains(fileName))
|
|
|
|
d->m_linkWatcher->removePath(fileName);
|
|
|
|
d->m_states.remove(fileName);
|
|
|
|
}
|
2010-01-22 16:49:57 +01:00
|
|
|
}
|
2010-11-23 12:47:45 +01:00
|
|
|
d->m_filesWithWatch.remove(file);
|
2010-01-22 16:49:57 +01:00
|
|
|
}
|
|
|
|
|
2008-12-02 12:01:29 +01:00
|
|
|
/*!
|
2010-07-12 16:53:07 +02:00
|
|
|
\fn bool FileManager::addFile(IFile *files, bool addWatcher)
|
2008-12-02 12:01:29 +01:00
|
|
|
|
2010-07-12 16:53:07 +02:00
|
|
|
Adds a IFile object to the collection. If \a addWatcher is true (the default),
|
|
|
|
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
|
|
|
*/
|
2010-11-18 18:11:15 +01:00
|
|
|
void FileManager::addFile(IFile *file, bool addWatcher)
|
2008-12-02 12:01:29 +01:00
|
|
|
{
|
2010-11-18 18:11:15 +01:00
|
|
|
addFiles(QList<IFile *>() << file, addWatcher);
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void FileManager::fileDestroyed(QObject *obj)
|
|
|
|
{
|
|
|
|
IFile *file = static_cast<IFile*>(obj);
|
2010-03-05 13:55:47 +01:00
|
|
|
// Check the special unwatched first:
|
|
|
|
if (d->m_filesWithoutWatch.contains(file)) {
|
|
|
|
d->m_filesWithoutWatch.removeOne(file);
|
|
|
|
return;
|
|
|
|
}
|
2010-01-22 16:49:57 +01:00
|
|
|
removeFileInfo(file);
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
\fn bool FileManager::removeFile(IFile *file)
|
|
|
|
|
|
|
|
Removes a IFile object from the collection.
|
|
|
|
|
|
|
|
Returns true if the file specified by \a file has been part of the file list.
|
|
|
|
*/
|
2010-11-18 18:11:15 +01:00
|
|
|
void FileManager::removeFile(IFile *file)
|
2008-12-02 12:01:29 +01:00
|
|
|
{
|
2010-11-23 12:47:45 +01:00
|
|
|
QTC_ASSERT(file, return);
|
2008-12-02 12:01:29 +01:00
|
|
|
|
2010-03-05 13:55:47 +01:00
|
|
|
// Special casing unwatched files
|
|
|
|
if (d->m_filesWithoutWatch.contains(file)) {
|
|
|
|
disconnect(file, SIGNAL(destroyed(QObject *)), this, SLOT(fileDestroyed(QObject *)));
|
|
|
|
d->m_filesWithoutWatch.removeOne(file);
|
2010-11-18 18:11:15 +01:00
|
|
|
return;
|
2010-03-05 13:55:47 +01:00
|
|
|
}
|
|
|
|
|
2010-11-23 12:47:45 +01:00
|
|
|
removeFileInfo(file);
|
2008-12-02 12:01:29 +01:00
|
|
|
disconnect(file, SIGNAL(changed()), this, SLOT(checkForNewFileName()));
|
|
|
|
disconnect(file, SIGNAL(destroyed(QObject *)), this, SLOT(fileDestroyed(QObject *)));
|
|
|
|
}
|
|
|
|
|
2010-11-23 12:47:45 +01:00
|
|
|
/* Slot reacting on IFile::changed. We need to check if the signal was sent
|
|
|
|
because the file was saved under different name. */
|
2008-12-02 12:01:29 +01:00
|
|
|
void FileManager::checkForNewFileName()
|
|
|
|
{
|
|
|
|
IFile *file = qobject_cast<IFile *>(sender());
|
2010-05-11 14:13:38 +02:00
|
|
|
// We modified the IFile
|
|
|
|
// Trust the other code to also update the m_states map
|
|
|
|
if (file == d->m_blockedIFile)
|
|
|
|
return;
|
2008-12-09 15:25:01 +01:00
|
|
|
QTC_ASSERT(file, return);
|
2010-11-23 12:47:45 +01:00
|
|
|
QTC_ASSERT(d->m_filesWithWatch.contains(file), 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
|
|
|
|
removeFileInfo(file);
|
2010-03-05 13:55:47 +01:00
|
|
|
addFileInfo(file);
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
2010-11-23 12:47:45 +01:00
|
|
|
/*!
|
|
|
|
\fn QString FileManager::fixFileName(const QString &fileName, FixMode fixmode)
|
|
|
|
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).
|
|
|
|
*/
|
|
|
|
QString FileManager::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);
|
2008-12-02 12:01:29 +01:00
|
|
|
#ifdef Q_OS_WIN
|
|
|
|
s = s.toLower();
|
|
|
|
#endif
|
2010-03-23 16:33:21 +01:00
|
|
|
return s;
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
\fn QList<IFile*> FileManager::modifiedFiles() const
|
|
|
|
|
|
|
|
Returns the list of IFile's that have been modified.
|
|
|
|
*/
|
|
|
|
QList<IFile *> FileManager::modifiedFiles() const
|
|
|
|
{
|
|
|
|
QList<IFile *> modifiedFiles;
|
|
|
|
|
2010-11-23 12:47:45 +01:00
|
|
|
foreach (IFile *file, d->m_filesWithWatch.keys()) {
|
|
|
|
if (file->isModified())
|
|
|
|
modifiedFiles << file;
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
2010-11-23 12:47:45 +01:00
|
|
|
|
2010-03-05 13:55:47 +01:00
|
|
|
foreach(IFile *file, d->m_filesWithoutWatch) {
|
|
|
|
if (file->isModified())
|
|
|
|
modifiedFiles << file;
|
|
|
|
}
|
|
|
|
|
2008-12-02 12:01:29 +01:00
|
|
|
return modifiedFiles;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
\fn void FileManager::blockFileChange(IFile *file)
|
|
|
|
|
|
|
|
Blocks the monitoring of the file the \a file argument points to.
|
|
|
|
*/
|
|
|
|
void FileManager::blockFileChange(IFile *file)
|
|
|
|
{
|
2010-01-22 16:49:57 +01:00
|
|
|
// Nothing to do
|
|
|
|
Q_UNUSED(file);
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
\fn void FileManager::unblockFileChange(IFile *file)
|
|
|
|
|
|
|
|
Enables the monitoring of the file the \a file argument points to, and update the status of the corresponding IFile's.
|
|
|
|
*/
|
|
|
|
void FileManager::unblockFileChange(IFile *file)
|
|
|
|
{
|
2010-01-22 16:49:57 +01:00
|
|
|
// We are updating the lastUpdated time to the current modification time
|
|
|
|
// in changedFile we'll compare the modification time with the last updated
|
|
|
|
// time, and if they are the same, then we don't deliver that notification
|
|
|
|
// to corresponding IFile
|
|
|
|
//
|
|
|
|
// Also we are updating the expected time of the file
|
|
|
|
// 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
|
|
|
|
|
|
|
|
updateFileInfo(file);
|
2010-11-23 12:47:45 +01:00
|
|
|
foreach (const QString &fileName, d->m_filesWithWatch.value(file))
|
|
|
|
updateExpectedState(fileName);
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
2010-01-22 16:49:57 +01:00
|
|
|
/*!
|
|
|
|
\fn void FileManager::expectFileChange(const QString &fileName)
|
|
|
|
|
|
|
|
Any subsequent change to \a fileName is treated as a expected file change.
|
|
|
|
|
|
|
|
\see FileManager::unexpectFileChange(const QString &fileName)
|
|
|
|
*/
|
|
|
|
void FileManager::expectFileChange(const QString &fileName)
|
2008-12-02 12:01:29 +01:00
|
|
|
{
|
2010-01-22 16:49:57 +01:00
|
|
|
// Nothing to do
|
|
|
|
Q_UNUSED(fileName);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
\fn void FileManager::unexpectFileChange(const QString &fileName)
|
|
|
|
|
|
|
|
Any change to \a fileName are unexpected again.
|
|
|
|
|
|
|
|
\see FileManager::expectFileChange(const QString &fileName)
|
|
|
|
*/
|
|
|
|
void FileManager::unexpectFileChange(const QString &fileName)
|
|
|
|
{
|
|
|
|
// 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;
|
|
|
|
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
|
|
|
}
|
|
|
|
|
2010-11-23 12:47:45 +01:00
|
|
|
/* only called from unblock and unexpect file change methods */
|
2010-01-22 16:49:57 +01:00
|
|
|
void FileManager::updateExpectedState(const QString &fileName)
|
|
|
|
{
|
2010-11-23 12:47:45 +01:00
|
|
|
if (fileName.isEmpty())
|
2010-01-22 16:49:57 +01:00
|
|
|
return;
|
2010-11-23 12:47:45 +01:00
|
|
|
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-03-05 13:55:47 +01:00
|
|
|
}
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
\fn QList<IFile*> FileManager::saveModifiedFilesSilently(const QList<IFile*> &files)
|
|
|
|
|
|
|
|
Tries to save the files listed in \a files . Returns the files that could not be saved.
|
|
|
|
*/
|
|
|
|
QList<IFile *> FileManager::saveModifiedFilesSilently(const QList<IFile *> &files)
|
|
|
|
{
|
|
|
|
return saveModifiedFiles(files, 0, true, QString());
|
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
2010-07-12 16:53:07 +02:00
|
|
|
\fn QList<IFile*> FileManager::saveModifiedFiles(const QList<IFile *> &files, bool *cancelled, const QString &message, const QString &alwaysSaveMessage, bool *alwaysSave)
|
|
|
|
|
|
|
|
Asks the user whether to save the files listed in \a files .
|
|
|
|
Opens a dialog with the given \a message, and a additional
|
|
|
|
text that should be used to ask if the user wants to enabled automatic save
|
|
|
|
of modified files (in this context).
|
|
|
|
The \a cancelled argument is set to true if the user cancelled the dialog,
|
|
|
|
\a alwaysSave is set to match the selection of the user, if files should
|
|
|
|
always automatically be saved.
|
|
|
|
Returns the files that have not been saved.
|
2008-12-02 12:01:29 +01:00
|
|
|
*/
|
|
|
|
QList<IFile *> FileManager::saveModifiedFiles(const QList<IFile *> &files,
|
2009-05-06 11:55:21 +02:00
|
|
|
bool *cancelled, const QString &message,
|
|
|
|
const QString &alwaysSaveMessage,
|
|
|
|
bool *alwaysSave)
|
2008-12-02 12:01:29 +01:00
|
|
|
{
|
2009-05-06 11:55:21 +02:00
|
|
|
return saveModifiedFiles(files, cancelled, false, message, alwaysSaveMessage, alwaysSave);
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
static QMessageBox::StandardButton skipFailedPrompt(QWidget *parent, const QString &fileName)
|
|
|
|
{
|
|
|
|
return QMessageBox::question(parent,
|
2009-09-29 12:17:37 +02:00
|
|
|
FileManager::tr("Cannot save file"),
|
|
|
|
FileManager::tr("Cannot save changes to '%1'. Do you want to continue and lose your changes?").arg(fileName),
|
2008-12-02 12:01:29 +01:00
|
|
|
QMessageBox::YesToAll| QMessageBox::Yes|QMessageBox::No,
|
|
|
|
QMessageBox::No);
|
|
|
|
}
|
|
|
|
|
|
|
|
QList<IFile *> FileManager::saveModifiedFiles(const QList<IFile *> &files,
|
2009-05-06 11:55:21 +02:00
|
|
|
bool *cancelled,
|
|
|
|
bool silently,
|
|
|
|
const QString &message,
|
|
|
|
const QString &alwaysSaveMessage,
|
|
|
|
bool *alwaysSave)
|
2008-12-02 12:01:29 +01:00
|
|
|
{
|
|
|
|
if (cancelled)
|
|
|
|
(*cancelled) = false;
|
|
|
|
|
|
|
|
QList<IFile *> notSaved;
|
2009-03-24 12:51:44 +01:00
|
|
|
QMap<IFile *, QString> modifiedFilesMap;
|
|
|
|
QList<IFile *> modifiedFiles;
|
2008-12-02 12:01:29 +01:00
|
|
|
|
|
|
|
foreach (IFile *file, files) {
|
|
|
|
if (file->isModified()) {
|
|
|
|
QString name = file->fileName();
|
|
|
|
if (name.isEmpty())
|
|
|
|
name = file->suggestedFileName();
|
|
|
|
|
|
|
|
// There can be several FileInterfaces pointing to the same file
|
|
|
|
// Select one that is not readonly.
|
2009-12-09 15:30:23 +01:00
|
|
|
if (!(modifiedFilesMap.key(name, 0)
|
|
|
|
&& file->isReadOnly()))
|
2009-03-24 12:51:44 +01:00
|
|
|
modifiedFilesMap.insert(file, name);
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
}
|
2009-03-24 12:51:44 +01:00
|
|
|
modifiedFiles = modifiedFilesMap.keys();
|
2008-12-02 12:01:29 +01:00
|
|
|
if (!modifiedFiles.isEmpty()) {
|
|
|
|
QList<IFile *> filesToSave;
|
|
|
|
if (silently) {
|
2009-03-24 12:51:44 +01:00
|
|
|
filesToSave = modifiedFiles;
|
2008-12-02 12:01:29 +01:00
|
|
|
} else {
|
2009-11-25 10:09:45 +01:00
|
|
|
Internal::SaveItemsDialog dia(d->m_mainWindow, modifiedFiles);
|
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)
|
|
|
|
*alwaysSave = dia.alwaysSaveChecked();
|
2009-03-24 12:51:44 +01:00
|
|
|
notSaved = modifiedFiles;
|
2008-12-02 12:01:29 +01:00
|
|
|
return notSaved;
|
|
|
|
}
|
2009-05-06 11:55:21 +02:00
|
|
|
if (alwaysSave)
|
|
|
|
*alwaysSave = dia.alwaysSaveChecked();
|
2008-12-02 12:01:29 +01:00
|
|
|
filesToSave = dia.itemsToSave();
|
|
|
|
}
|
|
|
|
|
|
|
|
bool yestoall = false;
|
2009-11-25 10:09:45 +01:00
|
|
|
Core::VCSManager *vcsManager = Core::ICore::instance()->vcsManager();
|
2008-12-02 12:01:29 +01:00
|
|
|
foreach (IFile *file, filesToSave) {
|
2009-03-24 12:51:44 +01:00
|
|
|
if (file->isReadOnly()) {
|
2009-11-25 10:09:45 +01:00
|
|
|
const QString directory = QFileInfo(file->fileName()).absolutePath();
|
|
|
|
if (IVersionControl *versionControl = vcsManager->findVersionControlForDirectory(directory))
|
2008-12-02 12:01:29 +01:00
|
|
|
versionControl->vcsOpen(file->fileName());
|
|
|
|
}
|
|
|
|
if (!file->isReadOnly() && !file->fileName().isEmpty()) {
|
|
|
|
blockFileChange(file);
|
|
|
|
const bool ok = file->save();
|
|
|
|
unblockFileChange(file);
|
|
|
|
if (!ok)
|
|
|
|
notSaved.append(file);
|
|
|
|
} else if (QFile::exists(file->fileName()) && !file->isSaveAsAllowed()) {
|
|
|
|
if (yestoall)
|
|
|
|
continue;
|
|
|
|
const QFileInfo fi(file->fileName());
|
2009-11-25 10:09:45 +01:00
|
|
|
switch (skipFailedPrompt(d->m_mainWindow, fi.fileName())) {
|
2008-12-02 12:01:29 +01:00
|
|
|
case QMessageBox::YesToAll:
|
|
|
|
yestoall = true;
|
|
|
|
break;
|
|
|
|
case QMessageBox::No:
|
|
|
|
if (cancelled)
|
|
|
|
*cancelled = true;
|
|
|
|
return filesToSave;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
QString fileName = getSaveAsFileName(file);
|
|
|
|
bool ok = false;
|
|
|
|
if (!fileName.isEmpty()) {
|
|
|
|
blockFileChange(file);
|
|
|
|
ok = file->save(fileName);
|
2009-05-08 17:57:27 +02:00
|
|
|
file->checkPermissions();
|
2008-12-02 12:01:29 +01:00
|
|
|
unblockFileChange(file);
|
|
|
|
}
|
|
|
|
if (!ok)
|
|
|
|
notSaved.append(file);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return notSaved;
|
|
|
|
}
|
|
|
|
|
2010-09-07 11:55:52 +02:00
|
|
|
QString FileManager::getSaveFileName(const QString &title, const QString &pathIn,
|
|
|
|
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(
|
|
|
|
d->m_mainWindow, title, path, filter, selectedFilter, QFileDialog::DontConfirmOverwrite);
|
|
|
|
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)
|
|
|
|
QRegExp regExp(".*\\s+\\((.*)\\)$");
|
|
|
|
const int index = regExp.lastIndexIn(*selectedFilter);
|
|
|
|
bool suffixOk = false;
|
|
|
|
if (index != -1) {
|
|
|
|
const QStringList &suffixes = regExp.cap(1).remove('*').split(' ');
|
|
|
|
foreach (const QString &suffix, suffixes)
|
|
|
|
if (fileName.endsWith(suffix)) {
|
|
|
|
suffixOk = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (!suffixOk && !suffixes.isEmpty())
|
|
|
|
fileName.append(suffixes.at(0));
|
|
|
|
}
|
|
|
|
}
|
2008-12-02 12:01:29 +01:00
|
|
|
if (QFile::exists(fileName)) {
|
2009-11-25 10:09:45 +01:00
|
|
|
if (QMessageBox::warning(d->m_mainWindow, 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;
|
|
|
|
}
|
|
|
|
|
2010-09-07 11:55:52 +02:00
|
|
|
QString FileManager::getSaveFileNameWithExtension(const QString &title, const QString &pathIn,
|
|
|
|
const QString &filter)
|
|
|
|
{
|
|
|
|
QString selected = filter;
|
|
|
|
return getSaveFileName(title, pathIn, filter, &selected);
|
|
|
|
}
|
|
|
|
|
2008-12-02 12:01:29 +01:00
|
|
|
/*!
|
|
|
|
\fn QString FileManager::getSaveAsFileName(IFile *file)
|
|
|
|
|
|
|
|
Asks the user for a new file name (Save File As) for /arg file.
|
|
|
|
*/
|
2010-09-07 11:55:52 +02:00
|
|
|
QString FileManager::getSaveAsFileName(IFile *file, const QString &filter, QString *selectedFilter)
|
2008-12-02 12:01:29 +01:00
|
|
|
{
|
|
|
|
if (!file)
|
|
|
|
return QLatin1String("");
|
|
|
|
QString absoluteFilePath = file->fileName();
|
|
|
|
const QFileInfo fi(absoluteFilePath);
|
|
|
|
QString fileName = fi.fileName();
|
|
|
|
QString path = fi.absolutePath();
|
|
|
|
if (absoluteFilePath.isEmpty()) {
|
|
|
|
fileName = file->suggestedFileName();
|
|
|
|
const QString defaultPath = file->defaultPath();
|
|
|
|
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()) {
|
|
|
|
if (const MimeType &mt = Core::ICore::instance()->mimeDatabase()->findByFile(fi))
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2009-11-26 18:03:16 +01:00
|
|
|
/*!
|
2010-07-12 16:53:07 +02:00
|
|
|
\fn QString FileManager::getOpenFileNames(const QString &filters, const QString &pathIn, QString *selectedFilter) const
|
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
|
|
|
|
and \a selectedFilter parameters is interpreted like in
|
|
|
|
QFileDialog::getOpenFileNames(), \a pathIn specifies a path to open the dialog
|
|
|
|
in, if that is not overridden by the users policy.
|
2009-11-26 18:03:16 +01:00
|
|
|
*/
|
|
|
|
|
|
|
|
QStringList FileManager::getOpenFileNames(const QString &filters,
|
|
|
|
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
|
|
|
}
|
2009-11-26 18:03:16 +01:00
|
|
|
const QStringList files = QFileDialog::getOpenFileNames(d->m_mainWindow,
|
|
|
|
tr("Open File"),
|
|
|
|
path, filters,
|
|
|
|
selectedFilter);
|
|
|
|
if (!files.isEmpty())
|
|
|
|
setFileDialogLastVisitedDirectory(QFileInfo(files.front()).absolutePath());
|
|
|
|
return files;
|
|
|
|
}
|
|
|
|
|
2010-11-26 16:01:34 +01:00
|
|
|
FileManager::ReadOnlyAction
|
|
|
|
FileManager::promptReadOnlyFile(const QString &fileName,
|
|
|
|
const IVersionControl *versionControl,
|
|
|
|
QWidget *parent,
|
|
|
|
bool displaySaveAsButton)
|
|
|
|
{
|
|
|
|
// Version Control: If automatic open is desired, open right away.
|
|
|
|
bool promptVCS = false;
|
|
|
|
if (versionControl && versionControl->supportsOperation(IVersionControl::OpenOperation)) {
|
|
|
|
if (versionControl->settingsFlags() & IVersionControl::AutoOpen)
|
|
|
|
return RO_OpenVCS;
|
|
|
|
promptVCS = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Create message box.
|
|
|
|
QMessageBox msgBox(QMessageBox::Question, tr("File is Read Only"),
|
|
|
|
tr("The file <i>%1</i> is read only.").arg(QDir::toNativeSeparators(fileName)),
|
|
|
|
QMessageBox::Cancel, parent);
|
|
|
|
|
|
|
|
QPushButton *vcsButton = 0;
|
|
|
|
if (promptVCS)
|
|
|
|
vcsButton = msgBox.addButton(tr("Open with VCS (%1)").arg(versionControl->displayName()), QMessageBox::AcceptRole);
|
|
|
|
|
|
|
|
QPushButton *makeWritableButton = msgBox.addButton(tr("Make writable"), QMessageBox::AcceptRole);
|
|
|
|
|
|
|
|
QPushButton *saveAsButton = 0;
|
|
|
|
if (displaySaveAsButton)
|
|
|
|
saveAsButton = msgBox.addButton(tr("Save as ..."), QMessageBox::ActionRole);
|
|
|
|
|
|
|
|
msgBox.setDefaultButton(vcsButton ? vcsButton : makeWritableButton);
|
|
|
|
msgBox.exec();
|
|
|
|
|
|
|
|
QAbstractButton *clickedButton = msgBox.clickedButton();
|
|
|
|
if (clickedButton == vcsButton)
|
|
|
|
return RO_OpenVCS;
|
|
|
|
if (clickedButton == makeWritableButton)
|
|
|
|
return RO_MakeWriteable;
|
2010-12-01 12:52:17 +01:00
|
|
|
if (displaySaveAsButton && clickedButton == saveAsButton)
|
2010-11-26 16:01:34 +01:00
|
|
|
return RO_SaveAs;
|
|
|
|
return RO_Cancel;
|
|
|
|
}
|
2009-11-26 18:03:16 +01:00
|
|
|
|
2010-01-22 16:49:57 +01:00
|
|
|
void FileManager::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
|
|
|
|
2010-11-23 12:47:45 +01:00
|
|
|
if (!d->m_changedFiles.contains(fileName) && d->m_states.contains(fileName))
|
|
|
|
d->m_changedFiles.append(fileName);
|
2010-01-22 16:49:57 +01:00
|
|
|
|
2009-11-25 10:09:45 +01: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
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void FileManager::mainWindowActivated()
|
|
|
|
{
|
2008-12-02 17:34:00 +01:00
|
|
|
//we need to do this asynchronously because
|
|
|
|
//opening a dialog ("Reload?") in a windowactivated event
|
|
|
|
//freezes on Mac
|
|
|
|
QTimer::singleShot(0, this, SLOT(checkForReload()));
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void FileManager::checkForReload()
|
|
|
|
{
|
2010-11-23 12:47:45 +01:00
|
|
|
if (d->m_changedFiles.isEmpty())
|
|
|
|
return;
|
2010-01-22 16:49:57 +01:00
|
|
|
if (QApplication::activeWindow() != d->m_mainWindow)
|
|
|
|
return;
|
2008-12-02 12:01:29 +01:00
|
|
|
|
2010-01-22 16:49:57 +01:00
|
|
|
if (d->m_blockActivated)
|
|
|
|
return;
|
|
|
|
|
|
|
|
d->m_blockActivated = true;
|
|
|
|
|
2010-03-19 10:28:05 +01:00
|
|
|
IFile::ReloadSetting defaultBehavior = EditorManager::instance()->reloadSetting();
|
|
|
|
Utils::ReloadPromptAnswer previousAnswer = Utils::ReloadCurrent;
|
2010-01-22 16:49:57 +01:00
|
|
|
|
2010-03-19 10:28:05 +01:00
|
|
|
QList<IEditor*> editorsToClose;
|
|
|
|
QMap<IFile*, QString> filesToSave;
|
2010-11-23 12:47:45 +01:00
|
|
|
|
|
|
|
// collect file information
|
|
|
|
QMap<QString, Internal::FileStateItem> currentStates;
|
|
|
|
QMap<QString, IFile::ChangeType> changeTypes;
|
|
|
|
QSet<IFile *> changedIFiles;
|
2010-03-19 10:28:05 +01:00
|
|
|
foreach (const QString &fileName, d->m_changedFiles) {
|
|
|
|
IFile::ChangeType type = IFile::TypeContents;
|
2010-11-23 12:47:45 +01:00
|
|
|
Internal::FileStateItem state;
|
2010-01-22 16:49:57 +01:00
|
|
|
QFileInfo fi(fileName);
|
2010-03-19 10:28:05 +01:00
|
|
|
if (!fi.exists()) {
|
|
|
|
type = IFile::TypeRemoved;
|
|
|
|
} 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);
|
|
|
|
foreach (IFile *file, d->m_states.value(fileName).lastUpdatedState.keys())
|
|
|
|
changedIFiles.insert(file);
|
|
|
|
}
|
|
|
|
|
|
|
|
// handle the IFiles
|
|
|
|
foreach (IFile *file, changedIFiles) {
|
|
|
|
IFile::ChangeTrigger behavior = IFile::TriggerInternal;
|
|
|
|
IFile::ChangeType type = IFile::TypePermissions;
|
|
|
|
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)
|
|
|
|
foreach (const QString & fileName, d->m_filesWithWatch.value(file)) {
|
|
|
|
// was the file reported?
|
|
|
|
if (!currentStates.contains(fileName))
|
|
|
|
continue;
|
2010-01-22 16:49:57 +01:00
|
|
|
|
2010-11-23 12:47:45 +01:00
|
|
|
Internal::FileStateItem currentState = currentStates.value(fileName);
|
|
|
|
Internal::FileStateItem expectedState = d->m_states.value(fileName).expected;
|
|
|
|
Internal::FileStateItem lastState = d->m_states.value(fileName).lastUpdatedState.value(file);
|
|
|
|
// 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?
|
|
|
|
if (currentState.modified != expectedState.modified || currentState.permissions != expectedState.permissions) {
|
|
|
|
behavior = IFile::TriggerExternal;
|
2010-03-19 10:28:05 +01:00
|
|
|
}
|
2010-11-23 12:47:45 +01:00
|
|
|
|
|
|
|
// find out the type
|
|
|
|
IFile::ChangeType fileChange = changeTypes.value(fileName);
|
|
|
|
if (fileChange == IFile::TypeRemoved) {
|
|
|
|
type = IFile::TypeRemoved;
|
|
|
|
behavior = IFile::TriggerExternal; // removed files always trigger externally
|
|
|
|
} else if (fileChange == IFile::TypeContents && type == IFile::TypePermissions) {
|
|
|
|
type = IFile::TypeContents;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!changed) // probably because the change was blocked with (un)blockFileChange
|
|
|
|
continue;
|
|
|
|
|
|
|
|
// handle it!
|
|
|
|
d->m_blockedIFile = file;
|
|
|
|
|
|
|
|
// we've got some modification
|
|
|
|
// check if it's contents or permissions:
|
|
|
|
if (type == IFile::TypePermissions) {
|
|
|
|
// Only permission change
|
|
|
|
file->reload(IFile::FlagReload, IFile::TypePermissions);
|
|
|
|
// now we know it's a content change or file was removed
|
|
|
|
} else if (defaultBehavior == IFile::ReloadUnmodified
|
|
|
|
&& type == IFile::TypeContents && !file->isModified()) {
|
|
|
|
// content change, but unmodified (and settings say to reload in this case)
|
|
|
|
file->reload(IFile::FlagReload, type);
|
|
|
|
// file was removed or it's a content change and the default behavior for
|
|
|
|
// unmodified files didn't kick in
|
|
|
|
} else if (defaultBehavior == IFile::IgnoreAll) {
|
|
|
|
// content change or removed, but settings say ignore
|
|
|
|
file->reload(IFile::FlagIgnore, type);
|
|
|
|
// either the default behavior is to always ask,
|
|
|
|
// or the ReloadUnmodified default behavior didn't kick in,
|
|
|
|
// so do whatever the IFile wants us to do
|
|
|
|
} else {
|
|
|
|
// check if IFile wants us to ask
|
|
|
|
if (file->reloadBehavior(behavior, type) == IFile::BehaviorSilent) {
|
|
|
|
// content change or removed, IFile wants silent handling
|
2010-03-19 10:28:05 +01:00
|
|
|
file->reload(IFile::FlagReload, type);
|
2010-11-23 12:47:45 +01:00
|
|
|
// IFile wants us to ask
|
|
|
|
} else if (type == IFile::TypeContents) {
|
|
|
|
// content change, IFile wants to ask user
|
|
|
|
if (previousAnswer == Utils::ReloadNone) {
|
|
|
|
// answer already given, ignore
|
|
|
|
file->reload(IFile::FlagIgnore, IFile::TypeContents);
|
|
|
|
} else if (previousAnswer == Utils::ReloadAll) {
|
|
|
|
// answer already given, reload
|
|
|
|
file->reload(IFile::FlagReload, IFile::TypeContents);
|
|
|
|
} else {
|
|
|
|
// Ask about content change
|
|
|
|
previousAnswer = Utils::reloadPrompt(file->fileName(), file->isModified(), QApplication::activeWindow());
|
|
|
|
switch (previousAnswer) {
|
|
|
|
case Utils::ReloadAll:
|
|
|
|
case Utils::ReloadCurrent:
|
2010-03-19 10:28:05 +01:00
|
|
|
file->reload(IFile::FlagReload, IFile::TypeContents);
|
2010-11-23 12:47:45 +01:00
|
|
|
break;
|
|
|
|
case Utils::ReloadSkipCurrent:
|
|
|
|
case Utils::ReloadNone:
|
|
|
|
file->reload(IFile::FlagIgnore, IFile::TypeContents);
|
|
|
|
break;
|
2010-03-19 10:28:05 +01:00
|
|
|
}
|
2010-11-23 12:47:45 +01:00
|
|
|
}
|
|
|
|
// IFile wants us to ask, and it's the TypeRemoved case
|
|
|
|
} else {
|
|
|
|
// Ask about removed file
|
|
|
|
bool unhandled = true;
|
|
|
|
while (unhandled) {
|
|
|
|
switch (Utils::fileDeletedPrompt(file->fileName(), QApplication::activeWindow())) {
|
|
|
|
case Utils::FileDeletedSave:
|
|
|
|
filesToSave.insert(file, file->fileName());
|
|
|
|
unhandled = false;
|
|
|
|
break;
|
|
|
|
case Utils::FileDeletedSaveAs:
|
|
|
|
{
|
|
|
|
const QString &saveFileName = getSaveAsFileName(file);
|
|
|
|
if (!saveFileName.isEmpty()) {
|
|
|
|
filesToSave.insert(file, saveFileName);
|
2010-03-19 10:28:05 +01:00
|
|
|
unhandled = false;
|
|
|
|
}
|
2010-11-23 12:47:45 +01:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
case Utils::FileDeletedClose:
|
|
|
|
editorsToClose << EditorManager::instance()->editorsForFile(file);
|
|
|
|
unhandled = false;
|
|
|
|
break;
|
2010-01-22 16:49:57 +01:00
|
|
|
}
|
|
|
|
}
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
}
|
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
|
|
|
|
removeFileInfo(file);
|
|
|
|
addFileInfo(file);
|
|
|
|
d->m_blockedIFile = 0;
|
2010-03-05 12:55:04 +01:00
|
|
|
}
|
2010-11-23 12:47:45 +01:00
|
|
|
|
|
|
|
// clean up
|
2010-01-22 16:49:57 +01:00
|
|
|
d->m_changedFiles.clear();
|
2010-03-19 10:28:05 +01:00
|
|
|
|
|
|
|
// handle deleted files
|
|
|
|
EditorManager::instance()->closeEditors(editorsToClose, false);
|
|
|
|
QMapIterator<IFile *, QString> it(filesToSave);
|
|
|
|
while (it.hasNext()) {
|
|
|
|
it.next();
|
|
|
|
blockFileChange(it.key());
|
|
|
|
it.key()->save(it.value());
|
|
|
|
unblockFileChange(it.key());
|
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
|
|
|
}
|
|
|
|
|
|
|
|
void FileManager::syncWithEditor(Core::IContext *context)
|
|
|
|
{
|
|
|
|
if (!context)
|
|
|
|
return;
|
|
|
|
|
2009-01-21 15:52:34 +01:00
|
|
|
Core::IEditor *editor = Core::EditorManager::instance()->currentEditor();
|
2010-10-05 14:57:36 +02:00
|
|
|
if (editor && (editor->widget() == context->widget()) &&
|
|
|
|
!editor->isTemporary())
|
2008-12-02 12:01:29 +01:00
|
|
|
setCurrentFile(editor->file()->fileName());
|
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
\fn void FileManager::addToRecentFiles(const QString &fileName)
|
|
|
|
|
|
|
|
Adds the \a fileName to the list of recent files.
|
|
|
|
*/
|
|
|
|
void FileManager::addToRecentFiles(const QString &fileName)
|
|
|
|
{
|
|
|
|
if (fileName.isEmpty())
|
|
|
|
return;
|
2010-11-23 12:47:45 +01:00
|
|
|
QString unifiedForm(fixFileName(fileName, KeepLinks));
|
2010-10-19 11:07:20 +02:00
|
|
|
QMutableStringListIterator it(d->m_recentFiles);
|
|
|
|
while (it.hasNext()) {
|
2010-11-23 12:47:45 +01:00
|
|
|
QString recentUnifiedForm(fixFileName(it.next(), 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-10-19 11:07:20 +02:00
|
|
|
d->m_recentFiles.prepend(fileName);
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
\fn QStringList FileManager::recentFiles() const
|
|
|
|
|
|
|
|
Returns the list of recent files.
|
|
|
|
*/
|
|
|
|
QStringList FileManager::recentFiles() const
|
|
|
|
{
|
2009-11-25 10:09:45 +01:00
|
|
|
return d->m_recentFiles;
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
2010-10-19 11:07:20 +02:00
|
|
|
void FileManager::saveSettings()
|
2008-12-02 12:01:29 +01:00
|
|
|
{
|
2009-11-25 10:09:45 +01:00
|
|
|
QSettings *s = Core::ICore::instance()->settings();
|
2009-11-26 18:03:16 +01:00
|
|
|
s->beginGroup(QLatin1String(settingsGroupC));
|
|
|
|
s->setValue(QLatin1String(filesKeyC), d->m_recentFiles);
|
|
|
|
s->endGroup();
|
|
|
|
s->beginGroup(QLatin1String(directoryGroupC));
|
|
|
|
s->setValue(QLatin1String(projectDirectoryKeyC), d->m_projectsDirectory);
|
|
|
|
s->setValue(QLatin1String(useProjectDirectoryKeyC), d->m_useProjectsDirectory);
|
2008-12-02 12:01:29 +01:00
|
|
|
s->endGroup();
|
|
|
|
}
|
|
|
|
|
2010-10-19 11:07:20 +02:00
|
|
|
void FileManager::readSettings()
|
|
|
|
{
|
|
|
|
const QSettings *s = Core::ICore::instance()->settings();
|
|
|
|
d->m_recentFiles.clear();
|
|
|
|
QStringList recentFiles = s->value(QLatin1String(settingsGroupC) + QLatin1Char('/') + QLatin1String(filesKeyC), QStringList()).toStringList();
|
|
|
|
// clean non-existing files
|
|
|
|
foreach (const QString &file, recentFiles) {
|
|
|
|
if (QFileInfo(file).isFile())
|
|
|
|
d->m_recentFiles.append(QDir::fromNativeSeparators(file)); // from native to guard against old settings
|
|
|
|
}
|
|
|
|
|
|
|
|
const QString directoryGroup = QLatin1String(directoryGroupC) + QLatin1Char('/');
|
|
|
|
const QString settingsProjectDir = s->value(directoryGroup + QLatin1String(projectDirectoryKeyC),
|
|
|
|
QString()).toString();
|
|
|
|
if (!settingsProjectDir.isEmpty() && QFileInfo(settingsProjectDir).isDir()) {
|
|
|
|
d->m_projectsDirectory = settingsProjectDir;
|
|
|
|
} else {
|
|
|
|
d->m_projectsDirectory = Utils::PathChooser::homePath();
|
|
|
|
}
|
|
|
|
d->m_useProjectsDirectory = s->value(directoryGroup + QLatin1String(useProjectDirectoryKeyC),
|
|
|
|
d->m_useProjectsDirectory).toBool();
|
|
|
|
}
|
|
|
|
|
2008-12-02 12:01:29 +01:00
|
|
|
/*!
|
|
|
|
|
|
|
|
The current file is e.g. the file currently opened when an editor is active,
|
|
|
|
or the selected file in case a Project Explorer is active ...
|
|
|
|
|
2009-04-24 16:00:19 +02:00
|
|
|
\sa currentFile
|
2008-12-02 12:01:29 +01:00
|
|
|
*/
|
|
|
|
void FileManager::setCurrentFile(const QString &filePath)
|
|
|
|
{
|
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;
|
|
|
|
emit currentFileChanged(d->m_currentFile);
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
Returns the absolute path of the current file
|
|
|
|
|
|
|
|
The current file is e.g. the file currently opened when an editor is active,
|
|
|
|
or the selected file in case a Project Explorer is active ...
|
|
|
|
|
2009-04-24 16:00:19 +02:00
|
|
|
\sa setCurrentFile
|
2008-12-02 12:01:29 +01:00
|
|
|
*/
|
|
|
|
QString FileManager::currentFile() const
|
|
|
|
{
|
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
|
|
|
|
a current file, use that, else use last visited directory.
|
|
|
|
|
|
|
|
\sa setFileDialogLastVisitedDirectory
|
|
|
|
*/
|
|
|
|
|
|
|
|
QString FileManager::fileDialogInitialDirectory() const
|
|
|
|
{
|
|
|
|
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
|
|
|
|
*/
|
|
|
|
|
|
|
|
QString FileManager::projectsDirectory() const
|
|
|
|
{
|
|
|
|
return d->m_projectsDirectory;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
|
|
|
|
Set the directory for projects.
|
|
|
|
|
|
|
|
\sa projectsDirectory, useProjectsDirectory
|
|
|
|
*/
|
|
|
|
|
|
|
|
void FileManager::setProjectsDirectory(const QString &dir)
|
|
|
|
{
|
|
|
|
d->m_projectsDirectory = dir;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
|
|
|
|
Returns whether the directory for projects is to be
|
|
|
|
used or the user wants the current directory.
|
|
|
|
|
|
|
|
\sa setProjectsDirectory, setUseProjectsDirectory
|
|
|
|
*/
|
|
|
|
|
|
|
|
bool FileManager::useProjectsDirectory() const
|
|
|
|
{
|
|
|
|
return d->m_useProjectsDirectory;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
|
|
|
|
Sets whether the directory for projects is to be used.
|
|
|
|
|
|
|
|
\sa projectsDirectory, useProjectsDirectory
|
|
|
|
*/
|
|
|
|
|
|
|
|
void FileManager::setUseProjectsDirectory(bool useProjectsDirectory)
|
|
|
|
{
|
|
|
|
d->m_useProjectsDirectory = useProjectsDirectory;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
|
|
|
|
Returns last visited directory of a file dialog.
|
|
|
|
|
|
|
|
\sa setFileDialogLastVisitedDirectory, fileDialogInitialDirectory
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
QString FileManager::fileDialogLastVisitedDirectory() const
|
|
|
|
{
|
|
|
|
return d->m_lastVisitedDirectory;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
|
|
|
|
Set the last visited directory of a file dialog that will be remembered
|
|
|
|
for the next one.
|
|
|
|
|
|
|
|
\sa fileDialogLastVisitedDirectory, fileDialogInitialDirectory
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
void FileManager::setFileDialogLastVisitedDirectory(const QString &directory)
|
|
|
|
{
|
|
|
|
d->m_lastVisitedDirectory = directory;
|
|
|
|
}
|
|
|
|
|
2009-12-21 11:08:20 +01:00
|
|
|
void FileManager::notifyFilesChangedInternally(const QStringList &files)
|
|
|
|
{
|
|
|
|
emit filesChangedInternally(files);
|
|
|
|
}
|
|
|
|
|
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
|
|
|
{
|
|
|
|
Core::FileManager *fm = Core::ICore::instance()->fileManager();
|
2010-01-22 16:49:57 +01:00
|
|
|
fm->expectFileChange(fileName);
|
2009-06-18 14:30:04 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
FileChangeBlocker::~FileChangeBlocker()
|
|
|
|
{
|
|
|
|
Core::FileManager *fm = Core::ICore::instance()->fileManager();
|
2010-01-22 16:49:57 +01:00
|
|
|
fm->unexpectFileChange(m_fileName);
|
2009-06-18 14:30:04 +02:00
|
|
|
}
|
2009-11-25 10:09:45 +01:00
|
|
|
|
|
|
|
} // namespace Core
|