From bac210d39b1b508f017f4c8d356cfec42eaca0d0 Mon Sep 17 00:00:00 2001 From: Kristian Bendiksen Date: Wed, 28 Feb 2024 08:10:52 +0100 Subject: [PATCH] Add support for well paths from OSDU. --- .../Application/CMakeLists_files.cmake | 5 + .../Application/RiaFileDownloader.cpp | 54 + .../Application/RiaFileDownloader.h | 16 + .../Application/RiaPreferences.cpp | 24 + .../Application/RiaPreferences.h | 7 + .../Application/RiaPreferencesOsdu.cpp | 84 ++ .../Application/RiaPreferencesOsdu.h | 48 + ApplicationLibCode/CMakeLists.txt | 2 + .../OsduImportCommands/CMakeLists_files.cmake | 7 +- .../OsduImportCommands/RiaOsduConnector.cpp | 654 +++++++++++ .../OsduImportCommands/RiaOsduConnector.h | 131 +++ .../RiaOsduOAuthHttpServerReplyHandler.cpp | 24 + .../RiaOsduOAuthHttpServerReplyHandler.h | 39 + .../RicWellPathsImportOsduFeature.cpp | 115 +- .../RicWellPathsImportOsduFeature.h | 2 +- .../OsduImportCommands/RimWellPathImport.cpp | 159 +-- .../OsduImportCommands/RimWellPathImport.h | 12 +- .../RiuWellImportWizard.cpp | 1046 +++-------------- .../OsduImportCommands/RiuWellImportWizard.h | 347 +++--- .../FileInterface/CMakeLists_files.cmake | 2 + .../FileInterface/RifOsduWellPathReader.cpp | 92 ++ .../FileInterface/RifOsduWellPathReader.h | 35 + .../RimContextCommandBuilder.cpp | 2 +- .../ProjectDataModel/RimProject.cpp | 3 - .../WellPath/CMakeLists_files.cmake | 2 + .../WellPath/RimOsduWellPath.cpp | 110 ++ .../WellPath/RimOsduWellPath.h | 50 + .../WellPath/RimWellPathCollection.cpp | 47 + .../WellPath/RimWellPathCollection.h | 3 + ApplicationLibCode/UnitTests/CMakeLists.txt | 1 + .../UnitTests/RifOsduWellPathReader-Test.cpp | 59 + .../UserInterface/RiuMenuBarBuildTools.cpp | 2 +- CMakeLists.txt | 3 +- 33 files changed, 1960 insertions(+), 1227 deletions(-) create mode 100644 ApplicationLibCode/Application/RiaFileDownloader.cpp create mode 100644 ApplicationLibCode/Application/RiaFileDownloader.h create mode 100644 ApplicationLibCode/Application/RiaPreferencesOsdu.cpp create mode 100644 ApplicationLibCode/Application/RiaPreferencesOsdu.h create mode 100644 ApplicationLibCode/Commands/OsduImportCommands/RiaOsduConnector.cpp create mode 100644 ApplicationLibCode/Commands/OsduImportCommands/RiaOsduConnector.h create mode 100644 ApplicationLibCode/Commands/OsduImportCommands/RiaOsduOAuthHttpServerReplyHandler.cpp create mode 100644 ApplicationLibCode/Commands/OsduImportCommands/RiaOsduOAuthHttpServerReplyHandler.h create mode 100644 ApplicationLibCode/FileInterface/RifOsduWellPathReader.cpp create mode 100644 ApplicationLibCode/FileInterface/RifOsduWellPathReader.h create mode 100644 ApplicationLibCode/ProjectDataModel/WellPath/RimOsduWellPath.cpp create mode 100644 ApplicationLibCode/ProjectDataModel/WellPath/RimOsduWellPath.h create mode 100644 ApplicationLibCode/UnitTests/RifOsduWellPathReader-Test.cpp diff --git a/ApplicationLibCode/Application/CMakeLists_files.cmake b/ApplicationLibCode/Application/CMakeLists_files.cmake index ed89dbc257c..f8745d79acf 100644 --- a/ApplicationLibCode/Application/CMakeLists_files.cmake +++ b/ApplicationLibCode/Application/CMakeLists_files.cmake @@ -9,6 +9,7 @@ set(SOURCE_GROUP_HEADER_FILES ${CMAKE_CURRENT_LIST_DIR}/RiaPreferencesSummary.h ${CMAKE_CURRENT_LIST_DIR}/RiaPreferencesGeoMech.h ${CMAKE_CURRENT_LIST_DIR}/RiaPreferencesSystem.h + ${CMAKE_CURRENT_LIST_DIR}/RiaPreferencesOsdu.h ${CMAKE_CURRENT_LIST_DIR}/RiaPorosityModel.h ${CMAKE_CURRENT_LIST_DIR}/RiaSummaryCurveDefinition.h ${CMAKE_CURRENT_LIST_DIR}/RiaCurveSetDefinition.h @@ -35,6 +36,7 @@ set(SOURCE_GROUP_HEADER_FILES ${CMAKE_CURRENT_LIST_DIR}/RiaLasDefines.h ${CMAKE_CURRENT_LIST_DIR}/RiaWellFlowDefines.h ${CMAKE_CURRENT_LIST_DIR}/RiaSummaryCurveAddress.h + ${CMAKE_CURRENT_LIST_DIR}/RiaFileDownloader.h ) set(SOURCE_GROUP_SOURCE_FILES @@ -48,6 +50,7 @@ set(SOURCE_GROUP_SOURCE_FILES ${CMAKE_CURRENT_LIST_DIR}/RiaPreferencesSummary.cpp ${CMAKE_CURRENT_LIST_DIR}/RiaPreferencesGeoMech.cpp ${CMAKE_CURRENT_LIST_DIR}/RiaPreferencesSystem.cpp + ${CMAKE_CURRENT_LIST_DIR}/RiaPreferencesOsdu.cpp ${CMAKE_CURRENT_LIST_DIR}/RiaPorosityModel.cpp ${CMAKE_CURRENT_LIST_DIR}/RiaSummaryCurveDefinition.cpp ${CMAKE_CURRENT_LIST_DIR}/RiaCurveSetDefinition.cpp @@ -74,6 +77,7 @@ set(SOURCE_GROUP_SOURCE_FILES ${CMAKE_CURRENT_LIST_DIR}/RiaLasDefines.cpp ${CMAKE_CURRENT_LIST_DIR}/RiaWellFlowDefines.cpp ${CMAKE_CURRENT_LIST_DIR}/RiaSummaryCurveAddress.cpp + ${CMAKE_CURRENT_LIST_DIR}/RiaFileDownloader.cpp ) list(APPEND CODE_HEADER_FILES ${SOURCE_GROUP_HEADER_FILES}) @@ -87,6 +91,7 @@ set(QT_MOC_HEADERS ${CMAKE_CURRENT_LIST_DIR}/RiaCompletionTypeCalculationScheduler.h ${CMAKE_CURRENT_LIST_DIR}/RiaPlotWindowRedrawScheduler.h ${CMAKE_CURRENT_LIST_DIR}/RiaScheduler.h + ${CMAKE_CURRENT_LIST_DIR}/RiaFileDownloader.h ) source_group( diff --git a/ApplicationLibCode/Application/RiaFileDownloader.cpp b/ApplicationLibCode/Application/RiaFileDownloader.cpp new file mode 100644 index 00000000000..8fbcd5b30a9 --- /dev/null +++ b/ApplicationLibCode/Application/RiaFileDownloader.cpp @@ -0,0 +1,54 @@ +#include "RiaFileDownloader.h" + +#include +#include +#include +#include +#include +#include + +#include "RiaLogging.h" + +RiaFileDownloader::RiaFileDownloader( QObject* parent ) + : QObject( parent ) +{ +} + +void RiaFileDownloader::downloadFile( const QUrl& url, const QString& filePath ) +{ + QNetworkAccessManager* manager = new QNetworkAccessManager( this ); + QNetworkRequest request( url ); + + RiaLogging::debug( "Downloading from: " + url.toString() ); + + QNetworkReply* reply = manager->get( request ); + + connect( reply, + &QNetworkReply::finished, + [=]() + { + if ( reply->error() ) + { + RiaLogging::error( "Download failed:" + reply->errorString() ); + emit done(); + } + else + { + QFile file( filePath ); + if ( file.open( QIODevice::WriteOnly ) ) + { + file.write( reply->readAll() ); + file.close(); + RiaLogging::info( "Download succeeded. File saved to " + filePath ); + emit done(); + } + else + { + RiaLogging::info( "Failed to save file to " + filePath ); + emit done(); + } + } + reply->deleteLater(); + manager->deleteLater(); + } ); +} diff --git a/ApplicationLibCode/Application/RiaFileDownloader.h b/ApplicationLibCode/Application/RiaFileDownloader.h new file mode 100644 index 00000000000..a29cfe423bc --- /dev/null +++ b/ApplicationLibCode/Application/RiaFileDownloader.h @@ -0,0 +1,16 @@ +#pragma once + +#include +#include +#include + +class RiaFileDownloader : public QObject +{ + Q_OBJECT +public: + explicit RiaFileDownloader( QObject* parent = nullptr ); + + void downloadFile( const QUrl& url, const QString& filePath ); +signals: + void done(); +}; diff --git a/ApplicationLibCode/Application/RiaPreferences.cpp b/ApplicationLibCode/Application/RiaPreferences.cpp index 1f0269778fd..eb2bbee2f18 100644 --- a/ApplicationLibCode/Application/RiaPreferences.cpp +++ b/ApplicationLibCode/Application/RiaPreferences.cpp @@ -279,6 +279,9 @@ RiaPreferences::RiaPreferences() CAF_PDM_InitFieldNoDefault( &m_systemPreferences, "systemPreferences", "systemPreferences" ); m_systemPreferences = new RiaPreferencesSystem; + + CAF_PDM_InitFieldNoDefault( &m_osduPreferences, "osduPreferences", "osduPreferences" ); + m_osduPreferences = new RiaPreferencesOsdu; } //-------------------------------------------------------------------------------------------------- @@ -487,6 +490,10 @@ void RiaPreferences::defineUiOrdering( QString uiConfigName, caf::PdmUiOrdering& m_loggerTrapSignalAndFlush.uiCapability()->setUiReadOnly( !m_loggerFilename().first ); m_loggerFlushInterval.uiCapability()->setUiReadOnly( !m_loggerFilename().first ); } + else if ( uiConfigName == RiaPreferences::tabNameOsdu() ) + { + m_osduPreferences()->uiOrdering( uiConfigName, uiOrdering ); + } else if ( RiaApplication::enableDevelopmentFeatures() && uiConfigName == RiaPreferences::tabNameSystem() ) { m_systemPreferences()->uiOrdering( uiConfigName, uiOrdering ); @@ -614,6 +621,14 @@ QString RiaPreferences::tabNameSystem() return "System"; } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QString RiaPreferences::tabNameOsdu() +{ + return "Osdu"; +} + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- @@ -654,6 +669,7 @@ QStringList RiaPreferences::tabNames() names << tabNameGeomech(); #endif names << tabNameImportExport(); + names << tabNameOsdu(); if ( RiaApplication::enableDevelopmentFeatures() ) { @@ -1018,6 +1034,14 @@ RiaPreferencesGeoMech* RiaPreferences::geoMechPreferences() const return m_geoMechPreferences(); } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RiaPreferencesOsdu* RiaPreferences::osduPreferences() const +{ + return m_osduPreferences(); +} + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- diff --git a/ApplicationLibCode/Application/RiaPreferences.h b/ApplicationLibCode/Application/RiaPreferences.h index 78f6d283c8a..4221c332e8e 100644 --- a/ApplicationLibCode/Application/RiaPreferences.h +++ b/ApplicationLibCode/Application/RiaPreferences.h @@ -25,6 +25,7 @@ #include "RiaDefines.h" #include "RiaFontCache.h" +#include "RiaPreferencesOsdu.h" #include "cafAppEnum.h" #include "cafPdmChildField.h" #include "cafPdmField.h" @@ -43,6 +44,7 @@ class RifReaderSettings; class RiaPreferencesSummary; class RiaPreferencesGeoMech; class RiaPreferencesSystem; +class RiaPreferencesOsdu; //-------------------------------------------------------------------------------------------------- /// @@ -125,6 +127,7 @@ class RiaPreferences : public caf::PdmObject RiaPreferencesGeoMech* geoMechPreferences() const; RiaPreferencesSummary* summaryPreferences() const; RiaPreferencesSystem* systemPreferences() const; + RiaPreferencesOsdu* osduPreferences() const; public: caf::PdmField enableGrpcServer; @@ -170,6 +173,7 @@ class RiaPreferences : public caf::PdmObject static QString tabNamePlotting(); static QString tabNameScripting(); static QString tabNameSystem(); + static QString tabNameOsdu(); static QString tabNameImportExport(); static double defaultMarginSize( QPageSize::PageSizeId pageSizeId ); @@ -230,6 +234,9 @@ class RiaPreferences : public caf::PdmObject // System settings caf::PdmChildField m_systemPreferences; + // Osdu settings + caf::PdmChildField m_osduPreferences; + // 3d view caf::PdmField> m_defaultMeshModeType; caf::PdmField> m_navigationPolicy; diff --git a/ApplicationLibCode/Application/RiaPreferencesOsdu.cpp b/ApplicationLibCode/Application/RiaPreferencesOsdu.cpp new file mode 100644 index 00000000000..941390f3456 --- /dev/null +++ b/ApplicationLibCode/Application/RiaPreferencesOsdu.cpp @@ -0,0 +1,84 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2024 Equinor ASA +// +// ResInsight 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. +// +// ResInsight 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 at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#include "RiaApplication.h" + +#include "RiaPreferences.h" +#include "RiaPreferencesOsdu.h" + +CAF_PDM_SOURCE_INIT( RiaPreferencesOsdu, "RiaPreferencesOsdu" ); + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RiaPreferencesOsdu::RiaPreferencesOsdu() +{ + CAF_PDM_InitFieldNoDefault( &m_server, "server", "Server" ); + CAF_PDM_InitFieldNoDefault( &m_dataPartitionId, "dataPartitionId", "Data Partition Id" ); + CAF_PDM_InitFieldNoDefault( &m_authority, "authority", "Authority" ); + CAF_PDM_InitFieldNoDefault( &m_scopes, "scopes", "Scopes" ); + CAF_PDM_InitFieldNoDefault( &m_clientId, "clientId", "Client Id" ); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RiaPreferencesOsdu* RiaPreferencesOsdu::current() +{ + return RiaApplication::instance()->preferences()->osduPreferences(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QString RiaPreferencesOsdu::server() const +{ + return m_server; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QString RiaPreferencesOsdu::dataPartitionId() const +{ + return m_dataPartitionId; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QString RiaPreferencesOsdu::authority() const +{ + return m_authority; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QString RiaPreferencesOsdu::scopes() const +{ + return m_scopes; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QString RiaPreferencesOsdu::clientId() const +{ + return m_clientId; +} diff --git a/ApplicationLibCode/Application/RiaPreferencesOsdu.h b/ApplicationLibCode/Application/RiaPreferencesOsdu.h new file mode 100644 index 00000000000..6a0643b082d --- /dev/null +++ b/ApplicationLibCode/Application/RiaPreferencesOsdu.h @@ -0,0 +1,48 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2024 Equinor ASA +// +// ResInsight 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. +// +// ResInsight 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 at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#pragma once + +#include "cafPdmField.h" +#include "cafPdmObject.h" + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +class RiaPreferencesOsdu : public caf::PdmObject +{ + CAF_PDM_HEADER_INIT; + +public: + RiaPreferencesOsdu(); + + static RiaPreferencesOsdu* current(); + + QString server() const; + QString dataPartitionId() const; + QString authority() const; + QString scopes() const; + QString clientId() const; + +private: + caf::PdmField m_server; + caf::PdmField m_dataPartitionId; + caf::PdmField m_authority; + caf::PdmField m_scopes; + caf::PdmField m_clientId; +}; diff --git a/ApplicationLibCode/CMakeLists.txt b/ApplicationLibCode/CMakeLists.txt index 67ad84624ba..01d647af090 100644 --- a/ApplicationLibCode/CMakeLists.txt +++ b/ApplicationLibCode/CMakeLists.txt @@ -32,6 +32,7 @@ if(Qt5Core_FOUND) Gui OpenGL Network + NetworkAuth Widgets Xml Concurrent @@ -44,6 +45,7 @@ if(Qt5Core_FOUND) Qt5::Core Qt5::Gui Qt5::Network + Qt5::NetworkAuth Qt5::OpenGL Qt5::Widgets Qt5::Xml diff --git a/ApplicationLibCode/Commands/OsduImportCommands/CMakeLists_files.cmake b/ApplicationLibCode/Commands/OsduImportCommands/CMakeLists_files.cmake index e4c129fb5b5..af4c5c046d4 100644 --- a/ApplicationLibCode/Commands/OsduImportCommands/CMakeLists_files.cmake +++ b/ApplicationLibCode/Commands/OsduImportCommands/CMakeLists_files.cmake @@ -5,6 +5,8 @@ set(SOURCE_GROUP_HEADER_FILES ${CMAKE_CURRENT_LIST_DIR}/RimWellPathImport.h ${CMAKE_CURRENT_LIST_DIR}/RimWellsEntry.h ${CMAKE_CURRENT_LIST_DIR}/RiuWellImportWizard.h + ${CMAKE_CURRENT_LIST_DIR}/RiaOsduOAuthHttpServerReplyHandler.h + ${CMAKE_CURRENT_LIST_DIR}/RiaOsduConnector.h ) set(SOURCE_GROUP_SOURCE_FILES @@ -14,14 +16,17 @@ set(SOURCE_GROUP_SOURCE_FILES ${CMAKE_CURRENT_LIST_DIR}/RimWellPathImport.cpp ${CMAKE_CURRENT_LIST_DIR}/RimWellsEntry.cpp ${CMAKE_CURRENT_LIST_DIR}/RiuWellImportWizard.cpp + ${CMAKE_CURRENT_LIST_DIR}/RiaOsduOAuthHttpServerReplyHandler.cpp + ${CMAKE_CURRENT_LIST_DIR}/RiaOsduConnector.cpp ) list(APPEND COMMAND_CODE_HEADER_FILES ${SOURCE_GROUP_HEADER_FILES}) list(APPEND COMMAND_CODE_SOURCE_FILES ${SOURCE_GROUP_SOURCE_FILES}) -list(APPEND COMMAND_QT_MOC_HEADERS +list(APPEND COMMAND_QT_MOC_HEADERS ${CMAKE_CURRENT_LIST_DIR}/RiaOsduConnector.h ${CMAKE_CURRENT_LIST_DIR}/RiuWellImportWizard.h + ${CMAKE_CURRENT_LIST_DIR}/RiaOsduOAuthHttpServerReplyHandler.h ) source_group( diff --git a/ApplicationLibCode/Commands/OsduImportCommands/RiaOsduConnector.cpp b/ApplicationLibCode/Commands/OsduImportCommands/RiaOsduConnector.cpp new file mode 100644 index 00000000000..8e364434e52 --- /dev/null +++ b/ApplicationLibCode/Commands/OsduImportCommands/RiaOsduConnector.cpp @@ -0,0 +1,654 @@ +#include "RiaOsduConnector.h" +#include "RiaFileDownloader.h" +#include "RiaLogging.h" +#include "RiaOsduOAuthHttpServerReplyHandler.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static const QString FIELD_KIND = "osdu:wks:master-data--Field:1.0.0"; +static const QString WELL_KIND = "osdu:wks:master-data--Well:1.2.0"; +static const QString WELLBORE_KIND = "osdu:wks:master-data--Wellbore:1.1.0"; +static const QString WELLBORE_TRAJECTORY_KIND = "osdu:wks:work-product-component--WellboreTrajectory:1.1.0"; + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RiaOsduConnector::RiaOsduConnector( QObject* parent, + const QString& server, + const QString& dataPartitionId, + const QString& authority, + const QString& scopes, + const QString& clientId ) + : QObject( parent ) + , m_server( server ) + , m_dataPartitionId( dataPartitionId ) + , m_authority( authority ) + , m_scopes( scopes ) + , m_clientId( clientId ) +{ + m_networkAccessManager = new QNetworkAccessManager( this ); + + m_osdu = new QOAuth2AuthorizationCodeFlow( this ); + + RiaLogging::debug( "SSL BUILD VERSION: " + QSslSocket::sslLibraryBuildVersionString() ); + RiaLogging::debug( "SSL VERSION STRING: " + QSslSocket::sslLibraryVersionString() ); + + int port = 35327; + + connect( m_osdu, + &QOAuth2AuthorizationCodeFlow::authorizeWithBrowser, + []( QUrl url ) + { + RiaLogging::info( "Authorize with url: " + url.toString() ); + QUrlQuery query( url ); + url.setQuery( query ); + QDesktopServices::openUrl( url ); + } ); + + QString authUrl = constructAuthUrl( m_authority ); + m_osdu->setAuthorizationUrl( QUrl( authUrl ) ); + + QString tokenUrl = constructTokenUrl( m_authority ); + m_osdu->setAccessTokenUrl( QUrl( tokenUrl ) ); + + // App key + m_osdu->setClientIdentifier( m_clientId ); + m_osdu->setScope( m_scopes ); + + auto replyHandler = new RiaOsduOAuthHttpServerReplyHandler( port, this ); + m_osdu->setReplyHandler( replyHandler ); + + connect( m_osdu, SIGNAL( granted() ), this, SLOT( accessGranted() ) ); +} + +void RiaOsduConnector::accessGranted() +{ + m_token = m_osdu->token(); + emit tokenReady( m_token ); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RiaOsduConnector::requestToken() +{ + RiaLogging::debug( "Requesting token." ); + m_osdu->grant(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RiaOsduConnector::~RiaOsduConnector() +{ +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RiaOsduConnector::requestFieldsByName( const QString& token, const QString& fieldName ) +{ + requestFieldsByName( m_server, m_dataPartitionId, token, fieldName ); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RiaOsduConnector::requestFieldsByName( const QString& fieldName ) +{ + requestFieldsByName( m_token, fieldName ); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RiaOsduConnector::requestFieldsByName( const QString& server, const QString& dataPartitionId, const QString& token, const QString& fieldName ) +{ + std::map params; + params["kind"] = FIELD_KIND; + params["limit"] = "10000"; + params["query"] = "data.FieldName:" + fieldName; + + auto reply = makeRequest( params, server, dataPartitionId, token ); + connect( reply, + &QNetworkReply::finished, + [this, reply]() + { + if ( reply->error() == QNetworkReply::NoError ) + { + parseFields( reply ); + } + } ); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RiaOsduConnector::requestWellsByFieldId( const QString& fieldId ) +{ + requestWellsByFieldId( m_server, m_dataPartitionId, m_token, fieldId ); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RiaOsduConnector::requestWellsByFieldId( const QString& server, const QString& dataPartitionId, const QString& token, const QString& fieldId ) +{ + std::map params; + params["kind"] = WELL_KIND; + params["limit"] = "10000"; + params["query"] = QString( "nested(data.GeoContexts, (FieldID:\"%1\"))" ).arg( fieldId ); + + auto reply = makeRequest( params, server, dataPartitionId, token ); + connect( reply, + &QNetworkReply::finished, + [this, reply, fieldId]() + { + if ( reply->error() == QNetworkReply::NoError ) + { + parseWells( reply ); + } + } ); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RiaOsduConnector::requestWellboresByWellId( const QString& wellId ) +{ + requestWellboresByWellId( m_server, m_dataPartitionId, m_token, wellId ); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RiaOsduConnector::requestWellboresByWellId( const QString& server, const QString& dataPartitionId, const QString& token, const QString& wellId ) +{ + std::map params; + params["kind"] = WELLBORE_KIND; + params["limit"] = "10000"; + params["query"] = "data.WellID: \"" + wellId + "\""; + + auto reply = makeRequest( params, server, dataPartitionId, token ); + connect( reply, + &QNetworkReply::finished, + [this, reply, wellId]() + { + if ( reply->error() == QNetworkReply::NoError ) + { + parseWellbores( reply, wellId ); + } + } ); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RiaOsduConnector::requestWellboreTrajectoryByWellboreId( const QString& wellboreId ) +{ + requestWellboreTrajectoryByWellboreId( m_server, m_dataPartitionId, m_token, wellboreId ); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RiaOsduConnector::requestFileDownloadByFileId( const QString& fileId ) +{ + requestFileDownloadByFileId( m_server, m_dataPartitionId, m_token, fileId ); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RiaOsduConnector::requestWellboreTrajectoryByWellboreId( const QString& server, + const QString& dataPartitionId, + const QString& token, + const QString& wellboreId ) +{ + std::map params; + params["kind"] = WELLBORE_TRAJECTORY_KIND; + params["limit"] = "10000"; + params["query"] = "data.WellboreID: \"" + wellboreId + "\""; + + auto reply = makeRequest( params, server, dataPartitionId, token ); + connect( reply, + &QNetworkReply::finished, + [this, reply, wellboreId]() + { + if ( reply->error() == QNetworkReply::NoError ) + { + parseWellTrajectory( reply, wellboreId ); + } + } ); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RiaOsduConnector::requestFileDownloadByFileId( const QString& server, const QString& dataPartitionId, const QString& token, const QString& fileId ) +{ + RiaLogging::info( "Requesting download of file id: " + fileId ); + auto reply = makeDownloadRequest( server, dataPartitionId, fileId, token ); + connect( reply, + &QNetworkReply::finished, + [this, reply, fileId]() + { + if ( reply->error() == QNetworkReply::NoError ) + { + saveFile( reply, fileId ); + } + else + { + RiaLogging::error( "File request for id " + fileId + " failed." + reply->errorString() ); + } + } ); +} + +//-------------------------------------------------------------------------------------------------- +// +//-------------------------------------------------------------------------------------------------- +QString RiaOsduConnector::constructSearchUrl( const QString& server ) +{ + return server + "/api/search/v2/query"; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QString RiaOsduConnector::constructDownloadUrl( const QString& server, const QString& fileId ) +{ + return server + "/api/file/v2/files/" + fileId + "/downloadURL"; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QString RiaOsduConnector::constructAuthUrl( const QString& authority ) +{ + return authority + "/oauth2/v2.0/authorize"; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QString RiaOsduConnector::constructTokenUrl( const QString& authority ) +{ + return authority + "/oauth2/v2.0/token"; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QNetworkReply* RiaOsduConnector::makeRequest( const std::map& parameters, + const QString& server, + const QString& dataPartitionId, + const QString& token ) +{ + QNetworkRequest m_networkRequest; + m_networkRequest.setUrl( QUrl( constructSearchUrl( server ) ) ); + + addStandardHeader( m_networkRequest, token, dataPartitionId ); + + QJsonObject obj; + for ( auto [key, value] : parameters ) + { + obj.insert( key, value ); + } + + QJsonDocument doc( obj ); + QString strJson( doc.toJson( QJsonDocument::Compact ) ); + + auto reply = m_networkAccessManager->post( m_networkRequest, strJson.toUtf8() ); + return reply; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RiaOsduConnector::parseFields( QNetworkReply* reply ) +{ + QByteArray result = reply->readAll(); + reply->deleteLater(); + + if ( reply->error() == QNetworkReply::NoError ) + { + QJsonDocument doc = QJsonDocument::fromJson( result ); + QJsonObject jsonObj = doc.object(); + QJsonArray resultsArray = jsonObj["results"].toArray(); + + m_fields.clear(); + + foreach ( const QJsonValue& value, resultsArray ) + { + QJsonObject resultObj = value.toObject(); + + QString id = resultObj["id"].toString(); + QString kind = resultObj["kind"].toString(); + QString fieldName = resultObj["data"].toObject()["FieldName"].toString(); + m_fields.push_back( OsduField{ id, kind, fieldName } ); + } + + emit fieldsFinished(); + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RiaOsduConnector::parseWells( QNetworkReply* reply ) +{ + QByteArray result = reply->readAll(); + reply->deleteLater(); + + if ( reply->error() == QNetworkReply::NoError ) + { + QJsonDocument doc = QJsonDocument::fromJson( result ); + QJsonObject jsonObj = doc.object(); + QJsonArray resultsArray = jsonObj["results"].toArray(); + + RiaLogging::info( QString( "Found %1 wells." ).arg( +resultsArray.size() ) ); + + m_wells.clear(); + foreach ( const QJsonValue& value, resultsArray ) + { + QJsonObject resultObj = value.toObject(); + QString id = resultObj["id"].toString(); + QString kind = resultObj["kind"].toString(); + QString name = resultObj["data"].toObject()["FacilityName"].toString(); + m_wells.push_back( OsduWell{ id, kind, name } ); + } + + emit wellsFinished(); + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RiaOsduConnector::parseWellbores( QNetworkReply* reply, const QString& wellId ) +{ + QByteArray result = reply->readAll(); + reply->deleteLater(); + + if ( reply->error() == QNetworkReply::NoError ) + { + QJsonDocument doc = QJsonDocument::fromJson( result ); + QJsonObject jsonObj = doc.object(); + QJsonArray resultsArray = jsonObj["results"].toArray(); + + RiaLogging::info( QString( "Found %1 wellbores." ).arg( resultsArray.size() ) ); + + m_wellbores[wellId].clear(); + foreach ( const QJsonValue& value, resultsArray ) + { + QJsonObject resultObj = value.toObject(); + QString id = resultObj["id"].toString(); + QString kind = resultObj["kind"].toString(); + QString name = resultObj["data"].toObject()["FacilityName"].toString(); + m_wellbores[wellId].push_back( OsduWellbore{ id, kind, name, wellId } ); + } + + emit wellboresFinished( wellId ); + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RiaOsduConnector::parseWellTrajectory( QNetworkReply* reply, const QString& wellboreId ) +{ + QByteArray result = reply->readAll(); + reply->deleteLater(); + + if ( reply->error() == QNetworkReply::NoError ) + { + QJsonDocument doc = QJsonDocument::fromJson( result ); + QJsonObject jsonObj = doc.object(); + QJsonArray resultsArray = jsonObj["results"].toArray(); + m_wellboreTrajectories.clear(); + foreach ( const QJsonValue& value, resultsArray ) + { + QJsonObject resultObj = value.toObject(); + QJsonObject dataObj = resultObj["data"].toObject(); + QJsonArray dataSets = dataObj["Datasets"].toArray(); + if ( dataSets.size() == 1 ) + { + QString id = resultObj["id"].toString(); + QString kind = resultObj["kind"].toString(); + QString dataSetId = dataSets[0].toString(); + QString description = dataObj["Description"].toString(); + + m_wellboreTrajectories[wellboreId].push_back( OsduWellboreTrajectory{ id, kind, description, dataSetId, wellboreId } ); + } + else if ( dataSets.size() > 1 ) + { + RiaLogging::error( "Encountered dataset with more than on file: currently not supported." ); + } + } + + emit wellboreTrajectoryFinished( wellboreId ); + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RiaOsduConnector::saveFile( QNetworkReply* reply, const QString& fileId ) +{ + QByteArray result = reply->readAll(); + reply->deleteLater(); + + if ( reply->error() == QNetworkReply::NoError ) + { + QEventLoop loop; + + QJsonDocument doc = QJsonDocument::fromJson( result ); + QJsonObject jsonObj = doc.object(); + + QString signedUrl = jsonObj["SignedUrl"].toString(); + + RiaFileDownloader* downloader = new RiaFileDownloader; + QUrl url( signedUrl ); + QString filePath = "/tmp/" + generateRandomString( 30 ) + ".txt"; + + QString formattedJsonString = doc.toJson( QJsonDocument::Indented ); + + RiaLogging::info( QString( "File download: %1 => %2" ).arg( signedUrl ).arg( filePath ) ); + connect( this, SIGNAL( fileDownloadFinished( const QString&, const QString& ) ), &loop, SLOT( quit() ) ); + connect( downloader, + &RiaFileDownloader::done, + [this, fileId, filePath]() + { + RiaLogging::info( QString( "Download complete %1 => %2" ).arg( fileId ).arg( filePath ) ); + emit( fileDownloadFinished( fileId, filePath ) ); + } ); + RiaLogging::info( "Starting download" ); + downloader->downloadFile( url, filePath ); + + downloader->deleteLater(); + loop.exec(); + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RiaOsduConnector::addStandardHeader( QNetworkRequest& networkRequest, const QString& token, const QString& dataPartitionId ) +{ + networkRequest.setHeader( QNetworkRequest::ContentTypeHeader, "application/json" ); + networkRequest.setRawHeader( "Authorization", "Bearer " + token.toUtf8() ); + networkRequest.setRawHeader( QByteArray( "Data-Partition-Id" ), dataPartitionId.toUtf8() ); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QNetworkReply* + RiaOsduConnector::makeDownloadRequest( const QString& server, const QString& dataPartitionId, const QString& id, const QString& token ) +{ + QNetworkRequest m_networkRequest; + + QString url = constructDownloadUrl( server, id ); + + m_networkRequest.setUrl( QUrl( url ) ); + + addStandardHeader( m_networkRequest, token, dataPartitionId ); + + auto reply = m_networkAccessManager->get( m_networkRequest ); + return reply; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QString RiaOsduConnector::generateRandomString( int randomStringLength ) +{ + const QString possibleCharacters( "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789" ); + QString randomString; + for ( int i = 0; i < randomStringLength; ++i ) + { + quint32 value = QRandomGenerator::global()->generate(); + int index = value % possibleCharacters.length(); + QChar nextChar = possibleCharacters.at( index ); + randomString.append( nextChar ); + } + return randomString; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QString RiaOsduConnector::server() const +{ + return m_server; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QString RiaOsduConnector::dataPartition() const +{ + return m_dataPartitionId; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +std::vector RiaOsduConnector::fields() const +{ + return m_fields; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +std::vector RiaOsduConnector::wells() const +{ + return m_wells; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +std::vector RiaOsduConnector::wellbores( const QString& wellId ) const +{ + auto it = m_wellbores.find( wellId ); + if ( it != m_wellbores.end() ) + return it->second; + else + return {}; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QString RiaOsduConnector::wellIdForWellboreId( const QString& wellboreId ) const +{ + auto findWellIdForWellboreId = []( const std::vector& wellbores, const QString& wellboreId ) + { + auto it = std::find_if( wellbores.begin(), wellbores.end(), [wellboreId]( const OsduWellbore& w ) { return w.id == wellboreId; } ); + if ( it != wellbores.end() ) + return it->wellId; + else + return QString(); + }; + + for ( auto [wellId, wellbores] : m_wellbores ) + { + if ( auto res = findWellIdForWellboreId( wellbores, wellboreId ); !res.isEmpty() ) + { + return wellId; + } + } + + return QString(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +std::vector RiaOsduConnector::wellboreTrajectories( const QString& wellboreId ) const +{ + auto it = m_wellboreTrajectories.find( wellboreId ); + if ( it != m_wellboreTrajectories.end() ) + return it->second; + else + return {}; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RiaOsduConnector::fileDownloadComplete( const QString& fileId, const QString& filePath ) +{ + m_filePath = filePath; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +std::pair RiaOsduConnector::requestFileContentsById( const QString& fileId ) +{ + if ( m_token.isEmpty() ) + { + // TODO: improve this.. + QEventLoop loop; + connect( this, SIGNAL( tokenReady( const QString& ) ), &loop, SLOT( quit() ) ); + requestToken(); + loop.exec(); + } + + QEventLoop loop2; + connect( this, + SIGNAL( fileDownloadFinished( const QString&, const QString& ) ), + this, + SLOT( fileDownloadComplete( const QString&, const QString& ) ) ); + connect( this, SIGNAL( fileDownloadFinished( const QString&, const QString& ) ), &loop2, SLOT( quit() ) ); + requestFileDownloadByFileId( m_server, m_dataPartitionId, m_token, fileId ); + loop2.exec(); + + QFile dataFile( m_filePath ); + + if ( !dataFile.open( QFile::ReadOnly ) ) + { + return { "", "Unable to open file: " + m_filePath }; + } + + QTextStream stream( &dataFile ); + auto fileContent = stream.readAll(); + + return { fileContent, "" }; +} diff --git a/ApplicationLibCode/Commands/OsduImportCommands/RiaOsduConnector.h b/ApplicationLibCode/Commands/OsduImportCommands/RiaOsduConnector.h new file mode 100644 index 00000000000..35866087ba0 --- /dev/null +++ b/ApplicationLibCode/Commands/OsduImportCommands/RiaOsduConnector.h @@ -0,0 +1,131 @@ +#pragma once + +#include + +#include +#include + +#include + +struct OsduField +{ + QString id; + QString kind; + QString name; +}; + +struct OsduWell +{ + QString id; + QString kind; + QString name; +}; + +struct OsduWellbore +{ + QString id; + QString kind; + QString name; + QString wellId; +}; + +struct OsduWellboreTrajectory +{ + QString id; + QString kind; + QString description; + QString dataSetId; + QString wellboreId; +}; + +//================================================================================================== +/// +//================================================================================================== +class RiaOsduConnector : public QObject +{ + Q_OBJECT +public: + RiaOsduConnector( QObject* parent, + const QString& server, + const QString& dataParitionId, + const QString& authority, + const QString& scopes, + const QString& clientId ); + ~RiaOsduConnector() override; + + void requestFieldsByName( const QString& token, const QString& fieldName ); + void requestFieldsByName( const QString& fieldName ); + void requestWellsByFieldId( const QString& fieldId ); + void requestWellboresByWellId( const QString& wellId ); + void requestWellboreTrajectoryByWellboreId( const QString& wellboreId ); + void requestFileDownloadByFileId( const QString& fileId ); + + std::pair requestFileContentsById( const QString& fileId ); + + QString wellIdForWellboreId( const QString& wellboreId ) const; + + QString server() const; + QString dataPartition() const; + + std::vector fields() const; + std::vector wells() const; + std::vector wellbores( const QString& wellId ) const; + std::vector wellboreTrajectories( const QString& wellboreId ) const; + +public slots: + void requestToken(); + void parseFields( QNetworkReply* reply ); + void parseWells( QNetworkReply* reply ); + void parseWellbores( QNetworkReply* reply, const QString& wellId ); + void parseWellTrajectory( QNetworkReply* reply, const QString& wellboreId ); + void saveFile( QNetworkReply* reply, const QString& fileId ); + void accessGranted(); + void fileDownloadComplete( const QString& fileId, const QString& filePath ); + +signals: + void fileDownloadFinished( const QString& fileId, const QString& filePath ); + void fieldsFinished(); + void wellsFinished(); + void wellboresFinished( const QString& wellId ); + void wellboreTrajectoryFinished( const QString& wellboreId ); + void tokenReady( const QString& token ); + +private: + void addStandardHeader( QNetworkRequest& networkRequest, const QString& token, const QString& dataPartitionId ); + + QNetworkReply* + makeRequest( const std::map& parameters, const QString& server, const QString& dataPartitionId, const QString& token ); + + QNetworkReply* makeDownloadRequest( const QString& server, const QString& dataPartitionId, const QString& id, const QString& token ); + + void requestFieldsByName( const QString& server, const QString& dataPartitionId, const QString& token, const QString& fieldName ); + void requestWellsByFieldId( const QString& server, const QString& dataPartitionId, const QString& token, const QString& fieldId ); + void requestWellboresByWellId( const QString& server, const QString& dataPartitionId, const QString& token, const QString& wellId ); + void requestWellboreTrajectoryByWellboreId( const QString& server, + const QString& dataPartitionId, + const QString& token, + const QString& wellboreId ); + void requestFileDownloadByFileId( const QString& server, const QString& dataPartitionId, const QString& token, const QString& fileId ); + + static QString generateRandomString( int length = 20 ); + static QString constructSearchUrl( const QString& server ); + static QString constructDownloadUrl( const QString& server, const QString& fileId ); + static QString constructAuthUrl( const QString& authority ); + static QString constructTokenUrl( const QString& authority ); + + QOAuth2AuthorizationCodeFlow* m_osdu; + QNetworkAccessManager* m_networkAccessManager; + + const QString m_server; + const QString m_dataPartitionId; + const QString m_authority; + const QString m_scopes; + const QString m_clientId; + + QString m_token; + std::vector m_fields; + std::vector m_wells; + std::map> m_wellbores; + std::map> m_wellboreTrajectories; + QString m_filePath; +}; diff --git a/ApplicationLibCode/Commands/OsduImportCommands/RiaOsduOAuthHttpServerReplyHandler.cpp b/ApplicationLibCode/Commands/OsduImportCommands/RiaOsduOAuthHttpServerReplyHandler.cpp new file mode 100644 index 00000000000..849ea56a781 --- /dev/null +++ b/ApplicationLibCode/Commands/OsduImportCommands/RiaOsduOAuthHttpServerReplyHandler.cpp @@ -0,0 +1,24 @@ +#include "RiaOsduOAuthHttpServerReplyHandler.h" + +#include +#include +#include +#include + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RiaOsduOAuthHttpServerReplyHandler::RiaOsduOAuthHttpServerReplyHandler( quint16 port, QObject* parent ) + : QOAuthHttpServerReplyHandler( port, parent ) + , m_port( port ) +{ +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QString RiaOsduOAuthHttpServerReplyHandler::callback() const +{ + const QUrl url( QString::fromLatin1( "http://localhost:%1/" ).arg( m_port ) ); + return url.toString( QUrl::EncodeDelimiters ); +} diff --git a/ApplicationLibCode/Commands/OsduImportCommands/RiaOsduOAuthHttpServerReplyHandler.h b/ApplicationLibCode/Commands/OsduImportCommands/RiaOsduOAuthHttpServerReplyHandler.h new file mode 100644 index 00000000000..cff0d4027c0 --- /dev/null +++ b/ApplicationLibCode/Commands/OsduImportCommands/RiaOsduOAuthHttpServerReplyHandler.h @@ -0,0 +1,39 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2024- Equinor ASA +// +// ResInsight 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. +// +// ResInsight 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 at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#pragma once + +#include + +#include +#include + +//================================================================================================== +/// +//================================================================================================== +class RiaOsduOAuthHttpServerReplyHandler : public QOAuthHttpServerReplyHandler +{ + Q_OBJECT +public: + RiaOsduOAuthHttpServerReplyHandler( quint16 port, QObject* parent ); + + QString callback() const override; + +private: + quint16 m_port; +}; diff --git a/ApplicationLibCode/Commands/OsduImportCommands/RicWellPathsImportOsduFeature.cpp b/ApplicationLibCode/Commands/OsduImportCommands/RicWellPathsImportOsduFeature.cpp index bf0c27b95e6..63025272523 100644 --- a/ApplicationLibCode/Commands/OsduImportCommands/RicWellPathsImportOsduFeature.cpp +++ b/ApplicationLibCode/Commands/OsduImportCommands/RicWellPathsImportOsduFeature.cpp @@ -21,63 +21,43 @@ #include "RiaApplication.h" #include "RiaGuiApplication.h" +#include "RiaLogging.h" +#include "RiaOsduConnector.h" #include "RiaPreferences.h" +#include "RigWellPath.h" + +#include "RiaPreferencesOsdu.h" #include "RimFileWellPath.h" +#include "RimOilField.h" +#include "RimOsduWellPath.h" #include "RimProject.h" #include "RimTools.h" +#include "RimWellPathCollection.h" #include "RimWellPathImport.h" #include "RiuMainWindow.h" #include "RiuWellImportWizard.h" +#include "cvfObject.h" + #include #include -#include -#include -CAF_CMD_SOURCE_INIT( RicWellPathsImportSsihubFeature, "RicWellPathsImportSsihubFeature" ); +CAF_CMD_SOURCE_INIT( RicWellPathsImportOsduFeature, "RicWellPathsImportOsduFeature" ); //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -void RicWellPathsImportSsihubFeature::onActionTriggered( bool isChecked ) +void RicWellPathsImportOsduFeature::onActionTriggered( bool isChecked ) { RiaApplication* app = RiaApplication::instance(); if ( !app->project() ) return; - if ( !app->isProjectSavedToDisc() ) - { - RiaGuiApplication* guiApp = RiaGuiApplication::instance(); - if ( guiApp ) - { - QMessageBox msgBox( guiApp->mainWindow() ); - msgBox.setIcon( QMessageBox::Question ); - - QString questionText = QString( "Import of well paths will be stored as a part of a ResInsight project file. Please " - "save the project to file before importing well paths." ); - - msgBox.setText( questionText ); - msgBox.setInformativeText( "Do you want to save the project?" ); - msgBox.setStandardButtons( QMessageBox::Yes | QMessageBox::No ); - - int ret = msgBox.exec(); - if ( ret == QMessageBox::Yes ) - { - guiApp->saveProject(); - } - } - - if ( !app->isProjectSavedToDisc() ) - { - return; - } - } - // Update the UTM bounding box from the reservoir app->project()->computeUtmAreaOfInterest(); - QString wellPathsFolderPath = RimFileWellPath::getCacheDirectoryPath(); + QString wellPathsFolderPath = QStandardPaths::writableLocation( QStandardPaths::CacheLocation ) + QString( "/wellpaths/" ); QDir::root().mkpath( wellPathsFolderPath ); if ( !app->project()->wellPathImport() ) return; @@ -86,35 +66,56 @@ void RicWellPathsImportSsihubFeature::onActionTriggered( bool isChecked ) QString copyOfOriginalObject = app->project()->wellPathImport()->writeObjectToXmlString(); if ( !app->preferences() ) return; - RiuWellImportWizard wellImportwizard( app->preferences()->ssihubAddress, - wellPathsFolderPath, - app->project()->wellPathImport(), - RiuMainWindow::instance() ); - // Get password/username from application cache - { -#ifdef _DEBUG - // Valid credentials for ssihubfake received in mail from Håkon - QString ssihubUsername = "admin"; - QString ssihubPassword = "resinsight"; -#else - QString ssihubUsername = app->cacheDataObject( "ssihub_username" ).toString(); - QString ssihubPassword; -#endif - wellImportwizard.setCredentials( ssihubUsername, ssihubPassword ); - } + RimProject* project = RimProject::current(); + if ( !project ) return; + + if ( project->oilFields.empty() ) return; + + RimOilField* oilField = project->activeOilField(); + if ( !oilField ) return; + + RiaPreferencesOsdu* osduPreferences = app->preferences()->osduPreferences(); + + const QString server = osduPreferences->server(); + const QString dataParitionId = osduPreferences->dataPartitionId(); + const QString authority = osduPreferences->authority(); + const QString scopes = osduPreferences->scopes(); + const QString clientId = osduPreferences->clientId(); + + auto m_osduConnector = new RiaOsduConnector( RiuMainWindow::instance(), server, dataParitionId, authority, scopes, clientId ); + + RiuWellImportWizard wellImportwizard( wellPathsFolderPath, m_osduConnector, app->project()->wellPathImport(), RiuMainWindow::instance() ); if ( QDialog::Accepted == wellImportwizard.exec() ) { - QStringList wellPaths = wellImportwizard.absoluteFilePathsToWellPaths(); - if ( !wellPaths.empty() ) + std::vector importedWells = wellImportwizard.importedWells(); + for ( auto w : importedWells ) { - QStringList errorMessages; - app->addWellPathsToModel( wellPaths, &errorMessages ); - app->project()->scheduleCreateDisplayModelAndRedrawAllViews(); + auto wellPath = new RimOsduWellPath; + wellPath->setName( w.name ); + wellPath->setWellId( w.wellId ); + wellPath->setWellboreId( w.wellboreId ); + wellPath->setWellboreTrajectoryId( w.wellboreTrajectoryId ); + wellPath->setFileId( w.fileId ); + + oilField->wellPathCollection->addWellPath( wellPath ); + + auto [wellPathGeometry, errorMessage] = RimWellPathCollection::loadWellPathGeometryFromOsdu( m_osduConnector, w.fileId ); + if ( wellPathGeometry.notNull() ) + { + wellPath->setWellPathGeometry( wellPathGeometry.p() ); + } + else + { + RiaLogging::error( "Importing OSDU well failed: " + errorMessage ); + } + + oilField->wellPathCollection->updateConnectedEditors(); } - app->setCacheDataObject( "ssihub_username", wellImportwizard.field( "username" ) ); + project->updateConnectedEditors(); + app->project()->scheduleCreateDisplayModelAndRedrawAllViews(); } else { @@ -125,8 +126,8 @@ void RicWellPathsImportSsihubFeature::onActionTriggered( bool isChecked ) //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -void RicWellPathsImportSsihubFeature::setupActionLook( QAction* actionToSetup ) +void RicWellPathsImportOsduFeature::setupActionLook( QAction* actionToSetup ) { - actionToSetup->setText( "Import Well Paths from &SSI-hub" ); + actionToSetup->setText( "Import Well Paths from &OSDU" ); actionToSetup->setIcon( QIcon( ":/WellCollection.png" ) ); } diff --git a/ApplicationLibCode/Commands/OsduImportCommands/RicWellPathsImportOsduFeature.h b/ApplicationLibCode/Commands/OsduImportCommands/RicWellPathsImportOsduFeature.h index 2ffb5e84be2..863d77f85a0 100644 --- a/ApplicationLibCode/Commands/OsduImportCommands/RicWellPathsImportOsduFeature.h +++ b/ApplicationLibCode/Commands/OsduImportCommands/RicWellPathsImportOsduFeature.h @@ -24,7 +24,7 @@ //================================================================================================== /// //================================================================================================== -class RicWellPathsImportSsihubFeature : public caf::CmdFeature +class RicWellPathsImportOsduFeature : public caf::CmdFeature { CAF_CMD_HEADER_INIT; diff --git a/ApplicationLibCode/Commands/OsduImportCommands/RimWellPathImport.cpp b/ApplicationLibCode/Commands/OsduImportCommands/RimWellPathImport.cpp index 97d18bcb898..41480eff1c0 100644 --- a/ApplicationLibCode/Commands/OsduImportCommands/RimWellPathImport.cpp +++ b/ApplicationLibCode/Commands/OsduImportCommands/RimWellPathImport.cpp @@ -53,12 +53,6 @@ RimWellPathImport::RimWellPathImport() { CAF_PDM_InitObject( "RimWellPathImport" ); - CAF_PDM_InitField( &wellTypeSurvey, "WellTypeSurvey", true, "Survey" ); - caf::PdmUiNativeCheckBoxEditor::configureFieldForEditor( &wellTypeSurvey ); - - CAF_PDM_InitField( &wellTypePlans, "WellTypePlans", true, "Plans" ); - caf::PdmUiNativeCheckBoxEditor::configureFieldForEditor( &wellTypePlans ); - caf::AppEnum defaultUtmMode = UTM_FILTER_OFF; CAF_PDM_InitField( &utmFilterMode, "UtmMode", defaultUtmMode, "Utm Filter" ); @@ -67,95 +61,7 @@ RimWellPathImport::RimWellPathImport() CAF_PDM_InitField( &east, "UtmEast", 0.0, "East" ); CAF_PDM_InitField( &west, "UtmWest", 0.0, "West" ); - CAF_PDM_InitFieldNoDefault( ®ions, "Regions", "" ); -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RimWellPathImport::updateRegions( const QStringList& regionStrings, const QStringList& fieldStrings, const QStringList& edmIds ) -{ - assert( regionStrings.size() == fieldStrings.size() && regionStrings.size() == edmIds.size() ); - - std::vector regionsToRemove; - - // Remove regions and fields not present in last request - for ( size_t regionIdx = 0; regionIdx < regions.size(); regionIdx++ ) - { - if ( !regionStrings.contains( regions[regionIdx]->name ) ) - { - regionsToRemove.push_back( regions[regionIdx] ); - } - else - { - std::vector fieldsToRemove; - - for ( size_t fIdx = 0; fIdx < regions[regionIdx]->fields.size(); fIdx++ ) - { - if ( !fieldStrings.contains( regions[regionIdx]->fields[fIdx]->name ) ) - { - fieldsToRemove.push_back( regions[regionIdx]->fields[fIdx] ); - } - } - - for ( size_t i = 0; i < fieldsToRemove.size(); i++ ) - { - regions[regionIdx]->fields.removeChild( fieldsToRemove[i] ); - - delete fieldsToRemove[i]; - } - } - } - - for ( size_t i = 0; i < regionsToRemove.size(); i++ ) - { - regions.removeChild( regionsToRemove[i] ); - - delete regionsToRemove[i]; - } - - for ( int i = 0; i < regionStrings.size(); i++ ) - { - RimOilRegionEntry* oilRegionEntry = nullptr; - RimOilFieldEntry* oilFieldEntry = nullptr; - - for ( size_t regionIdx = 0; regionIdx < regions.size(); regionIdx++ ) - { - if ( regions[regionIdx]->name == regionStrings[i] ) - { - oilRegionEntry = regions[regionIdx]; - - for ( size_t fIdx = 0; fIdx < regions[regionIdx]->fields.size(); fIdx++ ) - { - if ( regions[regionIdx]->fields[fIdx]->edmId == edmIds[i] ) - { - oilFieldEntry = regions[regionIdx]->fields[fIdx]; - } - } - } - } - - if ( !oilRegionEntry ) - { - oilRegionEntry = new RimOilRegionEntry; - oilRegionEntry->name = regionStrings[i]; - - regions.push_back( oilRegionEntry ); - } - - assert( oilRegionEntry ); - - if ( !oilFieldEntry ) - { - oilFieldEntry = new RimOilFieldEntry; - oilFieldEntry->name = fieldStrings[i]; - oilFieldEntry->edmId = edmIds[i]; - - oilRegionEntry->fields.push_back( oilFieldEntry ); - } - } - - updateFieldVisibility(); + CAF_PDM_InitFieldNoDefault( ®ions_OBSOLETE, "Regions", "" ); } //-------------------------------------------------------------------------------------------------- @@ -198,71 +104,10 @@ void RimWellPathImport::fieldChangedByUi( const caf::PdmFieldHandle* changedFiel } } -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RimWellPathImport::defineObjectEditorAttribute( QString uiConfigName, caf::PdmUiEditorAttribute* attribute ) -{ - caf::PdmUiTreeViewEditorAttribute* myAttr = dynamic_cast( attribute ); - if ( myAttr ) - { - QStringList colHeaders; - colHeaders << "Region"; - myAttr->columnHeaders = colHeaders; - } -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RimWellPathImport::defineUiOrdering( QString uiConfigName, caf::PdmUiOrdering& uiOrdering ) -{ - // NOTE: If the default uiOrdering is used, the first checkbox is not possible to interact with using the mouse - // (only keyboard). This is a workaround to make the first checkbox work. - // - // Related issue, but with an opposite fix - // https://github.com/OPM/ResInsight/commit/51443d7aa33abebfaa179e645c729fde19a64666 - // - auto group = uiOrdering.addNewGroup( "Well Types" ); - group->add( &wellTypeSurvey ); - group->add( &wellTypePlans ); -} - //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- RimWellPathImport::~RimWellPathImport() { - regions.deleteChildren(); -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RimWellPathImport::updateFilePaths() -{ - QString wellPathsFolderPath = RimFileWellPath::getCacheDirectoryPath(); - - for ( size_t regionIdx = 0; regionIdx < regions.size(); regionIdx++ ) - { - for ( size_t fIdx = 0; fIdx < regions[regionIdx]->fields.size(); fIdx++ ) - { - RimOilFieldEntry* oilField = regions[regionIdx]->fields[fIdx]; - - QFileInfo fi( oilField->wellsFilePath ); - - QString newWellsFilePath = wellPathsFolderPath + "/" + fi.fileName(); - oilField->wellsFilePath = newWellsFilePath; - - for ( size_t wIdx = 0; wIdx < oilField->wells.size(); wIdx++ ) - { - RimWellPathEntry* rimWellPathEntry = oilField->wells[wIdx]; - - QFileInfo fiWell( rimWellPathEntry->wellPathFilePath ); - - QString newFilePath = wellPathsFolderPath + "/" + fiWell.fileName(); - rimWellPathEntry->wellPathFilePath = newFilePath; - } - } - } + regions_OBSOLETE.deleteChildren(); } diff --git a/ApplicationLibCode/Commands/OsduImportCommands/RimWellPathImport.h b/ApplicationLibCode/Commands/OsduImportCommands/RimWellPathImport.h index b75f313cc99..bb4ad472a9a 100644 --- a/ApplicationLibCode/Commands/OsduImportCommands/RimWellPathImport.h +++ b/ApplicationLibCode/Commands/OsduImportCommands/RimWellPathImport.h @@ -41,25 +41,17 @@ class RimWellPathImport : public caf::PdmObject RimWellPathImport(); ~RimWellPathImport() override; - caf::PdmField wellTypeSurvey; - caf::PdmField wellTypePlans; - caf::PdmField> utmFilterMode; caf::PdmField north; caf::PdmField south; caf::PdmField east; caf::PdmField west; - caf::PdmChildArrayField regions; - - void updateRegions( const QStringList& regions, const QStringList& fields, const QStringList& edmIds ); - +protected: void initAfterRead() override; void fieldChangedByUi( const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue ) override; - void defineObjectEditorAttribute( QString uiConfigName, caf::PdmUiEditorAttribute* attribute ) override; - void defineUiOrdering( QString uiConfigName, caf::PdmUiOrdering& uiOrdering ) override; void updateFieldVisibility(); - void updateFilePaths(); + caf::PdmChildArrayField regions_OBSOLETE; }; diff --git a/ApplicationLibCode/Commands/OsduImportCommands/RiuWellImportWizard.cpp b/ApplicationLibCode/Commands/OsduImportCommands/RiuWellImportWizard.cpp index 7a53b71afe6..c1723f600ea 100644 --- a/ApplicationLibCode/Commands/OsduImportCommands/RiuWellImportWizard.cpp +++ b/ApplicationLibCode/Commands/OsduImportCommands/RiuWellImportWizard.cpp @@ -19,17 +19,11 @@ #include "RiuWellImportWizard.h" #include "RiaFeatureCommandContext.h" +#include "RiaOsduConnector.h" -#include "RifJsonEncodeDecode.h" - -#include "RimOilFieldEntry.h" -#include "RimOilRegionEntry.h" #include "RimWellPathImport.h" #include "cafCmdFeatureMenuBuilder.h" -#include "cafPdmDocument.h" -#include "cafPdmObject.h" -#include "cafPdmObjectGroup.h" #include "cafPdmUiListView.h" #include "cafPdmUiPropertyView.h" #include "cafPdmUiTreeAttributes.h" @@ -37,53 +31,37 @@ #include "cafPdmUiTreeViewEditor.h" #include "cafUtils.h" -#include +#include #include -#include -#include +#include #include #include #include - -CAF_PDM_XML_ABSTRACT_SOURCE_INIT( ObjectGroupWithHeaders, "ObjectGroupWithHeaders" ); // Do not use. Abstract class +#include +#include //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -RiuWellImportWizard::RiuWellImportWizard( const QString& webServiceAddress, - const QString& downloadFolder, +RiuWellImportWizard::RiuWellImportWizard( const QString& downloadFolder, + RiaOsduConnector* osduConnector, RimWellPathImport* wellPathImportObject, QWidget* parent /*= 0*/ ) : QWizard( parent ) { m_wellPathImportObject = wellPathImportObject; + m_osduConnector = osduConnector; m_destinationFolder = downloadFolder; - m_webServiceAddress = webServiceAddress; - m_myProgressDialog = nullptr; m_firstTimeRequestingAuthentication = true; - addPage( new AuthenticationPage( webServiceAddress, this ) ); - m_fieldSelectionPageId = addPage( new FieldSelectionPage( m_wellPathImportObject, this ) ); - m_wellSelectionPageId = addPage( new WellSelectionPage( m_wellPathImportObject, this ) ); - m_wellSummaryPageId = addPage( new WellSummaryPage( m_wellPathImportObject, this ) ); - - connect( this, SIGNAL( currentIdChanged( int ) ), SLOT( slotCurrentIdChanged( int ) ) ); - - connect( &m_networkAccessManager, - SIGNAL( authenticationRequired( QNetworkReply*, QAuthenticator* ) ), - this, - SLOT( slotAuthenticationRequired( QNetworkReply*, QAuthenticator* ) ) ); - -#if !defined( QT_NO_OPENSSL ) && !defined( CVF_OSX ) - connect( &m_networkAccessManager, - SIGNAL( sslErrors( QNetworkReply*, QList ) ), - this, - SLOT( sslErrors( QNetworkReply*, QList ) ) ); -#endif + addPage( new AuthenticationPage( m_osduConnector, this ) ); + addPage( new FieldSelectionPage( m_wellPathImportObject, m_osduConnector, this ) ); + addPage( new WellSelectionPage( m_wellPathImportObject, m_osduConnector, this ) ); + addPage( new WellSummaryPage( m_wellPathImportObject, m_osduConnector, this ) ); } //-------------------------------------------------------------------------------------------------- @@ -93,189 +71,12 @@ RiuWellImportWizard::~RiuWellImportWizard() { } -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -QString RiuWellImportWizard::jsonFieldsFilePath() -{ - return m_destinationFolder + "/fields.json"; -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -QString RiuWellImportWizard::jsonWellsFilePath() -{ - return m_destinationFolder + "/wellpaths.json"; -} - //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RiuWellImportWizard::downloadFields() { - QString wellFileName = jsonWellsFilePath(); - if ( caf::Utils::fileExists( wellFileName ) ) - { - QFile::remove( wellFileName ); - } - - QString completeUrlText = m_webServiceAddress + "/resinsight/projects"; - QString destinationFileName = jsonFieldsFilePath(); - - m_currentDownloadState = DOWNLOAD_FIELDS; - issueHttpRequestToFile( completeUrlText, destinationFileName ); - - return; -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RiuWellImportWizard::issueHttpRequestToFile( QString completeUrlText, QString destinationFileName ) -{ - setUrl( completeUrlText ); - m_file = new QFile( destinationFileName ); - if ( !m_file->open( QIODevice::WriteOnly ) ) - { - QMessageBox::information( this, - tr( "HTTP" ), - tr( "Unable to save the file %1: %2." ).arg( destinationFileName ).arg( m_file->errorString() ) ); - delete m_file; - m_file = nullptr; - return; - } - - // schedule the request - m_httpRequestAborted = false; - startRequest( m_url ); -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RiuWellImportWizard::cancelDownload() -{ - // m_statusLabel->setText(tr("Download canceled.")); - m_httpRequestAborted = true; - m_reply->abort(); -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RiuWellImportWizard::httpFinished() -{ - if ( m_httpRequestAborted ) - { - if ( m_file ) - { - m_file->close(); - m_file->remove(); - delete m_file; - m_file = nullptr; - } - m_reply->deleteLater(); - hideProgressDialog(); - return; - } - - m_file->flush(); - m_file->close(); - - QVariant redirectionTarget = m_reply->attribute( QNetworkRequest::RedirectionTargetAttribute ); - if ( m_reply->error() ) - { - m_file->remove(); - QMessageBox::information( this, tr( "HTTP" ), tr( "Download failed: %1." ).arg( m_reply->errorString() ) ); - } - else if ( !redirectionTarget.isNull() ) - { - QUrl newUrl = m_url.resolved( redirectionTarget.toUrl() ); - if ( QMessageBox::question( this, tr( "HTTP" ), tr( "Redirect to %1 ?" ).arg( newUrl.toString() ), QMessageBox::Yes | QMessageBox::No ) == - QMessageBox::Yes ) - { - m_url = newUrl; - m_reply->deleteLater(); - m_file->open( QIODevice::WriteOnly ); - m_file->resize( 0 ); - startRequest( m_url ); - return; - } - } - else - { - // m_statusLabel->setText(tr("Downloaded data to %1.").arg(m_destinationFolder)); - } - - if ( m_currentDownloadState == DOWNLOAD_WELL_PATH ) - { - QString singleWellPathFilePath = m_file->fileName(); - - QFile file( singleWellPathFilePath ); - if ( file.open( QFile::ReadOnly ) ) - { - QString singleWellPathContent = file.readAll(); - - // Strip leading and trailing [] - - if ( singleWellPathContent.indexOf( '{' ) > 0 ) - { - singleWellPathContent = singleWellPathContent.right( singleWellPathContent.size() - singleWellPathContent.indexOf( '{' ) ); - } - - if ( singleWellPathContent[singleWellPathContent.size() - 1] == ']' ) - { - singleWellPathContent = singleWellPathContent.left( singleWellPathContent.size() - 1 ); - } - - QString wellPathName = getValue( "name", singleWellPathContent ); - if ( !singleWellPathContent.isEmpty() && !wellPathName.isEmpty() ) - { - // Write out the content without leading/trailing [] - file.close(); - QFile::remove( singleWellPathFilePath ); - - if ( file.open( QFile::WriteOnly ) ) - { - QTextStream out( &file ); - out << singleWellPathContent; - } - } - - progressDialog()->setLabelText( QString( "Downloaded well path : %1" ).arg( wellPathName ) ); - } - - int newValue = progressDialog()->maximum() - m_wellRequestQueue.size(); - progressDialog()->setValue( newValue ); - } - - m_reply->deleteLater(); - m_reply = nullptr; - delete m_file; - m_file = nullptr; - - if ( m_currentDownloadState == DOWNLOAD_WELLS || m_currentDownloadState == DOWNLOAD_WELL_PATH ) - { - checkDownloadQueueAndIssueRequests(); - } - else if ( m_currentDownloadState == DOWNLOAD_FIELDS ) - { - updateFieldsModel(); - m_currentDownloadState = DOWNLOAD_UNDEFINED; - } -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RiuWellImportWizard::httpReadyRead() -{ - // this slot gets called every time the QNetworkReply has new data. - // We read all of its new data and write it into the file. - // That way we use less RAM than when reading it at the finished() - // signal of the QNetworkReply - if ( m_file ) m_file->write( m_reply->readAll() ); + m_osduConnector->requestFieldsByName( "AZERI" ); } //-------------------------------------------------------------------------------------------------- @@ -286,525 +87,226 @@ void RiuWellImportWizard::slotAuthenticationRequired( QNetworkReply* networkRepl { if ( m_firstTimeRequestingAuthentication ) { - // Use credentials from first wizard page - authenticator->setUser( field( "username" ).toString() ); - authenticator->setPassword( field( "password" ).toString() ); - m_firstTimeRequestingAuthentication = false; } else { QMessageBox::information( this, "Authentication failed", - "Failed to authenticate credentials. You will now be directed back to the first " - "wizard page." ); + "Failed to authenticate. You will now be directed back to the first wizard page." ); m_firstTimeRequestingAuthentication = true; restart(); } } -#if !defined( QT_NO_OPENSSL ) && !defined( CVF_OSX ) -void RiuWellImportWizard::sslErrors( QNetworkReply*, const QList& errors ) -{ - QString errorString; - foreach ( const QSslError& error, errors ) - { - if ( !errorString.isEmpty() ) errorString += ", "; - errorString += error.errorString(); - } - - if ( QMessageBox::warning( this, - tr( "HTTP" ), - tr( "One or more SSL errors has occurred: %1" ).arg( errorString ), - QMessageBox::Ignore | QMessageBox::Abort ) == QMessageBox::Ignore ) - { - m_reply->ignoreSslErrors(); - } -} -#endif - //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -void RiuWellImportWizard::setUrl( const QString& httpAddress ) +void RiuWellImportWizard::downloadWells( const QString& fieldId ) { - m_url = httpAddress; + m_osduConnector->requestWellsByFieldId( fieldId ); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -void RiuWellImportWizard::startRequest( QUrl url ) +void RiuWellImportWizard::downloadWellPaths( const QString& wellboreId ) { - auto request = QNetworkRequest( url ); - -#if !defined( QT_NO_OPENSSL ) && !defined( CVF_OSX ) - bool supportsSsl = QSslSocket::supportsSsl(); - if ( supportsSsl ) - { - QSslConfiguration config = QSslConfiguration::defaultConfiguration(); - config.setProtocol( QSsl::TlsV1_0 ); - request.setSslConfiguration( config ); - } -#endif - - m_reply = m_networkAccessManager.get( request ); - connect( m_reply, SIGNAL( finished() ), this, SLOT( httpFinished() ) ); - connect( m_reply, SIGNAL( readyRead() ), this, SLOT( httpReadyRead() ) ); -} - -//-------------------------------------------------------------------------------------------------- -/// Search for string, and find the associated value inside the next quoted string -// text content : "A" : "B" -// A search for key "A" returns B -//-------------------------------------------------------------------------------------------------- -QString RiuWellImportWizard::getValue( const QString& key, const QString& stringContent ) -{ - QString quotedKey = "\"" + key + "\""; - - int pos = stringContent.indexOf( quotedKey ); - if ( pos >= 0 ) - { - int valueStartPos = stringContent.indexOf( "\"", pos + quotedKey.size() ); - int valueEndPos = stringContent.indexOf( "\"", valueStartPos + 1 ); - - if ( valueStartPos >= 0 && valueEndPos > valueStartPos ) - { - return stringContent.mid( valueStartPos + 1, valueEndPos - valueStartPos - 1 ); - } - } - - return QString(); + m_osduConnector->requestWellboreTrajectoryByWellboreId( wellboreId ); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -QProgressDialog* RiuWellImportWizard::progressDialog() +void RiuWellImportWizard::resetAuthenticationCount() { - if ( !m_myProgressDialog ) - { - m_myProgressDialog = new QProgressDialog( this ); - } - - return m_myProgressDialog; + m_firstTimeRequestingAuthentication = true; + m_osduConnector->requestToken(); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -void RiuWellImportWizard::hideProgressDialog() +void RiuWellImportWizard::setSelectedFieldId( const QString& fieldId ) { - if ( m_myProgressDialog ) - { - m_myProgressDialog->hide(); - - QCoreApplication::processEvents(); - } + m_selectedFieldId = fieldId; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -void RiuWellImportWizard::updateFieldsModel() +QString RiuWellImportWizard::selectedFieldId() const { - QString fileName = jsonFieldsFilePath(); - - if ( caf::Utils::fileExists( fileName ) ) - { - QStringList regions; - QStringList fields; - QStringList edmIds; - - QMap jsonMap = ResInsightInternalJson::JsonReader::decodeFile( fileName ); - QVariantList variantList = ResInsightInternalJson::JsonReader::getVariantList( jsonMap ); - for ( const auto& listItem : variantList ) - { - QMap fieldMap = listItem.toMap(); - - regions.push_back( fieldMap["region"].toString() ); - fields.push_back( fieldMap["name"].toString() ); - edmIds.push_back( fieldMap["edmId"].toString() ); - } - - m_wellPathImportObject->updateRegions( regions, fields, edmIds ); - - for ( size_t i = 0; i < m_wellPathImportObject->regions.size(); i++ ) - { - m_wellPathImportObject->regions[i]->updateState(); - } - - m_wellPathImportObject->updateConnectedEditors(); - } + return m_selectedFieldId; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -void RiuWellImportWizard::downloadWells() +void RiuWellImportWizard::setSelectedWellboreId( const QString& wellboreId ) { - for ( size_t rIdx = 0; rIdx < m_wellPathImportObject->regions.size(); rIdx++ ) - { - RimOilRegionEntry* oilRegion = m_wellPathImportObject->regions[rIdx]; - if ( oilRegion->selected ) - { - for ( size_t fIdx = 0; fIdx < oilRegion->fields.size(); fIdx++ ) - { - RimOilFieldEntry* oilField = oilRegion->fields[fIdx]; - if ( oilField->selected ) - { - DownloadEntity urlToFile; - - QString wellRequest; - if ( m_wellPathImportObject->utmFilterMode == RimWellPathImport::UTM_FILTER_OFF ) - { - wellRequest = QString( "/resinsight/projects/%1/wells" ).arg( oilField->edmId ); - } - else - { - wellRequest = QString( "/resinsight/projects/%1/" - "wellsInArea?north=%2&south=%3&east=%4&west=%5&utmzone=32N" ) - .arg( oilField->edmId ) - .arg( QString::number( m_wellPathImportObject->north, 'g', 10 ) ) - .arg( QString::number( m_wellPathImportObject->south, 'g', 10 ) ) - .arg( QString::number( m_wellPathImportObject->east, 'g', 10 ) ) - .arg( QString::number( m_wellPathImportObject->west, 'g', 10 ) ); - } - - urlToFile.requestUrl = m_webServiceAddress + wellRequest; - urlToFile.responseFilename = m_destinationFolder + QString( "/wells_%1.json" ).arg( oilField->edmId ); - - oilField->wellsFilePath = urlToFile.responseFilename; - - m_wellRequestQueue.push_back( urlToFile ); - } - } - } - } - - m_currentDownloadState = DOWNLOAD_WELLS; - checkDownloadQueueAndIssueRequests(); + m_selectedWellboreId = wellboreId; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -void RiuWellImportWizard::downloadWellPaths() +QString RiuWellImportWizard::selectedWellboreId() const { - WellSelectionPage* wellSelectionPage = dynamic_cast( page( m_wellSelectionPageId ) ); - std::vector downloadEntities; - wellSelectionPage->selectedWellPathEntries( downloadEntities, nullptr ); - - for ( size_t i = 0; i < downloadEntities.size(); i++ ) - { - m_wellRequestQueue.push_back( downloadEntities[i] ); - } - - m_currentDownloadState = DOWNLOAD_WELL_PATH; - - progressDialog()->setMaximum( m_wellRequestQueue.size() ); - progressDialog()->setValue( 0 ); - progressDialog()->show(); - - checkDownloadQueueAndIssueRequests(); + return m_selectedWellboreId; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -void RiuWellImportWizard::checkDownloadQueueAndIssueRequests() +std::vector RiuWellImportWizard::importedWells() const { - if ( !m_wellRequestQueue.empty() ) - { - DownloadEntity firstItem = m_wellRequestQueue[0]; - m_wellRequestQueue.pop_front(); - - QString completeUrlText = firstItem.requestUrl; - QString absoluteFilePath = firstItem.responseFilename; - - issueHttpRequestToFile( completeUrlText, absoluteFilePath ); - - return; - } - - if ( m_currentDownloadState == DOWNLOAD_WELLS ) - { - hideProgressDialog(); - - // Update UI with downloaded wells - - for ( size_t rIdx = 0; rIdx < m_wellPathImportObject->regions.size(); rIdx++ ) - { - RimOilRegionEntry* oilRegion = m_wellPathImportObject->regions[rIdx]; - if ( oilRegion->selected ) - { - for ( size_t fIdx = 0; fIdx < oilRegion->fields.size(); fIdx++ ) - { - RimOilFieldEntry* oilField = oilRegion->fields[fIdx]; - if ( oilField->selected ) - { - parseWellsResponse( oilField ); - } - } - } - } - - m_wellPathImportObject->updateConnectedEditors(); - } - else if ( m_currentDownloadState == DOWNLOAD_WELL_PATH ) - { - WellSummaryPage* wellSummaryPage = dynamic_cast( page( m_wellSummaryPageId ) ); - if ( wellSummaryPage ) - { - wellSummaryPage->updateSummaryPage(); - } - } - - m_currentDownloadState = DOWNLOAD_UNDEFINED; - - hideProgressDialog(); + return m_wellInfos; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -void RiuWellImportWizard::resetAuthenticationCount() +void RiuWellImportWizard::addWellInfo( RiuWellImportWizard::WellInfo wellInfo ) { - m_firstTimeRequestingAuthentication = true; + m_wellInfos.push_back( wellInfo ); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -QStringList RiuWellImportWizard::absoluteFilePathsToWellPaths() const +AuthenticationPage::AuthenticationPage( RiaOsduConnector* osduConnector, QWidget* parent /*= 0*/ ) + : QWizardPage( parent ) + , m_accessOk( false ) { - QStringList filePaths; + setTitle( "OSDU - Login" ); - WellSelectionPage* wellSelectionPage = dynamic_cast( page( m_wellSelectionPageId ) ); - std::vector downloadEntities; - wellSelectionPage->selectedWellPathEntries( downloadEntities, nullptr ); + QVBoxLayout* layout = new QVBoxLayout; - for ( size_t i = 0; i < downloadEntities.size(); i++ ) - { - if ( caf::Utils::fileExists( downloadEntities[i].responseFilename ) ) - { - filePaths.push_back( downloadEntities[i].responseFilename ); - } - } + QLabel* label = new QLabel( "Checking OSDU connection..." ); + layout->addWidget( label ); - return filePaths; -} + QFormLayout* formLayout = new QFormLayout; + layout->addLayout( formLayout ); -//-------------------------------------------------------------------------------------------------- -/// Set wells hidden from the field selection page -/// TODO: This can be refactored when UIOrdering for objects is created -//-------------------------------------------------------------------------------------------------- -void RiuWellImportWizard::slotCurrentIdChanged( int currentId ) -{ - bool hideWells = true; - if ( currentId == m_wellSelectionPageId ) hideWells = false; + QLineEdit* serverLineEdit = new QLineEdit( osduConnector->server(), this ); + QLineEdit* partitionLineEdit = new QLineEdit( osduConnector->dataPartition(), this ); - for ( size_t rIdx = 0; rIdx < m_wellPathImportObject->regions.size(); rIdx++ ) - { - RimOilRegionEntry* oilRegion = m_wellPathImportObject->regions[rIdx]; - { - for ( size_t fIdx = 0; fIdx < oilRegion->fields.size(); fIdx++ ) - { - RimOilFieldEntry* oilField = oilRegion->fields[fIdx]; - oilField->wells.uiCapability()->setUiHidden( hideWells ); - } - } - } + formLayout->addRow( "Server:", serverLineEdit ); + formLayout->addRow( "Data Partition:", partitionLineEdit ); - // Update the editors to propagate the changes to UI - m_wellPathImportObject->updateConnectedEditors(); + setLayout( layout ); + + connect( osduConnector, SIGNAL( tokenReady( const QString& ) ), this, SLOT( accessOk() ) ); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -void RiuWellImportWizard::parseWellsResponse( RimOilFieldEntry* oilFieldEntry ) +void AuthenticationPage::initializePage() { - QStringList surveyNames; - QStringList planNames; - - if ( caf::Utils::fileExists( oilFieldEntry->wellsFilePath ) ) - { - QMap jsonMap = ResInsightInternalJson::JsonReader::decodeFile( oilFieldEntry->wellsFilePath ); - QVariantList variantList = ResInsightInternalJson::JsonReader::getVariantList( jsonMap ); - for ( const auto& listItem : variantList ) - { - QMap rootMap = listItem.toMap(); - - if ( m_wellPathImportObject->wellTypeSurvey ) - { - QMap surveyMap = rootMap["survey"].toMap(); - QString name = surveyMap["name"].toString(); - - if ( !oilFieldEntry->find( name, RimWellPathEntry::WELL_SURVEY ) ) - { - QMap linksMap = surveyMap["links"].toMap(); - QString requestUrl = m_webServiceAddress + linksMap["entity"].toString(); - QString surveyType = surveyMap["surveyType"].toString(); - RimWellPathEntry* surveyWellPathEntry = - RimWellPathEntry::createWellPathEntry( name, surveyType, requestUrl, m_destinationFolder, RimWellPathEntry::WELL_SURVEY ); - oilFieldEntry->wells.push_back( surveyWellPathEntry ); - } - - surveyNames.push_back( name ); - } - - if ( m_wellPathImportObject->wellTypePlans ) - { - QList plansList = rootMap["plans"].toList(); - QListIterator planIt( plansList ); - while ( planIt.hasNext() ) - { - QMap planMap = planIt.next().toMap(); - QString name = planMap["name"].toString(); - - if ( !oilFieldEntry->find( name, RimWellPathEntry::WELL_PLAN ) ) - { - QMap linksMap = planMap["links"].toMap(); - QString requestUrl = m_webServiceAddress + linksMap["entity"].toString(); - QString surveyType = planMap["surveyType"].toString(); - RimWellPathEntry* surveyWellPathEntry = - RimWellPathEntry::createWellPathEntry( name, surveyType, requestUrl, m_destinationFolder, RimWellPathEntry::WELL_PLAN ); - oilFieldEntry->wells.push_back( surveyWellPathEntry ); - } - - planNames.push_back( name ); - } - } - } - } - - // Delete the well path entries in the model that are not part of the reply from the web service - std::vector wellsToRemove; - - for ( size_t i = 0; i < oilFieldEntry->wells.size(); i++ ) - { - RimWellPathEntry* wellPathEntry = oilFieldEntry->wells[i]; - if ( wellPathEntry->wellPathType == RimWellPathEntry::WELL_PLAN ) - { - if ( !planNames.contains( wellPathEntry->name ) ) - { - wellsToRemove.push_back( wellPathEntry ); - } - } - else - { - if ( !surveyNames.contains( wellPathEntry->name ) ) - { - wellsToRemove.push_back( wellPathEntry ); - } - } - } - - for ( size_t i = 0; i < wellsToRemove.size(); i++ ) - { - oilFieldEntry->wells.removeChild( wellsToRemove[i] ); - - delete wellsToRemove[i]; - } - - WellSelectionPage* wellSelectionPage = dynamic_cast( page( m_wellSelectionPageId ) ); - if ( wellSelectionPage ) wellSelectionPage->buildWellTreeView(); + RiuWellImportWizard* wiz = dynamic_cast( wizard() ); + wiz->resetAuthenticationCount(); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -void RiuWellImportWizard::setCredentials( const QString& username, const QString& password ) +bool AuthenticationPage::isComplete() const { - // Set the initial value of the fields defined in the Authorization page - setField( "username", username ); - setField( "password", password ); + return m_accessOk; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -int RiuWellImportWizard::wellSelectionPageId() +void AuthenticationPage::accessOk() { - return m_wellSelectionPageId; + m_accessOk = true; + emit( completeChanged() ); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -AuthenticationPage::AuthenticationPage( const QString& webServiceAddress, QWidget* parent /*= 0*/ ) - : QWizardPage( parent ) +FieldSelectionPage::FieldSelectionPage( RimWellPathImport* wellPathImport, RiaOsduConnector* osduConnector, QWidget* parent /*= 0*/ ) { - setTitle( "SSIHUB - Login" ); + setTitle( "Field Selection" ); QVBoxLayout* layout = new QVBoxLayout; + setLayout( layout ); - QLabel* label = new QLabel( "Please enter your login information for SSIHUB at : " + webServiceAddress ); + QLabel* label = new QLabel( "Select fields" ); layout->addWidget( label ); - QFormLayout* formLayout = new QFormLayout; - layout->addLayout( formLayout ); + m_tableView = new QTableView( this ); + m_tableView->setSelectionBehavior( QAbstractItemView::SelectRows ); + m_osduFieldsModel = new OsduFieldTableModel; + m_tableView->setModel( m_osduFieldsModel ); + layout->addWidget( m_tableView ); + layout->setStretchFactor( m_tableView, 10 ); + + // Tree view + // caf::PdmUiTreeView* treeView = new caf::PdmUiTreeView( this ); + // treeView->setPdmItem( wellPathImport ); + // layout->addWidget( treeView ); + // layout->setStretchFactor( treeView, 10 ); - QLineEdit* usernameLineEdit = new QLineEdit( "", this ); - QLineEdit* passwordlLineEdit = new QLineEdit( "", this ); - passwordlLineEdit->setEchoMode( QLineEdit::Password ); + setSizePolicy( QSizePolicy( QSizePolicy::Expanding, QSizePolicy::Expanding ) ); - formLayout->addRow( "&Username:", usernameLineEdit ); - formLayout->addRow( "&Password:", passwordlLineEdit ); + m_osduConnector = osduConnector; + connect( m_osduConnector, SIGNAL( fieldsFinished() ), SLOT( fieldsFinished() ) ); - setLayout( layout ); + connect( m_tableView->selectionModel(), + SIGNAL( selectionChanged( const QItemSelection&, const QItemSelection& ) ), + SLOT( selectField( const QItemSelection&, const QItemSelection& ) ) ); - // Make variables accessible to other pages in wizard - // Use * at end of field name to indicate mandatory field - registerField( "username", usernameLineEdit ); - registerField( "password", passwordlLineEdit ); + connect( m_tableView->selectionModel(), + SIGNAL( selectionChanged( const QItemSelection&, const QItemSelection& ) ), + SIGNAL( completeChanged() ) ); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -void AuthenticationPage::initializePage() +void FieldSelectionPage::initializePage() { RiuWellImportWizard* wiz = dynamic_cast( wizard() ); - wiz->resetAuthenticationCount(); + wiz->downloadFields(); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -FieldSelectionPage::FieldSelectionPage( RimWellPathImport* wellPathImport, QWidget* parent /*= 0*/ ) +void FieldSelectionPage::fieldsFinished() { - setTitle( "Field Selection" ); - - QVBoxLayout* layout = new QVBoxLayout; - setLayout( layout ); - - QLabel* label = new QLabel( "Select fields" ); - layout->addWidget( label ); - - // Tree view - caf::PdmUiTreeView* treeView = new caf::PdmUiTreeView( this ); - treeView->setPdmItem( wellPathImport ); - layout->addWidget( treeView ); - layout->setStretchFactor( treeView, 10 ); - - // Property view - m_propertyView = new caf::PdmUiPropertyView( this ); - layout->addWidget( m_propertyView ); - m_propertyView->showProperties( wellPathImport ); + std::vector fields = m_osduConnector->fields(); + m_osduFieldsModel->setOsduFields( fields ); +} - setSizePolicy( QSizePolicy( QSizePolicy::Expanding, QSizePolicy::Expanding ) ); +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void FieldSelectionPage::selectField( const QItemSelection& newSelection, const QItemSelection& oldSelection ) +{ + if ( !newSelection.indexes().empty() ) + { + QModelIndex index = newSelection.indexes()[0]; + int column = 0; + QString fieldId = m_osduFieldsModel->data( index.siblingAtColumn( column ) ).toString(); + RiuWellImportWizard* wiz = dynamic_cast( wizard() ); + wiz->setSelectedFieldId( fieldId ); + } } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -void FieldSelectionPage::initializePage() +bool FieldSelectionPage::isComplete() const { - RiuWellImportWizard* wiz = dynamic_cast( wizard() ); - wiz->downloadFields(); + QItemSelectionModel* select = m_tableView->selectionModel(); + return select->selectedRows().size() == 1; } //-------------------------------------------------------------------------------------------------- @@ -812,13 +314,12 @@ void FieldSelectionPage::initializePage() //-------------------------------------------------------------------------------------------------- FieldSelectionPage::~FieldSelectionPage() { - m_propertyView->showProperties( nullptr ); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -WellSelectionPage::WellSelectionPage( RimWellPathImport* wellPathImport, QWidget* parent /*= 0*/ ) +WellSelectionPage::WellSelectionPage( RimWellPathImport* wellPathImport, RiaOsduConnector* osduConnector, QWidget* parent /*= 0*/ ) { QVBoxLayout* layout = new QVBoxLayout; setLayout( layout ); @@ -826,21 +327,26 @@ WellSelectionPage::WellSelectionPage( RimWellPathImport* wellPathImport, QWidget QLabel* label = new QLabel( "Select wells" ); layout->addWidget( label ); - m_wellSelectionTreeView = new caf::PdmUiTreeView( this ); - m_wellSelectionTreeView->treeView()->setContextMenuPolicy( Qt::CustomContextMenu ); - m_wellSelectionTreeView->enableSelectionManagerUpdating( true ); - m_wellSelectionTreeView->treeView()->setSelectionMode( QAbstractItemView::ExtendedSelection ); + m_tableView = new QTableView( this ); + m_tableView->setSelectionBehavior( QAbstractItemView::SelectRows ); + m_osduWellboresModel = new OsduWellboreTableModel; + m_tableView->setModel( m_osduWellboresModel ); + layout->addWidget( m_tableView ); + layout->setStretchFactor( m_tableView, 10 ); - connect( m_wellSelectionTreeView->treeView(), - SIGNAL( customContextMenuRequested( const QPoint& ) ), - SLOT( customMenuRequested( const QPoint& ) ) ); + m_wellPathImportObject = wellPathImport; - layout->addWidget( m_wellSelectionTreeView ); + m_osduConnector = osduConnector; + connect( m_osduConnector, SIGNAL( wellsFinished() ), SLOT( wellsFinished() ) ); + connect( m_osduConnector, SIGNAL( wellboresFinished( const QString& ) ), SLOT( wellboresFinished( const QString& ) ) ); - m_wellPathImportObject = wellPathImport; + connect( m_tableView->selectionModel(), + SIGNAL( selectionChanged( const QItemSelection&, const QItemSelection& ) ), + SLOT( selectWellbore( const QItemSelection&, const QItemSelection& ) ) ); - m_regionsWithVisibleWells = new ObjectGroupWithHeaders; - m_regionsWithVisibleWells->objects.uiCapability()->setUiHidden( true ); + connect( m_tableView->selectionModel(), + SIGNAL( selectionChanged( const QItemSelection&, const QItemSelection& ) ), + SIGNAL( completeChanged() ) ); } //-------------------------------------------------------------------------------------------------- @@ -851,211 +357,74 @@ void WellSelectionPage::initializePage() RiuWellImportWizard* wiz = dynamic_cast( wizard() ); if ( !wiz ) return; - wiz->downloadWells(); + QString fieldId = wiz->selectedFieldId(); + wiz->downloadWells( fieldId ); - setButtonText( QWizard::NextButton, "Download" ); + setButtonText( QWizard::NextButton, "Next" ); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -void WellSelectionPage::buildWellTreeView() +WellSelectionPage::~WellSelectionPage() { - for ( size_t rIdx = 0; rIdx < m_regionsWithVisibleWells->objects.size(); rIdx++ ) - { - caf::PdmObjectGroup* regGroup = dynamic_cast( m_regionsWithVisibleWells->objects[rIdx] ); - if ( !regGroup ) continue; - - for ( size_t fIdx = 0; fIdx < regGroup->objects.size(); fIdx++ ) - { - caf::PdmObjectGroup* fieldGroup = dynamic_cast( regGroup->objects[fIdx] ); - if ( !fieldGroup ) continue; - - // RimWellPathEntry objects are present here, they must be taken out out the container, but not deleted - // If fieldGroup->objects->deleteObjects is performed, the objects are deleted - fieldGroup->objects.clear(); - } - } - - // Delete all temporary pdm object groups - m_regionsWithVisibleWells->objects.deleteChildren(); - - for ( size_t rIdx = 0; rIdx < m_wellPathImportObject->regions.size(); rIdx++ ) - { - RimOilRegionEntry* oilRegion = m_wellPathImportObject->regions[rIdx]; - if ( oilRegion->selected ) - { - caf::PdmObjectCollection* regGroup = new caf::PdmObjectCollection; - regGroup->objects.uiCapability()->setUiHidden( true ); - - regGroup->setUiName( oilRegion->userDescriptionField()->uiCapability()->uiValue().toString() ); - - m_regionsWithVisibleWells->objects.push_back( regGroup ); - - for ( size_t fIdx = 0; fIdx < oilRegion->fields.size(); fIdx++ ) - { - RimOilFieldEntry* oilField = oilRegion->fields[fIdx]; - if ( oilField->selected ) - { - caf::PdmObjectCollection* fieldGroup = new caf::PdmObjectCollection; - fieldGroup->objects.uiCapability()->setUiHidden( true ); - - fieldGroup->setUiName( oilField->userDescriptionField()->uiCapability()->uiValue().toString() ); - - regGroup->objects.push_back( fieldGroup ); - - for ( size_t wIdx = 0; wIdx < oilField->wells.size(); wIdx++ ) - { - RimWellPathEntry* wellPathEntry = oilField->wells[wIdx]; - - // Create a copy of the PdmObject, as it is not supported to have multiple parents of any - // objects - QString objStr = wellPathEntry->writeObjectToXmlString(); - - RimWellPathEntry* wellPathCopy = new RimWellPathEntry; - wellPathCopy->readObjectFromXmlString( objStr, caf::PdmDefaultObjectFactory::instance() ); - wellPathCopy->selected = true; - - fieldGroup->objects.push_back( wellPathCopy ); - } - - sortObjectsByDescription( fieldGroup ); - } - } - } - } - - m_wellSelectionTreeView->setPdmItem( m_regionsWithVisibleWells ); - m_regionsWithVisibleWells->updateConnectedEditors(); - - m_wellSelectionTreeView->treeView()->expandAll(); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -WellSelectionPage::~WellSelectionPage() +void WellSelectionPage::wellsFinished() { - if ( m_wellSelectionTreeView ) + std::vector wells = m_osduConnector->wells(); + for ( auto w : wells ) { - m_wellSelectionTreeView->setPdmItem( nullptr ); + m_osduConnector->requestWellboresByWellId( w.id ); } - delete m_regionsWithVisibleWells; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -void WellSelectionPage::selectedWellPathEntries( std::vector& downloadEntities, caf::PdmObjectHandle* objHandle ) +void WellSelectionPage::wellboresFinished( const QString& wellId ) { - if ( objHandle == nullptr ) - { - objHandle = m_regionsWithVisibleWells; - } - - std::vector childFields = objHandle->fields(); - for ( size_t i = 0; i < childFields.size(); i++ ) - { - std::vector childObjects = childFields[i]->children(); - - for ( size_t j = 0; j < childObjects.size(); j++ ) - { - RimWellPathEntry* wellPathEntry = ( dynamic_cast( childObjects[j] ) ); - if ( wellPathEntry ) - { - if ( wellPathEntry->selected && wellPathEntry->isWellPathValid() ) - { - DownloadEntity urlToFile; - - urlToFile.name = wellPathEntry->name; - urlToFile.requestUrl = wellPathEntry->requestUrl; - urlToFile.responseFilename = wellPathEntry->wellPathFilePath; - - downloadEntities.push_back( urlToFile ); - } - } - else - { - selectedWellPathEntries( downloadEntities, childObjects[j] ); - } - } - } + std::vector wellbores = m_osduConnector->wellbores( wellId ); + if ( !wellbores.empty() ) m_osduWellboresModel->setOsduWellbores( wellId, wellbores ); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -void WellSelectionPage::customMenuRequested( const QPoint& pos ) +bool WellSelectionPage::isComplete() const { - QMenu menu; - - RiaFeatureCommandContextHelper helper( m_wellSelectionTreeView ); - - caf::CmdFeatureMenuBuilder menuBuilder; - - menuBuilder << "RicToggleItemsOnFeature"; - menuBuilder << "RicToggleItemsOffFeature"; - menuBuilder << "RicToggleItemsFeature"; - menuBuilder << "RicToggleItemsOnOthersOffFeature"; - - menuBuilder.appendToMenu( &menu ); - - // Qt doc: QAbstractScrollArea and its subclasses that map the context menu event to coordinates of the - // viewport(). Since we might get this signal from different treeViews, we need to map the position accordingly. - QObject* senderObj = sender(); - QTreeView* treeView = dynamic_cast( senderObj ); - if ( treeView ) - { - QPoint globalPos = treeView->viewport()->mapToGlobal( pos ); - menu.exec( globalPos ); - } + QItemSelectionModel* select = m_tableView->selectionModel(); + return select->selectedRows().size() == 1; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -bool lessByDescription( const caf::PdmPointer& obj1, const caf::PdmPointer& obj2 ) +void WellSelectionPage::selectWellbore( const QItemSelection& newSelection, const QItemSelection& oldSelection ) { - caf::PdmUiFieldHandle* uiFieldHandle1 = nullptr; - caf::PdmUiFieldHandle* uiFieldHandle2 = nullptr; - - if ( obj1.notNull() && obj1->uiCapability() && obj1->uiCapability()->userDescriptionField() ) - { - uiFieldHandle1 = obj1->uiCapability()->userDescriptionField()->uiCapability(); - } - - if ( obj2.notNull() && obj2->uiCapability() && obj2->uiCapability()->userDescriptionField() ) + if ( !newSelection.indexes().empty() ) { - uiFieldHandle2 = obj2->uiCapability()->userDescriptionField()->uiCapability(); + QModelIndex index = newSelection.indexes()[0]; + int column = 0; + QString wellboreId = m_osduWellboresModel->data( index.siblingAtColumn( column ) ).toString(); + RiuWellImportWizard* wiz = dynamic_cast( wizard() ); + wiz->setSelectedWellboreId( wellboreId ); } - - if ( uiFieldHandle1 && uiFieldHandle2 ) - { - QString string1 = uiFieldHandle1->uiValue().toString(); - QString string2 = uiFieldHandle2->uiValue().toString(); - - return string1 < string2; - } - - return true; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -void WellSelectionPage::sortObjectsByDescription( caf::PdmObjectCollection* objects ) -{ - std::sort( objects->objects.begin(), objects->objects.end(), lessByDescription ); -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -WellSummaryPage::WellSummaryPage( RimWellPathImport* wellPathImport, QWidget* parent /*= 0*/ ) +WellSummaryPage::WellSummaryPage( RimWellPathImport* wellPathImport, RiaOsduConnector* osduConnector, QWidget* parent /*= 0*/ ) { m_wellPathImportObject = wellPathImport; m_wellPathImportObject->setUiHidden( true ); + m_osduConnector = osduConnector; + QVBoxLayout* layout = new QVBoxLayout; setLayout( layout ); @@ -1063,18 +432,10 @@ WellSummaryPage::WellSummaryPage( RimWellPathImport* wellPathImport, QWidget* pa m_textEdit->setReadOnly( true ); layout->addWidget( m_textEdit ); - QPushButton* button = new QPushButton( "Show/hide details", this ); - connect( button, SIGNAL( clicked() ), this, SLOT( slotShowDetails() ) ); - layout->addWidget( button ); - - m_listView = new caf::PdmUiListView( this ); - layout->setStretchFactor( m_listView, 10 ); - layout->addWidget( m_listView ); - m_listView->hide(); - - m_objectGroup = new caf::PdmObjectCollection; - setButtonText( QWizard::FinishButton, "Import" ); + + connect( m_osduConnector, SIGNAL( wellboreTrajectoryFinished( const QString& ) ), SLOT( wellboreTrajectoryFinished( const QString& ) ) ); + connect( m_osduConnector, SIGNAL( fileDownloadFinished( const QString& ) ), SLOT( fileDownloadFinished( const QString& ) ) ); } //-------------------------------------------------------------------------------------------------- @@ -1083,98 +444,59 @@ WellSummaryPage::WellSummaryPage( RimWellPathImport* wellPathImport, QWidget* pa void WellSummaryPage::initializePage() { RiuWellImportWizard* wiz = dynamic_cast( wizard() ); - wiz->downloadWellPaths(); + + QString wellboreId = wiz->selectedWellboreId(); + wiz->downloadWellPaths( wellboreId ); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -void WellSummaryPage::updateSummaryPage() +void WellSummaryPage::fileDownloadFinished( const QString& fileId, const QString& filePath ) { - m_objectGroup->objects.deleteChildren(); - m_textEdit->setText( "Summary of imported wells\n\n" ); - size_t wellPathCount = 0; - QString errorString; - - RiuWellImportWizard* wiz = dynamic_cast( wizard() ); - WellSelectionPage* wellSelectionPage = dynamic_cast( wiz->page( wiz->wellSelectionPageId() ) ); - std::vector downloadEntities; - wellSelectionPage->selectedWellPathEntries( downloadEntities, nullptr ); - - for ( size_t i = 0; i < downloadEntities.size(); i++ ) - { - if ( caf::Utils::fileExists( downloadEntities[i].responseFilename ) ) - { - wellPathCount++; - } - else - { - errorString += - QString( "Failed to get file '%1' from well '%2'\n" ).arg( downloadEntities[i].responseFilename ).arg( downloadEntities[i].name ); - } - - SummaryPageDownloadEntity* sumPageEntity = new SummaryPageDownloadEntity; - sumPageEntity->name = downloadEntities[i].name; - sumPageEntity->responseFilename = downloadEntities[i].responseFilename; - sumPageEntity->requestUrl = downloadEntities[i].requestUrl; - - m_objectGroup->objects().push_back( sumPageEntity ); - } - - m_textEdit->setText( QString( "Downloaded successfully %1 well paths.\nPlease push 'Import' button to import well " - "paths into ResInsight.\n\n" ) - .arg( wellPathCount ) ); - if ( !errorString.isEmpty() ) - { - m_textEdit->append( "Detected following errors during well path download. See details below." ); - m_textEdit->append( errorString ); - } - - m_listView->setPdmObject( m_objectGroup ); - m_objectGroup->updateConnectedEditors(); + m_textEdit->append( "FileId:" ); + m_textEdit->append( fileId ); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -void WellSummaryPage::slotShowDetails() +void WellSummaryPage::wellboreTrajectoryFinished( const QString& wellboreId ) { - if ( m_listView->isHidden() ) - { - m_listView->show(); - } - else - { - m_listView->hide(); - } -} + std::vector wellboreTrajectories = m_osduConnector->wellboreTrajectories( wellboreId ); + std::vector wells = m_osduConnector->wells(); -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void ObjectGroupWithHeaders::defineObjectEditorAttribute( QString uiConfigName, caf::PdmUiEditorAttribute* attribute ) -{ - caf::PdmUiTreeViewEditorAttribute* myAttr = dynamic_cast( attribute ); - if ( myAttr ) + auto findWellForWellId = []( const std::vector& wells, const QString& wellId ) -> std::optional { - QStringList colHeaders; - colHeaders << "Wells"; - myAttr->columnHeaders = colHeaders; - } -} + auto it = std::find_if( wells.begin(), wells.end(), [wellId]( const OsduWell& w ) { return w.id == wellId; } ); + if ( it != wells.end() ) + return std::optional( *it ); + else + return {}; + }; -CAF_PDM_SOURCE_INIT( SummaryPageDownloadEntity, "SummaryPageDownloadEntity" ); + RiuWellImportWizard* wiz = dynamic_cast( wizard() ); -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -SummaryPageDownloadEntity::SummaryPageDownloadEntity() -{ - CAF_PDM_InitObject( "SummaryPageDownloadEntity" ); + for ( auto w : wellboreTrajectories ) + { + // TODO: remove hack. A lot of the data set IDs in OSDU has trailing ":" which should not be + // there (i.e. the real id is without it). Chop them off to make more data sets work. + QString fileId = w.dataSetId; + if ( fileId.endsWith( ":" ) ) fileId.truncate( fileId.lastIndexOf( QChar( ':' ) ) ); + + QString wellId = m_osduConnector->wellIdForWellboreId( w.wellboreId ); + std::optional well = findWellForWellId( wells, wellId ); - CAF_PDM_InitFieldNoDefault( &name, "Name", "" ); - CAF_PDM_InitFieldNoDefault( &requestUrl, "RequestUrl", "" ); - CAF_PDM_InitFieldNoDefault( &responseFilename, "ResponseFilename", "" ); + if ( well.has_value() ) + { + QString wellboreTrajectoryId = w.id; + wiz->addWellInfo( { .name = well.value().name, + .wellId = well.value().id, + .wellboreId = w.wellboreId, + .wellboreTrajectoryId = wellboreTrajectoryId, + .fileId = fileId } ); + } + } } diff --git a/ApplicationLibCode/Commands/OsduImportCommands/RiuWellImportWizard.h b/ApplicationLibCode/Commands/OsduImportCommands/RiuWellImportWizard.h index 16c841312f8..deb3b4f33b3 100644 --- a/ApplicationLibCode/Commands/OsduImportCommands/RiuWellImportWizard.h +++ b/ApplicationLibCode/Commands/OsduImportCommands/RiuWellImportWizard.h @@ -18,10 +18,6 @@ #pragma once -#include "cafPdmChildArrayField.h" -#include "cafPdmField.h" -#include "cafPdmObject.h" - #include #include #include @@ -29,105 +25,232 @@ #include #include +#include "RiaOsduConnector.h" + class QFile; -class QProgressDialog; class QLabel; class QTextEdit; +class QTableView; class RimWellPathImport; -class RimOilFieldEntry; -class RimWellPathEntry; namespace caf { class PdmUiTreeView; class PdmUiListView; class PdmUiPropertyView; -class PdmObjectCollection; } // namespace caf -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -class AuthenticationPage : public QWizardPage +class OsduFieldTableModel : public QAbstractTableModel { Q_OBJECT public: - AuthenticationPage( const QString& webServiceAddress, QWidget* parent = nullptr ); - - void initializePage() override; -}; + explicit OsduFieldTableModel( QObject* parent = nullptr ) + : QAbstractTableModel( parent ) + { + } -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -class FieldSelectionPage : public QWizardPage -{ - Q_OBJECT + int rowCount( const QModelIndex& parent = QModelIndex() ) const override + { + Q_UNUSED( parent ); + return static_cast( m_osduFields.size() ); + } -public: - FieldSelectionPage( RimWellPathImport* wellPathImport, QWidget* parent = nullptr ); - ~FieldSelectionPage() override; + int columnCount( const QModelIndex& parent = QModelIndex() ) const override + { + Q_UNUSED( parent ); + // Assuming you have three fields: id, kind, and name + return 3; + } - void initializePage() override; + QVariant data( const QModelIndex& index, int role = Qt::DisplayRole ) const override + { + if ( !index.isValid() ) return QVariant(); + + if ( index.row() >= static_cast( m_osduFields.size() ) || index.row() < 0 ) return QVariant(); + + if ( role == Qt::DisplayRole ) + { + const OsduField& field = m_osduFields.at( index.row() ); + switch ( index.column() ) + { + case 0: + return field.id; + case 1: + return field.kind; + case 2: + return field.name; + default: + return QVariant(); + } + } + + return QVariant(); + } + + QVariant headerData( int section, Qt::Orientation orientation, int role = Qt::DisplayRole ) const override + { + if ( role != Qt::DisplayRole ) return QVariant(); + + if ( orientation == Qt::Horizontal ) + { + switch ( section ) + { + case 0: + return tr( "ID" ); + case 1: + return tr( "Kind" ); + case 2: + return tr( "Name" ); + default: + return QVariant(); + } + } + return QVariant(); + } + + void setOsduFields( const std::vector& osduFields ) + { + beginInsertRows( QModelIndex(), 0, static_cast( osduFields.size() ) ); + m_osduFields = osduFields; + endInsertRows(); + } private: - caf::PdmUiPropertyView* m_propertyView; + std::vector m_osduFields; }; -//-------------------------------------------------------------------------------------------------- -/// Container class used to define column headers -//-------------------------------------------------------------------------------------------------- -class ObjectGroupWithHeaders : public caf::PdmObject +class OsduWellboreTableModel : public QAbstractTableModel { - CAF_PDM_HEADER_INIT; + Q_OBJECT public: - ObjectGroupWithHeaders() + explicit OsduWellboreTableModel( QObject* parent = nullptr ) + : QAbstractTableModel( parent ) { - CAF_PDM_InitFieldNoDefault( &objects, "PdmObjects", "" ); - - CAF_PDM_InitField( &m_isChecked, "IsChecked", true, "Active" ); - m_isChecked.uiCapability()->setUiHidden( true ); - }; + } - void defineObjectEditorAttribute( QString uiConfigName, caf::PdmUiEditorAttribute* attribute ) override; + int rowCount( const QModelIndex& parent = QModelIndex() ) const override + { + Q_UNUSED( parent ); + return static_cast( m_osduWellbores.size() ); + } -public: - caf::PdmChildArrayField objects; + int columnCount( const QModelIndex& parent = QModelIndex() ) const override + { + Q_UNUSED( parent ); + // Assuming you have three fields: id, kind, and name + return 3; + } -protected: - caf::PdmFieldHandle* objectToggleField() override { return &m_isChecked; } + QVariant data( const QModelIndex& index, int role = Qt::DisplayRole ) const override + { + if ( !index.isValid() ) return QVariant(); + + if ( index.row() >= static_cast( m_osduWellbores.size() ) || index.row() < 0 ) return QVariant(); + + if ( role == Qt::DisplayRole ) + { + const OsduWellbore& field = m_osduWellbores.at( index.row() ); + switch ( index.column() ) + { + case 0: + return field.id; + case 1: + return field.kind; + case 2: + return field.name; + default: + return QVariant(); + } + } + + return QVariant(); + } + + QVariant headerData( int section, Qt::Orientation orientation, int role = Qt::DisplayRole ) const override + { + if ( role != Qt::DisplayRole ) return QVariant(); + + if ( orientation == Qt::Horizontal ) + { + switch ( section ) + { + case 0: + return tr( "ID" ); + case 1: + return tr( "Kind" ); + case 2: + return tr( "Name" ); + default: + return QVariant(); + } + } + return QVariant(); + } + + void setOsduWellbores( const QString& wellId, const std::vector& osduWellbores ) + { + m_map[wellId] = osduWellbores; + m_osduWellbores.clear(); + for ( auto [name, values] : m_map ) + { + for ( auto v : values ) + m_osduWellbores.push_back( v ); + } + + beginInsertRows( QModelIndex(), 0, static_cast( m_osduWellbores.size() ) ); + endInsertRows(); + } -protected: - caf::PdmField m_isChecked; +private: + std::vector m_osduWellbores; + std::map> m_map; }; //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -class DownloadEntity +class AuthenticationPage : public QWizardPage { + Q_OBJECT + public: - QString name; - QString requestUrl; - QString responseFilename; + AuthenticationPage( RiaOsduConnector* osduConnector, QWidget* parent = nullptr ); + + void initializePage() override; + bool isComplete() const override; + +private slots: + void accessOk(); + +private: + bool m_accessOk; }; //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -class SummaryPageDownloadEntity : public caf::PdmObject +class FieldSelectionPage : public QWizardPage { - CAF_PDM_HEADER_INIT; + Q_OBJECT public: - SummaryPageDownloadEntity(); + FieldSelectionPage( RimWellPathImport* wellPathImport, RiaOsduConnector* m_osduConnector, QWidget* parent = nullptr ); + ~FieldSelectionPage() override; - caf::PdmField name; - caf::PdmField requestUrl; - caf::PdmField responseFilename; + void initializePage() override; + bool isComplete() const override; +private slots: + void fieldsFinished(); + void selectField( const QItemSelection& newSelection, const QItemSelection& oldSelection ); + +private: + // caf::PdmUiPropertyView* m_propertyView; + RiaOsduConnector* m_osduConnector; + QTableView* m_tableView; + OsduFieldTableModel* m_osduFieldsModel; }; //-------------------------------------------------------------------------------------------------- @@ -138,24 +261,22 @@ class WellSelectionPage : public QWizardPage Q_OBJECT public: - WellSelectionPage( RimWellPathImport* wellPathImport, QWidget* parent = nullptr ); + WellSelectionPage( RimWellPathImport* wellPathImport, RiaOsduConnector* m_osduConnector, QWidget* parent = nullptr ); ~WellSelectionPage() override; void initializePage() override; - void buildWellTreeView(); - - void selectedWellPathEntries( std::vector& downloadEntities, caf::PdmObjectHandle* objHandle ); - -private: - void sortObjectsByDescription( caf::PdmObjectCollection* objects ); + bool isComplete() const override; private slots: - void customMenuRequested( const QPoint& pos ); + void wellboresFinished( const QString& wellId ); + void wellsFinished(); + void selectWellbore( const QItemSelection& newSelection, const QItemSelection& oldSelection ); private: - ObjectGroupWithHeaders* m_regionsWithVisibleWells; RimWellPathImport* m_wellPathImportObject; - caf::PdmUiTreeView* m_wellSelectionTreeView; + RiaOsduConnector* m_osduConnector; + QTableView* m_tableView; + OsduWellboreTableModel* m_osduWellboresModel; }; //-------------------------------------------------------------------------------------------------- @@ -166,20 +287,18 @@ class WellSummaryPage : public QWizardPage Q_OBJECT public: - WellSummaryPage( RimWellPathImport* wellPathImport, QWidget* parent = nullptr ); + WellSummaryPage( RimWellPathImport* wellPathImport, RiaOsduConnector* osduConnector, QWidget* parent = nullptr ); void initializePage() override; - void updateSummaryPage(); - private slots: - void slotShowDetails(); + void wellboreTrajectoryFinished( const QString& wellId ); + void fileDownloadFinished( const QString& fileId, const QString& filePath ); private: - RimWellPathImport* m_wellPathImportObject; - QTextEdit* m_textEdit; - caf::PdmUiListView* m_listView; - caf::PdmObjectCollection* m_objectGroup; + RimWellPathImport* m_wellPathImportObject; + RiaOsduConnector* m_osduConnector; + QTextEdit* m_textEdit; }; //-------------------------------------------------------------------------------------------------- @@ -190,88 +309,50 @@ class RiuWellImportWizard : public QWizard Q_OBJECT public: - enum DownloadState + struct WellInfo { - DOWNLOAD_FIELDS, - DOWNLOAD_WELLS, - DOWNLOAD_WELL_PATH, - DOWNLOAD_UNDEFINED + QString name; + QString wellId; + QString wellboreId; + QString wellboreTrajectoryId; + QString fileId; }; -public: - RiuWellImportWizard( const QString& webServiceAddress, - const QString& downloadFolder, + RiuWellImportWizard( const QString& downloadFolder, + RiaOsduConnector* osduConnector, RimWellPathImport* wellPathImportObject, QWidget* parent = nullptr ); ~RiuWellImportWizard() override; - void setCredentials( const QString& username, const QString& password ); - QStringList absoluteFilePathsToWellPaths() const; - // Methods used from the wizard pages void resetAuthenticationCount(); -public slots: - void downloadWellPaths(); - void downloadWells(); - void downloadFields(); + void setSelectedFieldId( const QString& fieldId ); + QString selectedFieldId() const; + void setSelectedWellboreId( const QString& wellboreId ); + QString selectedWellboreId() const; - void checkDownloadQueueAndIssueRequests(); + void addWellInfo( RiuWellImportWizard::WellInfo wellInfo ); + std::vector importedWells() const; - void issueHttpRequestToFile( QString completeUrlText, QString destinationFileName ); - void cancelDownload(); - - void httpFinished(); - void httpReadyRead(); +public slots: + void downloadWellPaths( const QString& wellboreId ); + void downloadWells( const QString& fieldId ); + void downloadFields(); void slotAuthenticationRequired( QNetworkReply* networkReply, QAuthenticator* authenticator ); - int wellSelectionPageId(); - -#if !defined( QT_NO_OPENSSL ) && !defined( CVF_OSX ) - void sslErrors( QNetworkReply*, const QList& errors ); -#endif - -private slots: - void slotCurrentIdChanged( int currentId ); - private: - void startRequest( QUrl url ); - void setUrl( const QString& httpAddress ); + RiaOsduConnector* m_osduConnector; + QString m_selectedFieldId; + QString m_selectedWellboreId; - QString jsonFieldsFilePath(); - QString jsonWellsFilePath(); - - void updateFieldsModel(); - void parseWellsResponse( RimOilFieldEntry* oilFieldEntry ); - - QString getValue( const QString& key, const QString& stringContent ); - - QProgressDialog* progressDialog(); - void hideProgressDialog(); - -private: - QString m_webServiceAddress; QString m_destinationFolder; RimWellPathImport* m_wellPathImportObject; caf::PdmUiTreeView* m_pdmTreeView; - QProgressDialog* m_myProgressDialog; - - QUrl m_url; - QNetworkAccessManager m_networkAccessManager; - QNetworkReply* m_reply; - QFile* m_file; - bool m_httpRequestAborted; - bool m_firstTimeRequestingAuthentication; - QList m_wellRequestQueue; - - DownloadState m_currentDownloadState; - - int m_fieldSelectionPageId; - int m_wellSelectionPageId; - int m_wellSummaryPageId; + std::vector m_wellInfos; }; diff --git a/ApplicationLibCode/FileInterface/CMakeLists_files.cmake b/ApplicationLibCode/FileInterface/CMakeLists_files.cmake index 8d2d0a81233..f44a0e80f43 100644 --- a/ApplicationLibCode/FileInterface/CMakeLists_files.cmake +++ b/ApplicationLibCode/FileInterface/CMakeLists_files.cmake @@ -96,6 +96,7 @@ set(SOURCE_GROUP_HEADER_FILES ${CMAKE_CURRENT_LIST_DIR}/RifSummaryCalculationImporter.h ${CMAKE_CURRENT_LIST_DIR}/RifSummaryCalculationExporter.h ${CMAKE_CURRENT_LIST_DIR}/RifPolygonReader.h + ${CMAKE_CURRENT_LIST_DIR}/RifOsduWellPathReader.h ) set(SOURCE_GROUP_SOURCE_FILES @@ -191,6 +192,7 @@ set(SOURCE_GROUP_SOURCE_FILES ${CMAKE_CURRENT_LIST_DIR}/RifSummaryCalculationImporter.cpp ${CMAKE_CURRENT_LIST_DIR}/RifSummaryCalculationExporter.cpp ${CMAKE_CURRENT_LIST_DIR}/RifPolygonReader.cpp + ${CMAKE_CURRENT_LIST_DIR}/RifOsduWellPathReader.cpp ) list(APPEND CODE_HEADER_FILES ${SOURCE_GROUP_HEADER_FILES}) diff --git a/ApplicationLibCode/FileInterface/RifOsduWellPathReader.cpp b/ApplicationLibCode/FileInterface/RifOsduWellPathReader.cpp new file mode 100644 index 00000000000..2ac47bb23d5 --- /dev/null +++ b/ApplicationLibCode/FileInterface/RifOsduWellPathReader.cpp @@ -0,0 +1,92 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2024 Equinor ASA +// +// ResInsight 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. +// +// ResInsight 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 at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#include "RifOsduWellPathReader.h" + +#include "RiaTextStringTools.h" + +#include "SummaryPlotCommands/RicPasteAsciiDataToSummaryPlotFeatureUi.h" + +#include "RifCsvUserDataParser.h" + +#include "RigWellPath.h" + +#include "cvfObject.h" +#include "cvfVector3.h" + +#include +#include + +std::pair, QString> RifOsduWellPathReader::parseCsv( const QString& content ) +{ + QString errorMessage; + RifCsvUserDataPastedTextParser parser( content, &errorMessage ); + + AsciiDataParseOptions parseOptions; + parseOptions.cellSeparator = ","; + parseOptions.decimalSeparator = "."; + + std::vector>> readValues; + + if ( parser.parse( parseOptions ) ) + { + for ( auto s : parser.tableData().columnInfos() ) + { + if ( s.dataType != Column::NUMERIC ) continue; + + QString columnName = QString::fromStdString( s.columnName() ); + bool isNumber = false; + auto value = columnName.toDouble( &isNumber ); + std::vector values = s.values; + if ( isNumber ) + { + values.insert( values.begin(), value ); + } + readValues.push_back( { columnName, values } ); + } + } + + const int MD_INDEX = 0; + const int TVD_INDEX = 1; + const int X_INDEX = 4; + const int Y_INDEX = 5; + + if ( readValues.size() == 10 ) + { + const size_t firstSize = readValues[MD_INDEX].second.size(); + if ( ( firstSize == readValues[TVD_INDEX].second.size() ) && ( firstSize == readValues[X_INDEX].second.size() ) && + ( firstSize == readValues[Y_INDEX].second.size() ) ) + { + std::vector wellPathPoints; + std::vector measuredDepths; + + for ( size_t i = 0; i < firstSize; i++ ) + { + cvf::Vec3d point( readValues[X_INDEX].second[i], readValues[Y_INDEX].second[i], -readValues[TVD_INDEX].second[i] ); + double md = readValues[MD_INDEX].second[i]; + + wellPathPoints.push_back( point ); + measuredDepths.push_back( md ); + } + + return { new RigWellPath( wellPathPoints, measuredDepths ), "" }; + } + } + + return { nullptr, "Oh no!" }; +} diff --git a/ApplicationLibCode/FileInterface/RifOsduWellPathReader.h b/ApplicationLibCode/FileInterface/RifOsduWellPathReader.h new file mode 100644 index 00000000000..a78859dd6f7 --- /dev/null +++ b/ApplicationLibCode/FileInterface/RifOsduWellPathReader.h @@ -0,0 +1,35 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2024- Equinor ASA +// +// ResInsight 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. +// +// ResInsight 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 at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#pragma once + +#include + +#include "cvfObject.h" + +class RigWellPath; + +//================================================================================================== +// +// +//================================================================================================== +class RifOsduWellPathReader +{ +public: + static std::pair, QString> parseCsv( const QString& content ); +}; diff --git a/ApplicationLibCode/ProjectDataModel/RimContextCommandBuilder.cpp b/ApplicationLibCode/ProjectDataModel/RimContextCommandBuilder.cpp index 19dbea920c2..8bc343eed31 100644 --- a/ApplicationLibCode/ProjectDataModel/RimContextCommandBuilder.cpp +++ b/ApplicationLibCode/ProjectDataModel/RimContextCommandBuilder.cpp @@ -370,7 +370,7 @@ caf::CmdFeatureMenuBuilder RimContextCommandBuilder::commandsFromSelection() menuBuilder.addSeparator(); menuBuilder.subMenuStart( "Import" ); menuBuilder << "RicWellPathsImportFileFeature"; - menuBuilder << "RicWellPathsImportSsihubFeature"; + menuBuilder << "RicWellPathsImportOsduFeature"; menuBuilder << "RicWellPathFormationsImportFileFeature"; menuBuilder << "RicWellLogsImportFileFeature"; menuBuilder << "RicReloadWellPathFormationNamesFeature"; diff --git a/ApplicationLibCode/ProjectDataModel/RimProject.cpp b/ApplicationLibCode/ProjectDataModel/RimProject.cpp index a9ae2a490b5..18b1710b5c6 100644 --- a/ApplicationLibCode/ProjectDataModel/RimProject.cpp +++ b/ApplicationLibCode/ProjectDataModel/RimProject.cpp @@ -270,8 +270,6 @@ void RimProject::close() casesObsolete.deleteChildren(); caseGroupsObsolete.deleteChildren(); - wellPathImport->regions().deleteChildren(); - commandObjects.deleteChildren(); multiSnapshotDefinitions.deleteChildren(); @@ -512,7 +510,6 @@ void RimProject::setProjectFileNameAndUpdateDependencies( const QString& project filePath->setPath( newFilePath ); } - wellPathImport->updateFilePaths(); auto* wellPathColl = RimTools::wellPathCollection(); if ( wellPathColl ) { diff --git a/ApplicationLibCode/ProjectDataModel/WellPath/CMakeLists_files.cmake b/ApplicationLibCode/ProjectDataModel/WellPath/CMakeLists_files.cmake index fd3d9472d25..ab55fcaf614 100644 --- a/ApplicationLibCode/ProjectDataModel/WellPath/CMakeLists_files.cmake +++ b/ApplicationLibCode/ProjectDataModel/WellPath/CMakeLists_files.cmake @@ -15,6 +15,7 @@ set(SOURCE_GROUP_HEADER_FILES ${CMAKE_CURRENT_LIST_DIR}/RimWellIAModelBox.h ${CMAKE_CURRENT_LIST_DIR}/RimWellIAModelData.h ${CMAKE_CURRENT_LIST_DIR}/RimWellIADataAccess.h + ${CMAKE_CURRENT_LIST_DIR}/RimOsduWellPath.h ) set(SOURCE_GROUP_SOURCE_FILES @@ -34,6 +35,7 @@ set(SOURCE_GROUP_SOURCE_FILES ${CMAKE_CURRENT_LIST_DIR}/RimWellIAModelBox.cpp ${CMAKE_CURRENT_LIST_DIR}/RimWellIAModelData.cpp ${CMAKE_CURRENT_LIST_DIR}/RimWellIADataAccess.cpp + ${CMAKE_CURRENT_LIST_DIR}/RimOsduWellPath.cpp ) list(APPEND CODE_HEADER_FILES ${SOURCE_GROUP_HEADER_FILES}) diff --git a/ApplicationLibCode/ProjectDataModel/WellPath/RimOsduWellPath.cpp b/ApplicationLibCode/ProjectDataModel/WellPath/RimOsduWellPath.cpp new file mode 100644 index 00000000000..75298289395 --- /dev/null +++ b/ApplicationLibCode/ProjectDataModel/WellPath/RimOsduWellPath.cpp @@ -0,0 +1,110 @@ +#include "RimOsduWellPath.h" + +#include "cafPdmObjectScriptingCapability.h" + +CAF_PDM_SOURCE_INIT( RimOsduWellPath, "OsduWellPath" ); + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RimOsduWellPath::RimOsduWellPath() +{ + CAF_PDM_InitScriptableObjectWithNameAndComment( "Osdu Well Path", ":/Well.svg", "", "", "OsduWellPath", "Well Path Loaded From Osdu" ); + + CAF_PDM_InitFieldNoDefault( &m_wellId, "WellId", "Well Id" ); + m_wellId.uiCapability()->setUiReadOnly( true ); + + CAF_PDM_InitFieldNoDefault( &m_wellboreId, "WellboreId", "Wellbore Id" ); + m_wellboreId.uiCapability()->setUiReadOnly( true ); + + CAF_PDM_InitFieldNoDefault( &m_wellboreTrajectoryId, "WellboreTrajectoryId", "Wellbore Trajectory Id" ); + m_wellboreTrajectoryId.uiCapability()->setUiReadOnly( true ); + + CAF_PDM_InitFieldNoDefault( &m_fileId, "FileId", "File Id" ); + m_fileId.uiCapability()->setUiReadOnly( true ); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RimOsduWellPath::~RimOsduWellPath() +{ +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimOsduWellPath::setWellId( const QString& wellId ) +{ + m_wellId = wellId; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QString RimOsduWellPath::wellId() const +{ + return m_wellId; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimOsduWellPath::setWellboreId( const QString& wellboreId ) +{ + m_wellboreId = wellboreId; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QString RimOsduWellPath::wellboreId() const +{ + return m_wellboreId; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimOsduWellPath::setWellboreTrajectoryId( const QString& wellboreTrajectoryId ) +{ + m_wellboreTrajectoryId = wellboreTrajectoryId; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QString RimOsduWellPath::wellboreTrajectoryId() const +{ + return m_wellboreTrajectoryId; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimOsduWellPath::setFileId( const QString& fileId ) +{ + m_fileId = fileId; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QString RimOsduWellPath::fileId() const +{ + return m_fileId; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimOsduWellPath::defineUiOrdering( QString uiConfigName, caf::PdmUiOrdering& uiOrdering ) +{ + caf::PdmUiGroup* osduGroup = uiOrdering.addNewGroup( "OSDU" ); + osduGroup->add( &m_wellId ); + osduGroup->add( &m_wellboreId ); + osduGroup->add( &m_wellboreTrajectoryId ); + osduGroup->add( &m_fileId ); + + RimWellPath::defineUiOrdering( uiConfigName, uiOrdering ); +} diff --git a/ApplicationLibCode/ProjectDataModel/WellPath/RimOsduWellPath.h b/ApplicationLibCode/ProjectDataModel/WellPath/RimOsduWellPath.h new file mode 100644 index 00000000000..a1968cf336e --- /dev/null +++ b/ApplicationLibCode/ProjectDataModel/WellPath/RimOsduWellPath.h @@ -0,0 +1,50 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2024- Equinor ASA +// +// ResInsight 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. +// +// ResInsight 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 at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// +#pragma once + +#include "RimWellPath.h" + +class RimOsduWellPath : public RimWellPath +{ + CAF_PDM_HEADER_INIT; + +public: + RimOsduWellPath(); + ~RimOsduWellPath() override; + + void setWellId( const QString& wellId ); + QString wellId() const; + + void setWellboreId( const QString& wellboreId ); + QString wellboreId() const; + + void setWellboreTrajectoryId( const QString& wellboreTrajectoryId ); + QString wellboreTrajectoryId() const; + + void setFileId( const QString& fileId ); + QString fileId() const; + +protected: + void defineUiOrdering( QString uiConfigName, caf::PdmUiOrdering& uiOrdering ) override; + +private: + caf::PdmField m_wellId; + caf::PdmField m_wellboreId; + caf::PdmField m_wellboreTrajectoryId; + caf::PdmField m_fileId; +}; diff --git a/ApplicationLibCode/ProjectDataModel/WellPath/RimWellPathCollection.cpp b/ApplicationLibCode/ProjectDataModel/WellPath/RimWellPathCollection.cpp index e258825897c..7aa323c3715 100644 --- a/ApplicationLibCode/ProjectDataModel/WellPath/RimWellPathCollection.cpp +++ b/ApplicationLibCode/ProjectDataModel/WellPath/RimWellPathCollection.cpp @@ -20,6 +20,7 @@ #include "RimWellPathCollection.h" +#include "OsduImportCommands/RiaOsduConnector.h" #include "RiaColorTables.h" #include "RiaGuiApplication.h" #include "RiaLogging.h" @@ -27,6 +28,7 @@ #include "RiaTextStringTools.h" #include "RiaWellNameComparer.h" +#include "RifOsduWellPathReader.h" #include "RifWellPathFormationsImporter.h" #include "RifWellPathImporter.h" @@ -40,6 +42,7 @@ #include "RimFileWellPath.h" #include "RimModeledWellPath.h" #include "RimOilField.h" +#include "RimOsduWellPath.h" #include "RimPerforationCollection.h" #include "RimProject.h" #include "RimStimPlanModel.h" @@ -50,6 +53,8 @@ #include "RimWellPathCompletionSettings.h" #include "RimWellPathTieIn.h" +#include "RiuMainWindow.h" + #include "cafTreeNode.h" // TODO: Move to caf #include "Riu3DMainWindowTools.h" @@ -67,6 +72,7 @@ #include #include +#include namespace caf { @@ -149,6 +155,7 @@ void RimWellPathCollection::loadDataAndUpdate() auto* fWPath = dynamic_cast( wellPath ); auto* mWPath = dynamic_cast( wellPath ); + auto* oWPath = dynamic_cast( wellPath ); if ( fWPath ) { if ( !fWPath->filePath().isEmpty() ) @@ -164,6 +171,31 @@ void RimWellPathCollection::loadDataAndUpdate() { mWPath->createWellPathGeometry(); } + else if ( oWPath ) + { + RiaApplication* app = RiaApplication::instance(); + + RiaPreferencesOsdu* osduPreferences = app->preferences()->osduPreferences(); + + const QString server = osduPreferences->server(); + const QString dataParitionId = osduPreferences->dataPartitionId(); + const QString authority = osduPreferences->authority(); + const QString scopes = osduPreferences->scopes(); + const QString clientId = osduPreferences->clientId(); + + auto osduConnector = + std::make_unique( RiuMainWindow::instance(), server, dataParitionId, authority, scopes, clientId ); + + auto [wellPathGeometry, errorMessage] = loadWellPathGeometryFromOsdu( osduConnector.get(), oWPath->fileId() ); + if ( wellPathGeometry.notNull() ) + { + oWPath->setWellPathGeometry( wellPathGeometry.p() ); + } + else + { + RiaLogging::warning( errorMessage ); + } + } if ( wellPath ) { @@ -1013,3 +1045,18 @@ void RimWellPathCollection::onChildAdded( caf::PdmFieldHandle* containerForNewOb scheduleRedrawAffectedViews(); uiCapability()->updateConnectedEditors(); } + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +std::pair, QString> RimWellPathCollection::loadWellPathGeometryFromOsdu( RiaOsduConnector* osduConnector, + const QString& fileId ) +{ + auto [fileContents, errorMessage] = osduConnector->requestFileContentsById( fileId ); + if ( !errorMessage.isEmpty() ) + { + return { nullptr, errorMessage }; + } + + return RifOsduWellPathReader::parseCsv( fileContents ); +} diff --git a/ApplicationLibCode/ProjectDataModel/WellPath/RimWellPathCollection.h b/ApplicationLibCode/ProjectDataModel/WellPath/RimWellPathCollection.h index db57a692253..84e7d630353 100644 --- a/ApplicationLibCode/ProjectDataModel/WellPath/RimWellPathCollection.h +++ b/ApplicationLibCode/ProjectDataModel/WellPath/RimWellPathCollection.h @@ -38,6 +38,7 @@ #include +class RiaOsduConnector; class RifWellPathImporter; class RigWellPath; class RimFileWellPath; @@ -131,6 +132,8 @@ class RimWellPathCollection : public caf::PdmObject void onChildAdded( caf::PdmFieldHandle* containerForNewObject ) override; + static std::pair, QString> loadWellPathGeometryFromOsdu( RiaOsduConnector* osduConnector, const QString& fileId ); + protected: void fieldChangedByUi( const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue ) override; diff --git a/ApplicationLibCode/UnitTests/CMakeLists.txt b/ApplicationLibCode/UnitTests/CMakeLists.txt index ac7d8e0de61..7a484008a54 100644 --- a/ApplicationLibCode/UnitTests/CMakeLists.txt +++ b/ApplicationLibCode/UnitTests/CMakeLists.txt @@ -103,6 +103,7 @@ set(SOURCE_UNITTEST_FILES ${CMAKE_CURRENT_LIST_DIR}/RimEmReader-Test.cpp ${CMAKE_CURRENT_LIST_DIR}/RifPolygonReader-Test.cpp ${CMAKE_CURRENT_LIST_DIR}/RifParquetReader-Test.cpp + ${CMAKE_CURRENT_LIST_DIR}/RifOsduWellPathReader-Test.cpp ) if(RESINSIGHT_ENABLE_GRPC) diff --git a/ApplicationLibCode/UnitTests/RifOsduWellPathReader-Test.cpp b/ApplicationLibCode/UnitTests/RifOsduWellPathReader-Test.cpp new file mode 100644 index 00000000000..d4e915371f1 --- /dev/null +++ b/ApplicationLibCode/UnitTests/RifOsduWellPathReader-Test.cpp @@ -0,0 +1,59 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2024- Equinor ASA +// +// ResInsight 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. +// +// ResInsight 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 at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#include "gtest/gtest.h" + +#include "RifOsduWellPathReader.h" + +#include "RigWellPath.h" + +#include "cvfObject.h" + +TEST( RifOsduWellPathReader, ParseCsv ) +{ + std::string fileContent = R"( +MD,TVD,AZIMUTH,INCLINATION,X,Y,GODLEG_SEVERITY,DX,DY,UWI,WELLBORE,CRS,EPSG_CODE +0.0,0.0,1e-10,0.0,68.8767382,33.1345775,0.0,0.0,0.0,WELL NAME #1,WELL NAME #1,WGS84,4326 +271.49,271.49,1e-10,0.0,68.8767382,33.1345775,0.0,0.0,0.0,WELL NAME #1,WELL NAME #1,WGS84,4326 +306.29,306.29,272.01823962,0.08968724,68.8767375,33.1345774,0.24,-0.06,-0.01,WELL NAME #1,WELL NAME #1,WGS84,4326 +336.29,336.29,274.30140794,0.15846019,68.8767368,33.1345775,0.22,-0.12,0.0,WELL NAME #1,WELL NAME #1,WGS84,4326 +366.29,366.29,278.8234303,0.09299958,68.8767359,33.1345775,0.23,-0.2,0.0,WELL NAME #1,WELL NAME #1,WGS84,4326 +396.29,396.29,272.75661039,0.10458399,68.8767352,33.1345775,0.11,-0.26,0.0,WELL NAME #1,WELL NAME #1,WGS84,4326 +426.56,426.29,268.84493373,0.12982945,68.8767347,33.1345775,0.24,-0.3,0.0,WELL NAME #1,WELL NAME #1,WGS84,4326 +456.29,456.29,247.08294017,0.24449049,68.8767336,33.1345774,0.58,-0.39,-0.01,WELL NAME #1,WELL NAME #1,WGS84,4326 +486.29,486.28,228.45433687,1.77934187,68.876729,33.1345746,1.0,-0.78,-0.33,WELL NAME #1,WELL NAME #1,WGS84,4326 +516.29,516.25,234.24032672,3.25969626,68.8767165,33.1345672,1.41,-1.85,-1.15,WELL NAME #1,WELL NAME #1,WGS84,4326 +546.29,546.17,235.37605057,5.34499442,68.8766954,33.1345561,3.39,-3.64,-2.39,WELL NAME #1,WELL NAME #1,WGS84,4326 +576.29,575.97,233.86086873,7.54998951,68.8766625,33.1345381,1.98,-6.44,-4.4,WELL NAME #1,WELL NAME #1,WGS84,4326 +)"; + + QString fileContentAsQString = QString::fromStdString( fileContent ); + + auto [wellPath, errorMessage] = RifOsduWellPathReader::parseCsv( fileContentAsQString ); + EXPECT_TRUE( wellPath.notNull() ); + + EXPECT_EQ( 12u, wellPath->wellPathPoints().size() ); + EXPECT_EQ( 12u, wellPath->measuredDepths().size() ); + + cvf::Vec3d point = wellPath->wellPathPoints()[6]; + EXPECT_DOUBLE_EQ( 68.8767347, point.x() ); + EXPECT_DOUBLE_EQ( 33.1345775, point.y() ); + EXPECT_DOUBLE_EQ( -426.29, point.z() ); + + EXPECT_DOUBLE_EQ( 426.56, wellPath->measuredDepths()[6] ); +} diff --git a/ApplicationLibCode/UserInterface/RiuMenuBarBuildTools.cpp b/ApplicationLibCode/UserInterface/RiuMenuBarBuildTools.cpp index 9e48e1a273f..a658e219c91 100644 --- a/ApplicationLibCode/UserInterface/RiuMenuBarBuildTools.cpp +++ b/ApplicationLibCode/UserInterface/RiuMenuBarBuildTools.cpp @@ -138,7 +138,7 @@ void RiuMenuBarBuildTools::addImportMenuWithActions( QObject* parent, QMenu* men importMenu->addSeparator(); QMenu* importWellMenu = importMenu->addMenu( QIcon( ":/Well.svg" ), "Well Data" ); importWellMenu->addAction( cmdFeatureMgr->action( "RicWellPathsImportFileFeature" ) ); - importWellMenu->addAction( cmdFeatureMgr->action( "RicWellPathsImportSsihubFeature" ) ); + importWellMenu->addAction( cmdFeatureMgr->action( "RicWellPathsImportOsduFeature" ) ); importWellMenu->addAction( cmdFeatureMgr->action( "RicWellLogsImportFileFeature" ) ); importWellMenu->addAction( cmdFeatureMgr->action( "RicWellPathFormationsImportFileFeature" ) ); importWellMenu->addAction( cmdFeatureMgr->action( "RicImportWellMeasurementsFeature" ) ); diff --git a/CMakeLists.txt b/CMakeLists.txt index f99c07e292a..58c8c0ce246 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -508,7 +508,8 @@ endif() set(RI_QT_MINIMUM_VERSION 5.12) find_package( - Qt5 ${RI_QT_MINIMUM_VERSION} COMPONENTS Core Gui OpenGL Network Widgets + Qt5 ${RI_QT_MINIMUM_VERSION} COMPONENTS Core Gui OpenGL Network NetworkAuth + Widgets ) # Open GL