00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018 #include "qgsattributeeditor.h"
00019 #include <qgsvectorlayer.h>
00020 #include <qgsvectordataprovider.h>
00021 #include <qgsuniquevaluerenderer.h>
00022 #include <qgscategorizedsymbolrendererv2.h>
00023 #include <qgssymbol.h>
00024 #include <qgslonglongvalidator.h>
00025 #include <qgsfieldvalidator.h>
00026 #include <qgsmaplayerregistry.h>
00027 #include <qgslogger.h>
00028
00029 #include <QPushButton>
00030 #include <QLineEdit>
00031 #include <QTextEdit>
00032 #include <QFileDialog>
00033 #include <QComboBox>
00034 #include <QCheckBox>
00035 #include <QSpinBox>
00036 #include <QCompleter>
00037 #include <QHBoxLayout>
00038 #include <QPlainTextEdit>
00039 #include <QDial>
00040 #include <QCalendarWidget>
00041 #include <QDialogButtonBox>
00042 #include <QSettings>
00043 #include <QDir>
00044 #include <QUuid>
00045
00046 void QgsAttributeEditor::selectFileName()
00047 {
00048 QPushButton *pb = qobject_cast<QPushButton *>( sender() );
00049 if ( !pb )
00050 return;
00051
00052 QWidget *hbox = qobject_cast<QWidget *>( pb->parent() );
00053 if ( !hbox )
00054 return;
00055
00056 QLineEdit *le = hbox->findChild<QLineEdit *>();
00057 if ( !le )
00058 return;
00059
00060 QString fileName = QFileDialog::getOpenFileName( 0 , tr( "Select a file" ) );
00061 if ( fileName.isNull() )
00062 return;
00063
00064
00065 le->setText( QDir::toNativeSeparators( fileName ) );
00066 }
00067
00068 void QgsAttributeEditor::selectDate()
00069 {
00070 QPushButton *pb = qobject_cast<QPushButton *>( sender() );
00071 if ( !pb )
00072 return;
00073
00074 QWidget *hbox = qobject_cast<QWidget *>( pb->parent() );
00075 if ( !hbox )
00076 return;
00077
00078 QLineEdit *le = hbox->findChild<QLineEdit *>();
00079 if ( !le )
00080 return;
00081
00082 QDialog *dlg = new QDialog();
00083 dlg->setWindowTitle( tr( "Select a date" ) );
00084 QVBoxLayout *vl = new QVBoxLayout( dlg );
00085
00086 QCalendarWidget *cw = new QCalendarWidget( dlg );
00087 cw->setSelectedDate( QDate::fromString( le->text(), Qt::ISODate ) );
00088 vl->addWidget( cw );
00089
00090 QDialogButtonBox *buttonBox = new QDialogButtonBox( dlg );
00091 buttonBox->addButton( QDialogButtonBox::Ok );
00092 buttonBox->addButton( QDialogButtonBox::Cancel );
00093 vl->addWidget( buttonBox );
00094
00095 connect( buttonBox, SIGNAL( accepted() ), dlg, SLOT( accept() ) );
00096 connect( buttonBox, SIGNAL( rejected() ), dlg, SLOT( reject() ) );
00097
00098 if ( dlg->exec() == QDialog::Accepted )
00099 {
00100 le->setText( cw->selectedDate().toString( Qt::ISODate ) );
00101 }
00102 }
00103
00104 QComboBox *QgsAttributeEditor::comboBox( QWidget *editor, QWidget *parent )
00105 {
00106 QComboBox *cb = NULL;
00107 if ( editor )
00108 cb = qobject_cast<QComboBox *>( editor );
00109 else
00110 cb = new QComboBox( parent );
00111
00112 return cb;
00113 }
00114
00115 QWidget *QgsAttributeEditor::createAttributeEditor( QWidget *parent, QWidget *editor, QgsVectorLayer *vl, int idx, const QVariant &value )
00116 {
00117 if ( !vl )
00118 return NULL;
00119
00120 QWidget *myWidget = NULL;
00121 QgsVectorLayer::EditType editType = vl->editType( idx );
00122 const QgsField &field = vl->pendingFields()[idx];
00123 QVariant::Type myFieldType = field.type();
00124
00125 switch ( editType )
00126 {
00127 case QgsVectorLayer::UniqueValues:
00128 {
00129 QList<QVariant> values;
00130 vl->dataProvider()->uniqueValues( idx, values );
00131
00132 QComboBox *cb = comboBox( editor, parent );
00133 if ( cb )
00134 {
00135 cb->setEditable( false );
00136
00137 for ( QList<QVariant>::iterator it = values.begin(); it != values.end(); it++ )
00138 cb->addItem( it->toString(), it->toString() );
00139
00140 myWidget = cb;
00141 }
00142 }
00143 break;
00144
00145 case QgsVectorLayer::Enumeration:
00146 {
00147 QStringList enumValues;
00148 vl->dataProvider()->enumValues( idx, enumValues );
00149
00150 QComboBox *cb = comboBox( editor, parent );
00151 if ( cb )
00152 {
00153 QStringList::const_iterator s_it = enumValues.constBegin();
00154 for ( ; s_it != enumValues.constEnd(); ++s_it )
00155 {
00156 cb->addItem( *s_it, *s_it );
00157 }
00158
00159 myWidget = cb;
00160 }
00161 }
00162 break;
00163
00164 case QgsVectorLayer::ValueMap:
00165 {
00166 const QMap<QString, QVariant> &map = vl->valueMap( idx );
00167
00168 QComboBox *cb = comboBox( editor, parent );
00169 if ( cb )
00170 {
00171 for ( QMap<QString, QVariant>::const_iterator it = map.begin(); it != map.end(); it++ )
00172 {
00173 cb->addItem( it.key(), it.value() );
00174 }
00175
00176 myWidget = cb;
00177 }
00178 }
00179 break;
00180
00181 case QgsVectorLayer::ValueRelation:
00182 {
00183 QSettings settings;
00184 QString nullValue = settings.value( "qgis/nullValue", "NULL" ).toString();
00185
00186 const QgsVectorLayer::ValueRelationData &data = vl->valueRelation( idx );
00187
00188 QgsVectorLayer *layer = qobject_cast<QgsVectorLayer*>( QgsMapLayerRegistry::instance()->mapLayer( data.mLayer ) );
00189 QMap< QString, QString > map;
00190 if ( layer )
00191 {
00192 int ki = layer->fieldNameIndex( data.mOrderByValue ? data.mValue : data.mKey );
00193 int vi = layer->fieldNameIndex( data.mOrderByValue ? data.mKey : data.mValue );
00194
00195 if ( data.mAllowNull )
00196 map.insert( nullValue, tr( "(no selection)" ) );
00197
00198 if ( ki >= 0 && vi >= 0 )
00199 {
00200 layer->select( QgsAttributeList() << ki << vi, QgsRectangle(), false );
00201 QgsFeature f;
00202 while ( layer->nextFeature( f ) )
00203 {
00204 map.insert( f.attributeMap()[ ki ].toString(), f.attributeMap()[ vi ].toString() );
00205 }
00206 }
00207 }
00208
00209 QComboBox *cb = comboBox( editor, parent );
00210 if ( cb )
00211 {
00212 for ( QMap< QString, QString >::const_iterator it = map.begin(); it != map.end(); it++ )
00213 {
00214 if ( data.mOrderByValue )
00215 cb->addItem( it.key(), it.value() );
00216 else
00217 cb->addItem( it.value(), it.key() );
00218 }
00219
00220 myWidget = cb;
00221 }
00222 }
00223 break;
00224
00225 case QgsVectorLayer::Classification:
00226 {
00227 QMap<QString, QString> classes;
00228
00229 const QgsUniqueValueRenderer *uvr = dynamic_cast<const QgsUniqueValueRenderer *>( vl->renderer() );
00230 if ( uvr )
00231 {
00232 const QList<QgsSymbol *> symbols = uvr->symbols();
00233
00234 for ( int i = 0; i < symbols.size(); i++ )
00235 {
00236 QString label = symbols[i]->label();
00237 QString name = symbols[i]->lowerValue();
00238
00239 if ( label == "" )
00240 label = name;
00241
00242 classes.insert( name, label );
00243 }
00244 }
00245
00246 const QgsCategorizedSymbolRendererV2 *csr = dynamic_cast<const QgsCategorizedSymbolRendererV2 *>( vl->rendererV2() );
00247 if ( csr )
00248 {
00249 const QgsCategoryList &categories = (( QgsCategorizedSymbolRendererV2 * )csr )->categories();
00250 for ( int i = 0; i < categories.size(); i++ )
00251 {
00252 QString label = categories[i].label();
00253 QString value = categories[i].value().toString();
00254 if ( label.isEmpty() )
00255 label = value;
00256 classes.insert( value, label );
00257 }
00258 }
00259
00260 QComboBox *cb = comboBox( editor, parent );
00261 if ( cb )
00262 {
00263 for ( QMap<QString, QString>::const_iterator it = classes.begin(); it != classes.end(); it++ )
00264 {
00265 cb->addItem( it.value(), it.key() );
00266 }
00267
00268 myWidget = cb;
00269 }
00270 }
00271 break;
00272
00273 case QgsVectorLayer::DialRange:
00274 case QgsVectorLayer::SliderRange:
00275 case QgsVectorLayer::EditRange:
00276 {
00277 if ( myFieldType == QVariant::Int )
00278 {
00279 int min = vl->range( idx ).mMin.toInt();
00280 int max = vl->range( idx ).mMax.toInt();
00281 int step = vl->range( idx ).mStep.toInt();
00282
00283 if ( editType == QgsVectorLayer::EditRange )
00284 {
00285 QSpinBox *sb = NULL;
00286
00287 if ( editor )
00288 sb = qobject_cast<QSpinBox *>( editor );
00289 else
00290 sb = new QSpinBox( parent );
00291
00292 if ( sb )
00293 {
00294 sb->setRange( min, max );
00295 sb->setSingleStep( step );
00296
00297 myWidget = sb;
00298 }
00299 }
00300 else
00301 {
00302 QAbstractSlider *sl = NULL;
00303
00304 if ( editor )
00305 {
00306 sl = qobject_cast<QAbstractSlider*>( editor );
00307 }
00308 else if ( editType == QgsVectorLayer::DialRange )
00309 {
00310 sl = new QDial( parent );
00311 }
00312 else
00313 {
00314 sl = new QSlider( Qt::Horizontal, parent );
00315 }
00316
00317 if ( sl )
00318 {
00319 sl->setRange( min, max );
00320 sl->setSingleStep( step );
00321
00322 myWidget = sl;
00323 }
00324 }
00325 break;
00326 }
00327 else if ( myFieldType == QVariant::Double )
00328 {
00329 QDoubleSpinBox *dsb = NULL;
00330 if ( editor )
00331 dsb = qobject_cast<QDoubleSpinBox*>( editor );
00332 else
00333 dsb = new QDoubleSpinBox( parent );
00334
00335 if ( dsb )
00336 {
00337 double min = vl->range( idx ).mMin.toDouble();
00338 double max = vl->range( idx ).mMax.toDouble();
00339 double step = vl->range( idx ).mStep.toDouble();
00340
00341 dsb->setRange( min, max );
00342 dsb->setSingleStep( step );
00343
00344 myWidget = dsb;
00345 }
00346 break;
00347 }
00348 }
00349
00350 case QgsVectorLayer::CheckBox:
00351 {
00352 QCheckBox *cb = NULL;
00353 if ( editor )
00354 cb = qobject_cast<QCheckBox*>( editor );
00355 else
00356 cb = new QCheckBox( parent );
00357
00358 if ( cb )
00359 {
00360 myWidget = cb;
00361 break;
00362 }
00363 }
00364
00365
00366
00367 case QgsVectorLayer::LineEdit:
00368 case QgsVectorLayer::TextEdit:
00369 case QgsVectorLayer::UuidGenerator:
00370 case QgsVectorLayer::UniqueValuesEditable:
00371 case QgsVectorLayer::Immutable:
00372 {
00373 QLineEdit *le = NULL;
00374 QTextEdit *te = NULL;
00375 QPlainTextEdit *pte = NULL;
00376
00377 if ( editor )
00378 {
00379 le = qobject_cast<QLineEdit *>( editor );
00380 te = qobject_cast<QTextEdit *>( editor );
00381 pte = qobject_cast<QPlainTextEdit *>( editor );
00382 }
00383 else if ( editType == QgsVectorLayer::TextEdit )
00384 {
00385 pte = new QPlainTextEdit( parent );
00386 }
00387 else
00388 {
00389 le = new QLineEdit( parent );
00390 }
00391
00392 if ( le )
00393 {
00394
00395 if ( editType == QgsVectorLayer::UniqueValuesEditable )
00396 {
00397 QList<QVariant> values;
00398 vl->dataProvider()->uniqueValues( idx, values );
00399
00400 QStringList svalues;
00401 for ( QList<QVariant>::const_iterator it = values.begin(); it != values.end(); it++ )
00402 svalues << it->toString();
00403
00404 QCompleter *c = new QCompleter( svalues );
00405 c->setCompletionMode( QCompleter::PopupCompletion );
00406 le->setCompleter( c );
00407 }
00408
00409 if ( editType == QgsVectorLayer::UuidGenerator )
00410 {
00411 le->setReadOnly( true );
00412 }
00413
00414 le->setValidator( new QgsFieldValidator( le, field ) );
00415 myWidget = le;
00416 }
00417
00418 if ( te )
00419 {
00420 te->setAcceptRichText( true );
00421 myWidget = te;
00422 }
00423
00424 if ( pte )
00425 {
00426 myWidget = pte;
00427 }
00428
00429 if ( myWidget )
00430 {
00431 myWidget->setDisabled( editType == QgsVectorLayer::Immutable );
00432 }
00433 }
00434 break;
00435
00436 case QgsVectorLayer::Hidden:
00437 myWidget = NULL;
00438 break;
00439
00440 case QgsVectorLayer::FileName:
00441 case QgsVectorLayer::Calendar:
00442 {
00443 QPushButton *pb = NULL;
00444 QLineEdit *le = qobject_cast<QLineEdit *>( editor );
00445 if ( le )
00446 {
00447 if ( le )
00448 myWidget = le;
00449
00450 if ( editor->parent() )
00451 {
00452 pb = editor->parent()->findChild<QPushButton *>();
00453 }
00454 }
00455 else
00456 {
00457 le = new QLineEdit();
00458
00459 pb = new QPushButton( tr( "..." ) );
00460
00461 QHBoxLayout *hbl = new QHBoxLayout();
00462 hbl->addWidget( le );
00463 hbl->addWidget( pb );
00464
00465 myWidget = new QWidget( parent );
00466 myWidget->setBackgroundRole( QPalette::Window );
00467 myWidget->setAutoFillBackground( true );
00468 myWidget->setLayout( hbl );
00469 }
00470
00471 if ( pb )
00472 {
00473 if ( editType == QgsVectorLayer::FileName )
00474 connect( pb, SIGNAL( clicked() ), new QgsAttributeEditor( pb ), SLOT( selectFileName() ) );
00475 if ( editType == QgsVectorLayer::Calendar )
00476 connect( pb, SIGNAL( clicked() ), new QgsAttributeEditor( pb ), SLOT( selectDate() ) );
00477 }
00478 }
00479 break;
00480 }
00481
00482 setValue( myWidget, vl, idx, value );
00483
00484 return myWidget;
00485 }
00486
00487 bool QgsAttributeEditor::retrieveValue( QWidget *widget, QgsVectorLayer *vl, int idx, QVariant &value )
00488 {
00489 if ( !widget )
00490 return false;
00491
00492 const QgsField &theField = vl->pendingFields()[idx];
00493 QgsVectorLayer::EditType editType = vl->editType( idx );
00494 bool modified = false;
00495 QString text;
00496
00497 QSettings settings;
00498 QString nullValue = settings.value( "qgis/nullValue", "NULL" ).toString();
00499
00500 QLineEdit *le = qobject_cast<QLineEdit *>( widget );
00501 if ( le )
00502 {
00503 text = le->text();
00504 modified = le->isModified();
00505 if ( text == nullValue )
00506 {
00507 text = QString::null;
00508 }
00509 }
00510
00511 QTextEdit *te = qobject_cast<QTextEdit *>( widget );
00512 if ( te )
00513 {
00514 text = te->toHtml();
00515 modified = te->document()->isModified();
00516 if ( text == nullValue )
00517 {
00518 text = QString::null;
00519 }
00520 }
00521
00522 QPlainTextEdit *pte = qobject_cast<QPlainTextEdit *>( widget );
00523 if ( pte )
00524 {
00525 text = pte->toPlainText();
00526 modified = pte->document()->isModified();
00527 if ( text == nullValue )
00528 {
00529 text = QString::null;
00530 }
00531 }
00532
00533 QComboBox *cb = qobject_cast<QComboBox *>( widget );
00534 if ( cb )
00535 {
00536 if ( editType == QgsVectorLayer::UniqueValues ||
00537 editType == QgsVectorLayer::ValueMap ||
00538 editType == QgsVectorLayer::Classification ||
00539 editType == QgsVectorLayer::ValueRelation )
00540 {
00541 text = cb->itemData( cb->currentIndex() ).toString();
00542 if ( text == nullValue )
00543 {
00544 text = QString::null;
00545 }
00546 }
00547 else
00548 {
00549 text = cb->currentText();
00550 }
00551 modified = true;
00552 }
00553
00554 QSpinBox *sb = qobject_cast<QSpinBox *>( widget );
00555 if ( sb )
00556 {
00557 text = QString::number( sb->value() );
00558 }
00559
00560 QAbstractSlider *slider = qobject_cast<QAbstractSlider *>( widget );
00561 if ( slider )
00562 {
00563 text = QString::number( slider->value() );
00564 }
00565
00566 QDoubleSpinBox *dsb = qobject_cast<QDoubleSpinBox *>( widget );
00567 if ( dsb )
00568 {
00569 text = QString::number( dsb->value() );
00570 }
00571
00572 QCheckBox *ckb = qobject_cast<QCheckBox *>( widget );
00573 if ( ckb )
00574 {
00575 QPair<QString, QString> states = vl->checkedState( idx );
00576 text = ckb->isChecked() ? states.first : states.second;
00577 }
00578
00579 QCalendarWidget *cw = qobject_cast<QCalendarWidget *>( widget );
00580 if ( cw )
00581 {
00582 text = cw->selectedDate().toString();
00583 }
00584
00585 le = widget->findChild<QLineEdit *>();
00586 if ( le )
00587 {
00588 text = le->text();
00589 }
00590
00591 switch ( theField.type() )
00592 {
00593 case QVariant::Int:
00594 {
00595 bool ok;
00596 int myIntValue = text.toInt( &ok );
00597 if ( ok && !text.isEmpty() )
00598 {
00599 value = QVariant( myIntValue );
00600 modified = true;
00601 }
00602 else if ( modified )
00603 {
00604 value = QVariant();
00605 }
00606 }
00607 break;
00608 case QVariant::LongLong:
00609 {
00610 bool ok;
00611 qlonglong myLongValue = text.toLong( &ok );
00612 if ( ok && !text.isEmpty() )
00613 {
00614 value = QVariant( myLongValue );
00615 modified = true;
00616 }
00617 else if ( modified )
00618 {
00619 value = QVariant();
00620 }
00621 }
00622 case QVariant::Double:
00623 {
00624 bool ok;
00625 double myDblValue = text.toDouble( &ok );
00626 if ( ok && !text.isEmpty() )
00627 {
00628 value = QVariant( myDblValue );
00629 modified = true;
00630 }
00631 else if ( modified )
00632 {
00633 value = QVariant();
00634 }
00635 }
00636 break;
00637 case QVariant::Date:
00638 {
00639 QDate myDateValue = QDate::fromString( text, Qt::ISODate );
00640 if ( myDateValue.isValid() && !text.isEmpty() )
00641 {
00642 value = myDateValue;
00643 modified = true;
00644 }
00645 else if ( modified )
00646 {
00647 value = QVariant();
00648 }
00649 }
00650 break;
00651 default:
00652 modified = true;
00653 value = QVariant( text );
00654 break;
00655 }
00656
00657 return modified;
00658 }
00659
00660 bool QgsAttributeEditor::setValue( QWidget *editor, QgsVectorLayer *vl, int idx, const QVariant &value )
00661 {
00662 if ( !editor )
00663 return false;
00664
00665 QgsVectorLayer::EditType editType = vl->editType( idx );
00666 const QgsField &field = vl->pendingFields()[idx];
00667 QVariant::Type myFieldType = field.type();
00668
00669 QSettings settings;
00670 QString nullValue = settings.value( "qgis/nullValue", "NULL" ).toString();
00671
00672 switch ( editType )
00673 {
00674 case QgsVectorLayer::Classification:
00675 case QgsVectorLayer::UniqueValues:
00676 case QgsVectorLayer::Enumeration:
00677 case QgsVectorLayer::ValueMap:
00678 case QgsVectorLayer::ValueRelation:
00679 {
00680 QVariant v = value;
00681 QComboBox *cb = qobject_cast<QComboBox *>( editor );
00682 if ( cb == NULL )
00683 return false;
00684
00685 if ( v.isNull() )
00686 {
00687 v = nullValue;
00688 }
00689
00690 int idx = cb->findData( v );
00691 if ( idx < 0 )
00692 return false;
00693
00694 cb->setCurrentIndex( idx );
00695 }
00696 break;
00697
00698 case QgsVectorLayer::DialRange:
00699 case QgsVectorLayer::SliderRange:
00700 case QgsVectorLayer::EditRange:
00701 {
00702 if ( myFieldType == QVariant::Int )
00703 {
00704 if ( editType == QgsVectorLayer::EditRange )
00705 {
00706 QSpinBox *sb = qobject_cast<QSpinBox *>( editor );
00707 if ( sb == NULL )
00708 return false;
00709 sb->setValue( value.toInt() );
00710 }
00711 else
00712 {
00713 QAbstractSlider *sl = qobject_cast<QAbstractSlider *>( editor );
00714 if ( sl == NULL )
00715 return false;
00716 sl->setValue( value.toInt() );
00717 }
00718 break;
00719 }
00720 else if ( myFieldType == QVariant::Double )
00721 {
00722 QDoubleSpinBox *dsb = qobject_cast<QDoubleSpinBox *>( editor );
00723 if ( dsb == NULL )
00724 return false;
00725 dsb->setValue( value.toDouble() );
00726 }
00727 }
00728
00729 case QgsVectorLayer::CheckBox:
00730 {
00731 QCheckBox *cb = qobject_cast<QCheckBox *>( editor );
00732 if ( cb )
00733 {
00734 QPair<QString, QString> states = vl->checkedState( idx );
00735 cb->setChecked( value == states.first );
00736 break;
00737 }
00738 }
00739
00740
00741
00742 case QgsVectorLayer::LineEdit:
00743 case QgsVectorLayer::UniqueValuesEditable:
00744 case QgsVectorLayer::Immutable:
00745 case QgsVectorLayer::UuidGenerator:
00746 default:
00747 {
00748 QLineEdit *le = qobject_cast<QLineEdit *>( editor );
00749 QTextEdit *te = qobject_cast<QTextEdit *>( editor );
00750 QPlainTextEdit *pte = qobject_cast<QPlainTextEdit *>( editor );
00751 if ( !le && !te && !pte )
00752 return false;
00753
00754 QString text;
00755 if ( value.isNull() )
00756 {
00757 if ( myFieldType == QVariant::Int || myFieldType == QVariant::Double || myFieldType == QVariant::LongLong )
00758 text = "";
00759 else if ( editType == QgsVectorLayer::UuidGenerator )
00760 text = QUuid::createUuid().toString();
00761 else
00762 text = nullValue;
00763 }
00764 else
00765 {
00766 text = value.toString();
00767 }
00768
00769 if ( le )
00770 le->setText( text );
00771 if ( te )
00772 te->setHtml( text );
00773 if ( pte )
00774 pte->setPlainText( text );
00775 }
00776 break;
00777
00778 case QgsVectorLayer::FileName:
00779 case QgsVectorLayer::Calendar:
00780 {
00781 QLineEdit* le = qobject_cast<QLineEdit*>( editor );
00782 if ( !le )
00783 {
00784 le = editor->findChild<QLineEdit *>();
00785 }
00786 if ( !le )
00787 {
00788 return false;
00789 }
00790 le->setText( value.toString() );
00791 }
00792 break;
00793 }
00794
00795 return true;
00796 }