20 #include <QToolButton>
22 #include <QGridLayout>
38 setBackgroundRole( QPalette::Window );
39 setAutoFillBackground(
true );
41 mLayout =
new QHBoxLayout();
42 mLayout->setMargin( 0 );
45 mLinkLabel =
new QLabel(
this );
47 mLinkLabel->setOpenExternalLinks(
true );
50 mLinkLabel->setEnabled(
true );
51 mLinkLabel->setSizePolicy( QSizePolicy::Expanding, QSizePolicy::Preferred );
52 mLinkLabel->setTextFormat( Qt::RichText );
54 mLinkEditButton =
new QToolButton(
this );
56 connect( mLinkEditButton, &QToolButton::clicked,
this, &QgsFileWidget::editLink );
57 mLinkEditButton->hide();
60 mLineEdit =
new QgsFileDropEdit(
this );
61 mLineEdit->setDragEnabled(
true );
62 mLineEdit->setToolTip( tr(
"Full path to the file(s), including name and extension" ) );
63 connect( mLineEdit, &QLineEdit::textChanged,
this, &QgsFileWidget::textEdited );
64 mLayout->addWidget( mLineEdit );
66 mFileWidgetButton =
new QToolButton(
this );
67 mFileWidgetButton->setText( QChar( 0x2026 ) );
68 mFileWidgetButton->setToolTip( tr(
"Browse" ) );
69 connect( mFileWidgetButton, &QAbstractButton::clicked,
this, &QgsFileWidget::openFileDialog );
70 mLayout->addWidget( mFileWidgetButton );
83 const QStringList pathParts = path.split( QRegExp(
"\"\\s+\"" ), QString::SkipEmptyParts );
84 for (
const auto &pathsPart : pathParts )
86 QString cleaned = pathsPart;
87 cleaned.remove( QRegExp(
"(^\\s*\")|(\"\\s*)" ) );
88 paths.append( cleaned );
101 mLineEdit->setValue( path );
107 if ( mReadOnly == readOnly )
110 mReadOnly = readOnly;
122 mDialogTitle = title;
133 mLineEdit->setFilters( filters );
148 return mButtonVisible;
153 mButtonVisible = visible;
154 mFileWidgetButton->setVisible( visible );
157 void QgsFileWidget::textEdited(
const QString &path )
160 mLinkLabel->setText( toUrl( path ) );
162 if ( path.contains( QStringLiteral(
"\" \"" ) ) )
164 mLineEdit->setToolTip( tr(
"Selected files:<br><ul><li>%1</li></ul><br>" ).arg(
splitFilePaths( path ).join( QStringLiteral(
"</li><li>" ) ) ) );
168 mLineEdit->setToolTip( QString() );
173 void QgsFileWidget::editLink()
175 if ( !mUseLink || mReadOnly )
178 mIsLinkEdited = !mIsLinkEdited;
229 return mRelativeStorage;
242 void QgsFileWidget::updateLayout()
244 mLayout->removeWidget( mLineEdit );
245 mLayout->removeWidget( mLinkLabel );
246 mLayout->removeWidget( mLinkEditButton );
248 mLinkEditButton->setVisible( mUseLink && !mReadOnly );
250 mFileWidgetButton->setEnabled( !mReadOnly );
251 mLineEdit->setEnabled( !mReadOnly );
253 if ( mUseLink && !mIsLinkEdited )
255 mLayout->insertWidget( 0, mLinkLabel );
256 mLineEdit->setVisible(
false );
257 mLinkLabel->setVisible(
true );
261 mLayout->insertWidget( 1, mLinkEditButton );
267 mLayout->insertWidget( 0, mLineEdit );
268 mLineEdit->setVisible(
true );
269 mLinkLabel->setVisible(
false );
273 mLayout->insertWidget( 1, mLinkEditButton );
279 void QgsFileWidget::openFileDialog()
286 if ( !mFilePath.isEmpty() )
288 oldPath = relativePath( mFilePath,
false );
292 else if ( !mDefaultRoot.isEmpty() )
294 oldPath = QDir::cleanPath( mDefaultRoot );
298 QUrl url = QUrl::fromUserInput( oldPath );
299 if ( !url.isValid() )
301 QString defPath = QDir::cleanPath( QFileInfo(
QgsProject::instance()->absoluteFilePath() ).path() );
302 if ( defPath.isEmpty() )
304 defPath = QDir::homePath();
306 oldPath = settings.
value( QStringLiteral(
"UI/lastFileNameWidgetDir" ), defPath ).toString();
311 QStringList fileNames;
316 switch ( mStorageMode )
319 title = !mDialogTitle.isEmpty() ? mDialogTitle : tr(
"Select a file" );
320 fileName = QFileDialog::getOpenFileName(
this, title, QFileInfo( oldPath ).absoluteFilePath(), mFilter, &mSelectedFilter, mOptions );
323 title = !mDialogTitle.isEmpty() ? mDialogTitle : tr(
"Select one or more files" );
324 fileNames = QFileDialog::getOpenFileNames(
this, title, QFileInfo( oldPath ).absoluteFilePath(), mFilter, &mSelectedFilter, mOptions );
327 title = !mDialogTitle.isEmpty() ? mDialogTitle : tr(
"Select a directory" );
328 fileName = QFileDialog::getExistingDirectory(
this, title, QFileInfo( oldPath ).absoluteFilePath(), mOptions | QFileDialog::ShowDirsOnly );
332 title = !mDialogTitle.isEmpty() ? mDialogTitle : tr(
"Create or select a file" );
335 fileName = QFileDialog::getSaveFileName(
this, title, QFileInfo( oldPath ).absoluteFilePath(), mFilter, &mSelectedFilter, mOptions | QFileDialog::DontConfirmOverwrite );
339 fileName = QFileDialog::getSaveFileName(
this, title, QFileInfo( oldPath ).absoluteFilePath(), mFilter, &mSelectedFilter, mOptions );
350 if ( fileName.isEmpty() && fileNames.isEmpty( ) )
355 fileName = QDir::toNativeSeparators( QDir::cleanPath( QFileInfo( fileName ).absoluteFilePath() ) );
359 for (
int i = 0; i < fileNames.length(); i++ )
361 fileNames.replace( i, QDir::toNativeSeparators( QDir::cleanPath( QFileInfo( fileNames.at( i ) ).absoluteFilePath() ) ) );
366 switch ( mStorageMode )
370 settings.
setValue( QStringLiteral(
"UI/lastFileNameWidgetDir" ), QFileInfo( fileName ).absolutePath() );
373 settings.
setValue( QStringLiteral(
"UI/lastFileNameWidgetDir" ), fileName );
376 settings.
setValue( QStringLiteral(
"UI/lastFileNameWidgetDir" ), QFileInfo( fileNames.first( ) ).absolutePath() );
383 fileName = relativePath( fileName,
true );
388 for (
int i = 0; i < fileNames.length(); i++ )
390 fileNames.replace( i, relativePath( fileNames.at( i ),
true ) );
392 if ( fileNames.length() > 1 )
394 setFilePath( QStringLiteral(
"\"%1\"" ).arg( fileNames.join( QStringLiteral(
"\" \"" ) ) ) );
404 QString QgsFileWidget::relativePath(
const QString &filePath,
bool removeRelative )
const
406 QString RelativePath;
409 RelativePath = QDir::toNativeSeparators( QDir::cleanPath( QFileInfo(
QgsProject::instance()->absoluteFilePath() ).path() ) );
413 RelativePath = QDir::toNativeSeparators( QDir::cleanPath( mDefaultRoot ) );
416 if ( !RelativePath.isEmpty() )
418 if ( removeRelative )
420 return QDir::cleanPath( QDir( RelativePath ).relativeFilePath(
filePath ) );
432 QString QgsFileWidget::toUrl(
const QString &path )
const
435 if ( path.isEmpty() )
440 QString urlStr = relativePath( path,
false );
441 QUrl url = QUrl::fromUserInput( urlStr );
442 if ( !url.isValid() || !url.isLocalFile() )
444 QgsDebugMsg( QStringLiteral(
"URL: %1 is not valid or not a local file!" ).arg( path ) );
448 QString pathStr = url.toString();
451 rep = QStringLiteral(
"<a href=\"%1\">%2</a>" ).arg( pathStr, path );
455 QString fileName = QFileInfo( urlStr ).fileName();
456 rep = QStringLiteral(
"<a href=\"%1\">%2</a>" ).arg( pathStr, fileName );
467 QgsFileDropEdit::QgsFileDropEdit( QWidget *parent )
470 setAcceptDrops(
true );
473 void QgsFileDropEdit::setFilters(
const QString &filters )
475 mAcceptableExtensions.clear();
477 if ( filters.contains( QStringLiteral(
"*.*" ) ) )
480 QRegularExpression rx( QStringLiteral(
"\\*\\.(\\w+)" ) );
481 QRegularExpressionMatchIterator i = rx.globalMatch( filters );
482 while ( i.hasNext() )
484 QRegularExpressionMatch match = i.next();
485 if ( match.hasMatch() )
487 mAcceptableExtensions << match.captured( 1 ).toLower();
492 QString QgsFileDropEdit::acceptableFilePath( QDropEvent *event )
const
494 QStringList rawPaths;
496 if ( event->mimeData()->hasUrls() )
498 const QList< QUrl > urls =
event->mimeData()->urls();
499 rawPaths.reserve( urls.count() );
500 for (
const QUrl &url : urls )
502 const QString local = url.toLocalFile();
503 if ( !rawPaths.contains( local ) )
504 rawPaths.append( local );
511 if ( !rawPaths.contains( u.uri ) )
512 rawPaths.append( u.uri );
515 if ( !event->mimeData()->text().isEmpty() && !rawPaths.contains( event->mimeData()->text() ) )
516 rawPaths.append( event->mimeData()->text() );
518 paths.reserve( rawPaths.count() );
519 for (
const QString &path : qgis::as_const( rawPaths ) )
521 QFileInfo file( path );
522 switch ( mStorageMode )
528 if ( file.isFile() && ( mAcceptableExtensions.isEmpty() || mAcceptableExtensions.contains( file.suffix(), Qt::CaseInsensitive ) ) )
529 paths.append( file.filePath() );
537 paths.append( file.filePath() );
538 else if ( file.isFile() )
541 paths.append( file.absolutePath() );
549 if ( paths.size() > 1 )
551 return QStringLiteral(
"\"%1\"" ).arg( paths.join( QStringLiteral(
"\" \"" ) ) );
553 else if ( paths.size() == 1 )
555 return paths.first();
563 void QgsFileDropEdit::dragEnterEvent( QDragEnterEvent *event )
565 QString filePath = acceptableFilePath( event );
566 if ( !filePath.isEmpty() )
568 event->acceptProposedAction();
569 setHighlighted(
true );
577 void QgsFileDropEdit::dragLeaveEvent( QDragLeaveEvent *event )
579 QgsFilterLineEdit::dragLeaveEvent( event );
581 setHighlighted(
false );
584 void QgsFileDropEdit::dropEvent( QDropEvent *event )
586 QString filePath = acceptableFilePath( event );
587 if ( !filePath.isEmpty() )
591 setFocus( Qt::MouseFocusReason );
592 event->acceptProposedAction();
593 setHighlighted(
false );