Skip to content

Commit 8aa160b

Browse files
committedAug 5, 2012
Add html support in map tips
- Add new display tab to edit html text
1 parent ddd3b27 commit 8aa160b

File tree

5 files changed

+375
-75
lines changed

5 files changed

+375
-75
lines changed
 

‎src/app/qgsvectorlayerproperties.cpp

Lines changed: 63 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,10 @@ QgsVectorLayerProperties::QgsVectorLayerProperties(
9595
connect( layer, SIGNAL( attributeAdded( int ) ), this, SLOT( attributeAdded( int ) ) );
9696
connect( layer, SIGNAL( attributeDeleted( int ) ), this, SLOT( attributeDeleted( int ) ) );
9797

98+
connect( insertFieldButton, SIGNAL( clicked() ), this, SLOT( insertField() ) );
99+
connect( insertExpressionButton, SIGNAL( clicked() ), this, SLOT( insertExpression() ) );
100+
101+
98102
mAddAttributeButton->setIcon( QgsApplication::getThemeIcon( "/mActionNewAttribute.png" ) );
99103
mDeleteAttributeButton->setIcon( QgsApplication::getThemeIcon( "/mActionDeleteAttribute.png" ) );
100104
mToggleEditingButton->setIcon( QgsApplication::getThemeIcon( "/mActionToggleEditing.png" ) );
@@ -481,9 +485,55 @@ void QgsVectorLayerProperties::setLegendType( QString type )
481485
legendtypecombobox->setItemText( legendtypecombobox->currentIndex(), type );
482486
}
483487

488+
void QgsVectorLayerProperties::insertField()
489+
{
490+
// Convert the selected field to an expression and
491+
// insert it into the action at the cursor position
492+
493+
if ( !fieldComboBox->currentText().isNull() )
494+
{
495+
QString field = "[% \"";
496+
field += fieldComboBox->currentText();
497+
field += "\" %]";
498+
htmlMapTip->insertPlainText( field );
499+
}
500+
}
501+
502+
void QgsVectorLayerProperties::insertExpression()
503+
{
504+
QString selText = htmlMapTip->textCursor().selectedText();
505+
506+
// edit the selected expression if there's one
507+
if ( selText.startsWith( "[%" ) && selText.endsWith( "%]" ) )
508+
selText = selText.mid( 2, selText.size() - 4 );
509+
510+
// display the expression builder
511+
QgsExpressionBuilderDialog dlg( layer , selText, this );
512+
dlg.setWindowTitle( tr( "Insert expression" ) );
513+
if ( dlg.exec() == QDialog::Accepted )
514+
{
515+
QString expression = dlg.expressionBuilder()->expressionText();
516+
//Only add the expression if the user has entered some text.
517+
if ( !expression.isEmpty() )
518+
{
519+
htmlMapTip->insertPlainText( "[%" + expression + "%]" );
520+
}
521+
}
522+
}
523+
484524
void QgsVectorLayerProperties::setDisplayField( QString name )
485525
{
486-
displayFieldComboBox->setItemText( displayFieldComboBox->currentIndex(), name );
526+
int idx = displayFieldComboBox->findText( name );
527+
if ( idx == -1 )
528+
{
529+
htmlRadio->setChecked( true );
530+
htmlMapTip->setPlainText( name );
531+
}
532+
else
533+
{
534+
fieldComboRadio->setChecked( true );
535+
displayFieldComboBox->setCurrentIndex( idx );
536+
}
487537
}
488538

489539
//! @note in raster props, this method is called sync()
@@ -520,9 +570,10 @@ void QgsVectorLayerProperties::reset( void )
520570
for ( QgsFieldMap::const_iterator it = myFields.begin(); it != myFields.end(); ++it )
521571
{
522572
displayFieldComboBox->addItem( it->name() );
573+
fieldComboBox->addItem( it->name() );
523574
}
524-
displayFieldComboBox->setCurrentIndex( displayFieldComboBox->findText(
525-
layer->displayField() ) );
575+
576+
setDisplayField( layer-> displayField() );
526577

527578
// set up the scale based layer visibility stuff....
528579
chkUseScaleDependentRendering->setChecked( layer->hasScaleBasedVisibility() );
@@ -633,7 +684,15 @@ void QgsVectorLayerProperties::apply()
633684
}
634685

635686
// update the display field
636-
layer->setDisplayField( displayFieldComboBox->currentText() );
687+
if ( htmlRadio->isChecked() )
688+
{
689+
layer->setDisplayField( htmlMapTip->toPlainText() );
690+
}
691+
692+
if ( fieldComboRadio->isChecked() )
693+
{
694+
layer->setDisplayField( displayFieldComboBox->currentText() );
695+
}
637696

638697
layer->setEditForm( leEditForm->text() );
639698
layer->setEditFormInit( leEditFormInit->text() );

‎src/app/qgsvectorlayerproperties.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
#include "qgsfield.h"
2929
#include "qgsmapcanvas.h"
3030
#include "qgscontexthelp.h"
31+
#include "qgsexpressionbuilderdialog.h"
3132

3233
class QgsMapLayer;
3334

@@ -55,6 +56,7 @@ class QgsVectorLayerProperties : public QDialog, private Ui::QgsVectorLayerPrope
5556
/**Returns the display name entered in the dialog*/
5657
QString displayName();
5758
void setRendererDirty( bool ) {}
59+
5860
/**Sets the attribute that is used in the Identify Results dialog box*/
5961
void setDisplayField( QString name );
6062

@@ -70,6 +72,11 @@ class QgsVectorLayerProperties : public QDialog, private Ui::QgsVectorLayerPrope
7072

7173
public slots:
7274

75+
/** Insert a field in the expression text for the map tip **/
76+
void insertField();
77+
78+
void insertExpression();
79+
7380
void attributeTypeDialog();
7481

7582
void alterLayerDialog( const QString& string );

‎src/gui/qgsmaptip.cpp

Lines changed: 54 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,10 @@
1313
* *
1414
***************************************************************************/
1515
// QGIS includes
16-
#include <qgsmapcanvas.h>
17-
#include <qgsvectorlayer.h>
16+
#include "qgsmapcanvas.h"
17+
#include "qgsvectorlayer.h"
18+
#include "qgsexpression.h"
19+
#include "qgslogger.h"
1820

1921
// Qt includes
2022
#include <QPoint>
@@ -91,15 +93,59 @@ QString QgsMapTip::fetchFeature( QgsMapLayer *layer, QgsPoint &mapPosition, QgsM
9193

9294
r = mpMapCanvas->mapRenderer()->mapToLayerCoordinates( layer, r );
9395

94-
int idx = vlayer->fieldNameIndex( vlayer->displayField() );
95-
if ( idx < 0 )
96-
return "";
97-
9896
QgsFeature feature;
9997

100-
vlayer->select( QgsAttributeList() << idx, r, true, true );
98+
vlayer->select( vlayer->pendingAllAttributesList() , r, true, true );
10199
if ( !vlayer->nextFeature( feature ) )
102100
return "";
103101

104-
return feature.attributeMap().value( idx, "" ).toString();
102+
int idx = vlayer->fieldNameIndex( vlayer->displayField() );
103+
if ( idx < 0 )
104+
return replaceText( vlayer->displayField(), vlayer, feature );
105+
else
106+
return feature.attributeMap().value( idx, "" ).toString();
107+
108+
}
109+
110+
QString QgsMapTip::replaceText( QString displayText, QgsVectorLayer *layer, QgsFeature &feat )
111+
{
112+
QString expr_action;
113+
114+
int index = 0;
115+
while ( index < displayText.size() )
116+
{
117+
QRegExp rx = QRegExp( "\\[%([^\\]]+)%\\]" );
118+
119+
int pos = rx.indexIn( displayText, index );
120+
if ( pos < 0 )
121+
break;
122+
123+
int start = index;
124+
index = pos + rx.matchedLength();
125+
126+
QString to_replace = rx.cap( 1 ).trimmed();
127+
QgsDebugMsg( "Found expression: " + to_replace );
128+
129+
QgsExpression exp( to_replace );
130+
if ( exp.hasParserError() )
131+
{
132+
QgsDebugMsg( "Expression parser error: " + exp.parserErrorString() );
133+
expr_action += displayText.mid( start, index - start );
134+
continue;
135+
}
136+
137+
QVariant result = exp.evaluate( &feat, layer->pendingFields() );
138+
if ( exp.hasEvalError() )
139+
{
140+
QgsDebugMsg( "Expression parser eval error: " + exp.evalErrorString() );
141+
expr_action += displayText.mid( start, index - start );
142+
continue;
143+
}
144+
145+
QgsDebugMsg( "Expression result is: " + result.toString() );
146+
expr_action += displayText.mid( start, pos - start ) + result.toString();
147+
}
148+
149+
expr_action += displayText.mid( index );
150+
return expr_action;
105151
}

‎src/gui/qgsmaptip.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ class QgsMapCanvas;
2020
class QPoint;
2121
class QString;
2222

23+
#include "qgsfeature.h"
2324

2425
/** \ingroup gui
2526
* A maptip is a class to display a tip on a map canvas
@@ -57,6 +58,9 @@ class GUI_EXPORT QgsMapTip
5758
QString fetchFeature( QgsMapLayer * thepLayer,
5859
QgsPoint & theMapPosition,
5960
QgsMapCanvas *thepMapCanvas );
61+
62+
QString replaceText( QString displayText, QgsVectorLayer *layer, QgsFeature &feat );
63+
6064
// Flag to indicate if a maptip is currently being displayed
6165
bool mMapTipVisible;
6266
// Last point on the map canvas when the maptip timer fired. This point is in widget pixel

‎src/ui/qgsvectorlayerpropertiesbase.ui

Lines changed: 247 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -370,8 +370,8 @@
370370
<rect>
371371
<x>0</x>
372372
<y>0</y>
373-
<width>755</width>
374-
<height>519</height>
373+
<width>740</width>
374+
<height>548</height>
375375
</rect>
376376
</property>
377377
<layout class="QGridLayout" name="gridLayout_3">
@@ -382,30 +382,13 @@
382382
</property>
383383
<layout class="QGridLayout" name="gridLayout_2">
384384
<item row="0" column="0">
385-
<widget class="QLabel" name="textLabel3">
386-
<property name="text">
387-
<string>Display name</string>
388-
</property>
389-
</widget>
390-
</item>
391-
<item row="0" column="1">
392-
<widget class="QLineEdit" name="txtDisplayName"/>
393-
</item>
394-
<item row="0" column="3">
395-
<widget class="QComboBox" name="displayFieldComboBox">
396-
<property name="whatsThis">
397-
<string>Use this control to set which field is placed at the top level of the Identify Results dialog box.</string>
398-
</property>
399-
</widget>
400-
</item>
401-
<item row="1" column="0">
402385
<widget class="QLabel" name="label">
403386
<property name="text">
404387
<string>Edit UI</string>
405388
</property>
406389
</widget>
407390
</item>
408-
<item row="1" column="1" colspan="2">
391+
<item row="0" column="1" colspan="2">
409392
<layout class="QHBoxLayout" name="horizontalLayout_2">
410393
<item>
411394
<widget class="QLineEdit" name="leEditForm"/>
@@ -419,60 +402,54 @@
419402
</item>
420403
</layout>
421404
</item>
422-
<item row="1" column="3">
405+
<item row="0" column="3">
423406
<widget class="QPushButton" name="pbnIndex">
424407
<property name="text">
425408
<string>Create Spatial Index</string>
426409
</property>
427410
</widget>
428411
</item>
429-
<item row="4" column="0" colspan="3">
430-
<widget class="QLineEdit" name="leSpatialRefSys">
431-
<property name="readOnly">
432-
<bool>true</bool>
412+
<item row="1" column="3">
413+
<widget class="QPushButton" name="pbnUpdateExtents">
414+
<property name="text">
415+
<string>Update Extents</string>
433416
</property>
434417
</widget>
435418
</item>
436-
<item row="4" column="3">
437-
<widget class="QPushButton" name="pbnChangeSpatialRefSys">
438-
<property name="toolTip">
439-
<string>Specify the coordinate reference system of the layer's geometry.</string>
440-
</property>
441-
<property name="whatsThis">
442-
<string>Specify the coordinate reference system of the layer's geometry.</string>
443-
</property>
419+
<item row="1" column="1" colspan="2">
420+
<widget class="QLineEdit" name="leEditFormInit"/>
421+
</item>
422+
<item row="1" column="0">
423+
<widget class="QLabel" name="label_3">
444424
<property name="text">
445-
<string>Specify CRS</string>
425+
<string>Init function</string>
446426
</property>
447427
</widget>
448428
</item>
449-
<item row="0" column="2">
450-
<widget class="QLabel" name="textLabel2">
451-
<property name="toolTip">
452-
<string>Display field for the Identify Results dialog box</string>
453-
</property>
454-
<property name="whatsThis">
455-
<string>This sets the display field for the Identify Results dialog box</string>
456-
</property>
429+
<item row="2" column="0">
430+
<widget class="QLabel" name="label_4">
457431
<property name="text">
458-
<string>Display field</string>
432+
<string>CRS</string>
459433
</property>
460434
</widget>
461435
</item>
462-
<item row="2" column="3">
463-
<widget class="QPushButton" name="pbnUpdateExtents">
464-
<property name="text">
465-
<string>Update Extents</string>
436+
<item row="2" column="1">
437+
<widget class="QLineEdit" name="leSpatialRefSys">
438+
<property name="readOnly">
439+
<bool>true</bool>
466440
</property>
467441
</widget>
468442
</item>
469-
<item row="2" column="1" colspan="2">
470-
<widget class="QLineEdit" name="leEditFormInit"/>
471-
</item>
472-
<item row="2" column="0">
473-
<widget class="QLabel" name="label_3">
443+
<item row="2" column="3">
444+
<widget class="QPushButton" name="pbnChangeSpatialRefSys">
445+
<property name="toolTip">
446+
<string>Specify the coordinate reference system of the layer's geometry.</string>
447+
</property>
448+
<property name="whatsThis">
449+
<string>Specify the coordinate reference system of the layer's geometry.</string>
450+
</property>
474451
<property name="text">
475-
<string>Init function</string>
452+
<string>Specify CRS</string>
476453
</property>
477454
</widget>
478455
</item>
@@ -590,6 +567,135 @@
590567
</item>
591568
</layout>
592569
</widget>
570+
<widget class="QWidget" name="tab">
571+
<attribute name="icon">
572+
<iconset resource="../../images/images.qrc">
573+
<normaloff>:/images/themes/gis/mActionMapTips.png</normaloff>:/images/themes/gis/mActionMapTips.png</iconset>
574+
</attribute>
575+
<attribute name="title">
576+
<string>Display</string>
577+
</attribute>
578+
<layout class="QFormLayout" name="formLayout_2">
579+
<property name="fieldGrowthPolicy">
580+
<enum>QFormLayout::AllNonFixedFieldsGrow</enum>
581+
</property>
582+
<item row="0" column="0">
583+
<widget class="QLabel" name="textLabel3">
584+
<property name="text">
585+
<string>Legend display text</string>
586+
</property>
587+
</widget>
588+
</item>
589+
<item row="0" column="1">
590+
<widget class="QLineEdit" name="txtDisplayName"/>
591+
</item>
592+
<item row="1" column="0" colspan="2">
593+
<widget class="QGroupBox" name="groupBox">
594+
<property name="title">
595+
<string>Map Tip display text</string>
596+
</property>
597+
<layout class="QFormLayout" name="formLayout_3">
598+
<item row="0" column="0">
599+
<widget class="QRadioButton" name="fieldComboRadio">
600+
<property name="text">
601+
<string>Field</string>
602+
</property>
603+
</widget>
604+
</item>
605+
<item row="0" column="1">
606+
<widget class="QComboBox" name="displayFieldComboBox">
607+
<property name="enabled">
608+
<bool>false</bool>
609+
</property>
610+
</widget>
611+
</item>
612+
<item row="1" column="0">
613+
<widget class="QRadioButton" name="htmlRadio">
614+
<property name="text">
615+
<string>HTML</string>
616+
</property>
617+
</widget>
618+
</item>
619+
<item row="1" column="1">
620+
<widget class="QTextEdit" name="htmlMapTip">
621+
<property name="enabled">
622+
<bool>false</bool>
623+
</property>
624+
</widget>
625+
</item>
626+
<item row="2" column="1">
627+
<layout class="QHBoxLayout" name="horizontalLayout_14">
628+
<item>
629+
<widget class="QPushButton" name="insertExpressionButton">
630+
<property name="enabled">
631+
<bool>false</bool>
632+
</property>
633+
<property name="sizePolicy">
634+
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
635+
<horstretch>0</horstretch>
636+
<verstretch>0</verstretch>
637+
</sizepolicy>
638+
</property>
639+
<property name="toolTip">
640+
<string>Inserts an expression into the action</string>
641+
</property>
642+
<property name="text">
643+
<string>Insert expression...</string>
644+
</property>
645+
</widget>
646+
</item>
647+
<item>
648+
<spacer name="horizontalSpacer_4">
649+
<property name="orientation">
650+
<enum>Qt::Horizontal</enum>
651+
</property>
652+
<property name="sizeType">
653+
<enum>QSizePolicy::Fixed</enum>
654+
</property>
655+
<property name="sizeHint" stdset="0">
656+
<size>
657+
<width>40</width>
658+
<height>20</height>
659+
</size>
660+
</property>
661+
</spacer>
662+
</item>
663+
<item>
664+
<widget class="QComboBox" name="fieldComboBox">
665+
<property name="enabled">
666+
<bool>false</bool>
667+
</property>
668+
<property name="toolTip">
669+
<string>The valid attribute names for this layer</string>
670+
</property>
671+
</widget>
672+
</item>
673+
<item>
674+
<widget class="QPushButton" name="insertFieldButton">
675+
<property name="enabled">
676+
<bool>false</bool>
677+
</property>
678+
<property name="sizePolicy">
679+
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
680+
<horstretch>0</horstretch>
681+
<verstretch>0</verstretch>
682+
</sizepolicy>
683+
</property>
684+
<property name="toolTip">
685+
<string>Inserts the selected field into the action</string>
686+
</property>
687+
<property name="text">
688+
<string>Insert field</string>
689+
</property>
690+
</widget>
691+
</item>
692+
</layout>
693+
</item>
694+
</layout>
695+
</widget>
696+
</item>
697+
</layout>
698+
</widget>
593699
<widget class="QWidget" name="tabWidgetPage5">
594700
<attribute name="icon">
595701
<iconset resource="../../images/images.qrc">
@@ -615,8 +721,8 @@
615721
<rect>
616722
<x>0</x>
617723
<y>0</y>
618-
<width>733</width>
619-
<height>497</height>
724+
<width>722</width>
725+
<height>530</height>
620726
</rect>
621727
</property>
622728
<layout class="QVBoxLayout" name="verticalLayout">
@@ -727,8 +833,8 @@
727833
<rect>
728834
<x>0</x>
729835
<y>0</y>
730-
<width>733</width>
731-
<height>497</height>
836+
<width>722</width>
837+
<height>530</height>
732838
</rect>
733839
</property>
734840
<layout class="QGridLayout" name="gridLayout_17">
@@ -820,8 +926,8 @@
820926
<rect>
821927
<x>0</x>
822928
<y>0</y>
823-
<width>713</width>
824-
<height>637</height>
929+
<width>704</width>
930+
<height>627</height>
825931
</rect>
826932
</property>
827933
<layout class="QGridLayout" name="gridLayout_16">
@@ -1333,9 +1439,6 @@
13331439
</customwidget>
13341440
</customwidgets>
13351441
<tabstops>
1336-
<tabstop>txtDisplayName</tabstop>
1337-
<tabstop>displayFieldComboBox</tabstop>
1338-
<tabstop>leSpatialRefSys</tabstop>
13391442
<tabstop>pbnIndex</tabstop>
13401443
<tabstop>leMinimumScale</tabstop>
13411444
<tabstop>leMaximumScale</tabstop>
@@ -1345,5 +1448,86 @@
13451448
<resources>
13461449
<include location="../../images/images.qrc"/>
13471450
</resources>
1348-
<connections/>
1451+
<connections>
1452+
<connection>
1453+
<sender>fieldComboRadio</sender>
1454+
<signal>toggled(bool)</signal>
1455+
<receiver>displayFieldComboBox</receiver>
1456+
<slot>setEnabled(bool)</slot>
1457+
<hints>
1458+
<hint type="sourcelabel">
1459+
<x>69</x>
1460+
<y>128</y>
1461+
</hint>
1462+
<hint type="destinationlabel">
1463+
<x>178</x>
1464+
<y>128</y>
1465+
</hint>
1466+
</hints>
1467+
</connection>
1468+
<connection>
1469+
<sender>htmlRadio</sender>
1470+
<signal>toggled(bool)</signal>
1471+
<receiver>htmlMapTip</receiver>
1472+
<slot>setEnabled(bool)</slot>
1473+
<hints>
1474+
<hint type="sourcelabel">
1475+
<x>57</x>
1476+
<y>155</y>
1477+
</hint>
1478+
<hint type="destinationlabel">
1479+
<x>149</x>
1480+
<y>183</y>
1481+
</hint>
1482+
</hints>
1483+
</connection>
1484+
<connection>
1485+
<sender>htmlRadio</sender>
1486+
<signal>toggled(bool)</signal>
1487+
<receiver>insertFieldButton</receiver>
1488+
<slot>setEnabled(bool)</slot>
1489+
<hints>
1490+
<hint type="sourcelabel">
1491+
<x>83</x>
1492+
<y>152</y>
1493+
</hint>
1494+
<hint type="destinationlabel">
1495+
<x>660</x>
1496+
<y>350</y>
1497+
</hint>
1498+
</hints>
1499+
</connection>
1500+
<connection>
1501+
<sender>htmlRadio</sender>
1502+
<signal>toggled(bool)</signal>
1503+
<receiver>fieldComboBox</receiver>
1504+
<slot>setEnabled(bool)</slot>
1505+
<hints>
1506+
<hint type="sourcelabel">
1507+
<x>51</x>
1508+
<y>157</y>
1509+
</hint>
1510+
<hint type="destinationlabel">
1511+
<x>306</x>
1512+
<y>361</y>
1513+
</hint>
1514+
</hints>
1515+
</connection>
1516+
<connection>
1517+
<sender>htmlRadio</sender>
1518+
<signal>toggled(bool)</signal>
1519+
<receiver>insertExpressionButton</receiver>
1520+
<slot>setEnabled(bool)</slot>
1521+
<hints>
1522+
<hint type="sourcelabel">
1523+
<x>73</x>
1524+
<y>151</y>
1525+
</hint>
1526+
<hint type="destinationlabel">
1527+
<x>142</x>
1528+
<y>349</y>
1529+
</hint>
1530+
</hints>
1531+
</connection>
1532+
</connections>
13491533
</ui>

2 commit comments

Comments
 (2)

AndrewM- commented on Feb 28, 2014

@AndrewM-

Hi Nathan,
I cannot get the img display working. Can you please document the types of image paths that map tips can support. I have tried about a dozen variations on image URLs for displaying images in maptips without success. I am using GGIS 2.2 on a Win64 system. The image addresses that I would like to display look like this - 'H:\Photos\NonWork\2012-04-20_RedCliffPoint\Thumbs\P1190276.JPG'.

AndrewM- commented on Mar 3, 2014

@AndrewM-

Correction, the maptips do work with images e.g.[img src=''H:\Photos\NonWork\2012-04-20_RedCliffPoint\Thumbs\P1190276.JPG"/] with angle brakets. However if you see text instead of an image, then the problem is probably text before or after the line with the image link. I found that putting
tags on either side of the above line to separate the image from other content made things work.

Please sign in to comment.