diff --git a/src/plugins/coreplugin/fileutils.cpp b/src/plugins/coreplugin/fileutils.cpp index 369c132403b..827d5a80136 100644 --- a/src/plugins/coreplugin/fileutils.cpp +++ b/src/plugins/coreplugin/fileutils.cpp @@ -32,6 +32,9 @@ #include "fileutils.h" +#include +#include +#include #include #include @@ -41,6 +44,10 @@ #include #include +#if QT_VERSION < 0x050000 +#include +#endif + #ifndef Q_OS_WIN #include #include @@ -165,3 +172,35 @@ QString FileUtils::msgTerminalAction() return QApplication::translate("Core::Internal", "Open Terminal Here"); #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; +} diff --git a/src/plugins/coreplugin/fileutils.h b/src/plugins/coreplugin/fileutils.h index e5451ae5431..a3716347db3 100644 --- a/src/plugins/coreplugin/fileutils.h +++ b/src/plugins/coreplugin/fileutils.h @@ -49,6 +49,8 @@ struct CORE_EXPORT FileUtils // Platform-dependent action descriptions static QString msgGraphicalShellAction(); 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 diff --git a/src/plugins/projectexplorer/projectexplorer.cpp b/src/plugins/projectexplorer/projectexplorer.cpp index 27b77be91e3..57095a8102f 100644 --- a/src/plugins/projectexplorer/projectexplorer.cpp +++ b/src/plugins/projectexplorer/projectexplorer.cpp @@ -127,10 +127,6 @@ #include #include -#if QT_VERSION < 0x050000 -#include -#endif - #include #include #include @@ -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) { FileNode *fileNode = qobject_cast(node); @@ -2843,20 +2827,8 @@ void ProjectExplorerPlugin::renameFile(Node *node, const QString &to) QString dir = QFileInfo(orgFilePath).absolutePath(); QString newFilePath = dir + QLatin1Char('/') + to; - if (orgFilePath == newFilePath) - return; - - 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 + if (Core::FileUtils::renameFile(orgFilePath, newFilePath)) { + // Tell the project plugin about rename ProjectNode *projectNode = fileNode->projectNode(); if (!projectNode->renameFile(fileNode->fileType(), orgFilePath, newFilePath)) { QMessageBox::warning(Core::ICore::mainWindow(), tr("Project Editing Failed"), diff --git a/src/plugins/resourceeditor/resourceeditorw.cpp b/src/plugins/resourceeditor/resourceeditorw.cpp index 9e6e84caf3c..1a2dd084e45 100644 --- a/src/plugins/resourceeditor/resourceeditorw.cpp +++ b/src/plugins/resourceeditor/resourceeditorw.cpp @@ -54,6 +54,8 @@ #include #include #include +#include +#include namespace ResourceEditor { namespace Internal { @@ -103,6 +105,7 @@ ResourceEditorW::ResourceEditorW(const Core::Context &context, m_resourceEditor->setResourceDragEnabled(true); m_contextMenu->addAction(tr("Open File"), this, SLOT(openCurrentFile())); 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 // is inside of the qrc file, crashes happen when using "Open With" on it. // (That is because this editor instance is deleted in executeOpenWithMenuAction @@ -298,10 +301,9 @@ void ResourceEditorW::onUndoStackChanged(bool canUndo, bool canRedo) void ResourceEditorW::showContextMenu(const QPoint &globalPoint, const QString &fileName) { Core::DocumentManager::populateOpenWithMenu(m_openWithMenu, fileName); - if (!m_openWithMenu->actions().isEmpty()) { - m_currentFileName = fileName; - m_contextMenu->popup(globalPoint); - } + m_currentFileName = fileName; + m_renameAction->setEnabled(!document()->isFileReadOnly()); + m_contextMenu->popup(globalPoint); } void ResourceEditorW::openCurrentFile() @@ -320,6 +322,11 @@ void ResourceEditorW::onRefresh() m_resourceEditor.data()->refresh(); } +void ResourceEditorW::renameCurrentFile() +{ + m_resourceEditor->editCurrentItem(); +} + void ResourceEditorW::onUndo() { if (!m_resourceEditor.isNull()) diff --git a/src/plugins/resourceeditor/resourceeditorw.h b/src/plugins/resourceeditor/resourceeditorw.h index d5a0e684f04..94f46e24be8 100644 --- a/src/plugins/resourceeditor/resourceeditorw.h +++ b/src/plugins/resourceeditor/resourceeditorw.h @@ -111,6 +111,7 @@ private slots: void showContextMenu(const QPoint &globalPoint, const QString &fileName); void openCurrentFile(); void openFile(const QString &fileName); + void renameCurrentFile(); private: const QString m_extension; @@ -126,6 +127,7 @@ private: QMenu *m_openWithMenu; QString m_currentFileName; QToolBar *m_toolBar; + QAction *m_renameAction; public slots: void onRefresh(); diff --git a/src/shared/qrceditor/qrceditor.cpp b/src/shared/qrceditor/qrceditor.cpp index 1f2b7ea83f6..c3df8d39189 100644 --- a/src/shared/qrceditor/qrceditor.cpp +++ b/src/shared/qrceditor/qrceditor.cpp @@ -349,12 +349,12 @@ void QrcEditor::addFile(const QString &prefix, const QString &file) m_treeview->addFile(prefix, file); } -/* -void QrcEditor::removeFile(const QString &prefix, const QString &file) +void QrcEditor::editCurrentItem() { - 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' void QrcEditor::onAliasChanged(const QString &alias) { diff --git a/src/shared/qrceditor/qrceditor.h b/src/shared/qrceditor/qrceditor.h index 56a70d1cdae..6153f023c24 100644 --- a/src/shared/qrceditor/qrceditor.h +++ b/src/shared/qrceditor/qrceditor.h @@ -63,11 +63,11 @@ public: bool resourceDragEnabled() const; void addFile(const QString &prefix, const QString &file); -// void removeFile(const QString &prefix, const QString &file); const QUndoStack *commandHistory() const { return &m_history; } void refresh(); + void editCurrentItem(); signals: void dirtyChanged(bool dirty); diff --git a/src/shared/qrceditor/resourcefile.cpp b/src/shared/qrceditor/resourcefile.cpp index 7878cd8a5d7..dc976762a17 100644 --- a/src/shared/qrceditor/resourcefile.cpp +++ b/src/shared/qrceditor/resourcefile.cpp @@ -33,6 +33,8 @@ #include "resourcefile_p.h" #include +#include +#include #include #include @@ -89,6 +91,11 @@ bool File::exists() return m_exists; } +void File::setExists(bool exists) +{ + m_exists = exists; +} + /****************************************************************************** ** FileList */ @@ -378,6 +385,41 @@ void ResourceFile::replaceAlias(int prefix_idx, int file_idx, const QString &ali 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) { @@ -646,6 +688,22 @@ void ResourceModel::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(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) { static QStringList ext_list; @@ -701,7 +759,7 @@ QVariant ResourceModel::data(const QModelIndex &index, int role) const // File node Q_ASSERT(file); 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; if (!alias.isEmpty()) appendParenthesized(alias, stringRes); @@ -727,6 +785,13 @@ QVariant ResourceModel::data(const QModelIndex &index, int role) const result = m_prefixIcon; } 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: if (isFileNode) { // File node @@ -741,6 +806,26 @@ QVariant ResourceModel::data(const QModelIndex &index, int role) const 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 { prefix.clear(); @@ -924,6 +1009,14 @@ void ResourceModel::insertFile(int prefixIndex, int fileIndex, 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) { if (!model_idx.isValid()) diff --git a/src/shared/qrceditor/resourcefile_p.h b/src/shared/qrceditor/resourcefile_p.h index 5164c26b375..ecc71078b73 100644 --- a/src/shared/qrceditor/resourcefile_p.h +++ b/src/shared/qrceditor/resourcefile_p.h @@ -77,6 +77,7 @@ public: File(Prefix *prefix, const QString &_name, const QString &_alias = QString()); void checkExistence(); 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; } @@ -161,6 +162,8 @@ public: void replaceLang(int prefix_idx, const QString &lang); void replaceAlias(int prefix_idx, int file_idx, const QString &alias); + bool renameFile(const QString fileName, const QString &newFileName); + private: void replaceFile(int pref_idx, int file_idx, const QString &file); public: @@ -211,11 +214,13 @@ public: int rowCount(const QModelIndex &parent) const; int columnCount(const QModelIndex &parent) const; bool hasChildren(const QModelIndex &parent) const; + Qt::ItemFlags flags(const QModelIndex &index) const; void refresh(); protected: QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const; + bool setData(const QModelIndex &index, const QVariant &value, int role); public: QString fileName() const { return m_resource_file.fileName(); } @@ -247,6 +252,7 @@ private: QString relativePath(const QString &path) const { return m_resource_file.relativePath(path); } QString lastResourceOpenDirectory() const; + bool renameFile(const QString &fileName, const QString &newFileName); public: virtual bool reload(); diff --git a/src/shared/qrceditor/resourceview.cpp b/src/shared/qrceditor/resourceview.cpp index 427e527cc08..87e731991e3 100644 --- a/src/shared/qrceditor/resourceview.cpp +++ b/src/shared/qrceditor/resourceview.cpp @@ -183,6 +183,7 @@ ResourceView::ResourceView(QUndoStack *history, QWidget *parent) : advanceMergeId(); setModel(m_qrcModel); setContextMenuPolicy(Qt::CustomContextMenu); + setEditTriggers(EditKeyPressed); header()->hide();