/***************************************************************************
                          kmymoneycompletion.cpp  -  description
                             -------------------
    begin                : Mon Apr 26 2004
    copyright            : (C) 2000-2004 by Michael Edwardes
    email                : mte@users.sourceforge.net
                           Javier Campos Morales <javi_c@users.sourceforge.net>
                           Felix Rodriguez <frodriguez@users.sourceforge.net>
                           John C <thetacoturtle@users.sourceforge.net>
                           Thomas Baumgart <ipwizard@users.sourceforge.net>
                           Kevin Tambascio <ktambascio@users.sourceforge.net>
 ***************************************************************************/

/***************************************************************************
 *                                                                         *
 *   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.                                   *
 *                                                                         *
 ***************************************************************************/

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

// ----------------------------------------------------------------------------
// TQt Includes

#include <tqapplication.h>

// ----------------------------------------------------------------------------
// TDE Includes

#include <tdelistview.h>

// ----------------------------------------------------------------------------
// Project Includes

#include "kmymoneycompletion.h"
#include <kmymoney/kmymoneyselector.h>
#include <kmymoney/kmymoneylistviewitem.h>
#include "./kmymoneycombo.h"

const int kMyMoneyCompletion::MAX_ITEMS = 16;

kMyMoneyCompletion::kMyMoneyCompletion(TQWidget *parent, const char *name ) :
  TQVBox(parent, name, WType_Popup)
{
  m_selector = new KMyMoneySelector(this);
  m_selector->listView()->setFocusProxy(this);

  m_parent = parent;
  setFocusProxy((parent) ? parent : (TQWidget*) TQWidget::NoFocus);
  setFrameStyle(TQFrame::PopupPanel | TQFrame::Raised);
  connectSignals(m_selector, m_selector->listView());
}

void kMyMoneyCompletion::connectSignals(TQWidget* widget, TDEListView* lv)
{
  m_widget = widget;
  m_lv = lv;
  connect(lv, TQ_SIGNAL(executed(TQListViewItem*,const TQPoint&,int)), this, TQ_SLOT(slotItemSelected(TQListViewItem*,const TQPoint&,int)));
}

kMyMoneyCompletion::~kMyMoneyCompletion()
{
}

void kMyMoneyCompletion::adjustSize(void)
{
  TQListViewItemIterator it(m_lv, TQListViewItemIterator::Visible);
  int count = 0;
  while(it.current()) {
    ++count;
    ++it;
  }
  adjustSize(count);
}

void kMyMoneyCompletion::adjustSize(const int count)
{
  int w = m_widget->sizeHint().width();
  if(m_parent && w < m_parent->width())
    w = m_parent->width();

  TQFontMetrics fm(font());
  if(w < fm.maxWidth()*15)
    w = fm.maxWidth()*15;

  int h = 0;
  TQListViewItemIterator it(m_lv, TQListViewItemIterator::Visible);
  TQListViewItem* item = it.current();
  if(item)
    h = item->height() * (count > MAX_ITEMS ? MAX_ITEMS : count);

  // the offset of 4 in the next statement avoids the
  // display of a scroll bar if count < MAX_ITEMS.
  resize(w, h+4);

  if(m_parent) {
    // the code of this basic block is taken from TDECompletionBox::show()
    // and modified to our local needs

    // this is probably better, once kde switches to requiring qt3.1
    // TQRect screenSize = TQApplication::desktop()->availableGeometry(d->m_parent);
    // for now use this since it's qt3.0.x-safe
    TQRect screenSize = TQApplication::desktop()->screenGeometry(TQApplication::desktop()->screenNumber(m_parent));

    TQPoint orig = m_parent->mapToGlobal( TQPoint(0, m_parent->height()) );
    int x = orig.x();
    int y = orig.y();

    if ( x + width() > screenSize.right() )
        x = screenSize.right() - width();

    // check for the maximum height here to avoid flipping
    // of the completion box from top to bottom of the
    // edit widget. The offset (y) is certainly based
    // on the actual height.
    if(item) {
      if ((y + item->height()*MAX_ITEMS) > screenSize.bottom() )
        y = y - height() - m_parent->height();
    }

    move( x, y);
  }
}

void kMyMoneyCompletion::show(bool presetSelected)
{
  if(!m_id.isEmpty() && presetSelected)
    m_selector->setSelected(m_id);

  adjustSize();

  if(m_parent) {
    m_parent->installEventFilter(this);
    // make sure to install the filter for the combobox lineedit as well
    // We have do this here because TQObject::installEventFilter() is not
    // declared virtual and we have no chance to override it in KMyMoneyCombo
    KMyMoneyCombo* c = dynamic_cast<KMyMoneyCombo*>(m_parent);
    if(c && c->lineEdit()) {
      c->lineEdit()->installEventFilter(this);
    }
  }

  TQVBox::show();
}

void kMyMoneyCompletion::hide(void)
{
  if(m_parent) {
    m_parent->removeEventFilter(this);
    // make sure to uninstall the filter for the combobox lineedit as well
    // We have do this here because TQObject::installEventFilter() is not
    // declared virtual and we have no chance to override it in KMyMoneyCombo
    KMyMoneyCombo* c = dynamic_cast<KMyMoneyCombo*>(m_parent);
    if(c && c->lineEdit()) {
      c->lineEdit()->removeEventFilter(this);
    }
  }
  TQVBox::hide();
}

bool kMyMoneyCompletion::eventFilter(TQObject* o, TQEvent* e)
{
  int type = e->type();

  KMyMoneyCombo *c = dynamic_cast<KMyMoneyCombo*>(m_parent);
  TQListViewItem* item;
  if(o == m_parent || (c && o == c->lineEdit())) {
    if(isVisible()) {
      if(type == TQEvent::KeyPress) {
        TQKeyEvent* ev = static_cast<TQKeyEvent*> (e);
        TQKeyEvent evt(TQEvent::KeyPress,
                      Key_Down, 0, ev->state(), TQString(),
                      ev->isAutoRepeat(), ev->count());
        TQKeyEvent evbt(TQEvent::KeyPress,
                      Key_Up, 0, ev->state(), TQString(),
                      ev->isAutoRepeat(), ev->count());

        switch(ev->key()) {
          case Key_Tab:
          case Key_BackTab:
            slotItemSelected(m_lv->currentItem(), TQPoint(0,0), 0);
            break;

          case Key_Down:
          case Key_Next:
            item = m_lv->currentItem();
            while(item) {
              item = item->itemBelow();
              if(item && selector()->match(m_lastCompletion, item))
                break;
            }
            if(item) {
              m_lv->setCurrentItem(item);
              selector()->ensureItemVisible(item);
            }
            ev->accept();
            return true;

          case Key_Up:
          case Key_Prior:
            item = m_lv->currentItem();
            while(item) {
              item = item->itemAbove();
              if(item && selector()->match(m_lastCompletion, item))
                break;
            }
            if(item) {
              m_lv->setCurrentItem(item);
              // make sure, we always see a possible (non-selectable) group item
              if(item->itemAbove())
                item = item->itemAbove();
              selector()->ensureItemVisible(item);
            }
            ev->accept();
            return true;

          case Key_Escape:
            hide();
            ev->accept();
            return true;

          case Key_Enter:
          case Key_Return:
            slotItemSelected(m_lv->currentItem(), TQPoint(0,0), 0);
            ev->accept();
            return true;

          case Key_Home:
          case Key_End:
            if(ev->state() & ControlButton) {
              item = m_lv->currentItem();
              if(ev->key() == Key_Home) {
                while(item && item->itemAbove()) {
                  item = item->itemAbove();
                }
                while(item && !selector()->match(m_lastCompletion, item)) {
                  item = item->itemBelow();
                }
              } else {
                while(item && item->itemBelow()) {
                  item = item->itemBelow();
                }
                while(item && !selector()->match(m_lastCompletion, item)) {
                  item = item->itemAbove();
                }
              }
              if(item) {
                m_lv->setCurrentItem(item);
                // make sure, we always see a possible (non-selectable) group item
                if(item->itemAbove())
                  item = item->itemAbove();
                selector()->ensureItemVisible(item);
              }
              ev->accept();
              return true;
            }
            break;

          default:
            break;

        }
      }
    }
  }
  return TQVBox::eventFilter(o, e);
}

void kMyMoneyCompletion::slotMakeCompletion(const TQString& txt)
{
  int cnt = selector()->slotMakeCompletion(txt.stripWhiteSpace());

  if(m_parent && m_parent->isVisible() && !isVisible() && cnt)
    show(false);
  else {
    if(cnt != 0) {
      adjustSize();
    } else {
      hide();
    }
  }
}

void kMyMoneyCompletion::slotItemSelected(TQListViewItem *item, const TQPoint&, int)
{
  KMyMoneyListViewItem* it_v = static_cast<KMyMoneyListViewItem*>(item);
  if(it_v && it_v->isSelectable()) {
    TQString id = it_v->id();
    // hide the widget, so we can debug the slots that are connect
    // to the signal we emit very soon
    hide();
    m_id = id;
    emit itemSelected(id);
  }
}

void kMyMoneyCompletion::setSelected(const TQString& id)
{
  m_id = id;
  m_selector->setSelected(id, true);
}

#include "kmymoneycompletion.moc"
