QGIS/src/app/qgsvectorlayerproperties.cpp
2008-08-23 19:55:27 +00:00

1043 lines
32 KiB
C++

/***************************************************************************
qgsdlgvectorlayerproperties.cpp
Unified property dialog for vector layers
-------------------
begin : 2004-01-28
copyright : (C) 2004 by Gary E.Sherman
email : sherman at mrcc.com
***************************************************************************/
/***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/
/* $Id$ */
#include <memory>
#include "qgisapp.h"
#include "qgsapplication.h"
#include "qgsattributeactiondialog.h"
#include "qgscontexthelp.h"
#include "qgscontinuouscolordialog.h"
#include "qgscoordinatetransform.h"
#include "qgsgraduatedsymboldialog.h"
#include "qgslabeldialog.h"
#include "qgslabel.h"
#include "qgsgenericprojectionselector.h"
#include "qgslogger.h"
#include "qgsproject.h"
#include "qgssinglesymboldialog.h"
#include "qgsuniquevaluedialog.h"
#include "qgsvectorlayer.h"
#include "qgsvectorlayerproperties.h"
#include "qgsconfig.h"
#include "qgsvectordataprovider.h"
#ifdef HAVE_POSTGRESQL
#include "qgspgquerybuilder.h"
#include "../providers/postgres/qgspostgresprovider.h"
#endif
#include <QMessageBox>
#include <QDir>
#include <QFile>
#include <QFileDialog>
#include <QFileInfo>
#include <QSettings>
#include <QComboBox>
#include <QCheckBox>
#if QT_VERSION < 0x040300
#define toPlainText() text()
#endif
QgsVectorLayerProperties::QgsVectorLayerProperties(
QgsVectorLayer *lyr,
QWidget * parent,
Qt::WFlags fl)
: QDialog(parent, fl),
layer(lyr),
mRendererDialog(0)
{
setupUi(this);
connect(buttonBox, SIGNAL(accepted()), this, SLOT(accept()));
connect(buttonBox, SIGNAL(rejected()), this, SLOT(reject()));
connect(buttonBox->button(QDialogButtonBox::Apply), SIGNAL(clicked()), this, SLOT(apply()));
connect(this, SIGNAL(accepted()), this, SLOT(apply()));
connect(mAddAttributeButton, SIGNAL(clicked()), this, SLOT(addAttribute()));
connect(mDeleteAttributeButton, SIGNAL(clicked()), this, SLOT(deleteAttribute()));
connect(mToggleEditingButton, SIGNAL(clicked()), this, SLOT(toggleEditing()));
connect(this, SIGNAL(toggleEditing(QgsMapLayer*)),
QgisApp::instance(), SLOT(toggleEditing(QgsMapLayer*)));
connect(layer, SIGNAL(editingStarted()), this, SLOT(editingToggled()));
connect(layer, SIGNAL(editingStopped()), this, SLOT(editingToggled()));
connect(layer, SIGNAL(attributeAdded(int)), this, SLOT(attributeAdded(int)));
connect(layer, SIGNAL(attributeDeleted(int)), this, SLOT(attributeDeleted(int)));
mAddAttributeButton->setIcon(QgisApp::getThemeIcon("/mActionNewAttribute.png"));
mDeleteAttributeButton->setIcon(QgisApp::getThemeIcon("/mActionDeleteAttribute.png"));
mToggleEditingButton->setIcon(QgisApp::getThemeIcon("/mActionToggleEditing.png"));
// Create the Label dialog tab
QVBoxLayout *layout = new QVBoxLayout( labelOptionsFrame );
layout->setMargin(0);
labelDialog = new QgsLabelDialog ( layer->label(), labelOptionsFrame);
layout->addWidget( labelDialog );
labelOptionsFrame->setLayout(layout);
connect(labelDialog, SIGNAL(labelSourceSet()), this, SLOT(setLabelCheckBox()));
// Create the Actions dialog tab
QVBoxLayout *actionLayout = new QVBoxLayout( actionOptionsFrame );
actionLayout->setMargin(0);
const QgsFieldMap &fields = layer->pendingFields();
actionDialog = new QgsAttributeActionDialog ( layer->actions(), fields, actionOptionsFrame );
actionLayout->addWidget( actionDialog );
tblAttributes->setColumnCount(8);
tblAttributes->setRowCount( fields.size() );
tblAttributes->setHorizontalHeaderItem( 0, new QTableWidgetItem( tr("id") ) );
tblAttributes->setHorizontalHeaderItem( 1, new QTableWidgetItem( tr("name") ) );
tblAttributes->setHorizontalHeaderItem( 2, new QTableWidgetItem( tr("type") ) );
tblAttributes->setHorizontalHeaderItem( 3, new QTableWidgetItem( tr("length") ) );
tblAttributes->setHorizontalHeaderItem( 4, new QTableWidgetItem( tr("precision") ) );
tblAttributes->setHorizontalHeaderItem( 5, new QTableWidgetItem( tr("comment") ) );
tblAttributes->setHorizontalHeaderItem( 6, new QTableWidgetItem( tr("edit widget") ) );
tblAttributes->setHorizontalHeaderItem( 7, new QTableWidgetItem( tr("values") ) );
tblAttributes->setSelectionBehavior( QAbstractItemView::SelectRows );
tblAttributes->setSelectionMode( QAbstractItemView::MultiSelection );
loadRows();
reset();
if(layer->dataProvider())//enable spatial index button group if supported by provider
{
int capabilities=layer->dataProvider()->capabilities();
if(!(capabilities&QgsVectorDataProvider::CreateSpatialIndex))
{
pbnIndex->setEnabled(false);
}
}
updateButtons();
leSpatialRefSys->setText(layer->srs().proj4String());
leSpatialRefSys->setCursorPosition(0);
connect(sliderTransparency, SIGNAL(valueChanged(int)), this, SLOT(sliderTransparency_valueChanged(int)));
tabWidget->setCurrentIndex(0);
} // QgsVectorLayerProperties ctor
void QgsVectorLayerProperties::loadRows()
{
const QgsFieldMap &fields = layer->pendingFields();
int row=0;
for(QgsFieldMap::const_iterator it=fields.begin(); it!=fields.end(); it++, row++)
setRow( row, it.key(), it.value() );
tblAttributes->resizeColumnsToContents();
}
void QgsVectorLayerProperties::setRow(int row, int idx, const QgsField &field)
{
tblAttributes->setItem(row, 0, new QTableWidgetItem( QString::number(idx) ) );
tblAttributes->setItem(row, 1, new QTableWidgetItem( field.name() ) );
tblAttributes->setItem(row, 2, new QTableWidgetItem( field.typeName() ) );
tblAttributes->setItem(row, 3, new QTableWidgetItem( QString::number( field.length() ) ) );
tblAttributes->setItem(row, 4, new QTableWidgetItem( QString::number( field.precision() ) ) );
tblAttributes->setItem(row, 5, new QTableWidgetItem( field.comment() ) );
for(int i=0; i<6; i++)
tblAttributes->item(row, i)->setFlags( tblAttributes->item(row, i)->flags() & ~Qt::ItemIsEditable );
QComboBox *cb = new QComboBox();
cb->addItem( tr("line edit"), QgsVectorLayer::LineEdit);
cb->addItem( tr("unique values"), QgsVectorLayer::UniqueValues);
cb->addItem( tr("unique values (editable)"), QgsVectorLayer::UniqueValuesEditable);
cb->addItem( tr("value map"), QgsVectorLayer::ValueMap);
cb->addItem( tr("classification"), QgsVectorLayer::Classification);
cb->addItem( tr("range"), QgsVectorLayer::Range);
cb->setSizeAdjustPolicy(QComboBox::AdjustToContentsOnFirstShow);
cb->setCurrentIndex( layer->editType( idx ) );
tblAttributes->setCellWidget(row, 6, cb );
if( layer->editType(idx)==QgsVectorLayer::ValueMap )
{
// TODO: create a gui for value maps
QStringList mapList;
QMap<QString, QVariant> &map = layer->valueMap( idx );
for(QMap<QString, QVariant>::iterator mit=map.begin(); mit!=map.end(); mit++)
{
QgsDebugMsg( QString("idx:%1 key:%2 value:%3").arg( idx ).arg( mit.key() ).arg( mit.value().toString() ) );
if( mit.value().isNull() )
mapList << mit.key();
else
mapList << QString( "%1=%2" ).arg( mit.key() ).arg( mit.value().toString() );
}
tblAttributes->setItem(row, 7, new QTableWidgetItem( mapList.join(";") ) );
} else if( layer->editType(idx)==QgsVectorLayer::Range ) {
tblAttributes->setItem(
row, 7,
new QTableWidgetItem( QString("%1;%2;%3")
.arg( layer->range(idx).mMin.toString() )
.arg( layer->range(idx).mMax.toString() )
.arg( layer->range(idx).mStep.toString() )
)
);
}
}
QgsVectorLayerProperties::~QgsVectorLayerProperties()
{
disconnect(labelDialog, SIGNAL(labelSourceSet()), this, SLOT(setLabelCheckBox()));
}
void QgsVectorLayerProperties::toggleEditing()
{
emit toggleEditing(layer);
}
void QgsVectorLayerProperties::attributeAdded(int idx)
{
const QgsFieldMap &fields = layer->pendingFields();
int row = tblAttributes->rowCount();
tblAttributes->insertRow(row);
setRow(row, idx, fields[idx]);
tblAttributes->setCurrentCell(row, idx);
}
void QgsVectorLayerProperties::attributeDeleted(int idx)
{
for(int i=0; i<tblAttributes->rowCount(); i++)
{
if( tblAttributes->item(i, 0)->text().toInt()==idx )
{
tblAttributes->removeRow(i);
break;
}
}
}
void QgsVectorLayerProperties::addAttribute()
{
QgsAddAttrDialog dialog(layer->dataProvider(), this);
if(dialog.exec()==QDialog::Accepted)
{
if(!addAttribute(dialog.name(),dialog.type()))
{
QMessageBox::information(this,tr("Name conflict"),tr("The attribute could not be inserted. The name already exists in the table."));
}
}
}
bool QgsVectorLayerProperties::addAttribute(QString name, QString type)
{
QgsDebugMsg("inserting attribute " + name + " of type " + type );
return layer->addAttribute( name, type );
}
void QgsVectorLayerProperties::deleteAttribute()
{
QList<QTableWidgetItem*> items = tblAttributes->selectedItems();
QList<int> idxs;
for(QList<QTableWidgetItem*>::const_iterator it=items.begin(); it!=items.end(); it++)
{
if( (*it)->column()==0 )
idxs << (*it)->text().toInt();
}
for(QList<int>::const_iterator it=idxs.begin(); it!=idxs.end(); it++)
layer->deleteAttribute(*it);
}
void QgsVectorLayerProperties::editingToggled()
{
if( layer->isEditable() )
loadRows();
updateButtons();
}
void QgsVectorLayerProperties::updateButtons()
{
if ( layer->isEditable() )
{
int cap = layer->dataProvider()->capabilities();
mAddAttributeButton->setEnabled( cap & QgsVectorDataProvider::AddAttributes );
mDeleteAttributeButton->setEnabled( cap & QgsVectorDataProvider::DeleteAttributes );
mToggleEditingButton->setChecked( true );
}
else
{
mAddAttributeButton->setEnabled( false );
mDeleteAttributeButton->setEnabled( false );
mToggleEditingButton->setChecked( false );
}
}
void QgsVectorLayerProperties::sliderTransparency_valueChanged(int theValue)
{
//set the transparency percentage label to a suitable value
int myInt = static_cast < int >((theValue / 255.0) * 100); //255.0 to prevent integer division
lblTransparencyPercent->setText(tr("Transparency: ") + QString::number(myInt) + "%");
}//sliderTransparency_valueChanged
void QgsVectorLayerProperties::setLabelCheckBox()
{
labelCheckBox->setCheckState(Qt::Checked);
}
void QgsVectorLayerProperties::alterLayerDialog(const QString & dialogString)
{
widgetStackRenderers->removeWidget(mRendererDialog);
delete mRendererDialog;
mRendererDialog=0;
if(dialogString == tr("Single Symbol"))
{
mRendererDialog = new QgsSingleSymbolDialog(layer);
}
else if(dialogString == tr("Graduated Symbol"))
{
mRendererDialog = new QgsGraduatedSymbolDialog(layer);
}
else if(dialogString == tr("Continuous Color"))
{
mRendererDialog = new QgsContinuousColorDialog(layer);
}
else if(dialogString == tr("Unique Value"))
{
mRendererDialog = new QgsUniqueValueDialog(layer);
}
widgetStackRenderers->addWidget(mRendererDialog);
widgetStackRenderers->setCurrentWidget(mRendererDialog);
}
void QgsVectorLayerProperties::setLegendType(QString type)
{
legendtypecombobox->setItemText(legendtypecombobox->currentIndex(), type);
}
void QgsVectorLayerProperties::setDisplayField(QString name)
{
displayFieldComboBox->setItemText(displayFieldComboBox->currentIndex(), name);
}
//! @note in raster props, this method is called sync()
void QgsVectorLayerProperties::reset( void )
{
// populate the general information
txtDisplayName->setText(layer->name());
pbnQueryBuilder->setWhatsThis(tr("This button opens the PostgreSQL query "
"builder and allows you to create a subset of features to display on "
"the map canvas rather than displaying all features in the layer"));
txtSubsetSQL->setWhatsThis(tr("The query used to limit the features in the "
"layer is shown here. This is currently only supported for PostgreSQL "
"layers. To enter or modify the query, click on the Query Builder button"));
//see if we are dealing with a pg layer here
if(layer->providerType() == "postgres")
{
grpSubset->setEnabled(true);
txtSubsetSQL->setText(layer->subsetString());
// if the user is allowed to type an adhoc query, the app will crash if the query
// is bad. For this reason, the sql box is disabled and the query must be built
// using the query builder, either by typing it in by hand or using the buttons, etc
// on the builder. If the ability to enter a query directly into the box is required,
// a mechanism to check it must be implemented.
txtSubsetSQL->setEnabled(false);
pbnQueryBuilder->setEnabled(true);
}
else
{
grpSubset->setEnabled(false);
}
//get field list for display field combo
const QgsFieldMap& myFields = layer->pendingFields();
for (QgsFieldMap::const_iterator it = myFields.begin(); it != myFields.end(); ++it)
{
displayFieldComboBox->addItem( it->name() );
}
displayFieldComboBox->setCurrentIndex( displayFieldComboBox->findText(
layer->displayField() ) );
// set up the scale based layer visibility stuff....
chkUseScaleDependentRendering->setChecked(layer->scaleBasedVisibility());
spinMinimumScale->setValue((int)layer->minScale());
spinMaximumScale->setValue((int)layer->maxScale());
// symbology initialization
if(legendtypecombobox->count()==0)
{
legendtypecombobox->addItem(tr("Single Symbol"));
if(myFields.size()>0)
{
legendtypecombobox->addItem(tr("Graduated Symbol"));
legendtypecombobox->addItem(tr("Continuous Color"));
legendtypecombobox->addItem(tr("Unique Value"));
}
}
//find out the type of renderer in the vectorlayer, create a dialog with these settings and add it to the form
delete mRendererDialog;
mRendererDialog=0;
QString rtype=layer->renderer()->name();
if(rtype=="Single Symbol")
{
mRendererDialog=new QgsSingleSymbolDialog(layer);
legendtypecombobox->setCurrentIndex(0);
}
else if(rtype=="Graduated Symbol")
{
mRendererDialog=new QgsGraduatedSymbolDialog(layer);
legendtypecombobox->setCurrentIndex(1);
}
else if(rtype=="Continuous Color")
{
mRendererDialog=new QgsContinuousColorDialog(layer);
legendtypecombobox->setCurrentIndex(2);
}
else if(rtype == "Unique Value")
{
mRendererDialog=new QgsUniqueValueDialog(layer);
legendtypecombobox->setCurrentIndex(3);
}
if(mRendererDialog)
{
widgetStackRenderers->addWidget(mRendererDialog);
widgetStackRenderers->setCurrentWidget(mRendererDialog);
}
QObject::connect(legendtypecombobox, SIGNAL(activated(const QString &)), this,
SLOT(alterLayerDialog(const QString &)));
// reset fields in label dialog
layer->label()->setFields ( layer->pendingFields() );
//set the metadata contents
QString myStyle = QgsApplication::reportStyleSheet();
teMetadata->clear();
teMetadata->document()->setDefaultStyleSheet(myStyle);
teMetadata->setHtml(getMetadata());
actionDialog->init();
labelDialog->init();
labelCheckBox->setChecked(layer->hasLabelsEnabled());
//set the transparency slider
sliderTransparency->setValue(255 - layer->getTransparency());
//update the transparency percentage label
sliderTransparency_valueChanged(255 - layer->getTransparency());
} // reset()
//
// methods reimplemented from qt designer base class
//
void QgsVectorLayerProperties::on_buttonBox_helpRequested()
{
QgsContextHelp::run(context_id);
}
void QgsVectorLayerProperties::apply()
{
//
// Set up sql subset query if applicable
//
#ifdef HAVE_POSTGRESQL
//see if we are dealing with a pg layer here
if(layer->providerType() == "postgres")
{
grpSubset->setEnabled(true);
// set the subset sql for the layer
layer->setSubsetString(txtSubsetSQL->toPlainText());
// update the metadata with the updated sql subset
QString myStyle = QgsApplication::reportStyleSheet();
teMetadata->clear();
teMetadata->document()->setDefaultStyleSheet(myStyle);
teMetadata->setHtml(getMetadata());
// update the extents of the layer (fetched from the provider)
layer->updateExtents();
}
#endif
// set up the scale based layer visibility stuff....
layer->setScaleBasedVisibility(chkUseScaleDependentRendering->isChecked());
layer->setMinScale(spinMinimumScale->value());
layer->setMaxScale(spinMaximumScale->value());
// update the display field
layer->setDisplayField(displayFieldComboBox->currentText());
actionDialog->apply();
labelDialog->apply();
layer->enableLabels(labelCheckBox->isChecked());
layer->setLayerName(displayName());
for(int i=0; i<tblAttributes->rowCount(); i++)
{
int idx = tblAttributes->item(i, 0)->text().toInt();
const QgsField &field = layer->pendingFields()[idx];
QgsVectorLayer::EditType editType = layer->editType(idx);
QComboBox *cb = dynamic_cast<QComboBox*>( tblAttributes->cellWidget(i, 6) );
if(!cb)
continue;
layer->setEditType( idx, (QgsVectorLayer::EditType) cb->itemData( cb->currentIndex() ).toInt() );
if( editType==QgsVectorLayer::ValueMap )
{
QMap<QString, QVariant> &map = layer->valueMap(idx);
map.clear();
QString value = tblAttributes->item(i, 7)->text();
if( !value.isEmpty() )
{
QStringList values = tblAttributes->item(i, 7)->text().split(";");
for(int j=0; j<values.size(); j++)
{
QStringList args = values[j].split("=");
QVariant value;
if(args.size()==1 || (args.size()==2 && args[0]==args[1]))
{
QgsDebugMsg( QString("idx:%1 key:%2 value:%2").arg(idx).arg(args[0]) );
value = args[0];
}
else if(args.size()==2)
{
QgsDebugMsg( QString("idx:%1 key:%2 value:%3").arg( idx ).arg( args[0] ).arg( args[1] ) );
value = args[1];
}
if( value.canConvert( field.type() ) )
{
map.insert( args[0], value );
}
}
}
} else if( editType==QgsVectorLayer::Range ) {
QStringList values = tblAttributes->item(i, 7)->text().split(";");
if( values.size()==3 ) {
QVariant min = values[0];
QVariant max = values[1];
QVariant step = values[2];
if( min.canConvert(field.type()) &&
max.canConvert(field.type()) &&
step.canConvert(field.type()) )
{
min.convert( field.type() );
max.convert( field.type() );
step.convert( field.type() );
layer->range(idx) = QgsVectorLayer::RangeData(min,max,step);
}
}
}
}
QgsSingleSymbolDialog *sdialog =
dynamic_cast < QgsSingleSymbolDialog * >(widgetStackRenderers->currentWidget());
QgsGraduatedSymbolDialog *gdialog =
dynamic_cast < QgsGraduatedSymbolDialog * >(widgetStackRenderers->currentWidget());
QgsContinuousColorDialog *cdialog =
dynamic_cast < QgsContinuousColorDialog * >(widgetStackRenderers->currentWidget());
QgsUniqueValueDialog* udialog =
dynamic_cast< QgsUniqueValueDialog * >(widgetStackRenderers->currentWidget());
if (sdialog)
{
sdialog->apply();
}
else if (gdialog)
{
gdialog->apply();
}
else if (cdialog)
{
cdialog->apply();
}
else if(udialog)
{
udialog->apply();
}
layer->setTransparency(static_cast < unsigned int >(255 - sliderTransparency->value()));
// update symbology
emit refreshLegend(layer->getLayerID(), false);
layer->triggerRepaint();
// notify the project we've made a change
QgsProject::instance()->dirty(true);
}
void QgsVectorLayerProperties::on_pbnQueryBuilder_clicked()
{
#ifdef HAVE_POSTGRESQL
// launch the query builder using the PostgreSQL connection
// from the provider
// cast to postgres provider type
QgsPostgresProvider * myPGProvider = (QgsPostgresProvider *) layer->dataProvider() ; // FIXME use dynamic cast
// create the query builder object using the table name
// and postgres connection from the provider
QgsDataSourceURI uri(myPGProvider->dataSourceUri());
QgsPgQueryBuilder *pqb = new QgsPgQueryBuilder(&uri, this);
// Set the sql in the query builder to the same in the prop dialog
// (in case the user has already changed it)
pqb->setSql(txtSubsetSQL->toPlainText());
// Open the query builder
if(pqb->exec())
{
// if the sql is changed, update it in the prop subset text box
txtSubsetSQL->setText(pqb->sql());
//TODO If the sql is changed in the prop dialog, the layer extent should be recalculated
// The datasource for the layer needs to be updated with the new sql since this gets
// saved to the project file. This should happen at the map layer level...
}
// delete the query builder object
delete pqb;
#endif
}
void QgsVectorLayerProperties::on_pbnIndex_clicked()
{
QgsVectorDataProvider* pr=layer->dataProvider();
if(pr)
{
setCursor(Qt::WaitCursor);
bool errval=pr->createSpatialIndex();
setCursor(Qt::ArrowCursor);
if(errval)
{
QMessageBox::information(this, tr("Spatial Index"),
tr("Creation of spatial index successfull"));
}
else
{
// TODO: Remind the user to use OGR >= 1.2.6 and Shapefile
QMessageBox::information(this, tr("Spatial Index"), tr("Creation of spatial index failed"));
}
}
}
QString QgsVectorLayerProperties::getMetadata()
{
QString myMetadata = "<html><body>";
myMetadata += "<table width=\"100%\">";
//-------------
myMetadata += "<tr class=\"glossy\"><td>";
myMetadata += tr("General:");
myMetadata += "</td></tr>";
// data comment
if (!(layer->dataComment().isEmpty()))
{
myMetadata += "<tr><td>";
myMetadata += tr("Layer comment: ") +
layer->dataComment();
myMetadata += "</td></tr>";
}
//storage type
myMetadata += "<tr><td>";
myMetadata += tr("Storage type of this layer : ") +
layer->storageType();
myMetadata += "</td></tr>";
// data source
myMetadata += "<tr><td>";
myMetadata += tr("Source for this layer : ") +
layer->publicSource();
myMetadata += "</td></tr>";
//geom type
QGis::VectorType vectorType = layer->vectorType();
if ( vectorType < 0 || vectorType > QGis::Polygon )
{
QgsDebugMsg( "Invalid vector type" );
}
else
{
QString vectorTypeString( QGis::qgisVectorGeometryType[layer->vectorType()] );
myMetadata += "<tr><td>";
myMetadata += tr("Geometry type of the features in this layer : ") +
vectorTypeString;
myMetadata += "</td></tr>";
}
//feature count
myMetadata += "<tr><td>";
myMetadata += tr("The number of features in this layer : ") +
QString::number(layer->featureCount());
myMetadata += "</td></tr>";
//capabilities
myMetadata += "<tr><td>";
myMetadata += tr("Editing capabilities of this layer : ") +
layer->capabilitiesString();
myMetadata += "</td></tr>";
//-------------
QgsRect myExtent = layer->extent();
myMetadata += "<tr class=\"glossy\"><td>";
myMetadata += tr("Extents:");
myMetadata += "</td></tr>";
//extents in layer cs TODO...maybe make a little nested table to improve layout...
myMetadata += "<tr><td>";
myMetadata += tr("In layer spatial reference system units : ") +
tr("xMin,yMin ") +
QString::number(myExtent.xMin()) +
"," +
QString::number( myExtent.yMin()) +
tr(" : xMax,yMax ") +
QString::number(myExtent.xMax()) +
"," +
QString::number(myExtent.yMax());
myMetadata += "</td></tr>";
//extents in project cs
try
{
/*
// TODO: currently disabled, will revisit later [MD]
QgsRect myProjectedExtent = coordinateTransform->transformBoundingBox(layer->extent());
myMetadata += "<tr><td>";
myMetadata += tr("In project spatial reference system units : ") +
tr("xMin,yMin ") +
QString::number(myProjectedExtent.xMin()) +
"," +
QString::number( myProjectedExtent.yMin()) +
tr(" : xMax,yMax ") +
QString::number(myProjectedExtent.xMax()) +
"," +
QString::number(myProjectedExtent.yMax());
myMetadata += "</td></tr>";
*/
//
// Display layer spatial ref system
//
myMetadata += "<tr class=\"glossy\"><td>";
myMetadata += tr("Layer Spatial Reference System:");
myMetadata += "</td></tr>";
myMetadata += "<tr><td>";
myMetadata += layer->srs().proj4String().replace(QRegExp("\"")," \"");
myMetadata += "</td></tr>";
//
// Display project (output) spatial ref system
//
/*
// TODO: disabled for now, will revisit later [MD]
myMetadata += "<tr><td bgcolor=\"gray\">";
myMetadata += tr("Project (Output) Spatial Reference System:");
myMetadata += "</td></tr>";
myMetadata += "<tr><td>";
myMetadata += coordinateTransform->destCRS().proj4String().replace(QRegExp("\"")," \"");
myMetadata += "</td></tr>";
*/
}
catch(QgsCsException &cse)
{
Q_UNUSED(cse);
QgsDebugMsg( cse.what() );
myMetadata += "<tr><td>";
myMetadata += tr("In project spatial reference system units : ");
myMetadata += " (Invalid transformation of layer extents) ";
myMetadata += "</td></tr>";
}
#if 0
//
// Add the info about each field in the attribute table
//
myMetadata += "<tr class=\"glossy\"><td>";
myMetadata += tr("Attribute field info:");
myMetadata += "</td></tr>";
myMetadata += "<tr><td>";
// Start a nested table in this trow
myMetadata += "<table width=\"100%\">";
myMetadata += "<tr><th>";
myMetadata += tr("Field");
myMetadata += "</th>";
myMetadata += "<th>";
myMetadata += tr("Type");
myMetadata += "</th>";
myMetadata += "<th>";
myMetadata += tr("Length");
myMetadata += "</th>";
myMetadata += "<th>";
myMetadata += tr("Precision");
myMetadata += "</th>";
myMetadata += "<th>";
myMetadata += tr("Comment");
myMetadata += "</th>";
//get info for each field by looping through them
const QgsFieldMap& myFields = layer->pendingFields();
for (QgsFieldMap::const_iterator it = myFields.begin(); it != myFields.end(); ++it)
{
const QgsField& myField = *it;
myMetadata += "<tr><td>";
myMetadata += myField.name();
myMetadata += "</td>";
myMetadata += "<td>";
myMetadata += myField.typeName();
myMetadata += "</td>";
myMetadata += "<td>";
myMetadata += QString("%1").arg(myField.length());
myMetadata += "</td>";
myMetadata += "<td>";
myMetadata += QString("%1").arg(myField.precision());
myMetadata += "</td>";
myMetadata += "<td>";
myMetadata += QString("%1").arg(myField.comment());
myMetadata += "</td></tr>";
}
//close field list
myMetadata += "</table>"; //end of nested table
#endif
myMetadata += "</td></tr>"; //end of stats container table row
//
// Close the table
//
myMetadata += "</table>";
myMetadata += "</body></html>";
return myMetadata;
}
void QgsVectorLayerProperties::on_pbnChangeSpatialRefSys_clicked()
{
QgsGenericProjectionSelector * mySelector = new QgsGenericProjectionSelector(this);
mySelector->setMessage();
mySelector->setSelectedCRSID(layer->srs().srsid());
if(mySelector->exec())
{
QgsCoordinateReferenceSystem srs(mySelector->getSelectedCRSID(), QgsCoordinateReferenceSystem::QGIS_CRSID);
layer->setSrs(srs);
}
else
{
QApplication::restoreOverrideCursor();
}
delete mySelector;
leSpatialRefSys->setText(layer->srs().proj4String());
leSpatialRefSys->setCursorPosition(0);
}
void QgsVectorLayerProperties::on_pbnLoadDefaultStyle_clicked()
{
bool defaultLoadedFlag = false;
QString myMessage = layer->loadDefaultStyle( defaultLoadedFlag );
//reset if the default style was loaded ok only
if ( defaultLoadedFlag )
{
// all worked ok so no need to inform user
reset ();
}
else
{
//something went wrong - let them know why
QMessageBox::information( this,
tr("Default Style"),
myMessage
);
}
}
void QgsVectorLayerProperties::on_pbnSaveDefaultStyle_clicked()
{
apply(); // make sure the qml to save is uptodate
// a flag passed by reference
bool defaultSavedFlag = false;
// after calling this the above flag will be set true for success
// or false if the save operation failed
QString myMessage = layer->saveDefaultStyle( defaultSavedFlag );
if ( !defaultSavedFlag )
{
//only raise the message if something went wrong
QMessageBox::information( this,
tr("Default Style"),
myMessage
);
}
}
void QgsVectorLayerProperties::on_pbnLoadStyle_clicked()
{
QSettings myQSettings; // where we keep last used filter in persistant state
QString myLastUsedDir = myQSettings.value ( "style/lastStyleDir", "." ).toString();
//create a file dialog
std::auto_ptr < QFileDialog > myFileDialog
(
new QFileDialog (
this,
QFileDialog::tr ( "Load layer properties from style file (.qml)" ),
myLastUsedDir,
tr ( "QGIS Layer Style File (*.qml)" )
)
);
myFileDialog->setFileMode ( QFileDialog::AnyFile );
myFileDialog->setAcceptMode ( QFileDialog::AcceptOpen );
//prompt the user for a fileName
QString myFileName;
if ( myFileDialog->exec() == QDialog::Accepted )
{
QStringList myFiles = myFileDialog->selectedFiles();
if ( !myFiles.isEmpty() )
{
myFileName = myFiles[0];
}
}
if ( !myFileName.isEmpty() )
{
if ( myFileDialog->selectedFilter() == tr ( "QGIS Layer Style File (*.qml)" ) )
{
//ensure the user never ommitted the extension from the fileName
if ( !myFileName.endsWith( ".qml", Qt::CaseInsensitive ) )
{
myFileName += ".qml";
}
bool defaultLoadedFlag = false;
QString myMessage = layer->loadNamedStyle( myFileName, defaultLoadedFlag );
//reset if the default style was loaded ok only
if ( defaultLoadedFlag )
{
reset ();
}
else
{
//let the user know what went wrong
QMessageBox::information( this,
tr("Saved Style"),
myMessage
);
}
}
else
{
QMessageBox::warning ( this, tr ( "QGIS" ), tr ( "Unknown style format: " ) +
myFileDialog->selectedFilter() );
}
myQSettings.setValue ( "style/lastStyleDir", myFileDialog->directory().absolutePath() );
}
}
void QgsVectorLayerProperties::on_pbnSaveStyleAs_clicked()
{
QSettings myQSettings; // where we keep last used filter in persistant state
QString myLastUsedDir = myQSettings.value ( "style/lastStyleDir", "." ).toString();
//create a file dialog
std::auto_ptr < QFileDialog > myFileDialog
(
new QFileDialog (
this,
QFileDialog::tr ( "Save layer properties as style file (.qml)" ),
myLastUsedDir,
tr ( "QGIS Layer Style File (*.qml)" )
)
);
myFileDialog->setFileMode ( QFileDialog::AnyFile );
myFileDialog->setAcceptMode ( QFileDialog::AcceptSave );
//prompt the user for a fileName
QString myOutputFileName;
if ( myFileDialog->exec() == QDialog::Accepted )
{
QStringList myFiles = myFileDialog->selectedFiles();
if ( !myFiles.isEmpty() )
{
myOutputFileName = myFiles[0];
}
}
if ( !myOutputFileName.isEmpty() )
{
if ( myFileDialog->selectedFilter() == tr ( "QGIS Layer Style File (*.qml)" ) )
{
apply(); // make sure the qml to save is uptodate
//ensure the user never ommitted the extension from the fileName
if ( !myOutputFileName.endsWith ( ".qml", Qt::CaseInsensitive ) )
{
myOutputFileName += ".qml";
}
bool defaultLoadedFlag = false;
QString myMessage = layer->saveNamedStyle( myOutputFileName, defaultLoadedFlag );
//reset if the default style was loaded ok only
if ( defaultLoadedFlag )
{
reset ();
}
else
{
//let the user know what went wrong
QMessageBox::information( this,
tr("Saved Style"),
myMessage
);
}
}
else
{
QMessageBox::warning ( this, tr ( "QGIS" ), tr ( "Unknown style format: " ) +
myFileDialog->selectedFilter() );
}
myQSettings.setValue ( "style/lastStyleDir", myFileDialog->directory().absolutePath() );
}
}