Quantum GIS API Documentation  1.7.5-Wroclaw
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
qgsattributeeditor.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsattributeeditor.cpp - description
3  -------------------
4  begin : July 2009
5  copyright : (C) 2009 by Jürgen E. Fischer
6  email : jef@norbit.de
7  ***************************************************************************/
8 
9 /***************************************************************************
10  * *
11  * This program is free software; you can redistribute it and/or modify *
12  * it under the terms of the GNU General Public License as published by *
13  * the Free Software Foundation; either version 2 of the License, or *
14  * (at your option) any later version. *
15  * *
16  ***************************************************************************/
17 /* $Id$ */
18 
19 #include "qgsattributeeditor.h"
20 #include <qgsvectorlayer.h>
21 #include <qgsvectordataprovider.h>
22 #include <qgsuniquevaluerenderer.h>
24 #include <qgssymbol.h>
25 #include <qgslonglongvalidator.h>
26 #include <qgsfieldvalidator.h>
27 
28 #include <QPushButton>
29 #include <QLineEdit>
30 #include <QTextEdit>
31 #include <QFileDialog>
32 #include <QComboBox>
33 #include <QCheckBox>
34 #include <QSpinBox>
35 #include <QCompleter>
36 #include <QHBoxLayout>
37 #include <QPlainTextEdit>
38 #include <QDial>
39 #include <QCalendarWidget>
40 #include <QDialogButtonBox>
41 #include <QSettings>
42 #include <QDir>
43 
45 {
46  QPushButton *pb = qobject_cast<QPushButton *>( sender() );
47  if ( !pb )
48  return;
49 
50  QWidget *hbox = qobject_cast<QWidget *>( pb->parent() );
51  if ( !hbox )
52  return;
53 
54  QLineEdit *le = hbox->findChild<QLineEdit *>();
55  if ( !le )
56  return;
57 
58  QString fileName = QFileDialog::getOpenFileName( 0 , tr( "Select a file" ) );
59  if ( fileName.isNull() )
60  return;
61 
62  //le->setText( fileName );
63  le->setText( QDir::toNativeSeparators( fileName ) );
64 }
65 
67 {
68  QPushButton *pb = qobject_cast<QPushButton *>( sender() );
69  if ( !pb )
70  return;
71 
72  QWidget *hbox = qobject_cast<QWidget *>( pb->parent() );
73  if ( !hbox )
74  return;
75 
76  QLineEdit *le = hbox->findChild<QLineEdit *>();
77  if ( !le )
78  return;
79 
80  QDialog *dlg = new QDialog();
81  dlg->setWindowTitle( tr( "Select a date" ) );
82  QVBoxLayout *vl = new QVBoxLayout( dlg );
83 
84  QCalendarWidget *cw = new QCalendarWidget( dlg );
85  cw->setSelectedDate( QDate::fromString( le->text(), Qt::ISODate ) );
86  vl->addWidget( cw );
87 
88  QDialogButtonBox *buttonBox = new QDialogButtonBox( dlg );
89  buttonBox->addButton( QDialogButtonBox::Ok );
90  buttonBox->addButton( QDialogButtonBox::Cancel );
91  vl->addWidget( buttonBox );
92 
93  connect( buttonBox, SIGNAL( accepted() ), dlg, SLOT( accept() ) );
94  connect( buttonBox, SIGNAL( rejected() ), dlg, SLOT( reject() ) );
95 
96  if ( dlg->exec() == QDialog::Accepted )
97  {
98  le->setText( cw->selectedDate().toString( Qt::ISODate ) );
99  }
100 }
101 
102 QComboBox *QgsAttributeEditor::comboBox( QWidget *editor, QWidget *parent )
103 {
104  QComboBox *cb = NULL;
105  if ( editor )
106  cb = qobject_cast<QComboBox *>( editor );
107  else
108  cb = new QComboBox( parent );
109 
110  return cb;
111 }
112 
113 QWidget *QgsAttributeEditor::createAttributeEditor( QWidget *parent, QWidget *editor, QgsVectorLayer *vl, int idx, const QVariant &value )
114 {
115  if ( !vl )
116  return NULL;
117 
118  QWidget *myWidget = NULL;
119  QgsVectorLayer::EditType editType = vl->editType( idx );
120  const QgsField &field = vl->pendingFields()[idx];
121  QVariant::Type myFieldType = field.type();
122 
123  switch ( editType )
124  {
126  {
127  QList<QVariant> values;
128  vl->dataProvider()->uniqueValues( idx, values );
129 
130  QComboBox *cb = comboBox( editor, parent );
131  if ( cb )
132  {
133  cb->setEditable( false );
134 
135  for ( QList<QVariant>::iterator it = values.begin(); it != values.end(); it++ )
136  cb->addItem( it->toString(), it->toString() );
137 
138  myWidget = cb;
139  }
140  }
141  break;
142 
144  {
145  QStringList enumValues;
146  vl->dataProvider()->enumValues( idx, enumValues );
147 
148  QComboBox *cb = comboBox( editor, parent );
149  if ( cb )
150  {
151  QStringList::const_iterator s_it = enumValues.constBegin();
152  for ( ; s_it != enumValues.constEnd(); ++s_it )
153  {
154  cb->addItem( *s_it, *s_it );
155  }
156 
157  myWidget = cb;
158  }
159  }
160  break;
161 
163  {
164  const QMap<QString, QVariant> &map = vl->valueMap( idx );
165 
166  QComboBox *cb = comboBox( editor, parent );
167  if ( cb )
168  {
169  for ( QMap<QString, QVariant>::const_iterator it = map.begin(); it != map.end(); it++ )
170  {
171  cb->addItem( it.key(), it.value() );
172  }
173 
174  myWidget = cb;
175  }
176  }
177  break;
178 
180  {
181  QMap<QString, QString> classes;
182 
183  const QgsUniqueValueRenderer *uvr = dynamic_cast<const QgsUniqueValueRenderer *>( vl->renderer() );
184  if ( uvr )
185  {
186  const QList<QgsSymbol *> symbols = uvr->symbols();
187 
188  for ( int i = 0; i < symbols.size(); i++ )
189  {
190  QString label = symbols[i]->label();
191  QString name = symbols[i]->lowerValue();
192 
193  if ( label == "" )
194  label = name;
195 
196  classes.insert( name, label );
197  }
198  }
199 
200  const QgsCategorizedSymbolRendererV2 *csr = dynamic_cast<const QgsCategorizedSymbolRendererV2 *>( vl->rendererV2() );
201  if ( csr )
202  {
203  const QgsCategoryList &categories = (( QgsCategorizedSymbolRendererV2 * )csr )->categories(); // FIXME: QgsCategorizedSymbolRendererV2::categories() should be const
204  for ( int i = 0; i < categories.size(); i++ )
205  {
206  QString label = categories[i].label();
207  QString value = categories[i].value().toString();
208  if ( label.isEmpty() )
209  label = value;
210  classes.insert( value, label );
211  }
212  }
213 
214  QComboBox *cb = comboBox( editor, parent );
215  if ( cb )
216  {
217  for ( QMap<QString, QString>::const_iterator it = classes.begin(); it != classes.end(); it++ )
218  {
219  cb->addItem( it.value(), it.key() );
220  }
221 
222  myWidget = cb;
223  }
224  }
225  break;
226 
227 
231  {
232  if ( myFieldType == QVariant::Int )
233  {
234  int min = vl->range( idx ).mMin.toInt();
235  int max = vl->range( idx ).mMax.toInt();
236  int step = vl->range( idx ).mStep.toInt();
237 
238  if ( editType == QgsVectorLayer::EditRange )
239  {
240  QSpinBox *sb = NULL;
241 
242  if ( editor )
243  sb = qobject_cast<QSpinBox *>( editor );
244  else
245  sb = new QSpinBox( parent );
246 
247  if ( sb )
248  {
249  sb->setRange( min, max );
250  sb->setSingleStep( step );
251 
252  myWidget = sb;
253  }
254  }
255  else
256  {
257  QAbstractSlider *sl = NULL;
258 
259  if ( editor )
260  {
261  sl = qobject_cast<QAbstractSlider*>( editor );
262  }
263  else if ( editType == QgsVectorLayer::DialRange )
264  {
265  sl = new QDial( parent );
266  }
267  else
268  {
269  sl = new QSlider( Qt::Horizontal, parent );
270  }
271 
272  if ( sl )
273  {
274  sl->setRange( min, max );
275  sl->setSingleStep( step );
276 
277  myWidget = sl;
278  }
279  }
280  break;
281  }
282  else if ( myFieldType == QVariant::Double )
283  {
284  QDoubleSpinBox *dsb = NULL;
285  if ( editor )
286  dsb = qobject_cast<QDoubleSpinBox*>( editor );
287  else
288  dsb = new QDoubleSpinBox( parent );
289 
290  if ( dsb )
291  {
292  double min = vl->range( idx ).mMin.toDouble();
293  double max = vl->range( idx ).mMax.toDouble();
294  double step = vl->range( idx ).mStep.toDouble();
295 
296  dsb->setRange( min, max );
297  dsb->setSingleStep( step );
298 
299  myWidget = dsb;
300  }
301  break;
302  }
303  }
304 
306  {
307  QCheckBox *cb = NULL;
308  if ( editor )
309  cb = qobject_cast<QCheckBox*>( editor );
310  else
311  cb = new QCheckBox( parent );
312 
313  if ( cb )
314  {
315  myWidget = cb;
316  break;
317  }
318  }
319 
320  // fall-through
321 
326  {
327  QLineEdit *le = NULL;
328  QTextEdit *te = NULL;
329  QPlainTextEdit *pte = NULL;
330 
331  if ( editor )
332  {
333  le = qobject_cast<QLineEdit *>( editor );
334  te = qobject_cast<QTextEdit *>( editor );
335  pte = qobject_cast<QPlainTextEdit *>( editor );
336  }
337  else if ( editType == QgsVectorLayer::TextEdit )
338  {
339  pte = new QPlainTextEdit( parent );
340  }
341  else
342  {
343  le = new QLineEdit( parent );
344  }
345 
346  if ( le )
347  {
348 
349  if ( editType == QgsVectorLayer::UniqueValuesEditable )
350  {
351  QList<QVariant> values;
352  vl->dataProvider()->uniqueValues( idx, values );
353 
354  QStringList svalues;
355  for ( QList<QVariant>::const_iterator it = values.begin(); it != values.end(); it++ )
356  svalues << it->toString();
357 
358  QCompleter *c = new QCompleter( svalues );
359  c->setCompletionMode( QCompleter::PopupCompletion );
360  le->setCompleter( c );
361  }
362 
363  le->setValidator( new QgsFieldValidator( le, field ) );
364  myWidget = le;
365  }
366 
367  if ( te )
368  {
369  te->setAcceptRichText( true );
370  myWidget = te;
371  }
372 
373  if ( pte )
374  {
375  myWidget = pte;
376  }
377 
378  if ( myWidget )
379  {
380  myWidget->setDisabled( editType == QgsVectorLayer::Immutable );
381  }
382  }
383  break;
384 
386  myWidget = NULL;
387  break;
388 
391  {
392  QPushButton *pb = NULL;
393  QLineEdit *le = qobject_cast<QLineEdit *>( editor );
394  if ( le )
395  {
396  if ( le )
397  myWidget = le;
398 
399  if ( editor->parent() )
400  {
401  pb = editor->parent()->findChild<QPushButton *>();
402  }
403  }
404  else
405  {
406  le = new QLineEdit();
407 
408  pb = new QPushButton( tr( "..." ) );
409 
410  QHBoxLayout *hbl = new QHBoxLayout();
411  hbl->addWidget( le );
412  hbl->addWidget( pb );
413 
414  myWidget = new QWidget( parent );
415  myWidget->setBackgroundRole( QPalette::Window );
416  myWidget->setAutoFillBackground( true );
417  myWidget->setLayout( hbl );
418  }
419 
420  if ( pb )
421  {
422  if ( editType == QgsVectorLayer::FileName )
423  connect( pb, SIGNAL( clicked() ), new QgsAttributeEditor( pb ), SLOT( selectFileName() ) );
424  if ( editType == QgsVectorLayer::Calendar )
425  connect( pb, SIGNAL( clicked() ), new QgsAttributeEditor( pb ), SLOT( selectDate() ) );
426  }
427  }
428  break;
429  }
430 
431  setValue( myWidget, vl, idx, value );
432 
433  return myWidget;
434 }
435 
436 bool QgsAttributeEditor::retrieveValue( QWidget *widget, QgsVectorLayer *vl, int idx, QVariant &value )
437 {
438  if ( !widget )
439  return false;
440 
441  const QgsField &theField = vl->pendingFields()[idx];
442  QgsVectorLayer::EditType editType = vl->editType( idx );
443  bool modified = false;
444  QString text;
445 
446  QSettings settings;
447  QString nullValue = settings.value( "qgis/nullValue", "NULL" ).toString();
448 
449  QLineEdit *le = qobject_cast<QLineEdit *>( widget );
450  if ( le )
451  {
452  text = le->text();
453  modified = le->isModified();
454  if ( text == nullValue )
455  {
456  text = QString::null;
457  }
458  }
459 
460  QTextEdit *te = qobject_cast<QTextEdit *>( widget );
461  if ( te )
462  {
463  text = te->toHtml();
464  modified = te->document()->isModified();
465  if ( text == nullValue )
466  {
467  text = QString::null;
468  }
469  }
470 
471  QPlainTextEdit *pte = qobject_cast<QPlainTextEdit *>( widget );
472  if ( pte )
473  {
474  text = pte->toPlainText();
475  modified = pte->document()->isModified();
476  if ( text == nullValue )
477  {
478  text = QString::null;
479  }
480  }
481 
482  QComboBox *cb = qobject_cast<QComboBox *>( widget );
483  if ( cb )
484  {
485  if ( editType == QgsVectorLayer::UniqueValues ||
486  editType == QgsVectorLayer::ValueMap ||
487  editType == QgsVectorLayer::Classification )
488  {
489  text = cb->itemData( cb->currentIndex() ).toString();
490  if ( text == nullValue )
491  {
492  text = QString::null;
493  }
494  }
495  else
496  {
497  text = cb->currentText();
498  }
499  modified = true;
500  }
501 
502  QSpinBox *sb = qobject_cast<QSpinBox *>( widget );
503  if ( sb )
504  {
505  text = QString::number( sb->value() );
506  }
507 
508  QAbstractSlider *slider = qobject_cast<QAbstractSlider *>( widget );
509  if ( slider )
510  {
511  text = QString::number( slider->value() );
512  }
513 
514  QDoubleSpinBox *dsb = qobject_cast<QDoubleSpinBox *>( widget );
515  if ( dsb )
516  {
517  text = QString::number( dsb->value() );
518  }
519 
520  QCheckBox *ckb = qobject_cast<QCheckBox *>( widget );
521  if ( ckb )
522  {
523  QPair<QString, QString> states = vl->checkedState( idx );
524  text = ckb->isChecked() ? states.first : states.second;
525  }
526 
527  QCalendarWidget *cw = qobject_cast<QCalendarWidget *>( widget );
528  if ( cw )
529  {
530  text = cw->selectedDate().toString();
531  }
532 
533  le = widget->findChild<QLineEdit *>();
534  if ( le )
535  {
536  text = le->text();
537  }
538 
539  switch ( theField.type() )
540  {
541  case QVariant::Int:
542  {
543  bool ok;
544  int myIntValue = text.toInt( &ok );
545  if ( ok && !text.isEmpty() )
546  {
547  value = QVariant( myIntValue );
548  modified = true;
549  }
550  else if ( modified )
551  {
552  value = QVariant();
553  }
554  }
555  break;
556  case QVariant::LongLong:
557  {
558  bool ok;
559  qlonglong myLongValue = text.toLong( &ok );
560  if ( ok && !text.isEmpty() )
561  {
562  value = QVariant( myLongValue );
563  modified = true;
564  }
565  else if ( modified )
566  {
567  value = QVariant();
568  }
569  }
570  case QVariant::Double:
571  {
572  bool ok;
573  double myDblValue = text.toDouble( &ok );
574  if ( ok && !text.isEmpty() )
575  {
576  value = QVariant( myDblValue );
577  modified = true;
578  }
579  else if ( modified )
580  {
581  value = QVariant();
582  }
583  }
584  break;
585  case QVariant::Date:
586  {
587  QDate myDateValue = QDate::fromString( text, Qt::ISODate );
588  if ( myDateValue.isValid() && !text.isEmpty() )
589  {
590  value = myDateValue;
591  modified = true;
592  }
593  else if ( modified )
594  {
595  value = QVariant();
596  }
597  }
598  break;
599  default: //string
600  modified = true;
601  value = QVariant( text );
602  break;
603  }
604 
605  return modified;
606 }
607 
608 bool QgsAttributeEditor::setValue( QWidget *editor, QgsVectorLayer *vl, int idx, const QVariant &value )
609 {
610  if ( !editor )
611  return false;
612 
613  QgsVectorLayer::EditType editType = vl->editType( idx );
614  const QgsField &field = vl->pendingFields()[idx];
615  QVariant::Type myFieldType = field.type();
616 
617  QSettings settings;
618  QString nullValue = settings.value( "qgis/nullValue", "NULL" ).toString();
619 
620  switch ( editType )
621  {
626  {
627  QVariant v = value;
628  QComboBox *cb = qobject_cast<QComboBox *>( editor );
629  if ( cb == NULL )
630  return false;
631 
632  if ( v.isNull() )
633  {
634  v = nullValue;
635  }
636 
637  int idx = cb->findData( v );
638  if ( idx < 0 )
639  return false;
640 
641  cb->setCurrentIndex( idx );
642  }
643  break;
644 
648  {
649  if ( myFieldType == QVariant::Int )
650  {
651  if ( editType == QgsVectorLayer::EditRange )
652  {
653  QSpinBox *sb = qobject_cast<QSpinBox *>( editor );
654  if ( sb == NULL )
655  return false;
656  sb->setValue( value.toInt() );
657  }
658  else
659  {
660  QAbstractSlider *sl = qobject_cast<QAbstractSlider *>( editor );
661  if ( sl == NULL )
662  return false;
663  sl->setValue( value.toInt() );
664  }
665  break;
666  }
667  else if ( myFieldType == QVariant::Double )
668  {
669  QDoubleSpinBox *dsb = qobject_cast<QDoubleSpinBox *>( editor );
670  if ( dsb == NULL )
671  return false;
672  dsb->setValue( value.toDouble() );
673  }
674  }
675 
677  {
678  QCheckBox *cb = qobject_cast<QCheckBox *>( editor );
679  if ( cb )
680  {
681  QPair<QString, QString> states = vl->checkedState( idx );
682  cb->setChecked( value == states.first );
683  break;
684  }
685  }
686 
687  // fall-through
688 
692  default:
693  {
694  QLineEdit *le = qobject_cast<QLineEdit *>( editor );
695  QTextEdit *te = qobject_cast<QTextEdit *>( editor );
696  QPlainTextEdit *pte = qobject_cast<QPlainTextEdit *>( editor );
697  if ( !le && !te && !pte )
698  return false;
699 
700  QString text;
701  if ( value.isNull() )
702  if ( myFieldType == QVariant::Int || myFieldType == QVariant::Double || myFieldType == QVariant::LongLong )
703  text = "";
704  else
705  text = nullValue;
706  else
707  text = value.toString();
708 
709  if ( le )
710  le->setText( text );
711  if ( te )
712  te->setHtml( text );
713  if ( pte )
714  pte->setPlainText( text );
715  }
716  break;
717 
720  {
721  QLineEdit* le = qobject_cast<QLineEdit*>( editor );
722  if( !le )
723  {
724  le = editor->findChild<QLineEdit *>();
725  }
726  if ( !le )
727  {
728  return false;
729  }
730  le->setText( value.toString() );
731  }
732  break;
733  }
734 
735  return true;
736 }