You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
tdetoys/kworldwatch/mapwidget.cpp

580 lines
13 KiB

/*
**
** Copyright (C) 1998-2001 by Matthias Hözer-Klüpfel <hoelzer@kde.org>
** Maintainence has ceased - send questions to kde-devel@kde.org.
**
*/
/*
** 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.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program in a file called COPYING; if not, write to
** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
** MA 02110-1301, USA.
*/
/*
** Bug reports and questions can be sent to kde-devel@kde.org
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif // HAVE_CONFIG_H
#include <time.h>
#include <stdlib.h>
#include <tqdatetime.h>
#include <tdeapplication.h>
#include <tdecmdlineargs.h>
#include <kcolordialog.h>
#include <tdeconfig.h>
#include <tdeglobal.h>
#include <tdeglobalsettings.h>
#include <tdelocale.h>
#include <tdemessagebox.h>
#include <kstandarddirs.h>
#include <tqcursor.h>
#include <tqpainter.h>
#include <tqpopupmenu.h>
#include <tqregexp.h>
#include <tqiconset.h>
#include <tqtooltip.h>
#include "cities.h"
#include "about.h"
#include "flags.h"
#include "mapwidget.moc"
MapWidget::MapWidget(bool applet, bool restore, TQWidget *parent, const char *name)
: TQWidget(parent, name), _loader(), _illumination(true), _cities(true), _flags(true), _cityList(0),
_applet(applet), _width(0), _height(0)
{
// this ugly construction is necessary so we don't load
// the map twice.
_theme = "depths";
if (restore)
{
TDEConfig *config = kapp->config();
if (applet)
config = new TDEConfig("kwwwappletrc");
_theme = config->readEntry("Theme", "depths");
if (applet)
delete config;
}
setBackgroundMode(TQWidget::NoBackground);
gmt_position = 0;
time_t t = time(NULL);
setTime(gmtime(&t));
_flagList = new FlagList;
int id;
_flagPopup = new TQPopupMenu(this);
TQPixmap flag = TQPixmap(locate("data", "kworldclock/pics/flag-red.png"));
id = _flagPopup->insertItem(TQIconSet(flag), i18n("Add &Red"), this, TQ_SLOT(addFlag(int)));
_flagPopup->setItemParameter(id, 0);
flag = TQPixmap(locate("data", "kworldclock/pics/flag-green.png"));
id = _flagPopup->insertItem(TQIconSet(flag), i18n("Add &Green"), this, TQ_SLOT(addFlag(int)));
_flagPopup->setItemParameter(id, 1);
flag = TQPixmap(locate("data", "kworldclock/pics/flag-blue.png"));
id = _flagPopup->insertItem(TQIconSet(flag), i18n("Add &Blue"), this, TQ_SLOT(addFlag(int)));
_flagPopup->setItemParameter(id, 2);
id = _flagPopup->insertItem(i18n("Add &Custom..."), this, TQ_SLOT(addFlag(int)));
_flagPopup->setItemParameter(id, 3);
_flagPopup->insertSeparator();
_flagPopup->insertItem(i18n("&Remove Flag"), this, TQ_SLOT(removeFlag()));
_flagPopup->insertItem(i18n("&Remove All Flags"), this, TQ_SLOT(removeAllFlags()));
_themePopup = new TQPopupMenu(this);
_themes = MapLoader::themes();
int cnt=0;
TQPtrListIterator<MapTheme> it(_themes);
for ( ; it.current(); ++it)
{
int id = _themePopup->insertItem(it.current()->name(), this, TQ_SLOT(themeSelected(int)));
_themePopup->setItemParameter(id, cnt++);
it.current()->setID(id);
}
TQPopupMenu *_clocksPopup = new TQPopupMenu(this);
_clocksPopup->insertItem(i18n("&Add..."), this, TQ_SLOT(addClock()));
_popup = new TQPopupMenu(this);
_popup->insertItem(i18n("&Flags"), _flagPopup);
if (!applet)
_popup->insertItem(i18n("&Clocks"), _clocksPopup);
_popup->insertSeparator();
_popup->insertItem(i18n("&Map Theme"), _themePopup);
_illuminationID = _popup->insertItem(i18n("Show &Daylight"), this, TQ_SLOT(toggleIllumination()));
_citiesID = _popup->insertItem(i18n("Show &Cities"), this, TQ_SLOT(toggleCities()));
_flagsID = _popup->insertItem(i18n("Show F&lags"), this, TQ_SLOT(toggleFlags()));
if (!applet)
{
_popup->insertSeparator();
_popup->insertItem(i18n("&Save Settings"), this, TQ_SLOT(slotSaveSettings()));
}
_popup->insertSeparator();
_popup->insertItem(i18n("&About"), this, TQ_SLOT(about()));
TQTimer *timer = new TQTimer(this);
connect(timer, TQ_SIGNAL(timeout()), this, TQ_SLOT(timeout()));
timer->start(1000);
_cityIndicator = new TQLabel(0,0, WStyle_StaysOnTop | WStyle_Customize | WStyle_NoBorder | WStyle_Tool | WX11BypassWM );
_cityIndicator->setMargin(1);
_cityIndicator->setIndent(0);
_cityIndicator->setAutoMask(false);
_cityIndicator->setLineWidth(1);
_cityIndicator->setAlignment(TQLabel::AlignAuto | TQLabel::AlignTop);
_cityIndicator->setAutoResize(true);
_cityIndicator->setFrameStyle(TQFrame::Box | TQFrame::Plain);
_cityIndicator->setPalette(TQToolTip::palette());
if (restore && !applet)
load(kapp->config());
connect(&m_timer, TQ_SIGNAL(timeout()), this, TQ_SLOT(updateCityIndicator()));
}
MapWidget::~MapWidget()
{
if (_applet)
{
TDEConfig *conf = new TDEConfig("kwwwappletrc");
save(conf);
delete conf;
}
delete _cityList;
delete _flagList;
}
void MapWidget::load(TDEConfig *config)
{
setCities(config->readBoolEntry("Cities", true));
setIllumination(config->readBoolEntry("Illumination", true));
setFlags(config->readBoolEntry("Flags", true));
if ( !_applet )
{
TDECmdLineArgs *args = TDECmdLineArgs::parsedArgs();
if (args->isSet("theme"))
setTheme(TQString::fromLocal8Bit(args->getOption("theme")));
else
setTheme(config->readEntry("Theme", "depths"));
_flagList->load(config);
}
}
void MapWidget::save(TDEConfig *config)
{
config->writeEntry("Cities", _cities);
config->writeEntry("Illumination", _illumination);
config->writeEntry("Flags", _flags);
config->writeEntry("Theme", _theme);
_flagList->save(config);
}
void MapWidget::slotSaveSettings()
{
emit saveSettings();
}
void MapWidget::addClock()
{
if (!_cityList)
_cityList = new CityList;
TQPoint where;
City *c = _cityList->getNearestCity(_width, _height, gmt_position, _flagPos.x(), _flagPos.y(), where);
TQString zone = "";
if (c)
zone = c->name();
emit addClockClicked(zone);
}
void MapWidget::addFlag(int index)
{
TQColor col = TQt::red;
switch (index)
{
case 0:
col = TQt::red;
break;
case 1:
col = TQt::green;
break;
case 2:
col = TQt::blue;
break;
case 3:
if (KColorDialog::getColor(col, this) != KColorDialog::Accepted)
return;
break;
}
int x = _flagPos.x() - gmt_position + width()/2;
if (x>width())
x -= width();
double la = 90.0 - 180.0 * ((double)_flagPos.y()) / ((double)_height);
double lo = 360.0 * ((double)x) / ((double)_width) - 180.0;
_flagList->addFlag(new Flag(lo, la, col));
update();
}
void MapWidget::removeFlag()
{
_flagList->removeNearestFlag(_flagPos, _width, _height, gmt_position);
update();
}
void MapWidget::removeAllFlags()
{
if ( KMessageBox::warningContinueCancel( this, i18n( "Do you really want to remove all flags?" ), TQString(), KStdGuiItem::del() ) == KMessageBox::Continue )
_flagList->removeAllFlags();
update();
}
void MapWidget::setCities(bool c)
{
_cities = c;
_popup->setItemChecked(_citiesID, c);
if (c && !_cityList)
_cityList = new CityList;
setMouseTracking(c);
if (!c)
{
_cityIndicator->hide();
m_timer.stop();
}
update();
}
void MapWidget::toggleCities()
{
setCities(!_popup->isItemChecked(_citiesID));
}
void MapWidget::toggleIllumination()
{
setIllumination(!_popup->isItemChecked(_illuminationID));
}
void MapWidget::setFlags(bool f)
{
_flags = f;
_popup->setItemChecked(_flagsID, f);
update();
}
void MapWidget::toggleFlags()
{
setFlags(!_popup->isItemChecked(_flagsID));
}
void MapWidget::updateBackground()
{
if (!_height)
return;
_pixmap = calculatePixmap();
setBackgroundPixmap(_pixmap);
update();
}
TQPixmap MapWidget::getPixmap()
{
return _pixmap;
}
void MapWidget::setIllumination(bool i)
{
_illumination = i;
_popup->setItemChecked(_illuminationID, i);
updateBackground();
}
void MapWidget::timeout()
{
time_t t = time(NULL);
setTime(gmtime(&t));
if (_cities && !_currentCity.isEmpty())
_cityIndicator->setText(cityTime(_currentCity));
}
TQString MapWidget::cityTime(const TQString &city)
{
TQString result = i18n(city.latin1()); // Time zone translation
int pos = result.find("/");
if (pos >= 0)
result = result.mid(pos+1);
result.replace(TQRegExp("_"), " ");
result.append(": ");
char *initial_TZ = getenv("TZ");
setenv("TZ", city.latin1(), 1);
tzset();
time_t t = time(NULL);
TQDateTime dt;
dt.setTime_t(t);
result.append(TQString("%1, %2").arg(TDEGlobal::locale()->formatTime(dt.time(), true)).arg(TDEGlobal::locale()->formatDate(dt.date(), true)));
if (initial_TZ != 0)
setenv("TZ", initial_TZ, 1);
else
unsetenv("TZ");
tzset();
return result;
}
void MapWidget::enterEvent(TQEvent *)
{
if ( _cities )
updateCityIndicator();
}
void MapWidget::leaveEvent(TQEvent *)
{
_cityIndicator->hide();
m_timer.stop();
}
void MapWidget::about()
{
AboutDialog dlg(this, 0, true);
dlg.exec();
}
void MapWidget::themeSelected(int index)
{
TQString t = _themes.at(index)->tag();
if (!t.isEmpty())
setTheme(t);
}
void MapWidget::mousePressEvent(TQMouseEvent *ev)
{
if (ev->button() == TQt::RightButton)
{
_flagPos = ev->pos();
_popup->exec(ev->globalPos());
}
}
void MapWidget::mouseMoveEvent(TQMouseEvent *)
{
if (!_cities)
return;
if (!m_timer.isActive())
m_timer.start(25, true);
}
void MapWidget::updateCityIndicator()
{
TQPoint where;
TQPoint pos = mapFromGlobal(TQCursor::pos());
if (!_cityList)
_cityList = new CityList;
City *c = _cityList->getNearestCity(_width, _height, gmt_position, pos.x(), pos.y(), where);
if (c)
{
_currentCity = c->name();
showIndicator(TQCursor::pos());
}
else
_cityIndicator->hide();
}
void MapWidget::showIndicator(const TQPoint &pos)
{
_cityIndicator->setText(cityTime(_currentCity));
int w = _cityIndicator->width();
int h = _cityIndicator->height();
TQRect desk = TDEGlobalSettings::desktopGeometry(pos);
TQPoint newPos;
if (pos.x()+w+10 > desk.right())
newPos.setX(pos.x()-w-5);
else
newPos.setX(pos.x()+10);
if (pos.y()+h+10 > desk.bottom())
newPos.setY(pos.y()-h-5);
else
newPos.setY(pos.y()+10);
_cityIndicator->move(newPos);
_cityIndicator->show();
}
void MapWidget::setTheme(const TQString &theme)
{
_theme = theme;
TQPtrListIterator<MapTheme> it(_themes);
for ( ; it.current(); ++it)
_themePopup->setItemChecked(it.current()->ID(), theme == it.current()->tag());
if (_height)
setSize(_width, _height);
}
void MapWidget::setTime(struct tm *time)
{
sec = time->tm_hour*60*60 + time->tm_min*60 + time->tm_sec;
if (isVisible())
{
int old_position = gmt_position;
gmt_position = width() * sec / 86400; // note: greenwich is in the middle!
if (old_position != gmt_position)
updateBackground();
}
}
void MapWidget::setSize(int w, int h)
{
_width = w;
_height = h;
_loader.load(_width, _theme, _height);
gmt_position = width() * sec / 86400; // note: greenwich is in the middle!
updateBackground();
}
void MapWidget::resizeEvent(TQResizeEvent *ev)
{
setSize(width(), height());
TQWidget::resizeEvent(ev);
}
void MapWidget::paintContents(TQPainter *p)
{
if (_cities)
_cityList->paint(p, _width, _height, gmt_position);
if (_flags)
_flagList->paint(p, _width, _height, gmt_position);
}
void MapWidget::paintEvent(TQPaintEvent *ev)
{
TQWidget::paintEvent(ev);
if (_cities || _flags)
{
TQPainter p(this);
p.setClipping(true);
p.setClipRegion(ev->region());
paintContents(&p);
}
}
TQPixmap MapWidget::calculatePixmap()
{
TQPixmap map;
if (_illumination)
{
map = _loader.darkMap();
TQPixmap clean = _loader.lightMap();
TQPainter mp(&map);
clean.setMask(_loader.darkMask(map.width(), map.height()));
mp.drawPixmap(0,0, clean);
}
else
map = _loader.lightMap();
int greenwich = map.width()/2;
TQPixmap pm(_width, _height);
TQPainter p;
p.begin(&pm);
if (gmt_position >= greenwich)
{
p.drawPixmap(gmt_position-greenwich, 0, map, 0, 0, map.width()-gmt_position+greenwich);
p.drawPixmap(0,0, map, map.width()-gmt_position+greenwich, 0, gmt_position-greenwich);
}
else
{
p.drawPixmap(0,0, map, greenwich-gmt_position, 0, map.width()+gmt_position-greenwich);
p.drawPixmap(map.width()+gmt_position-greenwich, 0, map, 0, 0, greenwich-gmt_position);
}
return pm;
}