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