-
-
Notifications
You must be signed in to change notification settings - Fork 3k
/
qgslegend.h
612 lines (475 loc) · 22.8 KB
/
qgslegend.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
/***************************************************************************
qgslegend.h - description
-------------------
begin : Sun Jul 28 2002
copyright : (C) 2002 by Gary E.Sherman
email : sherman at mrcc dot com
Romans 3:23=>Romans 6:23=>Romans 10:9,10=>Romans 12
***************************************************************************/
/***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/
#ifndef QGSLEGEND_H
#define QGSLEGEND_H
#include <QTreeWidget>
#include <QPair>
#include <set>
#include "qgslegenditem.h"
class QgsLegendGroup;
class QgsLegendLayer;
class QgsMapLayer;
class QgsMapCanvas;
class QDomDocument;
class QDomElement;
class QDomNode;
class QMouseEvent;
class QTreeWidgetItem;
class QgsCoordinateReferenceSystem;
class QgsMapCanvasLayer;
#include "qgsmaplayer.h"
//Information about relationship between groups and layers
//key: group name (or null strings for single layers without groups)
//value: containter with layer ids contained in the group
typedef QPair< QString, QList<QString> > GroupLayerInfo;
struct DrawingOrderInfo
{
QString name;
QString id;
bool checked;
bool embeddedGroup;
};
struct LegendLayerAction
{
LegendLayerAction( QAction* a, QString m, QString i, bool all )
: action( a ), menu( m ), id( i ), allLayers( all ) {}
QAction* action;
QString menu;
QString id;
bool allLayers;
QList<QgsMapLayer*> layers;
};
/**
\class QgsLegend
\brief A Legend treeview for QGIS
Map legend is a specialised QListView designed to show groups of map layers,
map layers, and the map layer members, properties and symbols for each layer.
The legend supports simple operations such as displaying an ordered list of
layers in the current canvas, and complex operations such as drag/dropping
layer symbologies and properties between layers.
There are a variety of different items that can appear in a QgsLegend. All
items added to a QgsLegend should be inherited from QgsLegendItem as this
will ensure that they can perform legend specific tasks such as seeing if
dropping of other items onto them is allowed, returning their type etc.
The following types are defined:
<ul>
<li>QgsLegendGroup - a group folder for many layers (can include other groups)</li>
<li>QgsLegendLayer - a layer that contains one or more files associated with it.
allowing more than one file lets you create virtual layers where
1 or more files can share the same symbology and properties
and be treated as they are one layer for things such as hiding /
showing, scale dependent visibility etc.</li>
<li>QgsLegendSymbologyItem - a class break (vector) or pallette entry (raster) etc.
Double clicking on a symbology item will let you change
the properties for only that specific item. Can only exist
inside a legend layer.</li>
</ul>
@note Additional group types may be defined in the future to accommodate WMS, PostGIS etc layers.
@author Gary E.Sherman, Tim Sutton, Marco Hugentobler and Jens Oberender
*/
class QgsLegend : public QTreeWidget
{
Q_OBJECT
private:
// Moved here to match access of declaration later in file.
// Previous location raised a warning in msvc as the forward
// declaration was public while the definition was private
class QgsLegendPixmaps;
public:
/*! Constructor.
* @param qgis_app link to qgisapp
* @param theParent An optional parent widget
* @param theName An optional name for the widget
*/
QgsLegend( QgsMapCanvas *canvas, QWidget * parent = 0, const char *name = 0 );
//! Destructor
~QgsLegend();
/** Returns QgsLegendLayer accosiated with given item */
QgsLegendLayer* legendLayerForItem( QTreeWidgetItem* item );
/** Returns QgsLegendLayer associated with current layer */
QgsLegendLayer* currentLegendLayer();
/*!Returns the current layer if the current item is a QgsLegendLayer.
If the current item is a QgsLegendLayer, its first maplayer is returned.
Else, 0 is returned.*/
QgsMapLayer* currentLayer();
/** Returns the currently selected layers of QgsLegendLayers.
* @param inDrawOrder return layers in drawing order (added in 1.9)
* @returns list of layers, else an empty list */
QList<QgsMapLayer *> selectedLayers( bool inDrawOrder = false );
/** Returns true if layer selection has any editable vector layers
* @param modified return true of any of layers is also modified
* @note added in 1.9 */
bool selectedLayersEditable( bool modified = false );
/*!Returns all layers loaded in QgsMapCanvas in drawing order
Else, an empty list is returned.*/
QList<QgsMapLayer *> layers();
//!Return all layers in drawing order
QList<QgsLegendLayer *> legendLayers();
//!Return info about layers and embedded groups in drawing order
QList<DrawingOrderInfo> drawingOrder();
QStringList drawingOrderLayers();
void setDrawingOrder( QList<QgsMapLayer *> );
void setDrawingOrder( const QList<DrawingOrderInfo>& order );
/*!set the current layer
returns true if the layer exists, false otherwise*/
bool setCurrentLayer( QgsMapLayer *layer );
/**Writes the content of the legend to a project file*/
bool writeXML( QDomNode & layer_node, QDomDocument & document );
/**Restores the legend from a project file*/
bool readXML( QDomNode& legendnode );
/**Returns true, if the y-coordinate is >= the center of the item*/
bool yCoordAboveCenter( QgsLegendItem* it, int ycoord );
/**Returns true, if the item at index is a QgsLegendGroup*/
bool isLegendGroup( const QModelIndex &index );
/**Returns a string list of groups*/
QStringList groups();
//! Return the relationship between groups and layers in the legend
QList< GroupLayerInfo > groupLayerRelationship();
/**Returns the first item in the hierarchy*/
QTreeWidgetItem* firstItem();
/**Returns the next item (next sibling or next item on level above)*/
QTreeWidgetItem* nextItem( QTreeWidgetItem* item );
/**Returns the next sibling of an item or 0 if there is none*/
QTreeWidgetItem* nextSibling( QTreeWidgetItem* item );
/**Returns the previous sibling of an item or 0 if there is none*/
QTreeWidgetItem* previousSibling( QTreeWidgetItem* item );
/**Finds the next dom node. This function is used by QgsLegend, but probably its not a good place here*/
static QDomNode nextDomNode( const QDomNode& theNode );
/**Inserts an item into another one. Stores the item specific settings of the moved item (and its subitems)
and applies it afterwards again*/
void insertItem( QTreeWidgetItem* move, QTreeWidgetItem* into );
/**Moves an item after another one. Stores the item specific settings of the moved item (and its subitems)
and applies it afterwards again*/
void moveItem( QTreeWidgetItem* move, QTreeWidgetItem* after );
/**Removes an item from the legend. This is e.g. necessary before shifting it to another place*/
void removeItem( QTreeWidgetItem* item );
/**Returns the ids of the visible layers contained in this legend. The order is bottom->top*/
QStringList layerIDs();
/**Updates layer set of map canvas*/
void updateMapCanvasLayerSet();
/**Show/remove all layer in/from overview*/
void enableOverviewModeAllLayers( bool isInOverview );
/**Adds an entry to mPixmapWidthValues*/
void addPixmapWidthValue( int width );
/**Adds an entry to mPixmapHeightValues*/
void addPixmapHeightValue( int height );
/**Removes an entry from mPixmapWidthValues*/
void removePixmapWidthValue( int width );
/**Removes an entry from mPixmapHeightValues*/
void removePixmapHeightValue( int height );
/**Returns structure with legend pixmaps*/
QgsLegendPixmaps& pixmaps() { return mPixmaps; }
/**Returns a layers check state*/
Qt::CheckState layerCheckState( QgsMapLayer * layer );
/**Returns a layers expanded state*/
bool layerIsExpanded( QgsMapLayer * layer );
/**Add group from other project file. Returns a pointer to the new group in case of success or 0 in case of error*/
QgsLegendGroup* addEmbeddedGroup( const QString& groupName, const QString& projectFilePath, QgsLegendItem* parent = 0 );
/** return canvas */
QgsMapCanvas *canvas() { return mMapCanvas; }
/**Returns the legend layer to which a map layer belongs to*/
QgsLegendLayer* findLegendLayer( const QString& layerKey );
/**Returns the legend layer to which a map layer belongs to*/
QgsLegendLayer* findLegendLayer( const QgsMapLayer *layer );
/**Returns legend group by group name and project path (empty for not-embedded groups)*/
QgsLegendGroup* findLegendGroup( const QString& name, const QString& projectPath = QString() );
public slots:
/*!Adds a new layer group with the maplayers to the canvas*/
void addLayers( QList<QgsMapLayer *> );
/** Adds a new layer group with the maplayer to the canvas
* @note Deprecated since 1.8 - use addLayers rather
*/
void addLayer( QgsMapLayer * layer );
void setLayerVisible( QgsMapLayer * layer, bool visible );
/**Updates symbology items for a layer*/
void refreshLayerSymbology( QString key, bool expandItem = true );
void refreshLayerSymbology( QString key, QgsLegendItem::Expansion expandItem );
/*!
* Slot called to clear the tree of all items
* @note Usually connected to a QgsMapCanvas that will ask its legend to clear itself.
* @return void
*/
void removeAll();
/*!
* Called when the user wishes to toggle on or off all of the layers in
* the legend, and in the map.
* @return void
*/
void setLayersVisible( bool visible );
/*!
* Slot called when user wishes to add a new empty layer group to the legend.
* If a the legend has a currentItem() then the new group will be nested into it
* The user will be prompted for the name of the newly added group.
* @param name name of the new group
* @param expand expand the group
* @return index of inserted group
*/
int addGroupToCurrentItem( QString name = QString(), bool expand = true );
/*!
* Slot called when user wishes to add a new empty layer group to the legend.
* The user will be prompted for the name of the newly added group.
* @param name name of the new group
* @param expand expand the group
* @return index of inserted group
*/
int addGroup( QString name = QString(), bool expand = true, QTreeWidgetItem* parent = 0 );
/*!
* Slot called when user wishes to add a new empty layer group to the legend.
* All parameter are mandatory to be used to programatically nest a new group
* @param name name of the new group
* @param expand expand the group
* @return index of inserted group
*/
int addGroup( QString name, bool expand, int parentIndex );
/*!
* Removes all groups with the given name.
* @param name name of the groups to remove
* @return void
*/
void removeGroup( int groupIndex );
/*!
* @deprecated - use removeLayers() rather
*/
void removeLayer( QString );
/** Remove one or more layers from the legend */
void removeLayers( QStringList theLayers );
/** called to read legend settings from project */
void readProject( const QDomDocument & );
/** called to write legend settings to project */
void writeProject( QDomDocument & );
/*!
* Moves a layer to a group.
* @param ml the maplayer to move
* @param groupIndex index of group
* @note keep in mind that the group's index changes, if the moved layer is above the group.
*/
void moveLayer( QgsMapLayer* ml, int groupIndex );
/**Toggle show in overview for current layer*/
void legendLayerShowInOverview();
/**Zooms to extent of the current legend layer (considers there may be several
legend layer files*/
void legendLayerZoom();
/**Zooms so that the pixels of the raster layer occupies exactly one screen pixel.
Only works on raster layers*/
void legendLayerZoomNative();
/**Stretches the raster layer, if stretching is active, based on the min and max of the current extent.
Only workds on raster layers*/
void legendLayerStretchUsingCurrentExtent();
/**Updates check states when the map canvas layer set is changed */
void refreshCheckStates();
/** Remove selected layers */
void removeSelectedLayers();
/** Set CRS for selected layers */
void setCRSForSelectedLayers( const QgsCoordinateReferenceSystem &crs );
/** Update drawing order */
bool updateDrawingOrder();
/** Update drawing order */
void setUpdateDrawingOrder( bool updateDrawingOrder );
/** Update drawing order */
void unsetUpdateDrawingOrder( bool dontUpdateDrawingOrder ) { setUpdateDrawingOrder( !dontUpdateDrawingOrder ); }
/** Create a new group for the selected items **/
void groupSelectedLayers();
void addLegendLayerAction( QAction* action, QString menu, QString id,
QgsMapLayer::LayerType type, bool allLayers );
bool removeLegendLayerAction( QAction* action );
void addLegendLayerActionForLayer( QAction* action, QgsMapLayer* layer );
void removeLegendLayerActionsForLayer( QgsMapLayer* layer );
QList< LegendLayerAction > legendLayerActions( QgsMapLayer::LayerType type ) const;
/** Slot to update styles for legend items, since
* QgsLegend::item doesn't work in app stylesheet for individual legend types
* @note added in QGIS 1.9
*/
void updateLegendItemStyles();
/** Slot to update symbology for legend items
* @note added in QGIS 1.9
*/
void updateLegendItemSymbologies();
protected:
/*!Event handler for mouse movements.
* Mainly intended so handle cases where user is dragging and dropping
* items into or out of groups, or is reordering layers.
* @note Overrides method of the same name in the QListView class.
* @return void
*/
void mouseMoveEvent( QMouseEvent * e );
/*!
* Event handler for buton mouse presses.
* Mainly intended so handle cases where user is dragging and dropping
* items into or out of groups, or is reordering layers.
* @note Overrides method of the same name in the QListView class.
* @return void
*/
void mousePressEvent( QMouseEvent * e );
/*!
* Event handler for mouse button releases.
* Mainly intended so handle cases where user is dragging and dropping
* items into or out of groups, or is reordering layers. Each sublass of
* QgsLegendItem has an accept method that defines behaviour rules for
* whether another QgsLegendItem child instance can be dropped onto it.
* <h1>Behaviour rules for dropped legend items</h1>
* <ul>
* <li> Symbology groups, properies groups and layers groups can only be dropped
* onto QgsLegendLayer nodes. </li>
* <li>Only QgsLegendGroup and QgsLegendLayer can be top level items in the view</li>
* <li>Groups can be nested by dropping them into each other,</li>
* <li>Each group can have one or more layers</li>
* <li>Layers can be ordered by dragging them above or below another layer.</li>
* <li>The order for QgsLegendLayerGroup
* is predefined to sort in that order.</li>
* </ul>
* @note Overrides method of the same name in the QListView class.
* @return void
*/
void mouseReleaseEvent( QMouseEvent * e );
void mouseDoubleClickEvent( QMouseEvent* e );
/**Checks mPixmapWidthValues and mPixmapHeightValues and sets a new icon size if necessary*/
void adjustIconSize();
/**Initialize pixmaps - called when QgsLegend is constructed */
void initPixmaps();
/**This function compares the layer order before a drag with the current layer ordering and triggers a canvas repaint if it has changed*/
bool checkLayerOrderUpdate();
// mouse is pressed
bool mMousePressedFlag;
// position of mouse when it is pressed at the start of a drag event.
QPoint mLastPressPos;
// layer our prior to move
QStringList mLayersPriorToMove;
// keep track of the items being dragged
QList< QTreeWidgetItem * > mItemsBeingMoved;
// The target that the mouse is over when dragging
QTreeWidgetItem *mDropTarget;
// The action when the mouse is released
enum { BEFORE, INSERT, AFTER } mDropAction;
/** Groups defined in other project files.
Key: group name, value: absolute path to project file*/
QHash< QString, QString > mEmbeddedGroups;
/** Hide the line that indicates insertion position */
void hideLine();
/** Show the line that indicates insertion position */
void showLine( int y, int left );
/** Update the widget with latest changes immediately */
void updateLineWidget();
/** Returns the last visible item in the tree widget */
QTreeWidgetItem *lastVisibleItem();
/** read layer settings from XML element and add item */
QgsLegendLayer* readLayerFromXML( QDomElement& childelem, bool& isOpen );
private slots:
/**Calls 'handleRightClickEvent' on the item*/
void handleRightClickEvent( QTreeWidgetItem* item, const QPoint& position );
/**Removes the current legend group*/
void legendGroupRemove();
/**Set the CRS of the current legend group*/
void legendGroupSetCRS();
/**Removes a legend group and its layers*/
void removeGroup( QgsLegendGroup * lg );
/**Removes a legend group and its layers*/
void setGroupCRS( QgsLegendGroup * lg, const QgsCoordinateReferenceSystem &crs );
/**Sets all listview items to open*/
void expandAll();
/**Sets all listview items to closed*/
void collapseAll();
/** toogle update drawing order */
void toggleDrawingOrderUpdate();
void handleItemChange( QTreeWidgetItem* item, int column );
void handleCloseEditor( QWidget * editor, QAbstractItemDelegate::EndEditHint hint );
/** delegates current layer to map canvas */
void handleCurrentItemChanged( QTreeWidgetItem* current, QTreeWidgetItem* previous );
/**Calls openPersistentEditor for the current item*/
void openEditor();
/**Removes the current item and inserts it as a toplevel item at the end of the legend*/
void makeToTopLevelItem();
private:
bool readXML( QgsLegendGroup *parent, const QDomNode &node );
bool writeXML( QList<QTreeWidgetItem *> items, QDomNode &node, QDomDocument &document );
QList<QgsMapCanvasLayer> canvasLayers();
/*! Prevent the copying of QgsLegends
* @todo See if this is really required - we may want multiple map, canvas and
legend support at some stage in the future.
*/
QgsLegend( QgsLegend const & );
/*!
* Prevent the copying of QgsLegends
* @todo See if this is really required - we may want multiple map, canvas and
legend support at some stage in the future.
*/
QgsLegend & operator=( QgsLegend const & );
/*!
* A function to determine how far down in the list an item is (starting with one for the first Item).
*If the item is not in the legend, -1 is returned
* @see mItemBeingMovedOrigPos
*/
int getItemPos( QTreeWidgetItem* item );
/**Returns true if the item is a group embedde from another project*/
bool groupEmbedded( QTreeWidgetItem* item ) const;
/**Returns true if the parent group is embedded from another project*/
bool parentGroupEmbedded( QTreeWidgetItem* item ) const;
/**Pointer to the main canvas. Used for requiring repaints in case of legend changes*/
QgsMapCanvas* mMapCanvas;
/**Stores the width values of the LegendSymbologyItem pixmaps. The purpose of this is that the legend may automatically change
the global IconWidth when items are added or removed*/
std::multiset<int> mPixmapWidthValues;
/**Stores the width values of the LegendSymbologyItem pixmaps. The purpose of this is that the legend may automatically change
the global IconWidth when items are added or removed*/
std::multiset<int> mPixmapHeightValues;
/**QgsLegend does not set the icon with/height to values lower than the minimum icon size*/
QSize mMinimumIconSize;
bool mChanging;
/** moving the layers in the hierarchy also changes the drawing order */
bool mUpdateDrawingOrder;
/** structure which holds pixmap which are used in legend */
class QgsLegendPixmaps
{
public:
//! Pixmap which is shown by default
QPixmap mOriginalPixmap;
//! Pixmap to show a bogus vertex was encoutnered in this layer (applies to vector layers only)
QPixmap mProjectionErrorPixmap;
//! Pixmap to show if this layer is represented in overview or now
QPixmap mInOverviewPixmap;
//! Pixmap to show it this layer has currently editing turned on
QPixmap mEditablePixmap;
} mPixmaps;
//! Widget that holds the indicator line
QWidget *mInsertionLine;
QMap< QgsMapLayer::LayerType, QList< LegendLayerAction > > mLegendLayerActionMap;
#ifdef QGISDEBUG
void showItem( QString msg, QTreeWidgetItem *item );
#endif
void updateGroupCheckStates( QTreeWidgetItem *item );
bool verifyDrawingOrder();
/*!
* Check if current LegendItem belongs to a WMS layer
* @param item LegendItem to check if belongs to a WMS layer
* @return QImage A valid Legend image if belongs to WMS otherwise QImage()
*/
QImage getWmsLegendPixmap( QTreeWidgetItem *item );
//! popup QFrame containing WMS getLegendGraphic pixmap
QFrame *mGetLegendGraphicPopup;
signals:
void itemAdded( QModelIndex index );
void itemMoved( QModelIndex oldIndex, QModelIndex newIndex );
void itemMovedGroup( QgsLegendItem *item, int newGroupIndex ); // should we add oldGroup?
void itemRemoved( ); // should we add an argument?
void zOrderChanged();
void invisibleLayerRemoved();
void updateDrawingOrderChecked( bool );
void updateDrawingOrderUnchecked( bool );
//! Emitted whenever current (selected) layer changes
// the pointer to layer can be null if no layer is selected
void currentLayerChanged( QgsMapLayer * layer );
};
#endif