Implemented file rename in ResourceEditor.

Renaming supports version control.

To prevent code duplication part of ProjectExplorerPlugin::renameFile
implementation was separated into FileUtils::renameFile.

Change-Id: I28481bea89d0824339e5db025ceb7216713bd5a0
Reviewed-by: Eike Ziller <eike.ziller@nokia.com>
This commit is contained in:
Konstantin Tokarev
2012-05-24 23:04:29 +04:00
committed by Eike Ziller
parent bb66e54626
commit eef043e055
10 changed files with 162 additions and 40 deletions

View File

@@ -32,6 +32,9 @@
#include "fileutils.h" #include "fileutils.h"
#include <coreplugin/documentmanager.h>
#include <coreplugin/iversioncontrol.h>
#include <coreplugin/vcsmanager.h>
#include <utils/environment.h> #include <utils/environment.h>
#include <QDir> #include <QDir>
@@ -41,6 +44,10 @@
#include <QMessageBox> #include <QMessageBox>
#include <QWidget> #include <QWidget>
#if QT_VERSION < 0x050000
#include <QAbstractFileEngine>
#endif
#ifndef Q_OS_WIN #ifndef Q_OS_WIN
#include <coreplugin/icore.h> #include <coreplugin/icore.h>
#include <utils/consoleprocess.h> #include <utils/consoleprocess.h>
@@ -165,3 +172,35 @@ QString FileUtils::msgTerminalAction()
return QApplication::translate("Core::Internal", "Open Terminal Here"); return QApplication::translate("Core::Internal", "Open Terminal Here");
#endif #endif
} }
static inline bool fileSystemRenameFile(const QString &orgFilePath,
const QString &newFilePath)
{
#if QT_VERSION < 0x050000 // ### fixme: QTBUG-3570 might be fixed in Qt 5?
QFile f(orgFilePath); // Due to QTBUG-3570
QAbstractFileEngine *fileEngine = f.fileEngine();
if (!fileEngine->caseSensitive() && orgFilePath.compare(newFilePath, Qt::CaseInsensitive) == 0)
return fileEngine->rename(newFilePath);
#endif
return QFile::rename(orgFilePath, newFilePath);
}
bool FileUtils::renameFile(const QString &orgFilePath, const QString &newFilePath)
{
if (orgFilePath == newFilePath)
return false;
QString dir = QFileInfo(orgFilePath).absolutePath();
Core::IVersionControl *vc = Core::ICore::vcsManager()->findVersionControlForDirectory(dir);
bool result = false;
if (vc && vc->supportsOperation(Core::IVersionControl::MoveOperation))
result = vc->vcsMove(orgFilePath, newFilePath);
if (!result) // The moving via vcs failed or the vcs does not support moving, fall back
result = fileSystemRenameFile(orgFilePath, newFilePath);
if (result) {
// yeah we moved, tell the filemanager about it
Core::DocumentManager::renamedFile(orgFilePath, newFilePath);
}
return result;
}

View File

@@ -49,6 +49,8 @@ struct CORE_EXPORT FileUtils
// Platform-dependent action descriptions // Platform-dependent action descriptions
static QString msgGraphicalShellAction(); static QString msgGraphicalShellAction();
static QString msgTerminalAction(); static QString msgTerminalAction();
// File rename aware of version control and file system case-insensitiveness
static bool renameFile(const QString &from, const QString &to);
}; };
} // namespace Core } // namespace Core

View File

@@ -127,10 +127,6 @@
#include <QFileInfo> #include <QFileInfo>
#include <QSettings> #include <QSettings>
#if QT_VERSION < 0x050000
#include <QAbstractFileEngine>
#endif
#include <QAction> #include <QAction>
#include <QApplication> #include <QApplication>
#include <QFileDialog> #include <QFileDialog>
@@ -2822,18 +2818,6 @@ void ProjectExplorerPlugin::renameFile()
} }
} }
static inline bool fileSystemRenameFile(const QString &orgFilePath,
const QString &newFilePath)
{
#if QT_VERSION < 0x050000 // ### fixme: QTBUG-3570 might be fixed in Qt 5?
QFile f(orgFilePath); // Due to QTBUG-3570
QAbstractFileEngine *fileEngine = f.fileEngine();
if (!fileEngine->caseSensitive() && orgFilePath.compare(newFilePath, Qt::CaseInsensitive) == 0)
return fileEngine->rename(newFilePath);
#endif
return QFile::rename(orgFilePath, newFilePath);
}
void ProjectExplorerPlugin::renameFile(Node *node, const QString &to) void ProjectExplorerPlugin::renameFile(Node *node, const QString &to)
{ {
FileNode *fileNode = qobject_cast<FileNode *>(node); FileNode *fileNode = qobject_cast<FileNode *>(node);
@@ -2843,20 +2827,8 @@ void ProjectExplorerPlugin::renameFile(Node *node, const QString &to)
QString dir = QFileInfo(orgFilePath).absolutePath(); QString dir = QFileInfo(orgFilePath).absolutePath();
QString newFilePath = dir + QLatin1Char('/') + to; QString newFilePath = dir + QLatin1Char('/') + to;
if (orgFilePath == newFilePath) if (Core::FileUtils::renameFile(orgFilePath, newFilePath)) {
return; // Tell the project plugin about rename
Core::IVersionControl *vc = Core::ICore::vcsManager()->findVersionControlForDirectory(dir);
bool result = false;
if (vc && vc->supportsOperation(Core::IVersionControl::MoveOperation))
result = vc->vcsMove(orgFilePath, newFilePath);
if (!result) // The moving via vcs failed or the vcs does not support moving, fall back
result = fileSystemRenameFile(orgFilePath, newFilePath);
if (result) {
// yeah we moved, tell the filemanager about it
Core::DocumentManager::renamedFile(orgFilePath, newFilePath);
// Tell the project plugin about it
ProjectNode *projectNode = fileNode->projectNode(); ProjectNode *projectNode = fileNode->projectNode();
if (!projectNode->renameFile(fileNode->fileType(), orgFilePath, newFilePath)) { if (!projectNode->renameFile(fileNode->fileType(), orgFilePath, newFilePath)) {
QMessageBox::warning(Core::ICore::mainWindow(), tr("Project Editing Failed"), QMessageBox::warning(Core::ICore::mainWindow(), tr("Project Editing Failed"),

View File

@@ -54,6 +54,8 @@
#include <QMainWindow> #include <QMainWindow>
#include <QMenu> #include <QMenu>
#include <QToolBar> #include <QToolBar>
#include <QInputDialog>
#include <QMessageBox>
namespace ResourceEditor { namespace ResourceEditor {
namespace Internal { namespace Internal {
@@ -103,6 +105,7 @@ ResourceEditorW::ResourceEditorW(const Core::Context &context,
m_resourceEditor->setResourceDragEnabled(true); m_resourceEditor->setResourceDragEnabled(true);
m_contextMenu->addAction(tr("Open File"), this, SLOT(openCurrentFile())); m_contextMenu->addAction(tr("Open File"), this, SLOT(openCurrentFile()));
m_openWithMenu = m_contextMenu->addMenu(tr("Open With")); m_openWithMenu = m_contextMenu->addMenu(tr("Open With"));
m_renameAction = m_contextMenu->addAction(tr("Rename File..."), this, SLOT(renameCurrentFile()), Qt::Key_F2);
// Below we need QueuedConnection because otherwise, if this qrc file // Below we need QueuedConnection because otherwise, if this qrc file
// is inside of the qrc file, crashes happen when using "Open With" on it. // is inside of the qrc file, crashes happen when using "Open With" on it.
// (That is because this editor instance is deleted in executeOpenWithMenuAction // (That is because this editor instance is deleted in executeOpenWithMenuAction
@@ -298,11 +301,10 @@ void ResourceEditorW::onUndoStackChanged(bool canUndo, bool canRedo)
void ResourceEditorW::showContextMenu(const QPoint &globalPoint, const QString &fileName) void ResourceEditorW::showContextMenu(const QPoint &globalPoint, const QString &fileName)
{ {
Core::DocumentManager::populateOpenWithMenu(m_openWithMenu, fileName); Core::DocumentManager::populateOpenWithMenu(m_openWithMenu, fileName);
if (!m_openWithMenu->actions().isEmpty()) {
m_currentFileName = fileName; m_currentFileName = fileName;
m_renameAction->setEnabled(!document()->isFileReadOnly());
m_contextMenu->popup(globalPoint); m_contextMenu->popup(globalPoint);
} }
}
void ResourceEditorW::openCurrentFile() void ResourceEditorW::openCurrentFile()
{ {
@@ -320,6 +322,11 @@ void ResourceEditorW::onRefresh()
m_resourceEditor.data()->refresh(); m_resourceEditor.data()->refresh();
} }
void ResourceEditorW::renameCurrentFile()
{
m_resourceEditor->editCurrentItem();
}
void ResourceEditorW::onUndo() void ResourceEditorW::onUndo()
{ {
if (!m_resourceEditor.isNull()) if (!m_resourceEditor.isNull())

View File

@@ -111,6 +111,7 @@ private slots:
void showContextMenu(const QPoint &globalPoint, const QString &fileName); void showContextMenu(const QPoint &globalPoint, const QString &fileName);
void openCurrentFile(); void openCurrentFile();
void openFile(const QString &fileName); void openFile(const QString &fileName);
void renameCurrentFile();
private: private:
const QString m_extension; const QString m_extension;
@@ -126,6 +127,7 @@ private:
QMenu *m_openWithMenu; QMenu *m_openWithMenu;
QString m_currentFileName; QString m_currentFileName;
QToolBar *m_toolBar; QToolBar *m_toolBar;
QAction *m_renameAction;
public slots: public slots:
void onRefresh(); void onRefresh();

View File

@@ -349,12 +349,12 @@ void QrcEditor::addFile(const QString &prefix, const QString &file)
m_treeview->addFile(prefix, file); m_treeview->addFile(prefix, file);
} }
/* void QrcEditor::editCurrentItem()
void QrcEditor::removeFile(const QString &prefix, const QString &file)
{ {
m_treeview->removeFile(prefix, file); if (m_treeview->selectionModel()->currentIndex().isValid())
m_treeview->edit(m_treeview->selectionModel()->currentIndex());
} }
*/
// Slot for change of line edit content 'alias' // Slot for change of line edit content 'alias'
void QrcEditor::onAliasChanged(const QString &alias) void QrcEditor::onAliasChanged(const QString &alias)
{ {

View File

@@ -63,11 +63,11 @@ public:
bool resourceDragEnabled() const; bool resourceDragEnabled() const;
void addFile(const QString &prefix, const QString &file); void addFile(const QString &prefix, const QString &file);
// void removeFile(const QString &prefix, const QString &file);
const QUndoStack *commandHistory() const { return &m_history; } const QUndoStack *commandHistory() const { return &m_history; }
void refresh(); void refresh();
void editCurrentItem();
signals: signals:
void dirtyChanged(bool dirty); void dirtyChanged(bool dirty);

View File

@@ -33,6 +33,8 @@
#include "resourcefile_p.h" #include "resourcefile_p.h"
#include <coreplugin/fileiconprovider.h> #include <coreplugin/fileiconprovider.h>
#include <coreplugin/fileutils.h>
#include <utils/fileutils.h>
#include <QCoreApplication> #include <QCoreApplication>
#include <QDebug> #include <QDebug>
@@ -89,6 +91,11 @@ bool File::exists()
return m_exists; return m_exists;
} }
void File::setExists(bool exists)
{
m_exists = exists;
}
/****************************************************************************** /******************************************************************************
** FileList ** FileList
*/ */
@@ -378,6 +385,41 @@ void ResourceFile::replaceAlias(int prefix_idx, int file_idx, const QString &ali
fileList[file_idx]->alias = alias; fileList[file_idx]->alias = alias;
} }
bool ResourceFile::renameFile(const QString fileName, const QString &newFileName)
{
bool success = true;
FileList entries;
for (int i = 0; i < prefixCount(); ++i) {
const FileList &file_list = m_prefix_list.at(i)->file_list;
foreach (File *file, file_list) {
if (file->name == fileName)
entries.append(file);
if (file->name == newFileName)
return false; // prevent conflicts
}
}
Q_ASSERT(!entries.isEmpty());
entries.at(0)->checkExistence();
if (entries.at(0)->exists()) {
foreach (File *file, entries)
file->setExists(true);
success = Core::FileUtils::renameFile(entries.at(0)->name, newFileName);
}
if (success) {
bool exists = QFile::exists(newFileName);
foreach (File *file, entries) {
file->name = newFileName;
file->setExists(exists);
}
}
return success;
}
void ResourceFile::replaceFile(int pref_idx, int file_idx, const QString &file) void ResourceFile::replaceFile(int pref_idx, int file_idx, const QString &file)
{ {
@@ -646,6 +688,22 @@ void ResourceModel::refresh()
m_resource_file.refresh(); m_resource_file.refresh();
} }
Qt::ItemFlags ResourceModel::flags(const QModelIndex &index) const
{
Qt::ItemFlags f = QAbstractItemModel::flags(index);
const void *internalPointer = index.internalPointer();
const Node *node = reinterpret_cast<const Node *>(internalPointer);
const Prefix *prefix = node->prefix();
Q_ASSERT(prefix);
const bool isFileNode = (prefix != node);
if (isFileNode)
f |= Qt::ItemIsEditable;
return f;
}
bool ResourceModel::iconFileExtension(const QString &path) bool ResourceModel::iconFileExtension(const QString &path)
{ {
static QStringList ext_list; static QStringList ext_list;
@@ -701,7 +759,7 @@ QVariant ResourceModel::data(const QModelIndex &index, int role) const
// File node // File node
Q_ASSERT(file); Q_ASSERT(file);
QString conv_file = m_resource_file.relativePath(file->name); QString conv_file = m_resource_file.relativePath(file->name);
stringRes = conv_file.replace(QDir::separator(), QLatin1Char('/')); stringRes = QDir::fromNativeSeparators(conv_file);
const QString alias = file->alias; const QString alias = file->alias;
if (!alias.isEmpty()) if (!alias.isEmpty())
appendParenthesized(alias, stringRes); appendParenthesized(alias, stringRes);
@@ -727,6 +785,13 @@ QVariant ResourceModel::data(const QModelIndex &index, int role) const
result = m_prefixIcon; result = m_prefixIcon;
} }
break; break;
case Qt::EditRole:
if (isFileNode) {
Q_ASSERT(file);
QString conv_file = m_resource_file.relativePath(file->name);
result = QDir::fromNativeSeparators(conv_file);
}
break;
case Qt::ForegroundRole: case Qt::ForegroundRole:
if (isFileNode) { if (isFileNode) {
// File node // File node
@@ -741,6 +806,26 @@ QVariant ResourceModel::data(const QModelIndex &index, int role) const
return result; return result;
} }
bool ResourceModel::setData(const QModelIndex &index, const QVariant &value, int role)
{
if (!index.isValid())
return false;
if (role != Qt::EditRole)
return false;
const QDir baseDir = QFileInfo(fileName()).absoluteDir();
Utils::FileName newFileName = Utils::FileName::fromUserInput(
baseDir.absoluteFilePath(value.toString()));
if (newFileName.isEmpty())
return false;
if (!newFileName.isChildOf(Utils::FileName::fromString(baseDir.absolutePath())))
return false;
return renameFile(file(index), newFileName.toString());
}
void ResourceModel::getItem(const QModelIndex &index, QString &prefix, QString &file) const void ResourceModel::getItem(const QModelIndex &index, QString &prefix, QString &file) const
{ {
prefix.clear(); prefix.clear();
@@ -924,6 +1009,14 @@ void ResourceModel::insertFile(int prefixIndex, int fileIndex,
setDirty(true); setDirty(true);
} }
bool ResourceModel::renameFile(const QString &fileName, const QString &newFileName)
{
bool success = m_resource_file.renameFile(fileName, newFileName);
if (success)
setDirty(true);
return success;
}
void ResourceModel::changePrefix(const QModelIndex &model_idx, const QString &prefix) void ResourceModel::changePrefix(const QModelIndex &model_idx, const QString &prefix)
{ {
if (!model_idx.isValid()) if (!model_idx.isValid())

View File

@@ -77,6 +77,7 @@ public:
File(Prefix *prefix, const QString &_name, const QString &_alias = QString()); File(Prefix *prefix, const QString &_name, const QString &_alias = QString());
void checkExistence(); void checkExistence();
bool exists(); bool exists();
void setExists(bool exists);
bool operator < (const File &other) const { return name < other.name; } bool operator < (const File &other) const { return name < other.name; }
bool operator == (const File &other) const { return name == other.name; } bool operator == (const File &other) const { return name == other.name; }
@@ -161,6 +162,8 @@ public:
void replaceLang(int prefix_idx, const QString &lang); void replaceLang(int prefix_idx, const QString &lang);
void replaceAlias(int prefix_idx, int file_idx, const QString &alias); void replaceAlias(int prefix_idx, int file_idx, const QString &alias);
bool renameFile(const QString fileName, const QString &newFileName);
private: private:
void replaceFile(int pref_idx, int file_idx, const QString &file); void replaceFile(int pref_idx, int file_idx, const QString &file);
public: public:
@@ -211,11 +214,13 @@ public:
int rowCount(const QModelIndex &parent) const; int rowCount(const QModelIndex &parent) const;
int columnCount(const QModelIndex &parent) const; int columnCount(const QModelIndex &parent) const;
bool hasChildren(const QModelIndex &parent) const; bool hasChildren(const QModelIndex &parent) const;
Qt::ItemFlags flags(const QModelIndex &index) const;
void refresh(); void refresh();
protected: protected:
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const; QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const;
bool setData(const QModelIndex &index, const QVariant &value, int role);
public: public:
QString fileName() const { return m_resource_file.fileName(); } QString fileName() const { return m_resource_file.fileName(); }
@@ -247,6 +252,7 @@ private:
QString relativePath(const QString &path) const QString relativePath(const QString &path) const
{ return m_resource_file.relativePath(path); } { return m_resource_file.relativePath(path); }
QString lastResourceOpenDirectory() const; QString lastResourceOpenDirectory() const;
bool renameFile(const QString &fileName, const QString &newFileName);
public: public:
virtual bool reload(); virtual bool reload();

View File

@@ -183,6 +183,7 @@ ResourceView::ResourceView(QUndoStack *history, QWidget *parent) :
advanceMergeId(); advanceMergeId();
setModel(m_qrcModel); setModel(m_qrcModel);
setContextMenuPolicy(Qt::CustomContextMenu); setContextMenuPolicy(Qt::CustomContextMenu);
setEditTriggers(EditKeyPressed);
header()->hide(); header()->hide();