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