Skip to content

Commit

Permalink
improve relative path support
Browse files Browse the repository at this point in the history
git-svn-id: http://svn.osgeo.org/qgis/trunk/qgis@11571 c8812cc2-4d05-0410-92ff-de0c093fc19c
  • Loading branch information
jef committed Sep 5, 2009
1 parent a7f4136 commit 032b743
Show file tree
Hide file tree
Showing 4 changed files with 170 additions and 27 deletions.
8 changes: 8 additions & 0 deletions python/core/qgsproject.sip
Original file line number Diff line number Diff line change
Expand Up @@ -223,6 +223,14 @@ public:
*/
void dumpProperties() const;

/** prepare a filename to save it to the project file
@note added in 1.3 */
QString writePath( QString filename ) const;

/** turn filename read from the project file to an absolute path
@note added in 1.3 */
QString readPath( QString filename ) const;

signals:

//! emitted when project is being read
Expand Down
29 changes: 2 additions & 27 deletions src/core/qgsmaplayer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -152,20 +152,7 @@ bool QgsMapLayer::readXML( QDomNode & layer_node )
QDomElement mne = mnl.toElement();
mDataSource = mne.text();

QFileInfo fi( mDataSource );
if ( !fi.exists() && fi.isRelative() )
{
QFileInfo pfi( QgsProject::instance()->fileName() );
if ( pfi.exists() )
{
fi.setFile( pfi.canonicalPath() + QDir::separator() + mDataSource );

if ( fi.exists() )
{
mDataSource = fi.canonicalFilePath();
}
}
}
mDataSource = QgsProject::instance()->readPath( mDataSource );

// Set the CRS from project file, asking the user if necessary.
// Make it the saved CRS to have WMS layer projected correctly.
Expand Down Expand Up @@ -280,20 +267,8 @@ bool QgsMapLayer::writeXML( QDomNode & layer_node, QDomDocument & document )
QDomElement dataSource = document.createElement( "datasource" );

QString src = source();
QFileInfo srcInfo( src );

bool absolutePath = QgsProject::instance()->readBoolEntry( "Paths", "/Absolute", true );
if ( !absolutePath && srcInfo.exists() )
{
QFileInfo pfi( QgsProject::instance()->fileName() );
QgsDebugMsg( "project path: " + pfi.canonicalPath() );
QgsDebugMsg( "src path: " + srcInfo.canonicalFilePath() );
if ( srcInfo.canonicalFilePath().startsWith( pfi.canonicalPath() + "/" ) ) // QFileInfo always uses '/' for directory separator.
{
src = src.mid( pfi.canonicalPath().size() + 1 );
QgsDebugMsg( "use relative path: " + src );
}
}
src = QgsProject::instance()->writePath( src );

QDomText dataSourceText = document.createTextNode( src );
dataSource.appendChild( dataSourceText );
Expand Down
151 changes: 151 additions & 0 deletions src/core/qgsproject.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1300,3 +1300,154 @@ void QgsProject::dumpProperties() const
{
dump_( imp_->properties_ );
} // QgsProject::dumpProperties


// return the absolute path from a filename read from project file
QString QgsProject::readPath( QString src ) const
{
if ( readBoolEntry( "Paths", "/Absolute", true ) )
{
return src;
}

// relative path should always start with ./ or ../
if ( !src.startsWith( "./" ) && !src.startsWith( "../" ) )
{
#if defined(Q_OS_WIN)
if ( src.startsWith( "\\\\" ) ||
( src[0].isLetter() && src[1] == ':' ) )
{
// UNC or absolute path
return src;
}
#else
if ( src[0] == '/' )
{
// absolute path
return src;
}
#endif

// so this one isn't absolute, but also doesn't start // with ./ or ../.
// That means that it was saved with an earlier version of "relative path support",
// where the source file had to exist and only the project directory was stripped
// from the filename.
QFileInfo pfi( fileName() );
Q_ASSERT( pfi.exists() );
QFileInfo fi( pfi.canonicalPath() + "/" + src );

if ( !fi.exists() )
{
return src;
}
else
{
return fi.canonicalFilePath();
}
}

QString srcPath = src;
QString projPath = fileName();

#if defined(Q_OS_WIN)
srcPath.replace( "\\", "/" );
projPath.replace( "\\", "/" );
#endif

QStringList srcElems = srcPath.split( "/", QString::SkipEmptyParts );
QStringList projElems = projPath.split( "/", QString::SkipEmptyParts );

// remove project file element
projElems.removeLast();

// append source path elements
projElems.append( srcElems );
projElems.removeAll( "." );

// resolve ..
int pos;
while (( pos = projElems.indexOf( ".." ) ) > 0 )
{
// remove preceeding element and ..
projElems.removeAt( pos - 1 );
projElems.removeAt( pos - 1 );
}

return projElems.join( "/" );
}

// return the absolute or relative path to write it to the project file
QString QgsProject::writePath( QString src ) const
{
if ( readBoolEntry( "Paths", "/Absolute", true ) )
{
return src;
}

QString srcPath = src;
QString projPath = fileName();

#if defined( Q_OS_WIN )
const Qt::CaseSensitivity cs = Qt::CaseInsensitive;

srcPath.replace( "\\", "/" );

if ( srcPath.startsWith( "//" ) )
{
// keep UNC prefix
srcPath = "\\\\" + srcPath.mid( 2 );
}

projPath.replace( "\\", "/" );
if ( projPath.startsWith( "//" ) )
{
// keep UNC prefix
projPath = "\\\\" + projPath.mid( 2 );
}
#else
const Qt::CaseSensitivity cs = Qt::CaseSensitive;
#endif

QStringList projElems = projPath.split( "/", QString::SkipEmptyParts );
QStringList srcElems = srcPath.split( "/", QString::SkipEmptyParts );

// remove project file element
projElems.removeLast();

projElems.removeAll( "." );
srcElems.removeAll( "." );

// remove common part
int n = 0;
while ( srcElems.size() > 0 &&
projElems.size() > 0 &&
srcElems[0].compare( projElems[0], cs ) == 0 )
{
srcElems.removeFirst();
projElems.removeFirst();
n++;
}

if ( n == 0 )
{
// no common parts; might not even by a file
return src;
}

if ( projElems.size() > 0 )
{
// go up to the common directory
for ( int i = 0; i < projElems.size(); i++ )
{
srcElems.insert( 0, ".." );
}
}
else
{
// let it start with . nevertheless,
// so relative path always start with either ./ or ../
srcElems.insert( 0, "." );
}

return srcElems.join( "/" );
}
9 changes: 9 additions & 0 deletions src/core/qgsproject.h
Original file line number Diff line number Diff line change
Expand Up @@ -255,6 +255,15 @@ class CORE_EXPORT QgsProject : public QObject
*/
void dumpProperties() const;


/** prepare a filename to save it to the project file
@note added in 1.3 */
QString writePath( QString filename ) const;

/** turn filename read from the project file to an absolute path
@note added in 1.3 */
QString readPath( QString filename ) const;

signals:

//! emitted when project is being read
Expand Down

0 comments on commit 032b743

Please sign in to comment.