Quantum GIS API Documentation  1.7.4
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 /* $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 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines