RedPanda-CPP/RedPandaIDE/settingsdialog/editorcolorschemewidget.cpp

474 lines
17 KiB
C++

/*
* Copyright (C) 2020-2022 Roy Qu (royqh1979@gmail.com)
*
* 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 3 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. If not, see <https://www.gnu.org/licenses/>.
*/
#include "editorcolorschemewidget.h"
#include "ui_editorcolorschemewidget.h"
#include "../settings.h"
#include "../colorscheme.h"
#include "../mainwindow.h"
#include <QAction>
#include <QMessageBox>
#include <QDebug>
#include <QInputDialog>
#include <QFileDialog>
EditorColorSchemeWidget::EditorColorSchemeWidget(const QString& name, const QString& group, QWidget *parent) :
SettingsWidget(name,group,parent),
ui(new Ui::EditorColorSchemeWidget)
{
ui->setupUi(this);
mStatementColors = std::make_shared<QHash<StatementKind, std::shared_ptr<ColorSchemeItem> >>();
mDefaultSchemeComboFont = ui->cbScheme->font();
mModifiedSchemeComboFont = mDefaultSchemeComboFont;
mModifiedSchemeComboFont.setBold(true);
int schemeCount=0;
for (QString schemeName: pColorManager->getSchemes()) {
PColorScheme scheme = pColorManager->get(schemeName);
if (!scheme)
return;
ui->cbScheme->addItem(schemeName);
if (scheme->customed())
ui->cbScheme->setItemData(schemeCount,mModifiedSchemeComboFont,Qt::FontRole);
schemeCount++;
}
QItemSelectionModel *m = ui->treeItems->selectionModel();
ui->treeItems->setModel(&mDefinesModel);
delete m;
mDefinesModel.setHorizontalHeaderLabels(QStringList());
for (QString defineName : pColorManager->getDefines()) {
addDefine(defineName, pColorManager->getDefine(defineName));
}
ui->treeItems->expandAll();
QModelIndex groupIndex = mDefinesModel.index(0,0);
QModelIndex index = mDefinesModel.index(0,0,groupIndex);
ui->treeItems->setCurrentIndex(index);
connect(ui->treeItems->selectionModel(), &QItemSelectionModel::selectionChanged,
this, &EditorColorSchemeWidget::onItemSelectionChanged);
connect(ui->cbScheme, QOverload<int>::of(&QComboBox::currentIndexChanged),
this, &EditorColorSchemeWidget::changeSchemeComboFont);
connect(ui->cbScheme, QOverload<int>::of(&QComboBox::currentIndexChanged),
this, &EditorColorSchemeWidget::onItemSelectionChanged);
connect(this, &SettingsWidget::settingsChanged,this,
&EditorColorSchemeWidget::onSettingChanged);
ui->editDemo->document()->setText(
"#include <iostream>\n"
"#include <conio.h>\n"
"\n"
"int x=10;\n"
"\n"
"int main(int argc, char **argv)\n"
"{\n"
" int numbers[20];\n"
" float average, total; //breakpoint\n"
" for (int i = 0; i <= 19; i++)\n"
" { // active breakpoint\n"
" numbers[i] = i+x;\n"
" Total += i; // error line\n"
" }\n"
" average = total / 20; // comment\n"
" cout << \"total: \" << total << \"\nAverage: \" << average;\n"
" getch();\n"
"}\n"
);
ui->editDemo->setReadOnly(true);
ui->editDemo->setStatementColors(mStatementColors);
onItemSelectionChanged();
}
void EditorColorSchemeWidget::addDefine(const QString& name, PColorSchemeItemDefine define)
{
QList<QStandardItem*> items = mDefinesModel.findItems(define->group());
QStandardItem* pGroupItem;
if (items.count() == 0 ) {
//delete in the destructor
pGroupItem = new QStandardItem(define->group());
pGroupItem->setData("", NameRole);
mDefinesModel.appendRow(pGroupItem);
} else {
pGroupItem = items[0];
}
//delete in the destructor
QStandardItem* pWidgetItem = new QStandardItem(define->displayName());
pWidgetItem->setData(name, NameRole);
pGroupItem->appendRow(pWidgetItem);
}
PColorSchemeItem EditorColorSchemeWidget::getCurrentItem()
{
QItemSelectionModel * selectionModel = ui->treeItems->selectionModel();
QString name =mDefinesModel.data(selectionModel->currentIndex(),NameRole).toString();
if (name.isEmpty())
return PColorSchemeItem();
return pColorManager->getItem(ui->cbScheme->currentText(), name);
}
PColorScheme EditorColorSchemeWidget::getCurrentScheme()
{
return pColorManager->get(ui->cbScheme->currentText());
}
void EditorColorSchemeWidget::connectModificationSlots()
{
connect(ui->cbBackground,&QCheckBox::stateChanged,
this, &EditorColorSchemeWidget::onBackgroundChanged);
connect(ui->colorBackground,&ColorEdit::colorChanged,
this, &EditorColorSchemeWidget::onBackgroundChanged);
connect(ui->cbForeground,&QCheckBox::stateChanged,
this, &EditorColorSchemeWidget::onForegroundChanged);
connect(ui->colorForeground,&ColorEdit::colorChanged,
this, &EditorColorSchemeWidget::onForegroundChanged);
connect(ui->cbBold,&QCheckBox::stateChanged,
this, &EditorColorSchemeWidget::onFontStyleChanged);
connect(ui->cbItalic,&QCheckBox::stateChanged,
this, &EditorColorSchemeWidget::onFontStyleChanged);
connect(ui->cbStrikeout,&QCheckBox::stateChanged,
this, &EditorColorSchemeWidget::onFontStyleChanged);
connect(ui->cbUnderlined,&QCheckBox::stateChanged,
this, &EditorColorSchemeWidget::onFontStyleChanged);
}
void EditorColorSchemeWidget::disconnectModificationSlots()
{
disconnect(ui->cbBackground,&QCheckBox::stateChanged,
this, &EditorColorSchemeWidget::onBackgroundChanged);
disconnect(ui->colorBackground,&ColorEdit::colorChanged,
this, &EditorColorSchemeWidget::onBackgroundChanged);
disconnect(ui->cbForeground,&QCheckBox::stateChanged,
this, &EditorColorSchemeWidget::onForegroundChanged);
disconnect(ui->colorForeground,&ColorEdit::colorChanged,
this, &EditorColorSchemeWidget::onForegroundChanged);
disconnect(ui->cbBold,&QCheckBox::stateChanged,
this, &EditorColorSchemeWidget::onFontStyleChanged);
disconnect(ui->cbItalic,&QCheckBox::stateChanged,
this, &EditorColorSchemeWidget::onFontStyleChanged);
disconnect(ui->cbStrikeout,&QCheckBox::stateChanged,
this, &EditorColorSchemeWidget::onFontStyleChanged);
disconnect(ui->cbUnderlined,&QCheckBox::stateChanged,
this, &EditorColorSchemeWidget::onFontStyleChanged);
}
void EditorColorSchemeWidget::setCurrentSchemeModified()
{
PColorScheme scheme = getCurrentScheme();
if (scheme) {
scheme->setCustomed(true);
}
// if (mModifiedSchemes.contains(ui->cbScheme->currentText()))
// return;
mModifiedSchemes.insert(ui->cbScheme->currentText());
ui->cbScheme->setItemData(ui->cbScheme->currentIndex(),
mModifiedSchemeComboFont,Qt::FontRole);
ui->cbScheme->setFont(mModifiedSchemeComboFont);
//ui->cbScheme->view()->setFont(mDefaultSchemeComboFont);
//we must reset the editor here, because this slot is processed after the onSettingChanged
onSettingChanged();
}
EditorColorSchemeWidget::~EditorColorSchemeWidget()
{
delete ui;
mDefinesModel.clear();
}
static void setColorProp(ColorEdit* ce, QCheckBox* cb, const QColor& color) {
if (color.isValid()) {
cb->setChecked(true);
ce->setColor(color);
ce->setVisible(true);
} else {
cb->setChecked(false);
ce->setVisible(false);
}
}
void EditorColorSchemeWidget::onItemSelectionChanged()
{
disconnectModificationSlots();
QItemSelectionModel * selectionModel = ui->treeItems->selectionModel();
QString name =mDefinesModel.data(selectionModel->currentIndex(),NameRole).toString();
bool found = false;
if (!name.isEmpty()) {
PColorSchemeItemDefine define = pColorManager->getDefine(name);
if (define) {
found = true;
ui->cbBackground->setEnabled(define->hasBackground());
ui->colorBackground->setEnabled(define->hasBackground());
ui->cbForeground->setEnabled(define->hasForeground());
ui->colorForeground->setEnabled(define->hasForeground());
ui->grpFontStyles->setEnabled(define->hasFontStyle());
PColorSchemeItem item = pColorManager->getItem(ui->cbScheme->currentText(), name);
if (!item) {
PColorScheme scheme = pColorManager->get(ui->cbScheme->currentText());
if (scheme) {
scheme->addItem(name);
}
}
if (define->hasBackground() && item) {
setColorProp(ui->colorBackground, ui->cbBackground,item->background());
} else {
setColorProp(ui->colorBackground, ui->cbBackground,QColor());
}
if (define->hasForeground() && item) {
setColorProp(ui->colorForeground, ui->cbForeground,item->foreground());
} else {
setColorProp(ui->colorForeground, ui->cbForeground,QColor());
}
if (define->hasFontStyle() && item) {
ui->cbBold->setChecked(item->bold());
ui->cbItalic->setChecked(item->italic());
ui->cbUnderlined->setChecked(item->underlined());
ui->cbStrikeout->setChecked(item->strikeout());
} else {
ui->cbBold->setChecked(false);
ui->cbItalic->setChecked(false);
ui->cbUnderlined->setChecked(false);
ui->cbStrikeout->setChecked(false);
}
}
}
ui->widgetSchemeItem->setEnabled(found);
connectModificationSlots();
}
void EditorColorSchemeWidget::onSettingChanged()
{
pColorManager->updateStatementColors(mStatementColors,ui->cbScheme->currentText());
ui->editDemo->applyColorScheme(ui->cbScheme->currentText());
}
void EditorColorSchemeWidget::onForegroundChanged()
{
PColorSchemeItem item = getCurrentItem();
if (!item)
return;
ui->colorForeground->setVisible(ui->cbForeground->isChecked());
if (ui->cbForeground->isChecked()) {
item->setForeground(ui->colorForeground->color());
} else {
ui->colorForeground->setColor(QColor());
item->setForeground(QColor());
}
setCurrentSchemeModified();
}
void EditorColorSchemeWidget::onBackgroundChanged()
{
PColorSchemeItem item = getCurrentItem();
if (!item)
return;
ui->colorBackground->setVisible(ui->cbBackground->isChecked());
if (ui->cbBackground->isChecked()) {
item->setBackground(ui->colorBackground->color());
} else {
ui->colorBackground->setColor(QColor());
item->setBackground(QColor());
}
setCurrentSchemeModified();
}
void EditorColorSchemeWidget::onFontStyleChanged()
{
PColorSchemeItem item = getCurrentItem();
if (!item)
return;
item->setBold(ui->cbBold->isChecked());
item->setItalic(ui->cbItalic->isChecked());
item->setStrikeout(ui->cbStrikeout->isChecked());
item->setUnderlined(ui->cbUnderlined->isChecked());
setCurrentSchemeModified();
}
void EditorColorSchemeWidget::changeSchemeComboFont()
{
QString name = ui->cbScheme->currentText();
PColorScheme scheme = pColorManager->get(name);
if (scheme && scheme->customed()) {
ui->cbScheme->setFont(mModifiedSchemeComboFont);
} else {
ui->cbScheme->setFont(mDefaultSchemeComboFont);
}
//ui->cbScheme->view()->setFont(mDefaultSchemeComboFont);
}
void EditorColorSchemeWidget::doLoad()
{
ui->cbScheme->setCurrentText(pSettings->editor().colorScheme());
ui->chkRainborParenthesis->setChecked(pSettings->editor().rainbowParenthesis());
}
void EditorColorSchemeWidget::doSave()
{
try {
for (QString name:mModifiedSchemes) {
pColorManager->saveScheme(name);
}
pSettings->editor().setColorScheme(ui->cbScheme->currentText());
pSettings->editor().setRainbowParenthesis(ui->chkRainborParenthesis->isChecked());
pSettings->editor().save();
pMainWindow->updateEditorColorSchemes();
} catch (FileError e) {
QMessageBox::critical(this,tr("Error"),e.reason());
}
}
void EditorColorSchemeWidget::on_actionCopy_Scheme_triggered()
{
QString newName = pColorManager->copy(ui->cbScheme->currentText());
if (newName.isEmpty())
return;
ui->cbScheme->addItem(newName);
ui->cbScheme->setCurrentText(newName);
}
void EditorColorSchemeWidget::on_btnSchemeMenu_pressed()
{
QMenu menu;
PColorScheme scheme = getCurrentScheme();
if (scheme) {
if (scheme->customed()) {
menu.addAction(ui->actionReset_Scheme);
}
if (!scheme->bundled()) {
menu.addAction(ui->actionRename_Scheme);
menu.addAction(ui->actionDelete_Scheme);
}
QString name = ui->cbScheme->currentText();
if (!pColorManager->exists(name+ " Copy"))
menu.addAction(ui->actionCopy_Scheme);
menu.addAction(ui->actionExport_Scheme);
menu.addSeparator();
}
menu.addAction(ui->actionImport_Scheme);
QPoint p;
p.setX(0);
p.setY(ui->btnSchemeMenu->height()+2);
menu.exec(ui->btnSchemeMenu->mapToGlobal(p));
}
void EditorColorSchemeWidget::on_actionImport_Scheme_triggered()
{
QString filename = QFileDialog::getOpenFileName(this,
tr("Open"), QString(), tr("Color Scheme Files (*.scheme)"));
if (filename.isEmpty())
return;
QFileInfo fileInfo(filename);
QString name = fileInfo.fileName();
QString suffix = EXT_COLOR_SCHEME;
if (!name.toLower().endsWith(suffix))
return;
name.remove(name.length()-suffix.length(),suffix.length());
name.replace('_',' ');
if (!pColorManager->isValidName(name)) {
QMessageBox::critical(this,tr("Error"),tr("'%1' is not a valid name for color scheme file."));
return;
}
try {
PColorScheme scheme = ColorScheme::load(filename);
pColorManager->add(name, scheme);
ui->cbScheme->addItem(name);
ui->cbScheme->setCurrentText(name);
} catch (FileError e) {
QMessageBox::critical(this,tr("Error"),e.reason());
return;
}
}
void EditorColorSchemeWidget::on_actionRename_Scheme_triggered()
{
QString name = ui->cbScheme->currentText();
bool isOk;
QString newName = QInputDialog::getText(this,tr("New scheme name"),tr("New scheme name"),
QLineEdit::Normal,name,&isOk);
if (isOk) {
if (!pColorManager->isValidName(newName)) {
QMessageBox::critical(this,tr("Error"),tr("'%1' is not a valid scheme name!").arg(newName));
return;
}
try {
pColorManager->rename(name,newName);
ui->cbScheme->setItemText(
ui->cbScheme->currentIndex(),
newName
);
if (mModifiedSchemes.contains(name))
mModifiedSchemes.remove(name);
mModifiedSchemes.insert(newName);
} catch(FileError e) {
QMessageBox::critical(this,tr("Error"),e.reason());
}
}
}
void EditorColorSchemeWidget::on_actionReset_Scheme_triggered()
{
try {
if (pColorManager->restoreToDefault(ui->cbScheme->currentText())) {
ui->cbScheme->setItemData(
ui->cbScheme->currentIndex(),
QVariant(),
Qt::FontRole);
ui->cbScheme->setFont(mDefaultSchemeComboFont);
//ui->cbScheme->view()->setFont(mDefaultSchemeComboFont);
}
} catch (FileError e) {
QMessageBox::critical(this,tr("Error"),e.reason());
}
}
void EditorColorSchemeWidget::on_actionExport_Scheme_triggered()
{
QString filename = QFileDialog::getSaveFileName(this,
tr("Save"), QString(), tr("Color Scheme Files (*.scheme)"));
if (filename.isEmpty())
return;
try {
PColorScheme scheme = getCurrentScheme();
scheme->save(filename);
} catch (FileError e) {
QMessageBox::critical(this,tr("Error"),e.reason());
return;
}
}
void EditorColorSchemeWidget::on_actionDelete_Scheme_triggered()
{
QString name = ui->cbScheme->currentText();
if (QMessageBox::warning(this,tr("Confirm Delete Scheme"),
tr("Scheme '%1' will be deleted!<br />Do you really want to continue?")
.arg(name),
QMessageBox::Yes, QMessageBox::No)!=QMessageBox::Yes)
return;
try {
if (pColorManager->remove(name)) {
if (mModifiedSchemes.contains(name))
mModifiedSchemes.remove(name);
ui->cbScheme->removeItem(ui->cbScheme->currentIndex());
if (name == pSettings->editor().colorScheme())
doSave();
}
} catch (FileError e) {
QMessageBox::critical(this,tr("Error"),e.reason());
}
}