libyui-qt  2.43.5
/usr/src/RPM/BUILD/libyui-qt-2.43.5/src/YQTimezoneSelector.cc
00001 /*
00002   Copyright (C) 2000-2012 Novell, Inc
00003   This library is free software; you can redistribute it and/or modify
00004   it under the terms of the GNU Lesser General Public License as
00005   published by the Free Software Foundation; either version 2.1 of the
00006   License, or (at your option) version 3.0 of the License. This library
00007   is distributed in the hope that it will be useful, but WITHOUT ANY
00008   WARRANTY; without even the implied warranty of MERCHANTABILITY or
00009   FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
00010   License for more details. You should have received a copy of the GNU
00011   Lesser General Public License along with this library; if not, write
00012   to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
00013   Floor, Boston, MA 02110-1301 USA
00014 */
00015 
00016 
00017 /*-/
00018 
00019   File:         YQTimezoneSelector.cc
00020 
00021   Author:       Stephan Kulow <coolo@suse.de>
00022 
00023 /-*/
00024 
00025 
00026 #define YUILogComponent "qt-ui"
00027 #include <yui/YUILog.h>
00028 #include <math.h>
00029 
00030 #include <qdatetimeedit.h>
00031 
00032 #include "utf8.h"
00033 #include "YQUI.h"
00034 #include "YQTimezoneSelector.h"
00035 #include "YQWidgetCaption.h"
00036 #include <yui/YEvent.h>
00037 #include <QVBoxLayout>
00038 #include <QPainter>
00039 #include <QMouseEvent>
00040 #include <QDebug>
00041 #include <QToolTip>
00042 
00043 #include "icons/zoom-in.xpm"
00044 
00045 class YQTimezoneSelectorPrivate
00046 {
00047     QWidget *parent;
00048 
00049 public:
00050 
00051     YQTimezoneSelectorPrivate( QWidget *p ) {
00052         parent = p;
00053         blink = 0;
00054         highlight = 0;
00055     }
00056     QImage _pix;
00057     QPoint _zoom;
00058 
00059     struct Location
00060     {
00061         QString country;
00062         double latitude;
00063         double longitude;
00064         QString zone;
00065         QString comment;
00066         QString tip;
00067 
00068         QPoint pix_pos;
00069 
00070         bool operator<(const Location& l2) const;
00071     };
00072 
00073     Location _best;
00074 
00075     QList<Location> locations;
00076 
00077     Location findBest( const QPoint &pos ) const;
00078 
00079     QTimer *blink;
00080 
00081     int highlight;
00082 
00083     QPoint pixPosition( const Location &pos ) const;
00084 
00085     QPoint pixToWindow( const QPoint &pos ) const;
00086 
00087     QPixmap cachePix;
00088 };
00089 
00090 static float
00091 convert_pos (const QString &pos, int digits)
00092 {
00093     if (pos.length() < 4 || digits > 9) return 0.0;
00094 
00095     QString whole = pos.left( digits + 1 );
00096     QString fraction = pos.mid( digits + 1 );
00097 
00098     float t1 = whole.toFloat();
00099     float t2 = fraction.toFloat();
00100 
00101     if (t1 >= 0.0)
00102         return t1 + t2/pow (10.0, fraction.length() );
00103     else
00104         return t1 - t2/pow (10.0, fraction.length());
00105 }
00106 
00107 bool YQTimezoneSelectorPrivate::Location::operator<(const Location& l1 ) const
00108 {
00109     return l1.latitude < latitude;
00110 }
00111 
00112 YQTimezoneSelector::YQTimezoneSelector( YWidget * parent, const std::string & pixmap,  const std::map<std::string,std::string> & timezones )
00113     : QFrame( (QWidget *) parent->widgetRep() )
00114     , YTimezoneSelector( parent, pixmap, timezones )
00115 {
00116     d = new YQTimezoneSelectorPrivate( this );
00117 
00118     setWidgetRep( this );
00119     setMouseTracking(true);
00120     d->_pix.load( fromUTF8( pixmap ) );
00121 
00122     setStretchable( YD_HORIZ, true );
00123     setStretchable( YD_VERT,  true );
00124 
00125     char buf[4096];
00126     FILE *tzfile = fopen ("/usr/share/zoneinfo/zone.tab", "r");
00127     while (fgets (buf, sizeof(buf), tzfile))
00128     {
00129         if (*buf == '#') continue;
00130 
00131         QString sbuf = buf;
00132         QStringList arr = sbuf.trimmed().split( '\t' );
00133 
00134         int split_index = 1;
00135         while ( split_index < arr[1].length() && arr[1][split_index] != '-' && arr[1][split_index] != '+' )
00136             split_index++;
00137 
00138         YQTimezoneSelectorPrivate::Location loc;
00139         loc.country = arr[0];
00140         loc.zone = arr[2];
00141         std::map<std::string, std::string>::const_iterator tooltip = timezones.find( loc.zone.toStdString() );
00142         if (tooltip  == timezones.end() )
00143             continue;
00144 
00145         loc.tip = fromUTF8( tooltip->second );
00146         if ( arr.size() > 3 )
00147             loc.comment = arr[3];
00148         loc.latitude  = convert_pos ( arr[1].left( split_index ), 2);
00149         loc.longitude = convert_pos ( arr[1].mid( split_index ), 3);
00150 
00151         loc.pix_pos = d->pixPosition( loc );
00152 
00153         d->locations.push_back( loc );
00154     }
00155 
00156     fclose (tzfile);
00157 
00158     qSort( d->locations.begin(), d->locations.end() );
00159 
00160     d->blink = new QTimer( this );
00161     d->blink->setInterval( 200 );
00162     connect( d->blink, SIGNAL( timeout() ), SLOT( slotBlink() ) );
00163 
00164     d->highlight = 0;
00165 }
00166 
00167 YQTimezoneSelector::~YQTimezoneSelector()
00168 {
00169     delete d;
00170     // NOP
00171 }
00172 
00173 
00174 int YQTimezoneSelector::preferredWidth()
00175 {
00176     return 600;
00177 }
00178 
00179 
00180 int YQTimezoneSelector::preferredHeight()
00181 {
00182     return 300;
00183 }
00184 
00185 
00186 void YQTimezoneSelector::setSize( int newWidth, int newHeight )
00187 {
00188     resize( newWidth, newHeight );
00189 }
00190 
00191 QPoint YQTimezoneSelectorPrivate::pixPosition( const Location &pos ) const
00192 {
00193     return QPoint(  (int) ( _pix.width()  / 2 + _pix.width()  / 2 * pos.longitude / 180 ),
00194                     (int) ( _pix.height() / 2 - _pix.height() / 2 * pos.latitude  /  90 ) ) ;
00195 }
00196 
00197 void YQTimezoneSelector::mousePressEvent ( QMouseEvent * event )
00198 {
00199     if ( event->button() == Qt::RightButton )
00200     {
00201         d->_zoom = QPoint();
00202         d->cachePix = QPixmap();
00203     }
00204     else if ( event->button() == Qt::LeftButton )
00205     {
00206         d->_best = d->findBest( event->pos() );
00207 
00208         if ( d->_zoom.isNull() )
00209         {
00210             QPoint click = event->pos();
00211             /* keep the zoom point in unscaled math */
00212             d->_zoom.rx() = (int) ( double( click.x() ) * d->_pix.width()   / width() );
00213             d->_zoom.ry() = (int) ( double( click.y() ) * d->_pix.height() / height() );
00214         }
00215 
00216         d->cachePix = QPixmap();
00217 
00218         if ( notify() )
00219             YQUI::ui()->sendEvent( new YWidgetEvent( this, YEvent::ValueChanged ) );
00220 
00221         d->blink->start();
00222     } else
00223         return;
00224 
00225     update();
00226 }
00227 
00228 void YQTimezoneSelector::paintEvent( QPaintEvent *event )
00229 {
00230     QFrame::paintEvent( event );
00231     QPainter p( this );
00232 
00233     if ( d->cachePix.width() != width() || d->cachePix.height() != height() )
00234         d->cachePix = QPixmap();
00235 
00236     if ( d->_zoom.isNull() )
00237     {
00238         if ( d->cachePix.isNull() )
00239         {
00240             QImage t = d->_pix.scaled( width(),  height(), Qt::KeepAspectRatio );
00241             d->cachePix = QPixmap::fromImage( t );
00242         }
00243         p.drawPixmap( ( width() - d->cachePix.width() ) / 2, ( height() - d->cachePix.height() ) / 2, d->cachePix );
00244 
00245         setCursor( QCursor( QPixmap( zoom_in ) ) );
00246     } else {
00247         int left = qMin( qMax( d->_zoom.x() - width() / 2, 0 ), d->_pix.width() - width() );
00248         int top  = qMin( qMax( d->_zoom.y() - height() / 2, 0 ), d->_pix.height() - height() );
00249 
00250         if ( d->cachePix.isNull() )
00251             d->cachePix = QPixmap::fromImage( d->_pix.copy( QRect( QPoint( left, top ), size() ) ) );
00252 
00253         p.drawPixmap( 0, 0, d->cachePix );
00254 
00255         setCursor( Qt::CrossCursor );
00256     }
00257 
00258     p.setBrush( QColor( "#D8DF57" ) );
00259     p.setPen( QColor( "#B9DFD6" ) );
00260     for ( QList<YQTimezoneSelectorPrivate::Location>::const_iterator it = d->locations.begin(); it != d->locations.end(); ++it )
00261     {
00262         if ( !d->highlight || ( *it ).zone != d->_best.zone )
00263         {
00264             if ( d->_zoom.isNull() )
00265                 p.drawEllipse( QRect( d->pixToWindow( ( *it ).pix_pos ) - QPoint( 1,1 ), QSize( 3, 3 ) ) );
00266             else
00267                 p.drawEllipse( QRect( d->pixToWindow( ( *it ).pix_pos ) - QPoint( 2,2 ), QSize( 5, 5 ) ) );
00268         }
00269     }
00270     if ( d->highlight > 0 )
00271     {
00272 //        QPoint pos = d->pixPosition( d->_best );
00273         static const QColor blinks[] = { QColor( "#00ff00" ), QColor( "#22dd00" ), QColor( "#44bb00" ),
00274                                          QColor( "#669900" ), QColor( "#887700" ), QColor( "#aa5500" ),
00275                                          QColor( "#887700" ), QColor( "#669900" ), QColor( "#44bb00" ),
00276                                          QColor( "#22dd00" ) };
00277         int index = d->highlight - 1;
00278         p.setPen( blinks[ index ] );
00279         p.setBrush( blinks[ index ] );
00280 
00281         p.drawEllipse( QRect( d->pixToWindow( d->_best.pix_pos ) - QPoint( 2,2 ), QSize( 5, 5 ) ) );
00282 
00283         QFont f( font() );
00284         f.setBold( true );
00285         p.setFont( f );
00286         QFontMetrics fm( f );
00287 
00288         QPoint off = d->pixToWindow( d->_best.pix_pos ) + QPoint( 11, 4 );
00289         int tw = fm.width( d->_best.tip );
00290         if ( tw + off.x() > width() )
00291             off.rx() = d->pixToWindow( d->_best.pix_pos ).x() - tw - 10;
00292 
00293         p.setPen( Qt::black );
00294         p.drawText( off, d->_best.tip );
00295 
00296         p.setPen( Qt::white );
00297         p.drawText( off - QPoint( 1, 1 ), d->_best.tip );
00298 
00299     }
00300 }
00301 
00302 YQTimezoneSelectorPrivate::Location YQTimezoneSelectorPrivate::findBest( const QPoint &pos ) const
00303 {
00304     double min_dist = 2000;
00305     Location best;
00306     for ( QList<Location>::const_iterator it = locations.begin(); it != locations.end(); ++it )
00307     {
00308         double dist = QPoint( pixToWindow( ( *it ).pix_pos ) - pos ).manhattanLength ();
00309         if ( dist < min_dist )
00310         {
00311             min_dist = dist;
00312             best = *it;
00313         }
00314     }
00315     return best;
00316 }
00317 
00318 bool YQTimezoneSelector::event(QEvent *event)
00319 {
00320     if (event->type() == QEvent::ToolTip)
00321     {
00322         QHelpEvent *helpEvent = static_cast<QHelpEvent *>(event);
00323 
00324         YQTimezoneSelectorPrivate::Location best = d->findBest( helpEvent->pos() );
00325         QToolTip::showText(helpEvent->globalPos(), best.tip );
00326     }
00327     return QWidget::event(event);
00328 }
00329 
00330 
00331 std::string YQTimezoneSelector::currentZone() const
00332 {
00333     return d->_best.zone.toStdString();
00334 }
00335 
00336 QPoint YQTimezoneSelectorPrivate::pixToWindow( const QPoint &pos ) const
00337 {
00338     if ( _zoom.isNull() )
00339     {
00340         return QPoint( (int) ( double( pos.x() ) * cachePix.width()  / _pix.width()  ) + ( parent->width() - cachePix.width() ) / 2,
00341                        (int) ( double( pos.y() ) * cachePix.height() / _pix.height() ) + ( parent->height() - cachePix.height() ) /2 );
00342     }
00343     int left = qMin( qMax( _zoom.x() - parent->width() / 2, 0 ), _pix.width() - parent->width() );
00344     int top  = qMin( qMax( _zoom.y() - parent->height() / 2, 0 ), _pix.height() - parent->height() );
00345 
00346     return QPoint( pos.x() - left, pos.y() - top );
00347 }
00348 
00349 void YQTimezoneSelector::setCurrentZone( const std::string &_zone, bool zoom )
00350 {
00351     QString zone = fromUTF8( _zone );
00352 
00353     if ( d->_best.zone == zone )
00354         return;
00355 
00356     d->_best = YQTimezoneSelectorPrivate::Location();
00357 
00358     for ( QList<YQTimezoneSelectorPrivate::Location>::const_iterator it = d->locations.begin(); it != d->locations.end(); ++it )
00359     {
00360         if ( ( *it ).zone == zone )
00361             d->_best = *it;
00362     }
00363 
00364     if ( zoom )
00365         d->_zoom = d->_best.pix_pos;
00366     else
00367         d->_zoom = QPoint();
00368 
00369     d->cachePix = QPixmap();
00370     d->highlight = 1;
00371 
00372     d->blink->start();
00373     update();
00374 }
00375 
00376 void YQTimezoneSelector::slotBlink()
00377 {
00378     if ( d->_best.zone.isNull() )
00379     {
00380         d->blink->stop();
00381         return;
00382     }
00383 
00384     if ( d->highlight++ > 9 )
00385         d->highlight = 1;
00386 
00387     QPoint current = d->pixToWindow( d->_best.pix_pos );
00388     update( QRect( current - QPoint( 3, 3 ), QSize( 7, 7 ) ) );
00389 }
00390 
00391 #include "YQTimezoneSelector.moc"
 All Classes Functions Variables