Index: kdevplatform/shell/textdocument.h =================================================================== --- kdevplatform/shell/textdocument.h +++ kdevplatform/shell/textdocument.h @@ -85,7 +85,6 @@ Q_PRIVATE_SLOT(d, void modifiedOnDisk(KTextEditor::Document *, bool, KTextEditor::ModificationInterface::ModifiedOnDiskReason)) void newDocumentStatus(KTextEditor::Document*); - void populateContextMenu(KTextEditor::View*, QMenu*); void textChanged(KTextEditor::Document*); void documentUrlChanged(KTextEditor::Document*); void slotDocumentLoaded(); Index: kdevplatform/shell/textdocument.cpp =================================================================== --- kdevplatform/shell/textdocument.cpp +++ kdevplatform/shell/textdocument.cpp @@ -76,19 +76,67 @@ } } +class TextDocumentContextMenuData : public QObject +{ + Q_OBJECT +public: + TextDocumentContextMenuData(QObject* parent) + : QObject(parent) + , addedContextMenu(nullptr) + { + lastShownMenu.clear(); + } + + // dtor has to be out-of-line, after + ~TextDocumentContextMenuData(); + + void populateContextMenu( KTextEditor::View* v, QMenu* menu ) + { + if (!lastShownMenu.isNull() && addedContextMenu) { + qCDebug(SHELL) << "Removing items from previous contextmenu" << lastShownMenu; + foreach ( QAction* action, addedContextMenu->actions() ) { + lastShownMenu->removeAction(action); + } + } + + delete addedContextMenu; + addedContextMenu = new QMenu(); + + EditorContext c(v, v->cursorPosition()); + auto extensions = Core::self()->pluginController()->queryPluginsForContextMenuExtensions(&c, addedContextMenu); + + ContextMenuExtension::populateMenu(addedContextMenu, extensions); + + foreach ( QAction* action, addedContextMenu->actions() ) { + menu->addAction(action); + } + if (menu != lastShownMenu.data()) { + qCDebug(SHELL) << "Added items to new contextmenu" << menu; + lastShownMenu = menu; + } + } + + // we want to remove the previously added stuff before + // the menu shows again. + // This has to be a static instance because multiple views + // can share the same context menu instance. + QMenu* addedContextMenu; + QPointer lastShownMenu; +}; + class TextDocumentPrivate { public: - explicit TextDocumentPrivate(TextDocument *textDocument) + explicit TextDocumentPrivate(TextDocument *textDocument, ICore* core) : q(textDocument) { + if (!contextMenuData) { + contextMenuData = new TextDocumentContextMenuData(core->uiController()->activeMainWindow()); + } } ~TextDocumentPrivate() { - delete addedContextMenu; - addedContextMenu = nullptr; - saveSessionConfig(); delete document; } @@ -231,10 +279,26 @@ IDocument::DocumentState state = IDocument::Clean; QString encoding; bool loaded = false; - // we want to remove the added stuff when the menu hides - QMenu* addedContextMenu = nullptr; + // there is only a single contextmenu at a time so use a single (static) + // instance of the class keeping track of added menu actions. + static TextDocumentContextMenuData* contextMenuData; }; +TextDocumentContextMenuData* TextDocumentPrivate::contextMenuData = nullptr; + +TextDocumentContextMenuData::~TextDocumentContextMenuData() +{ + // don't assume there will ever be only 1 MainWindow in KDevelop: + // (this is why we have to be out-of-line) + if (TextDocumentPrivate::contextMenuData == this) { + TextDocumentPrivate::contextMenuData = nullptr; + } + delete addedContextMenu; + addedContextMenu = nullptr; + + lastShownMenu.clear(); +} + class TextViewPrivate { public: @@ -246,7 +310,7 @@ }; TextDocument::TextDocument(const QUrl &url, ICore* core, const QString& encoding) - :PartDocument(url, core), d(new TextDocumentPrivate(this)) + :PartDocument(url, core), d(new TextDocumentPrivate(this, core)) { d->encoding = encoding; } @@ -345,7 +409,7 @@ view->setStatusBarEnabled(Core::self()->partControllerInternal()->showTextEditorStatusBar()); - connect(view, &KTextEditor::View::contextMenuAboutToShow, this, &TextDocument::populateContextMenu); + connect(view, &KTextEditor::View::contextMenuAboutToShow, d->contextMenuData, &TextDocumentContextMenuData::populateContextMenu); if (KTextEditor::CodeCompletionInterface* cc = dynamic_cast(view)) cc->setAutomaticInvocationEnabled(core()->languageController()->completionSettings()->automaticCompletionEnabled()); @@ -670,27 +734,6 @@ notifyContentChanged(); } -void KDevelop::TextDocument::populateContextMenu( KTextEditor::View* v, QMenu* menu ) -{ - if (d->addedContextMenu) { - foreach ( QAction* action, d->addedContextMenu->actions() ) { - menu->removeAction(action); - } - delete d->addedContextMenu; - } - - d->addedContextMenu = new QMenu(); - - EditorContext c(v, v->cursorPosition()); - auto extensions = Core::self()->pluginController()->queryPluginsForContextMenuExtensions(&c, d->addedContextMenu); - - ContextMenuExtension::populateMenu(d->addedContextMenu, extensions); - - foreach ( QAction* action, d->addedContextMenu->actions() ) { - menu->addAction(action); - } -} - void KDevelop::TextDocument::repositoryCheckFinished(bool canRecreate) { if ( d->state != IDocument::Dirty && d->state != IDocument::DirtyAndModified ) { // document is not dirty for whatever reason, nothing to do. @@ -737,3 +780,4 @@ } #include "moc_textdocument.cpp" +#include "textdocument.moc"