/* * Copyright (C) 2024 Petr Mironychev * * This file is part of QodeAssist. * * QodeAssist 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 3 of the License, or * (at your option) any later version. * * QodeAssist 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 QodeAssist. If not, see . */ #include "GeneralSettings.hpp" #include #include #include #include #include #include #include #include #include #include #include #include #include "Logger.hpp" #include "SettingsConstants.hpp" #include "SettingsDialog.hpp" #include "SettingsTr.hpp" #include "SettingsUtils.hpp" #include "UpdateDialog.hpp" namespace QodeAssist::Settings { GeneralSettings &generalSettings() { static GeneralSettings settings; return settings; } GeneralSettings::GeneralSettings() { setAutoApply(false); setDisplayName(TrConstants::GENERAL); enableQodeAssist.setSettingsKey(Constants::ENABLE_QODE_ASSIST); enableQodeAssist.setLabelText(TrConstants::ENABLE_QODE_ASSIST); enableQodeAssist.setDefaultValue(true); enableLogging.setSettingsKey(Constants::ENABLE_LOGGING); enableLogging.setLabelText(TrConstants::ENABLE_LOG); enableLogging.setDefaultValue(false); enableCheckUpdate.setSettingsKey(Constants::ENABLE_CHECK_UPDATE); enableCheckUpdate.setLabelText(TrConstants::ENABLE_CHECK_UPDATE_ON_START); enableCheckUpdate.setDefaultValue(true); resetToDefaults.m_buttonText = TrConstants::RESET_TO_DEFAULTS; checkUpdate.m_buttonText = TrConstants::CHECK_UPDATE; initStringAspect(ccProvider, Constants::CC_PROVIDER, TrConstants::PROVIDER, "Ollama"); ccProvider.setReadOnly(true); ccSelectProvider.m_buttonText = TrConstants::SELECT; initStringAspect(ccModel, Constants::CC_MODEL, TrConstants::MODEL, "qwen2.5-coder:7b"); ccModel.setHistoryCompleter(Constants::CC_MODEL_HISTORY); ccSelectModel.m_buttonText = TrConstants::SELECT; initStringAspect(ccTemplate, Constants::CC_TEMPLATE, TrConstants::TEMPLATE, "Ollama Auto FIM"); ccTemplate.setReadOnly(true); ccSelectTemplate.m_buttonText = TrConstants::SELECT; initStringAspect(ccUrl, Constants::CC_URL, TrConstants::URL, "http://localhost:11434"); ccUrl.setHistoryCompleter(Constants::CC_URL_HISTORY); ccSetUrl.m_buttonText = TrConstants::SELECT; ccStatus.setDisplayStyle(Utils::StringAspect::LabelDisplay); ccStatus.setLabelText(TrConstants::STATUS); ccStatus.setDefaultValue(""); ccTest.m_buttonText = TrConstants::TEST; initStringAspect(caProvider, Constants::CA_PROVIDER, TrConstants::PROVIDER, "Ollama"); caProvider.setReadOnly(true); caSelectProvider.m_buttonText = TrConstants::SELECT; initStringAspect(caModel, Constants::CA_MODEL, TrConstants::MODEL, "qwen2.5-coder:7b"); caModel.setHistoryCompleter(Constants::CA_MODEL_HISTORY); caSelectModel.m_buttonText = TrConstants::SELECT; initStringAspect(caTemplate, Constants::CA_TEMPLATE, TrConstants::TEMPLATE, "Ollama Auto Chat"); caTemplate.setReadOnly(true); caSelectTemplate.m_buttonText = TrConstants::SELECT; initStringAspect(caUrl, Constants::CA_URL, TrConstants::URL, "http://localhost:11434"); caUrl.setHistoryCompleter(Constants::CA_URL_HISTORY); caSetUrl.m_buttonText = TrConstants::SELECT; caStatus.setDisplayStyle(Utils::StringAspect::LabelDisplay); caStatus.setLabelText(TrConstants::STATUS); caStatus.setDefaultValue(""); caTest.m_buttonText = TrConstants::TEST; readSettings(); Logger::instance().setLoggingEnabled(enableLogging()); setupConnections(); setLayouter([this]() { using namespace Layouting; auto ccGrid = Grid{}; ccGrid.addRow({ccProvider, ccSelectProvider}); ccGrid.addRow({ccUrl, ccSetUrl}); ccGrid.addRow({ccModel, ccSelectModel}); ccGrid.addRow({ccTemplate, ccSelectTemplate}); auto caGrid = Grid{}; caGrid.addRow({caProvider, caSelectProvider}); caGrid.addRow({caUrl, caSetUrl}); caGrid.addRow({caModel, caSelectModel}); caGrid.addRow({caTemplate, caSelectTemplate}); auto ccGroup = Group{title(TrConstants::CODE_COMPLETION), ccGrid}; auto caGroup = Group{title(TrConstants::CHAT_ASSISTANT), caGrid}; auto rootLayout = Column{ Row{enableQodeAssist, Stretch{1}, Row{checkUpdate, resetToDefaults}}, Row{enableLogging, Stretch{1}}, Row{enableCheckUpdate, Stretch{1}}, Space{8}, ccGroup, Space{8}, caGroup, Stretch{1}}; return rootLayout; }); } void GeneralSettings::showSelectionDialog(const QStringList &data, Utils::StringAspect &aspect, const QString &title, const QString &text) { if (data.isEmpty()) return; bool ok; QInputDialog dialog(Core::ICore::dialogParent()); dialog.setWindowTitle(title); dialog.setLabelText(text); dialog.setComboBoxItems(data); dialog.setComboBoxEditable(false); dialog.setFixedSize(400, 150); if (dialog.exec() == QDialog::Accepted) { QString result = dialog.textValue(); if (!result.isEmpty()) { aspect.setValue(result); writeSettings(); } } } void GeneralSettings::showModelsNotFoundDialog(Utils::StringAspect &aspect) { SettingsDialog dialog(TrConstants::CONNECTION_ERROR); dialog.addLabel(TrConstants::NO_MODELS_FOUND); dialog.addLabel(TrConstants::CHECK_CONNECTION); dialog.addSpacing(); ButtonAspect *providerButton = nullptr; ButtonAspect *urlButton = nullptr; if (&aspect == &ccModel) { providerButton = &ccSelectProvider; urlButton = &ccSetUrl; } else if (&aspect == &caModel) { providerButton = &caSelectProvider; urlButton = &caSetUrl; } if (providerButton && urlButton) { auto selectProviderBtn = new QPushButton(TrConstants::SELECT_PROVIDER); auto selectUrlBtn = new QPushButton(TrConstants::SELECT_URL); auto enterManuallyBtn = new QPushButton(TrConstants::ENTER_MODEL_MANUALLY); connect(selectProviderBtn, &QPushButton::clicked, &dialog, [this, providerButton, &dialog]() { dialog.close(); emit providerButton->clicked(); }); connect(selectUrlBtn, &QPushButton::clicked, &dialog, [this, urlButton, &dialog]() { dialog.close(); emit urlButton->clicked(); }); connect(enterManuallyBtn, &QPushButton::clicked, &dialog, [this, &aspect, &dialog]() { dialog.close(); showModelsNotSupportedDialog(aspect); }); dialog.buttonLayout()->addWidget(selectProviderBtn); dialog.buttonLayout()->addWidget(selectUrlBtn); dialog.buttonLayout()->addWidget(enterManuallyBtn); } auto closeBtn = new QPushButton(TrConstants::CLOSE); connect(closeBtn, &QPushButton::clicked, &dialog, &QDialog::close); dialog.buttonLayout()->addWidget(closeBtn); dialog.exec(); } void GeneralSettings::showModelsNotSupportedDialog(Utils::StringAspect &aspect) { SettingsDialog dialog(TrConstants::MODEL_SELECTION); dialog.addLabel(TrConstants::MODEL_LISTING_NOT_SUPPORTED_INFO); dialog.addSpacing(); QString key = QString("CompleterHistory/") .append( (&aspect == &ccModel) ? Constants::CC_MODEL_HISTORY : Constants::CA_MODEL_HISTORY); QStringList historyList = qtcSettings()->value(Utils::Key(key.toLocal8Bit())).toStringList(); auto modelList = dialog.addComboBox(historyList, aspect.value()); dialog.addSpacing(); auto okButton = new QPushButton(TrConstants::OK); connect(okButton, &QPushButton::clicked, &dialog, [this, &aspect, modelList, &dialog]() { QString value = modelList->currentText().trimmed(); if (!value.isEmpty()) { aspect.setValue(value); writeSettings(); dialog.accept(); } }); auto cancelButton = new QPushButton(TrConstants::CANCEL); connect(cancelButton, &QPushButton::clicked, &dialog, &QDialog::reject); dialog.buttonLayout()->addWidget(cancelButton); dialog.buttonLayout()->addWidget(okButton); modelList->setFocus(); dialog.exec(); } void GeneralSettings::showUrlSelectionDialog( Utils::StringAspect &aspect, const QStringList &predefinedUrls) { SettingsDialog dialog(TrConstants::URL_SELECTION); dialog.addLabel(TrConstants::URL_SELECTION_INFO); dialog.addSpacing(); QStringList allUrls = predefinedUrls; QString key = QString("CompleterHistory/") .append((&aspect == &ccUrl) ? Constants::CC_URL_HISTORY : Constants::CA_URL_HISTORY); QStringList historyList = qtcSettings()->value(Utils::Key(key.toLocal8Bit())).toStringList(); allUrls.append(historyList); allUrls.removeDuplicates(); auto urlList = dialog.addComboBox(allUrls, aspect.value()); dialog.addSpacing(); auto okButton = new QPushButton(TrConstants::OK); connect(okButton, &QPushButton::clicked, &dialog, [this, &aspect, urlList, &dialog]() { QString value = urlList->currentText().trimmed(); if (!value.isEmpty()) { aspect.setValue(value); writeSettings(); dialog.accept(); } }); auto cancelButton = new QPushButton(TrConstants::CANCEL); connect(cancelButton, &QPushButton::clicked, &dialog, &QDialog::reject); dialog.buttonLayout()->addWidget(cancelButton); dialog.buttonLayout()->addWidget(okButton); urlList->setFocus(); dialog.exec(); } void GeneralSettings::setupConnections() { connect(&enableLogging, &Utils::BoolAspect::volatileValueChanged, this, [this]() { Logger::instance().setLoggingEnabled(enableLogging.volatileValue()); }); connect(&resetToDefaults, &ButtonAspect::clicked, this, &GeneralSettings::resetPageToDefaults); connect(&checkUpdate, &ButtonAspect::clicked, this, [this]() { QodeAssist::UpdateDialog::checkForUpdatesAndShow(Core::ICore::dialogParent()); }); } void GeneralSettings::resetPageToDefaults() { QMessageBox::StandardButton reply; reply = QMessageBox::question(Core::ICore::dialogParent(), TrConstants::RESET_SETTINGS, TrConstants::CONFIRMATION, QMessageBox::Yes | QMessageBox::No); if (reply == QMessageBox::Yes) { resetAspect(enableQodeAssist); resetAspect(enableLogging); resetAspect(ccProvider); resetAspect(ccModel); resetAspect(ccTemplate); resetAspect(ccUrl); resetAspect(caProvider); resetAspect(caModel); resetAspect(caTemplate); resetAspect(caUrl); resetAspect(enableCheckUpdate); writeSettings(); } } class GeneralSettingsPage : public Core::IOptionsPage { public: GeneralSettingsPage() { setId(Constants::QODE_ASSIST_GENERAL_SETTINGS_PAGE_ID); setDisplayName(TrConstants::GENERAL); setCategory(Constants::QODE_ASSIST_GENERAL_OPTIONS_CATEGORY); setDisplayCategory(Constants::QODE_ASSIST_GENERAL_OPTIONS_DISPLAY_CATEGORY); setCategoryIconPath(":/resources/images/qoderassist-icon.png"); setSettingsProvider([] { return &generalSettings(); }); } }; const GeneralSettingsPage generalSettingsPage; } // namespace QodeAssist::Settings