diff --git a/shell/CMakeLists.txt b/shell/CMakeLists.txt index 939ba67fcb..c091526e03 100644 --- a/shell/CMakeLists.txt +++ b/shell/CMakeLists.txt @@ -1,144 +1,149 @@ add_subdirectory(settings) add_subdirectory(tests) set(KDevPlatformShell_LIB_SRCS workingsetcontroller.cpp workingsets/workingset.cpp workingsets/workingsetfilelabel.cpp workingsets/workingsettoolbutton.cpp workingsets/workingsettooltipwidget.cpp workingsets/workingsetwidget.cpp workingsets/closedworkingsetswidget.cpp workingsets/workingsethelpers.cpp assistantpopup.cpp mainwindow.cpp mainwindow_p.cpp plugincontroller.cpp shellextension.cpp core.cpp uicontroller.cpp projectcontroller.cpp project.cpp partcontroller.cpp #document.cpp partdocument.cpp textdocument.cpp documentcontroller.cpp languagecontroller.cpp language.cpp statusbar.cpp runcontroller.cpp sessioncontroller.cpp session.cpp sessionlock.cpp sessionchooserdialog.cpp savedialog.cpp sessiondialog.cpp sourceformattercontroller.cpp completionsettings.cpp openprojectpage.cpp openprojectdialog.cpp projectinfopage.cpp selectioncontroller.cpp documentationcontroller.cpp debugcontroller.cpp launchconfiguration.cpp launchconfigurationdialog.cpp loadedpluginsdialog.cpp testcontroller.cpp projectsourcepage.cpp debug.cpp configdialog.cpp editorconfigpage.cpp progresswidget/progressmanager.cpp progresswidget/statusbarprogresswidget.cpp progresswidget/overlaywidget.cpp progresswidget/progressdialog.cpp areadisplay.cpp settings/uipreferences.cpp settings/pluginpreferences.cpp + settings/sourceformattersettings.cpp + settings/editstyledialog.cpp + ) set(KDevPlatformShell_UI sessiondialog.ui projectinfopage.ui launchconfigurationdialog.ui projectsourcepage.ui settings/uiconfig.ui + settings/editstyledialog.ui + settings/sourceformattersettings.ui ) ki18n_wrap_ui(KDevPlatformShell_LIB_SRCS ${KDevPlatformShell_UI}) kconfig_add_kcfg_files(KDevPlatformShell_LIB_SRCS settings/uiconfig.kcfgc) add_library(KDevPlatformShell ${KDevPlatformShell_LIB_SRCS}) add_library(KDev::Shell ALIAS KDevPlatformShell) generate_export_header(KDevPlatformShell EXPORT_FILE_NAME shellexport.h) target_link_libraries(KDevPlatformShell LINK_PUBLIC KF5::XmlGui KDev::Sublime KDev::OutputView KDev::Debugger KDev::Interfaces LINK_PRIVATE Qt5::Declarative KF5::GuiAddons KF5::IconThemes KF5::KIOFileWidgets KF5::KIOWidgets KF5::Parts KF5::Notifications KF5::NotifyConfig KF5::TextEditor KF5::ThreadWeaver KF5::JobWidgets KF5::ItemViews KF5::WindowSystem KF5::KCMUtils #for KPluginSelector, not sure why it is in kcmutils KDev::Project KDev::Vcs KDev::Language KDev::Util KDev::Documentation ) set_target_properties(KDevPlatformShell PROPERTIES VERSION ${KDEVPLATFORM_LIB_VERSION} SOVERSION ${KDEVPLATFORM_LIB_SOVERSION} EXPORT_NAME Shell) install(FILES mainwindow.h plugincontroller.h shellextension.h core.h uicontroller.h projectcontroller.h project.h partcontroller.h partdocument.h textdocument.h documentcontroller.h languagecontroller.h session.h sessioncontroller.h sessionlock.h sourceformattercontroller.h language.h selectioncontroller.h runcontroller.h launchconfiguration.h ${CMAKE_CURRENT_BINARY_DIR}/shellexport.h DESTINATION ${INCLUDE_INSTALL_DIR}/kdevplatform/shell COMPONENT Devel ) install(TARGETS KDevPlatformShell EXPORT KDevPlatformTargets ${INSTALL_TARGETS_DEFAULT_ARGS} ) install( FILES debugger/kdevdebuggershellui.rc DESTINATION ${KXMLGUI_INSTALL_DIR}/kdevdebugger ) install( FILES kdevsessionui.rc DESTINATION ${KXMLGUI_INSTALL_DIR}/kdevsession ) install( FILES kdevsourceformatter.rc DESTINATION ${KXMLGUI_INSTALL_DIR}/kdevsourceformatter ) install( FILES AssistantButton.qml assistantpopup.qml DESTINATION ${DATA_INSTALL_DIR}/kdevelop ) diff --git a/shell/settings/CMakeLists.txt b/shell/settings/CMakeLists.txt index 6a2e6eda4e..4f2f0667dc 100644 --- a/shell/settings/CMakeLists.txt +++ b/shell/settings/CMakeLists.txt @@ -1,112 +1,90 @@ include_directories( ${KDevPlatform_SOURCE_DIR} ) ########### Background Parser set( bgsettings_cfg_SRCS bgpreferences.cpp ) set( bgsettings_cfg_UI bgsettings.ui ) ki18n_wrap_ui( bgsettings_cfg_SRCS ${bgsettings_cfg_UI} ) kconfig_add_kcfg_files( bgsettings_cfg_SRCS bgconfig.kcfgc ) add_library( kcm_kdev_bgsettings MODULE ${bgsettings_cfg_SRCS} ) target_link_libraries( kcm_kdev_bgsettings KF5::KCMUtils KDev::Shell KDev::Language) ########### Background Parser set( ccsettings_cfg_SRCS ccpreferences.cpp ) set( ccsettings_cfg_UI ccsettings.ui ) ki18n_wrap_ui( ccsettings_cfg_SRCS ${ccsettings_cfg_UI} ) kconfig_add_kcfg_files( ccsettings_cfg_SRCS ccconfig.kcfgc ) add_library( kcm_kdev_ccsettings MODULE ${ccsettings_cfg_SRCS} ) target_link_libraries( kcm_kdev_ccsettings KF5::KCMUtils KDev::Interfaces KDev::Shell KF5::TextEditor) ########### Project Configuration set( projectsettings_cfg_SRCS projectpreferences.cpp ) set( projectsettings_cfg_UI projectsettings.ui ) ki18n_wrap_ui( projectsettings_cfg_SRCS ${projectsettings_cfg_UI} ) kconfig_add_kcfg_files( projectsettings_cfg_SRCS projectconfig.kcfgc ) add_library( kcm_kdev_projectsettings MODULE ${projectsettings_cfg_SRCS} ) target_link_libraries( kcm_kdev_projectsettings KF5::KCMUtils KF5::KIOWidgets KDev::Shell) ########### Environment widget set( envsettings_cfg_SRCS environmentwidget.cpp environmentgroupmodel.cpp environmentpreferences.cpp ../debug.cpp ) set( envsettings_cfg_UI environmentwidget.ui ) ki18n_wrap_ui( envsettings_cfg_SRCS ${envsettings_cfg_UI} ) add_library( kcm_kdev_envsettings MODULE ${envsettings_cfg_SRCS} ) target_link_libraries( kcm_kdev_envsettings KF5::KCMUtils KDev::Shell KDev::Util) -########## Formatter Settings -set(kcm_kdevsourceformattersettings_SRCS - editstyledialog.cpp - sourceformattersettings.cpp - ../debug.cpp -) - -set(kcm_kdevsourceformattersettings_UI - editstyledialog.ui - sourceformattersettings.ui -) - -ki18n_wrap_ui(kcm_kdevsourceformattersettings_SRCS ${kcm_kdevsourceformattersettings_UI} ) -add_library(kcm_kdevsourceformattersettings MODULE ${kcm_kdevsourceformattersettings_SRCS}) -target_link_libraries(kcm_kdevsourceformattersettings - KF5::TextEditor KF5::Parts - KDev::Shell KDev::Util KDev::Language) - ########## Install TARGETS/Files install( TARGETS kcm_kdev_projectsettings kcm_kdev_ccsettings kcm_kdev_bgsettings kcm_kdev_envsettings - kcm_kdevsourceformattersettings DESTINATION ${PLUGIN_INSTALL_DIR}/kdevplatform/${KDEV_PLUGIN_VERSION}/kcm) configure_file(kcm_kdev_envsettings.desktop.cmake ${CMAKE_CURRENT_BINARY_DIR}/kcm_kdev_envsettings.desktop) kcoreaddons_desktop_to_json(kcm_kdev_envsettings ${CMAKE_CURRENT_BINARY_DIR}/kcm_kdev_envsettings.desktop) configure_file(kcm_kdev_projectsettings.desktop.cmake ${CMAKE_CURRENT_BINARY_DIR}/kcm_kdev_projectsettings.desktop) kcoreaddons_desktop_to_json(kcm_kdev_projectsettings ${CMAKE_CURRENT_BINARY_DIR}/kcm_kdev_projectsettings.desktop) configure_file(kcm_kdev_bgsettings.desktop.cmake ${CMAKE_CURRENT_BINARY_DIR}/kcm_kdev_bgsettings.desktop) kcoreaddons_desktop_to_json(kcm_kdev_bgsettings ${CMAKE_CURRENT_BINARY_DIR}/kcm_kdev_bgsettings.desktop) configure_file(kcm_kdev_ccsettings.desktop.cmake ${CMAKE_CURRENT_BINARY_DIR}/kcm_kdev_ccsettings.desktop) kcoreaddons_desktop_to_json(kcm_kdev_ccsettings ${CMAKE_CURRENT_BINARY_DIR}/kcm_kdev_ccsettings.desktop) -configure_file(kcm_kdevsourceformattersettings.desktop.cmake ${CMAKE_CURRENT_BINARY_DIR}/kcm_kdevsourceformattersettings.desktop) -kcoreaddons_desktop_to_json(kcm_kdevsourceformattersettings ${CMAKE_CURRENT_BINARY_DIR}/kcm_kdevsourceformattersettings.desktop) install( FILES ${CMAKE_CURRENT_BINARY_DIR}/kcm_kdev_envsettings.desktop ${CMAKE_CURRENT_BINARY_DIR}/kcm_kdev_projectsettings.desktop ${CMAKE_CURRENT_BINARY_DIR}/kcm_kdev_bgsettings.desktop ${CMAKE_CURRENT_BINARY_DIR}/kcm_kdev_ccsettings.desktop - ${CMAKE_CURRENT_BINARY_DIR}/kcm_kdevsourceformattersettings.desktop DESTINATION ${SERVICES_INSTALL_DIR} ) diff --git a/shell/settings/kcm_kdevsourceformattersettings.desktop.cmake b/shell/settings/kcm_kdevsourceformattersettings.desktop.cmake deleted file mode 100644 index 6f22083488..0000000000 --- a/shell/settings/kcm_kdevsourceformattersettings.desktop.cmake +++ /dev/null @@ -1,82 +0,0 @@ -[Desktop Entry] -Icon=text-field -Type=Service -ServiceTypes=KCModule - -X-KDE-ModuleType=Library -X-KDE-Library=kdevplatform/@KDEV_PLUGIN_VERSION@/kcm/kcm_kdevsourceformattersettings -X-KDE-FactoryName=kcm_kdevsourceformattersettings -X-KDE-ParentApp=kdevplatform -X-KDE-ParentComponents=kdevplatform -X-KDE-CfgDlgHierarchy=USERINTERFACE -X-KDE-Weight=5 - -Name=Source Formatter -Name[bg]=Форматиращ модул за програмен текст -Name[bs]=Formater izvornog koda -Name[ca]=Formatador de codi font -Name[ca@valencia]=Formatador de codi font -Name[da]=Formatering af kildekode -Name[de]=Quelltextformatierer -Name[el]=Διαμορφωτής πηγαίου κώδικα -Name[en_GB]=Source Formatter -Name[es]=Formateador de código -Name[et]=Lähtekoodi vormindaja -Name[fi]=Lähdekoodin muotoilu -Name[fr]=Formateur de sources -Name[gl]=Formatador do código -Name[hu]=Forrásformázó -Name[it]=Formattatore sorgenti -Name[ja]=ソースフォーマッタ -Name[kk]=Бастапқы код пішімдеуіші -Name[nb]=Kildeformattering -Name[nds]=Bornformateren -Name[nl]=Broncode-formatteerprogramma -Name[pl]=Formatowanie źródeł -Name[pt]=Formatador de Código -Name[pt_BR]=Formatador de código -Name[ru]=Форматирование кода -Name[sk]=Formátovač zdroja -Name[sl]=Oblikovalnik izvorne kode -Name[sv]=Källkodsformatering -Name[tr]=Kaynak Biçimlendirici -Name[ug]=مەنبەنى پىچقۇچ -Name[uk]=Форматування коду -Name[x-test]=xxSource Formatterxx -Name[zh_CN]=源代码格式化器 -Name[zh_TW]=源碼格式器 -Comment=Configure Source Formatter -Comment[bg]=Настройки за форматиране на програмен текст -Comment[bs]=Konfiguriši formater izvornog koda -Comment[ca]=Configura el formatador de codi font -Comment[ca@valencia]=Configura el formatador de codi font -Comment[da]=Indstil kildekodeformatering -Comment[de]=Quelltextformatierer einrichten -Comment[el]=Διαμόρφωση πηγαίου κώδικα -Comment[en_GB]=Configure Source Formatter -Comment[es]=Configurar formateador de código -Comment[et]=Lähtekoodi vormindaja seadistamine -Comment[fi]=Lähdekoodin muotoilun asetukset -Comment[fr]=Configurer le programme de formatage de sources -Comment[gl]=Configurar o formatador do código -Comment[hu]=Forrásformázó beállítása -Comment[it]=Configura il formattatore di sorgenti -Comment[ja]=ソースフォーマッタを設定します -Comment[kk]=Бастапқы код пішімдеуішін баптау -Comment[nb]=Sett opp kildeformattering -Comment[nds]=Bornformateren instellen -Comment[nl]=Broncode-formatteerprogramma instellen -Comment[pl]=Ustawienia formatowania źródeł -Comment[pt]=Configurar o Formatador de Código -Comment[pt_BR]=Configurar o formatador de código -Comment[ru]=Настройка форматирования исходного кода -Comment[sk]=Nastaviť formátovač zdroja -Comment[sl]=Nastavite oblikovalnik izvorne kode -Comment[sv]=Anpassa källkodsformatering -Comment[tr]=Kaynak Biçimlendiriciyi Yapılandır -Comment[ug]=مەنبەنى پىچقۇچنى سەپلەش -Comment[uk]=Налаштування форматування коду -Comment[x-test]=xxConfigure Source Formatterxx -Comment[zh_CN]=配置源代码格式化器 -Comment[zh_TW]=設定源碼格式器 - diff --git a/shell/settings/sourceformattersettings.cpp b/shell/settings/sourceformattersettings.cpp index b7daf38b93..8144a555d5 100644 --- a/shell/settings/sourceformattersettings.cpp +++ b/shell/settings/sourceformattersettings.cpp @@ -1,518 +1,532 @@ /* This file is part of KDevelop * Copyright (C) 2008 Cédric Pasteur This program is free software; you can redistribute it and/or modify it under the terms of the GNU 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 General Public License along with this program; see the file COPYING. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "sourceformattersettings.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "editstyledialog.h" #include "../debug.h" #define STYLE_ROLE (Qt::UserRole+1) -K_PLUGIN_FACTORY_WITH_JSON(SourceFormatterSettingsFactory, "kcm_kdevsourceformattersettings.json", registerPlugin();) - using KDevelop::Core; using KDevelop::ISourceFormatter; using KDevelop::SourceFormatterStyle; using KDevelop::SourceFormatterController; using KDevelop::SourceFormatter; const QString SourceFormatterSettings::userStylePrefix( "User" ); LanguageSettings::LanguageSettings() : selectedFormatter(0), selectedStyle(0) { } -SourceFormatterSettings::SourceFormatterSettings(QWidget *parent, const QVariantList &args) - : KCModule(KAboutData::pluginData("kcm_kdevsourceformattersettings"), parent, args) +SourceFormatterSettings::SourceFormatterSettings(QWidget* parent) + : KDevelop::ConfigPage(nullptr, nullptr, parent) { setupUi(this); connect( cbLanguages, static_cast(&KComboBox::currentIndexChanged), this, &SourceFormatterSettings::selectLanguage ); connect( cbFormatters, static_cast(&KComboBox::currentIndexChanged), this, &SourceFormatterSettings::selectFormatter ); connect( chkKateModelines, &QCheckBox::toggled, this, &SourceFormatterSettings::somethingChanged ); connect( chkKateOverrideIndentation, &QCheckBox::toggled, this, &SourceFormatterSettings::somethingChanged ); connect( styleList, &QListWidget::currentRowChanged, this, &SourceFormatterSettings::selectStyle ); connect( btnDelStyle, &QPushButton::clicked, this, &SourceFormatterSettings::deleteStyle ); connect( btnNewStyle, &QPushButton::clicked, this, &SourceFormatterSettings::newStyle ); connect( btnEditStyle, &QPushButton::clicked, this, &SourceFormatterSettings::editStyle ); connect( styleList, &QListWidget::itemChanged, this, &SourceFormatterSettings::styleNameChanged ); m_document = KTextEditor::Editor::instance()->createDocument(this); m_document->setReadWrite(false); m_view = m_document->createView(textEditor); m_view->setStatusBarEnabled(false); QVBoxLayout *layout2 = new QVBoxLayout(textEditor); layout2->addWidget(m_view); textEditor->setLayout(layout2); m_view->show(); KTextEditor::ConfigInterface *iface = qobject_cast(m_view); if (iface) { iface->setConfigValue("dynamic-word-wrap", false); iface->setConfigValue("icon-bar", false); } } SourceFormatterSettings::~SourceFormatterSettings() { qDeleteAll(formatters); } void selectAvailableStyle(LanguageSettings& lang) { Q_ASSERT(!lang.selectedFormatter->styles.empty()); lang.selectedStyle = *lang.selectedFormatter->styles.begin(); } -void SourceFormatterSettings::load() +void SourceFormatterSettings::reset() { SourceFormatterController* fmtctrl = Core::self()->sourceFormatterControllerInternal(); foreach( KDevelop::IPlugin* plugin, KDevelop::ICore::self()->pluginController()->allPluginsForExtension( "org.kdevelop.ISourceFormatter" ) ) { KDevelop::ISourceFormatter* ifmt = plugin->extension(); KPluginInfo info = KDevelop::Core::self()->pluginControllerInternal()->pluginInfo( plugin ); KDevelop::SourceFormatter* formatter; FormatterMap::const_iterator iter = formatters.constFind(ifmt->name()); if (iter == formatters.constEnd()) { formatter = fmtctrl->createFormatterForPlugin(ifmt); formatters[ifmt->name()] = formatter; } else { formatter = iter.value(); } for( const SourceFormatterStyle* style: formatter->styles ) { for ( const SourceFormatterStyle::MimeHighlightPair& item: style->mimeTypes() ) { QMimeType mime = QMimeDatabase().mimeTypeForName(item.mimeType); if (!mime.isValid()) { qWarning() << "plugin" << info.name() << "supports unknown mimetype entry" << item.mimeType; continue; } QString languageName = item.highlightMode; LanguageSettings& l = languages[languageName]; l.mimetypes.append(mime); l.formatters.insert( formatter ); } } } // Sort the languages, preferring firstly active, then loaded languages QList sortedLanguages; foreach( KDevelop::ILanguage* language, KDevelop::ICore::self()->languageController()->activeLanguages() + KDevelop::ICore::self()->languageController()->loadedLanguages() ) { if( languages.contains( language->name() ) && !sortedLanguages.contains(language->name()) ) { sortedLanguages.push_back( language->name() ); } } foreach( const QString& name, languages.keys() ) if( !sortedLanguages.contains( name ) ) sortedLanguages.push_back( name ); foreach( const QString& name, sortedLanguages ) { // Pick the first appropriate mimetype for this language KConfigGroup grp = fmtctrl->configuration(); LanguageSettings& l = languages[name]; foreach (const QMimeType& mimetype, l.mimetypes) { QStringList formatterAndStyleName = grp.readEntry(mimetype.name(), "").split("||", QString::KeepEmptyParts); FormatterMap::const_iterator formatterIter = formatters.constFind(formatterAndStyleName.first()); if (formatterIter == formatters.constEnd()) { qCDebug(SHELL) << "Reference to unknown formatter" << formatterAndStyleName.first(); Q_ASSERT(!l.formatters.empty()); // otherwise there should be no entry for 'name' l.selectedFormatter = *l.formatters.begin(); selectAvailableStyle(l); } else { l.selectedFormatter = formatterIter.value(); SourceFormatter::StyleMap::const_iterator styleIter = l.selectedFormatter->styles.constFind(formatterAndStyleName.at( 1 )); if (styleIter == l.selectedFormatter->styles.constEnd()) { qCDebug(SHELL) << "No style" << formatterAndStyleName.at( 1 ) << "found for formatter" << formatterAndStyleName.first(); selectAvailableStyle(l); } else { l.selectedStyle = styleIter.value(); } } break; } if (!l.selectedFormatter) { Q_ASSERT(!l.formatters.empty()); l.selectedFormatter = *l.formatters.begin(); } if (!l.selectedStyle) { selectAvailableStyle(l); } } bool b = blockSignals( true ); cbLanguages->blockSignals( !b ); cbFormatters->blockSignals( !b ); styleList->blockSignals( !b ); chkKateModelines->blockSignals( !b ); chkKateOverrideIndentation->blockSignals( !b ); cbLanguages->clear(); cbFormatters->clear(); styleList->clear(); chkKateModelines->setChecked( fmtctrl->configuration().readEntry( SourceFormatterController::kateModeLineConfigKey, false ) ); chkKateOverrideIndentation->setChecked( fmtctrl->configuration().readEntry( SourceFormatterController::kateOverrideIndentationConfigKey, false ) ); foreach( const QString& name, sortedLanguages ) { cbLanguages->addItem( name ); } if( cbLanguages->count() == 0 ) { cbLanguages->setEnabled( false ); selectLanguage( -1 ); } else { cbLanguages->setCurrentIndex( 0 ); selectLanguage( 0 ); } updatePreview(); blockSignals( b ); cbLanguages->blockSignals( b ); cbFormatters->blockSignals( b ); styleList->blockSignals( b ); chkKateModelines->blockSignals( b ); chkKateOverrideIndentation->blockSignals( b ); } -void SourceFormatterSettings::save() +void SourceFormatterSettings::apply() { KConfigGroup grp = Core::self()->sourceFormatterControllerInternal()->configuration(); for ( LanguageMap::const_iterator iter = languages.constBegin(); iter != languages.constEnd(); ++iter ) { foreach(const QMimeType& mime, iter.value().mimetypes) { grp.writeEntry(mime.name(), QString("%1||%2").arg(iter.value().selectedFormatter->formatter->name()).arg(iter.value().selectedStyle->name())); } } foreach( SourceFormatter* fmt, formatters ) { KConfigGroup fmtgrp = grp.group( fmt->formatter->name() ); // delete all styles so we don't leave any behind when all user styles are deleted foreach( const QString& subgrp, fmtgrp.groupList() ) { if( subgrp.startsWith( userStylePrefix ) ) { fmtgrp.deleteGroup( subgrp ); } } foreach( const SourceFormatterStyle* style, fmt->styles ) { if( style->name().startsWith( userStylePrefix ) ) { KConfigGroup stylegrp = fmtgrp.group( style->name() ); stylegrp.writeEntry( SourceFormatterController::styleCaptionKey, style->caption() ); stylegrp.writeEntry( SourceFormatterController::styleContentKey, style->content() ); stylegrp.writeEntry( SourceFormatterController::styleMimeTypesKey, style->mimeTypesVariant() ); stylegrp.writeEntry( SourceFormatterController::styleSampleKey, style->overrideSample() ); } } } grp.writeEntry( SourceFormatterController::kateModeLineConfigKey, chkKateModelines->isChecked() ); grp.writeEntry( SourceFormatterController::kateOverrideIndentationConfigKey, chkKateOverrideIndentation->isChecked() ); grp.sync(); Core::self()->sourceFormatterControllerInternal()->settingsChanged(); } void SourceFormatterSettings::enableStyleButtons() { bool userEntry = styleList->currentItem() && styleList->currentItem()->data( STYLE_ROLE ).toString().startsWith( userStylePrefix ); QString languageName = cbLanguages->currentText(); QMap< QString, LanguageSettings >::const_iterator it = languages.constFind(languageName); bool hasEditWidget = false; if (it != languages.constEnd()) { const LanguageSettings& l = it.value(); Q_ASSERT(l.selectedFormatter); ISourceFormatter* fmt = l.selectedFormatter->formatter; hasEditWidget = ( fmt && fmt->editStyleWidget( l.mimetypes.first() ) ); } btnDelStyle->setEnabled( userEntry ); btnEditStyle->setEnabled( userEntry && hasEditWidget ); btnNewStyle->setEnabled( cbFormatters->currentIndex() >= 0 && hasEditWidget ); } void SourceFormatterSettings::selectLanguage( int idx ) { cbFormatters->clear(); if( idx < 0 ) { cbFormatters->setEnabled( false ); selectFormatter( -1 ); return; } cbFormatters->setEnabled( true ); bool b = cbFormatters->blockSignals( true ); LanguageSettings& l = languages[cbLanguages->itemText( idx )]; foreach( const SourceFormatter* fmt, l.formatters ) { cbFormatters->addItem( fmt->formatter->caption(), fmt->formatter->name() ); } cbFormatters->setCurrentIndex(cbFormatters->findData(l.selectedFormatter->formatter->name())); cbFormatters->blockSignals(b); selectFormatter( cbFormatters->currentIndex() ); - emit changed( true ); + emit changed(); } void SourceFormatterSettings::selectFormatter( int idx ) { styleList->clear(); if( idx < 0 ) { styleList->setEnabled( false ); enableStyleButtons(); return; } styleList->setEnabled( true ); LanguageSettings& l = languages[ cbLanguages->currentText() ]; Q_ASSERT( idx < l.formatters.size() ); FormatterMap::const_iterator formatterIter = formatters.constFind(cbFormatters->itemData( idx ).toString()); Q_ASSERT( formatterIter != formatters.constEnd() ); Q_ASSERT( l.formatters.contains(formatterIter.value()) ); if (l.selectedFormatter != formatterIter.value()) { l.selectedFormatter = formatterIter.value(); l.selectedStyle = 0; // will hold 0 until a style is picked } foreach( const SourceFormatterStyle* style, formatterIter.value()->styles ) { if ( ! style->supportsLanguage(cbLanguages->currentText())) { // do not list items which do not support the selected language continue; } QListWidgetItem* item = addStyle( *style ); if (style == l.selectedStyle) { styleList->setCurrentItem(item); } } if (l.selectedStyle == 0) { styleList->setCurrentRow(0); } enableStyleButtons(); - emit changed( true ); + emit changed(); } void SourceFormatterSettings::selectStyle( int row ) { if( row < 0 ) { enableStyleButtons(); return; } styleList->setCurrentRow( row ); LanguageSettings& l = languages[ cbLanguages->currentText() ]; l.selectedStyle = l.selectedFormatter->styles[styleList->item( row )->data( STYLE_ROLE ).toString()]; enableStyleButtons(); updatePreview(); - emit changed( true ); + emit changed(); } void SourceFormatterSettings::deleteStyle() { Q_ASSERT( styleList->currentRow() >= 0 ); QListWidgetItem* item = styleList->currentItem(); LanguageSettings& l = languages[ cbLanguages->currentText() ]; SourceFormatter* fmt = l.selectedFormatter; SourceFormatter::StyleMap::iterator styleIter = fmt->styles.find(item->data( STYLE_ROLE ).toString()); QStringList otherLanguageNames; QList otherlanguages; for ( LanguageMap::iterator languageIter = languages.begin(); languageIter != languages.end(); ++languageIter ) { if ( &languageIter.value() != &l && languageIter.value().selectedStyle == styleIter.value() ) { otherLanguageNames.append(languageIter.key()); otherlanguages.append(&languageIter.value()); } } if (!otherLanguageNames.empty() && KMessageBox::warningContinueCancel(this, i18n("The style %1 is also used for the following languages:\n%2.\nAre you sure you want to delete it?", styleIter.value()->caption(), otherLanguageNames.join("\n")), i18n("Style being deleted")) != KMessageBox::Continue) { return; } styleList->takeItem( styleList->currentRow() ); fmt->styles.erase(styleIter); delete item; selectStyle( styleList->count() > 0 ? 0 : -1 ); foreach (LanguageSettings* lang, otherlanguages) { selectAvailableStyle(*lang); } updatePreview(); - emit changed( true ); + emit changed(); } void SourceFormatterSettings::editStyle() { QString language = cbLanguages->currentText(); Q_ASSERT( languages.contains( language ) ); LanguageSettings& l = languages[ language ]; SourceFormatter* fmt = l.selectedFormatter; QMimeType mimetype = l.mimetypes.first(); if( fmt->formatter->editStyleWidget( mimetype ) != 0 ) { EditStyleDialog dlg( fmt->formatter, mimetype, *l.selectedStyle, this ); if( dlg.exec() == QDialog::Accepted ) { l.selectedStyle->setContent(dlg.content()); } updatePreview(); - emit changed( true ); + emit changed(); } } void SourceFormatterSettings::newStyle() { QListWidgetItem* item = styleList->currentItem(); LanguageSettings& l = languages[ cbLanguages->currentText() ]; SourceFormatter* fmt = l.selectedFormatter; int idx = 0; for( int i = 0; i < styleList->count(); i++ ) { QString name = styleList->item( i )->data( STYLE_ROLE ).toString(); if( name.startsWith( userStylePrefix ) && name.mid( userStylePrefix.length() ).toInt() >= idx ) { idx = name.mid( userStylePrefix.length() ).toInt(); } } // Increase number for next style idx++; SourceFormatterStyle* s = new SourceFormatterStyle( QString( "%1%2" ).arg( userStylePrefix ).arg( idx ) ); if( item ) { SourceFormatterStyle* existstyle = fmt->styles[ item->data( STYLE_ROLE ).toString() ]; s->setCaption( i18n( "New %1", existstyle->caption() ) ); s->copyDataFrom( existstyle ); } else { s->setCaption( i18n( "New Style" ) ); } fmt->styles[ s->name() ] = s; QListWidgetItem* newitem = addStyle( *s ); selectStyle( styleList->row( newitem ) ); styleList->editItem( newitem ); - emit changed( true ); + emit changed(); } void SourceFormatterSettings::styleNameChanged( QListWidgetItem* item ) { if ( !item->isSelected() ) { return; } LanguageSettings& l = languages[ cbLanguages->currentText() ]; l.selectedStyle->setCaption( item->text() ); - emit changed( true ); + emit changed(); } QListWidgetItem* SourceFormatterSettings::addStyle( const SourceFormatterStyle& s ) { QListWidgetItem* item = new QListWidgetItem( styleList ); item->setText( s.caption() ); item->setData( STYLE_ROLE, s.name() ); if( s.name().startsWith( userStylePrefix ) ) { item->setFlags( item->flags() | Qt::ItemIsEditable ); } styleList->addItem( item ); return item; } void SourceFormatterSettings::updatePreview() { m_document->setReadWrite( true ); QString langName = cbLanguages->itemText( cbLanguages->currentIndex() ); if( !langName.isEmpty() ) { LanguageSettings& l = languages[ langName ]; SourceFormatter* fmt = l.selectedFormatter; SourceFormatterStyle* style = l.selectedStyle; descriptionLabel->setText( style->description() ); if( style->description().isEmpty() ) descriptionLabel->hide(); else descriptionLabel->show(); if( style->usePreview() ) { ISourceFormatter* ifmt = fmt->formatter; QMimeType mime = l.mimetypes.first(); m_document->setHighlightingMode( style->modeForMimetype( mime ) ); //NOTE: this is ugly, but otherwise kate might remove tabs again :-/ // see also: https://bugs.kde.org/show_bug.cgi?id=291074 KTextEditor::ConfigInterface* iface = qobject_cast(m_document); QVariant oldReplaceTabs; if (iface) { oldReplaceTabs = iface->configValue("replace-tabs"); iface->setConfigValue("replace-tabs", false); } m_document->setText( ifmt->formatSourceWithStyle( *style, ifmt->previewText( *style, mime ), QUrl(), mime ) ); if (iface) { iface->setConfigValue("replace-tabs", oldReplaceTabs); } previewLabel->show(); textEditor->show(); }else{ previewLabel->hide(); textEditor->hide(); } } else { m_document->setText( i18n( "No Language selected" ) ); } m_view->setCursorPosition( KTextEditor::Cursor( 0, 0 ) ); m_document->setReadWrite( false ); } void SourceFormatterSettings::somethingChanged() { // Widgets are managed manually, so we have to explicitly tell KCModule // that we have some changes, otherwise it won't call "save" and/or will not activate // "Appy" - unmanagedWidgetChangeState(true); + emit changed(); +} + +QString SourceFormatterSettings::name() const +{ + return i18n("Source Formatter"); } +QString SourceFormatterSettings::fullName() const +{ + return i18n("Configure Source Formatter"); +} + +QIcon SourceFormatterSettings::icon() const +{ + return QIcon::fromTheme(QStringLiteral("text-field")); +} + + #include "sourceformattersettings.moc" diff --git a/shell/settings/sourceformattersettings.h b/shell/settings/sourceformattersettings.h index e27933c453..6587c266ef 100644 --- a/shell/settings/sourceformattersettings.h +++ b/shell/settings/sourceformattersettings.h @@ -1,93 +1,98 @@ /* This file is part of KDevelop * Copyright (C) 2008 Cédric Pasteur This program is free software; you can redistribute it and/or modify it under the terms of the GNU 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 General Public License along with this program; see the file COPYING. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef KDEVPLATFORM_SOURCEFORMATTERSETTINGS_H #define KDEVPLATFORM_SOURCEFORMATTERSETTINGS_H #include -#include #include -#include +#include + +#include "sourceformattercontroller.h" #include "ui_sourceformattersettings.h" class QListWidgetItem; namespace KTextEditor { class Document; class View; } namespace KDevelop { class ISourceFormatter; class SourceFormatterStyle; } struct LanguageSettings { LanguageSettings(); QList mimetypes; QSet formatters; // weak pointers to selected formatter and style, no ownership KDevelop::SourceFormatter* selectedFormatter; // Should never be zero KDevelop::SourceFormatterStyle* selectedStyle; // TODO: can this be zero? Assume that not }; /** \short The settings modulefor the Source formatter plugin. * It supports predefined and custom styles. A live preview of the style * is shown on the right side of the page.s */ -class SourceFormatterSettings : public KCModule, public Ui::SourceFormatterSettingsUI +class SourceFormatterSettings : public KDevelop::ConfigPage, public Ui::SourceFormatterSettingsUI { Q_OBJECT public: - SourceFormatterSettings( QWidget *parent, const QVariantList &args ); + explicit SourceFormatterSettings(QWidget* parent = 0); virtual ~SourceFormatterSettings(); + virtual QString name() const override; + virtual QString fullName() const override; + virtual QIcon icon() const override; + public slots: - virtual void load(); - virtual void save(); + virtual void reset() override; + virtual void apply() override; private slots: void deleteStyle(); void editStyle(); void newStyle(); void selectLanguage( int ); void selectFormatter( int ); void selectStyle( int ); void styleNameChanged( QListWidgetItem* ); void somethingChanged(); private: void updatePreview(); QListWidgetItem* addStyle( const KDevelop::SourceFormatterStyle& s ); static const QString userStylePrefix; void enableStyleButtons(); // Language name -> language settings typedef QMap LanguageMap; LanguageMap languages; // formatter name -> formatter. Formatters owned by this typedef QMap FormatterMap; FormatterMap formatters; KTextEditor::Document* m_document; KTextEditor::View* m_view; }; #endif // KDEVPLATFORM_SOURCEFORMATTERSETTINGS_H diff --git a/shell/uicontroller.cpp b/shell/uicontroller.cpp index ebef97862e..37df64e375 100644 --- a/shell/uicontroller.cpp +++ b/shell/uicontroller.cpp @@ -1,712 +1,714 @@ /*************************************************************************** * 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 #include "core.h" #include "configpage.h" #include "configdialog.h" #include "debug.h" #include "editorconfigpage.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 "workingsetcontroller.h" #include "workingsets/workingset.h" #include "settings/uipreferences.h" #include "settings/pluginpreferences.h" +#include "settings/sourceformattersettings.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; }; 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() { auto editorConfigPage = new EditorConfigPage(activeMainWindow()); auto configPages = QList() << new UiPreferences(activeMainWindow()) << new PluginPreferences(activeMainWindow()) + << new SourceFormatterSettings(activeMainWindow()) << editorConfigPage; ConfigDialog cfgDlg(configPages, activeMainWindow()); auto addPluginPages = [&](IPlugin* plugin) { for (int i = 0, numPages = plugin->configPages(); i < numPages; ++i) { // insert them before the editor config page cfgDlg.addConfigPage(plugin->configPage(i, &cfgDlg), 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 (probably from the plugin selection dialog) // removal on plugin unload is already handled in ConfigDialog connect(ICore::self()->pluginController(), &IPluginController::pluginLoaded, &cfgDlg, 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"