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 const QStringList srcElems = srcPath.split(
'/', Qt::SkipEmptyParts );
166 QStringList projElems = projPath.split(
'/', Qt::SkipEmptyParts );
171 projElems.insert( 0,
"" );
172 projElems.insert( 0,
"" );
177 projElems.removeLast();
180 projElems << srcElems;
181 projElems.removeAll( QStringLiteral(
"." ) );
185 while ( ( pos = projElems.indexOf( QLatin1String(
".." ) ) ) > 0 )
188 projElems.removeAt( pos - 1 );
189 projElems.removeAt( pos - 1 );
192#if !defined(Q_OS_WIN)
194 projElems.prepend( QString() );
197 return vsiPrefix + projElems.join( QLatin1Char(
'/' ) );
202 QString
id = QUuid::createUuid().toString();
203 sCustomResolvers()->emplace_back( std::make_pair(
id, processor ) );
209 const size_t prevCount = sCustomResolvers()->size();
210 sCustomResolvers()->erase( std::remove_if( sCustomResolvers()->begin(), sCustomResolvers()->end(), [
id]( std::pair< QString, std::function< QString(
const QString & ) > > &a )
212 return a.first == id;
213 } ), sCustomResolvers()->end() );
214 return prevCount != sCustomResolvers()->size();
219 QString
id = QUuid::createUuid().toString();
220 sCustomWriters()->emplace_back( std::make_pair(
id, writer ) );
226 const size_t prevCount = sCustomWriters->size();
227 sCustomWriters()->erase( std::remove_if( sCustomWriters->begin(), sCustomWriters->end(), [
id]( std::pair< QString, std::function< QString(
const QString & ) > > &a )
229 return a.first == id;
230 } ), sCustomWriters->end() );
231 return prevCount != sCustomWriters->size();
243 if ( !localizedPath.isEmpty() )
244 return QStringLiteral(
"localized:" ) + localizedPath;
247 for (
const auto &writer : customWriters )
248 src = writer.second( src );
256 if ( !mAttachmentDir.isEmpty() && src.startsWith( mAttachmentDir ) )
259 return QStringLiteral(
"attachment:" ) + QFileInfo( src ).fileName();
262 if ( mBaseFileName.isEmpty() )
268 const QFileInfo pfi( QFileInfo( mBaseFileName ).path() );
269 QString projPath = pfi.canonicalFilePath();
273 if ( projPath.isEmpty() )
274 projPath = pfi.absoluteFilePath();
276 if ( projPath.isEmpty() )
282 const QUrl url { src };
283 QString srcPath { src };
286 if ( url.isLocalFile( ) )
288 srcPath = url.path();
289 urlQuery = url.query();
292 const QFileInfo srcFileInfo( srcPath );
293 if ( srcFileInfo.exists() )
294 srcPath = srcFileInfo.canonicalFilePath();
298 if ( ! vsiPrefix.isEmpty() )
300 srcPath.remove( 0, vsiPrefix.size() );
303#if defined( Q_OS_WIN )
304 const Qt::CaseSensitivity cs = Qt::CaseInsensitive;
306 srcPath.replace(
'\\',
'/' );
308 if ( srcPath.startsWith(
"//" ) )
311 srcPath =
"\\\\" + srcPath.mid( 2 );
314 projPath.replace(
'\\',
'/' );
315 if ( projPath.startsWith(
"//" ) )
318 projPath =
"\\\\" + projPath.mid( 2 );
321 const Qt::CaseSensitivity cs = Qt::CaseSensitive;
324 QStringList projElems = projPath.split(
'/', Qt::SkipEmptyParts );
325 QStringList srcElems = srcPath.split(
'/', Qt::SkipEmptyParts );
327 projElems.removeAll( QStringLiteral(
"." ) );
328 srcElems.removeAll( QStringLiteral(
"." ) );
332 while ( !srcElems.isEmpty() &&
333 !projElems.isEmpty() &&
334 srcElems[0].compare( projElems[0], cs ) == 0 )
336 srcElems.removeFirst();
337 projElems.removeFirst();
347 if ( !projElems.isEmpty() )
350 for (
int i = 0; i < projElems.size(); i++ )
352 srcElems.insert( 0, QStringLiteral(
".." ) );
359 srcElems.insert( 0, QStringLiteral(
"." ) );
363 QString returnPath { vsiPrefix + srcElems.join( QLatin1Char(
'/' ) ) };
364 if ( ! urlQuery.isEmpty() )
366 returnPath.append(
'?' );
367 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