void
HoverIndex::timerEvent(QTimerEvent * event)
{
    if (event->timerId() != timer.timerId() || items.isEmpty())
        return;

    Items::iterator it;
    IndexInfo::Fades::iterator step;
    it = items.begin();
    QWidget *w;
    while (it != items.end())
    {
        if (it.key().isNull())
        {
            it = items.erase(it);
            continue;
        }
        w = const_cast<QWidget*>(it.key().data());
        IndexInfo &info = it.value();
        if (info.fades[In].isEmpty() && info.fades[Out].isEmpty())
        {
            ++it; continue;
        }

        step = info.fades[In].begin();
        while (step != info.fades[In].end())
        {
            step.value() += 2;
            if ((uint)step.value() > (maxSteps-2))
                step = info.fades[In].erase(step);
            else
                ++step;
        }

        step = info.fades[Out].begin();
        while (step != info.fades[Out].end())
        {
            step.value() -= 2;
            if (step.value() < 1)
                step = info.fades[Out].erase(step);
            else
                ++step;
        }

        w->update();

        if (info.index == 0L && // nothing actually hovered
            info.fades[In].isEmpty() && // no fade ins
            info.fades[Out].isEmpty()) // no fade outs
            it = items.erase(it); // so remove this item
        else
            ++it;
    }

    if (items.isEmpty())
        timer.stop();
}
const IndexInfo *
HoverIndex::_info(const QWidget *widget, long int idx) const
{
    HoverIndex *that = const_cast<HoverIndex*>(this);
    QWidget *w = const_cast<QWidget*>(widget);
    Items::iterator it = that->items.find(w);
    if (it == items.end())
    {   // we have no entry yet
        if (idx == 0L)
            return 0L;
        // ... but we'll need one
        it = that->items.insert(w, IndexInfo(0L));
        connect(widget, SIGNAL(destroyed(QObject*)), this, SLOT(release(QObject*)));
//         if (!timer.isActive())
            that->timer.start(timeStep, that);
    }
    // we now have an entry - check for validity and update in case
    IndexInfo &info = it.value();
    if (info.index != idx)
    {   // sth. changed
        info.fades[In][idx] = 1;
        if (info.index)
        {
            int v = maxSteps;
            IndexInfo::Fades::iterator old = info.fades[In].find(info.index);
            if (old != info.fades[In].end())
            {
                v = old.value();
                info.fades[In].erase(old);
            }
            info.fades[Out][info.index] = v;
        }
        info.index = idx;
    }
    return &info;
}
void
HoverIndex::timerEvent(QTimerEvent * event)
{
    if (event->timerId() != timer.timerId() || items.isEmpty())
        return;

    Items::iterator it;
    IndexInfo::Fades::iterator step;
    it = items.begin();
    QWidget *w;
    while (it != items.end())
    {
        if (!it.key())
        {
            it = items.erase(it);
            continue;
        }
#if QT_VERSION >= 0x040400
        // below does work in general, but is... ugly?!
        // another way would be to map to a const widget first or perform a static_cast - ughh
        w = const_cast<QWidget*>(it.key().data());
#else
        w = const_cast<QWidget*>(&(*it.key()));
#endif
        IndexInfo &info = it.value();
        if (info.fades[In].isEmpty() && info.fades[Out].isEmpty())
        {
            ++it; continue;
        }

        step = info.fades[In].begin();
        while (step != info.fades[In].end())
        {
            step.value() += 2;
            if ((uint)step.value() > (maxSteps-2))
                step = info.fades[In].erase(step);
            else
                ++step;
        }

        step = info.fades[Out].begin();
        while (step != info.fades[Out].end())
        {
            step.value() -= 2;
            if (step.value() < 1)
                step = info.fades[Out].erase(step);
            else
                ++step;
        }

        w->update();

        if (info.index == 0L && // nothing actually hovered
            info.fades[In].isEmpty() && // no fade ins
            info.fades[Out].isEmpty()) // no fade outs
            it = items.erase(it); // so remove this item
        else
            ++it;
    }

    if (items.isEmpty())
        timer.stop();
}