QGIS API Documentation  master-3f58142
src/gui/qgsattributeeditor.cpp
Go to the documentation of this file.
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 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Defines