QGIS API Documentation  2.7.0-Master
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
qgsmapoverviewcanvas.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsmapoverviewcanvas.cpp
3  Map canvas subclassed for overview
4  -------------------
5  begin : 09/14/2005
6  copyright : (C) 2005 by Martin Dobias
7  email : won.der at centrum.sk
8  ***************************************************************************/
9 
10 /***************************************************************************
11  * *
12  * This program is free software; you can redistribute it and/or modify *
13  * it under the terms of the GNU General Public License as published by *
14  * the Free Software Foundation; either version 2 of the License, or *
15  * (at your option) any later version. *
16  * *
17  ***************************************************************************/
18 
19 #include "qgsmapcanvas.h"
20 #include "qgsmaplayer.h"
21 #include "qgsmaplayerregistry.h"
22 #include "qgsmapoverviewcanvas.h"
24 #include "qgsmaptopixel.h"
25 
26 #include <QPainter>
27 #include <QPaintEvent>
28 #include <QResizeEvent>
29 #include <QMouseEvent>
30 #include "qgslogger.h"
31 #include <limits.h>
32 
34 class QgsPanningWidget : public QWidget
35 {
36  public:
37  QgsPanningWidget( QWidget* parent )
38  : QWidget( parent )
39  {
40  setObjectName( "panningWidget" );
41  setMinimumSize( 5, 5 );
42  setAttribute( Qt::WA_NoSystemBackground );
43  }
44 
45  void resizeEvent( QResizeEvent* r )
46  {
47  QSize s = r->size();
48  QRegion reg( 0, 0, s.width(), s.height() );
49  QRegion reg2( 2, 2, s.width() - 4, s.height() - 4 );
50  QRegion reg3 = reg.subtracted( reg2 );
51  setMask( reg3 );
52  }
53 
54 
55  void paintEvent( QPaintEvent* pe )
56  {
57  Q_UNUSED( pe );
58 
59  QRect r( QPoint( 0, 0 ), size() );
60  QPainter p;
61  p.begin( this );
62  p.setPen( Qt::red );
63  p.setBrush( Qt::red );
64  p.drawRect( r );
65  p.end();
66  }
67 
68 };
69 
70 
71 
73  : QWidget( parent )
74  , mMapCanvas( mapCanvas )
75  , mJob( 0 )
76 {
77  setObjectName( "theOverviewCanvas" );
78  mPanningWidget = new QgsPanningWidget( this );
79 
81 
82  connect( mMapCanvas, SIGNAL( extentsChanged() ), this, SLOT( drawExtentRect() ) );
83 }
84 
86 {
87 }
88 
89 void QgsMapOverviewCanvas::resizeEvent( QResizeEvent* e )
90 {
91  mPixmap = QPixmap();
92 
93  mSettings.setOutputSize( e->size() );
94 
96 
97  refresh();
98 
99  QWidget::resizeEvent( e );
100 }
101 
102 void QgsMapOverviewCanvas::paintEvent( QPaintEvent* pe )
103 {
104  if ( !mPixmap.isNull() )
105  {
106  QPainter paint( this );
107  paint.drawPixmap( pe->rect().topLeft(), mPixmap, pe->rect() );
108  }
109 }
110 
111 
113 {
114  if ( !mMapCanvas ) return;
115 
116  const QgsRectangle& extent = mMapCanvas->extent();
117 
118  // show only when valid extent is set
119  if ( extent.isEmpty() || mSettings.visibleExtent().isEmpty() )
120  {
121  mPanningWidget->hide();
122  return;
123  }
124 
125  const QgsMapToPixel& cXf = mSettings.mapToPixel();
126  QgsPoint ll( extent.xMinimum(), extent.yMinimum() );
127  QgsPoint ur( extent.xMaximum(), extent.yMaximum() );
128 
129  // transform the points before drawing
130  cXf.transform( &ll );
131  cXf.transform( &ur );
132 
133 #if 0
134  // test whether panning widget should be drawn
135  bool show = false;
136  if ( ur.x() >= 0 && ur.x() < width() )
137  show = true;
138  if ( ll.x() >= 0 && ll.x() < width() )
139  show = true;
140  if ( ur.y() >= 0 && ur.y() < height() )
141  show = true;
142  if ( ll.y() >= 0 && ll.y() < height() )
143  show = true;
144  if ( !show )
145  {
146  QgsDebugMsg( "panning: extent out of overview area" );
147  mPanningWidget->hide();
148  return;
149  }
150 #endif
151 
152  // round values
153  int x1 = static_cast<int>( ur.x() + 0.5 ), x2 = static_cast<int>( ll.x() + 0.5 );
154  int y1 = static_cast<int>( ur.y() + 0.5 ), y2 = static_cast<int>( ll.y() + 0.5 );
155 
156  if ( x1 > x2 )
157  std::swap( x1, x2 );
158  if ( y1 > y2 )
159  std::swap( y1, y2 );
160 
161 #ifdef Q_WS_MAC
162  // setGeometry (Qt 4.2) is causing Mac window corruption (decorations
163  // are drawn at odd locations) if both coords are at limit. This may
164  // have something to do with Qt calculating dimensions as x2 - x1 + 1.
165  // (INT_MAX - INT_MIN + 1 is UINT_MAX + 1)
166  if ( x1 == INT_MIN && x2 == INT_MAX )
167  x1 += 1; // x2 -= 1 works too
168  if ( y1 == INT_MIN && y2 == INT_MAX )
169  y1 += 1;
170 #endif
171 
172  QRect r( x1, y1, x2 - x1 + 1, y2 - y1 + 1 );
173 
174  // allow for 5 pixel minimum widget size
175  if ( r.width() < 5 && x1 > INT_MIN + 2 ) // make sure no underflow occurs (2 is largest adjustment)
176  {
177  r.setX( r.x() - (( 5 - r.width() ) / 2 ) ); // adjust x by 1/2 the difference of calculated and min. width
178  r.setWidth( 5 );
179  }
180  if ( r.height() < 5 && y1 > INT_MIN + 2 )
181  {
182  r.setY( r.y() - (( 5 - r.height() ) / 2 ) ); // adjust y
183  r.setHeight( 5 );
184  }
185 
186  QgsDebugMsg( QString( "panning: extent to widget: [%1,%2] [%3x%4]" ).arg( x1 ).arg( y1 ).arg( r.width() ).arg( r.height() ) );
187 
188  mPanningWidget->setGeometry( r );
189  mPanningWidget->show(); // show if hidden
190 }
191 
192 
194 {
195 // if (mPanningWidget->isHidden())
196 // return;
197 
198  // set offset in panning widget if inside it
199  // for better experience with panning :)
200  if ( mPanningWidget->geometry().contains( e->pos() ) )
201  {
202  mPanningCursorOffset = e->pos() - mPanningWidget->pos();
203  }
204  else
205  {
206  // use center of the panning widget if outside
207  QSize s = mPanningWidget->size();
208  mPanningCursorOffset = QPoint( s.width() / 2, s.height() / 2 );
209  }
210  updatePanningWidget( e->pos() );
211 }
212 
213 
215 {
216 // if (mPanningWidget->isHidden())
217 // return;
218 
219  if ( e->button() == Qt::LeftButton )
220  {
221  // set new extent
222  const QgsMapToPixel& cXf = mSettings.mapToPixel();
223  QRect rect = mPanningWidget->geometry();
224 
225  QgsPoint center = cXf.toMapCoordinates( rect.center() );
226  QgsRectangle oldExtent = mMapCanvas->extent();
227  QgsRectangle ext;
228  ext.setXMinimum( center.x() - oldExtent.width() / 2 );
229  ext.setXMaximum( center.x() + oldExtent.width() / 2 );
230  ext.setYMinimum( center.y() - oldExtent.height() / 2 );
231  ext.setYMaximum( center.y() + oldExtent.height() / 2 );
232 
233  QgsDebugMsg( QString( "panning: new position: [%1,%2] [%3x%4]" ).arg( rect.left() ).arg( rect.top() ).arg( rect.width() ).arg( rect.height() ) );
234 
235  mMapCanvas->setExtent( ext );
236  mMapCanvas->refresh();
237  }
238 }
239 
240 
242 {
243  // move with panning widget if tracking cursor
244  if (( e->buttons() & Qt::LeftButton ) == Qt::LeftButton )
245  {
246  updatePanningWidget( e->pos() );
247  }
248 }
249 
250 
252 {
253 // if (mPanningWidget->isHidden())
254 // return;
255  mPanningWidget->move( pos.x() - mPanningCursorOffset.x(), pos.y() - mPanningCursorOffset.y() );
256 }
257 
259 {
261 
262  if ( !mSettings.hasValidSettings() )
263  {
264  mPixmap = QPixmap();
265  update();
266  return; // makes no sense to render anything
267  }
268 
269  if ( mJob )
270  {
271  QgsDebugMsg( "oveview - cancelling old" );
272  mJob->cancel();
273  QgsDebugMsg( "oveview - deleting old" );
274  delete mJob; // get rid of previous job (if any)
275  }
276 
277  QgsDebugMsg( "oveview - starting new" );
278 
279  // TODO: setup overview mode
281  connect( mJob, SIGNAL( finished() ), this, SLOT( mapRenderingFinished() ) );
282  mJob->start();
283 
285 
286  // schedule repaint
287  update();
288 
289  // update panning widget
290  drawExtentRect();
291 }
292 
294 {
295  QgsDebugMsg( "overview - finished" );
296  mPixmap = QPixmap::fromImage( mJob->renderedImage() );
297 
298  delete mJob;
299  mJob = 0;
300 
301  // schedule repaint
302  update();
303 }
304 
306 {
307  refresh();
308 }
309 
310 
311 void QgsMapOverviewCanvas::setBackgroundColor( const QColor& color )
312 {
313  mSettings.setBackgroundColor( color );
314 
315  // set erase color
316  QPalette palette;
317  palette.setColor( backgroundRole(), color );
318  setPalette( palette );
319 }
320 
321 void QgsMapOverviewCanvas::setLayerSet( const QStringList& layerSet )
322 {
323  QgsDebugMsg( "layerSet: " + layerSet.join( ", " ) );
324 
325  foreach ( const QString& layerID, mSettings.layers() )
326  {
327  if ( QgsMapLayer* ml = QgsMapLayerRegistry::instance()->mapLayer( layerID ) )
328  disconnect( ml, SIGNAL( repaintRequested() ), this, SLOT( layerRepaintRequested() ) );
329  }
330 
331  mSettings.setLayers( layerSet );
332 
333  foreach ( const QString& layerID, mSettings.layers() )
334  {
335  if ( QgsMapLayer* ml = QgsMapLayerRegistry::instance()->mapLayer( layerID ) )
336  connect( ml, SIGNAL( repaintRequested() ), this, SLOT( layerRepaintRequested() ) );
337  }
338 
340 }
341 
343 {
344  QgsRectangle rect;
345  if ( mSettings.hasValidSettings() )
346  rect = mSettings.fullExtent();
347  else
348  rect = mMapCanvas->fullExtent();
349 
350  // expand a bit to keep features on margin
351  rect.scale( 1.1 );
352 
353  mSettings.setExtent( rect );
354  drawExtentRect();
355 }
356 
358 {
360 }
361 
363 {
365 }
366 
368 {
369  return mSettings.layers();
370 }
QPoint mPanningCursorOffset
position of cursor inside panning widget
void setDestinationCrs(const QgsCoordinateReferenceSystem &crs)
sets destination coordinate reference system
A rectangle specified with double values.
Definition: qgsrectangle.h:35
Base class for all map layer types.
Definition: qgsmaplayer.h:48
bool isEmpty() const
test if rectangle is empty.
void mouseMoveEvent(QMouseEvent *e)
Overridden mouse move event.
void setXMaximum(double x)
Set the maximum x value.
Definition: qgsrectangle.h:163
QgsRectangle fullExtent() const
returns current extent of layer set
double yMaximum() const
Get the y maximum value (top side of rectangle)
Definition: qgsrectangle.h:188
#define QgsDebugMsg(str)
Definition: qgslogger.h:33
void resizeEvent(QResizeEvent *r)
void setExtent(const QgsRectangle &r)
Set the extent of the map canvas.
QgsMapCanvas * mMapCanvas
main map canvas - used to get/set extent
QgsMapRendererQImageJob * mJob
for rendering overview
QgsPoint transform(const QgsPoint &p) const
QgsRectangle visibleExtent() const
Return the actual extent derived from requested extent that takes takes output image size into accoun...
const QgsMapSettings & mapSettings() const
Get access to properties used for map rendering.
void refresh()
Repaints the canvas map.
void resizeEvent(QResizeEvent *e)
Overridden resize event.
const QgsMapToPixel & mapToPixel() const
void setBackgroundColor(const QColor &color)
changes background color
widget that serves as rectangle showing current extent in overview
void setLayers(const QStringList &layers)
Set list of layer IDs for map rendering.
virtual QImage renderedImage()=0
Get a preview/resulting image.
Map canvas is a class for displaying all GIS data types on a canvas.
Definition: qgsmapcanvas.h:104
double x() const
Definition: qgspoint.h:126
Enable drawing of labels on top of the map.
void setFlag(Flag flag, bool on=true)
Enable or disable a particular flag (other flags are not affected)
Perform transforms between map coordinates and device coordinates.
Definition: qgsmaptopixel.h:33
void paintEvent(QPaintEvent *pe)
double yMinimum() const
Get the y minimum value (bottom side of rectangle)
Definition: qgsrectangle.h:193
double xMaximum() const
Get the x maximum value (right side of rectangle)
Definition: qgsrectangle.h:178
QgsPanningWidget * mPanningWidget
widget for panning map in overview
bool hasValidSettings() const
Check whether the map settings are valid and can be used for rendering.
QgsMapSettings mSettings
map settings used for rendering of the overview map
const QgsCoordinateReferenceSystem & destinationCrs() const
returns CRS of destination coordinate reference system
void setYMinimum(double y)
Set the minimum y value.
Definition: qgsrectangle.h:168
QgsPanningWidget(QWidget *parent)
void paintEvent(QPaintEvent *pe)
Overridden paint event.
void refresh()
renders overview and updates panning widget
A class to represent a point.
Definition: qgspoint.h:63
QColor backgroundColor() const
Get the background color of the map.
virtual void start()=0
Start the rendering job and immediately return.
void hasCrsTransformEnabled(bool flag)
QgsPoint toMapCoordinates(int x, int y) const
Job implementation that renders everything sequentially in one thread.
void setBackgroundColor(const QColor &color)
Set the background color of the map.
QPixmap mPixmap
pixmap where the map is stored
static QgsMapLayerRegistry * instance()
Returns the instance pointer, creating the object on the first call.
void setLayerSet(const QStringList &layerSet)
updates layer set for overview
void setOutputSize(const QSize &size)
Set the size of the resulting map image.
void setYMaximum(double y)
Set the maximum y value.
Definition: qgsrectangle.h:173
void mouseReleaseEvent(QMouseEvent *e)
Overridden mouse release event.
void setExtent(const QgsRectangle &rect)
Set coordinates of the rectangle which should be rendered.
double y() const
Definition: qgspoint.h:134
virtual void cancel()=0
Stop the rendering job - does not return until the job has terminated.
QStringList layers() const
Get list of layer IDs for map rendering The layers are stored in the reverse order of how they are re...
QgsMapLayer * mapLayer(QString theLayerId)
Retrieve a pointer to a loaded layer by id.
QgsRectangle extent() const
Returns the current zoom exent of the map canvas.
QgsMapOverviewCanvas(QWidget *parent=0, QgsMapCanvas *mapCanvas=NULL)
double width() const
Width of the rectangle.
Definition: qgsrectangle.h:198
double size
Definition: qgssvgcache.cpp:77
double xMinimum() const
Get the x minimum value (left side of rectangle)
Definition: qgsrectangle.h:183
void updatePanningWidget(const QPoint &pos)
called when panning to reflect mouse movement
void setXMinimum(double x)
Set the minimum x value.
Definition: qgsrectangle.h:158
double height() const
Height of the rectangle.
Definition: qgsrectangle.h:203
void drawExtentRect()
used for overview canvas to reflect changed extent in main map canvas
void setCrsTransformEnabled(bool enabled)
sets whether to use projections for this layer set
QStringList layerSet() const
QgsRectangle fullExtent() const
Returns the combined exent for all layers on the map canvas.
void mousePressEvent(QMouseEvent *e)
Overridden mouse press event.
void scale(double scaleFactor, const QgsPoint *c=0)
Scale the rectangle around its center point.