27#include <QRegularExpression>
30typedef std::vector< std::pair< QString, std::function< QString(
const QString & ) > > >
CustomResolvers;
35 : mBaseFileName( baseFileName ), mAttachmentDir( attachmentDir )
45 for (
const auto &resolver : customResolvers )
46 filename = resolver.second( filename );
48 if ( filename.isEmpty() )
51 QString src = filename;
52 if ( src.startsWith( QLatin1String(
"inbuilt:" ) ) )
58 if ( src.startsWith( QLatin1String(
"localized:" ) ) )
60 QStringList parts = src.split(
"|" );
63 if ( !parts[0].isEmpty() )
65 return parts.join(
"|" );
72 if ( src.startsWith( QLatin1String(
"attachment:" ) ) )
75 return QDir( mAttachmentDir ).absoluteFilePath( src.mid( 11 ) );
78 if ( mBaseFileName.isNull() )
85 if ( ! vsiPrefix.isEmpty() )
89 if ( src.startsWith( QLatin1String(
"/vsi" ), Qt::CaseInsensitive ) )
90 src.remove( 0, vsiPrefix.size() );
96 if ( !src.startsWith( QLatin1String(
"./" ) ) && !src.startsWith( QLatin1String(
"../" ) ) )
99 if ( src.startsWith(
"\\\\" ) ||
100 src.startsWith(
"//" ) ||
101 ( src[0].isLetter() && src[1] ==
':' ) )
104 return vsiPrefix + src;
110 return vsiPrefix + src;
119 const QFileInfo pfi( mBaseFileName );
120 const QString home = pfi.absolutePath();
121 if ( home.isEmpty() )
122 return vsiPrefix + src;
124 const QFileInfo fi( home +
'/' + src );
128 return vsiPrefix + src;
132 return vsiPrefix + fi.canonicalFilePath();
136 QString srcPath = src;
137 QString projPath = mBaseFileName;
139 if ( projPath.isEmpty() )
141 return vsiPrefix + src;
147 thread_local const QRegularExpression delimiterRe( R
"re(delimiter=([^&]+))re" );
148 const QRegularExpressionMatch match = delimiterRe.match( srcPath );
149 if ( match.hasMatch() )
151 const QString delimiter = match.captured( 0 ).replace(
'\\', QLatin1String(
"%5C" ) );
152 srcPath.replace( match.captured( 0 ), delimiter );
155 srcPath.replace(
'\\',
'/' );
156 projPath.replace(
'\\',
'/' );
158 bool uncPath = projPath.startsWith(
"//" );
162 projPath = QFileInfo( projPath ).absoluteFilePath();
164#if QT_VERSION < QT_VERSION_CHECK(5, 15, 0)
165 QStringList srcElems = srcPath.split(
'/', QString::SkipEmptyParts );
166 QStringList projElems = projPath.split(
'/', QString::SkipEmptyParts );
168 const QStringList srcElems = srcPath.split(
'/', Qt::SkipEmptyParts );
169 QStringList projElems = projPath.split(
'/', Qt::SkipEmptyParts );
175 projElems.insert( 0,
"" );
176 projElems.insert( 0,
"" );
181 projElems.removeLast();
184 projElems << srcElems;
185 projElems.removeAll( QStringLiteral(
"." ) );
189 while ( ( pos = projElems.indexOf( QLatin1String(
".." ) ) ) > 0 )
192 projElems.removeAt( pos - 1 );
193 projElems.removeAt( pos - 1 );
196#if !defined(Q_OS_WIN)
198 projElems.prepend( QString() );
201 return vsiPrefix + projElems.join( QLatin1Char(
'/' ) );
206 QString
id = QUuid::createUuid().toString();
207 sCustomResolvers()->emplace_back( std::make_pair(
id, processor ) );
213 const size_t prevCount = sCustomResolvers()->size();
214 sCustomResolvers()->erase( std::remove_if( sCustomResolvers()->begin(), sCustomResolvers()->end(), [
id]( std::pair< QString, std::function< QString(
const QString & ) > > &a )
216 return a.first == id;
217 } ), sCustomResolvers()->end() );
218 return prevCount != sCustomResolvers()->size();
223 QString
id = QUuid::createUuid().toString();
224 sCustomWriters()->emplace_back( std::make_pair(
id, writer ) );
230 const size_t prevCount = sCustomWriters->size();
231 sCustomWriters()->erase( std::remove_if( sCustomWriters->begin(), sCustomWriters->end(), [
id]( std::pair< QString, std::function< QString(
const QString & ) > > &a )
233 return a.first == id;
234 } ), sCustomWriters->end() );
235 return prevCount != sCustomWriters->size();
247 if ( !localizedPath.isEmpty() )
248 return QStringLiteral(
"localized:" ) + localizedPath;
251 for (
const auto &writer : customWriters )
252 src = writer.second( src );
260 if ( !mAttachmentDir.isEmpty() && src.startsWith( mAttachmentDir ) )
263 return QStringLiteral(
"attachment:" ) + QFileInfo( src ).fileName();
266 if ( mBaseFileName.isEmpty() )
272 const QFileInfo pfi( QFileInfo( mBaseFileName ).path() );
273 QString projPath = pfi.canonicalFilePath();
277 if ( projPath.isEmpty() )
278 projPath = pfi.absoluteFilePath();
280 if ( projPath.isEmpty() )
286 const QUrl url { src };
287 QString srcPath { src };
290 if ( url.isLocalFile( ) )
292 srcPath = url.path();
293 urlQuery = url.query();
296 const QFileInfo srcFileInfo( srcPath );
297 if ( srcFileInfo.exists() )
298 srcPath = srcFileInfo.canonicalFilePath();
302 if ( ! vsiPrefix.isEmpty() )
304 srcPath.remove( 0, vsiPrefix.size() );
307#if defined( Q_OS_WIN )
308 const Qt::CaseSensitivity cs = Qt::CaseInsensitive;
310 srcPath.replace(
'\\',
'/' );
312 if ( srcPath.startsWith(
"//" ) )
315 srcPath =
"\\\\" + srcPath.mid( 2 );
318 projPath.replace(
'\\',
'/' );
319 if ( projPath.startsWith(
"//" ) )
322 projPath =
"\\\\" + projPath.mid( 2 );
325 const Qt::CaseSensitivity cs = Qt::CaseSensitive;
328#if QT_VERSION < QT_VERSION_CHECK(5, 15, 0)
329 QStringList projElems = projPath.split(
'/', QString::SkipEmptyParts );
330 QStringList srcElems = srcPath.split(
'/', QString::SkipEmptyParts );
332 QStringList projElems = projPath.split(
'/', Qt::SkipEmptyParts );
333 QStringList srcElems = srcPath.split(
'/', Qt::SkipEmptyParts );
336 projElems.removeAll( QStringLiteral(
"." ) );
337 srcElems.removeAll( QStringLiteral(
"." ) );
341 while ( !srcElems.isEmpty() &&
342 !projElems.isEmpty() &&
343 srcElems[0].compare( projElems[0], cs ) == 0 )
345 srcElems.removeFirst();
346 projElems.removeFirst();
356 if ( !projElems.isEmpty() )
359 for (
int i = 0; i < projElems.size(); i++ )
361 srcElems.insert( 0, QStringLiteral(
".." ) );
368 srcElems.insert( 0, QStringLiteral(
"." ) );
372 QString returnPath { vsiPrefix + srcElems.join( QLatin1Char(
'/' ) ) };
373 if ( ! urlQuery.isEmpty() )
375 returnPath.append(
'?' );
376 returnPath.append( urlQuery );
static QString pkgDataPath()
Returns the common root path of all application data directories.
static QgsLocalizedDataPathRegistry * localizedDataPathRegistry()
Returns the registry of data repositories These are used as paths for basemaps, logos,...
QString globalPath(const QString &localizedPath) const
Returns the global path if the file has been found in one of the paths, an empty string otherwise.
QString localizedPath(const QString &globalPath) const
Returns the localized path if the file has been found in one of the path, an empty string otherwise.
Resolves relative paths into absolute paths and vice versa.
QString writePath(const QString &filename) const
Prepare a filename to save it to the project file.
static bool removePathPreprocessor(const QString &id)
Removes the custom pre-processor function with matching id.
static QString setPathPreprocessor(const std::function< QString(const QString &filename)> &processor)
Sets a path pre-processor function, which allows for manipulation of paths and data sources prior to ...
QString readPath(const QString &filename) const
Turn filename read from the project file to an absolute path.
static bool removePathWriter(const QString &id)
Removes the custom writer function with matching id.
static QString setPathWriter(const std::function< QString(const QString &filename)> &writer)
Sets a path writer function, which allows for manipulation of paths and data sources prior to writing...
QString qgsVsiPrefix(const QString &path)
Q_GLOBAL_STATIC(QReadWriteLock, sDefinitionCacheLock)
std::vector< std::pair< QString, std::function< QString(const QString &) > > > CustomResolvers