TableLinkDialog.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/qt/widgets/externaltable/TableLinkDialog.h
22 
23  \brief A Qt dialog that allows users to create a new query layer based on the information of two distinct datasets
24 */
25 
26 // TerraLib
27 #include "../../../core/translator/Translator.h"
28 #include "../../../dataaccess/dataset/PrimaryKey.h"
29 #include "../../../dataaccess/datasource/DataSourceManager.h"
30 #include "../../../dataaccess/Enums.h"
31 #include "../../../dataaccess/query/BinaryFunction.h"
32 #include "../../../dataaccess/query/DataSetName.h"
33 #include "../../../dataaccess/query/Expression.h"
34 #include "../../../dataaccess/query/Field.h"
35 #include "../../../dataaccess/query/Join.h"
36 #include "../../../dataaccess/query/JoinConditionOn.h"
37 #include "../../../dataaccess/query/PropertyName.h"
38 #include "../../../dataaccess/utils/Utils.h"
39 #include "../../../geometry/GeometryProperty.h"
40 #include "../../../maptools/QueryLayer.h"
41 #include "../../../memory/DataSet.h"
42 #include "../../../qt/widgets/utils/ScopedCursor.h"
43 #include "../../../se/Utils.h"
44 #include "../table/DataSetTableView.h"
45 #include "FieldsDialog.h"
46 #include "TableLinkDialog.h"
47 #include "ui_TableLinkDialogForm.h"
48 
49 // Boost
50 #include <boost/uuid/random_generator.hpp>
51 #include <boost/uuid/uuid_io.hpp>
52 
53 //QT
54 #include <QMessageBox>
55 
56 // STL
57 #include <cassert>
58 
60  : QDialog(parent, f),
61  m_ui(new Ui::TableLinkDialogForm)
62 {
63  m_ui->setupUi(this);
64  m_ui->m_dataToolButton->setIcon(QIcon::fromTheme("view-data-table"));
65  m_ui->m_dataToolButton->setToolTip(tr("View dataset rows"));
66 
67  //Adjusting the dataSetTableView that will be used to display the tabular dataset's data
68  m_tabularView.reset(new DataSetTableView(m_ui->m_tabularFrame));
69  QGridLayout* tabularLayout = new QGridLayout(m_ui->m_tabularFrame);
70  tabularLayout->addWidget(m_tabularView.get());
71  tabularLayout->setContentsMargins(0, 0, 0, 0);
72 
73  m_tabularView->setAlternatingRowColors(true);
74  m_tabularView->verticalHeader()->setVisible(false);
75  m_tabularView->setSelectionMode(QAbstractItemView::NoSelection);
76  m_tabularView->hide();
77  m_ui->m_dataPreviewGroupBox->hide();
78  m_ui->m_helpPushButton->setPageReference("widgets/external_table/table_link_dialog.html");
79 
80  //Connecting signals and slots
81  connect(m_ui->m_dataSet2ComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(onDataCBIndexChanged(int)));
82  connect(m_ui->m_dataToolButton, SIGNAL(clicked()), this, SLOT(onDataToolButtonnClicked()));
83  connect(m_ui->m_OkPushButton, SIGNAL(clicked()), this, SLOT(onOkPushButtonClicked()));
84 
85 }
86 
88 
90 {
91  m_inputLayer.reset((te::map::DataSetLayer*)inLayer.get());
92  m_ui->m_dataSet1LineEdit->setText(QString::fromUtf8(m_inputLayer->getDataSetName().c_str()));
93  m_ds = te::da::DataSourceManager::getInstance().find(m_inputLayer->getDataSourceId());
94 
95  if(!m_ds->isOpened())
96  m_ds->open();
97 
98  getDataSets();
99 }
100 
102 {
103  size_t pos = m_inputLayer->getDataSetName().find(".");
104  std::string inputAlias = m_inputLayer->getDataSetName().substr(pos + 1, m_inputLayer->getDataSetName().size() - 1);
105 
106  if(pos != std::string::npos)
107  inputAlias = m_inputLayer->getDataSetName().substr(pos + 1, m_inputLayer->getDataSetName().size() - 1);
108  else
109  inputAlias = m_inputLayer->getDataSetName();
110 
111  te::da::DataSetName* inField = new te::da::DataSetName(m_inputLayer->getDataSetName(), inputAlias);
112  te::da::DataSetName* tabField = new te::da::DataSetName(m_ui->m_dataSet2ComboBox->currentText().toUtf8().data(), m_ui->m_dataSetAliasLineEdit->text().toUtf8().data());
113 
114  te::da::Expression* exp1 = new te::da::PropertyName(m_ui->m_dataset1ColumnComboBox->currentText().toUtf8().data());
115  te::da::Expression* exp2 = new te::da::PropertyName(m_ui->m_dataset2ColumnComboBox->currentText().toUtf8().data());
116  te::da::Expression* expression = new te::da::BinaryFunction("=", exp1, exp2);
117 
119 
120  te::da::Join* join = new te::da::Join(inField, tabField, type, new te::da::JoinConditionOn(expression));
121  return join;
122 }
123 
125 {
126  //fields
127  te::da::Fields* fields = new te::da::Fields;
128 
129  for (const std::string& unique : m_uniqueProps)
130  {
131  //Primary keys properties will have aliases to identify the original dataset
132  te::da::Field* f = new te::da::Field(unique, "\"" + unique + "\"");
133 
134  fields->push_back(f);
135  }
136 
137  for (const std::string& prop : m_properties)
138  {
139  te::da::Field* f = new te::da::Field(prop);
140  fields->push_back(f);
141  }
142 
143  //from
144  te::da::From* from = new te::da::From;
145 
146  //Join
147  from->push_back(getJoin());
148 
149  //build the select object
150  te::da::Select s(fields, from);
151 
152  return s;
153 }
154 
156 {
157  te::qt::widgets::ScopedCursor c(Qt::WaitCursor);
158 
159  static boost::uuids::basic_random_generator<boost::mt19937> gen;
160  boost::uuids::uuid u = gen();
161  std::string id = boost::uuids::to_string(u);
162 
163  std::string title = m_ui->m_layerTitleLineEdit->text().toUtf8().data();
164 
165  te::map::QueryLayerPtr layer(new te::map::QueryLayer(id, title));
166  layer->setDataSourceId(m_ds->getId());
167  layer->setDataSetName(m_inputLayer->getDataSetName());
168  layer->setRendererType("QUERY_LAYER_RENDERER");
169  layer->setQuery(new te::da::Select(getSelectQuery()));
170 
171  // SRID
172  std::unique_ptr<const te::map::LayerSchema> schema(layer->getSchema());
174  if(gp)
175  {
176  layer->setSRID(gp->getSRID());
177  layer->computeExtent();
178 
179  // style
180  layer->setStyle(te::se::CreateFeatureTypeStyle(gp->getGeometryType()));
181  }
182 
183  return layer;
184 }
185 
187 {
188  te::qt::widgets::ScopedCursor c(Qt::WaitCursor);
189 
190  std::string dsId = m_ds->getId();
191 
192  std::vector<std::string> datasetNames;
193 
194  te::da::GetDataSetNames(datasetNames, dsId);
195 
196  for (size_t i = 0; i < datasetNames.size(); i++)
197  {
198  std::unique_ptr<te::da::DataSetType> dataType(te::da::GetDataSetType(datasetNames[i], dsId));
199 
200  //The layer on the right side of the join must be different than the first and can not have a geometry
201  if((datasetNames[i] != m_inputLayer->getDataSetName()) && (!dataType->hasGeom()))
202  m_ui->m_dataSet2ComboBox->addItem(QString::fromUtf8(datasetNames[i].c_str()));
203  }
204 
205  if (m_ui->m_dataSet2ComboBox->count() == 0)
206  {
207  throw te::common::Exception(TE_TR("No tabular data available to be linked in the selected Data Source."));
208  return;
209  }
210 
211  std::string DsName = m_ui->m_dataSet2ComboBox->currentText().toUtf8().data();
212  size_t pos = DsName.find(".");
213  if(pos != std::string::npos)
214  m_ui->m_dataSetAliasLineEdit->setText(QString::fromUtf8(DsName.substr(pos + 1, DsName.size() - 1).c_str()));
215  else
216  m_ui->m_dataSetAliasLineEdit->setText(QString::fromUtf8(DsName.c_str()));
217 }
218 
220 {
221  m_uniqueProps.clear();
222  m_properties.clear();
223 
224  te::qt::widgets::ScopedCursor c(Qt::WaitCursor);
225 
226  //Clearing contents
227  int index = m_ui->m_dataset1ColumnComboBox->currentIndex();
228  m_ui->m_dataset1ColumnComboBox->clear();
229  m_ui->m_dataset2ColumnComboBox->clear();
230 
231  //get the dataset names
232  std::vector<std::string> datasetNames = m_ds->getDataSetNames();
233  std::vector<std::pair<std::string, std::string> > dataSetSelecteds;
234  std::string inputAlias;
235  size_t pos = m_inputLayer->getDataSetName().find(".");
236 
237  if(pos != std::string::npos)
238  inputAlias = m_inputLayer->getDataSetName().substr(pos + 1, m_inputLayer->getDataSetName().size() - 1);
239  else
240  inputAlias = m_inputLayer->getDataSetName();
241 
242  dataSetSelecteds.push_back(std::make_pair(m_inputLayer->getDataSetName(), inputAlias));
243  dataSetSelecteds.push_back(std::make_pair(m_ui->m_dataSet2ComboBox->currentText().toUtf8().data(), m_ui->m_dataSetAliasLineEdit->text().toUtf8().data()));
244 
245  //property names
246  std::set<std::string> propertyNames;
247 
248  //get properties for each data set
249  for(size_t t = 0; t < dataSetSelecteds.size(); ++t)
250  {
251  //alias name
252  std::string alias = dataSetSelecteds[t].second;
253 
254  //data set name
255  std::string dataSetName = dataSetSelecteds[t].first;
256 
257  //get datasettype
258  std::unique_ptr<te::da::DataSetType> dsType;
259 
260  for(unsigned int i = 0; i < datasetNames.size(); ++i)
261  {
262  if(datasetNames[i] == dataSetName)
263  {
264  dsType = m_ds->getDataSetType(datasetNames[i]);
265  break;
266  }
267  }
268 
269  if(dsType.get())
270  {
271  //Acquiring the primary key's properties
272  te::da::PrimaryKey* pk = dsType->getPrimaryKey();
273 
274  if(!pk)
275  return;
276 
277  for(size_t i = 0; i < dsType->size(); ++i)
278  {
279  te::dt::Property* curProp = dsType->getProperty(i);
280  std::string propName = curProp->getName();
281  std::string fullName = alias + "." + propName;
282  bool isNew = propertyNames.find(propName) == propertyNames.end();
283 
284  if(isNew)
285  propertyNames.insert(propName);
286 
287  if (pk->has(dsType->getProperty(i)) || !isNew)
288  m_uniqueProps.push_back(fullName);
289  else
290  m_properties.push_back(fullName);
291 
292  if(t == 0)
293  m_ui->m_dataset1ColumnComboBox->addItem(QString::fromUtf8(fullName.c_str()), QVariant(dsType->getProperty(i)->getType()));
294  else
295  {
296  m_ui->m_dataset2ColumnComboBox->addItem(QString::fromUtf8(fullName.c_str()), QVariant(dsType->getProperty(i)->getType()));
297  }
298  }
299  }
300  }
301 
302  if(index != -1)
303  m_ui->m_dataset1ColumnComboBox->setCurrentIndex(index);
304 }
305 
307 {
308  if(QDialog::Accepted == r)
309  {
310  QVariant dsv1, dsv2;
311  dsv1 = m_ui->m_dataset1ColumnComboBox->itemData(m_ui->m_dataset1ColumnComboBox->currentIndex());
312  dsv2 = m_ui->m_dataset2ColumnComboBox->itemData(m_ui->m_dataset2ColumnComboBox->currentIndex());
313  std::string title = m_ui->m_layerTitleLineEdit->text().toUtf8().data();
314 
315  if(dsv1 != dsv2)
316  {
317  QMessageBox::warning(this, tr("Tabular File"), "The types of the selected columns do not match.");
318  return;
319  }
320  else if(dsv1.toInt() != te::dt::STRING_TYPE && (dsv1.toInt() < te::dt::INT16_TYPE || dsv1.toInt() > te::dt::UINT64_TYPE))
321  {
322  QMessageBox::warning(this, tr("Tabular File"), "The types of the selected columns must be either an integer or a string.");
323  return;
324  }
325  else if (title.empty())
326  {
327  QMessageBox::warning(this, tr("Tabular File"), "The new layer must have a title.");
328  return;
329  }
330  else
331  {
332  QDialog::done(r);
333  return;
334  }
335  }
336  else
337  {
338  QDialog::done(r);
339  return;
340  }
341 }
342 
344 {
345  if (m_ds->getType() == "ADO")
346  {
347  QMessageBox::information(this, tr("Table link error"),
348  tr("This function is not available for the selected datasource"));
349  return QDialog::Rejected;
350  }
351  else if(!m_ds->getDataSetType(m_inputLayer->getDataSetName())->getPrimaryKey())
352  {
353  QMessageBox::information(this, tr("Table link error"),
354  tr("This function is not available for datasets without a primary key"));
355  return QDialog::Rejected;
356  }
357  else
358  return QDialog::exec();
359 }
360 
362 {
363  std::string DsName = m_ui->m_dataSet2ComboBox->currentText().toUtf8().data();
364  size_t pos = DsName.find(".");
365  if(pos != std::string::npos)
366  m_ui->m_dataSetAliasLineEdit->setText(QString::fromUtf8(DsName.substr(pos + 1, DsName.size() - 1).c_str()));
367  else
368  m_ui->m_dataSetAliasLineEdit->setText(QString::fromUtf8(DsName.c_str()));
369 
370  getProperties();
371  m_ui->m_tabularFrame->hide();
372  m_tabularView->hide();
373  m_ui->m_dataPreviewGroupBox->hide();
374 }
375 
377 {
378  std::string aux = m_ui->m_dataset2ColumnComboBox->currentText().toUtf8().data();
379  std::string alias;
380  size_t pos = aux.find(".");
381 
382  if (pos != std::string::npos)
383  alias = aux.substr(0, pos);
384  else
385  alias = aux;
386 
387  //get datasettype
388  std::unique_ptr<te::da::DataSetType> dsType;
389  dsType = m_ds->getDataSetType(alias);
390 
391  //Get Dataset
392 
393  std::unique_ptr<te::da::DataSet> dataSet = m_ds->getDataSet(alias);
394 
395  //Acquiring the dataSet properties
396  std::vector<std::size_t> dataSetProperties;
397 
398  for (size_t i = 0; i < dsType->size(); ++i)
399  {
400  dataSetProperties.push_back(i);
401  }
402 
403  //Adjusting the table that will display the tabular dataset
404  m_tabularView->setDataSet(new te::mem::DataSet(*dataSet.get(), dataSetProperties, 5));
405  m_tabularView->resizeColumnsToContents();
406 
407  if(m_ui->m_tabularFrame->isHidden())
408  {
409  m_tabularView->show();
410  m_ui->m_tabularFrame->show();
411  m_ui->m_dataPreviewGroupBox->show();
412  }
413  else
414  {
415  m_ui->m_tabularFrame->hide();
416  m_tabularView->hide();
417  m_ui->m_dataPreviewGroupBox->hide();
418  }
419 }
420 
422 {
423  this->accept();
424 }
std::unique_ptr< DataSetTableView > m_tabularView
The widget used to preview the data of the tabular dataset.
std::vector< std::string > m_uniqueProps
The name of the properties that must be unique in the output layer.
Geometric property.
std::unique_ptr< Ui::TableLinkDialogForm > m_ui
The widget&#39;s form.
The Field class can be used to model an expression that takes part of the output items of a SELECT...
void setSRID(int srid)
It sets the spatial reference system identifier associated to this property.
TableLinkDialog(QWidget *parent=0, Qt::WindowFlags f=0)
Constructor.
void setInputLayer(te::map::AbstractLayerPtr inLayer)
It sets the Datasource that is being used to generate the new Layer.
A class that models the name of a dataset used in a From clause.
Definition: DataSetName.h:43
te::da::DataSourcePtr m_ds
The dasource of the layers to be linked.
A class that models the name of any property of an object.
bool has(const te::dt::Property *p) const
It verifies if Property is associated to the primary key.
A layer resulting from a query.
Definition: QueryLayer.h:50
te::map::AbstractLayerPtr getQueryLayer()
Returns a new query layer based on the requested parameters.
#define TE_TR(message)
It marks a string in order to get translated.
Definition: Translator.h:242
It models a property definition.
Definition: Property.h:59
This is an abstract class that models a query expression.
TESEEXPORT Style * CreateFeatureTypeStyle(const te::gm::GeomType &geomType)
Try creates an appropriate feature type style based on given geometry type.
Implementation of a random-access dataset class for the TerraLib In-Memory Data Access driver...
static DataSourceManager & getInstance()
It returns a reference to the singleton instance.
te::map::DataSetLayerPtr m_inputLayer
The layer the will serve as the base for the link.
std::vector< std::string > m_properties
The name of the properties that the output layer will contain.
te::da::Join * getJoin()
Returns the generated Join.
boost::ptr_vector< Field > Fields
Fields is just a boost::ptr_vector of Field pointers.
Definition: Fields.h:37
JoinType
The type of join in a query.
te::da::Select getSelectQuery()
Returns a new query based on the requested parameters.
A Join clause combines two FromItems.
Definition: Join.h:50
TEDATAACCESSEXPORT void GetDataSetNames(std::vector< std::string > &datasetNames, const std::string &datasourceId)
This class is designed to declare objects to be thrown as exceptions by TerraLib. ...
A Select models a query to be used when retrieving data from a DataSource.
Definition: Select.h:65
boost::ptr_vector< FromItem > From
It models the FROM clause for a query.
Definition: From.h:37
void onDataToolButtonnClicked()
Displays or hides the data of the tabular Dataset.
It describes a primary key (pk) constraint.
Definition: PrimaryKey.h:52
A customized table view for te::map::AbstractLayer objects. Uses a te::qt::widgets::DataSetModel as i...
JoinConditionOn is a boolean expression and it specifies which items in a join are considered to matc...
TEDATAACCESSEXPORT DataSetType * GetDataSetType(const std::string &name, const std::string &datasourceId)
A layer with reference to a dataset.
Definition: DataSetLayer.h:47
boost::intrusive_ptr< QueryLayer > QueryLayerPtr
Definition: QueryLayer.h:170
TEDATAACCESSEXPORT te::gm::GeometryProperty * GetFirstGeomProperty(const DataSetType *dt)
boost::intrusive_ptr< AbstractLayer > AbstractLayerPtr
A base class for binary functions.
An object that when created shows a cursor during its scope.
Definition: ScopedCursor.h:48
const std::string & getName() const
It returns the property name.
Definition: Property.h:127