IntersectionDialog.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/vp/qt/IntersectionDialog.cpp
22 
23  \brief A dialog for intersection operation
24 */
25 
26 // TerraLib
27 #include "../../common/Logger.h"
28 #include "../../common/progress/ProgressManager.h"
29 #include "../../common/Translator.h"
30 #include "../../dataaccess/dataset/DataSetType.h"
31 #include "../../dataaccess/dataset/ObjectIdSet.h"
32 #include "../../dataaccess/datasource/DataSourceCapabilities.h"
33 #include "../../dataaccess/datasource/DataSourceInfo.h"
34 #include "../../dataaccess/datasource/DataSourceInfoManager.h"
35 #include "../../dataaccess/datasource/DataSourceManager.h"
36 #include "../../dataaccess/datasource/DataSourceFactory.h"
37 #include "../../dataaccess/utils/Utils.h"
38 #include "../../datatype/Property.h"
39 #include "../../qt/widgets/datasource/selector/DataSourceSelectorDialog.h"
40 #include "../../qt/widgets/layer/utils/DataSet2Layer.h"
41 #include "../../qt/widgets/progress/ProgressViewerDialog.h"
42 #include "../../srs/Config.h"
43 #include "../Exception.h"
44 #include "../IntersectionMemory.h"
45 #include "../IntersectionOp.h"
46 #include "../IntersectionQuery.h"
47 #include "IntersectionDialog.h"
48 #include "LayerTreeModel.h"
49 #include "ui_IntersectionDialogForm.h"
50 #include "Utils.h"
51 
52 // Qt
53 #include <QFileDialog>
54 #include <QMessageBox>
55 #include <QTreeWidget>
56 
57 // BOOST
58 #include <boost/filesystem.hpp>
59 #include <boost/uuid/random_generator.hpp>
60 #include <boost/uuid/uuid_io.hpp>
61 
62 te::vp::IntersectionDialog::IntersectionDialog(QWidget* parent, Qt::WindowFlags f)
63  : QDialog(parent, f),
64  m_ui(new Ui::IntersectionDialogForm),
65  m_layers(std::list<te::map::AbstractLayerPtr>())
66 {
67 // add controls
68  m_ui->setupUi(this);
69 
70  m_ui->m_imgLabel->setPixmap(QIcon::fromTheme("vp-intersection-hint").pixmap(48,48));
71  m_ui->m_targetDatasourceToolButton->setIcon(QIcon::fromTheme("datasource"));
72 
73  connect(m_ui->m_firstLayerComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(onFirstLayerComboBoxChanged(int)));
74  connect(m_ui->m_secondLayerComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(onSecondLayerComboBoxChanged(int)));
75  connect(m_ui->m_okPushButton, SIGNAL(clicked()), this, SLOT(onOkPushButtonClicked()));
76  connect(m_ui->m_targetDatasourceToolButton, SIGNAL(pressed()), this, SLOT(onTargetDatasourceToolButtonPressed()));
77  connect(m_ui->m_targetFileToolButton, SIGNAL(pressed()), this, SLOT(onTargetFileToolButtonPressed()));
78 
79  m_ui->m_helpPushButton->setNameSpace("dpi.inpe.br.plugins");
80  m_ui->m_helpPushButton->setPageReference("plugins/vp/vp_intersection.html");
81 }
82 
84 {
85 }
86 
87 void te::vp::IntersectionDialog::setLayers(std::list<te::map::AbstractLayerPtr> layers)
88 {
89  m_layers = layers;
90 
91  std::list<te::map::AbstractLayerPtr>::iterator it = m_layers.begin();
92 
93  while(it != m_layers.end())
94  {
95  std::auto_ptr<te::da::DataSetType> dsType = it->get()->getSchema();
96  if(dsType->hasGeom())
97  m_ui->m_firstLayerComboBox->addItem(QString(it->get()->getTitle().c_str()), QVariant(it->get()->getId().c_str()));
98  ++it;
99  }
100 }
101 
103 {
104  return m_layerResult;
105 }
106 
108 {
109  std::list<te::map::AbstractLayerPtr>::iterator it = m_layers.begin();
110  std::string layerID = m_ui->m_firstLayerComboBox->itemData(index, Qt::UserRole).toString().toStdString();
111 
112  m_ui->m_secondLayerComboBox->clear();
113  while(it != m_layers.end())
114  {
115  if(layerID != it->get()->getId().c_str())
116  {
117  std::auto_ptr<te::da::DataSetType> dsType = it->get()->getSchema();
118  if(dsType->hasGeom())
119  m_ui->m_secondLayerComboBox->addItem(QString(it->get()->getTitle().c_str()), QVariant(it->get()->getId().c_str()));
120  }
121  else
122  {
123  te::map::AbstractLayerPtr selectedLayer = it->get();
124  m_firstSelectedLayer = selectedLayer;
125  }
126 
127  ++it;
128  }
129 }
130 
132 {
133  std::list<te::map::AbstractLayerPtr>::iterator it = m_layers.begin();
134  std::string layerID = m_ui->m_secondLayerComboBox->itemData(index, Qt::UserRole).toString().toStdString();
135 
136  while(it != m_layers.end())
137  {
138  if(layerID == it->get()->getId().c_str())
139  {
140  te::map::AbstractLayerPtr selectedLayer = it->get();
141  m_secondSelectedLayer = selectedLayer;
142  }
143 
144  ++it;
145  }
146 }
147 
149 {
150  std::vector<int> inSRID;
151 
152  if(m_ui->m_firstLayerComboBox->currentText().isEmpty())
153  {
154  QMessageBox::warning(this, TE_TR("Intersection"), TE_TR("Select a first input layer."));
155  return;
156  }
157 
158  te::map::DataSetLayer* firstDataSetLayer = dynamic_cast<te::map::DataSetLayer*>(m_firstSelectedLayer.get());
159  if(!firstDataSetLayer)
160  {
161  QMessageBox::information(this, "Intersection", "Can not execute this operation on this type of first layer.");
162  return;
163  }
164 
165  inSRID.push_back(firstDataSetLayer->getSRID());
166 
167  const te::da::ObjectIdSet* firstOidSet = 0;
168  if(m_ui->m_firstSelectedCheckBox->isChecked())
169  {
170  firstOidSet = firstDataSetLayer->getSelected();
171  if(!firstOidSet)
172  {
173  QMessageBox::information(this, "Intersection", "Select the layer objects to perform the intersection operation.");
174  return;
175  }
176  }
177 
178  te::da::DataSourcePtr firstDataSource = te::da::GetDataSource(firstDataSetLayer->getDataSourceId(), true);
179  if (!firstDataSource.get())
180  {
181  QMessageBox::information(this, "Intersection", "The selected first input data source can not be accessed.");
182  return;
183  }
184 
185  if(m_ui->m_secondLayerComboBox->currentText().isEmpty())
186  {
187  QMessageBox::warning(this, TE_TR("Intersection"), TE_TR("Select a second input layer."));
188  return;
189  }
190 
191  te::map::DataSetLayer* secondDataSetLayer = dynamic_cast<te::map::DataSetLayer*>(m_secondSelectedLayer.get());
192  if(!secondDataSetLayer)
193  {
194  QMessageBox::information(this, "Intersection", "Can not execute this operation on this type of second layer.");
195  return;
196  }
197 
198  inSRID.push_back(secondDataSetLayer->getSRID());
199 
200  const te::da::ObjectIdSet* secondOidSet = 0;
201  if(m_ui->m_secondSelectedCheckBox->isChecked())
202  {
203  secondOidSet = m_secondSelectedLayer->getSelected();
204  if(!secondOidSet)
205  {
206  QMessageBox::information(this, "Intersection", "Select the layer objects to perform the intersection operation.");
207  return;
208  }
209  }
210 
211  te::da::DataSourcePtr secondDataSource = te::da::GetDataSource(secondDataSetLayer->getDataSourceId(), true);
212  if (!secondDataSource.get())
213  {
214  QMessageBox::information(this, "Intersection", "The selected second input data source can not be accessed.");
215  return;
216  }
217 
218  if(m_ui->m_repositoryLineEdit->text().isEmpty())
219  {
220  QMessageBox::warning(this, TE_TR("Intersection"), TE_TR("Select a repository for the resulting layer."));
221  return;
222  }
223 
224  if(m_ui->m_newLayerNameLineEdit->text().isEmpty())
225  {
226  QMessageBox::warning(this, TE_TR("Intersection"), TE_TR("Define a name for the resulting layer."));
227  return;
228  }
229 
230  if ((firstDataSetLayer->getSRID() == TE_UNKNOWN_SRS && secondDataSetLayer->getSRID() != TE_UNKNOWN_SRS) ||
231  (firstDataSetLayer->getSRID() != TE_UNKNOWN_SRS && secondDataSetLayer->getSRID() == TE_UNKNOWN_SRS))
232  {
233  int ret = QMessageBox::question(this, "Intersection", "The two layers have incompatible SRS. The result might be incorrect. Do you wish to continue?", QMessageBox::No, QMessageBox::Yes);
234  if (ret == QMessageBox::No)
235  return;
236  }
237 
238  //progress
241 
242  try
243  {
244  bool copyInputColumns = m_ui->m_copyColumnsCheckBox->isChecked();
245  std::string outputdataset = m_ui->m_newLayerNameLineEdit->text().toStdString();
246 
247  bool res;
248  if (m_toFile)
249  {
250  boost::filesystem::path uri(m_ui->m_repositoryLineEdit->text().toStdString());
251 
252  if (boost::filesystem::exists(uri))
253  {
254  QMessageBox::information(this, "Intersection", "Output file already exists. Remove it and try again. ");
255  return;
256  }
257 
258  std::size_t idx = outputdataset.find(".");
259  if(idx != std::string::npos)
260  outputdataset = outputdataset.substr(0, idx);
261 
262  std::map<std::string, std::string> dsinfo;
263  dsinfo["URI"] = uri.string();
264 
266  dsOGR->setConnectionInfo(dsinfo);
267  dsOGR->open();
268  if(dsOGR->dataSetExists(outputdataset))
269  {
270  QMessageBox::information(this, "Intersection", "Output file already exists. Remove it or select a new name and try again.");
271  return;
272  }
273 
274  std::auto_ptr<te::da::DataSetTypeConverter> firstConverter(new te::da::DataSetTypeConverter(firstDataSetLayer->getSchema().get(), dsOGR->getCapabilities(), dsOGR->getEncoding()));
275  te::da::AssociateDataSetTypeConverterSRID(firstConverter.get(), firstDataSetLayer->getSRID());
276 
277  std::auto_ptr<te::da::DataSetTypeConverter> secondConverter(new te::da::DataSetTypeConverter(secondDataSetLayer->getSchema().get(), dsOGR->getCapabilities(), dsOGR->getEncoding()));
278  te::da::AssociateDataSetTypeConverterSRID(secondConverter.get(), firstDataSetLayer->getSRID());
279 
280  this->setCursor(Qt::WaitCursor);
281 
282  te::vp::IntersectionOp* intersectionOp = 0;
283 
284  // select a strategy based on the capabilities of the input datasource
285  const te::da::DataSourceCapabilities firstDSCapabilities = firstDataSource->getCapabilities();
286  const te::da::DataSourceCapabilities secondDSCapabilities = secondDataSource->getCapabilities();
287 
288  if( firstDSCapabilities.getQueryCapabilities().supportsSpatialSQLDialect() &&
289  secondDSCapabilities.getQueryCapabilities().supportsSpatialSQLDialect() &&
290  (firstDataSource->getId() == secondDataSource->getId()))
291  {
292  intersectionOp = new te::vp::IntersectionQuery();
293  }
294  else
295  {
296  intersectionOp = new te::vp::IntersectionMemory();
297  }
298 
299  intersectionOp->setInput( firstDataSource, firstDataSetLayer->getDataSetName(), firstConverter,
300  secondDataSource, secondDataSetLayer->getDataSetName(), secondConverter,
301  firstOidSet, secondOidSet);
302  intersectionOp->setOutput(dsOGR, outputdataset);
303  intersectionOp->setParams(copyInputColumns);
304 
305  if (!intersectionOp->paramsAreValid())
306  res = false;
307  else
308  res = intersectionOp->run();
309 
310  if(!res)
311  {
312  dsOGR->close();
313  QMessageBox::information(this, "Intersection", "Error: could not generate the intersection.");
314  reject();
315  }
316  dsOGR->close();
317 
318  delete intersectionOp;
319 
320  // let's include the new datasource in the managers
321  boost::uuids::basic_random_generator<boost::mt19937> gen;
322  boost::uuids::uuid u = gen();
323  std::string id = boost::uuids::to_string(u);
324 
326  ds->setConnInfo(dsinfo);
327  ds->setTitle(uri.stem().string());
328  ds->setAccessDriver("OGR");
329  ds->setType("OGR");
330  ds->setDescription(uri.string());
331  ds->setId(id);
332 
333  te::da::DataSourcePtr newds = te::da::DataSourceManager::getInstance().get(id, "OGR", ds->getConnInfo());
334  newds->open();
336  m_outputDatasource = ds;
337  }
338  else
339  {
340  te::da::DataSourcePtr aux = te::da::GetDataSource(m_outputDatasource->getId());
341  if (!aux.get())
342  {
343  QMessageBox::information(this, "Intersection", "The output data source can not be accessed.");
344  return;
345  }
346  if (aux->dataSetExists(outputdataset))
347  {
348  QMessageBox::information(this, "Intersection", "Dataset already exists. Remove it or select a new name and try again. ");
349  return;
350  }
351 
352  std::auto_ptr<te::da::DataSetTypeConverter> firstConverter(new te::da::DataSetTypeConverter(firstDataSetLayer->getSchema().get(), aux->getCapabilities(), aux->getEncoding()));
353  te::da::AssociateDataSetTypeConverterSRID(firstConverter.get(), firstDataSetLayer->getSRID());
354 
355  std::auto_ptr<te::da::DataSetTypeConverter> secondConverter(new te::da::DataSetTypeConverter(secondDataSetLayer->getSchema().get(), aux->getCapabilities(), aux->getEncoding()));
356  te::da::AssociateDataSetTypeConverterSRID(secondConverter.get(), firstDataSetLayer->getSRID());
357 
358  this->setCursor(Qt::WaitCursor);
359 
360  te::vp::IntersectionOp* intersectionOp = 0;
361 
362  // select a strategy based on the capabilities of the input datasource
363  const te::da::DataSourceCapabilities firstDSCapabilities = firstDataSource->getCapabilities();
364  const te::da::DataSourceCapabilities secondDSCapabilities = secondDataSource->getCapabilities();
365 
366  if( firstDSCapabilities.getQueryCapabilities().supportsSpatialSQLDialect() &&
367  secondDSCapabilities.getQueryCapabilities().supportsSpatialSQLDialect() &&
368  (firstDataSource->getId() == secondDataSource->getId()) &&
369  (firstDataSetLayer->getSRID() == secondDataSetLayer->getSRID()))
370  {
371  intersectionOp = new te::vp::IntersectionQuery();
372  }
373  else
374  {
375  intersectionOp = new te::vp::IntersectionMemory();
376  }
377 
378  intersectionOp->setInput( firstDataSource, firstDataSetLayer->getDataSetName(), firstConverter,
379  secondDataSource, secondDataSetLayer->getDataSetName(), secondConverter,
380  firstOidSet, secondOidSet);
381  intersectionOp->setOutput(aux, outputdataset);
382  intersectionOp->setParams(copyInputColumns);
383 
384  if (!intersectionOp->paramsAreValid())
385  res = false;
386  else
387  res = intersectionOp->run();
388 
389  delete intersectionOp;
390 
391  if(!res)
392  {
393  this->setCursor(Qt::ArrowCursor);
394  QMessageBox::information(this, "Intersection", "Error: could not generate the intersection.");
395  reject();
396  }
397  }
398 
399  // creating a layer for the result
400  te::da::DataSourcePtr outDataSource = te::da::GetDataSource(m_outputDatasource->getId());
401 
402  te::qt::widgets::DataSet2Layer converter(m_outputDatasource->getId());
403 
404  te::da::DataSetTypePtr dt(outDataSource->getDataSetType(outputdataset).release());
405  m_layerResult = converter(dt);
406  }
407  catch(const std::exception& e)
408  {
409  this->setCursor(Qt::ArrowCursor);
410  QMessageBox::warning(this, TE_TR("Intersection"), e.what());
411 
412 #ifdef TERRALIB_LOGGER_ENABLED
413  std::string str = "Intersection - ";
414  str += e.what();
415  te::common::Logger::logDebug("vp", str.c_str());
416 #endif //TERRALIB_LOGGER_ENABLED
417 
419  return;
420  }
421 
423  this->setCursor(Qt::ArrowCursor);
424  accept();
425 }
426 
428 {
429  m_ui->m_newLayerNameLineEdit->clear();
430  m_ui->m_newLayerNameLineEdit->setEnabled(true);
432  dlg.exec();
433 
434  std::list<te::da::DataSourceInfoPtr> dsPtrList = dlg.getSelecteds();
435 
436  if(dsPtrList.empty())
437  return;
438 
439  std::list<te::da::DataSourceInfoPtr>::iterator it = dsPtrList.begin();
440 
441  m_ui->m_repositoryLineEdit->setText(QString(it->get()->getTitle().c_str()));
442 
443  m_outputDatasource = *it;
444 
445  m_toFile = false;
446 }
447 
449 {
450  m_ui->m_newLayerNameLineEdit->clear();
451  m_ui->m_repositoryLineEdit->clear();
452 
453  QString fileName = QFileDialog::getSaveFileName(this, tr("Save as..."),
454  QString(), tr("Shapefile (*.shp *.SHP);;"),0, QFileDialog::DontConfirmOverwrite);
455 
456  if (fileName.isEmpty())
457  return;
458 
459  boost::filesystem::path outfile(fileName.toStdString());
460  std::string aux = outfile.leaf().string();
461  m_ui->m_newLayerNameLineEdit->setText(aux.c_str());
462  aux = outfile.string();
463  m_ui->m_repositoryLineEdit->setText(aux.c_str());
464 
465  m_toFile = true;
466  m_ui->m_newLayerNameLineEdit->setEnabled(false);
467 }
TEDATAACCESSEXPORT DataSourcePtr GetDataSource(const std::string &datasourceId, const bool opened=true)
Search for a data source with the informed id in the DataSourceManager.
Definition: Utils.cpp:262
Utility functions for the data access module.
const std::string & getDataSetName() const
void setLayers(std::list< te::map::AbstractLayerPtr > layers)
Set the layer that can be used.
std::auto_ptr< Ui::IntersectionDialogForm > m_ui
boost::shared_ptr< DataSetType > DataSetTypePtr
Definition: DataSetType.h:653
boost::shared_ptr< DataSource > DataSourcePtr
Definition: DataSource.h:1435
TEDATAACCESSEXPORT void AssociateDataSetTypeConverterSRID(DataSetTypeConverter *converter, const int &inputSRID, const int &outputSRID=TE_UNKNOWN_SRS)
Definition: Utils.cpp:670
A class that represents the known capabilities of a specific data source, i.e. this class informs all...
virtual bool paramsAreValid()
#define TE_TR(message)
It marks a string in order to get translated.
Definition: Translator.h:346
const QueryCapabilities & getQueryCapabilities() const
An converter for DataSetType.
The class that defines the model used in the Qt Model/View architecture.
void removeViewer(int viewerId)
Dettach a progress viewer.
static ProgressManager & getInstance()
It returns a reference to the singleton instance.
const std::string & getDataSourceId() const
#define TE_UNKNOWN_SRS
A numeric value to represent a unknown SRS identification in TerraLib.
Definition: Config.h:41
This class represents a set of unique ids created in the same context. i.e. from the same data set...
Definition: ObjectIdSet.h:55
static std::auto_ptr< DataSource > make(const std::string &dsType)
URI C++ Library.
te::map::AbstractLayerPtr getLayer()
virtual bool run()=0
bool supportsSpatialSQLDialect() const
void setOutput(te::da::DataSourcePtr outDsrc, std::string dsname)
A dialog intersection operation.
void setInput(te::da::DataSourcePtr inFirstDsrc, std::string inFirstDsetName, std::auto_ptr< te::da::DataSetTypeConverter > firstConverter, te::da::DataSourcePtr inSecondDsrc, std::string inSecondDsetName, std::auto_ptr< te::da::DataSetTypeConverter > secondConverter, const te::da::ObjectIdSet *firstOidSet=0, const te::da::ObjectIdSet *secondOidSet=0)
int addViewer(AbstractProgressViewer *apv)
Attach a progress viewer.
virtual const te::da::ObjectIdSet * getSelected() const
It returns the selected group of this Layer.
const std::list< te::da::DataSourceInfoPtr > & getSelecteds() const
A dialog for selecting a data source.
A class that represents a data source component.
void setParams(const bool &copyInputColumns)
virtual int getSRID() const
It returns the Spatial Reference System ID associated to the Layer.
A layer with reference to a dataset.
Definition: DataSetLayer.h:47
void onSecondLayerComboBoxChanged(int index)
std::auto_ptr< LayerSchema > getSchema() const
It returns the layer schema.
IntersectionDialog(QWidget *parent=0, Qt::WindowFlags f=0)
boost::intrusive_ptr< AbstractLayer > AbstractLayerPtr
void onFirstLayerComboBoxChanged(int index)
boost::shared_ptr< DataSourceInfo > DataSourceInfoPtr