[FEATURE] multi-layer identify

git-svn-id: http://svn.osgeo.org/qgis/trunk@11572 c8812cc2-4d05-0410-92ff-de0c093fc19c
This commit is contained in:
jef 2009-09-05 19:49:47 +00:00
parent ddd64be82b
commit 92bb2a3117
13 changed files with 735 additions and 826 deletions

View File

@ -64,6 +64,9 @@ class QgsRectangle
//! return true when rectangle contains other rectangle
//! @note added in version 1.1
bool contains( const QgsRectangle& rect ) const;
//! return true when rectangle contains a point
//! @note added in version 1.3
bool contains( const QgsPoint& p ) const;
//! expand the rectangle so that covers both the original rectangle and the given rectangle
void combineExtentWith(QgsRectangle *rect);
//! expand the rectangle so that covers both the original rectangle and the given point

View File

@ -767,7 +767,7 @@ void QgisApp::createActions()
shortcuts->registerAction( mActionIdentify, tr( "Ctrl+Shift+I", "Click on features to identify them" ) );
mActionIdentify->setStatusTip( tr( "Click on features to identify them" ) );
connect( mActionIdentify, SIGNAL( triggered() ), this, SLOT( identify() ) );
mActionIdentify->setEnabled( false );
mActionIdentify->setEnabled( QSettings().value( "/Map/identifyMode", 0 ).toInt() != 0 );
mActionMeasure = new QAction( getThemeIcon( "mActionMeasure.png" ), tr( "Measure Line " ), this );
shortcuts->registerAction( mActionMeasure, tr( "Ctrl+Shift+M", "Measure a Line" ) );
@ -5542,7 +5542,7 @@ void QgisApp::activateDeactivateLayerRelatedActions( QgsMapLayer* layer )
if ( !layer )
{
mActionSelect->setEnabled( false );
mActionIdentify->setEnabled( false );
mActionIdentify->setEnabled( QSettings().value( "/Map/identifyMode", 0 ).toInt() != 0 );
mActionZoomActualSize->setEnabled( false );
mActionOpenTable->setEnabled( false );
mActionToggleEditing->setEnabled( false );
@ -5785,18 +5785,24 @@ void QgisApp::activateDeactivateLayerRelatedActions( QgsMapLayer* layer )
//Enable the Identify tool ( GDAL datasets draw without a provider )
//but turn off if data provider exists and has no Identify capabilities
mActionIdentify->setEnabled( true );
const QgsRasterLayer* vlayer = dynamic_cast<const QgsRasterLayer*>( layer );
const QgsRasterDataProvider* dprovider = vlayer->dataProvider();
if ( dprovider )
QSettings settings;
int identifyMode = settings.value( "/Map/identifyMode", 0 ).toInt();
if ( identifyMode == 0 )
{
// does provider allow the identify map tool?
if ( dprovider->capabilities() & QgsRasterDataProvider::Identify )
const QgsRasterLayer *rlayer = dynamic_cast<const QgsRasterLayer*>( layer );
const QgsRasterDataProvider* dprovider = rlayer->dataProvider();
if ( dprovider )
{
mActionIdentify->setEnabled( TRUE );
}
else
{
mActionIdentify->setEnabled( FALSE );
// does provider allow the identify map tool?
if ( dprovider->capabilities() & QgsRasterDataProvider::Identify )
{
mActionIdentify->setEnabled( true );
}
else
{
mActionIdentify->setEnabled( false );
}
}
}
}

View File

@ -21,6 +21,12 @@
#include "qgscontexthelp.h"
#include "qgsapplication.h"
#include "qgisapp.h"
#include "qgsmaplayer.h"
#include "qgsvectorlayer.h"
#include "qgsrubberband.h"
#include "qgsgeometry.h"
#include "qgsattributedialog.h"
#include "qgsmapcanvas.h"
#include <QCloseEvent>
#include <QLabel>
@ -33,13 +39,25 @@
#include "qgslogger.h"
QgsIdentifyResults::QgsIdentifyResults( const QgsAttributeAction& actions,
QWidget *parent, Qt::WFlags f )
// Tree hierachy
//
// layer [userrole: QgsMapLayer]
// feature: displayfield|displayvalue [userrole: fid]
// derived attributes
// name value
// name value
// name value
// name value
// feature
// derived attributes
// name value
// name value
QgsIdentifyResults::QgsIdentifyResults( QgsMapCanvas *canvas, QWidget *parent, Qt::WFlags f )
: QDialog( parent, f ),
mActions( actions ),
mClickedOnValue( 0 ),
mActionPopup( 0 ),
mCurrentFeatureId( 0 )
mRubberBand( 0 ),
mCanvas( canvas )
{
setupUi( this );
lstResults->setColumnCount( 2 );
@ -48,16 +66,12 @@ QgsIdentifyResults::QgsIdentifyResults( const QgsAttributeAction& actions,
connect( buttonCancel, SIGNAL( clicked() ),
this, SLOT( close() ) );
connect( lstResults, SIGNAL( itemClicked( QTreeWidgetItem*, int ) ),
this, SLOT( clicked( QTreeWidgetItem * ) ) );
connect( lstResults, SIGNAL( itemExpanded( QTreeWidgetItem* ) ),
this, SLOT( itemExpanded( QTreeWidgetItem* ) ) );
connect( lstResults, SIGNAL( currentItemChanged( QTreeWidgetItem*, QTreeWidgetItem* ) ),
this, SLOT( handleCurrentItemChanged( QTreeWidgetItem*, QTreeWidgetItem* ) ) );
// The label to use for the Derived node in the identify results
mDerivedLabel = tr( "(Derived)" );
}
QgsIdentifyResults::~QgsIdentifyResults()
@ -65,6 +79,58 @@ QgsIdentifyResults::~QgsIdentifyResults()
delete mActionPopup;
}
QTreeWidgetItem *QgsIdentifyResults::layerItem( QObject *layer )
{
QTreeWidgetItem *item;
for ( int i = 0; i < lstResults->topLevelItemCount(); i++ )
{
item = lstResults->topLevelItem( i );
if ( item->data( 0, Qt::UserRole ).value<QObject*>() == layer )
return item;
}
return 0;
}
void QgsIdentifyResults::addFeature( QgsMapLayer *layer, int fid,
QString displayField, QString displayValue,
const QMap<QString, QString> &attributes,
const QMap<QString, QString> &derivedAttributes )
{
QTreeWidgetItem *item = layerItem( layer );
if ( item == 0 )
{
item = new QTreeWidgetItem( QStringList() << layer->name() << tr( "Layer" ) );
item->setData( 0, Qt::UserRole, QVariant::fromValue( dynamic_cast<QObject*>( layer ) ) );
lstResults->addTopLevelItem( item );
connect( layer, SIGNAL( destroyed() ), this, SLOT( layerDestroyed() ) );
}
QTreeWidgetItem *featItem = new QTreeWidgetItem( QStringList() << displayField << displayValue );
featItem->setData( 0, Qt::UserRole, fid );
for ( QMap<QString, QString>::const_iterator it = attributes.begin(); it != attributes.end(); it++ )
{
featItem->addChild( new QTreeWidgetItem( QStringList() << it.key() << it.value() ) );
}
if ( derivedAttributes.size() >= 0 )
{
QTreeWidgetItem *derivedItem = new QTreeWidgetItem( QStringList() << tr( "(Derived)" ) );
featItem->addChild( derivedItem );
for ( QMap< QString, QString>::const_iterator it = derivedAttributes.begin(); it != derivedAttributes.end(); it++ )
{
derivedItem->addChild( new QTreeWidgetItem( QStringList() << it.key() << it.value() ) );
}
}
item->addChild( featItem );
}
// Call to show the dialog box.
void QgsIdentifyResults::show()
{
@ -96,16 +162,30 @@ void QgsIdentifyResults::closeEvent( QCloseEvent *e )
void QgsIdentifyResults::contextMenuEvent( QContextMenuEvent* event )
{
QTreeWidgetItem* item = lstResults->itemAt( lstResults->viewport()->mapFrom( this, event->pos() ) );
QTreeWidgetItem *item = lstResults->itemAt( lstResults->viewport()->mapFrom( this, event->pos() ) );
// if the user clicked below the end of the attribute list, just return
if ( item == NULL )
if ( !item )
return;
if ( mActionPopup == 0 )
{
QgsVectorLayer *vlayer = vectorLayer( item );
if ( vlayer == 0 )
return;
QgsAttributeAction *actions = vlayer->actions();
mActionPopup = new QMenu();
QAction *a;
if ( vlayer->isEditable() )
{
a = mActionPopup->addAction( tr( "Edit feature" ) );
a->setEnabled( true );
a->setData( QVariant::fromValue( -3 ) );
}
a = mActionPopup->addAction( tr( "Copy attribute value" ) );
a->setEnabled( true );
a->setData( QVariant::fromValue( -2 ) );
@ -114,7 +194,7 @@ void QgsIdentifyResults::contextMenuEvent( QContextMenuEvent* event )
a->setEnabled( true );
a->setData( QVariant::fromValue( -1 ) );
if ( mActions.size() > 0 )
if ( actions && actions->size() > 0 )
{
// The assumption is made that an instance of QgsIdentifyResults is
// created for each new Identify Results dialog box, and that the
@ -124,8 +204,8 @@ void QgsIdentifyResults::contextMenuEvent( QContextMenuEvent* event )
a->setEnabled( false );
mActionPopup->addSeparator();
QgsAttributeAction::aIter iter = mActions.begin();
for ( int j = 0; iter != mActions.end(); ++iter, ++j )
QgsAttributeAction::aIter iter = actions->begin();
for ( int j = 0; iter != actions->end(); ++iter, ++j )
{
QAction* a = mActionPopup->addAction( iter->name() );
// The menu action stores an integer that is used later on to
@ -134,14 +214,9 @@ void QgsIdentifyResults::contextMenuEvent( QContextMenuEvent* event )
}
}
connect( mActionPopup, SIGNAL( triggered( QAction* ) ),
this, SLOT( popupItemSelected( QAction* ) ) );
connect( mActionPopup, SIGNAL( triggered( QAction* ) ), this, SLOT( popupItemSelected( QAction* ) ) );
}
// Save the attribute values as these are needed for substituting into
// the action.
extractAllItemData( item );
mActionPopup->popup( event->globalPos() );
}
@ -160,75 +235,6 @@ void QgsIdentifyResults::saveWindowLocation()
settings.setValue( "/Windows/Identify/geometry", saveGeometry() );
}
/** add an attribute and its value to the list */
void QgsIdentifyResults::addAttribute( QTreeWidgetItem * fnode, QString field, QString value )
{
QStringList labels;
labels << field << value;
new QTreeWidgetItem( fnode, labels );
}
void QgsIdentifyResults::addAttribute( QString field, QString value )
{
QStringList labels;
labels << field << value;
new QTreeWidgetItem( lstResults, labels );
}
void QgsIdentifyResults::addDerivedAttribute( QTreeWidgetItem * fnode, QString field, QString value )
{
QTreeWidgetItem * daRootNode;
// Determine if this is the first derived attribute for this feature or not
if ( mDerivedAttributeRootNodes.find( fnode ) != mDerivedAttributeRootNodes.end() )
{
// Reuse existing derived-attribute root node
daRootNode = mDerivedAttributeRootNodes[fnode];
}
else
{
// Create new derived-attribute root node
daRootNode = new QTreeWidgetItem( fnode, QStringList( mDerivedLabel ) );
QFont font = daRootNode->font( 0 );
font.setItalic( true );
daRootNode->setFont( 0, font );
mDerivedAttributeRootNodes[fnode] = daRootNode;
}
QStringList labels;
labels << field << value;
new QTreeWidgetItem( daRootNode, labels );
}
void QgsIdentifyResults::addEdit( QTreeWidgetItem * fnode, int id )
{
QStringList labels;
labels << "edit" << QString::number( id );
QTreeWidgetItem *item = new QTreeWidgetItem( fnode, labels );
item->setIcon( 0, QgisApp::getThemeIcon( "/mIconEditable.png" ) );
}
void QgsIdentifyResults::addAction( QTreeWidgetItem * fnode, int id, QString field, QString value )
{
QStringList labels;
labels << field << value << "action" << QString::number( id );
QTreeWidgetItem *item = new QTreeWidgetItem( fnode, labels );
item->setIcon( 0, QgisApp::getThemeIcon( "/mAction.png" ) );
}
/** Add a feature node to the list */
QTreeWidgetItem *QgsIdentifyResults::addNode( QString label )
{
return new QTreeWidgetItem( lstResults, QStringList( label ) );
}
void QgsIdentifyResults::setTitle( QString title )
{
setWindowTitle( tr( "Identify Results - %1" ).arg( title ) );
}
void QgsIdentifyResults::setColumnText( int column, const QString & label )
{
QTreeWidgetItem* header = lstResults->headerItem();
@ -238,6 +244,10 @@ void QgsIdentifyResults::setColumnText( int column, const QString & label )
// Run the action that was selected in the popup menu
void QgsIdentifyResults::popupItemSelected( QAction* menuAction )
{
QTreeWidgetItem *item = lstResults->currentItem();
if ( item == 0 )
return;
int id = menuAction->data().toInt();
if ( id < 0 )
@ -245,13 +255,20 @@ void QgsIdentifyResults::popupItemSelected( QAction* menuAction )
QClipboard *clipboard = QApplication::clipboard();
QString text;
if ( id == -2 )
if ( id == -3 )
{
text = mValues[ mClickedOnValue ].second;
editFeature( item );
}
else if ( id == -2 )
{
text = item->data( 1, Qt::DisplayRole ).toString();
}
else
{
for ( std::vector< std::pair<QString, QString> >::const_iterator it = mValues.begin(); it != mValues.end(); it++ )
std::vector< std::pair<QString, QString> > attributes;
retrieveAttributes( item, attributes );
for ( std::vector< std::pair<QString, QString> >::iterator it = attributes.begin(); it != attributes.end(); it++ )
{
text += QString( "%1: %2\n" ).arg( it->first ).arg( it->second );
}
@ -262,17 +279,10 @@ void QgsIdentifyResults::popupItemSelected( QAction* menuAction )
}
else
{
mActions.doAction( id, mValues, mClickedOnValue );
doAction( item );
}
}
/** Expand all the identified features (show their attributes). */
void QgsIdentifyResults::showAllAttributes()
{
// Easy now with Qt 4.2...
lstResults->expandAll();
}
void QgsIdentifyResults::expandColumnsToFit()
{
lstResults->resizeColumnToContents( 0 );
@ -281,40 +291,86 @@ void QgsIdentifyResults::expandColumnsToFit()
void QgsIdentifyResults::clear()
{
mDerivedAttributeRootNodes.clear();
lstResults->clear();
if ( mRubberBand )
{
delete mRubberBand;
mRubberBand = 0;
}
}
void QgsIdentifyResults::setMessage( QString shortMsg, QString longMsg )
void QgsIdentifyResults::doAction( QTreeWidgetItem *item )
{
QStringList labels;
labels << shortMsg << longMsg;
new QTreeWidgetItem( lstResults, labels );
}
void QgsIdentifyResults::setActions( const QgsAttributeAction& actions )
{
mActions = actions;
}
void QgsIdentifyResults::clicked( QTreeWidgetItem *item )
{
if ( !item )
std::vector< std::pair<QString, QString> > attributes;
QTreeWidgetItem *featItem = retrieveAttributes( item, attributes );
if ( !featItem )
return;
if ( item->text( 2 ) == "action" )
{
int id = item->text( 3 ).toInt();
int id = featItem->data( 0, Qt::UserRole ).toInt();
extractAllItemData( item );
QgsVectorLayer *layer = dynamic_cast<QgsVectorLayer *>( featItem->parent()->data( 0, Qt::UserRole ).value<QObject *>() );
if ( !layer )
return;
mActions.doAction( id, mValues, mClickedOnValue );
}
else if ( item->text( 0 ) == "edit" )
{
emit editFeature( item->text( 1 ).toInt() );
}
layer->actions()->doAction( id, attributes, id );
}
QTreeWidgetItem *QgsIdentifyResults::featureItem( QTreeWidgetItem *item )
{
QTreeWidgetItem *featItem;
if ( item->parent() )
{
if ( item->parent()->parent() )
{
// attribute item
featItem = item->parent();
}
else
{
// feature item
featItem = item;
}
}
else
{
// layer item
if ( item->childCount() > 1 )
return 0;
featItem = item->child( 0 );
}
return featItem;
}
QgsVectorLayer *QgsIdentifyResults::vectorLayer( QTreeWidgetItem *item )
{
if ( item->parent() )
{
item = featureItem( item )->parent();
}
return dynamic_cast<QgsVectorLayer *>( item->data( 0, Qt::UserRole ).value<QObject *>() );
}
QTreeWidgetItem *QgsIdentifyResults::retrieveAttributes( QTreeWidgetItem *item, std::vector< std::pair<QString, QString> > &attributes )
{
QTreeWidgetItem *featItem = featureItem( item );
attributes.clear();
for ( int i = 0; i < featItem->childCount(); i++ )
{
QTreeWidgetItem *item = featItem->child( i );
if ( item->childCount() > 0 )
continue;
attributes.push_back( std::make_pair( item->data( 0, Qt::DisplayRole ).toString(), item->data( 1, Qt::DisplayRole ).toString() ) );
}
return featItem;
}
void QgsIdentifyResults::on_buttonHelp_clicked()
{
QgsContextHelp::run( context_id );
@ -327,99 +383,94 @@ void QgsIdentifyResults::itemExpanded( QTreeWidgetItem* item )
void QgsIdentifyResults::handleCurrentItemChanged( QTreeWidgetItem* current, QTreeWidgetItem* previous )
{
if ( lstResults->model()->rowCount() <= 1 )
return;
if ( current == NULL )
{
mCurrentFeatureId = 0;
emit selectedFeatureChanged( 0 );
emit selectedFeatureChanged( 0, 0 );
return;
}
// move to node where is saved feature ID
QTreeWidgetItem* topLevelItem = current;
while ( topLevelItem->parent() != NULL )
{
topLevelItem = topLevelItem->parent();
}
QVariant fid = topLevelItem->data( 0, Qt::UserRole );
// no data saved...
if ( fid.type() != QVariant::Int )
return;
int fid2 = fid.toInt();
if ( fid2 == mCurrentFeatureId )
return;
mCurrentFeatureId = fid2;
emit selectedFeatureChanged( mCurrentFeatureId );
highlightFeature( current );
}
void QgsIdentifyResults::extractAllItemData( QTreeWidgetItem* item )
void QgsIdentifyResults::layerDestroyed()
{
// Extracts the name/value pairs from the given item. This includes data
// under the (Derived) item.
delete layerItem( sender() );
}
// A little bit complicated because the user could of right-clicked
// on any item in the dialog box. We want a toplevel item, so walk upwards
// as far as possible.
// We also want to keep track of which row in the identify results table was
// actually clicked on. This is stored as an index into the mValues vector.
void QgsIdentifyResults::highlightFeature( QTreeWidgetItem *item )
{
QgsVectorLayer *layer = vectorLayer( item );
if ( !layer )
return;
QTreeWidgetItem* child = item;
QTreeWidgetItem* parent = child->parent();
while ( parent != 0 )
QTreeWidgetItem *featItem = featureItem( item );
if ( !featItem )
return;
int fid = featItem->data( 0, Qt::UserRole ).toInt();
delete mRubberBand;
mRubberBand = 0;
QgsFeature feat;
if ( ! layer->featureAtId( fid, feat, true, false ) )
{
child = parent;
parent = parent->parent();
return;
}
parent = child;
mValues.clear();
// For the code below we
// need to do the comparison on the text strings rather than the
// pointers because if the user clicked on the parent, we need
// to pick up which child that actually is (the parent in the
// identify results dialog box is just one of the children
// that has been chosen by some method).
int valuesIndex = 0;
for ( int j = 0; j < parent->childCount(); ++j )
if ( !feat.geometry() )
{
// For derived attributes, build up a virtual name
if ( parent->child( j )->text( 0 ) == mDerivedLabel )
{
for ( int k = 0; k < parent->child( j )->childCount(); ++k )
{
mValues.push_back(
std::make_pair( mDerivedLabel + "."
+ parent->child( j )->child( k )->text( 0 ),
parent->child( j )->child( k )->text( 1 ) ) );
return;
}
if ( item == parent->child( j )->child( k ) )
{
mClickedOnValue = valuesIndex;
}
mRubberBand = new QgsRubberBand( mCanvas, feat.geometry()->type() == QGis::Polygon );
valuesIndex++;
}
}
else // do the actual feature attributes
{
mValues.push_back( std::make_pair( parent->child( j )->text( 0 ),
parent->child( j )->text( 1 ) ) );
if ( item == parent->child( j ) )
{
mClickedOnValue = valuesIndex;
}
valuesIndex++;
}
if ( mRubberBand )
{
mRubberBand->setToGeometry( feat.geometry(), layer );
mRubberBand->setWidth( 2 );
mRubberBand->setColor( Qt::red );
mRubberBand->show();
}
}
void QgsIdentifyResults::editFeature( QTreeWidgetItem *item )
{
QgsVectorLayer *layer = vectorLayer( item );
if ( !layer || !layer->isEditable() )
return;
QTreeWidgetItem *featItem = featureItem( item );
if ( !featItem )
return;
int fid = featItem->data( 0, Qt::UserRole ).toInt();
QgsFeature f;
if ( ! layer->featureAtId( fid, f ) )
return;
QgsAttributeMap src = f.attributeMap();
layer->beginEditCommand( tr( "Attribute changed" ) );
QgsAttributeDialog *ad = new QgsAttributeDialog( layer, &f );
if ( ad->exec() )
{
const QgsAttributeMap &dst = f.attributeMap();
for ( QgsAttributeMap::const_iterator it = dst.begin(); it != dst.end(); it++ )
{
if ( !src.contains( it.key() ) || it.value() != src[it.key()] )
{
layer->changeAttributeValue( f.id(), it.key(), it.value() );
}
}
layer->endEditCommand();
}
else
{
layer->destroyEditCommand();
}
delete ad;
mCanvas->refresh();
}

View File

@ -30,6 +30,11 @@ class QTreeWidgetItem;
class QAction;
class QMenu;
class QgsMapLayer;
class QgsVectorLayer;
class QgsRubberBand;
class QgsMapCanvas;
/**
*@author Gary E.Sherman
*/
@ -41,54 +46,26 @@ class QgsIdentifyResults: public QDialog, private Ui::QgsIdentifyResultsBase
//! Constructor - takes it own copy of the QgsAttributeAction so
// that it is independent of whoever created it.
QgsIdentifyResults( const QgsAttributeAction& actions, QWidget *parent = 0, Qt::WFlags f = 0 );
QgsIdentifyResults( QgsMapCanvas *canvas, QWidget *parent = 0, Qt::WFlags f = 0 );
~QgsIdentifyResults();
/** Add an attribute to the feature display node */
void addAttribute( QTreeWidgetItem *parent, QString field, QString value );
/** Add an attribute */
void addAttribute( QString field, QString value );
/** Add a derived attribute (e.g. Length, Area) to the feature display node */
void addDerivedAttribute( QTreeWidgetItem *parent, QString field, QString value );
/** Add an action to the feature display node */
void addAction( QTreeWidgetItem *parent, int id, QString field, QString value );
/** Add an edit action to the feature display node */
void addEdit( QTreeWidgetItem *parent, int id );
/** Add a feature node to the feature display */
QTreeWidgetItem * addNode( QString label );
/** Set the title for the identify results dialog */
void setTitle( QString title );
/** Set header column */
void setColumnText( int column, const QString & label );
void saveWindowLocation();
void restorePosition();
void closeEvent( QCloseEvent *e );
void showAllAttributes();
/** Resize all of the columns to fit the data in them */
void expandColumnsToFit();
/** Remove results */
void clear();
/** Add add feature */
void addFeature( QgsMapLayer *layer, int fid,
QString displayField, QString displayValue,
const QMap< QString, QString > &attributes,
const QMap< QString, QString > &derivedAttributes );
void closeEvent( QCloseEvent *e );
/** Set "No features ... " */
void setMessage( QString shortMsg, QString longMsg );
/** Set actions */
void setActions( const QgsAttributeAction& actions );
//void accept();
//void reject();
signals:
void selectedFeatureChanged( int featureId );
void editFeature( int featureId );
void selectedFeatureChanged( QgsVectorLayer *, int featureId );
public slots:
@ -98,43 +75,39 @@ class QgsIdentifyResults: public QDialog, private Ui::QgsIdentifyResultsBase
void contextMenuEvent( QContextMenuEvent* );
void popupItemSelected( QAction* menuAction );
/* Item in tree was clicked */
void clicked( QTreeWidgetItem *lvi );
void layerDestroyed();
//! Context help
void on_buttonHelp_clicked();
/* Called when an item is expanded so that we can ensure that the
column width if expanded to show it */
void itemExpanded( QTreeWidgetItem* );
void itemExpanded( QTreeWidgetItem * );
//! sends signal if current feature id has changed
void handleCurrentItemChanged( QTreeWidgetItem* current, QTreeWidgetItem* previous );
void handleCurrentItemChanged( QTreeWidgetItem *current, QTreeWidgetItem *previous );
private:
QMenu *mActionPopup;
QgsRubberBand *mRubberBand;
QgsMapCanvas *mCanvas;
bool mEditable;
QgsAttributeAction mActions;
int mClickedOnValue;
QMenu* mActionPopup;
std::vector<std::pair<QString, QString> > mValues;
static const int context_id = 689216579;
int mCurrentFeatureId;
QString mDerivedLabel;
/**
Keeps track of what derived-attribute (e.g. Length, Area)
root nodes have been generated for each feature in this widget.
QgsVectorLayer *vectorLayer( QTreeWidgetItem *item );
QTreeWidgetItem *featureItem( QTreeWidgetItem *item );
QTreeWidgetItem *layerItem( QObject *layer );
QTreeWidgetItem *retrieveAttributes( QTreeWidgetItem *item, std::vector< std::pair<QString, QString> > &attributes );
First item: Feature root node
Second item: Derived-attribute root node for that feature
*/
std::map<QTreeWidgetItem *, QTreeWidgetItem *> mDerivedAttributeRootNodes;
void setColumnText( int column, const QString & label );
void expandColumnsToFit();
void saveWindowLocation();
void restorePosition();
// Convenience function to populate mValues with all of the item names and
// values for a item, including the derived ones.
void extractAllItemData( QTreeWidgetItem* item );
void highlightFeature( QTreeWidgetItem *item );
void editFeature( QTreeWidgetItem *item );
void doAction( QTreeWidgetItem *item );
};
#endif

View File

@ -26,11 +26,11 @@
#include "qgsmessageviewer.h"
#include "qgsmaptoolidentify.h"
#include "qgsrasterlayer.h"
#include "qgsrubberband.h"
#include "qgscoordinatereferencesystem.h"
#include "qgsvectordataprovider.h"
#include "qgsvectorlayer.h"
#include "qgsattributedialog.h"
#include "qgsproject.h"
#include "qgsmaplayerregistry.h"
#include <QSettings>
#include <QMessageBox>
@ -39,14 +39,13 @@
#include <QPixmap>
QgsMapToolIdentify::QgsMapToolIdentify( QgsMapCanvas* canvas )
: QgsMapTool( canvas ),
mResults( 0 ),
mRubberBand( 0 ),
mLayer( 0 )
: QgsMapTool( canvas )
{
// set cursor
QPixmap myIdentifyQPixmap = QPixmap(( const char ** ) identify_cursor );
mCursor = QCursor( myIdentifyQPixmap, 1, 1 );
mResults = new QgsIdentifyResults( canvas, mCanvas->window() );
}
QgsMapToolIdentify::~QgsMapToolIdentify()
@ -55,8 +54,6 @@ QgsMapToolIdentify::~QgsMapToolIdentify()
{
mResults->done( 0 );
}
delete mRubberBand;
}
void QgsMapToolIdentify::canvasMoveEvent( QMouseEvent * e )
@ -74,164 +71,86 @@ void QgsMapToolIdentify::canvasReleaseEvent( QMouseEvent * e )
return;
}
// delete rubber band if there was any
delete mRubberBand;
mRubberBand = 0;
mResults->clear();
mLayer = mCanvas->currentLayer();
QSettings settings;
int identifyMode = settings.value( "/Map/identifyMode", 0 ).toInt();
if ( !mLayer )
bool res = false;
if ( identifyMode == 0 )
{
QMessageBox::warning( mCanvas,
tr( "No active layer" ),
tr( "To identify features, you must choose an active layer by clicking on its name in the legend" ) );
return;
}
QgsMapLayer *layer = mCanvas->currentLayer();
// cleanup, when layer is removed
connect( mLayer, SIGNAL( destroyed() ), this, SLOT( layerDestroyed() ) );
if ( !layer )
{
QMessageBox::warning( mCanvas,
tr( "No active layer" ),
tr( "To identify features, you must choose an active layer by clicking on its name in the legend" ) );
return;
}
// call identify method for selected layer
// In the special case of the WMS provider,
// coordinates are sent back to the server as pixel coordinates
// not the layer's native CRS. So identify on screen coordinates!
if ( mLayer->type() == QgsMapLayer::RasterLayer &&
dynamic_cast<QgsRasterLayer*>( mLayer )->providerKey() == "wms" )
{
identifyRasterWmsLayer( QgsPoint( e->x(), e->y() ) );
res = identifyLayer( layer, e->x(), e->y() );
}
else
{
// convert screen coordinates to map coordinates
QgsPoint idPoint = mCanvas->getCoordinateTransform()->toMapCoordinates( e->x(), e->y() );
QStringList noIdentifyLayerIdList = QgsProject::instance()->readListEntry( "Identify", "/disabledLayers" );
if ( mLayer->type() == QgsMapLayer::VectorLayer )
for ( int i = 0; i < mCanvas->layerCount(); i++ )
{
identifyVectorLayer( idPoint );
}
else if ( mLayer->type() == QgsMapLayer::RasterLayer )
{
identifyRasterLayer( idPoint );
}
else
{
QgsDebugMsg( "unknown layer type!" );
QgsMapLayer *layer = mCanvas->layer( i );
if ( noIdentifyLayerIdList.contains( layer->getLayerID() ) )
continue;
if ( identifyLayer( layer, e->x(), e->y() ) )
{
res = true;
if ( identifyMode == 1 )
break;
}
}
}
}
void QgsMapToolIdentify::identifyRasterLayer( const QgsPoint& point )
{
QgsRasterLayer *layer = dynamic_cast<QgsRasterLayer*>( mLayer );
if ( !layer )
{
return;
}
QMap<QString, QString> attributes;
layer->identify( point, attributes );
if ( !mResults )
{
QgsAttributeAction aa;
mResults = new QgsIdentifyResults( aa, mCanvas->window() );
mResults->setAttribute( Qt::WA_DeleteOnClose );
// Be informed when the dialog box is closed so that we can stop using it.
connect( mResults, SIGNAL( accepted() ), this, SLOT( resultsDialogGone() ) );
connect( mResults, SIGNAL( rejected() ), this, SLOT( resultsDialogGone() ) );
mResults->restorePosition();
}
else
if ( res )
{
mResults->show();
mResults->raise();
mResults->clear();
}
mResults->setTitle( layer->name() );
mResults->setColumnText( 0, tr( "Band" ) );
QMap<QString, QString>::iterator it;
for ( it = attributes.begin(); it != attributes.end(); it++ )
{
mResults->addAttribute( it.key(), it.value() );
}
mResults->addAttribute( tr( "(clicked coordinate)" ), point.toString() );
mResults->showAllAttributes();
mResults->show();
}
void QgsMapToolIdentify::identifyRasterWmsLayer( const QgsPoint& point )
{
QgsRasterLayer *layer = dynamic_cast<QgsRasterLayer*>( mLayer );
if ( !layer )
{
return;
}
//if WMS layer does not cover the view origin,
//we need to map the view pixel coordinates
//to WMS layer pixel coordinates
QgsRectangle viewExtent = mCanvas->extent();
double mapUnitsPerPixel = mCanvas->mapUnitsPerPixel();
if ( mapUnitsPerPixel == 0 )
{
return;
}
double xMinView = viewExtent.xMinimum();
double yMaxView = viewExtent.yMaximum();
QgsRectangle layerExtent = layer->extent();
double xMinLayer = layerExtent.xMinimum();
double yMaxLayer = layerExtent.yMaximum();
double i, j;
if ( xMinView < xMinLayer )
{
i = ( int )( point.x() - ( xMinLayer - xMinView ) / mapUnitsPerPixel );
}
else
{
i = point.x();
mResults->hide();
QMessageBox::information( 0, tr( "Identify results" ), tr( "No features at this position found." ) );
}
}
if ( yMaxView > yMaxLayer )
bool QgsMapToolIdentify::identifyLayer( QgsMapLayer *layer, int x, int y )
{
bool res = false;
if ( layer->type() == QgsMapLayer::RasterLayer )
{
j = ( int )( point.y() - ( yMaxView - yMaxLayer ) / mapUnitsPerPixel );
res = identifyRasterLayer( dynamic_cast<QgsRasterLayer *>( layer ), x, y );
}
else
{
j = point.y();
res = identifyVectorLayer( dynamic_cast<QgsVectorLayer *>( layer ), x, y );
}
QString text = layer->identifyAsText( QgsPoint( i, j ) );
if ( text.isEmpty() )
{
showError();
return;
}
QgsMessageViewer* viewer = new QgsMessageViewer();
viewer->setWindowTitle( layer->name() );
viewer->setMessageAsPlainText( tr( "WMS identify result for %1:\n%2" ).arg( point.toString() ).arg( text ) );
viewer->showMessage(); // deletes itself on close
return res;
}
void QgsMapToolIdentify::identifyVectorLayer( const QgsPoint& point )
bool QgsMapToolIdentify::identifyVectorLayer( QgsVectorLayer *layer, int x, int y )
{
QgsVectorLayer *layer = dynamic_cast<QgsVectorLayer*>( mLayer );
if ( !layer )
{
return;
}
return false;
QMap< QString, QString > attributes, derivedAttributes;
QgsPoint point = mCanvas->getCoordinateTransform()->toMapCoordinates( x, y );
derivedAttributes.insert( tr( "(clicked coordinate)" ), point.toString() );
// load identify radius from settings
QSettings settings;
@ -239,8 +158,6 @@ void QgsMapToolIdentify::identifyVectorLayer( const QgsPoint& point )
QString ellipsoid = settings.value( "/qgis/measure/ellipsoid", "WGS84" ).toString();
int featureCount = 0;
QgsAttributeAction& actions = *layer->actions();
QString fieldIndex = layer->displayField();
const QgsFieldMap& fields = layer->pendingFields();
// init distance/area calculator
@ -249,9 +166,10 @@ void QgsMapToolIdentify::identifyVectorLayer( const QgsPoint& point )
calc.setEllipsoid( ellipsoid );
calc.setSourceCrs( layer->srs().srsid() );
mFeatureList.clear();
QApplication::setOverrideCursor( Qt::WaitCursor );
QgsFeatureList featureList;
// toLayerCoordinates will throw an exception for an 'invalid' point.
// For example, if you project a world map onto a globe using EPSG 2163
// and then click somewhere off the globe, an exception will be thrown.
@ -271,7 +189,7 @@ void QgsMapToolIdentify::identifyVectorLayer( const QgsPoint& point )
layer->select( layer->pendingAllAttributesList(), r, true, true );
QgsFeature f;
while ( layer->nextFeature( f ) )
mFeatureList << QgsFeature( f );
featureList << QgsFeature( f );
}
catch ( QgsCsException & cse )
{
@ -282,62 +200,29 @@ void QgsMapToolIdentify::identifyVectorLayer( const QgsPoint& point )
QApplication::restoreOverrideCursor();
if ( layer->isEditable() && mFeatureList.size() == 1 )
{
editFeature( mFeatureList[0] );
return;
}
QgsFeatureList::iterator f_it = featureList.begin();
// display features falling within the search radius
if ( !mResults )
{
mResults = new QgsIdentifyResults( actions, mCanvas->window() );
mResults->setAttribute( Qt::WA_DeleteOnClose );
// Be informed when the dialog box is closed so that we can stop using it.
connect( mResults, SIGNAL( accepted() ), this, SLOT( resultsDialogGone() ) );
connect( mResults, SIGNAL( rejected() ), this, SLOT( resultsDialogGone() ) );
connect( mResults, SIGNAL( selectedFeatureChanged( int ) ), this, SLOT( highlightFeature( int ) ) );
connect( mResults, SIGNAL( editFeature( int ) ), this, SLOT( editFeature( int ) ) );
// restore the identify window position and show it
mResults->restorePosition();
}
else
{
mResults->raise();
mResults->clear();
mResults->setActions( actions );
}
QApplication::setOverrideCursor( Qt::WaitCursor );
int lastFeatureId = 0;
QgsFeatureList::iterator f_it = mFeatureList.begin();
for ( ; f_it != mFeatureList.end(); ++f_it )
for ( ; f_it != featureList.end(); ++f_it )
{
featureCount++;
QTreeWidgetItem* featureNode = mResults->addNode( "foo" );
featureNode->setData( 0, Qt::UserRole, QVariant( f_it->id() ) ); // save feature id
lastFeatureId = f_it->id();
featureNode->setText( 0, fieldIndex );
if ( layer->isEditable() )
mResults->addEdit( featureNode, f_it->id() );
int fid = f_it->id();
QString displayField, displayValue;
QMap<QString, QString> attributes, derivedAttributes;
const QgsAttributeMap& attr = f_it->attributeMap();
for ( QgsAttributeMap::const_iterator it = attr.begin(); it != attr.end(); ++it )
{
//QgsDebugMsg(it->fieldName() + " == " + fieldIndex);
if ( fields[it.key()].name() == fieldIndex )
{
featureNode->setText( 1, it->toString() );
}
QString attributeName = layer->attributeDisplayName( it.key() );
mResults->addAttribute( featureNode, attributeName, it->isNull() ? "NULL" : it->toString() );
if ( fields[it.key()].name() == layer->displayField() )
{
displayField = attributeName;
displayValue = it->toString();
}
attributes.insert( attributeName, it->isNull() ? "NULL" : it->toString() );
}
// Calculate derived attributes and insert:
@ -348,18 +233,18 @@ void QgsMapToolIdentify::identifyVectorLayer( const QgsPoint& point )
QGis::UnitType myDisplayUnits;
convertMeasurement( calc, dist, myDisplayUnits, false );
QString str = calc.textUnit( dist, 3, myDisplayUnits, false ); // dist and myDisplayUnits are out params
mResults->addDerivedAttribute( featureNode, tr( "Length" ), str );
derivedAttributes.insert( tr( "Length" ), str );
if ( f_it->geometry()->wkbType() == QGis::WKBLineString )
{
// Add the start and end points in as derived attributes
str = QLocale::system().toString( f_it->geometry()->asPolyline().first().x(), 'g', 10 );
mResults->addDerivedAttribute( featureNode, tr( "firstX", "attributes get sorted; translation for lastX should be lexically larger than this one" ), str );
derivedAttributes.insert( tr( "firstX", "attributes get sorted; translation for lastX should be lexically larger than this one" ), str );
str = QLocale::system().toString( f_it->geometry()->asPolyline().first().y(), 'g', 10 );
mResults->addDerivedAttribute( featureNode, tr( "firstY" ), str );
derivedAttributes.insert( tr( "firstY" ), str );
str = QLocale::system().toString( f_it->geometry()->asPolyline().last().x(), 'g', 10 );
mResults->addDerivedAttribute( featureNode, tr( "lastX", "attributes get sorted; translation for firstX should be lexically smaller than this one" ), str );
derivedAttributes.insert( tr( "lastX", "attributes get sorted; translation for firstX should be lexically smaller than this one" ), str );
str = QLocale::system().toString( f_it->geometry()->asPolyline().last().y(), 'g', 10 );
mResults->addDerivedAttribute( featureNode, tr( "lastY" ), str );
derivedAttributes.insert( tr( "lastY" ), str );
}
}
else if ( layer->geometryType() == QGis::Polygon )
@ -368,179 +253,91 @@ void QgsMapToolIdentify::identifyVectorLayer( const QgsPoint& point )
QGis::UnitType myDisplayUnits;
convertMeasurement( calc, area, myDisplayUnits, true ); // area and myDisplayUnits are out params
QString str = calc.textUnit( area, 3, myDisplayUnits, true );
mResults->addDerivedAttribute( featureNode, tr( "Area" ), str );
derivedAttributes.insert( tr( "Area" ), str );
}
else if ( layer->geometryType() == QGis::Point )
{
// Include the x and y coordinates of the point as a derived attribute
QString str;
str = QLocale::system().toString( f_it->geometry()->asPoint().x(), 'g', 10 );
mResults->addDerivedAttribute( featureNode, "X", str );
derivedAttributes.insert( "X", str );
str = QLocale::system().toString( f_it->geometry()->asPoint().y(), 'g', 10 );
mResults->addDerivedAttribute( featureNode, "Y", str );
derivedAttributes.insert( "Y", str );
}
// Add actions
QgsAttributeAction::aIter iter = actions.begin();
for ( register int i = 0; iter != actions.end(); ++iter, ++i )
{
mResults->addAction( featureNode, i, tr( "action" ), iter->name() );
}
mResults->addFeature( layer, fid, displayField, displayValue, attributes, derivedAttributes );
}
QgsDebugMsg( "Feature count on identify: " + QString::number( featureCount ) );
//also test the not commited features //todo: eliminate copy past code
if ( featureCount == 1 )
{
mResults->showAllAttributes();
highlightFeature( lastFeatureId );
}
else if ( featureCount == 0 )
{
mResults->setMessage( tr( "No features found" ), tr( "No features were found in the active layer at the point you clicked" ) );
}
mResults->setTitle( tr( "%1 - %n feature(s) found", "Identify results window title", featureCount ).arg( layer->name() ) );
QApplication::restoreOverrideCursor();
mResults->show();
return featureCount > 0;
}
void QgsMapToolIdentify::showError()
bool QgsMapToolIdentify::identifyRasterLayer( QgsRasterLayer *layer, int x, int y )
{
#if 0
QMessageBox::warning(
this,
mapLayer->lastErrorTitle(),
tr( "Could not draw %1 because:\n%2", "COMMENTED OUT" ).arg( mapLayer->name() ).arg( mapLayer->lastError() )
);
#endif
bool res = true;
QgsMessageViewer * mv = new QgsMessageViewer();
if ( !layer )
return false;
if ( mLayer )
QgsRasterDataProvider *dprovider = layer->dataProvider();
if ( dprovider && ( dprovider->capabilities() & QgsRasterDataProvider::Identify ) == 0 )
return false;
QMap< QString, QString > attributes, derivedAttributes;
QgsPoint idPoint = mCanvas->getCoordinateTransform()->toMapCoordinates( x, y );
QString type;
if ( layer->providerKey() == "wms" )
{
mv->setWindowTitle( mLayer->lastErrorTitle() );
mv->setMessageAsPlainText( tr( "Could not identify objects on %1 because:\n%2" )
.arg( mLayer->name() ).arg( mLayer->lastError() ) );
type = tr( "WMS layer" );
//if WMS layer does not cover the view origin,
//we need to map the view pixel coordinates
//to WMS layer pixel coordinates
QgsRectangle viewExtent = mCanvas->extent();
QgsRectangle layerExtent = layer->extent();
double mapUnitsPerPixel = mCanvas->mapUnitsPerPixel();
if ( mapUnitsPerPixel > 0 && viewExtent.intersects( layerExtent ) )
{
double xMinView = viewExtent.xMinimum();
double yMaxView = viewExtent.yMaximum();
double xMinLayer = layerExtent.xMinimum();
double yMaxLayer = layerExtent.yMaximum();
idPoint.set(
xMinView < xMinLayer ? floor( x - ( xMinLayer - xMinView ) / mapUnitsPerPixel ) : x,
yMaxView > yMaxLayer ? floor( y - ( yMaxView - yMaxLayer ) / mapUnitsPerPixel ) : y
);
attributes.insert( tr( "Feature info" ), layer->identifyAsText( idPoint ) );
}
else
{
res = false;
}
}
else
{
mv->setWindowTitle( tr( "Layer was removed" ) );
mv->setMessageAsPlainText( tr( "Layer to identify objects on was removed" ) );
type = tr( "Raster" );
res = layer->extent().contains( idPoint ) && layer->identify( idPoint, attributes );
}
mv->exec(); // deletes itself on close
if ( res )
{
derivedAttributes.insert( tr( "(clicked coordinate)" ), idPoint.toString() );
mResults->addFeature( layer, -1, type, "", attributes, derivedAttributes );
}
return res;
}
void QgsMapToolIdentify::resultsDialogGone()
{
mResults = 0;
delete mRubberBand;
mRubberBand = 0;
}
void QgsMapToolIdentify::deactivate()
{
if ( mResults )
mResults->done( 0 ); // close the window
QgsMapTool::deactivate();
}
void QgsMapToolIdentify::highlightFeature( int featureId )
{
QgsVectorLayer* layer = dynamic_cast<QgsVectorLayer*>( mLayer );
if ( !layer )
return;
delete mRubberBand;
mRubberBand = 0;
QgsFeature feat;
if ( ! layer->featureAtId( featureId, feat, true, false ) )
{
return;
}
if ( !feat.geometry() )
{
return;
}
mRubberBand = new QgsRubberBand( mCanvas, feat.geometry()->type() == QGis::Polygon );
if ( mRubberBand )
{
mRubberBand->setToGeometry( feat.geometry(), layer );
mRubberBand->setWidth( 2 );
mRubberBand->setColor( Qt::red );
mRubberBand->show();
}
}
void QgsMapToolIdentify::editFeature( int featureId )
{
for ( QgsFeatureList::iterator it = mFeatureList.begin(); it != mFeatureList.end(); it++ )
{
if ( it->id() == featureId )
{
editFeature( *it );
break;
}
}
}
void QgsMapToolIdentify::editFeature( QgsFeature &f )
{
QgsVectorLayer* layer = dynamic_cast<QgsVectorLayer*>( mLayer );
if ( !layer || !layer->isEditable() )
{
return;
}
QgsAttributeMap src = f.attributeMap();
layer->beginEditCommand( tr( "Attribute changed" ) );
QgsAttributeDialog *ad = new QgsAttributeDialog( layer, &f );
if ( ad->exec() )
{
const QgsAttributeMap &dst = f.attributeMap();
for ( QgsAttributeMap::const_iterator it = dst.begin(); it != dst.end(); it++ )
{
if ( !src.contains( it.key() ) || it.value() != src[it.key()] )
{
layer->changeAttributeValue( f.id(), it.key(), it.value() );
}
}
layer->endEditCommand();
}
else
{
layer->destroyEditCommand();
}
delete ad;
mCanvas->refresh();
}
void QgsMapToolIdentify::layerDestroyed()
{
mLayer = 0;
if ( mResults )
{
mResults->clear();
}
if ( mRubberBand )
{
delete mRubberBand;
mRubberBand = 0;
}
}
void QgsMapToolIdentify::convertMeasurement( QgsDistanceArea &calc, double &measure, QGis::UnitType &u, bool isArea )

View File

@ -57,68 +57,27 @@ class QgsMapToolIdentify : public QgsMapTool
//! Overridden mouse release event
virtual void canvasReleaseEvent( QMouseEvent * e );
//! called when map tool is being deactivated
virtual void deactivate();
public slots:
//! creates rubberband on top of the feature to highlight it
void highlightFeature( int featureId );
//! edit a feature
void editFeature( int featureId );
private:
/**
* \brief function for identifying pixel values at a coordinate in a non-OGC-WMS raster layer
*
* \param point[in] The coordinate (as the CRS of the raster layer)
*/
void identifyRasterLayer( const QgsPoint& point );
/**
* \brief function for identifying a pixel in a OGC WMS raster layer
*
* \param point[in] The pixel coordinate (as it was displayed locally on screen)
*
* \note WMS Servers prefer to receive coordinates in image space not CRS space, therefore
* this special variant of identifyRasterLayer.
*/
void identifyRasterWmsLayer( const QgsPoint& point );
/**
* \brief function for identifying features at a coordinate in a vector layer
*
* \param point[in] The coordinate (as the CRS of the vector layer)
*/
void identifyVectorLayer( const QgsPoint& point );
//! show whatever error is exposed by the QgsMapLayer.
void showError();
//! edit a feature
void editFeature( QgsFeature &f );
bool identifyLayer( QgsMapLayer *layer, int x, int y );
bool identifyRasterLayer( QgsRasterLayer *layer, int x, int y );
bool identifyVectorLayer( QgsVectorLayer *layer, int x, int y );
//! Pointer to the identify results dialog for name/value pairs
QgsIdentifyResults *mResults;
//! Rubber band for highlighting identified feature
QgsRubberBand* mRubberBand;
QgsMapLayer *mLayer;
//! list of identified features
QgsFeatureList mFeatureList;
//! Private helper
void convertMeasurement( QgsDistanceArea &calc, double &measure, QGis::UnitType &u, bool isArea );
void addFeature( QgsMapLayer *layer, int fid,
QString displayField, QString displayValue,
const QMap< QString, QString > &attributes,
const QMap< QString, QString > &derivedAttributes );
/** Add an action to the feature display node */
private slots:
// Let us know when the QgsIdentifyResults dialog box has been closed
void resultsDialogGone();
// layer was destroyed
void layerDestroyed();
};
#endif

View File

@ -50,9 +50,14 @@ QgsOptions::QgsOptions( QWidget *parent, Qt::WFlags fl ) :
connect( buttonBox, SIGNAL( rejected() ), this, SLOT( reject() ) );
connect( this, SIGNAL( accepted() ), this, SLOT( saveOptions() ) );
cmbIdentifyMode->addItem( tr( "current layer" ), 0 );
cmbIdentifyMode->addItem( tr( "top down, stop at first" ), 1 );
cmbIdentifyMode->addItem( tr( "top down" ), 2 );
// read the current browser and set it
QSettings settings;
QgsDebugMsg( QString( "Standard Identify radius setting: %1" ).arg( QGis::DEFAULT_IDENTIFY_RADIUS ) );
int identifyMode = settings.value( "/Map/identifyMode", 0 ).toInt();
cmbIdentifyMode->setCurrentIndex( cmbIdentifyMode->findData( identifyMode ) );
double identifyValue = settings.value( "/Map/identifyRadius", QGis::DEFAULT_IDENTIFY_RADIUS ).toDouble();
QgsDebugMsg( QString( "Standard Identify radius setting read from settings file: %1" ).arg( identifyValue ) );
spinBoxIdentifyValue->setValue( identifyValue );
@ -349,6 +354,7 @@ void QgsOptions::saveOptions()
settings.setValue( "proxy/proxyExcludedUrls", proxyExcludeString );
//general settings
settings.setValue( "/Map/identifyMode", cmbIdentifyMode->itemData( cmbIdentifyMode->currentIndex() ).toInt() );
settings.setValue( "/Map/identifyRadius", spinBoxIdentifyValue->value() );
settings.setValue( "/qgis/showLegendClassifiers", cbxLegendClassifiers->isChecked() );
settings.setValue( "/qgis/hideSplash", cbxHideSplash->isChecked() );

View File

@ -30,6 +30,7 @@
#include "qgsproject.h"
#include "qgsrenderer.h"
#include "qgssnappingdialog.h"
#include "qgsrasterlayer.h"
//qt includes
#include <QColorDialog>
@ -205,6 +206,56 @@ QgsProjectProperties::QgsProjectProperties( QgsMapCanvas* mapCanvas, QWidget *pa
mSnappingLayerSettings.insert( *idIter, newEntry );
}
}
QStringList noIdentifyLayerIdList = QgsProject::instance()->readListEntry( "Identify", "/disabledLayers" );
const QMap<QString, QgsMapLayer*> &mapLayers = QgsMapLayerRegistry::instance()->mapLayers();
twIdentifyLayers->setColumnCount( 3 );
twIdentifyLayers->horizontalHeader()->setVisible( true );
twIdentifyLayers->setHorizontalHeaderItem( 0, new QTableWidgetItem( tr( "Layer" ) ) );
twIdentifyLayers->setHorizontalHeaderItem( 1, new QTableWidgetItem( tr( "Type" ) ) );
twIdentifyLayers->setHorizontalHeaderItem( 2, new QTableWidgetItem( tr( "Identifiable" ) ) );
twIdentifyLayers->setRowCount( mapLayers.size() );
twIdentifyLayers->verticalHeader()->setResizeMode( QHeaderView::ResizeToContents );
int i = 0;
for ( QMap<QString, QgsMapLayer*>::const_iterator it = mapLayers.constBegin(); it != mapLayers.constEnd(); it++, i++ )
{
currentLayer = it.value();
QTableWidgetItem *twi = new QTableWidgetItem( QString::number( i ) );
twi->setData( Qt::UserRole, it.key() );
twIdentifyLayers->setVerticalHeaderItem( i, twi );
twIdentifyLayers->setItem( i, 0, new QTableWidgetItem( currentLayer->name() ) );
QString type;
if ( currentLayer->type() == QgsMapLayer::VectorLayer )
{
type = tr( "Vector" );
}
else if ( currentLayer->type() == QgsMapLayer::RasterLayer )
{
QgsRasterLayer *rl = dynamic_cast<QgsRasterLayer *>( currentLayer );
if ( rl && rl->providerKey() == "wms" )
{
type = tr( "WMS" );
}
else
{
type = tr( "Raster" );
}
}
twIdentifyLayers->setItem( i, 1, new QTableWidgetItem( type ) );
QCheckBox *cb = new QCheckBox();
cb->setChecked( !noIdentifyLayerIdList.contains( currentLayer->getLayerID() ) );
twIdentifyLayers->setCellWidget( i, 2, cb );
}
restoreState();
}
@ -387,6 +438,19 @@ void QgsProjectProperties::apply()
QgsProject::instance()->writeEntry( "Digitizing", "/LayerSnappingEnabledList", enabledList );
}
QStringList noIdentifyLayerList;
for ( int i = 0; i < twIdentifyLayers->rowCount(); i++ )
{
QCheckBox *cb = dynamic_cast<QCheckBox*>( twIdentifyLayers->cellWidget( i, 2 ) );
if ( cb && !cb->isChecked() )
{
QString id = twIdentifyLayers->verticalHeaderItem( i )->data( Qt::UserRole ).toString();
noIdentifyLayerList << id;
}
}
QgsProject::instance()->writeEntry( "Identify", "/disabledLayers", noIdentifyLayerList );
//todo XXX set canvas colour
emit refresh();
}

View File

@ -161,6 +161,11 @@ bool QgsRectangle::contains( const QgsRectangle& rect ) const
return ( rect.xmin >= xmin && rect.xmax <= xmax && rect.ymin >= ymin && rect.ymax <= ymax );
}
bool QgsRectangle::contains( const QgsPoint &p ) const
{
return xmin <= p.x() && p.x() <= xmax &&
ymin <= p.y() && p.y() <= ymax;
}
void QgsRectangle::combineExtentWith( QgsRectangle * rect )
{

View File

@ -87,6 +87,9 @@ class CORE_EXPORT QgsRectangle
//! return true when rectangle contains other rectangle
//! @note added in version 1.1
bool contains( const QgsRectangle& rect ) const;
//! return true when rectangle contains a point
//! @note added in version 1.3
bool contains( const QgsPoint &p ) const;
//! expand the rectangle so that covers both the original rectangle and the given rectangle
void combineExtentWith( QgsRectangle *rect );
//! expand the rectangle so that covers both the original rectangle and the given point

View File

@ -1507,7 +1507,7 @@ bool QgsRasterLayer::draw( QgsRenderContext& rendererContext )
{
QgsDebugMsg( "Wanting a '" + mProviderKey + "' provider to draw this." );
emit statusChanged( tr( "Retrieving using %1" ).arg( mProviderKey ) );
emit statusChanged( tr( "Retrieving %1 using %2" ).arg( name() ).arg( mProviderKey ) );
mDataProvider->setDpi( rendererContext.rasterScaleFactor() * 25.4 * rendererContext.scaleFactor() );
@ -1594,6 +1594,7 @@ bool QgsRasterLayer::draw( QgsRenderContext& rendererContext )
delete image;
}
emit statusChanged( tr( "%1 retrieved using %2" ).arg( name() ).arg( mProviderKey ) );
}
else
{
@ -1846,12 +1847,9 @@ bool QgsRasterLayer::identify( const QgsPoint& thePoint, QMap<QString, QString>&
return false;
}
double x = thePoint.x();
double y = thePoint.y();
QgsDebugMsg( thePoint.toString() );
QgsDebugMsg( QString::number( x ) + ", " + QString::number( y ) );
if ( x < mLayerExtent.xMinimum() || x > mLayerExtent.xMaximum() || y < mLayerExtent.yMinimum() || y > mLayerExtent.yMaximum() )
if ( !mLayerExtent.contains( thePoint ) )
{
// Outside the raster
for ( int i = 1; i <= GDALGetRasterCount( mGdalDataset ); i++ )
@ -1861,6 +1859,9 @@ bool QgsRasterLayer::identify( const QgsPoint& thePoint, QMap<QString, QString>&
}
else
{
double x = thePoint.x();
double y = thePoint.y();
/* Calculate the row / column where the point falls */
double xres = ( mLayerExtent.xMaximum() - mLayerExtent.xMinimum() ) / mWidth;
double yres = ( mLayerExtent.yMaximum() - mLayerExtent.yMinimum() ) / mHeight;

View File

@ -6,8 +6,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>617</width>
<height>521</height>
<width>654</width>
<height>546</height>
</rect>
</property>
<property name="windowTitle">
@ -503,13 +503,13 @@
<item row="0" column="0">
<widget class="QGroupBox" name="groupBox_7">
<property name="title">
<string>Search radius</string>
<string>Identify</string>
</property>
<layout class="QGridLayout">
<property name="margin">
<number>11</number>
</property>
<item row="1" column="0" colspan="2">
<item row="2" column="0" colspan="2">
<widget class="QLabel" name="textLabel2">
<property name="text">
<string>&lt;b&gt;Note:&lt;/b&gt; Specify the search radius as a percentage of the map width</string>
@ -519,7 +519,7 @@
</property>
</widget>
</item>
<item row="0" column="0">
<item row="1" column="0">
<widget class="QLabel" name="textLabel1_3">
<property name="text">
<string>Search radius for identifying features and displaying map tips</string>
@ -529,7 +529,7 @@
</property>
</widget>
</item>
<item row="0" column="1">
<item row="1" column="1">
<widget class="QDoubleSpinBox" name="spinBoxIdentifyValue">
<property name="suffix">
<string>%</string>
@ -545,6 +545,16 @@
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QComboBox" name="cmbIdentifyMode"/>
</item>
<item row="0" column="0">
<widget class="QLabel" name="label_4">
<property name="text">
<string>Mode</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>

View File

@ -1,81 +1,87 @@
<ui version="4.0" >
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>QgsProjectPropertiesBase</class>
<widget class="QDialog" name="QgsProjectPropertiesBase" >
<property name="geometry" >
<widget class="QDialog" name="QgsProjectPropertiesBase">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>536</width>
<height>713</height>
<width>451</width>
<height>515</height>
</rect>
</property>
<property name="windowTitle" >
<property name="windowTitle">
<string>Project Properties</string>
</property>
<property name="windowIcon" >
<iconset>
<normaloff/>
</iconset>
</property>
<property name="sizeGripEnabled" >
<property name="sizeGripEnabled">
<bool>true</bool>
</property>
<property name="modal" >
<property name="modal">
<bool>true</bool>
</property>
<layout class="QGridLayout" >
<item row="0" column="0" >
<widget class="QTabWidget" name="tabWidget" >
<property name="currentIndex" >
<layout class="QGridLayout">
<item row="2" column="0">
<widget class="QDialogButtonBox" name="buttonBox">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Apply|QDialogButtonBox::Cancel|QDialogButtonBox::Help|QDialogButtonBox::Ok</set>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QTabWidget" name="tabWidget">
<property name="currentIndex">
<number>0</number>
</property>
<widget class="QWidget" name="tab1" >
<attribute name="title" >
<widget class="QWidget" name="tab1">
<attribute name="title">
<string>General</string>
</attribute>
<layout class="QGridLayout" >
<item row="0" column="0" >
<widget class="QGroupBox" name="titleBox" >
<property name="title" >
<string>Title and colors</string>
<layout class="QGridLayout">
<item row="0" column="0">
<widget class="QGroupBox" name="titleBox">
<property name="title">
<string>General settings</string>
</property>
<layout class="QGridLayout" >
<item row="0" column="0" >
<widget class="QLabel" name="label_2" >
<property name="text" >
<layout class="QGridLayout">
<item row="0" column="0">
<widget class="QLabel" name="label_2">
<property name="text">
<string>Project title</string>
</property>
</widget>
</item>
<item row="0" column="1" colspan="3" >
<widget class="QLineEdit" name="titleEdit" >
<property name="toolTip" >
<item row="0" column="1" colspan="3">
<widget class="QLineEdit" name="titleEdit">
<property name="toolTip">
<string>Descriptive project name</string>
</property>
<property name="text" >
<property name="text">
<string>Default project title</string>
</property>
</widget>
</item>
<item row="1" column="0" >
<widget class="QLabel" name="textLabel1" >
<property name="text" >
<item row="1" column="0">
<widget class="QLabel" name="textLabel1">
<property name="text">
<string>Selection color</string>
</property>
<property name="buddy" >
<property name="buddy">
<cstring>pbnSelectionColour</cstring>
</property>
</widget>
</item>
<item row="1" column="2" >
<item row="1" column="2">
<spacer>
<property name="orientation" >
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeType" >
<property name="sizeType">
<enum>QSizePolicy::Expanding</enum>
</property>
<property name="sizeHint" >
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
@ -83,35 +89,35 @@
</property>
</spacer>
</item>
<item row="1" column="3" >
<widget class="QgsColorButton" name="pbnSelectionColour" >
<property name="minimumSize" >
<item row="1" column="3">
<widget class="QgsColorButton" name="pbnSelectionColour">
<property name="minimumSize">
<size>
<width>100</width>
<height>0</height>
</size>
</property>
<property name="text" >
<property name="text">
<string/>
</property>
</widget>
</item>
<item row="2" column="0" colspan="2" >
<widget class="QLabel" name="label" >
<property name="text" >
<item row="2" column="0" colspan="2">
<widget class="QLabel" name="label">
<property name="text">
<string>Background color</string>
</property>
<property name="buddy" >
<property name="buddy">
<cstring>pbnCanvasColor</cstring>
</property>
</widget>
</item>
<item row="2" column="2" >
<item row="2" column="2">
<spacer>
<property name="orientation" >
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" >
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
@ -119,60 +125,58 @@
</property>
</spacer>
</item>
<item row="2" column="3" >
<widget class="QgsColorButton" name="pbnCanvasColor" >
<property name="minimumSize" >
<item row="2" column="3">
<widget class="QgsColorButton" name="pbnCanvasColor">
<property name="minimumSize">
<size>
<width>100</width>
<height>0</height>
</size>
</property>
<property name="text" >
<property name="text">
<string/>
</property>
</widget>
</item>
<item row="3" column="0" colspan="4">
<widget class="QCheckBox" name="cbxAbsolutePath">
<property name="text">
<string>Save absolute paths</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item row="1" column="0" >
<widget class="QGroupBox" name="btnGrpMapUnits" >
<property name="title" >
<item row="1" column="0">
<widget class="QGroupBox" name="btnGrpMapUnits">
<property name="title">
<string>Layer units (only used when CRS transformation is disabled)</string>
</property>
<layout class="QHBoxLayout" >
<property name="leftMargin" >
<number>11</number>
</property>
<property name="topMargin" >
<number>11</number>
</property>
<property name="rightMargin" >
<number>11</number>
</property>
<property name="bottomMargin" >
<layout class="QHBoxLayout">
<property name="margin">
<number>11</number>
</property>
<item>
<widget class="QRadioButton" name="radMeters" >
<property name="text" >
<widget class="QRadioButton" name="radMeters">
<property name="text">
<string>Meters</string>
</property>
<property name="checked" >
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QRadioButton" name="radFeet" >
<property name="text" >
<widget class="QRadioButton" name="radFeet">
<property name="text">
<string>Feet</string>
</property>
</widget>
</item>
<item>
<widget class="QRadioButton" name="radDecimalDegrees" >
<property name="text" >
<widget class="QRadioButton" name="radDecimalDegrees">
<property name="text">
<string>Decimal degrees</string>
</property>
</widget>
@ -180,60 +184,60 @@
</layout>
</widget>
</item>
<item row="2" column="0" >
<widget class="QGroupBox" name="btnGrpPrecision" >
<property name="title" >
<item row="2" column="0">
<widget class="QGroupBox" name="btnGrpPrecision">
<property name="title">
<string>Precision</string>
</property>
<layout class="QGridLayout" >
<item row="0" column="0" >
<widget class="QRadioButton" name="radAutomatic" >
<property name="toolTip" >
<layout class="QGridLayout">
<item row="0" column="0">
<widget class="QRadioButton" name="radAutomatic">
<property name="toolTip">
<string>Automatically sets the number of decimal places in the mouse position display</string>
</property>
<property name="whatsThis" >
<property name="whatsThis">
<string>The number of decimal places that are used when displaying the mouse position is automatically set to be enough so that moving the mouse by one pixel gives a change in the position display</string>
</property>
<property name="text" >
<property name="text">
<string>Automatic</string>
</property>
<property name="checked" >
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
<item row="0" column="1" >
<widget class="QRadioButton" name="radManual" >
<property name="toolTip" >
<item row="0" column="1">
<widget class="QRadioButton" name="radManual">
<property name="toolTip">
<string>Sets the number of decimal places to use for the mouse position display</string>
</property>
<property name="whatsThis" >
<property name="whatsThis">
<string>Sets the number of decimal places to use for the mouse position display</string>
</property>
<property name="text" >
<property name="text">
<string>Manual</string>
</property>
</widget>
</item>
<item row="0" column="2" >
<widget class="QSpinBox" name="spinBoxDP" >
<property name="toolTip" >
<item row="0" column="2">
<widget class="QSpinBox" name="spinBoxDP">
<property name="toolTip">
<string>The number of decimal places for the manual option</string>
</property>
<property name="whatsThis" >
<property name="whatsThis">
<string>The number of decimal places for the manual option</string>
</property>
</widget>
</item>
<item row="0" column="3" >
<widget class="QLabel" name="textLabel3" >
<property name="sizePolicy" >
<sizepolicy vsizetype="Fixed" hsizetype="Fixed" >
<item row="0" column="3">
<widget class="QLabel" name="textLabel3">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text" >
<property name="text">
<string>decimal places</string>
</property>
</widget>
@ -241,35 +245,35 @@
</layout>
</widget>
</item>
<item row="3" column="0" >
<widget class="QGroupBox" name="grpDigitizing" >
<property name="sizePolicy" >
<sizepolicy vsizetype="Expanding" hsizetype="Preferred" >
<item row="3" column="0">
<widget class="QGroupBox" name="grpDigitizing">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="title" >
<property name="title">
<string>Digitizing</string>
</property>
<layout class="QGridLayout" >
<item row="0" column="0" >
<widget class="QCheckBox" name="mEnableTopologicalEditingCheckBox" >
<property name="text" >
<layout class="QGridLayout">
<item row="0" column="0">
<widget class="QCheckBox" name="mEnableTopologicalEditingCheckBox">
<property name="text">
<string>Enable topological editing</string>
</property>
</widget>
</item>
<item row="1" column="0" >
<widget class="QCheckBox" name="mAvoidIntersectionsCheckBox" >
<property name="text" >
<item row="1" column="0">
<widget class="QCheckBox" name="mAvoidIntersectionsCheckBox">
<property name="text">
<string>Avoid intersections of new polygons</string>
</property>
</widget>
</item>
<item row="2" column="0" >
<widget class="QPushButton" name="mSnappingOptionsPushButton" >
<property name="text" >
<item row="2" column="0">
<widget class="QPushButton" name="mSnappingOptionsPushButton">
<property name="text">
<string>Snapping options...</string>
</property>
</widget>
@ -277,59 +281,86 @@
</layout>
</widget>
</item>
<item row="4" column="0" >
<widget class="QCheckBox" name="cbxAbsolutePath" >
<property name="text" >
<string>Save absolute paths</string>
</property>
</widget>
</item>
</layout>
</widget>
<widget class="QWidget" name="tab2" >
<attribute name="title" >
<widget class="QWidget" name="tab2">
<attribute name="title">
<string>Coordinate Reference System (CRS)</string>
</attribute>
<layout class="QGridLayout" >
<property name="leftMargin" >
<layout class="QGridLayout">
<property name="leftMargin">
<number>3</number>
</property>
<property name="topMargin" >
<property name="topMargin">
<number>11</number>
</property>
<property name="rightMargin" >
<property name="rightMargin">
<number>3</number>
</property>
<property name="bottomMargin" >
<property name="bottomMargin">
<number>11</number>
</property>
<item row="0" column="0" >
<widget class="QCheckBox" name="cbxProjectionEnabled" >
<property name="text" >
<item row="0" column="0">
<widget class="QCheckBox" name="cbxProjectionEnabled">
<property name="text">
<string>Enable 'on the fly' CRS transformation</string>
</property>
</widget>
</item>
<item row="1" column="0" >
<widget class="QgsProjectionSelector" native="1" name="projectionSelector" />
<item row="1" column="0">
<widget class="QgsProjectionSelector" name="projectionSelector" native="true"/>
</item>
</layout>
</widget>
<widget class="QWidget" name="tab3">
<attribute name="title">
<string>Identifiable layers</string>
</attribute>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QTableWidget" name="twIdentifyLayers">
<property name="sortingEnabled">
<bool>true</bool>
</property>
<attribute name="horizontalHeaderVisible">
<bool>false</bool>
</attribute>
<attribute name="horizontalHeaderShowSortIndicator" stdset="0">
<bool>false</bool>
</attribute>
<attribute name="horizontalHeaderStretchLastSection">
<bool>true</bool>
</attribute>
<attribute name="horizontalHeaderVisible">
<bool>false</bool>
</attribute>
<column>
<property name="text">
<string>Layer</string>
</property>
</column>
<column>
<property name="text">
<string>Type</string>
</property>
</column>
<column>
<property name="text">
<string>Identifiable</string>
</property>
<property name="textAlignment">
<set>AlignHCenter|AlignVCenter|AlignCenter</set>
</property>
</column>
</widget>
</item>
</layout>
</widget>
</widget>
</item>
<item row="2" column="0" >
<widget class="QDialogButtonBox" name="buttonBox" >
<property name="orientation" >
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons" >
<set>QDialogButtonBox::Apply|QDialogButtonBox::Cancel|QDialogButtonBox::Help|QDialogButtonBox::NoButton|QDialogButtonBox::Ok</set>
</property>
</widget>
</item>
</layout>
</widget>
<layoutdefault spacing="6" margin="11" />
<layoutdefault spacing="6" margin="11"/>
<customwidgets>
<customwidget>
<class>QgsColorButton</class>
@ -368,11 +399,11 @@
<receiver>spinBoxDP</receiver>
<slot>setEnabled(bool)</slot>
<hints>
<hint type="sourcelabel" >
<hint type="sourcelabel">
<x>229</x>
<y>280</y>
</hint>
<hint type="destinationlabel" >
<hint type="destinationlabel">
<x>416</x>
<y>286</y>
</hint>
@ -384,11 +415,11 @@
<receiver>textLabel3</receiver>
<slot>setEnabled(bool)</slot>
<hints>
<hint type="sourcelabel" >
<hint type="sourcelabel">
<x>240</x>
<y>281</y>
</hint>
<hint type="destinationlabel" >
<hint type="destinationlabel">
<x>583</x>
<y>290</y>
</hint>
@ -400,11 +431,11 @@
<receiver>spinBoxDP</receiver>
<slot>setDisabled(bool)</slot>
<hints>
<hint type="sourcelabel" >
<hint type="sourcelabel">
<x>100</x>
<y>290</y>
</hint>
<hint type="destinationlabel" >
<hint type="destinationlabel">
<x>395</x>
<y>285</y>
</hint>
@ -416,11 +447,11 @@
<receiver>textLabel3</receiver>
<slot>setDisabled(bool)</slot>
<hints>
<hint type="sourcelabel" >
<hint type="sourcelabel">
<x>87</x>
<y>284</y>
</hint>
<hint type="destinationlabel" >
<hint type="destinationlabel">
<x>589</x>
<y>285</y>
</hint>