29#include <QRegularExpression>
32typedef std::vector< std::pair< QString, std::function< QString(
const QString & ) > > >
CustomResolvers;
37 : mBaseFileName( baseFileName ), mAttachmentDir( attachmentDir )
47 for (
const auto &resolver : customResolvers )
48 filename = resolver.second( filename );
50 if ( filename.isEmpty() )
53 QString src = filename;
54 if ( src.startsWith(
"inbuilt:"_L1 ) )
60 if ( src.startsWith(
"localized:"_L1 ) )
62 QStringList parts = src.split(
"|" );
65 if ( !parts[0].isEmpty() )
67 return parts.join(
"|" );
74 if ( src.startsWith(
"attachment:"_L1 ) )
77 return QDir( mAttachmentDir ).absoluteFilePath( src.mid( 11 ) );
80 if ( mBaseFileName.isNull() )
87 if ( ! vsiPrefix.isEmpty() )
91 if ( src.startsWith(
"/vsi"_L1, Qt::CaseInsensitive ) )
92 src.remove( 0, vsiPrefix.size() );
98 if ( !src.startsWith(
"./"_L1 ) && !src.startsWith(
"../"_L1 ) )
101 if ( src.startsWith(
"\\\\" ) ||
102 src.startsWith(
"//" ) ||
103 ( src[0].isLetter() && src[1] ==
':' ) )
106 return vsiPrefix + src;
112 return vsiPrefix + src;
121 const QFileInfo pfi( mBaseFileName );
122 const QString home = pfi.absolutePath();
123 if ( home.isEmpty() )
124 return vsiPrefix + src;
126 const QFileInfo fi( home +
'/' + src );
130 return vsiPrefix + src;
134 return vsiPrefix + QDir::cleanPath( fi.absoluteFilePath() );
138 QString srcPath = src;
139 QString projPath = mBaseFileName;
141 if ( projPath.isEmpty() )
143 return vsiPrefix + src;
149 thread_local const QRegularExpression delimiterRe( R
"re(delimiter=([^&]+))re" );
150 const QRegularExpressionMatch match = delimiterRe.match( srcPath );
151 if ( match.hasMatch() )
153 const QString delimiter = match.captured( 0 ).replace(
'\\',
"%5C"_L1 );
154 srcPath.replace( match.captured( 0 ), delimiter );
157 srcPath.replace(
'\\',
'/' );
158 projPath.replace(
'\\',
'/' );
160 bool uncPath = projPath.startsWith(
"//" );
164 projPath = QFileInfo( projPath ).absoluteFilePath();
166 const QStringList srcElems = srcPath.split(
'/', Qt::SkipEmptyParts );
167 QStringList projElems = projPath.split(
'/', Qt::SkipEmptyParts );
172 projElems.insert( 0,
"" );
173 projElems.insert( 0,
"" );
178 projElems.removeLast();
181 projElems << srcElems;
182 projElems.removeAll( u
"."_s );
186 while ( ( pos = projElems.indexOf(
".."_L1 ) ) > 0 )
189 projElems.removeAt( pos - 1 );
190 projElems.removeAt( pos - 1 );
193#if !defined(Q_OS_WIN)
195 projElems.prepend( QString() );
198 return vsiPrefix + projElems.join(
'/'_L1 );
203 QString
id = QUuid::createUuid().toString();
204 sCustomResolvers()->emplace_back( std::make_pair(
id, processor ) );
210 const size_t prevCount = sCustomResolvers()->size();
211 sCustomResolvers()->erase( std::remove_if( sCustomResolvers()->begin(), sCustomResolvers()->end(), [
id]( std::pair< QString, std::function< QString(
const QString & ) > > &a )
213 return a.first == id;
214 } ), sCustomResolvers()->end() );
215 return prevCount != sCustomResolvers()->size();
220 QString
id = QUuid::createUuid().toString();
221 sCustomWriters()->emplace_back( std::make_pair(
id, writer ) );
227 const size_t prevCount = sCustomWriters()->size();
228 sCustomWriters()->erase( std::remove_if( sCustomWriters()->begin(), sCustomWriters()->end(), [
id]( std::pair< QString, std::function< QString(
const QString & ) > > &a )
230 return a.first == id;
231 } ), 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() &&
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, u
".."_s );
368 srcElems.insert( 0, u
"."_s );
372 QString returnPath { vsiPrefix + srcElems.join(
'/'_L1 ) };
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,...
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