View Issue Details
| ID | Project | Category | View Status | Date Submitted | Last Update |
|---|---|---|---|---|---|
| 0017828 | Scribus | User Interface | public | 2026-06-02 10:08 | 2026-07-13 04:30 |
| Reporter | qirat | Assigned To | cbradney | ||
| Priority | normal | Severity | minor | Reproducibility | have not tried |
| Status | assigned | Resolution | open | ||
| Platform | Linux | OS | Fedora Workstation | OS Version | 44 |
| Summary | 0017828: [PATCH] Deleting many unused styles at once hides the buttons | ||||
| Description | If the list is too long the buttons go off screen below (maybe not on bigger screens but it happens on my 15" laptop, 1080p) | ||||
| Steps To Reproduce | Have many styles unused and try removing them | ||||
| Additional Information | How about fixing the dialog box's height with the buttons always visible, and making the style list scrollable? Anyway, you know better. | ||||
| Tags | No tags attached. | ||||
| Attached Files | |||||
| Patch | Yes | ||||
|
|
(Created with AI), this fixes it for me. Makes the list scrollable. delete-unused-dialog-resizable-v4-r27707.patch (4,467 bytes)
--- scribus/ui/stylemanager.cpp
+++ scribus/ui/stylemanager.cpp
@@ -5,11 +5,21 @@
for which a new license (GPL+exception) is in place.
*/
+#include <QAbstractItemView>
#include <QDebug>
+#include <QDialog>
+#include <QDialogButtonBox>
#include <QEvent>
+#include <QHeaderView>
+#include <QLabel>
#include <QMenu>
-#include <QToolTip>
#include <QMessageBox>
+#include <QPushButton>
+#include <QScreen>
+#include <QSizePolicy>
+#include <QToolTip>
+#include <QTreeWidget>
+#include <QVBoxLayout>
#include "commonstrings.h"
#include "fileloader.h"
@@ -537,7 +547,13 @@
slotOk();
int totalUnused = 0;
- QStringList unusedSummary;
+
+ struct UnusedStyleEntry
+ {
+ QString typeName;
+ QString styleName;
+ };
+ QList<UnusedStyleEntry> unusedStyles;
struct ItemDeletion
{
@@ -579,7 +595,7 @@
if (!usedMap->contains(styleName))
{
removeList.append(RemoveItem(styleName, QString()));
- unusedSummary << QString(" %1: %2").arg(styleitem->typeName(), styleName);
+ unusedStyles.append({styleitem->typeName(), styleName});
}
}
@@ -592,20 +608,70 @@
if (totalUnused == 0)
{
- ScMessageBox::information(this, tr("Remove Unused Styles"),
- tr("All styles in this document are in use. Nothing to remove."));
+ ScMessageBox::information(this, tr("Delete Unused Styles"),
+ tr("All styles in this document are in use. Nothing to delete."));
return;
}
- // Confirmation dialog
- QString message = tr("Found %1 unused style(s):\n\n").arg(totalUnused);
- message += unusedSummary.join("\n");
- message += "\n\n";
- message += tr("Remove all unused styles?");
-
- int result = ScMessageBox::question(this, tr("Remove Unused Styles"), message, QMessageBox::Yes | QMessageBox::No, QMessageBox::No);
+ QDialog dialog(this);
+ dialog.setWindowTitle(tr("Delete Unused Styles"));
+ dialog.setSizeGripEnabled(true);
+
+ QVBoxLayout* layout = new QVBoxLayout(&dialog);
+
+ QLabel* summaryLabel = new QLabel(tr("%n unused style(s) found.", nullptr, totalUnused), &dialog);
+ layout->addWidget(summaryLabel);
+
+ QLabel* detailLabel = new QLabel(tr("The following styles are not used by any object in the document:"), &dialog);
+ detailLabel->setWordWrap(true);
+ layout->addWidget(detailLabel);
+
+ QTreeWidget* unusedStyleList = new QTreeWidget(&dialog);
+ unusedStyleList->setHeaderLabels(QStringList() << tr("Type") << tr("Style"));
+ unusedStyleList->setRootIsDecorated(false);
+ unusedStyleList->setAlternatingRowColors(true);
+ unusedStyleList->setSelectionMode(QAbstractItemView::NoSelection);
+ unusedStyleList->setUniformRowHeights(true);
+ unusedStyleList->setMinimumHeight(180);
+ unusedStyleList->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
+
+ for (int i = 0; i < unusedStyles.count(); ++i)
+ {
+ QTreeWidgetItem* row = new QTreeWidgetItem(unusedStyleList);
+ row->setText(0, unusedStyles.at(i).typeName);
+ row->setText(1, unusedStyles.at(i).styleName);
+ }
+
+ QHeaderView* unusedStyleListHeader = unusedStyleList->header();
+ unusedStyleListHeader->setSectionResizeMode(QHeaderView::Interactive);
+ unusedStyleListHeader->setStretchLastSection(false);
+ unusedStyleList->resizeColumnToContents(0);
+ unusedStyleList->setColumnWidth(0, qMax(120, unusedStyleList->columnWidth(0)));
+ unusedStyleList->setColumnWidth(1, qMax(320, unusedStyleList->columnWidth(1)));
+ layout->addWidget(unusedStyleList);
+
+ QLabel* warningLabel = new QLabel(tr("Delete all listed styles?"), &dialog);
+ warningLabel->setWordWrap(true);
+ layout->addWidget(warningLabel);
+
+ QDialogButtonBox* buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, &dialog);
+ buttonBox->button(QDialogButtonBox::Ok)->setText(tr("Delete Styles"));
+ connect(buttonBox, SIGNAL(accepted()), &dialog, SLOT(accept()));
+ connect(buttonBox, SIGNAL(rejected()), &dialog, SLOT(reject()));
+ layout->addWidget(buttonBox);
+
+ const QScreen* dialogScreen = screen();
+ if (dialogScreen)
+ {
+ const QRect availableGeometry = dialogScreen->availableGeometry();
+ const int dialogWidth = qMin(qMax(560, availableGeometry.width() / 2), qMax(320, availableGeometry.width() - 80));
+ const int dialogHeight = qMin(520, qMax(280, availableGeometry.height() - 120));
+ dialog.resize(dialogWidth, dialogHeight);
+ }
+ else
+ dialog.resize(560, 520);
- if (result != QMessageBox::Yes)
+ if (dialog.exec() != QDialog::Accepted)
return;
// Delete through each StyleItem — modifies temp copies only
|
|
|
|
|
|
I cannot set the patch to "Yes". Please see. |
|
|
I would probably use an icon instead of the "Paragraph Styles" text. At first sight, the patch seems to be OK. But needs a more careful review, than what I did. |
|
|
You mean icons instead of text in the column "Type", right? That is better. |
|
|
Here is the improved version: * icons used * two part view ** show style by category --- show total count --- show count by category 1_delete-unused-dialog-layout-v3-r27707.patch (9,922 bytes)
--- scribus/ui/stylemanager.cpp
+++ scribus/ui/stylemanager.cpp
@@ -5,14 +5,28 @@
for which a new license (GPL+exception) is in place.
*/
+#include <QAbstractItemView>
#include <QDebug>
+#include <QDialog>
+#include <QDialogButtonBox>
#include <QEvent>
+#include <QFont>
+#include <QHeaderView>
+#include <QHBoxLayout>
+#include <QKeyEvent>
+#include <QLabel>
#include <QMenu>
-#include <QToolTip>
#include <QMessageBox>
+#include <QMouseEvent>
+#include <QPushButton>
+#include <QSizePolicy>
+#include <QToolTip>
+#include <QTreeWidget>
+#include <QVBoxLayout>
#include "commonstrings.h"
#include "fileloader.h"
+#include "iconmanager.h"
#include "prefsfile.h"
#include "prefsmanager.h"
#include "scraction.h"
@@ -32,6 +46,39 @@
#include "ui/scmessagebox.h"
#include "ui/styleview.h"
+namespace
+{
+class ReadOnlyTreeWidget : public QTreeWidget
+{
+public:
+ explicit ReadOnlyTreeWidget(QWidget* parent = nullptr)
+ : QTreeWidget(parent)
+ {
+ }
+
+protected:
+ void mousePressEvent(QMouseEvent* event) override
+ {
+ event->accept();
+ }
+
+ void mouseReleaseEvent(QMouseEvent* event) override
+ {
+ event->accept();
+ }
+
+ void mouseDoubleClickEvent(QMouseEvent* event) override
+ {
+ event->accept();
+ }
+
+ void keyPressEvent(QKeyEvent* event) override
+ {
+ event->accept();
+ }
+};
+}
+
const QString StyleManager::SEPARATOR = "$$$$"; // dumb but it works
StyleManager::StyleManager(QWidget *parent, const char *name)
@@ -537,7 +584,22 @@
slotOk();
int totalUnused = 0;
- QStringList unusedSummary;
+
+ struct UnusedStyleEntry
+ {
+ QString typeName;
+ QString iconName;
+ QString styleName;
+ };
+ QList<UnusedStyleEntry> unusedStyles;
+
+ struct UnusedStyleType
+ {
+ QString typeName;
+ QString iconName;
+ int count;
+ };
+ QList<UnusedStyleType> unusedStyleTypes;
struct ItemDeletion
{
@@ -552,17 +614,33 @@
// Match StyleItem subclass to the right ResourceCollection map
const QMap<QString, QString>* usedMap = nullptr;
+ QString iconName;
if (qobject_cast<SMParagraphStyle*>(styleitem))
+ {
usedMap = &usedResources.styles();
+ iconName = "paragraph-style";
+ }
else if (qobject_cast<SMCharacterStyle*>(styleitem))
+ {
usedMap = &usedResources.charStyles();
+ iconName = "character-style";
+ }
else if (qobject_cast<SMLineStyle*>(styleitem))
+ {
usedMap = &usedResources.lineStyles();
+ iconName = "stroke-style";
+ }
else if (qobject_cast<SMTableStyle*>(styleitem))
+ {
usedMap = &usedResources.tableStyles();
+ iconName = "table-style";
+ }
else if (qobject_cast<SMCellStyle*>(styleitem))
+ {
usedMap = &usedResources.cellStyles();
+ iconName = "table-cell-style";
+ }
else
continue;
@@ -579,10 +657,12 @@
if (!usedMap->contains(styleName))
{
removeList.append(RemoveItem(styleName, QString()));
- unusedSummary << QString(" %1: %2").arg(styleitem->typeName(), styleName);
+ unusedStyles.append({styleitem->typeName(), iconName, styleName});
}
}
+ unusedStyleTypes.append({styleitem->typeName(), iconName, removeList.count()});
+
if (!removeList.isEmpty())
{
deletions.append({styleitem, removeList});
@@ -592,20 +672,149 @@
if (totalUnused == 0)
{
- ScMessageBox::information(this, tr("Remove Unused Styles"),
- tr("All styles in this document are in use. Nothing to remove."));
+ ScMessageBox::information(this, tr("Delete Unused Styles"),
+ tr("All styles in this document are in use. Nothing to delete."));
return;
}
- // Confirmation dialog
- QString message = tr("Found %1 unused style(s):\n\n").arg(totalUnused);
- message += unusedSummary.join("\n");
- message += "\n\n";
- message += tr("Remove all unused styles?");
+ QDialog dialog(this);
+ dialog.setWindowTitle(tr("Delete Unused Styles"));
+ dialog.setSizeGripEnabled(false);
+
+ QVBoxLayout* layout = new QVBoxLayout(&dialog);
+ layout->setSpacing(10);
+ layout->setSizeConstraint(QLayout::SetFixedSize);
+
+ const int paneSpacing = 24;
+ const QSize overviewPaneSize(220, 300);
+ const QSize listPaneSize(540, 300);
+ const int listHeight = 230;
+
+ QWidget* contentWidget = new QWidget(&dialog);
+ QHBoxLayout* contentLayout = new QHBoxLayout(contentWidget);
+ contentLayout->setContentsMargins(0, 0, 0, 0);
+ contentLayout->setSpacing(paneSpacing);
+
+ QWidget* overviewPane = new QWidget(contentWidget);
+ overviewPane->setFixedSize(overviewPaneSize);
+ QVBoxLayout* overviewLayout = new QVBoxLayout(overviewPane);
+ overviewLayout->setContentsMargins(0, 0, 0, 0);
+ overviewLayout->setSpacing(8);
+
+ QLabel* overviewTitle = new QLabel(tr("Styles by Type"), overviewPane);
+ QFont overviewTitleFont = overviewTitle->font();
+ overviewTitleFont.setBold(true);
+ overviewTitle->setFont(overviewTitleFont);
+ overviewLayout->addWidget(overviewTitle);
+
+ QLabel* summaryLabel = new QLabel(tr("Total unused styles found: %1").arg(totalUnused), overviewPane);
+ summaryLabel->setWordWrap(true);
+ overviewLayout->addWidget(summaryLabel);
+
+ const QSize typeIconSize(16, 16);
+ for (int i = 0; i < unusedStyleTypes.count(); ++i)
+ {
+ const UnusedStyleType& styleType = unusedStyleTypes.at(i);
+ QHBoxLayout* typeRow = new QHBoxLayout;
+ typeRow->setContentsMargins(0, 0, 0, 0);
+
+ QLabel* typeIcon = new QLabel(overviewPane);
+ typeIcon->setFixedSize(typeIconSize);
+ typeIcon->setAlignment(Qt::AlignCenter);
+ typeIcon->setPixmap(IconManager::instance().loadIcon(styleType.iconName).pixmap(typeIconSize));
+ typeIcon->setToolTip(styleType.typeName);
+ typeRow->addWidget(typeIcon);
+
+ QLabel* typeName = new QLabel(styleType.typeName, overviewPane);
+ typeRow->addWidget(typeName, 1);
+
+ QLabel* typeCount = new QLabel(QString::number(styleType.count), overviewPane);
+ typeCount->setMinimumWidth(24);
+ typeCount->setAlignment(Qt::AlignRight | Qt::AlignVCenter);
+ typeRow->addWidget(typeCount);
+
+ overviewLayout->addLayout(typeRow);
+ }
+ overviewLayout->addStretch();
+
+ QWidget* listPane = new QWidget(contentWidget);
+ listPane->setFixedSize(listPaneSize);
+ QVBoxLayout* listLayout = new QVBoxLayout(listPane);
+ listLayout->setContentsMargins(0, 0, 0, 0);
+ listLayout->setSpacing(8);
+
+ QLabel* listTitle = new QLabel(tr("Unused Styles"), listPane);
+ QFont listTitleFont = listTitle->font();
+ listTitleFont.setBold(true);
+ listTitle->setFont(listTitleFont);
+ listLayout->addWidget(listTitle);
+
+ QLabel* detailLabel = new QLabel(tr("The following styles are not used by any object in the document:"), listPane);
+ detailLabel->setWordWrap(true);
+ listLayout->addWidget(detailLabel);
+
+ QTreeWidget* unusedStyleList = new ReadOnlyTreeWidget(listPane);
+ unusedStyleList->setHeaderLabels(QStringList() << tr("Type") << tr("Style Name"));
+ unusedStyleList->headerItem()->setTextAlignment(0, Qt::AlignCenter);
+ unusedStyleList->setRootIsDecorated(false);
+ unusedStyleList->setAlternatingRowColors(true);
+ unusedStyleList->setSelectionMode(QAbstractItemView::NoSelection);
+ unusedStyleList->setFocusPolicy(Qt::NoFocus);
+ unusedStyleList->setEditTriggers(QAbstractItemView::NoEditTriggers);
+ unusedStyleList->setContextMenuPolicy(Qt::NoContextMenu);
+ unusedStyleList->setUniformRowHeights(true);
+ unusedStyleList->setFixedHeight(listHeight);
+ unusedStyleList->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
+
+ for (int i = 0; i < unusedStyles.count(); ++i)
+ {
+ const UnusedStyleEntry& style = unusedStyles.at(i);
+ QTreeWidgetItem* row = new QTreeWidgetItem(unusedStyleList);
+ row->setData(0, Qt::AccessibleTextRole, style.typeName);
+ row->setText(1, style.styleName);
+
+ QLabel* typeIcon = new QLabel(unusedStyleList);
+ typeIcon->setAlignment(Qt::AlignCenter);
+ typeIcon->setPixmap(IconManager::instance().loadIcon(style.iconName).pixmap(typeIconSize));
+ typeIcon->setToolTip(style.typeName);
+ typeIcon->setAccessibleName(style.typeName);
+ typeIcon->setAttribute(Qt::WA_TransparentForMouseEvents);
+ unusedStyleList->setItemWidget(row, 0, typeIcon);
+ }
+
+ QHeaderView* unusedStyleListHeader = unusedStyleList->header();
+ unusedStyleListHeader->setSectionResizeMode(QHeaderView::Interactive);
+ unusedStyleListHeader->setStretchLastSection(false);
+ unusedStyleList->setColumnWidth(0, 64);
+ unusedStyleList->resizeColumnToContents(1);
+ unusedStyleList->setColumnWidth(1, qMax(320, unusedStyleList->columnWidth(1)));
+ listLayout->addWidget(unusedStyleList);
+
+ contentLayout->addWidget(overviewPane);
+ contentLayout->addWidget(listPane);
+ layout->addWidget(contentWidget);
+
+ const QString warningText = (totalUnused == 1)
+ ? tr("This style will be permanently deleted.")
+ : tr("These styles will be permanently deleted.");
+ QLabel* warningLabel = new QLabel(warningText, &dialog);
+ warningLabel->setWordWrap(true);
+ QHBoxLayout* warningLayout = new QHBoxLayout;
+ warningLayout->setContentsMargins(0, 0, 0, 0);
+ warningLayout->setSpacing(0);
+ warningLayout->addSpacing(overviewPaneSize.width() + paneSpacing);
+ warningLayout->addWidget(warningLabel, 1);
+ layout->addLayout(warningLayout);
+
+ QDialogButtonBox* buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, &dialog);
+ QPushButton* deleteStylesButton = buttonBox->button(QDialogButtonBox::Ok);
+ deleteStylesButton->setText(tr("Delete Styles"));
+ deleteStylesButton->setIcon(IconManager::instance().loadIcon("edit-delete"));
+ connect(buttonBox, SIGNAL(accepted()), &dialog, SLOT(accept()));
+ connect(buttonBox, SIGNAL(rejected()), &dialog, SLOT(reject()));
+ layout->addWidget(buttonBox);
- int result = ScMessageBox::question(this, tr("Remove Unused Styles"), message, QMessageBox::Yes | QMessageBox::No, QMessageBox::No);
-
- if (result != QMessageBox::Yes)
+ if (dialog.exec() != QDialog::Accepted)
return;
// Delete through each StyleItem — modifies temp copies only
@@ -619,7 +828,6 @@
slotOk();
}
-
void StyleManager::slotImport()
{
if (!m_doc)
|
|
|
|
|
|
The screenshot looks good I would probably put the summary below or on the righ side. In my eyes, the main content is the list of styles.. |
|
|
Yeah, that crossed my mind too. However, I took it so: - English is LTR, so summary first, then details (I hope this logic it makes sense). - the main content should be on the right near the buttons (the main, sensitive operation) - it is consistence with many other areas of Scribus, like SM, the main work of styling goes on the right. - the icons in the summary on the left serve like index so that one should wuickly know what each icon means in the right side. Index should come first? The "total" line in the summary could be moved to the bottom of the summary. However, it makes sense at the top too. Putting summary below would contradict my 2nd point above: The summary could be ignored if one wants but if it comes just before/above the buttons it kind of ask of an extra attention from the user which I personally beleive it does not need. What do you think? |
|
|
I went with the summary because there was an empty space anyway. And, that "Styles by Type" could be renamed to "Summary", of course. |
|
|
Here is v4: - space optimised - better polished overall |
|
|
Here is v4: - space optimised - better polished overall - smaller size 1_delete-unused-dialog-layout-v4.1-r27708.patch (10,879 bytes)
--- scribus/ui/stylemanager.cpp
+++ scribus/ui/stylemanager.cpp
@@ -5,14 +5,29 @@
for which a new license (GPL+exception) is in place.
*/
+#include <QAbstractItemView>
#include <QDebug>
+#include <QDialog>
+#include <QDialogButtonBox>
#include <QEvent>
+#include <QFont>
+#include <QHeaderView>
+#include <QHBoxLayout>
+#include <QKeyEvent>
+#include <QLabel>
#include <QMenu>
-#include <QToolTip>
#include <QMessageBox>
+#include <QMouseEvent>
+#include <QPushButton>
+#include <QSizePolicy>
+#include <QStyle>
+#include <QToolTip>
+#include <QTreeWidget>
+#include <QVBoxLayout>
#include "commonstrings.h"
#include "fileloader.h"
+#include "iconmanager.h"
#include "prefsfile.h"
#include "prefsmanager.h"
#include "scraction.h"
@@ -32,6 +47,39 @@
#include "ui/scmessagebox.h"
#include "ui/styleview.h"
+namespace
+{
+class ReadOnlyTreeWidget : public QTreeWidget
+{
+public:
+ explicit ReadOnlyTreeWidget(QWidget* parent = nullptr)
+ : QTreeWidget(parent)
+ {
+ }
+
+protected:
+ void mousePressEvent(QMouseEvent* event) override
+ {
+ event->accept();
+ }
+
+ void mouseReleaseEvent(QMouseEvent* event) override
+ {
+ event->accept();
+ }
+
+ void mouseDoubleClickEvent(QMouseEvent* event) override
+ {
+ event->accept();
+ }
+
+ void keyPressEvent(QKeyEvent* event) override
+ {
+ event->accept();
+ }
+};
+}
+
const QString StyleManager::SEPARATOR = "$$$$"; // dumb but it works
StyleManager::StyleManager(QWidget *parent, const char *name)
@@ -537,7 +585,22 @@
slotOk();
int totalUnused = 0;
- QStringList unusedSummary;
+
+ struct UnusedStyleEntry
+ {
+ QString typeName;
+ QString iconName;
+ QString styleName;
+ };
+ QList<UnusedStyleEntry> unusedStyles;
+
+ struct UnusedStyleType
+ {
+ QString typeName;
+ QString iconName;
+ int count;
+ };
+ QList<UnusedStyleType> unusedStyleTypes;
struct ItemDeletion
{
@@ -552,17 +615,33 @@
// Match StyleItem subclass to the right ResourceCollection map
const QMap<QString, QString>* usedMap = nullptr;
+ QString iconName;
if (qobject_cast<SMParagraphStyle*>(styleitem))
+ {
usedMap = &usedResources.styles();
+ iconName = "paragraph-style";
+ }
else if (qobject_cast<SMCharacterStyle*>(styleitem))
+ {
usedMap = &usedResources.charStyles();
+ iconName = "character-style";
+ }
else if (qobject_cast<SMLineStyle*>(styleitem))
+ {
usedMap = &usedResources.lineStyles();
+ iconName = "stroke-style";
+ }
else if (qobject_cast<SMTableStyle*>(styleitem))
+ {
usedMap = &usedResources.tableStyles();
+ iconName = "table-style";
+ }
else if (qobject_cast<SMCellStyle*>(styleitem))
+ {
usedMap = &usedResources.cellStyles();
+ iconName = "table-cell-style";
+ }
else
continue;
@@ -579,10 +658,12 @@
if (!usedMap->contains(styleName))
{
removeList.append(RemoveItem(styleName, QString()));
- unusedSummary << QString(" %1: %2").arg(styleitem->typeName(), styleName);
+ unusedStyles.append({styleitem->typeName(), iconName, styleName});
}
}
+ unusedStyleTypes.append({styleitem->typeName(), iconName, removeList.count()});
+
if (!removeList.isEmpty())
{
deletions.append({styleitem, removeList});
@@ -592,20 +673,173 @@
if (totalUnused == 0)
{
- ScMessageBox::information(this, tr("Remove Unused Styles"),
- tr("All styles in this document are in use. Nothing to remove."));
+ ScMessageBox::information(this, tr("Delete Unused Styles"),
+ tr("All styles in this document are in use. Nothing to delete."));
return;
}
- // Confirmation dialog
- QString message = tr("Found %1 unused style(s):\n\n").arg(totalUnused);
- message += unusedSummary.join("\n");
- message += "\n\n";
- message += tr("Remove all unused styles?");
+ QDialog dialog(this);
+ dialog.setWindowTitle(tr("Delete Unused Styles"));
+ dialog.setSizeGripEnabled(false);
+
+ QVBoxLayout* layout = new QVBoxLayout(&dialog);
+ layout->setSpacing(10);
+ layout->setSizeConstraint(QLayout::SetFixedSize);
+
+ const int paneSpacing = 24;
+ const QSize overviewPaneSize(220, 300);
+ const int listPaneHeight = 300;
+ const int listHeight = 230;
+
+ QWidget* contentWidget = new QWidget(&dialog);
+ QHBoxLayout* contentLayout = new QHBoxLayout(contentWidget);
+ contentLayout->setContentsMargins(0, 0, 0, 0);
+ contentLayout->setSpacing(paneSpacing);
+
+ QWidget* overviewPane = new QWidget(contentWidget);
+ overviewPane->setFixedSize(overviewPaneSize);
+ QVBoxLayout* overviewLayout = new QVBoxLayout(overviewPane);
+ overviewLayout->setContentsMargins(0, 0, 0, 0);
+ overviewLayout->setSpacing(8);
+
+ QLabel* overviewTitle = new QLabel(tr("Summary"), overviewPane);
+ QFont overviewTitleFont = overviewTitle->font();
+ overviewTitleFont.setBold(true);
+ overviewTitle->setFont(overviewTitleFont);
+ overviewLayout->addWidget(overviewTitle);
+
+ const QSize typeIconSize(16, 16);
+ for (int i = 0; i < unusedStyleTypes.count(); ++i)
+ {
+ const UnusedStyleType& styleType = unusedStyleTypes.at(i);
+ QHBoxLayout* typeRow = new QHBoxLayout;
+ typeRow->setContentsMargins(0, 0, 0, 0);
+
+ QLabel* typeIcon = new QLabel(overviewPane);
+ typeIcon->setFixedSize(typeIconSize);
+ typeIcon->setAlignment(Qt::AlignCenter);
+ typeIcon->setPixmap(IconManager::instance().loadIcon(styleType.iconName).pixmap(typeIconSize));
+ typeIcon->setToolTip(styleType.typeName);
+ typeRow->addWidget(typeIcon);
+
+ QLabel* typeName = new QLabel(styleType.typeName, overviewPane);
+ typeRow->addWidget(typeName, 1);
+
+ QLabel* typeCount = new QLabel(QString::number(styleType.count), overviewPane);
+ typeCount->setMinimumWidth(24);
+ typeCount->setAlignment(Qt::AlignRight | Qt::AlignVCenter);
+ typeRow->addWidget(typeCount);
+
+ overviewLayout->addLayout(typeRow);
+ }
+
+ overviewLayout->addSpacing(8);
+ QHBoxLayout* totalRow = new QHBoxLayout;
+ totalRow->setContentsMargins(0, 0, 0, 0);
+
+ QLabel* totalIconSpacer = new QLabel(overviewPane);
+ totalIconSpacer->setFixedSize(typeIconSize);
+ totalRow->addWidget(totalIconSpacer);
+
+ QLabel* totalLabel = new QLabel(tr("Total unused styles:"), overviewPane);
+ QFont totalFont = totalLabel->font();
+ totalFont.setBold(true);
+ totalLabel->setFont(totalFont);
+ totalRow->addWidget(totalLabel, 1);
+
+ QLabel* totalCount = new QLabel(QString::number(totalUnused), overviewPane);
+ totalCount->setFont(totalFont);
+ totalCount->setMinimumWidth(24);
+ totalCount->setAlignment(Qt::AlignRight | Qt::AlignVCenter);
+ totalRow->addWidget(totalCount);
+
+ overviewLayout->addLayout(totalRow);
+ overviewLayout->addStretch();
+
+ QWidget* listPane = new QWidget(contentWidget);
+ listPane->setFixedHeight(listPaneHeight);
+ QVBoxLayout* listLayout = new QVBoxLayout(listPane);
+ listLayout->setContentsMargins(0, 0, 0, 0);
+ listLayout->setSpacing(8);
+
+ QLabel* listTitle = new QLabel(tr("Unused Styles"), listPane);
+ QFont listTitleFont = listTitle->font();
+ listTitleFont.setBold(true);
+ listTitle->setFont(listTitleFont);
+ listLayout->addWidget(listTitle);
+
+ QLabel* detailLabel = new QLabel(tr("The following styles are not used by any object in the document:"), listPane);
+ detailLabel->setWordWrap(true);
+ listLayout->addWidget(detailLabel);
+
+ QTreeWidget* unusedStyleList = new ReadOnlyTreeWidget(listPane);
+ unusedStyleList->setHeaderLabels(QStringList() << tr("Type") << tr("Style Name"));
+ unusedStyleList->headerItem()->setTextAlignment(0, Qt::AlignCenter);
+ unusedStyleList->setRootIsDecorated(false);
+ unusedStyleList->setAlternatingRowColors(true);
+ unusedStyleList->setSelectionMode(QAbstractItemView::NoSelection);
+ unusedStyleList->setFocusPolicy(Qt::NoFocus);
+ unusedStyleList->setEditTriggers(QAbstractItemView::NoEditTriggers);
+ unusedStyleList->setContextMenuPolicy(Qt::NoContextMenu);
+ unusedStyleList->setUniformRowHeights(true);
+ unusedStyleList->setFixedHeight(listHeight);
+ unusedStyleList->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
+
+ for (int i = 0; i < unusedStyles.count(); ++i)
+ {
+ const UnusedStyleEntry& style = unusedStyles.at(i);
+ QTreeWidgetItem* row = new QTreeWidgetItem(unusedStyleList);
+ row->setData(0, Qt::AccessibleTextRole, style.typeName);
+ row->setText(1, style.styleName);
+
+ QLabel* typeIcon = new QLabel(unusedStyleList);
+ typeIcon->setAlignment(Qt::AlignCenter);
+ typeIcon->setPixmap(IconManager::instance().loadIcon(style.iconName).pixmap(typeIconSize));
+ typeIcon->setToolTip(style.typeName);
+ typeIcon->setAccessibleName(style.typeName);
+ typeIcon->setAttribute(Qt::WA_TransparentForMouseEvents);
+ unusedStyleList->setItemWidget(row, 0, typeIcon);
+ }
+
+ QHeaderView* unusedStyleListHeader = unusedStyleList->header();
+ unusedStyleListHeader->setSectionResizeMode(QHeaderView::Interactive);
+ unusedStyleListHeader->setStretchLastSection(false);
+ unusedStyleList->setColumnWidth(0, 64);
+ unusedStyleList->resizeColumnToContents(1);
+ unusedStyleList->setColumnWidth(1, qMax(320, unusedStyleList->columnWidth(1)));
+ unusedStyleList->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
+ const int listPaneWidth = unusedStyleListHeader->length()
+ + unusedStyleList->style()->pixelMetric(QStyle::PM_ScrollBarExtent, nullptr, unusedStyleList)
+ + 2 * unusedStyleList->frameWidth();
+ unusedStyleList->setFixedWidth(listPaneWidth);
+ listPane->setFixedWidth(listPaneWidth);
+ listLayout->addWidget(unusedStyleList);
+
+ contentLayout->addWidget(overviewPane);
+ contentLayout->addWidget(listPane);
+ layout->addWidget(contentWidget);
+
+ const QString warningText = (totalUnused == 1)
+ ? tr("This style will be permanently deleted.")
+ : tr("These styles will be permanently deleted.");
+ QLabel* warningLabel = new QLabel(warningText, &dialog);
+ warningLabel->setWordWrap(true);
+ QHBoxLayout* warningLayout = new QHBoxLayout;
+ warningLayout->setContentsMargins(0, 0, 0, 0);
+ warningLayout->setSpacing(0);
+ warningLayout->addSpacing(overviewPaneSize.width() + paneSpacing);
+ warningLayout->addWidget(warningLabel, 1);
+ layout->addLayout(warningLayout);
+
+ QDialogButtonBox* buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, &dialog);
+ QPushButton* deleteStylesButton = buttonBox->button(QDialogButtonBox::Ok);
+ deleteStylesButton->setText(tr("Delete Styles"));
+ deleteStylesButton->setIcon(IconManager::instance().loadIcon("edit-delete"));
+ connect(buttonBox, SIGNAL(accepted()), &dialog, SLOT(accept()));
+ connect(buttonBox, SIGNAL(rejected()), &dialog, SLOT(reject()));
+ layout->addWidget(buttonBox);
- int result = ScMessageBox::question(this, tr("Remove Unused Styles"), message, QMessageBox::Yes | QMessageBox::No, QMessageBox::No);
-
- if (result != QMessageBox::Yes)
+ if (dialog.exec() != QDialog::Accepted)
return;
// Delete through each StyleItem — modifies temp copies only
@@ -619,7 +853,6 @@
slotOk();
}
-
void StyleManager::slotImport()
{
if (!m_doc)
|
| Date Modified | Username | Field | Change |
|---|---|---|---|
| 2026-06-02 10:08 | qirat | New Issue | |
| 2026-06-02 10:08 | qirat | File Added: Screenshot From 2026-06-01 06-14-48.png | |
| 2026-06-02 17:55 | cbradney | Assigned To | => cbradney |
| 2026-06-02 17:55 | cbradney | Status | new => assigned |
| 2026-07-11 02:38 | qirat | Note Added: 0054009 | |
| 2026-07-11 02:38 | qirat | File Added: delete-unused-dialog-resizable-v4-r27707.patch | |
| 2026-07-11 02:39 | qirat | Note Added: 0054010 | |
| 2026-07-11 02:39 | qirat | File Added: delete_unused_style_scrollable.png | |
| 2026-07-11 02:48 | qirat | Note Added: 0054011 | |
| 2026-07-11 07:21 | ale | Summary | Deleting many unused styles at once hides the buttons => [PATCH] Deleting many unused styles at once hides the buttons |
| 2026-07-11 07:21 | ale | Patch | No => Yes |
| 2026-07-11 07:29 | ale | Note Added: 0054017 | |
| 2026-07-11 07:36 | qirat | Note Added: 0054018 | |
| 2026-07-11 09:16 | qirat | Note Added: 0054019 | |
| 2026-07-11 09:16 | qirat | File Added: 1_delete-unused-dialog-layout-v3-r27707.patch | |
| 2026-07-11 09:17 | qirat | Note Added: 0054020 | |
| 2026-07-11 09:17 | qirat | File Added: delete-unused-dialog-layout-v3-r27707.png | |
| 2026-07-12 06:46 | ale | Note Added: 0054023 | |
| 2026-07-12 07:10 | qirat | Note Added: 0054024 | |
| 2026-07-12 07:13 | qirat | Note Added: 0054025 | |
| 2026-07-13 04:06 | qirat | Note Added: 0054027 | |
| 2026-07-13 04:06 | qirat | File Added: 1_delete-unused-dialog-layout-v4-r27707.patch | |
| 2026-07-13 04:06 | qirat | File Added: delete-unused-dialog-layout-v4-r27707.png | |
| 2026-07-13 04:13 | qirat | File Deleted: delete-unused-dialog-layout-v4-r27707.png | |
| 2026-07-13 04:13 | qirat | File Deleted: 1_delete-unused-dialog-layout-v4-r27707.patch | |
| 2026-07-13 04:30 | qirat | Note Added: 0054028 | |
| 2026-07-13 04:30 | qirat | File Added: 1_delete-unused-dialog-layout-v4.1-r27708.patch | |
| 2026-07-13 04:30 | qirat | File Added: delete-unused-dialog-layout-v4.1-r27708.png |