29using namespace Qt::StringLiterals;
32#include <QRegularExpression>
35typedef std::vector< std::pair< QString, std::function< QString(
const QString & ) > > >
CustomResolvers;
40 : mBaseFileName( baseFileName ), mAttachmentDir( attachmentDir )
50 for (
const auto &resolver : customResolvers )
51 filename = resolver.second( filename );
53 if ( filename.isEmpty() )
56 QString src = filename;
57 if ( src.startsWith(
"inbuilt:"_L1 ) )
63 if ( src.startsWith(
"localized:"_L1 ) )
65 QStringList parts = src.split(
"|" );
68 if ( !parts[0].isEmpty() )
70 return parts.join(
"|" );
77 if ( src.startsWith(
"attachment:"_L1 ) )
80 return QDir( mAttachmentDir ).absoluteFilePath( src.mid( 11 ) );
83 if ( mBaseFileName.isNull() )
90 if ( ! vsiPrefix.isEmpty() )
94 if ( src.startsWith(
"/vsi"_L1, Qt::CaseInsensitive ) )
95 src.remove( 0, vsiPrefix.size() );
101 if ( !src.startsWith(
"./"_L1 ) && !src.startsWith(
"../"_L1 ) )
104 if ( src.startsWith(
"\\\\" ) ||
105 src.startsWith(
"//" ) ||
106 ( src[0].isLetter() && src[1] ==
':' ) )
109 return vsiPrefix + src;
115 return vsiPrefix + src;
124 const QFileInfo pfi( mBaseFileName );
125 const QString home = pfi.absolutePath();
126 if ( home.isEmpty() )
127 return vsiPrefix + src;
129 const QFileInfo fi( home +
'/' + src );
133 return vsiPrefix + src;
137 return vsiPrefix + QDir::cleanPath( fi.absoluteFilePath() );
141 QString srcPath = src;
142 QString projPath = mBaseFileName;
144 if ( projPath.isEmpty() )
146 return vsiPrefix + src;
152 thread_local const QRegularExpression delimiterRe( R
"re(delimiter=([^&]+))re" );
153 const QRegularExpressionMatch match = delimiterRe.match( srcPath );
154 if ( match.hasMatch() )
156 const QString delimiter = match.captured( 0 ).replace(
'\\',
"%5C"_L1 );
157 srcPath.replace( match.captured( 0 ), delimiter );
160 srcPath.replace(
'\\',
'/' );
161 projPath.replace(
'\\',
'/' );
163 bool uncPath = projPath.startsWith(
"//" );
167 projPath = QFileInfo( projPath ).absoluteFilePath();
169 const QStringList srcElems = srcPath.split(
'/', Qt::SkipEmptyParts );
170 QStringList projElems = projPath.split(
'/', Qt::SkipEmptyParts );
175 projElems.insert( 0,
"" );
176 projElems.insert( 0,
"" );
181 projElems.removeLast();
184 projElems << srcElems;
185 projElems.removeAll( u
"."_s );
189 while ( ( pos = projElems.indexOf(
".."_L1 ) ) > 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(
'/'_L1 );
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 u
"localized:"_s + localizedPath;
251 for (
const auto &writer : customWriters )
252 src = writer.second( src );
260 if ( !mAttachmentDir.isEmpty() && src.startsWith( mAttachmentDir ) )
263 return u
"attachment:"_s + QFileInfo( src ).fileName();
266 if ( mBaseFileName.isEmpty() )
272 const QFileInfo pfi( QFileInfo( mBaseFileName ).path() );
274 QString projPath = pfi.absoluteFilePath();
278 if ( projPath.isEmpty() )
279 projPath = pfi.absoluteFilePath();
281 if ( projPath.isEmpty() )
287 const QUrl url { src };
288 QString srcPath { src };
291 if ( url.isLocalFile( ) )
293 srcPath = url.path();
294 urlQuery = url.query();
297 const QFileInfo srcFileInfo( srcPath );
300 if ( !srcFileInfo.isAbsolute() )
304 if ( srcFileInfo.exists() )
306 srcPath = QDir::cleanPath( srcFileInfo.absoluteFilePath() );
310 if ( ! vsiPrefix.isEmpty() )
312 srcPath.remove( 0, vsiPrefix.size() );
315#if defined( Q_OS_WIN )
316 const Qt::CaseSensitivity cs = Qt::CaseInsensitive;
318 srcPath.replace(
'\\',
'/' );
320 if ( srcPath.startsWith(
"//" ) )
323 srcPath =
"\\\\" + srcPath.mid( 2 );
326 projPath.replace(
'\\',
'/' );
327 if ( projPath.startsWith(
"//" ) )
330 projPath =
"\\\\" + projPath.mid( 2 );
333 const Qt::CaseSensitivity cs = Qt::CaseSensitive;
336 QStringList projElems = projPath.split(
'/', Qt::SkipEmptyParts );
337 QStringList srcElems = srcPath.split(
'/', Qt::SkipEmptyParts );
339 projElems.removeAll( u
"."_s );
340 srcElems.removeAll( u
"."_s );
344 while ( !srcElems.isEmpty() &&
345 !projElems.isEmpty() &&
346 srcElems[0].compare( projElems[0], cs ) == 0 )
348 srcElems.removeFirst();
349 projElems.removeFirst();
359 if ( !projElems.isEmpty() )
362 for (
int i = 0; i < projElems.size(); i++ )
364 srcElems.insert( 0, u
".."_s );
371 srcElems.insert( 0, u
"."_s );
375 QString returnPath { vsiPrefix + srcElems.join(
'/'_L1 ) };
376 if ( ! urlQuery.isEmpty() )
378 returnPath.append(
'?' );
379 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,...
static QString vsiPrefixForPath(const QString &path)
Returns a the vsi prefix which corresponds to a file path, or an empty string if the path is not asso...
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.
QString writePath(const QString &filename) const
Prepare a filename to save it to the project file.
QgsPathResolver(const QString &baseFileName=QString(), const QString &attachmentDir=QString())
Initialize path resolver with a base filename. Null filename means no conversion between relative/abs...
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...
Q_GLOBAL_STATIC(QReadWriteLock, sDefinitionCacheLock)
std::vector< std::pair< QString, std::function< QString(const QString &) > > > CustomResolvers