All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Groups Pages
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_helpPushButton, SIGNAL(clicked()), this, SLOT(onHelpPushButtonClicked()));
76  connect(m_ui->m_okPushButton, SIGNAL(clicked()), this, SLOT(onOkPushButtonClicked()));
77  connect(m_ui->m_targetDatasourceToolButton, SIGNAL(pressed()), this, SLOT(onTargetDatasourceToolButtonPressed()));
78  connect(m_ui->m_targetFileToolButton, SIGNAL(pressed()), this, SLOT(onTargetFileToolButtonPressed()));
79 
80  m_ui->m_helpPushButton->setNameSpace("dpi.inpe.br.plugins");
81  m_ui->m_helpPushButton->setPageReference("plugins/vp/vp_intersection.html");
82 }
83 
85 {
86 }
87 
88 void te::vp::IntersectionDialog::setLayers(std::list<te::map::AbstractLayerPtr> layers)
89 {
90  m_layers = layers;
91 
92  std::list<te::map::AbstractLayerPtr>::iterator it = m_layers.begin();
93 
94  while(it != m_layers.end())
95  {
96  std::auto_ptr<te::da::DataSetType> dsType = it->get()->getSchema();
97  if(dsType->hasGeom())
98  m_ui->m_firstLayerComboBox->addItem(QString(it->get()->getTitle().c_str()), QVariant(it->get()->getId().c_str()));
99  ++it;
100  }
101 }
102 
104 {
105  return m_layerResult;
106 }
107 
109 {
110  std::list<te::map::AbstractLayerPtr>::iterator it = m_layers.begin();
111  std::string layerID = m_ui->m_firstLayerComboBox->itemData(index, Qt::UserRole).toString().toStdString();
112 
113  m_ui->m_secondLayerComboBox->clear();
114  while(it != m_layers.end())
115  {
116  if(layerID != it->get()->getId().c_str())
117  {
118  std::auto_ptr<te::da::DataSetType> dsType = it->get()->getSchema();
119  if(dsType->hasGeom())
120  m_ui->m_secondLayerComboBox->addItem(QString(it->get()->getTitle().c_str()), QVariant(it->get()->getId().c_str()));
121  }
122  else
123  {
124  te::map::AbstractLayerPtr selectedLayer = it->get();
125  m_firstSelectedLayer = selectedLayer;
126  }
127 
128  ++it;
129  }
130 }
131 
133 {
134  std::list<te::map::AbstractLayerPtr>::iterator it = m_layers.begin();
135  std::string layerID = m_ui->m_secondLayerComboBox->itemData(index, Qt::UserRole).toString().toStdString();
136 
137  while(it != m_layers.end())
138  {
139  if(layerID == it->get()->getId().c_str())
140  {
141  te::map::AbstractLayerPtr selectedLayer = it->get();
142  m_secondSelectedLayer = selectedLayer;
143  }
144 
145  ++it;
146  }
147 }
148 
150 {
151  QMessageBox::information(this, "Intersection Operation", "Under development");
152 }
153 
155 {
156  if(m_ui->m_firstLayerComboBox->currentText().isEmpty())
157  {
158  QMessageBox::warning(this, TE_TR("Intersection"), TE_TR("Select a first input layer."));
159  return;
160  }
161 
162  te::map::DataSetLayer* firstDataSetLayer = dynamic_cast<te::map::DataSetLayer*>(m_firstSelectedLayer.get());
163  if(!firstDataSetLayer)
164  {
165  QMessageBox::information(this, "Intersection", "Can not execute this operation on this type of first layer.");
166  return;
167  }
168 
169  const te::da::ObjectIdSet* firstOidSet = 0;
170  if(m_ui->m_firstSelectedCheckBox->isChecked())
171  {
172  firstOidSet = firstDataSetLayer->getSelected();
173  if(!firstOidSet)
174  {
175  QMessageBox::information(this, "Intersection", "Select the layer objects to perform the intersection operation.");
176  return;
177  }
178  }
179 
180  te::da::DataSourcePtr firstDataSource = te::da::GetDataSource(firstDataSetLayer->getDataSourceId(), true);
181  if (!firstDataSource.get())
182  {
183  QMessageBox::information(this, "Intersection", "The selected first input data source can not be accessed.");
184  return;
185  }
186 
187  if(m_ui->m_secondLayerComboBox->currentText().isEmpty())
188  {
189  QMessageBox::warning(this, TE_TR("Intersection"), TE_TR("Select a second input layer."));
190  return;
191  }
192 
193  te::map::DataSetLayer* secondDataSetLayer = dynamic_cast<te::map::DataSetLayer*>(m_secondSelectedLayer.get());
194  if(!secondDataSetLayer)
195  {
196  QMessageBox::information(this, "Intersection", "Can not execute this operation on this type of second layer.");
197  return;
198  }
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  this->setCursor(Qt::WaitCursor);
275 
276  te::vp::IntersectionOp* intersectionOp = 0;
277 
278  // select a strategy based on the capabilities of the input datasource
279  const te::da::DataSourceCapabilities firstDSCapabilities = firstDataSource->getCapabilities();
280  const te::da::DataSourceCapabilities secondDSCapabilities = secondDataSource->getCapabilities();
281 
282  if( firstDSCapabilities.getQueryCapabilities().supportsSpatialSQLDialect() &&
283  secondDSCapabilities.getQueryCapabilities().supportsSpatialSQLDialect() &&
284  (firstDataSource->getId() == secondDataSource->getId()))
285  {
286  intersectionOp = new te::vp::IntersectionQuery();
287  }
288  else
289  {
290  intersectionOp = new te::vp::IntersectionMemory();
291  }
292 
293  intersectionOp->setInput( firstDataSource, firstDataSetLayer->getDataSetName(), firstDataSetLayer->getSchema(),
294  secondDataSource, secondDataSetLayer->getDataSetName(), secondDataSetLayer->getSchema(),
295  firstOidSet, secondOidSet);
296  intersectionOp->setOutput(dsOGR, outputdataset);
297  intersectionOp->setParams(copyInputColumns, firstDataSetLayer->getSRID());
298 
299  if (!intersectionOp->paramsAreValid())
300  res = false;
301  else
302  res = intersectionOp->run();
303 
304  if(!res)
305  {
306  dsOGR->close();
307  QMessageBox::information(this, "Intersection", "Error: could not generate the intersection.");
308  reject();
309  }
310  dsOGR->close();
311 
312  delete intersectionOp;
313 
314  // let's include the new datasource in the managers
315  boost::uuids::basic_random_generator<boost::mt19937> gen;
316  boost::uuids::uuid u = gen();
317  std::string id = boost::uuids::to_string(u);
318 
320  ds->setConnInfo(dsinfo);
321  ds->setTitle(uri.stem().string());
322  ds->setAccessDriver("OGR");
323  ds->setType("OGR");
324  ds->setDescription(uri.string());
325  ds->setId(id);
326 
327  te::da::DataSourcePtr newds = te::da::DataSourceManager::getInstance().get(id, "OGR", ds->getConnInfo());
328  newds->open();
330  m_outputDatasource = ds;
331  }
332  else
333  {
334  te::da::DataSourcePtr aux = te::da::GetDataSource(m_outputDatasource->getId());
335  if (!aux.get())
336  {
337  QMessageBox::information(this, "Intersection", "The output data source can not be accessed.");
338  return;
339  }
340  if (aux->dataSetExists(outputdataset))
341  {
342  QMessageBox::information(this, "Intersection", "Dataset already exists. Remove it or select a new name and try again. ");
343  return;
344  }
345  this->setCursor(Qt::WaitCursor);
346 
347  te::vp::IntersectionOp* intersectionOp = 0;
348 
349  // select a strategy based on the capabilities of the input datasource
350  const te::da::DataSourceCapabilities firstDSCapabilities = firstDataSource->getCapabilities();
351  const te::da::DataSourceCapabilities secondDSCapabilities = secondDataSource->getCapabilities();
352 
353  if( firstDSCapabilities.getQueryCapabilities().supportsSpatialSQLDialect() &&
354  secondDSCapabilities.getQueryCapabilities().supportsSpatialSQLDialect() &&
355  (firstDataSource->getId() == secondDataSource->getId()) &&
356  (firstDataSetLayer->getSRID() == secondDataSetLayer->getSRID()))
357  {
358  intersectionOp = new te::vp::IntersectionQuery();
359  }
360  else
361  {
362  intersectionOp = new te::vp::IntersectionMemory();
363  }
364 
365  intersectionOp->setInput( firstDataSource, firstDataSetLayer->getDataSetName(), firstDataSetLayer->getSchema(),
366  secondDataSource, secondDataSetLayer->getDataSetName(), secondDataSetLayer->getSchema(),
367  firstOidSet, secondOidSet);
368  intersectionOp->setOutput(aux, outputdataset);
369  intersectionOp->setParams(copyInputColumns, firstDataSetLayer->getSRID());
370 
371  if (!intersectionOp->paramsAreValid())
372  res = false;
373  else
374  res = intersectionOp->run();
375 
376  delete intersectionOp;
377 
378  if(!res)
379  {
380  this->setCursor(Qt::ArrowCursor);
381  QMessageBox::information(this, "Intersection", "Error: could not generate the intersection.");
382  reject();
383  }
384  }
385 
386  // creating a layer for the result
387  te::da::DataSourcePtr outDataSource = te::da::GetDataSource(m_outputDatasource->getId());
388 
389  te::qt::widgets::DataSet2Layer converter(m_outputDatasource->getId());
390 
391  te::da::DataSetTypePtr dt(outDataSource->getDataSetType(outputdataset).release());
392  m_layerResult = converter(dt);
393  }
394  catch(const std::exception& e)
395  {
396  this->setCursor(Qt::ArrowCursor);
397  QMessageBox::warning(this, TE_TR("Intersection"), e.what());
398 
399 #ifdef TERRALIB_LOGGER_ENABLED
400  std::string str = "Intersection - ";
401  str += e.what();
402  te::common::Logger::logDebug("vp", str.c_str());
403 #endif //TERRALIB_LOGGER_ENABLED
404 
406  return;
407  }
408 
410  this->setCursor(Qt::ArrowCursor);
411  accept();
412 }
413 
415 {
416  m_ui->m_newLayerNameLineEdit->clear();
417  m_ui->m_newLayerNameLineEdit->setEnabled(true);
419  dlg.exec();
420 
421  std::list<te::da::DataSourceInfoPtr> dsPtrList = dlg.getSelecteds();
422 
423  if(dsPtrList.size() <= 0)
424  return;
425 
426  std::list<te::da::DataSourceInfoPtr>::iterator it = dsPtrList.begin();
427 
428  m_ui->m_repositoryLineEdit->setText(QString(it->get()->getTitle().c_str()));
429 
430  m_outputDatasource = *it;
431 
432  m_toFile = false;
433 }
434 
436 {
437  m_ui->m_newLayerNameLineEdit->clear();
438  m_ui->m_repositoryLineEdit->clear();
439 
440  QString fileName = QFileDialog::getSaveFileName(this, tr("Save as..."),
441  QString(), tr("Shapefile (*.shp *.SHP);;"),0, QFileDialog::DontConfirmOverwrite);
442 
443  if (fileName.isEmpty())
444  return;
445 
446  boost::filesystem::path outfile(fileName.toStdString());
447  std::string aux = outfile.leaf().string();
448  m_ui->m_newLayerNameLineEdit->setText(aux.c_str());
449  aux = outfile.string();
450  m_ui->m_repositoryLineEdit->setText(aux.c_str());
451 
452  m_toFile = true;
453  m_ui->m_newLayerNameLineEdit->setEnabled(false);
454 }
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.
void setInput(te::da::DataSourcePtr inFirstDsrc, std::string inFirstDsetName, std::auto_ptr< te::da::DataSetType > inFirstDsetType, te::da::DataSourcePtr inSecondDsrc, std::string inSecondDsetName, std::auto_ptr< te::da::DataSetType > inSecondDsetType, const te::da::ObjectIdSet *firstOidSet=0, const te::da::ObjectIdSet *secondOidSet=0)
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
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:347
const QueryCapabilities & getQueryCapabilities() const
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:44
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)
te::map::AbstractLayerPtr getLayer()
virtual bool run()=0
bool supportsSpatialSQLDialect() const
void setOutput(te::da::DataSourcePtr outDsrc, std::string dsname)
void setParams(const bool &copyInputColumns, std::size_t inSRID)
A dialog intersection operation.
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.
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