diff options
Diffstat (limited to 'korganizer/actionmanager.cpp')
-rw-r--r-- | korganizer/actionmanager.cpp | 1956 |
1 files changed, 1956 insertions, 0 deletions
diff --git a/korganizer/actionmanager.cpp b/korganizer/actionmanager.cpp new file mode 100644 index 000000000..4a900abd3 --- /dev/null +++ b/korganizer/actionmanager.cpp @@ -0,0 +1,1956 @@ +/* + This file is part of KOrganizer. + + Copyright (c) 2002 Mike Pilone <mpilone@slac.com> + Copyright (c) 2002 Don Sanders <sanders@kde.org> + Copyright (c) 2004 Cornelius Schumacher <schumacher@kde.org> + Copyright (C) 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 "actionmanager.h" + +#include "alarmclient.h" +#include "calendarview.h" +#include "kocore.h" +#include "kodialogmanager.h" +#include "koglobals.h" +#include "koprefs.h" +#include "koviewmanager.h" +#include "kowindowlist.h" +#include "kprocess.h" +#include "konewstuff.h" +#include "history.h" +#include "kogroupware.h" +#include "resourceview.h" +#include "importdialog.h" +#include "eventarchiver.h" +#include "stdcalendar.h" +#include "freebusymanager.h" + +#include <libkcal/calendarlocal.h> +#include <libkcal/calendarresources.h> +#include <libkcal/htmlexport.h> +#include <libkcal/htmlexportsettings.h> + +#include <libkmime/kmime_message.h> + +#include <dcopclient.h> +#include <kaction.h> +#include <kfiledialog.h> +#include <kiconloader.h> +#include <kio/netaccess.h> +#include <kkeydialog.h> +#include <kpopupmenu.h> +#include <kstandarddirs.h> +#include <ktip.h> +#include <ktempfile.h> +#include <kxmlguiclient.h> +#include <kwin.h> +#include <knotifyclient.h> +#include <kstdguiitem.h> +#include <kdeversion.h> +#include <kactionclasses.h> + +#include <qapplication.h> +#include <qcursor.h> +#include <qtimer.h> +#include <qlabel.h> + + +// FIXME: Several places in the file don't use KConfigXT yet! +KOWindowList *ActionManager::mWindowList = 0; + +ActionManager::ActionManager( KXMLGUIClient *client, CalendarView *widget, + QObject *parent, KOrg::MainWindow *mainWindow, + bool isPart ) + : QObject( parent ), KCalendarIface(), mRecent( 0 ), + mResourceButtonsAction( 0 ), mResourceViewShowAction( 0 ), mCalendar( 0 ), + mCalendarResources( 0 ), mResourceView( 0 ), mIsClosing( false ) +{ + mGUIClient = client; + mACollection = mGUIClient->actionCollection(); + mCalendarView = widget; + mIsPart = isPart; + mTempFile = 0; + mNewStuff = 0; + mHtmlExportSync = false; + mMainWindow = mainWindow; +} + +ActionManager::~ActionManager() +{ + delete mNewStuff; + + // Remove Part plugins + KOCore::self()->unloadParts( mMainWindow, mParts ); + + delete mTempFile; + + // Take this window out of the window list. + mWindowList->removeWindow( mMainWindow ); + + delete mCalendarView; + + delete mCalendar; + + kdDebug(5850) << "~ActionManager() done" << endl; +} + +// see the Note: below for why this method is necessary +void ActionManager::init() +{ + // Construct the groupware object + KOGroupware::create( mCalendarView, mCalendarResources ); + + // add this instance of the window to the static list. + if ( !mWindowList ) { + mWindowList = new KOWindowList; + // Show tip of the day, when the first calendar is shown. + if ( !mIsPart ) + QTimer::singleShot( 0, this, SLOT( showTipOnStart() ) ); + } + // Note: We need this ActionManager to be fully constructed, and + // parent() to have a valid reference to it before the following + // addWindow is called. + mWindowList->addWindow( mMainWindow ); + + initActions(); + + // set up autoSaving stuff + mAutoSaveTimer = new QTimer( this ); + connect( mAutoSaveTimer,SIGNAL( timeout() ), SLOT( checkAutoSave() ) ); + if ( KOPrefs::instance()->mAutoSave && + KOPrefs::instance()->mAutoSaveInterval > 0 ) { + mAutoSaveTimer->start( 1000 * 60 * KOPrefs::instance()->mAutoSaveInterval ); + } + + mAutoArchiveTimer = new QTimer( this ); + connect( mAutoArchiveTimer, SIGNAL( timeout() ), SLOT( slotAutoArchive() ) ); + // First auto-archive should be in 5 minutes (like in kmail). + if ( KOPrefs::instance()->mAutoArchive ) + mAutoArchiveTimer->start( 5 * 60 * 1000, true ); // singleshot + + setTitle(); + + connect( mCalendarView, SIGNAL( modifiedChanged( bool ) ), SLOT( setTitle() ) ); + connect( mCalendarView, SIGNAL( configChanged() ), SLOT( updateConfig() ) ); + + connect( mCalendarView, SIGNAL( incidenceSelected( Incidence * ) ), + this, SLOT( processIncidenceSelection( Incidence * ) ) ); + connect( mCalendarView, SIGNAL( exportHTML( HTMLExportSettings * ) ), + this, SLOT( exportHTML( HTMLExportSettings * ) ) ); + + processIncidenceSelection( 0 ); + + // Update state of paste action + mCalendarView->checkClipboard(); +} + +void ActionManager::createCalendarLocal() +{ + mCalendar = new CalendarLocal( KOPrefs::instance()->mTimeZoneId ); + mCalendarView->setCalendar( mCalendar ); + mCalendarView->readSettings(); + + initCalendar( mCalendar ); +} + +void ActionManager::createCalendarResources() +{ + mCalendarResources = KOrg::StdCalendar::self(); + + CalendarResourceManager *manager = mCalendarResources->resourceManager(); + + kdDebug(5850) << "CalendarResources used by KOrganizer:" << endl; + CalendarResourceManager::Iterator it; + for( it = manager->begin(); it != manager->end(); ++it ) { + kdDebug(5850) << " " << (*it)->resourceName() << endl; + (*it)->setResolveConflict( true ); +// (*it)->dump(); + } + + setDestinationPolicy(); + + mCalendarView->setCalendar( mCalendarResources ); + mCalendarView->readSettings(); + + ResourceViewFactory factory( mCalendarResources, mCalendarView ); + mCalendarView->addExtension( &factory ); + mResourceView = factory.resourceView(); + + connect( mCalendarResources, SIGNAL( calendarChanged() ), + mCalendarView, SLOT( slotCalendarChanged() ) ); + connect( mCalendarResources, SIGNAL( signalErrorMessage( const QString & ) ), + mCalendarView, SLOT( showErrorMessage( const QString & ) ) ); + + connect( mCalendarView, SIGNAL( configChanged() ), + SLOT( updateConfig() ) ); + + initCalendar( mCalendarResources ); +} + +void ActionManager::initCalendar( Calendar *cal ) +{ + cal->setOwner( Person( KOPrefs::instance()->fullName(), + KOPrefs::instance()->email() ) ); + // setting fullName and email do not really count as modifying the calendar + mCalendarView->setModified( false ); +} + +void ActionManager::initActions() +{ + KAction *action; + + + //*************************** FILE MENU ********************************** + + //~~~~~~~~~~~~~~~~~~~~~~~ LOADING / SAVING ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + if ( mIsPart ) { + if ( mMainWindow->hasDocument() ) { + KStdAction::openNew( this, SLOT(file_new()), mACollection, "korganizer_openNew" ); + KStdAction::open( this, SLOT( file_open() ), mACollection, "korganizer_open" ); + mRecent = KStdAction::openRecent( this, SLOT( file_open( const KURL& ) ), + mACollection, "korganizer_openRecent" ); + KStdAction::revert( this,SLOT( file_revert() ), mACollection, "korganizer_revert" ); + KStdAction::saveAs( this, SLOT( file_saveas() ), mACollection, + "korganizer_saveAs" ); + KStdAction::save( this, SLOT( file_save() ), mACollection, "korganizer_save" ); + } + KStdAction::print( mCalendarView, SLOT( print() ), mACollection, "korganizer_print" ); + } else { + KStdAction::openNew( this, SLOT( file_new() ), mACollection ); + KStdAction::open( this, SLOT( file_open() ), mACollection ); + mRecent = KStdAction::openRecent( this, SLOT( file_open( const KURL& ) ), + mACollection ); + if ( mMainWindow->hasDocument() ) { + KStdAction::revert( this,SLOT( file_revert() ), mACollection ); + KStdAction::save( this, SLOT( file_save() ), mACollection ); + KStdAction::saveAs( this, SLOT( file_saveas() ), mACollection ); + } + KStdAction::print( mCalendarView, SLOT( print() ), mACollection ); + } + + + //~~~~~~~~~~~~~~~~~~~~~~~~ IMPORT / EXPORT ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + new KAction( i18n("Import &Calendar..."), 0, this, SLOT( file_merge() ), + mACollection, "import_icalendar" ); + new KAction( i18n("&Import From UNIX Ical tool"), 0, this, SLOT( file_icalimport() ), + mACollection, "import_ical" ); + new KAction( i18n("Get &Hot New Stuff..."), 0, this, + SLOT( downloadNewStuff() ), mACollection, + "downloadnewstuff" ); + + new KAction( i18n("Export &Web Page..."), "webexport", 0, + mCalendarView, SLOT( exportWeb() ), + mACollection, "export_web" ); + new KAction( i18n("&iCalendar..."), 0, + mCalendarView, SLOT( exportICalendar() ), + mACollection, "export_icalendar" ); + new KAction( i18n("&vCalendar..."), 0, + mCalendarView, SLOT( exportVCalendar() ), + mACollection, "export_vcalendar" ); + new KAction( i18n("Upload &Hot New Stuff..."), 0, this, + SLOT( uploadNewStuff() ), mACollection, + "uploadnewstuff" ); + + + + new KAction( i18n("Archive O&ld Entries..."), 0, this, SLOT( file_archive() ), + mACollection, "file_archive" ); + new KAction( i18n("delete completed to-dos", "Pur&ge Completed To-dos"), 0, + mCalendarView, SLOT( purgeCompleted() ), mACollection, + "purge_completed" ); + + + + + //************************** EDIT MENU ********************************* + KAction *pasteAction; + KOrg::History *h = mCalendarView->history(); + if ( mIsPart ) { + // edit menu + mCutAction = KStdAction::cut( mCalendarView, SLOT( edit_cut() ), + mACollection, "korganizer_cut" ); + mCopyAction = KStdAction::copy( mCalendarView, SLOT( edit_copy() ), + mACollection, "korganizer_copy" ); + pasteAction = KStdAction::paste( mCalendarView, SLOT( edit_paste() ), + mACollection, "korganizer_paste" ); + mUndoAction = KStdAction::undo( h, SLOT( undo() ), + mACollection, "korganizer_undo" ); + mRedoAction = KStdAction::redo( h, SLOT( redo() ), + mACollection, "korganizer_redo" ); + } else { + mCutAction = KStdAction::cut( mCalendarView,SLOT( edit_cut() ), + mACollection ); + mCopyAction = KStdAction::copy( mCalendarView,SLOT( edit_copy() ), + mACollection ); + pasteAction = KStdAction::paste( mCalendarView,SLOT( edit_paste() ), + mACollection ); + mUndoAction = KStdAction::undo( h, SLOT( undo() ), mACollection ); + mRedoAction = KStdAction::redo( h, SLOT( redo() ), mACollection ); + } + mDeleteAction = new KAction( i18n("&Delete"), "editdelete", 0, + mCalendarView, SLOT( appointment_delete() ), + mACollection, "edit_delete" ); + if ( mIsPart ) { + KStdAction::find( mCalendarView->dialogManager(), SLOT( showSearchDialog() ), + mACollection, "korganizer_find" ); + } else { + KStdAction::find( mCalendarView->dialogManager(), SLOT( showSearchDialog() ), + mACollection ); + } + pasteAction->setEnabled( false ); + mUndoAction->setEnabled( false ); + mRedoAction->setEnabled( false ); + connect( mCalendarView, SIGNAL( pasteEnabled( bool ) ), + pasteAction, SLOT( setEnabled( bool ) ) ); + connect( h, SIGNAL( undoAvailable( const QString & ) ), + SLOT( updateUndoAction( const QString & ) ) ); + connect( h, SIGNAL( redoAvailable( const QString & ) ), + SLOT( updateRedoAction( const QString & ) ) ); + + + + + //************************** VIEW MENU ********************************* + + //~~~~~~~~~~~~~~~~~~~~~~~~~~~~ VIEWS ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + new KAction( i18n("What's &Next"), + KOGlobals::self()->smallIcon( "whatsnext" ), 0, + mCalendarView->viewManager(), SLOT( showWhatsNextView() ), + mACollection, "view_whatsnext" ); + new KAction( i18n("&Day"), + KOGlobals::self()->smallIcon( "1day" ), 0, + mCalendarView->viewManager(), SLOT( showDayView() ), + mACollection, "view_day" ); + mNextXDays = new KAction( "", + KOGlobals::self()->smallIcon( "xdays" ), 0, + mCalendarView->viewManager(), + SLOT( showNextXView() ), + mACollection, "view_nextx" ); + mNextXDays->setText( i18n( "&Next Day", "Ne&xt %n Days", + KOPrefs::instance()->mNextXDays ) ); + new KAction( i18n("W&ork Week"), + KOGlobals::self()->smallIcon( "5days" ), 0, + mCalendarView->viewManager(), SLOT( showWorkWeekView() ), + mACollection, "view_workweek" ); + new KAction( i18n("&Week"), + KOGlobals::self()->smallIcon( "7days" ), 0, + mCalendarView->viewManager(), SLOT( showWeekView() ), + mACollection, "view_week" ); + new KAction( i18n("&Month"), + KOGlobals::self()->smallIcon( "month" ), 0, + mCalendarView->viewManager(), SLOT( showMonthView() ), + mACollection, "view_month" ); + new KAction( i18n("&List"), + KOGlobals::self()->smallIcon( "list" ), 0, + mCalendarView->viewManager(), SLOT( showListView() ), + mACollection, "view_list" ); + new KAction( i18n("&To-do List"), + KOGlobals::self()->smallIcon( "todo" ), 0, + mCalendarView->viewManager(), SLOT( showTodoView() ), + mACollection, "view_todo" ); + new KAction( i18n("&Journal"), + KOGlobals::self()->smallIcon( "journal" ), 0, + mCalendarView->viewManager(), SLOT( showJournalView() ), + mACollection, "view_journal" ); + new KAction( i18n("&Timeline View"), + KOGlobals::self()->smallIcon( "timeline" ), 0, + mCalendarView->viewManager(), SLOT( showTimelineView() ), + mACollection, "view_timeline" ); + + //~~~~~~~~~~~~~~~~~~~~~~~~~~~ FILTERS ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + new KAction( i18n("&Refresh"), 0, + mCalendarView, SLOT( updateView() ), + mACollection, "update" ); +// TODO: +// new KAction( i18n("Hide &Completed To-dos"), 0, +// mCalendarView, SLOT( toggleHideCompleted() ), +// mACollection, "hide_completed_todos" ); + + mFilterAction = new KSelectAction( i18n("F&ilter"), 0, + mACollection, "filter_select" ); + mFilterAction->setEditable( false ); + connect( mFilterAction, SIGNAL( activated(int) ), + mCalendarView, SLOT( filterActivated( int ) ) ); + connect( mCalendarView, SIGNAL( newFilterListSignal( const QStringList & ) ), + mFilterAction, SLOT( setItems( const QStringList & ) ) ); + connect( mCalendarView, SIGNAL( selectFilterSignal( int ) ), + mFilterAction, SLOT( setCurrentItem( int ) ) ); + connect( mCalendarView, SIGNAL( filterChanged() ), + this, SLOT( setTitle() ) ); + + + //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ZOOM ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + // TODO: try to find / create better icons for the following 4 actions + new KAction( i18n( "Zoom In Horizontally" ), "viewmag+", 0, + mCalendarView->viewManager(), SLOT( zoomInHorizontally() ), + mACollection, "zoom_in_horizontally" ); + new KAction( i18n( "Zoom Out Horizontally" ), "viewmag-", 0, + mCalendarView->viewManager(), SLOT( zoomOutHorizontally() ), + mACollection, "zoom_out_horizontally" ); + new KAction( i18n( "Zoom In Vertically" ), "viewmag+", 0, + mCalendarView->viewManager(), SLOT( zoomInVertically() ), + mACollection, "zoom_in_vertically" ); + new KAction( i18n( "Zoom Out Vertically" ), "viewmag-", 0, + mCalendarView->viewManager(), SLOT( zoomOutVertically() ), + mACollection, "zoom_out_vertically" ); + + + + + //************************** Actions MENU ********************************* + + new KAction( i18n("Go to &Today"), "today", 0, + mCalendarView,SLOT( goToday() ), + mACollection, "go_today" ); + bool isRTL = QApplication::reverseLayout(); + action = new KAction( i18n("Go &Backward"), isRTL ? "forward" : "back", 0, + mCalendarView,SLOT( goPrevious() ), + mACollection, "go_previous" ); + + // Changing the action text by setText makes the toolbar button disappear. + // This has to be fixed first, before the connects below can be reenabled. + /* + connect( mCalendarView, SIGNAL( changeNavStringPrev( const QString & ) ), + action, SLOT( setText( const QString & ) ) ); + connect( mCalendarView, SIGNAL( changeNavStringPrev( const QString & ) ), + this, SLOT( dumpText( const QString & ) ) );*/ + + action = new KAction( i18n("Go &Forward"), isRTL ? "back" : "forward", 0, + mCalendarView,SLOT( goNext() ), + mACollection, "go_next" ); + /* + connect( mCalendarView,SIGNAL( changeNavStringNext( const QString & ) ), + action,SLOT( setText( const QString & ) ) ); + */ + + + //************************** Actions MENU ********************************* + new KAction( i18n("New E&vent..."), + KOGlobals::self()->smallIcon( "newappointment" ), 0, + mCalendarView, SLOT( newEvent() ), + mACollection, "new_event" ); + new KAction( i18n("New &To-do..."), + KOGlobals::self()->smallIcon( "newtodo" ), 0, + mCalendarView, SLOT( newTodo() ), + mACollection, "new_todo" ); + action = new KAction( i18n("New Su&b-to-do..."), 0, + mCalendarView,SLOT( newSubTodo() ), + mACollection, "new_subtodo" ); + action->setEnabled( false ); + connect( mCalendarView,SIGNAL( todoSelected( bool ) ), + action,SLOT( setEnabled( bool ) ) ); + new KAction( i18n("New &Journal..."), + KOGlobals::self()->smallIcon( "newjournal" ), 0, + mCalendarView, SLOT( newJournal() ), + mACollection, "new_journal" ); + + mShowIncidenceAction = new KAction( i18n("&Show"), 0, + mCalendarView,SLOT( showIncidence() ), + mACollection, "show_incidence" ); + mEditIncidenceAction = new KAction( i18n("&Edit..."), 0, + mCalendarView,SLOT( editIncidence() ), + mACollection, "edit_incidence" ); + mDeleteIncidenceAction = new KAction( i18n("&Delete"), Key_Delete, + mCalendarView,SLOT( deleteIncidence()), + mACollection, "delete_incidence" ); + + action = new KAction( i18n("&Make Sub-to-do Independent"), 0, + mCalendarView,SLOT( todo_unsub() ), + mACollection, "unsub_todo" ); + action->setEnabled( false ); + connect( mCalendarView,SIGNAL( subtodoSelected( bool ) ), + action,SLOT( setEnabled( bool ) ) ); +// TODO: Add item to move the incidence to different resource +// mAssignResourceAction = new KAction( i18n("Assign &Resource..."), 0, +// mCalendarView, SLOT( assignResource()), +// mACollection, "assign_resource" ); +// TODO: Add item to quickly toggle the reminder of a given incidence +// mToggleAlarmAction = new KToggleAction( i18n("&Activate Reminder"), 0, +// mCalendarView, SLOT( toggleAlarm()), +// mACollection, "activate_alarm" ); + + + + + //************************** SCHEDULE MENU ******************************** + mPublishEvent = new KAction( i18n("&Publish Item Information..."), "mail_send", 0, + mCalendarView, SLOT( schedule_publish() ), + mACollection, "schedule_publish" ); + mPublishEvent->setEnabled( false ); + + action = new KAction( i18n("Send &Invitation to Attendees"),"mail_generic",0, + mCalendarView,SLOT( schedule_request() ), + mACollection,"schedule_request" ); + action->setEnabled( false ); + connect( mCalendarView, SIGNAL( organizerEventsSelected( bool ) ), + action, SLOT( setEnabled( bool ) ) ); + + action = new KAction( i18n("Re&quest Update"), 0, + mCalendarView, SLOT( schedule_refresh() ), + mACollection, "schedule_refresh" ); + action->setEnabled( false ); + connect( mCalendarView,SIGNAL( groupEventsSelected( bool ) ), + action,SLOT( setEnabled( bool ) ) ); + + action = new KAction( i18n("Send &Cancelation to Attendees"), 0, + mCalendarView, SLOT( schedule_cancel() ), + mACollection, "schedule_cancel" ); + action->setEnabled( false ); + connect( mCalendarView,SIGNAL( organizerEventsSelected( bool ) ), + action,SLOT( setEnabled( bool ) ) ); + + action = new KAction( i18n("Send Status &Update"),"mail_reply",0, + mCalendarView,SLOT( schedule_reply() ), + mACollection,"schedule_reply" ); + action->setEnabled( false ); + connect( mCalendarView,SIGNAL( groupEventsSelected( bool ) ), + action,SLOT( setEnabled( bool ) ) ); + + action = new KAction( i18n("counter proposal","Request Chan&ge"),0, + mCalendarView,SLOT( schedule_counter() ), + mACollection, "schedule_counter" ); + action->setEnabled( false ); + connect( mCalendarView,SIGNAL( groupEventsSelected( bool ) ), + action,SLOT( setEnabled( bool ) ) ); + + mForwardEvent = new KAction( i18n("&Send as iCalendar..."), "mail_forward", 0, + mCalendarView, SLOT(schedule_forward()), + mACollection, "schedule_forward" ); + mForwardEvent->setEnabled( false ); + + action = new KAction( i18n("&Mail Free Busy Information..."), 0, + mCalendarView, SLOT( mailFreeBusy() ), + mACollection, "mail_freebusy" ); + action->setEnabled( true ); + + action = new KAction( i18n("&Upload Free Busy Information"), 0, + mCalendarView, SLOT( uploadFreeBusy() ), + mACollection, "upload_freebusy" ); + action->setEnabled( true ); + + if ( !mIsPart ) { + action = new KAction( i18n("&Addressbook"),"contents",0, + mCalendarView,SLOT( openAddressbook() ), + mACollection,"addressbook" ); + } + + + + + //************************** SETTINGS MENU ******************************** + + //~~~~~~~~~~~~~~~~~~~~~~~~~~~~ SIDEBAR ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + mDateNavigatorShowAction = new KToggleAction( i18n("Show Date Navigator"), 0, + this, SLOT( toggleDateNavigator() ), + mACollection, "show_datenavigator" ); + mTodoViewShowAction = new KToggleAction ( i18n("Show To-do View"), 0, + this, SLOT( toggleTodoView() ), + mACollection, "show_todoview" ); + mEventViewerShowAction = new KToggleAction ( i18n("Show Item Viewer"), 0, + this, SLOT( toggleEventViewer() ), + mACollection, "show_eventviewer" ); + KConfig *config = KOGlobals::self()->config(); + config->setGroup( "Settings" ); + mDateNavigatorShowAction->setChecked( + config->readBoolEntry( "DateNavigatorVisible", true ) ); + // if we are a kpart, then let's not show the todo in the left pane by + // default since there's also a Todo part and we'll assume they'll be + // using that as well, so let's not duplicate it (by default) here + mTodoViewShowAction->setChecked( + config->readBoolEntry( "TodoViewVisible", mIsPart ? false : true ) ); + mEventViewerShowAction->setChecked( + config->readBoolEntry( "EventViewerVisible", true ) ); + toggleDateNavigator(); + toggleTodoView(); + toggleEventViewer(); + + if ( !mMainWindow->hasDocument() ) { + mResourceViewShowAction = new KToggleAction ( i18n("Show Resource View"), 0, + this, SLOT( toggleResourceView() ), + mACollection, "show_resourceview" ); + mResourceButtonsAction = new KToggleAction( i18n("Show &Resource Buttons"), 0, + this, SLOT( toggleResourceButtons() ), + mACollection, "show_resourcebuttons" ); + mResourceViewShowAction->setChecked( + config->readBoolEntry( "ResourceViewVisible", true ) ); + mResourceButtonsAction->setChecked( + config->readBoolEntry( "ResourceButtonsVisible", true ) ); + + toggleResourceView(); + toggleResourceButtons(); + } + + + //~~~~~~~~~~~~~~~~~~~~~~~~~~~~ SIDEBAR ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + new KAction( i18n("Configure &Date && Time..."), 0, + this, SLOT( configureDateTime() ), + mACollection, "conf_datetime" ); +// TODO: Add an item to show the resource management dlg +// new KAction( i18n("Manage &Resources..."), 0, +// this, SLOT( manageResources() ), +// mACollection, "conf_resources" ); + new KAction( i18n("Manage View &Filters..."), "configure", 0, + mCalendarView, SLOT( editFilters() ), + mACollection, "edit_filters" ); + new KAction( i18n("Manage C&ategories..."), 0, + mCalendarView->dialogManager(), SLOT( showCategoryEditDialog() ), + mACollection, "edit_categories" ); + if ( mIsPart ) { + new KAction( i18n("&Configure Calendar..."), "configure", 0, + mCalendarView, SLOT( edit_options() ), + mACollection, "korganizer_configure" ); + KStdAction::keyBindings( this, SLOT( keyBindings() ), + mACollection, "korganizer_configure_shortcuts" ); + } else { + KStdAction::preferences( mCalendarView, SLOT( edit_options() ), + mACollection ); + KStdAction::keyBindings( this, SLOT( keyBindings() ), mACollection ); + } + + + + + //**************************** HELP MENU ********************************** + KStdAction::tipOfDay( this, SLOT( showTip() ), mACollection, + "help_tipofday" ); +// new KAction( i18n("Show Intro Page"), 0, +// mCalendarView,SLOT( showIntro() ), +// mACollection,"show_intro" ); + + + + + //************************* TOOLBAR ACTIONS ******************************* + QLabel *filterLabel = new QLabel( i18n("Filter: "), mCalendarView ); + filterLabel->hide(); + new KWidgetAction( filterLabel, i18n("Filter: "), 0, 0, 0, + mACollection, "filter_label" ); + +} + +void ActionManager::readSettings() +{ + // read settings from the KConfig, supplying reasonable + // defaults where none are to be found + + KConfig *config = KOGlobals::self()->config(); + if ( mRecent ) mRecent->loadEntries( config ); + mCalendarView->readSettings(); +} + +void ActionManager::writeSettings() +{ + kdDebug(5850) << "ActionManager::writeSettings" << endl; + + KConfig *config = KOGlobals::self()->config(); + mCalendarView->writeSettings(); + + config->setGroup( "Settings" ); + if ( mResourceButtonsAction ) { + config->writeEntry( "ResourceButtonsVisible", + mResourceButtonsAction->isChecked() ); + } + if ( mDateNavigatorShowAction ) { + config->writeEntry( "DateNavigatorVisible", + mDateNavigatorShowAction->isChecked() ); + } + if ( mTodoViewShowAction ) { + config->writeEntry( "TodoViewVisible", + mTodoViewShowAction->isChecked() ); + } + if ( mResourceViewShowAction ) { + config->writeEntry( "ResourceViewVisible", + mResourceViewShowAction->isChecked() ); + } + if ( mEventViewerShowAction ) { + config->writeEntry( "EventViewerVisible", + mEventViewerShowAction->isChecked() ); + } + + if ( mRecent ) mRecent->saveEntries( config ); + + config->sync(); + + if ( mCalendarResources ) { + mCalendarResources->resourceManager()->writeConfig(); + } +} + +void ActionManager::file_new() +{ + emit actionNew(); +} + +void ActionManager::file_open() +{ + KURL url; + QString defaultPath = locateLocal( "data","korganizer/" ); + url = KFileDialog::getOpenURL( defaultPath,i18n("*.vcs *.ics|Calendar Files"), + dialogParent() ); + + file_open( url ); +} + +void ActionManager::file_open( const KURL &url ) +{ + if ( url.isEmpty() ) return; + + // is that URL already opened somewhere else? Activate that window + KOrg::MainWindow *korg=ActionManager::findInstance( url ); + if ( ( 0 != korg )&&( korg != mMainWindow ) ) { + KWin::setActiveWindow( korg->topLevelWidget()->winId() ); + return; + } + + kdDebug(5850) << "ActionManager::file_open(): " << url.prettyURL() << endl; + + // Open the calendar file in the same window only if we have an empty calendar window, and not the resource calendar + if ( !mCalendarView->isModified() && mFile.isEmpty() && !mCalendarResources ) { + openURL( url ); + } else { + emit actionNew( url ); + } +} + +void ActionManager::file_icalimport() +{ + // FIXME: eventually, we will need a dialog box to select import type, etc. + // for now, hard-coded to ical file, $HOME/.calendar. + int retVal = -1; + QString progPath; + KTempFile tmpfn; + + QString homeDir = QDir::homeDirPath() + QString::fromLatin1( "/.calendar" ); + + if ( !QFile::exists( homeDir ) ) { + KMessageBox::error( dialogParent(), + i18n( "You have no ical file in your home directory.\n" + "Import cannot proceed.\n" ) ); + return; + } + + KProcess proc; + proc << "ical2vcal" << tmpfn.name(); + bool success = proc.start( KProcess::Block ); + + if ( !success ) { + kdDebug(5850) << "Error starting ical2vcal." << endl; + return; + } else { + retVal = proc.exitStatus(); + } + + kdDebug(5850) << "ical2vcal return value: " << retVal << endl; + + if ( retVal >= 0 && retVal <= 2 ) { + // now we need to MERGE what is in the iCal to the current calendar. + mCalendarView->openCalendar( tmpfn.name(),1 ); + if ( !retVal ) + KMessageBox::information( dialogParent(), + i18n( "KOrganizer successfully imported and " + "merged your .calendar file from ical " + "into the currently opened calendar." ), + "dotCalendarImportSuccess" ); + else + KMessageBox::information( dialogParent(), + i18n( "KOrganizer encountered some unknown fields while " + "parsing your .calendar ical file, and had to " + "discard them; please check to see that all " + "your relevant data was correctly imported." ), + i18n("ICal Import Successful with Warning") ); + } else if ( retVal == -1 ) { + KMessageBox::error( dialogParent(), + i18n( "KOrganizer encountered an error parsing your " + ".calendar file from ical; import has failed." ) ); + } else if ( retVal == -2 ) { + KMessageBox::error( dialogParent(), + i18n( "KOrganizer does not think that your .calendar " + "file is a valid ical calendar; import has failed." ) ); + } + tmpfn.unlink(); +} + +void ActionManager::file_merge() +{ + KURL url = KFileDialog::getOpenURL( locateLocal( "data","korganizer/" ), + i18n("*.vcs *.ics|Calendar Files"), + dialogParent() ); + if ( ! url.isEmpty() ) // isEmpty if user cancelled the dialog + importCalendar( url ); +} + +void ActionManager::file_archive() +{ + mCalendarView->archiveCalendar(); +} + +void ActionManager::file_revert() +{ + openURL( mURL ); +} + +void ActionManager::file_saveas() +{ + KURL url = getSaveURL(); + + if ( url.isEmpty() ) return; + + saveAsURL( url ); +} + +void ActionManager::file_save() +{ + if ( mMainWindow->hasDocument() ) { + if ( mURL.isEmpty() ) { + file_saveas(); + return; + } else { + saveURL(); + } + } else { + mCalendarView->calendar()->save(); + } + + // export to HTML + if ( KOPrefs::instance()->mHtmlWithSave ) { + exportHTML(); + } +} + +void ActionManager::file_close() +{ + if ( !saveModifiedURL() ) return; + + mCalendarView->closeCalendar(); + KIO::NetAccess::removeTempFile( mFile ); + mURL=""; + mFile=""; + + setTitle(); +} + +bool ActionManager::openURL( const KURL &url,bool merge ) +{ + kdDebug(5850) << "ActionManager::openURL()" << endl; + + if ( url.isEmpty() ) { + kdDebug(5850) << "ActionManager::openURL(): Error! Empty URL." << endl; + return false; + } + if ( !url.isValid() ) { + kdDebug(5850) << "ActionManager::openURL(): Error! URL is malformed." << endl; + return false; + } + + if ( url.isLocalFile() ) { + mURL = url; + mFile = url.path(); + if ( !KStandardDirs::exists( mFile ) ) { + mMainWindow->showStatusMessage( i18n("New calendar '%1'.") + .arg( url.prettyURL() ) ); + mCalendarView->setModified(); + } else { + bool success = mCalendarView->openCalendar( mFile, merge ); + if ( success ) { + showStatusMessageOpen( url, merge ); + } + } + setTitle(); + } else { + QString tmpFile; + if( KIO::NetAccess::download( url, tmpFile, view() ) ) { + kdDebug(5850) << "--- Downloaded to " << tmpFile << endl; + bool success = mCalendarView->openCalendar( tmpFile, merge ); + if ( merge ) { + KIO::NetAccess::removeTempFile( tmpFile ); + if ( success ) + showStatusMessageOpen( url, merge ); + } else { + if ( success ) { + KIO::NetAccess::removeTempFile( mFile ); + mURL = url; + mFile = tmpFile; + KConfig *config = KOGlobals::self()->config(); + config->setGroup( "General" ); + setTitle(); + kdDebug(5850) << "-- Add recent URL: " << url.prettyURL() << endl; + if ( mRecent ) mRecent->addURL( url ); + showStatusMessageOpen( url, merge ); + } + } + return success; + } else { + QString msg; + msg = i18n("Cannot download calendar from '%1'.").arg( url.prettyURL() ); + KMessageBox::error( dialogParent(), msg ); + return false; + } + } + return true; +} + +bool ActionManager::addResource( const KURL &mUrl ) +{ + CalendarResources *cr = KOrg::StdCalendar::self(); + + CalendarResourceManager *manager = cr->resourceManager(); + + ResourceCalendar *resource = 0; + + QString name; + + kdDebug(5850) << "URL: " << mUrl << endl; + if ( mUrl.isLocalFile() ) { + kdDebug(5850) << "Local Resource" << endl; + resource = manager->createResource( "file" ); + if ( resource ) + resource->setValue( "File", mUrl.path() ); + name = mUrl.path(); + } else { + kdDebug(5850) << "Remote Resource" << endl; + resource = manager->createResource( "remote" ); + if ( resource ) + resource->setValue( "DownloadURL", mUrl.url() ); + name = mUrl.prettyURL(); + resource->setReadOnly( true ); + } + + if ( resource ) { + resource->setTimeZoneId( KOPrefs::instance()->mTimeZoneId ); + resource->setResourceName( name ); + manager->add( resource ); + mMainWindow->showStatusMessage( i18n( "Added calendar resource for URL '%1'." ) + .arg( name ) ); + // we have to call resourceAdded manually, because for in-process changes + // the dcop signals are not connected, so the resource's signals would not + // be connected otherwise + if ( mCalendarResources ) + mCalendarResources->resourceAdded( resource ); + } else { + QString msg = i18n("Unable to create calendar resource '%1'.") + .arg( name ); + KMessageBox::error( dialogParent(), msg ); + } + return true; +} + + +void ActionManager::showStatusMessageOpen( const KURL &url, bool merge ) +{ + if ( merge ) { + mMainWindow->showStatusMessage( i18n("Merged calendar '%1'.") + .arg( url.prettyURL() ) ); + } else { + mMainWindow->showStatusMessage( i18n("Opened calendar '%1'.") + .arg( url.prettyURL() ) ); + } +} + +void ActionManager::closeURL() +{ + kdDebug(5850) << "ActionManager::closeURL()" << endl; + + file_close(); +} + +bool ActionManager::saveURL() +{ + QString ext; + + if ( mURL.isLocalFile() ) { + ext = mFile.right( 4 ); + } else { + ext = mURL.filename().right( 4 ); + } + + if ( ext == ".vcs" ) { + int result = KMessageBox::warningContinueCancel( + dialogParent(), + i18n( "Your calendar will be saved in iCalendar format. Use " + "'Export vCalendar' to save in vCalendar format." ), + i18n("Format Conversion"), i18n("Proceed"), "dontaskFormatConversion", + true ); + if ( result != KMessageBox::Continue ) return false; + + QString filename = mURL.fileName(); + filename.replace( filename.length() - 4, 4, ".ics" ); + mURL.setFileName( filename ); + if ( mURL.isLocalFile() ) { + mFile = mURL.path(); + } + setTitle(); + if ( mRecent ) mRecent->addURL( mURL ); + } + + if ( !mCalendarView->saveCalendar( mFile ) ) { + kdDebug(5850) << "ActionManager::saveURL(): calendar view save failed." + << endl; + return false; + } else { + mCalendarView->setModified( false ); + } + + if ( !mURL.isLocalFile() ) { + if ( !KIO::NetAccess::upload( mFile, mURL, view() ) ) { + QString msg = i18n("Cannot upload calendar to '%1'") + .arg( mURL.prettyURL() ); + KMessageBox::error( dialogParent() ,msg ); + return false; + } + } + + // keep saves on a regular interval + if ( KOPrefs::instance()->mAutoSave ) { + mAutoSaveTimer->stop(); + mAutoSaveTimer->start( 1000*60*KOPrefs::instance()->mAutoSaveInterval ); + } + + mMainWindow->showStatusMessage( i18n("Saved calendar '%1'.").arg( mURL.prettyURL() ) ); + + return true; +} + +void ActionManager::exportHTML() +{ + HTMLExportSettings settings( "KOrganizer" ); + // Manually read in the config, because parametrized kconfigxt objects don't + // seem to load the config theirselves + settings.readConfig(); + + QDate qd1; + qd1 = QDate::currentDate(); + QDate qd2; + qd2 = QDate::currentDate(); + if ( settings.monthView() ) + qd2.addMonths( 1 ); + else + qd2.addDays( 7 ); + settings.setDateStart( qd1 ); + settings.setDateEnd( qd2 ); + exportHTML( &settings ); +} + +void ActionManager::exportHTML( HTMLExportSettings *settings ) +{ + if ( !settings || settings->outputFile().isEmpty() ) + return; + settings->setEMail( KOPrefs::instance()->email() ); + settings->setName( KOPrefs::instance()->fullName() ); + + settings->setCreditName( "KOrganizer" ); + settings->setCreditURL( "http://korganizer.kde.org" ); + + KCal::HtmlExport mExport( mCalendarView->calendar(), settings ); + + QDate cdate = settings->dateStart().date(); + QDate qd2 = settings->dateEnd().date(); + while ( cdate <= qd2 ) { + QStringList holidays = KOGlobals::self()->holiday( cdate ); + if ( !holidays.isEmpty() ) { + QStringList::ConstIterator it = holidays.begin(); + for ( ; it != holidays.end(); ++it ) { + mExport.addHoliday( cdate, *it ); + } + } + cdate = cdate.addDays( 1 ); + } + + KURL dest( settings->outputFile() ); + if ( dest.isLocalFile() ) { + mExport.save( dest.path() ); + } else { + KTempFile tf; + QString tfile = tf.name(); + tf.close(); + mExport.save( tfile ); + if ( !KIO::NetAccess::upload( tfile, dest, view() ) ) { + KNotifyClient::event ( view()->winId(), + i18n("Could not upload file.") ); + } + tf.unlink(); + } +} + +bool ActionManager::saveAsURL( const KURL &url ) +{ + kdDebug(5850) << "ActionManager::saveAsURL() " << url.prettyURL() << endl; + + if ( url.isEmpty() ) { + kdDebug(5850) << "ActionManager::saveAsURL(): Empty URL." << endl; + return false; + } + if ( !url.isValid() ) { + kdDebug(5850) << "ActionManager::saveAsURL(): Malformed URL." << endl; + return false; + } + + QString fileOrig = mFile; + KURL URLOrig = mURL; + + KTempFile *tempFile = 0; + if ( url.isLocalFile() ) { + mFile = url.path(); + } else { + tempFile = new KTempFile; + mFile = tempFile->name(); + } + mURL = url; + + bool success = saveURL(); // Save local file and upload local file + if ( success ) { + delete mTempFile; + mTempFile = tempFile; + KIO::NetAccess::removeTempFile( fileOrig ); + KConfig *config = KOGlobals::self()->config(); + config->setGroup( "General" ); + setTitle(); + if ( mRecent ) mRecent->addURL( mURL ); + } else { + KMessageBox::sorry( dialogParent(), i18n("Unable to save calendar to the file %1.").arg( mFile ), i18n("Error") ); + kdDebug(5850) << "ActionManager::saveAsURL() failed" << endl; + mURL = URLOrig; + mFile = fileOrig; + delete tempFile; + } + + return success; +} + + +bool ActionManager::saveModifiedURL() +{ + kdDebug(5850) << "ActionManager::saveModifiedURL()" << endl; + + // If calendar isn't modified do nothing. + if ( !mCalendarView->isModified() ) return true; + + mHtmlExportSync = true; + if ( KOPrefs::instance()->mAutoSave && !mURL.isEmpty() ) { + // Save automatically, when auto save is enabled. + return saveURL(); + } else { + int result = KMessageBox::warningYesNoCancel( + dialogParent(), + i18n("The calendar has been modified.\nDo you want to save it?"), + QString::null, + KStdGuiItem::save(), KStdGuiItem::discard() ); + switch( result ) { + case KMessageBox::Yes: + if ( mURL.isEmpty() ) { + KURL url = getSaveURL(); + return saveAsURL( url ); + } else { + return saveURL(); + } + case KMessageBox::No: + return true; + case KMessageBox::Cancel: + default: + { + mHtmlExportSync = false; + return false; + } + } + } +} + + +KURL ActionManager::getSaveURL() +{ + KURL url = KFileDialog::getSaveURL( locateLocal( "data","korganizer/" ), + i18n("*.vcs *.ics|Calendar Files"), + dialogParent() ); + + if ( url.isEmpty() ) return url; + + QString filename = url.fileName( false ); + + QString e = filename.right( 4 ); + if ( e != ".vcs" && e != ".ics" ) { + // Default save format is iCalendar + filename += ".ics"; + } + + url.setFileName( filename ); + + kdDebug(5850) << "ActionManager::getSaveURL(): url: " << url.url() << endl; + + return url; +} + +void ActionManager::saveProperties( KConfig *config ) +{ + kdDebug(5850) << "ActionManager::saveProperties" << endl; + + config->writeEntry( "UseResourceCalendar", !mMainWindow->hasDocument() ); + if ( mMainWindow->hasDocument() ) { + config->writePathEntry( "Calendar",mURL.url() ); + } +} + +void ActionManager::readProperties( KConfig *config ) +{ + kdDebug(5850) << "ActionManager::readProperties" << endl; + + bool isResourceCalendar( + config->readBoolEntry( "UseResourceCalendar", true ) ); + QString calendarUrl = config->readPathEntry( "Calendar" ); + + if ( !isResourceCalendar && !calendarUrl.isEmpty() ) { + mMainWindow->init( true ); + KURL u( calendarUrl ); + openURL( u ); + } else { + mMainWindow->init( false ); + } +} + +void ActionManager::checkAutoSave() +{ + kdDebug(5850) << "ActionManager::checkAutoSave()" << endl; + + // Don't save if auto save interval is zero + if ( KOPrefs::instance()->mAutoSaveInterval == 0 ) return; + + // has this calendar been saved before? If yes automatically save it. + if ( KOPrefs::instance()->mAutoSave ) { + if ( mCalendarResources || ( mCalendar && !url().isEmpty() ) ) { + saveCalendar(); + } + } +} + + +// Configuration changed as a result of the options dialog. +void ActionManager::updateConfig() +{ + kdDebug(5850) << "ActionManager::updateConfig()" << endl; + + if ( KOPrefs::instance()->mAutoSave && !mAutoSaveTimer->isActive() ) { + checkAutoSave(); + if ( KOPrefs::instance()->mAutoSaveInterval > 0 ) { + mAutoSaveTimer->start( 1000 * 60 * + KOPrefs::instance()->mAutoSaveInterval ); + } + } + if ( !KOPrefs::instance()->mAutoSave ) mAutoSaveTimer->stop(); + mNextXDays->setText( i18n( "&Next Day", "&Next %n Days", + KOPrefs::instance()->mNextXDays ) ); + + KOCore::self()->reloadPlugins(); + mParts = KOCore::self()->reloadParts( mMainWindow, mParts ); + + setDestinationPolicy(); + + if ( mResourceView ) + mResourceView->updateView(); + + KOGroupware::instance()->freeBusyManager()->setBrokenUrl( false ); +} + +void ActionManager::setDestinationPolicy() +{ + if ( mCalendarResources ) { + if ( KOPrefs::instance()->mDestination == KOPrefs::askDestination ) + mCalendarResources->setAskDestinationPolicy(); + else + mCalendarResources->setStandardDestinationPolicy(); + } +} + +void ActionManager::configureDateTime() +{ + KProcess *proc = new KProcess; + *proc << "kcmshell" << "language"; + + connect( proc,SIGNAL( processExited( KProcess * ) ), + SLOT( configureDateTimeFinished( KProcess * ) ) ); + + if ( !proc->start() ) { + KMessageBox::sorry( dialogParent(), + i18n("Could not start control module for date and time format.") ); + delete proc; + } +} + +void ActionManager::showTip() +{ + KTipDialog::showTip( dialogParent(),QString::null,true ); +} + +void ActionManager::showTipOnStart() +{ + KTipDialog::showTip( dialogParent() ); +} + +KOrg::MainWindow *ActionManager::findInstance( const KURL &url ) +{ + if ( mWindowList ) { + if ( url.isEmpty() ) return mWindowList->defaultInstance(); + else return mWindowList->findInstance( url ); + } else { + return 0; + } +} + +void ActionManager::dumpText( const QString &str ) +{ + kdDebug(5850) << "ActionManager::dumpText(): " << str << endl; +} + +void ActionManager::toggleDateNavigator() +{ + bool visible = mDateNavigatorShowAction->isChecked(); + if ( mCalendarView ) mCalendarView->showDateNavigator( visible ); +} + +void ActionManager::toggleTodoView() +{ + bool visible = mTodoViewShowAction->isChecked(); + if ( mCalendarView ) mCalendarView->showTodoView( visible ); +} + +void ActionManager::toggleEventViewer() +{ + bool visible = mEventViewerShowAction->isChecked(); + if ( mCalendarView ) mCalendarView->showEventViewer( visible ); +} + +void ActionManager::toggleResourceView() +{ + bool visible = mResourceViewShowAction->isChecked(); + kdDebug(5850) << "toggleResourceView: " << endl; + if ( mResourceView ) { + if ( visible ) mResourceView->show(); + else mResourceView->hide(); + } +} + +void ActionManager::toggleResourceButtons() +{ + bool visible = mResourceButtonsAction->isChecked(); + + kdDebug(5850) << "RESOURCE VIEW " << long( mResourceView ) << endl; + + if ( mResourceView ) mResourceView->showButtons( visible ); +} + +bool ActionManager::openURL( const QString &url ) +{ + return openURL( KURL( url ) ); +} + +bool ActionManager::mergeURL( const QString &url ) +{ + return openURL( KURL( url ),true ); +} + +bool ActionManager::saveAsURL( const QString &url ) +{ + return saveAsURL( KURL( url ) ); +} + +QString ActionManager::getCurrentURLasString() const +{ + return mURL.url(); +} + +bool ActionManager::editIncidence( const QString& uid ) +{ + return mCalendarView->editIncidence( uid ); +} + +bool ActionManager::deleteIncidence( const QString& uid, bool force ) +{ + return mCalendarView->deleteIncidence( uid, force ); +} + +bool ActionManager::addIncidence( const QString& ical ) +{ + return mCalendarView->addIncidence( ical ); +} + +void ActionManager::configureDateTimeFinished( KProcess *proc ) +{ + delete proc; +} + +void ActionManager::downloadNewStuff() +{ + kdDebug(5850) << "ActionManager::downloadNewStuff()" << endl; + + if ( !mNewStuff ) mNewStuff = new KONewStuff( mCalendarView ); + mNewStuff->download(); +} + +void ActionManager::uploadNewStuff() +{ + if ( !mNewStuff ) mNewStuff = new KONewStuff( mCalendarView ); + mNewStuff->upload(); +} + +QString ActionManager::localFileName() +{ + return mFile; +} + +class ActionManager::ActionStringsVisitor : public IncidenceBase::Visitor +{ + public: + ActionStringsVisitor() : mShow( 0 ), mEdit( 0 ), mDelete( 0 ) {} + + bool act( IncidenceBase *incidence, KAction *show, KAction *edit, KAction *del ) + { + mShow = show; + mEdit = edit; + mDelete = del; + return incidence->accept( *this ); + } + + protected: + bool visit( Event * ) { + if ( mShow ) mShow->setText( i18n("&Show Event") ); + if ( mEdit ) mEdit->setText( i18n("&Edit Event...") ); + if ( mDelete ) mDelete->setText( i18n("&Delete Event") ); + return true; + } + bool visit( Todo * ) { + if ( mShow ) mShow->setText( i18n("&Show To-do") ); + if ( mEdit ) mEdit->setText( i18n("&Edit To-do...") ); + if ( mDelete ) mDelete->setText( i18n("&Delete To-do") ); + return true; + } + bool visit( Journal * ) { return assignDefaultStrings(); } + protected: + bool assignDefaultStrings() { + if ( mShow ) mShow->setText( i18n("&Show") ); + if ( mEdit ) mEdit->setText( i18n("&Edit...") ); + if ( mDelete ) mDelete->setText( i18n("&Delete") ); + return true; + } + KAction *mShow; + KAction *mEdit; + KAction *mDelete; +}; + +void ActionManager::processIncidenceSelection( Incidence *incidence ) +{ +// kdDebug(5850) << "ActionManager::processIncidenceSelection()" << endl; + + if ( !incidence ) { + enableIncidenceActions( false ); + return; + } + + enableIncidenceActions( true ); + + if ( incidence->isReadOnly() ) { + mCutAction->setEnabled( false ); + mDeleteAction->setEnabled( false ); + } + + ActionStringsVisitor v; + if ( !v.act( incidence, mShowIncidenceAction, mEditIncidenceAction, mDeleteIncidenceAction ) ) { + mShowIncidenceAction->setText( i18n("&Show") ); + mEditIncidenceAction->setText( i18n("&Edit...") ); + mDeleteIncidenceAction->setText( i18n("&Delete") ); + } +} + +void ActionManager::enableIncidenceActions( bool enabled ) +{ + mShowIncidenceAction->setEnabled( enabled ); + mEditIncidenceAction->setEnabled( enabled ); + mDeleteIncidenceAction->setEnabled( enabled ); +// mAssignResourceAction->setEnabled( enabled ); + + mCutAction->setEnabled( enabled ); + mCopyAction->setEnabled( enabled ); + mDeleteAction->setEnabled( enabled ); + mPublishEvent->setEnabled( enabled ); + mForwardEvent->setEnabled( enabled ); +} + +void ActionManager::keyBindings() +{ + KKeyDialog dlg( false, view() ); + if ( mMainWindow ) + dlg.insert( mMainWindow->getActionCollection() ); + + KOrg::Part *part; + for ( part = mParts.first(); part; part = mParts.next() ) { + dlg.insert( part->actionCollection(), part->shortInfo() ); + } + dlg.configure(); +} + +void ActionManager::loadParts() +{ + mParts = KOCore::self()->loadParts( mMainWindow ); +} + +void ActionManager::setTitle() +{ + mMainWindow->setTitle(); +} + +KCalendarIface::ResourceRequestReply ActionManager::resourceRequest( const QValueList<QPair<QDateTime, QDateTime> >&, + const QCString& resource, + const QString& vCalIn ) +{ + kdDebug(5850) << k_funcinfo << "resource=" << resource << " vCalIn=" << vCalIn << endl; + KCalendarIface::ResourceRequestReply reply; + reply.vCalOut = "VCalOut"; + return reply; +} + +void ActionManager::openEventEditor( const QString& text ) +{ + mCalendarView->newEvent( text ); +} + +void ActionManager::openEventEditor( const QString& summary, + const QString& description, + const QString& attachment ) +{ + mCalendarView->newEvent( summary, description, attachment ); +} + +void ActionManager::openEventEditor( const QString& summary, + const QString& description, + const QString& attachment, + const QStringList& attendees ) +{ + mCalendarView->newEvent( summary, description, attachment, attendees ); +} + +void ActionManager::openEventEditor( const QString & summary, + const QString & description, + const QString & uri, + const QString & file, + const QStringList & attendees, + const QString & attachmentMimetype ) +{ + int action = KOPrefs::instance()->defaultEmailAttachMethod(); + if ( attachmentMimetype != "message/rfc822" ) { + action = KOPrefs::Link; + } else if ( KOPrefs::instance()->defaultEmailAttachMethod() == KOPrefs::Ask ) { + KPopupMenu *menu = new KPopupMenu( 0 ); + menu->insertItem( i18n("Attach as &link"), KOPrefs::Link ); + menu->insertItem( i18n("Attach &inline"), KOPrefs::InlineFull ); + menu->insertItem( i18n("Attach inline &without attachments"), KOPrefs::InlineBody ); + menu->insertSeparator(); + menu->insertItem( SmallIcon("cancel"), i18n("C&ancel"), KOPrefs::Ask ); + action = menu->exec( QCursor::pos(), 0 ); + delete menu; + } + + QString attData; + KTempFile tf; + tf.setAutoDelete( true ); + switch ( action ) { + case KOPrefs::Ask: + return; + case KOPrefs::Link: + attData = uri; + break; + case KOPrefs::InlineFull: + attData = file; + break; + case KOPrefs::InlineBody: + { + QFile f( file ); + if ( !f.open( IO_ReadOnly ) ) + return; + KMime::Message *msg = new KMime::Message(); + msg->setContent( QCString( f.readAll() ) ); + QCString head = msg->head(); + msg->parse(); + if ( msg == msg->textContent() || msg->textContent() == 0 ) { // no attachments + attData = file; + } else { + if ( KMessageBox::warningContinueCancel( 0, + i18n("Removing attachments from an email might invalidate its signature."), + i18n("Remove Attachments"), KStdGuiItem::cont(), "BodyOnlyInlineAttachment" ) + != KMessageBox::Continue ) + return; + // due to kmime shortcomings in KDE3, we need to assemble the result manually + int begin = 0; + int end = head.find( '\n' ); + bool skipFolded = false; + while ( end >= 0 && end > begin ) { + if ( head.find( "Content-Type:", begin, false ) != begin && + head.find( "Content-Transfer-Encoding:", begin, false ) != begin && + !(skipFolded && (head[begin] == ' ' || head[end] == '\t')) ) { + QCString line = head.mid( begin, end - begin ); + tf.file()->writeBlock( line.data(), line.length() ); + tf.file()->writeBlock( "\n", 1 ); + skipFolded = false; + } else { + skipFolded = true; + } + + begin = end + 1; + end = head.find( '\n', begin ); + if ( end < 0 && begin < (int)head.length() ) + end = head.length() - 1; + } + QCString cte = msg->textContent()->contentTransferEncoding()->as7BitString(); + if ( !cte.stripWhiteSpace().isEmpty() ) { + tf.file()->writeBlock( cte.data(), cte.length() ); + tf.file()->writeBlock( "\n", 1 ); + } + QCString ct = msg->textContent()->contentType()->as7BitString(); + if ( !ct.stripWhiteSpace().isEmpty() ) + tf.file()->writeBlock( ct.data(), ct.length() ); + tf.file()->writeBlock( "\n", 1 ); + tf.file()->writeBlock( msg->textContent()->body() ); + attData = tf.name(); + } + tf.close(); + delete msg; + break; + } + default: + // menu could have been closed by cancel, if so, do nothing + return; + } + + mCalendarView->newEvent( summary, description, attData, attendees, attachmentMimetype, action != KOPrefs::Link ); +} + +void ActionManager::openTodoEditor( const QString& text ) +{ + mCalendarView->newTodo( text ); +} + +void ActionManager::openTodoEditor( const QString& summary, + const QString& description, + const QString& attachment ) +{ + mCalendarView->newTodo( summary, description, attachment ); +} + +void ActionManager::openTodoEditor( const QString& summary, + const QString& description, + const QString& attachment, + const QStringList& attendees ) +{ + mCalendarView->newTodo( summary, description, attachment, attendees ); +} + +void ActionManager::openTodoEditor(const QString & summary, + const QString & description, + const QString & uri, + const QString & file, + const QStringList & attendees, + const QString & attachmentMimetype) +{ + int action = KOPrefs::instance()->defaultTodoAttachMethod(); + if ( attachmentMimetype != "message/rfc822" ) { + action = KOPrefs::TodoAttachLink; + } else if ( KOPrefs::instance()->defaultTodoAttachMethod() == KOPrefs::TodoAttachAsk ) { + KPopupMenu *menu = new KPopupMenu( 0 ); + menu->insertItem( i18n("Attach as &link"), KOPrefs::TodoAttachLink ); + menu->insertItem( i18n("Attach &inline"), KOPrefs::TodoAttachInlineFull ); + menu->insertSeparator(); + menu->insertItem( SmallIcon("cancel"), i18n("C&ancel"), KOPrefs::TodoAttachAsk ); + action = menu->exec( QCursor::pos(), 0 ); + delete menu; + } + + QString attData; + switch ( action ) { + case KOPrefs::TodoAttachAsk: + return; + case KOPrefs::TodoAttachLink: + attData = uri; + break; + case KOPrefs::TodoAttachInlineFull: + attData = file; + break; + default: + // menu could have been closed by cancel, if so, do nothing + return; + } + + mCalendarView->newTodo( summary, description, attData, attendees, attachmentMimetype, action != KOPrefs::Link ); +} + +void ActionManager::openJournalEditor( const QDate& date ) +{ + mCalendarView->newJournal( date ); +} + +void ActionManager::openJournalEditor( const QString& text, const QDate& date ) +{ + mCalendarView->newJournal( text, date ); +} + +void ActionManager::openJournalEditor( const QString& text ) +{ + mCalendarView->newJournal( text ); +} + +//TODO: +// void ActionManager::openJournalEditor( const QString& summary, +// const QString& description, +// const QString& attachment ) +// { +// mCalendarView->newJournal( summary, description, attachment ); +// } + + +void ActionManager::showJournalView() +{ + mCalendarView->viewManager()->showJournalView(); +} + +void ActionManager::showTodoView() +{ + mCalendarView->viewManager()->showTodoView(); +} + +void ActionManager::showEventView() +{ + mCalendarView->viewManager()->showEventView(); +} + +void ActionManager::goDate( const QDate& date ) +{ + mCalendarView->goDate( date ); +} + +void ActionManager::goDate( const QString& date ) +{ + goDate( KGlobal::locale()->readDate( date ) ); +} + +void ActionManager::showDate(const QDate & date) +{ + mCalendarView->showDate( date ); +} + + +void ActionManager::updateUndoAction( const QString &text ) +{ + if ( text.isNull() ) { + mUndoAction->setEnabled( false ); + mUndoAction->setText( i18n("Undo") ); + } else { + mUndoAction->setEnabled( true ); + if ( text.isEmpty() ) mUndoAction->setText( i18n("Undo") ); + else mUndoAction->setText( i18n("Undo (%1)").arg( text ) ); + } +} + +void ActionManager::updateRedoAction( const QString &text ) +{ + if ( text.isNull() ) { + mRedoAction->setEnabled( false ); + mRedoAction->setText( i18n( "Redo" ) ); + } else { + mRedoAction->setEnabled( true ); + if ( text.isEmpty() ) mRedoAction->setText( i18n("Redo") ); + else mRedoAction->setText( i18n( "Redo (%1)" ).arg( text ) ); + } +} + +bool ActionManager::queryClose() +{ + kdDebug(5850) << "ActionManager::queryClose()" << endl; + + bool close = true; + + if ( mCalendar && mCalendar->isModified() ) { + int res = KMessageBox::questionYesNoCancel( dialogParent(), + i18n("The calendar contains unsaved changes. Do you want to save them before exiting?"), QString::null, KStdGuiItem::save(), KStdGuiItem::discard() ); + // Exit on yes and no, don't exit on cancel. If saving fails, ask for exiting. + if ( res == KMessageBox::Yes ) { + close = saveModifiedURL(); + if ( !close ) { + int res1 = KMessageBox::questionYesNo( dialogParent(), i18n("Unable to save the calendar. Do you still want to close this window?"), QString::null, KStdGuiItem::close(), KStdGuiItem::cancel() ); + close = ( res1 == KMessageBox::Yes ); + } + } else { + close = ( res == KMessageBox::No ); + } + } else if ( mCalendarResources ) { + if ( !mIsClosing ) { + kdDebug(5850) << "!mIsClosing" << endl; + if ( !saveResourceCalendar() ) return false; + + // FIXME: Put main window into a state indicating final saving. + mIsClosing = true; +// FIXME: Close main window when save is finished +// connect( mCalendarResources, SIGNAL( calendarSaved() ), +// mMainWindow, SLOT( close() ) ); + } + if ( mCalendarResources->isSaving() ) { + kdDebug(5850) << "ActionManager::queryClose(): isSaving" << endl; + close = false; + KMessageBox::information( dialogParent(), + i18n("Unable to exit. Saving still in progress.") ); + } else { + kdDebug(5850) << "ActionManager::queryClose(): close = true" << endl; + close = true; + } + } else { + close = true; + } + + return close; +} + +void ActionManager::saveCalendar() +{ + if ( mCalendar ) { + if ( view()->isModified() ) { + if ( !url().isEmpty() ) { + saveURL(); + } else { + QString location = locateLocal( "data", "korganizer/kontact.ics" ); + saveAsURL( location ); + } + } + } else if ( mCalendarResources ) { + mCalendarResources->save(); + // FIXME: Make sure that asynchronous saves don't fail. + } +} + +bool ActionManager::saveResourceCalendar() +{ + if ( !mCalendarResources ) return false; + CalendarResourceManager *m = mCalendarResources->resourceManager(); + + CalendarResourceManager::ActiveIterator it; + for ( it = m->activeBegin(); it != m->activeEnd(); ++it ) { + if ( (*it)->readOnly() ) continue; + if ( !(*it)->save() ) { + int result = KMessageBox::warningContinueCancel( view(), + i18n( "Saving of '%1' failed. Check that the resource is " + "properly configured.\nIgnore problem and continue without " + "saving or cancel save?" ).arg( (*it)->resourceName() ), + i18n("Save Error"), KStdGuiItem::dontSave() ); + if ( result == KMessageBox::Cancel ) return false; + } + } + return true; +} + +void ActionManager::importCalendar( const KURL &url ) +{ + if ( !url.isValid() ) { + KMessageBox::error( dialogParent(), + i18n("URL '%1' is invalid.").arg( url.prettyURL() ) ); + return; + } + + ImportDialog *dialog; + dialog = new ImportDialog( url, mMainWindow->topLevelWidget() ); + connect( dialog, SIGNAL( dialogFinished( ImportDialog * ) ), + SLOT( slotImportDialogFinished( ImportDialog * ) ) ); + connect( dialog, SIGNAL( openURL( const KURL &, bool ) ), + SLOT( openURL( const KURL &, bool ) ) ); + connect( dialog, SIGNAL( newWindow( const KURL & ) ), + SIGNAL( actionNew( const KURL & ) ) ); + connect( dialog, SIGNAL( addResource( const KURL & ) ), + SLOT( addResource( const KURL & ) ) ); + + dialog->show(); +} + +void ActionManager::slotImportDialogFinished( ImportDialog *dlg ) +{ + dlg->deleteLater(); + mCalendarView->updateView(); +} + +void ActionManager::slotAutoArchivingSettingsModified() +{ + if ( KOPrefs::instance()->mAutoArchive ) + mAutoArchiveTimer->start( 4 * 60 * 60 * 1000, true ); // check again in 4 hours + else + mAutoArchiveTimer->stop(); +} + +void ActionManager::slotAutoArchive() +{ + if ( !mCalendarView->calendar() ) // can this happen? + return; + mAutoArchiveTimer->stop(); + EventArchiver archiver; + connect( &archiver, SIGNAL( eventsDeleted() ), mCalendarView, SLOT( updateView() ) ); + archiver.runAuto( mCalendarView->calendar(), mCalendarView, false /*no gui*/ ); + // restart timer with the correct delay ( especially useful for the first time ) + slotAutoArchivingSettingsModified(); +} + +void ActionManager::loadProfile( const QString & path ) +{ + KOPrefs::instance()->writeConfig(); + KConfig* const cfg = KOPrefs::instance()->config(); + + const KConfig profile( path+"/korganizerrc", /*read-only=*/false, /*useglobals=*/false ); + const QStringList groups = profile.groupList(); + for ( QStringList::ConstIterator it = groups.begin(), end = groups.end(); it != end; ++it ) + { + cfg->setGroup( *it ); + typedef QMap<QString, QString> StringMap; + const StringMap entries = profile.entryMap( *it ); + for ( StringMap::ConstIterator it2 = entries.begin(), end = entries.end(); it2 != end; ++it2 ) + { + cfg->writeEntry( it2.key(), it2.data() ); + } + } + + cfg->sync(); + KOPrefs::instance()->readConfig(); +} + +namespace { + void copyConfigEntry( KConfig* source, KConfig* dest, const QString& group, const QString& key, const QString& defaultValue=QString() ) + { + source->setGroup( group ); + dest->setGroup( group ); + dest->writeEntry( key, source->readEntry( key, defaultValue ) ); + } +} + +void ActionManager::saveToProfile( const QString & path ) const +{ + KOPrefs::instance()->writeConfig(); + KConfig* const cfg = KOPrefs::instance()->config(); + + KConfig profile( path+"/korganizerrc", /*read-only=*/false, /*useglobals=*/false ); + ::copyConfigEntry( cfg, &profile, "Views", "Agenda View Calendar Display" ); +} + +QWidget *ActionManager::dialogParent() +{ + return mCalendarView->topLevelWidget(); +} + +#include "actionmanager.moc" |