@@ -62,175 +62,323 @@ class CoordinateItemDelegate : public QStyledItemDelegate
62
62
};
63
63
64
64
65
- QgsNodeEditor::QgsNodeEditor (
66
- QgsVectorLayer *layer,
67
- QgsSelectedFeature *selectedFeature,
68
- QgsMapCanvas *canvas )
65
+ QgsNodeEditorModel::QgsNodeEditorModel ( QgsVectorLayer* layer, QgsSelectedFeature* selectedFeature, QgsMapCanvas* canvas, QObject* parent )
66
+ : QAbstractTableModel( parent )
67
+ , mLayer( layer )
68
+ , mSelectedFeature( selectedFeature )
69
+ , mCanvas( canvas )
70
+ , mHasZ( false )
71
+ , mHasM( false )
72
+ , mHasR( true ) // always show for now - avoids scanning whole feature for curves TODO - avoid this
73
+ , mZCol( -1 )
74
+ , mMCol( -1 )
75
+ , mRCol( -1 )
69
76
{
70
- setWindowTitle ( tr ( " Vertex editor" ) );
71
- setFeatures ( features () ^ QDockWidget::DockWidgetClosable );
72
77
73
- mLayer = layer;
74
- mSelectedFeature = selectedFeature;
75
- mCanvas = canvas;
78
+ if ( !mSelectedFeature ->vertexMap ().isEmpty () )
79
+ {
80
+ mHasZ = mSelectedFeature ->vertexMap ().at ( 0 )->point ().is3D ();
81
+ mHasM = mSelectedFeature ->vertexMap ().at ( 0 )->point ().isMeasure ();
76
82
77
- mTableWidget = new QTableWidget ( 0 , 6 , this );
78
- mTableWidget ->setHorizontalHeaderLabels ( QStringList () << " id" << " x" << " y" << " z" << " m" << " r" );
79
- mTableWidget ->setSelectionMode ( QTableWidget::ExtendedSelection );
80
- mTableWidget ->setSelectionBehavior ( QTableWidget::SelectRows );
81
- mTableWidget ->verticalHeader ()->hide ();
82
- mTableWidget ->horizontalHeader ()->setResizeMode ( 1 , QHeaderView::Stretch );
83
- mTableWidget ->horizontalHeader ()->setResizeMode ( 2 , QHeaderView::Stretch );
84
- mTableWidget ->horizontalHeader ()->setResizeMode ( 3 , QHeaderView::Stretch );
85
- mTableWidget ->horizontalHeader ()->setResizeMode ( 4 , QHeaderView::Stretch );
86
- mTableWidget ->horizontalHeader ()->setResizeMode ( 5 , QHeaderView::Stretch );
87
- mTableWidget ->setItemDelegateForColumn ( 1 , new CoordinateItemDelegate () );
88
- mTableWidget ->setItemDelegateForColumn ( 2 , new CoordinateItemDelegate () );
89
- mTableWidget ->setItemDelegateForColumn ( 3 , new CoordinateItemDelegate () );
90
- mTableWidget ->setItemDelegateForColumn ( 4 , new CoordinateItemDelegate () );
91
- mTableWidget ->setItemDelegateForColumn ( 5 , new CoordinateItemDelegate () );
92
-
93
- setWidget ( mTableWidget );
83
+ if ( mHasZ )
84
+ mZCol = 2 ;
94
85
95
- connect ( mSelectedFeature , SIGNAL ( selectionChanged () ), this , SLOT ( updateTableSelection () ) );
96
- connect ( mSelectedFeature , SIGNAL ( vertexMapChanged () ), this , SLOT ( rebuildTable () ) );
97
- connect ( mTableWidget , SIGNAL ( itemSelectionChanged () ), this , SLOT ( updateNodeSelection () ) );
98
- connect ( mTableWidget , SIGNAL ( cellChanged ( int , int ) ), this , SLOT ( tableValueChanged ( int , int ) ) );
86
+ if ( mHasM )
87
+ mMCol = 2 + ( mHasZ ? 1 : 0 );
88
+
89
+ if ( mHasR )
90
+ mRCol = 2 + ( mHasZ ? 1 : 0 ) + ( mHasM ? 1 : 0 );
91
+ }
92
+
93
+ QWidget* parentWidget = dynamic_cast < QWidget* >( parent );
94
+ if ( parentWidget )
95
+ {
96
+ mWidgetFont = parentWidget->font ();
97
+ }
99
98
100
- rebuildTable ( );
99
+ connect ( mSelectedFeature , SIGNAL ( vertexMapChanged () ), this , SLOT ( featureChanged () ) );
101
100
}
102
101
103
- void QgsNodeEditor::rebuildTable ()
102
+ int QgsNodeEditorModel::rowCount ( const QModelIndex& parent ) const
104
103
{
105
- QFont curvePointFont = mTableWidget ->font ();
106
- curvePointFont.setItalic ( true );
107
-
108
- mTableWidget ->blockSignals ( true );
109
- mTableWidget ->setRowCount ( 0 );
110
- int row = 0 ;
111
- bool hasR = false ;
112
- Q_FOREACH ( const QgsVertexEntry* entry, mSelectedFeature ->vertexMap () )
113
- {
114
- mTableWidget ->insertRow ( row );
104
+ if ( parent.isValid () )
105
+ return 0 ;
115
106
116
- QTableWidgetItem* idItem = new QTableWidgetItem ();
117
- idItem->setData ( Qt::DisplayRole, row );
118
- idItem->setFlags ( idItem->flags () ^ Qt::ItemIsEditable );
119
- mTableWidget ->setItem ( row, 0 , idItem );
107
+ return mSelectedFeature ->vertexMap ().count ();
108
+ }
120
109
121
- QTableWidgetItem* xItem = new QTableWidgetItem ();
122
- xItem->setData ( Qt::EditRole, entry->point ().x () );
123
- mTableWidget ->setItem ( row, 1 , xItem );
110
+ int QgsNodeEditorModel::columnCount ( const QModelIndex& parent ) const
111
+ {
112
+ Q_UNUSED ( parent );
113
+ return 2 + ( mHasZ ? 1 : 0 ) + ( mHasM ? 1 : 0 ) + ( mHasR ? 1 : 0 );
114
+ }
124
115
125
- QTableWidgetItem* yItem = new QTableWidgetItem ();
126
- yItem->setData ( Qt::EditRole, entry->point ().y () );
127
- mTableWidget ->setItem ( row, 2 , yItem );
116
+ QVariant QgsNodeEditorModel::data ( const QModelIndex& index, int role ) const
117
+ {
118
+ if ( !index.isValid () ||
119
+ ( role != Qt::DisplayRole && role != Qt::EditRole && role != MinRadiusRole && role != Qt::FontRole ) )
120
+ return QVariant ();
128
121
129
- QTableWidgetItem* zItem = new QTableWidgetItem ();
130
- zItem->setData ( Qt::EditRole, entry->point ().z () );
131
- mTableWidget ->setItem ( row, 3 , zItem );
122
+ if ( index.row () >= mSelectedFeature ->vertexMap ().count () )
123
+ return QVariant ();
132
124
133
- QTableWidgetItem* mItem = new QTableWidgetItem ();
134
- mItem ->setData ( Qt::EditRole, entry->point ().m () );
135
- mTableWidget ->setItem ( row, 4 , mItem );
125
+ if ( index.column () >= columnCount () )
126
+ return QVariant ();
136
127
137
- QTableWidgetItem* rItem = new QTableWidgetItem ();
138
- mTableWidget ->setItem ( row, 5 , rItem );
128
+ // get QgsVertexEntry for row
129
+ const QgsVertexEntry* vertex = mSelectedFeature ->vertexMap ().at ( index.row () );
130
+ if ( !vertex )
131
+ {
132
+ return QVariant ();
133
+ }
139
134
140
- bool curvePoint = ( entry->vertexId ().type == QgsVertexId::CurveVertex );
141
- if ( curvePoint )
135
+ if ( role == Qt::FontRole )
136
+ {
137
+ double r = 0 ;
138
+ double minRadius = 0 ;
139
+ if ( calcR ( index.row (), r, minRadius ) )
142
140
{
143
- idItem->setFont ( curvePointFont );
144
- xItem->setFont ( curvePointFont );
145
- yItem->setFont ( curvePointFont );
146
- zItem->setFont ( curvePointFont );
147
- mItem ->setFont ( curvePointFont );
148
- rItem->setFont ( curvePointFont );
141
+ QFont curvePointFont = mWidgetFont ;
142
+ curvePointFont.setItalic ( true );
143
+ return curvePointFont;
144
+ }
145
+ else
146
+ {
147
+ return QVariant ();
148
+ }
149
+ }
149
150
150
- const QgsPointV2& p1 = mSelectedFeature ->vertexMap ()[row - 1 ]->point ();
151
- const QgsPointV2& p2 = mSelectedFeature ->vertexMap ()[row]->point ();
152
- const QgsPointV2& p3 = mSelectedFeature ->vertexMap ()[row + 1 ]->point ();
151
+ if ( role == MinRadiusRole )
152
+ {
153
+ if ( index.column () == mRCol )
154
+ {
155
+ double r = 0 ;
156
+ double minRadius = 0 ;
157
+ if ( calcR ( index.row (), r, minRadius ) )
158
+ {
159
+ return minRadius;
160
+ }
161
+ }
162
+ return QVariant ();
163
+ }
153
164
154
- double r, cx, cy;
155
- QgsGeometryUtils::circleCenterRadius ( p1, p2, p3, r, cx, cy );
156
- rItem->setData ( Qt::EditRole, r );
165
+ if ( index.column () == 0 )
166
+ return vertex->point ().x ();
167
+ else if ( index.column () == 1 )
168
+ return vertex->point ().y ();
169
+ else if ( index.column () == mZCol )
170
+ return vertex->point ().z ();
171
+ else if ( index.column () == mMCol )
172
+ return vertex->point ().m ();
173
+ else if ( index.column () == mRCol )
174
+ {
175
+ double r = 0 ;
176
+ double minRadius = 0 ;
177
+ if ( calcR ( index.row (), r, minRadius ) )
178
+ {
179
+ return r;
180
+ }
181
+ return QVariant ();
182
+ }
183
+ else
184
+ {
185
+ return QVariant ();
186
+ }
157
187
158
- double x13 = p3.x () - p1.x (), y13 = p3.y () - p1.y ();
159
- rItem->setData ( MinRadiusRole, 0.5 * qSqrt ( x13 * x13 + y13 * y13 ) );
188
+ }
160
189
161
- hasR = true ;
190
+ QVariant QgsNodeEditorModel::headerData ( int section, Qt::Orientation orientation, int role ) const
191
+ {
192
+ if ( role == Qt::DisplayRole )
193
+ {
194
+ if ( orientation == Qt::Vertical ) // row
195
+ {
196
+ return QVariant ( section );
162
197
}
163
198
else
164
199
{
165
- rItem->setFlags ( rItem->flags () & ~( Qt::ItemIsSelectable | Qt::ItemIsEnabled ) );
200
+ if ( section == 0 )
201
+ return QVariant ( tr ( " x" ) );
202
+ else if ( section == 1 )
203
+ return QVariant ( tr ( " y" ) );
204
+ else if ( section == mZCol )
205
+ return QVariant ( tr ( " z" ) );
206
+ else if ( section == mMCol )
207
+ return QVariant ( tr ( " m" ) );
208
+ else if ( section == mRCol )
209
+ return QVariant ( tr ( " r" ) );
210
+ else
211
+ return QVariant ();
166
212
}
167
-
168
- ++row;
169
213
}
170
- mTableWidget ->setColumnHidden ( 3 , !mSelectedFeature ->vertexMap ()[0 ]->point ().is3D () );
171
- mTableWidget ->setColumnHidden ( 4 , !mSelectedFeature ->vertexMap ()[0 ]->point ().isMeasure () );
172
- mTableWidget ->setColumnHidden ( 5 , !hasR );
173
- mTableWidget ->resizeColumnToContents ( 0 );
174
- mTableWidget ->blockSignals ( false );
214
+ else
215
+ {
216
+ return QVariant ();
217
+ }
175
218
}
176
219
177
- void QgsNodeEditor::tableValueChanged ( int row, int col )
220
+ bool QgsNodeEditorModel::setData ( const QModelIndex& index, const QVariant& value, int role )
178
221
{
179
- int nodeIdx = mTableWidget ->item ( row, 0 )->data ( Qt::DisplayRole ).toInt ();
180
- double x, y;
181
- if ( col == 5 ) // radius modified
182
- {
183
- double r = mTableWidget ->item ( row, 5 )->data ( Qt::EditRole ).toDouble ();
184
- double x1 = mTableWidget ->item ( row - 1 , 1 )->data ( Qt::EditRole ).toDouble ();
185
- double y1 = mTableWidget ->item ( row - 1 , 2 )->data ( Qt::EditRole ).toDouble ();
186
- double x2 = mTableWidget ->item ( row , 1 )->data ( Qt::EditRole ).toDouble ();
187
- double y2 = mTableWidget ->item ( row , 2 )->data ( Qt::EditRole ).toDouble ();
188
- double x3 = mTableWidget ->item ( row + 1 , 1 )->data ( Qt::EditRole ).toDouble ();
189
- double y3 = mTableWidget ->item ( row + 1 , 2 )->data ( Qt::EditRole ).toDouble ();
190
-
191
- QgsPointV2 result;
192
- QgsGeometryUtils::segmentMidPoint ( QgsPointV2 ( x1, y1 ), QgsPointV2 ( x3, y3 ), result, r, QgsPointV2 ( x2, y2 ) );
193
- x = result.x ();
194
- y = result.y ();
222
+ if ( !index.isValid () || role != Qt::EditRole )
223
+ {
224
+ return false ;
195
225
}
196
- else
226
+ if ( index. row () >= mSelectedFeature -> vertexMap (). count () )
197
227
{
198
- x = mTableWidget ->item ( row, 1 )->data ( Qt::EditRole ).toDouble ();
199
- y = mTableWidget ->item ( row, 2 )->data ( Qt::EditRole ).toDouble ();
228
+ return false ;
200
229
}
201
- double z = mTableWidget ->item ( row, 3 )->data ( Qt::EditRole ).toDouble ();
202
- double m = mTableWidget ->item ( row, 4 )->data ( Qt::EditRole ).toDouble ();
230
+
231
+ double x = ( index.column () == 0 ? value.toDouble () : mSelectedFeature ->vertexMap ().at ( index.row () )->point ().x () );
232
+ double y = ( index.column () == 1 ? value.toDouble () : mSelectedFeature ->vertexMap ().at ( index.row () )->point ().y () );
233
+
234
+ if ( index.column () == mRCol ) // radius modified
235
+ {
236
+ if ( index.row () == 0 || index.row () >= mSelectedFeature ->vertexMap ().count () - 1 )
237
+ return false ;
238
+
239
+ double r = value.toDouble ();
240
+ double x1 = mSelectedFeature ->vertexMap ().at ( index.row () - 1 )->point ().x ();
241
+ double y1 = mSelectedFeature ->vertexMap ().at ( index.row () - 1 )->point ().y ();
242
+ double x2 = x;
243
+ double y2 = y;
244
+ double x3 = mSelectedFeature ->vertexMap ().at ( index.row () + 1 )->point ().x ();
245
+ double y3 = mSelectedFeature ->vertexMap ().at ( index.row () + 1 )->point ().y ();
246
+
247
+ QgsPointV2 result;
248
+ if ( QgsGeometryUtils::segmentMidPoint ( QgsPointV2 ( x1, y1 ), QgsPointV2 ( x3, y3 ), result, r, QgsPointV2 ( x2, y2 ) ) )
249
+ {
250
+ x = result.x ();
251
+ y = result.y ();
252
+ }
253
+ }
254
+ double z = ( index.column () == mZCol ? value.toDouble () : mSelectedFeature ->vertexMap ().at ( index.row () )->point ().z () );
255
+ double m = ( index.column () == mMCol ? value.toDouble () : mSelectedFeature ->vertexMap ().at ( index.row () )->point ().m () );
203
256
QgsPointV2 p ( QgsWKBTypes::PointZM, x, y, z, m );
204
257
205
258
mLayer ->beginEditCommand ( QObject::tr ( " Moved vertices" ) );
206
- mLayer ->moveVertex ( p, mSelectedFeature ->featureId (), nodeIdx );
259
+ mLayer ->moveVertex ( p, mSelectedFeature ->featureId (), index. row () );
207
260
mLayer ->endEditCommand ();
208
261
mCanvas ->refresh ();
262
+
263
+ return false ;
264
+ }
265
+
266
+ Qt::ItemFlags QgsNodeEditorModel::flags ( const QModelIndex& index ) const
267
+ {
268
+ Qt::ItemFlags flags = QAbstractItemModel::flags ( index );
269
+
270
+ if ( index.isValid () )
271
+ {
272
+ return flags | Qt::ItemIsEditable;
273
+ }
274
+ else
275
+ {
276
+ return flags;
277
+ }
278
+ }
279
+
280
+ bool QgsNodeEditorModel::calcR ( int row, double & r, double & minRadius ) const
281
+ {
282
+ if ( row <= 0 || row >= mSelectedFeature ->vertexMap ().count () - 1 )
283
+ return false ;
284
+
285
+ const QgsVertexEntry* entry = mSelectedFeature ->vertexMap ().at ( row );
286
+
287
+ bool curvePoint = ( entry->vertexId ().type == QgsVertexId::CurveVertex );
288
+ if ( !curvePoint )
289
+ return false ;
290
+
291
+ const QgsPointV2& p1 = mSelectedFeature ->vertexMap ().at ( row - 1 )->point ();
292
+ const QgsPointV2& p2 = mSelectedFeature ->vertexMap ().at ( row )->point ();
293
+ const QgsPointV2& p3 = mSelectedFeature ->vertexMap ().at ( row + 1 )->point ();
294
+
295
+ double cx, cy;
296
+ QgsGeometryUtils::circleCenterRadius ( p1, p2, p3, r, cx, cy );
297
+
298
+ double x13 = p3.x () - p1.x (), y13 = p3.y () - p1.y ();
299
+ minRadius = 0.5 * qSqrt ( x13 * x13 + y13 * y13 );
300
+
301
+ return true ;
302
+ }
303
+
304
+ void QgsNodeEditorModel::featureChanged ()
305
+ {
306
+ // TODO - avoid reset
307
+ reset ();
308
+ }
309
+
310
+ QgsNodeEditor::QgsNodeEditor (
311
+ QgsVectorLayer *layer,
312
+ QgsSelectedFeature *selectedFeature,
313
+ QgsMapCanvas *canvas )
314
+ : mUpdatingTableSelection( false )
315
+ , mUpdatingNodeSelection( false )
316
+ {
317
+ setWindowTitle ( tr ( " Vertex Editor" ) );
318
+ setFeatures ( features () ^ QDockWidget::DockWidgetClosable );
319
+
320
+ mLayer = layer;
321
+ mSelectedFeature = selectedFeature;
322
+ mCanvas = canvas;
323
+
324
+ mTableView = new QTableView ( this );
325
+ mNodeModel = new QgsNodeEditorModel ( mLayer , mSelectedFeature , mCanvas , this );
326
+ mTableView ->setModel ( mNodeModel );
327
+
328
+ mTableView ->setSelectionMode ( QTableWidget::ExtendedSelection );
329
+ mTableView ->setSelectionBehavior ( QTableWidget::SelectRows );
330
+ mTableView ->setItemDelegateForColumn ( 0 , new CoordinateItemDelegate () );
331
+ mTableView ->setItemDelegateForColumn ( 1 , new CoordinateItemDelegate () );
332
+ mTableView ->setItemDelegateForColumn ( 2 , new CoordinateItemDelegate () );
333
+ mTableView ->setItemDelegateForColumn ( 3 , new CoordinateItemDelegate () );
334
+ mTableView ->setItemDelegateForColumn ( 4 , new CoordinateItemDelegate () );
335
+
336
+ setWidget ( mTableView );
337
+
338
+ connect ( mSelectedFeature , SIGNAL ( selectionChanged () ), this , SLOT ( updateTableSelection () ) );
339
+ connect ( mTableView ->selectionModel (), SIGNAL ( selectionChanged ( QItemSelection, QItemSelection ) ), this , SLOT ( updateNodeSelection ( QItemSelection, QItemSelection ) ) );
340
+ connect ( mTableView , SIGNAL ( cellChanged ( int , int ) ), this , SLOT ( tableValueChanged ( int , int ) ) );
209
341
}
210
342
211
343
void QgsNodeEditor::updateTableSelection ()
212
344
{
213
- mTableWidget ->blockSignals ( true );
214
- mTableWidget ->clearSelection ();
345
+ if ( mUpdatingNodeSelection )
346
+ return ;
347
+
348
+ mUpdatingTableSelection = true ;
349
+ mTableView ->selectionModel ()->clearSelection ();
215
350
const QList<QgsVertexEntry*>& vertexMap = mSelectedFeature ->vertexMap ();
351
+ int firstSelectedRow = -1 ;
216
352
for ( int i = 0 , n = vertexMap.size (); i < n; ++i )
217
353
{
218
354
if ( vertexMap[i]->isSelected () )
219
355
{
220
- mTableWidget ->selectRow ( i );
356
+ if ( firstSelectedRow < 0 )
357
+ firstSelectedRow = i;
358
+ mTableView ->selectionModel ()->select ( mNodeModel ->index ( i, 0 ), QItemSelectionModel::Rows | QItemSelectionModel::Select );
221
359
}
222
360
}
223
- mTableWidget ->blockSignals ( false );
361
+
362
+ if ( firstSelectedRow >= 0 )
363
+ mTableView ->scrollTo ( mNodeModel ->index ( firstSelectedRow, 0 ), QAbstractItemView::PositionAtTop );
364
+
365
+ mUpdatingTableSelection = false ;
224
366
}
225
367
226
- void QgsNodeEditor::updateNodeSelection ()
368
+ void QgsNodeEditor::updateNodeSelection ( const QItemSelection&, const QItemSelection& )
227
369
{
228
- mSelectedFeature ->blockSignals ( true );
370
+ if ( mUpdatingTableSelection )
371
+ return ;
372
+
373
+ mUpdatingNodeSelection = true ;
374
+
229
375
mSelectedFeature ->deselectAllVertexes ();
230
- Q_FOREACH ( const QModelIndex& index, mTableWidget ->selectionModel ()->selectedRows () )
376
+ Q_FOREACH ( const QModelIndex& index, mTableView ->selectionModel ()->selectedRows () )
231
377
{
232
- int nodeIdx = mTableWidget -> item ( index.row (), 0 )-> data ( Qt::DisplayRole ). toInt ();
378
+ int nodeIdx = index.row ();
233
379
mSelectedFeature ->selectVertex ( nodeIdx );
234
380
}
235
- mSelectedFeature ->blockSignals ( false );
381
+
382
+ mUpdatingNodeSelection = false ;
236
383
}
384
+
0 commit comments