📄 zonemap.cpp
字号:
/************************************************************************ Copyright (C) 2000-2002 Trolltech AS. All rights reserved.**** This file is part of the Qtopia Environment.**** This file may be distributed and/or modified under the terms of the** GNU General Public License version 2 as published by the Free Software** Foundation and appearing in the file LICENSE.GPL included in the** packaging of this file.**** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.**** See http://www.trolltech.com/gpl/ for GPL licensing information.**** Contact info@trolltech.com if any conditions of this licensing are** not clear to you.************************************************************************/#include "sun.h"#include "zonemap.h"#include <qtopia/resource.h>#include <qtopia/timestring.h>#include <qtopia/timezone.h>#include <qtopia/qpeapplication.h>#include <qdatetime.h>#include <qfile.h>#include <qimage.h>#include <qlabel.h>#include <qlist.h>#include <qmessagebox.h>#include <qpixmap.h>#include <qpainter.h>#include <qregexp.h>#include <qtextstream.h>#include <qtimer.h>#include <qtoolbutton.h>#include <qwhatsthis.h>#include <limits.h>// the map file...#ifndef Q_OS_WIN32static const char strZONEINFO[] = "/usr/share/zoneinfo/zone.tab";#elsestatic const char strZONEINFO[] = "./etc/zoneinfo/zone.tab";#endifstatic const char strMAP[] = "simple_grid_400";// the maximum distance we'll allow the pointer to be away from a city// and still show the city's timestatic const int iTHRESHOLD = 50000;// The label offset (how far away from pointer)static const int iLABELOFFSET = 8;// the size of the dot to draw, and where to start itstatic const int iCITYSIZE = 3;const int iCITYOFFSET = 2;// the darkening functionstatic inline void darken( QImage *pImage, int start, int stop, int row );static void dayNight( QImage *pImage );ZoneMap::ZoneMap( QWidget *parent, const char* name ) : QScrollView( parent, name ), ox( 0 ), oy( 0 ), drawableW( -1 ), drawableH( -1 ), bZoom( FALSE ), bIllum( TRUE ), citiesInit( FALSE ){ viewport()->setFocusPolicy( StrongFocus ); // get the map loaded // just set the current image to point pixCurr = new QPixmap(); QPixmap pixZoom = Resource::loadPixmap( "mag" ); cmdZoom = new QToolButton( this ); cmdZoom->setPixmap( pixZoom ); cmdZoom->setToggleButton( true ); cmdZoom->setSizePolicy( QSizePolicy( (QSizePolicy::SizeType)0, (QSizePolicy::SizeType)0, cmdZoom->sizePolicy().hasHeightForWidth() ) ); cmdZoom->setMaximumSize( cmdZoom->sizeHint() ); // probably don't need this, but just in case... cmdZoom->move( width() - cmdZoom->width(), height() - cmdZoom->height() ); QWhatsThis::add( cmdZoom, tr("Click to zoom the map in/out.") ); lblCity = new QLabel( tr( "CITY" ), this ); lblCity->setMinimumSize( lblCity->sizeHint() ); lblCity->setFrameStyle( QFrame::Plain | QFrame::Box ); lblCity->setBackgroundColor( yellow ); lblCity->hide(); // A timer to make sure the label gets hidden tHide = new QTimer( this ); QObject::connect( tHide, SIGNAL( timeout() ), lblCity, SLOT( hide() ) ); QObject::connect( tHide, SIGNAL( timeout() ), this, SLOT( slotRedraw() ) ); QTimer *tUpdate = new QTimer( this ); QObject::connect( tUpdate, SIGNAL( timeout() ), this, SLOT( slotUpdate() ) ); QObject::connect( qApp, SIGNAL( timeChanged() ), this, SLOT( slotUpdate() ) ); QObject::connect( cmdZoom, SIGNAL( toggled( bool ) ), this, SLOT( slotZoom( bool ) ) ); QObject::connect( &norm, SIGNAL( signalNewPoint( const QPoint& ) ), this, SLOT( slotFindCity( const QPoint& ) ) ); // update the sun's movement every 5 minutes tUpdate->start( 5 * 60 * 1000 ); // May as well read in the timezone information too... cities.setAutoDelete(TRUE); QTimer::singleShot( 0, this, SLOT(initCities()) );}ZoneMap::~ZoneMap(){ delete pixCurr;}void ZoneMap::viewportMousePressEvent( QMouseEvent* event ){ // add the mouse event into the normalizer, and get the average, // pass it along slotRedraw(); norm.start(); norm.addEvent( event->pos() );}void ZoneMap::viewportMouseMoveEvent( QMouseEvent* event ){ if ((event->x() >= 0 && event->x() < viewport()->width()) && (event->y() >= 0 && event->y() < viewport()->height())) { norm.addEvent( event->pos() ); }}void ZoneMap::viewportMouseReleaseEvent( QMouseEvent* ){ // get the averaged points in case a timeout hasn't occurred, // more for "mouse clicks" norm.stop(); if (m_last.isValid()) { emit signalTz( m_last.id() ); m_last = TimeZone(); } tHide->start( 2000, true );}void ZoneMap::keyPressEvent( QKeyEvent *ke ){ switch ( ke->key() ) { case Key_Left: case Key_Right: case Key_Up: case Key_Down: { tHide->stop(); if ( !m_cursor.isValid() ) slotFindCity( QPoint( contentsWidth(), contentsHeight() ) / 2 ); TimeZone city = findCityNear( m_cursor, ke->key() ); if ( city.isValid() ) { m_cursor = city; int tmpx, tmpy; zoneToWin( m_cursor.lon(), m_cursor.lat(), tmpx, tmpy ); ensureVisible( tmpx, tmpy ); showCity( m_cursor ); tHide->start( 3000, true ); } } break; case Key_Space: case Key_Enter: case Key_Return: if ( m_cursor.isValid() ) { emit signalTz( m_cursor.id()); tHide->start( 0, true ); } break; }}const TimeZone ZoneMap::findCityNear( const TimeZone &city, int key ){ initCities(); long ddist = LONG_MAX; QCString closestZone; for ( unsigned i = 0; i < cities.count(); i++ ) { CityPos *cp = cities[i]; long dy = (cp->lat - city.lat())/100; long dx = (cp->lon - city.lon())/100; switch ( key ) { case Key_Right: case Key_Left: if ( key == Key_Left ) dx = -dx; if ( dx > 0 ) { long dist = QABS(dy)*4 + dx; if ( dist < ddist ) { ddist = dist; closestZone = cp->id; } } break; case Key_Down: case Key_Up: if ( key == Key_Down ) dy = -dy; if ( dy > 0 ) { long dist = QABS(dx)*4 + dy; if ( dist < ddist ) { ddist = dist; closestZone = cp->id; } } break; } } TimeZone nearCity( closestZone );// nearCity.dump(); return nearCity;}void ZoneMap::slotFindCity( const QPoint &pos ){ initCities(); // given coordinates on the screen find the closest city and display the // label close to it int tmpx, tmpy, x, y; if ( tHide->isActive() ) tHide->stop(); viewportToContents(pos.x(), pos.y(), tmpx, tmpy); winToZone( tmpx, tmpy, x, y ); // Find city alogorithim: start out at an (near) infinite distance away and // then find the closest city, (similar to the Z-buffer technique, I guess) // the only problem is that this is all done with doubles, but I don't know // another way to do it at the moment. Another problem is a linked list is // used obviously something indexed would help long lDistance; long lClosest = LONG_MAX; QCString closestZone; for ( unsigned i = 0; i < cities.count(); i++ ) { CityPos *cp = cities[i]; // use the manhattenLength, a good enough of an appoximation here lDistance = QABS(y - cp->lat) + QABS(x - cp->lon); // first to zero wins! if ( lDistance < lClosest ) { lClosest = lDistance; closestZone = cp->id; } } // Okay, we found the closest city, but it might still be too far away. if ( lClosest <= iTHRESHOLD ) { m_cursor = TimeZone(closestZone); showCity( m_cursor ); }}void ZoneMap::showCity( const TimeZone &city ){ if ( m_last == city ) return; m_last = city; QDateTime cityTime = city.fromUtc(TimeZone::utcDateTime()); lblCity->setText( city.city().replace( QRegExp("_"), " ") + "\n" + TimeString::localHM( cityTime.time())); lblCity->setMinimumSize( lblCity->sizeHint() ); lblCity->resize( QMAX(lblCity->sizeHint().width(),80), QMAX(lblCity->sizeHint().height(),40) );
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -