1# -*- coding: utf-8 -*- 2"""QGIS Unit tests for QgsFieldModel 3 4.. note:: This program is free software; you can redistribute it and/or modify 5it under the terms of the GNU General Public License as published by 6the Free Software Foundation; either version 2 of the License, or 7(at your option) any later version. 8""" 9__author__ = 'Nyall Dawson' 10__date__ = '14/11/2016' 11__copyright__ = 'Copyright 2016, The QGIS Project' 12 13import qgis # NOQA 14 15from qgis.core import (QgsField, 16 QgsFields, 17 QgsVectorLayer, 18 QgsFieldModel, 19 QgsFieldProxyModel, 20 QgsEditorWidgetSetup, 21 QgsProject, 22 QgsVectorLayerJoinInfo, 23 QgsFieldConstraints) 24from qgis.PyQt.QtCore import QVariant, Qt, QModelIndex 25 26from qgis.testing import start_app, unittest 27 28start_app() 29 30 31def create_layer(): 32 layer = QgsVectorLayer("Point?field=fldtxt:string&field=fldint:integer", 33 "addfeat", "memory") 34 layer.setEditorWidgetSetup(0, QgsEditorWidgetSetup('Hidden', {})) 35 layer.setEditorWidgetSetup(1, QgsEditorWidgetSetup('ValueMap', {})) 36 assert layer.isValid() 37 return layer 38 39 40def create_model(): 41 l = create_layer() 42 m = QgsFieldModel() 43 m.setLayer(l) 44 return l, m 45 46 47class TestQgsFieldModel(unittest.TestCase): 48 49 def testGettersSetters(self): 50 """ test model getters/setters """ 51 l = create_layer() 52 m = QgsFieldModel() 53 54 self.assertFalse(m.layer()) 55 m.setLayer(l) 56 self.assertEqual(m.layer(), l) 57 58 m.setAllowExpression(True) 59 self.assertTrue(m.allowExpression()) 60 m.setAllowExpression(False) 61 self.assertFalse(m.allowExpression()) 62 63 m.setAllowEmptyFieldName(True) 64 self.assertTrue(m.allowEmptyFieldName()) 65 m.setAllowEmptyFieldName(False) 66 self.assertFalse(m.allowEmptyFieldName()) 67 68 fields = QgsFields() 69 fields.append(QgsField('test1', QVariant.String)) 70 fields.append(QgsField('test2', QVariant.String)) 71 m.setFields(fields) 72 self.assertIsNone(m.layer()) 73 self.assertEqual(m.fields(), fields) 74 75 def testIndexFromName(self): 76 l, m = create_model() 77 i = m.indexFromName('fldtxt') 78 self.assertTrue(i.isValid()) 79 self.assertEqual(i.row(), 0) 80 i = m.indexFromName('fldint') 81 self.assertTrue(i.isValid()) 82 self.assertEqual(i.row(), 1) 83 i = m.indexFromName('not a field') 84 self.assertFalse(i.isValid()) 85 86 # test with alias 87 i = m.indexFromName('text field') 88 self.assertFalse(i.isValid()) 89 l.setFieldAlias(0, 'text field') 90 i = m.indexFromName('text field') 91 self.assertTrue(i.isValid()) 92 self.assertEqual(i.row(), 0) 93 i = m.indexFromName('int field') 94 self.assertFalse(i.isValid()) 95 l.setFieldAlias(1, 'int field') 96 i = m.indexFromName('int field') 97 self.assertTrue(i.isValid()) 98 self.assertEqual(i.row(), 1) 99 100 # should be case insensitive 101 i = m.indexFromName('FLDTXT') 102 self.assertTrue(i.isValid()) 103 self.assertEqual(i.row(), 0) 104 i = m.indexFromName('FLDINT') 105 self.assertTrue(i.isValid()) 106 self.assertEqual(i.row(), 1) 107 108 # try with expression 109 m.setAllowExpression(True) 110 i = m.indexFromName('not a field') 111 # still not valid - needs expression set first 112 self.assertFalse(i.isValid()) 113 m.setExpression('not a field') 114 i = m.indexFromName('not a field') 115 self.assertTrue(i.isValid()) 116 self.assertEqual(i.row(), 2) 117 118 # try with null 119 i = m.indexFromName(None) 120 self.assertFalse(i.isValid()) 121 m.setAllowEmptyFieldName(True) 122 i = m.indexFromName(None) 123 self.assertTrue(i.isValid()) 124 self.assertEqual(i.row(), 0) 125 # when null is shown, all other rows should be offset 126 self.assertEqual(m.indexFromName('fldtxt').row(), 1) 127 self.assertEqual(m.indexFromName('fldint').row(), 2) 128 self.assertEqual(m.indexFromName('not a field').row(), 3) 129 self.assertEqual(m.indexFromName('FLDTXT').row(), 1) 130 self.assertEqual(m.indexFromName('FLDINT').row(), 2) 131 132 def testIsField(self): 133 l, m = create_model() 134 self.assertTrue(m.isField('fldtxt')) 135 self.assertTrue(m.isField('fldint')) 136 self.assertFalse(m.isField(None)) 137 self.assertFalse(m.isField('an expression')) 138 139 def testRowCount(self): 140 l, m = create_model() 141 self.assertEqual(m.rowCount(), 2) 142 m.setAllowEmptyFieldName(True) 143 self.assertEqual(m.rowCount(), 3) 144 m.setAllowExpression(True) 145 m.setExpression('not a field') 146 self.assertEqual(m.rowCount(), 4) 147 m.setExpression('not a field') 148 self.assertEqual(m.rowCount(), 4) 149 m.setExpression('not a field 2') 150 self.assertEqual(m.rowCount(), 4) 151 m.removeExpression() 152 self.assertEqual(m.rowCount(), 3) 153 154 def testFieldNameRole(self): 155 l, m = create_model() 156 self.assertEqual(m.data(m.indexFromName('fldtxt'), QgsFieldModel.FieldNameRole), 'fldtxt') 157 self.assertEqual(m.data(m.indexFromName('fldint'), QgsFieldModel.FieldNameRole), 'fldint') 158 self.assertFalse(m.data(m.indexFromName('an expression'), QgsFieldModel.FieldNameRole)) 159 self.assertFalse(m.data(m.indexFromName(None), QgsFieldModel.FieldNameRole)) 160 m.setAllowExpression(True) 161 m.setExpression('an expression') 162 self.assertFalse(m.data(m.indexFromName('an expression'), QgsFieldModel.FieldNameRole)) 163 m.setAllowEmptyFieldName(True) 164 self.assertFalse(m.data(m.indexFromName(None), QgsFieldModel.FieldNameRole)) 165 166 def testExpressionRole(self): 167 l, m = create_model() 168 self.assertEqual(m.data(m.indexFromName('fldtxt'), QgsFieldModel.ExpressionRole), 'fldtxt') 169 self.assertEqual(m.data(m.indexFromName('fldint'), QgsFieldModel.ExpressionRole), 'fldint') 170 self.assertFalse(m.data(m.indexFromName('an expression'), QgsFieldModel.ExpressionRole)) 171 self.assertFalse(m.data(m.indexFromName(None), QgsFieldModel.ExpressionRole)) 172 m.setAllowExpression(True) 173 m.setExpression('an expression') 174 self.assertEqual(m.data(m.indexFromName('an expression'), QgsFieldModel.ExpressionRole), 'an expression') 175 m.setAllowEmptyFieldName(True) 176 self.assertFalse(m.data(m.indexFromName(None), QgsFieldModel.ExpressionRole)) 177 178 def testFieldIndexRole(self): 179 l, m = create_model() 180 self.assertEqual(m.data(m.indexFromName('fldtxt'), QgsFieldModel.FieldIndexRole), 0) 181 self.assertEqual(m.data(m.indexFromName('fldint'), QgsFieldModel.FieldIndexRole), 1) 182 self.assertFalse(m.data(m.indexFromName('an expression'), QgsFieldModel.FieldIndexRole)) 183 self.assertFalse(m.data(m.indexFromName(None), QgsFieldModel.FieldIndexRole)) 184 m.setAllowExpression(True) 185 m.setExpression('an expression') 186 self.assertFalse(m.data(m.indexFromName('an expression'), QgsFieldModel.FieldIndexRole)) 187 m.setAllowEmptyFieldName(True) 188 self.assertFalse(m.data(m.indexFromName(None), QgsFieldModel.FieldIndexRole)) 189 190 def testIsExpressionRole(self): 191 l, m = create_model() 192 self.assertFalse(m.data(m.indexFromName('fldtxt'), QgsFieldModel.IsExpressionRole)) 193 self.assertFalse(m.data(m.indexFromName('fldint'), QgsFieldModel.IsExpressionRole)) 194 self.assertFalse(m.data(m.indexFromName('an expression'), QgsFieldModel.IsExpressionRole)) 195 self.assertFalse(m.data(m.indexFromName(None), QgsFieldModel.IsExpressionRole)) 196 m.setAllowExpression(True) 197 m.setExpression('an expression') 198 self.assertTrue(m.data(m.indexFromName('an expression'), QgsFieldModel.IsExpressionRole)) 199 m.setAllowEmptyFieldName(True) 200 self.assertFalse(m.data(m.indexFromName(None), QgsFieldModel.IsExpressionRole)) 201 202 def testExpressionValidityRole(self): 203 l, m = create_model() 204 self.assertTrue(m.data(m.indexFromName('fldtxt'), QgsFieldModel.ExpressionValidityRole)) 205 self.assertTrue(m.data(m.indexFromName('fldint'), QgsFieldModel.ExpressionValidityRole)) 206 self.assertFalse(m.data(m.indexFromName('an expression'), QgsFieldModel.ExpressionValidityRole)) 207 self.assertFalse(m.data(m.indexFromName(None), QgsFieldModel.ExpressionValidityRole)) 208 m.setAllowExpression(True) 209 m.setExpression('an expression') 210 self.assertFalse(m.data(m.indexFromName('an expression'), QgsFieldModel.ExpressionValidityRole)) 211 m.setAllowEmptyFieldName(True) 212 self.assertTrue(m.data(m.indexFromName(None), QgsFieldModel.ExpressionValidityRole)) 213 214 def testFieldTypeRole(self): 215 l, m = create_model() 216 self.assertEqual(m.data(m.indexFromName('fldtxt'), QgsFieldModel.FieldTypeRole), QVariant.String) 217 self.assertEqual(m.data(m.indexFromName('fldint'), QgsFieldModel.FieldTypeRole), QVariant.Int) 218 self.assertFalse(m.data(m.indexFromName('an expression'), QgsFieldModel.FieldTypeRole)) 219 self.assertFalse(m.data(m.indexFromName(None), QgsFieldModel.FieldTypeRole)) 220 m.setAllowExpression(True) 221 m.setExpression('an expression') 222 self.assertFalse(m.data(m.indexFromName('an expression'), QgsFieldModel.FieldTypeRole)) 223 m.setAllowEmptyFieldName(True) 224 self.assertFalse(m.data(m.indexFromName(None), QgsFieldModel.FieldTypeRole)) 225 226 def testFieldOriginRole(self): 227 l, m = create_model() 228 self.assertEqual(m.data(m.indexFromName('fldtxt'), QgsFieldModel.FieldOriginRole), QgsFields.OriginProvider) 229 self.assertEqual(m.data(m.indexFromName('fldint'), QgsFieldModel.FieldOriginRole), QgsFields.OriginProvider) 230 self.assertFalse(m.data(m.indexFromName('an expression'), QgsFieldModel.FieldOriginRole)) 231 self.assertFalse(m.data(m.indexFromName(None), QgsFieldModel.FieldOriginRole)) 232 m.setAllowExpression(True) 233 m.setExpression('an expression') 234 self.assertFalse(m.data(m.indexFromName('an expression'), QgsFieldModel.FieldOriginRole)) 235 m.setAllowEmptyFieldName(True) 236 self.assertFalse(m.data(m.indexFromName(None), QgsFieldModel.FieldOriginRole)) 237 238 def testIsEmptyRole(self): 239 l, m = create_model() 240 self.assertFalse(m.data(m.indexFromName('fldtxt'), QgsFieldModel.IsEmptyRole), QgsFields.OriginProvider) 241 self.assertFalse(m.data(m.indexFromName('fldint'), QgsFieldModel.IsEmptyRole), QgsFields.OriginProvider) 242 self.assertFalse(m.data(m.indexFromName('an expression'), QgsFieldModel.IsEmptyRole)) 243 self.assertFalse(m.data(m.indexFromName(None), QgsFieldModel.IsEmptyRole)) 244 m.setAllowExpression(True) 245 m.setExpression('an expression') 246 self.assertFalse(m.data(m.indexFromName('an expression'), QgsFieldModel.IsEmptyRole)) 247 m.setAllowEmptyFieldName(True) 248 self.assertTrue(m.data(m.indexFromName(None), QgsFieldModel.IsEmptyRole)) 249 250 def testDisplayRole(self): 251 l, m = create_model() 252 self.assertEqual(m.data(m.indexFromName('fldtxt'), Qt.DisplayRole), 'fldtxt') 253 self.assertEqual(m.data(m.indexFromName('fldint'), Qt.DisplayRole), 'fldint') 254 self.assertFalse(m.data(m.indexFromName('an expression'), Qt.DisplayRole)) 255 self.assertFalse(m.data(m.indexFromName(None), Qt.DisplayRole)) 256 m.setAllowExpression(True) 257 m.setExpression('an expression') 258 self.assertEqual(m.data(m.indexFromName('an expression'), Qt.DisplayRole), 'an expression') 259 m.setAllowEmptyFieldName(True) 260 self.assertFalse(m.data(m.indexFromName(None), Qt.DisplayRole)) 261 262 def testManualFields(self): 263 _, m = create_model() 264 fields = QgsFields() 265 fields.append(QgsField('f1', QVariant.String)) 266 fields.append(QgsField('f2', QVariant.String)) 267 m.setFields(fields) 268 self.assertEqual(m.rowCount(), 2) 269 self.assertEqual(m.data(m.index(0, 0, QModelIndex()), Qt.DisplayRole), 'f1') 270 self.assertEqual(m.data(m.index(1, 0, QModelIndex()), Qt.DisplayRole), 'f2') 271 272 def testEditorWidgetTypeRole(self): 273 l, m = create_model() 274 self.assertEqual(m.data(m.indexFromName('fldtxt'), QgsFieldModel.EditorWidgetType), 'Hidden') 275 self.assertEqual(m.data(m.indexFromName('fldint'), QgsFieldModel.EditorWidgetType), 'ValueMap') 276 self.assertIsNone(m.data(m.indexFromName('an expression'), QgsFieldModel.EditorWidgetType)) 277 self.assertIsNone(m.data(m.indexFromName(None), QgsFieldModel.EditorWidgetType)) 278 m.setAllowExpression(True) 279 m.setExpression('an expression') 280 self.assertIsNone(m.data(m.indexFromName('an expression'), QgsFieldModel.EditorWidgetType)) 281 m.setAllowEmptyFieldName(True) 282 self.assertIsNone(m.data(m.indexFromName(None), QgsFieldModel.EditorWidgetType)) 283 284 def testJoinedFieldIsEditableRole(self): 285 layer = QgsVectorLayer("Point?field=id_a:integer", 286 "addfeat", "memory") 287 layer2 = QgsVectorLayer("Point?field=id_b:integer&field=value_b", 288 "addfeat", "memory") 289 QgsProject.instance().addMapLayers([layer, layer2]) 290 291 # editable join 292 join_info = QgsVectorLayerJoinInfo() 293 join_info.setTargetFieldName("id_a") 294 join_info.setJoinLayer(layer2) 295 join_info.setJoinFieldName("id_b") 296 join_info.setPrefix("B_") 297 join_info.setEditable(True) 298 join_info.setUpsertOnEdit(True) 299 layer.addJoin(join_info) 300 301 m = QgsFieldModel() 302 m.setLayer(layer) 303 304 self.assertIsNone(m.data(m.indexFromName('id_a'), QgsFieldModel.JoinedFieldIsEditable)) 305 self.assertTrue(m.data(m.indexFromName('B_value_b'), QgsFieldModel.JoinedFieldIsEditable)) 306 self.assertIsNone(m.data(m.indexFromName('an expression'), QgsFieldModel.JoinedFieldIsEditable)) 307 self.assertIsNone(m.data(m.indexFromName(None), QgsFieldModel.JoinedFieldIsEditable)) 308 m.setAllowExpression(True) 309 m.setExpression('an expression') 310 self.assertIsNone(m.data(m.indexFromName('an expression'), QgsFieldModel.JoinedFieldIsEditable)) 311 m.setAllowEmptyFieldName(True) 312 self.assertIsNone(m.data(m.indexFromName(None), QgsFieldModel.JoinedFieldIsEditable)) 313 314 proxy_m = QgsFieldProxyModel() 315 proxy_m.setFilters(QgsFieldProxyModel.AllTypes | QgsFieldProxyModel.HideReadOnly) 316 proxy_m.sourceFieldModel().setLayer(layer) 317 self.assertEqual(proxy_m.rowCount(), 2) 318 self.assertEqual(proxy_m.data(proxy_m.index(0, 0)), 'id_a') 319 self.assertEqual(proxy_m.data(proxy_m.index(1, 0)), 'B_value_b') 320 321 # not editable join 322 layer3 = QgsVectorLayer("Point?field=id_a:integer", 323 "addfeat", "memory") 324 QgsProject.instance().addMapLayers([layer3]) 325 join_info = QgsVectorLayerJoinInfo() 326 join_info.setTargetFieldName("id_a") 327 join_info.setJoinLayer(layer2) 328 join_info.setJoinFieldName("id_b") 329 join_info.setPrefix("B_") 330 join_info.setEditable(False) 331 332 layer3.addJoin(join_info) 333 m = QgsFieldModel() 334 m.setLayer(layer3) 335 336 self.assertIsNone(m.data(m.indexFromName('id_a'), QgsFieldModel.JoinedFieldIsEditable)) 337 self.assertFalse(m.data(m.indexFromName('B_value_b'), QgsFieldModel.JoinedFieldIsEditable)) 338 self.assertIsNone(m.data(m.indexFromName('an expression'), QgsFieldModel.JoinedFieldIsEditable)) 339 self.assertIsNone(m.data(m.indexFromName(None), QgsFieldModel.JoinedFieldIsEditable)) 340 m.setAllowExpression(True) 341 m.setExpression('an expression') 342 self.assertIsNone(m.data(m.indexFromName('an expression'), QgsFieldModel.JoinedFieldIsEditable)) 343 m.setAllowEmptyFieldName(True) 344 self.assertIsNone(m.data(m.indexFromName(None), QgsFieldModel.JoinedFieldIsEditable)) 345 346 proxy_m = QgsFieldProxyModel() 347 proxy_m.sourceFieldModel().setLayer(layer3) 348 proxy_m.setFilters(QgsFieldProxyModel.AllTypes | QgsFieldProxyModel.HideReadOnly) 349 self.assertEqual(proxy_m.rowCount(), 1) 350 self.assertEqual(proxy_m.data(proxy_m.index(0, 0)), 'id_a') 351 352 def testFieldIsWidgetEditableRole(self): 353 l, m = create_model() 354 self.assertTrue(m.data(m.indexFromName('fldtxt'), QgsFieldModel.FieldIsWidgetEditable)) 355 self.assertTrue(m.data(m.indexFromName('fldint'), QgsFieldModel.FieldIsWidgetEditable)) 356 self.assertFalse(m.data(m.indexFromName('an expression'), QgsFieldModel.FieldIsWidgetEditable)) 357 self.assertFalse(m.data(m.indexFromName(None), QgsFieldModel.FieldIsWidgetEditable)) 358 m.setAllowExpression(True) 359 m.setExpression('an expression') 360 self.assertTrue(m.data(m.indexFromName('an expression'), QgsFieldModel.FieldIsWidgetEditable)) 361 m.setAllowEmptyFieldName(True) 362 self.assertTrue(m.data(m.indexFromName(None), QgsFieldModel.FieldIsWidgetEditable)) 363 364 editFormConfig = l.editFormConfig() 365 idx = l.fields().indexOf('fldtxt') 366 # Make fldtxt readOnly 367 editFormConfig.setReadOnly(idx, True) 368 l.setEditFormConfig(editFormConfig) 369 # It's read only, so the widget is NOT editable 370 self.assertFalse(m.data(m.indexFromName('fldtxt'), QgsFieldModel.FieldIsWidgetEditable)) 371 372 def testFieldTooltip(self): 373 f = QgsField('my_string', QVariant.String, 'string') 374 self.assertEqual(QgsFieldModel.fieldToolTip(f), "<b>my_string</b><br><font style='font-family:monospace; white-space: nowrap;'>string NULL</font>") 375 f.setAlias('my alias') 376 self.assertEqual(QgsFieldModel.fieldToolTip(f), "<b>my alias</b> (my_string)<br><font style='font-family:monospace; white-space: nowrap;'>string NULL</font>") 377 f.setLength(20) 378 self.assertEqual(QgsFieldModel.fieldToolTip(f), "<b>my alias</b> (my_string)<br><font style='font-family:monospace; white-space: nowrap;'>string(20) NULL</font>") 379 f = QgsField('my_real', QVariant.Double, 'real', 8, 3) 380 self.assertEqual(QgsFieldModel.fieldToolTip(f), "<b>my_real</b><br><font style='font-family:monospace; white-space: nowrap;'>real(8, 3) NULL</font>") 381 f.setComment('Comment text') 382 self.assertEqual(QgsFieldModel.fieldToolTip(f), "<b>my_real</b><br><font style='font-family:monospace; white-space: nowrap;'>real(8, 3) NULL</font><br><em>Comment text</em>") 383 384 def testFieldTooltipExtended(self): 385 layer = QgsVectorLayer("Point?", "tooltip", "memory") 386 f = QgsField('my_real', QVariant.Double, 'real', 8, 3, 'Comment text') 387 layer.addExpressionField('1+1', f) 388 layer.updateFields() 389 self.assertEqual(QgsFieldModel.fieldToolTipExtended(QgsField('my_string', QVariant.String, 'string'), layer), '') 390 self.assertEqual(QgsFieldModel.fieldToolTipExtended(f, layer), "<b>my_real</b><br><font style='font-family:monospace; white-space: nowrap;'>real(8, 3) NULL</font><br><em>Comment text</em><br><font style='font-family:monospace;'>1+1</font>") 391 f.setAlias('my alias') 392 constraints = f.constraints() 393 constraints.setConstraint(QgsFieldConstraints.ConstraintUnique) 394 f.setConstraints(constraints) 395 self.assertEqual(QgsFieldModel.fieldToolTipExtended(f, layer), "<b>my alias</b> (my_real)<br><font style='font-family:monospace; white-space: nowrap;'>real(8, 3) NULL UNIQUE</font><br><em>Comment text</em><br><font style='font-family:monospace;'>1+1</font>") 396 397 398if __name__ == '__main__': 399 unittest.main() 400