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;
259 switch ( mStorageMode )
262 title = !mDialogTitle.isEmpty() ? mDialogTitle : tr(
"Select a file" );
263 fileName = QFileDialog::getOpenFileName(
this, title, QFileInfo( oldPath ).absoluteFilePath(), mFilter, &mSelectedFilter );
266 title = !mDialogTitle.isEmpty() ? mDialogTitle : tr(
"Select one or more files" );
267 fileNames = QFileDialog::getOpenFileNames(
this, title, QFileInfo( oldPath ).absoluteFilePath(), mFilter, &mSelectedFilter );
270 title = !mDialogTitle.isEmpty() ? mDialogTitle : tr(
"Select a directory" );
271 fileName = QFileDialog::getExistingDirectory(
this, title, QFileInfo( oldPath ).absoluteFilePath(), QFileDialog::ShowDirsOnly );
275 title = !mDialogTitle.isEmpty() ? mDialogTitle : tr(
"Create or select a file" );
278 fileName = QFileDialog::getSaveFileName(
this, title, QFileInfo( oldPath ).absoluteFilePath(), mFilter, &mSelectedFilter, QFileDialog::DontConfirmOverwrite );
282 fileName = QFileDialog::getSaveFileName(
this, title, QFileInfo( oldPath ).absoluteFilePath(), mFilter, &mSelectedFilter );
293 if ( fileName.isEmpty() && fileNames.isEmpty( ) )
298 fileName = QDir::toNativeSeparators( QDir::cleanPath( QFileInfo( fileName ).absoluteFilePath() ) );
302 for (
int i = 0; i < fileNames.length(); i++ )
304 fileNames.replace( i, QDir::toNativeSeparators( QDir::cleanPath( QFileInfo( fileNames.at( i ) ).absoluteFilePath() ) ) );
309 switch ( mStorageMode )
313 settings.
setValue( QStringLiteral(
"UI/lastFileNameWidgetDir" ), QFileInfo( fileName ).absolutePath() );
316 settings.
setValue( QStringLiteral(
"UI/lastFileNameWidgetDir" ), fileName );
319 settings.
setValue( QStringLiteral(
"UI/lastFileNameWidgetDir" ), QFileInfo( fileNames.first( ) ).absolutePath() );
326 fileName = relativePath( fileName,
true );
331 for (
int i = 0; i < fileNames.length(); i++ )
333 fileNames.replace( i, relativePath( fileNames.at( i ), true ) );
335 if ( fileNames.length() > 1 )
337 setFilePath( QStringLiteral(
"\"%1\"" ).arg( fileNames.join( QStringLiteral(
"\" \"" ) ) ) );
347 QString QgsFileWidget::relativePath(
const QString &
filePath,
bool removeRelative )
const 349 QString RelativePath;
352 RelativePath = QDir::toNativeSeparators( QDir::cleanPath( QFileInfo(
QgsProject::instance()->absoluteFilePath() ).path() ) );
356 RelativePath = QDir::toNativeSeparators( QDir::cleanPath( mDefaultRoot ) );
359 if ( !RelativePath.isEmpty() )
361 if ( removeRelative )
363 return QDir::cleanPath( QDir( RelativePath ).relativeFilePath(
filePath ) );
375 QString QgsFileWidget::toUrl(
const QString &path )
const 378 if ( path.isEmpty() )
383 QString urlStr = relativePath( path,
false );
384 QUrl url = QUrl::fromUserInput( urlStr );
385 if ( !url.isValid() || !url.isLocalFile() )
387 QgsDebugMsg( QStringLiteral(
"URL: %1 is not valid or not a local file!" ).arg( path ) );
391 QString pathStr = url.toString();
394 rep = QStringLiteral(
"<a href=\"%1\">%2</a>" ).arg( pathStr, path );
398 QString fileName = QFileInfo( urlStr ).fileName();
399 rep = QStringLiteral(
"<a href=\"%1\">%2</a>" ).arg( pathStr, fileName );
410 QgsFileDropEdit::QgsFileDropEdit( QWidget *parent )
414 setAcceptDrops(
true );
417 void QgsFileDropEdit::setFilters(
const QString &filters )
419 mAcceptableExtensions.clear();
421 if ( filters.contains( QStringLiteral(
"*.*" ) ) )
424 QRegularExpression rx( QStringLiteral(
"\\*\\.(\\w+)" ) );
425 QRegularExpressionMatchIterator i = rx.globalMatch( filters );
426 while ( i.hasNext() )
428 QRegularExpressionMatch match = i.next();
429 if ( match.hasMatch() )
431 mAcceptableExtensions << match.captured( 1 ).toLower();
436 QString QgsFileDropEdit::acceptableFilePath( QDropEvent *event )
const 438 QStringList rawPaths;
440 if ( event->mimeData()->hasUrls() )
442 const QList< QUrl > urls =
event->mimeData()->urls();
443 rawPaths.reserve( urls.count() );
444 for (
const QUrl &url : urls )
446 const QString local = url.toLocalFile();
447 if ( !rawPaths.contains( local ) )
448 rawPaths.append( local );
455 if ( !rawPaths.contains( u.uri ) )
456 rawPaths.append( u.uri );
459 if ( !event->mimeData()->text().isEmpty() && !rawPaths.contains( event->mimeData()->text() ) )
460 rawPaths.append( event->mimeData()->text() );
462 paths.reserve( rawPaths.count() );
463 for (
const QString &path : qgis::as_const( rawPaths ) )
465 QFileInfo file( path );
466 switch ( mStorageMode )
472 if ( file.isFile() && ( mAcceptableExtensions.isEmpty() || mAcceptableExtensions.contains( file.suffix(), Qt::CaseInsensitive ) ) )
473 paths.append( file.filePath() );
481 paths.append( file.filePath() );
482 else if ( file.isFile() )
485 paths.append( file.absolutePath() );
493 if ( paths.size() > 1 )
495 return QStringLiteral(
"\"%1\"" ).arg( paths.join( QStringLiteral(
"\" \"" ) ) );
497 else if ( paths.size() == 1 )
499 return paths.first();
507 void QgsFileDropEdit::dragEnterEvent( QDragEnterEvent *event )
509 QString
filePath = acceptableFilePath( event );
510 if ( !filePath.isEmpty() )
512 event->acceptProposedAction();
522 void QgsFileDropEdit::dragLeaveEvent( QDragLeaveEvent *event )
524 QgsFilterLineEdit::dragLeaveEvent( event );
530 void QgsFileDropEdit::dropEvent( QDropEvent *event )
532 QString
filePath = acceptableFilePath( event );
533 if ( !filePath.isEmpty() )
537 setFocus( Qt::MouseFocusReason );
538 event->acceptProposedAction();
544 void QgsFileDropEdit::paintEvent( QPaintEvent *e )
546 QgsFilterLineEdit::paintEvent( e );
551 p.setPen( QPen( palette().highlight(), width ) );
552 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.