From 839770e7c2d482f119a6a42afe6358eaf8958a8c Mon Sep 17 00:00:00 2001 From: Mustafa Comoglu Date: Mon, 13 Apr 2026 20:30:05 +1000 Subject: [PATCH 1/4] [scolv] Add Nearby Cities tab MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adds a Nearby Cities tab to scolv that lists cities and locations near the current origin, sorted by distance. The tab provides a convenient way to select a descriptive region name and set it on the event without leaving scolv. Cities are sourced exclusively from the built-in cities.xml via SCApp->cities(). The CityD struct has been extended in seiscomp/common (see feature/cityd-state-type) to carry type, state and stateFull attributes enriched from GeoNames and Natural Earth data. Features: - Table showing Name, Type, State, Country, Distance (km), Direction, Population and capital flag (★); capital cities rendered in bold - 16-point compass direction - Correct numeric sorting on Distance and Population columns - "Set as Region Name" button sets a REGION_NAME EventDescription on the current event via notifier to the EVENT messaging group - Five selectable region name format templates - "Full state name" toggle switches between stateFull and state Configuration (cities.* in scolv.cfg): maxDist Maximum search radius in km (default: 1000) maxCount Maximum cities displayed (default: 20) minPopulation Minimum population filter (default: 10000) useFullState Show full state name vs abbreviation (default: true) --- apps/gui-qt/scolv/descriptions/scolv.xml | 37 +++ apps/gui-qt/scolv/mainframe.cpp | 311 ++++++++++++++++++++++- apps/gui-qt/scolv/mainframe.h | 16 ++ apps/gui-qt/scolv/mainframe.ui | 177 +++++++++++++ 4 files changed, 539 insertions(+), 2 deletions(-) diff --git a/apps/gui-qt/scolv/descriptions/scolv.xml b/apps/gui-qt/scolv/descriptions/scolv.xml index d385e06e3..559fd2dc5 100644 --- a/apps/gui-qt/scolv/descriptions/scolv.xml +++ b/apps/gui-qt/scolv/descriptions/scolv.xml @@ -1028,6 +1028,43 @@ + + + Configuration of the Nearby Cities tab in scolv. The tab lists + cities and locations near the current origin, sorted by distance. + Cities are sourced from the built-in cities.xml (via SCApp) and + optionally from a user-supplied extended locations file. + + + + Maximum search radius in km around the origin. Cities beyond + this distance are not shown. + + + + + Maximum number of cities displayed. When more cities fall + within the search radius, the closest ones are kept. + + + + + Minimum population for a location to appear in the table. + Capital cities from cities.xml (category "C") are + always shown regardless of this threshold. Entries in the + extended locations file that have no population value (or + zero) are also always included. + + + + + When enabled, the full state or administrative region name is + shown in the State column (e.g. "New South Wales") instead + of the abbreviation (e.g. "NSW"). Requires cities.xml entries + to carry the stateFull attribute. + + + diff --git a/apps/gui-qt/scolv/mainframe.cpp b/apps/gui-qt/scolv/mainframe.cpp index 2f5d8dc60..39968020c 100644 --- a/apps/gui-qt/scolv/mainframe.cpp +++ b/apps/gui-qt/scolv/mainframe.cpp @@ -56,9 +56,16 @@ #include #include #include +#include + +#include +#include +#include #include #include +#include +#include //#include #define WITH_SMALL_SUMMARY @@ -137,6 +144,33 @@ string trim(const std::string &str) { } +// Numeric QTableWidgetItem so distance/population columns sort correctly +class NumericItem : public QTableWidgetItem { + public: + NumericItem(double value, const QString &text) + : QTableWidgetItem(text), _value(value) {} + + bool operator<(const QTableWidgetItem &other) const override { + const NumericItem *o = dynamic_cast(&other); + return o ? _value < o->_value : QTableWidgetItem::operator<(other); + } + private: + double _value; +}; + + +static const char *compassDir(double az) { + static const char *dirs[16] = { + "N","NNE","NE","ENE","E","ESE","SE","SSE", + "S","SSW","SW","WSW","W","WNW","NW","NNW" + }; + return dirs[static_cast((az + 11.25) / 22.5) % 16]; +} + + + + + } @@ -709,7 +743,7 @@ MainFrame::MainFrame(){ layoutMagnitudes->addWidget(_magnitudes); _tabEventEdit = new QWidget; - _ui.tabWidget->insertTab(_ui.tabWidget->count()-1, _tabEventEdit, "Event"); + _ui.tabWidget->insertTab(_ui.tabWidget->indexOf(_ui.tabNearbyCities), _tabEventEdit, "Event"); _eventEdit = new EventEdit(SCApp->query(), mapTree.get(), _tabEventEdit); QLayout* layoutEventEdit = new QVBoxLayout(_tabEventEdit); @@ -990,6 +1024,25 @@ MainFrame::MainFrame(){ } catch ( ... ) {} + // Nearby Cities config + try { _citiesMaxDist = SCApp->configGetDouble("cities.maxDist"); } catch ( ... ) {} + try { _citiesMaxCount = SCApp->configGetInt("cities.maxCount"); } catch ( ... ) {} + try { _citiesMinPopulation = SCApp->configGetInt("cities.minPopulation"); } catch ( ... ) {} + try { _citiesUseFullState = SCApp->configGetBool("cities.useFullState"); } catch ( ... ) {} + + _ui.citiesUseFullState->setChecked(_citiesUseFullState); + + connect(_ui.citiesTable->selectionModel(), + &QItemSelectionModel::selectionChanged, + this, &MainFrame::onCitySelectionChanged); + connect(_ui.setRegionBtn, &QPushButton::clicked, + this, &MainFrame::onSetRegionName); + connect(_ui.regionFormatCombo, + static_cast(&QComboBox::currentIndexChanged), + this, &MainFrame::onRegionFormatChanged); + connect(_ui.citiesUseFullState, &QCheckBox::toggled, + this, [this](bool){ updateCitiesTab(_currentOrigin.get()); }); + SCApp->settings().endGroup(); } @@ -1295,7 +1348,7 @@ void MainFrame::setOrigin(Seiscomp::DataModel::Origin *o, Seiscomp::DataModel::Event *e, bool newOrigin, bool relocated) { _currentOrigin = o; - _eventID = ""; + _eventID = e ? e->publicID() : ""; _magnitudes->setOrigin(o, e); @@ -1306,6 +1359,9 @@ void MainFrame::setOrigin(Seiscomp::DataModel::Origin *o, _eventSmallSummaryCurrent->setEvent(e, o, true); #endif + updateCitiesTab(o); + updateCurrentRegionLabel(e); + if ( newOrigin && relocated && _computeMagnitudesAutomatically && (o->magnitudeCount() == 0) ) _originLocator->computeMagnitudes(); } @@ -1348,6 +1404,9 @@ bool MainFrame::populateOrigin(Seiscomp::DataModel::Origin *org, Seiscomp::DataM #endif _eventEdit->setEvent(ev, org); + updateCitiesTab(org); + updateCurrentRegionLabel(ev); + return true; } @@ -1877,5 +1936,253 @@ void MainFrame::trayIconMessageClicked() { } + + +void MainFrame::updateCitiesTab(DataModel::Origin *origin) { + QTableWidget *t = _ui.citiesTable; + t->setSortingEnabled(false); + t->setRowCount(0); + _ui.regionPreview->clear(); + _ui.setRegionBtn->setEnabled(false); + + if ( !origin ) return; + + double originLat = origin->latitude().value(); + double originLon = origin->longitude().value(); + double maxDistDeg = Math::Geo::km2deg(_citiesMaxDist); + + struct Entry { + double distKm; + double az; + QString name; + QString type; + QString state; + QString country; + double population; + bool isCapital; + }; + std::vector entries; + + bool useFullState = _ui.citiesUseFullState->isChecked(); + + for ( const auto &city : SCApp->cities() ) { + double dist, az; + Math::Geo::delazi(originLat, originLon, city.lat, city.lon, + &dist, &az); + if ( dist > maxDistDeg ) continue; + + bool isCapital = city.category() == "C"; + if ( !isCapital && + static_cast(city.population()) < _citiesMinPopulation ) + continue; + + QString stateDisplay = (useFullState && !city.stateFull().empty()) + ? QString::fromStdString(city.stateFull()) + : QString::fromStdString(city.state()); + + entries.push_back({ + Math::Geo::deg2km(dist), az, + QString::fromStdString(city.name()), + QString::fromStdString(city.type()), + stateDisplay, + QString::fromStdString(city.countryID()), + city.population(), + isCapital + }); + } + + std::sort(entries.begin(), entries.end(), + [](const Entry &a, const Entry &b){ return a.distKm < b.distKm; }); + + if ( static_cast(entries.size()) > _citiesMaxCount ) + entries.resize(static_cast(_citiesMaxCount)); + + t->setRowCount(static_cast(entries.size())); + + for ( int i = 0; i < static_cast(entries.size()); ++i ) { + const Entry &e = entries[i]; + + auto boldify = [&](QTableWidgetItem *item) { + if ( e.isCapital ) { + QFont f = item->font(); + f.setBold(true); + item->setFont(f); + } + return item; + }; + + t->setItem(i, 0, boldify(new QTableWidgetItem(e.name))); + t->setItem(i, 1, boldify(new QTableWidgetItem(e.type))); + t->setItem(i, 2, boldify(new QTableWidgetItem(e.state))); + t->setItem(i, 3, boldify(new QTableWidgetItem(e.country))); + t->setItem(i, 4, boldify(new NumericItem( + e.distKm, QString::number(static_cast(e.distKm + 0.5))))); + t->setItem(i, 5, boldify(new QTableWidgetItem( + QString::fromLatin1(compassDir(e.az))))); + t->setItem(i, 6, boldify(new NumericItem( + e.population, + QString::number(static_cast(e.population))))); + + auto *capItem = new QTableWidgetItem( + e.isCapital ? QString("\u2605") : QString()); + capItem->setTextAlignment(Qt::AlignCenter); + t->setItem(i, 7, capItem); + } + + t->setSortingEnabled(true); + t->horizontalHeader()->resizeSections(QHeaderView::ResizeToContents); +} + + +void MainFrame::updateCurrentRegionLabel(DataModel::Event *event) { + if ( !event ) { + _ui.currentRegionLabel->setText(tr("Region: \u2014")); + return; + } + for ( size_t i = 0; i < event->eventDescriptionCount(); ++i ) { + auto *d = event->eventDescription(i); + if ( d->type() == DataModel::REGION_NAME ) { + _ui.currentRegionLabel->setText( + tr("Region: %1").arg(d->text().c_str())); + return; + } + } + _ui.currentRegionLabel->setText(tr("Region: \u2014")); +} + + +QString MainFrame::formatRegionName(const QString &name, const QString &state, + const QString &country, int distKm, + const QString &dir) const { + QString loc = !state.isEmpty() ? state : country; + + switch ( _ui.regionFormatCombo->currentIndex() ) { + case 0: return QString("%1 of %2%3") + .arg(dir, name, loc.isEmpty() ? "" : ", " + loc); + case 1: return QString("%1, %2 at %3 km") + .arg(name, dir).arg(distKm); + case 2: return QString("%1 km %2 of %3") + .arg(distKm).arg(dir, name); + case 3: return QString("%1 (%2, %3 km)") + .arg(name, dir).arg(distKm); + case 4: return QString("%1 km %2 of %3%4") + .arg(distKm).arg(dir, name, + loc.isEmpty() ? "" : ", " + loc); + default: return name; + } +} + + +void MainFrame::updateRegionPreview() { + int row = _ui.citiesTable->currentRow(); + if ( row < 0 ) { + _ui.regionPreview->clear(); + _ui.setRegionBtn->setEnabled(false); + return; + } + + auto cell = [&](int col) -> QString { + auto *item = _ui.citiesTable->item(row, col); + return item ? item->text() : QString(); + }; + + QString name = cell(0); + QString state = cell(2); + QString country = cell(3); + int distKm = static_cast(cell(4).toDouble() + 0.5); + QString dir = cell(5); + + _ui.regionPreview->setText( + formatRegionName(name, state, country, distKm, dir)); + _ui.setRegionBtn->setEnabled(!_eventID.empty()); +} + + +void MainFrame::onCitySelectionChanged() { + updateRegionPreview(); +} + + +void MainFrame::onRegionFormatChanged() { + updateRegionPreview(); +} + + +void MainFrame::onSetRegionName() { + QString regionText = _ui.regionPreview->text().trimmed(); + if ( regionText.isEmpty() ) return; + if ( _eventID.empty() ) { + QMessageBox::warning(this, tr("No Event"), + tr("No event is currently loaded.")); + return; + } + + if ( QMessageBox::question( + this, tr("Set Region Name"), + tr("Set region name for event %1 to:\n\n\"%2\"?") + .arg(_eventID.c_str(), regionText), + QMessageBox::Yes | QMessageBox::No) != QMessageBox::Yes ) + return; + + DataModel::EventPtr evt = DataModel::Event::Find(_eventID); + if ( !evt && SCApp->query() ) + evt = DataModel::Event::Cast( + SCApp->query()->loadObject( + DataModel::Event::TypeInfo(), _eventID)); + if ( !evt ) { + QMessageBox::critical(this, tr("Error"), + tr("Could not load event '%1'.") + .arg(_eventID.c_str())); + return; + } + + if ( SCApp->query() ) + SCApp->query()->loadEventDescriptions(evt.get()); + + DataModel::EventDescription *desc = nullptr; + DataModel::Operation op = DataModel::OP_ADD; + DataModel::EventDescriptionPtr newDesc; + + for ( size_t i = 0; i < evt->eventDescriptionCount(); ++i ) { + if ( evt->eventDescription(i)->type() == DataModel::REGION_NAME ) { + desc = evt->eventDescription(i); + op = DataModel::OP_UPDATE; + break; + } + } + + if ( !desc ) { + newDesc = new DataModel::EventDescription; + newDesc->setType(DataModel::REGION_NAME); + evt->add(newDesc.get()); + desc = newDesc.get(); + } + + desc->setText(regionText.toStdString()); + + DataModel::NotifierMessagePtr msg = new DataModel::NotifierMessage; + msg->attach(new DataModel::Notifier( + "EventParameters", DataModel::OP_UPDATE, evt.get())); + msg->attach(new DataModel::Notifier(evt->publicID(), op, desc)); + + if ( !SCApp->sendMessage(SCApp->messageGroups().event.c_str(), msg.get()) ) { + QMessageBox::critical(this, tr("Error"), + tr("Failed to send region name update.\n" + "Check messaging connection.")); + return; + } + + for ( DataModel::NotifierMessage::iterator it = msg->begin(); + it != msg->end(); ++it ) + SCApp->emitNotifier(it->get()); + + _ui.currentRegionLabel->setText(tr("Region: %1").arg(regionText)); + + QMessageBox::information(this, tr("Region Name Set"), + tr("Region name updated to:\n\"%1\"") + .arg(regionText)); +} + + } } diff --git a/apps/gui-qt/scolv/mainframe.h b/apps/gui-qt/scolv/mainframe.h index a99182787..f97df0e1e 100644 --- a/apps/gui-qt/scolv/mainframe.h +++ b/apps/gui-qt/scolv/mainframe.h @@ -32,6 +32,7 @@ namespace Seiscomp { namespace Gui { + class EventListView; class EventSummary; class EventEdit; @@ -64,6 +65,9 @@ class MainFrame : public MainWindow { private slots: void configureAcquisition(); + void onCitySelectionChanged(); + void onSetRegionName(); + void onRegionFormatChanged(); void messageAvailable(Seiscomp::Core::Message*, Seiscomp::Client::Packet*); @@ -95,6 +99,12 @@ class MainFrame : public MainWindow { private: bool populateOrigin(Seiscomp::DataModel::Origin*, Seiscomp::DataModel::Event*, bool); + void updateCitiesTab(Seiscomp::DataModel::Origin*); + void updateRegionPreview(); + void updateCurrentRegionLabel(Seiscomp::DataModel::Event*); + QString formatRegionName(const QString &name, const QString &state, + const QString &country, int distKm, + const QString &dir) const; // This creates an EventParameters instance containing copies // of all event attributes relevant for publication incl. @@ -132,6 +142,12 @@ class MainFrame : public MainWindow { bool _exportScriptTerminate; QWidget *_currentTabWidget; QProcess _exportProcess; + + // Nearby Cities tab + double _citiesMaxDist{1000.0}; + int _citiesMaxCount{20}; + int _citiesMinPopulation{10000}; + bool _citiesUseFullState{true}; }; diff --git a/apps/gui-qt/scolv/mainframe.ui b/apps/gui-qt/scolv/mainframe.ui index 7eb09a17b..75bc3481d 100644 --- a/apps/gui-qt/scolv/mainframe.ui +++ b/apps/gui-qt/scolv/mainframe.ui @@ -67,6 +67,183 @@ Magnitudes + + + Nearby Cities + + + + 4 + + + + + + + Full state name + + + Show full state name (e.g. Queensland) instead of abbreviation (e.g. QLD) + + + + + + + Qt::Horizontal + + + + + + + Region: — + + + + + + + + + QAbstractItemView::NoEditTriggers + + + QAbstractItemView::SelectRows + + + QAbstractItemView::SingleSelection + + + true + + + true + + + + Name + + + + + Type + + + + + State + + + + + Country + + + + + Distance (km) + + + + + Direction + + + + + Population + + + + + + + + + + + + + Set Region Name + + + + + + + + Format: + + + + + + + + DIRECTION of NAME, STATE + + + + + NAME, DIRECTION at DISTANCE km + + + + + DISTANCE km DIRECTION of NAME + + + + + NAME (DIRECTION, DISTANCE km) + + + + + DISTANCE km DIRECTION of NAME, STATE + + + + + + + + + + true + + + Select a city to preview the region name... + + + + + + + + + Qt::Horizontal + + + + + + + Set as Region Name + + + false + + + + + + + + + + Events From 2f35c18b3602d8a08a6c10943bd2fc0e9a8ac56c Mon Sep 17 00:00:00 2001 From: Mustafa Comoglu Date: Tue, 14 Apr 2026 07:46:44 +1000 Subject: [PATCH 2/4] [scolv] Update Nearby Cities tab for AdminRegion and country name - Use city.adminRegion() instead of deprecated state()/stateFull() - Fall back to city.country() in Region column when no admin region set - Rename column header "State" to "Region" - Update useFullState config description --- apps/gui-qt/scolv/descriptions/scolv.xml | 8 ++++---- apps/gui-qt/scolv/mainframe.cpp | 17 ++++++++++++----- apps/gui-qt/scolv/mainframe.ui | 2 +- 3 files changed, 17 insertions(+), 10 deletions(-) diff --git a/apps/gui-qt/scolv/descriptions/scolv.xml b/apps/gui-qt/scolv/descriptions/scolv.xml index 559fd2dc5..1b7fda05f 100644 --- a/apps/gui-qt/scolv/descriptions/scolv.xml +++ b/apps/gui-qt/scolv/descriptions/scolv.xml @@ -1058,10 +1058,10 @@ - When enabled, the full state or administrative region name is - shown in the State column (e.g. "New South Wales") instead - of the abbreviation (e.g. "NSW"). Requires cities.xml entries - to carry the stateFull attribute. + When enabled, the full administrative region name is shown in the + Region column (e.g. "New South Wales") instead of the + abbreviation (e.g. "NSW"). If no region is available, the + full country name is shown as fallback. diff --git a/apps/gui-qt/scolv/mainframe.cpp b/apps/gui-qt/scolv/mainframe.cpp index 39968020c..b0b34dd64 100644 --- a/apps/gui-qt/scolv/mainframe.cpp +++ b/apps/gui-qt/scolv/mainframe.cpp @@ -1976,16 +1976,23 @@ void MainFrame::updateCitiesTab(DataModel::Origin *origin) { static_cast(city.population()) < _citiesMinPopulation ) continue; - QString stateDisplay = (useFullState && !city.stateFull().empty()) - ? QString::fromStdString(city.stateFull()) - : QString::fromStdString(city.state()); + const auto ®ion = city.adminRegion(); + QString regionDisplay; + if ( !region.name.empty() ) + regionDisplay = useFullState + ? QString::fromStdString(region.name) + : (region.abbr.empty() + ? QString::fromStdString(region.name) + : QString::fromStdString(region.abbr)); + else + regionDisplay = QString::fromStdString(city.country()); entries.push_back({ Math::Geo::deg2km(dist), az, QString::fromStdString(city.name()), QString::fromStdString(city.type()), - stateDisplay, - QString::fromStdString(city.countryID()), + regionDisplay, + QString::fromStdString(city.country()), city.population(), isCapital }); diff --git a/apps/gui-qt/scolv/mainframe.ui b/apps/gui-qt/scolv/mainframe.ui index 75bc3481d..fb1c08918 100644 --- a/apps/gui-qt/scolv/mainframe.ui +++ b/apps/gui-qt/scolv/mainframe.ui @@ -132,7 +132,7 @@ - State + Region From a5d231eda64c19b196e999807ef62aa79f0cebeb Mon Sep 17 00:00:00 2001 From: Mustafa Comoglu Date: Thu, 30 Apr 2026 21:10:04 +1000 Subject: [PATCH 3/4] [scolv] Update type display for CityType enum city.type() now returns a CityType enum wrapper (MAKEENUM) rather than std::string following the change in SeisComP/common#189. --- apps/gui-qt/scolv/mainframe.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/gui-qt/scolv/mainframe.cpp b/apps/gui-qt/scolv/mainframe.cpp index b0b34dd64..356474722 100644 --- a/apps/gui-qt/scolv/mainframe.cpp +++ b/apps/gui-qt/scolv/mainframe.cpp @@ -1990,7 +1990,7 @@ void MainFrame::updateCitiesTab(DataModel::Origin *origin) { entries.push_back({ Math::Geo::deg2km(dist), az, QString::fromStdString(city.name()), - QString::fromStdString(city.type()), + QString(city.type().toString()), regionDisplay, QString::fromStdString(city.country()), city.population(), From 167da91304b743025c02dd8f679167161641e793 Mon Sep 17 00:00:00 2001 From: Mustafa Comoglu Date: Thu, 30 Apr 2026 21:23:41 +1000 Subject: [PATCH 4/4] [scolv] Robustness fixes for Nearby Cities tab - Guard _citiesMaxCount against zero/negative config value (default 20) - Use QOverload::of() for QComboBox signal (cleaner Qt5 syntax) - Show "-" instead of empty string for CITYTYPE_UNKNOWN in type column - Remove extra blank lines in anonymous namespace --- apps/gui-qt/scolv/mainframe.cpp | 7 +++---- apps/gui-qt/scolv/mainframe.h | 1 - 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/apps/gui-qt/scolv/mainframe.cpp b/apps/gui-qt/scolv/mainframe.cpp index 356474722..ec4f837c4 100644 --- a/apps/gui-qt/scolv/mainframe.cpp +++ b/apps/gui-qt/scolv/mainframe.cpp @@ -169,8 +169,6 @@ static const char *compassDir(double az) { - - } @@ -1027,6 +1025,7 @@ MainFrame::MainFrame(){ // Nearby Cities config try { _citiesMaxDist = SCApp->configGetDouble("cities.maxDist"); } catch ( ... ) {} try { _citiesMaxCount = SCApp->configGetInt("cities.maxCount"); } catch ( ... ) {} + if ( _citiesMaxCount <= 0 ) _citiesMaxCount = 20; try { _citiesMinPopulation = SCApp->configGetInt("cities.minPopulation"); } catch ( ... ) {} try { _citiesUseFullState = SCApp->configGetBool("cities.useFullState"); } catch ( ... ) {} @@ -1038,7 +1037,7 @@ MainFrame::MainFrame(){ connect(_ui.setRegionBtn, &QPushButton::clicked, this, &MainFrame::onSetRegionName); connect(_ui.regionFormatCombo, - static_cast(&QComboBox::currentIndexChanged), + QOverload::of(&QComboBox::currentIndexChanged), this, &MainFrame::onRegionFormatChanged); connect(_ui.citiesUseFullState, &QCheckBox::toggled, this, [this](bool){ updateCitiesTab(_currentOrigin.get()); }); @@ -1990,7 +1989,7 @@ void MainFrame::updateCitiesTab(DataModel::Origin *origin) { entries.push_back({ Math::Geo::deg2km(dist), az, QString::fromStdString(city.name()), - QString(city.type().toString()), + city.type() == Math::Geo::CITYTYPE_UNKNOWN ? QString("-") : QString(city.type().toString()), regionDisplay, QString::fromStdString(city.country()), city.population(), diff --git a/apps/gui-qt/scolv/mainframe.h b/apps/gui-qt/scolv/mainframe.h index f97df0e1e..362afe638 100644 --- a/apps/gui-qt/scolv/mainframe.h +++ b/apps/gui-qt/scolv/mainframe.h @@ -32,7 +32,6 @@ namespace Seiscomp { namespace Gui { - class EventListView; class EventSummary; class EventEdit;