diff --git a/ApplicationLibCode/Commands/OsduCommands/RiuWellImportWizard.cpp b/ApplicationLibCode/Commands/OsduCommands/RiuWellImportWizard.cpp index cbb94abc66..9d349bc6c6 100644 --- a/ApplicationLibCode/Commands/OsduCommands/RiuWellImportWizard.cpp +++ b/ApplicationLibCode/Commands/OsduCommands/RiuWellImportWizard.cpp @@ -18,16 +18,25 @@ #include "RiuWellImportWizard.h" +#include "RiaStringListSerializer.h" + #include #include #include +#include +#include +#include #include #include #include #include +// Static member definitions +const QString FieldSelectionPage::FIELD_SEARCH_HISTORY_KEY = "OsduWellImport/FieldSearchHistory"; +const QString WellSelectionPage::WELL_FILTER_HISTORY_KEY = "OsduWellImport/WellFilterHistory"; + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- @@ -158,6 +167,14 @@ void RiuWellImportWizard::addWellInfo( RiuWellImportWizard::WellInfo wellInfo ) m_wellInfos.push_back( wellInfo ); } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RiuWellImportWizard::clearWellInfos() +{ + m_wellInfos.clear(); +} + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- @@ -228,8 +245,11 @@ FieldSelectionPage::FieldSelectionPage( RiaOsduConnector* osduConnector, QWidget setLayout( layout ); QHBoxLayout* searchLayout = new QHBoxLayout; - m_searchTextEdit = new QLineEdit( this ); - searchLayout->addWidget( m_searchTextEdit ); + m_searchComboBox = new QComboBox( this ); + m_searchComboBox->setEditable( true ); + m_searchComboBox->setInsertPolicy( QComboBox::NoInsert ); + m_searchComboBox->setSizePolicy( QSizePolicy::Expanding, QSizePolicy::Fixed ); + searchLayout->addWidget( m_searchComboBox ); m_searchButton = new QPushButton( "Search", this ); m_searchButton->setEnabled( false ); @@ -263,8 +283,9 @@ FieldSelectionPage::FieldSelectionPage( RiaOsduConnector* osduConnector, QWidget m_osduConnector = osduConnector; connect( m_osduConnector, SIGNAL( fieldsFinished() ), SLOT( fieldsFinished() ) ); - connect( m_searchTextEdit, SIGNAL( textChanged( const QString& ) ), this, SLOT( onSearchTextChanged( const QString& ) ) ); - connect( m_searchTextEdit, SIGNAL( returnPressed() ), this, SLOT( searchForFields() ) ); + connect( m_searchComboBox->lineEdit(), SIGNAL( textChanged( const QString& ) ), this, SLOT( onSearchTextChanged( const QString& ) ) ); + connect( m_searchComboBox->lineEdit(), SIGNAL( returnPressed() ), this, SLOT( searchForFields() ) ); + connect( m_searchComboBox, SIGNAL( currentTextChanged( const QString& ) ), this, SLOT( onSearchTextChanged( const QString& ) ) ); connect( m_searchButton, SIGNAL( clicked() ), this, SLOT( searchForFields() ) ); @@ -275,6 +296,28 @@ FieldSelectionPage::FieldSelectionPage( RiaOsduConnector* osduConnector, QWidget connect( m_tableView->selectionModel(), SIGNAL( selectionChanged( const QItemSelection&, const QItemSelection& ) ), SIGNAL( completeChanged() ) ); + + // Load search history after all UI elements are created + { + RiaStringListSerializer serializer( FIELD_SEARCH_HISTORY_KEY ); + QStringList history = serializer.textStrings(); + + m_searchComboBox->clear(); + m_searchComboBox->addItems( history ); + + // Set the last used search term as default (first item in history) + if ( !history.isEmpty() ) + { + m_searchComboBox->setCurrentText( history.first() ); + // Enable search button if text meets minimum requirements + m_searchButton->setEnabled( history.first().length() >= MINIMUM_CHARACTERS_FOR_SEARCH ); + } + else + { + m_searchComboBox->setCurrentText( "" ); // Start with empty text if no history + m_searchButton->setEnabled( false ); + } + } } //-------------------------------------------------------------------------------------------------- @@ -292,8 +335,13 @@ void FieldSelectionPage::searchForFields() { RiuWellImportWizard* wiz = dynamic_cast( wizard() ); - QString text = m_searchTextEdit->text(); - if ( text.length() >= MINIMUM_CHARACTERS_FOR_SEARCH ) wiz->downloadFields( text ); + QString text = m_searchComboBox->currentText(); + if ( text.length() >= MINIMUM_CHARACTERS_FOR_SEARCH ) + { + RiaStringListSerializer serializer( FIELD_SEARCH_HISTORY_KEY ); + serializer.addString( text, 10 ); + wiz->downloadFields( text ); + } } //-------------------------------------------------------------------------------------------------- @@ -349,8 +397,11 @@ WellSelectionPage::WellSelectionPage( RiaOsduConnector* osduConnector, QWidget* QHBoxLayout* filterLayout = new QHBoxLayout; filterLayout->addWidget( new QLabel( "Filter:", this ) ); - QLineEdit* filterLineEdit = new QLineEdit( this ); - filterLayout->addWidget( filterLineEdit ); + m_filterComboBox = new QComboBox( this ); + m_filterComboBox->setEditable( true ); + m_filterComboBox->setInsertPolicy( QComboBox::NoInsert ); + m_filterComboBox->setSizePolicy( QSizePolicy::Expanding, QSizePolicy::Fixed ); + filterLayout->addWidget( m_filterComboBox ); layout->addLayout( filterLayout ); @@ -378,7 +429,20 @@ WellSelectionPage::WellSelectionPage( RiaOsduConnector* osduConnector, QWidget* header->setSectionResizeMode( nameColumn, QHeaderView::ResizeToContents ); header->setStretchLastSection( true ); - QObject::connect( filterLineEdit, &QLineEdit::textChanged, m_proxyModel, &QSortFilterProxyModel::setFilterWildcard ); + QObject::connect( m_filterComboBox->lineEdit(), &QLineEdit::textChanged, m_proxyModel, &QSortFilterProxyModel::setFilterWildcard ); + + // Add to history when text is entered and filter is applied + QObject::connect( m_filterComboBox->lineEdit(), + &QLineEdit::editingFinished, + [this]() + { + QString filterText = m_filterComboBox->currentText(); + if ( !filterText.isEmpty() && filterText.length() >= 2 ) // Minimum 2 characters for history + { + RiaStringListSerializer serializer( WELL_FILTER_HISTORY_KEY ); + serializer.addString( filterText, 10 ); + } + } ); m_osduConnector = osduConnector; connect( m_osduConnector, SIGNAL( wellboresByFieldIdFinished( const QString& ) ), SLOT( wellboresByFieldIdFinished( const QString& ) ) ); @@ -390,6 +454,34 @@ WellSelectionPage::WellSelectionPage( RiaOsduConnector* osduConnector, QWidget* connect( m_tableView->selectionModel(), SIGNAL( selectionChanged( const QItemSelection&, const QItemSelection& ) ), SIGNAL( completeChanged() ) ); + + // Load well filter history after all UI elements and proxy model are created + { + RiaStringListSerializer serializer( WELL_FILTER_HISTORY_KEY ); + QStringList history = serializer.textStrings(); + + m_filterComboBox->clear(); + m_filterComboBox->addItems( history ); + + // Set the last used filter as default (first item in history) + if ( !history.isEmpty() ) + { + m_filterComboBox->setCurrentText( history.first() ); + // Apply the filter to the proxy model + if ( m_proxyModel ) + { + m_proxyModel->setFilterWildcard( history.first() ); + } + } + else + { + m_filterComboBox->setCurrentText( "" ); // Start with empty text if no history + if ( m_proxyModel ) + { + m_proxyModel->setFilterWildcard( "" ); + } + } + } } //-------------------------------------------------------------------------------------------------- @@ -490,6 +582,20 @@ WellSummaryPage::WellSummaryPage( RiaOsduConnector* osduConnector, QWidget* pare QVBoxLayout* layout = new QVBoxLayout; setLayout( layout ); + // Existence Kind filter + QHBoxLayout* existenceFilterLayout = new QHBoxLayout; + existenceFilterLayout->addWidget( new QLabel( "Import:", this ) ); + + m_showAllRadioButton = new QRadioButton( "All", this ); + m_showActualRadioButton = new QRadioButton( "Actual only", this ); + m_showActualRadioButton->setChecked( true ); // Default to Actual only + + existenceFilterLayout->addWidget( m_showAllRadioButton ); + existenceFilterLayout->addWidget( m_showActualRadioButton ); + existenceFilterLayout->addStretch(); + + layout->addLayout( existenceFilterLayout ); + m_textEdit = new QTextEdit( this ); m_textEdit->setReadOnly( true ); layout->addWidget( m_textEdit ); @@ -499,6 +605,9 @@ WellSummaryPage::WellSummaryPage( RiaOsduConnector* osduConnector, QWidget* pare connect( m_osduConnector, SIGNAL( wellboreTrajectoryFinished( const QString&, int, const QString& ) ), SLOT( wellboreTrajectoryFinished( const QString&, int, const QString& ) ) ); + + connect( m_showAllRadioButton, SIGNAL( toggled( bool ) ), this, SLOT( onFilterChanged() ) ); + connect( m_showActualRadioButton, SIGNAL( toggled( bool ) ), this, SLOT( onFilterChanged() ) ); } //-------------------------------------------------------------------------------------------------- @@ -512,6 +621,7 @@ void WellSummaryPage::initializePage() QMutexLocker lock( &m_mutex ); m_pendingWellboreIds.clear(); + m_wellboreTrajectories.clear(); for ( const QString& wellboreId : wiz->selectedWellboreIds() ) { m_pendingWellboreIds.insert( wellboreId ); @@ -530,11 +640,12 @@ void WellSummaryPage::wellboreTrajectoryFinished( const QString& wellboreId, int { std::vector wellboreTrajectories = m_osduConnector->wellboreTrajectories( wellboreId ); - RiuWellImportWizard* wiz = dynamic_cast( wizard() ); - { QMutexLocker lock( &m_mutex ); + // Store trajectory data for filtering + m_wellboreTrajectories[wellboreId] = wellboreTrajectories; + std::optional wellbore = m_osduConnector->wellboreById( wellboreId ); if ( wellbore.has_value() ) { @@ -550,25 +661,108 @@ void WellSummaryPage::wellboreTrajectoryFinished( const QString& wellboreId, int { m_textEdit->append( QString( "Wellbore '%1': Found %2 trajectory(ies)." ).arg( wellbore.value().name ).arg( numTrajectories ) ); } - - for ( auto w : wellboreTrajectories ) - { - QString wellboreTrajectoryId = w.id; - wiz->addWellInfo( { .name = wellbore.value().name, - .wellId = wellbore.value().wellId, - .wellboreId = w.wellboreId, - .wellboreTrajectoryId = wellboreTrajectoryId, - .existenceKind = w.existenceKind, - .datumElevation = wellbore.value().datumElevation } ); - } } m_pendingWellboreIds.erase( wellboreId ); } + // Update the display after data is loaded + if ( m_pendingWellboreIds.empty() ) + { + updateSummaryDisplay(); + } + emit( completeChanged() ); } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void WellSummaryPage::onFilterChanged() +{ + if ( m_pendingWellboreIds.empty() ) + { + updateSummaryDisplay(); + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void WellSummaryPage::updateSummaryDisplay() +{ + RiuWellImportWizard* wiz = dynamic_cast( wizard() ); + if ( !wiz ) return; + + // Clear the text display + m_textEdit->clear(); + + // Clear existing well infos and rebuild based on current filter + wiz->clearWellInfos(); + + QMutexLocker lock( &m_mutex ); + + for ( const auto& [wellboreId, trajectories] : m_wellboreTrajectories ) + { + std::optional wellbore = m_osduConnector->wellboreById( wellboreId ); + if ( wellbore.has_value() ) + { + int includedCount = 0; + for ( const auto& w : trajectories ) + { + if ( shouldIncludeTrajectory( w.existenceKind ) ) + { + QString wellboreTrajectoryId = w.id; + wiz->addWellInfo( { .name = wellbore.value().name, + .wellId = wellbore.value().wellId, + .wellboreId = w.wellboreId, + .wellboreTrajectoryId = wellboreTrajectoryId, + .existenceKind = w.existenceKind, + .datumElevation = wellbore.value().datumElevation } ); + includedCount++; + } + } + + // Show trajectory count and filtering info + if ( m_showActualRadioButton->isChecked() ) + { + if ( includedCount != static_cast( trajectories.size() ) ) + { + m_textEdit->append( QString( "Wellbore '%1': Found %2 trajectory(ies), %3 included after filtering." ) + .arg( wellbore.value().name ) + .arg( trajectories.size() ) + .arg( includedCount ) ); + } + else + { + m_textEdit->append( QString( "Wellbore '%1': Found %2 trajectory(ies) (all match filter)." ) + .arg( wellbore.value().name ) + .arg( trajectories.size() ) ); + } + } + else + { + m_textEdit->append( + QString( "Wellbore '%1': Found %2 trajectory(ies)." ).arg( wellbore.value().name ).arg( trajectories.size() ) ); + } + } + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool WellSummaryPage::shouldIncludeTrajectory( const QString& existenceKind ) const +{ + if ( m_showActualRadioButton->isChecked() ) + { + // Match the OSDU format: "data:reference-data--ExistenceKind:Actual:" + return existenceKind.contains( ":Actual:", Qt::CaseInsensitive ); + } + + return true; +} + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- diff --git a/ApplicationLibCode/Commands/OsduCommands/RiuWellImportWizard.h b/ApplicationLibCode/Commands/OsduCommands/RiuWellImportWizard.h index 608864fb39..11d866d304 100644 --- a/ApplicationLibCode/Commands/OsduCommands/RiuWellImportWizard.h +++ b/ApplicationLibCode/Commands/OsduCommands/RiuWellImportWizard.h @@ -34,6 +34,8 @@ class QFile; class QLabel; class QTextEdit; class QTableView; +class QRadioButton; +class QComboBox; class OsduFieldTableModel : public QAbstractTableModel { Q_OBJECT @@ -299,9 +301,10 @@ private slots: void searchForFields(); private: - static const int MINIMUM_CHARACTERS_FOR_SEARCH = 3; + static const int MINIMUM_CHARACTERS_FOR_SEARCH = 3; + static const QString FIELD_SEARCH_HISTORY_KEY; - QLineEdit* m_searchTextEdit; + QComboBox* m_searchComboBox; QPushButton* m_searchButton; RiaOsduConnector* m_osduConnector; QTableView* m_tableView; @@ -327,10 +330,13 @@ private slots: void selectWellbore( const QItemSelection& newSelection, const QItemSelection& oldSelection ); private: + static const QString WELL_FILTER_HISTORY_KEY; + RiaOsduConnector* m_osduConnector; QTableView* m_tableView; OsduWellboreTableModel* m_osduWellboresModel; QSortFilterProxyModel* m_proxyModel; + QComboBox* m_filterComboBox; }; //-------------------------------------------------------------------------------------------------- @@ -348,12 +354,19 @@ public: private slots: void wellboreTrajectoryFinished( const QString& wellboreId, int numTrajectories, const QString& errorMessage ); + void onFilterChanged(); private: - RiaOsduConnector* m_osduConnector; - QTextEdit* m_textEdit; - std::set m_pendingWellboreIds; - mutable QMutex m_mutex; + bool shouldIncludeTrajectory( const QString& existenceKind ) const; + void updateSummaryDisplay(); + + RiaOsduConnector* m_osduConnector; + QTextEdit* m_textEdit; + QRadioButton* m_showAllRadioButton; + QRadioButton* m_showActualRadioButton; + std::set m_pendingWellboreIds; + std::map> m_wellboreTrajectories; + mutable QMutex m_mutex; }; //-------------------------------------------------------------------------------------------------- @@ -386,6 +399,7 @@ public: std::vector selectedWellboreIds() const; void addWellInfo( RiuWellImportWizard::WellInfo wellInfo ); + void clearWellInfos(); std::vector importedWells() const; public slots: