[education/cantor] src: Improve table of contents usability and settings
Alexander Semke <[email protected]>
| Newsgroups | gmane.comp.kde.cvs |
|---|---|
| Message-ID | <[email protected]> |
Git commit 47e3885316ec1527f89e99e74d193431fae988a3 by Alexander Semke, on behalf of Nanhao Lv.
Committed on 26/07/2026 at 19:50.
Pushed by asemke into branch 'master'.
Improve table of contents usability and settings
M +85 -4 src/cantor.cpp
M +169 -25 src/formating.ui
M +77 -7 src/panelplugins/tocpanel/tocpanelplugin.cpp
M +6 -0 src/panelplugins/tocpanel/tocpanelplugin.h
M +1 -38 src/settings.ui
https://invent.kde.org/education/cantor/-/commit/47e3885316ec1527f89e99e74d193431fae988a3
diff --git a/src/cantor.cpp b/src/cantor.cpp
index f7aa6245..ad689429 100644
--- a/src/cantor.cpp
+++ b/src/cantor.cpp
@@ -29,11 +29,17 @@
#include <QDir>
#include <QDockWidget>
#include <QFileDialog>
+#include <QFontComboBox>
+#include <QFormLayout>
#include <QStatusBar>
#include <QGraphicsView>
+#include <QHBoxLayout>
+#include <QLabel>
#include <QPushButton>
#include <QRegularExpression>
#include <QMenuBar>
+#include <QSpinBox>
+#include <QToolButton>
#include "lib/backend.h"
#include "lib/worksheetaccess.h"
@@ -748,14 +754,89 @@ void CantorShell::showSettings()
base.kcfg_DefaultTheme->addItem(theme.translatedName(), theme.name());
}
- QWidget *formattingSettings = new QWidget;
- Ui::SettingsFormatting formatting;
- formatting.setupUi(formattingSettings);
+ QWidget *tocSettings = new QWidget;
+ Ui::SettingsToc toc;
+ toc.setupUi(tocSettings);
+
+ for (auto* fontFamilyEditor : tocSettings->findChildren<QFontComboBox*>())
+ fontFamilyEditor->setProperty("kcfg_property", QByteArray("currentFont"));
+
+ const auto addFontSizeButtons = [](QSpinBox* spinBox)
+ {
+ auto* formLayout = qobject_cast<QFormLayout*>(spinBox->parentWidget()->layout());
+ if (!formLayout)
+ return;
+
+ int row = -1;
+ QFormLayout::ItemRole role = QFormLayout::FieldRole;
+ formLayout->getWidgetPosition(spinBox, &row, &role);
+ if (row < 0)
+ return;
+
+ auto* editor = new QWidget(spinBox->parentWidget());
+ auto* layout = new QHBoxLayout(editor);
+ layout->setContentsMargins(0, 0, 0, 0);
+ layout->setSpacing(2);
+
+ formLayout->removeWidget(spinBox);
+ spinBox->setButtonSymbols(QAbstractSpinBox::NoButtons);
+ spinBox->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
+ layout->addWidget(spinBox);
+
+ auto* decreaseButton = new QToolButton(editor);
+ decreaseButton->setText(QStringLiteral("−"));
+ decreaseButton->setToolTip(i18n("Decrease font size"));
+ decreaseButton->setAutoRepeat(true);
+ layout->addWidget(decreaseButton);
+
+ auto* increaseButton = new QToolButton(editor);
+ increaseButton->setText(QStringLiteral("+"));
+ increaseButton->setToolTip(i18n("Increase font size"));
+ increaseButton->setAutoRepeat(true);
+ layout->addWidget(increaseButton);
+
+ connect(decreaseButton, &QToolButton::clicked, spinBox, &QSpinBox::stepDown);
+ connect(increaseButton, &QToolButton::clicked, spinBox, &QSpinBox::stepUp);
+
+ const auto updateButtons = [spinBox, decreaseButton, increaseButton](int value)
+ {
+ decreaseButton->setEnabled(value > spinBox->minimum());
+ increaseButton->setEnabled(value < spinBox->maximum());
+ };
+ connect(spinBox, &QSpinBox::valueChanged, editor, updateButtons);
+ updateButtons(spinBox->value());
+
+ formLayout->setWidget(row, role, editor);
+ };
+
+ const QList<QSpinBox*> fontSizeEditors = {
+ toc.kcfg_ChapterFontSize,
+ toc.kcfg_SubchapterFontSize,
+ toc.kcfg_SectionFontSize,
+ toc.kcfg_SubsectionFontSize,
+ toc.kcfg_ParagraphFontSize,
+ toc.kcfg_SubparagraphFontSize,
+ };
+ for (auto* fontSizeEditor : fontSizeEditors)
+ addFontSizeButtons(fontSizeEditor);
+
+ const auto tocLabels = tocSettings->findChildren<QLabel*>();
+ int tocLabelWidth = 0;
+ for (const auto* label : tocLabels)
+ {
+ if (label->buddy())
+ tocLabelWidth = qMax(tocLabelWidth, label->sizeHint().width());
+ }
+ for (auto* label : tocLabels)
+ {
+ if (label->buddy())
+ label->setMinimumWidth(tocLabelWidth);
+ }
base.kcfg_DefaultBackend->addItems(Cantor::Backend::listAvailableBackends());
dialog->addPage(generalSettings, i18n("General"), QLatin1String("preferences-other"));
- dialog->addPage(formattingSettings, i18n("Formatting"), QLatin1String("preferences-other"));
+ dialog->addPage(tocSettings, i18n("Table of Contents"), QLatin1String("view-list-tree"));
for (auto* backend : Cantor::Backend::availableBackends())
{
if (backend->config()) //It has something to configure, so add it to the dialog
diff --git a/src/formating.ui b/src/formating.ui
index 2bd4aeca..8c33ac98 100644
--- a/src/formating.ui
+++ b/src/formating.ui
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
- <class>SettingsFormatting</class>
- <widget class="QWidget" name="SettingsFormatting">
+ <class>SettingsToc</class>
+ <widget class="QWidget" name="SettingsToc">
<property name="geometry">
<rect>
<x>0</x>
@@ -24,7 +24,74 @@
<number>0</number>
</property>
<item>
- <widget class="QTabWidget" name="tabWidget">
+ <widget class="QLabel" name="hierarchyEntriesLabel">
+ <property name="font">
+ <font>
+ <weight>75</weight>
+ <bold>true</bold>
+ </font>
+ </property>
+ <property name="text">
+ <string>Hierarchy Entries:</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <layout class="QFormLayout" name="hierarchyLevelLayout">
+ <property name="leftMargin">
+ <number>9</number>
+ </property>
+ <property name="rightMargin">
+ <number>9</number>
+ </property>
+ <item row="0" column="0">
+ <widget class="QLabel" name="hierarchyLevelLabel">
+ <property name="text">
+ <string>Hierarchy level:</string>
+ </property>
+ <property name="buddy">
+ <cstring>hierarchyLevelComboBox</cstring>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1">
+ <widget class="QComboBox" name="hierarchyLevelComboBox">
+ <item>
+ <property name="text">
+ <string>Chapter</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Subchapter</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Section</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Subsection</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Paragraph</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Subparagraph</string>
+ </property>
+ </item>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <widget class="QStackedWidget" name="hierarchyFontStack">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Maximum">
<horstretch>0</horstretch>
@@ -34,14 +101,14 @@
<property name="currentIndex">
<number>0</number>
</property>
- <property name="documentMode">
- <bool>true</bool>
- </property>
<widget class="QWidget" name="ChapterTab">
- <attribute name="title">
- <string>Chapter Font</string>
- </attribute>
<layout class="QFormLayout" name="verticalLayout">
+ <property name="leftMargin">
+ <number>9</number>
+ </property>
+ <property name="rightMargin">
+ <number>9</number>
+ </property>
<item row="0" column="0">
<widget class="QLabel" name="lChapterFontFamily">
<property name="text">
@@ -95,10 +162,13 @@
</layout>
</widget>
<widget class="QWidget" name="SubchapterTab">
- <attribute name="title">
- <string>Subchapter Font</string>
- </attribute>
<layout class="QFormLayout" name="verticalLayout4">
+ <property name="leftMargin">
+ <number>9</number>
+ </property>
+ <property name="rightMargin">
+ <number>9</number>
+ </property>
<item row="0" column="0">
<widget class="QLabel" name="lSubchapterFontFamily">
<property name="text">
@@ -152,10 +222,13 @@
</layout>
</widget>
<widget class="QWidget" name="SectionTab">
- <attribute name="title">
- <string>Section Font</string>
- </attribute>
<layout class="QFormLayout" name="verticalLayout3">
+ <property name="leftMargin">
+ <number>9</number>
+ </property>
+ <property name="rightMargin">
+ <number>9</number>
+ </property>
<item row="0" column="0">
<widget class="QLabel" name="lSectionFontFamily">
<property name="text">
@@ -209,10 +282,13 @@
</layout>
</widget>
<widget class="QWidget" name="SubsectionTab">
- <attribute name="title">
- <string>Subsection Font</string>
- </attribute>
<layout class="QFormLayout" name="verticalLayout6">
+ <property name="leftMargin">
+ <number>9</number>
+ </property>
+ <property name="rightMargin">
+ <number>9</number>
+ </property>
<item row="0" column="0">
<widget class="QLabel" name="lSubsectionFontFamily">
<property name="text">
@@ -266,10 +342,13 @@
</layout>
</widget>
<widget class="QWidget" name="ParagraphTab">
- <attribute name="title">
- <string>Paragraph Font</string>
- </attribute>
<layout class="QFormLayout" name="verticalLayout2">
+ <property name="leftMargin">
+ <number>9</number>
+ </property>
+ <property name="rightMargin">
+ <number>9</number>
+ </property>
<item row="0" column="0">
<widget class="QLabel" name="lParagraphFontFamily">
<property name="text">
@@ -323,10 +402,13 @@
</layout>
</widget>
<widget class="QWidget" name="SubparagraphTab">
- <attribute name="title">
- <string>Subparagraph Font</string>
- </attribute>
<layout class="QFormLayout" name="verticalLayout5">
+ <property name="leftMargin">
+ <number>9</number>
+ </property>
+ <property name="rightMargin">
+ <number>9</number>
+ </property>
<item row="0" column="0">
<widget class="QLabel" name="lSubparagraphFontFamily">
<property name="text">
@@ -381,6 +463,51 @@
</widget>
</widget>
</item>
+ <item>
+ <widget class="QLabel" name="visibleItemsLabel">
+ <property name="font">
+ <font>
+ <weight>75</weight>
+ <bold>true</bold>
+ </font>
+ </property>
+ <property name="text">
+ <string>Visible Items:</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <layout class="QGridLayout" name="tocDefaultsLayout">
+ <item row="0" column="0">
+ <widget class="QCheckBox" name="kcfg_ShowTocChaptersDefault">
+ <property name="text">
+ <string>Show chapters</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="0">
+ <widget class="QCheckBox" name="kcfg_ShowTocSectionsDefault">
+ <property name="text">
+ <string>Show sections</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1">
+ <widget class="QCheckBox" name="kcfg_ShowTocCommandEntriesDefault">
+ <property name="text">
+ <string>Show command entries</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="1">
+ <widget class="QCheckBox" name="kcfg_ShowTocPlotsDefault">
+ <property name="text">
+ <string>Show plots</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
<item>
<spacer name="verticalSpacer">
<property name="orientation">
@@ -397,5 +524,22 @@
</layout>
</widget>
<resources/>
- <connections/>
+ <connections>
+ <connection>
+ <sender>hierarchyLevelComboBox</sender>
+ <signal>currentIndexChanged(int)</signal>
+ <receiver>hierarchyFontStack</receiver>
+ <slot>setCurrentIndex(int)</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>0</x>
+ <y>0</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>0</x>
+ <y>0</y>
+ </hint>
+ </hints>
+ </connection>
+ </connections>
</ui>
diff --git a/src/panelplugins/tocpanel/tocpanelplugin.cpp b/src/panelplugins/tocpanel/tocpanelplugin.cpp
index 473537e2..f00511f0 100644
--- a/src/panelplugins/tocpanel/tocpanelplugin.cpp
+++ b/src/panelplugins/tocpanel/tocpanelplugin.cpp
@@ -10,6 +10,7 @@
#include <QAbstractItemDelegate>
#include <QAction>
#include <QDebug>
+#include <QIcon>
#include <QItemSelectionModel>
#include <QKeyEvent>
#include <QLabel>
@@ -41,6 +42,20 @@ const QLatin1String TocNodeTypeSection("section");
const QLatin1String TocNodeTypeCommand("command");
const QLatin1String TocNodeTypePlot("plot");
+QIcon iconForTocNodeType(const QString& nodeType)
+{
+ if (nodeType == TocNodeTypeChapter)
+ return QIcon::fromTheme(QStringLiteral("view-list-tree"));
+ if (nodeType == TocNodeTypeSection)
+ return QIcon::fromTheme(QStringLiteral("format-list-ordered"));
+ if (nodeType == TocNodeTypeCommand)
+ return QIcon::fromTheme(QStringLiteral("code-context"));
+ if (nodeType == TocNodeTypePlot)
+ return QIcon::fromTheme(QStringLiteral("office-chart-line"));
+
+ return {};
+}
+
class HierarchyNameDelegate : public QStyledItemDelegate
{
public:
@@ -147,6 +162,7 @@ void TableOfContentPanelPlugin::connectToShell(QObject* cantorShell)
connect(this, SIGNAL(requestRenamePlot(QString,QString,QString)), cantorShell, SIGNAL(requestRenamePlot(QString,QString,QString)));
connect(this, SIGNAL(requestDeletePlot(QString,QString)), cantorShell, SIGNAL(requestDeletePlot(QString,QString)));
connect(cantorShell, SIGNAL(tocReadOnlyChanged(bool)), this, SLOT(handleReadOnlyChanged(bool)));
+ connect(cantorShell, SIGNAL(settingsChanges()), this, SLOT(handleSettingsChanges()));
}
bool TableOfContentPanelPlugin::showOnStartup()
@@ -194,6 +210,7 @@ void TableOfContentPanelPlugin::constructMainWidget()
auto* emptyLabel = new QLabel(container);
emptyLabel->setAlignment(Qt::AlignCenter);
emptyLabel->setWordWrap(true);
+ emptyLabel->setContextMenuPolicy(Qt::CustomContextMenu);
emptyLabel->hide();
view->setEditTriggers(QAbstractItemView::NoEditTriggers);
@@ -218,6 +235,10 @@ void TableOfContentPanelPlugin::constructMainWidget()
connect(view, &QTreeView::customContextMenuRequested, this, &TableOfContentPanelPlugin::handleContextMenuRequested);
connect(view, &QTreeView::expanded, this, &TableOfContentPanelPlugin::handleExpanded);
connect(view, &QTreeView::collapsed, this, &TableOfContentPanelPlugin::handleCollapsed);
+ connect(emptyLabel, &QLabel::customContextMenuRequested, this, [this, emptyLabel](const QPoint& position)
+ {
+ showContextMenu(QModelIndex{}, emptyLabel->mapToGlobal(position));
+ });
connect(delegate, &QAbstractItemDelegate::commitData, this, &TableOfContentPanelPlugin::handleEditorCommit);
connect(delegate, &QAbstractItemDelegate::closeEditor, this, &TableOfContentPanelPlugin::handleEditorClosed);
connect(searchEdit, &QLineEdit::textChanged, this, [this](const QString& text)
@@ -397,6 +418,7 @@ void TableOfContentPanelPlugin::rebuildModel()
QStandardItem* parentItem = parentIndex >= 0 ? visibleItems.at(parentIndex) : m_model.invisibleRootItem();
auto* item = new QStandardItem(node.displayText);
+ item->setIcon(iconForTocNodeType(node.type));
item->setEditable(node.editable && !m_readOnly);
item->setData(node.id, NodeIdRole);
@@ -961,10 +983,15 @@ void TableOfContentPanelPlugin::clearNodes()
void TableOfContentPanelPlugin::resetVisibilityToDefaults()
{
- m_showChapters = Settings::showTocChaptersDefault();
- m_showSections = Settings::showTocSectionsDefault();
- m_showCommandEntries = Settings::showTocCommandEntriesDefault();
- m_showPlots = Settings::showTocPlotsDefault();
+ m_defaultShowChapters = Settings::showTocChaptersDefault();
+ m_defaultShowSections = Settings::showTocSectionsDefault();
+ m_defaultShowCommandEntries = Settings::showTocCommandEntriesDefault();
+ m_defaultShowPlots = Settings::showTocPlotsDefault();
+
+ m_showChapters = m_defaultShowChapters;
+ m_showSections = m_defaultShowSections;
+ m_showCommandEntries = m_defaultShowCommandEntries;
+ m_showPlots = m_defaultShowPlots;
}
void TableOfContentPanelPlugin::cleanupStateAfterNodeChange()
@@ -1053,6 +1080,43 @@ void TableOfContentPanelPlugin::handleReadOnlyChanged(bool readOnly)
rebuildModel();
}
+void TableOfContentPanelPlugin::handleSettingsChanges()
+{
+ const bool showChapters = Settings::showTocChaptersDefault();
+ const bool showSections = Settings::showTocSectionsDefault();
+ const bool showCommandEntries = Settings::showTocCommandEntriesDefault();
+ const bool showPlots = Settings::showTocPlotsDefault();
+
+ bool changed = false;
+ if (showChapters != m_defaultShowChapters)
+ {
+ m_defaultShowChapters = showChapters;
+ m_showChapters = showChapters;
+ changed = true;
+ }
+ if (showSections != m_defaultShowSections)
+ {
+ m_defaultShowSections = showSections;
+ m_showSections = showSections;
+ changed = true;
+ }
+ if (showCommandEntries != m_defaultShowCommandEntries)
+ {
+ m_defaultShowCommandEntries = showCommandEntries;
+ m_showCommandEntries = showCommandEntries;
+ changed = true;
+ }
+ if (showPlots != m_defaultShowPlots)
+ {
+ m_defaultShowPlots = showPlots;
+ m_showPlots = showPlots;
+ changed = true;
+ }
+
+ if (changed)
+ rebuildModel();
+}
+
void TableOfContentPanelPlugin::handleExpanded(const QModelIndex& index)
{
if (m_updatingModel)
@@ -1089,10 +1153,16 @@ void TableOfContentPanelPlugin::handleContextMenuRequested(const QPoint& positio
if (!m_mainWidget)
return;
- if (m_editorActive)
+ showContextMenu(m_mainWidget->indexAt(position), m_mainWidget->viewport()->mapToGlobal(position));
+}
+
+void TableOfContentPanelPlugin::showContextMenu(const QModelIndex& index, const QPoint& globalPosition)
+{
+ if (!m_mainWidget)
return;
- const QModelIndex index = m_mainWidget->indexAt(position);
+ if (m_editorActive)
+ return;
QMenu menu(m_mainWidget);
@@ -1290,7 +1360,7 @@ void TableOfContentPanelPlugin::handleContextMenuRequested(const QPoint& positio
m_mainWidget->collapseAll();
});
- menu.exec(m_mainWidget->viewport()->mapToGlobal(position));
+ menu.exec(globalPosition);
}
K_PLUGIN_FACTORY_WITH_JSON(tocpanelplugin, "tocpanelplugin.json", registerPlugin<TableOfContentPanelPlugin>();)
diff --git a/src/panelplugins/tocpanel/tocpanelplugin.h b/src/panelplugins/tocpanel/tocpanelplugin.h
index 1f45df9f..b7bd2668 100644
--- a/src/panelplugins/tocpanel/tocpanelplugin.h
+++ b/src/panelplugins/tocpanel/tocpanelplugin.h
@@ -65,6 +65,7 @@ class TableOfContentPanelPlugin : public Cantor::PanelPlugin
void handleCollapsed(const QModelIndex& index);
void handleContextMenuRequested(const QPoint& position);
void handleReadOnlyChanged(bool readOnly);
+ void handleSettingsChanges();
private:
enum ItemRole
@@ -128,6 +129,7 @@ private:
void updateSearchVisibility();
void saveCurrentExpansionState();
void showContextMenuForIndex(const QModelIndex& index);
+ void showContextMenu(const QModelIndex& index, const QPoint& globalPosition);
void deleteItemAtIndex(const QModelIndex& index);
private:
@@ -146,6 +148,10 @@ private:
bool m_showSections{true};
bool m_showCommandEntries{false};
bool m_showPlots{false};
+ bool m_defaultShowChapters{true};
+ bool m_defaultShowSections{true};
+ bool m_defaultShowCommandEntries{false};
+ bool m_defaultShowPlots{false};
bool m_readOnly{false};
QSet<QString> m_expandedNodeIds;
diff --git a/src/settings.ui b/src/settings.ui
index 0f6c4fc2..882c6f95 100644
--- a/src/settings.ui
+++ b/src/settings.ui
@@ -24,44 +24,7 @@
</property>
</widget>
</item>
- <item row="22" column="0" colspan="6">
- <widget class="QGroupBox" name="tocDefaultsGroupBox">
- <property name="title">
- <string>Worksheet Structure Navigator:</string>
- </property>
- <layout class="QGridLayout" name="tocDefaultsLayout">
- <item row="0" column="0" colspan="2">
- <widget class="QCheckBox" name="kcfg_ShowTocChaptersDefault">
- <property name="text">
- <string>Show chapters by default</string>
- </property>
- </widget>
- </item>
- <item row="1" column="0" colspan="2">
- <widget class="QCheckBox" name="kcfg_ShowTocSectionsDefault">
- <property name="text">
- <string>Show sections by default</string>
- </property>
- </widget>
- </item>
- <item row="2" column="0" colspan="2">
- <widget class="QCheckBox" name="kcfg_ShowTocCommandEntriesDefault">
- <property name="text">
- <string>Show command entries by default</string>
- </property>
- </widget>
- </item>
- <item row="3" column="0" colspan="2">
- <widget class="QCheckBox" name="kcfg_ShowTocPlotsDefault">
- <property name="text">
- <string>Show plots by default</string>
- </property>
- </widget>
- </item>
- </layout>
- </widget>
- </item>
- <item row="23" column="0">
+ <item row="22" column="0">
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>