QGIS API Documentation  3.26.3-Buenos Aires (65e4edfdad)
qgscptcityarchive.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgscptcityarchive.cpp
3  ---------------------
4  begin : August 2012
5  copyright : (C) 2009 by Martin Dobias
6  copyright : (C) 2011 Radim Blazek
7  copyright : (C) 2012 by Etienne Tourigny
8  email : etourigny.dev at gmail.com
9  ***************************************************************************
10  * *
11  * This program is free software; you can redistribute it and/or modify *
12  * it under the terms of the GNU General Public License as published by *
13  * the Free Software Foundation; either version 2 of the License, or *
14  * (at your option) any later version. *
15  * *
16  ***************************************************************************/
17 
18 #include "qgssettings.h"
19 #include "qgscptcityarchive.h"
20 #include "qgis.h"
21 #include "qgsdataprovider.h"
22 #include "qgslogger.h"
23 #include "qgsconfig.h"
24 #include "qgsmimedatautils.h"
25 #include "qgsapplication.h"
26 #include "qgssymbollayerutils.h"
27 
28 #include <QApplication>
29 #include <QDateTime>
30 #include <QDir>
31 #include <QFileInfo>
32 #include <QVector>
33 #include <QStyle>
34 #include <QDomDocument>
35 #include <QDomElement>
36 #include <QRegularExpression>
37 
38 typedef QMap< QString, QgsCptCityArchive * > ArchiveRegistry;
39 typedef QMap< QString, QMap< QString, QString > > CopyingInfoMap;
40 
41 Q_GLOBAL_STATIC( QString, sDefaultArchiveName )
42 Q_GLOBAL_STATIC( ArchiveRegistry, sArchiveRegistry )
43 Q_GLOBAL_STATIC( CopyingInfoMap, sCopyingInfoMap )
44 
45 QMap< QString, QgsCptCityArchive * > QgsCptCityArchive::archiveRegistry()
46 {
47  return *sArchiveRegistry();
48 }
49 
50 QgsCptCityArchive::QgsCptCityArchive( const QString &archiveName, const QString &baseDir )
51  : mArchiveName( archiveName )
52  , mBaseDir( baseDir )
53 {
54  QgsDebugMsgLevel( "archiveName = " + archiveName + " baseDir = " + baseDir, 2 );
55 
56  // make Author items
57  QgsCptCityDirectoryItem *dirItem = nullptr;
58  const auto constEntryList = QDir( mBaseDir ).entryList( QDir::Dirs | QDir::NoDotAndDotDot, QDir::Name );
59  for ( const QString &path : constEntryList )
60  {
61  if ( path == QLatin1String( "selections" ) )
62  continue;
63  QgsDebugMsgLevel( "path= " + path, 2 );
64  dirItem = new QgsCptCityDirectoryItem( nullptr, QFileInfo( path ).baseName(), path );
65  if ( dirItem->isValid() )
66  mRootItems << dirItem;
67  else
68  delete dirItem;
69  }
70 
71  // make selection items
72  QgsCptCitySelectionItem *selItem = nullptr;
73  const QDir seldir( mBaseDir + '/' + "selections" );
74  QgsDebugMsgLevel( "populating selection from " + seldir.path(), 2 );
75  const QStringList fileList = seldir.entryList( QStringList() << QStringLiteral( "*.xml" ), QDir::Files );
76  for ( const QString &selfile : fileList )
77  {
78  QgsDebugMsgLevel( "file= " + seldir.path() + '/' + selfile, 2 );
79  selItem = new QgsCptCitySelectionItem( nullptr, QFileInfo( selfile ).baseName(),
80  seldir.dirName() + '/' + selfile );
81  //TODO remove item if there are no children (e.g. esri in qgis-sel)
82  if ( selItem->isValid() )
83  mSelectionItems << selItem;
84  else
85  delete selItem;
86  }
87 
88  // make "All Ramps items" (which will contain all ramps without hierarchy)
89  QgsCptCityAllRampsItem *allRampsItem = nullptr;
90  allRampsItem = new QgsCptCityAllRampsItem( nullptr, QObject::tr( "All Ramps" ),
91  mRootItems );
92  mRootItems.prepend( allRampsItem );
93  allRampsItem = new QgsCptCityAllRampsItem( nullptr, QObject::tr( "All Ramps" ),
94  mSelectionItems );
95  mSelectionItems.prepend( allRampsItem );
96 }
97 
99 {
100  const auto constMRootItems = mRootItems;
101  for ( QgsCptCityDataItem *item : constMRootItems )
102  delete item;
103  const auto constMSelectionItems = mSelectionItems;
104  for ( QgsCptCityDataItem *item : constMSelectionItems )
105  delete item;
106  mRootItems.clear();
107  mSelectionItems.clear();
108 }
109 
111 {
112  // if was set with setBaseDir, return that value
113  // else return global default
114  if ( ! mBaseDir.isNull() )
115  return mBaseDir;
116  else
118 }
119 
120 QString QgsCptCityArchive::baseDir( QString archiveName )
121 {
122  // search for matching archive in the registry
123  if ( archiveName.isNull() )
125  if ( QgsCptCityArchive *archive = sArchiveRegistry()->value( archiveName, nullptr ) )
126  return archive->baseDir();
127  else
128  return defaultBaseDir();
129 }
130 
132 {
133  QString baseDir, archiveName;
134  const QgsSettings settings;
135 
136  // use CptCity/baseDir setting if set, default is user dir
137  baseDir = settings.value( QStringLiteral( "CptCity/baseDir" ),
138  QString( QgsApplication::pkgDataPath() + "/resources" ) ).toString();
139  // sub-dir defaults to cpt-city
140  archiveName = settings.value( QStringLiteral( "CptCity/archiveName" ), DEFAULT_CPTCITY_ARCHIVE ).toString();
141 
142  return baseDir + '/' + archiveName;
143 }
144 
145 
146 QString QgsCptCityArchive::findFileName( const QString &target, const QString &startDir, const QString &baseDir )
147 {
148  // QgsDebugMsgLevel( "target= " + target + " startDir= " + startDir + " baseDir= " + baseDir, 2 );
149 
150  if ( startDir.isEmpty() || ! startDir.startsWith( baseDir ) )
151  return QString();
152 
153  QDir dir = QDir( startDir );
154  //todo test when
155  while ( ! dir.exists( target ) && dir.path() != baseDir )
156  {
157  if ( ! dir.cdUp() )
158  break;
159  }
160  if ( ! dir.exists( target ) )
161  return QString();
162  else
163  return dir.path() + '/' + target;
164 }
165 
166 
167 QString QgsCptCityArchive::copyingFileName( const QString &path ) const
168 {
169  return QgsCptCityArchive::findFileName( QStringLiteral( "COPYING.xml" ),
170  baseDir() + '/' + path, baseDir() );
171 }
172 
173 QString QgsCptCityArchive::descFileName( const QString &path ) const
174 {
175  return QgsCptCityArchive::findFileName( QStringLiteral( "DESC.xml" ),
176  baseDir() + '/' + path, baseDir() );
177 }
178 
180 {
181  QgsStringMap copyingMap;
182 
183  if ( fileName.isNull() )
184  return copyingMap;
185 
186  if ( sCopyingInfoMap()->contains( fileName ) )
187  {
188  QgsDebugMsgLevel( "found copying info in copyingInfoMap, file = " + fileName, 2 );
189  return sCopyingInfoMap()->value( fileName );
190  }
191 
192  QgsDebugMsgLevel( "fileName = " + fileName, 2 );
193 
194  // import xml file
195  QFile f( fileName );
196  if ( !f.open( QFile::ReadOnly ) )
197  {
198  QgsDebugMsg( "Couldn't open xml file: " + fileName );
199  return copyingMap;
200  }
201 
202  // parse the document
203  QDomDocument doc( QStringLiteral( "license" ) );
204  if ( !doc.setContent( &f ) )
205  {
206  f.close();
207  QgsDebugMsg( "Couldn't parse xml file: " + fileName );
208  return copyingMap;
209  }
210  f.close();
211 
212  // get root element
213  const QDomElement docElem = doc.documentElement();
214  if ( docElem.tagName() != QLatin1String( "copying" ) )
215  {
216  QgsDebugMsg( "Incorrect root tag: " + docElem.tagName() );
217  return copyingMap;
218  }
219 
220  // load author information
221  const QDomElement authorsElement = docElem.firstChildElement( QStringLiteral( "authors" ) );
222  if ( authorsElement.isNull() )
223  {
224  QgsDebugMsgLevel( QStringLiteral( "authors tag missing" ), 2 );
225  }
226  else
227  {
228  QDomElement e = authorsElement.firstChildElement();
229  QStringList authors;
230  while ( ! e.isNull() )
231  {
232  if ( e.tagName() == QLatin1String( "author" ) )
233  {
234  if ( ! e.firstChildElement( QStringLiteral( "name" ) ).isNull() )
235  authors << e.firstChildElement( QStringLiteral( "name" ) ).text().simplified();
236  // org???
237  }
238  e = e.nextSiblingElement();
239  }
240  copyingMap[ QStringLiteral( "authors" )] = authors.join( QLatin1String( ", " ) );
241  }
242 
243  // load license information
244  const QDomElement licenseElement = docElem.firstChildElement( QStringLiteral( "license" ) );
245  if ( licenseElement.isNull() )
246  {
247  QgsDebugMsgLevel( QStringLiteral( "license tag missing" ), 2 );
248  }
249  else
250  {
251  QDomElement e = licenseElement.firstChildElement( QStringLiteral( "informal" ) );
252  if ( ! e.isNull() )
253  copyingMap[ QStringLiteral( "license/informal" )] = e.text().simplified();
254  e = licenseElement.firstChildElement( QStringLiteral( "year" ) );
255  if ( ! e.isNull() )
256  copyingMap[ QStringLiteral( "license/year" )] = e.text().simplified();
257  e = licenseElement.firstChildElement( QStringLiteral( "text" ) );
258  if ( ! e.isNull() && e.attribute( QStringLiteral( "href" ) ) != QString() )
259  copyingMap[ QStringLiteral( "license/url" )] = e.attribute( QStringLiteral( "href" ) );
260  }
261 
262  // load src information
263  const QDomElement element = docElem.firstChildElement( QStringLiteral( "src" ) );
264  if ( element.isNull() )
265  {
266  QgsDebugMsgLevel( QStringLiteral( "src tag missing" ), 2 );
267  }
268  else
269  {
270  const QDomElement e = element.firstChildElement( QStringLiteral( "link" ) );
271  if ( ! e.isNull() && e.attribute( QStringLiteral( "href" ) ) != QString() )
272  copyingMap[ QStringLiteral( "src/link" )] = e.attribute( QStringLiteral( "href" ) );
273  }
274 
275  // save copyingMap for further access
276  ( *sCopyingInfoMap() )[ fileName ] = copyingMap;
277  return copyingMap;
278 }
279 
281 {
282  QgsStringMap descMap;
283 
284  QgsDebugMsgLevel( "description fileName = " + fileName, 2 );
285 
286  QFile f( fileName );
287  if ( ! f.open( QFile::ReadOnly ) )
288  {
289  QgsDebugMsgLevel( "description file " + fileName + " ] does not exist", 2 );
290  return descMap;
291  }
292 
293  // parse the document
294  QString errMsg;
295  QDomDocument doc( QStringLiteral( "description" ) );
296  if ( !doc.setContent( &f, &errMsg ) )
297  {
298  f.close();
299  QgsDebugMsg( "Couldn't parse file " + fileName + " : " + errMsg );
300  return descMap;
301  }
302  f.close();
303 
304  // read description
305  const QDomElement docElem = doc.documentElement();
306  if ( docElem.tagName() != QLatin1String( "description" ) )
307  {
308  QgsDebugMsg( "Incorrect root tag: " + docElem.tagName() );
309  return descMap;
310  }
311  // should we make sure the <dir> tag is OK?
312 
313  QDomElement e = docElem.firstChildElement( QStringLiteral( "name" ) );
314  if ( e.isNull() )
315  {
316  QgsDebugMsgLevel( QStringLiteral( "name tag missing" ), 2 );
317  }
318  descMap[ QStringLiteral( "name" )] = e.text().simplified();
319  e = docElem.firstChildElement( QStringLiteral( "full" ) );
320  if ( e.isNull() )
321  {
322  QgsDebugMsgLevel( QStringLiteral( "full tag missing" ), 2 );
323  }
324  descMap[ QStringLiteral( "full" )] = e.text().simplified();
325 
326  return descMap;
327 }
328 
329 QMap< double, QPair<QColor, QColor> >QgsCptCityArchive::gradientColorMap( const QString &fileName )
330 {
331  QMap< double, QPair<QColor, QColor> > colorMap;
332 
333  // import xml file
334  QFile f( fileName );
335  if ( !f.open( QFile::ReadOnly ) )
336  {
337  QgsDebugMsg( "Couldn't open SVG file: " + fileName );
338  return colorMap;
339  }
340 
341  // parse the document
342  QDomDocument doc( QStringLiteral( "gradient" ) );
343  if ( !doc.setContent( &f ) )
344  {
345  f.close();
346  QgsDebugMsg( "Couldn't parse SVG file: " + fileName );
347  return colorMap;
348  }
349  f.close();
350 
351  const QDomElement docElem = doc.documentElement();
352 
353  if ( docElem.tagName() != QLatin1String( "svg" ) )
354  {
355  QgsDebugMsg( "Incorrect root tag: " + docElem.tagName() );
356  return colorMap;
357  }
358 
359  // load color ramp from first linearGradient node
360  QDomElement rampsElement = docElem.firstChildElement( QStringLiteral( "linearGradient" ) );
361  if ( rampsElement.isNull() )
362  {
363  const QDomNodeList nodeList = docElem.elementsByTagName( QStringLiteral( "linearGradient" ) );
364  if ( ! nodeList.isEmpty() )
365  rampsElement = nodeList.at( 0 ).toElement();
366  }
367  if ( rampsElement.isNull() )
368  {
369  QgsDebugMsg( QStringLiteral( "linearGradient tag missing" ) );
370  return colorMap;
371  }
372 
373  // loop for all stop tags
374  QDomElement e = rampsElement.firstChildElement();
375 
376  while ( !e.isNull() )
377  {
378  if ( e.tagName() == QLatin1String( "stop" ) )
379  {
380  //todo integrate this into symbollayerutils, keep here for now...
381  double offset;
382  QString offsetStr = e.attribute( QStringLiteral( "offset" ) ); // offset="50.00%" | offset="0.5"
383  const QString colorStr = e.attribute( QStringLiteral( "stop-color" ), QString() ); // stop-color="rgb(222,235,247)"
384  const QString opacityStr = e.attribute( QStringLiteral( "stop-opacity" ), QStringLiteral( "1.0" ) ); // stop-opacity="1.0000"
385  if ( offsetStr.endsWith( '%' ) )
386  offset = offsetStr.remove( offsetStr.size() - 1, 1 ).toDouble() / 100.0;
387  else
388  offset = offsetStr.toDouble();
389 
390  QColor color;
391  if ( colorStr.isEmpty() )
392  {
393  // SVG spec says that stops without color default to black!
394  color = QColor( 0, 0, 0 );
395  }
396  else
397  {
398  color = QgsSymbolLayerUtils::parseColor( colorStr );
399  }
400 
401  if ( color.isValid() )
402  {
403  const int alpha = opacityStr.toDouble() * 255; // test
404  color.setAlpha( alpha );
405  if ( colorMap.contains( offset ) )
406  colorMap[offset].second = color;
407  else
408  colorMap[offset] = qMakePair( color, color );
409  }
410  else
411  {
412  QgsDebugMsg( QStringLiteral( "at offset=%1 invalid color \"%2\"" ).arg( offset ).arg( colorStr ) );
413  }
414  }
415  else
416  {
417  QgsDebugMsg( "unknown tag: " + e.tagName() );
418  }
419 
420  e = e.nextSiblingElement();
421  }
422 
423  return colorMap;
424 }
425 
427 {
428  return ( mRootItems.isEmpty() );
429 }
430 
431 
433 {
434  const QgsSettings settings;
435  *sDefaultArchiveName() = settings.value( QStringLiteral( "CptCity/archiveName" ), DEFAULT_CPTCITY_ARCHIVE ).toString();
436  if ( sArchiveRegistry()->contains( *sDefaultArchiveName() ) )
437  return sArchiveRegistry()->value( *sDefaultArchiveName() );
438  else
439  return nullptr;
440 }
441 
442 void QgsCptCityArchive::initArchive( const QString &archiveName, const QString &archiveBaseDir )
443 {
444  QgsDebugMsgLevel( "archiveName = " + archiveName + " archiveBaseDir = " + archiveBaseDir, 2 );
445  QgsCptCityArchive *archive = new QgsCptCityArchive( archiveName, archiveBaseDir );
446  if ( sArchiveRegistry()->contains( archiveName ) )
447  delete ( *sArchiveRegistry() )[ archiveName ];
448  ( *sArchiveRegistry() )[ archiveName ] = archive;
449 }
450 
452 {
453  const QgsSettings settings;
454  // use CptCity/baseDir setting if set, default is user dir
455  const QString baseDir = settings.value( QStringLiteral( "CptCity/baseDir" ),
456  QString( QgsApplication::pkgDataPath() + "/resources" ) ).toString();
457  // sub-dir defaults to
458  const QString defArchiveName = settings.value( QStringLiteral( "CptCity/archiveName" ), DEFAULT_CPTCITY_ARCHIVE ).toString();
459 
460  if ( ! sArchiveRegistry()->contains( defArchiveName ) )
461  initArchive( defArchiveName, baseDir + '/' + defArchiveName );
462 }
463 
465 {
466  QgsStringMap archivesMap;
467  QString baseDir, defArchiveName;
468  const QgsSettings settings;
469 
470  // use CptCity/baseDir setting if set, default is user dir
471  baseDir = settings.value( QStringLiteral( "CptCity/baseDir" ),
472  QString( QgsApplication::pkgDataPath() + "/resources" ) ).toString();
473  // sub-dir defaults to
474  defArchiveName = settings.value( QStringLiteral( "CptCity/archiveName" ), DEFAULT_CPTCITY_ARCHIVE ).toString();
475 
476  QgsDebugMsgLevel( "baseDir= " + baseDir + " defArchiveName= " + defArchiveName, 2 );
477  if ( loadAll )
478  {
479  const QDir dir( baseDir );
480  const QStringList fileList = dir.entryList( QStringList() << QStringLiteral( "cpt-city*" ), QDir::Dirs );
481  for ( const QString &entry : fileList )
482  {
483  if ( QFile::exists( baseDir + '/' + entry + "/VERSION.xml" ) )
484  archivesMap[ entry ] = baseDir + '/' + entry;
485  }
486  }
487  else
488  {
489  archivesMap[ defArchiveName ] = baseDir + '/' + defArchiveName;
490  }
491 
492  for ( QgsStringMap::iterator it = archivesMap.begin();
493  it != archivesMap.end(); ++it )
494  {
495  if ( QDir( it.value() ).exists() )
496  QgsCptCityArchive::initArchive( it.key(), it.value() );
497  else
498  {
499  QgsDebugMsg( QStringLiteral( "not loading archive [%1] because dir %2 does not exist " ).arg( it.key(), it.value() ) );
500  }
501  }
502  *sDefaultArchiveName() = defArchiveName;
503 }
504 
506 {
507  qDeleteAll( *sArchiveRegistry() );
508  sArchiveRegistry()->clear();
509 }
510 
511 
512 // --------
513 
515  const QString &name, const QString &path )
516 // Do not pass parent to QObject, Qt would delete this when parent is deleted
517  : mType( type )
518  , mParent( parent )
519  , mPopulated( false )
520  , mName( name )
521  , mPath( path )
522  , mValid( true )
523 {
524 }
525 
526 QVector<QgsCptCityDataItem *> QgsCptCityDataItem::createChildren()
527 {
528  QVector<QgsCptCityDataItem *> children;
529  return children;
530 }
531 
533 {
534  if ( mPopulated )
535  return;
536 
537  QgsDebugMsgLevel( "mPath = " + mPath, 2 );
538 
539  QApplication::setOverrideCursor( Qt::WaitCursor );
540 
541  const QVector<QgsCptCityDataItem *> children = createChildren();
542  const auto constChildren = children;
543  for ( QgsCptCityDataItem *child : constChildren )
544  {
545  // initialization, do not refresh! That would result in infinite loop (beginInsertItems->rowCount->populate)
546  addChildItem( child );
547  }
548  mPopulated = true;
549 
550  QApplication::restoreOverrideCursor();
551 }
552 
554 {
555  // if ( !mPopulated )
556  // populate();
557  return mChildren.size();
558 }
559 
561 {
562  if ( !mPopulated )
563  return 0;
564 
565  int count = 0;
566  const auto constMChildren = mChildren;
567  for ( QgsCptCityDataItem *child : constMChildren )
568  {
569  if ( child )
570  count += child->leafCount();
571  }
572  return count;
573 }
574 
575 
577 {
578  return ( mPopulated ? !mChildren.isEmpty() : true );
579 }
580 
582 {
583  QgsDebugMsgLevel( QStringLiteral( "add child #%1 - %2 - %3" ).arg( mChildren.size() ).arg( child->mName ).arg( child->mType ), 2 );
584 
585  int i;
586  if ( type() == ColorRamp )
587  {
588  for ( i = 0; i < mChildren.size(); i++ )
589  {
590  // sort items by type, so directories are after data items
591  if ( mChildren.at( i )->mType == child->mType &&
592  mChildren.at( i )->mName.localeAwareCompare( child->mName ) >= 0 )
593  break;
594  }
595  }
596  else
597  {
598  for ( i = 0; i < mChildren.size(); i++ )
599  {
600  if ( mChildren.at( i )->mName.localeAwareCompare( child->mName ) >= 0 )
601  break;
602  }
603  }
604 
605  if ( refresh )
606  emit beginInsertItems( this, i, i );
607 
608  mChildren.insert( i, child );
609 
614 
615  if ( refresh )
616  emit endInsertItems();
617 }
619 {
620  // QgsDebugMsgLevel( "mName = " + child->mName, 2 );
621  const int i = mChildren.indexOf( child );
622  Q_ASSERT( i >= 0 );
623  emit beginRemoveItems( this, i, i );
624  mChildren.remove( i );
625  delete child;
626  emit endRemoveItems();
627 }
628 
630 {
631  // QgsDebugMsgLevel( "mName = " + child->mName, 2 );
632  const int i = mChildren.indexOf( child );
633  Q_ASSERT( i >= 0 );
634  emit beginRemoveItems( this, i, i );
635  mChildren.remove( i );
636  emit endRemoveItems();
641  child->setParent( nullptr );
642  return child;
643 }
644 
645 int QgsCptCityDataItem::findItem( QVector<QgsCptCityDataItem *> items, QgsCptCityDataItem *item )
646 {
647  for ( int i = 0; i < items.size(); i++ )
648  {
649  // QgsDebugMsgLevel( QString::number( i ) + " : " + items[i]->mPath + " x " + item->mPath, 2 );
650  if ( items[i]->equal( item ) )
651  return i;
652  }
653  return -1;
654 }
655 
657 {
658  QgsDebugMsgLevel( "mPath = " + mPath, 2 );
659 
660  QApplication::setOverrideCursor( Qt::WaitCursor );
661 
662  const QVector<QgsCptCityDataItem *> items = createChildren();
663 
664  // Remove no more present items
665  QVector<QgsCptCityDataItem *> remove;
666  const auto constMChildren = mChildren;
667  for ( QgsCptCityDataItem *child : constMChildren )
668  {
669  if ( findItem( items, child ) >= 0 )
670  continue;
671  remove.append( child );
672  }
673  const auto constRemove = remove;
674  for ( QgsCptCityDataItem *child : constRemove )
675  {
676  deleteChildItem( child );
677  }
678 
679  // Add new items
680  const auto constItems = items;
681  for ( QgsCptCityDataItem *item : constItems )
682  {
683  // Is it present in children?
684  if ( findItem( mChildren, item ) >= 0 )
685  {
686  delete item;
687  continue;
688  }
689  addChildItem( item, true );
690  }
691 
692  QApplication::restoreOverrideCursor();
693 }
694 
696 {
697  return ( metaObject()->className() == other->metaObject()->className() &&
698  mPath == other->path() );
699 }
700 
701 // ---------------------------------------------------------------------
702 
704  const QString &name, const QString &path, const QString &variantName, bool initialize )
705  : QgsCptCityDataItem( ColorRamp, parent, name, path )
706  , mInitialized( false )
707  , mRamp( path, variantName, false )
708 {
709  // QgsDebugMsgLevel( "name= " + name + " path= " + path, 2 );
710  mPopulated = true;
711  if ( initialize )
712  init();
713 }
714 
716  const QString &name, const QString &path, const QStringList &variantList, bool initialize )
717  : QgsCptCityDataItem( ColorRamp, parent, name, path )
718  , mInitialized( false )
719  , mRamp( path, variantList, QString(), false )
720 {
721  // QgsDebugMsgLevel( "name= " + name + " path= " + path, 2 );
722  mPopulated = true;
723  if ( initialize )
724  init();
725 }
726 
727 // TODO only load file when icon is requested...
729 {
730  if ( mInitialized )
731  return;
732  mInitialized = true;
733 
734  QgsDebugMsgLevel( "path = " + path(), 2 );
735 
736  // make preview from variant if exists
737  QStringList variantList = mRamp.variantList();
738  if ( mRamp.variantName().isNull() && ! variantList.isEmpty() )
739  mRamp.setVariantName( variantList[ variantList.count() / 2 ] );
740 
741  mRamp.loadFile();
742 
743  // is this item valid? this might fail when there are variants, check
744  if ( ! QFile::exists( mRamp.fileName() ) )
745  mValid = false;
746  else
747  mValid = true;
748 
749  // load file and set info
750  if ( mRamp.count() > 0 )
751  {
752  if ( variantList.isEmpty() )
753  {
754  int count = mRamp.count();
755  if ( mRamp.isDiscrete() )
756  count--;
757  mInfo = QString::number( count ) + ' ' + tr( "colors" ) + " - ";
758  if ( mRamp.isDiscrete() )
759  mInfo += tr( "discrete" );
760  else
761  {
762  if ( !mRamp.hasMultiStops() )
763  mInfo += tr( "continuous" );
764  else
765  mInfo += tr( "continuous (multi)" );
766  }
767  mShortInfo = QFileInfo( mName ).fileName();
768  }
769  else
770  {
771  mInfo = QString::number( variantList.count() ) + ' ' + tr( "variants" );
772  // mShortInfo = QFileInfo( mName ).fileName() + " (" + QString::number( variantList.count() ) + ')';
773  mShortInfo = QFileInfo( mName ).fileName();
774  }
775  }
776  else
777  {
778  mInfo.clear();
779  }
780 
781 }
782 
784 {
785  //QgsDebugMsg ( mPath + " x " + other->mPath );
786  if ( type() != other->type() )
787  {
788  return false;
789  }
790  //const QgsCptCityColorRampItem *o = qobject_cast<const QgsCptCityColorRampItem *> ( other );
791  const QgsCptCityColorRampItem *o = qobject_cast<const QgsCptCityColorRampItem *>( other );
792  return o &&
793  mPath == o->mPath &&
794  mName == o->mName &&
795  ramp().variantName() == o->ramp().variantName();
796 }
797 
799 {
800  return icon( QSize( 100, 15 ) );
801 }
802 
803 QIcon QgsCptCityColorRampItem::icon( QSize size )
804 {
805  const auto constMIcons = mIcons;
806  for ( const QIcon &icon : constMIcons )
807  {
808  if ( icon.availableSizes().contains( size ) )
809  return icon;
810  }
811 
812  QIcon icon;
813 
814  init();
815 
816  if ( mValid && mRamp.count() > 0 )
817  {
819  }
820  else
821  {
822  QPixmap blankPixmap( size );
823  blankPixmap.fill( Qt::white );
824  icon = QIcon( blankPixmap );
825  mInfo.clear();
826  }
827 
828  mIcons.append( icon );
829  return icon;
830 }
831 
832 // ---------------------------------------------------------------------
834  const QString &name, const QString &path )
835  : QgsCptCityDataItem( Collection, parent, name, path )
836  , mPopulatedRamps( false )
837 {
838 }
839 
841 {
842  qDeleteAll( mChildren );
843 }
844 
845 QVector< QgsCptCityDataItem * > QgsCptCityCollectionItem::childrenRamps( bool recursive )
846 {
847  QVector< QgsCptCityDataItem * > rampItems;
848  QVector< QgsCptCityDataItem * > deleteItems;
849 
850  populate();
851 
852  // recursively add children
853  const auto constChildren = children();
854  for ( QgsCptCityDataItem *childItem : constChildren )
855  {
856  QgsCptCityCollectionItem *collectionItem = qobject_cast<QgsCptCityCollectionItem *>( childItem );
857  QgsCptCityColorRampItem *rampItem = qobject_cast<QgsCptCityColorRampItem *>( childItem );
858  QgsDebugMsgLevel( QStringLiteral( "child path= %1 coll= %2 ramp = %3" ).arg( childItem->path() ).arg( nullptr != collectionItem ).arg( nullptr != rampItem ), 2 );
859  if ( collectionItem && recursive )
860  {
861  collectionItem->populate();
862  rampItems << collectionItem->childrenRamps( true );
863  }
864  else if ( rampItem )
865  {
866  // init rampItem to get palette and icon, test if is valid after loading file
867  rampItem->init();
868  if ( rampItem->isValid() )
869  rampItems << rampItem;
870  else
871  deleteItems << rampItem;
872  }
873  else
874  {
875  QgsDebugMsg( "invalid item " + childItem->path() );
876  }
877  }
878 
879  // delete invalid items - this is not efficient, but should only happens once
880  const auto constDeleteItems = deleteItems;
881  for ( QgsCptCityDataItem *deleteItem : constDeleteItems )
882  {
883  QgsDebugMsg( QStringLiteral( "item %1 is invalid, will be deleted" ).arg( deleteItem->path() ) );
884  const int i = mChildren.indexOf( deleteItem );
885  if ( i != -1 )
886  mChildren.remove( i );
887  delete deleteItem;
888  }
889 
890  return rampItems;
891 }
892 
893 //-----------------------------------------------------------------------
895  const QString &name, const QString &path )
896  : QgsCptCityCollectionItem( parent, name, path )
897 {
898  mType = Directory;
899  mValid = QDir( QgsCptCityArchive::defaultBaseDir() + '/' + mPath ).exists();
900  if ( ! mValid )
901  {
902  QgsDebugMsg( "created invalid dir item, path = " + QgsCptCityArchive::defaultBaseDir()
903  + '/' + mPath );
904  }
905 
906  // parse DESC.xml to get mInfo
907  mInfo.clear();
908  const QString fileName = QgsCptCityArchive::defaultBaseDir() + '/' +
909  mPath + '/' + "DESC.xml";
910  const QgsStringMap descMap = QgsCptCityArchive::description( fileName );
911  if ( descMap.contains( QStringLiteral( "name" ) ) )
912  mInfo = descMap.value( QStringLiteral( "name" ) );
913 
914  // populate();
915 }
916 
917 QVector<QgsCptCityDataItem *> QgsCptCityDirectoryItem::createChildren()
918 {
919  if ( ! mValid )
920  return QVector<QgsCptCityDataItem *>();
921 
922  QVector<QgsCptCityDataItem *> children;
923 
924  // add children schemes
925  QMapIterator< QString, QStringList> it( rampsMap() );
926  while ( it.hasNext() )
927  {
928  it.next();
929  // QgsDebugMsgLevel( "schemeName = " + it.key(), 2 );
930  QgsCptCityDataItem *item =
931  new QgsCptCityColorRampItem( this, it.key(), it.key(), it.value() );
932  if ( item->isValid() )
933  children << item;
934  else
935  delete item;
936  }
937 
938  // add children dirs
939  const auto constDirEntries = dirEntries();
940  for ( const QString &childPath : constDirEntries )
941  {
942  QgsCptCityDataItem *childItem =
943  QgsCptCityDirectoryItem::dataItem( this, childPath, mPath + '/' + childPath );
944  if ( childItem )
945  children << childItem;
946  }
947 
948  QgsDebugMsgLevel( QStringLiteral( "name= %1 path= %2 found %3 children" ).arg( mName, mPath ).arg( children.count() ), 2 );
949 
950  return children;
951 }
952 
953 QMap< QString, QStringList > QgsCptCityDirectoryItem::rampsMap()
954 {
955  if ( ! mRampsMap.isEmpty() )
956  return mRampsMap;
957 
958  QString curName, prevName, curVariant, curSep, schemeName;
959  QStringList listVariant;
960  QStringList schemeNamesAll, schemeNames;
961  bool prevAdd, curAdd;
962 
963  const QDir dir( QgsCptCityArchive::defaultBaseDir() + '/' + mPath );
964  schemeNamesAll = dir.entryList( QStringList( QStringLiteral( "*.svg" ) ), QDir::Files, QDir::Name );
965 
966  // TODO detect if there are duplicate names with different variant counts, combine in 1
967  for ( int i = 0; i < schemeNamesAll.count(); i++ )
968  {
969  // schemeName = QFileInfo( schemeNamesAll[i] ).baseName();
970  schemeName = schemeNamesAll[i];
971  schemeName.chop( 4 );
972  // QgsDebugMsgLevel("scheme = "+schemeName, 2);
973  curName = schemeName;
974  curVariant.clear();
975 
976  // find if name ends with 1-3 digit number
977  // TODO need to detect if ends with b/c also
978  if ( schemeName.length() > 1 && schemeName.endsWith( 'a' ) && ! listVariant.isEmpty() &&
979  ( ( prevName + listVariant.last() + 'a' ) == curName ) )
980  {
981  curName = prevName;
982  curVariant = listVariant.last() + 'a';
983  }
984  else
985  {
986  const thread_local QRegularExpression rxVariant( "^(.*[^\\d])(\\d{1,3})$" );
987  const QRegularExpressionMatch match = rxVariant.match( schemeName );
988  if ( match.hasMatch() )
989  {
990  curName = match.captured( 1 );
991  curVariant = match.captured( 2 );
992  }
993  }
994 
995  curSep = curName.right( 1 );
996  if ( curSep == QLatin1String( "-" ) || curSep == QLatin1String( "_" ) )
997  {
998  curName.chop( 1 );
999  curVariant = curSep + curVariant;
1000  }
1001 
1002  if ( prevName.isEmpty() )
1003  prevName = curName;
1004 
1005  // add element, unless it is empty, or a variant of last element
1006  prevAdd = false;
1007  curAdd = false;
1008  if ( curName.isEmpty() )
1009  curName = QStringLiteral( "__empty__" );
1010  // if current is a variant of last, don't add previous and append current variant
1011  if ( curName == prevName )
1012  {
1013  // add current element if it is the last one in the archive
1014  if ( i == schemeNamesAll.count() - 1 )
1015  prevAdd = true;
1016  listVariant << curVariant;
1017  }
1018  else
1019  {
1020  if ( !prevName.isEmpty() )
1021  {
1022  prevAdd = true;
1023  }
1024  // add current element if it is the last one in the archive
1025  if ( i == schemeNamesAll.count() - 1 )
1026  curAdd = true;
1027  }
1028 
1029  // QgsDebugMsgLevel(QString("prevAdd=%1 curAdd=%2 prevName=%3 curName=%4 count=%5").arg(prevAdd).arg(curAdd).arg(prevName).arg(curName).arg(listVariant.count()), 2);
1030 
1031  if ( prevAdd )
1032  {
1033  // depending on number of variants, make one or more items
1034  if ( listVariant.isEmpty() )
1035  {
1036  // set num colors=-1 to parse file on request only
1037  // mSchemeNumColors[ prevName ] = -1;
1038  schemeNames << prevName;
1039  mRampsMap[ mPath + '/' + prevName ] = QStringList();
1040  }
1041  else if ( listVariant.count() <= 3 )
1042  {
1043  // for 1-2 items, create independent items
1044  for ( int j = 0; j < listVariant.count(); j++ )
1045  {
1046  // mSchemeNumColors[ prevName + listVariant[j] ] = -1;
1047  schemeNames << prevName + listVariant[j];
1048  mRampsMap[ mPath + '/' + prevName + listVariant[j] ] = QStringList();
1049  }
1050  }
1051  else
1052  {
1053  // mSchemeVariants[ path + '/' + prevName ] = listVariant;
1054  mRampsMap[ mPath + '/' + prevName ] = listVariant;
1055  schemeNames << prevName;
1056  }
1057  listVariant.clear();
1058  }
1059  if ( curAdd )
1060  {
1061  if ( !curVariant.isEmpty() )
1062  curName += curVariant;
1063  schemeNames << curName;
1064  mRampsMap[ mPath + '/' + curName ] = QStringList();
1065  }
1066  // save current to compare next
1067  if ( prevAdd || curAdd )
1068  {
1069  prevName = curName;
1070  if ( !curVariant.isEmpty() )
1071  listVariant << curVariant;
1072  }
1073 
1074  }
1075 #if 0
1076  //TODO what to do with other vars? e.g. schemeNames
1077  // add schemes to archive
1078  mSchemeMap[ path ] = schemeNames;
1079  schemeCount += schemeName.count();
1080  schemeNames.clear();
1081  listVariant.clear();
1082  prevName = "";
1083 #endif
1084  return mRampsMap;
1085 }
1086 
1088 {
1089  return QDir( QgsCptCityArchive::defaultBaseDir() +
1090  '/' + mPath ).entryList( QDir::Dirs | QDir::NoDotAndDotDot, QDir::Name );
1091 }
1092 
1094 {
1095  //QgsDebugMsg ( mPath + " x " + other->mPath );
1096  if ( type() != other->type() )
1097  {
1098  return false;
1099  }
1100  return ( path() == other->path() );
1101 }
1102 
1104  const QString &name, const QString &path )
1105 {
1106  QgsDebugMsgLevel( "name= " + name + " path= " + path, 2 );
1107 
1108  // first create item with constructor
1110  if ( dirItem && ! dirItem->isValid() )
1111  {
1112  delete dirItem;
1113  return nullptr;
1114  }
1115  if ( ! dirItem )
1116  return nullptr;
1117 
1118  // fetch sub-dirs and ramps to know what to do with this item
1119  const QStringList dirEntries = dirItem->dirEntries();
1120  QMap< QString, QStringList > rampsMap = dirItem->rampsMap();
1121 
1122  QgsDebugMsgLevel( QStringLiteral( "item has %1 dirs and %2 ramps" ).arg( dirEntries.count() ).arg( rampsMap.count() ), 2 );
1123 
1124  // return item if has at least one subdir
1125  if ( !dirEntries.isEmpty() )
1126  return dirItem;
1127 
1128  // if 0 ramps, delete item
1129  if ( rampsMap.isEmpty() )
1130  {
1131  delete dirItem;
1132  return nullptr;
1133  }
1134  // if 1 ramp, return this child's item
1135  // so we don't have a directory with just 1 item (with many variants possibly)
1136  else if ( rampsMap.count() == 1 )
1137  {
1138  delete dirItem;
1139  QgsCptCityColorRampItem *rampItem =
1140  new QgsCptCityColorRampItem( parent, rampsMap.begin().key(),
1141  rampsMap.begin().key(), rampsMap.begin().value() );
1142  if ( ! rampItem->isValid() )
1143  {
1144  delete rampItem;
1145  return nullptr;
1146  }
1147  return rampItem;
1148  }
1149  return dirItem;
1150 }
1151 
1152 
1153 //-----------------------------------------------------------------------
1155  const QString &name, const QString &path )
1156  : QgsCptCityCollectionItem( parent, name, path )
1157 {
1158  mType = Selection;
1159  mValid = ! path.isNull();
1160  if ( mValid )
1161  parseXml();
1162 }
1163 
1164 QVector<QgsCptCityDataItem *> QgsCptCitySelectionItem::createChildren()
1165 {
1166  if ( ! mValid )
1167  return QVector<QgsCptCityDataItem *>();
1168 
1169  QgsCptCityDataItem *item = nullptr;
1170  QVector<QgsCptCityDataItem *> children;
1171 
1172  QgsDebugMsgLevel( "name= " + mName + " path= " + mPath, 2 );
1173 
1174  // add children archives
1175  for ( QString childPath : std::as_const( mSelectionsList ) )
1176  {
1177  QgsDebugMsgLevel( "childPath = " + childPath + " name= " + QFileInfo( childPath ).baseName(), 2 );
1178  if ( childPath.endsWith( '/' ) )
1179  {
1180  childPath.chop( 1 );
1181  QgsCptCityDataItem *childItem =
1182  QgsCptCityDirectoryItem::dataItem( this, childPath, childPath );
1183  if ( childItem )
1184  {
1185  if ( childItem->isValid() )
1186  children << childItem;
1187  else
1188  delete childItem;
1189  }
1190  }
1191  else
1192  {
1193  const QString fileName = QgsCptCityColorRamp::fileNameForVariant( childPath, QString() );
1194  if ( !QFile::exists( fileName ) )
1195  {
1196  continue;
1197  }
1198 
1199  item = new QgsCptCityColorRampItem( this, childPath, childPath, QString(), true );
1200  if ( item->isValid() )
1201  children << item;
1202  else
1203  delete item;
1204  }
1205  }
1206 
1207  QgsDebugMsgLevel( QStringLiteral( "path= %1 inserted %2 children" ).arg( mPath ).arg( children.count() ), 2 );
1208 
1209  return children;
1210 }
1211 
1213 {
1214  const QString filename = QgsCptCityArchive::defaultBaseDir() + '/' + mPath;
1215 
1216  QgsDebugMsgLevel( "reading file " + filename, 2 );
1217 
1218  QFile f( filename );
1219  if ( ! f.open( QFile::ReadOnly ) )
1220  {
1221  QgsDebugMsg( filename + " does not exist" );
1222  return;
1223  }
1224 
1225  // parse the document
1226  QString errMsg;
1227  QDomDocument doc( QStringLiteral( "selection" ) );
1228  if ( !doc.setContent( &f, &errMsg ) )
1229  {
1230  f.close();
1231  QgsDebugMsg( "Couldn't parse file " + filename + " : " + errMsg );
1232  return;
1233  }
1234  f.close();
1235 
1236  // read description
1237  const QDomElement docElem = doc.documentElement();
1238  if ( docElem.tagName() != QLatin1String( "selection" ) )
1239  {
1240  QgsDebugMsg( "Incorrect root tag: " + docElem.tagName() );
1241  return;
1242  }
1243  QDomElement e = docElem.firstChildElement( QStringLiteral( "name" ) );
1244  if ( ! e.isNull() && ! e.text().isNull() )
1245  mName = e.text();
1246  mInfo = docElem.firstChildElement( QStringLiteral( "synopsis" ) ).text().simplified();
1247 
1248  // get archives
1249  const QDomElement collectsElem = docElem.firstChildElement( QStringLiteral( "seealsocollects" ) );
1250  e = collectsElem.firstChildElement( QStringLiteral( "collect" ) );
1251  while ( ! e.isNull() )
1252  {
1253  if ( ! e.attribute( QStringLiteral( "dir" ) ).isNull() )
1254  {
1255  // TODO parse description and use that, instead of default archive name
1256  const QString dir = e.attribute( QStringLiteral( "dir" ) ) + '/';
1257  if ( QFile::exists( QgsCptCityArchive::defaultBaseDir() + '/' + dir ) )
1258  {
1259  mSelectionsList << dir;
1260  }
1261  }
1262  e = e.nextSiblingElement();
1263  }
1264  // get individual gradients
1265  const QDomElement gradientsElem = docElem.firstChildElement( QStringLiteral( "gradients" ) );
1266  e = gradientsElem.firstChildElement( QStringLiteral( "gradient" ) );
1267  while ( ! e.isNull() )
1268  {
1269  if ( ! e.attribute( QStringLiteral( "dir" ) ).isNull() )
1270  {
1271  // QgsDebugMsgLevel( "add " + e.attribute( "dir" ) + '/' + e.attribute( "file" ) + " to " + selname, 2 );
1272  // TODO parse description and save elsewhere
1273  const QString dir = e.attribute( QStringLiteral( "dir" ) );
1274  if ( QFile::exists( QgsCptCityArchive::defaultBaseDir() + '/' + dir ) )
1275  {
1276  mSelectionsList << dir + '/' + e.attribute( QStringLiteral( "file" ) );
1277  }
1278  }
1279  e = e.nextSiblingElement();
1280  }
1281 }
1282 
1284 {
1285  //QgsDebugMsgLevel( mPath + " x " + other->mPath, 2 );
1286  if ( type() != other->type() )
1287  {
1288  return false;
1289  }
1290  return ( path() == other->path() );
1291 }
1292 
1293 //-----------------------------------------------------------------------
1295  const QString &name, const QVector<QgsCptCityDataItem *> &items )
1296  : QgsCptCityCollectionItem( parent, name, QString() )
1297  , mItems( items )
1298 {
1299  mType = AllRamps;
1300  mValid = true;
1301  // populate();
1302 }
1303 
1304 QVector<QgsCptCityDataItem *> QgsCptCityAllRampsItem::createChildren()
1305 {
1306  if ( ! mValid )
1307  return QVector<QgsCptCityDataItem *>();
1308 
1309  QVector<QgsCptCityDataItem *> children;
1310 
1311  // add children ramps of each item
1312  const auto constMItems = mItems;
1313  for ( QgsCptCityDataItem *item : constMItems )
1314  {
1315  QgsCptCityCollectionItem *colItem = qobject_cast< QgsCptCityCollectionItem * >( item );
1316  if ( colItem )
1317  children += colItem->childrenRamps( true );
1318  }
1319 
1320  return children;
1321 }
1322 
1323 //-----------------------------------------------------------------------
1324 
1326  QgsCptCityArchive *archive, ViewType viewType )
1327  : QAbstractItemModel( parent )
1328  , mArchive( archive )
1329  , mViewType( viewType )
1330 {
1331  Q_ASSERT( mArchive );
1332  QgsDebugMsgLevel( QLatin1String( "archiveName = " ) + archive->archiveName() + " viewType=" + QString::number( static_cast< int >( viewType ) ), 2 );
1333  // keep iconsize for now, but not effectively used
1334  mIconSize = QSize( 100, 15 );
1335  addRootItems();
1336 }
1337 
1339 {
1340  removeRootItems();
1341 }
1342 
1344 {
1345  if ( mViewType == Authors )
1346  {
1348  }
1349  else if ( mViewType == Selections )
1350  {
1352  }
1353  QgsDebugMsgLevel( QStringLiteral( "added %1 root items" ).arg( mRootItems.size() ), 2 );
1354 }
1355 
1357 {
1358  mRootItems.clear();
1359 }
1360 
1361 Qt::ItemFlags QgsCptCityBrowserModel::flags( const QModelIndex &index ) const
1362 {
1363  if ( !index.isValid() )
1364  return Qt::ItemFlags();
1365 
1366  Qt::ItemFlags flags = Qt::ItemIsEnabled | Qt::ItemIsSelectable;
1367 
1368  return flags;
1369 }
1370 
1371 QVariant QgsCptCityBrowserModel::data( const QModelIndex &index, int role ) const
1372 {
1373  if ( !index.isValid() )
1374  return QVariant();
1375 
1376  QgsCptCityDataItem *item = dataItem( index );
1377 
1378  if ( !item )
1379  {
1380  return QVariant();
1381  }
1382  else if ( role == Qt::DisplayRole )
1383  {
1384  if ( index.column() == 0 )
1385  return item->name();
1386  if ( index.column() == 1 )
1387  {
1388  return item->info();
1389  }
1390  }
1391  else if ( role == Qt::ToolTipRole )
1392  {
1393  if ( item->type() == QgsCptCityDataItem::ColorRamp &&
1394  mViewType == List )
1395  return QString( item->path() + '\n' + item->info() );
1396  return item->toolTip();
1397  }
1398  else if ( role == Qt::DecorationRole && index.column() == 1 &&
1399  item->type() == QgsCptCityDataItem::ColorRamp )
1400  {
1401  // keep iconsize for now, but not effectively used
1402  return item->icon( mIconSize );
1403  }
1404  else if ( role == Qt::FontRole &&
1405  qobject_cast< QgsCptCityCollectionItem * >( item ) )
1406  {
1407  // collectionitems are larger and bold
1408  QFont font;
1409  font.setPointSize( 11 ); //FIXME why is the font so small?
1410  font.setBold( true );
1411  return font;
1412  }
1413  else
1414  {
1415  // unsupported role
1416  return QVariant();
1417  }
1418  return QVariant();
1419 }
1420 
1421 QVariant QgsCptCityBrowserModel::headerData( int section, Qt::Orientation orientation, int role ) const
1422 {
1423  Q_UNUSED( section )
1424  if ( orientation == Qt::Horizontal && role == Qt::DisplayRole )
1425  {
1426  if ( section == 0 )
1427  return QVariant( tr( "Name" ) );
1428  else if ( section == 1 )
1429  return QVariant( tr( "Info" ) );
1430  }
1431  return QVariant();
1432 }
1433 
1434 int QgsCptCityBrowserModel::rowCount( const QModelIndex &parent ) const
1435 {
1436  //qDebug("rowCount: idx: (valid %d) %d %d", parent.isValid(), parent.row(), parent.column());
1437 
1438  if ( !parent.isValid() )
1439  {
1440  // root item: its children are top level items
1441  return mRootItems.count(); // mRoot
1442  }
1443  else
1444  {
1445  // ordinary item: number of its children
1446  QgsCptCityDataItem *item = dataItem( parent );
1447  return item ? item->rowCount() : 0;
1448  }
1449 }
1450 
1451 bool QgsCptCityBrowserModel::hasChildren( const QModelIndex &parent ) const
1452 {
1453  if ( !parent.isValid() )
1454  return true; // root item: its children are top level items
1455 
1456  QgsCptCityDataItem *item = dataItem( parent );
1457 
1458  return item && item->hasChildren();
1459 }
1460 
1461 int QgsCptCityBrowserModel::columnCount( const QModelIndex &parent ) const
1462 {
1463  Q_UNUSED( parent )
1464  return 2;
1465 }
1466 
1467 QModelIndex QgsCptCityBrowserModel::findPath( const QString &path )
1468 {
1469  QModelIndex rootIndex; // starting from root
1470  bool foundParent = false, foundChild = true;
1471  QString itemPath;
1472 
1473  QgsDebugMsgLevel( "path = " + path, 2 );
1474 
1475  // special case if searching for first item "All Ramps", do not search into tree
1476  if ( path.isEmpty() )
1477  {
1478  for ( int i = 0; i < rowCount( rootIndex ); i++ )
1479  {
1480  QModelIndex idx = index( i, 0, rootIndex );
1481  QgsCptCityDataItem *item = dataItem( idx );
1482  if ( !item )
1483  return QModelIndex(); // an error occurred
1484 
1485  itemPath = item->path();
1486 
1487  if ( itemPath == path )
1488  {
1489  QgsDebugMsgLevel( "Arrived " + itemPath, 2 );
1490  return idx; // we have found the item we have been looking for
1491  }
1492  }
1493  }
1494 
1495  while ( foundChild )
1496  {
1497  foundChild = false; // assume that the next child item will not be found
1498 
1499  int i = 0;
1500  // if root skip first item "All Ramps"
1501  if ( itemPath.isEmpty() )
1502  i = 1;
1503  for ( ; i < rowCount( rootIndex ); i++ )
1504  {
1505  QModelIndex idx = index( i, 0, rootIndex );
1506  QgsCptCityDataItem *item = dataItem( idx );
1507  if ( !item )
1508  return QModelIndex(); // an error occurred
1509 
1510  itemPath = item->path();
1511 
1512  if ( itemPath == path )
1513  {
1514  QgsDebugMsgLevel( "Arrived " + itemPath, 2 );
1515  return idx; // we have found the item we have been looking for
1516  }
1517 
1518  if ( ! itemPath.endsWith( '/' ) )
1519  itemPath += '/';
1520 
1521  foundParent = false;
1522 
1523  // QgsDebugMsgLevel( "path= " + path + " itemPath= " + itemPath, 2 );
1524 
1525  // if we are using a selection collection, search for target in the mapping in this group
1526  if ( item->type() == QgsCptCityDataItem::Selection )
1527  {
1528  const QgsCptCitySelectionItem *selItem = qobject_cast<const QgsCptCitySelectionItem *>( item );
1529  if ( selItem )
1530  {
1531  const auto constSelectionsList = selItem->selectionsList();
1532  for ( QString childPath : constSelectionsList )
1533  {
1534  if ( childPath.endsWith( '/' ) )
1535  childPath.chop( 1 );
1536  // QgsDebugMsgLevel( "childPath= " + childPath, 2 );
1537  if ( path.startsWith( childPath ) )
1538  {
1539  foundParent = true;
1540  break;
1541  }
1542  }
1543  }
1544  }
1545  // search for target in parent directory
1546  else if ( path.startsWith( itemPath ) )
1547  {
1548  foundParent = true;
1549  }
1550 
1551  if ( foundParent )
1552  {
1553  QgsDebugMsgLevel( "found parent " + path, 2 );
1554  // we have found a preceding item: stop searching on this level and go deeper
1555  foundChild = true;
1556  rootIndex = idx;
1557  if ( canFetchMore( rootIndex ) )
1558  fetchMore( rootIndex );
1559  break;
1560  }
1561  }
1562  }
1563 
1564  return QModelIndex(); // not found
1565 }
1566 
1568 {
1569  beginResetModel();
1570  removeRootItems();
1571  addRootItems();
1572  endResetModel();
1573 }
1574 
1575 /* Refresh dir path */
1576 void QgsCptCityBrowserModel::refresh( const QString &path )
1577 {
1578  const QModelIndex idx = findPath( path );
1579  if ( idx.isValid() )
1580  {
1581  QgsCptCityDataItem *item = dataItem( idx );
1582  if ( item )
1583  item->refresh();
1584  }
1585 }
1586 
1587 QModelIndex QgsCptCityBrowserModel::index( int row, int column, const QModelIndex &parent ) const
1588 {
1590  const QVector<QgsCptCityDataItem *> &items = p ? p->children() : mRootItems;
1591  QgsCptCityDataItem *item = items.value( row, nullptr );
1592  return item ? createIndex( row, column, item ) : QModelIndex();
1593 }
1594 
1595 QModelIndex QgsCptCityBrowserModel::parent( const QModelIndex &index ) const
1596 {
1597  QgsCptCityDataItem *item = dataItem( index );
1598  if ( !item )
1599  return QModelIndex();
1600 
1601  return findItem( item->parent() );
1602 }
1603 
1605 {
1606  const QVector<QgsCptCityDataItem *> &items = parent ? parent->children() : mRootItems;
1607 
1608  for ( int i = 0; i < items.size(); i++ )
1609  {
1610  if ( items[i] == item )
1611  return createIndex( i, 0, item );
1612 
1613  QModelIndex childIndex = findItem( item, items[i] );
1614  if ( childIndex.isValid() )
1615  return childIndex;
1616  }
1617 
1618  return QModelIndex();
1619 }
1620 
1621 /* Refresh item */
1622 void QgsCptCityBrowserModel::refresh( const QModelIndex &index )
1623 {
1624  QgsCptCityDataItem *item = dataItem( index );
1625  if ( !item )
1626  return;
1627 
1628  QgsDebugMsgLevel( "Refresh " + item->path(), 2 );
1629  item->refresh();
1630 }
1631 
1633 {
1634  QgsDebugMsgLevel( "parent mPath = " + parent->path(), 2 );
1635  const QModelIndex idx = findItem( parent );
1636  if ( !idx.isValid() )
1637  return;
1638  QgsDebugMsgLevel( QStringLiteral( "valid" ), 2 );
1639  beginInsertRows( idx, first, last );
1640  QgsDebugMsgLevel( QStringLiteral( "end" ), 2 );
1641 }
1643 {
1644  endInsertRows();
1645 }
1647 {
1648  QgsDebugMsgLevel( "parent mPath = " + parent->path(), 2 );
1649  const QModelIndex idx = findItem( parent );
1650  if ( !idx.isValid() )
1651  return;
1652  beginRemoveRows( idx, first, last );
1653 }
1655 {
1656  endRemoveRows();
1657 }
1659 {
1664 }
1665 
1666 bool QgsCptCityBrowserModel::canFetchMore( const QModelIndex &parent ) const
1667 {
1668  QgsCptCityDataItem *item = dataItem( parent );
1669  // fetch all items initially so we know which items have children
1670  // (nicer looking and less confusing)
1671 
1672  if ( ! item )
1673  return false;
1674 
1675  // except for "All Ramps" - this is populated when clicked on
1676  if ( item->type() == QgsCptCityDataItem::AllRamps )
1677  return false;
1678 
1679  item->populate();
1680 
1681  return ( ! item->isPopulated() );
1682 }
1683 
1684 void QgsCptCityBrowserModel::fetchMore( const QModelIndex &parent )
1685 {
1686  QgsCptCityDataItem *item = dataItem( parent );
1687  if ( item )
1688  {
1689  item->populate();
1690  QgsDebugMsgLevel( "path = " + item->path(), 2 );
1691  }
1692 }
1693 
1694 
1695 #if 0
1696 QStringList QgsCptCityBrowserModel::mimeTypes() const
1697 {
1698  QStringList types;
1699  // In theory the mime type convention is: application/x-vnd.<vendor>.<application>.<type>
1700  // but it seems a bit over formalized. Would be an application/x-qgis-uri better?
1701  types << "application/x-vnd.qgis.qgis.uri";
1702  return types;
1703 }
1704 
1705 QMimeData *QgsCptCityBrowserModel::mimeData( const QModelIndexList &indexes ) const
1706 {
1708  const auto constIndexes = indexes;
1709  for ( const QModelIndex &index : constIndexes )
1710  {
1711  if ( index.isValid() )
1712  {
1713  QgsCptCityDataItem *ptr = ( QgsCptCityDataItem * ) index.internalPointer();
1714  if ( ptr->type() != QgsCptCityDataItem::Layer ) continue;
1715  QgsLayerItem *layer = ( QgsLayerItem * ) ptr;
1716  lst.append( QgsMimeDataUtils::Uri( ayer ) );
1717  }
1718  }
1719  return QgsMimeDataUtils::encodeUriList( lst );
1720 }
1721 
1722 bool QgsCptCityBrowserModel::dropMimeData( const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent )
1723 {
1724  Q_UNUSED( row )
1725  Q_UNUSED( column )
1726 
1727  QgsCptCityDataItem *destItem = dataItem( parent );
1728  if ( !destItem )
1729  {
1730  QgsDebugMsg( QStringLiteral( "DROP PROBLEM!" ) );
1731  return false;
1732  }
1733 
1734  return destItem->handleDrop( data, action );
1735 }
1736 #endif
1737 
1739 {
1740  void *v = idx.internalPointer();
1741  QgsCptCityDataItem *d = reinterpret_cast<QgsCptCityDataItem *>( v );
1742  Q_ASSERT( !v || d );
1743  return d;
1744 }
QgsSymbolLayerUtils::parseColor
static QColor parseColor(const QString &colorStr, bool strictEval=false)
Attempts to parse a string as a color using a variety of common formats, including hex codes,...
Definition: qgssymbollayerutils.cpp:3828
QgsCptCityDataItem::populate
virtual void populate()
Definition: qgscptcityarchive.cpp:532
QgsCptCityDataItem::mInfo
QString mInfo
Definition: qgscptcityarchive.h:186
QgsCptCityDataItem::isValid
bool isValid()
Definition: qgscptcityarchive.h:176
QgsCptCityDataItem::rowCount
int rowCount()
Definition: qgscptcityarchive.cpp:553
QgsCptCityColorRampItem::mRamp
QgsCptCityColorRamp mRamp
Definition: qgscptcityarchive.h:230
QgsCptCityDataItem::path
QString path() const
Definition: qgscptcityarchive.h:167
QgsCptCityDirectoryItem::createChildren
QVector< QgsCptCityDataItem * > createChildren() override
Definition: qgscptcityarchive.cpp:917
QgsCptCityColorRampItem
Item that represents a layer that can be opened with one of the providers.
Definition: qgscptcityarchive.h:203
QgsCptCityDataItem::isPopulated
bool isPopulated()
Definition: qgscptcityarchive.h:130
QgsSettings::value
QVariant value(const QString &key, const QVariant &defaultValue=QVariant(), Section section=NoSection) const
Returns the value for setting key.
Definition: qgssettings.cpp:161
QgsCptCityDataItem::icon
virtual QIcon icon()
Definition: qgscptcityarchive.h:164
QgsCptCityArchive::findFileName
static QString findFileName(const QString &target, const QString &startDir, const QString &baseDir)
Definition: qgscptcityarchive.cpp:146
QgsDebugMsgLevel
#define QgsDebugMsgLevel(str, level)
Definition: qgslogger.h:39
QgsCptCityBrowserModel::hasChildren
bool hasChildren(const QModelIndex &parent=QModelIndex()) const override
Definition: qgscptcityarchive.cpp:1451
QgsCptCityColorRampItem::mIcons
QList< QIcon > mIcons
Definition: qgscptcityarchive.h:231
QgsCptCityBrowserModel::data
QVariant data(const QModelIndex &index, int role=Qt::DisplayRole) const override
Definition: qgscptcityarchive.cpp:1371
QgsCptCityDirectoryItem::QgsCptCityDirectoryItem
QgsCptCityDirectoryItem(QgsCptCityDataItem *parent, const QString &name, const QString &path)
Definition: qgscptcityarchive.cpp:894
QgsCptCityBrowserModel::canFetchMore
bool canFetchMore(const QModelIndex &parent) const override
Definition: qgscptcityarchive.cpp:1666
QgsCptCityBrowserModel::beginRemoveItems
void beginRemoveItems(QgsCptCityDataItem *parent, int first, int last)
Definition: qgscptcityarchive.cpp:1646
QgsCptCityBrowserModel::parent
QModelIndex parent(const QModelIndex &index) const override
Definition: qgscptcityarchive.cpp:1595
qgssymbollayerutils.h
CopyingInfoMap
QMap< QString, QMap< QString, QString > > CopyingInfoMap
Definition: qgscptcityarchive.cpp:39
QgsCptCityColorRampItem::mInitialized
bool mInitialized
Definition: qgscptcityarchive.h:229
QgsCptCityArchive::descFileName
QString descFileName(const QString &dirName) const
Definition: qgscptcityarchive.cpp:173
QgsCptCitySelectionItem
A selection: contains subdirectories and color ramps.
Definition: qgscptcityarchive.h:284
QgsCptCityDataItem::setParent
void setParent(QgsCptCityDataItem *parent)
Definition: qgscptcityarchive.h:162
ArchiveRegistry
QMap< QString, QgsCptCityArchive * > ArchiveRegistry
Definition: qgscptcityarchive.cpp:38
qgis.h
DEFAULT_CPTCITY_ARCHIVE
#define DEFAULT_CPTCITY_ARCHIVE
Definition: qgscptcityarchive.h:33
QgsCptCityArchive::defaultBaseDir
static QString defaultBaseDir()
Definition: qgscptcityarchive.cpp:131
QgsCptCityArchive::initArchives
static void initArchives(bool loadAll=false)
Definition: qgscptcityarchive.cpp:464
QgsCptCityArchive
Definition: qgscptcityarchive.h:39
QgsCptCitySelectionItem::createChildren
QVector< QgsCptCityDataItem * > createChildren() override
Definition: qgscptcityarchive.cpp:1164
QgsCptCityColorRampItem::init
void init()
Definition: qgscptcityarchive.cpp:728
QgsSettings
This class is a composition of two QSettings instances:
Definition: qgssettings.h:61
QgsCptCityArchive::defaultArchive
static QgsCptCityArchive * defaultArchive()
Definition: qgscptcityarchive.cpp:432
QgsCptCityDataItem::beginRemoveItems
void beginRemoveItems(QgsCptCityDataItem *parent, int first, int last)
QgsCptCityColorRamp::variantName
QString variantName() const
Definition: qgscolorrampimpl.h:763
QgsCptCityArchive::QgsCptCityArchive
QgsCptCityArchive(const QString &archiveName=DEFAULT_CPTCITY_ARCHIVE, const QString &baseDir=QString())
Definition: qgscptcityarchive.cpp:50
qgsmimedatautils.h
QgsCptCityColorRamp::variantList
QStringList variantList() const
Definition: qgscolorrampimpl.h:764
QgsCptCityBrowserModel::mIconSize
QSize mIconSize
Definition: qgscptcityarchive.h:403
QgsMimeDataUtils::UriList
QList< QgsMimeDataUtils::Uri > UriList
Definition: qgsmimedatautils.h:164
QgsDebugMsg
#define QgsDebugMsg(str)
Definition: qgslogger.h:38
QgsCptCityAllRampsItem::createChildren
QVector< QgsCptCityDataItem * > createChildren() override
Definition: qgscptcityarchive.cpp:1304
QgsCptCityBrowserModel::mRootItems
QVector< QgsCptCityDataItem * > mRootItems
Definition: qgscptcityarchive.h:400
QgsCptCityDirectoryItem::equal
bool equal(const QgsCptCityDataItem *other) override
Definition: qgscptcityarchive.cpp:1093
qgscptcityarchive.h
QgsCptCityDataItem::mValid
bool mValid
Definition: qgscptcityarchive.h:190
Q_GLOBAL_STATIC
Q_GLOBAL_STATIC(QReadWriteLock, sDefinitionCacheLock)
QgsCptCityBrowserModel::mViewType
ViewType mViewType
Definition: qgscptcityarchive.h:402
QgsCptCityDataItem::Selection
@ Selection
Definition: qgscptcityarchive.h:108
QgsCptCityArchive::~QgsCptCityArchive
~QgsCptCityArchive()
Definition: qgscptcityarchive.cpp:98
QgsCptCityDataItem::handleDrop
virtual bool handleDrop(const QMimeData *, Qt::DropAction)
Definition: qgscptcityarchive.h:151
QgsCptCityColorRampItem::equal
bool equal(const QgsCptCityDataItem *other) override
Definition: qgscptcityarchive.cpp:783
QgsCptCityDataItem::hasChildren
bool hasChildren()
Definition: qgscptcityarchive.cpp:576
QgsCptCityBrowserModel::refresh
void refresh(const QString &path)
Definition: qgscptcityarchive.cpp:1576
QgsCptCityDataItem::mName
QString mName
Definition: qgscptcityarchive.h:184
QgsCptCityColorRampItem::ramp
const QgsCptCityColorRamp & ramp() const
Definition: qgscptcityarchive.h:222
qgsapplication.h
QgsCptCityDirectoryItem::dataItem
static QgsCptCityDataItem * dataItem(QgsCptCityDataItem *parent, const QString &name, const QString &path)
Definition: qgscptcityarchive.cpp:1103
QgsCptCityAllRampsItem::QgsCptCityAllRampsItem
QgsCptCityAllRampsItem(QgsCptCityDataItem *parent, const QString &name, const QVector< QgsCptCityDataItem * > &items)
Definition: qgscptcityarchive.cpp:1294
QgsCptCityBrowserModel::endInsertItems
void endInsertItems()
Definition: qgscptcityarchive.cpp:1642
QgsCptCityArchive::rootItems
QVector< QgsCptCityDataItem * > rootItems() const
Definition: qgscptcityarchive.h:77
QgsCptCityCollectionItem::childrenRamps
QVector< QgsCptCityDataItem * > childrenRamps(bool recursive)
Definition: qgscptcityarchive.cpp:845
QgsCptCityBrowserModel::fetchMore
void fetchMore(const QModelIndex &parent) override
Definition: qgscptcityarchive.cpp:1684
QgsCptCityDataItem::leafCount
virtual int leafCount() const
Definition: qgscptcityarchive.cpp:560
QgsCptCityDataItem::mPopulated
bool mPopulated
Definition: qgscptcityarchive.h:183
QgsCptCityDataItem::name
QString name() const
Definition: qgscptcityarchive.h:166
QgsGradientColorRamp::count
int count() const override
Returns number of defined colors, or -1 if undefined.
Definition: qgscolorrampimpl.h:156
QgsCptCityCollectionItem
A Collection: logical collection of subcollections and color ramps.
Definition: qgscptcityarchive.h:239
QgsCptCityBrowserModel::flags
Qt::ItemFlags flags(const QModelIndex &index) const override
Definition: qgscptcityarchive.cpp:1361
QgsCptCityBrowserModel::removeRootItems
void removeRootItems()
Definition: qgscptcityarchive.cpp:1356
QgsCptCityBrowserModel::beginInsertItems
void beginInsertItems(QgsCptCityDataItem *parent, int first, int last)
Definition: qgscptcityarchive.cpp:1632
QgsCptCitySelectionItem::QgsCptCitySelectionItem
QgsCptCitySelectionItem(QgsCptCityDataItem *parent, const QString &name, const QString &path)
Definition: qgscptcityarchive.cpp:1154
QgsCptCityBrowserModel::columnCount
int columnCount(const QModelIndex &parent=QModelIndex()) const override
Definition: qgscptcityarchive.cpp:1461
QgsCptCityArchive::initDefaultArchive
static void initDefaultArchive()
Definition: qgscptcityarchive.cpp:451
QgsCptCityDataItem::createChildren
virtual QVector< QgsCptCityDataItem * > createChildren()
Definition: qgscptcityarchive.cpp:526
QgsCptCityDataItem::endRemoveItems
void endRemoveItems()
QgsCptCityBrowserModel::~QgsCptCityBrowserModel
~QgsCptCityBrowserModel() override
Definition: qgscptcityarchive.cpp:1338
QgsCptCityBrowserModel::QgsCptCityBrowserModel
QgsCptCityBrowserModel(QObject *parent=nullptr, QgsCptCityArchive *archive=QgsCptCityArchive::defaultArchive(), ViewType Type=Authors)
Definition: qgscptcityarchive.cpp:1325
QgsCptCityDataItem::QgsCptCityDataItem
QgsCptCityDataItem(QgsCptCityDataItem::Type type, QgsCptCityDataItem *parent, const QString &name, const QString &path)
Definition: qgscptcityarchive.cpp:514
QgsCptCityBrowserModel::reload
void reload()
Definition: qgscptcityarchive.cpp:1567
QgsCptCityColorRamp::fileNameForVariant
static QString fileNameForVariant(const QString &schema, const QString &variant)
Returns the source file name for a CPT schema and variant.
Definition: qgscolorrampimpl.cpp:1019
QgsCptCityDataItem::mChildren
QVector< QgsCptCityDataItem * > mChildren
Definition: qgscptcityarchive.h:182
QgsCptCityDataItem::refresh
virtual void refresh()
Definition: qgscptcityarchive.cpp:656
QgsCptCityDataItem
Base class for all items in the model.
Definition: qgscptcityarchive.h:99
QgsCptCityBrowserModel::findPath
QModelIndex findPath(const QString &path)
Returns index of a path.
Definition: qgscptcityarchive.cpp:1467
QgsCptCityAllRampsItem::mItems
QVector< QgsCptCityDataItem * > mItems
Definition: qgscptcityarchive.h:315
QgsCptCityDataItem::ColorRamp
@ ColorRamp
Definition: qgscptcityarchive.h:105
QgsCptCityDataItem::beginInsertItems
void beginInsertItems(QgsCptCityDataItem *parent, int first, int last)
QgsCptCityArchive::copyingInfo
static QMap< QString, QString > copyingInfo(const QString &fileName)
Definition: qgscptcityarchive.cpp:179
QgsCptCityDirectoryItem::rampsMap
QMap< QString, QStringList > rampsMap()
Definition: qgscptcityarchive.cpp:953
QgsApplication::pkgDataPath
static QString pkgDataPath()
Returns the common root path of all application data directories.
Definition: qgsapplication.cpp:645
QgsCptCityBrowserModel::Authors
@ Authors
Definition: qgscptcityarchive.h:330
QgsCptCityArchive::clearArchives
static void clearArchives()
Definition: qgscptcityarchive.cpp:505
QgsCptCityDataItem::findItem
static int findItem(QVector< QgsCptCityDataItem * > items, QgsCptCityDataItem *item)
Definition: qgscptcityarchive.cpp:645
QgsMimeDataUtils::Uri
Definition: qgsmimedatautils.h:40
QgsCptCityBrowserModel::addRootItems
void addRootItems()
Definition: qgscptcityarchive.cpp:1343
QgsCptCityArchive::baseDir
QString baseDir() const
Definition: qgscptcityarchive.cpp:110
QgsCptCityArchive::archiveName
QString archiveName() const
Definition: qgscptcityarchive.h:68
QgsCptCityArchive::isEmpty
bool isEmpty()
Definition: qgscptcityarchive.cpp:426
QgsCptCityDataItem::addChildItem
virtual void addChildItem(QgsCptCityDataItem *child, bool refresh=false)
Definition: qgscptcityarchive.cpp:581
QgsCptCityBrowserModel::findItem
QModelIndex findItem(QgsCptCityDataItem *item, QgsCptCityDataItem *parent=nullptr) const
Definition: qgscptcityarchive.cpp:1604
QgsCptCityColorRamp::setVariantName
void setVariantName(const QString &variantName)
Definition: qgscolorrampimpl.h:768
QgsStringMap
QMap< QString, QString > QgsStringMap
Definition: qgis.h:2781
QgsCptCityBrowserModel::rowCount
int rowCount(const QModelIndex &parent=QModelIndex()) const override
Definition: qgscptcityarchive.cpp:1434
QgsMimeDataUtils::encodeUriList
static QMimeData * encodeUriList(const UriList &layers)
Encodes a URI list to a new QMimeData object.
Definition: qgsmimedatautils.cpp:220
QgsCptCityDataItem::parent
QgsCptCityDataItem * parent() const
Definition: qgscptcityarchive.h:161
QgsCptCityDirectoryItem
A directory: contains subdirectories and color ramps.
Definition: qgscptcityarchive.h:259
QgsCptCitySelectionItem::parseXml
void parseXml()
Definition: qgscptcityarchive.cpp:1212
QgsCptCityArchive::initArchive
static void initArchive(const QString &archiveName, const QString &archiveBaseDir)
Definition: qgscptcityarchive.cpp:442
QgsCptCityBrowserModel::endRemoveItems
void endRemoveItems()
Definition: qgscptcityarchive.cpp:1654
QgsCptCityBrowserModel::headerData
QVariant headerData(int section, Qt::Orientation orientation, int role=Qt::DisplayRole) const override
Definition: qgscptcityarchive.cpp:1421
QgsCptCityBrowserModel::connectItem
void connectItem(QgsCptCityDataItem *item)
Definition: qgscptcityarchive.cpp:1658
QgsCptCityColorRampItem::icon
QIcon icon() override
Definition: qgscptcityarchive.cpp:798
QgsCptCityDataItem::deleteChildItem
virtual void deleteChildItem(QgsCptCityDataItem *child)
Definition: qgscptcityarchive.cpp:618
qgssettings.h
QgsCptCityDataItem::Directory
@ Directory
Definition: qgscptcityarchive.h:107
QgsCptCityColorRamp::hasMultiStops
bool hasMultiStops() const
Definition: qgscolorrampimpl.h:774
QgsCptCityBrowserModel::Selections
@ Selections
Definition: qgscptcityarchive.h:331
QgsCptCityDataItem::removeChildItem
virtual QgsCptCityDataItem * removeChildItem(QgsCptCityDataItem *child)
Definition: qgscptcityarchive.cpp:629
QgsCptCityColorRampItem::QgsCptCityColorRampItem
QgsCptCityColorRampItem(QgsCptCityDataItem *parent, const QString &name, const QString &path, const QString &variantName=QString(), bool initialize=false)
Definition: qgscptcityarchive.cpp:703
QgsCptCityDataItem::endInsertItems
void endInsertItems()
QgsCptCityDirectoryItem::mRampsMap
QMap< QString, QStringList > mRampsMap
Definition: qgscptcityarchive.h:276
qgsdataprovider.h
QgsLayerItem
Item that represents a layer that can be opened with one of the providers.
Definition: qgslayeritem.h:29
QgsCptCityBrowserModel::dataItem
QgsCptCityDataItem * dataItem(const QModelIndex &idx) const
Returns a list of mime that can describe model indexes.
Definition: qgscptcityarchive.cpp:1738
QgsCptCityArchive::copyingFileName
QString copyingFileName(const QString &dirName) const
Definition: qgscptcityarchive.cpp:167
QgsCptCitySelectionItem::mSelectionsList
QStringList mSelectionsList
Definition: qgscptcityarchive.h:298
QgsCptCityDataItem::AllRamps
@ AllRamps
Definition: qgscptcityarchive.h:109
QgsCptCityAllRampsItem
An "All ramps item", which contains all items in a flat hierarchy.
Definition: qgscptcityarchive.h:305
QgsCptCityArchive::description
static QMap< QString, QString > description(const QString &fileName)
Definition: qgscptcityarchive.cpp:280
QgsCptCitySelectionItem::selectionsList
QStringList selectionsList() const
Definition: qgscptcityarchive.h:294
qgslogger.h
QgsCptCityBrowserModel::ViewType
ViewType
Definition: qgscptcityarchive.h:328
QgsCptCityDataItem::children
QVector< QgsCptCityDataItem * > children() const
Definition: qgscptcityarchive.h:163
QgsCptCityBrowserModel::List
@ List
Definition: qgscptcityarchive.h:332
QgsCptCityArchive::gradientColorMap
static QMap< double, QPair< QColor, QColor > > gradientColorMap(const QString &fileName)
Definition: qgscptcityarchive.cpp:329
QgsCptCitySelectionItem::equal
bool equal(const QgsCptCityDataItem *other) override
Definition: qgscptcityarchive.cpp:1283
QgsCptCityCollectionItem::~QgsCptCityCollectionItem
~QgsCptCityCollectionItem() override
Definition: qgscptcityarchive.cpp:840
QgsCptCityDataItem::type
Type type() const
Definition: qgscptcityarchive.h:160
QgsCptCityDataItem::toolTip
QString toolTip() const
Definition: qgscptcityarchive.h:174
QgsCptCityDirectoryItem::dirEntries
QStringList dirEntries() const
Definition: qgscptcityarchive.cpp:1087
QgsCptCityCollectionItem::QgsCptCityCollectionItem
QgsCptCityCollectionItem(QgsCptCityDataItem *parent, const QString &name, const QString &path)
Definition: qgscptcityarchive.cpp:833
QgsGradientColorRamp::isDiscrete
bool isDiscrete() const
Returns true if the gradient is using discrete interpolation, rather than smoothly interpolating betw...
Definition: qgscolorrampimpl.h:207
QgsCptCityDataItem::mPath
QString mPath
Definition: qgscptcityarchive.h:185
QgsCptCityDataItem::info
QString info() const
Definition: qgscptcityarchive.h:168
QgsCptCityDataItem::mShortInfo
QString mShortInfo
Definition: qgscptcityarchive.h:187
QgsCptCityDataItem::equal
virtual bool equal(const QgsCptCityDataItem *other)
Definition: qgscptcityarchive.cpp:695
QgsCptCityBrowserModel::index
QModelIndex index(int row, int column, const QModelIndex &parent=QModelIndex()) const override
Definition: qgscptcityarchive.cpp:1587
QgsCptCityColorRamp::loadFile
bool loadFile()
Definition: qgscolorrampimpl.cpp:1051
QgsSymbolLayerUtils::colorRampPreviewIcon
static QIcon colorRampPreviewIcon(QgsColorRamp *ramp, QSize size, int padding=0)
Returns an icon preview for a color ramp.
Definition: qgssymbollayerutils.cpp:1021
QgsCptCityDataItem::Type
Type
Definition: qgscptcityarchive.h:103
QgsCptCityDataItem::mType
Type mType
Definition: qgscptcityarchive.h:180
QgsCptCityBrowserModel::mArchive
QgsCptCityArchive * mArchive
Definition: qgscptcityarchive.h:401
QgsCptCityColorRamp::fileName
QString fileName() const
Definition: qgscolorrampimpl.cpp:1024
QgsCptCityArchive::selectionItems
QVector< QgsCptCityDataItem * > selectionItems() const
Definition: qgscptcityarchive.h:78