|
Quantum GIS API Documentation
master-693a1fe
|
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 00018 #include "qgsattributeeditor.h" 00019 #include <qgsvectorlayer.h> 00020 #include <qgsvectordataprovider.h> 00021 #include <qgscategorizedsymbolrendererv2.h> 00022 #include <qgslonglongvalidator.h> 00023 #include <qgsfieldvalidator.h> 00024 #include <qgsmaplayerregistry.h> 00025 #include <qgslogger.h> 00026 #include <qgsexpression.h> 00027 #include <qgsfilterlineedit.h> 00028 #include <qgscolorbutton.h> 00029 #include <qgsnetworkaccessmanager.h> 00030 00031 #include <QScrollArea> 00032 #include <QPushButton> 00033 #include <QLineEdit> 00034 #include <QTextEdit> 00035 #include <QFileDialog> 00036 #include <QComboBox> 00037 #include <QListWidget> 00038 #include <QCheckBox> 00039 #include <QSpinBox> 00040 #include <QCompleter> 00041 #include <QHBoxLayout> 00042 #include <QPlainTextEdit> 00043 #include <QDial> 00044 #include <QCalendarWidget> 00045 #include <QDialogButtonBox> 00046 #include <QSettings> 00047 #include <QDir> 00048 #include <QUuid> 00049 #include <QGroupBox> 00050 #include <QLabel> 00051 #include <QWebView> 00052 00053 void QgsAttributeEditor::selectFileName() 00054 { 00055 QPushButton *pb = qobject_cast<QPushButton *>( sender() ); 00056 if ( !pb ) 00057 return; 00058 00059 QWidget *hbox = qobject_cast<QWidget *>( pb->parent() ); 00060 if ( !hbox ) 00061 return; 00062 00063 QLineEdit *le = hbox->findChild<QLineEdit *>(); 00064 if ( !le ) 00065 return; 00066 00067 QString fileName = QFileDialog::getOpenFileName( 0 , tr( "Select a file" ), QFileInfo( le->text() ).absolutePath() ); 00068 if ( fileName.isNull() ) 00069 return; 00070 00071 le->setText( QDir::toNativeSeparators( fileName ) ); 00072 } 00073 00074 void QgsAttributeEditor::selectDate() 00075 { 00076 QPushButton *pb = qobject_cast<QPushButton *>( sender() ); 00077 if ( !pb ) 00078 return; 00079 00080 QWidget *hbox = qobject_cast<QWidget *>( pb->parent() ); 00081 if ( !hbox ) 00082 return; 00083 00084 QLineEdit *le = hbox->findChild<QLineEdit *>(); 00085 if ( !le ) 00086 return; 00087 00088 QDialog *dlg = new QDialog(); 00089 dlg->setWindowTitle( tr( "Select a date" ) ); 00090 QVBoxLayout *vl = new QVBoxLayout( dlg ); 00091 00092 const QgsFieldValidator *v = dynamic_cast<const QgsFieldValidator *>( le->validator() ); 00093 QString dateFormat = v ? v->dateFormat() : "yyyy-MM-dd"; 00094 00095 QCalendarWidget *cw = new QCalendarWidget( dlg ); 00096 QString prevValue = le->text(); 00097 cw->setSelectedDate( QDate::fromString( prevValue, dateFormat ) ); 00098 vl->addWidget( cw ); 00099 00100 QDialogButtonBox *buttonBox = new QDialogButtonBox( dlg ); 00101 buttonBox->addButton( QDialogButtonBox::Ok ); 00102 buttonBox->addButton( QDialogButtonBox::Cancel ); 00103 vl->addWidget( buttonBox ); 00104 00105 connect( buttonBox, SIGNAL( accepted() ), dlg, SLOT( accept() ) ); 00106 connect( buttonBox, SIGNAL( rejected() ), dlg, SLOT( reject() ) ); 00107 00108 if ( dlg->exec() == QDialog::Accepted ) 00109 { 00110 QString newValue = cw->selectedDate().toString( dateFormat ); 00111 le->setText( newValue ); 00112 le->setModified( newValue != prevValue ); 00113 } 00114 } 00115 00116 void QgsAttributeEditor::loadUrl( const QString &url ) 00117 { 00118 QLineEdit *le = qobject_cast<QLineEdit *>( sender() ); 00119 if ( !le ) 00120 return; 00121 00122 QWidget *hbox = qobject_cast<QWidget *>( le->parent() ); 00123 if ( !hbox ) 00124 return; 00125 00126 QWebView *ww = hbox->findChild<QWebView *>(); 00127 if ( !ww ) 00128 return; 00129 00130 ww->load( url ); 00131 } 00132 00133 void QgsAttributeEditor::loadPixmap( const QString &name ) 00134 { 00135 QLineEdit *le = qobject_cast<QLineEdit *>( sender() ); 00136 if ( !le ) 00137 return; 00138 00139 QWidget *hbox = qobject_cast<QWidget *>( le->parent() ); 00140 if ( !hbox ) 00141 return; 00142 00143 QLabel *lw = hbox->findChild<QLabel *>(); 00144 if ( !lw ) 00145 return; 00146 00147 QPixmap pm( name ); 00148 if ( pm.isNull() ) 00149 return; 00150 00151 QSize size( mLayer->widgetSize( mIdx ) ); 00152 if ( size.width() == 0 && size.height() > 0 ) 00153 { 00154 size.setWidth( size.height() * pm.size().width() / pm.size().height() ); 00155 } 00156 else if ( size.width() > 0 && size.height() == 0 ) 00157 { 00158 size.setHeight( size.width() * pm.size().height() / pm.size().width() ); 00159 } 00160 00161 pm = pm.scaled( size, Qt::KeepAspectRatio, Qt::SmoothTransformation ); 00162 00163 lw->setPixmap( pm ); 00164 lw->setMinimumSize( size ); 00165 } 00166 00167 void QgsAttributeEditor::updateUrl() 00168 { 00169 QPushButton *pb = qobject_cast<QPushButton *>( sender() ); 00170 if ( !pb ) 00171 return; 00172 00173 QWidget *hbox = qobject_cast<QWidget *>( pb->parent() ); 00174 if ( !hbox ) 00175 return; 00176 00177 QWebView *ww = hbox->findChild<QWebView *>(); 00178 if ( !ww ) 00179 return; 00180 00181 QLineEdit *le = hbox->findChild<QLineEdit *>(); 00182 if ( !le ) 00183 return; 00184 00185 le->blockSignals( true ); 00186 le->setText( ww->url().toString() ); 00187 le->blockSignals( false ); 00188 } 00189 00190 void QgsAttributeEditor::updateColor() 00191 { 00192 QString color; 00193 QgsColorButton *scb = qobject_cast<QgsColorButton *>( sender() ); 00194 QLineEdit *sle = qobject_cast<QLineEdit *>( sender() ); 00195 00196 if ( !scb && !sle ) 00197 return; 00198 00199 QWidget *hbox = qobject_cast<QWidget *>( sender()->parent() ); 00200 if ( !hbox ) 00201 return; 00202 00203 QgsColorButton *cb = hbox->findChild<QgsColorButton *>(); 00204 if ( !cb ) 00205 return; 00206 00207 QLineEdit *le = hbox->findChild<QLineEdit *>(); 00208 if ( !le ) 00209 return; 00210 00211 if ( scb ) 00212 { 00213 le->blockSignals( true ); 00214 le->setText( scb->color().name() ); 00215 le->blockSignals( false ); 00216 } 00217 00218 if ( sle ) 00219 { 00220 cb->blockSignals( true ); 00221 cb->setColor( QColor( sle->text() ) ); 00222 cb->blockSignals( false ); 00223 } 00224 } 00225 00226 QComboBox *QgsAttributeEditor::comboBox( QWidget *editor, QWidget *parent ) 00227 { 00228 QComboBox *cb = 0; 00229 if ( editor ) 00230 cb = qobject_cast<QComboBox *>( editor ); 00231 else 00232 cb = new QComboBox( parent ); 00233 00234 return cb; 00235 } 00236 00237 QListWidget *QgsAttributeEditor::listWidget( QWidget *editor, QWidget *parent ) 00238 { 00239 QListWidget *lw = 0; 00240 if ( editor ) 00241 lw = qobject_cast<QListWidget *>( editor ); 00242 else 00243 lw = new QListWidget( parent ); 00244 00245 return lw; 00246 } 00247 00248 QWidget *QgsAttributeEditor::createAttributeEditor( QWidget *parent, QWidget *editor, QgsVectorLayer *vl, int idx, const QVariant &value ) 00249 { 00250 QMap<int, QWidget*> dummyProxyWidgets; 00251 return createAttributeEditor( parent, editor, vl, idx, value, dummyProxyWidgets ); 00252 } 00253 00254 QWidget *QgsAttributeEditor::createAttributeEditor( QWidget *parent, QWidget *editor, QgsVectorLayer *vl, int idx, const QVariant &value, QMap<int, QWidget*> &proxyWidgets ) 00255 { 00256 if ( !vl ) 00257 return 0; 00258 00259 QWidget *myWidget = 0; 00260 QgsVectorLayer::EditType editType = vl->editType( idx ); 00261 const QgsField &field = vl->pendingFields()[idx]; 00262 QVariant::Type myFieldType = field.type(); 00263 00264 bool synchronized = false; 00265 00266 switch ( editType ) 00267 { 00268 case QgsVectorLayer::UniqueValues: 00269 { 00270 QList<QVariant> values; 00271 vl->dataProvider()->uniqueValues( idx, values ); 00272 00273 QComboBox *cb = comboBox( editor, parent ); 00274 if ( cb ) 00275 { 00276 cb->setEditable( false ); 00277 00278 for ( QList<QVariant>::iterator it = values.begin(); it != values.end(); it++ ) 00279 cb->addItem( it->toString(), it->toString() ); 00280 00281 myWidget = cb; 00282 } 00283 00284 } 00285 break; 00286 00287 case QgsVectorLayer::Enumeration: 00288 { 00289 QStringList enumValues; 00290 vl->dataProvider()->enumValues( idx, enumValues ); 00291 00292 QComboBox *cb = comboBox( editor, parent ); 00293 if ( cb ) 00294 { 00295 QStringList::const_iterator s_it = enumValues.constBegin(); 00296 for ( ; s_it != enumValues.constEnd(); ++s_it ) 00297 { 00298 cb->addItem( *s_it, *s_it ); 00299 } 00300 00301 myWidget = cb; 00302 } 00303 } 00304 break; 00305 00306 case QgsVectorLayer::ValueMap: 00307 { 00308 const QMap<QString, QVariant> &map = vl->valueMap( idx ); 00309 00310 QComboBox *cb = comboBox( editor, parent ); 00311 if ( cb ) 00312 { 00313 for ( QMap<QString, QVariant>::const_iterator it = map.begin(); it != map.end(); it++ ) 00314 { 00315 cb->addItem( it.key(), it.value() ); 00316 } 00317 00318 myWidget = cb; 00319 } 00320 } 00321 break; 00322 00323 case QgsVectorLayer::ValueRelation: 00324 { 00325 const QgsVectorLayer::ValueRelationData &data = vl->valueRelation( idx ); 00326 00327 QgsVectorLayer *layer = qobject_cast<QgsVectorLayer*>( QgsMapLayerRegistry::instance()->mapLayer( data.mLayer ) ); 00328 QMap< QString, QString > map; 00329 00330 if ( layer ) 00331 { 00332 int ki = layer->fieldNameIndex( data.mOrderByValue ? data.mValue : data.mKey ); 00333 int vi = layer->fieldNameIndex( data.mOrderByValue ? data.mKey : data.mValue ); 00334 00335 QgsExpression *e = 0; 00336 if ( !data.mFilterExpression.isEmpty() ) 00337 { 00338 e = new QgsExpression( data.mFilterExpression ); 00339 if ( e->hasParserError() || !e->prepare( layer->pendingFields() ) ) 00340 ki = -1; 00341 } 00342 00343 if ( ki >= 0 && vi >= 0 ) 00344 { 00345 QSet<int> attributes; 00346 attributes << ki << vi; 00347 00348 QgsFeatureRequest::Flag flags = QgsFeatureRequest::NoGeometry; 00349 00350 if ( e ) 00351 { 00352 if ( e->needsGeometry() ) 00353 flags = QgsFeatureRequest::NoFlags; 00354 00355 foreach ( const QString &field, e->referencedColumns() ) 00356 { 00357 int idx = layer->fieldNameIndex( field ); 00358 if ( idx < 0 ) 00359 continue; 00360 attributes << idx; 00361 } 00362 } 00363 00364 QgsFeatureIterator fit = layer->getFeatures( QgsFeatureRequest().setFlags( flags ).setSubsetOfAttributes( attributes.toList() ) ); 00365 QgsFeature f; 00366 while ( fit.nextFeature( f ) ) 00367 { 00368 if ( e && !e->evaluate( &f ).toBool() ) 00369 continue; 00370 00371 map.insert( f.attribute( ki ).toString(), f.attribute( vi ).toString() ); 00372 } 00373 } 00374 } 00375 00376 if ( !data.mAllowMulti ) 00377 { 00378 QComboBox *cb = comboBox( editor, parent ); 00379 if ( cb ) 00380 { 00381 if ( data.mAllowNull ) 00382 { 00383 QSettings settings; 00384 cb->addItem( tr( "(no selection)" ), settings.value( "qgis/nullValue", "NULL" ).toString() ); 00385 } 00386 00387 for ( QMap< QString, QString >::const_iterator it = map.begin(); it != map.end(); it++ ) 00388 { 00389 if ( data.mOrderByValue ) 00390 cb->addItem( it.key(), it.value() ); 00391 else 00392 cb->addItem( it.value(), it.key() ); 00393 } 00394 00395 myWidget = cb; 00396 } 00397 } 00398 else 00399 { 00400 QListWidget *lw = listWidget( editor, parent ); 00401 if ( lw ) 00402 { 00403 QStringList checkList = value.toString().remove( QChar( '{' ) ).remove( QChar( '}' ) ).split( "," ); 00404 00405 for ( QMap< QString, QString >::const_iterator it = map.begin(); it != map.end(); it++ ) 00406 { 00407 QListWidgetItem *item; 00408 if ( data.mOrderByValue ) 00409 { 00410 item = new QListWidgetItem( it.key() ); 00411 item->setData( Qt::UserRole, it.value() ); 00412 item->setCheckState( checkList.contains( it.value() ) ? Qt::Checked : Qt::Unchecked ); 00413 } 00414 else 00415 { 00416 item = new QListWidgetItem( it.value() ); 00417 item->setData( Qt::UserRole, it.key() ); 00418 item->setCheckState( checkList.contains( it.key() ) ? Qt::Checked : Qt::Unchecked ); 00419 } 00420 lw->addItem( item ); 00421 } 00422 00423 myWidget = lw; 00424 } 00425 } 00426 } 00427 break; 00428 00429 case QgsVectorLayer::Classification: 00430 { 00431 QMap<QString, QString> classes; 00432 00433 const QgsCategorizedSymbolRendererV2 *csr = dynamic_cast<const QgsCategorizedSymbolRendererV2 *>( vl->rendererV2() ); 00434 if ( csr ) 00435 { 00436 const QgsCategoryList &categories = (( QgsCategorizedSymbolRendererV2 * )csr )->categories(); // FIXME: QgsCategorizedSymbolRendererV2::categories() should be const 00437 for ( int i = 0; i < categories.size(); i++ ) 00438 { 00439 QString label = categories[i].label(); 00440 QString value = categories[i].value().toString(); 00441 if ( label.isEmpty() ) 00442 label = value; 00443 classes.insert( value, label ); 00444 } 00445 } 00446 00447 QComboBox *cb = comboBox( editor, parent ); 00448 if ( cb ) 00449 { 00450 for ( QMap<QString, QString>::const_iterator it = classes.begin(); it != classes.end(); it++ ) 00451 { 00452 cb->addItem( it.value(), it.key() ); 00453 } 00454 00455 myWidget = cb; 00456 } 00457 } 00458 break; 00459 00460 case QgsVectorLayer::DialRange: 00461 case QgsVectorLayer::SliderRange: 00462 case QgsVectorLayer::EditRange: 00463 { 00464 if ( myFieldType == QVariant::Int ) 00465 { 00466 int min = vl->range( idx ).mMin.toInt(); 00467 int max = vl->range( idx ).mMax.toInt(); 00468 int step = vl->range( idx ).mStep.toInt(); 00469 00470 if ( editType == QgsVectorLayer::EditRange ) 00471 { 00472 QSpinBox *sb = 0; 00473 00474 if ( editor ) 00475 sb = qobject_cast<QSpinBox *>( editor ); 00476 else 00477 sb = new QSpinBox( parent ); 00478 00479 if ( sb ) 00480 { 00481 sb->setRange( min, max ); 00482 sb->setSingleStep( step ); 00483 00484 myWidget = sb; 00485 } 00486 } 00487 else 00488 { 00489 QAbstractSlider *sl = 0; 00490 00491 if ( editor ) 00492 { 00493 sl = qobject_cast<QAbstractSlider*>( editor ); 00494 } 00495 else if ( editType == QgsVectorLayer::DialRange ) 00496 { 00497 sl = new QDial( parent ); 00498 } 00499 else 00500 { 00501 sl = new QSlider( Qt::Horizontal, parent ); 00502 } 00503 00504 if ( sl ) 00505 { 00506 sl->setRange( min, max ); 00507 sl->setSingleStep( step ); 00508 00509 myWidget = sl; 00510 } 00511 } 00512 break; 00513 } 00514 else if ( myFieldType == QVariant::Double ) 00515 { 00516 QDoubleSpinBox *dsb = 0; 00517 if ( editor ) 00518 dsb = qobject_cast<QDoubleSpinBox*>( editor ); 00519 else 00520 dsb = new QDoubleSpinBox( parent ); 00521 00522 if ( dsb ) 00523 { 00524 double min = vl->range( idx ).mMin.toDouble(); 00525 double max = vl->range( idx ).mMax.toDouble(); 00526 double step = vl->range( idx ).mStep.toDouble(); 00527 00528 dsb->setRange( min, max ); 00529 dsb->setSingleStep( step ); 00530 00531 myWidget = dsb; 00532 } 00533 break; 00534 } 00535 } 00536 00537 case QgsVectorLayer::CheckBox: 00538 { 00539 QCheckBox *cb = 0; 00540 QGroupBox *gb = 0; 00541 if ( editor ) 00542 { 00543 gb = qobject_cast<QGroupBox *>( editor ); 00544 cb = qobject_cast<QCheckBox*>( editor ); 00545 } 00546 else 00547 cb = new QCheckBox( parent ); 00548 00549 if ( cb ) 00550 { 00551 myWidget = cb; 00552 break; 00553 } 00554 else if ( gb ) 00555 { 00556 myWidget = gb; 00557 break; 00558 } 00559 } 00560 00561 // fall-through 00562 00563 case QgsVectorLayer::LineEdit: 00564 case QgsVectorLayer::TextEdit: 00565 case QgsVectorLayer::UuidGenerator: 00566 case QgsVectorLayer::UniqueValuesEditable: 00567 case QgsVectorLayer::Immutable: 00568 { 00569 QLineEdit *le = 0; 00570 QTextEdit *te = 0; 00571 QPlainTextEdit *pte = 0; 00572 QComboBox * cb = 0; 00573 00574 if ( editor ) 00575 { 00576 le = qobject_cast<QLineEdit *>( editor ); 00577 te = qobject_cast<QTextEdit *>( editor ); 00578 pte = qobject_cast<QPlainTextEdit *>( editor ); 00579 cb = qobject_cast<QComboBox *>( editor ); 00580 } 00581 else if ( editType == QgsVectorLayer::TextEdit ) 00582 { 00583 pte = new QPlainTextEdit( parent ); 00584 } 00585 else 00586 { 00587 le = new QgsFilterLineEdit( parent ); 00588 } 00589 00590 if ( le ) 00591 { 00592 if ( editType == QgsVectorLayer::UniqueValuesEditable ) 00593 { 00594 QList<QVariant> values; 00595 vl->dataProvider()->uniqueValues( idx, values ); 00596 00597 QStringList svalues; 00598 for ( QList<QVariant>::const_iterator it = values.begin(); it != values.end(); it++ ) 00599 svalues << it->toString(); 00600 00601 QCompleter *c = new QCompleter( svalues ); 00602 c->setCompletionMode( QCompleter::PopupCompletion ); 00603 le->setCompleter( c ); 00604 } 00605 00606 if ( editType == QgsVectorLayer::UuidGenerator ) 00607 { 00608 le->setReadOnly( true ); 00609 } 00610 00611 le->setValidator( new QgsFieldValidator( le, field, vl->dateFormat( idx ) ) ); 00612 00613 myWidget = le; 00614 } 00615 00616 if ( te ) 00617 { 00618 te->setAcceptRichText( true ); 00619 myWidget = te; 00620 } 00621 00622 if ( pte ) 00623 { 00624 myWidget = pte; 00625 } 00626 00627 if ( cb ) 00628 { 00629 if ( cb->isEditable() ) 00630 cb->setValidator( new QgsFieldValidator( cb, field, vl->dateFormat( idx ) ) ); 00631 myWidget = cb; 00632 } 00633 00634 if ( myWidget ) 00635 { 00636 if ( editType == QgsVectorLayer::Immutable ) 00637 { 00638 myWidget->setDisabled( true ); 00639 } 00640 00641 QgsStringRelay* relay = NULL; 00642 00643 QMap<int, QWidget*>::const_iterator it = proxyWidgets.find( idx ); 00644 if ( it != proxyWidgets.end() ) 00645 { 00646 QObject* obj = qvariant_cast<QObject*>(( *it )->property( "QgisAttrEditProxy" ) ); 00647 relay = qobject_cast<QgsStringRelay*>( obj ); 00648 } 00649 else 00650 { 00651 relay = new QgsStringRelay( myWidget ); 00652 } 00653 00654 const char* rSlot = SLOT( changeText( QString ) ); 00655 const char* rSig = SIGNAL( textChanged( QString ) ); 00656 const char* wSlot = SLOT( setText( QString ) ); 00657 const char* wSig = SIGNAL( textChanged( QString ) ); 00658 if ( te || pte ) 00659 { 00660 rSlot = SLOT( changeText() ); 00661 wSig = SIGNAL( textChanged() ); 00662 } 00663 if ( pte ) 00664 { 00665 wSlot = SLOT( setPlainText( QString ) ); 00666 } 00667 if ( cb && cb->isEditable() ) 00668 { 00669 wSlot = SLOT( setEditText( QString ) ); 00670 wSig = SIGNAL( editTextChanged( QString ) ); 00671 } 00672 00673 synchronized = connect( relay, rSig, myWidget, wSlot ); 00674 synchronized &= connect( myWidget, wSig, relay, rSlot ); 00675 00676 // store list of proxies in relay 00677 relay->appendProxy( myWidget ); 00678 00679 if ( !cb || cb->isEditable() ) 00680 { 00681 myWidget->setProperty( "QgisAttrEditSlot", QVariant( QByteArray( wSlot ) ) ); 00682 myWidget->setProperty( "QgisAttrEditProxy", QVariant( QMetaType::QObjectStar, &relay ) ); 00683 } 00684 } 00685 } 00686 break; 00687 00688 case QgsVectorLayer::Hidden: 00689 myWidget = 0; 00690 break; 00691 00692 case QgsVectorLayer::FileName: 00693 case QgsVectorLayer::Calendar: 00694 case QgsVectorLayer::Photo: 00695 case QgsVectorLayer::WebView: 00696 case QgsVectorLayer::Color: 00697 { 00698 QCalendarWidget *cw = qobject_cast<QCalendarWidget *>( editor ); 00699 if ( cw ) 00700 { 00701 myWidget = cw; 00702 break; 00703 } 00704 00705 QWebView *ww = qobject_cast<QWebView *>( editor ); 00706 if ( ww ) 00707 { 00708 ww->page()->setNetworkAccessManager( QgsNetworkAccessManager::instance() ); 00709 ww->page()->setLinkDelegationPolicy( QWebPage::DelegateAllLinks ); 00710 ww->settings()->setAttribute( QWebSettings::LocalContentCanAccessRemoteUrls, true ); 00711 #ifdef QGISDEBUG 00712 ww->settings()->setAttribute( QWebSettings::DeveloperExtrasEnabled, true ); 00713 #endif 00714 myWidget = ww; 00715 break; 00716 } 00717 00718 QLabel *lw = qobject_cast<QLabel *>( editor ); 00719 if ( lw ) 00720 { 00721 myWidget = lw; 00722 break; 00723 } 00724 00725 QgsColorButton *cb = qobject_cast<QgsColorButton *>( editor ); 00726 if ( cb ) 00727 { 00728 myWidget = cb; 00729 break; 00730 } 00731 00732 QPushButton *pb = 0; 00733 QLineEdit *le = qobject_cast<QLineEdit *>( editor ); 00734 if ( le ) 00735 { 00736 if ( le ) 00737 myWidget = le; 00738 00739 if ( editor->parent() ) 00740 { 00741 pb = editor->parent()->findChild<QPushButton *>(); 00742 } 00743 } 00744 else 00745 { 00746 myWidget = new QWidget( parent ); 00747 myWidget->setBackgroundRole( QPalette::Window ); 00748 myWidget->setAutoFillBackground( true ); 00749 00750 le = new QgsFilterLineEdit( myWidget ); 00751 switch ( editType ) 00752 { 00753 case QgsVectorLayer::FileName: 00754 case QgsVectorLayer::Photo: 00755 case QgsVectorLayer::Calendar: 00756 pb = new QPushButton( tr( "..." ), myWidget ); 00757 break; 00758 00759 case QgsVectorLayer::WebView: 00760 pb = new QPushButton( tr( "<" ), myWidget ); 00761 break; 00762 00763 case QgsVectorLayer::Color: 00764 pb = new QgsColorButton( myWidget ); 00765 break; 00766 00767 default: 00768 break; 00769 } 00770 00771 00772 int row = 0; 00773 QGridLayout *layout = new QGridLayout( myWidget ); 00774 if ( editType == QgsVectorLayer::Photo ) 00775 { 00776 lw = new QLabel( myWidget ); 00777 layout->addWidget( lw, 0, 0, 1, 2 ); 00778 row++; 00779 } 00780 else if ( editType == QgsVectorLayer::WebView ) 00781 { 00782 ww = new QWebView( myWidget ); 00783 ww->page()->setNetworkAccessManager( QgsNetworkAccessManager::instance() ); 00784 ww->page()->setLinkDelegationPolicy( QWebPage::DelegateAllLinks ); 00785 ww->settings()->setAttribute( QWebSettings::LocalContentCanAccessRemoteUrls, true ); 00786 #ifdef QGISDEBUG 00787 ww->settings()->setAttribute( QWebSettings::DeveloperExtrasEnabled, true ); 00788 #endif 00789 layout->addWidget( ww, 0, 0, 1, 2 ); 00790 row++; 00791 } 00792 00793 layout->addWidget( le, row, 0 ); 00794 layout->addWidget( pb, row, 1 ); 00795 00796 myWidget->setLayout( layout ); 00797 } 00798 00799 if ( le ) 00800 { 00801 le->setValidator( new QgsFieldValidator( le, field, vl->dateFormat( idx ) ) ); 00802 00803 if ( ww ) 00804 connect( le, SIGNAL( textChanged( const QString & ) ), new QgsAttributeEditor( le, vl, idx ), SLOT( loadUrl( const QString & ) ) ); 00805 if ( lw ) 00806 connect( le, SIGNAL( textChanged( const QString & ) ), new QgsAttributeEditor( le, vl, idx ), SLOT( loadPixmap( const QString & ) ) ); 00807 if ( editType == QgsVectorLayer::Color ) 00808 connect( le, SIGNAL( textChanged( const QString & ) ), new QgsAttributeEditor( le ), SLOT( updateColor() ) ); 00809 } 00810 00811 if ( pb ) 00812 { 00813 if ( editType == QgsVectorLayer::FileName || editType == QgsVectorLayer::Photo ) 00814 connect( pb, SIGNAL( clicked() ), new QgsAttributeEditor( pb ), SLOT( selectFileName() ) ); 00815 if ( editType == QgsVectorLayer::WebView ) 00816 connect( pb, SIGNAL( clicked() ), new QgsAttributeEditor( pb ), SLOT( updateUrl() ) ); 00817 if ( editType == QgsVectorLayer::Calendar ) 00818 connect( pb, SIGNAL( clicked() ), new QgsAttributeEditor( pb ), SLOT( selectDate() ) ); 00819 if ( editType == QgsVectorLayer::Color ) 00820 connect( pb, SIGNAL( colorChanged( const QColor & ) ), new QgsAttributeEditor( pb ), SLOT( updateColor() ) ); 00821 } 00822 } 00823 break; 00824 } 00825 00826 QMap<int, QWidget*>::const_iterator it = proxyWidgets.find( idx ); 00827 if ( it != proxyWidgets.end() ) 00828 { 00829 if ( !synchronized ) 00830 { 00831 myWidget->setEnabled( false ); 00832 } 00833 } 00834 else 00835 { 00836 proxyWidgets.insert( idx, myWidget ); 00837 } 00838 00839 setValue( myWidget, vl, idx, value ); 00840 00841 return myWidget; 00842 } 00843 00844 bool QgsAttributeEditor::retrieveValue( QWidget *widget, QgsVectorLayer *vl, int idx, QVariant &value ) 00845 { 00846 if ( !widget ) 00847 return false; 00848 00849 const QgsField &theField = vl->pendingFields()[idx]; 00850 QgsVectorLayer::EditType editType = vl->editType( idx ); 00851 bool modified = false; 00852 QString text; 00853 00854 QSettings settings; 00855 QString nullValue = settings.value( "qgis/nullValue", "NULL" ).toString(); 00856 00857 QLineEdit *le = qobject_cast<QLineEdit *>( widget ); 00858 if ( le ) 00859 { 00860 text = le->text(); 00861 modified = le->isModified(); 00862 if ( text == nullValue ) 00863 { 00864 text = QString::null; 00865 } 00866 } 00867 00868 QTextEdit *te = qobject_cast<QTextEdit *>( widget ); 00869 if ( te ) 00870 { 00871 text = te->toHtml(); 00872 modified = te->document()->isModified(); 00873 if ( text == nullValue ) 00874 { 00875 text = QString::null; 00876 } 00877 } 00878 00879 QPlainTextEdit *pte = qobject_cast<QPlainTextEdit *>( widget ); 00880 if ( pte ) 00881 { 00882 text = pte->toPlainText(); 00883 modified = pte->document()->isModified(); 00884 if ( text == nullValue ) 00885 { 00886 text = QString::null; 00887 } 00888 } 00889 00890 QComboBox *cb = qobject_cast<QComboBox *>( widget ); 00891 if ( cb ) 00892 { 00893 if ( editType == QgsVectorLayer::UniqueValues || 00894 editType == QgsVectorLayer::ValueMap || 00895 editType == QgsVectorLayer::Classification || 00896 editType == QgsVectorLayer::ValueRelation ) 00897 { 00898 text = cb->itemData( cb->currentIndex() ).toString(); 00899 if ( text == nullValue ) 00900 { 00901 text = QString::null; 00902 } 00903 } 00904 else 00905 { 00906 text = cb->currentText(); 00907 } 00908 modified = true; 00909 } 00910 00911 QListWidget *lw = qobject_cast<QListWidget *>( widget ); 00912 if ( lw ) 00913 { 00914 if ( editType == QgsVectorLayer::ValueRelation ) 00915 { 00916 text = '{'; 00917 for ( int i = 0, n = 0; i < lw->count(); i++ ) 00918 { 00919 if ( lw->item( i )->checkState() == Qt::Checked ) 00920 { 00921 if ( n > 0 ) 00922 { 00923 text.append( ',' ); 00924 } 00925 text.append( lw->item( i )->data( Qt::UserRole ).toString() ); 00926 n++; 00927 } 00928 } 00929 text.append( '}' ); 00930 } 00931 else 00932 { 00933 text = QString::null; 00934 } 00935 modified = true; 00936 } 00937 00938 QSpinBox *sb = qobject_cast<QSpinBox *>( widget ); 00939 if ( sb ) 00940 { 00941 text = QString::number( sb->value() ); 00942 } 00943 00944 QAbstractSlider *slider = qobject_cast<QAbstractSlider *>( widget ); 00945 if ( slider ) 00946 { 00947 text = QString::number( slider->value() ); 00948 } 00949 00950 QDoubleSpinBox *dsb = qobject_cast<QDoubleSpinBox *>( widget ); 00951 if ( dsb ) 00952 { 00953 text = QString::number( dsb->value() ); 00954 } 00955 00956 QCheckBox *ckb = qobject_cast<QCheckBox *>( widget ); 00957 if ( ckb ) 00958 { 00959 QPair<QString, QString> states = vl->checkedState( idx ); 00960 text = ckb->isChecked() ? states.first : states.second; 00961 } 00962 00963 QGroupBox *gb = qobject_cast<QGroupBox *>( widget ); 00964 if ( gb ) 00965 { 00966 QPair<QString, QString> states = vl->checkedState( idx ); 00967 text = gb->isChecked() ? states.first : states.second; 00968 } 00969 00970 QCalendarWidget *cw = qobject_cast<QCalendarWidget *>( widget ); 00971 if ( cw ) 00972 { 00973 text = cw->selectedDate().toString( vl->dateFormat( idx ) ); 00974 } 00975 00976 le = widget->findChild<QLineEdit *>(); 00977 // QCalendarWidget and QGroupBox have an internal QLineEdit which returns the year 00978 // part of the date so we need to skip this if we have a QCalendarWidget 00979 if ( !cw && !gb && le ) 00980 { 00981 text = le->text(); 00982 modified = le->isModified(); 00983 if ( text == nullValue ) 00984 { 00985 text = QString::null; 00986 } 00987 } 00988 00989 switch ( theField.type() ) 00990 { 00991 case QVariant::Int: 00992 { 00993 bool ok; 00994 int myIntValue = text.toInt( &ok ); 00995 if ( ok && !text.isEmpty() ) 00996 { 00997 value = QVariant( myIntValue ); 00998 modified = true; 00999 } 01000 else if ( modified ) 01001 { 01002 value = QVariant(); 01003 } 01004 } 01005 break; 01006 case QVariant::LongLong: 01007 { 01008 bool ok; 01009 qlonglong myLongValue = text.toLong( &ok ); 01010 if ( ok && !text.isEmpty() ) 01011 { 01012 value = QVariant( myLongValue ); 01013 modified = true; 01014 } 01015 else if ( modified ) 01016 { 01017 value = QVariant(); 01018 } 01019 } 01020 case QVariant::Double: 01021 { 01022 bool ok; 01023 double myDblValue = text.toDouble( &ok ); 01024 if ( ok && !text.isEmpty() ) 01025 { 01026 value = QVariant( myDblValue ); 01027 modified = true; 01028 } 01029 else if ( modified ) 01030 { 01031 value = QVariant(); 01032 } 01033 } 01034 break; 01035 case QVariant::Date: 01036 { 01037 QDate myDateValue = QDate::fromString( text, vl->dateFormat( idx ) ); 01038 if ( myDateValue.isValid() && !text.isEmpty() ) 01039 { 01040 value = myDateValue; 01041 modified = true; 01042 } 01043 else if ( modified ) 01044 { 01045 value = QVariant(); 01046 } 01047 } 01048 break; 01049 default: //string 01050 modified = true; 01051 if ( text.isNull() ) 01052 value = QVariant(); 01053 else 01054 value = QVariant( text ); 01055 break; 01056 } 01057 01058 return modified; 01059 } 01060 01061 bool QgsAttributeEditor::setValue( QWidget *editor, QgsVectorLayer *vl, int idx, const QVariant &value ) 01062 { 01063 if ( !editor ) 01064 return false; 01065 01066 QgsVectorLayer::EditType editType = vl->editType( idx ); 01067 const QgsField &field = vl->pendingFields()[idx]; 01068 QVariant::Type myFieldType = field.type(); 01069 01070 QSettings settings; 01071 QString nullValue = settings.value( "qgis/nullValue", "NULL" ).toString(); 01072 01073 switch ( editType ) 01074 { 01075 case QgsVectorLayer::Classification: 01076 case QgsVectorLayer::UniqueValues: 01077 case QgsVectorLayer::Enumeration: 01078 case QgsVectorLayer::ValueMap: 01079 case QgsVectorLayer::ValueRelation: 01080 { 01081 QVariant v = value; 01082 QComboBox *cb = qobject_cast<QComboBox *>( editor ); 01083 if ( !cb ) 01084 return false; 01085 01086 if ( v.isNull() ) 01087 { 01088 v = nullValue; 01089 } 01090 01091 int idx = cb->findData( v ); 01092 if ( idx < 0 ) 01093 return false; 01094 01095 cb->setCurrentIndex( idx ); 01096 } 01097 break; 01098 01099 case QgsVectorLayer::DialRange: 01100 case QgsVectorLayer::SliderRange: 01101 case QgsVectorLayer::EditRange: 01102 { 01103 if ( myFieldType == QVariant::Int ) 01104 { 01105 if ( editType == QgsVectorLayer::EditRange ) 01106 { 01107 QSpinBox *sb = qobject_cast<QSpinBox *>( editor ); 01108 if ( !sb ) 01109 return false; 01110 sb->setValue( value.toInt() ); 01111 } 01112 else 01113 { 01114 QAbstractSlider *sl = qobject_cast<QAbstractSlider *>( editor ); 01115 if ( !sl ) 01116 return false; 01117 sl->setValue( value.toInt() ); 01118 } 01119 break; 01120 } 01121 else if ( myFieldType == QVariant::Double ) 01122 { 01123 QDoubleSpinBox *dsb = qobject_cast<QDoubleSpinBox *>( editor ); 01124 if ( !dsb ) 01125 return false; 01126 dsb->setValue( value.toDouble() ); 01127 } 01128 } 01129 01130 case QgsVectorLayer::CheckBox: 01131 { 01132 QGroupBox *gb = qobject_cast<QGroupBox *>( editor ); 01133 if ( gb ) 01134 { 01135 QPair<QString, QString> states = vl->checkedState( idx ); 01136 gb->setChecked( value == states.first ); 01137 break; 01138 } 01139 01140 QCheckBox *cb = qobject_cast<QCheckBox *>( editor ); 01141 if ( cb ) 01142 { 01143 QPair<QString, QString> states = vl->checkedState( idx ); 01144 cb->setChecked( value == states.first ); 01145 break; 01146 } 01147 } 01148 01149 // fall-through 01150 01151 case QgsVectorLayer::LineEdit: 01152 case QgsVectorLayer::UniqueValuesEditable: 01153 case QgsVectorLayer::Immutable: 01154 case QgsVectorLayer::UuidGenerator: 01155 case QgsVectorLayer::TextEdit: 01156 { 01157 QgsFilterLineEdit *fle = qobject_cast<QgsFilterLineEdit *>( editor ); 01158 QLineEdit *le = qobject_cast<QLineEdit *>( editor ); 01159 QComboBox *cb = qobject_cast<QComboBox *>( editor ); 01160 QTextEdit *te = qobject_cast<QTextEdit *>( editor ); 01161 QPlainTextEdit *pte = qobject_cast<QPlainTextEdit *>( editor ); 01162 if ( !le && ! cb && !te && !pte ) 01163 return false; 01164 01165 if ( fle && !( myFieldType == QVariant::Int || myFieldType == QVariant::Double || myFieldType == QVariant::LongLong || myFieldType == QVariant::Date ) ) 01166 { 01167 fle->setNullValue( nullValue ); 01168 } 01169 01170 QString text; 01171 if ( value.isNull() ) 01172 { 01173 if ( myFieldType == QVariant::Int || myFieldType == QVariant::Double || myFieldType == QVariant::LongLong || myFieldType == QVariant::Date ) 01174 text = ""; 01175 else if ( editType == QgsVectorLayer::UuidGenerator ) 01176 text = QUuid::createUuid().toString(); 01177 else 01178 text = nullValue; 01179 } 01180 else 01181 { 01182 text = field.displayString( value ); 01183 } 01184 01185 if ( le ) 01186 le->setText( text ); 01187 if ( cb && cb->isEditable() ) 01188 cb->setEditText( text ); 01189 if ( te ) 01190 te->setHtml( text ); 01191 if ( pte ) 01192 pte->setPlainText( text ); 01193 } 01194 break; 01195 01196 case QgsVectorLayer::FileName: 01197 case QgsVectorLayer::Calendar: 01198 case QgsVectorLayer::Photo: 01199 case QgsVectorLayer::WebView: 01200 case QgsVectorLayer::Color: 01201 { 01202 QCalendarWidget *cw = qobject_cast<QCalendarWidget *>( editor ); 01203 if ( cw ) 01204 { 01205 cw->setSelectedDate( value.toDate() ); 01206 break; 01207 } 01208 01209 QWebView *ww = qobject_cast<QWebView *>( editor ); 01210 if ( ww ) 01211 { 01212 ww->load( value.toString() ); 01213 break; 01214 } 01215 01216 QLabel *lw = qobject_cast<QLabel *>( editor ); 01217 if ( lw ) 01218 break; 01219 01220 QgsColorButton *cb = qobject_cast<QgsColorButton *>( editor ); 01221 if ( cb ) 01222 { 01223 cb->setColor( QColor( value.toString() ) ); 01224 break; 01225 } 01226 01227 QgsFilterLineEdit *fle = qobject_cast<QgsFilterLineEdit*>( editor ); 01228 QLineEdit *le = qobject_cast<QLineEdit*>( editor ); 01229 if ( !le ) 01230 { 01231 le = editor->findChild<QLineEdit *>(); 01232 fle = qobject_cast<QgsFilterLineEdit *>( le ); 01233 } 01234 if ( !le ) 01235 return false; 01236 01237 if ( fle && !( myFieldType == QVariant::Int || myFieldType == QVariant::Double || myFieldType == QVariant::LongLong || myFieldType == QVariant::Date ) ) 01238 { 01239 fle->setNullValue( nullValue ); 01240 } 01241 01242 QString text; 01243 if ( value.isNull() ) 01244 { 01245 if ( myFieldType == QVariant::Int || myFieldType == QVariant::Double || myFieldType == QVariant::LongLong || myFieldType == QVariant::Date ) 01246 text = ""; 01247 else 01248 text = nullValue; 01249 } 01250 else if ( editType == QgsVectorLayer::Calendar && value.canConvert( QVariant::Date ) ) 01251 { 01252 text = value.toDate().toString( vl->dateFormat( idx ) ); 01253 } 01254 else 01255 { 01256 text = value.toString(); 01257 } 01258 01259 le->setText( text ); 01260 } 01261 break; 01262 01263 case QgsVectorLayer::Hidden: 01264 break; 01265 } 01266 01267 return true; 01268 } 01269 01270 QWidget* QgsAttributeEditor::createWidgetFromDef( const QgsAttributeEditorElement* widgetDef, QWidget* parent, QgsVectorLayer* vl, QgsAttributes &attrs, QMap<int, QWidget*> &proxyWidgets, bool createGroupBox ) 01271 { 01272 QWidget *newWidget = 0; 01273 01274 switch ( widgetDef->type() ) 01275 { 01276 case QgsAttributeEditorElement::AeTypeField: 01277 { 01278 const QgsAttributeEditorField* fieldDef = dynamic_cast<const QgsAttributeEditorField*>( widgetDef ); 01279 newWidget = createAttributeEditor( parent, 0, vl, fieldDef->idx(), attrs.value( fieldDef->idx(), QVariant() ), proxyWidgets ); 01280 01281 if ( vl->editType( fieldDef->idx() ) != QgsVectorLayer::Immutable ) 01282 { 01283 newWidget->setEnabled( newWidget->isEnabled() && vl->isEditable() ); 01284 } 01285 01286 break; 01287 } 01288 01289 case QgsAttributeEditorElement::AeTypeContainer: 01290 { 01291 const QgsAttributeEditorContainer* container = dynamic_cast<const QgsAttributeEditorContainer*>( widgetDef ); 01292 QWidget* myContainer; 01293 01294 if ( createGroupBox ) 01295 { 01296 QGroupBox* groupBox = new QGroupBox( parent ); 01297 groupBox->setTitle( container->name() ); 01298 myContainer = groupBox; 01299 newWidget = myContainer; 01300 } 01301 else 01302 { 01303 QScrollArea *scrollArea = new QScrollArea( parent ); 01304 01305 myContainer = new QWidget( scrollArea ); 01306 01307 scrollArea->setWidget( myContainer ); 01308 scrollArea->setWidgetResizable( true ); 01309 scrollArea->setFrameShape( QFrame::NoFrame ); 01310 01311 newWidget = scrollArea; 01312 } 01313 01314 QGridLayout* gbLayout = new QGridLayout( myContainer ); 01315 myContainer->setLayout( gbLayout ); 01316 01317 int index = 0; 01318 01319 QList<QgsAttributeEditorElement*>children = container->children(); 01320 01321 for ( QList<QgsAttributeEditorElement*>::const_iterator it = children.begin(); it != children.end(); ++it ) 01322 { 01323 QgsAttributeEditorElement* childDef = *it; 01324 QWidget* editor = createWidgetFromDef( childDef, myContainer, vl, attrs, proxyWidgets, true ); 01325 01326 if ( childDef->type() == QgsAttributeEditorElement::AeTypeContainer ) 01327 { 01328 gbLayout->addWidget( editor, index, 0, 1, 2 ); 01329 } 01330 else 01331 { 01332 const QgsAttributeEditorField* fieldDef = dynamic_cast<const QgsAttributeEditorField*>( childDef ); 01333 01334 //show attribute alias if available 01335 QString myFieldName = vl->attributeDisplayName( fieldDef->idx() ); 01336 QLabel * mypLabel = new QLabel( myContainer ); 01337 gbLayout->addWidget( mypLabel, index, 0 ); 01338 mypLabel->setText( myFieldName ); 01339 01340 // add editor widget 01341 gbLayout->addWidget( editor, index, 1 ); 01342 } 01343 01344 ++index; 01345 } 01346 gbLayout->addItem( new QSpacerItem( 0, 0, QSizePolicy::Minimum, QSizePolicy::Expanding ), index , 0 ); 01347 01348 break; 01349 } 01350 01351 default: 01352 QgsDebugMsg( "Unknown attribute editor widget type encountered..." ); 01353 break; 01354 } 01355 01356 return newWidget; 01357 } 01358 01359 void QgsStringRelay::changeText() 01360 { 01361 QObject* sObj = QObject::sender(); 01362 QTextEdit *te = qobject_cast<QTextEdit *>( sObj ); 01363 QPlainTextEdit *pte = qobject_cast<QPlainTextEdit *>( sObj ); 01364 01365 if ( te ) 01366 changeText( te->toPlainText() ); 01367 if ( pte ) 01368 changeText( pte->toPlainText() ); 01369 } 01370 01371 void QgsStringRelay::changeText( QString str ) 01372 { 01373 QObject* sObj = QObject::sender(); 01374 const char* sSlot = sObj->property( "QgisAttrEditSlot" ).toByteArray().constData(); 01375 01376 // disconnect widget being edited from relay's signal 01377 disconnect( this, SIGNAL( textChanged( QString ) ), sObj, sSlot ); 01378 01379 // block all proxies' signals 01380 QList<bool> oldBlockSigs; 01381 for ( int i = 0; i < mProxyList.size(); ++i ) 01382 { 01383 oldBlockSigs << ( mProxyList[i] )->blockSignals( true ); 01384 } 01385 01386 // update all proxies not being edited without creating cyclical signals/slots 01387 emit textChanged( str ); 01388 01389 // reconnect widget being edited and reset blockSignals state 01390 connect( this, SIGNAL( textChanged( QString ) ), sObj, sSlot ); 01391 for ( int i = 0; i < mProxyList.size(); ++i ) 01392 { 01393 mProxyList[i]->blockSignals( oldBlockSigs[i] ); 01394 } 01395 }