From 763e707139cae4bf25f91e6e55d7d6becbd9aa02 Mon Sep 17 00:00:00 2001 From: Peter Hartmann Date: Thu, 23 Jan 2025 16:57:17 +0100 Subject: [PATCH] select directories --- examples/gallery/dialog/DialogPage.cpp | 12 ++ src/dialogs/QskDialog.cpp | 155 ++++++++++++++++++++----- src/dialogs/QskDialog.h | 3 + 3 files changed, 139 insertions(+), 31 deletions(-) diff --git a/examples/gallery/dialog/DialogPage.cpp b/examples/gallery/dialog/DialogPage.cpp index 08864387..0fc586d8 100644 --- a/examples/gallery/dialog/DialogPage.cpp +++ b/examples/gallery/dialog/DialogPage.cpp @@ -101,6 +101,9 @@ namespace auto fileSelectionButton = new Button( "File selection", this ); connect( fileSelectionButton, &Button::clicked, this, &ButtonBox::execFileSelection ); + auto directorySelectionButton = new Button( "Directory selection", this ); + connect( directorySelectionButton, &Button::clicked, this, &ButtonBox::execDirectorySelection ); + setExtraSpacingAt( Qt::BottomEdge ); } @@ -169,6 +172,15 @@ namespace // not implemented for now (class is not public) #else ( void ) qskDialog->selectFile( "select file", QDir::currentPath() ); +#endif + } + + void execDirectorySelection() + { +#ifndef QSK_USE_EXEC + // not implemented for now (class is not public) +#else + ( void ) qskDialog->selectDirectory( "select directory", QDir::currentPath() ); #endif } }; diff --git a/src/dialogs/QskDialog.cpp b/src/dialogs/QskDialog.cpp index 1c9c1b02..566352dc 100644 --- a/src/dialogs/QskDialog.cpp +++ b/src/dialogs/QskDialog.cpp @@ -14,6 +14,7 @@ #include "QskSelectionSubWindow.h" #include "QskSelectionWindow.h" +#include "QskEvent.h" #include "QskFunctions.h" #include "QskListView.h" #include "QskPushButton.h" @@ -157,25 +158,60 @@ namespace } }; + // copied from QskListView.cpp: + static inline int qskRowAt( const QskListView* listView, const QPointF& pos ) + { + const auto rect = listView->viewContentsRect(); + if ( rect.contains( pos ) ) + { + const auto y = pos.y() - rect.top() + listView->scrollPos().y(); + + const int row = y / listView->rowHeight(); + if ( row >= 0 && row < listView->rowCount() ) + return row; + } + + return -1; + } + + // copied from QskGestureRecognizer.cpp: + static QMouseEvent* qskClonedMouseEvent( const QMouseEvent* event ) + { + QMouseEvent* clonedEvent; + + #if QT_VERSION < QT_VERSION_CHECK( 6, 0, 0 ) + clonedEvent = QQuickWindowPrivate::cloneMouseEvent( + const_cast< QMouseEvent* >( event ), nullptr ); + #else + clonedEvent = event->clone(); + #endif + clonedEvent->setAccepted( false ); + + return clonedEvent; + } + class FileSystemView : public QskListView { + using Inherited = QskListView; + public: - FileSystemView( const QString& directory, QQuickItem* parent = nullptr ) + FileSystemView( const QString& directory, QDir::Filters filter, QQuickItem* parent = nullptr ) : QskListView( parent ) , m_model( new QFileSystemModel( this ) ) { connect( m_model, &QFileSystemModel::directoryLoaded, this, [this]() { - columnWidths.fill( 0 ); + m_columnWidths.fill( 0 ); updateScrollableSize(); setScrollPos( { 0, 0 } ); setSelectedRow( -1 ); update(); }); + m_model->setFilter( filter ); m_model->setRootPath( directory ); - columnWidths.fill( 0, m_model->columnCount() ); + m_columnWidths.fill( 0, m_model->columnCount() ); } virtual int rowCount() const override @@ -192,7 +228,7 @@ namespace virtual qreal columnWidth( int col ) const override { - auto w = columnWidths.at( col ); + auto w = m_columnWidths.at( col ); if( col == 0 ) w = qMax( 250, w ); @@ -220,9 +256,9 @@ namespace const auto w = qskHorizontalAdvance( effectiveFont( Text ), v.toString() ); - if( w > columnWidths.at( col ) ) + if( w > m_columnWidths.at( col ) ) { - columnWidths[ col ] = w; + m_columnWidths[ col ] = w; } return v; @@ -233,9 +269,42 @@ namespace return m_model; } + protected: + + void mousePressEvent( QMouseEvent* event ) override + { + if( m_doubleClickEvent && m_doubleClickEvent->timestamp() == event->timestamp() ) + { + // do not select rows from double click mouse events + m_doubleClickEvent = nullptr; + } + else + { + Inherited::mousePressEvent( event ); + } + } + + void mouseDoubleClickEvent( QMouseEvent* event ) override + { + m_doubleClickEvent = qskClonedMouseEvent( event ); + + const int row = qskRowAt( this, qskMousePosition( event ) ); + const auto path = valueAt( row, 0 ).toString(); + + QFileInfo fi( m_model->rootPath(), path ); + + if( fi.isDir() ) + { + m_model->setRootPath( fi.absoluteFilePath() ); + } + + Inherited::mouseDoubleClickEvent( event ); + } + private: QFileSystemModel* const m_model; - mutable QVector< int > columnWidths; + mutable QVector< int > m_columnWidths; + QMouseEvent* m_doubleClickEvent = nullptr; }; template< typename W > @@ -245,7 +314,8 @@ namespace public: FileSelectionWindow( QObject* parent, const QString& title, - QskDialog::Actions actions, QskDialog::Action defaultAction,const QString& directory ) + QskDialog::Actions actions, QskDialog::Action defaultAction, + const QString& directory, QDir::Filters filter ) : WindowOrSubWindow< W >( parent, title, actions, defaultAction ) { auto* outerBox = new QskLinearBox( Qt::Vertical ); @@ -255,14 +325,14 @@ namespace outerBox->setFixedSize( 700, 500 ); #endif setupHeader( outerBox ); - setupFileSystemView( directory, outerBox ); + setupFileSystemView( directory, filter, outerBox ); updateHeader( directory ); Inherited::setContentItem( outerBox ); } - QString selectedFile() const + QString selectedPath() const { if( m_fileView->selectedRow() != -1 ) { @@ -344,24 +414,12 @@ namespace m_headerScrollArea->ensureItemVisible( m_breadcrumbsButtons.last() ); } - void setupFileSystemView( const QString& directory, QQuickItem* parentItem ) + void setupFileSystemView( const QString& directory, QDir::Filters filter, QQuickItem* parentItem ) { - m_fileView = new FileSystemView( directory, parentItem ); + m_fileView = new FileSystemView( directory, filter, parentItem ); QObject::connect( m_fileView->model(), &QFileSystemModel::rootPathChanged, this, &FileSelectionWindow< W >::updateHeader ); - - QObject::connect( m_fileView, &QskListView::selectedRowChanged, - this, [this]( int row ) - { - const auto path = m_fileView->valueAt( row, 0 ).toString(); - QFileInfo fi( m_fileView->model()->rootPath(), path ); - - if( fi.isDir() ) - { - m_fileView->model()->setRootPath( fi.absoluteFilePath() ); - } - }); } QskScrollArea* m_headerScrollArea; @@ -527,12 +585,12 @@ static QString qskSelectWindow( } template< typename W > -static QString qskSelectFile( FileSelectionWindow< W >& window ) +static QString qskSelectPath( FileSelectionWindow< W >& window ) { - QString selectedFile = window.selectedFile(); + QString selectedFile = window.selectedPath(); if( window.exec() == QskDialog::Accepted ) - selectedFile = window.selectedFile(); + selectedFile = window.selectedPath(); return selectedFile; } @@ -660,6 +718,8 @@ QString QskDialog::selectFile( const auto defaultAction = QskDialog::Ok; #endif + const auto flags = QDir::AllEntries | QDir::NoDotAndDotDot | QDir::AllDirs; + if ( m_data->policy == EmbeddedBox ) { auto quickWindow = qobject_cast< QQuickWindow* >( m_data->transientParent ); @@ -669,13 +729,46 @@ QString QskDialog::selectFile( if ( quickWindow ) { - FileSelectionWindow< QskDialogSubWindow > window( quickWindow, title, actions, defaultAction, directory ); - return qskSelectFile< QskDialogSubWindow >( window ); + FileSelectionWindow< QskDialogSubWindow > window( quickWindow, title, + actions, defaultAction, directory, flags ); + return qskSelectPath< QskDialogSubWindow >( window ); } } - FileSelectionWindow< QskDialogWindow > window( m_data->transientParent, title, actions, defaultAction, directory ); - return qskSelectFile< QskDialogWindow >( window ); + FileSelectionWindow< QskDialogWindow > window( m_data->transientParent, title, + actions, defaultAction, directory, flags ); + return qskSelectPath< QskDialogWindow >( window ); +} + +QString QskDialog::selectDirectory( + const QString& title, const QString& directory ) const +{ +#if 1 + // should be parameters + const auto actions = QskDialog::Ok | QskDialog::Cancel; + const auto defaultAction = QskDialog::Ok; +#endif + + const auto flags = QDir::NoDotAndDotDot | QDir::AllDirs; + + if ( m_data->policy == EmbeddedBox ) + { + auto quickWindow = qobject_cast< QQuickWindow* >( m_data->transientParent ); + + if ( quickWindow == nullptr ) + quickWindow = qskSomeQuickWindow(); + + if ( quickWindow ) + { + FileSelectionWindow< QskDialogSubWindow > window( quickWindow, title, + actions, defaultAction, directory, flags ); + return qskSelectPath< QskDialogSubWindow >( window ); + } + } + + FileSelectionWindow< QskDialogWindow > window( m_data->transientParent, title, + actions, defaultAction, directory, flags ); + return qskSelectPath< QskDialogWindow >( window ); } QskDialog::ActionRole QskDialog::actionRole( Action action ) diff --git a/src/dialogs/QskDialog.h b/src/dialogs/QskDialog.h index 89259a1e..41d5f3e6 100644 --- a/src/dialogs/QskDialog.h +++ b/src/dialogs/QskDialog.h @@ -133,6 +133,9 @@ class QSK_EXPORT QskDialog : public QObject Q_INVOKABLE QString selectFile( const QString& title, const QString& directory ) const; + Q_INVOKABLE QString selectDirectory( const QString& title, + const QString& directory ) const; + static ActionRole actionRole( Action action ); Q_SIGNALS: