20 #include <QToolButton> 22 #include <QFileDialog> 23 #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 );
56 mLineEdit =
new QgsFileDropEdit(
this );
57 mLineEdit->setDragEnabled(
true );
58 connect( mLineEdit, &QLineEdit::textChanged,
this, &QgsFileWidget::textEdited );
59 mLayout->addWidget( mLineEdit );
61 mFileWidgetButton =
new QToolButton(
this );
62 mFileWidgetButton->setText( QChar( 0x2026 ) );
63 connect( mFileWidgetButton, &QAbstractButton::clicked,
this, &QgsFileWidget::openFileDialog );
64 mLayout->addWidget( mFileWidgetButton );
77 const QStringList pathParts = path.split( QRegExp(
"\"\\s+\"" ), QString::SkipEmptyParts );
78 for (
const auto &pathsPart : pathParts )
80 QString cleaned = pathsPart;
81 cleaned.remove( QRegExp(
"(^\\s*\")|(\"\\s*)" ) );
82 paths.append( cleaned );
95 mLineEdit->setValue( path );
101 mFileWidgetButton->setEnabled( !readOnly );
102 mLineEdit->setEnabled( !readOnly );
112 mDialogTitle = title;
123 mLineEdit->setFilters( filters );
128 return mButtonVisible;
133 mButtonVisible = visible;
134 mFileWidgetButton->setVisible( visible );
137 void QgsFileWidget::textEdited(
const QString &path )
140 mLinkLabel->setText( toUrl( path ) );
142 if ( path.contains( QStringLiteral(
"\" \"" ) ) )
144 mLineEdit->setToolTip( tr(
"Selected files:<br><ul><li>%1</li></ul><br>" ).arg(
splitFilePaths( path ).join( QStringLiteral(
"</li><li>" ) ) ) );
148 mLineEdit->setToolTip( QString() );
161 mLinkLabel->setVisible( mUseLink );
162 mLineEdit->setVisible( !mUseLink );
165 mLayout->removeWidget( mLineEdit );
166 mLayout->insertWidget( 0, mLinkLabel );
170 mLayout->removeWidget( mLinkLabel );
171 mLayout->insertWidget( 0, mLineEdit );
203 mLineEdit->setStorageMode( storageMode );
208 return mRelativeStorage;
221 void QgsFileWidget::openFileDialog()
228 if ( !mFilePath.isEmpty() )
230 oldPath = relativePath( mFilePath,
false );
234 else if ( !mDefaultRoot.isEmpty() )
236 oldPath = QDir::cleanPath( mDefaultRoot );
240 QUrl url = QUrl::fromUserInput( oldPath );
241 if ( !url.isValid() )
243 QString defPath = QDir::cleanPath( QFileInfo(
QgsProject::instance()->absoluteFilePath() ).path() );
244 if ( defPath.isEmpty() )
246 defPath = QDir::homePath();
248 oldPath = settings.
value( QStringLiteral(
"UI/lastFileNameWidgetDir" ), defPath ).toString();
253 QStringList fileNames;
256 switch ( mStorageMode )
259 title = !mDialogTitle.isEmpty() ? mDialogTitle : tr(
"Select a file" );
260 fileName = QFileDialog::getOpenFileName(
this, title, QFileInfo( oldPath ).absoluteFilePath(), mFilter, &mSelectedFilter );
263 title = !mDialogTitle.isEmpty() ? mDialogTitle : tr(
"Select one or more files" );
264 fileNames = QFileDialog::getOpenFileNames(
this, title, QFileInfo( oldPath ).absoluteFilePath(), mFilter, &mSelectedFilter );
267 title = !mDialogTitle.isEmpty() ? mDialogTitle : tr(
"Select a directory" );
268 fileName = QFileDialog::getExistingDirectory(
this, title, QFileInfo( oldPath ).absoluteFilePath(), QFileDialog::ShowDirsOnly );
272 title = !mDialogTitle.isEmpty() ? mDialogTitle : tr(
"Create or select a file" );
275 fileName = QFileDialog::getSaveFileName(
this, title, QFileInfo( oldPath ).absoluteFilePath(), mFilter, &mSelectedFilter, QFileDialog::DontConfirmOverwrite );
279 fileName = QFileDialog::getSaveFileName(
this, title, QFileInfo( oldPath ).absoluteFilePath(), mFilter, &mSelectedFilter );
289 if ( fileName.isEmpty() && fileNames.isEmpty( ) )
294 fileName = QDir::toNativeSeparators( QDir::cleanPath( QFileInfo( fileName ).absoluteFilePath() ) );
298 for (
int i = 0; i < fileNames.length(); i++ )
300 fileNames.replace( i, QDir::toNativeSeparators( QDir::cleanPath( QFileInfo( fileNames.at( i ) ).absoluteFilePath() ) ) );
305 switch ( mStorageMode )
309 settings.
setValue( QStringLiteral(
"UI/lastFileNameWidgetDir" ), QFileInfo( fileName ).absolutePath() );
312 settings.
setValue( QStringLiteral(
"UI/lastFileNameWidgetDir" ), fileName );
315 settings.
setValue( QStringLiteral(
"UI/lastFileNameWidgetDir" ), QFileInfo( fileNames.first( ) ).absolutePath() );
322 fileName = relativePath( fileName,
true );
327 for (
int i = 0; i < fileNames.length(); i++ )
329 fileNames.replace( i, relativePath( fileNames.at( i ), true ) );
331 if ( fileNames.length() > 1 )
333 setFilePath( QStringLiteral(
"\"%1\"" ).arg( fileNames.join( QStringLiteral(
"\" \"" ) ) ) );
343 QString QgsFileWidget::relativePath(
const QString &
filePath,
bool removeRelative )
const 345 QString RelativePath;
348 RelativePath = QDir::toNativeSeparators( QDir::cleanPath( QFileInfo(
QgsProject::instance()->absoluteFilePath() ).path() ) );
352 RelativePath = QDir::toNativeSeparators( QDir::cleanPath( mDefaultRoot ) );
355 if ( !RelativePath.isEmpty() )
357 if ( removeRelative )
359 return QDir::cleanPath( QDir( RelativePath ).relativeFilePath(
filePath ) );
371 QString QgsFileWidget::toUrl(
const QString &path )
const 374 if ( path.isEmpty() )
379 QString urlStr = relativePath( path,
false );
380 QUrl url = QUrl::fromUserInput( urlStr );
381 if ( !url.isValid() || !url.isLocalFile() )
383 QgsDebugMsg( QStringLiteral(
"URL: %1 is not valid or not a local file!" ).arg( path ) );
387 QString pathStr = url.toString();
390 rep = QStringLiteral(
"<a href=\"%1\">%2</a>" ).arg( pathStr, path );
394 QString fileName = QFileInfo( urlStr ).fileName();
395 rep = QStringLiteral(
"<a href=\"%1\">%2</a>" ).arg( pathStr, fileName );
406 QgsFileDropEdit::QgsFileDropEdit( QWidget *parent )
410 setAcceptDrops(
true );
413 void QgsFileDropEdit::setFilters(
const QString &filters )
415 mAcceptableExtensions.clear();
417 if ( filters.contains( QStringLiteral(
"*.*" ) ) )
420 QRegularExpression rx( QStringLiteral(
"\\*\\.(\\w+)" ) );
421 QRegularExpressionMatchIterator i = rx.globalMatch( filters );
422 while ( i.hasNext() )
424 QRegularExpressionMatch match = i.next();
425 if ( match.hasMatch() )
427 mAcceptableExtensions << match.captured( 1 ).toLower();
432 QString QgsFileDropEdit::acceptableFilePath( QDropEvent *event )
const 434 QStringList rawPaths;
436 if ( event->mimeData()->hasUrls() )
438 const QList< QUrl > urls =
event->mimeData()->urls();
439 rawPaths.reserve( urls.count() );
440 for (
const QUrl &url : urls )
442 const QString local = url.toLocalFile();
443 if ( !rawPaths.contains( local ) )
444 rawPaths.append( local );
451 if ( !rawPaths.contains( u.uri ) )
452 rawPaths.append( u.uri );
455 if ( !event->mimeData()->text().isEmpty() && !rawPaths.contains( event->mimeData()->text() ) )
456 rawPaths.append( event->mimeData()->text() );
458 paths.reserve( rawPaths.count() );
459 for (
const QString &path : qgis::as_const( rawPaths ) )
461 QFileInfo file( path );
462 switch ( mStorageMode )
468 if ( file.isFile() && ( mAcceptableExtensions.isEmpty() || mAcceptableExtensions.contains( file.suffix(), Qt::CaseInsensitive ) ) )
469 paths.append( file.filePath() );
477 paths.append( file.filePath() );
478 else if ( file.isFile() )
481 paths.append( file.absolutePath() );
489 if ( paths.size() > 1 )
491 return QStringLiteral(
"\"%1\"" ).arg( paths.join( QStringLiteral(
"\" \"" ) ) );
493 else if ( paths.size() == 1 )
495 return paths.first();
503 void QgsFileDropEdit::dragEnterEvent( QDragEnterEvent *event )
505 QString
filePath = acceptableFilePath( event );
506 if ( !filePath.isEmpty() )
508 event->acceptProposedAction();
518 void QgsFileDropEdit::dragLeaveEvent( QDragLeaveEvent *event )
520 QgsFilterLineEdit::dragLeaveEvent( event );
526 void QgsFileDropEdit::dropEvent( QDropEvent *event )
528 QString
filePath = acceptableFilePath( event );
529 if ( !filePath.isEmpty() )
533 setFocus( Qt::MouseFocusReason );
534 event->acceptProposedAction();
540 void QgsFileDropEdit::paintEvent( QPaintEvent *e )
542 QgsFilterLineEdit::paintEvent( e );
547 p.setPen( QPen( palette().highlight(), width ) );
548 QRect r = rect().adjusted( width, width, -width, -width );
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.
static UriList decodeUriList(const QMimeData *data)
QLineEdit subclass with built in support for clearing the widget's value and handling custom null val...
static QString nullRepresentation()
This string is used to represent the value NULL throughout QGIS.
void setValue(const QString &key, const QVariant &value, QgsSettings::Section section=QgsSettings::NoSection)
Sets the value of setting key to value.
static QgsProject * instance()
Returns the QgsProject singleton instance.
QList< QgsMimeDataUtils::Uri > UriList
static QString addExtensionFromFilter(const QString &fileName, const QString &filter)
Ensures that a fileName ends with an extension from the specified filter string.