#11993 Improve ensemble search dialog

Use tree view instead of list view. Add filtering based on text match using realization numbers. Clean up user interface. Rename several GUI items.
This commit is contained in:
Magne Sjaastad
2024-12-19 10:56:41 +01:00
parent fb90844901
commit 997e14c90e
5 changed files with 378 additions and 215 deletions

View File

@@ -309,19 +309,30 @@ std::set<int> RiaStdStringTools::valuesFromRangeSelection( const std::string& s
std::istringstream tokenStream( token ); std::istringstream tokenStream( token );
int startIndex, endIndex; int startIndex, endIndex;
char dash; char dash, colon;
int step = 1;
if ( tokenStream >> startIndex ) if ( tokenStream >> startIndex )
{ {
if ( tokenStream >> dash && dash == '-' && tokenStream >> endIndex ) if ( tokenStream >> dash && dash == '-' && tokenStream >> endIndex )
{ {
if ( tokenStream >> colon && colon == ':' )
{
tokenStream >> step;
}
if ( step <= 0 )
{
step = 1; // Ensure step is positive
}
if ( startIndex > endIndex ) if ( startIndex > endIndex )
{ {
// If start is greater than end, swap them // If start is greater than end, swap them
std::swap( startIndex, endIndex ); std::swap( startIndex, endIndex );
} }
for ( int i = startIndex; i <= endIndex; ++i ) for ( int i = startIndex; i <= endIndex; i += step )
{ {
result.insert( i ); result.insert( i );
} }

View File

@@ -21,11 +21,11 @@
#include "RiaEnsembleNameTools.h" #include "RiaEnsembleNameTools.h"
#include "RiaFilePathTools.h" #include "RiaFilePathTools.h"
#include "RiaGuiApplication.h" #include "RiaGuiApplication.h"
#include "RiaStdStringTools.h"
#include "RiaStringListSerializer.h" #include "RiaStringListSerializer.h"
#include "RiuFileDialogTools.h" #include "RiuFileDialogTools.h"
#include "RiuTools.h" #include "RiuTools.h"
#include "opm/io/eclipse/EclUtil.hpp"
#include <QAbstractItemView> #include <QAbstractItemView>
#include <QAction> #include <QAction>
@@ -38,7 +38,6 @@
#include <QGroupBox> #include <QGroupBox>
#include <QLabel> #include <QLabel>
#include <QLineEdit> #include <QLineEdit>
#include <QListWidget>
#include <QMenu> #include <QMenu>
#include <QPushButton> #include <QPushButton>
#include <QRegularExpression> #include <QRegularExpression>
@@ -48,19 +47,143 @@
#include <QTime> #include <QTime>
#include <QToolBar> #include <QToolBar>
#include <QToolTip> #include <QToolTip>
#include <QTreeView>
#include <QVBoxLayout> #include <QVBoxLayout>
#include <algorithm> #include <algorithm>
#include <vector> #include <vector>
#define RECURSIVE_FILESEARCH_DEFAULT_DIALOG_HEIGHT 350 // Anonymous namespace for internal functions
#define FIND_BUTTON_FIND_TEXT "Find" namespace
#define FILES_FOUND_TEXT "Files Found" {
// Get all first level items, usually the ensemble items
auto firstLevelItems = []( QStandardItem* rootItem ) -> QList<QStandardItem*>
{
QList<QStandardItem*> firstLevelItems;
for ( int i = 0; i < rootItem->rowCount(); ++i )
{
QStandardItem* item = rootItem->child( i );
if ( item )
{
firstLevelItems.append( item );
}
}
return firstLevelItems;
};
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
/// Internal functions ///
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
static void sortStringsByLength( QStringList& strings, bool ascending = true ); void setCheckedStateChildItems( QStandardItem* parentItem, Qt::CheckState checkState )
{
if ( !parentItem ) return;
for ( int i = 0; i < parentItem->rowCount(); ++i )
{
auto childItem = parentItem->child( i );
if ( childItem && childItem->isCheckable() )
{
childItem->setCheckState( checkState );
}
setCheckedStateChildItems( childItem, checkState );
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void findItemsMatching( QStandardItem* parentItem, const QString& substring, QList<QStandardItem*>& matchingItems )
{
if ( !parentItem ) return;
for ( int i = 0; i < parentItem->rowCount(); ++i )
{
auto searchString = substring + "/";
auto childItem = parentItem->child( i );
if ( childItem )
{
auto textToMatch = childItem->text();
textToMatch.replace( '\\', '/' );
if ( childItem && textToMatch.contains( searchString, Qt::CaseInsensitive ) )
{
matchingItems.append( childItem );
}
}
findItemsMatching( childItem, substring, matchingItems );
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void getTextForCheckedItems( QStandardItem* root, QStandardItem* parentItem, const QString& prefix, QStringList& checkedItems )
{
if ( !parentItem ) return;
for ( int i = 0; i < parentItem->rowCount(); ++i )
{
auto childItem = parentItem->child( i );
if ( childItem && childItem->isCheckable() && childItem->checkState() == Qt::Checked )
{
if ( parentItem != root )
{
checkedItems.append( prefix + childItem->text() );
}
getTextForCheckedItems( root, childItem, prefix, checkedItems );
}
}
}
int defaultDialogHeight()
{
return 550;
}
QString findButtonText()
{
return "Search";
}
QString filesFoundText()
{
return "File Selection";
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void sortStringsByLength( QStringList& strings, bool ascending )
{
QStringList sorted = strings;
int numItems = sorted.size();
bool swapped;
do
{
swapped = false;
for ( int i = 0; i < numItems - 1; i++ )
{
int s0 = strings[i].size();
int s1 = strings[i + 1].size();
if ( ( ascending && s0 > s1 ) || ( !ascending && s0 < s1 ) )
{
const QString temp = strings[i];
strings[i] = strings[i + 1];
strings[i + 1] = temp;
swapped = true;
}
}
} while ( swapped );
}
} // namespace
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
/// ///
@@ -145,15 +268,17 @@ RicRecursiveFileSearchDialogResult RicRecursiveFileSearchDialog::runRecursiveSea
RiaStringListSerializer stringListSerializer( fileFilterRegistryKey ); RiaStringListSerializer stringListSerializer( fileFilterRegistryKey );
stringListSerializer.addString( dialog.m_fileFilterField->currentText(), maxItemsInRegistry ); stringListSerializer.addString( dialog.m_fileFilterField->currentText(), maxItemsInRegistry );
} }
return { .ok = dialog.result() == QDialog::Accepted,
.files = dialog.m_foundFiles,
.rootDir = dialog.rootDirWithEndSeparator(),
.pathFilter = dialog.pathFilterWithoutStartSeparator(),
.fileNameFilter = dialog.fileNameFilter(),
.fileType = dialog.fileType(),
.groupingMode = dialog.ensembleGroupingMode() };
} }
return RicRecursiveFileSearchDialogResult( dialog.result() == QDialog::Accepted, return {};
dialog.m_foundFiles,
dialog.rootDirWithEndSeparator(),
dialog.pathFilterWithoutStartSeparator(),
dialog.fileNameFilter(),
dialog.fileType(),
dialog.ensembleGroupingMode() );
} }
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
@@ -180,10 +305,11 @@ RicRecursiveFileSearchDialog::RicRecursiveFileSearchDialog( QWidget* parent, con
m_effectiveFilterLabel = new QLabel(); m_effectiveFilterLabel = new QLabel();
m_effectiveFilterContentLabel = new QLabel(); m_effectiveFilterContentLabel = new QLabel();
m_ensembleGroupingMode = new QComboBox(); m_ensembleGroupingMode = new QComboBox();
m_searchRootLabel = new QLabel();
m_searchRootContentLabel = new QLabel();
m_findOrCancelButton = new QPushButton(); m_findOrCancelButton = new QPushButton();
m_fileListWidget = new QListWidget(); m_fileTreeView = new QTreeView();
m_treeViewFilterLabel = new QLabel( "Selection Filter" );
m_treeViewFilterLineEdit = new QLineEdit();
m_treeViewFilterButton = new QPushButton( "Apply" );
m_buttons = new QDialogButtonBox( QDialogButtonBox::Ok | QDialogButtonBox::Cancel ); m_buttons = new QDialogButtonBox( QDialogButtonBox::Ok | QDialogButtonBox::Cancel );
@@ -198,11 +324,21 @@ RicRecursiveFileSearchDialog::RicRecursiveFileSearchDialog( QWidget* parent, con
connect( m_fileExtensionField, SIGNAL( textChanged( const QString& ) ), this, SLOT( slotFileExtensionChanged( const QString& ) ) ); connect( m_fileExtensionField, SIGNAL( textChanged( const QString& ) ), this, SLOT( slotFileExtensionChanged( const QString& ) ) );
connect( m_fileListWidget, connect( m_fileTreeView,
SIGNAL( customContextMenuRequested( const QPoint& ) ), SIGNAL( customContextMenuRequested( const QPoint& ) ),
this, this,
SLOT( slotFileListCustomMenuRequested( const QPoint& ) ) ); SLOT( slotFileListCustomMenuRequested( const QPoint& ) ) );
connect( m_treeViewFilterButton, SIGNAL( clicked() ), this, SLOT( slotFilterTreeViewClicked() ) );
connect( m_treeViewFilterLineEdit, &QLineEdit::returnPressed, m_treeViewFilterButton, &QPushButton::click );
connect( m_treeViewFilterLineEdit, &QLineEdit::textEdited, m_treeViewFilterButton, &QPushButton::click );
m_treeViewFilterLineEdit->setPlaceholderText( "Select Realizations: 1, 5-7, 9-18:3" );
m_treeViewFilterLabel->setVisible( false );
m_treeViewFilterButton->setVisible( false );
m_treeViewFilterLineEdit->setVisible( false );
connect( m_browseButton, SIGNAL( clicked() ), this, SLOT( slotBrowseButtonClicked() ) ); connect( m_browseButton, SIGNAL( clicked() ), this, SLOT( slotBrowseButtonClicked() ) );
connect( m_findOrCancelButton, SIGNAL( clicked() ), this, SLOT( slotFindOrCancelButtonClicked() ) ); connect( m_findOrCancelButton, SIGNAL( clicked() ), this, SLOT( slotFindOrCancelButtonClicked() ) );
@@ -210,35 +346,44 @@ RicRecursiveFileSearchDialog::RicRecursiveFileSearchDialog( QWidget* parent, con
connect( m_buttons, SIGNAL( accepted() ), this, SLOT( slotDialogOkClicked() ) ); connect( m_buttons, SIGNAL( accepted() ), this, SLOT( slotDialogOkClicked() ) );
connect( m_buttons, SIGNAL( rejected() ), this, SLOT( slotDialogCancelClicked() ) ); connect( m_buttons, SIGNAL( rejected() ), this, SLOT( slotDialogCancelClicked() ) );
m_buttons->button( QDialogButtonBox::Ok )->setDefault( true );
// Set widget properties // Set widget properties
m_pathFilterLabel->setText( "Path pattern" ); m_pathFilterLabel->setText( "Path pattern" );
m_fileFilterLabel->setText( "File pattern" ); m_fileFilterLabel->setText( "File pattern" );
m_fileTypeLabel->setText( "File type" ); m_fileTypeLabel->setText( "File type" );
m_fileExtensionLabel->setText( "File extension" ); m_fileExtensionLabel->setText( "File extension" );
m_effectiveFilterLabel->setText( "Effective filter" ); m_effectiveFilterLabel->setText( "Effective filter" );
m_searchRootLabel->setText( "Root" );
m_searchRootLabel->setVisible( false );
m_effectiveFilterContentLabel->setSizePolicy( QSizePolicy::Expanding, QSizePolicy::Preferred ); m_effectiveFilterContentLabel->setSizePolicy( QSizePolicy::Expanding, QSizePolicy::Preferred );
m_searchRootContentLabel->setSizePolicy( QSizePolicy::Expanding, QSizePolicy::Preferred );
m_searchRootContentLabel->setVisible( false );
m_fileListWidget->setSelectionMode( QAbstractItemView::ExtendedSelection ); QObject::connect( &m_filePathModel,
m_fileListWidget->setVisible( false ); &QStandardItemModel::itemChanged,
m_fileListWidget->setContextMenuPolicy( Qt::CustomContextMenu ); []( QStandardItem* item )
m_fileListWidget->setMinimumHeight( 350 ); {
if ( item->isCheckable() )
{
setCheckedStateChildItems( item, item->checkState() );
}
} );
m_fileTreeView->setModel( &m_filePathModel );
m_fileTreeView->setHeaderHidden( true );
m_fileTreeView->setSelectionMode( QAbstractItemView::ExtendedSelection );
m_fileTreeView->setContextMenuPolicy( Qt::CustomContextMenu );
m_fileTreeView->setVisible( false );
m_fileTreeView->setMinimumHeight( 350 );
m_browseButton->setText( "..." ); m_browseButton->setText( "..." );
m_browseButton->setFixedWidth( 25 ); m_browseButton->setFixedWidth( 25 );
m_findOrCancelButton->setText( FIND_BUTTON_FIND_TEXT ); m_findOrCancelButton->setText( findButtonText() );
m_findOrCancelButton->setFixedWidth( 75 ); m_findOrCancelButton->setFixedWidth( 75 );
m_findOrCancelButton->setDefault( true );
// Define layout // Define layout
QVBoxLayout* dialogLayout = new QVBoxLayout(); QVBoxLayout* dialogLayout = new QVBoxLayout();
QGroupBox* inputGroup = new QGroupBox( "Filter" ); QGroupBox* inputGroup = new QGroupBox( "Search" );
QGridLayout* inputGridLayout = new QGridLayout(); QGridLayout* inputGridLayout = new QGridLayout();
int row = 0; int row = 0;
inputGridLayout->addWidget( m_pathFilterLabel, row, 0 ); inputGridLayout->addWidget( m_pathFilterLabel, row, 0 );
@@ -277,11 +422,13 @@ RicRecursiveFileSearchDialog::RicRecursiveFileSearchDialog( QWidget* parent, con
m_outputGroup = new QGroupBox( "Files Found" ); m_outputGroup = new QGroupBox( "Files Found" );
QGridLayout* outputGridLayout = new QGridLayout(); QGridLayout* outputGridLayout = new QGridLayout();
outputGridLayout->addWidget( m_searchRootLabel, 1, 0 );
outputGridLayout->addWidget( m_searchRootContentLabel, 1, 1 );
// outputGridLayout->addWidget(m_fileListLabel, 2, 0); outputGridLayout->addWidget( m_treeViewFilterLabel, 1, 0 );
outputGridLayout->addWidget( m_fileListWidget, 2, 0, 1, 3 ); outputGridLayout->addWidget( m_treeViewFilterLineEdit, 1, 1 );
outputGridLayout->addWidget( m_treeViewFilterButton, 1, 2 );
outputGridLayout->addWidget( m_fileTreeView, 2, 0, 1, 3 );
m_outputGroup->setLayout( outputGridLayout ); m_outputGroup->setLayout( outputGridLayout );
dialogLayout->addWidget( inputGroup ); dialogLayout->addWidget( inputGroup );
@@ -397,7 +544,7 @@ QStringList RicRecursiveFileSearchDialog::fileExtensions() const
} }
QStringList exts = m_fileExtensions; QStringList exts = m_fileExtensions;
sortStringsByLength( exts ); sortStringsByLength( exts, true );
return exts; return exts;
} }
@@ -429,10 +576,10 @@ QString RicRecursiveFileSearchDialog::extensionFromFileNameFilter() const
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
void RicRecursiveFileSearchDialog::updateFileListWidget() void RicRecursiveFileSearchDialog::updateFileListWidget()
{ {
m_fileListWidget->clear();
if ( ensembleGroupingMode() != RiaEnsembleNameTools::EnsembleGroupingMode::NONE ) if ( ensembleGroupingMode() != RiaEnsembleNameTools::EnsembleGroupingMode::NONE )
{ {
m_filePathModel.clear();
if ( m_fileType == RicRecursiveFileSearchDialog::FileType::STIMPLAN_SUMMARY || if ( m_fileType == RicRecursiveFileSearchDialog::FileType::STIMPLAN_SUMMARY ||
m_fileType == RicRecursiveFileSearchDialog::FileType::REVEAL_SUMMARY ) m_fileType == RicRecursiveFileSearchDialog::FileType::REVEAL_SUMMARY )
{ {
@@ -440,8 +587,7 @@ void RicRecursiveFileSearchDialog::updateFileListWidget()
std::map<QString, QStringList> groupedByEnsemble = RiaEnsembleNameTools::groupFilesByCustomEnsemble( m_foundFiles, fileType ); std::map<QString, QStringList> groupedByEnsemble = RiaEnsembleNameTools::groupFilesByCustomEnsemble( m_foundFiles, fileType );
for ( auto [ensembleName, groupedFileNames] : groupedByEnsemble ) for ( auto [ensembleName, groupedFileNames] : groupedByEnsemble )
{ {
new QListWidgetItem( QDir::toNativeSeparators( ensembleName ), m_fileListWidget ); addToTreeView( ensembleName, groupedFileNames );
addToFileListWidget( groupedFileNames );
} }
} }
else else
@@ -450,31 +596,39 @@ void RicRecursiveFileSearchDialog::updateFileListWidget()
for ( const QStringList& groupedFileNames : groupedByEnsemble ) for ( const QStringList& groupedFileNames : groupedByEnsemble )
{ {
QString ensembleName = RiaEnsembleNameTools::findSuitableEnsembleName( groupedFileNames, ensembleGroupingMode() ); QString ensembleName = RiaEnsembleNameTools::findSuitableEnsembleName( groupedFileNames, ensembleGroupingMode() );
new QListWidgetItem( QDir::toNativeSeparators( ensembleName ), m_fileListWidget ); addToTreeView( ensembleName, groupedFileNames );
addToFileListWidget( groupedFileNames );
} }
} }
}
else QModelIndex index = m_filePathModel.index( 0, 0 );
{ m_fileTreeView->expand( index );
addToFileListWidget( m_foundFiles );
} }
} }
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
/// ///
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
void RicRecursiveFileSearchDialog::addToFileListWidget( const QStringList& fileNames ) void RicRecursiveFileSearchDialog::addToTreeView( const QString& ensembleName, const QStringList& fileNames )
{ {
auto rootItem = m_filePathModel.invisibleRootItem();
int rootSearchPathLength = rootDirWithEndSeparator().size(); int rootSearchPathLength = rootDirWithEndSeparator().size();
bool isEmpty = m_filePathModel.rowCount() == 0;
auto ensembleItem = new QStandardItem( QDir::toNativeSeparators( ensembleName ) );
ensembleItem->setCheckable( true );
if ( isEmpty ) ensembleItem->setCheckState( Qt::Checked );
rootItem->appendRow( ensembleItem );
for ( const auto& fileName : fileNames ) for ( const auto& fileName : fileNames )
{ {
QString itemText = fileName; auto itemText = fileName;
itemText.remove( 0, rootSearchPathLength ); itemText.remove( 0, rootSearchPathLength );
QListWidgetItem* item = new QListWidgetItem( QDir::toNativeSeparators( itemText ), m_fileListWidget );
item->setFlags( item->flags() | Qt::ItemIsUserCheckable ); auto fileItem = new QStandardItem( QDir::toNativeSeparators( itemText ) );
item->setCheckState( Qt::Checked ); fileItem->setCheckable( true );
if ( isEmpty ) fileItem->setCheckState( Qt::Checked );
ensembleItem->appendRow( fileItem );
} }
} }
@@ -484,8 +638,8 @@ void RicRecursiveFileSearchDialog::addToFileListWidget( const QStringList& fileN
void RicRecursiveFileSearchDialog::clearFileList() void RicRecursiveFileSearchDialog::clearFileList()
{ {
m_foundFiles.clear(); m_foundFiles.clear();
m_fileListWidget->clear(); m_filePathModel.clear();
m_outputGroup->setTitle( FILES_FOUND_TEXT ); m_outputGroup->setTitle( filesFoundText() );
setOkButtonEnabled( false ); setOkButtonEnabled( false );
} }
@@ -530,8 +684,12 @@ void RicRecursiveFileSearchDialog::updateStatus( Status status, const QString& e
lastStatusUpdate = now; lastStatusUpdate = now;
m_fileListWidget->clear(); m_filePathModel.clear();
new QListWidgetItem( newStatus, m_fileListWidget );
// Show status message in the tree view
auto rootItem = m_filePathModel.invisibleRootItem();
auto ensembleItem = new QStandardItem( newStatus );
rootItem->appendRow( ensembleItem );
} }
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
@@ -708,7 +866,6 @@ void RicRecursiveFileSearchDialog::updateEffectiveFilter()
// Present native separators to the user // Present native separators to the user
m_effectiveFilterContentLabel->setText( QDir::toNativeSeparators( effFilterText ) ); m_effectiveFilterContentLabel->setText( QDir::toNativeSeparators( effFilterText ) );
m_searchRootContentLabel->setText( QDir::toNativeSeparators( rootDirWithEndSeparator() ) );
} }
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
@@ -728,7 +885,6 @@ void RicRecursiveFileSearchDialog::warningIfInvalidCharacters()
{ {
QToolTip::showText( m_fileFilterField->mapToGlobal( QPoint( 0, 0 ) ), "File pattern contains invalid characters" ); QToolTip::showText( m_fileFilterField->mapToGlobal( QPoint( 0, 0 ) ), "File pattern contains invalid characters" );
m_effectiveFilterContentLabel->setText( "(Invalid filter)" ); m_effectiveFilterContentLabel->setText( "(Invalid filter)" );
m_searchRootContentLabel->setText( "" );
} }
else else
{ {
@@ -743,7 +899,7 @@ void RicRecursiveFileSearchDialog::slotPathFilterChanged( const QString& text )
{ {
updateEffectiveFilter(); updateEffectiveFilter();
warningIfInvalidCharacters(); warningIfInvalidCharacters();
m_findOrCancelButton->setDefault( true ); m_findOrCancelButton->setFocus();
} }
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
@@ -754,7 +910,7 @@ void RicRecursiveFileSearchDialog::slotFileFilterChanged( const QString& text )
clearFileList(); clearFileList();
updateEffectiveFilter(); updateEffectiveFilter();
warningIfInvalidCharacters(); warningIfInvalidCharacters();
m_findOrCancelButton->setDefault( true ); m_findOrCancelButton->setFocus();
} }
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
@@ -806,7 +962,7 @@ void RicRecursiveFileSearchDialog::slotFileListCustomMenuRequested( const QPoint
connect( action, SIGNAL( triggered() ), SLOT( slotToggleFileListItems() ) ); connect( action, SIGNAL( triggered() ), SLOT( slotToggleFileListItems() ) );
menu.addAction( action ); menu.addAction( action );
QPoint globalPoint = m_fileListWidget->mapToGlobal( point ); QPoint globalPoint = m_fileTreeView->mapToGlobal( point );
menu.exec( globalPoint ); menu.exec( globalPoint );
} }
@@ -815,71 +971,98 @@ void RicRecursiveFileSearchDialog::slotFileListCustomMenuRequested( const QPoint
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
void RicRecursiveFileSearchDialog::slotToggleFileListItems() void RicRecursiveFileSearchDialog::slotToggleFileListItems()
{ {
for ( auto& item : m_fileListWidget->selectedItems() ) auto selectionModel = m_fileTreeView->selectionModel();
auto indices = selectionModel->selectedIndexes();
for ( auto& index : indices )
{ {
if ( ( item->flags() & Qt::ItemIsUserCheckable ) != 0 ) if ( index.isValid() )
{
auto item = m_filePathModel.itemFromIndex( index );
if ( item && item->isCheckable() )
{ {
item->setCheckState( item->checkState() == Qt::Checked ? Qt::Unchecked : Qt::Checked ); item->setCheckState( item->checkState() == Qt::Checked ? Qt::Unchecked : Qt::Checked );
} }
} }
} }
}
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
/// ///
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
void RicRecursiveFileSearchDialog::slotTurnOffFileListItems() void RicRecursiveFileSearchDialog::slotTurnOffFileListItems()
{ {
for ( auto& item : m_fileListWidget->selectedItems() ) auto selectionModel = m_fileTreeView->selectionModel();
auto indices = selectionModel->selectedIndexes();
for ( auto& index : indices )
{ {
if ( ( item->flags() & Qt::ItemIsUserCheckable ) != 0 ) if ( index.isValid() )
{
auto item = m_filePathModel.itemFromIndex( index );
if ( item && item->isCheckable() )
{ {
item->setCheckState( Qt::Unchecked ); item->setCheckState( Qt::Unchecked );
} }
} }
} }
}
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
/// ///
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
void RicRecursiveFileSearchDialog::slotTurnOnFileListItems() void RicRecursiveFileSearchDialog::slotTurnOnFileListItems()
{ {
for ( auto& item : m_fileListWidget->selectedItems() ) auto selectionModel = m_fileTreeView->selectionModel();
auto indices = selectionModel->selectedIndexes();
for ( auto& index : indices )
{ {
if ( ( item->flags() & Qt::ItemIsUserCheckable ) != 0 ) if ( index.isValid() )
{
auto item = m_filePathModel.itemFromIndex( index );
if ( item && item->isCheckable() )
{ {
item->setCheckState( Qt::Checked ); item->setCheckState( Qt::Checked );
} }
} }
} }
}
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
/// ///
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
void RicRecursiveFileSearchDialog::slotCopyFileItemText() void RicRecursiveFileSearchDialog::slotCopyFileItemText()
{ {
if ( m_fileListWidget->currentItem() ) auto index = m_fileTreeView->currentIndex();
{ {
QString relativePathText = m_fileListWidget->currentItem()->text(); if ( index.isValid() )
{
auto item = m_filePathModel.itemFromIndex( index );
if ( item )
{
QString relativePathText = item->text();
QApplication::clipboard()->setText( relativePathText ); QApplication::clipboard()->setText( relativePathText );
} }
} }
}
}
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
/// ///
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
void RicRecursiveFileSearchDialog::slotFindOrCancelButtonClicked() void RicRecursiveFileSearchDialog::slotFindOrCancelButtonClicked()
{ {
if ( m_findOrCancelButton->text() == FIND_BUTTON_FIND_TEXT ) if ( m_findOrCancelButton->text() == findButtonText() )
{ {
clearFileList(); clearFileList();
if ( !m_fileListWidget->isVisible() ) m_treeViewFilterLabel->setVisible( true );
{ m_treeViewFilterButton->setVisible( true );
m_fileListWidget->setVisible( true ); m_treeViewFilterLineEdit->setVisible( true );
m_searchRootLabel->setVisible( true );
m_searchRootContentLabel->setVisible( true );
if ( height() < RECURSIVE_FILESEARCH_DEFAULT_DIALOG_HEIGHT ) resize( width(), RECURSIVE_FILESEARCH_DEFAULT_DIALOG_HEIGHT ); if ( !m_fileTreeView->isVisible() )
{
m_fileTreeView->setVisible( true );
if ( height() < defaultDialogHeight() ) resize( width(), defaultDialogHeight() );
} }
m_findOrCancelButton->setText( "Cancel" ); m_findOrCancelButton->setText( "Cancel" );
@@ -897,7 +1080,7 @@ void RicRecursiveFileSearchDialog::slotFindOrCancelButtonClicked()
updateFileListWidget(); updateFileListWidget();
m_findOrCancelButton->setText( FIND_BUTTON_FIND_TEXT ); m_findOrCancelButton->setText( findButtonText() );
if ( m_isCancelPressed ) if ( m_isCancelPressed )
{ {
@@ -909,11 +1092,14 @@ void RicRecursiveFileSearchDialog::slotFindOrCancelButtonClicked()
} }
else else
{ {
m_outputGroup->setTitle( QString( "%1 (%2)" ).arg( FILES_FOUND_TEXT ).arg( m_foundFiles.size() ) ); m_outputGroup->setTitle( QString( "%1 (%2)" ).arg( filesFoundText() ).arg( m_foundFiles.size() ) );
} }
setOkButtonEnabled( !m_foundFiles.isEmpty() ); setOkButtonEnabled( !m_foundFiles.isEmpty() );
m_buttons->button( QDialogButtonBox::Ok )->setDefault( true );
m_buttons->button( QDialogButtonBox::Ok )->setFocus();
slotFilterTreeViewClicked();
} }
else else
{ {
@@ -921,22 +1107,52 @@ void RicRecursiveFileSearchDialog::slotFindOrCancelButtonClicked()
} }
} }
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RicRecursiveFileSearchDialog::slotFilterTreeViewClicked()
{
QString filterText = m_treeViewFilterLineEdit->text();
auto values = RiaStdStringTools::valuesFromRangeSelection( filterText.toStdString() );
auto items = firstLevelItems( m_filePathModel.invisibleRootItem() );
for ( auto item : items )
{
if ( item->checkState() == Qt::Unchecked ) continue;
if ( filterText.isEmpty() )
{
setCheckedStateChildItems( item, Qt::Checked );
}
else
{
setCheckedStateChildItems( item, Qt::Unchecked );
for ( auto val : values )
{
QString searchString = "realization-" + QString::number( val );
QList<QStandardItem*> matchingItems;
findItemsMatching( item, searchString, matchingItems );
for ( auto item : matchingItems )
{
item->setCheckState( Qt::Checked );
}
}
}
}
}
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
/// ///
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
void RicRecursiveFileSearchDialog::slotDialogOkClicked() void RicRecursiveFileSearchDialog::slotDialogOkClicked()
{ {
m_foundFiles.clear(); QStringList checkedItems;
getTextForCheckedItems( m_filePathModel.invisibleRootItem(), m_filePathModel.invisibleRootItem(), rootDirWithEndSeparator(), checkedItems );
int itemCount = m_fileListWidget->count(); m_foundFiles = checkedItems;
for ( int i = 0; i < itemCount; i++ )
{
const QListWidgetItem* item = m_fileListWidget->item( i );
if ( ( item->flags() & Qt::ItemIsUserCheckable ) != 0 && item->checkState() )
{
m_foundFiles.push_back( rootDirWithEndSeparator() + RiaFilePathTools::toInternalSeparator( item->text() ) );
}
}
accept(); accept();
} }
@@ -950,6 +1166,15 @@ void RicRecursiveFileSearchDialog::slotDialogCancelClicked()
reject(); reject();
} }
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RicRecursiveFileSearchDialog::showEvent( QShowEvent* event )
{
m_findOrCancelButton->setFocus();
QDialog::showEvent( event );
}
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
/// ///
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
@@ -998,100 +1223,6 @@ QStringList RicRecursiveFileSearchDialog::fileTypeToExtensionStrings( const std:
return extensions; return extensions;
} }
//--------------------------------------------------------------------------------------------------
/// Internal functions
//--------------------------------------------------------------------------------------------------
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void sortStringsByLength( QStringList& strings, bool ascending /*= true*/ )
{
QStringList sorted = strings;
int numItems = sorted.size();
bool swapped;
do
{
swapped = false;
for ( int i = 0; i < numItems - 1; i++ )
{
int s0 = strings[i].size();
int s1 = strings[i + 1].size();
if ( ( ascending && s0 > s1 ) || ( !ascending && s0 < s1 ) )
{
const QString temp = strings[i];
strings[i] = strings[i + 1];
strings[i + 1] = temp;
swapped = true;
}
}
} while ( swapped );
}
//--------------------------------------------------------------------------------------------------
/// Obsolete
//--------------------------------------------------------------------------------------------------
QStringList RicRecursiveFileSearchDialog::buildDirectoryListRecursive( const QString& currentDir, int level )
{
QStringList allDirs;
if ( m_isCancelPressed ) return allDirs;
QString currPathFilter = pathFilterWithoutStartSeparator();
bool subStringFilter = false;
// Optimizing for speed by a refined match at first directory level
if ( level == 1 )
{
QString pathFilter = pathFilterWithoutStartSeparator();
if ( !pathFilter.startsWith( "*" ) )
{
int wildcardIndex = pathFilter.indexOf( QRegularExpression( QString( "[*%1]" ).arg( RiaFilePathTools::separator() ) ) );
if ( wildcardIndex >= 0 )
{
currPathFilter = pathFilter.left( wildcardIndex + 1 );
subStringFilter = true;
}
}
}
QString currRelPath = RiaFilePathTools::relativePath( rootDirWithEndSeparator(), currentDir );
if ( pathFilterMatch( currPathFilter, currRelPath ) )
{
allDirs.push_back( currentDir );
}
else if ( level == 1 && subStringFilter )
{
return QStringList();
}
QDir qdir( currentDir );
QStringList subDirs = qdir.entryList( QDir::Dirs | QDir::NoDotAndDotDot );
for ( QString subDir : subDirs )
{
QString subDirFullPath = qdir.absoluteFilePath( subDir );
updateStatus( SEARCHING_FOR_DIRS, subDirFullPath );
QApplication::processEvents();
allDirs += buildDirectoryListRecursive( subDirFullPath, level + 1 );
}
return m_isCancelPressed ? QStringList() : allDirs;
}
//--------------------------------------------------------------------------------------------------
/// Obsolete
//--------------------------------------------------------------------------------------------------
bool RicRecursiveFileSearchDialog::pathFilterMatch( const QString& pathFilter, const QString& relPath )
{
QString pattern = pathFilter;
if ( relPath.endsWith( RiaFilePathTools::separator() ) && !pathFilter.endsWith( RiaFilePathTools::separator() ) )
pattern += RiaFilePathTools::separator();
QRegularExpression regexp( pattern, QRegularExpression::CaseInsensitiveOption );
auto match = regexp.match( relPath );
return match.hasMatch();
}
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
/// ///
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
@@ -1167,7 +1298,6 @@ RiaDefines::FileType RicRecursiveFileSearchDialog::mapSummaryFileType( RicRecurs
return RiaDefines::FileType::STIMPLAN_SUMMARY; return RiaDefines::FileType::STIMPLAN_SUMMARY;
default: default:
{ {
CAF_ASSERT( false && "Unsupported file type" );
return RiaDefines::FileType::SMSPEC; return RiaDefines::FileType::SMSPEC;
} }
} }

View File

@@ -26,6 +26,7 @@
#include "Summary/RiaSummaryDefines.h" #include "Summary/RiaSummaryDefines.h"
#include <QDialog> #include <QDialog>
#include <QStandardItemModel>
class QLabel; class QLabel;
class QLineEdit; class QLineEdit;
@@ -33,12 +34,12 @@ class QTextEdit;
class QDialogButtonBox; class QDialogButtonBox;
class QPushButton; class QPushButton;
class QMainWindow; class QMainWindow;
class QListWidget;
class QGroupBox; class QGroupBox;
class QComboBox; class QComboBox;
class QCheckBox; class QCheckBox;
class QTreeView;
class RicRecursiveFileSearchDialogResult; struct RicRecursiveFileSearchDialogResult;
//================================================================================================== //==================================================================================================
/// ///
@@ -101,7 +102,7 @@ private:
void updateFileListWidget(); void updateFileListWidget();
void clearFileList(); void clearFileList();
void addToFileListWidget( const QStringList& fileNames ); void addToTreeView( const QString& ensembleName, const QStringList& fileNames );
// File search methods // File search methods
@@ -123,6 +124,7 @@ private slots:
void slotBrowseButtonClicked(); void slotBrowseButtonClicked();
void slotUseRealizationStarClicked(); void slotUseRealizationStarClicked();
void slotFindOrCancelButtonClicked(); void slotFindOrCancelButtonClicked();
void slotFilterTreeViewClicked();
void slotFileListCustomMenuRequested( const QPoint& point ); void slotFileListCustomMenuRequested( const QPoint& point );
void slotCopyFileItemText(); void slotCopyFileItemText();
@@ -133,6 +135,8 @@ private slots:
void slotDialogOkClicked(); void slotDialogOkClicked();
void slotDialogCancelClicked(); void slotDialogCancelClicked();
void showEvent( QShowEvent* event ) override;
private: private:
QLabel* m_pathFilterLabel; QLabel* m_pathFilterLabel;
QComboBox* m_pathFilterField; QComboBox* m_pathFilterField;
@@ -155,9 +159,13 @@ private:
QComboBox* m_ensembleGroupingMode; QComboBox* m_ensembleGroupingMode;
QGroupBox* m_outputGroup; QGroupBox* m_outputGroup;
QLabel* m_searchRootLabel;
QLabel* m_searchRootContentLabel; QLabel* m_treeViewFilterLabel;
QListWidget* m_fileListWidget; QLineEdit* m_treeViewFilterLineEdit;
QPushButton* m_treeViewFilterButton;
QTreeView* m_fileTreeView;
QStandardItemModel m_filePathModel;
QDialogButtonBox* m_buttons; QDialogButtonBox* m_buttons;
@@ -167,35 +175,13 @@ private:
FileType m_fileType; FileType m_fileType;
bool m_isCancelPressed; bool m_isCancelPressed;
// Obsolete. Here for reference if this search mode is needed later
QStringList buildDirectoryListRecursive( const QString& currentDir, int level = 0 );
bool pathFilterMatch( const QString& pathFilter, const QString& relPath );
}; };
//================================================================================================== //==================================================================================================
/// ///
//================================================================================================== //==================================================================================================
class RicRecursiveFileSearchDialogResult struct RicRecursiveFileSearchDialogResult
{ {
public:
RicRecursiveFileSearchDialogResult( bool ok,
const QStringList& files,
const QString& rootDir,
const QString& pathFilter,
const QString& fileNameFilter,
RicRecursiveFileSearchDialog::FileType fileType,
RiaEnsembleNameTools::EnsembleGroupingMode groupingMode )
: ok( ok )
, files( files )
, rootDir( rootDir )
, pathFilter( pathFilter )
, fileNameFilter( fileNameFilter )
, fileType( fileType )
, groupingMode( groupingMode )
{
}
bool ok; bool ok;
QStringList files; QStringList files;
QString rootDir; QString rootDir;

View File

@@ -107,6 +107,9 @@ size_t RimCellFilterIntervalTool::numberFromPart( std::string strVal ) const
// Define a range with the comma separated format A,B,C-D, etc., i.e. 1,4,5-8 // Define a range with the comma separated format A,B,C-D, etc., i.e. 1,4,5-8
// Only numbers > 0 are supported. // Only numbers > 0 are supported.
// For a range with increment > 1, use i.e. 4-8:2 // For a range with increment > 1, use i.e. 4-8:2
//
// Related code in RiaStdStringTools::valuesFromRangeSelection( const std::string& s )
//
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
void RimCellFilterIntervalTool::setInterval( bool enabled, std::string intervalText ) void RimCellFilterIntervalTool::setInterval( bool enabled, std::string intervalText )
{ {

View File

@@ -231,6 +231,39 @@ TEST( RiaStdStringToolsTest, ValuesFromRangeSelectionMinMax )
ASSERT_EQ( expectedValues, actualValues ); ASSERT_EQ( expectedValues, actualValues );
} }
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
TEST( RiaStdStringToolsTest, ValuesWithStep )
{
{
std::string testString = "1, 4-10:2,13-15";
std::set<int> expectedValues = { 1, 4, 6, 8, 10, 13, 14, 15 };
auto actualValues = RiaStdStringTools::valuesFromRangeSelection( testString );
ASSERT_EQ( expectedValues, actualValues );
}
{
std::string testString = "4-6:invalid";
std::set<int> expectedValues = { 4, 5, 6 };
auto actualValues = RiaStdStringTools::valuesFromRangeSelection( testString );
ASSERT_EQ( expectedValues, actualValues );
}
{
std::string testString = "b-5";
std::set<int> expectedValues = {};
auto actualValues = RiaStdStringTools::valuesFromRangeSelection( testString );
ASSERT_EQ( expectedValues, actualValues );
}
}
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
/// ///
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------