You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
tdepim/korganizer/koeditorgeneraltodo.cpp

572 lines
18 KiB

/*
This file is part of KOrganizer.
Copyright (c) 2000,2001 Cornelius Schumacher <schumacher@kde.org>
Copyright (C) 2003-2004 Reinhold Kainhofer <reinhold@kainhofer.com>
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.
This program 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
As a special exception, permission is given to link this program
with any edition of Qt, and distribute the resulting executable,
without including the source code for Qt in the source distribution.
*/
#include <qtooltip.h>
#include <qfiledialog.h>
#include <qlayout.h>
#include <qvbox.h>
#include <qbuttongroup.h>
#include <qvgroupbox.h>
#include <qwidgetstack.h>
#include <qdatetime.h>
#include <qcheckbox.h>
#include <qlabel.h>
#include <qspinbox.h>
#include <qpushbutton.h>
#include <qwhatsthis.h>
#include <kglobal.h>
#include <klocale.h>
#include <kiconloader.h>
#include <kmessagebox.h>
#include <kdebug.h>
#include <kstandarddirs.h>
#include <kfiledialog.h>
#include <ktextedit.h>
#include <libkcal/todo.h>
#include <libkdepim/kdateedit.h>
#include "koprefs.h"
#include "koglobals.h"
#include "ktimeedit.h"
#include "koeditorgeneraltodo.h"
#include "koeditorgeneraltodo.moc"
KOEditorGeneralTodo::KOEditorGeneralTodo(QObject* parent,
const char* name)
: KOEditorGeneral( parent, name)
{
}
KOEditorGeneralTodo::~KOEditorGeneralTodo()
{
}
void KOEditorGeneralTodo::finishSetup()
{
QWidget::setTabOrder( mSummaryEdit, mLocationEdit );
QWidget::setTabOrder( mLocationEdit, mStartCheck );
QWidget::setTabOrder( mStartCheck, mStartDateEdit );
QWidget::setTabOrder( mStartDateEdit, mStartTimeEdit );
QWidget::setTabOrder( mStartTimeEdit, mDueCheck );
QWidget::setTabOrder( mDueCheck, mDueDateEdit );
QWidget::setTabOrder( mDueDateEdit, mDueTimeEdit );
QWidget::setTabOrder( mDueTimeEdit, mTimeButton );
QWidget::setTabOrder( mTimeButton, mCompletedCombo );
QWidget::setTabOrder( mCompletedCombo, mPriorityCombo );
QWidget::setTabOrder( mPriorityCombo, mAlarmButton );
QWidget::setTabOrder( mAlarmButton, mAlarmTimeEdit );
QWidget::setTabOrder( mAlarmTimeEdit, mAlarmIncrCombo );
// QWidget::setTabOrder( mAlarmIncrCombo, mAlarmSoundButton );
QWidget::setTabOrder( mAlarmIncrCombo, mAlarmEditButton );
// QWidget::setTabOrder( mAlarmSoundButton, mAlarmProgramButton );
// QWidget::setTabOrder( mAlarmProgramButton, mDescriptionEdit );
QWidget::setTabOrder( mAlarmEditButton, mDescriptionEdit );
QWidget::setTabOrder( mDescriptionEdit, mCategoriesButton );
QWidget::setTabOrder( mCategoriesButton, mSecrecyCombo );
// QWidget::setTabOrder( mSecrecyCombo, mDescriptionEdit );
mSummaryEdit->setFocus();
}
void KOEditorGeneralTodo::initTime(QWidget *parent,QBoxLayout *topLayout)
{
kdDebug(5850) << k_funcinfo << endl;
QBoxLayout *timeLayout = new QVBoxLayout(topLayout);
QGroupBox *timeGroupBox = new QGroupBox(1,QGroupBox::Horizontal,
i18n("Date && Time"),parent);
timeLayout->addWidget(timeGroupBox);
QFrame *timeBoxFrame = new QFrame(timeGroupBox);
QWhatsThis::add( timeBoxFrame,
i18n("Sets options for due and start dates and times "
"for this to-do.") );
QGridLayout *layoutTimeBox = new QGridLayout(timeBoxFrame,1,1);
layoutTimeBox->setSpacing(topLayout->spacing());
QString whatsThis = i18n("Sets the start date for this to-do");
mStartCheck = new QCheckBox(i18n("Sta&rt:"),timeBoxFrame);
QWhatsThis::add( mStartCheck, whatsThis );
layoutTimeBox->addWidget(mStartCheck,0,0);
connect(mStartCheck,SIGNAL(toggled(bool)),SLOT(enableStartEdit(bool)));
connect(mStartCheck,SIGNAL(toggled(bool)),SLOT(startDateModified()));
mStartDateEdit = new KDateEdit(timeBoxFrame);
QWhatsThis::add( mStartDateEdit, whatsThis );
layoutTimeBox->addWidget(mStartDateEdit,0,1);
connect(mStartDateEdit,SIGNAL(dateChanged(const QDate&)),SLOT(startDateModified()));
mStartTimeEdit = new KTimeEdit(timeBoxFrame);
QWhatsThis::add( mStartTimeEdit,
i18n("Sets the start time for this to-do.") );
layoutTimeBox->addWidget(mStartTimeEdit,0,2);
connect(mStartTimeEdit,SIGNAL(timeChanged(QTime)),SLOT(startDateModified()));
whatsThis = i18n("Sets the due date for this to-do.");
mDueCheck = new QCheckBox(i18n("&Due:"),timeBoxFrame);
QWhatsThis::add( mDueCheck, whatsThis );
layoutTimeBox->addWidget(mDueCheck,1,0);
connect(mDueCheck,SIGNAL(toggled(bool)),SLOT(enableDueEdit(bool)));
connect(mDueCheck,SIGNAL(toggled(bool)),SLOT(showAlarm()));
connect(mDueCheck,SIGNAL(toggled(bool)),SIGNAL(dueDateEditToggle(bool)));
connect(mDueCheck,SIGNAL(toggled(bool)),SLOT(dateChanged()));
mDueDateEdit = new KDateEdit(timeBoxFrame);
QWhatsThis::add( mDueDateEdit, whatsThis );
layoutTimeBox->addWidget(mDueDateEdit,1,1);
connect(mDueDateEdit,SIGNAL(dateChanged(const QDate&)),SLOT(dateChanged()));
mDueTimeEdit = new KTimeEdit(timeBoxFrame);
QWhatsThis::add( mDueTimeEdit,
i18n("Sets the due time for this to-do.") );
layoutTimeBox->addWidget(mDueTimeEdit,1,2);
connect(mDueTimeEdit,SIGNAL(timeChanged( QTime )),SLOT(dateChanged()));
mTimeButton = new QCheckBox(i18n("Ti&me associated"),timeBoxFrame);
QWhatsThis::add( mTimeButton,
i18n("Sets whether or not this to-do's start and due dates "
"have times associated with them.") );
layoutTimeBox->addMultiCellWidget(mTimeButton,2,2,0,2);
connect(mTimeButton,SIGNAL(toggled(bool)),SLOT(enableTimeEdits(bool)));
connect(mTimeButton,SIGNAL(toggled(bool)),SLOT(dateChanged()));
// some more layouting
layoutTimeBox->setColStretch(3,1);
QBoxLayout *secLayout = new QHBoxLayout();
layoutTimeBox->addLayout( secLayout, 0, 4 );
initSecrecy( timeBoxFrame, secLayout );
}
void KOEditorGeneralTodo::initCompletion(QWidget *parent, QBoxLayout *topLayout)
{
QString whatsThis = i18n("Sets the current completion status of this to-do "
"as a percentage.");
mCompletedCombo = new QComboBox(parent);
QWhatsThis::add( mCompletedCombo, whatsThis );
for (int i = 0; i <= 100; i+=10) {
// xgettext:no-c-format
QString label = i18n("Percent complete", "%1 %").arg (i);
mCompletedCombo->insertItem(label);
}
connect(mCompletedCombo,SIGNAL(activated(int)),SLOT(completedChanged(int)));
topLayout->addWidget(mCompletedCombo);
mCompletedLabel = new QLabel(i18n("co&mpleted"),parent);
topLayout->addWidget(mCompletedLabel);
mCompletedLabel->setBuddy( mCompletedCombo );
mCompletionDateEdit = new KDateEdit( parent );
mCompletionDateEdit->hide();
topLayout->addWidget( mCompletionDateEdit );
mCompletionTimeEdit = new KTimeEdit( parent, QTime() );
mCompletionTimeEdit->hide();
topLayout->addWidget( mCompletionTimeEdit );
}
void KOEditorGeneralTodo::initPriority(QWidget *parent, QBoxLayout *topLayout)
{
QString whatsThis = i18n("Sets the priority of this to-do on a scale "
"from one to nine, with one being the highest "
"priority, five being a medium priority, and "
"nine being the lowest. In programs that have a "
"different scale, the numbers will be adjusted "
"to match the appropriate scale.");
QLabel *priorityLabel = new QLabel(i18n("&Priority:"),parent);
topLayout->addWidget(priorityLabel);
mPriorityCombo = new QComboBox(parent);
mPriorityCombo->insertItem(i18n("unspecified"));
mPriorityCombo->insertItem(i18n("1 (highest)"));
mPriorityCombo->insertItem(i18n("2"));
mPriorityCombo->insertItem(i18n("3"));
mPriorityCombo->insertItem(i18n("4"));
mPriorityCombo->insertItem(i18n("5 (medium)"));
mPriorityCombo->insertItem(i18n("6"));
mPriorityCombo->insertItem(i18n("7"));
mPriorityCombo->insertItem(i18n("8"));
mPriorityCombo->insertItem(i18n("9 (lowest)"));
topLayout->addWidget(mPriorityCombo);
priorityLabel->setBuddy( mPriorityCombo );
}
void KOEditorGeneralTodo::initStatus(QWidget *parent,QBoxLayout *topLayout)
{
QBoxLayout *statusLayout = new QHBoxLayout(topLayout);
initCompletion( parent, statusLayout );
statusLayout->addStretch( 1 );
initPriority( parent, statusLayout );
}
void KOEditorGeneralTodo::setDefaults( const QDateTime &due, bool allDay )
{
kdDebug(5850) << k_funcinfo << due <<endl;
KOEditorGeneral::setDefaults(allDay);
mTimeButton->setChecked( !allDay );
mTimeButton->setEnabled( mTimeButton->isChecked() /* i.e. !allDay */ );
enableTimeEdits( !allDay );
mDueCheck->setChecked( due.isValid() );
enableDueEdit( due.isValid() );
mStartCheck->setChecked(false);
enableStartEdit(false);
if ( due.isValid() ) {
mDueDateEdit->setDate( due.date() );
mDueTimeEdit->setTime( due.time() );
} else {
// Make it due tomorrow.
mDueDateEdit->setDate( QDate::currentDate().addDays(1) );
mDueTimeEdit->setTime( QTime::currentTime() );
}
if ( !due.isValid() || (QDateTime::currentDateTime() < due) ) {
mStartDateEdit->setDate( QDate::currentDate() );
mStartTimeEdit->setTime( QTime::currentTime() );
} else {
mStartDateEdit->setDate( due.date().addDays( -1 ) );
mStartTimeEdit->setTime( due.time() );
}
mStartDateModified = false;
mPriorityCombo->setCurrentItem(5);
mCompletedCombo->setCurrentItem(0);
}
void KOEditorGeneralTodo::readTodo(Todo *todo, Calendar *calendar)
{
KOEditorGeneral::readIncidence(todo, calendar);
QDateTime dueDT;
if (todo->hasDueDate()) {
enableAlarm( true );
dueDT = todo->dtDue();
mDueDateEdit->setDate(todo->dtDue().date());
mDueTimeEdit->setTime(todo->dtDue().time());
mDueCheck->setChecked(true);
} else {
enableAlarm( false );
mDueDateEdit->setEnabled(false);
mDueTimeEdit->setEnabled(false);
mDueDateEdit->setDate(QDate::currentDate());
mDueTimeEdit->setTime(QTime::currentTime());
mDueCheck->setChecked(false);
}
if (todo->hasStartDate()) {
mStartDateEdit->setDate(todo->dtStart().date());
mStartTimeEdit->setTime(todo->dtStart().time());
mStartCheck->setChecked(true);
} else {
mStartDateEdit->setEnabled(false);
mStartTimeEdit->setEnabled(false);
mStartDateEdit->setDate(QDate::currentDate());
mStartTimeEdit->setTime(QTime::currentTime());
mStartCheck->setChecked(false);
}
mTimeButton->setChecked( !todo->doesFloat() );
mAlreadyComplete = false;
mCompletedCombo->setCurrentItem(todo->percentComplete() / 10);
if (todo->isCompleted() && todo->hasCompletedDate()) {
mCompleted = todo->completed();
mAlreadyComplete = true;
}
setCompletedDate();
mPriorityCombo->setCurrentItem( todo->priority() );
mStartDateModified = false;
}
void KOEditorGeneralTodo::writeTodo(Todo *todo)
{
KOEditorGeneral::writeIncidence(todo);
// temp. until something better happens.
QString tmpStr;
todo->setHasDueDate(mDueCheck->isChecked());
todo->setHasStartDate(mStartCheck->isChecked());
QDate tmpSDate, tmpDDate;
QTime tmpSTime, tmpDTime;
QDateTime tmpStartDT, tmpDueDT;
if ( mTimeButton->isChecked() ) {
todo->setFloats(false);
// set due date/time
tmpDDate = mDueDateEdit->date();
tmpDTime = mDueTimeEdit->getTime();
tmpDueDT.setDate(tmpDDate);
tmpDueDT.setTime(tmpDTime);
// set start date/time
if ( mStartCheck->isChecked() ) {
tmpSDate = mStartDateEdit->date();
tmpSTime = mStartTimeEdit->getTime();
tmpStartDT.setDate(tmpSDate);
tmpStartDT.setTime(tmpSTime);
} else {
tmpStartDT = tmpDueDT;
}
} else {
todo->setFloats(true);
// need to change this.
tmpDDate = mDueDateEdit->date();
tmpDTime.setHMS(0,0,0);
tmpDueDT.setDate(tmpDDate);
tmpDueDT.setTime(tmpDTime);
if ( mStartCheck->isChecked() ) {
tmpSDate = mStartDateEdit->date();
tmpSTime.setHMS(0,0,0);
tmpStartDT.setDate(tmpSDate);
tmpStartDT.setTime(tmpSTime);
} else {
tmpStartDT = tmpDueDT;
}
}
// TODO: Don't use the due date for the recurrence, but the start date (cf. rfc 2445)
if ( todo->doesRecur() && !mStartDateModified ) {
todo->setDtDue( tmpDueDT );
} else {
todo->setDtDue( tmpDueDT, true );
todo->setDtStart( tmpStartDT );
todo->setDtRecurrence( tmpDueDT );
}
todo->setPriority( mPriorityCombo->currentItem() );
// set completion state
todo->setPercentComplete(mCompletedCombo->currentItem() * 10);
if (mCompletedCombo->currentItem() == 10 && mCompleted.isValid()) {
QDateTime completed( mCompletionDateEdit->date(),
mCompletionTimeEdit->getTime() );
int difference = mCompleted.secsTo( completed );
if ( (difference < 60) && (difference > -60) &&
(completed.time().minute() == mCompleted.time().minute() ) ) {
// completion time wasn't changed substantially (only the seconds
// truncated, but that's an effect done by KTimeEdit automatically).
completed = mCompleted;
}
todo->setCompleted( completed );
}
}
void KOEditorGeneralTodo::enableDueEdit(bool enable)
{
mDueDateEdit->setEnabled( enable );
if(mDueCheck->isChecked() || mStartCheck->isChecked()) {
mTimeButton->setEnabled(true);
} else {
mTimeButton->setEnabled(false);
}
if (enable) {
mDueTimeEdit->setEnabled( mTimeButton->isChecked() );
} else {
mDueTimeEdit->setEnabled( false );
}
}
void KOEditorGeneralTodo::enableStartEdit( bool enable )
{
mStartDateEdit->setEnabled( enable );
if(mDueCheck->isChecked() || mStartCheck->isChecked()) {
mTimeButton->setEnabled(true);
}
else {
mTimeButton->setEnabled(false);
mTimeButton->setChecked(false);
}
if (enable) {
mStartTimeEdit->setEnabled( mTimeButton->isChecked() );
} else {
mStartTimeEdit->setEnabled( false );
}
}
void KOEditorGeneralTodo::enableTimeEdits(bool enable)
{
if(mStartCheck->isChecked()) {
mStartTimeEdit->setEnabled( enable );
}
if(mDueCheck->isChecked()) {
mDueTimeEdit->setEnabled( enable );
}
}
void KOEditorGeneralTodo::showAlarm()
{
enableAlarm( mDueCheck->isChecked() );
}
bool KOEditorGeneralTodo::validateInput()
{
if (mDueCheck->isChecked()) {
if (!mDueDateEdit->date().isValid()) {
KMessageBox::sorry(0,i18n("Please specify a valid due date."));
return false;
}
if (mTimeButton->isChecked()) {
if (!mDueTimeEdit->inputIsValid()) {
KMessageBox::sorry(0,i18n("Please specify a valid due time."));
return false;
}
}
}
if (mStartCheck->isChecked()) {
if (!mStartDateEdit->date().isValid()) {
KMessageBox::sorry(0,i18n("Please specify a valid start date."));
return false;
}
if (mTimeButton->isChecked()) {
if (!mStartTimeEdit->inputIsValid()) {
KMessageBox::sorry(0,i18n("Please specify a valid start time."));
return false;
}
}
}
if (mStartCheck->isChecked() && mDueCheck->isChecked()) {
QDateTime startDate;
QDateTime dueDate;
startDate.setDate(mStartDateEdit->date());
dueDate.setDate(mDueDateEdit->date());
if (mTimeButton->isChecked()) {
startDate.setTime(mStartTimeEdit->getTime());
dueDate.setTime(mDueTimeEdit->getTime());
}
if (startDate > dueDate) {
KMessageBox::sorry(0,
i18n("The start date cannot be after the due date."));
return false;
}
}
return KOEditorGeneral::validateInput();
}
void KOEditorGeneralTodo::completedChanged(int index)
{
if (index == 10) {
mCompleted = QDateTime::currentDateTime();
}
setCompletedDate();
}
void KOEditorGeneralTodo::dateChanged()
{
KLocale *l = KGlobal::locale();
QString dateTimeStr = "";
if ( mStartCheck->isChecked() ) {
dateTimeStr += i18n("Start: %1").arg(
l->formatDate( mStartDateEdit->date() ) );
if ( mTimeButton->isChecked() )
dateTimeStr += QString(" %1").arg(
l->formatTime( mStartTimeEdit->getTime() ) );
}
if ( mDueCheck->isChecked() ) {
dateTimeStr += i18n(" Due: %1").arg(
l->formatDate( mDueDateEdit->date() ) );
if ( mTimeButton->isChecked() )
dateTimeStr += QString(" %1").arg(
l->formatTime( mDueTimeEdit->getTime() ) );
}
emit dateTimeStrChanged( dateTimeStr );
QDateTime endDt( mDueDateEdit->date(), mDueTimeEdit->getTime() );
emit signalDateTimeChanged( endDt, endDt );
}
void KOEditorGeneralTodo::startDateModified()
{
mStartDateModified = true;
dateChanged();
}
void KOEditorGeneralTodo::setCompletedDate()
{
if (mCompletedCombo->currentItem() == 10 && mCompleted.isValid()) {
mCompletedLabel->setText(i18n("co&mpleted on"));
// .arg(KGlobal::locale()->formatDateTime(mCompleted)));
mCompletionDateEdit->show();
mCompletionTimeEdit->show();
mCompletionDateEdit->setDate( mCompleted.date() );
mCompletionTimeEdit->setTime( mCompleted.time() );
} else {
mCompletedLabel->setText(i18n("co&mpleted"));
mCompletionDateEdit->hide();
mCompletionTimeEdit->hide();
}
}
void KOEditorGeneralTodo::modified (Todo* todo, int modification)
{
switch (modification) {
case KOGlobals::PRIORITY_MODIFIED:
mPriorityCombo->setCurrentItem( todo->priority() );
break;
case KOGlobals::COMPLETION_MODIFIED:
mCompletedCombo->setCurrentItem(todo->percentComplete() / 10);
if (todo->isCompleted() && todo->hasCompletedDate()) {
mCompleted = todo->completed();
}
setCompletedDate();
break;
case KOGlobals::CATEGORY_MODIFIED:
setCategories( todo->categories() );
break;
case KOGlobals::UNKNOWN_MODIFIED: // fall through
default:
readTodo( todo, 0 );
break;
}
}