/* -------------------------------------------------------------

   matchview.cpp (part of The KDE Dictionary Client)

   Copyright (C) 2000-2001 Christian Gebauer <gebauer@kde.org>

   This file is distributed under the Artistic License.
   See LICENSE for details.

   -------------------------------------------------------------

   MatchView  This widget contains the list of matching definitions

 ------------------------------------------------------------- */

#include <tqclipboard.h>
#include <tqcombobox.h>
#include <tqpushbutton.h>
#include <tqheader.h>
#include <tqlayout.h>
#include <tqpainter.h>
#include <tqregexp.h>

#include <tdepopupmenu.h>
#include <tdelocale.h>
#include <tdeapplication.h>
#include <kiconloader.h>
#include <tdemessagebox.h>

#include "dict.h"
#include "options.h"
#include "matchview.h"


//*********  MatchViewItem  ********************************************


MatchViewItem::MatchViewItem(TQListView *view, const TQString &text)
  : TQListViewItem(view,text)
{
}


MatchViewItem::MatchViewItem(TQListView *view,TQListViewItem *after,const TQString &text)
  : TQListViewItem(view,after,text)
{
}


MatchViewItem::MatchViewItem(TQListViewItem *item,const TQString &text,const TQString &commandStr)
: TQListViewItem(item,text), command(commandStr)
{
}


MatchViewItem::MatchViewItem(TQListViewItem *item,TQListViewItem *after,const TQString &text,const TQString &commandStr)
: TQListViewItem(item,after,text), command(commandStr)
{
}


MatchViewItem::~MatchViewItem()
{
}


void MatchViewItem::setOpen(bool o)
{
  if (o && !childCount()) {
    listView()->setUpdatesEnabled(false);

    MatchViewItem *sub=0;
    TQString command, label;
    TQRegExp exp("\"*\"", true, true);
    TQStringList::iterator it;
    for (it = subEntrys.begin(); it != subEntrys.end(); ++it) {
      command = "define ";
      command += (*it);
      command += "\r\n";
      exp.search((*it));
      label = exp.cap();
      label = label.mid(1, label.length()-2); // remove quotes
      if (sub)
        sub = new MatchViewItem(this, sub, label, command);
      else
        sub = new MatchViewItem(this, label, command);
    }

    subEntrys.clear();

    listView()->setUpdatesEnabled(true);
  }

  if (childCount())
    TQListViewItem::setOpen(o);
}


void MatchViewItem::paintCell(TQPainter *p, const TQColorGroup &cg, int column, int width, int alignment)
{
  if(command.isEmpty()) {
    TQFont font=p->font();
    font.setBold(true);
    p->setFont(font);
  }
  TQListViewItem::paintCell(p,cg,column,width,alignment);
}


//********* MatchView  ******************************************


MatchView::MatchView(TQWidget *parent, const char *name)
  : TQWidget(parent,name),getOn(false),getAllOn(false)
{
  setCaption(tdeApp->makeStdCaption(i18n("Match List")));

  TQVBoxLayout * boxLayout = new TQVBoxLayout(this, 1, 0);

  boxLayout->addSpacing(1);
  w_strat = new TQComboBox(false,this);
  w_strat->setFixedHeight(w_strat->sizeHint().height());
  connect(w_strat,TQ_SIGNAL(activated(int)),this,TQ_SLOT(strategySelected(int)));
  boxLayout->addWidget(w_strat,0);
  boxLayout->addSpacing(1);

  w_list = new TQListView(this);
  w_list->setFocusPolicy(TQWidget::StrongFocus);
  w_list->header()->hide();
  w_list->addColumn("foo");
  w_list->setColumnWidthMode(0,TQListView::Maximum);
  w_list->setColumnWidth(0,0);
  w_list->setSelectionMode(TQListView::Extended);
  w_list->setTreeStepSize(18);
  w_list->setSorting(-1);                                 // disable sorting
  w_list->setMinimumHeight(w_strat->sizeHint().height());
  connect(w_list,TQ_SIGNAL(selectionChanged()),TQ_SLOT(enableGetButton()));
  connect(w_list,TQ_SIGNAL(returnPressed(TQListViewItem *)),TQ_SLOT(returnPressed(TQListViewItem *)));
  connect(w_list,TQ_SIGNAL(doubleClicked(TQListViewItem *)),TQ_SLOT(getOneItem(TQListViewItem *)));
  connect(w_list,TQ_SIGNAL(mouseButtonPressed(int, TQListViewItem *, const TQPoint &, int)),
                 TQ_SLOT(mouseButtonPressed(int, TQListViewItem *, const TQPoint &, int)));
  connect(w_list,TQ_SIGNAL(rightButtonPressed(TQListViewItem *,const TQPoint &,int)),TQ_SLOT(buildPopupMenu(TQListViewItem *,const TQPoint &,int)));
  boxLayout->addWidget(w_list,1);

  boxLayout->addSpacing(1);
  w_get = new TQPushButton(i18n("&Get Selected"),this);
  w_get->setFixedHeight(w_get->sizeHint().height()-3);
  w_get->setMinimumWidth(w_get->sizeHint().width()-20);
  w_get->setEnabled(false);
  connect(w_get, TQ_SIGNAL(clicked()), this, TQ_SLOT(getSelected()));
  boxLayout->addWidget(w_get,0);

  w_getAll = new TQPushButton(i18n("Get &All"),this);
  w_getAll->setFixedHeight(w_getAll->sizeHint().height()-3);
  w_getAll->setMinimumWidth(w_getAll->sizeHint().width()-20);
  w_getAll->setEnabled(false);
  connect(w_getAll, TQ_SIGNAL(clicked()), this, TQ_SLOT(getAll()));
  boxLayout->addWidget(w_getAll,0);
  connect(interface,TQ_SIGNAL(matchReady(const TQStringList &)),this,TQ_SLOT(newList(const TQStringList &)));
  rightBtnMenu = new TDEPopupMenu();
}


MatchView::~MatchView()
{
}


void MatchView::updateStrategyCombo()
{
  w_strat->clear();
  w_strat->insertStringList(global->strategies);
  w_strat->setCurrentItem(global->currentStrategy);
}


bool MatchView::selectStrategy(const TQString &strategy) const
{
  int newCurrent = global->strategies.findIndex(strategy);
  if (newCurrent == -1)
    return false;
  else {
    global->currentStrategy = newCurrent;
    w_strat->setCurrentItem(global->currentStrategy);
    return true;
  }
}


void MatchView::match(const TQString &query)
{
  interface->match(query.utf8());
}


void MatchView::closeEvent ( TQCloseEvent * e )
{
  e->accept();                            // hides the widget
  emit(windowClosed());
}


void MatchView::strategySelected(int num)
{
  global->currentStrategy = num;
}


void MatchView::enableGetButton()
{
  if (w_getAll->isEnabled()) {
    w_get->setEnabled(true);
    getOn = true;
  }
}


void MatchView::mouseButtonPressed(int button, TQListViewItem *, const TQPoint &, int)
{
  if (button == TQt::MidButton)
    emit(clipboardRequested());
}


void MatchView::returnPressed(TQListViewItem *)
{
  getSelected();
}


void MatchView::getOneItem(TQListViewItem *i)
{
  TQStringList defines;

  if ((!i->childCount())&&(i->parent()))
    defines.append(((MatchViewItem *)(i))->command);
  else {
    i = i->firstChild();
    while (i) {
      defines.append(((MatchViewItem *)(i))->command);
      i = i->nextSibling();
    }
  }

  doGet(defines);
}


void MatchView::getSelected()
{
  TQStringList defines;
  MatchViewItem *top = static_cast<MatchViewItem*>(w_list->firstChild());
  MatchViewItem *sub;

  while (top) {
    if (top->isSelected()&&(!top->subEntrys.isEmpty())) {
      TQString command;
      TQStringList::iterator it;
      for (it = top->subEntrys.begin(); it != top->subEntrys.end(); ++it) {
        command = "define ";
        command += (*it);
        command += "\r\n";
        defines.append(command);
      }
    } else {
      sub = static_cast<MatchViewItem*>(top->firstChild());
      while (sub) {
        if (top->isSelected()||sub->isSelected())
          defines.append(sub->command);
        sub = static_cast<MatchViewItem*>(sub->nextSibling());
      }
    }
    top = static_cast<MatchViewItem*>(top->nextSibling());
  }
  doGet(defines);
}


void MatchView::getAll()
{
  TQStringList defines;
  MatchViewItem *top = static_cast<MatchViewItem*>(w_list->firstChild());
  MatchViewItem *sub;

  while (top) {
    if (!top->subEntrys.isEmpty()) {
      TQString command;
      TQStringList::iterator it;
      for (it = top->subEntrys.begin(); it != top->subEntrys.end(); ++it) {
        command = "define ";
        command += (*it);
        command += "\r\n";
        defines.append(command);
      }
    } else {
      sub = static_cast<MatchViewItem*>(top->firstChild());
      while (sub) {
        defines.append(sub->command);
        sub = static_cast<MatchViewItem*>(sub->nextSibling());
      }
    }
    top = static_cast<MatchViewItem*>(top->nextSibling());
  }
  doGet(defines);
}


void MatchView::doGet(TQStringList &defines)
{
  if (defines.count() > 0) {
    if (defines.count() > global->maxDefinitions) {
      KMessageBox::sorry(global->topLevel,i18n("You have selected %1 definitions,\nbut Kdict will fetch only the first %2 definitions.\nYou can modify this limit in the Preferences Dialog.")
                                             .arg(defines.count()).arg(global->maxDefinitions));
      while (defines.count()>global->maxDefinitions)
        defines.pop_back();
    }
    interface->getDefinitions(defines);
  }
}


void MatchView::newList(const TQStringList &matches)
{
  MatchViewItem *top=0;
  bool initialOpen = (matches.count()<200);
  int numDb = 0;

  rightBtnMenu->hide();
  w_list->clear();
  w_list->setColumnWidth(0,0);
  w_list->setUpdatesEnabled(false);
  w_get->setEnabled(false);
  getOn = false;

  if (matches.isEmpty()) {
    w_list->setColumnWidth(0,w_get->width()-5);
    w_list->setRootIsDecorated(false);
    w_getAll->setEnabled(false);
    getAllOn = false;
    top = new MatchViewItem(w_list,top,i18n(" No Hits"));
  } else {
    w_list->setRootIsDecorated(true);
    w_getAll->setEnabled(true);
    getAllOn = true;
    TQString lastDb, db, match;

    TQStringList::const_iterator it;
    for (it = matches.begin(); it != matches.end(); ++it) {
      db = (*it).section(' ', 0, 0);

      if (db != lastDb) {
        numDb++;
        if (top) {
          top->setOpen(initialOpen);
          top = new MatchViewItem(w_list, top, db);
        } else
          top = new MatchViewItem(w_list, db);
        top->setExpandable(true);
        lastDb = db;
      }

      if (top)
        top->subEntrys.append(*it);
    }

    if ((numDb == 1)||(initialOpen))
      top->setOpen(true);
  }

  w_list->setUpdatesEnabled(true);
  w_list->repaint();
  w_list->setFocus();
}


// construct the right-mouse-button-popup-menu on demand
void MatchView::buildPopupMenu(TQListViewItem *i, const TQPoint &_point, int)
{
  rightBtnMenu->clear();

  if ((i!=0L)&&(i->isExpandable()||i->parent())) {
    popupCurrent = (MatchViewItem *)(i);
    rightBtnMenu->insertItem(i18n("&Get"),this,TQ_SLOT(popupGetCurrent()));
    if (!i->isExpandable()) {       // toplevel item -> only "get"
      rightBtnMenu->insertItem(i18n("&Match"),this,TQ_SLOT(popupMatchCurrent()));
      rightBtnMenu->insertItem(i18n("&Define"),this,TQ_SLOT(popupDefineCurrent()));
    }
    rightBtnMenu->insertSeparator();
  }

  tdeApp->clipboard()->setSelectionMode(false);
  TQString text = tdeApp->clipboard()->text();
  if (text.isEmpty()) {
    tdeApp->clipboard()->setSelectionMode(true);
    text = tdeApp->clipboard()->text();
  }
  if (!text.isEmpty()) {
    popupClip = tdeApp->clipboard()->text();
    rightBtnMenu->insertItem(i18n("Match &Clipboard Content"),this,TQ_SLOT(popupMatchClip()));
    rightBtnMenu->insertItem(SmallIcon("define_clip"),i18n("D&efine Clipboard Content"),this,TQ_SLOT(popupDefineClip()));
    rightBtnMenu->insertSeparator();
  }

  int ID = rightBtnMenu->insertItem(i18n("Get &Selected"),this,TQ_SLOT(getSelected()));
  rightBtnMenu->setItemEnabled(ID,getOn);
  ID = rightBtnMenu->insertItem(i18n("Get &All"),this,TQ_SLOT(getAll()));
  rightBtnMenu->setItemEnabled(ID,getAllOn);

  if (w_list->childCount()) {
    rightBtnMenu->insertSeparator();
    rightBtnMenu->insertItem(i18n("E&xpand List"),this,TQ_SLOT(expandList()));
    rightBtnMenu->insertItem(i18n("C&ollapse List"),this,TQ_SLOT(collapseList()));
  }

  rightBtnMenu->popup(_point);
}


void MatchView::popupGetCurrent()
{
  getOneItem(popupCurrent);
}


void MatchView::popupDefineCurrent()
{
  emit(defineRequested(popupCurrent->text(0)));
}


void MatchView::popupMatchCurrent()
{
  emit(matchRequested(popupCurrent->text(0)));
}


void MatchView::popupDefineClip()
{
  emit(defineRequested(popupClip));
}


void MatchView::popupMatchClip()
{
  emit(matchRequested(popupClip));
}


void MatchView::expandList()
{
  TQListViewItem *top = w_list->firstChild();

  while (top) {
    w_list->setOpen(top,true);
    top = top->nextSibling();
  }
}


void MatchView::collapseList()
{
  w_list->setCurrentItem(w_list->firstChild());
  TQListViewItem *top = w_list->firstChild();

  while (top) {
    w_list->setOpen(top,false);
    top = top->nextSibling();
  }
}

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

#include "matchview.moc"
