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 mLineEdit->setToolTip( tr(
"Full path to the file(s), including name and extension" ) );
59 connect( mLineEdit, &QLineEdit::textChanged,
this, &QgsFileWidget::textEdited );
60 mLayout->addWidget( mLineEdit );
62 mFileWidgetButton =
new QToolButton(
this );
63 mFileWidgetButton->setText( QChar( 0x2026 ) );
64 mFileWidgetButton->setToolTip( tr(
"Browse" ) );
65 connect( mFileWidgetButton, &QAbstractButton::clicked,
this, &QgsFileWidget::openFileDialog );
66 mLayout->addWidget( mFileWidgetButton );
79 const QStringList pathParts = path.split( QRegExp(
"\"\\s+\"" ), QString::SkipEmptyParts );
80 for (
const auto &pathsPart : pathParts )
82 QString cleaned = pathsPart;
83 cleaned.remove( QRegExp(
"(^\\s*\")|(\"\\s*)" ) );
84 paths.append( cleaned );
97 mLineEdit->setValue( path );
103 mFileWidgetButton->setEnabled( !readOnly );
104 mLineEdit->setEnabled( !readOnly );
114 mDialogTitle = title;
125 mLineEdit->setFilters( filters );
130 return mButtonVisible;
135 mButtonVisible = visible;
136 mFileWidgetButton->setVisible( visible );
139 void QgsFileWidget::textEdited(
const QString &path )
142 mLinkLabel->setText( toUrl( path ) );
144 if ( path.contains( QStringLiteral(
"\" \"" ) ) )
146 mLineEdit->setToolTip( tr(
"Selected files:<br><ul><li>%1</li></ul><br>" ).arg(
splitFilePaths( path ).join( QStringLiteral(
"</li><li>" ) ) ) );
150 mLineEdit->setToolTip( QString() );
163 mLinkLabel->setVisible( mUseLink );
164 mLineEdit->setVisible( !mUseLink );
167 mLayout->removeWidget( mLineEdit );
168 mLayout->insertWidget( 0, mLinkLabel );
172 mLayout->removeWidget( mLinkLabel );
173 mLayout->insertWidget( 0, mLineEdit );
205 mLineEdit->setStorageMode( storageMode );
210 return mRelativeStorage;
223 void QgsFileWidget::openFileDialog()
230 if ( !mFilePath.isEmpty() )
232 oldPath = relativePath( mFilePath,
false );
236 else if ( !mDefaultRoot.isEmpty() )
238 oldPath = QDir::cleanPath( mDefaultRoot );
242 QUrl url = QUrl::fromUserInput( oldPath );
243 if ( !url.isValid() )
245 QString defPath = QDir::cleanPath( QFileInfo(
QgsProject::instance()->absoluteFilePath() ).path() );
246 if ( defPath.isEmpty() )
248 defPath = QDir::homePath();
250 oldPath = settings.
value( QStringLiteral(
"UI/lastFileNameWidgetDir" ), defPath ).toString();
255 QStringList fileNames;
258 switch ( mStorageMode )
261 title = !mDialogTitle.isEmpty() ? mDialogTitle : tr(
"Select a file" );
262 fileName = QFileDialog::getOpenFileName(
this, title, QFileInfo( oldPath ).absoluteFilePath(), mFilter, &mSelectedFilter );
265 title = !mDialogTitle.isEmpty() ? mDialogTitle : tr(
"Select one or more files" );
266 fileNames = QFileDialog::getOpenFileNames(
this, title, QFileInfo( oldPath ).absoluteFilePath(), mFilter, &mSelectedFilter );
269 title = !mDialogTitle.isEmpty() ? mDialogTitle : tr(
"Select a directory" );
270 fileName = QFileDialog::getExistingDirectory(
this, title, QFileInfo( oldPath ).absoluteFilePath(), QFileDialog::ShowDirsOnly );
274 title = !mDialogTitle.isEmpty() ? mDialogTitle : tr(
"Create or select a file" );
277 fileName = QFileDialog::getSaveFileName(
this, title, QFileInfo( oldPath ).absoluteFilePath(), mFilter, &mSelectedFilter, QFileDialog::DontConfirmOverwrite );
281 fileName = QFileDialog::getSaveFileName(
this, title, QFileInfo( oldPath ).absoluteFilePath(), mFilter, &mSelectedFilter );
291 if ( fileName.isEmpty() && fileNames.isEmpty( ) )
296 fileName = QDir::toNativeSeparators( QDir::cleanPath( QFileInfo( fileName ).absoluteFilePath() ) );
300 for (
int i = 0; i < fileNames.length(); i++ )
302 fileNames.replace( i, QDir::toNativeSeparators( QDir::cleanPath( QFileInfo( fileNames.at( i ) ).absoluteFilePath() ) ) );
307 switch ( mStorageMode )
311 settings.
setValue( QStringLiteral(
"UI/lastFileNameWidgetDir" ), QFileInfo( fileName ).absolutePath() );
314 settings.
setValue( QStringLiteral(
"UI/lastFileNameWidgetDir" ), fileName );
317 settings.
setValue( QStringLiteral(
"UI/lastFileNameWidgetDir" ), QFileInfo( fileNames.first( ) ).absolutePath() );
324 fileName = relativePath( fileName,
true );
329 for (
int i = 0; i < fileNames.length(); i++ )
331 fileNames.replace( i, relativePath( fileNames.at( i ), true ) );
333 if ( fileNames.length() > 1 )
335 setFilePath( QStringLiteral(
"\"%1\"" ).arg( fileNames.join( QStringLiteral(
"\" \"" ) ) ) );
345 QString QgsFileWidget::relativePath(
const QString &
filePath,
bool removeRelative )
const 347 QString RelativePath;
350 RelativePath = QDir::toNativeSeparators( QDir::cleanPath( QFileInfo(
QgsProject::instance()->absoluteFilePath() ).path() ) );
354 RelativePath = QDir::toNativeSeparators( QDir::cleanPath( mDefaultRoot ) );
357 if ( !RelativePath.isEmpty() )
359 if ( removeRelative )
361 return QDir::cleanPath( QDir( RelativePath ).relativeFilePath(
filePath ) );
373 QString QgsFileWidget::toUrl(
const QString &path )
const 376 if ( path.isEmpty() )
381 QString urlStr = relativePath( path,
false );
382 QUrl url = QUrl::fromUserInput( urlStr );
383 if ( !url.isValid() || !url.isLocalFile() )
385 QgsDebugMsg( QStringLiteral(
"URL: %1 is not valid or not a local file!" ).arg( path ) );
389 QString pathStr = url.toString();
392 rep = QStringLiteral(
"<a href=\"%1\">%2</a>" ).arg( pathStr, path );
396 QString fileName = QFileInfo( urlStr ).fileName();
397 rep = QStringLiteral(
"<a href=\"%1\">%2</a>" ).arg( pathStr, fileName );
408 QgsFileDropEdit::QgsFileDropEdit( QWidget *parent )
412 setAcceptDrops(
true );
415 void QgsFileDropEdit::setFilters(
const QString &filters )
417 mAcceptableExtensions.clear();
419 if ( filters.contains( QStringLiteral(
"*.*" ) ) )
422 QRegularExpression rx( QStringLiteral(
"\\*\\.(\\w+)" ) );
423 QRegularExpressionMatchIterator i = rx.globalMatch( filters );
424 while ( i.hasNext() )
426 QRegularExpressionMatch match = i.next();
427 if ( match.hasMatch() )
429 mAcceptableExtensions << match.captured( 1 ).toLower();
434 QString QgsFileDropEdit::acceptableFilePath( QDropEvent *event )
const 436 QStringList rawPaths;
438 if ( event->mimeData()->hasUrls() )
440 const QList< QUrl > urls =
event->mimeData()->urls();
441 rawPaths.reserve( urls.count() );
442 for (
const QUrl &url : urls )
444 const QString local = url.toLocalFile();
445 if ( !rawPaths.contains( local ) )
446 rawPaths.append( local );
453 if ( !rawPaths.contains( u.uri ) )
454 rawPaths.append( u.uri );
457 if ( !event->mimeData()->text().isEmpty() && !rawPaths.contains( event->mimeData()->text() ) )
458 rawPaths.append( event->mimeData()->text() );
460 paths.reserve( rawPaths.count() );
461 for (
const QString &path : qgis::as_const( rawPaths ) )
463 QFileInfo file( path );
464 switch ( mStorageMode )
470 if ( file.isFile() && ( mAcceptableExtensions.isEmpty() || mAcceptableExtensions.contains( file.suffix(), Qt::CaseInsensitive ) ) )
471 paths.append( file.filePath() );
479 paths.append( file.filePath() );
480 else if ( file.isFile() )
483 paths.append( file.absolutePath() );
491 if ( paths.size() > 1 )
493 return QStringLiteral(
"\"%1\"" ).arg( paths.join( QStringLiteral(
"\" \"" ) ) );
495 else if ( paths.size() == 1 )
497 return paths.first();
505 void QgsFileDropEdit::dragEnterEvent( QDragEnterEvent *event )
507 QString
filePath = acceptableFilePath( event );
508 if ( !filePath.isEmpty() )
510 event->acceptProposedAction();
520 void QgsFileDropEdit::dragLeaveEvent( QDragLeaveEvent *event )
522 QgsFilterLineEdit::dragLeaveEvent( event );
528 void QgsFileDropEdit::dropEvent( QDropEvent *event )
530 QString
filePath = acceptableFilePath( event );
531 if ( !filePath.isEmpty() )
535 setFocus( Qt::MouseFocusReason );
536 event->acceptProposedAction();
542 void QgsFileDropEdit::paintEvent( QPaintEvent *e )
544 QgsFilterLineEdit::paintEvent( e );
549 p.setPen( QPen( palette().highlight(), width ) );
550 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.