QGIS API Documentation  2.0.1-Dufour
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Groups 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 "qgsmaprenderer.h"
21 #include "qgsmapoverviewcanvas.h"
22 #include "qgsmaptopixel.h"
23 
24 #include <QPainter>
25 #include <QPaintEvent>
26 #include <QResizeEvent>
27 #include <QMouseEvent>
28 #include "qgslogger.h"
29 #include <limits.h>
30 
32 class QgsPanningWidget : public QWidget
33 {
34  public:
35  QgsPanningWidget( QWidget* parent )
36  : QWidget( parent )
37  {
38  setObjectName( "panningWidget" );
39  setMinimumSize( 5, 5 );
40  setAttribute( Qt::WA_NoSystemBackground );
41  }
42 
43  void resizeEvent( QResizeEvent* r )
44  {
45  QSize s = r->size();
46  QRegion reg( 0, 0, s.width(), s.height() );
47  QRegion reg2( 2, 2, s.width() - 4, s.height() - 4 );
48  QRegion reg3 = reg.subtract( reg2 );
49  setMask( reg3 );
50  }
51 
52 
53  void paintEvent( QPaintEvent* pe )
54  {
55  Q_UNUSED( pe );
56 
57  QRect r( QPoint( 0, 0 ), size() );
58  QPainter p;
59  p.begin( this );
60  p.setPen( Qt::red );
61  p.setBrush( Qt::red );
62  p.drawRect( r );
63  p.end();
64  }
65 
66 };
67 
68 
69 
71  : QWidget( parent ), mMapCanvas( mapCanvas )
72 {
73  setObjectName( "theOverviewCanvas" );
74  mPanningWidget = new QgsPanningWidget( this );
75 
78 
79  setBackgroundColor( palette().window().color() );
80 }
81 
83 {
84  delete mMapRenderer;
85 }
86 
87 void QgsMapOverviewCanvas::resizeEvent( QResizeEvent* e )
88 {
89  mNewSize = e->size();
90 }
91 
92 void QgsMapOverviewCanvas::paintEvent( QPaintEvent* pe )
93 {
94  if ( mNewSize.isValid() )
95  {
96  mPixmap = QPixmap( mNewSize );
97  mMapRenderer->setOutputSize( mNewSize, mPixmap.logicalDpiX() );
99  mNewSize = QSize();
100  refresh();
101  }
102 
103  QPainter paint( this );
104  paint.drawPixmap( pe->rect().topLeft(), mPixmap, pe->rect() );
105 }
106 
107 
109 {
110  if ( !mMapCanvas || !mMapRenderer ) return;
111 
112  const QgsRectangle& extent = mMapCanvas->extent();
113 
114  // show only when valid extent is set
115  if ( extent.isEmpty() || mMapRenderer->extent().isEmpty() )
116  {
117  mPanningWidget->hide();
118  return;
119  }
120 
122  QgsPoint ll( extent.xMinimum(), extent.yMinimum() );
123  QgsPoint ur( extent.xMaximum(), extent.yMaximum() );
124  if ( cXf )
125  {
126  // transform the points before drawing
127  cXf->transform( &ll );
128  cXf->transform( &ur );
129  }
130 
131 #if 0
132  // test whether panning widget should be drawn
133  bool show = false;
134  if ( ur.x() >= 0 && ur.x() < width() )
135  show = true;
136  if ( ll.x() >= 0 && ll.x() < width() )
137  show = true;
138  if ( ur.y() >= 0 && ur.y() < height() )
139  show = true;
140  if ( ll.y() >= 0 && ll.y() < height() )
141  show = true;
142  if ( !show )
143  {
144  QgsDebugMsg( "panning: extent out of overview area" );
145  mPanningWidget->hide();
146  return;
147  }
148 #endif
149 
150  // round values
151  int x1 = static_cast<int>( ur.x() + 0.5 ), x2 = static_cast<int>( ll.x() + 0.5 );
152  int y1 = static_cast<int>( ur.y() + 0.5 ), y2 = static_cast<int>( ll.y() + 0.5 );
153 
154  if ( x1 > x2 )
155  std::swap( x1, x2 );
156  if ( y1 > y2 )
157  std::swap( y1, y2 );
158 
159 #ifdef Q_WS_MAC
160  // setGeometry (Qt 4.2) is causing Mac window corruption (decorations
161  // are drawn at odd locations) if both coords are at limit. This may
162  // have something to do with Qt calculating dimensions as x2 - x1 + 1.
163  // (INT_MAX - INT_MIN + 1 is UINT_MAX + 1)
164  if ( x1 == INT_MIN && x2 == INT_MAX )
165  x1 += 1; // x2 -= 1 works too
166  if ( y1 == INT_MIN && y2 == INT_MAX )
167  y1 += 1;
168 #endif
169 
170  QRect r( x1, y1, x2 - x1 + 1, y2 - y1 + 1 );
171 
172  // allow for 5 pixel minimum widget size
173  if ( r.width() < 5 && x1 > INT_MIN + 2 ) // make sure no underflow occurs (2 is largest adjustment)
174  {
175  r.setX( r.x() - (( 5 - r.width() ) / 2 ) ); // adjust x by 1/2 the difference of calculated and min. width
176  r.setWidth( 5 );
177  }
178  if ( r.height() < 5 && y1 > INT_MIN + 2 )
179  {
180  r.setY( r.y() - (( 5 - r.height() ) / 2 ) ); // adjust y
181  r.setHeight( 5 );
182  }
183 
184  QgsDebugMsg( QString( "panning: extent to widget: [%1,%2] [%3x%4]" ).arg( x1 ).arg( y1 ).arg( r.width() ).arg( r.height() ) );
185 
186  mPanningWidget->setGeometry( r );
187  mPanningWidget->show(); // show if hidden
188 }
189 
190 
192 {
193 // if (mPanningWidget->isHidden())
194 // return;
195 
196  // set offset in panning widget if inside it
197  // for better experience with panning :)
198  if ( mPanningWidget->geometry().contains( e->pos() ) )
199  {
200  mPanningCursorOffset = e->pos() - mPanningWidget->pos();
201  }
202  else
203  {
204  // use center of the panning widget if outside
205  QSize s = mPanningWidget->size();
206  mPanningCursorOffset = QPoint( s.width() / 2, s.height() / 2 );
207  }
208  updatePanningWidget( e->pos() );
209 }
210 
211 
213 {
214 // if (mPanningWidget->isHidden())
215 // return;
216 
217  if ( e->button() == Qt::LeftButton )
218  {
219  // set new extent
221  QRect rect = mPanningWidget->geometry();
222 
223  QgsPoint center = cXf->toMapCoordinates( rect.center() );
224  QgsRectangle oldExtent = mMapCanvas->extent();
225  QgsRectangle ext;
226  ext.setXMinimum( center.x() - oldExtent.width() / 2 );
227  ext.setXMaximum( center.x() + oldExtent.width() / 2 );
228  ext.setYMinimum( center.y() - oldExtent.height() / 2 );
229  ext.setYMaximum( center.y() + oldExtent.height() / 2 );
230 
231  QgsDebugMsg( QString( "panning: new position: [%1,%2] [%3x%4]" ).arg( rect.left() ).arg( rect.top() ).arg( rect.width() ).arg( rect.height() ) );
232 
233  mMapCanvas->setExtent( ext );
234  mMapCanvas->refresh();
235  }
236 }
237 
238 
240 {
241  // move with panning widget if tracking cursor
242  if (( e->buttons() & Qt::LeftButton ) == Qt::LeftButton )
243  {
244  updatePanningWidget( e->pos() );
245  }
246 }
247 
248 
250 {
251 // if (mPanningWidget->isHidden())
252 // return;
253  mPanningWidget->move( pos.x() - mPanningCursorOffset.x(), pos.y() - mPanningCursorOffset.y() );
254 }
255 
256 
258 {
259  if ( mPixmap.isNull() || mPixmap.paintingActive() )
260  return;
261 
262  mPixmap.fill( mBgColor ); //palette().color(backgroundRole());
263 
264  QPainter painter;
265  painter.begin( &mPixmap );
266 
267  // antialiasing
268  if ( mAntiAliasing )
269  painter.setRenderHint( QPainter::Antialiasing );
270 
271  // render image
272  mMapRenderer->render( &painter );
273 
274  painter.end();
275 
276  // schedule repaint
277  update();
278 
279  // update panning widget
280  drawExtentRect();
281 }
282 
283 
284 void QgsMapOverviewCanvas::setBackgroundColor( const QColor& color )
285 {
286  mBgColor = color;
287 
288  // set erase color
289  QPalette palette;
290  palette.setColor( backgroundRole(), color );
291  setPalette( palette );
292 }
293 
294 void QgsMapOverviewCanvas::setLayerSet( const QStringList& layerSet )
295 {
296  QgsDebugMsg( "layerSet: " + layerSet.join( ", " ) );
297  if ( !mMapRenderer ) return;
298  mMapRenderer->setLayerSet( layerSet );
301 }
302 
304 {
305  if ( !mMapRenderer ) return;
306  QgsRectangle rect;
307  if ( !mMapRenderer->layerSet().isEmpty() )
308  {
309  rect = mMapRenderer->fullExtent();
310  // expand a bit to keep features on margin
311  rect.scale( 1.1 );
312  }
313  mMapRenderer->setExtent( rect );
314  drawExtentRect();
315 }
316 
318 {
320 }
321 
323 {
326 }
327 
329 {
330  return mMapRenderer->layerSet();
331 }