QodeAssist/settings/GeneralSettings.cpp
2025-01-13 20:11:27 +01:00

352 lines
12 KiB
C++

/*
* 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 <https://www.gnu.org/licenses/>.
*/
#include "GeneralSettings.hpp"
#include <coreplugin/dialogs/ioptionspage.h>
#include <coreplugin/icore.h>
#include <utils/layoutbuilder.h>
#include <utils/utilsicons.h>
#include <QInputDialog>
#include <QMessageBox>
#include <QTimer>
#include <QtWidgets/qboxlayout.h>
#include <QtWidgets/qcompleter.h>
#include <QtWidgets/qgroupbox.h>
#include <QtWidgets/qradiobutton.h>
#include <QtWidgets/qstackedwidget.h>
#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