mirror of
https://github.com/qelectrotech/qelectrotech-source-mirror.git
synced 2026-10-07 20:34:14 +02:00
3a61513f29
Configure QElectroTech > Toolbar contents: pick a toolbar, drag or add commands from the list on the left, remove them with Delete, reorder, add separators, and add, rename or delete toolbars of one's own. Reset to defaults gives a toolbar its original contents back. Each toolbar is stored as a list of command ids in QSettings (diagrameditor/toolbars/<objectName>), the same pattern the shortcut bar uses. A toolbar the user never changed stores nothing and is built exactly as before; an id no command carries any more is skipped. The four buttons that are widgets rather than commands (handle size, text grid, background colour, conductor colour) get ids of their own and can each be on one toolbar at a time. Stored scripts can go on any toolbar. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
424 lines
14 KiB
C++
424 lines
14 KiB
C++
/*
|
|
Copyright 2006-2026 The QElectroTech Team
|
|
This file is part of QElectroTech.
|
|
|
|
QElectroTech 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.
|
|
|
|
QElectroTech 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 QElectroTech. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
#include "toolbarcommandsconfigpage.h"
|
|
|
|
#include "../../qeticons.h"
|
|
#include "../../shortcutmanager.h"
|
|
|
|
#include <QAction>
|
|
#include <QComboBox>
|
|
#include <QGridLayout>
|
|
#include <QHBoxLayout>
|
|
#include <QInputDialog>
|
|
#include <QLabel>
|
|
#include <QLineEdit>
|
|
#include <QListWidget>
|
|
#include <QPushButton>
|
|
#include <QTimer>
|
|
#include <QVBoxLayout>
|
|
|
|
ToolbarCommandsConfigPage::ToolbarCommandsConfigPage(QWidget *parent) :
|
|
ConfigPage(parent)
|
|
{
|
|
const QStringList available = DiagramToolbarSettings::availableCommandIds();
|
|
for (const ShortcutManager::ShortcutInfo &info :
|
|
ShortcutManager::instance().allShortcuts()) {
|
|
if (available.contains(info.id)) {
|
|
m_descriptions.insert(info.id, info.description);
|
|
}
|
|
}
|
|
m_custom = DiagramToolbarSettings::customToolbars();
|
|
for (const DiagramToolbarSettings::Toolbar &toolbar : DiagramToolbarSettings::toolbars()) {
|
|
m_pending.insert(toolbar.name, DiagramToolbarSettings::ids(toolbar.name));
|
|
}
|
|
|
|
auto *explanation = new QLabel(
|
|
tr("Choisissez les commandes de chaque barre d'outils de l'éditeur "
|
|
"de schémas. Glissez une commande de la liste de gauche vers la "
|
|
"barre, ou double-cliquez dessus ; Suppr la retire."), this);
|
|
explanation->setWordWrap(true);
|
|
|
|
m_toolbar = new QComboBox(this);
|
|
m_toolbar->setObjectName(QStringLiteral("toolbarCombo"));
|
|
auto *new_toolbar = new QPushButton(tr("Nouvelle barre…"), this);
|
|
new_toolbar->setObjectName(QStringLiteral("newToolbarButton"));
|
|
m_rename = new QPushButton(tr("Renommer…"), this);
|
|
m_delete = new QPushButton(tr("Supprimer la barre"), this);
|
|
m_delete->setObjectName(QStringLiteral("deleteToolbarButton"));
|
|
auto *reset = new QPushButton(tr("Valeurs par défaut"), this);
|
|
reset->setObjectName(QStringLiteral("resetButton"));
|
|
|
|
m_filter = new QLineEdit(this);
|
|
m_filter->setPlaceholderText(tr("Rechercher une commande"));
|
|
m_filter->setClearButtonEnabled(true);
|
|
|
|
m_available = new QListWidget(this);
|
|
m_available->setObjectName(QStringLiteral("availableList"));
|
|
m_available->setSelectionMode(QAbstractItemView::ExtendedSelection);
|
|
m_available->setSortingEnabled(true);
|
|
m_available->setDragDropMode(QAbstractItemView::DragOnly);
|
|
m_available->setDefaultDropAction(Qt::MoveAction);
|
|
m_chosen = new QListWidget(this);
|
|
m_chosen->setObjectName(QStringLiteral("chosenList"));
|
|
m_chosen->setSelectionMode(QAbstractItemView::ExtendedSelection);
|
|
//Takes commands dragged from the list on the left, and reorders
|
|
m_chosen->setDragDropMode(QAbstractItemView::DragDrop);
|
|
m_chosen->setDefaultDropAction(Qt::MoveAction);
|
|
|
|
auto *add = new QPushButton(tr("Ajouter →"), this);
|
|
auto *separator = new QPushButton(tr("Séparateur"), this);
|
|
separator->setObjectName(QStringLiteral("separatorButton"));
|
|
auto *remove = new QPushButton(tr("← Retirer"), this);
|
|
auto *up = new QPushButton(tr("Monter"), this);
|
|
auto *down = new QPushButton(tr("Descendre"), this);
|
|
|
|
auto *buttons = new QVBoxLayout();
|
|
buttons->addStretch();
|
|
buttons->addWidget(add);
|
|
buttons->addWidget(separator);
|
|
buttons->addWidget(remove);
|
|
buttons->addSpacing(12);
|
|
buttons->addWidget(up);
|
|
buttons->addWidget(down);
|
|
buttons->addStretch();
|
|
|
|
auto *grid = new QGridLayout();
|
|
grid->addWidget(new QLabel(tr("Commandes disponibles"), this), 0, 0);
|
|
grid->addWidget(new QLabel(tr("Dans la barre, dans l'ordre"), this), 0, 2);
|
|
grid->addWidget(m_filter, 1, 0);
|
|
grid->addWidget(m_available, 2, 0);
|
|
grid->addLayout(buttons, 2, 1);
|
|
grid->addWidget(m_chosen, 1, 2, 2, 1);
|
|
|
|
auto *toolbar_row = new QHBoxLayout();
|
|
toolbar_row->addWidget(new QLabel(tr("Barre d'outils :"), this));
|
|
toolbar_row->addWidget(m_toolbar, 1);
|
|
toolbar_row->addWidget(new_toolbar);
|
|
toolbar_row->addWidget(m_rename);
|
|
toolbar_row->addWidget(m_delete);
|
|
toolbar_row->addWidget(reset);
|
|
|
|
auto *layout = new QVBoxLayout(this);
|
|
layout->addWidget(explanation);
|
|
layout->addLayout(toolbar_row);
|
|
layout->addLayout(grid);
|
|
|
|
connect(m_toolbar, qOverload<int>(&QComboBox::currentIndexChanged), this, [this]() {
|
|
storeToolbar();
|
|
showToolbar();
|
|
});
|
|
connect(m_filter, &QLineEdit::textChanged, this, &ToolbarCommandsConfigPage::fillAvailable);
|
|
connect(add, &QPushButton::clicked, this, &ToolbarCommandsConfigPage::addSelected);
|
|
connect(separator, &QPushButton::clicked, this, &ToolbarCommandsConfigPage::addSeparator);
|
|
connect(remove, &QPushButton::clicked, this, &ToolbarCommandsConfigPage::removeSelected);
|
|
connect(up, &QPushButton::clicked, this, [this]() { moveSelected(-1); });
|
|
connect(down, &QPushButton::clicked, this, [this]() { moveSelected(1); });
|
|
connect(reset, &QPushButton::clicked, this, &ToolbarCommandsConfigPage::resetToolbar);
|
|
connect(new_toolbar, &QPushButton::clicked, this, &ToolbarCommandsConfigPage::newToolbar);
|
|
connect(m_rename, &QPushButton::clicked, this, &ToolbarCommandsConfigPage::renameToolbar);
|
|
connect(m_delete, &QPushButton::clicked, this, &ToolbarCommandsConfigPage::deleteToolbar);
|
|
connect(m_available, &QListWidget::itemDoubleClicked, this, &ToolbarCommandsConfigPage::addSelected);
|
|
connect(m_chosen, &QListWidget::itemDoubleClicked, this, &ToolbarCommandsConfigPage::removeSelected);
|
|
//A command dropped from the left is no longer available. Later,
|
|
//not now: a dropped row is inserted before its data is set.
|
|
connect(m_chosen->model(), &QAbstractItemModel::rowsInserted, this, [this]() {
|
|
if (m_chosen->property("filling").toBool()) return;
|
|
QTimer::singleShot(0, this, [this]() {
|
|
storeToolbar();
|
|
fillAvailable();
|
|
});
|
|
});
|
|
|
|
auto *delete_key = new QAction(m_chosen);
|
|
delete_key->setShortcut(QKeySequence::Delete);
|
|
delete_key->setShortcutContext(Qt::WidgetShortcut);
|
|
m_chosen->addAction(delete_key);
|
|
connect(delete_key, &QAction::triggered, this, &ToolbarCommandsConfigPage::removeSelected);
|
|
|
|
fillToolbarCombo(DiagramToolbarSettings::builtInNames().constFirst());
|
|
}
|
|
|
|
/**
|
|
@brief ToolbarCommandsConfigPage::applyConf
|
|
Save the user's own toolbars and every toolbar's contents, then
|
|
rebuild the toolbars of the open diagram editors.
|
|
*/
|
|
void ToolbarCommandsConfigPage::applyConf()
|
|
{
|
|
storeToolbar();
|
|
DiagramToolbarSettings::setCustomToolbars(m_custom);
|
|
for (const DiagramToolbarSettings::Toolbar &toolbar : DiagramToolbarSettings::toolbars()) {
|
|
DiagramToolbarSettings::setIds(toolbar.name, m_pending.value(toolbar.name));
|
|
}
|
|
DiagramToolbarSettings::applyToAll();
|
|
}
|
|
|
|
QString ToolbarCommandsConfigPage::title() const
|
|
{
|
|
return tr("Contenu des barres", "configuration page title: what each toolbar holds");
|
|
}
|
|
|
|
QIcon ToolbarCommandsConfigPage::icon() const
|
|
{
|
|
return QET::Icons::ConfigureToolbars;
|
|
}
|
|
|
|
/**
|
|
@brief ToolbarCommandsConfigPage::fillToolbarCombo
|
|
List the built-in toolbars and the user's own, and show @a current.
|
|
*/
|
|
void ToolbarCommandsConfigPage::fillToolbarCombo(const QString ¤t)
|
|
{
|
|
const QSignalBlocker blocker(m_toolbar);
|
|
m_toolbar->clear();
|
|
for (const QString &name : DiagramToolbarSettings::builtInNames()) {
|
|
m_toolbar->addItem(DiagramToolbarSettings::builtInTitle(name), name);
|
|
}
|
|
for (const DiagramToolbarSettings::Toolbar &toolbar : std::as_const(m_custom)) {
|
|
m_toolbar->addItem(toolbar.title, toolbar.name);
|
|
}
|
|
const int index = m_toolbar->findData(current);
|
|
m_toolbar->setCurrentIndex(index < 0 ? 0 : index);
|
|
showToolbar();
|
|
}
|
|
|
|
/**
|
|
@brief ToolbarCommandsConfigPage::showToolbar
|
|
Fill both lists for the toolbar chosen in the combo box.
|
|
*/
|
|
void ToolbarCommandsConfigPage::showToolbar()
|
|
{
|
|
m_shown = m_toolbar->currentData().toString();
|
|
const bool custom = !DiagramToolbarSettings::builtInNames().contains(m_shown);
|
|
m_rename->setEnabled(custom);
|
|
m_delete->setEnabled(custom);
|
|
|
|
m_chosen->setProperty("filling", true);
|
|
m_chosen->clear();
|
|
for (const QString &id : m_pending.value(m_shown)) {
|
|
m_chosen->addItem(makeItem(id));
|
|
}
|
|
m_chosen->setProperty("filling", false);
|
|
fillAvailable();
|
|
}
|
|
|
|
/**
|
|
@brief ToolbarCommandsConfigPage::storeToolbar
|
|
Keep the shown toolbar's list, in the order on screen.
|
|
*/
|
|
void ToolbarCommandsConfigPage::storeToolbar()
|
|
{
|
|
if (m_shown.isEmpty()) {
|
|
return;
|
|
}
|
|
QStringList ids;
|
|
for (int i = 0 ; i < m_chosen->count() ; ++i) {
|
|
ids << m_chosen->item(i)->data(Qt::UserRole).toString();
|
|
}
|
|
m_pending.insert(m_shown, ids);
|
|
}
|
|
|
|
/**
|
|
@brief ToolbarCommandsConfigPage::fillAvailable
|
|
List what can still go on the shown toolbar and matches the search: a
|
|
command not already on it, and a widget button on no toolbar at all
|
|
(a widget can only be in one place).
|
|
*/
|
|
void ToolbarCommandsConfigPage::fillAvailable()
|
|
{
|
|
QStringList on_shown;
|
|
for (int i = 0 ; i < m_chosen->count() ; ++i) {
|
|
on_shown << m_chosen->item(i)->data(Qt::UserRole).toString();
|
|
}
|
|
QStringList on_any = on_shown;
|
|
for (auto it = m_pending.cbegin() ; it != m_pending.cend() ; ++it) {
|
|
if (it.key() != m_shown) on_any << it.value();
|
|
}
|
|
|
|
QStringList ids;
|
|
for (auto it = m_descriptions.cbegin() ; it != m_descriptions.cend() ; ++it) {
|
|
if (!on_shown.contains(it.key())) ids << it.key();
|
|
}
|
|
for (const QString &id : DiagramToolbarSettings::widgetIds()) {
|
|
if (!on_any.contains(id)) ids << id;
|
|
}
|
|
|
|
m_available->clear();
|
|
const QString filter = m_filter->text().trimmed();
|
|
for (const QString &id : std::as_const(ids)) {
|
|
QListWidgetItem *item = makeItem(id);
|
|
if (filter.isEmpty() || item->text().contains(filter, Qt::CaseInsensitive)) {
|
|
m_available->addItem(item);
|
|
} else {
|
|
delete item;
|
|
}
|
|
}
|
|
}
|
|
|
|
void ToolbarCommandsConfigPage::addSelected()
|
|
{
|
|
const QList<QListWidgetItem *> selected = m_available->selectedItems();
|
|
if (selected.isEmpty()) {
|
|
return;
|
|
}
|
|
m_chosen->setProperty("filling", true);
|
|
for (QListWidgetItem *item : selected) {
|
|
m_chosen->addItem(m_available->takeItem(m_available->row(item)));
|
|
}
|
|
m_chosen->setProperty("filling", false);
|
|
storeToolbar();
|
|
fillAvailable();
|
|
}
|
|
|
|
/**
|
|
@brief ToolbarCommandsConfigPage::addSeparator
|
|
Insert a separator after the selected row, or at the end.
|
|
*/
|
|
void ToolbarCommandsConfigPage::addSeparator()
|
|
{
|
|
const int row = m_chosen->currentRow();
|
|
m_chosen->setProperty("filling", true);
|
|
m_chosen->insertItem(row < 0 ? m_chosen->count() : row + 1,
|
|
makeItem(DiagramToolbarSettings::separatorId()));
|
|
m_chosen->setProperty("filling", false);
|
|
storeToolbar();
|
|
}
|
|
|
|
void ToolbarCommandsConfigPage::removeSelected()
|
|
{
|
|
for (QListWidgetItem *item : m_chosen->selectedItems()) {
|
|
delete m_chosen->takeItem(m_chosen->row(item));
|
|
}
|
|
storeToolbar();
|
|
fillAvailable();
|
|
}
|
|
|
|
/**
|
|
@brief ToolbarCommandsConfigPage::moveSelected
|
|
Move the selected command @a step rows, keeping it selected.
|
|
*/
|
|
void ToolbarCommandsConfigPage::moveSelected(int step)
|
|
{
|
|
const int row = m_chosen->currentRow();
|
|
const int target = row + step;
|
|
if (row < 0 || target < 0 || target >= m_chosen->count()) {
|
|
return;
|
|
}
|
|
m_chosen->setProperty("filling", true);
|
|
QListWidgetItem *item = m_chosen->takeItem(row);
|
|
m_chosen->insertItem(target, item);
|
|
m_chosen->setProperty("filling", false);
|
|
m_chosen->setCurrentRow(target);
|
|
storeToolbar();
|
|
}
|
|
|
|
/**
|
|
@brief ToolbarCommandsConfigPage::resetToolbar
|
|
Give the shown toolbar its defaults back; the user's own toolbar is
|
|
emptied.
|
|
*/
|
|
void ToolbarCommandsConfigPage::resetToolbar()
|
|
{
|
|
m_pending.insert(m_shown, DiagramToolbarSettings::defaultIds(m_shown));
|
|
//A widget the defaults put here leaves the toolbar it was moved to
|
|
for (const QString &id : DiagramToolbarSettings::defaultIds(m_shown)) {
|
|
if (!DiagramToolbarSettings::isWidget(id)) continue;
|
|
for (auto it = m_pending.begin() ; it != m_pending.end() ; ++it) {
|
|
if (it.key() != m_shown) it.value().removeAll(id);
|
|
}
|
|
}
|
|
showToolbar();
|
|
}
|
|
|
|
void ToolbarCommandsConfigPage::newToolbar()
|
|
{
|
|
bool ok = false;
|
|
const QString title = QInputDialog::getText(this, tr("Nouvelle barre d'outils"),
|
|
tr("Nom de la barre d'outils :"),
|
|
QLineEdit::Normal, QString(), &ok).trimmed();
|
|
if (!ok || title.isEmpty()) {
|
|
return;
|
|
}
|
|
storeToolbar();
|
|
DiagramToolbarSettings::Toolbar toolbar;
|
|
toolbar.name = DiagramToolbarSettings::newCustomName(m_custom);
|
|
toolbar.title = title;
|
|
toolbar.custom = true;
|
|
m_custom << toolbar;
|
|
m_pending.insert(toolbar.name, QStringList());
|
|
fillToolbarCombo(toolbar.name);
|
|
}
|
|
|
|
void ToolbarCommandsConfigPage::renameToolbar()
|
|
{
|
|
for (DiagramToolbarSettings::Toolbar &toolbar : m_custom) {
|
|
if (toolbar.name != m_shown) continue;
|
|
bool ok = false;
|
|
const QString title = QInputDialog::getText(this, tr("Renommer la barre d'outils"),
|
|
tr("Nom de la barre d'outils :"),
|
|
QLineEdit::Normal, toolbar.title, &ok).trimmed();
|
|
if (ok && !title.isEmpty()) {
|
|
storeToolbar();
|
|
toolbar.title = title;
|
|
fillToolbarCombo(m_shown);
|
|
}
|
|
return;
|
|
}
|
|
}
|
|
|
|
void ToolbarCommandsConfigPage::deleteToolbar()
|
|
{
|
|
const QString name = m_shown;
|
|
for (int i = 0 ; i < m_custom.size() ; ++i) {
|
|
if (m_custom.at(i).name == name) {
|
|
m_custom.removeAt(i);
|
|
m_pending.remove(name);
|
|
m_shown.clear();
|
|
fillToolbarCombo(DiagramToolbarSettings::builtInNames().constFirst());
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
@brief ToolbarCommandsConfigPage::makeItem
|
|
@return a list item for @a id with the command's text and icon. An id
|
|
no live action carries (a command from a build without it, or a script
|
|
since removed) is still listed, by its id, so saving does not silently
|
|
drop it.
|
|
*/
|
|
QListWidgetItem *ToolbarCommandsConfigPage::makeItem(const QString &id) const
|
|
{
|
|
QString text = m_descriptions.value(id, id);
|
|
QString tip;
|
|
QIcon icon;
|
|
if (id == DiagramToolbarSettings::separatorId()) {
|
|
text = tr("─── Séparateur ───");
|
|
} else if (DiagramToolbarSettings::isWidget(id)) {
|
|
text = DiagramToolbarSettings::widgetTitle(id);
|
|
} else if (QAction *action = ShortcutManager::instance().action(id, nullptr)) {
|
|
icon = action->icon();
|
|
tip = action->statusTip();
|
|
}
|
|
auto *item = new QListWidgetItem(icon, text);
|
|
item->setData(Qt::UserRole, id);
|
|
//Tells apart commands with the same name ("Ajouter une ligne")
|
|
item->setToolTip(tip);
|
|
return item;
|
|
}
|