Skip to content

Commit 8a0ba27

Browse files
committed
ColorListWidget: Remove unused colors
Add a button to the Colors window that allows to remove colors which are not used by any symbol. Before the removal a popup window offers to show the list of colors to be removed and asks for confirmation.
1 parent 803f195 commit 8a0ba27

File tree

2 files changed

+66
-6
lines changed

2 files changed

+66
-6
lines changed

src/gui/widgets/color_list_widget.cpp

Lines changed: 61 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
/*
22
* Copyright 2012, 2013 Thomas Schöps
33
* Copyright 2012-2018, 2021, 2024 Kai Pastor
4+
* Copyright 2025 Matthias Kühlewein
45
*
56
* This file is part of OpenOrienteering.
67
*
@@ -21,12 +22,15 @@
2122

2223
#include "color_list_widget.h"
2324

25+
#include <vector>
26+
2427
#include <Qt>
2528
#include <QtGlobal>
2629
#include <QAbstractButton>
2730
#include <QAbstractItemView>
2831
#include <QAction>
2932
#include <QApplication>
33+
#include <QChar>
3034
#include <QColor>
3135
#include <QDialog>
3236
#include <QFlags>
@@ -48,8 +52,8 @@
4852
#include <QTableWidget>
4953
#include <QTableWidgetItem>
5054
#include <QToolButton>
51-
#include <QVBoxLayout>
5255
#include <QVariant>
56+
#include <QVBoxLayout>
5357

5458
#include "core/map.h"
5559
#include "core/map_color.h"
@@ -123,6 +127,9 @@ ColorListWidget::ColorListWidget(Map* map, MainWindow* window, QWidget* parent)
123127
edit_button = createToolButton(QIcon(QString::fromLatin1(":/images/settings.png")), QApplication::translate("OpenOrienteering::MapEditorController", "&Edit").remove(QLatin1Char('&')));
124128
edit_button->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
125129

130+
auto cleanup_button = createToolButton(QIcon(QString::fromLatin1(":/images/delete.png")), tr("Cleanup"));
131+
cleanup_button->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
132+
126133
auto help_button = createToolButton(QIcon(QString::fromLatin1(":/images/help.png")), tr("Help"));
127134
help_button->setAutoRaise(true);
128135

@@ -132,6 +139,7 @@ ColorListWidget::ColorListWidget(Map* map, MainWindow* window, QWidget* parent)
132139
buttons_group_layout->addLayout(up_down_layout);
133140
buttons_group_layout->addWidget(edit_button);
134141
buttons_group_layout->addWidget(new QLabel(QString::fromLatin1(" ")), 1);
142+
buttons_group_layout->addWidget(cleanup_button);
135143
buttons_group_layout->addWidget(help_button);
136144

137145
// The layout of all components below the table
@@ -184,6 +192,7 @@ ColorListWidget::ColorListWidget(Map* map, MainWindow* window, QWidget* parent)
184192
connect(move_up_button, &QAbstractButton::clicked, this, &ColorListWidget::moveColorUp);
185193
connect(move_down_button, &QAbstractButton::clicked, this, &ColorListWidget::moveColorDown);
186194
connect(edit_button, &QAbstractButton::clicked, this, &ColorListWidget::editCurrentColor);
195+
connect(cleanup_button, &QAbstractButton::clicked, this, &ColorListWidget::removeUnusedColors);
187196
connect(help_button, &QAbstractButton::clicked, this, &ColorListWidget::showHelp);
188197

189198
connect(map, &Map::colorAdded, this, &ColorListWidget::colorAdded);
@@ -223,9 +232,10 @@ void ColorListWidget::newColor()
223232
editCurrentColor();
224233
}
225234

226-
bool ColorListWidget::confirmColorDeletion(const MapColor* color_to_be_removed) const
235+
std::pair<QString, bool> ColorListWidget::determineColorUsage(const MapColor* color_to_be_removed) const
227236
{
228237
QString detailed_text;
238+
bool color_used_by_symbols = false;
229239

230240
std::vector<const Symbol*> remaining_symbols;
231241
remaining_symbols.reserve(std::size_t(map->getNumSymbols()));
@@ -246,6 +256,7 @@ bool ColorListWidget::confirmColorDeletion(const MapColor* color_to_be_removed)
246256
{
247257
detailed_text += tr("This color is used by the following symbols:") + QChar::LineFeed
248258
+ direct_usage + QChar::LineFeed;
259+
color_used_by_symbols = true;
249260
}
250261
}
251262

@@ -286,18 +297,25 @@ bool ColorListWidget::confirmColorDeletion(const MapColor* color_to_be_removed)
286297
{
287298
detailed_text += tr("This spot color is used by the following symbols:") + QChar::LineFeed
288299
+ transitive_usage;
300+
color_used_by_symbols = true;
289301
}
290302
}
291303
}
292-
293-
if (detailed_text.isEmpty())
304+
305+
return std::make_pair(detailed_text, color_used_by_symbols);
306+
}
307+
308+
bool ColorListWidget::confirmColorDeletion(const MapColor* color_to_be_removed) const
309+
{
310+
const auto result = determineColorUsage(color_to_be_removed);
311+
if (result.first.isEmpty())
294312
return true;
295313

296314
QMessageBox msgBox;
297315
msgBox.setWindowTitle(tr("Confirmation"));
298316
msgBox.setIcon(QMessageBox::Warning);
299317
msgBox.setText(tr("Color \"%1\" is used by other elements. Removing the color will change the appearance of these elements. Do you really want to remove it?").arg(color_to_be_removed->getName()));
300-
msgBox.setDetailedText(detailed_text);
318+
msgBox.setDetailedText(result.first);
301319
msgBox.setStandardButtons(QMessageBox::Yes | QMessageBox::No);
302320
return msgBox.exec() == QMessageBox::Yes;
303321
}
@@ -393,6 +411,44 @@ void ColorListWidget::editCurrentColor()
393411
}
394412
}
395413

414+
void ColorListWidget::removeUnusedColors()
415+
{
416+
QString unused_color_names;
417+
std::vector<int> unused_colors;
418+
unused_colors.reserve(std::size_t(map->getNumColors()));
419+
for (auto row = color_table->rowCount() - 1; row >= 0; --row)
420+
{
421+
const auto color = map->getMapColor(row);
422+
const auto result = determineColorUsage(color);
423+
if (!result.second)
424+
{
425+
unused_colors.push_back(row);
426+
unused_color_names = color->getName() + QChar::LineFeed + unused_color_names;
427+
}
428+
}
429+
if (unused_colors.empty())
430+
{
431+
QMessageBox::information(this, tr("Information"), tr("There are no unused colors to be removed."), QMessageBox::Ok);
432+
}
433+
else
434+
{
435+
QMessageBox msgBox;
436+
msgBox.setWindowTitle(tr("Confirmation"));
437+
msgBox.setIcon(QMessageBox::Question);
438+
msgBox.setText(tr("Do you want to remove %n unused color(s) from the map?", nullptr, unused_colors.size()));
439+
msgBox.setDetailedText(unused_color_names);
440+
msgBox.setStandardButtons(QMessageBox::Yes | QMessageBox::No);
441+
if (msgBox.exec() == QMessageBox::No)
442+
return;
443+
444+
for (auto i : unused_colors)
445+
map->deleteColor(i);
446+
447+
map->setColorsDirty();
448+
map->updateAllObjects();
449+
}
450+
}
451+
396452
void ColorListWidget::showHelp() const
397453
{
398454
Util::showHelp(window, "color_dock_widget.html");

src/gui/widgets/color_list_widget.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@
2222
#ifndef OPENORIENTEERING_COLOR_LIST_WIDGET_H
2323
#define OPENORIENTEERING_COLOR_LIST_WIDGET_H
2424

25+
#include <utility>
26+
2527
#include <QObject>
2628
#include <QWidget>
2729

@@ -60,6 +62,7 @@ protected slots:
6062
void moveColorUp();
6163
void moveColorDown();
6264
void editCurrentColor();
65+
void removeUnusedColors();
6366
void showHelp() const;
6467

6568
void cellChange(int row, int column);
@@ -75,6 +78,7 @@ protected slots:
7578
private:
7679
void addRow(int row);
7780
void updateRow(int row);
81+
std::pair<QString, bool> determineColorUsage(const OpenOrienteering::MapColor* color_to_be_removed) const;
7882
bool confirmColorDeletion(const OpenOrienteering::MapColor* color_to_be_removed) const;
7983

8084
// Color list
@@ -96,4 +100,4 @@ protected slots:
96100

97101
} // namespace OpenOrienteering
98102

99-
#endif
103+
#endif // OPENORIENTEERING_COLOR_LIST_WIDGET_H

0 commit comments

Comments
 (0)