/* ============================================================
 *
 * This file is a part of digiKam project
 * http://www.digikam.org
 *
 * Date        : 2005-01-01
 * Description : a combo box with a width not depending of text 
 *               content size
 * 
 * Copyright (C) 2005 by Tom Albers <tomalbers@kde.nl>
 * Copyright (C) 2006-2007 by Gilles Caulier <caulier dot gilles at gmail dot com> 
 *
 * 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, 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.
 * 
 * ============================================================ */

/** @file squeezedcombobox.cpp */

// TQt includes.

#include <tqlistbox.h>
#include <tqcombobox.h>
#include <tqpair.h>
#include <tqtimer.h>
#include <tqvaluelist.h>
#include <tqstyle.h>
#include <tqapplication.h>
#include <tqtooltip.h>
#include <tqmap.h>

// Local includes.

#include "squeezedcombobox.h"
#include "squeezedcombobox.moc"

namespace Digikam
{

class SqueezedComboBoxPriv
{
public:

    SqueezedComboBoxPriv()
    {
        timer   = 0;
        tooltip = 0;
    }

    TQMap<int, TQString>   originalItems;

    TQTimer              *timer;

    SqueezedComboBoxTip *tooltip;
};

SqueezedComboBox::SqueezedComboBox(TQWidget *parent, const char *name)
                : TQComboBox(parent, name)
{
    d = new SqueezedComboBoxPriv;
    d->timer = new TQTimer(this);

    // See B.K.O #138747 : always for TQComboBox instance to use a TQListbox to 
    // render content independently of Widget style used. 
    setListBox(new TQListBox(this));

    d->tooltip = new SqueezedComboBoxTip(listBox()->viewport(), this);
    setMinimumWidth(100);

    connect(d->timer, TQT_SIGNAL(timeout()),
            this, TQT_SLOT(slotTimeOut()));

    connect(this, TQT_SIGNAL(activated( int )),
            this, TQT_SLOT(slotUpdateToolTip( int )));
}

SqueezedComboBox::~SqueezedComboBox()
{
    delete d->tooltip;
    delete d->timer;
    delete d;
}

TQSize SqueezedComboBox::sizeHint() const
{
    constPolish();
    TQFontMetrics fm = fontMetrics();

    int maxW = count() ? 18 : 7 * fm.width(TQChar('x')) + 18;
    int maxH = TQMAX( fm.lineSpacing(), 14 ) + 2;

    return style().tqsizeFromContents(TQStyle::CT_ComboBox, this,
    TQSize(maxW, maxH)).expandedTo(TQApplication::globalStrut());
}

void SqueezedComboBox::insertSqueezedItem(const TQString& newItem, int index)
{
    d->originalItems[index] = newItem;
    insertItem( squeezeText(newItem), index );

    // if this is the first item, set the tooltip.
    if (index == 0)
        slotUpdateToolTip(0);
}

void SqueezedComboBox::insertSqueezedList(const TQStringList& newItems, int index)
{
    for(TQStringList::const_iterator it = newItems.begin() ; it != newItems.end() ; ++it)
    {
        insertSqueezedItem(*it, index);
        index++;
    }
}

void SqueezedComboBox::resizeEvent(TQResizeEvent *)
{
    d->timer->start(200, true);
}

void SqueezedComboBox::slotTimeOut()
{
    TQMapIterator<int,TQString> it;
    for (it = d->originalItems.begin() ; it != d->originalItems.end();
         ++it)
    {
        changeItem(squeezeText(it.data()), it.key());
    }
}

TQString SqueezedComboBox::squeezeText(const TQString& original)
{
    // not the complete widgetSize is usable. Need to compensate for that.
    int widgetSize = width()-30;
    TQFontMetrics fm(fontMetrics());

    // If we can fit the full text, return that.
    if (fm.width(original) < widgetSize)
        return(original);

    // We need to squeeze.
    TQString sqItem = original; // prevent empty return value;
    widgetSize = widgetSize-fm.width("...");
    for (uint i = 0 ; i != original.length(); ++i)
    {
        if ((int)fm.width(original.right(i)) > widgetSize)
        {
            sqItem = TQString(original.left(i) + "...");
            break;
        }
    }
    return sqItem;
}

void SqueezedComboBox::slotUpdateToolTip(int index)
{
    TQToolTip::remove(this);
    TQToolTip::add(this, d->originalItems[index]);
}

TQString SqueezedComboBox::itemHighlighted()
{
    int curItem = listBox()->currentItem();
    return d->originalItems[curItem];
}

// ------------------------------------------------------------------------

SqueezedComboBoxTip::SqueezedComboBoxTip(TQWidget *parent, SqueezedComboBox *name)
                   : TQToolTip( parent )
{
    m_originalWidget = name;
}

void SqueezedComboBoxTip::maybeTip(const TQPoint &pos)
{
    TQListBox* listBox = m_originalWidget->listBox();
    if (!listBox)
        return;

    TQListBoxItem* selectedItem = listBox->itemAt( pos );
    if (selectedItem)
    {
        TQRect positionToolTip = listBox->itemRect(selectedItem);
        TQString toolTipText = m_originalWidget->itemHighlighted();
        if (!toolTipText.isNull())
            tip(positionToolTip, toolTipText);
    }
}

}  // namespace Digikam
