20 #include <QToolButton>
22 #include <QGridLayout>
38 setBackgroundRole( QPalette::Window );
39 setAutoFillBackground(
true );
41 mLayout =
new QHBoxLayout();
42 mLayout->setContentsMargins( 0, 0, 0, 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 );
96 mLineEdit->setValue( path );
101 if ( mReadOnly == readOnly )
104 mReadOnly = readOnly;
116 mDialogTitle = title;
127 mLineEdit->setFilters( filters );
142 return mButtonVisible;
147 mButtonVisible = visible;
148 mFileWidgetButton->setVisible( visible );
151 void QgsFileWidget::textEdited(
const QString &path )
154 mLinkLabel->setText( toUrl( path ) );
156 if ( path.contains( QStringLiteral(
"\" \"" ) ) )
158 mLineEdit->setToolTip( tr(
"Selected files:<br><ul><li>%1</li></ul><br>" ).arg(
splitFilePaths( path ).join( QLatin1String(
"</li><li>" ) ) ) );
162 mLineEdit->setToolTip( QString() );
167 void QgsFileWidget::editLink()
169 if ( !mUseLink || mReadOnly )
172 mIsLinkEdited = !mIsLinkEdited;
223 return mRelativeStorage;
236 void QgsFileWidget::updateLayout()
238 mLayout->removeWidget( mLineEdit );
239 mLayout->removeWidget( mLinkLabel );
240 mLayout->removeWidget( mLinkEditButton );
242 mLinkEditButton->setVisible( mUseLink && !mReadOnly );
244 mFileWidgetButton->setEnabled( !mReadOnly );
245 mLineEdit->setEnabled( !mReadOnly );
247 if ( mUseLink && !mIsLinkEdited )
249 mLayout->insertWidget( 0, mLinkLabel );
250 mLineEdit->setVisible(
false );
251 mLinkLabel->setVisible(
true );
255 mLayout->insertWidget( 1, mLinkEditButton );
261 mLayout->insertWidget( 0, mLineEdit );
262 mLineEdit->setVisible(
true );
263 mLinkLabel->setVisible(
false );
267 mLayout->insertWidget( 1, mLinkEditButton );
273 void QgsFileWidget::openFileDialog()
280 if ( !mFilePath.isEmpty() )
282 oldPath = relativePath( mFilePath,
false );
286 else if ( !mDefaultRoot.isEmpty() )
288 oldPath = QDir::cleanPath( mDefaultRoot );
292 QUrl url = QUrl::fromUserInput( oldPath );
293 if ( !url.isValid() )
295 QString defPath = QDir::cleanPath( QFileInfo(
QgsProject::instance()->absoluteFilePath() ).path() );
296 if ( defPath.isEmpty() )
298 defPath = QDir::homePath();
300 oldPath = settings.
value( QStringLiteral(
"UI/lastFileNameWidgetDir" ), defPath ).toString();
305 QStringList fileNames;
310 switch ( mStorageMode )
313 title = !mDialogTitle.isEmpty() ? mDialogTitle : tr(
"Select a file" );
314 fileName = QFileDialog::getOpenFileName(
this, title, QFileInfo( oldPath ).absoluteFilePath(), mFilter, &mSelectedFilter, mOptions );
317 title = !mDialogTitle.isEmpty() ? mDialogTitle : tr(
"Select one or more files" );
318 fileNames = QFileDialog::getOpenFileNames(
this, title, QFileInfo( oldPath ).absoluteFilePath(), mFilter, &mSelectedFilter, mOptions );
321 title = !mDialogTitle.isEmpty() ? mDialogTitle : tr(
"Select a directory" );
322 fileName = QFileDialog::getExistingDirectory(
this, title, QFileInfo( oldPath ).absoluteFilePath(), mOptions | QFileDialog::ShowDirsOnly );
326 title = !mDialogTitle.isEmpty() ? mDialogTitle : tr(
"Create or select a file" );
329 fileName = QFileDialog::getSaveFileName(
this, title, QFileInfo( oldPath ).absoluteFilePath(), mFilter, &mSelectedFilter, mOptions | QFileDialog::DontConfirmOverwrite );
333 fileName = QFileDialog::getSaveFileName(
this, title, QFileInfo( oldPath ).absoluteFilePath(), mFilter, &mSelectedFilter, mOptions );
344 if ( fileName.isEmpty() && fileNames.isEmpty( ) )
349 fileName = QDir::toNativeSeparators( QDir::cleanPath( QFileInfo( fileName ).absoluteFilePath() ) );
353 for (
int i = 0; i < fileNames.length(); i++ )
355 fileNames.replace( i, QDir::toNativeSeparators( QDir::cleanPath( QFileInfo( fileNames.at( i ) ).absoluteFilePath() ) ) );
360 switch ( mStorageMode )
364 settings.
setValue( QStringLiteral(
"UI/lastFileNameWidgetDir" ), QFileInfo( fileName ).absolutePath() );
367 settings.
setValue( QStringLiteral(
"UI/lastFileNameWidgetDir" ), fileName );
370 settings.
setValue( QStringLiteral(
"UI/lastFileNameWidgetDir" ), QFileInfo( fileNames.first( ) ).absolutePath() );
377 fileName = relativePath( fileName,
true );
382 for (
int i = 0; i < fileNames.length(); i++ )
384 fileNames.replace( i, relativePath( fileNames.at( i ),
true ) );
386 if ( fileNames.length() > 1 )
388 setFilePath( QStringLiteral(
"\"%1\"" ).arg( fileNames.join( QLatin1String(
"\" \"" ) ) ) );
398 QString QgsFileWidget::relativePath(
const QString &filePath,
bool removeRelative )
const
400 QString RelativePath;
403 RelativePath = QDir::toNativeSeparators( QDir::cleanPath( QFileInfo(
QgsProject::instance()->absoluteFilePath() ).path() ) );
407 RelativePath = QDir::toNativeSeparators( QDir::cleanPath( mDefaultRoot ) );
410 if ( !RelativePath.isEmpty() )
412 if ( removeRelative )
414 return QDir::cleanPath( QDir( RelativePath ).relativeFilePath(
filePath ) );
426 QString QgsFileWidget::toUrl(
const QString &path )
const
429 if ( path.isEmpty() )
434 QString urlStr = relativePath( path,
false );
435 QUrl url = QUrl::fromUserInput( urlStr );
436 if ( !url.isValid() || !url.isLocalFile() )
438 QgsDebugMsg( QStringLiteral(
"URL: %1 is not valid or not a local file!" ).arg( path ) );
442 QString pathStr = url.toString();
445 rep = QStringLiteral(
"<a href=\"%1\">%2</a>" ).arg( pathStr, path );
449 QString fileName = QFileInfo( urlStr ).fileName();
450 rep = QStringLiteral(
"<a href=\"%1\">%2</a>" ).arg( pathStr, fileName );
461 QgsFileDropEdit::QgsFileDropEdit( QWidget *parent )
464 setAcceptDrops(
true );
467 void QgsFileDropEdit::setFilters(
const QString &filters )
469 mAcceptableExtensions.clear();
471 if ( filters.contains( QStringLiteral(
"*.*" ) ) )
474 QRegularExpression rx( QStringLiteral(
"\\*\\.(\\w+)" ) );
475 QRegularExpressionMatchIterator i = rx.globalMatch( filters );
476 while ( i.hasNext() )
478 QRegularExpressionMatch match = i.next();
479 if ( match.hasMatch() )
481 mAcceptableExtensions << match.captured( 1 ).toLower();
486 QString QgsFileDropEdit::acceptableFilePath( QDropEvent *event )
const
488 QStringList rawPaths;
490 if ( event->mimeData()->hasUrls() )
492 const QList< QUrl > urls =
event->mimeData()->urls();
493 rawPaths.reserve( urls.count() );
494 for (
const QUrl &url : urls )
496 const QString local = url.toLocalFile();
497 if ( !rawPaths.contains( local ) )
498 rawPaths.append( local );
505 if ( !rawPaths.contains( u.uri ) )
506 rawPaths.append( u.uri );
509 if ( !event->mimeData()->text().isEmpty() && !rawPaths.contains( event->mimeData()->text() ) )
510 rawPaths.append( event->mimeData()->text() );
512 paths.reserve( rawPaths.count() );
513 for (
const QString &path : qgis::as_const( rawPaths ) )
515 QFileInfo file( path );
516 switch ( mStorageMode )
522 if ( file.isFile() && ( mAcceptableExtensions.isEmpty() || mAcceptableExtensions.contains( file.suffix(), Qt::CaseInsensitive ) ) )
523 paths.append( file.filePath() );
531 paths.append( file.filePath() );
532 else if ( file.isFile() )
535 paths.append( file.absolutePath() );
543 if ( paths.size() > 1 )
545 return QStringLiteral(
"\"%1\"" ).arg( paths.join( QLatin1String(
"\" \"" ) ) );
547 else if ( paths.size() == 1 )
549 return paths.first();
557 void QgsFileDropEdit::dragEnterEvent( QDragEnterEvent *event )
559 QString filePath = acceptableFilePath( event );
560 if ( !filePath.isEmpty() )
562 event->acceptProposedAction();
563 setHighlighted(
true );
571 void QgsFileDropEdit::dragLeaveEvent( QDragLeaveEvent *event )
573 QgsFilterLineEdit::dragLeaveEvent( event );
575 setHighlighted(
false );
578 void QgsFileDropEdit::dropEvent( QDropEvent *event )
580 QString filePath = acceptableFilePath( event );
581 if ( !filePath.isEmpty() )
585 setFocus( Qt::MouseFocusReason );
586 event->acceptProposedAction();
587 setHighlighted(
false );