/***************************************************************************
                          table.cpp - Table widget
                             -------------------
    copyright            : (C) 2004      Michal Rudolf <mrudolf@kdewebdev.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.                                   *
 *                                                                         *
 ***************************************************************************/


/* KDE INCLUDES */
#include <tdelocale.h>
#include <tdeglobal.h>
#include <tdemessagebox.h>

/* QT INCLUDES */
#include <tqmetaobject.h>
#include <tqstring.h>
#include <tqwidget.h>
#include <tqstringlist.h>
#include <tqpoint.h>

/* OTHER INCLUDES */
#include "kommanderplugin.h"
#include "specials.h"
#include "table.h"

enum Functions {
  FirstFunction = 365,
  TBL_sortColumnExtra,
  TBL_keepCellVisible,
  TBL_selectCells,
  TBL_selectRow,
  TBL_selectColumn,
  TBL_setColumnReadOnly,
  TBL_setRowReadOnly,
  TBL_rowCount,
  TBL_colHeader,
  TBL_rowHeader,
  LastFunction
};


Table::Table(TQWidget *a_parent, const char *a_name)
  : TQTable(a_parent, a_name), KommanderWidget(TQT_TQOBJECT(this))
{
  TQStringList states;
  states << "default";
  setStates(states);
  setDisplayStates(states);
  KommanderPlugin::setDefaultGroup(Group::DCOP);
  KommanderPlugin::registerFunction(TBL_sortColumnExtra, "sortColumnExtra(TQString widget, int col, bool ascending, bool wholeRows)", i18n("Sets a column to sort ascending or descending. Optionally can sort with rows intact for database use."), 2, 4);
  KommanderPlugin::registerFunction(TBL_keepCellVisible, "keepCellVisible(TQString widget, int row, int col)", i18n("Scrolls the table so the cell indicated is visible."), 3);
  KommanderPlugin::registerFunction(TBL_selectCells, "selectCells(TQString widget, int row, int col, int row, int col)", i18n("Select cells using the upper left and lower right cell addresses"), 5);
  KommanderPlugin::registerFunction(TBL_selectRow, "selectRow(TQString widget, int row)", i18n("Select the row with the zero based index."), 2);
  KommanderPlugin::registerFunction(TBL_selectColumn, "selectColumn(TQString widget, int col)", i18n("Select the column with the zero based index."), 2);
  KommanderPlugin::registerFunction(TBL_setColumnReadOnly, "setColumnReadOnly(TQString widget, int col, bool Readonly)", i18n("Set the column read only using zero based index."), 3);
  KommanderPlugin::registerFunction(TBL_setRowReadOnly, "setRowReadOnly(TQString widget, int row, bool Readonly)", i18n("Set the row read only using zero based index."), 3);
  KommanderPlugin::registerFunction(TBL_rowCount, "rowCount(TQString widget)", i18n("Returns the number of rows of the table"), 1);
  KommanderPlugin::registerFunction(TBL_colHeader, "columnHeader(TQString widget, int Column)", i18n("Returns the text of the header for the column index"), 2);
  KommanderPlugin::registerFunction(TBL_rowHeader, "rowHeader(TQString widget, int Row)", i18n("Returns the text of the header for the row index"), 2);

}

Table::~Table()
{
}

TQString Table::currentState() const
{
  return TQString("default");
}

bool Table::isKommanderWidget() const
{
  return true;
}

TQStringList Table::associatedText() const
{
  return KommanderWidget::associatedText();
}

void Table::setAssociatedText(const TQStringList& a_at)
{
  KommanderWidget::setAssociatedText(a_at);
}

void Table::setPopulationText(const TQString& a_text)
{
  KommanderWidget::setPopulationText(a_text);
}

TQString Table::populationText() const
{
  return KommanderWidget::populationText();
}

void Table::populate()
{
  setWidgetText(KommanderWidget::evalAssociatedText( populationText()));
}

void Table::setWidgetText(const TQString&)
{
}

TQString Table::selectedArea()
{
  TQTableSelection sel = selection(currentSelection());
  return TQString("%1,%2,%3,%4").arg(sel.topRow()).arg(sel.leftCol()).arg(sel.bottomRow()).arg(sel.rightCol());
}


bool Table::isFunctionSupported(int f)
{
  return f == DCOP::currentColumn || f == DCOP::currentRow || f == DCOP::insertColumn || 
      f == DCOP::insertRow || f == DCOP::cellText || f == DCOP::setCellText || f == DCOP::setCellWidget || f == DCOP::cellWidget || f == DCOP::columnCount ||
      f == DCOP::removeRow || f == DCOP::removeColumn || f == DCOP::setColumnCaption ||
      f == DCOP::setRowCaption || f == DCOP::text || f == DCOP::setText || f == DCOP::selection || f == DCOP::geometry || f == DCOP::hasFocus || f == DCOP::getBackgroundColor || f == DCOP::setBackgroundColor  || (f >= FirstFunction && f <= LastFunction);
}

void Table::setCellWidget(int row, int col, const TQString & _widgetName)
{
  KommanderWidget *w = widgetByName(_widgetName);
  if (w)
  {
    TQWidget *widget = TQT_TQWIDGET(w->object());
    if (TQTable::cellWidget(row, col) != widget)
    { 
      setCurrentCell(-1, -1); //hack to not delete the cellwidget after clicking away to another cell. 
//I don't know why it does so, but without this on a click to another cell calls endEdit, which calls
//clearCellWidget, all this before the currentChanged signal is emitted.
//this hack does ugly things once table starts scrolling - let's try to minize damage
//we should have a way to test doe cellWidget looses focus and send it right or down too
      TQTable::ensureCellVisible(row, col);
      clearCellWidget(row, col);
      TQTable::setCellWidget(row, col, widget);
   }
  } else
    clearCellWidget(row, col);
}

TQString Table::cellWidget(int row, int col)
{

  TQWidget *widget = TQTable::cellWidget(row, col);
  if (widget)  
  {
    KommanderWidget *w = widgetByName(widget->name());
    if (w)
      return widget->name();
  }
  return TQString();
}

void Table::setCellText(int row, int col, const TQString& text)
{
  TQWidget *widget = TQTable::cellWidget(row, col);
  if (widget)  
  {
    KommanderWidget *w = widgetByName(widget->name());
    if (w)
      widget->reparent(parentDialog(), TQPoint(0,0));
  }  
  setText(row, col, text);
  endEdit(row, col, false, false);
}

void Table::clearCellWidget(int row, int col)
{
  TQTable::clearCellWidget(row, col); //just for debugging
}

void Table::contextMenuEvent( TQContextMenuEvent * e )
{
  e->accept();
  TQPoint p = e->globalPos();
  emit contextMenuRequested(p.x(), p.y());
}

void Table::columnClicked(int col)
{
  emit columnHeaderClicked(col);
  static bool ascending = TRUE;
  if (!sorting()) return;
  ascending=!ascending;
  sortColumn( col, ascending, TRUE);
}

TQString Table::handleDCOP(int function, const TQStringList& args)
{
  switch (function) 
  {
    case DCOP::cellText:
      return text(args[0].toInt(), args[1].toInt());
    case DCOP::setCellText:
      if (numRows() >= args[0].toInt() && numCols() >+ args[1].toInt())
        setCellText(args[0].toInt(), args[1].toInt(), args[2]);
      break;
    case DCOP::setCellWidget:
      if (numRows() >= args[0].toInt() && numCols() >+ args[1].toInt())
        setCellWidget(args[0].toInt(), args[1].toInt(), args[2]);
      break;
    case DCOP::cellWidget:
      return cellWidget(args[0].toInt(), args[1].toInt());
      break;
    case DCOP::insertRow:
      insertRows(args[0].toInt(), args.count() == 1 ? 1 : args[1].toInt());
      break;
    case DCOP::insertColumn:
      insertColumns(args[0].toInt(), args.count() == 1 ? 1 : args[1].toInt());
      break;
    case DCOP::currentColumn:
      return TQString::number(currentColumn());
    case DCOP::currentRow:
      return TQString::number(currentRow());
    case DCOP::columnCount:
      return TQString::number(numCols());
      break;
    case DCOP::removeColumn:
    if (numCols() >= args[0].toInt())
    {
      if (!args[1].toInt())
        removeColumn(args[0].toInt());
      else
      {
        int column = args[0].toInt();
        int lines = args[1].toInt();
        for (int i = 0; i < lines; i++)
          removeColumn(column);
      }
      break;
    }
    case TBL_rowCount:
      return TQString::number(numRows());
      break;
    case DCOP::removeRow:
    {
      int row = args[0].toInt();
      int lines = args[1].toInt();
      for (int i = 0; i < lines; i++)
        removeRow(row);
      break;
    }
    case DCOP::setColumnCaption:
      if (numCols() >= args[0].toInt())
        horizontalHeader()->setLabel(args[0].toInt(), args[1]);
      break;
    case DCOP::setRowCaption:
      if (numRows() >= args[0].toInt())
        verticalHeader()->setLabel(args[0].toInt(), args[1]);
      break;
    case DCOP::text:
    {
      TQString rows;
      for (int r = 0; r < numRows(); r++)
      {
        TQString row;
        for (int c = 0; c < numCols(); c++)
        {
          if (c)
            row += '\t';
          row += text(r,c);
        }
        if (r)
          rows += '\n';
        rows += row;
      }
      return rows;
    }
    case DCOP::setText:
    {
      int r = 0, c = 0;
      setNumCols(0);
      setNumRows(0);
      TQStringList rows;
      TQStringList row;
      rows = TQStringList::split("\n", args[0], true);
      setNumRows(rows.count());
      for (TQStringList::Iterator it = rows.begin(); it != rows.end(); ++it, ++r) 
      {
        row = TQStringList::split("\t", *it, true);
        if (!r)
          setNumCols(row.count());
        c = 0;
        for (TQStringList::Iterator itr = row.begin(); itr != row.end(); ++itr, ++c)
          setText(r, c, *itr);
      }
      break;
    }
    case DCOP::selection:
      return selectedArea();
      break;
    case DCOP::getBackgroundColor:
      return this->paletteBackgroundColor().name();
      break;
    case DCOP::setBackgroundColor:
    {
      TQColor color;
      color.setNamedColor(args[0]);
      this->setPaletteBackgroundColor(color);
      break;
    }
    case TBL_sortColumnExtra:
      if (numCols() >= args[0].toInt())
        TQTable::sortColumn(args[0].toInt(), args[1].toInt(), args[2].toInt());
      break;
    case TBL_keepCellVisible:
      if (numRows() >= args[0].toInt() && numCols() >+ args[1].toInt())
        TQTable::ensureCellVisible(args[0].toInt()-1, args[1].toInt()-1);
      break;
    case   TBL_selectCells:
      if (numRows() >= args[0].toInt() && numCols() >+ args[1].toInt() && numRows() >= args[2].toInt() && numCols() >+ args[3].toInt())
        TQTable::selectCells (args[0].toInt(), args[1].toInt(), args[2].toInt(), args[3].toInt());
      break;
    case TBL_selectRow:
      if (numRows() >= args[0].toInt())
        TQTable::selectRow (args[0].toInt());
      break;
    case TBL_selectColumn:
      if (numCols() >= args[0].toInt())
        TQTable::selectColumn (args[0].toInt());
      break;
    case TBL_setColumnReadOnly:
      if (numCols() >= args[0].toInt())
        TQTable::setColumnReadOnly (args[0].toInt(), args[1].toUInt());
      break;
    case TBL_setRowReadOnly:
      if (numRows() >= args[0].toInt())
        TQTable::setRowReadOnly (args[0].toInt(), args[1].toUInt());
      break;
    case TBL_colHeader:
    {
      TQHeader* hdr = TQTable::horizontalHeader();
      if (numCols() >= args[0].toInt())
        return hdr->label(args[0].toInt());
      else
        return "No column at index "+args[0];
      break;
    }
    case TBL_rowHeader:
    {
      TQHeader* hdr = TQTable::verticalHeader();
      if (numRows() >= args[0].toInt())
        return hdr->label(args[0].toInt());
      else
        return "No row at index "+args[0];
      break;
    }
    case DCOP::geometry:
    {
      TQString geo = TQString::number(this->x())+" "+TQString::number(this->y())+" "+TQString::number(this->width())+" "+TQString::number(this->height());
      return geo;
      break;
    }
    case DCOP::hasFocus:
      return TQString::number(this->hasFocus());
      break;
    default:
      return KommanderWidget::handleDCOP(function, args);
  }
  return TQString();
}

#include "table.moc"

