28#include <QRegularExpression>
31typedef std::vector< std::pair< QString, std::function< QString(
const QString & ) > > >
CustomResolvers;
36 : mBaseFileName( baseFileName ), mAttachmentDir( attachmentDir )
46 for (
const auto &resolver : customResolvers )
47 filename = resolver.second( filename );
49 if ( filename.isEmpty() )
52 QString src = filename;
53 if ( src.startsWith( QLatin1String(
"inbuilt:" ) ) )
59 if ( src.startsWith( QLatin1String(
"localized:" ) ) )
61 QStringList parts = src.split(
"|" );
64 if ( !parts[0].isEmpty() )
66 return parts.join(
"|" );
73 if ( src.startsWith( QLatin1String(
"attachment:" ) ) )
76 return QDir( mAttachmentDir ).absoluteFilePath( src.mid( 11 ) );
79 if ( mBaseFileName.isNull() )
86 if ( ! vsiPrefix.isEmpty() )
90 if ( src.startsWith( QLatin1String(
"/vsi" ), Qt::CaseInsensitive ) )
91 src.remove( 0, vsiPrefix.size() );
97 if ( !src.startsWith( QLatin1String(
"./" ) ) && !src.startsWith( QLatin1String(
"../" ) ) )
100 if ( src.startsWith(
"\\\\" ) ||
101 src.startsWith(
"//" ) ||
102 ( src[0].isLetter() && src[1] ==
':' ) )
105 return vsiPrefix + src;
111 return vsiPrefix + src;
120 const QFileInfo pfi( mBaseFileName );
121 const QString home = pfi.absolutePath();
122 if ( home.isEmpty() )
123 return vsiPrefix + src;
125 const QFileInfo fi( home +
'/' + src );
129 return vsiPrefix + src;
133 return vsiPrefix + fi.canonicalFilePath();
137 QString srcPath = src;
138 QString projPath = mBaseFileName;
140 if ( projPath.isEmpty() )
142 return vsiPrefix + src;
148 thread_local const QRegularExpression delimiterRe( R
"re(delimiter=([^&]+))re" );
149 const QRegularExpressionMatch match = delimiterRe.match( srcPath );
150 if ( match.hasMatch() )
152 const QString delimiter = match.captured( 0 ).replace(
'\\', QLatin1String(
"%5C" ) );
153 srcPath.replace( match.captured( 0 ), delimiter );
156 srcPath.replace(
'\\',
'/' );
157 projPath.replace(
'\\',
'/' );
159 bool uncPath = projPath.startsWith(
"//" );
163 projPath = QFileInfo( projPath ).absoluteFilePath();
165#if QT_VERSION < QT_VERSION_CHECK(5, 15, 0)
166 QStringList srcElems = srcPath.split(
'/', QString::SkipEmptyParts );
167 QStringList projElems = projPath.split(
'/', QString::SkipEmptyParts );
169 const QStringList srcElems = srcPath.split(
'/', Qt::SkipEmptyParts );
170 QStringList projElems = projPath.split(
'/', Qt::SkipEmptyParts );
176 projElems.insert( 0,
"" );
177 projElems.insert( 0,
"" );
182 projElems.removeLast();
185 projElems << srcElems;
186 projElems.removeAll( QStringLiteral(
"." ) );
190 while ( ( pos = projElems.indexOf( QLatin1String(
".." ) ) ) > 0 )
193 projElems.removeAt( pos - 1 );
194 projElems.removeAt( pos - 1 );
197#if !defined(Q_OS_WIN)
199 projElems.prepend( QString() );
202 return vsiPrefix + projElems.join( QLatin1Char(
'/' ) );
207 QString
id = QUuid::createUuid().toString();
208 sCustomResolvers()->emplace_back( std::make_pair(
id, processor ) );
214 const size_t prevCount = sCustomResolvers()->size();
215 sCustomResolvers()->erase( std::remove_if( sCustomResolvers()->begin(), sCustomResolvers()->end(), [
id]( std::pair< QString, std::function< QString(
const QString & ) > > &a )
217 return a.first == id;
218 } ), sCustomResolvers()->end() );
219 return prevCount != sCustomResolvers()->size();
224 QString
id = QUuid::createUuid().toString();
225 sCustomWriters()->emplace_back( std::make_pair(
id, writer ) );
231 const size_t prevCount = sCustomWriters->size();
232 sCustomWriters()->erase( std::remove_if( sCustomWriters->begin(), sCustomWriters->end(), [
id]( std::pair< QString, std::function< QString(
const QString & ) > > &a )
234 return a.first == id;
235 } ), sCustomWriters->end() );
236 return prevCount != sCustomWriters->size();
248 if ( !localizedPath.isEmpty() )
249 return QStringLiteral(
"localized:" ) + localizedPath;
252 for (
const auto &writer : customWriters )
253 src = writer.second( src );
261 if ( !mAttachmentDir.isEmpty() && src.startsWith( mAttachmentDir ) )
264 return QStringLiteral(
"attachment:" ) + QFileInfo( src ).fileName();
267 if ( mBaseFileName.isEmpty() )
273 const QFileInfo pfi( QFileInfo( mBaseFileName ).path() );
274 QString projPath = pfi.canonicalFilePath();
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 );
298 if ( srcFileInfo.exists() )
299 srcPath = srcFileInfo.canonicalFilePath();
303 if ( ! vsiPrefix.isEmpty() )
305 srcPath.remove( 0, vsiPrefix.size() );
308#if defined( Q_OS_WIN )
309 const Qt::CaseSensitivity cs = Qt::CaseInsensitive;
311 srcPath.replace(
'\\',
'/' );
313 if ( srcPath.startsWith(
"//" ) )
316 srcPath =
"\\\\" + srcPath.mid( 2 );
319 projPath.replace(
'\\',
'/' );
320 if ( projPath.startsWith(
"//" ) )
323 projPath =
"\\\\" + projPath.mid( 2 );
326 const Qt::CaseSensitivity cs = Qt::CaseSensitive;
329#if QT_VERSION < QT_VERSION_CHECK(5, 15, 0)
330 QStringList projElems = projPath.split(
'/', QString::SkipEmptyParts );
331 QStringList srcElems = srcPath.split(
'/', QString::SkipEmptyParts );
333 QStringList projElems = projPath.split(
'/', Qt::SkipEmptyParts );
334 QStringList srcElems = srcPath.split(
'/', Qt::SkipEmptyParts );
337 projElems.removeAll( QStringLiteral(
"." ) );
338 srcElems.removeAll( QStringLiteral(
"." ) );
342 while ( !srcElems.isEmpty() &&
343 !projElems.isEmpty() &&
344 srcElems[0].compare( projElems[0], cs ) == 0 )
346 srcElems.removeFirst();
347 projElems.removeFirst();
357 if ( !projElems.isEmpty() )
360 for (
int i = 0; i < projElems.size(); i++ )
362 srcElems.insert( 0, QStringLiteral(
".." ) );
369 srcElems.insert( 0, QStringLiteral(
"." ) );
373 QString returnPath { vsiPrefix + srcElems.join( QLatin1Char(
'/' ) ) };
374 if ( ! urlQuery.isEmpty() )
376 returnPath.append(
'?' );
377 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.
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...
Q_GLOBAL_STATIC(QReadWriteLock, sDefinitionCacheLock)
std::vector< std::pair< QString, std::function< QString(const QString &) > > > CustomResolvers