18 #include <QApplication>
23 #include <QMouseEvent>
24 #include <QTreeWidget>
25 #include <QTreeWidgetItem>
28 #include <QDomDocument>
29 #include <QDomElement>
36 #include "qgsconfig.h"
50 return *sArchiveRegistry();
54 : mArchiveName( archiveName )
61 const auto constEntryList = QDir( mBaseDir ).entryList( QDir::Dirs | QDir::NoDotAndDotDot, QDir::Name );
62 for (
const QString &path : constEntryList )
64 if ( path == QLatin1String(
"selections" ) )
69 mRootItems << dirItem;
76 QDir seldir( mBaseDir +
'/' +
"selections" );
77 QgsDebugMsg(
"populating selection from " + seldir.path() );
78 const QStringList fileList = seldir.entryList( QStringList() << QStringLiteral(
"*.xml" ), QDir::Files );
79 for (
const QString &selfile : fileList )
81 QgsDebugMsg(
"file= " + seldir.path() +
'/' + selfile );
83 seldir.dirName() +
'/' + selfile );
86 mSelectionItems << selItem;
95 mRootItems.prepend( allRampsItem );
98 mSelectionItems.prepend( allRampsItem );
103 const auto constMRootItems = mRootItems;
106 const auto constMSelectionItems = mSelectionItems;
110 mSelectionItems.clear();
117 if ( ! mBaseDir.isNull() )
129 return archive->baseDir();
140 baseDir = settings.
value( QStringLiteral(
"CptCity/baseDir" ),
153 if ( startDir.isEmpty() || ! startDir.startsWith(
baseDir ) )
156 QDir dir = QDir( startDir );
158 while ( ! dir.exists( target ) && dir.path() !=
baseDir )
163 if ( ! dir.exists( target ) )
166 return dir.path() +
'/' + target;
186 if ( fileName.isNull() )
189 if ( sCopyingInfoMap()->contains( fileName ) )
191 QgsDebugMsg(
"found copying info in copyingInfoMap, file = " + fileName );
192 return sCopyingInfoMap()->value( fileName );
199 if ( !f.open( QFile::ReadOnly ) )
201 QgsDebugMsg(
"Couldn't open xml file: " + fileName );
206 QDomDocument doc( QStringLiteral(
"license" ) );
207 if ( !doc.setContent( &f ) )
210 QgsDebugMsg(
"Couldn't parse xml file: " + fileName );
216 QDomElement docElem = doc.documentElement();
217 if ( docElem.tagName() != QLatin1String(
"copying" ) )
219 QgsDebugMsg(
"Incorrect root tag: " + docElem.tagName() );
224 QDomElement authorsElement = docElem.firstChildElement( QStringLiteral(
"authors" ) );
225 if ( authorsElement.isNull() )
227 QgsDebugMsg( QStringLiteral(
"authors tag missing" ) );
231 QDomElement e = authorsElement.firstChildElement();
233 while ( ! e.isNull() )
235 if ( e.tagName() == QLatin1String(
"author" ) )
237 if ( ! e.firstChildElement( QStringLiteral(
"name" ) ).isNull() )
238 authors << e.firstChildElement( QStringLiteral(
"name" ) ).text().simplified();
241 e = e.nextSiblingElement();
243 copyingMap[ QStringLiteral(
"authors" )] = authors.join( QStringLiteral(
", " ) );
247 QDomElement licenseElement = docElem.firstChildElement( QStringLiteral(
"license" ) );
248 if ( licenseElement.isNull() )
250 QgsDebugMsg( QStringLiteral(
"license tag missing" ) );
254 QDomElement e = licenseElement.firstChildElement( QStringLiteral(
"informal" ) );
256 copyingMap[ QStringLiteral(
"license/informal" )] = e.text().simplified();
257 e = licenseElement.firstChildElement( QStringLiteral(
"year" ) );
259 copyingMap[ QStringLiteral(
"license/year" )] = e.text().simplified();
260 e = licenseElement.firstChildElement( QStringLiteral(
"text" ) );
261 if ( ! e.isNull() && e.attribute( QStringLiteral(
"href" ) ) != QString() )
262 copyingMap[ QStringLiteral(
"license/url" )] = e.attribute( QStringLiteral(
"href" ) );
266 QDomElement element = docElem.firstChildElement( QStringLiteral(
"src" ) );
267 if ( element.isNull() )
269 QgsDebugMsg( QStringLiteral(
"src tag missing" ) );
273 QDomElement e = element.firstChildElement( QStringLiteral(
"link" ) );
274 if ( ! e.isNull() && e.attribute( QStringLiteral(
"href" ) ) != QString() )
275 copyingMap[ QStringLiteral(
"src/link" )] = e.attribute( QStringLiteral(
"href" ) );
279 ( *sCopyingInfoMap() )[ fileName ] = copyingMap;
287 QgsDebugMsg(
"description fileName = " + fileName );
290 if ( ! f.open( QFile::ReadOnly ) )
292 QgsDebugMsg(
"description file " + fileName +
" ] does not exist" );
298 QDomDocument doc( QStringLiteral(
"description" ) );
299 if ( !doc.setContent( &f, &errMsg ) )
302 QgsDebugMsg(
"Couldn't parse file " + fileName +
" : " + errMsg );
308 QDomElement docElem = doc.documentElement();
309 if ( docElem.tagName() != QLatin1String(
"description" ) )
311 QgsDebugMsg(
"Incorrect root tag: " + docElem.tagName() );
316 QDomElement e = docElem.firstChildElement( QStringLiteral(
"name" ) );
319 QgsDebugMsg( QStringLiteral(
"name tag missing" ) );
321 descMap[ QStringLiteral(
"name" )] = e.text().simplified();
322 e = docElem.firstChildElement( QStringLiteral(
"full" ) );
325 QgsDebugMsg( QStringLiteral(
"full tag missing" ) );
327 descMap[ QStringLiteral(
"full" )] = e.text().simplified();
334 QMap< double, QPair<QColor, QColor> > colorMap;
338 if ( !f.open( QFile::ReadOnly ) )
340 QgsDebugMsg(
"Couldn't open SVG file: " + fileName );
345 QDomDocument doc( QStringLiteral(
"gradient" ) );
346 if ( !doc.setContent( &f ) )
349 QgsDebugMsg(
"Couldn't parse SVG file: " + fileName );
354 QDomElement docElem = doc.documentElement();
356 if ( docElem.tagName() != QLatin1String(
"svg" ) )
358 QgsDebugMsg(
"Incorrect root tag: " + docElem.tagName() );
363 QDomElement rampsElement = docElem.firstChildElement( QStringLiteral(
"linearGradient" ) );
364 if ( rampsElement.isNull() )
366 QDomNodeList nodeList = docElem.elementsByTagName( QStringLiteral(
"linearGradient" ) );
367 if ( ! nodeList.isEmpty() )
368 rampsElement = nodeList.at( 0 ).toElement();
370 if ( rampsElement.isNull() )
372 QgsDebugMsg( QStringLiteral(
"linearGradient tag missing" ) );
377 QDomElement e = rampsElement.firstChildElement();
379 while ( !e.isNull() )
381 if ( e.tagName() == QLatin1String(
"stop" ) )
385 QString offsetStr = e.attribute( QStringLiteral(
"offset" ) );
386 QString colorStr = e.attribute( QStringLiteral(
"stop-color" ), QString() );
387 QString opacityStr = e.attribute( QStringLiteral(
"stop-opacity" ), QStringLiteral(
"1.0" ) );
388 if ( offsetStr.endsWith(
'%' ) )
389 offset = offsetStr.remove( offsetStr.size() - 1, 1 ).toDouble() / 100.0;
391 offset = offsetStr.toDouble();
395 if ( color != QColor() )
397 int alpha = opacityStr.toDouble() * 255;
398 color.setAlpha( alpha );
399 if ( colorMap.contains( offset ) )
400 colorMap[offset].second = color;
402 colorMap[offset] = qMakePair( color, color );
406 QgsDebugMsg( QStringLiteral(
"at offset=%1 invalid color" ).arg( offset ) );
414 e = e.nextSiblingElement();
422 return ( mRootItems.isEmpty() );
430 if ( sArchiveRegistry()->contains( *sDefaultArchiveName() ) )
431 return sArchiveRegistry()->value( *sDefaultArchiveName() );
449 QString
baseDir = settings.
value( QStringLiteral(
"CptCity/baseDir" ),
454 if ( ! sArchiveRegistry()->contains( defArchiveName ) )
461 QString
baseDir, defArchiveName;
465 baseDir = settings.
value( QStringLiteral(
"CptCity/baseDir" ),
474 const QStringList fileList = dir.entryList( QStringList() << QStringLiteral(
"cpt-city*" ), QDir::Dirs );
475 for (
const QString &entry : fileList )
477 if ( QFile::exists(
baseDir +
'/' + entry +
"/VERSION.xml" ) )
478 archivesMap[ entry ] =
baseDir +
'/' + entry;
483 archivesMap[ defArchiveName ] =
baseDir +
'/' + defArchiveName;
486 for ( QgsStringMap::iterator it = archivesMap.begin();
487 it != archivesMap.end(); ++it )
489 if ( QDir( it.value() ).exists() )
493 QgsDebugMsg( QStringLiteral(
"not loading archive [%1] because dir %2 does not exist " ).arg( it.key(), it.value() ) );
496 *sDefaultArchiveName() = defArchiveName;
501 qDeleteAll( *sArchiveRegistry() );
502 sArchiveRegistry()->clear();
509 const QString &name,
const QString &path )
513 , mPopulated( false )
522 QVector<QgsCptCityDataItem *>
children;
533 QApplication::setOverrideCursor( Qt::WaitCursor );
536 const auto constChildren =
children;
544 QApplication::restoreOverrideCursor();
564 count += child->leafCount();
586 mChildren.at( i )->mName.localeAwareCompare( child->
mName ) >= 0 )
594 if (
mChildren.at( i )->mName.localeAwareCompare( child->
mName ) >= 0 )
641 for (
int i = 0; i < items.size(); i++ )
644 if ( items[i]->
equal( item ) )
654 QApplication::setOverrideCursor( Qt::WaitCursor );
659 QVector<QgsCptCityDataItem *> remove;
663 if (
findItem( items, child ) >= 0 )
665 remove.append( child );
667 const auto constRemove = remove;
674 const auto constItems = items;
686 QApplication::restoreOverrideCursor();
691 return ( metaObject()->className() == other->metaObject()->className() &&
698 const QString &name,
const QString &path,
const QString &variantName,
bool initialize )
700 , mInitialized( false )
701 , mRamp( path, variantName, false )
710 const QString &name,
const QString &path,
const QStringList &variantList,
bool initialize )
712 , mInitialized( false )
713 , mRamp( path, variantList, QString(), false )
746 if ( variantList.isEmpty() )
751 mInfo = QString::number( count ) +
' ' + tr(
"colors" ) +
" - ";
753 mInfo += tr(
"discrete" );
757 mInfo += tr(
"continuous" );
759 mInfo += tr(
"continuous (multi)" );
765 mInfo = QString::number( variantList.count() ) +
' ' + tr(
"variants" );
794 return icon( QSize( 100, 15 ) );
799 const auto constMIcons =
mIcons;
800 for (
const QIcon &
icon : constMIcons )
802 if (
icon.availableSizes().contains( size ) )
816 QPixmap blankPixmap( size );
817 blankPixmap.fill( Qt::white );
818 icon = QIcon( blankPixmap );
828 const QString &name,
const QString &path )
830 , mPopulatedRamps( false )
841 QVector< QgsCptCityDataItem * > rampItems;
842 QVector< QgsCptCityDataItem * > deleteItems;
847 const auto constChildren =
children();
852 QgsDebugMsgLevel( QStringLiteral(
"child path= %1 coll= %2 ramp = %3" ).arg( childItem->path() ).arg(
nullptr != collectionItem ).arg(
nullptr != rampItem ), 2 );
853 if ( collectionItem && recursive )
863 rampItems << rampItem;
865 deleteItems << rampItem;
869 QgsDebugMsg(
"invalid item " + childItem->path() );
874 const auto constDeleteItems = deleteItems;
877 QgsDebugMsg( QStringLiteral(
"item %1 is invalid, will be deleted" ).arg( deleteItem->path() ) );
889 const QString &name,
const QString &path )
903 mPath +
'/' +
"DESC.xml";
905 if ( descMap.contains( QStringLiteral(
"name" ) ) )
906 mInfo = descMap.value( QStringLiteral(
"name" ) );
914 return QVector<QgsCptCityDataItem *>();
916 QVector<QgsCptCityDataItem *>
children;
919 QMapIterator< QString, QStringList> it(
rampsMap() );
920 while ( it.hasNext() )
934 for (
const QString &childPath : constDirEntries )
952 QString curName, prevName, curVariant, curSep, schemeName;
953 QStringList listVariant;
954 QStringList schemeNamesAll, schemeNames;
955 bool prevAdd, curAdd;
958 schemeNamesAll = dir.entryList( QStringList( QStringLiteral(
"*.svg" ) ), QDir::Files, QDir::Name );
961 for (
int i = 0; i < schemeNamesAll.count(); i++ )
964 schemeName = schemeNamesAll[i];
965 schemeName.chop( 4 );
968 curName = schemeName;
973 if ( schemeName.length() > 1 && schemeName.endsWith(
'a' ) && ! listVariant.isEmpty() &&
974 ( ( prevName + listVariant.last() +
'a' ) == curName ) )
977 curVariant = listVariant.last() +
'a';
981 QRegExp rxVariant(
"^(.*[^\\d])(\\d{1,3})$" );
982 int pos = rxVariant.indexIn( schemeName );
985 curName = rxVariant.cap( 1 );
986 curVariant = rxVariant.cap( 2 );
990 curSep = curName.right( 1 );
991 if ( curSep == QLatin1String(
"-" ) || curSep == QLatin1String(
"_" ) )
994 curVariant = curSep + curVariant;
997 if ( prevName.isEmpty() )
1003 if ( curName.isEmpty() )
1004 curName = QStringLiteral(
"__empty__" );
1006 if ( curName == prevName )
1009 if ( i == schemeNamesAll.count() - 1 )
1011 listVariant << curVariant;
1015 if ( !prevName.isEmpty() )
1020 if ( i == schemeNamesAll.count() - 1 )
1029 if ( listVariant.isEmpty() )
1033 schemeNames << prevName;
1036 else if ( listVariant.count() <= 3 )
1039 for (
int j = 0; j < listVariant.count(); j++ )
1042 schemeNames << prevName + listVariant[j];
1043 mRampsMap[
mPath +
'/' + prevName + listVariant[j] ] = QStringList();
1050 schemeNames << prevName;
1052 listVariant.clear();
1056 if ( !curVariant.isEmpty() )
1057 curName += curVariant;
1058 schemeNames << curName;
1062 if ( prevAdd || curAdd )
1065 if ( !curVariant.isEmpty() )
1066 listVariant << curVariant;
1073 mSchemeMap[
path ] = schemeNames;
1074 schemeCount += schemeName.count();
1075 schemeNames.clear();
1076 listVariant.clear();
1085 '/' +
mPath ).entryList( QDir::Dirs | QDir::NoDotAndDotDot, QDir::Name );
1095 return (
path() == other->
path() );
1099 const QString &name,
const QString &path )
1105 if ( dirItem && ! dirItem->
isValid() )
1150 const QString &name,
const QString &path )
1162 return QVector<QgsCptCityDataItem *>();
1165 QVector<QgsCptCityDataItem *>
children;
1171 for ( QString childPath : constMSelectionsList )
1173 QgsDebugMsg(
"childPath = " + childPath +
" name= " + QFileInfo( childPath ).baseName() );
1174 if ( childPath.endsWith(
'/' ) )
1176 childPath.chop( 1 );
1209 QFile f( filename );
1210 if ( ! f.open( QFile::ReadOnly ) )
1218 QDomDocument doc( QStringLiteral(
"selection" ) );
1219 if ( !doc.setContent( &f, &errMsg ) )
1222 QgsDebugMsg(
"Couldn't parse file " + filename +
" : " + errMsg );
1228 QDomElement docElem = doc.documentElement();
1229 if ( docElem.tagName() != QLatin1String(
"selection" ) )
1231 QgsDebugMsg(
"Incorrect root tag: " + docElem.tagName() );
1234 QDomElement e = docElem.firstChildElement( QStringLiteral(
"name" ) );
1235 if ( ! e.isNull() && ! e.text().isNull() )
1237 mInfo = docElem.firstChildElement( QStringLiteral(
"synopsis" ) ).text().simplified();
1240 QDomElement collectsElem = docElem.firstChildElement( QStringLiteral(
"seealsocollects" ) );
1241 e = collectsElem.firstChildElement( QStringLiteral(
"collect" ) );
1242 while ( ! e.isNull() )
1244 if ( ! e.attribute( QStringLiteral(
"dir" ) ).isNull() )
1249 e = e.nextSiblingElement();
1252 QDomElement gradientsElem = docElem.firstChildElement( QStringLiteral(
"gradients" ) );
1253 e = gradientsElem.firstChildElement( QStringLiteral(
"gradient" ) );
1254 while ( ! e.isNull() )
1256 if ( ! e.attribute( QStringLiteral(
"dir" ) ).isNull() )
1260 mSelectionsList << e.attribute( QStringLiteral(
"dir" ) ) +
'/' + e.attribute( QStringLiteral(
"file" ) );
1262 e = e.nextSiblingElement();
1273 return (
path() == other->
path() );
1278 const QString &name,
const QVector<QgsCptCityDataItem *> &items )
1290 return QVector<QgsCptCityDataItem *>();
1292 QVector<QgsCptCityDataItem *>
children;
1295 const auto constMItems =
mItems;
1310 : QAbstractItemModel( parent )
1311 , mArchive( archive )
1312 , mViewType( viewType )
1315 QgsDebugMsg(
"archiveName = " + archive->
archiveName() +
" viewType=" +
static_cast< int >( viewType ) );
1352 if ( !
index.isValid() )
1353 return Qt::ItemFlags();
1355 Qt::ItemFlags
flags = Qt::ItemIsEnabled | Qt::ItemIsSelectable;
1362 if ( !
index.isValid() )
1371 else if ( role == Qt::DisplayRole )
1373 if (
index.column() == 0 )
1374 return item->
name();
1375 if (
index.column() == 1 )
1377 return item->
info();
1380 else if ( role == Qt::ToolTipRole )
1384 return item->
path() +
'\n' + item->
info();
1387 else if ( role == Qt::DecorationRole &&
index.column() == 1 &&
1393 else if ( role == Qt::FontRole &&
1394 qobject_cast< QgsCptCityCollectionItem * >( item ) )
1398 font.setPointSize( 11 );
1399 font.setBold(
true );
1413 if ( orientation == Qt::Horizontal && role == Qt::DisplayRole )
1416 return QVariant( tr(
"Name" ) );
1417 else if ( section == 1 )
1418 return QVariant( tr(
"Info" ) );
1436 return item ? item->
rowCount() : 0;
1458 QModelIndex rootIndex;
1459 bool foundParent =
false, foundChild =
true;
1465 if ( path.isEmpty() )
1467 for (
int i = 0; i <
rowCount( rootIndex ); i++ )
1469 QModelIndex idx =
index( i, 0, rootIndex );
1472 return QModelIndex();
1474 itemPath = item->
path();
1476 if ( itemPath == path )
1484 while ( foundChild )
1490 if ( itemPath.isEmpty() )
1492 for ( ; i <
rowCount( rootIndex ); i++ )
1494 QModelIndex idx =
index( i, 0, rootIndex );
1497 return QModelIndex();
1499 itemPath = item->
path();
1501 if ( itemPath == path )
1507 if ( ! itemPath.endsWith(
'/' ) )
1510 foundParent =
false;
1521 for ( QString childPath : constSelectionsList )
1523 if ( childPath.endsWith(
'/' ) )
1524 childPath.chop( 1 );
1526 if ( path.startsWith( childPath ) )
1535 else if ( path.startsWith( itemPath ) )
1553 return QModelIndex();
1567 QModelIndex idx =
findPath( path );
1568 if ( idx.isValid() )
1581 return item ? createIndex( row, column, item ) : QModelIndex();
1588 return QModelIndex();
1597 for (
int i = 0; i < items.size(); i++ )
1599 if ( items[i] == item )
1600 return createIndex( i, 0, item );
1602 QModelIndex childIndex =
findItem( item, items[i] );
1603 if ( childIndex.isValid() )
1607 return QModelIndex();
1625 if ( !idx.isValid() )
1628 beginInsertRows( idx, first, last );
1639 if ( !idx.isValid() )
1641 beginRemoveRows( idx, first, last );
1685 QStringList QgsCptCityBrowserModel::mimeTypes()
const
1690 types <<
"application/x-vnd.qgis.qgis.uri";
1694 QMimeData *QgsCptCityBrowserModel::mimeData(
const QModelIndexList &indexes )
const
1697 const auto constIndexes = indexes;
1698 for (
const QModelIndex &
index : constIndexes )
1700 if (
index.isValid() )
1703 if ( ptr->
type() != QgsCptCityDataItem::Layer )
continue;
1711 bool QgsCptCityBrowserModel::dropMimeData(
const QMimeData *data, Qt::DropAction action,
int row,
int column,
const QModelIndex &parent )
1729 void *v = idx.internalPointer();
1731 Q_ASSERT( !v || d );