20 #include <QToolButton> 22 #include <QFileDialog> 23 #include <QGridLayout> 37 setBackgroundRole( QPalette::Window );
38 setAutoFillBackground(
true );
40 mLayout =
new QHBoxLayout();
41 mLayout->setMargin( 0 );
44 mLinkLabel =
new QLabel(
this );
46 mLinkLabel->setOpenExternalLinks(
true );
49 mLinkLabel->setEnabled(
true );
50 mLinkLabel->setSizePolicy( QSizePolicy::Expanding, QSizePolicy::Preferred );
51 mLinkLabel->setTextFormat( Qt::RichText );
55 mLineEdit =
new QgsFileDropEdit(
this );
56 connect( mLineEdit, &QLineEdit::textChanged,
this, &QgsFileWidget::textEdited );
57 mLayout->addWidget( mLineEdit );
59 mFileWidgetButton =
new QToolButton(
this );
60 mFileWidgetButton->setText( QChar( 0x2026 ) );
61 connect( mFileWidgetButton, &QAbstractButton::clicked,
this, &QgsFileWidget::openFileDialog );
62 mLayout->addWidget( mFileWidgetButton );
75 const QStringList pathParts = path.split( QRegExp(
"\"\\s+\"" ), QString::SkipEmptyParts );
76 for (
const auto &pathsPart : pathParts )
78 QString cleaned = pathsPart;
79 cleaned.remove( QRegExp(
"(^\\s*\")|(\"\\s*)" ) );
80 paths.append( cleaned );
93 mLineEdit->setValue( path );
99 mFileWidgetButton->setEnabled( !readOnly );
100 mLineEdit->setEnabled( !readOnly );
110 mDialogTitle = title;
121 mLineEdit->setFilters( filters );
126 return mButtonVisible;
131 mButtonVisible = visible;
132 mFileWidgetButton->setVisible( visible );
135 void QgsFileWidget::textEdited(
const QString &path )
138 mLinkLabel->setText( toUrl( path ) );
140 if ( path.contains( QStringLiteral(
"\" \"" ) ) )
142 mLineEdit->setToolTip( tr(
"Selected files:<br><ul><li>%1</li></ul><br>" ).arg(
splitFilePaths( path ).join( QStringLiteral(
"</li><li>" ) ) ) );
146 mLineEdit->setToolTip( QString() );
159 mLinkLabel->setVisible( mUseLink );
160 mLineEdit->setVisible( !mUseLink );
163 mLayout->removeWidget( mLineEdit );
164 mLayout->insertWidget( 0, mLinkLabel );
168 mLayout->removeWidget( mLinkLabel );
169 mLayout->insertWidget( 0, mLineEdit );
201 mLineEdit->setStorageMode( storageMode );
206 return mRelativeStorage;
219 void QgsFileWidget::openFileDialog()
225 if ( !mDefaultRoot.isEmpty() )
227 oldPath = QDir::cleanPath( mDefaultRoot );
230 else if ( !mFilePath.isEmpty() )
232 oldPath = relativePath( mFilePath,
false );
236 QUrl url = QUrl::fromUserInput( oldPath );
237 if ( !url.isValid() )
240 if ( defPath.isEmpty() )
242 defPath = QDir::homePath();
244 oldPath = settings.
value( QStringLiteral(
"UI/lastFileNameWidgetDir" ), defPath ).toString();
249 QStringList fileNames;
252 switch ( mStorageMode )
255 title = !mDialogTitle.isEmpty() ? mDialogTitle : tr(
"Select a file" );
256 fileName = QFileDialog::getOpenFileName(
this, title, QFileInfo( oldPath ).absoluteFilePath(), mFilter, &mSelectedFilter );
259 title = !mDialogTitle.isEmpty() ? mDialogTitle : tr(
"Select one or more files" );
260 fileNames = QFileDialog::getOpenFileNames(
this, title, QFileInfo( oldPath ).absoluteFilePath(), mFilter, &mSelectedFilter );
263 title = !mDialogTitle.isEmpty() ? mDialogTitle : tr(
"Select a directory" );
264 fileName = QFileDialog::getExistingDirectory(
this, title, QFileInfo( oldPath ).absoluteFilePath(), QFileDialog::ShowDirsOnly );
268 title = !mDialogTitle.isEmpty() ? mDialogTitle : tr(
"Create or select a file" );
271 fileName = QFileDialog::getSaveFileName(
this, title, QFileInfo( oldPath ).absoluteFilePath(), mFilter, &mSelectedFilter, QFileDialog::DontConfirmOverwrite );
275 fileName = QFileDialog::getSaveFileName(
this, title, QFileInfo( oldPath ).absoluteFilePath(), mFilter, &mSelectedFilter );
285 if ( fileName.isEmpty() && fileNames.isEmpty( ) )
290 fileName = QDir::toNativeSeparators( QDir::cleanPath( QFileInfo( fileName ).absoluteFilePath() ) );
294 for (
int i = 0; i < fileNames.length(); i++ )
296 fileNames.replace( i, QDir::toNativeSeparators( QDir::cleanPath( QFileInfo( fileNames.at( i ) ).absoluteFilePath() ) ) );
301 switch ( mStorageMode )
305 settings.
setValue( QStringLiteral(
"UI/lastFileNameWidgetDir" ), QFileInfo( fileName ).absolutePath() );
308 settings.
setValue( QStringLiteral(
"UI/lastFileNameWidgetDir" ), fileName );
311 settings.
setValue( QStringLiteral(
"UI/lastFileNameWidgetDir" ), QFileInfo( fileNames.first( ) ).absolutePath() );
318 fileName = relativePath( fileName,
true );
323 for (
int i = 0; i < fileNames.length(); i++ )
325 fileNames.replace( i, relativePath( fileNames.at( i ), true ) );
327 if ( fileNames.length() > 1 )
329 setFilePath( QStringLiteral(
"\"%1\"" ).arg( fileNames.join( QStringLiteral(
"\" \"" ) ) ) );
339 QString QgsFileWidget::relativePath(
const QString &
filePath,
bool removeRelative )
const 341 QString RelativePath;
344 RelativePath = QDir::toNativeSeparators( QDir::cleanPath(
QgsProject::instance()->fileInfo().absolutePath() ) );
348 RelativePath = QDir::toNativeSeparators( QDir::cleanPath( mDefaultRoot ) );
351 if ( !RelativePath.isEmpty() )
353 if ( removeRelative )
355 return QDir::cleanPath( QDir( RelativePath ).relativeFilePath(
filePath ) );
367 QString QgsFileWidget::toUrl(
const QString &path )
const 370 if ( path.isEmpty() )
375 QString urlStr = relativePath( path,
false );
376 QUrl url = QUrl::fromUserInput( urlStr );
377 if ( !url.isValid() || !url.isLocalFile() )
379 QgsDebugMsg( QString(
"URL: %1 is not valid or not a local file!" ).arg( path ) );
383 QString pathStr = url.toString();
386 rep = QStringLiteral(
"<a href=\"%1\">%2</a>" ).arg( pathStr, path );
390 QString fileName = QFileInfo( urlStr ).fileName();
391 rep = QStringLiteral(
"<a href=\"%1\">%2</a>" ).arg( pathStr, fileName );
402 QgsFileDropEdit::QgsFileDropEdit( QWidget *parent )
406 setAcceptDrops(
true );
409 void QgsFileDropEdit::setFilters(
const QString &filters )
411 mAcceptableExtensions.clear();
413 if ( filters.contains( QStringLiteral(
"*.*" ) ) )
416 QRegularExpression rx( QStringLiteral(
"\\*\\.(\\w+)" ) );
417 QRegularExpressionMatchIterator i = rx.globalMatch( filters );
418 while ( i.hasNext() )
420 QRegularExpressionMatch match = i.next();
421 if ( match.hasMatch() )
423 mAcceptableExtensions << match.captured( 1 ).toLower();
428 QString QgsFileDropEdit::acceptableFilePath( QDropEvent *event )
const 431 if ( event->mimeData()->hasUrls() )
433 Q_FOREACH (
const QUrl &url, event->mimeData()->urls() )
435 QFileInfo file( url.toLocalFile() );
437 ( mAcceptableExtensions.isEmpty() || mAcceptableExtensions.contains( file.suffix(), Qt::CaseInsensitive ) ) )
439 paths.append( file.filePath() );
442 if ( paths.size() > 1 )
444 return QStringLiteral(
"\"%1\"" ).arg( paths.join( QStringLiteral(
"\" \"" ) ) );
446 else if ( paths.size() == 1 )
448 return paths.first();
456 void QgsFileDropEdit::dragEnterEvent( QDragEnterEvent *event )
458 QString
filePath = acceptableFilePath( event );
459 if ( !filePath.isEmpty() )
461 event->acceptProposedAction();
471 void QgsFileDropEdit::dragLeaveEvent( QDragLeaveEvent *event )
473 QgsFilterLineEdit::dragLeaveEvent( event );
479 void QgsFileDropEdit::dropEvent( QDropEvent *event )
481 QString
filePath = acceptableFilePath( event );
482 if ( !filePath.isEmpty() )
486 setFocus( Qt::MouseFocusReason );
487 event->acceptProposedAction();
493 void QgsFileDropEdit::paintEvent( QPaintEvent *e )
495 QgsFilterLineEdit::paintEvent( e );
500 p.setPen( QPen( palette().highlight(), width ) );
501 QRect r = rect().adjusted( width, width, -width, -width );
This class is a composition of two QSettings instances:
void setValue(const QString &key, const QVariant &value, const QgsSettings::Section section=QgsSettings::NoSection)
Sets the value of setting key to value.
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.
QVariant value(const QString &key, const QVariant &defaultValue=QVariant(), const Section section=NoSection) const
Returns the value for setting key.
static QgsProject * instance()
Returns the QgsProject singleton instance.
static QString addExtensionFromFilter(const QString &fileName, const QString &filter)
Ensures that a fileName ends with an extension from the specified filter string.