EditInfoTool.cpp
Go to the documentation of this file.
1 /* Copyright (C) 2008 National Institute For Space Research (INPE) - Brazil.
2 
3  This file is part of the TerraLib - a Framework for building GIS enabled applications.
4 
5  TerraLib is free software: you can redistribute it and/or modify
6  it under the terms of the GNU Lesser General Public License as published by
7  the Free Software Foundation, either version 3 of the License,
8  or (at your option) any later version.
9 
10  TerraLib is distributed in the hope that it will be useful,
11  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  GNU Lesser General Public License for more details.
14 
15  You should have received a copy of the GNU Lesser General Public License
16  along with TerraLib. See COPYING. If not, write to
17  TerraLib Team at <terralib-team@terralib.org>.
18 */
19 
20 /*!
21  \file terralib/edit/qt/tools/EditInfoTool.h
22 
23  \brief This class implements a concrete tool for edit attributes of geometry.
24 */
25 
26 //TerraLib
27 #include "../../../core/encoding/CharEncoding.h"
28 #include "../../../common/STLUtils.h"
29 #include "../../../geometry.h"
30 #include "../../../dataaccess/dataset/ObjectId.h"
31 #include "../../../dataaccess/dataset/ObjectIdSet.h"
32 #include "../../../dataaccess/query/In.h"
33 #include "../../../dataaccess/query/LiteralString.h"
34 #include "../../../dataaccess/utils/Utils.h"
35 #include "../../../datatype/AbstractData.h"
36 #include "../../../datatype/SimpleData.h"
37 #include "../../../qt/af/events/LayerEvents.h"
38 #include "../../../qt/af/events/MapEvents.h"
39 #include "../../../qt/widgets/canvas/MapDisplay.h"
40 #include "../../../qt/widgets/Utils.h"
41 #include "../../Feature.h"
42 #include "../../RepositoryManager.h"
43 #include "../../Utils.h"
44 #include "../Renderer.h"
45 #include "../Utils.h"
46 #include "EditInfoTool.h"
47 
48 // Qt
49 #include <QMessageBox>
50 #include <QMouseEvent>
51 #include <QPainter>
52 #include <QPixmap>
53 #include <QDebug>
54 #include <QGridLayout>
55 #include <QPushButton>
56 
57 // STL
58 #include <cassert>
59 #include <memory>
60 #include <iostream>
61 
63 : GeometriesUpdateTool(display, layer.get(), parent),
64  m_restrictivePropertyPos(0),
65  m_dialog(new QDialog(display)),
66  m_infoWidget(new QTreeWidget(display))
67 {
68  updateCursor();
69 
70  QGridLayout* layout = new QGridLayout(m_dialog);
71 
72  m_dialog->setWindowTitle(tr("Edit Information"));
73  m_dialog->setMinimumSize(300, 300);
74 
75  // Setup the widget that will be used to show the informations
76  m_infoWidget->setWindowFlags(Qt::Tool);
77  m_infoWidget->setAlternatingRowColors(true);
78  m_infoWidget->setMinimumSize(250, 250);
79  m_infoWidget->setColumnCount(2);
80 
81  QStringList labels;
82  labels << tr("Property") << tr("Value");
83  m_infoWidget->setHeaderLabels(labels);
84 
85  layout->addWidget(m_infoWidget,0,0,1,3);
86 
87  QLayoutItem* layoutItem = new QSpacerItem(40, 20, QSizePolicy::MinimumExpanding, QSizePolicy::Minimum);
88  layout->addItem(layoutItem, 1, 0);
89 
90  QPushButton* okPushButton = new QPushButton(tr("&Save"));
91  QPushButton* cancelPushButton = new QPushButton(tr("&Cancel"));
92 
93  layout->addWidget(okPushButton, 1, 1);
94  layout->addWidget(cancelPushButton, 1, 2);
95 
96  // Signals & slots
97  connect(okPushButton, SIGNAL(pressed()), this, SLOT(onOkPushButtonPressed()));
98  connect(cancelPushButton, SIGNAL(pressed()), this, SLOT(onCancelPushButtonPressed()));
99  connect(m_infoWidget, SIGNAL(itemDoubleClicked(QTreeWidgetItem*, int)), this, SLOT(onAttributesTreeWidgetItemDoubleClicked(QTreeWidgetItem*, int)));
100 
101 }
102 
104 {
105  m_dialog->close();
106 
107  delete m_dialog;
108 }
109 
111 {
112  if (e->button() != Qt::LeftButton)
113  return false;
114 
115  // Clear info widget!
116  m_infoWidget->clear();
117 
119 
120  if (m_feature == nullptr)
121  return false;
122 
124  return false;
125 
126  m_data = m_feature->getData();
127 
128  // Build the search envelope
129  te::gm::Envelope reprojectedEnvelope = buildEnvelope(GetPosition(e));
130 
131  if ((m_layer->getSRID() != TE_UNKNOWN_SRS) &&
132  (m_display->getSRID() != TE_UNKNOWN_SRS) &&
133  (m_layer->getSRID() != m_display->getSRID()))
134  {
135  reprojectedEnvelope.transform(m_display->getSRID(), m_layer->getSRID());
136  }
137 
138  if (!reprojectedEnvelope.within(m_layer->getExtent()))
139  return false;
140 
141  // Get the property names that compose the object id
142  std::vector<std::string> oidPropertyNames;
143  te::da::GetOIDPropertyNames(m_layer->getSchema().get(), oidPropertyNames);
144 
145  te::da::In* in = new te::da::In(oidPropertyNames[0]);
146 
148 
149  m_dataset = m_layer->getData(in).release();
150 
151  if (m_dataset->size() == 0)
152  return false;
153 
154  getInfo(reprojectedEnvelope);
155 
156  m_dialog->show();
157 
158  return true;
159 }
160 
162 {
163  QPointF pixelOffset(4.0, 4.0);
164 
165  QRectF rect(pos - pixelOffset, pos + pixelOffset);
166 
167  // Converts rect boundary to world coordinates
168  QPointF ll(rect.left(), rect.bottom());
169  QPointF ur(rect.right(), rect.top());
170  ll = m_display->transform(ll);
171  ur = m_display->transform(ur);
172 
173  te::gm::Envelope env(ll.x(), ll.y(), ur.x(), ur.y());
174 
175  return env;
176 }
177 
179 {
180  te::gm::Envelope env = buildEnvelope(pos);
181 
182  try
183  {
184  m_feature = PickFeature(layer, env, m_display->getSRID());
185  }
186  catch (std::exception& e)
187  {
188  QMessageBox::critical(m_display, tr("Error"), QString(tr("The geometry cannot be selected from the layer. Details:") + " %1.").arg(e.what()));
189  }
190 }
191 
193 {
194  // Get the property pos that compose the object id
196 
197  // Get the geometry property position
199 
200  // Generates a geometry from the given extent. It will be used to refine the results
201  std::unique_ptr<te::gm::Geometry> geometryFromEnvelope(te::gm::GetGeomFromEnvelope(&e, m_layer->getSRID()));
202 
203  // The restriction point. It will be used to refine the results
204  te::gm::Coord2D center = e.getCenter();
205  te::gm::Point point(center.x, center.y, m_layer->getSRID());
206 
207  std::size_t gpos;
209 
210  if (m_feature->getData().size() == 0)
211  {
212  // Fills the QTreeWidgetItem
213  while (m_dataset->moveNext())
214  {
215  std::unique_ptr<te::gm::Geometry> g(dynamic_cast<te::gm::Geometry*>(m_feature->getGeometry()->clone()));
216  g->setSRID(m_layer->getSRID());
217 
218  if (g->contains(&point) || g->crosses(geometryFromEnvelope.get()) || geometryFromEnvelope->contains(g.get()))
219  {
220  for (std::size_t i = 0; i < m_dataset->getNumProperties(); ++i)
221  {
222  QTreeWidgetItem* propertyItem = new QTreeWidgetItem;
223 
225  propertyItem->setText(0, m_dataset->getPropertyName(pos).c_str());
226 
228  propertyItem->setIcon(0, QIcon::fromTheme("geometry"));
229 
230  if (!m_dataset->isNull(pos))
231  {
232  QString qvalue;
233 
235  {
236  std::string value = m_dataset->getString(pos);
237  qvalue = QString::fromUtf8(value.c_str());
238  }
239  else
240  {
242  qvalue = (m_dataset->getAsString(pos).substr(0, 15) + "...").c_str();
243  else
244  qvalue = m_dataset->getAsString(pos, 3).c_str();
245  }
246 
247  propertyItem->setText(1, qvalue);
248  }
249  else // property null value!
250  propertyItem->setText(1, tr(""));
251 
252  m_infoWidget->addTopLevelItem(propertyItem);
253 
254  // fill the m_data
255  std::unique_ptr<te::dt::AbstractData> data(m_dataset->getValue(pos));
256  m_data[pos] = data.release();
257  }
258 
259  break;
260  }
261  }
262  }
263  else
264  {
265  while (m_dataset->moveNext())
266  {
267  std::unique_ptr<te::gm::Geometry> g(m_dataset->getGeometry(gpos));
268  g->setSRID(m_layer->getSRID());
269 
270  if (g->contains(&point) || g->crosses(geometryFromEnvelope.get()) || geometryFromEnvelope->contains(g.get()))
271  {
272  std::map<std::size_t, te::dt::AbstractData* > ::iterator it;
273 
274  for (std::size_t i = 0; i < m_dataset->getNumProperties(); ++i)
275  {
276  QTreeWidgetItem* propertyItem = new QTreeWidgetItem;
277 
279  propertyItem->setText(0, m_dataset->getPropertyName(pos).c_str());
280 
281  it = m_data.find(pos);
282  if (it != m_data.end())
283  propertyItem->setText(1, QString(it->second->toString().c_str()));
284  else
285  {
286  QString qvalue;
287 
289  {
290  propertyItem->setIcon(0, QIcon::fromTheme("geometry"));
291  qvalue = (m_dataset->getAsString(pos).substr(0, 15) + "...").c_str();
292  }
293  else
294  qvalue = m_dataset->getAsString(pos, 3).c_str();
295 
296  propertyItem->setText(1, qvalue);
297 
298  }
299 
300  m_infoWidget->addTopLevelItem(propertyItem);
301  }
302  }
303  }
304  }
305 
306  draw(); // to show feedback!
307 }
308 
309 // Hack from http://stackoverflow.com/a/13374558 to making only one column of a QTreeWidgetItem editable
311 {
312  bool isrestrictive = false;
313 
314  for (std::size_t i = 0; i < m_restrictivePropertyPos.size(); ++i)
315  {
316  if ((int)m_restrictivePropertyPos[i] == m_infoWidget->currentIndex().row())
317  {
318  isrestrictive = true;
319  break;
320  }
321  }
322 
323  Qt::ItemFlags tmp = item->flags();
324  if (column == 1 && !isrestrictive)
325  item->setFlags(tmp | Qt::ItemIsEditable);
326  else if (tmp & Qt::ItemIsEditable)
327  item->setFlags(tmp ^ Qt::ItemIsEditable);
328 
329 }
330 
331 std::unique_ptr<te::dt::AbstractData> te::edit::EditInfoTool::getValue(int type, QString value) const
332 {
333  switch (type)
334  {
335  case te::dt::INT16_TYPE:
336  return std::unique_ptr<te::dt::AbstractData>(new te::dt::Int16(atoi(value.toUtf8().data())));
337 
338  case te::dt::INT32_TYPE:
339  return std::unique_ptr<te::dt::AbstractData>(new te::dt::Int32(atoi(value.toUtf8().data())));
340 
341  case te::dt::INT64_TYPE:
342  return std::unique_ptr<te::dt::AbstractData>(new te::dt::Int64(atoi(value.toUtf8().data())));
343 
344  case te::dt::FLOAT_TYPE:
345  return std::unique_ptr<te::dt::AbstractData>(new te::dt::Float(atof(value.toUtf8().data())));
346 
347  case te::dt::DOUBLE_TYPE:
348  return std::unique_ptr<te::dt::AbstractData>(new te::dt::Double(atof(value.toUtf8().data())));
349 
351  return std::unique_ptr<te::dt::AbstractData>(new te::dt::Numeric(value.toUtf8().data()));
352 
353  case te::dt::STRING_TYPE:
354  return std::unique_ptr<te::dt::AbstractData>(new te::dt::String(value.toUtf8().data()));
355 
356  default:
357  return std::unique_ptr<te::dt::AbstractData>();
358  }
359 }
360 
362 {
363  if (m_feature == nullptr)
364  return;
365 
367 
368  if (m_dataset->moveNext())
369  {
370  int level_item = 0;
371  for (std::map<std::size_t, te::dt::AbstractData*>::const_iterator it = m_data.begin(); it != m_data.end(); ++it)
372  {
373  QTreeWidgetItem* propertyItem = m_infoWidget->topLevelItem(level_item);
374 
375  std::unique_ptr<te::dt::AbstractData> data(getValue(m_dataset->getPropertyDataType(it->first), propertyItem->text(1)));
376 
377  m_data[it->first] = data.release();
378 
379  m_dataset->getValue(it->first);
380 
381  level_item++;
382  }
383  }
384 
385  storeFeature();
386 }
387 
389 {
390  m_dialog->close();
391 }
392 
394 {
395  const te::gm::Envelope& env = m_display->getExtent();
396  if (!env.isValid())
397  return;
398 
399  // Clear!
400  QPixmap* draft = m_display->getDraftPixmap();
401  draft->fill(Qt::transparent);
402 
403  // Initialize the renderer
404  Renderer& renderer = Renderer::getInstance();
405  renderer.begin(draft, env, m_display->getSRID());
406 
407  // Draw the layer edited geometries
408  renderer.drawRepository(m_layer->getId(), env, m_display->getSRID());
409 
410  if (m_feature == nullptr)
411  {
412  renderer.end();
413  m_display->repaint();
414  return;
415  }
416 
417  // Draw the current geometry
418  renderer.setPolygonStyle(QColor(0, 255, 0, 80), Qt::red, 3);
419  renderer.draw(m_feature->getGeometry(), false);
420 
421  renderer.end();
422 
423  m_display->repaint();
424 
425 }
426 
428 {
429  setCursor(Qt::WhatsThisCursor);
430 }
431 
433 {
435 
437 }
virtual std::unique_ptr< te::gm::Geometry > getGeometry(std::size_t i) const =0
Method for retrieving a geometric attribute value.
virtual const std::string & getId() const
It returns the layer id.
SimpleData< std::string, STRING_TYPE > String
Definition: SimpleData.h:229
double y
y-coordinate.
Definition: Coord2D.h:114
bool mousePressEvent(QMouseEvent *e)
This event handler can be reimplemented in a concrete tool class to receive mouse press events for th...
virtual const te::gm::Envelope & getExtent() const
It returns the Layer extent (or minimum bounding box).
#define TE_UNKNOWN_SRS
A numeric value to represent a unknown SRS identification in TerraLib.
double x
x-coordinate.
Definition: Coord2D.h:113
te::da::ObjectId * getId() const
Definition: Feature.cpp:134
SimpleData< boost::int64_t, INT64_TYPE > Int64
Definition: SimpleData.h:223
SimpleData< boost::int32_t, INT32_TYPE > Int32
Definition: SimpleData.h:221
TEDATAACCESSEXPORT std::size_t GetPropertyPos(const DataSet *dataset, const std::string &name)
Feature * clone() const
Definition: Feature.cpp:182
te::gm::Geometry * getGeometry() const
Definition: Feature.cpp:139
SimpleData< float, FLOAT_TYPE > Float
Definition: SimpleData.h:226
A widget to control the display of a set of layers.
An utility struct for representing 2D coordinates.
Definition: Coord2D.h:40
te::edit::OperationType getOperationTypeId() const
Definition: Feature.cpp:159
This class implements a concrete tool for edit attributes of geometry.
std::unique_ptr< te::dt::AbstractData > getValue(int type, QString value) const
SimpleData< std::string, NUMERIC_TYPE > Numeric
Definition: SimpleData.h:228
virtual std::size_t size() const =0
It returns the collection size, if it is known.
virtual bool moveNext()=0
It moves the internal pointer to the next item of the collection.
Coord2D getCenter() const
It returns the rectangle&#39;s center coordinate.
virtual QPointF transform(const QPointF &p)
Transforms the given point, in screen coordinates, to a point in world coordinates.
TEDATAACCESSEXPORT std::size_t GetFirstSpatialPropertyPos(const te::da::DataSet *dataset)
It returns the first dataset spatial property or NULL if none is found.
static T & getInstance()
It returns a reference to the singleton instance.
Definition: Singleton.h:126
A point with x and y coordinate values.
Definition: Point.h:50
virtual int getPropertyDataType(std::size_t i) const =0
It returns the underlying data type of the property at position pos.
An Envelope defines a 2D rectangular region.
bool within(const Envelope &rhs) const
It returns true if this envelope is "spatially within" the rhs envelope.
virtual int getSRID() const
It return the Spatial Reference System used by the Map Display.
virtual std::unique_ptr< LayerSchema > getSchema() const =0
It returns the layer schema.
TEEDITEXPORT Feature * PickFeature(const te::map::AbstractLayerPtr &layer, const te::gm::Envelope &env, int srid)
void onAttributesTreeWidgetItemDoubleClicked(QTreeWidgetItem *item, int column)
TEEDITQTEXPORT QPointF GetPosition(QMouseEvent *e)
virtual const te::gm::Envelope & getExtent() const
It returns the world extent showned by the MapDisplay.
void draw(te::gm::Geometry *geom, bool showVertexes=false)
Definition: Renderer.cpp:260
std::string getValueAsString() const
It gets the properties values used to uniquely identify a data set element as string.
virtual AbstractData * clone() const =0
It returns a clone of this object.
virtual std::string getAsString(std::size_t i, int precision=0) const
Method for retrieving a data value as a string plain representation.
void setData(const std::map< std::size_t, te::dt::AbstractData * > &data)
Definition: Feature.cpp:103
QTreeWidget * m_infoWidget
Widget used to show the informations.
Definition: EditInfoTool.h:98
void getInfo(const te::gm::Envelope &e)
This is a singleton for rendering geometries and features.
Definition: Renderer.h:70
te::map::AbstractLayer * m_layer
TEDATAACCESSEXPORT void GetOIDPropertyPos(const DataSetType *type, std::vector< std::size_t > &ppos)
virtual std::unique_ptr< te::da::DataSet > getData(te::common::TraverseType travType=te::common::FORWARDONLY, const te::common::AccessPolicy accessPolicy=te::common::RAccess) const =0
It gets the dataset identified by the layer name.
virtual QPixmap * getDraftPixmap() const
It returns the map display draft pixmap.
virtual std::unique_ptr< te::dt::AbstractData > getValue(std::size_t i) const
Method for retrieving any other type of data value stored in the data source.
void begin(QPaintDevice *device, const te::gm::Envelope &e, int srid)
Definition: Renderer.cpp:59
virtual bool moveBeforeFirst()=0
It moves the internal pointer to a position before the first item in the collection.
std::vector< std::size_t > m_restrictivePropertyPos
Definition: EditInfoTool.h:96
SimpleData< double, DOUBLE_TYPE > Double
Definition: SimpleData.h:227
void drawRepository(const std::string &source, const te::gm::Envelope &e, int srid)
Definition: Renderer.cpp:78
void setCursor(const QCursor &cursor)
It sets the tool cursor.
MapDisplay * m_display
The map display associated with the tool.
Definition: AbstractTool.h:171
te::da::DataSet * m_dataset
The attributes dataset type.
Definition: EditInfoTool.h:94
TEDATAACCESSEXPORT void GetOIDPropertyNames(const DataSetType *type, std::vector< std::string > &pnames)
virtual bool isNull(std::size_t i) const =0
It checks if the attribute value is NULL.
virtual int getSRID() const
It returns the Spatial Reference System ID associated to the Layer.
A class that represents the IN operator.
Definition: In.h:52
std::map< std::size_t, te::dt::AbstractData * > m_data
Definition: EditInfoTool.h:95
virtual std::size_t getNumProperties() const =0
It returns the number of properties that composes an item of the dataset.
virtual std::string getPropertyName(std::size_t i) const =0
It returns the property name at position pos.
SimpleData< boost::int16_t, INT16_TYPE > Int16
Definition: SimpleData.h:219
void pickFeature(const te::map::AbstractLayerPtr &layer, const QPointF &pos)
TEDATAACCESSEXPORT te::gm::GeometryProperty * GetFirstGeomProperty(const DataSetType *dt)
te::gm::Envelope buildEnvelope(const QPointF &pos)
void setPolygonStyle(const QColor &fillColor, const QColor &contourColor, const std::size_t &contourWidth)
Definition: Renderer.cpp:351
boost::intrusive_ptr< AbstractLayer > AbstractLayerPtr
void transform(int oldsrid, int newsrid)
It will transform the coordinates of the Envelope from the old SRS to the new one.
bool isValid() const
It tells if the rectangle is valid or not.
virtual std::string getString(std::size_t i) const =0
Method for retrieving a string value attribute.
const std::map< std::size_t, te::dt::AbstractData * > & getData() const
Definition: Feature.cpp:144
TEGEOMEXPORT Geometry * GetGeomFromEnvelope(const Envelope *const e, int srid)
It creates a Geometry (a polygon) from the given envelope.
EditInfoTool(te::qt::widgets::MapDisplay *display, const te::map::AbstractLayerPtr &layer, QObject *parent=0)
This class models a string Literal value.
Definition: LiteralString.h:46