diff --git a/interfaces/configpage.cpp b/interfaces/configpage.cpp index 3f8fee1e0d..cc751a5551 100644 --- a/interfaces/configpage.cpp +++ b/interfaces/configpage.cpp @@ -1,158 +1,81 @@ /* * This file is part of KDevelop * Copyright 2014 Alex Richardson * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) version 3, or any * later version accepted by the membership of KDE e.V. (or its * successor approved by the membership of KDE e.V.), which shall * act as a proxy defined in Section 6 of version 3 of the license. * * 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library. If not, see . */ #include "configpage.h" #include #include #include using namespace KDevelop; ConfigPage::ConfigPage(IPlugin* plugin, KCoreConfigSkeleton* config, QWidget* parent) : KTextEditor::ConfigPage(parent), m_configSkeleton(config), m_plugin(plugin) { if (m_configSkeleton) { m_configManager.reset(new KConfigDialogManager(parent, m_configSkeleton)); connect(m_configManager.data(), &KConfigDialogManager::widgetModified, this, &ConfigPage::changed); // m_configManager->addWidget(this) must be called from the config dialog, // since the widget tree is not complete yet when calling this constructor } } ConfigPage::~ConfigPage() { } void ConfigPage::apply() { Q_ASSERT(m_configManager); // if null, this method must be overriden m_configManager->updateSettings(); m_configSkeleton->load(); m_configManager->updateWidgets(); } void ConfigPage::defaults() { Q_ASSERT(m_configManager); // if null, this method must be overriden m_configManager->updateWidgetsDefault(); } void ConfigPage::reset() { Q_ASSERT(m_configManager); // if null, this method must be overriden m_configManager->updateWidgets(); } void ConfigPage::initConfigManager() { if (m_configManager) { m_configManager->addWidget(this); m_configManager->updateWidgets(); } } QList ConfigPage::childPages() { return {}; } IPlugin* ConfigPage::plugin() { return m_plugin; } - -KTextEditorConfigPageAdapter::KTextEditorConfigPageAdapter(KTextEditor::ConfigPage* page, QWidget* parent) - : ConfigPage(nullptr, nullptr, parent), m_page(page) -{ - page->setParent(this); - QVBoxLayout* layout = new QVBoxLayout(this); - layout->addWidget(page); - this->setLayout(layout); -} - -KTextEditorConfigPageAdapter::~KTextEditorConfigPageAdapter() -{ -} - -void KTextEditorConfigPageAdapter::apply() -{ - m_page->apply(); -} - -void KTextEditorConfigPageAdapter::defaults() -{ - m_page->defaults(); -} - -void KTextEditorConfigPageAdapter::reset() -{ - m_page->reset(); -} - -QString KTextEditorConfigPageAdapter::fullName() const -{ - return m_page->fullName(); -} - -QIcon KTextEditorConfigPageAdapter::icon() const -{ - return m_page->icon(); -} - -QString KTextEditorConfigPageAdapter::name() const -{ - return m_page->name(); -} - -EditorConfigPage::EditorConfigPage(QWidget* parent) - : ConfigPage(nullptr, nullptr, parent) -{ - qDebug("Editor config page created"); - setObjectName("editorconfig"); -} - -EditorConfigPage::~EditorConfigPage() -{ - qDebug("Editor config page deleted"); -} - -QString EditorConfigPage::name() const { - return i18n("Editor"); -} - -QIcon EditorConfigPage::icon() const { - return QIcon::fromTheme(QStringLiteral("accessories-text-editor")); -} - -QString EditorConfigPage::fullName() const { - return i18n("Configure Text editor"); -} - -QList EditorConfigPage::childPages() -{ - QList ret; - auto editor = KTextEditor::Editor::instance(); - for (int i = 0; i < editor->configPages(); ++i) { - ret.append(new KTextEditorConfigPageAdapter(editor->configPage(i, this), this)); - } - return ret; -}; diff --git a/interfaces/configpage.h b/interfaces/configpage.h index dab4265789..332a9ecf8b 100644 --- a/interfaces/configpage.h +++ b/interfaces/configpage.h @@ -1,123 +1,82 @@ /* * This file is part of KDevelop * Copyright 2014 Alex Richardson * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) version 3, or any * later version accepted by the membership of KDE e.V. (or its * successor approved by the membership of KDE e.V.), which shall * act as a proxy defined in Section 6 of version 3 of the license. * * 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library. If not, see . */ #ifndef KDEVELOP_CONFIGPAGE_H #define KDEVELOP_CONFIGPAGE_H #include #include #include #include #include "interfacesexport.h" namespace KDevelop { class IPlugin; class KDEVPLATFORMINTERFACES_EXPORT ConfigPage : public KTextEditor::ConfigPage { Q_OBJECT public: /** * Create a new config page * @param plugin the plugin that created this config page * @param config the config skeleton that is used to store the preferences. If you don't use * a K(Core)ConfigSkeleton to save the settings you can also pass null here. * However this means that you will have to manually implement the apply(), defaults() and reset() slots */ explicit ConfigPage(IPlugin* plugin, KCoreConfigSkeleton* config = nullptr, QWidget* parent = nullptr); virtual ~ConfigPage(); /** * Get any subpages of the current page. * @return By default returns an empty list */ virtual QList childPages(); /** * @return the plugin that this config page was created by or nullptr if it was not created by a plugin. */ IPlugin* plugin(); public Q_SLOTS: virtual void apply() override; virtual void defaults() override; virtual void reset() override; public: /** * Initializes the KConfigDialogManager. * Must be called explicitly since not all child widgets are available at the end of the constructor. * This is handled automatically by KDevelop::ConfigDialog, subclasses don't need to call this. */ void initConfigManager(); KCoreConfigSkeleton* configSkeleton() { return m_configSkeleton; } private: QScopedPointer m_configManager; KCoreConfigSkeleton* m_configSkeleton; IPlugin* m_plugin; }; -class KDEVPLATFORMINTERFACES_EXPORT KTextEditorConfigPageAdapter : public ConfigPage -{ - Q_OBJECT - -public: - explicit KTextEditorConfigPageAdapter(KTextEditor::ConfigPage* page, QWidget* parent = nullptr); - virtual ~KTextEditorConfigPageAdapter(); - - virtual QString name() const override; - virtual QIcon icon() const override; - virtual QString fullName() const override; - -public Q_SLOTS: - virtual void apply() override; - virtual void defaults() override; - virtual void reset() override; - -private: - KTextEditor::ConfigPage* m_page; -}; - - -class KDEVPLATFORMINTERFACES_EXPORT EditorConfigPage : public ConfigPage -{ - Q_OBJECT - -public: - EditorConfigPage(QWidget* parent); - virtual ~EditorConfigPage(); - - virtual QString name() const override; - virtual QIcon icon() const override; - virtual QString fullName() const override; - virtual QList childPages() override; - -public Q_SLOTS: - virtual void apply() override {}; - virtual void reset() override {}; - virtual void defaults() override {}; -}; - } #endif // KDEVELOP_CONFIGPAGE_H diff --git a/shell/uicontroller.cpp b/shell/uicontroller.cpp index 90415cbcc1..6386fd1411 100644 --- a/shell/uicontroller.cpp +++ b/shell/uicontroller.cpp @@ -1,727 +1,813 @@ /*************************************************************************** * Copyright 2007 Alexander Dymo * * * * This program 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 program 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 General Public License for more details. * * * * You should have received a copy of the GNU Library General Public * * License along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * ***************************************************************************/ #include "uicontroller.h" #include #include #include #include #include #include #include #include +#include #include #include #include #include #include #include #include #include #include #include "core.h" #include "configpage.h" #include "configdialog.h" #include "debug.h" #include "shellextension.h" #include "partcontroller.h" #include "plugincontroller.h" #include "mainwindow.h" #include "partdocument.h" #include "textdocument.h" #include "documentcontroller.h" #include "assistantpopup.h" #include #include #include #include #include #include #include #include "workingsetcontroller.h" #include "workingsets/workingset.h" #include "settings/uipreferences.h" #include "settings/pluginpreferences.h" namespace KDevelop { class UiControllerPrivate { public: UiControllerPrivate(UiController *controller) : areasRestored(false), m_controller(controller) { if (Core::self()->workingSetControllerInternal()) Core::self()->workingSetControllerInternal()->initializeController(m_controller); QMap desired; desired["org.kdevelop.ClassBrowserView"] = Sublime::Left; desired["org.kdevelop.DocumentsView"] = Sublime::Left; desired["org.kdevelop.ProjectsView"] = Sublime::Left; desired["org.kdevelop.FileManagerView"] = Sublime::Left; desired["org.kdevelop.ProblemReporterView"] = Sublime::Bottom; desired["org.kdevelop.OutputView"] = Sublime::Bottom; desired["org.kdevelop.ContextBrowser"] = Sublime::Bottom; desired["org.kdevelop.KonsoleView"] = Sublime::Bottom; desired["org.kdevelop.SnippetView"] = Sublime::Right; desired["org.kdevelop.ExternalScriptView"] = Sublime::Right; Sublime::Area* a = new Sublime::Area(m_controller, "code", i18n("Code")); a->setDesiredToolViews(desired); a->setIconName("document-edit"); m_controller->addDefaultArea(a); desired.clear(); desired["org.kdevelop.debugger.VariablesView"] = Sublime::Left; desired["org.kdevelop.debugger.BreakpointsView"] = Sublime::Bottom; desired["org.kdevelop.debugger.StackView"] = Sublime::Bottom; desired["org.kdevelop.debugger.ConsoleView"] = Sublime::Bottom; desired["org.kdevelop.KonsoleView"] = Sublime::Bottom; a = new Sublime::Area(m_controller, "debug", i18n("Debug")); a->setDesiredToolViews(desired); a->setIconName("tools-report-bug"); m_controller->addDefaultArea(a); desired.clear(); desired["org.kdevelop.ProjectsView"] = Sublime::Left; desired["org.kdevelop.PatchReview"] = Sublime::Bottom; a = new Sublime::Area(m_controller, "review", i18n("Review")); a->setDesiredToolViews(desired); a->setIconName("applications-engineering"); m_controller->addDefaultArea(a); if(!(Core::self()->setupFlags() & Core::NoUi)) { defaultMainWindow = new MainWindow(m_controller); m_controller->addMainWindow(defaultMainWindow); activeSublimeWindow = defaultMainWindow; } else { activeSublimeWindow = defaultMainWindow = 0; } m_assistantTimer.setSingleShot(true); m_assistantTimer.setInterval(100); } void widgetChanged(QWidget*, QWidget* now) { if (now) { Sublime::MainWindow* win = qobject_cast(now->window()); if( win ) { activeSublimeWindow = win; } } } Core *core; MainWindow* defaultMainWindow; QMap factoryDocuments; Sublime::MainWindow* activeSublimeWindow; bool areasRestored; //Currently shown assistant popup. QPointer currentShownAssistant; QTimer m_assistantTimer; private: UiController *m_controller; }; class UiToolViewFactory: public Sublime::ToolFactory { public: UiToolViewFactory(IToolViewFactory *factory): m_factory(factory) {} ~UiToolViewFactory() { delete m_factory; } virtual QWidget* create(Sublime::ToolDocument *doc, QWidget *parent = 0) { Q_UNUSED( doc ); return m_factory->create(parent); } virtual QList< QAction* > contextMenuActions(QWidget* viewWidget) const { return m_factory->contextMenuActions( viewWidget ); } QList toolBarActions( QWidget* viewWidget ) const { return m_factory->toolBarActions( viewWidget ); } QString id() const { return m_factory->id(); } private: IToolViewFactory *m_factory; }; class ViewSelectorItem: public QListWidgetItem { public: ViewSelectorItem(const QString &text, QListWidget *parent = 0, int type = Type) :QListWidgetItem(text, parent, type) {} IToolViewFactory *factory; }; class NewToolViewListWidget: public QListWidget { Q_OBJECT public: NewToolViewListWidget(MainWindow *mw, QWidget* parent = 0) :QListWidget(parent), m_mw(mw) { connect(this, &NewToolViewListWidget::doubleClicked, this, &NewToolViewListWidget::addNewToolViewByDoubleClick); } Q_SIGNALS: void addNewToolView(MainWindow *mw, QListWidgetItem *item); private Q_SLOTS: void addNewToolViewByDoubleClick(QModelIndex index) { QListWidgetItem *item = itemFromIndex(index); // Disable item so that the toolview can not be added again. item->setFlags(item->flags() & ~Qt::ItemIsEnabled); emit addNewToolView(m_mw, item); } private: MainWindow *m_mw; }; +class KTextEditorConfigPageAdapter : public ConfigPage +{ + Q_OBJECT + +public: + explicit KTextEditorConfigPageAdapter(KTextEditor::ConfigPage* page, QWidget* parent = nullptr) + : ConfigPage(nullptr, nullptr, parent), m_page(page) + { + page->setParent(this); + QVBoxLayout* layout = new QVBoxLayout(this); + layout->addWidget(page); + this->setLayout(layout); + } + virtual ~KTextEditorConfigPageAdapter() {} + + virtual QString name() const override + { + return m_page->name(); + } + virtual QIcon icon() const override + { + return m_page->icon(); + } + virtual QString fullName() const override + { + return m_page->fullName(); + } +public Q_SLOTS: + virtual void apply() override + { + m_page->apply(); + } + virtual void defaults() override + { + m_page->defaults(); + } + virtual void reset() override + { + m_page->reset(); + } + +private: + KTextEditor::ConfigPage* m_page; +}; + + +class EditorConfigPage : public ConfigPage +{ + Q_OBJECT + +public: + EditorConfigPage(QWidget* parent) + : ConfigPage(nullptr, nullptr, parent) + { + setObjectName("editorconfig"); + } + virtual ~EditorConfigPage() {}; + + virtual QString name() const override + { + return i18n("Editor"); + } + virtual QIcon icon() const override + { + return QIcon::fromTheme(QStringLiteral("accessories-text-editor")); + } + virtual QString fullName() const override + { + return i18n("Configure Text editor"); + } + virtual QList childPages() override + { + QList ret; + auto editor = KTextEditor::Editor::instance(); + for (int i = 0; i < editor->configPages(); ++i) { + ret.append(new KTextEditorConfigPageAdapter(editor->configPage(i, this), this)); + } + return ret; + } + +public Q_SLOTS: + virtual void apply() override {}; + virtual void reset() override {}; + virtual void defaults() override {}; +}; UiController::UiController(Core *core) :Sublime::Controller(0), IUiController(), d(new UiControllerPrivate(this)) { setObjectName("UiController"); d->core = core; if (!defaultMainWindow() || (Core::self()->setupFlags() & Core::NoUi)) return; connect(qApp, &QApplication::focusChanged, this, [&] (QWidget* old, QWidget* now) { d->widgetChanged(old, now); } ); setupActions(); } UiController::~UiController() { delete d; } void UiController::setupActions() { } void UiController::mainWindowDeleted(MainWindow* mw) { if (d->defaultMainWindow == mw) d->defaultMainWindow = 0L; if (d->activeSublimeWindow == mw) d->activeSublimeWindow = 0L; } // FIXME: currently, this always create new window. Probably, // should just rename it. void UiController::switchToArea(const QString &areaName, SwitchMode switchMode) { if (switchMode == ThisWindow) { showArea(areaName, activeSublimeWindow()); return; } MainWindow *main = new MainWindow(this); addMainWindow(main); showArea(areaName, main); main->initialize(); // WTF? First, enabling this code causes crashes since we // try to disconnect some already-deleted action, or something. // Second, this code will disconnection the clients from guiFactory // of the previous main window. Ick! #if 0 //we need to add all existing guiclients to the new mainwindow //@todo adymo: add only ones that belong to the area (when the area code is there) foreach (KXMLGUIClient *client, oldMain->guiFactory()->clients()) main->guiFactory()->addClient(client); #endif main->show(); } QWidget* UiController::findToolView(const QString& name, IToolViewFactory *factory, FindFlags flags) { if(!d->areasRestored || !activeArea()) return 0; QList< Sublime::View* > views = activeArea()->toolViews(); foreach(Sublime::View* view, views) { Sublime::ToolDocument *doc = dynamic_cast(view->document()); if(doc && doc->title() == name && view->widget()) { if(flags & Raise) view->requestRaise(); return view->widget(); } } QWidget* ret = 0; if(flags & Create) { if(!d->factoryDocuments.contains(factory)) d->factoryDocuments[factory] = new Sublime::ToolDocument(name, this, new UiToolViewFactory(factory)); Sublime::ToolDocument *doc = d->factoryDocuments[factory]; Sublime::View* view = addToolViewToArea(factory, doc, activeArea()); if(view) ret = view->widget(); if(flags & Raise) findToolView(name, factory, Raise); } return ret; } void UiController::raiseToolView(QWidget* toolViewWidget) { if(!d->areasRestored) return; QList< Sublime::View* > views = activeArea()->toolViews(); foreach(Sublime::View* view, views) { if(view->widget() == toolViewWidget) { view->requestRaise(); return; } } } void UiController::addToolView(const QString & name, IToolViewFactory *factory) { if (!factory) return; qCDebug(SHELL) ; Sublime::ToolDocument *doc = new Sublime::ToolDocument(name, this, new UiToolViewFactory(factory)); d->factoryDocuments[factory] = doc; /* Until areas are restored, we don't know which views should be really added, and which not, so we just record view availability. */ if (d->areasRestored) { foreach (Sublime::Area* area, allAreas()) { addToolViewToArea(factory, doc, area); } } } void KDevelop::UiController::raiseToolView(Sublime::View * view) { foreach( Sublime::Area* area, allAreas() ) { if( area->toolViews().contains( view ) ) area->raiseToolView( view ); } } void KDevelop::UiController::removeToolView(IToolViewFactory *factory) { if (!factory) return; qCDebug(SHELL) ; //delete the tooldocument Sublime::ToolDocument *doc = d->factoryDocuments[factory]; ///@todo adymo: on document deletion all its views shall be also deleted foreach (Sublime::View *view, doc->views()) { foreach (Sublime::Area *area, allAreas()) if (area->removeToolView(view)) view->deleteLater(); } d->factoryDocuments.remove(factory); delete doc; } Sublime::Area *UiController::activeArea() { Sublime::MainWindow *m = activeSublimeWindow(); if (m) return activeSublimeWindow()->area(); return 0; } Sublime::MainWindow *UiController::activeSublimeWindow() { return d->activeSublimeWindow; } MainWindow *UiController::defaultMainWindow() { return d->defaultMainWindow; } void UiController::initialize() { defaultMainWindow()->initialize(); } void UiController::cleanup() { foreach (Sublime::MainWindow* w, mainWindows()) w->saveSettings(); saveAllAreas(KSharedConfig::openConfig()); } void UiController::selectNewToolViewToAdd(MainWindow *mw) { if (!mw || !mw->area()) return; QDialog *dia = new QDialog(mw); dia->setWindowTitle(i18n("Select Tool View to Add")); auto mainLayout = new QVBoxLayout(dia); NewToolViewListWidget *list = new NewToolViewListWidget(mw, dia); list->setSelectionMode(QAbstractItemView::ExtendedSelection); list->setSortingEnabled(true); for (QMap::const_iterator it = d->factoryDocuments.constBegin(); it != d->factoryDocuments.constEnd(); ++it) { ViewSelectorItem *item = new ViewSelectorItem(it.value()->title(), list); item->factory = it.key(); if (!item->factory->allowMultiple() && toolViewPresent(it.value(), mw->area())) { // Disable item if the toolview is already present. item->setFlags(item->flags() & ~Qt::ItemIsEnabled); } list->addItem(item); } list->setFocus(); connect(list, &NewToolViewListWidget::addNewToolView, this, &UiController::addNewToolView); mainLayout->addWidget(list); auto buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok|QDialogButtonBox::Cancel); auto okButton = buttonBox->button(QDialogButtonBox::Ok); okButton->setDefault(true); okButton->setShortcut(Qt::CTRL | Qt::Key_Return); dia->connect(buttonBox, SIGNAL(accepted()), dia, SLOT(accept())); dia->connect(buttonBox, SIGNAL(rejected()), dia, SLOT(reject())); mainLayout->addWidget(buttonBox); if (dia->exec() == QDialog::Accepted) { foreach (QListWidgetItem* item, list->selectedItems()) { addNewToolView(mw, item); } } delete dia; } void UiController::addNewToolView(MainWindow *mw, QListWidgetItem* item) { ViewSelectorItem *current = static_cast(item); Sublime::ToolDocument *doc = d->factoryDocuments[current->factory]; Sublime::View *view = doc->createView(); mw->area()->addToolView(view, Sublime::dockAreaToPosition(current->factory->defaultPosition())); current->factory->viewCreated(view); } void UiController::showSettingsDialog() { // QStringList blacklist = d->core->pluginControllerInternal()->projectPlugins(); // foreach(const KPluginInfo& info, d->core->pluginControllerInternal()->allPluginInfos()) { // if (!blacklist.contains(info.pluginName()) && !info.isPluginEnabled()) { // blacklist << info.pluginName(); // } // } // kDebug() << "blacklist" << blacklist; // KSettings::Dialog cfgDlg( QStringList() << "kdevplatform", // activeMainWindow() ); // cfgDlg.setMinimumSize( 550, 300 ); // cfgDlg.setComponentBlacklist( blacklist ); // cfgDlg.exec(); auto editorConfigPage = new EditorConfigPage(activeMainWindow()); auto configPages = QList() << new UiPreferences(activeMainWindow()) << new PluginPreferences(activeMainWindow()) << editorConfigPage; ConfigDialog cfgDlg(configPages, activeMainWindow()); auto addPluginPages = [&](IPlugin* plugin) { for (int i = 0; i < plugin->configPages(); ++i) { // insert them before the editor config page cfgDlg.addConfigPage(plugin->configPage(i, activeMainWindow()), editorConfigPage); } }; for (IPlugin* plugin : ICore::self()->pluginController()->loadedPlugins()) { addPluginPages(plugin); } // TODO: only load settings if a UI related page was changed? connect(&cfgDlg, &ConfigDialog::configSaved, activeSublimeWindow(), &Sublime::MainWindow::loadSettings); // make sure that pages get added whenever a new plugin is loaded connect(ICore::self()->pluginController(), &IPluginController::pluginLoaded, addPluginPages); cfgDlg.exec(); } Sublime::Controller* UiController::controller() { return this; } KParts::MainWindow *UiController::activeMainWindow() { return activeSublimeWindow(); } void UiController::saveArea(Sublime::Area * area, KConfigGroup & group) { area->save(group); if (!area->workingSet().isEmpty()) { WorkingSet* set = Core::self()->workingSetControllerInternal()->getWorkingSet(area->workingSet()); set->saveFromArea(area, area->rootIndex()); } } void UiController::loadArea(Sublime::Area * area, const KConfigGroup & group) { area->load(group); if (!area->workingSet().isEmpty()) { WorkingSet* set = Core::self()->workingSetControllerInternal()->getWorkingSet(area->workingSet()); Q_ASSERT(set->isConnected(area)); Q_UNUSED(set); } } void UiController::saveAllAreas(KSharedConfigPtr config) { KConfigGroup uiConfig(config, "User Interface"); int wc = mainWindows().size(); uiConfig.writeEntry("Main Windows Count", wc); for (int w = 0; w < wc; ++w) { KConfigGroup mainWindowConfig(&uiConfig, QString("Main Window %1").arg(w)); foreach (Sublime::Area* defaultArea, defaultAreas()) { // FIXME: using object name seems ugly. QString type = defaultArea->objectName(); Sublime::Area* area = this->area(w, type); KConfigGroup areaConfig(&mainWindowConfig, "Area " + type); areaConfig.deleteGroup(); areaConfig.writeEntry("id", type); saveArea(area, areaConfig); areaConfig.sync(); } } uiConfig.sync(); } void UiController::loadAllAreas(KSharedConfigPtr config) { KConfigGroup uiConfig(config, "User Interface"); int wc = uiConfig.readEntry("Main Windows Count", 1); /* It is expected the main windows are restored before restoring areas. */ if (wc > mainWindows().size()) wc = mainWindows().size(); QList changedAreas; /* Offer all toolviews to the default areas. */ foreach (Sublime::Area *area, defaultAreas()) { QMap::const_iterator i, e; for (i = d->factoryDocuments.constBegin(), e = d->factoryDocuments.constEnd(); i != e; ++i) { addToolViewIfWanted(i.key(), i.value(), area); } } /* Restore per-windows areas. */ for (int w = 0; w < wc; ++w) { KConfigGroup mainWindowConfig(&uiConfig, QString("Main Window %1").arg(w)); Sublime::MainWindow *mw = mainWindows()[w]; /* We loop over default areas. This means that if the config file has an area of some type that is not in default set, we'd just ignore it. I think it's fine -- the model were a given mainwindow can has it's own area types not represented in the default set is way too complex. */ foreach (Sublime::Area* defaultArea, defaultAreas()) { QString type = defaultArea->objectName(); Sublime::Area* area = this->area(w, type); KConfigGroup areaConfig(&mainWindowConfig, "Area " + type); qCDebug(SHELL) << "Trying to restore area " << type; /* This is just an easy check that a group exists, to avoid "restoring" area from empty config group, wiping away programmatically installed defaults. */ if (areaConfig.readEntry("id", "") == type) { qCDebug(SHELL) << "Restoring area " << type; loadArea(area, areaConfig); } // At this point we know which toolviews the area wants. // Tender all tool views we have. QMap::const_iterator i, e; for (i = d->factoryDocuments.constBegin(), e = d->factoryDocuments.constEnd(); i != e; ++i) { addToolViewIfWanted(i.key(), i.value(), area); } } // Force reload of the changes. showAreaInternal(mw->area(), mw); mw->enableAreaSettingsSave(); } d->areasRestored = true; } void UiController::addToolViewToDockArea(IToolViewFactory* factory, Qt::DockWidgetArea area) { addToolViewToArea(factory, d->factoryDocuments[factory], activeArea(), Sublime::dockAreaToPosition(area)); } bool UiController::toolViewPresent(Sublime::ToolDocument* doc, Sublime::Area* area) { foreach (Sublime::View *view, doc->views()) { if( area->toolViews().contains( view ) ) return true; } return false; } void UiController::addToolViewIfWanted(IToolViewFactory* factory, Sublime::ToolDocument* doc, Sublime::Area* area) { if (area->wantToolView(factory->id())) { addToolViewToArea(factory, doc, area); } } Sublime::View* UiController::addToolViewToArea(IToolViewFactory* factory, Sublime::ToolDocument* doc, Sublime::Area* area, Sublime::Position p) { Sublime::View* view = doc->createView(); area->addToolView( view, p == Sublime::AllPositions ? Sublime::dockAreaToPosition(factory->defaultPosition()) : p); connect(view, &Sublime::View::raise, this, static_cast(&UiController::raiseToolView)); factory->viewCreated(view); return view; } void UiController::registerStatus(QObject* status) { Sublime::MainWindow* w = activeSublimeWindow(); if (!w) return; MainWindow* mw = qobject_cast(w); if (!mw) return; mw->registerStatus(status); } void UiController::showErrorMessage(const QString& message, int timeout) { Sublime::MainWindow* w = activeSublimeWindow(); if (!w) return; MainWindow* mw = qobject_cast(w); if (!mw) return; QMetaObject::invokeMethod(mw, "showErrorMessage", Q_ARG(QString, message), Q_ARG(int, timeout)); } void UiController::hideAssistant() { if (d->currentShownAssistant) { d->currentShownAssistant->hide(); } } void UiController::popUpAssistant(const KDevelop::IAssistant::Ptr& assistant) { if(!assistant) return; Sublime::View* view = d->activeSublimeWindow->activeView(); if( !view ) { qCDebug(SHELL) << "no active view in mainwindow"; return; } auto editorView = qobject_cast(view->widget()); Q_ASSERT(editorView); if (editorView) { if ( !d->currentShownAssistant ) { d->currentShownAssistant = new AssistantPopup; } d->currentShownAssistant->reset(editorView, assistant); } } const QMap< IToolViewFactory*, Sublime::ToolDocument* >& UiController::factoryDocuments() const { return d->factoryDocuments; } } #include "uicontroller.moc" #include "moc_uicontroller.cpp"