18#include "moc_qgsfilewidget.cpp" 
   26#include <QRegularExpression> 
   41  mLayout->setContentsMargins( 0, 0, 0, 0 );
 
   50  mLinkLabel->setSizePolicy( QSizePolicy::Expanding, QSizePolicy::Preferred );
 
   58  mLineEdit->setToolTip( tr( 
"Full path to the file(s), including name and extension" ) );
 
   59  connect( 
mLineEdit, &QLineEdit::textChanged, 
this, &QgsFileWidget::textEdited );
 
   60  connect( 
mLineEdit, &QgsFileDropEdit::fileDropped, 
this, &QgsFileWidget::fileDropped );
 
   66  connect( 
mLinkEditButton, &QToolButton::clicked, 
this, &QgsFileWidget::editLink );
 
   72  connect( 
mFileWidgetButton, &QAbstractButton::clicked, 
this, &QgsFileWidget::openFileDialog );
 
 
   86  const thread_local QRegularExpression partsRegex = QRegularExpression( QStringLiteral( 
"\"\\s+\"" ) );
 
   87  const QStringList pathParts = path.split( partsRegex, Qt::SkipEmptyParts );
 
   89  const thread_local QRegularExpression cleanRe( QStringLiteral( 
"(^\\s*\")|(\"\\s*)" ) );
 
   90  paths.reserve( pathParts.size() );
 
   91  for ( 
const QString &pathsPart : pathParts )
 
   93    QString cleaned = pathsPart;
 
   94    cleaned.remove( cleanRe );
 
   95    paths.append( cleaned );
 
 
  160  return path.contains( QStringLiteral( 
"\" \"" ) );
 
 
  163void QgsFileWidget::textEdited( 
const QString &path )
 
  170    mLineEdit->setToolTip( tr( 
"Selected files:<br><ul><li>%1</li></ul><br>" ).arg( 
splitFilePaths( path ).join( QLatin1String( 
"</li><li>" ) ) ) );
 
  179void QgsFileWidget::editLink()
 
  188void QgsFileWidget::fileDropped( 
const QString &filePath )
 
  192  mLineEdit->setFocus( Qt::MouseFocusReason );
 
  269void QgsFileWidget::openFileDialog()
 
  288  QUrl url = QUrl::fromUserInput( oldPath );
 
  289  if ( !url.isValid() )
 
  291    QString defPath = QDir::cleanPath( QFileInfo( 
QgsProject::instance()->absoluteFilePath() ).path() );
 
  292    if ( defPath.isEmpty() )
 
  294      defPath = QDir::homePath();
 
  296    oldPath = settings.
value( QStringLiteral( 
"UI/lastFileNameWidgetDir" ), defPath ).toString();
 
  301  QStringList fileNames;
 
  318        fileName = QFileDialog::getExistingDirectory( 
this, title, QFileInfo( oldPath ).absoluteFilePath(), 
mOptions );
 
  325          fileName = QFileDialog::getSaveFileName( 
this, title, QFileInfo( oldPath ).absoluteFilePath(), 
mFilter, &
mSelectedFilter, 
mOptions | QFileDialog::DontConfirmOverwrite );
 
  341        if ( 
mFilter.contains( QLatin1String( 
"(*.gdb *.GDB gdb)" ) ) && ( fileName.endsWith( QLatin1String( 
"/gdb.gdb" ) ) || fileName.endsWith( QLatin1String( 
"\\gdb.gdb" ) ) ) )
 
  343          fileName.chop( 
static_cast<int>( strlen( 
"/gdb.gdb" ) ) );
 
  354  if ( fileName.isEmpty() && fileNames.isEmpty() )
 
  358    fileNames << fileName;
 
  360  for ( 
int i = 0; i < fileNames.length(); i++ )
 
  362    fileNames.replace( i, QDir::toNativeSeparators( QDir::cleanPath( QFileInfo( fileNames.at( i ) ).absoluteFilePath() ) ) );
 
  371      settings.
setValue( QStringLiteral( 
"UI/lastFileNameWidgetDir" ), QFileInfo( fileNames.first() ).absolutePath() );
 
  374      settings.
setValue( QStringLiteral( 
"UI/lastFileNameWidgetDir" ), fileNames.first() );
 
  383  Q_ASSERT( fileNames.count() );
 
  386  for ( 
int i = 0; i < fileNames.length(); i++ )
 
  388    fileNames.replace( i, 
relativePath( fileNames.at( i ), 
true ) );
 
 
  402    if ( filePaths.length() > 1 )
 
  404      setFilePath( QStringLiteral( 
"\"%1\"" ).arg( filePaths.join( QLatin1String( 
"\" \"" ) ) ) );
 
 
  415  QString RelativePath;
 
  418    RelativePath = QDir::toNativeSeparators( QDir::cleanPath( QFileInfo( 
QgsProject::instance()->absoluteFilePath() ).path() ) );
 
  422    RelativePath = QDir::toNativeSeparators( QDir::cleanPath( 
mDefaultRoot ) );
 
  425  if ( !RelativePath.isEmpty() )
 
  427    if ( removeRelative )
 
  429      return QDir::cleanPath( QDir( RelativePath ).relativeFilePath( 
filePath ) );
 
 
  442  QSize size { 
mLineEdit->minimumSizeHint() };
 
  444  size.setWidth( size.width() + btnSize.width() );
 
  445  size.setHeight( std::max( size.height(), btnSize.height() ) );
 
 
  460    return QStringLiteral( 
"<a>%1</a>" ).arg( path );
 
  464  QUrl url = QUrl::fromUserInput( urlStr );
 
  465  if ( !url.isValid() || !url.isLocalFile() )
 
  467    QgsDebugMsgLevel( QStringLiteral( 
"URL: %1 is not valid or not a local file!" ).arg( path ), 2 );
 
  471  QString pathStr = url.toString();
 
  474    rep = QStringLiteral( 
"<a href=\"%1\">%2</a>" ).arg( pathStr, path );
 
  478    QString fileName = QFileInfo( urlStr ).fileName();
 
  479    rep = QStringLiteral( 
"<a href=\"%1\">%2</a>" ).arg( pathStr, fileName );
 
 
  489QgsFileDropEdit::QgsFileDropEdit( QWidget *parent )
 
  492  setAcceptDrops( 
true );
 
  495void QgsFileDropEdit::setFilters( 
const QString &filters )
 
  497  mAcceptableExtensions.clear();
 
  499  if ( filters.contains( QStringLiteral( 
"*.*" ) ) )
 
  502  const thread_local QRegularExpression rx( QStringLiteral( 
"\\*\\.(\\w+)" ) );
 
  503  QRegularExpressionMatchIterator i = rx.globalMatch( filters );
 
  504  while ( i.hasNext() )
 
  506    QRegularExpressionMatch match = i.next();
 
  507    if ( match.hasMatch() )
 
  509      mAcceptableExtensions << match.captured( 1 ).toLower();
 
  514QStringList QgsFileDropEdit::acceptableFilePaths( QDropEvent *event )
 const 
  516  QStringList rawPaths;
 
  518  if ( event->mimeData()->hasUrls() )
 
  520    const QList<QUrl> urls = 
event->mimeData()->urls();
 
  521    rawPaths.reserve( urls.count() );
 
  522    for ( 
const QUrl &url : urls )
 
  524      const QString local = url.toLocalFile();
 
  525      if ( !rawPaths.contains( local ) )
 
  526        rawPaths.append( local );
 
  533    if ( !rawPaths.contains( u.uri ) )
 
  534      rawPaths.append( u.uri );
 
  537  if ( !event->mimeData()->text().isEmpty() && !rawPaths.contains( event->mimeData()->text() ) )
 
  538    rawPaths.append( event->mimeData()->text() );
 
  540  paths.reserve( rawPaths.count() );
 
  541  for ( 
const QString &path : std::as_const( rawPaths ) )
 
  543    QFileInfo file( path );
 
  544    switch ( mStorageMode )
 
  550        if ( file.isFile() && ( mAcceptableExtensions.isEmpty() || mAcceptableExtensions.contains( file.suffix(), Qt::CaseInsensitive ) ) )
 
  551          paths.append( file.filePath() );
 
  559          paths.append( file.filePath() );
 
  560        else if ( file.isFile() )
 
  563          paths.append( file.absolutePath() );
 
  574QString QgsFileDropEdit::acceptableFilePath( QDropEvent *event )
 const 
  576  const QStringList paths = acceptableFilePaths( event );
 
  577  if ( paths.size() > 1 )
 
  579    return QStringLiteral( 
"\"%1\"" ).arg( paths.join( QLatin1String( 
"\" \"" ) ) );
 
  581  else if ( paths.size() == 1 )
 
  583    return paths.first();
 
  591void QgsFileDropEdit::dragEnterEvent( QDragEnterEvent *event )
 
  593  QString filePath = acceptableFilePath( event );
 
  594  if ( !filePath.isEmpty() )
 
  596    event->acceptProposedAction();
 
  597    setHighlighted( 
true );
 
  605void QgsFileDropEdit::dragLeaveEvent( QDragLeaveEvent *event )
 
  607  QgsFilterLineEdit::dragLeaveEvent( event );
 
  609  setHighlighted( 
false );
 
  612void QgsFileDropEdit::dropEvent( QDropEvent *event )
 
  614  QString filePath = acceptableFilePath( event );
 
  615  if ( !filePath.isEmpty() )
 
  617    event->acceptProposedAction();
 
  618    emit fileDropped( filePath );
 
  621  setHighlighted( 
false );
 
static QString nullRepresentation()
Returns the string used to represent the value NULL throughout QGIS.
 
static QIcon getThemeIcon(const QString &name, const QColor &fillColor=QColor(), const QColor &strokeColor=QColor())
Helper to get a theme icon.
 
static QString addExtensionFromFilter(const QString &fileName, const QString &filter)
Ensures that a fileName ends with an extension from the specified filter string.
 
QLineEdit subclass with built in support for clearing the widget's value and handling custom null val...
 
Trick to keep a widget focused and avoid QT crashes.
 
A QgsFilterLineEdit subclass with the ability to "highlight" the edges of the widget.
 
QList< QgsMimeDataUtils::Uri > UriList
 
static UriList decodeUriList(const QMimeData *data)
 
static QgsProject * instance()
Returns the QgsProject singleton instance.
 
Stores settings for use within QGIS.
 
QVariant value(const QString &key, const QVariant &defaultValue=QVariant(), Section section=NoSection) const
Returns the value for setting key.
 
void setValue(const QString &key, const QVariant &value, QgsSettings::Section section=QgsSettings::NoSection)
Sets the value of setting key to value.
 
#define QgsDebugMsgLevel(str, level)