29using namespace Qt::StringLiterals;
31#if defined( Q_OS_WIN )
32#include <QRegularExpression>
35typedef std::vector< std::pair< QString, std::function< QString(
const QString & ) > > >
CustomResolvers;
40 : mBaseFileName( baseFileName )
41 , 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 ) )
103#if defined( Q_OS_WIN )
104 if ( src.startsWith(
"\\\\" ) || src.startsWith(
"//" ) || ( src[0].isLetter() && src[1] ==
':' ) )
107 return vsiPrefix + src;
113 return vsiPrefix + src;
122 const QFileInfo pfi( mBaseFileName );
123 const QString home = pfi.absolutePath();
124 if ( home.isEmpty() )
125 return vsiPrefix + src;
127 const QFileInfo fi( home +
'/' + src );
131 return vsiPrefix + src;
135 return vsiPrefix + QDir::cleanPath( fi.absoluteFilePath() );
139 QString srcPath = src;
140 QString projPath = mBaseFileName;
142 if ( projPath.isEmpty() )
144 return vsiPrefix + src;
147#if defined( Q_OS_WIN )
150 thread_local const QRegularExpression delimiterRe( R
"re(delimiter=([^&]+))re" );
151 const QRegularExpressionMatch match = delimiterRe.match( srcPath );
152 if ( match.hasMatch() )
154 const QString delimiter = match.captured( 0 ).replace(
'\\',
"%5C"_L1 );
155 srcPath.replace( match.captured( 0 ), delimiter );
158 srcPath.replace(
'\\',
'/' );
159 projPath.replace(
'\\',
'/' );
161 bool uncPath = projPath.startsWith(
"//" );
165 projPath = QFileInfo( projPath ).absoluteFilePath();
167 const QStringList srcElems = srcPath.split(
'/', Qt::SkipEmptyParts );
168 QStringList projElems = projPath.split(
'/', Qt::SkipEmptyParts );
170#if defined( Q_OS_WIN )
173 projElems.insert( 0,
"" );
174 projElems.insert( 0,
"" );
179 projElems.removeLast();
182 projElems << srcElems;
183 projElems.removeAll( u
"."_s );
187 while ( ( pos = projElems.indexOf(
".."_L1 ) ) > 0 )
190 projElems.removeAt( pos - 1 );
191 projElems.removeAt( pos - 1 );
194#if !defined( Q_OS_WIN )
196 projElems.prepend( QString() );
199 return vsiPrefix + projElems.join(
'/'_L1 );
204 QString
id = QUuid::createUuid().toString();
205 sCustomResolvers()->emplace_back( std::make_pair(
id, processor ) );
211 const size_t prevCount = sCustomResolvers()->size();
212 sCustomResolvers()->erase(
213 std::remove_if( sCustomResolvers()->begin(), sCustomResolvers()->end(), [
id]( std::pair< QString, std::function< QString(
const QString & ) > > &a ) {
return a.first == id; } ),
214 sCustomResolvers()->end()
216 return prevCount != sCustomResolvers()->size();
221 QString
id = QUuid::createUuid().toString();
222 sCustomWriters()->emplace_back( std::make_pair(
id, writer ) );
228 const size_t prevCount = sCustomWriters()->size();
229 sCustomWriters()->erase(
230 std::remove_if( sCustomWriters()->begin(), sCustomWriters()->end(), [
id]( std::pair< QString, std::function< QString(
const QString & ) > > &a ) {
return a.first == id; } ), sCustomWriters()->end()
232 return prevCount != sCustomWriters()->size();
244 if ( !localizedPath.isEmpty() )
245 return u
"localized:"_s + localizedPath;
248 for (
const auto &writer : customWriters )
249 src = writer.second( src );
257 if ( !mAttachmentDir.isEmpty() && src.startsWith( mAttachmentDir ) )
260 return u
"attachment:"_s + QFileInfo( src ).fileName();
263 if ( mBaseFileName.isEmpty() )
269 const QFileInfo pfi( QFileInfo( mBaseFileName ).path() );
271 QString projPath = pfi.absoluteFilePath();
275 if ( projPath.isEmpty() )
276 projPath = pfi.absoluteFilePath();
278 if ( projPath.isEmpty() )
284 const QUrl url { src };
285 QString srcPath { src };
288 if ( url.isLocalFile() )
290 srcPath = url.path();
291 urlQuery = url.query();
294 const QFileInfo srcFileInfo( srcPath );
297 if ( !srcFileInfo.isAbsolute() )
301 if ( srcFileInfo.exists() )
303 srcPath = QDir::cleanPath( srcFileInfo.absoluteFilePath() );
307 if ( !vsiPrefix.isEmpty() )
309 srcPath.remove( 0, vsiPrefix.size() );
312#if defined( Q_OS_WIN )
313 const Qt::CaseSensitivity cs = Qt::CaseInsensitive;
315 srcPath.replace(
'\\',
'/' );
317 if ( srcPath.startsWith(
"//" ) )
320 srcPath =
"\\\\" + srcPath.mid( 2 );
323 projPath.replace(
'\\',
'/' );
324 if ( projPath.startsWith(
"//" ) )
327 projPath =
"\\\\" + projPath.mid( 2 );
330 const Qt::CaseSensitivity cs = Qt::CaseSensitive;
333 QStringList projElems = projPath.split(
'/', Qt::SkipEmptyParts );
334 QStringList srcElems = srcPath.split(
'/', Qt::SkipEmptyParts );
336 projElems.removeAll( u
"."_s );
337 srcElems.removeAll( u
"."_s );
341 while ( !srcElems.isEmpty() && !projElems.isEmpty() && srcElems[0].compare( projElems[0], cs ) == 0 )
343 srcElems.removeFirst();
344 projElems.removeFirst();
354 if ( !projElems.isEmpty() )
357 for (
int i = 0; i < projElems.size(); i++ )
359 srcElems.insert( 0, u
".."_s );
366 srcElems.insert( 0, u
"."_s );
370 QString returnPath { vsiPrefix + srcElems.join(
'/'_L1 ) };
371 if ( !urlQuery.isEmpty() )
373 returnPath.append(
'?' );
374 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