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