/* This file is part of the KDE project
    Copyright (C) 1997 Tim D. Gilman (tdgilman@best.org)
              (C) 1998-2001 Mirko Boehm (mirko@kde.org)
              (C) 2004-2006 Dag Andersen <danders@get2net.dk>

   This library is free software; you can redistribute it and/or
   modify it under the terms of the GNU Library General Public
   License as published by the Free Software Foundation; either
   version 2 of the License, or (at your option) any later version.

   This library 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
   Library General Public License for more details.

   You should have received a copy of the GNU Library General Public License
   along with this library; see the file COPYING.LIB.  If not, write to
   the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 * Boston, MA 02110-1301, USA.
*/

#include "kptdatetable.h"
#include "kptmap.h"

#include <tdeapplication.h>
#include <knotifyclient.h>
#include <kcalendarsystem.h>

#include <tqdatetime.h>
#include <tqstring.h>
#include <tqpen.h>
#include <tqpainter.h>
#include <tqdialog.h>
#include <assert.h>
#include <tqlayout.h>
#include <tqvaluelist.h>
#include <tdeglobalsettings.h>

#include <kdebug.h>

namespace KPlato
{

DateValidator::DateValidator(TQWidget* parent, const char* name)
    : TQValidator(TQT_TQOBJECT(parent), name)
{
}

TQValidator::State
DateValidator::validate(TQString& text, int&) const
{
  TQDate temp;
  // ----- everything is tested in date():
  return date(text, temp);
}

TQValidator::State
DateValidator::date(const TQString& text, TQDate& d) const
{
  TQDate tmp = TDEGlobal::locale()->readDate(text);
  if (!tmp.isNull())
    {
      d = tmp;
      return Acceptable;
    } else
      return Valid;
}

void
DateValidator::fixup( TQString& ) const
{

}


DateTable::DateTable(TQWidget *parent, TQDate date_, const char* name, WFlags f)
    : TQGridView(parent, name, f),
      m_enabled(true)
{
    //kdDebug()<<k_funcinfo<<endl;
    m_dateStartCol = 1;
    m_selectedDates.clear();
    m_selectedWeekdays.clear();

    TQPair<int, int> p(0,0);
    m_weeks.fill(p, 7);

    setFontSize(10);
    if(!date_.isValid()) {
        kdError() <<k_funcinfo<<"Given date is invalid, using current date." << endl;
        date_=TQDate::currentDate();
    }
    setFocusPolicy( TQ_StrongFocus );
    setNumCols(7+m_dateStartCol); // 7 days a week + maybe 1 for weeknumbers
    setNumRows(7); // 6 weeks max + headline

    setHScrollBarMode(AlwaysOff);
    setVScrollBarMode(AlwaysOff);
    viewport()->setEraseColor(TDEGlobalSettings::baseColor());
    setDate(date_); // this initializes firstday, numdays, numDaysPrevMonth

    colorBackgroundHoliday = TQColor(0, 245, 255, TQColor::Hsv);
    //colorBackgroundHoliday = colorBackgroundHoliday.light();
    colorBackgroundWorkday = TQColor(208, 230, 240, TQColor::Hsv);;
    //colorBackgroundWorkday = colorBackgroundWorkday.light();
    colorTextHoliday = black;
    colorTextWorkday = black;
    colorLine = black;
    backgroundSelectColor = TDEGlobalSettings::highlightColor();
    penSelectColor=TDEGlobalSettings::baseColor();

}

void DateTable::paintWeekday(TQPainter *painter, int col) {
    TQRect rect;
    int w=cellWidth();
    int h=cellHeight();

    TQFont font = TDEGlobalSettings::generalFont();
    font.setBold(true);
    if (!m_enabled)
        font.setItalic(true);
    painter->setFont(font);

    int day = weekday(col);

    //kdDebug()<<k_funcinfo<<" col="<<col<<" day="<<day<<" name="<<daystr<<endl;

    painter->setBrush(TDEGlobalSettings::baseColor());
    painter->setPen(TDEGlobalSettings::baseColor());
    painter->drawRect(0, 0, w, h);
    painter->setPen(TDEGlobalSettings::textColor());

    if (m_markedWeekdays.state(day) == Map::Working) {
        painter->setPen(colorBackgroundWorkday);
        painter->setBrush(colorBackgroundWorkday);
        painter->drawRect(0, 0, w, h);
        painter->setPen(colorTextWorkday);
    } else if (m_markedWeekdays.state(day) == Map::NonWorking) {
        painter->setPen(colorBackgroundHoliday);
        painter->setBrush(colorBackgroundHoliday);
        painter->drawRect(0, 0, w, h);
        painter->setPen(colorTextHoliday);
    }
    if (m_selectedWeekdays.contains(day)) {
        painter->setPen(backgroundSelectColor);
        painter->setBrush(backgroundSelectColor);
        painter->drawRect(2, 2, w-4, h-4);
        painter->setPen(penSelectColor);
    }
    painter->drawText(0, 0, w, h-1, AlignCenter, TDEGlobal::locale()->calendar()->weekDayName(day, true), -1, &rect);
    painter->setPen(colorLine);
    painter->moveTo(0, h-1);
    painter->lineTo(w-1, h-1);

    if(rect.width()>maxCell.width()) maxCell.setWidth(rect.width());
    if(rect.height()>maxCell.height()) maxCell.setHeight(rect.height());

    //kdDebug()<<k_funcinfo<<"headline: row,col=("<<row<<","<<col<<")"<<" day="<<daystr<<endl;
}

void DateTable::paintWeekNumber(TQPainter *painter, int row) {
    TQRect rect;
    int w=cellWidth();
    int h=cellHeight();

    TQFont font=TDEGlobalSettings::generalFont();
    font.setBold(true);
    if (!m_enabled)
        font.setItalic(true);
    painter->setFont(font);

    painter->setBrush(TDEGlobalSettings::baseColor());
    painter->setPen(TDEGlobalSettings::baseColor());
    painter->drawRect(0, 0, w, h);
    painter->setPen(TDEGlobalSettings::textColor());
    
    painter->drawText(0, 0, w, h-1, AlignCenter, TQString("%1").arg(m_weeks[row].first), -1, &rect);
    painter->setPen(colorLine);
    painter->moveTo(w-1, 0);
    painter->lineTo(w-1, h-1);

    if(rect.width()>maxCell.width()) maxCell.setWidth(rect.width());
    if(rect.height()>maxCell.height()) maxCell.setHeight(rect.height());
}

void DateTable::paintDay(TQPainter *painter, int row, int col) {
    //kdDebug()<<k_funcinfo<<"row,col=("<<row<<","<<col<<")"<<" num col="<<numCols()<<endl;
    TQRect rect;
    int w=cellWidth();
    int h=cellHeight();

    TQFont font=TDEGlobalSettings::generalFont();
    font.setPointSize(fontsize);
    if (!m_enabled)
        font.setItalic(true);
    painter->setFont(font);

    TQDate d = getDate(position(row, col));

    painter->setBrush(TDEGlobalSettings::baseColor());
    painter->setPen(TDEGlobalSettings::baseColor());
    painter->drawRect(0, 0, w, h);

    // First paint the dates background
    if (m_markedDates.state(d) == Map::NonWorking) {
        //kdDebug()<<k_funcinfo<<"Marked date: "<<d<<"  row,col=("<<row<<","<<col<<")=NonWorking"<<endl;
        painter->setPen(colorBackgroundHoliday);
        painter->setBrush(colorBackgroundHoliday);
        painter->drawRect(0, 0, w, h);
    } else if (m_markedDates.state(d) == Map::Working) {
        //kdDebug()<<k_funcinfo<<"Marked date: "<<d<<"  row,col=("<<row<<","<<col<<")=Working"<<endl;
        painter->setPen(colorBackgroundWorkday);
        painter->setBrush(colorBackgroundWorkday);
        painter->drawRect(0, 0, w, h);
    }
    if(m_selectedDates.contains(d)) {
        //kdDebug()<<k_funcinfo<<"Selected: "<<d<<" row,col=("<<row<<","<<col<<")"<<endl;
        painter->setPen(backgroundSelectColor);
        painter->setBrush(backgroundSelectColor);
        painter->drawRect(2, 2, w-4, h-4);
    }
    // If weeks or weekdays are selected/marked we draw lines around the date
    TQPen pen = painter->pen();
    if (m_markedWeekdays.state(weekday(col)) == Map::Working) {
        //kdDebug()<<k_funcinfo<<"Marked weekday: row,dayCol=("<<row<<","<<dayCol<<")=Working"<<endl;
        pen.setColor(colorBackgroundWorkday);
        painter->setPen(pen);
        painter->moveTo(0, 0);
        painter->lineTo(0, h-1);
        painter->moveTo(w-1, 0);
        painter->lineTo(w-1, h-1);
    }
    // then paint square if current date
    if (d  == TQDate::currentDate()) {
        painter->setPen(colorLine);
        painter->drawRect(1, 1, w-2, h-2);
    }

    // and now the day number
    d.month() == date.month() ? painter->setPen(TDEGlobalSettings::textColor()) : painter->setPen(gray);
    painter->drawText(0, 0, w, h, AlignCenter, TQString().setNum(d.day()), -1, &rect);

    if(rect.width()>maxCell.width()) maxCell.setWidth(rect.width());
    if(rect.height()>maxCell.height()) maxCell.setHeight(rect.height());
}

void DateTable::paintCell(TQPainter *painter, int row, int col) {
    //kdDebug()<<k_funcinfo<<"row,col=("<<row<<","<<col<<")"<<"enabled="<<m_enabled<<endl;
    if (row == 0 && col == 0) {
        painter->save();
        int w=cellWidth();
        int h=cellHeight();
        painter->setPen(colorLine);
        painter->setBrush(TDEGlobalSettings::baseColor());
        painter->moveTo(w-1, 0);
        painter->lineTo(w-1, h-1);
        painter->lineTo(0, h-1);
        painter->restore();
        return;
    }
    painter->save();
    if(row==0) { // we are drawing the weekdays
        paintWeekday(painter, col);
    } else if (col == 0) { // draw week numbers
        paintWeekNumber(painter, row);
    } else { // draw the day
        paintDay(painter, row, col);
    }
    painter->restore();
}

//FIXME
void DateTable::keyPressEvent( TQKeyEvent *e ) {
    if (!m_enabled)
        return;
    if ( e->key() == TQt::Key_Prior ) {
        setDate(date.addMonths(-1));
        return;
    }
    if ( e->key() == TQt::Key_Next ) {
        setDate(date.addMonths(1));
        return;
    }

    if ( e->key() == TQt::Key_Up ) {
        if ( date.day() > 7 ) {
            setDate(date.addDays(-7));
            return;
        }
    }
    if ( e->key() == TQt::Key_Down ) {
        if ( date.day() <= date.daysInMonth()-7 ) {
            setDate(date.addDays(7));
            return;
        }
    }
    if ( e->key() == TQt::Key_Left ) {
        if ( date.day() > 1 ) {
            setDate(date.addDays(-1));
            return;
        }
    }
    if ( e->key() == TQt::Key_Right ) {
        if ( date.day() < date.daysInMonth() ) {
            setDate(date.addDays(1));
            return;
        }
    }

    if ( e->key() == TQt::Key_Minus ) {
        setDate(date.addDays(-1));
        return;
    }
    if ( e->key() == TQt::Key_Plus ) {
        setDate(date.addDays(1));
        return;
    }
    if ( e->key() == TQt::Key_N ) {
        setDate(TQDate::currentDate());
        return;
    }
    if ( e->key() == TQt::Key_Control ) {
        return;
    }
    if ( e->key() == TQt::Key_Shift ) {
        return;
    }

    KNotifyClient::beep();
}

void DateTable::viewportResizeEvent(TQResizeEvent * e) {
  TQGridView::viewportResizeEvent(e);

  setCellWidth(viewport()->width()/numCols());
  setCellHeight(viewport()->height()/numRows());
}

void DateTable::setFontSize(int size) {
  int count;
  TQFontMetrics metrics(fontMetrics());
  TQRect rect;
  // ----- store rectangles:
  fontsize=size;
  // ----- find largest day name:
  maxCell.setWidth(0);
  maxCell.setHeight(0);
  for(count=0; count<7; ++count)
    {
      rect=metrics.boundingRect(TDEGlobal::locale()->calendar()->weekDayName(count+1, true));
      maxCell.setWidth(TQMAX(maxCell.width(), rect.width()));
      maxCell.setHeight(TQMAX(maxCell.height(), rect.height()));
    }
  // ----- compare with a real wide number and add some space:
  rect=metrics.boundingRect(TQString::fromLatin1("88"));
  maxCell.setWidth(TQMAX(maxCell.width()+2, rect.width()));
  maxCell.setHeight(TQMAX(maxCell.height()+4, rect.height()));
}

//FIXME
void DateTable::wheelEvent ( TQWheelEvent * e ) {
    setDate(date.addMonths( -(int)(e->delta()/120)) );
    e->accept();
}


void DateTable::contentsMousePressEvent(TQMouseEvent *e) {
    if (!m_enabled)
        return;
    //kdDebug()<<k_funcinfo<<endl;
    if(e->type()!=TQEvent::MouseButtonPress) {
        return;
    }
    TQPoint mouseCoord = e->pos();
    int row=rowAt(mouseCoord.y());
    int col=columnAt(mouseCoord.x());
    if (row == 0 && col == 0) { // user clicked on (unused) upper left square
        updateSelectedCells();
        m_selectedWeekdays.clear();
        m_selectedDates.clear();
        repaintContents(false);
        emit selectionCleared();
        return;
    }
    if (col == 0) { // user clicked on week numbers
        updateSelectedCells();
        m_selectedWeekdays.clear();
        m_selectedDates.clear();
        updateSelectedCells();
        repaintContents(false);
        return;
    }
    if (row==0 && col>0) { // the user clicked on weekdays
        updateSelectedCells();
        m_selectedDates.clear();
        int day = weekday(col);
        if (e->state() & ShiftButton) {
            // select all days between this and the furthest away selected day,
            // check first downside - then upside, clear all others
            bool select = false;
            for(int i=m_dateStartCol; i < col; ++i) {
                //kdDebug()<<"Down["<<i<<"]: col="<<col<<" day="<<day<<" column(i)="<<column(i)<<endl;
                if (m_selectedWeekdays.contains(weekday(i))) {
                    select = true; // we have hit a selected day; select the rest
                } else if (select) {
                    m_selectedWeekdays.toggle(weekday(i)); // select
                }
            }
            bool selected = select;
            select = false;
            for(int i=7; i > col; --i) {
                //kdDebug()<<"Up["<<i<<"]: col="<<col<<" day="<<day<<" column(i)="<<column(i)<<endl;
                if (m_selectedWeekdays.contains(weekday(i))) {
                    if (selected) m_selectedWeekdays.toggle(weekday(i)); // deselect
                    else select = true;
                } else if (select) {
                    m_selectedWeekdays.toggle(weekday(i)); // select
                }
            }
            if (!m_selectedWeekdays.contains(day)) {
                m_selectedWeekdays.toggle(day); // always select
            }
        } else if (e->state() & ControlButton) {
            // toggle select this date
            m_selectedWeekdays.toggle(day);
        } else {
            // toggle select this, clear all others
            m_selectedWeekdays.toggleClear(day);
        }
        updateSelectedCells();
        repaintContents(false);
        if (m_enabled) {
            //kdDebug()<<k_funcinfo<<"emit weekdaySelected("<<day<<")"<<endl;
            emit weekdaySelected(day); // day= 1..7
        }
        return;
    }

    if (contentsMousePressEvent_internal(e)) {
        // Date hit,
        m_selectedWeekdays.clear();
        if (e->state() & ShiftButton) {
            // find first&last date
            TQDate first;
            TQDate last;
            DateMap::ConstIterator it;
            for (it = m_selectedDates.constBegin(); it != m_selectedDates.constEnd(); ++it) {
                //kdDebug()<<k_funcinfo<<it.key()<<endl;
                TQDate d = TQDate::fromString(it.key(), Qt::ISODate);
                if (!d.isValid())
                    continue;
                if (!first.isValid() || first > d)
                    first = d;
                if (!last.isValid() || last < d)
                    last = d;
            }
            // select between anchor and pressed date inclusive
            m_selectedDates.clear();
            if (first.isValid() && last.isValid()) {
                TQDate anchor = first < date ? first : last;
                int i = anchor > date ? -1 : 1;
                while (anchor != date) {
                    //kdDebug()<<k_funcinfo<<anchor.toString(Qt::ISODate)<<endl;
                    m_selectedDates.toggle(anchor);
                    anchor = anchor.addDays(i);
                }
            }
            m_selectedDates.toggle(date);
        } else if (e->state() & ControlButton) {
            // toggle select this date
            m_selectedDates.toggle(date);
            //kdDebug()<<k_funcinfo<<"toggle date: "<<date.toString()<<" state="<<m_selectedDates.state(date)<<endl;
        } else {
            // Select this, clear all others
            m_selectedDates.clear();
            m_selectedDates.toggleClear(date);
            //kdDebug()<<k_funcinfo<<"toggleClear date: "<<date.toString()<<" state="<<m_selectedDates.state(date)<<endl;
        }
    }
    repaintContents(false);
}

bool DateTable::contentsMousePressEvent_internal(TQMouseEvent *e) {
    TQPoint mouseCoord = e->pos();
    int row=rowAt(mouseCoord.y());
    int col=columnAt(mouseCoord.x());
    if(row<1 || col<0) { // the user clicked on the frame of the table
        return false;
    }
    //kdDebug()<<k_funcinfo<<"pos["<<row<<","<<col<<"]="<<position(row,col)<<" firstday="<<firstday<<endl;
    selectDate(getDate(position(row, col)));
    return true;
}

bool DateTable::selectDate(const TQDate& date_) {
    //kdDebug()<<k_funcinfo<<"date="<<date_.toString()<<endl;
    bool changed=false;
    TQDate temp;
    // -----
    if(!date_.isValid()) {
        return false;
    }
    if(date!=date_) {
        date=date_;
        changed=true;
    }

    temp.setYMD(date.year(), date.month(), 1);
    firstday=column(TDEGlobal::locale()->calendar()->dayOfWeek(temp));
    if(firstday==1) firstday=8; // Reserve row 1 for previous month
    numdays=date.daysInMonth();
    if(date.month()==1) { // set to december of previous year
        temp.setYMD(date.year()-1, 12, 1);
        setWeekNumbers(TQDate(date.year()-1, 12, 31));
    } else { // set to previous month
        temp.setYMD(date.year(), date.month()-1, 1);
        TQDate d(date.year(), date.month()-1,1);
        setWeekNumbers(d.addDays(d.daysInMonth()-1));
    }
    numDaysPrevMonth=temp.daysInMonth();
    if(changed) {
        repaintContents(false);
    }
    if (m_enabled)
        emit(dateChanged(date));
    return true;
}

bool DateTable::setDate(const TQDate& date_, bool repaint) {
    //kdDebug()<<k_funcinfo<<"date="<<date_.toString()<<endl;
    bool changed=false;
    TQDate temp;
    // -----
    if(!date_.isValid()) {
        //kdDebug() << "DateTable::setDate: refusing to set invalid date." << endl;
        return false;
        }
    if(date!=date_) {
        date=date_;
        changed=true;
    }
    //m_selectedDates.clear();

    temp.setYMD(date.year(), date.month(), 1);
    firstday=column(TDEGlobal::locale()->calendar()->dayOfWeek(temp));
    if(firstday==1) firstday=8;
    //kdDebug()<<k_funcinfo<<"date="<<temp<<"day="<<(TDEGlobal::locale()->calendar()->dayOfWeek(temp))<<" firstday="<<firstday<<endl;
    numdays=date.daysInMonth();
    if(date.month()==1) { // set to december of previous year
        temp.setYMD(date.year()-1, 12, 1);
        setWeekNumbers(TQDate(date.year()-1, 12, 31));
    } else { // set to previous month
        temp.setYMD(date.year(), date.month()-1, 1);
        TQDate d(date.year(), date.month()-1,1);
        setWeekNumbers(d.addDays(d.daysInMonth()-1));
    }
/*    if (m_selectedWeekdays.isEmpty() &&
        !m_selectedDates.isEmpty() && !m_selectedDates.contains(date))
    {
        //kdDebug()<<k_funcinfo<<"date inserted"<<endl;
        m_selectedDates.insert(date);
    }*/
    numDaysPrevMonth=temp.daysInMonth();
    if(changed && repaint) {
        repaintContents(false);
    }
    if (m_enabled)
      emit(dateChanged(date));
    return true;
}

const TQDate& DateTable::getDate() const {
  return date;
}

void DateTable::focusInEvent( TQFocusEvent *e ) {
    TQGridView::focusInEvent( e );
}

void DateTable::focusOutEvent( TQFocusEvent *e ) {
    TQGridView::focusOutEvent( e );
}

TQSize DateTable::sizeHint() const {
    if(maxCell.height()>0 && maxCell.width()>0) {
      return TQSize(maxCell.width()*numCols()+2*frameWidth(),
             (maxCell.height()+2)*numRows()+2*frameWidth());
    } else {
      //kdDebug() << "DateTable::sizeHint: obscure failure - " << endl;
      return TQSize(-1, -1);
    }
}

void DateTable::setWeekNumbers(TQDate date) {
    if (!date.isValid()) {
        kdError()<<k_funcinfo<<"Invalid date"<<endl;
    }
    TQDate d(date);
    for (int i = 1; i < 7; ++i) {
        m_weeks[i].first = d.weekNumber(&(m_weeks[i].second));
        //kdDebug()<<k_funcinfo<<"date="<<d.toString()<<" week=("<<m_weeks[i].first<<","<<m_weeks[i].second<<")"<<endl;
        d = d.addDays(7);
    }
}

void DateTable::updateCells() {
    //kdDebug()<<k_funcinfo<<endl;
    for (int row=0; row < numRows(); ++row) {
        for (int col=0; col < numCols(); ++col) {
            updateCell(row, col);
        }
    }
}

void DateTable::updateSelectedCells() {
    //kdDebug()<<k_funcinfo<<endl;
    TQDate dt(date.year(), date.month(), 1);
    dt = dt.addDays(-firstday);
    for (int pos=0; pos < 42; ++pos) {
        if (m_selectedDates.contains(dt.addDays(pos)) ||
            m_selectedWeekdays.contains(pos%7+1))
        {
            updateCell(pos/7+1, pos%7+1);
            //kdDebug()<<k_funcinfo<<" update cell ("<<pos/7+1<<","<<pos%7+1<<") date="<<dt.addDays(pos).toString()<<endl;
        }
    }
}

void DateTable::updateMarkedCells() {
    TQDate dt(date.year(), date.month(), 1);
    dt = dt.addDays(-firstday);
    for (int pos=0; pos < 42; ++pos) {
        if (m_markedDates.contains(dt.addDays(pos)) ||
            m_markedWeekdays.contains(pos%7+1))
        {
            updateCell(pos/7+1, pos%7+1);
            //kdDebug()<<k_funcinfo<<" update cell ("<<pos/7+1<<","<<pos%7+1<<") date="<<dt.addDays(pos).toString()<<endl;
        }
    }
}

void DateTable::setMarkedWeekdays(const IntMap days) {
    updateMarkedCells();
    m_markedWeekdays.clear();
    m_markedWeekdays = days;
    updateMarkedCells();
    repaintContents(false);
}

bool DateTable::weekdayMarked(int day) {
    return m_markedWeekdays.contains(day);
}

bool DateTable::dateMarked(TQDate date) {
    return m_markedDates[date.toString()];
}

TQDate DateTable::getDate(int pos) const {
    return TQDate(date.year(), date.month(), 1).addDays(pos-firstday); 
}

int DateTable::weekday(int col) const {
    int day = col - m_dateStartCol + TDEGlobal::locale()->weekStartDay();
    if (day > 7) day %= 7;
    //kdDebug()<<k_funcinfo<<"col="<<col<<" day="<<day<<" StartCol="<<m_dateStartCol<<" weekStartDay="<<TDEGlobal::locale()->weekStartDay()<<endl;
    return day;
}

int DateTable::column(int weekday) const {
    int col = weekday - TDEGlobal::locale()->weekStartDay();
    if (col < 0) col += 7;
    //kdDebug()<<k_funcinfo<<"col="<<col<<" day="<<col<<" StartCol="<<m_dateStartCol<<" weekStartDay="<<TDEGlobal::locale()->weekStartDay()<<endl;
    return col + m_dateStartCol;
}

void DateTable::clear() {
    clearSelection();
    m_markedDates.clear();
    m_markedWeekdays.clear();
    repaintContents(false);
}

void DateTable::clearSelection() {
    m_selectedDates.clear();
    m_selectedWeekdays.clear();
    repaintContents(false);
}

 void DateTable::setEnabled(bool yes) {
    if (m_enabled == yes)
        return;
    m_enabled=yes;
    updateCells();
}

void DateTable::markSelected(int state) {
    if (!m_selectedDates.isEmpty()) {
        DateMap::iterator it;
        for(it = m_selectedDates.begin(); it != m_selectedDates.end(); ++it) {
            m_markedDates.insert(it.key(), state);
            //kdDebug()<<k_funcinfo<<"marked date: "<<it.key()<<"="<<state<<endl;
        }
    } else if (!m_selectedWeekdays.isEmpty()) {
        IntMap::iterator it;
        for(it = m_selectedWeekdays.begin(); it != m_selectedWeekdays.end(); ++it) {
            m_markedWeekdays.insert(it.key(), state);
            //kdDebug()<<k_funcinfo<<"marked weekday: "<<it.key()<<"="<<state<<endl;
        }
    }
    updateSelectedCells();
    repaintContents(false);
}

DateInternalWeekSelector::DateInternalWeekSelector
(int fontsize, TQWidget* parent, const char* name)
  : TQLineEdit(parent, name),
    val(new TQIntValidator(TQT_TQOBJECT(this))),
    result(0)
{
  TQFont font;
  // -----
  font=TDEGlobalSettings::generalFont();
  font.setPointSize(fontsize);
  setFont(font);
  setFrameStyle(TQFrame::NoFrame);
  val->setRange(1, 53);
  setValidator(val);
  connect(this, TQT_SIGNAL(returnPressed()), TQT_SLOT(weekEnteredSlot()));
}

void
DateInternalWeekSelector::weekEnteredSlot()
{
  bool ok;
  int week;
  // ----- check if this is a valid week:
  week=text().toInt(&ok);
  if(!ok)
    {
      KNotifyClient::beep();
      return;
    }
  result=week;
  emit(closeMe(1));
}

int
DateInternalWeekSelector::getWeek() const
{
  return result;
}

void
DateInternalWeekSelector::setWeek(int week)
{
  TQString temp;
  // -----
  temp.setNum(week);
  setText(temp);
}

DateInternalMonthPicker::DateInternalMonthPicker
(int fontsize, TQWidget* parent, const char* name)
  : TQGridView(parent, name),
    result(0) // invalid
{
  TQRect rect;
  TQFont font;
  // -----
  activeCol = -1;
  activeRow = -1;
  font=TDEGlobalSettings::generalFont();
  font.setPointSize(fontsize);
  setFont(font);
  setHScrollBarMode(AlwaysOff);
  setVScrollBarMode(AlwaysOff);
  setFrameStyle(TQFrame::NoFrame);
  setNumRows(4);
  setNumCols(3);
  // enable to find drawing failures:
  // setTableFlags(Tbl_clipCellPainting);
  viewport()->setEraseColor(TDEGlobalSettings::baseColor()); // for consistency with the datepicker
  // ----- find the preferred size
  //       (this is slow, possibly, but unfortunatly it is needed here):
  TQFontMetrics metrics(font);
  for(int i=1; i <= 12; ++i)
    {
      rect=metrics.boundingRect(TDEGlobal::locale()->calendar()->monthName(i, false));
      if(max.width()<rect.width()) max.setWidth(rect.width());
      if(max.height()<rect.height()) max.setHeight(rect.height());
    }

}

TQSize
DateInternalMonthPicker::sizeHint() const
{
  return TQSize((max.width()+6)*numCols()+2*frameWidth(),
         (max.height()+6)*numRows()+2*frameWidth());
}

int
DateInternalMonthPicker::getResult() const
{
  return result;
}

void
DateInternalMonthPicker::setupPainter(TQPainter *p)
{
  p->setPen(TDEGlobalSettings::textColor());
}

void
DateInternalMonthPicker::viewportResizeEvent(TQResizeEvent*)
{
  setCellWidth(width()/3);
  setCellHeight(height()/4);
}

void
DateInternalMonthPicker::paintCell(TQPainter* painter, int row, int col)
{
  int index;
  TQString text;
  // ----- find the number of the cell:
  index=3*row+col+1;
  text=TDEGlobal::locale()->calendar()->monthName(index, false);
  painter->drawText(0, 0, cellWidth(), cellHeight(), AlignCenter, text);
  if ( activeCol == col && activeRow == row )
      painter->drawRect( 0, 0, cellWidth(), cellHeight() );
}

void
DateInternalMonthPicker::contentsMousePressEvent(TQMouseEvent *e)
{
  if(!isEnabled() || e->button() != Qt::LeftButton)
    {
      KNotifyClient::beep();
      return;
    }
  // -----
  int row, col;
  TQPoint mouseCoord;
  // -----
  mouseCoord = e->pos();
  row=rowAt(mouseCoord.y());
  col=columnAt(mouseCoord.x());

  if(row<0 || col<0)
    { // the user clicked on the frame of the table
      activeCol = -1;
      activeRow = -1;
    } else {
      activeCol = col;
      activeRow = row;
      updateCell( row, col /*, false */ );
  }
}

void
DateInternalMonthPicker::contentsMouseMoveEvent(TQMouseEvent *e)
{
  if (e->state() & Qt::LeftButton)
    {
      int row, col;
      TQPoint mouseCoord;
      // -----
      mouseCoord = e->pos();
      row=rowAt(mouseCoord.y());
      col=columnAt(mouseCoord.x());
      int tmpRow = -1, tmpCol = -1;
      if(row<0 || col<0)
        { // the user clicked on the frame of the table
          if ( activeCol > -1 )
            {
              tmpRow = activeRow;
              tmpCol = activeCol;
            }
          activeCol = -1;
          activeRow = -1;
        } else {
          bool differentCell = (activeRow != row || activeCol != col);
          if ( activeCol > -1 && differentCell)
            {
              tmpRow = activeRow;
              tmpCol = activeCol;
            }
          if ( differentCell)
            {
              activeRow = row;
              activeCol = col;
              updateCell( row, col /*, false */ ); // mark the new active cell
            }
        }
      if ( tmpRow > -1 ) // repaint the former active cell
          updateCell( tmpRow, tmpCol /*, true */ );
    }
}

void
DateInternalMonthPicker::contentsMouseReleaseEvent(TQMouseEvent *e)
{
  if(!isEnabled())
    {
      return;
    }
  // -----
  int row, col, pos;
  TQPoint mouseCoord;
  // -----
  mouseCoord = e->pos();
  row=rowAt(mouseCoord.y());
  col=columnAt(mouseCoord.x());
  if(row<0 || col<0)
    { // the user clicked on the frame of the table
      emit(closeMe(0));
    }
  pos=3*row+col+1;
  result=pos;
  emit(closeMe(1));
}



DateInternalYearSelector::DateInternalYearSelector
(int fontsize, TQWidget* parent, const char* name)
  : TQLineEdit(parent, name),
    val(new TQIntValidator(TQT_TQOBJECT(this))),
    result(0)
{
  TQFont font;
  // -----
  font=TDEGlobalSettings::generalFont();
  font.setPointSize(fontsize);
  setFont(font);
  setFrameStyle(TQFrame::NoFrame);
  // we have to respect the limits of TQDate here, I fear:
  val->setRange(0, 8000);
  setValidator(val);
  connect(this, TQT_SIGNAL(returnPressed()), TQT_SLOT(yearEnteredSlot()));
}

void
DateInternalYearSelector::yearEnteredSlot()
{
  bool ok;
  int year;
  TQDate date;
  // ----- check if this is a valid year:
  year=text().toInt(&ok);
  if(!ok)
    {
      KNotifyClient::beep();
      return;
    }
  date.setYMD(year, 1, 1);
  if(!date.isValid())
    {
      KNotifyClient::beep();
      return;
    }
  result=year;
  emit(closeMe(1));
}

int
DateInternalYearSelector::getYear() const
{
  return result;
}

void
DateInternalYearSelector::setYear(int year)
{
  TQString temp;
  // -----
  temp.setNum(year);
  setText(temp);
}

PopupFrame::PopupFrame(TQWidget* parent, const char*  name)
  : TQFrame(parent, name, WType_Popup),
    result(0), // rejected
    main(0)
{
  setFrameStyle(TQFrame::Box|TQFrame::Raised);
  setMidLineWidth(2);
}

void
PopupFrame::keyPressEvent(TQKeyEvent* e)
{
  if(e->key()==Key_Escape)
    {
      result=0; // rejected
      tqApp->exit_loop();
    }
}

void
PopupFrame::close(int r)
{
  result=r;
  tqApp->exit_loop();
}

void
PopupFrame::setMainWidget(TQWidget* m)
{
  main=m;
  if(main!=0)
    {
      resize(main->width()+2*frameWidth(), main->height()+2*frameWidth());
    }
}

void
PopupFrame::resizeEvent(TQResizeEvent*)
{
  if(main!=0)
    {
      main->setGeometry(frameWidth(), frameWidth(),
          width()-2*frameWidth(), height()-2*frameWidth());
    }
}

void
PopupFrame::popup(const TQPoint &pos)
{
  // Make sure the whole popup is visible.
  TQRect d = TQApplication::desktop()->screenGeometry(TQApplication::desktop()->screenNumber(pos));
  int x = pos.x();
  int y = pos.y();
  int w = width();
  int h = height();
  if (x+w > d.x()+d.width())
    x = d.width() - w;
  if (y+h > d.y()+d.height())
    y = d.height() - h;
  if (x < d.x())
    x = 0;
  if (y < d.y())
    y = 0;

  // Pop the thingy up.
  move(x, y);
  show();
}

int
PopupFrame::exec(TQPoint pos)
{
  popup(pos);
  repaint();
  tqApp->enter_loop();
  hide();
  return result;
}

int
PopupFrame::exec(int x, int y)
{
  return exec(TQPoint(x, y));
}

void PopupFrame::virtual_hook( int, void* )
{ /*BASE::virtual_hook( id, data );*/ }

void DateTable::virtual_hook( int, void* )
{ /*BASE::virtual_hook( id, data );*/ }

}  //KPlato namespace

#include "kptdatetable.moc"
