mirror of
https://bitbucket.org/smil3y/kde-playground.git
synced 2025-02-24 10:52:52 +00:00
834 lines
27 KiB
C++
834 lines
27 KiB
C++
/*
|
|
Copyright (c) 2010 Bertjan Broeksema <broeksema@kde.org>
|
|
Copyright (c) 2010 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.com>
|
|
Copyright (C) 2012 Allen Winter <winter@kde.org>
|
|
|
|
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 "incidencedialog.h"
|
|
#include "combinedincidenceeditor.h"
|
|
#include "editorconfig.h"
|
|
#include "incidencealarm.h"
|
|
#include "incidenceattachment.h"
|
|
#include "incidenceattendee.h"
|
|
#include "incidencecategories.h"
|
|
#include "incidencecompletionpriority.h"
|
|
#include "incidencedatetime.h"
|
|
#include "incidencedescription.h"
|
|
#include "incidencerecurrence.h"
|
|
#include "incidencesecrecy.h"
|
|
#include "incidencewhatwhere.h"
|
|
#include "templatemanagementdialog.h"
|
|
#include "ui_dialogdesktop.h"
|
|
|
|
#include <incidenceeditor-ng/globalsettings.h>
|
|
|
|
#include <calendarsupport/kcalprefs.h>
|
|
#include <calendarsupport/utils.h>
|
|
|
|
#include <Akonadi/CollectionComboBox>
|
|
#include <Akonadi/Item>
|
|
#include <Akonadi/Calendar/ETMCalendar>
|
|
|
|
#include <KCalCore/ICalFormat>
|
|
#include <KCalCore/MemoryCalendar>
|
|
#include <KCalUtils/Stringify>
|
|
|
|
#include <KMessageBox>
|
|
#include <KStandardDirs>
|
|
#include <KSystemTimeZones>
|
|
|
|
#include <QCloseEvent>
|
|
|
|
using namespace IncidenceEditorNG;
|
|
|
|
namespace IncidenceEditorNG {
|
|
|
|
enum Tabs {
|
|
GeneralTab = 0,
|
|
AttendeesTab,
|
|
AlarmsTab,
|
|
RecurrenceTab,
|
|
AttachmentsTab
|
|
};
|
|
|
|
class IncidenceDialogPrivate : public ItemEditorUi
|
|
{
|
|
IncidenceDialog *q_ptr;
|
|
Q_DECLARE_PUBLIC( IncidenceDialog )
|
|
|
|
public:
|
|
Ui::EventOrTodoDesktop *mUi;
|
|
Akonadi::CollectionComboBox *mCalSelector;
|
|
bool mCloseOnSave;
|
|
|
|
EditorItemManager *mItemManager;
|
|
CombinedIncidenceEditor *mEditor;
|
|
IncidenceDateTime *mIeDateTime;
|
|
IncidenceAttendee *mIeAttendee;
|
|
IncidenceRecurrence *mIeRecurrence;
|
|
bool mInitiallyDirty;
|
|
Akonadi::Item mItem;
|
|
QString typeToString( const int type ) const;
|
|
|
|
public:
|
|
IncidenceDialogPrivate( Akonadi::IncidenceChanger *changer, IncidenceDialog *qq );
|
|
~IncidenceDialogPrivate();
|
|
|
|
/// General methods
|
|
void handleAlarmCountChange( int newCount );
|
|
void handleRecurrenceChange( IncidenceEditorNG::RecurrenceType type );
|
|
void loadTemplate( const QString &templateName );
|
|
void manageTemplates();
|
|
void saveTemplate( const QString &templateName );
|
|
void storeTemplatesInConfig( const QStringList &newTemplates );
|
|
void updateAttachmentCount( int newCount );
|
|
void updateAttendeeCount( int newCount );
|
|
void updateButtonStatus( bool isDirty );
|
|
void showMessage( const QString &text, KMessageWidget::MessageType type );
|
|
void slotInvalidCollection();
|
|
|
|
/// ItemEditorUi methods
|
|
virtual bool containsPayloadIdentifiers( const QSet<QByteArray> &partIdentifiers ) const;
|
|
void handleItemSaveFinish( EditorItemManager::SaveAction );
|
|
void handleItemSaveFail( EditorItemManager::SaveAction, const QString &errorMessage );
|
|
virtual bool hasSupportedPayload( const Akonadi::Item &item ) const;
|
|
virtual bool isDirty() const;
|
|
virtual bool isValid() const;
|
|
virtual void load( const Akonadi::Item &item );
|
|
virtual Akonadi::Item save( const Akonadi::Item &item );
|
|
virtual Akonadi::Collection selectedCollection() const;
|
|
void slotButtonClicked( int button );
|
|
|
|
virtual void reject( RejectReason reason, const QString &errorMessage = QString() );
|
|
};
|
|
|
|
}
|
|
|
|
IncidenceDialogPrivate::IncidenceDialogPrivate( Akonadi::IncidenceChanger *changer,
|
|
IncidenceDialog *qq )
|
|
: q_ptr( qq ),
|
|
mUi( new Ui::EventOrTodoDesktop ),
|
|
mCalSelector( new Akonadi::CollectionComboBox ),
|
|
mCloseOnSave( false ),
|
|
mItemManager( new EditorItemManager( this, changer ) ),
|
|
mEditor( new CombinedIncidenceEditor ),
|
|
mInitiallyDirty( false )
|
|
{
|
|
Q_Q( IncidenceDialog );
|
|
mUi->setupUi( q->mainWidget() );
|
|
QGridLayout *layout = new QGridLayout( mUi->mCalSelectorPlaceHolder );
|
|
layout->setSpacing( 0 );
|
|
layout->addWidget( mCalSelector );
|
|
mCalSelector->setAccessRightsFilter( Akonadi::Collection::CanCreateItem );
|
|
|
|
q->connect( mCalSelector, SIGNAL(currentChanged(Akonadi::Collection)),
|
|
SLOT(handleSelectedCollectionChange(Akonadi::Collection)) );
|
|
|
|
// Now instantiate the logic of the dialog. These editors update the ui, validate
|
|
// fields and load/store incidences in the ui.
|
|
IncidenceWhatWhere *ieGeneral = new IncidenceWhatWhere( mUi );
|
|
mEditor->combine( ieGeneral );
|
|
|
|
IncidenceCategories *ieCategories = new IncidenceCategories( mUi );
|
|
mEditor->combine( ieCategories );
|
|
|
|
mIeDateTime = new IncidenceDateTime( mUi );
|
|
mEditor->combine( mIeDateTime );
|
|
|
|
IncidenceCompletionPriority *ieCompletionPriority = new IncidenceCompletionPriority( mUi );
|
|
mEditor->combine( ieCompletionPriority );
|
|
|
|
IncidenceDescription *ieDescription = new IncidenceDescription( mUi );
|
|
mEditor->combine( ieDescription );
|
|
|
|
IncidenceAlarm *ieAlarm = new IncidenceAlarm( mIeDateTime, mUi );
|
|
mEditor->combine( ieAlarm );
|
|
|
|
IncidenceAttachment *ieAttachments = new IncidenceAttachment( mUi );
|
|
mEditor->combine( ieAttachments );
|
|
|
|
mIeRecurrence = new IncidenceRecurrence( mIeDateTime, mUi );
|
|
mEditor->combine( mIeRecurrence );
|
|
|
|
IncidenceSecrecy *ieSecrecy = new IncidenceSecrecy( mUi );
|
|
mEditor->combine( ieSecrecy );
|
|
|
|
mIeAttendee = new IncidenceAttendee( qq, mIeDateTime, mUi );
|
|
mEditor->combine( mIeAttendee );
|
|
|
|
q->connect( mEditor, SIGNAL(showMessage(QString,KMessageWidget::MessageType)),
|
|
SLOT(showMessage(QString,KMessageWidget::MessageType)) );
|
|
q->connect( mEditor, SIGNAL(dirtyStatusChanged(bool)),
|
|
SLOT(updateButtonStatus(bool)) );
|
|
q->connect( mItemManager,
|
|
SIGNAL(itemSaveFinished(IncidenceEditorNG::EditorItemManager::SaveAction)),
|
|
SLOT(handleItemSaveFinish(IncidenceEditorNG::EditorItemManager::SaveAction)));
|
|
q->connect( mItemManager,
|
|
SIGNAL(itemSaveFailed(IncidenceEditorNG::EditorItemManager::SaveAction,QString)),
|
|
SLOT(handleItemSaveFail(IncidenceEditorNG::EditorItemManager::SaveAction,QString)));
|
|
q->connect( ieAlarm, SIGNAL(alarmCountChanged(int)),
|
|
SLOT(handleAlarmCountChange(int)) );
|
|
q->connect( mIeRecurrence, SIGNAL(recurrenceChanged(IncidenceEditorNG::RecurrenceType)),
|
|
SLOT(handleRecurrenceChange(IncidenceEditorNG::RecurrenceType)) );
|
|
q->connect( ieAttachments, SIGNAL(attachmentCountChanged(int)),
|
|
SLOT(updateAttachmentCount(int)) );
|
|
q->connect( mIeAttendee, SIGNAL(attendeeCountChanged(int)),
|
|
SLOT(updateAttendeeCount(int)) );
|
|
}
|
|
|
|
IncidenceDialogPrivate::~IncidenceDialogPrivate()
|
|
{
|
|
delete mItemManager;
|
|
delete mEditor;
|
|
delete mUi;
|
|
}
|
|
|
|
void IncidenceDialogPrivate::slotInvalidCollection()
|
|
{
|
|
showMessage(i18n("Select a valid collection first."), KMessageWidget::Warning);
|
|
}
|
|
|
|
void IncidenceDialogPrivate::showMessage( const QString &text, KMessageWidget::MessageType type )
|
|
{
|
|
mUi->mMessageWidget->setText(text);
|
|
mUi->mMessageWidget->setMessageType(type);
|
|
mUi->mMessageWidget->show();
|
|
}
|
|
|
|
void IncidenceDialogPrivate::handleAlarmCountChange( int newCount )
|
|
{
|
|
QString tabText;
|
|
if ( newCount > 0 ) {
|
|
tabText =
|
|
i18nc( "@title:tab Tab to configure the reminders of an event or todo",
|
|
"Reminder (%1)", newCount );
|
|
} else {
|
|
tabText =
|
|
i18nc( "@title:tab Tab to configure the reminders of an event or todo",
|
|
"Reminder" );
|
|
}
|
|
|
|
mUi->mTabWidget->setTabText( AlarmsTab, tabText );
|
|
}
|
|
|
|
void IncidenceDialogPrivate::handleRecurrenceChange( IncidenceEditorNG::RecurrenceType type )
|
|
{
|
|
QString tabText =
|
|
i18nc( "@title:tab Tab to configure the recurrence of an event or todo",
|
|
"Rec&urrence" );
|
|
|
|
// Keep this numbers in sync with the items in mUi->mRecurrenceTypeCombo. I
|
|
// tried adding an enum to IncidenceRecurrence but for whatever reason I could
|
|
// Qt not play nice with namespaced enums in signal/slot connections.
|
|
// Anyways, I don't expect these values to change.
|
|
switch ( type ) {
|
|
case RecurrenceTypeNone:
|
|
break;
|
|
case RecurrenceTypeDaily:
|
|
tabText += i18nc( "@title:tab Daily recurring event, capital first letter only", " (D)" );
|
|
break;
|
|
case RecurrenceTypeWeekly:
|
|
tabText += i18nc( "@title:tab Weekly recurring event, capital first letter only", " (W)" );
|
|
break;
|
|
case RecurrenceTypeMonthly:
|
|
tabText += i18nc( "@title:tab Monthly recurring event, capital first letter only", " (M)" );
|
|
break;
|
|
case RecurrenceTypeYearly:
|
|
tabText += i18nc( "@title:tab Yearly recurring event, capital first letter only", " (Y)" );
|
|
break;
|
|
case RecurrenceTypeException:
|
|
tabText += i18nc( "@title:tab Exception to a recurring event, capital first letter only", " (E)" );
|
|
break;
|
|
default:
|
|
Q_ASSERT_X( false, "handleRecurrenceChange", "Fix your program" );
|
|
}
|
|
|
|
mUi->mTabWidget->setTabText( RecurrenceTab, tabText );
|
|
}
|
|
|
|
QString IncidenceDialogPrivate::typeToString( const int type ) const
|
|
{
|
|
// Do not translate.
|
|
switch( type ) {
|
|
case KCalCore::Incidence::TypeEvent:
|
|
return "Event";
|
|
case KCalCore::Incidence::TypeTodo:
|
|
return "Todo";
|
|
case KCalCore::Incidence::TypeJournal:
|
|
return "Journal";
|
|
default:
|
|
return "Unknown";
|
|
}
|
|
}
|
|
|
|
void IncidenceDialogPrivate::loadTemplate( const QString &templateName )
|
|
{
|
|
Q_Q( IncidenceDialog );
|
|
|
|
KCalCore::MemoryCalendar::Ptr cal( new KCalCore::MemoryCalendar( KSystemTimeZones::local() ) );
|
|
|
|
const QString fileName = KStandardDirs::locateLocal(
|
|
"data",
|
|
"korganizer/templates/" +
|
|
typeToString( mEditor->type() ) + '/' +
|
|
templateName );
|
|
|
|
if ( fileName.isEmpty() ) {
|
|
KMessageBox::error(
|
|
q,
|
|
i18nc( "@info", "Unable to find template '%1'.", fileName ) );
|
|
return;
|
|
}
|
|
|
|
KCalCore::ICalFormat format;
|
|
if ( !format.load( cal, fileName ) ) {
|
|
KMessageBox::error(
|
|
q,
|
|
i18nc( "@info", "Error loading template file '%1'.", fileName ) );
|
|
return;
|
|
}
|
|
|
|
KCalCore::Incidence::List incidences = cal->incidences();
|
|
if ( incidences.isEmpty() ) {
|
|
KMessageBox::error(
|
|
q,
|
|
i18nc( "@info", "Template does not contain a valid incidence." ) );
|
|
return;
|
|
}
|
|
|
|
mIeDateTime->setActiveDate( QDate() );
|
|
KCalCore::Incidence::Ptr newInc = KCalCore::Incidence::Ptr( incidences.first()->clone() );
|
|
newInc->setUid( KCalCore::CalFormat::createUniqueId() );
|
|
|
|
// We add a custom property so that some fields aren't loaded, dates for example
|
|
newInc->setCustomProperty( QByteArray("kdepim"), "isTemplate", "true");
|
|
mEditor->load( newInc );
|
|
newInc->removeCustomProperty( QByteArray(), "isTemplate");
|
|
}
|
|
|
|
void IncidenceDialogPrivate::manageTemplates()
|
|
{
|
|
Q_Q( IncidenceDialog );
|
|
|
|
QStringList &templates =
|
|
IncidenceEditorNG::EditorConfig::instance()->templates( mEditor->type() );
|
|
|
|
QPointer<IncidenceEditorNG::TemplateManagementDialog> dialog(
|
|
new IncidenceEditorNG::TemplateManagementDialog(
|
|
q, templates, KCalUtils::Stringify::incidenceType( mEditor->type() ) ) );
|
|
|
|
q->connect( dialog, SIGNAL(loadTemplate(QString)),
|
|
SLOT(loadTemplate(QString)) );
|
|
q->connect( dialog, SIGNAL(templatesChanged(QStringList)),
|
|
SLOT(storeTemplatesInConfig(QStringList)) );
|
|
q->connect( dialog, SIGNAL(saveTemplate(QString)),
|
|
SLOT(saveTemplate(QString)) );
|
|
dialog->exec();
|
|
delete dialog;
|
|
}
|
|
|
|
void IncidenceDialogPrivate::saveTemplate( const QString &templateName )
|
|
{
|
|
Q_ASSERT( ! templateName.isEmpty() );
|
|
|
|
KCalCore::MemoryCalendar::Ptr cal( new KCalCore::MemoryCalendar( KSystemTimeZones::local() ) );
|
|
|
|
switch( mEditor->type() ) {
|
|
case KCalCore::Incidence::TypeEvent:
|
|
{
|
|
KCalCore::Event::Ptr event( new KCalCore::Event() );
|
|
mEditor->save( event );
|
|
cal->addEvent( KCalCore::Event::Ptr( event->clone() ) );
|
|
break;
|
|
}
|
|
case KCalCore::Incidence::TypeTodo:
|
|
{
|
|
KCalCore::Todo::Ptr todo( new KCalCore::Todo );
|
|
mEditor->save( todo );
|
|
cal->addTodo( KCalCore::Todo::Ptr( todo->clone() ) );
|
|
break;
|
|
}
|
|
case KCalCore::Incidence::TypeJournal:
|
|
{
|
|
KCalCore::Journal::Ptr journal( new KCalCore::Journal );
|
|
mEditor->save( journal );
|
|
cal->addJournal( KCalCore::Journal::Ptr( journal->clone() ) );
|
|
break;
|
|
}
|
|
default:
|
|
Q_ASSERT_X( false, "saveTemplate", "Fix your program" );
|
|
}
|
|
|
|
const QString fileName = KStandardDirs::locateLocal(
|
|
"data",
|
|
"korganizer/templates/" +
|
|
typeToString( mEditor->type() ) + '/' +
|
|
templateName );
|
|
|
|
KCalCore::ICalFormat format;
|
|
format.save( cal, fileName );
|
|
}
|
|
|
|
void IncidenceDialogPrivate::storeTemplatesInConfig( const QStringList &templateNames )
|
|
{
|
|
// I find this somewhat broken. templates() returns a reference, maybe it should
|
|
// be changed by adding a setTemplates method.
|
|
IncidenceEditorNG::EditorConfig::instance()->templates( mEditor->type() ) = templateNames;
|
|
IncidenceEditorNG::EditorConfig::instance()->config()->writeConfig();
|
|
}
|
|
|
|
void IncidenceDialogPrivate::updateAttachmentCount( int newCount )
|
|
{
|
|
if ( newCount > 0 ) {
|
|
mUi->mTabWidget->setTabText(
|
|
AttachmentsTab,
|
|
i18nc( "@title:tab Tab to modify attachments of an event or todo",
|
|
"Attac&hments (%1)", newCount ) );
|
|
} else {
|
|
mUi->mTabWidget->setTabText(
|
|
AttachmentsTab,
|
|
i18nc( "@title:tab Tab to modify attachments of an event or todo",
|
|
"Attac&hments" ) );
|
|
}
|
|
}
|
|
|
|
void IncidenceDialogPrivate::updateAttendeeCount( int newCount )
|
|
{
|
|
if ( newCount > 0 ) {
|
|
mUi->mTabWidget->setTabText(
|
|
AttendeesTab,
|
|
i18nc( "@title:tab Tab to modify attendees of an event or todo",
|
|
"&Attendees (%1)", newCount ) );
|
|
} else {
|
|
mUi->mTabWidget->setTabText(
|
|
AttendeesTab,
|
|
i18nc( "@title:tab Tab to modify attendees of an event or todo",
|
|
"&Attendees" ) );
|
|
}
|
|
}
|
|
|
|
void IncidenceDialogPrivate::updateButtonStatus( bool isDirty )
|
|
{
|
|
Q_Q( IncidenceDialog );
|
|
q->enableButton( KDialog::Apply, isDirty || mInitiallyDirty );
|
|
}
|
|
|
|
bool IncidenceDialogPrivate::containsPayloadIdentifiers(
|
|
const QSet<QByteArray> &partIdentifiers ) const
|
|
{
|
|
return partIdentifiers.contains( QByteArray( "PLD:RFC822" ) );
|
|
}
|
|
|
|
void IncidenceDialogPrivate::handleItemSaveFail( EditorItemManager::SaveAction,
|
|
const QString &errorMessage )
|
|
{
|
|
Q_Q( IncidenceDialog );
|
|
|
|
bool retry = false;
|
|
|
|
if ( !errorMessage.isEmpty() ) {
|
|
const QString message = i18nc( "@info",
|
|
"Unable to store the incidence in the calendar. Try again?\n\n "
|
|
"Reason: %1", errorMessage );
|
|
retry = ( KMessageBox::warningYesNo( q, message ) == KMessageBox::Yes );
|
|
}
|
|
|
|
if ( retry ) {
|
|
mItemManager->save();
|
|
} else {
|
|
updateButtonStatus( isDirty() );
|
|
q->enableButtonOk( true );
|
|
q->enableButtonCancel( true );
|
|
}
|
|
}
|
|
|
|
void IncidenceDialogPrivate::handleItemSaveFinish( EditorItemManager::SaveAction saveAction )
|
|
{
|
|
Q_Q( IncidenceDialog );
|
|
|
|
if ( mCloseOnSave ) {
|
|
q->accept();
|
|
} else {
|
|
const Akonadi::Item item = mItemManager->item();
|
|
Q_ASSERT( item.isValid() );
|
|
Q_ASSERT( item.hasPayload() );
|
|
Q_ASSERT( item.hasPayload<KCalCore::Incidence::Ptr>() );
|
|
// Now the item is succesfull saved, reload it in the editor in order to
|
|
// reset the dirty status of the editor.
|
|
mEditor->load( item.payload<KCalCore::Incidence::Ptr>() );
|
|
|
|
// Set the buttons to a reasonable state as well (ok and apply should be
|
|
// disabled at this point).
|
|
q->enableButtonOk( true );
|
|
q->enableButtonCancel( true );
|
|
q->enableButtonApply( isDirty() );
|
|
}
|
|
|
|
if ( saveAction == EditorItemManager::Create ) {
|
|
emit q->incidenceCreated( mItemManager->item() );
|
|
}
|
|
}
|
|
|
|
bool IncidenceDialogPrivate::hasSupportedPayload( const Akonadi::Item &item ) const
|
|
{
|
|
return CalendarSupport::incidence( item );
|
|
}
|
|
|
|
bool IncidenceDialogPrivate::isDirty() const
|
|
{
|
|
if ( mItem.isValid() ) {
|
|
return mEditor->isDirty() ||
|
|
mCalSelector->currentCollection().id() != mItem.storageCollectionId();
|
|
} else {
|
|
return mEditor->isDirty();
|
|
}
|
|
}
|
|
|
|
bool IncidenceDialogPrivate::isValid() const
|
|
{
|
|
Q_Q( const IncidenceDialog );
|
|
if ( mEditor->isValid() ) {
|
|
// Check if there's a selected collection.
|
|
if ( mCalSelector->currentCollection().isValid() ) {
|
|
return true;
|
|
} else {
|
|
emit q->invalidCollection();
|
|
kWarning() << "Select a collection first";
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
void IncidenceDialogPrivate::load( const Akonadi::Item &item )
|
|
{
|
|
Q_Q( IncidenceDialog );
|
|
|
|
Q_ASSERT( hasSupportedPayload( item ) );
|
|
|
|
if ( CalendarSupport::hasJournal( item ) ) {
|
|
//mUi->mTabWidget->removeTab( 5 );
|
|
mUi->mTabWidget->removeTab( AttachmentsTab );
|
|
mUi->mTabWidget->removeTab( RecurrenceTab );
|
|
mUi->mTabWidget->removeTab( AlarmsTab );
|
|
mUi->mTabWidget->removeTab( AttendeesTab );
|
|
}
|
|
|
|
mEditor->load( CalendarSupport::incidence( item ) );
|
|
|
|
const KCalCore::Incidence::Ptr incidence = CalendarSupport::incidence( item );
|
|
const QStringList allEmails = IncidenceEditorNG::EditorConfig::instance()->allEmails();
|
|
KCalCore::Attendee::Ptr me = incidence->attendeeByMails( allEmails );
|
|
|
|
if ( incidence->attendeeCount() > 1 && // >1 because you won't drink alone
|
|
me && ( me->status() == KCalCore::Attendee::NeedsAction ||
|
|
me->status() == KCalCore::Attendee::Tentative ||
|
|
me->status() == KCalCore::Attendee::InProcess ) ) {
|
|
// Show the invitation bar: "You are invited [accept] [decline]"
|
|
mUi->mInvitationBar->show();
|
|
} else {
|
|
mUi->mInvitationBar->hide();
|
|
}
|
|
|
|
kDebug() << "Loading item " << item.id() << "; parent " << item.parentCollection().id()
|
|
<< "; storage " << item.storageCollectionId();
|
|
|
|
if ( item.parentCollection().isValid() ) {
|
|
mCalSelector->setDefaultCollection( item.parentCollection() );
|
|
}
|
|
|
|
if ( !mCalSelector->mimeTypeFilter().contains( "text/calendar" ) ||
|
|
!mCalSelector->mimeTypeFilter().contains( incidence->mimeType() ) )
|
|
{
|
|
mCalSelector->setMimeTypeFilter( QStringList() << incidence->mimeType() << "text/calendar" );
|
|
}
|
|
|
|
if ( mEditor->type() == KCalCore::Incidence::TypeTodo ) {
|
|
q->setWindowIcon( SmallIcon( "view-calendar-tasks" ) );
|
|
} else if ( mEditor->type() == KCalCore::Incidence::TypeEvent ) {
|
|
q->setWindowIcon( SmallIcon( "view-calendar-day" ) );
|
|
} else if ( mEditor->type() == KCalCore::Incidence::TypeJournal ) {
|
|
q->setWindowIcon( SmallIcon( "view-pim-journal" ) );
|
|
}
|
|
|
|
// Initialize tab's titles
|
|
updateAttachmentCount( incidence->attachments().size() );
|
|
handleRecurrenceChange( mIeRecurrence->currentRecurrenceType() );
|
|
handleAlarmCountChange( incidence->alarms().count() );
|
|
|
|
mItem = item;
|
|
|
|
q->show();
|
|
}
|
|
|
|
Akonadi::Item IncidenceDialogPrivate::save( const Akonadi::Item &item )
|
|
{
|
|
Q_ASSERT( mEditor->incidence<KCalCore::Incidence>() );
|
|
|
|
KCalCore::Incidence::Ptr incidenceInEditor = mEditor->incidence<KCalCore::Incidence>();
|
|
KCalCore::Incidence::Ptr newIncidence( incidenceInEditor->clone() );
|
|
|
|
Akonadi::Item result = item;
|
|
result.setMimeType( newIncidence->mimeType() );
|
|
|
|
// There's no editor that has the relatedTo property. We must set it here, by hand.
|
|
// Otherwise it gets lost.
|
|
// FIXME: Why don't we clone() incidenceInEditor then pass the clone to save(),
|
|
// I wonder if we're not leaking other properties.
|
|
newIncidence->setRelatedTo( incidenceInEditor->relatedTo() );
|
|
|
|
mEditor->save( newIncidence );
|
|
|
|
// TODO: Remove this once we support moving of events/todo's
|
|
mCalSelector->setEnabled( false );
|
|
|
|
// Make sure that we don't loose uid for existing incidence
|
|
newIncidence->setUid( mEditor->incidence<KCalCore::Incidence>()->uid() );
|
|
|
|
// Mark the incidence as changed
|
|
if ( mItem.isValid() ) {
|
|
newIncidence->setRevision( newIncidence->revision() + 1 );
|
|
}
|
|
|
|
result.setPayload<KCalCore::Incidence::Ptr>( newIncidence );
|
|
return result;
|
|
}
|
|
|
|
Akonadi::Collection IncidenceDialogPrivate::selectedCollection() const
|
|
{
|
|
return mCalSelector->currentCollection();
|
|
}
|
|
|
|
void IncidenceDialogPrivate::reject( RejectReason reason, const QString &errorMessage )
|
|
{
|
|
Q_UNUSED( reason );
|
|
|
|
Q_Q( IncidenceDialog );
|
|
kError() << "Rejecting:" << errorMessage;
|
|
q->deleteLater();
|
|
}
|
|
|
|
/// IncidenceDialog
|
|
|
|
IncidenceDialog::IncidenceDialog( Akonadi::IncidenceChanger *changer,
|
|
QWidget *parent, Qt::WFlags flags )
|
|
: KDialog( parent, flags ),
|
|
d_ptr( new IncidenceDialogPrivate( changer, this ) )
|
|
{
|
|
Q_D( IncidenceDialog );
|
|
setAttribute( Qt::WA_DeleteOnClose );
|
|
|
|
d->mUi->mTabWidget->setCurrentIndex( 0 );
|
|
d->mUi->mSummaryEdit->setFocus();
|
|
|
|
setButtons( KDialog::Ok | KDialog::Apply | KDialog::Cancel | KDialog::Default );
|
|
setButtonToolTip( KDialog::Apply,
|
|
i18nc( "@info:tooltip", "Save current changes" ) );
|
|
setButtonToolTip( KDialog::Ok,
|
|
i18nc( "@action:button", "Save changes and close dialog" ) );
|
|
setButtonToolTip( KDialog::Cancel,
|
|
i18nc( "@action:button", "Discard changes and close dialog" ) );
|
|
setDefaultButton( KDialog::Ok );
|
|
enableButton( Apply, false );
|
|
|
|
setButtonText( Default, i18nc( "@action:button", "&Templates..." ) );
|
|
setButtonIcon( Default, KIcon( "project-development-new-template" ) );
|
|
setButtonToolTip( Default,
|
|
i18nc( "@info:tooltip",
|
|
"Manage templates for this item" ) );
|
|
setButtonWhatsThis( Default,
|
|
i18nc( "@info:whatsthis",
|
|
"Push this button to show a dialog that helps "
|
|
"you manage a set of templates. Templates "
|
|
"can make creating new items easier and faster "
|
|
"by putting your favorite default values into "
|
|
"the editor automatically." ) );
|
|
|
|
setModal( false );
|
|
showButtonSeparator( false );
|
|
|
|
connect( d->mUi->mAcceptInvitationButton, SIGNAL(clicked()),
|
|
d->mIeAttendee, SLOT(acceptForMe()) );
|
|
connect( d->mUi->mAcceptInvitationButton, SIGNAL(clicked()),
|
|
d->mUi->mInvitationBar, SLOT(hide()) );
|
|
connect( d->mUi->mDeclineInvitationButton, SIGNAL(clicked()),
|
|
d->mIeAttendee, SLOT(declineForMe()) );
|
|
connect( d->mUi->mDeclineInvitationButton, SIGNAL(clicked()),
|
|
d->mUi->mInvitationBar, SLOT(hide()) );
|
|
connect( this, SIGNAL(invalidCollection()),
|
|
this, SLOT(slotInvalidCollection()));
|
|
readConfig();
|
|
}
|
|
|
|
IncidenceDialog::~IncidenceDialog()
|
|
{
|
|
writeConfig();
|
|
delete d_ptr;
|
|
}
|
|
|
|
void IncidenceDialog::writeConfig()
|
|
{
|
|
KConfigGroup group( KGlobal::config(), "IncidenceDialog" );
|
|
group.writeEntry( "Size", size() );
|
|
|
|
const Akonadi::Collection col = d_ptr->mCalSelector->currentCollection();
|
|
// col might not be valid if the collection wasn't found yet (the combo is async), skip saving in that case
|
|
if (col.isValid() && col.id() != IncidenceEditorNG::GlobalSettings::self()->lastSelectedFolder()) {
|
|
IncidenceEditorNG::GlobalSettings::self()->setLastSelectedFolder(col.id());
|
|
IncidenceEditorNG::GlobalSettings::self()->writeConfig();
|
|
}
|
|
}
|
|
|
|
void IncidenceDialog::readConfig()
|
|
{
|
|
KConfigGroup group( KGlobal::config(), "IncidenceDialog" );
|
|
const QSize size = group.readEntry( "Size", QSize() );
|
|
if ( size.isValid() ) {
|
|
resize( size );
|
|
} else {
|
|
resize( QSize( 500, 500 ).expandedTo( minimumSizeHint() ) );
|
|
}
|
|
}
|
|
|
|
|
|
void IncidenceDialog::load( const Akonadi::Item &item, const QDate &activeDate )
|
|
{
|
|
Q_D( IncidenceDialog );
|
|
d->mIeDateTime->setActiveDate( activeDate );
|
|
if ( item.isValid() ) { // We're editing
|
|
d->mItemManager->load( item );
|
|
// TODO: Remove this once we support moving of events/todo's
|
|
d->mCalSelector->setEnabled( false );
|
|
} else { // We're creating
|
|
Q_ASSERT( d->hasSupportedPayload( item ) );
|
|
d->load( item );
|
|
show();
|
|
}
|
|
}
|
|
|
|
void IncidenceDialog::selectCollection( const Akonadi::Collection &collection )
|
|
{
|
|
Q_D( IncidenceDialog );
|
|
if ( collection.isValid() ) {
|
|
d->mCalSelector->setDefaultCollection( collection );
|
|
} else {
|
|
d->mCalSelector->setCurrentIndex( 0 );
|
|
}
|
|
}
|
|
|
|
void IncidenceDialog::setIsCounterProposal( bool isCounterProposal )
|
|
{
|
|
Q_D( IncidenceDialog );
|
|
d->mItemManager->setIsCounterProposal( isCounterProposal );
|
|
}
|
|
|
|
QObject *IncidenceDialog::typeAheadReceiver() const
|
|
{
|
|
Q_D( const IncidenceDialog );
|
|
return d->mUi->mSummaryEdit;
|
|
}
|
|
|
|
void IncidenceDialog::slotButtonClicked( int button )
|
|
{
|
|
Q_D( IncidenceDialog );
|
|
|
|
switch( button ) {
|
|
case KDialog::Ok:
|
|
{
|
|
if ( d->isDirty() || d->mInitiallyDirty ) {
|
|
enableButtonOk( false );
|
|
enableButtonCancel( false );
|
|
enableButtonApply( false );
|
|
d->mCloseOnSave = true;
|
|
d->mInitiallyDirty = false;
|
|
d->mItemManager->save();
|
|
} else {
|
|
close();
|
|
}
|
|
break;
|
|
}
|
|
case KDialog::Apply:
|
|
{
|
|
enableButtonOk( false );
|
|
enableButtonCancel( false );
|
|
enableButtonApply( false );
|
|
|
|
d->mCloseOnSave = false;
|
|
d->mInitiallyDirty = false;
|
|
d->mItemManager->save();
|
|
break;
|
|
}
|
|
case KDialog::Cancel:
|
|
if ( d->isDirty() &&
|
|
KMessageBox::questionYesNo(
|
|
this,
|
|
i18nc( "@info", "Do you really want to cancel?" ),
|
|
i18nc( "@title:window", "KOrganizer Confirmation" ) ) == KMessageBox::Yes ) {
|
|
KDialog::reject(); // Discard current changes
|
|
} else if ( !d->isDirty() ) {
|
|
KDialog::reject(); // No pending changes, just close the dialog.
|
|
} // else { // the user wasn't finished editting after all }
|
|
break;
|
|
case KDialog::Default:
|
|
d->manageTemplates();
|
|
break;
|
|
default:
|
|
Q_ASSERT( false ); // Shouldn't happen
|
|
break;
|
|
}
|
|
}
|
|
|
|
void IncidenceDialog::closeEvent( QCloseEvent *event )
|
|
{
|
|
Q_D( IncidenceDialog );
|
|
if ( d->isDirty() &&
|
|
KMessageBox::questionYesNo(
|
|
this,
|
|
i18nc( "@info", "Do you really want to cancel?" ),
|
|
i18nc( "@title:window", "KOrganizer Confirmation" ) ) == KMessageBox::Yes ) {
|
|
KDialog::reject(); // Discard current changes
|
|
KDialog::closeEvent( event );
|
|
} else if ( !d->isDirty() ) {
|
|
KDialog::reject(); // No pending changes, just close the dialog.
|
|
KDialog::closeEvent( event );
|
|
} else {
|
|
event->ignore();
|
|
}
|
|
}
|
|
|
|
void IncidenceDialog::setInitiallyDirty( bool initiallyDirty )
|
|
{
|
|
Q_D( IncidenceDialog );
|
|
d->mInitiallyDirty = initiallyDirty;
|
|
}
|
|
|
|
Akonadi::Item IncidenceDialog::item() const
|
|
{
|
|
Q_D( const IncidenceDialog );
|
|
return d->mItemManager->item();
|
|
}
|
|
|
|
void IncidenceDialog::handleSelectedCollectionChange( const Akonadi::Collection &collection )
|
|
{
|
|
Q_D( IncidenceDialog );
|
|
if ( d->mItem.parentCollection().isValid() ) {
|
|
enableButton( Apply, collection.id() != d->mItem.parentCollection().id() );
|
|
}
|
|
}
|
|
|
|
#include "moc_incidencedialog.cpp"
|