Commit 9bc9fe73 authored by dt's avatar dt

File renaming

Reviewed-By: con
Reviewed-By: Friedemann Kleint

We now support renaming files. The version control system tries first to
rename, if that doesn't support or can't rename the file we do a normal
rename. (Note: git, hg, perforce > 2009.02 support renaming, cvs not.
(perforce untested)). We correctly notify all editors of the renamed
file and tell the project manager to rename the file in the project.

Note: Only the qt4projectmanager knows how to rename files.

Note: renaming folders, moving files to different folders, renaming
.pro/.pri files is not supported. Those things can be later added after
this has proven to work correctly in the simple case.

Also we don't do any actions based on the renaming like renaming
classes, changing include guards or #include lines.
parent e65e0117
...@@ -196,6 +196,12 @@ public: ...@@ -196,6 +196,12 @@ public:
} }
} }
void rename(const QString &newName) {
m_fileName = newName;
m_editor->editorInterface()->setDisplayName(QFileInfo(fileName()).fileName());
emit changed();
}
bool open(const QString &fileName) { bool open(const QString &fileName) {
QFile file(fileName); QFile file(fileName);
if (file.open(QIODevice::ReadOnly)) { if (file.open(QIODevice::ReadOnly)) {
...@@ -305,6 +311,7 @@ public: ...@@ -305,6 +311,7 @@ public:
m_toolBar->addWidget(w); m_toolBar->addWidget(w);
connect(m_editor, SIGNAL(cursorPositionChanged(int)), this, SLOT(updateCursorPosition(int))); connect(m_editor, SIGNAL(cursorPositionChanged(int)), this, SLOT(updateCursorPosition(int)));
connect(m_file, SIGNAL(changed()), this, SIGNAL(changed()));
} }
~BinEditorInterface() { ~BinEditorInterface() {
delete m_editor; delete m_editor;
......
...@@ -155,6 +155,9 @@ ImageViewer::ImageViewer(QObject *parent) ...@@ -155,6 +155,9 @@ ImageViewer::ImageViewer(QObject *parent)
layout->setMargin(0); layout->setMargin(0);
m_imageView->setLayout(layout); m_imageView->setLayout(layout);
layout->addWidget(m_label, 0, 0, 1, 1); layout->addWidget(m_label, 0, 0, 1, 1);
connect(m_file, SIGNAL(changed()),
this, SIGNAL(changed()));
} }
ImageViewer::~ImageViewer() ImageViewer::~ImageViewer()
......
...@@ -70,6 +70,7 @@ public: ...@@ -70,6 +70,7 @@ public:
explicit ImageViewerFile(ImageViewer *parent = 0); explicit ImageViewerFile(ImageViewer *parent = 0);
bool save(const QString &fileName = QString()) { Q_UNUSED(fileName); return false; } bool save(const QString &fileName = QString()) { Q_UNUSED(fileName); return false; }
void rename(const QString &newName) { m_fileName = newName; }
QString fileName() const { return m_fileName; } QString fileName() const { return m_fileName; }
QString defaultPath() const { return QString(); } QString defaultPath() const { return QString(); }
......
...@@ -595,6 +595,13 @@ bool CMakeFile::isSaveAsAllowed() const ...@@ -595,6 +595,13 @@ bool CMakeFile::isSaveAsAllowed() const
return false; return false;
} }
void CMakeFile::rename(const QString &newName)
{
Q_ASSERT(false);
Q_UNUSED(newName);
// Can't happen....
}
Core::IFile::ReloadBehavior CMakeFile::reloadBehavior(ChangeTrigger state, ChangeType type) const Core::IFile::ReloadBehavior CMakeFile::reloadBehavior(ChangeTrigger state, ChangeType type) const
{ {
Q_UNUSED(state) Q_UNUSED(state)
......
...@@ -196,6 +196,8 @@ public: ...@@ -196,6 +196,8 @@ public:
ReloadBehavior reloadBehavior(ChangeTrigger state, ChangeType type) const; ReloadBehavior reloadBehavior(ChangeTrigger state, ChangeType type) const;
void reload(ReloadFlag flag, ChangeType type); void reload(ReloadFlag flag, ChangeType type);
void rename(const QString &newName);
private: private:
CMakeProject *m_project; CMakeProject *m_project;
QString m_fileName; QString m_fileName;
......
...@@ -43,8 +43,9 @@ bool CMakeProjectNode::hasBuildTargets() const ...@@ -43,8 +43,9 @@ bool CMakeProjectNode::hasBuildTargets() const
return true; return true;
} }
QList<ProjectExplorer::ProjectNode::ProjectAction> CMakeProjectNode::supportedActions() const QList<ProjectExplorer::ProjectNode::ProjectAction> CMakeProjectNode::supportedActions(Node *node) const
{ {
Q_UNUSED(node);
return QList<ProjectAction>(); return QList<ProjectAction>();
} }
......
...@@ -42,7 +42,7 @@ class CMakeProjectNode : public ProjectExplorer::ProjectNode ...@@ -42,7 +42,7 @@ class CMakeProjectNode : public ProjectExplorer::ProjectNode
public: public:
CMakeProjectNode(const QString &fileName); CMakeProjectNode(const QString &fileName);
virtual bool hasBuildTargets() const; virtual bool hasBuildTargets() const;
virtual QList<ProjectExplorer::ProjectNode::ProjectAction> supportedActions() const; virtual QList<ProjectExplorer::ProjectNode::ProjectAction> supportedActions(Node *node) const;
virtual bool addSubProjects(const QStringList &proFilePaths); virtual bool addSubProjects(const QStringList &proFilePaths);
virtual bool removeSubProjects(const QStringList &proFilePaths); virtual bool removeSubProjects(const QStringList &proFilePaths);
virtual bool addFiles(const ProjectExplorer::FileType fileType, virtual bool addFiles(const ProjectExplorer::FileType fileType,
......
...@@ -123,6 +123,11 @@ struct FileManagerPrivate { ...@@ -123,6 +123,11 @@ struct FileManagerPrivate {
QString m_lastVisitedDirectory; QString m_lastVisitedDirectory;
QString m_projectsDirectory; QString m_projectsDirectory;
bool m_useProjectsDirectory; bool m_useProjectsDirectory;
// When we are callling into a IFile
// we don't want to receive a changed()
// signal
// That makes the code easier
IFile *m_blockedIFile;
}; };
FileManagerPrivate::FileManagerPrivate(QObject *q, QMainWindow *mw) : FileManagerPrivate::FileManagerPrivate(QObject *q, QMainWindow *mw) :
...@@ -131,10 +136,11 @@ FileManagerPrivate::FileManagerPrivate(QObject *q, QMainWindow *mw) : ...@@ -131,10 +136,11 @@ FileManagerPrivate::FileManagerPrivate(QObject *q, QMainWindow *mw) :
m_blockActivated(false), m_blockActivated(false),
m_lastVisitedDirectory(QDir::currentPath()), m_lastVisitedDirectory(QDir::currentPath()),
#ifdef Q_OS_MAC // Creator is in bizarre places when launched via finder. #ifdef Q_OS_MAC // Creator is in bizarre places when launched via finder.
m_useProjectsDirectory(true) m_useProjectsDirectory(true),
#else #else
m_useProjectsDirectory(false) m_useProjectsDirectory(false),
#endif #endif
m_blockedIFile(0)
{ {
} }
...@@ -252,6 +258,55 @@ void FileManager::updateFileInfo(IFile *file) ...@@ -252,6 +258,55 @@ void FileManager::updateFileInfo(IFile *file)
d->m_states[fixedname].lastUpdatedState.insert(file, item); d->m_states[fixedname].lastUpdatedState.insert(file, item);
} }
/// Dumps the state of the file manager's map
/// For debugging purposes
void FileManager::dump()
{
QMap<QString, Internal::FileState>::const_iterator it, end;
it = d->m_states.constBegin();
end = d->m_states.constEnd();
for (; it != end; ++it) {
qDebug()<<" ";
qDebug() << it.key();
qDebug() << it.value().expected.modified;
QMap<IFile *, Internal::FileStateItem>::const_iterator jt, jend;
jt = it.value().lastUpdatedState.constBegin();
jend = it.value().lastUpdatedState.constEnd();
for (; jt != jend; ++jt) {
qDebug() << jt.key() << jt.value().modified;
}
}
}
void FileManager::renamedFile(const QString &from, QString &to)
{
QString fixedFrom = fixFileName(from);
QString fixedTo = fixFileName(to);
if (d->m_states.contains(fixedFrom)) {
QTC_ASSERT(!d->m_states.contains(to), return);
d->m_states.insert(fixedTo, d->m_states.value(fixedFrom));
d->m_states.remove(fixedFrom);
QFileInfo fi(to);
d->m_states[fixedTo].expected.modified = fi.lastModified();
d->m_states[fixedTo].expected.permissions = fi.permissions();
d->m_fileWatcher->removePath(fixedFrom);
d->m_fileWatcher->addPath(fixedTo);
QMap<IFile *, Internal::FileStateItem>::iterator it, end;
it = d->m_states[fixedTo].lastUpdatedState.begin();
end = d->m_states[fixedTo].lastUpdatedState.end();
for ( ; it != end; ++it) {
d->m_blockedIFile = it.key();
it.key()->rename(to);
d->m_blockedIFile = it.key();
it.value().modified = fi.lastModified();
}
}
}
/// ///
/// Does not use file->fileName, as such is save to use /// Does not use file->fileName, as such is save to use
/// with renamed files and deleted files /// with renamed files and deleted files
...@@ -336,6 +391,10 @@ bool FileManager::removeFile(IFile *file) ...@@ -336,6 +391,10 @@ bool FileManager::removeFile(IFile *file)
void FileManager::checkForNewFileName() void FileManager::checkForNewFileName()
{ {
IFile *file = qobject_cast<IFile *>(sender()); IFile *file = qobject_cast<IFile *>(sender());
// We modified the IFile
// Trust the other code to also update the m_states map
if (file == d->m_blockedIFile)
return;
QTC_ASSERT(file, return); QTC_ASSERT(file, return);
const QString &fileName = fixFileName(file->fileName()); const QString &fileName = fixFileName(file->fileName());
...@@ -751,6 +810,7 @@ void FileManager::checkForReload() ...@@ -751,6 +810,7 @@ void FileManager::checkForReload()
end = lastUpdated.constEnd(); end = lastUpdated.constEnd();
for ( ; it != end; ++it) { for ( ; it != end; ++it) {
IFile *file = it.key(); IFile *file = it.key();
d->m_blockedIFile = file;
// Compare // Compare
if (it.value().modified == fi.lastModified() if (it.value().modified == fi.lastModified()
&& it.value().permissions == fi.permissions()) { && it.value().permissions == fi.permissions()) {
...@@ -832,6 +892,7 @@ void FileManager::checkForReload() ...@@ -832,6 +892,7 @@ void FileManager::checkForReload()
} }
updateFileInfo(file); updateFileInfo(file);
d->m_blockedIFile = 0;
} }
} }
......
...@@ -63,6 +63,8 @@ public: ...@@ -63,6 +63,8 @@ public:
bool isFileManaged(const QString &fileName) const; bool isFileManaged(const QString &fileName) const;
QList<IFile *> modifiedFiles() const; QList<IFile *> modifiedFiles() const;
void renamedFile(const QString &from, QString &to);
void blockFileChange(IFile *file); void blockFileChange(IFile *file);
void unblockFileChange(IFile *file); void unblockFileChange(IFile *file);
...@@ -74,6 +76,7 @@ public: ...@@ -74,6 +76,7 @@ public:
QStringList recentFiles() const; QStringList recentFiles() const;
void saveRecentFiles(); void saveRecentFiles();
// current file // current file
void setCurrentFile(const QString &filePath); void setCurrentFile(const QString &filePath);
QString currentFile() const; QString currentFile() const;
...@@ -128,6 +131,7 @@ private slots: ...@@ -128,6 +131,7 @@ private slots:
void syncWithEditor(Core::IContext *context); void syncWithEditor(Core::IContext *context);
private: private:
void dump();
void addFileInfo(IFile *file); void addFileInfo(IFile *file);
void removeFileInfo(IFile *file); void removeFileInfo(IFile *file);
void removeFileInfo(const QString &fileName, IFile *file); void removeFileInfo(const QString &fileName, IFile *file);
......
...@@ -87,6 +87,7 @@ public: ...@@ -87,6 +87,7 @@ public:
virtual ReloadBehavior reloadBehavior(ChangeTrigger state, ChangeType type) const = 0; virtual ReloadBehavior reloadBehavior(ChangeTrigger state, ChangeType type) const = 0;
virtual void reload(ReloadFlag flag, ChangeType type) = 0; virtual void reload(ReloadFlag flag, ChangeType type) = 0;
virtual void rename(const QString &newName) = 0;
virtual void checkPermissions() {} virtual void checkPermissions() {}
......
...@@ -42,7 +42,7 @@ class CORE_EXPORT IVersionControl : public QObject ...@@ -42,7 +42,7 @@ class CORE_EXPORT IVersionControl : public QObject
Q_OBJECT Q_OBJECT
public: public:
enum Operation { enum Operation {
AddOperation, DeleteOperation, OpenOperation, AddOperation, DeleteOperation, OpenOperation, MoveOperation,
CreateRepositoryOperation, CreateRepositoryOperation,
SnapshotOperations, SnapshotOperations,
AnnotateOperation AnnotateOperation
...@@ -101,6 +101,12 @@ public: ...@@ -101,6 +101,12 @@ public:
*/ */
virtual bool vcsDelete(const QString &filename) = 0; virtual bool vcsDelete(const QString &filename) = 0;
/*!
* Called to rename a file, should do the actual on disk renaming
* (e.g. git mv, svn move, p4 move)
*/
virtual bool vcsMove(const QString &from, const QString &to) = 0;
/*! /*!
* Called to initialize the version control system in a directory. * Called to initialize the version control system in a directory.
*/ */
......
...@@ -54,6 +54,7 @@ bool CVSControl::supportsOperation(Operation operation) const ...@@ -54,6 +54,7 @@ bool CVSControl::supportsOperation(Operation operation) const
case DeleteOperation: case DeleteOperation:
case AnnotateOperation: case AnnotateOperation:
break; break;
case MoveOperation:
case OpenOperation: case OpenOperation:
case CreateRepositoryOperation: case CreateRepositoryOperation:
case SnapshotOperations: case SnapshotOperations:
...@@ -81,6 +82,11 @@ bool CVSControl::vcsDelete(const QString &fileName) ...@@ -81,6 +82,11 @@ bool CVSControl::vcsDelete(const QString &fileName)
return m_plugin->vcsDelete(fi.absolutePath(), fi.fileName()); return m_plugin->vcsDelete(fi.absolutePath(), fi.fileName());
} }
bool CVSControl::vcsMove(const QString &from, const QString &to)
{
return false;
}
bool CVSControl::vcsCreateRepository(const QString &) bool CVSControl::vcsCreateRepository(const QString &)
{ {
return false; return false;
......
...@@ -52,6 +52,7 @@ public: ...@@ -52,6 +52,7 @@ public:
virtual bool vcsOpen(const QString &fileName); virtual bool vcsOpen(const QString &fileName);
virtual bool vcsAdd(const QString &fileName); virtual bool vcsAdd(const QString &fileName);
virtual bool vcsDelete(const QString &filename); virtual bool vcsDelete(const QString &filename);
virtual bool vcsMove(const QString &from, const QString &to);
virtual bool vcsCreateRepository(const QString &directory); virtual bool vcsCreateRepository(const QString &directory);
virtual QString vcsCreateSnapshot(const QString &topLevel); virtual QString vcsCreateSnapshot(const QString &topLevel);
virtual QStringList vcsSnapshots(const QString &topLevel); virtual QStringList vcsSnapshots(const QString &topLevel);
......
...@@ -81,6 +81,7 @@ FormWindowEditor::FormWindowEditor(Internal::DesignerXmlEditor *editor, ...@@ -81,6 +81,7 @@ FormWindowEditor::FormWindowEditor(Internal::DesignerXmlEditor *editor,
connect(&(d->m_file), SIGNAL(reload(QString)), this, SLOT(slotOpen(QString))); connect(&(d->m_file), SIGNAL(reload(QString)), this, SLOT(slotOpen(QString)));
// Force update of open editors model. // Force update of open editors model.
connect(&(d->m_file), SIGNAL(saved()), this, SIGNAL(changed())); connect(&(d->m_file), SIGNAL(saved()), this, SIGNAL(changed()));
connect(&(d->m_file), SIGNAL(changed()), this, SIGNAL(changed()));
} }
FormWindowEditor::~FormWindowEditor() FormWindowEditor::~FormWindowEditor()
......
...@@ -91,6 +91,15 @@ bool FormWindowFile::save(const QString &name /*= QString()*/) ...@@ -91,6 +91,15 @@ bool FormWindowFile::save(const QString &name /*= QString()*/)
return true; return true;
} }
void FormWindowFile::rename(const QString &newName)
{
m_formWindow->setFileName(newName);
QFileInfo fi(newName);
m_fileName = fi.absoluteFilePath();
emit setDisplayName(fi.fileName());
emit changed();
}
QString FormWindowFile::fileName() const QString FormWindowFile::fileName() const
{ {
return m_fileName; return m_fileName;
......
...@@ -60,6 +60,7 @@ public: ...@@ -60,6 +60,7 @@ public:
virtual QString defaultPath() const; virtual QString defaultPath() const;
virtual QString suggestedFileName() const; virtual QString suggestedFileName() const;
virtual QString mimeType() const; virtual QString mimeType() const;
virtual void rename(const QString &newName);
// Internal // Internal
void setSuggestedFileName(const QString &fileName); void setSuggestedFileName(const QString &fileName);
......
...@@ -591,6 +591,13 @@ bool GenericProjectFile::isSaveAsAllowed() const ...@@ -591,6 +591,13 @@ bool GenericProjectFile::isSaveAsAllowed() const
return false; return false;
} }
void GenericProjectFile::rename(const QString &newName)
{
// Can't happen
Q_UNUSED(newName);
Q_ASSERT(false);
}
Core::IFile::ReloadBehavior GenericProjectFile::reloadBehavior(ChangeTrigger state, ChangeType type) const Core::IFile::ReloadBehavior GenericProjectFile::reloadBehavior(ChangeTrigger state, ChangeType type) const
{ {
Q_UNUSED(state) Q_UNUSED(state)
......
...@@ -161,6 +161,7 @@ public: ...@@ -161,6 +161,7 @@ public:
virtual bool isModified() const; virtual bool isModified() const;
virtual bool isReadOnly() const; virtual bool isReadOnly() const;
virtual bool isSaveAsAllowed() const; virtual bool isSaveAsAllowed() const;
virtual void rename(const QString &newName);
ReloadBehavior reloadBehavior(ChangeTrigger state, ChangeType type) const; ReloadBehavior reloadBehavior(ChangeTrigger state, ChangeType type) const;
void reload(ReloadFlag flag, ChangeType type); void reload(ReloadFlag flag, ChangeType type);
......
...@@ -170,8 +170,9 @@ bool GenericProjectNode::hasBuildTargets() const ...@@ -170,8 +170,9 @@ bool GenericProjectNode::hasBuildTargets() const
return true; return true;
} }
QList<ProjectExplorer::ProjectNode::ProjectAction> GenericProjectNode::supportedActions() const QList<ProjectExplorer::ProjectNode::ProjectAction> GenericProjectNode::supportedActions(Node *node) const
{ {
Q_UNUSED(node);
return QList<ProjectAction>() return QList<ProjectAction>()
<< AddFile << AddFile
<< RemoveFile; << RemoveFile;
......
...@@ -55,7 +55,7 @@ public: ...@@ -55,7 +55,7 @@ public:
virtual bool hasBuildTargets() const; virtual bool hasBuildTargets() const;
virtual QList<ProjectExplorer::ProjectNode::ProjectAction> supportedActions() const; virtual QList<ProjectExplorer::ProjectNode::ProjectAction> supportedActions(Node *node) const;
virtual bool addSubProjects(const QStringList &proFilePaths); virtual bool addSubProjects(const QStringList &proFilePaths);
virtual bool removeSubProjects(const QStringList &proFilePaths); virtual bool removeSubProjects(const QStringList &proFilePaths);
......
...@@ -525,6 +525,27 @@ bool GitClient::synchronousDelete(const QString &workingDirectory, ...@@ -525,6 +525,27 @@ bool GitClient::synchronousDelete(const QString &workingDirectory,
return rc; return rc;
} }
bool GitClient::synchronousMove(const QString &workingDirectory,
const QString &from,
const QString &to)
{
if (Git::Constants::debug)
qDebug() << Q_FUNC_INFO << workingDirectory << from << to;
QByteArray outputText;
QByteArray errorText;
QStringList arguments;
arguments << QLatin1String("mv");
arguments << (from);
arguments << (to);
const bool rc = synchronousGit(workingDirectory, arguments, &outputText, &errorText);
if (!rc) {
const QString errorMessage = tr("Unable to move from %1 to %2: %3").
arg(from, to, commandOutputFromLocal8Bit(errorText));
outputWindow()->appendError(errorMessage);
}
return rc;
}
bool GitClient::synchronousReset(const QString &workingDirectory, bool GitClient::synchronousReset(const QString &workingDirectory,
const QStringList &files, const QStringList &files,
QString *errorMessage) QString *errorMessage)
......
...@@ -101,6 +101,9 @@ public: ...@@ -101,6 +101,9 @@ public:
bool synchronousDelete(const QString &workingDirectory, bool synchronousDelete(const QString &workingDirectory,
bool force, bool force,
const QStringList &files); const QStringList &files);
bool synchronousMove(const QString &workingDirectory,
const QString &from,
const QString &to);
bool synchronousReset(const QString &workingDirectory, bool synchronousReset(const QString &workingDirectory,
const QStringList &files = QStringList(), const QStringList &files = QStringList(),
QString *errorMessage = 0); QString *errorMessage = 0);
......
...@@ -75,6 +75,9 @@ bool GitVersionControl::supportsOperation(Operation operation) const ...@@ -75,6 +75,9 @@ bool GitVersionControl::supportsOperation(Operation operation) const
case DeleteOperation: case DeleteOperation:
rc = true; rc = true;
break; break;
case MoveOperation:
rc = true;
break;
case OpenOperation: case OpenOperation:
break; break;
case CreateRepositoryOperation: case CreateRepositoryOperation:
...@@ -107,6 +110,13 @@ bool GitVersionControl::vcsDelete(const QString & fileName) ...@@ -107,6 +110,13 @@ bool GitVersionControl::vcsDelete(const QString & fileName)
return gitClient()->synchronousDelete(fi.absolutePath(), true, QStringList(fi.fileName())); return gitClient()->synchronousDelete(fi.absolutePath(), true, QStringList(fi.fileName()));
} }
bool GitVersionControl::vcsMove(const QString &from, const QString &to)
{
const QFileInfo fromInfo(from);
const QFileInfo toInfo(to);
return gitClient()->synchronousMove(fromInfo.absolutePath(), fromInfo.absoluteFilePath(), toInfo.absoluteFilePath());
}
bool GitVersionControl::vcsCreateRepository(const QString &directory) bool GitVersionControl::vcsCreateRepository(const QString &directory)
{ {
return gitClient()->synchronousInit(directory); return gitClient()->synchronousInit(directory);
......
...@@ -53,6 +53,7 @@ public: ...@@ -53,6 +53,7 @@ public:
virtual bool vcsOpen(const QString &fileName); virtual bool vcsOpen(const QString &fileName);
virtual bool vcsAdd(const QString &fileName); virtual bool vcsAdd(const QString &fileName);
virtual bool vcsDelete(const QString &filename); virtual bool vcsDelete(const QString &filename);
virtual bool vcsMove(const QString &from, const QString &to);
virtual bool vcsCreateRepository(const QString &directory); virtual bool vcsCreateRepository(const QString &directory);
virtual QString vcsCreateSnapshot(const QString &topLevel); virtual QString vcsCreateSnapshot(const QString &topLevel);