diff --git a/kdevplatform/plugins/projectmanagerview/projectmanagerviewplugin.cpp b/kdevplatform/plugins/projectmanagerview/projectmanagerviewplugin.cpp index 6365e2e7b2..f77b6e04e8 100644 --- a/kdevplatform/plugins/projectmanagerview/projectmanagerviewplugin.cpp +++ b/kdevplatform/plugins/projectmanagerview/projectmanagerviewplugin.cpp @@ -1,744 +1,793 @@ /* This file is part of KDevelop Copyright 2004 Roberto Raggi Copyright 2007 Andreas Pakulat - Copyright 2017 Alexander Potashev + Copyright 2016, 2017 Alexander Potashev This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "projectmanagerviewplugin.h" #include #include #include #include #include #include #include #include #include #include #include #include #include +#include +#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "projectmanagerview.h" #include "debug.h" #include "cutcopypastehelpers.h" using namespace KDevelop; K_PLUGIN_FACTORY_WITH_JSON(ProjectManagerFactory, "kdevprojectmanagerview.json", registerPlugin();) +namespace { + +QAction* createSeparatorAction() +{ + QAction* separator = new QAction(nullptr); + separator->setSeparator(true); + return separator; +} + +// Returns nullptr iff the list of URLs to copy/cut was empty +QMimeData* createClipboardMimeData(const bool cut) +{ + auto* ctx = dynamic_cast( + ICore::self()->selectionController()->currentSelection()); + QList urls; + QList mostLocalUrls; + for (const ProjectBaseItem* item : ctx->items()) { + if (item->folder() || item->file()) { + const QUrl& url = item->path().toUrl(); + urls << url; + mostLocalUrls << KFileItem(url).mostLocalUrl(); + } + } + qCDebug(PLUGIN_PROJECTMANAGERVIEW) << urls; + + if (urls.isEmpty()) { + return nullptr; + } + + QMimeData* mimeData = new QMimeData; + KIO::setClipboardDataCut(mimeData, cut); + KUrlMimeData::setUrls(urls, mostLocalUrls, mimeData); + return mimeData; +} + +} // anonymous namespace + class KDevProjectManagerViewFactory: public KDevelop::IToolViewFactory { public: explicit KDevProjectManagerViewFactory( ProjectManagerViewPlugin *plugin ): mplugin( plugin ) {} QWidget* create( QWidget *parent = nullptr ) override { return new ProjectManagerView( mplugin, parent ); } Qt::DockWidgetArea defaultPosition() override { return Qt::LeftDockWidgetArea; } QString id() const override { return QStringLiteral("org.kdevelop.ProjectsView"); } private: ProjectManagerViewPlugin *mplugin; }; class ProjectManagerViewPluginPrivate { public: ProjectManagerViewPluginPrivate() {} KDevProjectManagerViewFactory *factory; QList ctxProjectItemList; QAction* m_buildAll; QAction* m_build; QAction* m_install; QAction* m_clean; QAction* m_configure; QAction* m_prune; }; static QList itemsFromIndexes(const QList& indexes) { QList items; ProjectModel* model = ICore::self()->projectController()->projectModel(); foreach(const QModelIndex& index, indexes) { items += model->itemFromIndex(index); } return items; } ProjectManagerViewPlugin::ProjectManagerViewPlugin( QObject *parent, const QVariantList& ) : IPlugin( QStringLiteral("kdevprojectmanagerview"), parent ), d(new ProjectManagerViewPluginPrivate) { d->m_buildAll = new QAction( i18n("Build all Projects"), this ); d->m_buildAll->setIcon(QIcon::fromTheme(QStringLiteral("run-build"))); connect( d->m_buildAll, &QAction::triggered, this, &ProjectManagerViewPlugin::buildAllProjects ); actionCollection()->addAction( QStringLiteral("project_buildall"), d->m_buildAll ); d->m_build = new QAction( i18n("Build Selection"), this ); d->m_build->setIconText( i18n("Build") ); actionCollection()->setDefaultShortcut( d->m_build, Qt::Key_F8 ); d->m_build->setIcon(QIcon::fromTheme(QStringLiteral("run-build"))); d->m_build->setEnabled( false ); connect( d->m_build, &QAction::triggered, this, &ProjectManagerViewPlugin::buildProjectItems ); actionCollection()->addAction( QStringLiteral("project_build"), d->m_build ); d->m_install = new QAction( i18n("Install Selection"), this ); d->m_install->setIconText( i18n("Install") ); d->m_install->setIcon(QIcon::fromTheme(QStringLiteral("run-build-install"))); actionCollection()->setDefaultShortcut( d->m_install, Qt::SHIFT + Qt::Key_F8 ); d->m_install->setEnabled( false ); connect( d->m_install, &QAction::triggered, this, &ProjectManagerViewPlugin::installProjectItems ); actionCollection()->addAction( QStringLiteral("project_install"), d->m_install ); d->m_clean = new QAction( i18n("Clean Selection"), this ); d->m_clean->setIconText( i18n("Clean") ); d->m_clean->setIcon(QIcon::fromTheme(QStringLiteral("run-build-clean"))); d->m_clean->setEnabled( false ); connect( d->m_clean, &QAction::triggered, this, &ProjectManagerViewPlugin::cleanProjectItems ); actionCollection()->addAction( QStringLiteral("project_clean"), d->m_clean ); d->m_configure = new QAction( i18n("Configure Selection"), this ); d->m_configure->setMenuRole( QAction::NoRole ); // OSX: Be explicit about role, prevent hiding due to conflict with "Preferences..." menu item d->m_configure->setIconText( i18n("Configure") ); d->m_configure->setIcon(QIcon::fromTheme(QStringLiteral("run-build-configure"))); d->m_configure->setEnabled( false ); connect( d->m_configure, &QAction::triggered, this, &ProjectManagerViewPlugin::configureProjectItems ); actionCollection()->addAction( QStringLiteral("project_configure"), d->m_configure ); d->m_prune = new QAction( i18n("Prune Selection"), this ); d->m_prune->setIconText( i18n("Prune") ); d->m_prune->setIcon(QIcon::fromTheme(QStringLiteral("run-build-prune"))); d->m_prune->setEnabled( false ); connect( d->m_prune, &QAction::triggered, this, &ProjectManagerViewPlugin::pruneProjectItems ); actionCollection()->addAction( QStringLiteral("project_prune"), d->m_prune ); // only add the action so that its known in the actionCollection // and so that it's shortcut etc. pp. is restored // apparently that is not possible to be done in the view itself *sigh* actionCollection()->addAction( QStringLiteral("locate_document") ); setXMLFile( QStringLiteral("kdevprojectmanagerview.rc") ); d->factory = new KDevProjectManagerViewFactory( this ); core()->uiController()->addToolView( i18n("Projects"), d->factory ); connect(core()->selectionController(), &ISelectionController::selectionChanged, this, &ProjectManagerViewPlugin::updateActionState); connect(ICore::self()->projectController()->buildSetModel(), &KDevelop::ProjectBuildSetModel::rowsInserted, this, &ProjectManagerViewPlugin::updateFromBuildSetChange); connect(ICore::self()->projectController()->buildSetModel(), &KDevelop::ProjectBuildSetModel::rowsRemoved, this, &ProjectManagerViewPlugin::updateFromBuildSetChange); connect(ICore::self()->projectController()->buildSetModel(), &KDevelop::ProjectBuildSetModel::modelReset, this, &ProjectManagerViewPlugin::updateFromBuildSetChange); } void ProjectManagerViewPlugin::updateFromBuildSetChange() { updateActionState( core()->selectionController()->currentSelection() ); } void ProjectManagerViewPlugin::updateActionState( KDevelop::Context* ctx ) { bool isEmpty = ICore::self()->projectController()->buildSetModel()->items().isEmpty(); if( isEmpty ) { isEmpty = !ctx || ctx->type() != Context::ProjectItemContext || static_cast(ctx)->items().isEmpty(); } d->m_build->setEnabled( !isEmpty ); d->m_install->setEnabled( !isEmpty ); d->m_clean->setEnabled( !isEmpty ); d->m_configure->setEnabled( !isEmpty ); d->m_prune->setEnabled( !isEmpty ); } ProjectManagerViewPlugin::~ProjectManagerViewPlugin() { delete d; } void ProjectManagerViewPlugin::unload() { qCDebug(PLUGIN_PROJECTMANAGERVIEW) << "unloading manager view"; core()->uiController()->removeToolView(d->factory); } ContextMenuExtension ProjectManagerViewPlugin::contextMenuExtension(KDevelop::Context* context, QWidget* parent) { if( context->type() != KDevelop::Context::ProjectItemContext ) return IPlugin::contextMenuExtension(context, parent); KDevelop::ProjectItemContext* ctx = static_cast(context); QList items = ctx->items(); d->ctxProjectItemList.clear(); if( items.isEmpty() ) return IPlugin::contextMenuExtension(context, parent); //TODO: also needs: removeTarget, removeFileFromTarget, runTargetsFromContextMenu ContextMenuExtension menuExt; bool needsCreateFile = true; bool needsCreateFolder = true; bool needsCloseProjects = true; bool needsBuildItems = true; bool needsFolderItems = true; - bool needsRemoveAndRename = true; + bool needsCutRenameRemove = true; bool needsRemoveTargetFiles = true; bool needsPaste = true; //needsCreateFile if there is one item and it's a folder or target needsCreateFile &= (items.count() == 1) && (items.first()->folder() || items.first()->target()); //needsCreateFolder if there is one item and it's a folder needsCreateFolder &= (items.count() == 1) && (items.first()->folder()); needsPaste = needsCreateFolder; foreach( ProjectBaseItem* item, items ) { d->ctxProjectItemList << item->index(); //needsBuildItems if items are limited to targets and buildfolders needsBuildItems &= item->target() || item->type() == ProjectBaseItem::BuildFolder; //needsCloseProjects if items are limited to top level folders (Project Folders) needsCloseProjects &= item->folder() && !item->folder()->parent(); //needsFolderItems if items are limited to folders needsFolderItems &= (bool)item->folder(); //needsRemove if items are limited to non-top-level folders or files that don't belong to targets - needsRemoveAndRename &= (item->folder() && item->parent()) || (item->file() && !item->parent()->target()); + needsCutRenameRemove &= (item->folder() && item->parent()) || (item->file() && !item->parent()->target()); //needsRemoveTargets if items are limited to file items with target parents needsRemoveTargetFiles &= (item->file() && item->parent()->target()); } if ( needsCreateFile ) { QAction* action = new QAction(i18n("Create &File..."), parent); action->setIcon(QIcon::fromTheme(QStringLiteral("document-new"))); connect( action, &QAction::triggered, this, &ProjectManagerViewPlugin::createFileFromContextMenu ); menuExt.addAction( ContextMenuExtension::FileGroup, action ); } if ( needsCreateFolder ) { QAction* action = new QAction(i18n("Create F&older..."), parent); action->setIcon(QIcon::fromTheme(QStringLiteral("folder-new"))); connect( action, &QAction::triggered, this, &ProjectManagerViewPlugin::createFolderFromContextMenu ); menuExt.addAction( ContextMenuExtension::FileGroup, action ); } if ( needsBuildItems ) { QAction* action = new QAction(i18nc("@action", "&Build"), parent); action->setIcon(QIcon::fromTheme(QStringLiteral("run-build"))); connect( action, &QAction::triggered, this, &ProjectManagerViewPlugin::buildItemsFromContextMenu ); menuExt.addAction( ContextMenuExtension::BuildGroup, action ); action = new QAction(i18nc("@action", "&Install"), parent); action->setIcon(QIcon::fromTheme(QStringLiteral("run-build-install"))); connect( action, &QAction::triggered, this, &ProjectManagerViewPlugin::installItemsFromContextMenu ); menuExt.addAction( ContextMenuExtension::BuildGroup, action ); action = new QAction(i18nc("@action", "&Clean"), parent); action->setIcon(QIcon::fromTheme(QStringLiteral("run-build-clean"))); connect( action, &QAction::triggered, this, &ProjectManagerViewPlugin::cleanItemsFromContextMenu ); menuExt.addAction( ContextMenuExtension::BuildGroup, action ); action = new QAction(i18n("&Add to Build Set"), parent); action->setIcon(QIcon::fromTheme(QStringLiteral("list-add"))); connect( action, &QAction::triggered, this, &ProjectManagerViewPlugin::addItemsFromContextMenuToBuildset ); menuExt.addAction( ContextMenuExtension::BuildGroup, action ); } if ( needsCloseProjects ) { QAction* close = new QAction(i18np("C&lose Project", "Close Projects", items.count()), parent); close->setIcon(QIcon::fromTheme(QStringLiteral("project-development-close"))); connect( close, &QAction::triggered, this, &ProjectManagerViewPlugin::closeProjects ); menuExt.addAction( ContextMenuExtension::ProjectGroup, close ); } if ( needsFolderItems ) { QAction* action = new QAction(i18n("&Reload"), parent); action->setIcon(QIcon::fromTheme(QStringLiteral("view-refresh"))); connect( action, &QAction::triggered, this, &ProjectManagerViewPlugin::reloadFromContextMenu ); menuExt.addAction( ContextMenuExtension::FileGroup, action ); } - if ( needsRemoveAndRename ) { + + // Populating cut/copy/paste group + if ( !menuExt.actions(ContextMenuExtension::FileGroup).isEmpty() ) { + menuExt.addAction( ContextMenuExtension::FileGroup, createSeparatorAction() ); + } + if ( needsCutRenameRemove ) { + QAction* cut = KStandardAction::cut(this, SLOT(cutFromContextMenu()), this); + cut->setShortcutContext(Qt::WidgetShortcut); + menuExt.addAction(ContextMenuExtension::FileGroup, cut); + } + { + QAction* copy = KStandardAction::copy(this, SLOT(copyFromContextMenu()), this); + copy->setShortcutContext(Qt::WidgetShortcut); + menuExt.addAction( ContextMenuExtension::FileGroup, copy ); + } + if (needsPaste) { + QAction* paste = KStandardAction::paste(this, SLOT(pasteFromContextMenu()), this); + paste->setShortcutContext(Qt::WidgetShortcut); + menuExt.addAction( ContextMenuExtension::FileGroup, paste ); + } + + // Populating rename/remove group + { + menuExt.addAction( ContextMenuExtension::FileGroup, createSeparatorAction() ); + } + if ( needsCutRenameRemove ) { QAction* remove = new QAction(i18n("Remo&ve"), parent); remove->setIcon(QIcon::fromTheme(QStringLiteral("user-trash"))); connect( remove, &QAction::triggered, this, &ProjectManagerViewPlugin::removeFromContextMenu ); menuExt.addAction( ContextMenuExtension::FileGroup, remove ); QAction* rename = new QAction(i18n("Re&name..."), parent); rename->setIcon(QIcon::fromTheme(QStringLiteral("edit-rename"))); connect( rename, &QAction::triggered, this, &ProjectManagerViewPlugin::renameItemFromContextMenu ); menuExt.addAction( ContextMenuExtension::FileGroup, rename ); } if ( needsRemoveTargetFiles ) { QAction* remove = new QAction(i18n("Remove From &Target"), parent); remove->setIcon(QIcon::fromTheme(QStringLiteral("user-trash"))); connect( remove, &QAction::triggered, this, &ProjectManagerViewPlugin::removeTargetFilesFromContextMenu ); menuExt.addAction( ContextMenuExtension::FileGroup, remove ); } - { - QAction* copy = KStandardAction::copy(this, SLOT(copyFromContextMenu()), parent); - copy->setShortcutContext(Qt::WidgetShortcut); - menuExt.addAction( ContextMenuExtension::FileGroup, copy ); - } - if (needsPaste) { - QAction* paste = KStandardAction::paste(this, SLOT(pasteFromContextMenu()), parent); - paste->setShortcutContext(Qt::WidgetShortcut); - menuExt.addAction( ContextMenuExtension::FileGroup, paste ); + if ( needsCutRenameRemove || needsRemoveTargetFiles ) { + menuExt.addAction(ContextMenuExtension::FileGroup, createSeparatorAction()); } return menuExt; } void ProjectManagerViewPlugin::closeProjects() { QList projectsToClose; ProjectModel* model = ICore::self()->projectController()->projectModel(); foreach( const QModelIndex& index, d->ctxProjectItemList ) { KDevelop::ProjectBaseItem* item = model->itemFromIndex(index); if( !projectsToClose.contains( item->project() ) ) { projectsToClose << item->project(); } } d->ctxProjectItemList.clear(); foreach( KDevelop::IProject* proj, projectsToClose ) { core()->projectController()->closeProject( proj ); } } void ProjectManagerViewPlugin::installItemsFromContextMenu() { runBuilderJob( BuilderJob::Install, itemsFromIndexes(d->ctxProjectItemList) ); d->ctxProjectItemList.clear(); } void ProjectManagerViewPlugin::cleanItemsFromContextMenu() { runBuilderJob( BuilderJob::Clean, itemsFromIndexes( d->ctxProjectItemList ) ); d->ctxProjectItemList.clear(); } void ProjectManagerViewPlugin::buildItemsFromContextMenu() { runBuilderJob( BuilderJob::Build, itemsFromIndexes( d->ctxProjectItemList ) ); d->ctxProjectItemList.clear(); } QList ProjectManagerViewPlugin::collectAllProjects() { QList items; foreach( KDevelop::IProject* project, core()->projectController()->projects() ) { items << project->projectItem(); } return items; } void ProjectManagerViewPlugin::buildAllProjects() { runBuilderJob( BuilderJob::Build, collectAllProjects() ); } QList ProjectManagerViewPlugin::collectItems() { QList items; QList buildItems = ICore::self()->projectController()->buildSetModel()->items(); if( !buildItems.isEmpty() ) { foreach( const BuildItem& buildItem, buildItems ) { if( ProjectBaseItem* item = buildItem.findItem() ) { items << item; } } } else { KDevelop::ProjectItemContext* ctx = static_cast(ICore::self()->selectionController()->currentSelection()); items = ctx->items(); } return items; } void ProjectManagerViewPlugin::runBuilderJob( BuilderJob::BuildType type, QList items ) { BuilderJob* builder = new BuilderJob; builder->addItems( type, items ); builder->updateJobName(); ICore::self()->uiController()->registerStatus(new JobStatus(builder)); ICore::self()->runController()->registerJob( builder ); } void ProjectManagerViewPlugin::installProjectItems() { runBuilderJob( KDevelop::BuilderJob::Install, collectItems() ); } void ProjectManagerViewPlugin::pruneProjectItems() { runBuilderJob( KDevelop::BuilderJob::Prune, collectItems() ); } void ProjectManagerViewPlugin::configureProjectItems() { runBuilderJob( KDevelop::BuilderJob::Configure, collectItems() ); } void ProjectManagerViewPlugin::cleanProjectItems() { runBuilderJob( KDevelop::BuilderJob::Clean, collectItems() ); } void ProjectManagerViewPlugin::buildProjectItems() { runBuilderJob( KDevelop::BuilderJob::Build, collectItems() ); } void ProjectManagerViewPlugin::addItemsFromContextMenuToBuildset( ) { foreach( KDevelop::ProjectBaseItem* item, itemsFromIndexes( d->ctxProjectItemList )) { ICore::self()->projectController()->buildSetModel()->addProjectItem( item ); } } void ProjectManagerViewPlugin::runTargetsFromContextMenu( ) { foreach( KDevelop::ProjectBaseItem* item, itemsFromIndexes( d->ctxProjectItemList )) { KDevelop::ProjectExecutableTargetItem* t=item->executable(); if(t) { qCDebug(PLUGIN_PROJECTMANAGERVIEW) << "Running target: " << t->text() << t->builtUrl(); } } } void ProjectManagerViewPlugin::projectConfiguration( ) { if( !d->ctxProjectItemList.isEmpty() ) { ProjectModel* model = ICore::self()->projectController()->projectModel(); core()->projectController()->configureProject( model->itemFromIndex(d->ctxProjectItemList.at( 0 ))->project() ); } } void ProjectManagerViewPlugin::reloadFromContextMenu( ) { QList< KDevelop::ProjectFolderItem* > folders; foreach( KDevelop::ProjectBaseItem* item, itemsFromIndexes( d->ctxProjectItemList ) ) { if ( item->folder() ) { // since reloading should be recursive, only pass the upper-most items bool found = false; foreach ( KDevelop::ProjectFolderItem* existing, folders ) { if ( existing->path().isParentOf(item->folder()->path()) ) { // simply skip this child found = true; break; } else if ( item->folder()->path().isParentOf(existing->path()) ) { // remove the child in the list and add the current item instead folders.removeOne(existing); // continue since there could be more than one existing child } } if ( !found ) { folders << item->folder(); } } } foreach( KDevelop::ProjectFolderItem* folder, folders ) { folder->project()->projectFileManager()->reload(folder); } } void ProjectManagerViewPlugin::createFolderFromContextMenu( ) { foreach( KDevelop::ProjectBaseItem* item, itemsFromIndexes( d->ctxProjectItemList )) { if ( item->folder() ) { QWidget* window(ICore::self()->uiController()->activeMainWindow()->window()); QString name = QInputDialog::getText ( window, i18n ( "Create Folder in %1", item->folder()->path().pathOrUrl() ), i18n ( "Folder Name" ) ); if (!name.isEmpty()) { item->project()->projectFileManager()->addFolder( Path(item->path(), name), item->folder() ); } } } } void ProjectManagerViewPlugin::removeFromContextMenu() { removeItems(itemsFromIndexes( d->ctxProjectItemList )); } void ProjectManagerViewPlugin::removeItems(const QList< ProjectBaseItem* >& items) { if (items.isEmpty()) { return; } //copy the list of selected items and sort it to guarantee parents will come before children QList sortedItems = items; std::sort(sortedItems.begin(), sortedItems.end(), ProjectBaseItem::pathLessThan); Path lastFolder; QHash< IProjectFileManager*, QList > filteredItems; QStringList itemPaths; foreach( KDevelop::ProjectBaseItem* item, sortedItems ) { if (item->isProjectRoot()) { continue; } else if (item->folder() || item->file()) { //make sure no children of folders that will be deleted are listed if (lastFolder.isParentOf(item->path())) { continue; } else if (item->folder()) { lastFolder = item->path(); } IProjectFileManager* manager = item->project()->projectFileManager(); if (manager) { filteredItems[manager] << item; itemPaths << item->path().pathOrUrl(); } } } if (filteredItems.isEmpty()) { return; } if (KMessageBox::warningYesNoList( QApplication::activeWindow(), i18np("Do you really want to delete this item?", "Do you really want to delete these %1 items?", itemPaths.size()), itemPaths, i18n("Delete Files"), KStandardGuiItem::del(), KStandardGuiItem::cancel() ) == KMessageBox::No) { return; } //Go though projectmanagers, have them remove the files and folders that they own QHash< IProjectFileManager*, QList >::iterator it; for (it = filteredItems.begin(); it != filteredItems.end(); ++it) { Q_ASSERT(it.key()); it.key()->removeFilesAndFolders(it.value()); } } void ProjectManagerViewPlugin::removeTargetFilesFromContextMenu() { QList items = itemsFromIndexes( d->ctxProjectItemList ); QHash< IBuildSystemManager*, QList > itemsByBuildSystem; foreach(ProjectBaseItem *item, items) itemsByBuildSystem[item->project()->buildSystemManager()].append(item->file()); QHash< IBuildSystemManager*, QList >::iterator it; for (it = itemsByBuildSystem.begin(); it != itemsByBuildSystem.end(); ++it) it.key()->removeFilesFromTargets(it.value()); } void ProjectManagerViewPlugin::renameItemFromContextMenu() { renameItems(itemsFromIndexes( d->ctxProjectItemList )); } void ProjectManagerViewPlugin::renameItems(const QList< ProjectBaseItem* >& items) { if (items.isEmpty()) { return; } QWidget* window = ICore::self()->uiController()->activeMainWindow()->window(); foreach( KDevelop::ProjectBaseItem* item, items ) { if ((item->type()!=ProjectBaseItem::BuildFolder && item->type()!=ProjectBaseItem::Folder && item->type()!=ProjectBaseItem::File) || !item->parent()) { continue; } const QString src = item->text(); //Change QInputDialog->KFileSaveDialog? QString name = QInputDialog::getText( window, i18n("Rename..."), i18n("New name for '%1':", item->text()), QLineEdit::Normal, item->text() ); if (!name.isEmpty() && name != src) { ProjectBaseItem::RenameStatus status = item->rename( name ); switch(status) { case ProjectBaseItem::RenameOk: break; case ProjectBaseItem::ExistingItemSameName: KMessageBox::error(window, i18n("There is already a file named '%1'", name)); break; case ProjectBaseItem::ProjectManagerRenameFailed: KMessageBox::error(window, i18n("Could not rename '%1'", name)); break; case ProjectBaseItem::InvalidNewName: KMessageBox::error(window, i18n("'%1' is not a valid file name", name)); break; } } } } ProjectFileItem* createFile(const ProjectFolderItem* item) { QWidget* window = ICore::self()->uiController()->activeMainWindow()->window(); QString name = QInputDialog::getText(window, i18n("Create File in %1", item->path().pathOrUrl()), i18n("File name:")); if(name.isEmpty()) return nullptr; ProjectFileItem* ret = item->project()->projectFileManager()->addFile( Path(item->path(), name), item->folder() ); if (ret) { ICore::self()->documentController()->openDocument( ret->path().toUrl() ); } return ret; } void ProjectManagerViewPlugin::createFileFromContextMenu( ) { foreach( KDevelop::ProjectBaseItem* item, itemsFromIndexes( d->ctxProjectItemList ) ) { if ( item->folder() ) { createFile(item->folder()); } else if ( item->target() ) { ProjectFolderItem* folder=dynamic_cast(item->parent()); if(folder) { ProjectFileItem* f=createFile(folder); if(f) item->project()->buildSystemManager()->addFilesToTarget(QList() << f, item->target()); } } } } void ProjectManagerViewPlugin::copyFromContextMenu() { - KDevelop::ProjectItemContext* ctx = static_cast(ICore::self()->selectionController()->currentSelection()); - QList urls; - foreach (ProjectBaseItem* item, ctx->items()) { - if (item->folder() || item->file()) { - urls << item->path().toUrl(); - } - } - qCDebug(PLUGIN_PROJECTMANAGERVIEW) << urls; - if (!urls.isEmpty()) { - QMimeData* data = new QMimeData; - data->setUrls(urls); - qApp->clipboard()->setMimeData(data); - } + qApp->clipboard()->setMimeData(createClipboardMimeData(false)); +} + +void ProjectManagerViewPlugin::cutFromContextMenu() +{ + qApp->clipboard()->setMimeData(createClipboardMimeData(true)); } static void selectItemsByPaths(ProjectManagerView* view, const Path::List& paths) { KDevelop::ProjectModel* projectModel = KDevelop::ICore::self()->projectController()->projectModel(); QList newItems; for (const Path& path : paths) { QList items = projectModel->itemsForPath(IndexedString(path.path())); newItems.append(items); for (ProjectBaseItem* item : items) { view->expandItem(item->parent()); } } view->selectItems(newItems); } void ProjectManagerViewPlugin::pasteFromContextMenu() { KDevelop::ProjectItemContext* ctx = static_cast(ICore::self()->selectionController()->currentSelection()); if (ctx->items().count() != 1) { return; //do nothing if multiple or none items are selected } ProjectBaseItem* destItem = ctx->items().at(0); if (!destItem->folder()) { return; //do nothing if the target is not a directory } const QMimeData* data = qApp->clipboard()->mimeData(); qCDebug(PLUGIN_PROJECTMANAGERVIEW) << data->urls(); Path::List origPaths = toPathList(data->urls()); const bool isCut = KIO::isClipboardDataCut(data); const CutCopyPasteHelpers::SourceToDestinationMap map = CutCopyPasteHelpers::mapSourceToDestination(origPaths, destItem->folder()->path()); QVector tasks = CutCopyPasteHelpers::copyMoveItems( map.filteredPaths, destItem, isCut ? CutCopyPasteHelpers::Operation::CUT : CutCopyPasteHelpers::Operation::COPY); // Select new items in the project manager view ProjectManagerViewItemContext* itemCtx = dynamic_cast(ICore::self()->selectionController()->currentSelection()); if (itemCtx) { Path::List finalPathsList; for (const auto& task : tasks) { if (task.m_status == CutCopyPasteHelpers::TaskStatus::SUCCESS && task.m_type != CutCopyPasteHelpers::TaskType::DELETION) { for (const Path& src : task.m_src) { finalPathsList.append(map.finalPaths[src]); } } } selectItemsByPaths(itemCtx->view(), finalPathsList); } // If there was a single failure, display a warning dialog. const bool anyFailed = std::any_of(tasks.begin(), tasks.end(), [](const CutCopyPasteHelpers::TaskInfo& task) { return task.m_status != CutCopyPasteHelpers::TaskStatus::SUCCESS; }); if (anyFailed) { QWidget* window = ICore::self()->uiController()->activeMainWindow()->window(); showWarningDialogForFailedPaste(window, tasks); } } - #include "projectmanagerviewplugin.moc" diff --git a/kdevplatform/plugins/projectmanagerview/projectmanagerviewplugin.h b/kdevplatform/plugins/projectmanagerview/projectmanagerviewplugin.h index 48fbd43ed9..e674ce5f3b 100644 --- a/kdevplatform/plugins/projectmanagerview/projectmanagerviewplugin.h +++ b/kdevplatform/plugins/projectmanagerview/projectmanagerviewplugin.h @@ -1,87 +1,88 @@ /* This file is part of KDevelop Copyright 2004 Roberto Raggi Copyright 2007 Andreas Pakulat This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef KDEVPLATFORM_PLUGIN_PROJECTMANAGERVIEWPLUGIN_H #define KDEVPLATFORM_PLUGIN_PROJECTMANAGERVIEWPLUGIN_H #include #include #include namespace KDevelop { class ProjectBaseItem; } class ProjectManagerView; class ProjectManagerViewPlugin: public KDevelop::IPlugin { Q_OBJECT public: public: explicit ProjectManagerViewPlugin(QObject *parent, const QVariantList & = QVariantList() ); ~ProjectManagerViewPlugin() override; // Plugin methods void unload() override; KDevelop::ContextMenuExtension contextMenuExtension(KDevelop::Context* context, QWidget* parent) override; void removeItems(const QList& items); void renameItems(const QList< KDevelop::ProjectBaseItem* >& items); public Q_SLOTS: void buildProjectItems(); void installProjectItems(); void cleanProjectItems(); void copyFromContextMenu(); void pasteFromContextMenu(); protected Q_SLOTS: void closeProjects(); void buildItemsFromContextMenu(); void installItemsFromContextMenu(); void cleanItemsFromContextMenu(); void configureProjectItems(); void pruneProjectItems(); void buildAllProjects(); void addItemsFromContextMenuToBuildset(); void projectConfiguration(); void runTargetsFromContextMenu(); void reloadFromContextMenu(); void createFolderFromContextMenu(); void createFileFromContextMenu(); void removeFromContextMenu(); + void cutFromContextMenu(); void removeTargetFilesFromContextMenu(); void renameItemFromContextMenu(); void updateActionState( KDevelop::Context* ctx ); void updateFromBuildSetChange(); private: QList recurseAndFetchCheckedItems( KDevelop::ProjectBaseItem* item ); QList collectItems(); QList collectAllProjects(); void runBuilderJob( KDevelop::BuilderJob::BuildType type, QList items ); class ProjectManagerViewPluginPrivate* const d; }; #endif