Skip to content

Commit fc7ca7b

Browse files
author
mhugent
committed
checkbox for legend groups
git-svn-id: http://svn.osgeo.org/qgis/trunk@4927 c8812cc2-4d05-0410-92ff-de0c093fc19c
1 parent 078c75a commit fc7ca7b

10 files changed

+287
-55
lines changed

qgis.dtd

+2-2
Original file line numberDiff line numberDiff line change
@@ -120,9 +120,9 @@ outlinecolor,outlinestyle,outlinewidth,fillcolor,fillpattern) >
120120
<!ELEMENT legend (legendgroup* | legendlayer*) >
121121
<!ATTLIST legend open (1|0|true|false) "false"> #open or closed
122122
<!ELEMENT legendgroup (legendlayer*) >
123-
<!ATTLIST legendgroup open (1|0|true|false) "false" name CDATA> #open or closed
123+
<!ATTLIST legendgroup open (1|0|true|false) "false" name CDATA checked (Qt::Checked|Qt::Unchecked|Qt::PartiallyChecked) "Qt::Checked">
124124
<!ELEMENT legendlayer (legendsymbologyitem+, legendlayerfilegroup>
125-
<!ATTLIST legendlayer open (1|0|true|false) "false" checked (Qt::Checked|Qt::Unchecked|Qt::PartiallyChecked) "Qt::Checked"> #open or closed
125+
<!ATTLIST legendlayer open (1|0|true|false) "false" checked (Qt::Checked|Qt::Unchecked|Qt::PartiallyChecked) "Qt::Checked">
126126
<!ELEMENT legendlayerfilegroup (legendlayerfile*) >
127127
<!ATTLIST legendlayerfilegroup open (1|0|true|false) "false" > #open or closed
128128
<!ATTLIST legendlayerfilegroup hidden(1|0|true|false) "false"> #hidden or shown

src/legend/qgslegend.cpp

+186-6
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,7 @@ QgsLegend::~QgsLegend()
8484
void QgsLegend::addGroup()
8585
{
8686
QgsLegendGroup* group = new QgsLegendGroup(this, tr("group"));
87+
mStateOfCheckBoxes.insert(std::make_pair(group, Qt::Checked)); //insert the check state into the map to query for changes later
8788
setExpanded(indexFromItem(group), true);
8889
}
8990

@@ -224,8 +225,7 @@ void QgsLegend::mouseMoveEvent(QMouseEvent * e)
224225
setCursor( QCursor(Qt::PointingHandCursor) );
225226
if(origin->parent() != dest)
226227
{
227-
removeItem(origin);
228-
dest->insert(origin, false);
228+
insertItem(origin, dest);
229229
setCurrentItem(origin);
230230
}
231231
}
@@ -438,7 +438,7 @@ int QgsLegend::getItemPos(QTreeWidgetItem* item)
438438

439439
void QgsLegend::addLayer( QgsMapLayer * layer )
440440
{
441-
QgsLegendLayer * llayer = new QgsLegendLayer(QString(layer->name()));
441+
QgsLegendLayer * llayer = new QgsLegendLayer(layer->name());
442442
mStateOfCheckBoxes.insert(std::make_pair(llayer, Qt::Checked)); //insert the check state into the map to query for changes later
443443
QgsLegendLayerFileGroup * llfgroup = new QgsLegendLayerFileGroup(llayer,QString("Files"));
444444
QgsLegendLayerFile * llfile = new QgsLegendLayerFile(llfgroup, QgsLegendLayerFile::nameFromLayer(layer), layer);
@@ -681,7 +681,7 @@ bool QgsLegend::writeXML( QDomNode & layer_node, QDomDocument & document )
681681
QDomElement legendpropertynode;
682682
QDomElement legendlayerfilenode;
683683
QgsLegendLayerFile* llf;
684-
Qt::CheckState cstate; //check state for legend layers
684+
Qt::CheckState cstate; //check state for legend layers and legend groups
685685

686686
QTreeWidgetItem* currentItem = firstItem();
687687
while(currentItem)
@@ -707,6 +707,19 @@ bool QgsLegend::writeXML( QDomNode & layer_node, QDomDocument & document )
707707
legendgroupnode.setAttribute("open","false");
708708
}
709709
legendgroupnode.setAttribute("name",item->text(0));
710+
cstate = item->checkState(0);
711+
if(cstate == Qt::Checked)
712+
{
713+
legendgroupnode.setAttribute("checked","Qt::Checked");
714+
}
715+
else if(cstate == Qt::Unchecked)
716+
{
717+
legendgroupnode.setAttribute("checked","Qt::Unchecked");
718+
}
719+
else if(cstate == Qt::PartiallyChecked)
720+
{
721+
legendgroupnode.setAttribute("checked","Qt::PartiallyChecked");
722+
}
710723
legendnode.appendChild(legendgroupnode);
711724
tmplegendnode = legendnode;
712725
legendnode = legendgroupnode;
@@ -837,6 +850,25 @@ bool QgsLegend::readXML(QDomNode& legendnode)
837850
{
838851
QgsLegendGroup* theGroup = new QgsLegendGroup(this, name);
839852
childelem.attribute("open") == "true" ? expandItem(theGroup) : collapseItem(theGroup);
853+
//set the checkbox of the legend group to the right state
854+
blockSignals(true);
855+
QString checked = childelem.attribute("checked");
856+
if(checked == "Qt::Checked")
857+
{
858+
theGroup->setCheckState(0, Qt::Checked);
859+
mStateOfCheckBoxes.insert(std::make_pair(theGroup, Qt::Checked));
860+
}
861+
else if(checked == "Qt::Unchecked")
862+
{
863+
theGroup->setCheckState(0, Qt::Unchecked);
864+
mStateOfCheckBoxes.insert(std::make_pair(theGroup, Qt::Unchecked));
865+
}
866+
else if(checked == "Qt::PartiallyChecked")
867+
{
868+
theGroup->setCheckState(0, Qt::PartiallyChecked);
869+
mStateOfCheckBoxes.insert(std::make_pair(theGroup, Qt::PartiallyChecked));
870+
}
871+
blockSignals(false);
840872
lastGroup = theGroup;
841873
}
842874
else if(childelem.tagName()=="legendlayer")
@@ -1121,6 +1153,20 @@ QDomNode QgsLegend::nextDomNode(const QDomNode& theNode)
11211153
}
11221154
}
11231155

1156+
void QgsLegend::insertItem(QTreeWidgetItem* move, QTreeWidgetItem* into)
1157+
{
1158+
QgsLegendItem* movedItem = dynamic_cast<QgsLegendItem*>(move);
1159+
QgsLegendItem* intoItem = dynamic_cast<QgsLegendItem*>(into);
1160+
1161+
if(movedItem && intoItem)
1162+
{
1163+
movedItem->storeAppearanceSettings();//store settings in the moved item and its children
1164+
removeItem(movedItem);
1165+
intoItem->insert(movedItem);
1166+
movedItem->restoreAppearanceSettings();//apply the settings again
1167+
}
1168+
}
1169+
11241170
void QgsLegend::moveItem(QTreeWidgetItem* move, QTreeWidgetItem* after)
11251171
{
11261172
static_cast<QgsLegendItem*>(move)->storeAppearanceSettings();//store settings in the moved item and its childern
@@ -1227,7 +1273,138 @@ void QgsLegend::changeSymbologySettings(const QString& key, const std::list< std
12271273

12281274
void QgsLegend::handleItemChange(QTreeWidgetItem* item, int row)
12291275
{
1276+
if(!item)
1277+
{
1278+
return;
1279+
}
1280+
12301281
closePersistentEditor(item, row);
1282+
1283+
std::map<QTreeWidgetItem*, Qt::CheckState>::iterator it = mStateOfCheckBoxes.find(item);
1284+
if(it != mStateOfCheckBoxes.end())
1285+
{
1286+
if(it->second != item->checkState(0)) //the checkState has changed
1287+
{
1288+
1289+
QgsLegendLayerFile* llf = dynamic_cast<QgsLegendLayerFile*>(item); //item is a layer file
1290+
if(llf)
1291+
{
1292+
if(llf->layer())
1293+
{
1294+
llf->layer()->setVisible(item->checkState(0) == Qt::Checked);
1295+
}
1296+
//update check state of the legend layer
1297+
QgsLegendLayer* ll = dynamic_cast<QgsLegendLayer*>(item->parent()->parent());
1298+
if(ll)
1299+
{
1300+
ll->updateCheckState();
1301+
mStateOfCheckBoxes[ll] = ll->checkState(0);
1302+
}
1303+
//update check state of the legend group (if any)
1304+
if(item->parent()->parent()->parent())
1305+
{
1306+
QgsLegendGroup* lg = dynamic_cast<QgsLegendGroup*>(item->parent()->parent()->parent());
1307+
if(lg)
1308+
{
1309+
lg->updateCheckState();
1310+
mStateOfCheckBoxes[lg] = lg->checkState(0);
1311+
}
1312+
}
1313+
mStateOfCheckBoxes[item] = item->checkState(0);
1314+
return;
1315+
}
1316+
1317+
std::list<QgsLegendLayerFile*> subfiles;
1318+
QgsLegendGroup* lg = dynamic_cast<QgsLegendGroup*>(item); //item is a legend group
1319+
if(lg)
1320+
{
1321+
//set all the child layer files to the new check state
1322+
subfiles = lg->legendLayerFiles();
1323+
mMapCanvas->setRenderFlag(false);
1324+
for(std::list<QgsLegendLayerFile*>::iterator iter = subfiles.begin(); iter != subfiles.end(); ++iter)
1325+
{
1326+
#ifdef QGISDEBUG
1327+
if(item->checkState(0) == Qt::Checked)
1328+
{
1329+
qWarning("item checked");
1330+
}
1331+
else if(item->checkState(0) == Qt::Unchecked)
1332+
{
1333+
qWarning("item unchecked");
1334+
}
1335+
else if(item->checkState(0) == Qt::PartiallyChecked)
1336+
{
1337+
qWarning("item partially checked");
1338+
}
1339+
#endif
1340+
blockSignals(true);
1341+
(*iter)->setCheckState(0, item->checkState(0));
1342+
blockSignals(false);
1343+
mStateOfCheckBoxes[(*iter)] = item->checkState(0);
1344+
if((*iter)->layer())
1345+
{
1346+
(*iter)->layer()->setVisible(item->checkState(0) == Qt::Checked);
1347+
}
1348+
}
1349+
1350+
//update the check states of all child legend layers
1351+
for(int i = 0; i < lg->childCount(); ++i)
1352+
{
1353+
static_cast<QgsLegendLayer*>(lg->child(i))->updateCheckState();
1354+
mStateOfCheckBoxes[lg->child(i)] = lg->child(i)->checkState(0);
1355+
}
1356+
mMapCanvas->setRenderFlag(true);
1357+
mStateOfCheckBoxes[item] = item->checkState(0);
1358+
return;
1359+
}
1360+
1361+
QgsLegendLayer* ll = dynamic_cast<QgsLegendLayer*>(item); //item is a legend layer
1362+
if(ll)
1363+
{
1364+
//set all the child layer files to the new check state
1365+
subfiles = ll->legendLayerFiles();
1366+
mMapCanvas->setRenderFlag(false);
1367+
for(std::list<QgsLegendLayerFile*>::iterator iter = subfiles.begin(); iter != subfiles.end(); ++iter)
1368+
{
1369+
blockSignals(true);
1370+
(*iter)->setCheckState(0, item->checkState(0));
1371+
blockSignals(false);
1372+
mStateOfCheckBoxes[(*iter)] = item->checkState(0);
1373+
if((*iter)->layer())
1374+
{
1375+
(*iter)->layer()->setVisible(item->checkState(0) == Qt::Checked);
1376+
}
1377+
}
1378+
if(ll->parent())
1379+
{
1380+
static_cast<QgsLegendGroup*>(ll->parent())->updateCheckState();
1381+
mStateOfCheckBoxes[ll->parent()] = ll->parent()->checkState(0);
1382+
}
1383+
mMapCanvas->setRenderFlag(true);
1384+
//update check state of the legend group
1385+
}
1386+
mStateOfCheckBoxes[item] = item->checkState(0);
1387+
}
1388+
}
1389+
#if 0
1390+
QgsLegendGroup* lg = dynamic_cast<QgsLegendGroup*>(item);
1391+
if(lg)
1392+
{
1393+
#ifdef QGISDEBUG
1394+
qWarning("detected legend group in QgsLegend::handleItemChange");
1395+
#endif
1396+
std::map<QTreeWidgetItem*, Qt::CheckState>::iterator it = mStateOfCheckBoxes.find(item);
1397+
if(it != mStateOfCheckBoxes.end())
1398+
{
1399+
if(it->second != item->checkState(0)) //the checkState has changed
1400+
{
1401+
bool checked = (item->checkState(0) == Qt::Checked);
1402+
1403+
}
1404+
}
1405+
return;
1406+
}
1407+
12311408
QgsLegendLayerFile* llf = dynamic_cast<QgsLegendLayerFile*>(item);
12321409
if(llf)
12331410
{
@@ -1244,7 +1421,7 @@ void QgsLegend::handleItemChange(QTreeWidgetItem* item, int row)
12441421
{
12451422
bool checked = (item->checkState(0) == Qt::Checked);
12461423
theLayer->setVisible(checked);
1247-
//todo: check, how the checkbox of the legendlayer needs to be updated
1424+
//check, how the checkbox of the legendlayer needs to be updated
12481425
QgsLegendLayer* ll = dynamic_cast<QgsLegendLayer*>(item->parent()->parent());
12491426
std::list<QgsLegendLayerFile*> llfiles = ll->legendLayerFiles();
12501427
std::list<QgsLegendLayerFile*>::iterator iter = llfiles.begin();
@@ -1304,6 +1481,7 @@ void QgsLegend::handleItemChange(QTreeWidgetItem* item, int row)
13041481
}
13051482
}
13061483
}
1484+
#endif //0
13071485
}
13081486

13091487
void QgsLegend::openEditor()
@@ -1317,11 +1495,13 @@ void QgsLegend::openEditor()
13171495

13181496
void QgsLegend::makeToTopLevelItem()
13191497
{
1320-
QTreeWidgetItem* theItem = currentItem();
1498+
QgsLegendItem* theItem = dynamic_cast<QgsLegendItem*>(currentItem());
13211499
if(theItem)
13221500
{
1501+
theItem->storeAppearanceSettings();
13231502
removeItem(theItem);
13241503
addTopLevelItem(theItem);
1504+
theItem->restoreAppearanceSettings();
13251505
}
13261506
}
13271507

src/legend/qgslegend.h

+6-1
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,12 @@ class QgsLegend : public QTreeWidget
124124
/**Finds the next dom node. This function is used by QgsLegend, but probably its not a good place here*/
125125
static QDomNode nextDomNode(const QDomNode& theNode);
126126

127-
/**Moves an item after another one*/
127+
/**Inserts an item into another one. Stores the item specific settings of the moved item (and its subitems)
128+
and applies it afterwards again*/
129+
void insertItem(QTreeWidgetItem* move, QTreeWidgetItem* into);
130+
131+
/**Moves an item after another one. Stores the item specific settings of the moved item (and its subitems)
132+
and applies it afterwards again*/
128133
void moveItem(QTreeWidgetItem* move, QTreeWidgetItem* after);
129134

130135
/**Removes an item from the legend. This is e.g. necessary before shifting it to another place*/

src/legend/qgslegendgroup.cpp

+51-4
Original file line numberDiff line numberDiff line change
@@ -19,30 +19,35 @@
1919
***************************************************************************/
2020
#include "qgsapplication.h"
2121
#include "qgslegendgroup.h"
22+
#include "qgslegendlayer.h"
23+
#include "qgslegendlayerfile.h"
2224
#include <QCoreApplication>
2325
#include <QIcon>
2426

2527
QgsLegendGroup::QgsLegendGroup(QTreeWidgetItem * theItem ,QString theName)
2628
: QgsLegendItem(theItem,theName)
2729
{
2830
mType=LEGEND_GROUP;
29-
setFlags(Qt::ItemIsEditable | Qt::ItemIsEnabled | Qt::ItemIsSelectable);
31+
setFlags(Qt::ItemIsEditable | Qt::ItemIsUserCheckable | Qt::ItemIsEnabled | Qt::ItemIsSelectable);
32+
setCheckState (0, Qt::Checked);
3033
QIcon myIcon(QgsApplication::themePath()+"/mActionFolder.png");
3134
setIcon(0, myIcon);
3235
}
3336
QgsLegendGroup::QgsLegendGroup(QTreeWidget* theListView, QString theString)
3437
: QgsLegendItem(theListView,theString)
3538
{
3639
mType=LEGEND_GROUP;
37-
setFlags(Qt::ItemIsEditable | Qt::ItemIsEnabled | Qt::ItemIsSelectable);
40+
setFlags(Qt::ItemIsEditable | Qt::ItemIsUserCheckable | Qt::ItemIsEnabled | Qt::ItemIsSelectable);
41+
setCheckState (0, Qt::Checked);
3842
QIcon myIcon(QgsApplication::themePath()+"/mActionFolder.png");
3943
setIcon(0, myIcon);
4044
}
4145

4246
QgsLegendGroup::QgsLegendGroup(QString name): QgsLegendItem()
4347
{
4448
mType=LEGEND_GROUP;
45-
setFlags(Qt::ItemIsEditable | Qt::ItemIsEnabled | Qt::ItemIsSelectable);
49+
setFlags(Qt::ItemIsEditable | Qt::ItemIsUserCheckable | Qt::ItemIsEnabled | Qt::ItemIsSelectable);
50+
setCheckState (0, Qt::Checked);
4651
QIcon myIcon(QgsApplication::themePath()+"/mActionFolder.png");
4752
setText(0, name);
4853
setIcon(0, myIcon);
@@ -90,10 +95,52 @@ QgsLegendItem::DRAG_ACTION QgsLegendGroup::accept(const QgsLegendItem* li) const
9095
return NO_ACTION;
9196
}
9297

93-
bool QgsLegendGroup::insert(QgsLegendItem* theItem, bool changesettings)
98+
bool QgsLegendGroup::insert(QgsLegendItem* theItem)
9499
{
95100
if(theItem->type() == LEGEND_LAYER)
96101
{
97102
addChild(theItem);
98103
}
99104
}
105+
106+
std::list<QgsLegendLayerFile*> QgsLegendGroup::legendLayerFiles()
107+
{
108+
std::list<QgsLegendLayerFile*> result;
109+
for(int i = 0; i < childCount(); ++i)
110+
{
111+
QgsLegendLayer* childItem = dynamic_cast<QgsLegendLayer*>(child(i));
112+
if(childItem)
113+
{
114+
std::list<QgsLegendLayerFile*> childList = childItem->legendLayerFiles();
115+
result.splice(result.end(), childList);
116+
}
117+
}
118+
return result;
119+
}
120+
121+
void QgsLegendGroup::updateCheckState()
122+
{
123+
std::list<QgsLegendLayerFile*> llfiles = legendLayerFiles();
124+
if(llfiles.size() < 1)
125+
{
126+
return;
127+
}
128+
129+
std::list<QgsLegendLayerFile*>::iterator iter = llfiles.begin();
130+
Qt::CheckState theState = (*iter)->checkState(0);
131+
for(; iter != llfiles.end(); ++iter)
132+
{
133+
if(theState != (*iter)->checkState(0))
134+
{
135+
theState = Qt::PartiallyChecked;
136+
break;
137+
}
138+
}
139+
140+
if(theState != checkState(0))
141+
{
142+
treeWidget()->blockSignals(true);
143+
setCheckState(0, theState);
144+
treeWidget()->blockSignals(false);
145+
}
146+
}

0 commit comments

Comments
 (0)