1
/***************************************************************************
2
qgsdelimitedtextprovider.cpp - Data provider for delimted text
5
copyright : (C) 2004 by Gary E.Sherman
6
email : sherman at mrcc.com
7
***************************************************************************/
9
/***************************************************************************
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. *
16
***************************************************************************/
17
/* $Id: qgsdelimitedtextprovider.cpp 6196 2006-12-06 20:42:12Z wonder $ */
19
#include "qgsdelimitedtextprovider.h"
25
#include <QDataStream>
26
#include <QTextStream>
27
#include <QStringList>
28
#include <QMessageBox>
33
#include <ogrsf_frmts.h>
35
#include "qgsdataprovider.h"
36
#include "qgsencodingfiledialog.h"
37
#include "qgsfeature.h"
41
#include "qgsmessageviewer.h"
44
#define QGISEXTERN extern "C" __declspec( dllexport )
46
#define QGISEXTERN extern "C"
50
static const QString TEXT_PROVIDER_KEY = "delimitedtext";
51
static const QString TEXT_PROVIDER_DESCRIPTION = "Delimited text data provider";
55
QgsDelimitedTextProvider::QgsDelimitedTextProvider(QString const &uri)
56
: QgsVectorDataProvider(uri),
57
mMinMaxCacheDirty(true),
58
mShowInvalidLines(true)
60
// Get the file name and mDelimiter out of the uri
61
mFileName = uri.left(uri.find("?"));
62
// split the string up on & to get the individual parameters
63
QStringList parameters = QStringList::split("&", uri.mid(uri.find("?")));
65
std::cerr << "Parameter count after split on &" << parameters.
68
// get the individual parameters and assign values
69
QStringList temp = parameters.grep("delimiter=");
70
mDelimiter = temp.size()? temp[0].mid(temp[0].find("=") + 1) : "";
71
temp = parameters.grep("xField=");
72
mXField = temp.size()? temp[0].mid(temp[0].find("=") + 1) : "";
73
temp = parameters.grep("yField=");
74
mYField = temp.size()? temp[0].mid(temp[0].find("=") + 1) : "";
75
// Decode the parts of the uri. Good if someone entered '=' as a delimiter, for instance.
76
mFileName = QUrl::fromPercentEncoding(mFileName.toUtf8());
77
mDelimiter = QUrl::fromPercentEncoding(mDelimiter.toUtf8());
78
mXField = QUrl::fromPercentEncoding(mXField.toUtf8());
79
mYField = QUrl::fromPercentEncoding(mYField.toUtf8());
81
std::cerr << "Data source uri is " << (const char *)uri.toLocal8Bit().data() << std::endl;
82
std::cerr << "Delimited text file is: " << (const char *)mFileName.toLocal8Bit().data() << std::endl;
83
std::cerr << "Delimiter is: " << (const char *)mDelimiter.toLocal8Bit().data() << std::endl;
84
std::cerr << "xField is: " << (const char *)mXField.toLocal8Bit().data() << std::endl;
85
std::cerr << "yField is: " << (const char *)mYField.toLocal8Bit().data() << std::endl;
88
// if delimiter contains some special characters, convert them
89
// (we no longer use delimiter as regexp as it introduces problems with special characters)
90
mDelimiter.replace("\\t", "\t"); // replace "\t" with a real tabulator
92
// Set the selection rectangle to null
93
mSelectionRectangle = 0;
94
// assume the layer is invalid until proven otherwise
96
if (!mFileName.isEmpty() && !mDelimiter.isEmpty() && !mXField.isEmpty() &&
99
// check to see that the file exists and perform some sanity checks
100
if (QFile::exists(mFileName))
102
// Open the file and get number of rows, etc. We assume that the
103
// file has a header row and process accordingly. Caller should make
104
// sure the the delimited file is properly formed.
105
mFile = new QFile(mFileName);
106
if (mFile->open(QIODevice::ReadOnly))
108
mStream = new QTextStream(mFile);
113
// set the initial extent
114
mExtent = new QgsRect();
115
//commented out by Tim for now - setMinimal needs to be merged in from 0.7 branch
116
//mExtent->setMinimal(); // This defeats normalization
117
bool firstPoint = true;
118
while (!mStream->atEnd())
121
line = mStream->readLine(); // line of text excluding '\n', default local 8 bit encoding.
122
if (mNumberFeatures++ == 0)
124
// Get the fields from the header row and store them in the
128
cerr << "Attempting to split the input line: " << (const char *)line.toLocal8Bit().data() <<
129
" using delimiter " << (const char *)mDelimiter.toLocal8Bit().data() << std::endl;
131
QStringList fieldList = QStringList::split(mDelimiter, line, true);
133
std::cerr << "Split line into "
134
<< fieldList.size() << " parts" << std::endl;
136
// We don't know anything about a text based field other
137
// than its name. All fields are assumed to be text
139
for (QStringList::Iterator it = fieldList.begin();
140
it != fieldList.end(); ++it)
143
if (field.length() > 0)
145
attributeFields.push_back(QgsField(*it, "Text"));
146
fieldPositions[*it] = fieldPos++;
147
// check to see if this field matches either the x or y field
151
std::cerr << "Found x field " << (const char *)(*it).toLocal8Bit().data() << std::endl;
158
std::cerr << "Found y field " << (const char *)(*it).toLocal8Bit().data() << std::endl;
163
std::cerr << "Adding field: " << (const char *)(*it).toLocal8Bit().data() << std::endl;
170
cerr << "Field count for the delimited text file is " <<
171
attributeFields.size() << std::endl;
176
// examine the x,y and update extents
177
// std::cout << line << std::endl;
178
// split the line on the delimiter
180
QStringList::split(mDelimiter, line, true);
181
//if(parts.size() == attributeFields.size())
183
// // we can populate attributes if required
184
// fieldsMatch = true;
187
// fieldsMatch = false;
190
std::cout << "Record hit line " << lineNumber << ": " <<
191
parts[fieldPositions[mXField]] << ", " <<
192
parts[fieldPositions[mYField]] << std::endl;
194
// Get the x and y values, first checking to make sure they
196
QString sX = parts[fieldPositions[mXField]];
197
QString sY = parts[fieldPositions[mYField]];
198
//std::cout << "x ,y " << sX << ", " << sY << std::endl;
201
double x = sX.toDouble(&xOk);
202
double y = sY.toDouble(&yOk);
208
if (x > mExtent->xMax())
212
if (x < mExtent->xMin())
216
if (y > mExtent->yMax())
220
if (y < mExtent->yMin())
226
{ // Extent for the first point is just the first point
227
mExtent->set(x,y,x,y);
239
std::cerr << "Data store is valid" << std::endl;
240
std::cerr << "Number of features " << mNumberFeatures << std::endl;
241
std::cerr << "Extents " << (const char *)mExtent->stringRep().toLocal8Bit().data() << std::endl;
248
cerr << "Data store is invalid. Specified x,y fields do not match\n"
249
<< "those in the database (xyCount=" << xyCount << ")" << std::endl;
253
std::cerr << "Done checking validity\n";
256
//resize the cache matrix
257
mMinMaxCache = new double *[attributeFields.size()];
258
for (int i = 0; i < attributeFields.size(); i++)
260
mMinMaxCache[i] = new double[2];
264
// file does not exist
266
cerr << "Data source " << (const char *)getDataSourceUri().toLocal8Bit().data() << " could not be opened" <<
272
// uri is invalid so the layer must be too...
273
std::cerr << "Data source is invalid" << std::endl;
278
QgsDelimitedTextProvider::~QgsDelimitedTextProvider()
283
for (int i = 0; i < fieldCount(); i++)
285
delete mMinMaxCache[i];
287
delete[]mMinMaxCache;
291
QString QgsDelimitedTextProvider::storageType()
293
return "Delimited text file";
298
* Get the first feature resutling from a select operation
301
QgsFeature * QgsDelimitedTextProvider::getFirstFeature(bool fetchAttributes)
303
QgsFeature *f = new QgsFeature;
305
reset(); // reset back to first feature
307
if ( getNextFeature_( *f, fetchAttributes ) )
315
} // QgsDelimitedTextProvider::getFirstFeature(bool fetchAttributes)
319
insure double value is properly translated into locate endian-ness
324
translateDouble_( double d )
332
// break double into byte sized chunks
335
to.char_val[7] = from.char_val[0];
336
to.char_val[6] = from.char_val[1];
337
to.char_val[5] = from.char_val[2];
338
to.char_val[4] = from.char_val[3];
339
to.char_val[3] = from.char_val[4];
340
to.char_val[2] = from.char_val[5];
341
to.char_val[1] = from.char_val[6];
342
to.char_val[0] = from.char_val[7];
346
} // translateDouble_
350
QgsDelimitedTextProvider::getNextFeature_( QgsFeature & feature,
352
std::list<int> const * desiredAttributes )
354
// before we do anything else, assume that there's something wrong with
356
feature.setValid( false );
357
while ( ! mStream->atEnd() )
359
QString line = mStream->readLine(); // Default local 8 bit encoding
360
// lex the tokens from the current data line
361
QStringList tokens = QStringList::split(mDelimiter, line, true);
366
int xFieldPos = fieldPositions[mXField];
367
int yFieldPos = fieldPositions[mYField];
369
double x = tokens[xFieldPos].toDouble( &xOk );
370
double y = tokens[yFieldPos].toDouble( &yOk );
374
// Accumulate any lines that weren't ok, to report on them
375
// later, and look at the next line in the file, but only if
377
if (mShowInvalidLines)
378
mInvalidLines << line;
383
// Give every valid line in the file an id, even if it's not
384
// in the current extent or bounds.
385
++mFid; // increment to next feature ID
387
if (! boundsCheck(x,y))
390
// at this point, one way or another, the current feature values
392
feature.setValid( true );
394
feature.setFeatureId( mFid );
397
QDataStream s( &buffer, QIODevice::WriteOnly ); // open on buffers's data
401
case QgsDataProvider::NDR :
402
// we're on a little-endian platform, so tell the data
403
// stream to use that
404
s.setByteOrder( QDataStream::LittleEndian );
405
s << (Q_UINT8)1; // 1 is for little-endian
407
case QgsDataProvider::XDR :
408
// don't change byte order since QDataStream is big endian by default
409
s << (Q_UINT8)0; // 0 is for big-endian
412
qDebug( "%s:%d unknown endian", __FILE__, __LINE__ );
413
//delete [] geometry;
417
s << (Q_UINT32)QGis::WKBPoint;
421
unsigned char* geometry = new unsigned char[buffer.size()];
422
memcpy(geometry, buffer.data(), buffer.size());
424
feature.setGeometryAndOwnership( geometry, sizeof(wkbPoint) );
426
if ( getAttributes && ! desiredAttributes )
428
for (int fi = 0; fi < attributeFields.size(); fi++)
430
feature.addAttribute(attributeFields[fi].name(), tokens[fi]);
433
// regardless of whether getAttributes is true or not, if the
434
// programmer went through the trouble of passing in such a list of
435
// attribute fields, then obviously they want them
436
else if ( desiredAttributes )
438
for ( std::list<int>::const_iterator i = desiredAttributes->begin();
439
i != desiredAttributes->end();
442
feature.addAttribute(attributeFields[*i].name(), tokens[*i]);
445
// We have a good line, so return
448
} // ! textStream EOF
450
// End of the file. If there are any lines that couldn't be
451
// loaded, display them now.
453
if (mShowInvalidLines && !mInvalidLines.isEmpty())
455
mShowInvalidLines = false;
456
QgsMessageViewer lineViewer;
457
lineViewer.setMessageAsPlainText(tr("Note: the following lines were not loaded because Qgis was unable to determine values for the x and y coordinates:\n"));
458
for (int i = 0; i < mInvalidLines.size(); ++i)
459
lineViewer.appendMessage(mInvalidLines.at(i));
462
// We no longer need these lines.
463
mInvalidLines.empty();
468
} // getNextFeature_( QgsFeature & feature )
473
Get the next feature resulting from a select operation
474
Return 0 if there are no features in the selection set
475
* @return false if unable to get the next feature
477
bool QgsDelimitedTextProvider::getNextFeature(QgsFeature & feature,
478
bool fetchAttributes)
480
return getNextFeature_( feature, fetchAttributes );
481
} // QgsDelimitedTextProvider::getNextFeature
485
QgsFeature * QgsDelimitedTextProvider::getNextFeature(bool fetchAttributes)
487
QgsFeature * f = new QgsFeature;
489
if ( getNextFeature( *f, fetchAttributes ) )
497
} // QgsDelimitedTextProvider::getNextFeature(bool fetchAttributes)
501
QgsFeature * QgsDelimitedTextProvider::getNextFeature(std::list<int> const & desiredAttributes, int featureQueueSize)
503
QgsFeature * f = new QgsFeature;
505
if ( getNextFeature_( *f, true, &desiredAttributes ) )
514
} // QgsDelimitedTextProvider::getNextFeature(std::list < int >&attlist)
520
* Select features based on a bounding rectangle. Features can be retrieved
521
* with calls to getFirstFeature and getNextFeature.
522
* @param mbr QgsRect containing the extent to use in selecting features
524
void QgsDelimitedTextProvider::select(QgsRect * rect, bool useIntersect)
527
// Setting a spatial filter doesn't make much sense since we have to
528
// compare each point against the rectangle.
529
// We store the rect and use it in getNextFeature to determine if the
530
// feature falls in the selection area
532
mSelectionRectangle = new QgsRect((*rect));
537
* Identify features within the search radius specified by rect
538
* @param rect Bounding rectangle of search radius
539
* @return std::vector containing QgsFeature objects that intersect rect
541
std::vector < QgsFeature > &QgsDelimitedTextProvider::identify(QgsRect * rect)
543
// reset the data source since we need to be able to read through
546
std::cerr << "Attempting to identify features falling within " << (const char *)rect->
547
stringRep().toLocal8Bit().data() << std::endl;
548
// select the features
551
//TODO fix this later for win32
552
std::vector < QgsFeature > feat;
559
unsigned char * QgsDelimitedTextProvider::getGeometryPointer(OGRFeature *fet){
560
unsigned char *gPtr=0;
561
// get the wkb representation
563
//geom->exportToWkb((OGRwkbByteOrder) endian(), gPtr);
570
// Return the extent of the layer
571
QgsRect *QgsDelimitedTextProvider::extent()
573
return new QgsRect(mExtent->xMin(), mExtent->yMin(), mExtent->xMax(),
578
* Return the feature type
580
int QgsDelimitedTextProvider::geometryType() const
582
return 1; // WKBPoint
586
* Return the feature type
588
long QgsDelimitedTextProvider::featureCount() const
590
return mNumberFeatures;
594
* Return the number of fields
596
int QgsDelimitedTextProvider::fieldCount() const
598
return attributeFields.size();
602
* Fetch attributes for a selected feature
604
void QgsDelimitedTextProvider::getFeatureAttributes(int key, QgsFeature * f)
606
//for (int i = 0; i < ogrFet->GetFieldCount(); i++) {
608
// // add the feature attributes to the tree
609
// OGRFieldDefn *fldDef = ogrFet->GetFieldDefnRef(i);
610
// QString fld = fldDef->GetNameRef();
611
// // OGRFieldType fldType = fldDef->GetType();
614
// val = ogrFet->GetFieldAsString(i);
615
// f->addAttribute(fld, val);
619
std::vector<QgsField> const & QgsDelimitedTextProvider::fields() const
621
return attributeFields;
624
void QgsDelimitedTextProvider::reset()
626
// Reset feature id to 0
628
// Skip ahead one line since first record is always assumed to be
632
//reset any spatial filters
633
if(mSelectionRectangle && mExtent)
635
*mSelectionRectangle = *mExtent;
639
QString QgsDelimitedTextProvider::minValue(int position)
641
if (position >= fieldCount())
644
cerr << "Warning: access requested to invalid position " <<
645
"in QgsDelimitedTextProvider::minValue(..)" << std::endl;
647
if (mMinMaxCacheDirty)
651
return QString::number(mMinMaxCache[position][0], 'f', 2);
655
QString QgsDelimitedTextProvider::maxValue(int position)
657
if (position >= fieldCount())
660
cerr << "Warning: access requested to invalid position " <<
661
"in QgsDelimitedTextProvider::maxValue(..)" << std::endl;
663
if (mMinMaxCacheDirty)
667
return QString::number(mMinMaxCache[position][1], 'f', 2);
670
void QgsDelimitedTextProvider::fillMinMaxCash()
672
for (int i = 0; i < fieldCount(); i++)
674
mMinMaxCache[i][0] = DBL_MAX;
675
mMinMaxCache[i][1] = -DBL_MAX;
681
getNextFeature(f, true);
684
for (int i = 0; i < fieldCount(); i++)
686
double value = (f.attributeMap())[i].fieldValue().toDouble();
687
if (value < mMinMaxCache[i][0])
689
mMinMaxCache[i][0] = value;
691
if (value > mMinMaxCache[i][1])
693
mMinMaxCache[i][1] = value;
697
while (getNextFeature(f, true));
699
mMinMaxCacheDirty = false;
702
//TODO - add sanity check for shape file layers, to include cheking to
703
// see if the .shp, .dbf, .shx files are all present and the layer
704
// actually has features
705
bool QgsDelimitedTextProvider::isValid()
711
* Check to see if the point is within the selection rectangle
713
bool QgsDelimitedTextProvider::boundsCheck(double x, double y)
716
if (mSelectionRectangle)
717
inBounds = (((x <= mSelectionRectangle->xMax()) &&
718
(x >= mSelectionRectangle->xMin())) &&
719
((y <= mSelectionRectangle->yMax()) &&
720
(y >= mSelectionRectangle->yMin())));
721
// QString hit = inBounds?"true":"false";
723
// std::cerr << "Checking if " << x << ", " << y << " is in " <<
724
//mSelectionRectangle->stringRep().ascii() << ": " << hit.ascii() << std::endl;
728
int QgsDelimitedTextProvider::capabilities() const
730
return QgsVectorDataProvider::SaveAsShapefile;
734
bool QgsDelimitedTextProvider::saveAsShapefile()
736
// save the layer as a shapefile
737
QString driverName = "ESRI Shapefile";
738
OGRSFDriver *poDriver;
741
OGRSFDriverRegistrar::GetRegistrar()->
742
GetDriverByName((const char *)driverName.toLocal8Bit().data());
743
bool returnValue = true;
744
if (poDriver != NULL)
746
// get a name for the shapefile
747
// Get a file to process, starting at the current directory
748
// Set inital dir to last used in delimited text plugin
751
QString shapefileName;
752
QString filter = tr("Shapefiles (*.shp)", "The *.shp is used as a file filter in a dialog box");
753
QString dirName = settings.readEntry("/Plugin-DelimitedText/text_path", "./");
755
QgsEncodingFileDialog* openFileDialog = new QgsEncodingFileDialog(0,
756
tr("Save layer as..."),
761
// allow for selection of more than one file
762
openFileDialog->setMode(QFileDialog::AnyFile);
765
if (openFileDialog->exec() == QDialog::Accepted)
767
shapefileName = openFileDialog->selectedFile();
768
enc = openFileDialog->encoding();
775
if (!shapefileName.isNull())
777
// add the extension if not present
778
if (shapefileName.find(".shp") == -1)
780
shapefileName += ".shp";
783
// create the data source
784
poDS = poDriver->CreateDataSource(QFile::encodeName(shapefileName).constData(), NULL);
787
QTextCodec* saveCodec = QTextCodec::codecForName(enc.toLocal8Bit().data());
791
qWarning("error finding QTextCodec in QgsDelimitedTextProvider::saveAsShapefile()");
793
saveCodec = QTextCodec::codecForLocale();
796
std::cerr << "created datasource" << std::endl;
797
// datasource created, now create the output layer, use utf8() for now.
800
poDS->CreateLayer((const char *) (shapefileName.
801
left(shapefileName.find(".shp"))).utf8(), NULL,
802
static_cast < OGRwkbGeometryType > (1), NULL);
805
std::cerr << "created layer" << std::endl;
806
// calculate the field lengths
807
int *lengths = getFieldLengths();
809
std::cerr << "creating " << attributeFields.
810
size() << " fields" << std::endl;
811
for (int i = 0; i < attributeFields.size(); i++)
813
// check the field length - if > 10 we need to truncate it
814
QgsField attrField = attributeFields[i];
815
if (attrField.name().length() > 10)
817
attrField = attrField.name().left(10);
819
// all fields are created as string (for now)
820
OGRFieldDefn fld(saveCodec->fromUnicode(attrField.name()), OFTString);
821
// set the length for the field -- but we don't know what it is...
822
fld.SetWidth(lengths[i]);
824
std::cerr << "creating field " << (const char *)attrField.
825
name().toLocal8Bit().data() << " width length " << lengths[i] << std::endl;
826
if (poLayer->CreateField(&fld) != OGRERR_NONE)
828
QMessageBox::warning(0, tr("Error"),
829
tr("Error creating field ") + attrField.name());
832
// read the delimited text file and create the features
833
std::cerr << "Done creating fields" << std::endl;
837
while (!mStream->atEnd())
839
line = mStream->readLine(); // line of text excluding '\n'
842
QStringList::split(mDelimiter, line, true);
844
// create the feature
845
OGRFeature *poFeature;
847
poFeature = new OGRFeature(poLayer->GetLayerDefn());
849
// iterate over the parts and set the fields
850
// set limit - we will ignore extra fields on the line
851
int limit = attributeFields.size();
853
if (parts.size() < limit)
856
// this is bad - not enough values where supplied on the line
857
// TODO We should inform the user about this...
862
for (int i = 0; i < limit; i++)
864
if (parts[i] != QString::null)
866
poFeature->SetField(saveCodec->fromUnicode(attributeFields[i].name()).data(),
867
saveCodec->fromUnicode(parts[i]).data());
872
poFeature->SetField(saveCodec->fromUnicode(attributeFields[i].name()).data(), "");
875
std::cerr << "Field values set" << std::endl;
877
OGRPoint *poPoint = new OGRPoint();
878
QString sX = parts[fieldPositions[mXField]];
879
QString sY = parts[fieldPositions[mYField]];
880
poPoint->setX(sX.toDouble());
881
poPoint->setY(sY.toDouble());
882
std::cerr << "Setting geometry" << std::endl;
884
poFeature->SetGeometryDirectly(poPoint);
885
if (poLayer->CreateFeature(poFeature) != OGRERR_NONE)
887
std::cerr << "Failed to create feature in shapefile" << std::
892
std::cerr << "Added feature" << std::endl;
902
QMessageBox::warning(0, tr("Error"), tr("Layer creation failed"));
908
QMessageBox::warning(0, tr("Error creating shapefile"),
909
tr("The shapefile could not be created (") +
910
shapefileName + ")");
914
//std::cerr << "Saving to " << shapefileName << std::endl;
918
QMessageBox::warning(0, tr("Driver not found"),
919
driverName + tr(" driver is not available"));
927
size_t QgsDelimitedTextProvider::layerCount() const
929
return 1; // XXX How to calculate the layers?
930
} // QgsOgrProvider::layerCount()
934
int *QgsDelimitedTextProvider::getFieldLengths()
936
// this function parses the entire data file and calculates the
939
// Only do this if we haven't done it already (ie. the vector is
941
int *lengths = new int[attributeFields.size()];
942
// init the lengths to zero
943
for (int il = 0; il < attributeFields.size(); il++)
952
while (!mStream->atEnd())
954
line = mStream->readLine(); // line of text excluding '\n'
956
QStringList parts = QStringList::split(mDelimiter, line, true);
957
// iterate over the parts and update the max value
958
for (int i = 0; i < parts.size(); i++)
960
if (parts[i] != QString::null)
962
// std::cerr << "comparing length for " << parts[i] << " against max len of " << lengths[i] << std::endl;
963
if (parts[i].length() > lengths[i])
965
lengths[i] = parts[i].length();
979
QString QgsDelimitedTextProvider::name() const
981
return TEXT_PROVIDER_KEY;
986
QString QgsDelimitedTextProvider::description() const
988
return TEXT_PROVIDER_DESCRIPTION;
989
} // QgsDelimitedTextProvider::name()
993
* Class factory to return a pointer to a newly created
994
* QgsDelimitedTextProvider object
996
QGISEXTERN QgsDelimitedTextProvider *classFactory(const QString *uri)
998
return new QgsDelimitedTextProvider(*uri);
1001
/** Required key function (used to map the plugin to a data store type)
1003
QGISEXTERN QString providerKey()
1005
return TEXT_PROVIDER_KEY;
1009
* Required description function
1011
QGISEXTERN QString description()
1013
return TEXT_PROVIDER_DESCRIPTION;
1017
* Required isProvider function. Used to determine if this shared library
1018
* is a data provider plugin
1020
QGISEXTERN bool isProvider()