20 #include <QToolButton>
22 #include <QGridLayout>
25 #include <QRegularExpression>
39 setBackgroundRole( QPalette::Window );
40 setAutoFillBackground(
true );
43 mLayout->setContentsMargins( 0, 0, 0, 0 );
52 mLinkLabel->setSizePolicy( QSizePolicy::Expanding, QSizePolicy::Preferred );
60 mLineEdit->setToolTip( tr(
"Full path to the file(s), including name and extension" ) );
61 connect(
mLineEdit, &QLineEdit::textChanged,
this, &QgsFileWidget::textEdited );
62 connect(
mLineEdit, &QgsFileDropEdit::fileDropped,
this, &QgsFileWidget::fileDropped );
68 connect(
mLinkEditButton, &QToolButton::clicked,
this, &QgsFileWidget::editLink );
74 connect(
mFileWidgetButton, &QAbstractButton::clicked,
this, &QgsFileWidget::openFileDialog );
88 #if QT_VERSION < QT_VERSION_CHECK(5, 15, 0)
89 const QStringList pathParts = path.split( QRegExp(
"\"\\s+\"" ), QString::SkipEmptyParts );
91 const thread_local QRegularExpression partsRegex = QRegularExpression( QStringLiteral(
"\"\\s+\"" ) );
92 const QStringList pathParts = path.split( partsRegex, Qt::SkipEmptyParts );
95 const thread_local QRegularExpression cleanRe( QStringLiteral(
"(^\\s*\")|(\"\\s*)" ) );
96 paths.reserve( pathParts.size() );
97 for (
const QString &pathsPart : pathParts )
99 QString cleaned = pathsPart;
100 cleaned.remove( cleanRe );
101 paths.append( cleaned );
166 return path.contains( QStringLiteral(
"\" \"" ) );
169 void QgsFileWidget::textEdited(
const QString &path )
176 mLineEdit->setToolTip( tr(
"Selected files:<br><ul><li>%1</li></ul><br>" ).arg(
splitFilePaths( path ).join( QLatin1String(
"</li><li>" ) ) ) );
185 void QgsFileWidget::editLink()
194 void QgsFileWidget::fileDropped(
const QString &filePath )
198 mLineEdit->setFocus( Qt::MouseFocusReason );
277 void QgsFileWidget::openFileDialog()
296 QUrl url = QUrl::fromUserInput( oldPath );
297 if ( !url.isValid() )
299 QString defPath = QDir::cleanPath( QFileInfo(
QgsProject::instance()->absoluteFilePath() ).path() );
300 if ( defPath.isEmpty() )
302 defPath = QDir::homePath();
304 oldPath = settings.
value( QStringLiteral(
"UI/lastFileNameWidgetDir" ), defPath ).toString();
309 QStringList fileNames;
326 fileName = QFileDialog::getExistingDirectory(
this, title, QFileInfo( oldPath ).absoluteFilePath(),
mOptions | QFileDialog::ShowDirsOnly );
333 fileName = QFileDialog::getSaveFileName(
this, title, QFileInfo( oldPath ).absoluteFilePath(),
mFilter, &
mSelectedFilter,
mOptions | QFileDialog::DontConfirmOverwrite );
348 if ( fileName.isEmpty() && fileNames.isEmpty( ) )
352 fileNames << fileName;
354 for (
int i = 0; i < fileNames.length(); i++ )
356 fileNames.replace( i, QDir::toNativeSeparators( QDir::cleanPath( QFileInfo( fileNames.at( i ) ).absoluteFilePath() ) ) );
365 settings.
setValue( QStringLiteral(
"UI/lastFileNameWidgetDir" ), QFileInfo( fileNames.first() ).absolutePath() );
368 settings.
setValue( QStringLiteral(
"UI/lastFileNameWidgetDir" ), fileNames.first() );
377 Q_ASSERT( fileNames.count() );
380 for (
int i = 0; i < fileNames.length(); i++ )
382 fileNames.replace( i,
relativePath( fileNames.at( i ),
true ) );
396 if ( filePaths.length() > 1 )
398 setFilePath( QStringLiteral(
"\"%1\"" ).arg( filePaths.join( QLatin1String(
"\" \"" ) ) ) );
409 QString RelativePath;
412 RelativePath = QDir::toNativeSeparators( QDir::cleanPath( QFileInfo(
QgsProject::instance()->absoluteFilePath() ).path() ) );
416 RelativePath = QDir::toNativeSeparators( QDir::cleanPath(
mDefaultRoot ) );
419 if ( !RelativePath.isEmpty() )
421 if ( removeRelative )
423 return QDir::cleanPath( QDir( RelativePath ).relativeFilePath(
filePath ) );
438 if ( path.isEmpty() )
445 return QStringLiteral(
"<a>%1</a>" ).arg( path );
449 QUrl url = QUrl::fromUserInput( urlStr );
450 if ( !url.isValid() || !url.isLocalFile() )
452 QgsDebugMsgLevel( QStringLiteral(
"URL: %1 is not valid or not a local file!" ).arg( path ), 2 );
456 QString pathStr = url.toString();
459 rep = QStringLiteral(
"<a href=\"%1\">%2</a>" ).arg( pathStr, path );
463 QString fileName = QFileInfo( urlStr ).fileName();
464 rep = QStringLiteral(
"<a href=\"%1\">%2</a>" ).arg( pathStr, fileName );
474 QgsFileDropEdit::QgsFileDropEdit( QWidget *parent )
477 setAcceptDrops(
true );
480 void QgsFileDropEdit::setFilters(
const QString &filters )
482 mAcceptableExtensions.clear();
484 if ( filters.contains( QStringLiteral(
"*.*" ) ) )
487 QRegularExpression rx( QStringLiteral(
"\\*\\.(\\w+)" ) );
488 QRegularExpressionMatchIterator i = rx.globalMatch( filters );
489 while ( i.hasNext() )
491 QRegularExpressionMatch match = i.next();
492 if ( match.hasMatch() )
494 mAcceptableExtensions << match.captured( 1 ).toLower();
499 QStringList QgsFileDropEdit::acceptableFilePaths( QDropEvent *event )
const
501 QStringList rawPaths;
503 if ( event->mimeData()->hasUrls() )
505 const QList< QUrl > urls =
event->mimeData()->urls();
506 rawPaths.reserve( urls.count() );
507 for (
const QUrl &url : urls )
509 const QString local = url.toLocalFile();
510 if ( !rawPaths.contains( local ) )
511 rawPaths.append( local );
518 if ( !rawPaths.contains( u.uri ) )
519 rawPaths.append( u.uri );
522 if ( !event->mimeData()->text().isEmpty() && !rawPaths.contains( event->mimeData()->text() ) )
523 rawPaths.append( event->mimeData()->text() );
525 paths.reserve( rawPaths.count() );
526 for (
const QString &path : std::as_const( rawPaths ) )
528 QFileInfo file( path );
529 switch ( mStorageMode )
535 if ( file.isFile() && ( mAcceptableExtensions.isEmpty() || mAcceptableExtensions.contains( file.suffix(), Qt::CaseInsensitive ) ) )
536 paths.append( file.filePath() );
544 paths.append( file.filePath() );
545 else if ( file.isFile() )
548 paths.append( file.absolutePath() );
559 QString QgsFileDropEdit::acceptableFilePath( QDropEvent *event )
const
561 const QStringList paths = acceptableFilePaths( event );
562 if ( paths.size() > 1 )
564 return QStringLiteral(
"\"%1\"" ).arg( paths.join( QLatin1String(
"\" \"" ) ) );
566 else if ( paths.size() == 1 )
568 return paths.first();
576 void QgsFileDropEdit::dragEnterEvent( QDragEnterEvent *event )
578 QString filePath = acceptableFilePath( event );
579 if ( !filePath.isEmpty() )
581 event->acceptProposedAction();
582 setHighlighted(
true );
590 void QgsFileDropEdit::dragLeaveEvent( QDragLeaveEvent *event )
592 QgsFilterLineEdit::dragLeaveEvent( event );
594 setHighlighted(
false );
597 void QgsFileDropEdit::dropEvent( QDropEvent *event )
599 QString filePath = acceptableFilePath( event );
600 if ( !filePath.isEmpty() )
602 event->acceptProposedAction();
603 emit fileDropped( filePath );
606 setHighlighted(
false );
static QString nullRepresentation()
This string is used to represent the value NULL throughout QGIS.
static QIcon getThemeIcon(const QString &name, const QColor &fillColor=QColor(), const QColor &strokeColor=QColor())
Helper to get a theme icon.
static QString addExtensionFromFilter(const QString &fileName, const QString &filter)
Ensures that a fileName ends with an extension from the specified filter string.
QLineEdit subclass with built in support for clearing the widget's value and handling custom null val...
Trick to keep a widget focused and avoid QT crashes.
A QgsFilterLineEdit subclass with the ability to "highlight" the edges of the widget.
QList< QgsMimeDataUtils::Uri > UriList
static UriList decodeUriList(const QMimeData *data)
static QgsProject * instance()
Returns the QgsProject singleton instance.
This class is a composition of two QSettings instances:
QVariant value(const QString &key, const QVariant &defaultValue=QVariant(), Section section=NoSection) const
Returns the value for setting key.
void setValue(const QString &key, const QVariant &value, QgsSettings::Section section=QgsSettings::NoSection)
Sets the value of setting key to value.
#define QgsDebugMsgLevel(str, level)