/***************************************************************************
                          kwordquizview.cpp  -  description
                             -------------------
    begin                : Wed Jul 24 20:12:30 PDT 2002
    copyright            : (C) 2002 by Peter Hedlund
    email                : peter.hedlund@kdemail.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.                                   *
 *                                                                         *
 ***************************************************************************/

// include files for TQt
#include <tqpainter.h>
#include <tqtable.h>
#include <tqclipboard.h>
#include <tqlineedit.h>

// include files for KDE
#include <tdelocale.h> //i18n
#include <tdemessagebox.h> // always useful
#include <krandomsequence.h>
#include <tdeglobalsettings.h>
#include <knotifyclient.h>

// application specific includes
#include "kwordquizview.h"
#include "kwordquizdoc.h"
#include "kwordquiz.h"
#include "dlgsort.h"
#include "prefs.h"
#include "dlgrc.h"
#include "dlgspecchar.h"

TQValueList<WQUndo> *KWordQuizView::m_undoList = 0L;

KWTQTableItem::KWTQTableItem(TQTable* table, EditType et, const TQString & text) : TQTableItem(table, et, text)
{}

int KWTQTableItem::alignment() const
{
  bool num;
  bool ok1 = false;
  bool ok2 = false;
  (void)text().toInt(&ok1);
  if (!ok1)
    (void)text().toDouble(&ok2);
  num = ok1 || ok2;

  return (num ? TQt::AlignRight : TQt::AlignAuto) | TQt::AlignVCenter;
}

KWordQuizView::KWordQuizView(TQWidget *parent, const char *name) : TQTable(parent, name)
{
  if(!m_undoList)
    m_undoList = new TQValueList<WQUndo>();

  setNumCols(2);
  setNumRows(50);
  setColumnWidth(1, 250);
  setColumnWidth(0, 250);
  setSelectionMode(TQTable::Single);
  horizontalHeader()->setLabel(0, i18n("Column 1"));
  horizontalHeader()->setLabel(1, i18n("Column 2"));
  setMinimumSize(0, 0); //This seems to improve resizing of main window
  dlgSpecChar = 0;
}

KWordQuizView::~KWordQuizView()
{
}

KWordQuizDoc *KWordQuizView::getDocument() const
{
  KWordQuizApp *theApp=(KWordQuizApp *) parentWidget();
  return theApp->getDocument();
}

void KWordQuizView::print(KPrinter *pPrinter)
{
  TQPainter painter;

  //type 0 Vocabulary list
  //type 1 Vocabulary exam
  //type 2 Flashcards
  int type = pPrinter->option("kde-kwordquiz-type").toInt();

  //I think working with screen resolution is enough for our purposes
  int res = pPrinter->resolution();
  int pad = 2;
  int marg = res;
  int card_marg = res / 2;
  int card_width = 5 * res;
  int card_height = 3 * res;
  int card_text_marg = res /5;
  int card_line_top = 30;

  if (type == 2)
    pPrinter->setOrientation(KPrinter::Landscape);

  painter.begin(pPrinter);

  int pageNum = 1;

  int cw0 = verticalHeader()->width();
  int cw1 = columnWidth(0);
  int cw2 = columnWidth(1);
  int cw3 = 0;



  if (type == 1)
    cw3 = 50;

  int gridWidth = cw0 + cw1 + cw2 + cw3;
  int lPos = marg;
  int tPos = marg + horizontalHeader()->height();

  TQRect w = painter.window();

  doNewPage(painter, res, type);

  if (type == 2)
  {
    tPos = card_marg;
    for (int rc = 0; rc < numRows(); ++rc)
    {

      //draw rectangle 2 cards wide
      painter.drawRect(card_marg, tPos, 2 * card_width, card_height);
      //divide into 2 cards with line
      painter.drawLine(card_marg + card_width, tPos, card_marg + card_width, tPos + card_height);
      //draw line inside card
      painter.drawLine(card_marg + card_text_marg, tPos + card_line_top,
        card_marg + card_width - card_text_marg, tPos + card_line_top);
      painter.drawLine(card_marg + card_width + card_text_marg, tPos + card_line_top,
        card_marg + card_width + card_width - card_text_marg, tPos + card_line_top);
      //draw headers
      painter.setFont(TDEGlobalSettings::generalFont());
      painter.drawText(card_marg + card_text_marg, tPos, card_width, card_line_top, AlignAuto | AlignVCenter, horizontalHeader()->label(0));
      painter.drawText(card_marg + card_width + card_text_marg, tPos, card_width, card_line_top, AlignAuto | AlignVCenter, horizontalHeader()->label(1));
      //draw text
      painter.setFont(font());
      painter.drawText(card_marg + card_text_marg, tPos + card_line_top, card_width - (2 * card_text_marg), card_height - card_line_top, AlignHCenter | AlignVCenter | WordBreak, text(rc, 0));
      painter.drawText(card_marg + card_width + card_text_marg, tPos + card_line_top, card_width - (2 * card_text_marg), card_height - card_line_top, AlignHCenter | AlignVCenter | WordBreak, text(rc, 1));

      tPos = tPos + card_height + card_line_top;

      if (tPos + card_height + card_line_top > w.height() - card_marg)
      {
        doEndOfPage(painter, tPos, pageNum++, res, type);
        tPos = card_marg;
        pPrinter->newPage();
        doNewPage(painter, res, type);
      }
    }

  }
  else
  {

    for (int rc = 0; rc < numRows(); ++rc)
    {
      painter.drawLine(lPos, tPos, lPos + gridWidth, tPos);
      painter.setFont(TDEGlobalSettings::generalFont());

      painter.drawText(lPos, tPos, cw0 - pad, rowHeight(rc), AlignRight | AlignVCenter, TQString::number(rc + 1));

      painter.setFont(font());
      painter.drawText(lPos + cw0 + pad, tPos, cw1, rowHeight(rc), AlignAuto | AlignVCenter | WordBreak, text(rc, 0));

      if (type == 0)
        painter.drawText(lPos + cw0 + cw1 + pad, tPos, cw2, rowHeight(rc), AlignAuto | AlignVCenter | WordBreak, text(rc, 1));

      tPos = tPos + rowHeight(rc);

      if (tPos + rowHeight(rc + 1) > w.height() - marg)
      {
        doEndOfPage(painter, tPos, pageNum++, res, type);
        tPos = marg + horizontalHeader()->height();
        pPrinter->newPage();
        doNewPage(painter, res, type);
      }
    }
  }
  doEndOfPage(painter, tPos, pageNum++,  res, type);
  painter.end();
}

void KWordQuizView::doNewPage( TQPainter & painter, int res, int type )
{
    int cw0 = verticalHeader()->width();
    int cw1 = columnWidth(0);
    int cw2 = columnWidth(1);
    int cw3 = 0;
    int marg = res;
    int card_marg = res / 2;
    int pad = 2;

    if (type == 1)
      cw3 = 50;

    TQRect w = painter.window();

    painter.setFont(TDEGlobalSettings::generalFont());

    if (type == 2)
    {
      painter.drawText(card_marg, card_marg - 20, i18n("KWordQuiz - %1").arg(getDocument()->URL().fileName()));
      return;
    }
    painter.drawLine(marg, marg, marg + cw0 + cw1 + cw2 + cw3, marg);

    painter.drawText(marg, marg - 20, i18n("KWordQuiz - %1").arg(getDocument()->URL().fileName()));

    if (type == 1)
    {
      TQString score = i18n("Name:_____________________________ Date:__________");
      TQRect r = painter.boundingRect(0, 0, 0, 0, AlignAuto, score);
      painter.drawText(w.width() - r.width() - marg, marg - 20, score);
    }

    painter.drawText(marg, marg, cw0, horizontalHeader()->height(), AlignRight | AlignVCenter, "");

    painter.drawText(marg + cw0 + pad, marg, cw1, horizontalHeader()->height(), AlignAuto | AlignVCenter, horizontalHeader()->label(0));
    painter.drawText(marg + cw0 + cw1 + pad, marg, cw2, horizontalHeader()->height(), AlignAuto | AlignVCenter, horizontalHeader()->label(1));

    if (type == 1)
      painter.drawText(marg + cw0 + cw1 + cw2 + pad, marg, cw3, horizontalHeader()->height(), AlignAuto | AlignVCenter, i18n("Score"));

}

void KWordQuizView::doEndOfPage( TQPainter & painter, int vPos, int pageNum, int res, int type )
{
    int marg = res;
    painter.setFont(TDEGlobalSettings::generalFont());
    TQRect w = painter.window();
    TQRect r = painter.boundingRect(0, 0, 0, 0, AlignAuto, TQString::number(pageNum));
    painter.drawText((w.width()/2) - (r.width()/2), w.height() - marg + 20, TQString::number(pageNum));

    if (type == 2)
      return;

    int cw0 = verticalHeader()->width();
    int cw1 = columnWidth(0);
    int cw2 = columnWidth(1);
    int cw3 = 0;

    if (type == 1)
      cw3 = 50;

    //Last horizontal line
    painter.drawLine(marg, vPos, marg + cw0 + cw1 + cw2 + cw3, vPos);
   //Four vertical lines
    painter.drawLine(marg, marg, marg, vPos);
    painter.drawLine(marg + cw0, marg, marg + cw0, vPos);
    painter.drawLine(marg + cw0 + cw1, marg, marg + cw0 + cw1, vPos);
    painter.drawLine(marg + cw0 + cw1 + cw2, marg, marg + cw0 + cw1 + cw2, vPos);

    if (type == 1)
      painter.drawLine(marg + cw0 + cw1 + cw2 + cw3, marg, marg + cw0 + cw1 + cw2 + cw3, vPos);

}



/*!
    \fn KWordQuizView::gridIsEmpty()
 */
bool KWordQuizView::gridIsEmpty()
{
  for(int i = 0; i < numRows(); i++){
    for(int j = 0; j < 2; j++){
      if(!text(i, j).isEmpty()){
        return false;
      }
    }
  }
  return true;
}

TQWidget * KWordQuizView::beginEdit( int row, int col, bool replace )
{
  m_currentText = text(row, col);
  cellEditor = TQTable::beginEdit(row, col, replace);
  if (cellEditor)
    cellEditor->installEventFilter(this);
  return cellEditor;
}

void KWordQuizView::endEdit( int row, int col, bool accept, bool replace )
{
  // this code gets called after enter and arrow keys, now we
  // only process if editing really has been done

  if (cellWidget(row, col) != 0) //if edited the cellWidget still exists
  {
    if (((TQLineEdit *) cellWidget(row, col))->text() != m_currentText)
      addUndo(i18n("&Undo Entry"));
    TQTable::endEdit(row, col, accept, replace); //this will destroy the cellWidget
    if (!text(row, col).isEmpty())
    {
      TQTableItem* itm;
      itm = item(row, col);
      itm->setWordWrap(true);
      adjustRow(row);
      getDocument() -> setModified(true);
      if (Prefs::enableBlanks())
        if (!checkForBlank(text(row, col), true))
          KNotifyClient::event(winId(), "SyntaxError", i18n("There is an error with the Fill-in-the-blank brackets"));
    }
  }
}

void KWordQuizView::adjustRow( int row )
{
  // we want to make the row high enough to display content, but
  // if the user already made it even higher we keep that height
  int rh = rowHeight(row);
  TQTable::adjustRow(row);
  if (rh > rowHeight(row))
    setRowHeight(row, rh);
}

void KWordQuizView::saveCurrentSelection(bool clear = true)
{

  m_currentRow = currentRow();
  m_currentCol = currentColumn();

  if (numSelections() > 0)
  {
    m_currentSel = selection(0);
    if (clear)
      clearSelection();
  }
  else
  {
    TQTableSelection* ts;
    ts = new TQTableSelection(m_currentRow, m_currentCol, m_currentRow, m_currentCol);
    m_currentSel = *ts;
  }
}

void KWordQuizView::doEditUndo( )
{
  if (isEditing())
  {
    if (((TQLineEdit *) cellWidget(currentRow(), currentColumn()))->isUndoAvailable())
      ((TQLineEdit *) cellWidget(currentRow(), currentColumn()))->undo();
  }
  else
  {
    WQUndo undo;
    if (m_undoList->count() > 0)
    {
      setUpdatesEnabled(false);
      undo = m_undoList->first();
      setFont(undo.font());
      verticalHeader()->setMinimumWidth(undo.colWidth0());
      setColumnWidth(0, undo.colWidth1());
      setColumnWidth(1, undo.colWidth2());
      setNumRows(0);
      setNumRows(undo.numRows());
      setCurrentCell(undo.currentRow(), undo.currentCol());
      addSelection(undo.selection());

      TQString s;
      int i = 0;
      KWqlDataItemList dataList = undo.list();
      KWqlDataItemList::ConstIterator end(dataList.end());
      for(KWqlDataItemList::ConstIterator dataIt = dataList.begin(); dataIt != end; ++dataIt)
      {
        s = (*dataIt).frontText();
        if (!s.isEmpty())
          setText(i, 0, s); //calling setText only when there actually is text helps with sorting
        s = (*dataIt).backText();
        if (!s.isEmpty())
          setText(i, 1, s);
        setRowHeight(i, (*dataIt).rowHeight());
        i++;
      }

      m_undoList->remove(m_undoList->begin());
      setUpdatesEnabled(true);
    }

    if (m_undoList->count() > 0)
    {
      undo = m_undoList->first();
      emit undoChange(undo.text(), true);
    }
    else
      emit undoChange(i18n("Cannot &Undo"), false);
  }
}

void KWordQuizView::doEditCut( )
{
  if (isEditing())
  {
    ((TQLineEdit *) cellWidget(currentRow(), currentColumn()))->cut();
  }
  else
  {
    addUndo(i18n("&Undo Cut"));
    doEditCopy();
    saveCurrentSelection();
    for (int r = m_currentSel.topRow(); r <= m_currentSel.bottomRow(); ++r)
      for(int c = m_currentSel.leftCol(); c <= m_currentSel.rightCol(); ++c)
        clearCell(r, c);
  }
  getDocument()->setModified(true);
}

void KWordQuizView::doEditCopy( )
{
  bool mod = getDocument()->isModified();
  if (isEditing())
  {
    ((TQLineEdit *) cellWidget(currentRow(), currentColumn()))->copy();
  }
  else
  {
    saveCurrentSelection(false);
    TQString s;
    for (int r = m_currentSel.topRow(); r <= m_currentSel.bottomRow(); ++r)
    {
      for (int c = m_currentSel.leftCol(); c <= m_currentSel.rightCol(); ++c)
        s = s + text(r, c) + "\t";
      s = s + "\n";
    }
    kapp->clipboard()->setText(s);
  }
  getDocument()->setModified(mod);
}

void KWordQuizView::doEditPaste( )
{
  if (isEditing())
  {
    ((TQLineEdit *) cellWidget(currentRow(), currentColumn()))->paste();
  }
  else
  {
    addUndo(i18n("&Undo Paste"));
    saveCurrentSelection();
    int tr = m_currentSel.topRow();
    int br = m_currentSel.bottomRow();
    int lc = m_currentSel.leftCol();
    int rc = m_currentSel.rightCol();

    if (lc == rc && tr == br) //one cell selected
    {
      TQString s = kapp->clipboard()->text();
      TQStringList sl;
      sl = TQStringList::split("\n", s);

      uint r = numRows() - tr;

      if (sl.count() > r) //do we need to add rows?
      {
        setNumRows(numRows() + (sl.count() - r));
        br = numRows();
      }
      else
        br= br + sl.count() - 1;

      if (lc == 0) //left col?
        if (sl[0].find("\t") < ((int) sl[0].length() - 1))
          rc = 1; //expand to second column;

      uint i = 0;
      int ar = tr;
      TQStringList sr;
      while(i < sl.count() && br <= numRows() )
      {
        int ac = lc;

        sr = TQStringList::split("\t", sl[i]);
        int c = 0;
        while (ac <= rc)
        {
          setText(ar, ac, sr[c]);
          ac++;
          c++;
        }
        ar++;
        i++;
      }


    }
    else
    {
      TQString s = kapp->clipboard()->text();
      TQStringList sl;
      sl = TQStringList::split("\n", s);
      uint i = 0;
      int ar = tr;
      TQStringList sr;
      while(i < sl.count() && ar <= br )
      {
        int ac = lc;

        sr = TQStringList::split("\t", sl[i]);
        int c = 0;
        while (ac <= rc)
        {
          setText(ar, ac, sr[c]);
          ac++;
          c++;
        }
        ar++;
        i++;
      }
    }

    //restore selection
    addSelection(TQTableSelection(tr, lc, br, rc));
    setCurrentCell(m_currentRow, m_currentCol);
  }
  getDocument()->setModified(true);
}

void KWordQuizView::doEditClear( )
{
  if (isEditing())
  {
    ((TQLineEdit *) cellWidget(currentRow(), currentColumn()))->clear();
  }
  else
  {
    addUndo(i18n("&Undo Clear"));
    saveCurrentSelection(false);
    for (int r = m_currentSel.topRow(); r <= m_currentSel.bottomRow(); ++r)
      for(int c = m_currentSel.leftCol(); c <= m_currentSel.rightCol(); ++c)
        clearCell(r, c);
  }
  getDocument()->setModified(true);
}

void KWordQuizView::doEditInsert( )
{
  addUndo(i18n("&Undo Insert"));
  setUpdatesEnabled(false);
  saveCurrentSelection();
  insertRows(m_currentSel.topRow(), m_currentSel.bottomRow() - m_currentSel.topRow() + 1);

  addSelection(TQTableSelection(m_currentSel.topRow(), m_currentSel.leftCol(), m_currentSel.bottomRow(), m_currentSel.rightCol()));
  setCurrentCell(m_currentRow, m_currentCol);
  setUpdatesEnabled(true);
  repaintContents();
  getDocument()->setModified(true);
}

void KWordQuizView::doEditDelete( )
{
  addUndo(i18n("&Undo Delete"));
  //retrieve current selection
  saveCurrentSelection();

  int tr = m_currentSel.topRow();
  int br = m_currentSel.bottomRow();

  if (tr == 0 && br == numRows() - 1)
    br--; //leave one row if all rows are selected

  for (int r = br; r >= tr; --r)
    removeRow(r);

  if (br > numRows())
    br = numRows(); //adjust for new numRows

  //restore selection as much as possible
  addSelection(TQTableSelection(tr, m_currentSel.leftCol(), br, m_currentSel.rightCol()));
  setCurrentCell(m_currentRow, m_currentCol);
  getDocument()->setModified(true);
}

const char delim_start = '[';
const char delim_end = ']';


bool KWordQuizView::checkForBlank( const TQString  & s, bool blank )
{
  if (!blank)
    return true;

  bool result = false;
  int openCount = 0;
  int closeCount = 0;
  TQMemArray<int> openPos(0);
  TQMemArray<int> closePos(0);

  for (uint i = 0; i<= s.length(); ++i)
  {
    if (s[i] == delim_start)
    {
      openCount++;
      openPos.resize(openCount);
      openPos[openCount] = i;
    }

    if (s[i] == delim_end)
    {
      closeCount++;
      closePos.resize(closeCount);
      closePos[closeCount] = i;
    }
  }

  if (openCount == 0 && closeCount == 0)
    return true;

  if (openCount > 0 && closeCount > 0)
    if (openPos.size() == closePos.size())
      for (uint i = 0; i <= openPos.size(); ++i)
        result = (openPos[i] < closePos[i]);

  return result;
}

void KWordQuizView::doEditMarkBlank( )
{
  if (isEditing())
  {
    addUndo(i18n("&Undo Mark Blank"));
    TQLineEdit * l = (TQLineEdit *) cellWidget(currentRow(), currentColumn());
    if (l->text().length() > 0)
    {
      TQString s = l->text();
      int cp = l->cursorPosition();
      if (!l->hasSelectedText())
      {
        if (!s[cp].isSpace() && !s[cp - 1].isSpace())
        {
          l->cursorWordBackward(false);
          int cp1 = l->cursorPosition();
          l->cursorWordForward(false);
          if (l->cursorPosition() != (int) s.length())
          {  while(l->text()[l->cursorPosition()].isSpace())
              l->cursorBackward(false, 1);
          }
          int cp2 = l->cursorPosition();
          if (cp2 == (int) s.length())
            l->setSelection(cp1, cp2 - cp1);
          else
            l->setSelection(cp1, cp2 - cp1 - 1);

        }
        else
          return;
      }


      if (l->hasSelectedText())
      {
        TQString st = l->selectedText();
        int len = st.length();
        st = st.prepend(delim_start);
        st = st.append(delim_end);
        int ss = l->selectionStart();
        s = s.replace(ss, len, st);
        l->setText(s);
        l->setSelection(ss, st.length());
      }
    }
  }
}

void KWordQuizView::doEditUnmarkBlank( )
{
  addUndo(i18n("&Undo Unmark Blank"));
  TQString s;

  if (isEditing())
  {
    TQLineEdit * l = (TQLineEdit *) cellWidget(currentRow(), currentColumn());

    if (l->hasSelectedText())
    {
      TQString ls = l->text();
      s = l->selectedText();
      int len = s.length();
      s.remove(delim_start);
      s.remove(delim_end);
      int ss = l->selectionStart();
      ls = ls.replace(ss, len, s);
      l->setText(ls);
      l->setSelection(ss, s.length());
    }
    else
    {
      if (l->text().length() > 0)
      {
        s = l->text();
        int cs = l->cursorPosition();

        int fr = s.findRev(delim_start, cs);
        if (fr > 0)
        {
          s = s.replace(fr, 1, "");
          cs--;
        }
        int ff = s.find(delim_end, cs);
        if (ff > 0)
          s = s.replace(ff, 1, "");

        l->setText(s);
        l->setCursorPosition(cs);
      }
    }
  }
  else
  {
    saveCurrentSelection(false);
    for (int r = m_currentSel.topRow(); r <= m_currentSel.bottomRow(); ++r)
      for(int c = m_currentSel.leftCol(); c <= m_currentSel.rightCol(); ++c)
      {
        s = text(r, c);
        s = s.remove(delim_start);
        s = s.remove(delim_end);
        setText(r, c, s);
      }
  }
}

bool KWordQuizView::checkSyntax(bool all, bool blanks)
{
  int errorCount = 0;
  int r1, r2, c1 ,c2;

  if (all)
  {
    r1 = 0;
    r2 = numRows() - 1;
    c1 = 0;
    c2 = 1;
  }
  else
  {
    saveCurrentSelection(false);
    r1 = m_currentSel.topRow();
    r2 = m_currentSel.bottomRow();
    c1 = m_currentSel.leftCol();
    c2 = m_currentSel.rightCol();
  }

  for (int r = r1; r <= r2; ++r)
    for(int c = c1 ; c <= c2 ; ++c )
    {
      TQString s = text(r, c);
      if (s.length() > 0)
        for (uint i = 0; i <= s.length(); ++i)
          if (s[i] == delim_start || s[i] == delim_end)
            if (!checkForBlank(s, blanks))
              errorCount++;
    }
  return (errorCount == 0);
}

void KWordQuizView::doVocabSort( )
{
  saveCurrentSelection();
  DlgSort* dlg;
  dlg = new DlgSort(this, "dlg_sort", true);
  dlg->setLanguage(1, horizontalHeader()->label(0));
  dlg->setLanguage(2, horizontalHeader()->label(1));
  dlg->disableResize();
  if (dlg->exec() == KDialogBase::Accepted)
  {
    addUndo(i18n("&Undo Sort"));
    if (dlg->base())
      sortColumn(0, dlg->ascending(), true);
    else
      sortColumn(1, dlg->ascending(), true);
      getDocument()->setModified(true);
  }
  //restore selection
  addSelection(TQTableSelection(m_currentSel.topRow(), m_currentSel.leftCol(), m_currentSel.bottomRow(), m_currentSel.rightCol()));
  setCurrentCell(m_currentRow, m_currentCol);
}

void KWordQuizView::doVocabShuffle( )
{
  //@todo handle empty rows
  addUndo(i18n("&Undo Shuffle"));
  saveCurrentSelection();
  KRandomSequence* rs;
  rs = new KRandomSequence();
  int count = numRows();
  setUpdatesEnabled(false);
  while (count > 0)
  {
    swapRows(count-1, rs->getLong(count));
    count--;
  }
  //restore selection
  addSelection(TQTableSelection(m_currentSel.topRow(), m_currentSel.leftCol(), m_currentSel.bottomRow(), m_currentSel.rightCol()));
  setCurrentCell(m_currentRow, m_currentCol);
  setUpdatesEnabled(true);
  repaintContents();
  getDocument()->setModified(true);
}

void KWordQuizView::doVocabRC( )
{
  saveCurrentSelection();
  DlgRC* dlg;
  dlg = new DlgRC(this, "dlg_rc", true);
  //dlg->setInitialSize(TQSize(225, 230), true);
  dlg->setNumRows(numRows());
  dlg->setRowHeight(rowHeight(m_currentRow));
  dlg->setColWidth(columnWidth(m_currentCol));
  dlg->disableResize();
  if (dlg->exec() == KDialogBase::Accepted)
  {
    if (dlg->numRows() < 1)
      setNumRows(1);
    else
      setNumRows(dlg->numRows());
    for (int i = m_currentSel.topRow(); i <= m_currentSel.bottomRow(); ++i)
      setRowHeight(i, dlg->rowHeight());
    for (int i = m_currentSel.leftCol(); i <= m_currentSel.rightCol(); ++i)
      setColumnWidth(i, dlg->colWidth());
    getDocument()->setModified(true);
  }
  addSelection(TQTableSelection(m_currentSel.topRow(), m_currentSel.leftCol(), m_currentSel.bottomRow(), m_currentSel.rightCol()));
  setCurrentCell(m_currentRow, m_currentCol);
}

void KWordQuizView::doVocabSpecChar( )
{
  TQString f = font().family();
  TQChar c=' ';
  if (dlgSpecChar==0)
  {
    dlgSpecChar = new DlgSpecChar( this, "insert special char", f, c, false );
    connect( dlgSpecChar, TQ_SIGNAL(insertChar(TQChar)), this, TQ_SLOT(slotSpecChar(TQChar)));
    connect( dlgSpecChar, TQ_SIGNAL( finished() ), this, TQ_SLOT( slotDlgSpecCharClosed() ) );
  }
  dlgSpecChar->show();
}

void KWordQuizView::slotDlgSpecCharClosed( )
{
  if ( dlgSpecChar )
  {
    disconnect( dlgSpecChar, TQ_SIGNAL(insertChar(TQChar)), this, TQ_SLOT(slotSpecChar(TQChar)));
    disconnect( dlgSpecChar, TQ_SIGNAL( finished() ), this, TQ_SLOT( slotDlgSpecCharClosed() ) );
    dlgSpecChar->deleteLater();
    dlgSpecChar = 0L;
  }
}

void KWordQuizView::slotSpecChar(const TQChar & c)
{
  if (isEditing())
  {
    TQLineEdit * l = (TQLineEdit *) cellWidget(currentRow(), currentColumn());
    if (l->hasSelectedText())
    {
      TQString ls = l->text();
      TQString s = l->selectedText();
      int len = s.length();
      int ss = l->selectionStart();
      ls = ls.replace(ss, len, c);
      l->setText(ls);
      l->setSelection(ss, 1);
    }
    else
    {
      TQString s = l->text();
      int i = l->cursorPosition();
      s.insert(i, c);
      l->setText(s);
      l->setCursorPosition(i + 1);
    }
  }
  else
  {
    editCell(currentRow(), currentColumn(), true);
    ((TQLineEdit *) cellWidget(currentRow(), currentColumn()))->setText(c);
    ((TQLineEdit *) cellWidget(currentRow(), currentColumn()))->setCursorPosition(1);
  }
}

void KWordQuizView::activateNextCell( )
{
  saveCurrentSelection(false);
  int tr = m_currentSel.topRow();
  int br = m_currentSel.bottomRow();
  int lc = m_currentSel.leftCol();
  int rc = m_currentSel.rightCol();

  if (lc == rc && tr == br) //one cell selected
  {
    clearSelection();
    switch(Prefs::enterMove())
    {
      case 0:
        if (m_currentRow == (numRows() - 1))
          setNumRows(numRows() + 1);
        setCurrentCell(m_currentRow + 1, m_currentCol);
        break;
      case 1:
        if (m_currentCol == 0)
          setCurrentCell(m_currentRow, m_currentCol + 1);
        else
          {
          if (m_currentRow == (numRows() - 1))
            setNumRows(numRows() + 1);
          setCurrentCell(m_currentRow + 1, m_currentCol - 1);
          }
        break;
      case 2:
        setCurrentCell(m_currentRow, m_currentCol);
        break;
    }
  }
  else //a larger selection, move within it
  {
    //addSelection(TQTableSelection(m_currentSel.topRow(), m_currentSel.leftCol(), m_currentSel.bottomRow(), m_currentSel.rightCol()));
    switch(Prefs::enterMove())
    {
      case 0:
        if (m_currentRow == br)
        {
          if (m_currentCol < rc)
            setCurrentCell(tr, rc);
          else
            setCurrentCell(tr, lc);
        }
        else
          if (m_currentRow < br)
            setCurrentCell(m_currentRow + 1, m_currentCol);
        break;
      case 1:
        if (m_currentCol == rc)
        {
          if (m_currentRow < br)
            setCurrentCell(m_currentRow + 1, lc);
          else
            setCurrentCell(tr, lc);
        }
        else
          setCurrentCell(m_currentRow, m_currentCol + 1);
        break;
      case 2:
        setCurrentCell(m_currentRow, m_currentCol);
        break;
    }
  }
}

void KWordQuizView::addUndo( const TQString & caption )
{
  while (m_undoList->count() > 10)
  {
    m_undoList->remove(m_undoList->begin());
  }

  WQUndo* undo = new WQUndo();
  undo->setText(caption);
  undo->setFont(font());
  undo->setColWidth0(verticalHeader()->width());
  undo->setColWidth1(columnWidth(0));
  undo->setColWidth2(columnWidth(1));
  undo->setNumRows(numRows());
  undo->setCurrentRow(currentRow());
  undo->setCurrentCol(currentColumn());
  undo->setSelection(selection(0));

  KWqlDataItemList list;
  for(int i = 0; i < numRows(); i++)
  {
    KWqlDataItem item(text(i, 0), text(i, 1), rowHeight(i));
    list.append(item);
  }

  undo->setList(list);

  m_undoList->prepend(*undo);

  getDocument()->setModified(true);

  emit undoChange(caption, true);
}

void KWordQuizView::setFont( const TQFont & font)
{
  TQTable::setFont(font);
  horizontalHeader()->setFont(TDEGlobalSettings::generalFont());
  verticalHeader()->setFont(TDEGlobalSettings::generalFont());
  for (int i = 0; i < numRows(); ++i)
    adjustRow(i); //setRowHeight(i, fontMetrics().lineSpacing() );
}

void KWordQuizView::paintCell( TQPainter * p, int row, int col, const TQRect & cr, bool selected, const TQColorGroup & cg )
{
  TQColorGroup g (cg);

  if (Prefs::enableBlanks())
    if (!checkForBlank(text(row, col), true))
      g.setColor(TQColorGroup::Text, TQt::red);

  TQTable::paintCell (p, row, col, cr, selected, g );
}

void KWordQuizView::keyPressEvent( TQKeyEvent * e)
{
  /*if (isEditing())
    if (e->key() == Key_Tab)
    {
      endEdit(currentRow(), currentColumn(), true, true);
      activateNextCell();
      return;
    }
    else
      return;
  */
  if (e->key() == Key_Tab)
  {
    activateNextCell();
    return;
  }
  TQTable::keyPressEvent(e);
}

void KWordQuizView::slotCheckedAnswer( int i )
{
  if (i == -1)
  {
    clearSelection();
    addSelection(TQTableSelection(m_currentSel.topRow(), m_currentSel.leftCol(), m_currentSel.bottomRow(), m_currentSel.rightCol()));
    setCurrentCell(m_currentRow, m_currentCol);
  }
  else
  {
    clearSelection();
    setCurrentCell(i, 0);
    selectRow(i);
  }
}

bool KWordQuizView::eventFilter( TQObject * o, TQEvent * e )
{
  if (o == cellEditor)
  {
    if ( e->type() == TQEvent::KeyPress )
    {
      TQKeyEvent *k = (TQKeyEvent *)e;
      if (k->key() == Key_Tab)
      {
        endEdit(currentRow(), currentColumn(), true, true);
        activateNextCell();
        return true;
      }
    }
  }
  return TQTable::eventFilter(o, e);
}

void KWordQuizView::setText(int row, int col, const TQString & text)
{
  TQTableItem *itm = item(row, col);
  if (itm) {
    itm->setText(text);
    itm->updateEditor(row, col);
    updateCell(row, col);
  } else {
    KWTQTableItem *i = new KWTQTableItem(this, TQTableItem::OnTyping, text);
    setItem(row, col, i);
  }
}

#include "kwordquizview.moc"
