diff --git a/code-check-wrapper.sh b/code-check-wrapper.sh
index 42dd46dba..f89d228c3 100755
--- a/code-check-wrapper.sh
+++ b/code-check-wrapper.sh
@@ -1,6 +1,6 @@
#!/bin/sh -e
-# Copyright 2017, 2018 Kai Pastor
+# Copyright 2017, 2018, 2024 Kai Pastor
#
# This file is part of OpenOrienteering.
#
@@ -71,6 +71,7 @@ for I in \
map_coord.cpp \
map_editor.cpp \
map_find_feature.cpp \
+ map_information_dialog.cpp \
map_printer \
map_widget.cpp \
mapper_proxystyle.cpp \
diff --git a/images/map-information.png b/images/map-information.png
new file mode 100755
index 000000000..d7d75d800
Binary files /dev/null and b/images/map-information.png differ
diff --git a/resources.qrc b/resources.qrc
index a3fd91f57..83ef2a9fd 100644
--- a/resources.qrc
+++ b/resources.qrc
@@ -117,6 +117,7 @@
images/view-zoom-out.png
images/window-new.png
images/mapper-icon/Mapper-128.png
+ images/map-information.png
doc/tip-of-the-day/tips_en.txt
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index faa764cb0..6a25ffb2d 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -1,6 +1,6 @@
#
# Copyright 2012-2014 Thomas Schöps
-# Copyright 2012-2018 Kai Pastor
+# Copyright 2012-2024 Kai Pastor
#
# This file is part of OpenOrienteering.
#
@@ -163,6 +163,7 @@ set(Mapper_Common_SRCS
gui/map/map_editor.cpp
gui/map/map_editor_activity.cpp
gui/map/map_find_feature.cpp
+ gui/map/map_information_dialog.cpp
gui/map/map_widget.cpp
gui/map/rotate_map_dialog.cpp
gui/map/stretch_map_dialog.cpp
diff --git a/src/gui/map/map_editor.cpp b/src/gui/map/map_editor.cpp
index 7d79cf311..bf2646364 100644
--- a/src/gui/map/map_editor.cpp
+++ b/src/gui/map/map_editor.cpp
@@ -124,6 +124,7 @@
#include "gui/map/map_dialog_scale.h"
#include "gui/map/map_editor_activity.h"
#include "gui/map/map_find_feature.h"
+#include "gui/map/map_information_dialog.h"
#include "gui/map/map_widget.h"
#include "gui/map/rotate_map_dialog.h"
#include "gui/symbols/symbol_replacement.h"
@@ -462,6 +463,7 @@ void MapEditorController::setEditingInProgress(bool value)
scale_map_act->setEnabled(!editing_in_progress);
rotate_map_act->setEnabled(!editing_in_progress);
map_notes_act->setEnabled(!editing_in_progress);
+ map_info_act->setEnabled(!editing_in_progress);
// Map menu, continued
const int num_parts = map->getNumParts();
@@ -1027,6 +1029,7 @@ void MapEditorController::createActions()
scale_map_act = newAction("scalemap", tr("Change map scale..."), this, SLOT(scaleMapClicked()), "tool-scale.png", tr("Change the map scale and adjust map objects and symbol sizes"), "map_menu.html");
rotate_map_act = newAction("rotatemap", tr("Rotate map..."), this, SLOT(rotateMapClicked()), "tool-rotate.png", tr("Rotate the whole map"), "map_menu.html");
map_notes_act = newAction("mapnotes", tr("Map notes..."), this, SLOT(mapNotesClicked()), nullptr, QString{}, "map_menu.html");
+ map_info_act = newAction("mapinfo", tr("Map information..."), this, SLOT(mapInfoClicked()), "map-information.png", QString{}, "map_menu.html");
template_window_act = newCheckAction("templatewindow", tr("Template setup window"), this, SLOT(showTemplateWindow(bool)), "templates.png", tr("Show/Hide the template window"), "templates_menu.html");
//QAction* template_config_window_act = newCheckAction("templateconfigwindow", tr("Template configurations window"), this, SLOT(showTemplateConfigurationsWindow(bool)), "window-new", tr("Show/Hide the template configurations window"));
@@ -1253,6 +1256,7 @@ void MapEditorController::createMenuAndToolbars()
map_menu->addAction(scale_map_act);
map_menu->addAction(rotate_map_act);
map_menu->addAction(map_notes_act);
+ map_menu->addAction(map_info_act);
map_menu->addSeparator();
updateMapPartsUI();
map_menu->addAction(mappart_add_act);
@@ -2282,6 +2286,13 @@ void MapEditorController::mapNotesClicked()
}
}
+void MapEditorController::mapInfoClicked()
+{
+ MapInformationDialog dialog(window, map);
+ dialog.setWindowModality(Qt::WindowModal);
+ dialog.exec();
+}
+
void MapEditorController::createTemplateWindow()
{
Q_ASSERT(!template_dock_widget);
diff --git a/src/gui/map/map_editor.h b/src/gui/map/map_editor.h
index 0e641d449..4cbb8e775 100644
--- a/src/gui/map/map_editor.h
+++ b/src/gui/map/map_editor.h
@@ -1,6 +1,6 @@
/*
* Copyright 2012, 2013, 2014 Thomas Schöps
- * Copyright 2013-2021 Kai Pastor
+ * Copyright 2013-2024 Kai Pastor
*
* This file is part of OpenOrienteering.
*
@@ -348,6 +348,8 @@ public slots:
void rotateMapClicked();
/** Shows the dialog to enter map notes. */
void mapNotesClicked();
+ /** Shows the map information. */
+ void mapInfoClicked();
/** Shows or hides the template setup dock widget. */
void showTemplateWindow(bool show);
@@ -746,6 +748,7 @@ protected slots:
QAction* scale_map_act = {};
QAction* rotate_map_act = {};
QAction* map_notes_act = {};
+ QAction* map_info_act = {};
QAction* symbol_set_id_act = {};
std::unique_ptr symbol_report_feature;
diff --git a/src/gui/map/map_information_dialog.cpp b/src/gui/map/map_information_dialog.cpp
new file mode 100644
index 000000000..9d3c44089
--- /dev/null
+++ b/src/gui/map/map_information_dialog.cpp
@@ -0,0 +1,395 @@
+/*
+ * Copyright 2024 Matthias Kühlewein
+ *
+ * This file is part of OpenOrienteering.
+ *
+ * OpenOrienteering 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.
+ *
+ * OpenOrienteering 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 OpenOrienteering. If not, see .
+ */
+
+#include "map_information_dialog.h"
+
+#include
+#include
+#include
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include "core/georeferencing.h"
+#include "core/map.h"
+#include "core/objects/object.h"
+#include "core/symbols/symbol.h"
+#include "core/symbols/text_symbol.h"
+#include "gui/file_dialog.h"
+#include "gui/main_window.h"
+#include "gui/map/map_editor.h"
+#include "undo/undo_manager.h"
+
+
+namespace OpenOrienteering {
+
+MapInformationDialog::MapInformationDialog(MainWindow* parent, Map* map)
+ : QDialog(parent, Qt::WindowSystemMenuHint | Qt::WindowTitleHint | Qt::WindowCloseButtonHint)
+ , map(map)
+ , main_window(parent)
+ , text_report_indent{3}
+{
+ setWindowTitle(tr("Map information"));
+
+ auto* save_button = new QPushButton(QIcon(QLatin1String(":/images/save.png")), tr("Save"));
+ auto* ok_button = new QPushButton(QIcon(QLatin1String(":/images/arrow-right.png")), tr("OK"));
+ ok_button->setDefault(true);
+
+ auto* buttons_layout = new QHBoxLayout();
+ buttons_layout->addWidget(save_button);
+ buttons_layout->addStretch(1);
+ buttons_layout->addWidget(ok_button);
+
+ map_info_tree = new QTreeWidget();
+ map_info_tree->setColumnCount(2);
+ map_info_tree->setHeaderHidden(true);
+
+ retrieveInformation();
+ buildTree();
+ setupTreeWidget();
+
+ map_info_tree->header()->setSectionResizeMode(0, QHeaderView::ResizeToContents);
+
+ auto* layout = new QVBoxLayout();
+ layout->addWidget(map_info_tree);
+ layout->addLayout(buttons_layout);
+ setLayout(layout);
+ resize(650, 600);
+
+ connect(save_button, &QAbstractButton::clicked, this, &MapInformationDialog::save);
+ connect(ok_button, &QAbstractButton::clicked, this, &QDialog::accept);
+}
+
+MapInformationDialog::~MapInformationDialog() = default;
+
+
+// retrieve and store the information
+void MapInformationDialog::retrieveInformation()
+{
+ map_information.map_scale = int(map->getScaleDenominator());
+
+ const auto& map_crs = map->getGeoreferencing().getProjectedCRSId();
+ map_information.map_crs = map->getGeoreferencing().getProjectedCRSName();
+ if (map_crs != QLatin1String("Local") && map_crs != QLatin1String("PROJ.4"))
+ {
+ const auto& projected_crs_parameters = map->getGeoreferencing().getProjectedCRSParameters();
+ if (!projected_crs_parameters.empty())
+ {
+ QString crs_details = QLatin1String(" (") + (map_crs == QLatin1String("EPSG") ? tr("code") : tr("zone")) + QChar::Space + projected_crs_parameters.front() + QLatin1Char(')');
+ map_information.map_crs += crs_details;
+ }
+ }
+
+ map_information.map_parts_num = map->getNumParts();
+ map_information.map_parts.reserve(map_information.map_parts_num);
+ map_information.symbols_num = map->getNumSymbols();
+ map_information.templates_num = map->getNumTemplates();
+ map_information.colors_num = map->getNumColors();
+
+ for (int i = 0; i < map_information.colors_num; ++i)
+ {
+ const auto* map_color = map->getMapColor(i);
+ if (map_color)
+ {
+ ColorUsage color = {};
+ color.name = map_color->getName();
+ for (int j = 0; j < map_information.symbols_num; ++j)
+ {
+ const auto* symbol = map->getSymbol(j);
+ if (symbol->getType())
+ {
+ if (symbol->containsColor(map_color))
+ {
+ color.symbols.push_back({getFullSymbolName(symbol)});
+ }
+ }
+ }
+ map_information.colors.emplace_back(color);
+ }
+ }
+
+ const auto& undo_manager = map->undoManager();
+ map_information.undo_steps_num = undo_manager.canUndo() ? undo_manager.undoStepCount() : 0;
+ map_information.redo_steps_num = undo_manager.canRedo() ? undo_manager.redoStepCount() : 0;
+
+ int i = 0;
+ for (auto& name : {tr("Point symbols"), tr("Line symbols"), tr("Area symbols"), tr("Text symbols"), tr("Combined symbols"), tr("Undefined symbols")})
+ map_information.map_objects[i++].category.name = name;
+
+ for (i = 0; i < map_information.map_parts_num; ++i)
+ {
+ const auto* map_part = map->getPart(i);
+ const auto map_part_objects = map_part->getNumObjects();
+ map_information.map_parts.push_back({map_part->getName(), map_part_objects});
+ map_information.map_objects_num += map_part_objects;
+
+ for (int j = 0; j < map_part_objects; ++j)
+ {
+ const auto* symbol = map_part->getObject(j)->getSymbol();
+ addSymbol(symbol);
+ }
+ }
+ for (auto& map_object : map_information.map_objects)
+ {
+ if (map_object.category.num > 1)
+ {
+ auto& objects_vector = map_object.objects;
+ sort(begin(objects_vector), end(objects_vector), [](const SymbolNum& sym1, const SymbolNum& sym2) { return Symbol::lessByNumber(sym1.symbol, sym2.symbol); });
+ }
+ }
+ for (i = 0; i < map_information.symbols_num; ++i)
+ {
+ const auto* symbol = map->getSymbol(i);
+ if (symbol->getType() == Symbol::Text)
+ {
+ addFont(symbol);
+ }
+ }
+ map_information.fonts_num = static_cast(map_information.font_names.size());
+}
+
+void MapInformationDialog::addSymbol(const Symbol* symbol)
+{
+ const auto symbol_type = symbol->getType();
+ int symbol_index;
+ for (symbol_index = 0; symbol_index < 5; ++symbol_index)
+ {
+ if ((symbol_type & (1 << symbol_index)) == symbol_type)
+ break;
+ }
+ const bool undefined_object = map->findSymbolIndex(symbol) < 0;
+ auto& object_category = map_information.map_objects[symbol_index];
+ auto& objects_vector = object_category.objects;
+ auto found = std::find_if(begin(objects_vector), end(objects_vector), [&symbol](const SymbolNum& sym_count) { return sym_count.symbol == symbol; });
+ if (found != std::end(objects_vector))
+ {
+ ++found->num;
+ }
+ else
+ {
+ std::vector colors;
+ for (int i = 0; i < map_information.colors_num; ++i)
+ {
+ const auto* map_color = map->getMapColor(i);
+ if (map_color && symbol->containsColor(map_color))
+ {
+ colors.push_back({map_color->getName()});
+ }
+ }
+ objects_vector.push_back({symbol, undefined_object ? tr("") : getFullSymbolName(symbol), 1, colors});
+ }
+ ++object_category.category.num;
+}
+
+void MapInformationDialog::addFont(const Symbol* symbol)
+{
+ const auto* text_symbol = symbol->asText();
+ const auto& font_family = text_symbol->getFontFamily();
+ const auto font_family_substituted = QFontInfo(text_symbol->getQFont()).family();
+ auto& font_names = map_information.font_names;
+ auto found = std::find_if(begin(font_names), end(font_names), [&font_family](const FontNum& font_count) { return font_count.name == font_family; });
+ if (found != std::end(font_names))
+ {
+ ++found->num;
+ }
+ else
+ {
+ font_names.push_back({font_family, font_family_substituted, 1});
+ }
+}
+
+// create textual information and put it in the tree widget
+void MapInformationDialog::buildTree()
+{
+ tree_item_hierarchy.reserve(4);
+ max_item_length = 0;
+
+ addTreeItem(0, tr("Map"), tr("%n object(s)", nullptr, map_information.map_objects_num));
+
+ addTreeItem(1, tr("Scale"), QString::fromLatin1("1:%1").arg(map_information.map_scale));
+
+ addTreeItem(1, tr("Coordinate reference system"), map_information.map_crs);
+
+ addTreeItem(0, tr("Map parts"), tr("%n part(s)", nullptr, map_information.map_parts_num));
+ for (const auto& map_part : map_information.map_parts)
+ {
+ addTreeItem(1, map_part.name, tr("%n object(s)", nullptr, map_part.num));
+ }
+
+ addTreeItem(0, tr("Symbols"), tr("%n symbol(s)", nullptr, map_information.symbols_num));
+
+ addTreeItem(0, tr("Templates"), tr("%n template(s)", nullptr, map_information.templates_num));
+
+ if (map_information.undo_steps_num || map_information.redo_steps_num)
+ {
+ QString undo_redo_type = map_information.undo_steps_num ? tr("Undo") : tr("Redo");
+ QString undo_redo_num = QString::fromLatin1("%1").arg(map_information.undo_steps_num ? map_information.undo_steps_num : map_information.redo_steps_num);
+ if (map_information.undo_steps_num && map_information.redo_steps_num)
+ {
+ undo_redo_type.append(QLatin1Char('/')).append(tr("Redo"));
+ undo_redo_num.append(QString::fromLatin1("/%1").arg(map_information.redo_steps_num));
+ }
+ undo_redo_type.append(QChar::Space).append(tr("steps"));
+ undo_redo_num.append(QChar::Space).append(map_information.undo_steps_num + map_information.redo_steps_num > 1 ? tr("steps") : tr("step"));
+ addTreeItem(0, undo_redo_type, undo_redo_num);
+ }
+
+ addTreeItem(0, tr("Colors"), tr("%n color(s)", nullptr, map_information.colors_num));
+ if (map_information.colors_num)
+ {
+ for (const auto& color : map_information.colors)
+ {
+ addTreeItem(1, color.name);
+ if (color.symbols.size())
+ {
+ for (const auto& symbol : color.symbols)
+ {
+ addTreeItem(2, symbol);
+ }
+ }
+ }
+ }
+
+ addTreeItem(0, tr("Fonts"), tr("%n font(s)", nullptr, map_information.fonts_num));
+ for (const auto& font_name : map_information.font_names)
+ {
+ addTreeItem(1, (font_name.name == font_name.name_substitute ? font_name.name : font_name.name + tr(" (substituted by ") + font_name.name_substitute + QLatin1Char(')')),
+ tr("%n symbol(s)", nullptr, font_name.num));
+ }
+
+ addTreeItem(0, tr("Objects"), tr("%n object(s)", nullptr, map_information.map_objects_num));
+ for (const auto& map_object : map_information.map_objects)
+ {
+ if (map_object.category.num)
+ {
+ addTreeItem(1, map_object.category.name, tr("%n object(s)", nullptr, map_object.category.num));
+ for (const auto& object : map_object.objects)
+ {
+ addTreeItem(2, object.name, tr("%n object(s)", nullptr, object.num));
+ if (object.colors.size())
+ {
+ for (const auto& color : object.colors)
+ {
+ addTreeItem(3, color);
+ }
+ }
+ }
+ }
+ }
+}
+
+void MapInformationDialog::addTreeItem(const int level, const QString& item, const QString& value)
+{
+ Q_ASSERT(level >= 0 && level <= 3);
+
+ tree_items.push_back({level, item, value});
+ max_item_length = qMax(max_item_length, level * text_report_indent + item.length());
+}
+
+void MapInformationDialog::setupTreeWidget()
+{
+ for (const auto &tree_item : tree_items)
+ {
+ auto tree_depth = static_cast(tree_item_hierarchy.size());
+ Q_ASSERT(tree_item.level <= tree_depth);
+
+ for (; tree_depth > tree_item.level; --tree_depth)
+ tree_item_hierarchy.pop_back();
+
+ QTreeWidgetItem* tree_widget_item;
+ if (tree_depth)
+ tree_widget_item = new QTreeWidgetItem(tree_item_hierarchy.back());
+ else
+ tree_widget_item = new QTreeWidgetItem(map_info_tree);
+ tree_widget_item->setText(0, tree_item.item);
+ tree_widget_item->setText(1, tree_item.value);
+ tree_item_hierarchy.emplace_back(tree_widget_item); // always store last tree item
+ }
+}
+
+QString MapInformationDialog::makeTextReport() const
+{
+ QString text_report;
+ for (const auto &tree_item : tree_items)
+ {
+ QString item_value;
+ if (!text_report.isEmpty() && !tree_item.level) // separate items on topmost level
+ text_report += QChar::LineFeed;
+ item_value.fill(QChar::Space, tree_item.level * text_report_indent);
+ item_value.append(tree_item.item);
+ if (!tree_item.value.isEmpty())
+ {
+ item_value = item_value.leftJustified(max_item_length + 5, QChar::Space);
+ item_value.append(tree_item.value);
+ }
+ text_report += item_value + QChar::LineFeed;
+ }
+ return text_report;
+}
+
+// slot
+void MapInformationDialog::save()
+{
+ auto filepath = FileDialog::getSaveFileName(
+ this,
+ ::OpenOrienteering::MainWindow::tr("Save file"),
+ QFileInfo(main_window->currentPath()).canonicalPath(),
+ tr("Textfiles (*.txt)") );
+
+ if (filepath.isEmpty())
+ return;
+ if (!filepath.endsWith(QLatin1String(".txt"), Qt::CaseInsensitive))
+ filepath.append(QLatin1String(".txt"));
+
+ QSaveFile file(filepath);
+ if (file.open(QIODevice::WriteOnly | QIODevice::Text))
+ {
+ file.write(makeTextReport().toUtf8());
+ if (file.commit())
+ return;
+ }
+ QMessageBox::warning(this, tr("Error"),
+ tr("Cannot save file:\n%1\n\n%2")
+ .arg(filepath, file.errorString()) );
+}
+
+inline
+const QString MapInformationDialog::getFullSymbolName(const Symbol* symbol) const
+{
+ return (symbol->getNumberAsString() + QStringLiteral(" ") + symbol->getPlainTextName());
+}
+
+} // namespace OpenOrienteering
diff --git a/src/gui/map/map_information_dialog.h b/src/gui/map/map_information_dialog.h
new file mode 100644
index 000000000..b917635cf
--- /dev/null
+++ b/src/gui/map/map_information_dialog.h
@@ -0,0 +1,177 @@
+/*
+ * Copyright 2024 Matthias Kühlewein
+ *
+ * This file is part of OpenOrienteering.
+ *
+ * OpenOrienteering 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.
+ *
+ * OpenOrienteering 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 OpenOrienteering. If not, see .
+ */
+
+#ifndef OPENORIENTEERING_MAP_INFORMATION_DIALOG_H
+#define OPENORIENTEERING_MAP_INFORMATION_DIALOG_H
+
+#include
+#include
+
+#include
+#include
+#include
+
+class QTreeWidget;
+class QTreeWidgetItem;
+class QWidget;
+
+namespace OpenOrienteering {
+
+class Map;
+class MainWindow;
+class Symbol;
+
+/**
+ * A class for providing information about the current map.
+ *
+ * Information is given about the number of objects in total and per map part,
+ * the number of symbols, templates and undo/redo steps.
+ * For each color a list of symbols using that color is shown.
+ * All fonts (and their substitutions) being used by symbols are shown.
+ * For objects there is a hierarchical view:
+ * - the number of objects per symbol class (e.g., Point symbols, Line symbols etc.)
+ * - for each symbol class the symbols in use and the related number of objects
+ * - for each symbol the colors used by it
+ */
+class MapInformationDialog : public QDialog
+{
+Q_OBJECT
+public:
+ /**
+ * Creates a new MapInformationDialog object.
+ */
+ MapInformationDialog(MainWindow* parent, Map* map);
+
+ ~MapInformationDialog() override;
+
+private slots:
+ void save();
+
+private:
+ struct ItemNum {
+ QString name;
+ int num = 0;
+ };
+
+ struct FontNum {
+ QString name;
+ QString name_substitute; // the substituted font name, can be the same as 'name'
+ int num = 0;
+ };
+
+ struct SymbolNum {
+ const Symbol* symbol;
+ QString name;
+ int num;
+ std::vector colors;
+ };
+
+ struct ObjectCategory {
+ ItemNum category;
+ std::vector objects;
+ };
+
+ struct ColorUsage {
+ QString name;
+ std::vector symbols;
+ };
+
+ struct MapInfo {
+ int map_objects_num = 0;
+ int map_scale;
+ QString map_crs;
+ int map_parts_num;
+ std::vector map_parts;
+ int symbols_num;
+ int undo_steps_num;
+ int redo_steps_num;
+ int templates_num;
+ int colors_num;
+ std::vector colors;
+ int fonts_num;
+ std::vector font_names;
+ std::array map_objects;
+ } map_information;
+
+ struct TreeItem {
+ int level;
+ QString item;
+ QString value;
+ };
+
+ /**
+ * Retrieves the map information and stores it in the map_information structure.
+ */
+ void retrieveInformation();
+
+ /**
+ * For a given symbol:
+ * - Retrieves the symbol class and counts its objects.
+ * - Counts the objects.
+ * - Retrieves all colors.
+ */
+ void addSymbol(const Symbol* symbol);
+
+ /**
+ * Retrieves font (and its substitution) for a given text symbol and counts
+ * the font occurrence.
+ */
+ void addFont(const Symbol* symbol);
+
+ /**
+ * Creates the textual information from the stored information and
+ * puts it in the tree widget.
+ */
+ void buildTree();
+
+ /**
+ * Adds an item, its level and (in most cases) its value to the tree_items list and
+ * determines the maximum length of all (indented) items for creating a text report.
+ */
+ void addTreeItem(const int level, const QString& item, const QString& value = QString());
+
+ /**
+ * Processes tree_items list to hierarchically setup the tree widget.
+ */
+ void setupTreeWidget();
+
+ /**
+ * Processes tree_items list to create a text report.
+ */
+ QString makeTextReport() const;
+
+ /**
+ * Takes a pointer to a symbol and returns a string consisting of the symbol's number and name.
+ */
+ const QString getFullSymbolName(const Symbol* symbol) const;
+
+ const Map* map;
+ const MainWindow* main_window;
+
+ std::vector tree_items;
+ QTreeWidget* map_info_tree;
+ std::vector tree_item_hierarchy;
+
+ int max_item_length;
+ const int text_report_indent;
+};
+
+} // namespace OpenOrienteering
+
+#endif // OPENORIENTEERING_MAP_INFORMATION_DIALOG_H