~ubuntu-branches/ubuntu/oneiric/kdepim/oneiric-updates

« back to all changes in this revision

Viewing changes to kalarm/messagewin.cpp

  • Committer: Package Import Robot
  • Author(s): Philip Muškovac
  • Date: 2011-06-28 19:33:24 UTC
  • mfrom: (0.2.13) (0.1.13 sid)
  • Revision ID: package-import@ubuntu.com-20110628193324-8yvjs8sdv9rdoo6c
Tags: 4:4.7.0-0ubuntu1
* New upstream release
  - update install files
  - add missing kdepim-doc package to control file
  - Fix Vcs lines
  - kontact breaks/replaces korganizer << 4:4.6.80
  - tighten the dependency of kdepim-dev on libkdepim4 to fix lintian error

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
/*
2
2
 *  messagewin.cpp  -  displays an alarm message
3
3
 *  Program:  kalarm
4
 
 *  Copyright © 2001-2010 by David Jarvie <djarvie@kde.org>
 
4
 *  Copyright © 2001-2011 by David Jarvie <djarvie@kde.org>
5
5
 *
6
6
 *  This program is free software; you can redistribute it and/or modify
7
7
 *  it under the terms of the GNU General Public License as published by
24
24
 
25
25
#include "alarmcalendar.h"
26
26
#include "autoqpointer.h"
 
27
#ifdef USE_AKONADI
 
28
#include "collectionmodel.h"
 
29
#endif
27
30
#include "deferdlg.h"
28
31
#include "desktop.h"
29
32
#include "editdlg.h"
88
91
#include <stdlib.h>
89
92
#include <string.h>
90
93
 
 
94
#ifdef USE_AKONADI
 
95
using namespace KCalCore;
 
96
#else
91
97
using namespace KCal;
 
98
#endif
92
99
 
93
100
#ifdef Q_WS_X11
94
101
enum FullScreenType { NoFullScreen = 0, FullScreen = 1, FullScreenActive = 2 };
110
117
// A text label widget which can be scrolled and copied with the mouse
111
118
class MessageText : public KTextEdit
112
119
{
113
 
        public:
114
 
                MessageText(QWidget* parent = 0)
115
 
                        : KTextEdit(parent),
116
 
                          mNewLine(false)
117
 
                {
118
 
                        setReadOnly(true);
119
 
                        setFrameStyle(NoFrame);
120
 
                        setLineWrapMode(NoWrap);
121
 
                }
122
 
                int scrollBarHeight() const     { return horizontalScrollBar()->height(); }
123
 
                int scrollBarWidth() const      { return verticalScrollBar()->width(); }
124
 
                void setBackgroundColour(const QColor& c)
125
 
                {
126
 
                        QPalette pal = viewport()->palette();
127
 
                        pal.setColor(viewport()->backgroundRole(), c);
128
 
                        viewport()->setPalette(pal);
129
 
                }
130
 
                virtual QSize sizeHint() const
131
 
                {
132
 
                        QSizeF docsize = document()->size();
133
 
                        return QSize(static_cast<int>(docsize.width() + 0.99) + verticalScrollBar()->width(),
134
 
                                     static_cast<int>(docsize.height() + 0.99) + horizontalScrollBar()->height());
135
 
                }
136
 
                bool newLine() const       { return mNewLine; }
137
 
                void setNewLine(bool nl)   { mNewLine = nl; }
138
 
        private:
139
 
                bool mNewLine;
 
120
    public:
 
121
        MessageText(QWidget* parent = 0)
 
122
            : KTextEdit(parent),
 
123
              mNewLine(false)
 
124
        {
 
125
            setReadOnly(true);
 
126
            setFrameStyle(NoFrame);
 
127
            setLineWrapMode(NoWrap);
 
128
        }
 
129
        int scrollBarHeight() const     { return horizontalScrollBar()->height(); }
 
130
        int scrollBarWidth() const      { return verticalScrollBar()->width(); }
 
131
        void setBackgroundColour(const QColor& c)
 
132
        {
 
133
            QPalette pal = viewport()->palette();
 
134
            pal.setColor(viewport()->backgroundRole(), c);
 
135
            viewport()->setPalette(pal);
 
136
        }
 
137
        virtual QSize sizeHint() const
 
138
        {
 
139
            QSizeF docsize = document()->size();
 
140
            return QSize(static_cast<int>(docsize.width() + 0.99) + verticalScrollBar()->width(),
 
141
                         static_cast<int>(docsize.height() + 0.99) + horizontalScrollBar()->height());
 
142
        }
 
143
        bool newLine() const       { return mNewLine; }
 
144
        void setNewLine(bool nl)   { mNewLine = nl; }
 
145
    private:
 
146
        bool mNewLine;
140
147
};
141
148
 
142
149
 
147
154
 
148
155
// Error message bit masks
149
156
enum {
150
 
        ErrMsg_Speak     = 0x01,
151
 
        ErrMsg_AudioFile = 0x02
 
157
    ErrMsg_Speak     = 0x01,
 
158
    ErrMsg_AudioFile = 0x02
152
159
};
153
160
 
154
161
 
167
174
*  displayed.
168
175
*/
169
176
MessageWin::MessageWin(const KAEvent* event, const KAAlarm& alarm, int flags)
170
 
        : MainWindowBase(0, static_cast<Qt::WFlags>(WFLAGS | WFLAGS2 | ((flags & ALWAYS_HIDE) || getWorkAreaAndModal() ? Qt::WindowType(0) : Qt::X11BypassWindowManagerHint))),
171
 
          mMessage(event->cleanText()),
172
 
          mFont(event->font()),
173
 
          mBgColour(event->bgColour()),
174
 
          mFgColour(event->fgColour()),
175
 
          mDateTime((alarm.type() & KAAlarm::REMINDER_ALARM) ? event->mainDateTime(true) : alarm.dateTime(true)),
176
 
          mEventID(event->id()),
177
 
          mAudioFile(event->audioFile()),
178
 
          mVolume(event->soundVolume()),
179
 
          mFadeVolume(event->fadeVolume()),
180
 
          mFadeSeconds(qMin(event->fadeSeconds(), 86400)),
181
 
          mDefaultDeferMinutes(event->deferDefaultMinutes()),
182
 
          mAlarmType(alarm.type()),
183
 
          mAction(event->action()),
 
177
    : MainWindowBase(0, static_cast<Qt::WFlags>(WFLAGS | WFLAGS2 | ((flags & ALWAYS_HIDE) || getWorkAreaAndModal() ? Qt::WindowType(0) : Qt::X11BypassWindowManagerHint))),
 
178
      mMessage(event->cleanText()),
 
179
      mFont(event->font()),
 
180
      mBgColour(event->bgColour()),
 
181
      mFgColour(event->fgColour()),
 
182
#ifdef USE_AKONADI
 
183
      mEventItemId(event->itemId()),
 
184
#endif
 
185
      mEventID(event->id()),
 
186
      mAudioFile(event->audioFile()),
 
187
      mVolume(event->soundVolume()),
 
188
      mFadeVolume(event->fadeVolume()),
 
189
      mFadeSeconds(qMin(event->fadeSeconds(), 86400)),
 
190
      mDefaultDeferMinutes(event->deferDefaultMinutes()),
 
191
      mAlarmType(alarm.type()),
 
192
      mAction(event->action()),
184
193
#ifdef KMAIL_SUPPORTED
185
 
          mKMailSerialNumber(event->kmailSerialNumber()),
186
 
#else
187
 
          mKMailSerialNumber(0),
188
 
#endif
189
 
          mCommandError(event->commandError()),
190
 
          mRestoreHeight(0),
191
 
          mAudioRepeat(event->repeatSound()),
192
 
          mConfirmAck(event->confirmAck()),
193
 
          mNoDefer(true),
194
 
          mInvalid(false),
195
 
          mEvent(*event),
196
 
          mResource(AlarmCalendar::resources()->resourceForEvent(mEventID)),
197
 
          mTimeLabel(0),
198
 
          mRemainingText(0),
199
 
          mEditButton(0),
200
 
          mDeferButton(0),
201
 
          mSilenceButton(0),
202
 
          mKMailButton(0),
203
 
          mCommandText(0),
204
 
          mDontShowAgainCheck(0),
205
 
          mEditDlg(0),
206
 
          mDeferDlg(0),
207
 
          mFlags(event->flags()),
208
 
          mLateCancel(event->lateCancel()),
209
 
          mAlwaysHide(flags & ALWAYS_HIDE),
210
 
          mErrorWindow(false),
211
 
          mInitialised(false),
212
 
          mNoPostAction(alarm.type() & KAAlarm::REMINDER_ALARM),
213
 
          mRecreating(false),
214
 
          mBeep(event->beep()),
215
 
          mSpeak(event->speak()),
216
 
          mRescheduleEvent(!(flags & NO_RESCHEDULE)),
217
 
          mShown(false),
218
 
          mPositioning(false),
219
 
          mNoCloseConfirm(false),
220
 
          mDisableDeferral(false)
 
194
      mKMailSerialNumber(event->kmailSerialNumber()),
 
195
#else
 
196
      mKMailSerialNumber(0),
 
197
#endif
 
198
      mCommandError(event->commandError()),
 
199
      mRestoreHeight(0),
 
200
      mAudioRepeat(event->repeatSound()),
 
201
      mConfirmAck(event->confirmAck()),
 
202
      mNoDefer(true),
 
203
      mInvalid(false),
 
204
      mEvent(*event),
 
205
#ifdef USE_AKONADI
 
206
      mCollection(AlarmCalendar::resources()->collectionForEvent(mEventItemId)),
 
207
#else
 
208
      mResource(AlarmCalendar::resources()->resourceForEvent(mEventID)),
 
209
#endif
 
210
      mTimeLabel(0),
 
211
      mRemainingText(0),
 
212
      mEditButton(0),
 
213
      mDeferButton(0),
 
214
      mSilenceButton(0),
 
215
      mKMailButton(0),
 
216
      mCommandText(0),
 
217
      mDontShowAgainCheck(0),
 
218
      mEditDlg(0),
 
219
      mDeferDlg(0),
 
220
      mFlags(event->flags()),
 
221
      mLateCancel(event->lateCancel()),
 
222
      mAlwaysHide(flags & ALWAYS_HIDE),
 
223
      mErrorWindow(false),
 
224
      mInitialised(false),
 
225
      mNoPostAction(alarm.type() & KAAlarm::REMINDER_ALARM),
 
226
      mRecreating(false),
 
227
      mBeep(event->beep()),
 
228
      mSpeak(event->speak()),
 
229
      mRescheduleEvent(!(flags & NO_RESCHEDULE)),
 
230
      mShown(false),
 
231
      mPositioning(false),
 
232
      mNoCloseConfirm(false),
 
233
      mDisableDeferral(false)
221
234
{
222
 
        kDebug() << "event";
223
 
        setAttribute(static_cast<Qt::WidgetAttribute>(WidgetFlags));
224
 
        setWindowModality(Qt::WindowModal);
225
 
        setObjectName("MessageWin");    // used by LikeBack
226
 
        if (!(flags & (NO_INIT_VIEW | ALWAYS_HIDE)))
227
 
        {
228
 
                bool readonly = AlarmCalendar::resources()->eventReadOnly(mEventID);
229
 
                mShowEdit = !mEventID.isEmpty()  &&  !readonly;
230
 
                mNoDefer  = readonly || (flags & NO_DEFER) || alarm.repeatAtLogin();
231
 
                initView();
232
 
        }
233
 
        // Set to save settings automatically, but don't save window size.
234
 
        // File alarm window size is saved elsewhere.
235
 
        setAutoSaveSettings(QLatin1String("MessageWin"), false);
236
 
        mWindowList.append(this);
237
 
        if (event->autoClose())
238
 
                mCloseTime = alarm.dateTime().effectiveDateTime().addSecs(event->lateCancel() * 60);
239
 
        if (mAlwaysHide)
240
 
        {
241
 
                hide();
242
 
                displayComplete();    // play audio, etc.
243
 
        }
 
235
    kDebug() << "event";
 
236
    setAttribute(static_cast<Qt::WidgetAttribute>(WidgetFlags));
 
237
    setWindowModality(Qt::WindowModal);
 
238
    setObjectName("MessageWin");    // used by LikeBack
 
239
    if (alarm.type() & KAAlarm::REMINDER_ALARM)
 
240
    {
 
241
        if (event->reminderMinutes() < 0)
 
242
        {
 
243
            event->previousOccurrence(alarm.dateTime(false).effectiveKDateTime(), mDateTime, false);
 
244
            if (!mDateTime.isValid()  &&  event->repeatAtLogin())
 
245
                mDateTime = alarm.dateTime().addSecs(event->reminderMinutes() * 60);
 
246
        }
 
247
        else
 
248
            mDateTime = event->mainDateTime(true);
 
249
    }
 
250
    else
 
251
        mDateTime = alarm.dateTime(true);
 
252
    if (!(flags & (NO_INIT_VIEW | ALWAYS_HIDE)))
 
253
    {
 
254
#ifdef USE_AKONADI
 
255
        bool readonly = AlarmCalendar::resources()->eventReadOnly(mEventItemId);
 
256
#else
 
257
        bool readonly = AlarmCalendar::resources()->eventReadOnly(mEventID);
 
258
#endif
 
259
        mShowEdit = !mEventID.isEmpty()  &&  !readonly;
 
260
        mNoDefer  = readonly || (flags & NO_DEFER) || alarm.repeatAtLogin();
 
261
        initView();
 
262
    }
 
263
    // Set to save settings automatically, but don't save window size.
 
264
    // File alarm window size is saved elsewhere.
 
265
    setAutoSaveSettings(QLatin1String("MessageWin"), false);
 
266
    mWindowList.append(this);
 
267
    if (event->autoClose())
 
268
        mCloseTime = alarm.dateTime().effectiveDateTime().addSecs(event->lateCancel() * 60);
 
269
    if (mAlwaysHide)
 
270
    {
 
271
        hide();
 
272
        displayComplete();    // play audio, etc.
 
273
    }
244
274
}
245
275
 
246
276
/******************************************************************************
251
281
void MessageWin::showError(const KAEvent& event, const DateTime& alarmDateTime,
252
282
                           const QStringList& errmsgs, const QString& dontShowAgain)
253
283
{
254
 
        if (!dontShowAgain.isEmpty()
255
 
        &&  KAlarm::dontShowErrors(event.id(), dontShowAgain))
256
 
                return;
257
 
 
258
 
        // Don't pile up duplicate error messages for the same alarm
259
 
        for (int i = 0, end = mWindowList.count();  i < end;  ++i)
260
 
        {
261
 
                MessageWin* w = mWindowList[i];
262
 
                if (w->mErrorWindow  &&  w->mEventID == event.id()
263
 
                &&  w->mErrorMsgs == errmsgs  &&  w->mDontShowAgain == dontShowAgain)
264
 
                        return;
265
 
        }
266
 
 
267
 
        (new MessageWin(&event, alarmDateTime, errmsgs, dontShowAgain))->show();
 
284
    if (!dontShowAgain.isEmpty()
 
285
    &&  KAlarm::dontShowErrors(event.id(), dontShowAgain))
 
286
        return;
 
287
 
 
288
    // Don't pile up duplicate error messages for the same alarm
 
289
    for (int i = 0, end = mWindowList.count();  i < end;  ++i)
 
290
    {
 
291
        MessageWin* w = mWindowList[i];
 
292
        if (w->mErrorWindow  &&  w->mEventID == event.id()
 
293
        &&  w->mErrorMsgs == errmsgs  &&  w->mDontShowAgain == dontShowAgain)
 
294
            return;
 
295
    }
 
296
 
 
297
    (new MessageWin(&event, alarmDateTime, errmsgs, dontShowAgain))->show();
268
298
}
269
299
 
270
300
/******************************************************************************
274
304
*/
275
305
MessageWin::MessageWin(const KAEvent* event, const DateTime& alarmDateTime,
276
306
                       const QStringList& errmsgs, const QString& dontShowAgain)
277
 
        : MainWindowBase(0, WFLAGS | WFLAGS2),
278
 
          mMessage(event->cleanText()),
279
 
          mDateTime(alarmDateTime),
280
 
          mEventID(event->id()),
281
 
          mAlarmType(KAAlarm::MAIN_ALARM),
282
 
          mAction(event->action()),
283
 
          mKMailSerialNumber(0),
284
 
          mCommandError(KAEvent::CMD_NO_ERROR),
285
 
          mErrorMsgs(errmsgs),
286
 
          mDontShowAgain(dontShowAgain),
287
 
          mRestoreHeight(0),
288
 
          mConfirmAck(false),
289
 
          mShowEdit(false),
290
 
          mNoDefer(true),
291
 
          mInvalid(false),
292
 
          mEvent(*event),
293
 
          mResource(0),
294
 
          mTimeLabel(0),
295
 
          mRemainingText(0),
296
 
          mEditButton(0),
297
 
          mDeferButton(0),
298
 
          mSilenceButton(0),
299
 
          mKMailButton(0),
300
 
          mCommandText(0),
301
 
          mDontShowAgainCheck(0),
302
 
          mEditDlg(0),
303
 
          mDeferDlg(0),
304
 
          mAlwaysHide(false),
305
 
          mErrorWindow(true),
306
 
          mInitialised(false),
307
 
          mNoPostAction(true),
308
 
          mRecreating(false),
309
 
          mRescheduleEvent(false),
310
 
          mShown(false),
311
 
          mPositioning(false),
312
 
          mNoCloseConfirm(false),
313
 
          mDisableDeferral(false)
 
307
    : MainWindowBase(0, WFLAGS | WFLAGS2),
 
308
      mMessage(event->cleanText()),
 
309
      mDateTime(alarmDateTime),
 
310
#ifdef USE_AKONADI
 
311
      mEventItemId(event->itemId()),
 
312
#endif
 
313
      mEventID(event->id()),
 
314
      mAlarmType(KAAlarm::MAIN_ALARM),
 
315
      mAction(event->action()),
 
316
      mKMailSerialNumber(0),
 
317
      mCommandError(KAEvent::CMD_NO_ERROR),
 
318
      mErrorMsgs(errmsgs),
 
319
      mDontShowAgain(dontShowAgain),
 
320
      mRestoreHeight(0),
 
321
      mConfirmAck(false),
 
322
      mShowEdit(false),
 
323
      mNoDefer(true),
 
324
      mInvalid(false),
 
325
      mEvent(*event),
 
326
#ifndef USE_AKONADI
 
327
      mResource(0),
 
328
#endif
 
329
      mTimeLabel(0),
 
330
      mRemainingText(0),
 
331
      mEditButton(0),
 
332
      mDeferButton(0),
 
333
      mSilenceButton(0),
 
334
      mKMailButton(0),
 
335
      mCommandText(0),
 
336
      mDontShowAgainCheck(0),
 
337
      mEditDlg(0),
 
338
      mDeferDlg(0),
 
339
      mAlwaysHide(false),
 
340
      mErrorWindow(true),
 
341
      mInitialised(false),
 
342
      mNoPostAction(true),
 
343
      mRecreating(false),
 
344
      mRescheduleEvent(false),
 
345
      mShown(false),
 
346
      mPositioning(false),
 
347
      mNoCloseConfirm(false),
 
348
      mDisableDeferral(false)
314
349
{
315
 
        kDebug() << "errmsg";
316
 
        setAttribute(static_cast<Qt::WidgetAttribute>(WidgetFlags));
317
 
        setWindowModality(Qt::WindowModal);
318
 
        setObjectName("ErrorWin");    // used by LikeBack
319
 
        getWorkAreaAndModal();
320
 
        initView();
321
 
        mWindowList.append(this);
 
350
    kDebug() << "errmsg";
 
351
    setAttribute(static_cast<Qt::WidgetAttribute>(WidgetFlags));
 
352
    setWindowModality(Qt::WindowModal);
 
353
    setObjectName("ErrorWin");    // used by LikeBack
 
354
    getWorkAreaAndModal();
 
355
    initView();
 
356
    mWindowList.append(this);
322
357
}
323
358
 
324
359
/******************************************************************************
326
361
*  The window is initialised by readProperties().
327
362
*/
328
363
MessageWin::MessageWin()
329
 
        : MainWindowBase(0, WFLAGS),
330
 
          mTimeLabel(0),
331
 
          mRemainingText(0),
332
 
          mEditButton(0),
333
 
          mDeferButton(0),
334
 
          mSilenceButton(0),
335
 
          mKMailButton(0),
336
 
          mCommandText(0),
337
 
          mDontShowAgainCheck(0),
338
 
          mEditDlg(0),
339
 
          mDeferDlg(0),
340
 
          mAlwaysHide(false),
341
 
          mErrorWindow(false),
342
 
          mInitialised(false),
343
 
          mRecreating(false),
344
 
          mRescheduleEvent(false),
345
 
          mShown(false),
346
 
          mPositioning(false),
347
 
          mNoCloseConfirm(false),
348
 
          mDisableDeferral(false)
 
364
    : MainWindowBase(0, WFLAGS),
 
365
      mTimeLabel(0),
 
366
      mRemainingText(0),
 
367
      mEditButton(0),
 
368
      mDeferButton(0),
 
369
      mSilenceButton(0),
 
370
      mKMailButton(0),
 
371
      mCommandText(0),
 
372
      mDontShowAgainCheck(0),
 
373
      mEditDlg(0),
 
374
      mDeferDlg(0),
 
375
      mAlwaysHide(false),
 
376
      mErrorWindow(false),
 
377
      mInitialised(false),
 
378
      mRecreating(false),
 
379
      mRescheduleEvent(false),
 
380
      mShown(false),
 
381
      mPositioning(false),
 
382
      mNoCloseConfirm(false),
 
383
      mDisableDeferral(false)
349
384
{
350
 
        kDebug() << "restore";
351
 
        setAttribute(WidgetFlags);
352
 
        setWindowModality(Qt::WindowModal);
353
 
        setObjectName("RestoredMsgWin");    // used by LikeBack
354
 
        getWorkAreaAndModal();
355
 
        mWindowList.append(this);
 
385
    kDebug() << "restore";
 
386
    setAttribute(WidgetFlags);
 
387
    setWindowModality(Qt::WindowModal);
 
388
    setObjectName("RestoredMsgWin");    // used by LikeBack
 
389
    getWorkAreaAndModal();
 
390
    mWindowList.append(this);
356
391
}
357
392
 
358
393
/******************************************************************************
360
395
*/
361
396
MessageWin::~MessageWin()
362
397
{
363
 
        kDebug() << mEventID;
364
 
        if (mAudioOwner == this  &&  mAudioThread)
365
 
                mAudioThread->quit();
366
 
        mErrorMessages.remove(mEventID);
367
 
        mWindowList.removeAll(this);
368
 
        if (!mRecreating)
369
 
        {
370
 
                if (!mNoPostAction  &&  !mEvent.postAction().isEmpty())
371
 
                        theApp()->alarmCompleted(mEvent);
372
 
                if (!mWindowList.count())
373
 
                        theApp()->quitIf();
374
 
        }
 
398
    kDebug() << mEventID;
 
399
    if (mAudioOwner == this  &&  mAudioThread)
 
400
        mAudioThread->quit();
 
401
    mErrorMessages.remove(mEventID);
 
402
    mWindowList.removeAll(this);
 
403
    if (!mRecreating)
 
404
    {
 
405
        if (!mNoPostAction  &&  !mEvent.postAction().isEmpty())
 
406
            theApp()->alarmCompleted(mEvent);
 
407
        if (!mWindowList.count())
 
408
            theApp()->quitIf();
 
409
    }
375
410
}
376
411
 
377
412
/******************************************************************************
379
414
*/
380
415
void MessageWin::initView()
381
416
{
382
 
        bool reminder = (!mErrorWindow  &&  (mAlarmType & KAAlarm::REMINDER_ALARM));
383
 
        int leading = fontMetrics().leading();
384
 
        setCaption((mAlarmType & KAAlarm::REMINDER_ALARM) ? i18nc("@title:window", "Reminder") : i18nc("@title:window", "Message"));
385
 
        QWidget* topWidget = new QWidget(this);
386
 
        setCentralWidget(topWidget);
387
 
        QVBoxLayout* topLayout = new QVBoxLayout(topWidget);
388
 
        topLayout->setMargin(KDialog::marginHint());
389
 
        topLayout->setSpacing(KDialog::spacingHint());
390
 
 
391
 
        QPalette labelPalette = palette();
392
 
        labelPalette.setColor(backgroundRole(), labelPalette.color(QPalette::Window));
393
 
 
394
 
        // Show the alarm date/time, together with an advance reminder text where appropriate
395
 
        // Alarm date/time: display time zone if not local time zone.
396
 
        mTimeLabel = new QLabel(topWidget);
397
 
        mTimeLabel->setText(dateTimeToDisplay());
398
 
        mTimeLabel->setFrameStyle(QFrame::Box | QFrame::Raised);
399
 
        mTimeLabel->setPalette(labelPalette);
400
 
        mTimeLabel->setAutoFillBackground(true);
401
 
        topLayout->addWidget(mTimeLabel, 0, Qt::AlignHCenter);
402
 
        mTimeLabel->setWhatsThis(i18nc("@info:whatsthis", "The scheduled date/time for the message (as opposed to the actual time of display)."));
403
 
 
404
 
        if (mDateTime.isValid())
405
 
        {
406
 
                // Reminder
407
 
                if (reminder)
408
 
                {
409
 
                        QString s = i18nc("@info", "Reminder");
410
 
                        QRegExp re("^(<[^>]+>)*");
411
 
                        re.indexIn(s);
412
 
                        s.insert(re.matchedLength(), mTimeLabel->text() + "<br/>");
413
 
                        mTimeLabel->setText(s);
414
 
                        mTimeLabel->setAlignment(Qt::AlignHCenter);
415
 
                }
416
 
        }
417
 
        else
418
 
                mTimeLabel->hide();
419
 
 
420
 
        if (!mErrorWindow)
421
 
        {
422
 
                // It's a normal alarm message window
423
 
                switch (mAction)
424
 
                {
425
 
                        case KAEventData::FILE:
426
 
                        {
427
 
                                // Display the file name
428
 
                                KSqueezedTextLabel* label = new KSqueezedTextLabel(mMessage, topWidget);
429
 
                                label->setFrameStyle(QFrame::Box | QFrame::Raised);
430
 
                                label->setTextInteractionFlags(Qt::TextSelectableByMouse | Qt::TextSelectableByKeyboard);
431
 
                                label->setPalette(labelPalette);
432
 
                                label->setAutoFillBackground(true);
433
 
                                label->setWhatsThis(i18nc("@info:whatsthis", "The file whose contents are displayed below"));
434
 
                                topLayout->addWidget(label, 0, Qt::AlignHCenter);
435
 
 
436
 
                                // Display contents of file
437
 
                                bool opened = false;
438
 
                                bool dir = false;
439
 
                                QString tmpFile;
440
 
                                KUrl url(mMessage);
441
 
                                if (KIO::NetAccess::download(url, tmpFile, MainWindow::mainMainWindow()))
442
 
                                {
443
 
                                        QFile qfile(tmpFile);
444
 
                                        QFileInfo info(qfile);
445
 
                                        if (!(dir = info.isDir()))
446
 
                                        {
447
 
                                                opened = true;
448
 
                                                KTextBrowser* view = new KTextBrowser(topWidget);
449
 
                                                view->setFrameStyle(QFrame::NoFrame);
450
 
                                                view->setWordWrapMode(QTextOption::NoWrap);
451
 
                                                QPalette pal = view->viewport()->palette();
452
 
                                                pal.setColor(view->viewport()->backgroundRole(), mBgColour);
453
 
                                                view->viewport()->setPalette(pal);
454
 
                                                view->setTextColor(mFgColour);
455
 
                                                view->setCurrentFont(mFont);
456
 
                                                KMimeType::Ptr mime = KMimeType::findByUrl(url);
457
 
                                                if (mime->is("application/octet-stream"))
458
 
                                                        mime = KMimeType::findByFileContent(tmpFile);
459
 
                                                switch (KAlarm::fileType(mime))
460
 
                                                {
461
 
                                                        case KAlarm::Image:
462
 
                                                                view->setHtml("<img source=\"" + tmpFile + "\">");
463
 
                                                                break;
464
 
                                                        case KAlarm::TextFormatted:
465
 
                                                                view->QTextBrowser::setSource(tmpFile);   //krazy:exclude=qclasses
466
 
                                                                break;
467
 
                                                        default:
468
 
                                                        {
469
 
                                                                // Assume a plain text file
470
 
                                                                if (qfile.open(QIODevice::ReadOnly))
471
 
                                                                {
472
 
                                                                        QTextStream str(&qfile);
473
 
 
474
 
                                                                        view->setPlainText(str.readAll());
475
 
                                                                        qfile.close();
476
 
                                                                }
477
 
                                                                break;
478
 
                                                        }
479
 
                                                }
480
 
                                                view->setMinimumSize(view->sizeHint());
481
 
                                                topLayout->addWidget(view);
482
 
 
483
 
                                                // Set the default size to 20 lines square.
484
 
                                                // Note that after the first file has been displayed, this size
485
 
                                                // is overridden by the user-set default stored in the config file.
486
 
                                                // So there is no need to calculate an accurate size.
487
 
                                                int h = 20*view->fontMetrics().lineSpacing() + 2*view->frameWidth();
488
 
                                                view->resize(QSize(h, h).expandedTo(view->sizeHint()));
489
 
                                                view->setWhatsThis(i18nc("@info:whatsthis", "The contents of the file to be displayed"));
490
 
                                        }
491
 
                                        KIO::NetAccess::removeTempFile(tmpFile);
492
 
                                }
493
 
                                if (!opened)
494
 
                                {
495
 
                                        // File couldn't be opened
496
 
                                        bool exists = KIO::NetAccess::exists(url, KIO::NetAccess::SourceSide, MainWindow::mainMainWindow());
497
 
                                        mErrorMsgs += dir ? i18nc("@info", "File is a folder") : exists ? i18nc("@info", "Failed to open file") : i18nc("@info", "File not found");
498
 
                                }
499
 
                                break;
500
 
                        }
501
 
                        case KAEventData::MESSAGE:
502
 
                        {
503
 
                                // Message label
504
 
                                // Using MessageText instead of QLabel allows scrolling and mouse copying
505
 
                                MessageText* text = new MessageText(topWidget);
506
 
                                text->setAutoFillBackground(true);
507
 
                                text->setBackgroundColour(mBgColour);
508
 
                                text->setTextColor(mFgColour);
509
 
                                text->setCurrentFont(mFont);
510
 
                                text->insertPlainText(mMessage);
511
 
                                int lineSpacing = text->fontMetrics().lineSpacing();
512
 
                                QSize s = text->sizeHint();
513
 
                                int h = s.height();
514
 
                                text->setMaximumHeight(h + text->scrollBarHeight());
515
 
                                text->setMinimumHeight(qMin(h, lineSpacing*4));
516
 
                                text->setMaximumWidth(s.width() + text->scrollBarWidth());
517
 
                                text->setWhatsThis(i18nc("@info:whatsthis", "The alarm message"));
518
 
                                int vspace = lineSpacing/2;
519
 
                                int hspace = lineSpacing - KDialog::marginHint();
520
 
                                topLayout->addSpacing(vspace);
521
 
                                topLayout->addStretch();
522
 
                                // Don't include any horizontal margins if message is 2/3 screen width
523
 
                                if (text->sizeHint().width() >= KAlarm::desktopWorkArea(mScreenNumber).width()*2/3)
524
 
                                        topLayout->addWidget(text, 1, Qt::AlignHCenter);
525
 
                                else
526
 
                                {
527
 
                                        QHBoxLayout* layout = new QHBoxLayout();
528
 
                                        layout->addSpacing(hspace);
529
 
                                        layout->addWidget(text, 1, Qt::AlignHCenter);
530
 
                                        layout->addSpacing(hspace);
531
 
                                        topLayout->addLayout(layout);
532
 
                                }
533
 
                                if (!reminder)
534
 
                                        topLayout->addStretch();
535
 
                                break;
536
 
                        }
537
 
                        case KAEventData::COMMAND:
538
 
                        {
539
 
                                mCommandText = new MessageText(topWidget);
540
 
                                mCommandText->setBackgroundColour(mBgColour);
541
 
                                mCommandText->setTextColor(mFgColour);
542
 
                                mCommandText->setCurrentFont(mFont);
543
 
                                topLayout->addWidget(mCommandText);
544
 
                                mCommandText->setWhatsThis(i18nc("@info:whatsthis", "The output of the alarm's command"));
545
 
                                theApp()->execCommandAlarm(mEvent, mEvent.alarm(mAlarmType), this, SLOT(readProcessOutput(ShellProcess*)));
546
 
                                break;
547
 
                        }
548
 
                        case KAEventData::EMAIL:
549
 
                        default:
550
 
                                break;
551
 
                }
552
 
 
553
 
                if (reminder)
554
 
                {
555
 
                        // Reminder: show remaining time until the actual alarm
556
 
                        mRemainingText = new QLabel(topWidget);
557
 
                        mRemainingText->setFrameStyle(QFrame::Box | QFrame::Raised);
558
 
                        mRemainingText->setMargin(leading);
559
 
                        mRemainingText->setPalette(labelPalette);
560
 
                        mRemainingText->setAutoFillBackground(true);
561
 
                        if (mDateTime.isDateOnly()  ||  KDateTime::currentLocalDate().daysTo(mDateTime.date()) > 0)
562
 
                        {
563
 
                                setRemainingTextDay();
564
 
                                MidnightTimer::connect(this, SLOT(setRemainingTextDay()));    // update every day
565
 
                        }
566
 
                        else
567
 
                        {
568
 
                                setRemainingTextMinute();
569
 
                                MinuteTimer::connect(this, SLOT(setRemainingTextMinute()));   // update every minute
570
 
                        }
571
 
                        topLayout->addWidget(mRemainingText, 0, Qt::AlignHCenter);
572
 
                        topLayout->addSpacing(KDialog::spacingHint());
573
 
                        topLayout->addStretch();
574
 
                }
575
 
        }
576
 
        else
577
 
        {
578
 
                // It's an error message
579
 
                switch (mAction)
580
 
                {
581
 
                        case KAEventData::EMAIL:
582
 
                        {
583
 
                                // Display the email addresses and subject.
584
 
                                QFrame* frame = new QFrame(topWidget);
585
 
                                frame->setFrameStyle(QFrame::Box | QFrame::Raised);
586
 
                                frame->setWhatsThis(i18nc("@info:whatsthis", "The email to send"));
587
 
                                topLayout->addWidget(frame, 0, Qt::AlignHCenter);
588
 
                                QGridLayout* grid = new QGridLayout(frame);
589
 
                                grid->setMargin(KDialog::marginHint());
590
 
                                grid->setSpacing(KDialog::spacingHint());
591
 
 
592
 
                                QLabel* label = new QLabel(i18nc("@info Email addressee", "To:"), frame);
593
 
                                label->setFixedSize(label->sizeHint());
594
 
                                grid->addWidget(label, 0, 0, Qt::AlignLeft);
595
 
                                label = new QLabel(mEvent.emailAddresses("\n"), frame);
596
 
                                label->setFixedSize(label->sizeHint());
597
 
                                grid->addWidget(label, 0, 1, Qt::AlignLeft);
598
 
 
599
 
                                label = new QLabel(i18nc("@info Email subject", "Subject:"), frame);
600
 
                                label->setFixedSize(label->sizeHint());
601
 
                                grid->addWidget(label, 1, 0, Qt::AlignLeft);
602
 
                                label = new QLabel(mEvent.emailSubject(), frame);
603
 
                                label->setFixedSize(label->sizeHint());
604
 
                                grid->addWidget(label, 1, 1, Qt::AlignLeft);
605
 
                                break;
606
 
                        }
607
 
                        case KAEventData::COMMAND:
608
 
                        case KAEventData::FILE:
609
 
                        case KAEventData::MESSAGE:
610
 
                        default:
611
 
                                // Just display the error message strings
612
 
                                break;
613
 
                }
614
 
        }
615
 
 
616
 
        if (!mErrorMsgs.count())
617
 
        {
618
 
                topWidget->setAutoFillBackground(true);
619
 
                QPalette palette = topWidget->palette();
620
 
                palette.setColor(topWidget->backgroundRole(), mBgColour);
621
 
                topWidget->setPalette(palette);
622
 
        }
623
 
        else
624
 
        {
625
 
                setCaption(i18nc("@title:window", "Error"));
626
 
                QHBoxLayout* layout = new QHBoxLayout();
627
 
                layout->setMargin(2*KDialog::marginHint());
628
 
                layout->addStretch();
629
 
                topLayout->addLayout(layout);
630
 
                QLabel* label = new QLabel(topWidget);
631
 
                label->setPixmap(DesktopIcon("dialog-error"));
632
 
                label->setFixedSize(label->sizeHint());
633
 
                layout->addWidget(label, 0, Qt::AlignRight);
634
 
                QVBoxLayout* vlayout = new QVBoxLayout();
635
 
                layout->addLayout(vlayout);
636
 
                for (QStringList::Iterator it = mErrorMsgs.begin();  it != mErrorMsgs.end();  ++it)
637
 
                {
638
 
                        label = new QLabel(*it, topWidget);
639
 
                        label->setFixedSize(label->sizeHint());
640
 
                        vlayout->addWidget(label, 0, Qt::AlignLeft);
641
 
                }
642
 
                layout->addStretch();
643
 
                if (!mDontShowAgain.isEmpty())
644
 
                {
645
 
                        mDontShowAgainCheck = new QCheckBox(i18nc("@option:check", "Do not display this error message again for this alarm"), topWidget);
646
 
                        mDontShowAgainCheck->setFixedSize(mDontShowAgainCheck->sizeHint());
647
 
                        topLayout->addWidget(mDontShowAgainCheck, 0, Qt::AlignLeft);
648
 
                }
649
 
        }
650
 
 
651
 
        QGridLayout* grid = new QGridLayout();
652
 
        grid->setColumnStretch(0, 1);     // keep the buttons right-adjusted in the window
653
 
        topLayout->addLayout(grid);
654
 
        int gridIndex = 1;
655
 
 
656
 
        // Close button
657
 
        mOkButton = new PushButton(KStandardGuiItem::close(), topWidget);
658
 
        // Prevent accidental acknowledgement of the message if the user is typing when the window appears
659
 
        mOkButton->clearFocus();
660
 
        mOkButton->setFocusPolicy(Qt::ClickFocus);    // don't allow keyboard selection
661
 
        mOkButton->setFixedSize(mOkButton->sizeHint());
662
 
        connect(mOkButton, SIGNAL(clicked()), SLOT(slotOk()));
663
 
        grid->addWidget(mOkButton, 0, gridIndex++, Qt::AlignHCenter);
664
 
        mOkButton->setWhatsThis(i18nc("@info:whatsthis", "Acknowledge the alarm"));
665
 
 
666
 
        if (mShowEdit)
667
 
        {
668
 
                // Edit button
669
 
                mEditButton = new PushButton(i18nc("@action:button", "&Edit..."), topWidget);
670
 
                mEditButton->setFocusPolicy(Qt::ClickFocus);    // don't allow keyboard selection
671
 
                mEditButton->setFixedSize(mEditButton->sizeHint());
672
 
                connect(mEditButton, SIGNAL(clicked()), SLOT(slotEdit()));
673
 
                grid->addWidget(mEditButton, 0, gridIndex++, Qt::AlignHCenter);
674
 
                mEditButton->setWhatsThis(i18nc("@info:whatsthis", "Edit the alarm."));
675
 
        }
676
 
 
677
 
        // Defer button
678
 
        mDeferButton = new PushButton(i18nc("@action:button", "&Defer..."), topWidget);
679
 
        mDeferButton->setFocusPolicy(Qt::ClickFocus);    // don't allow keyboard selection
680
 
        mDeferButton->setFixedSize(mDeferButton->sizeHint());
681
 
        connect(mDeferButton, SIGNAL(clicked()), SLOT(slotDefer()));
682
 
        grid->addWidget(mDeferButton, 0, gridIndex++, Qt::AlignHCenter);
683
 
        mDeferButton->setWhatsThis(i18nc("@info:whatsthis", "<para>Defer the alarm until later.</para>"
684
 
                                        "<para>You will be prompted to specify when the alarm should be redisplayed.</para>"));
685
 
 
686
 
        if (mNoDefer)
687
 
                mDeferButton->hide();
688
 
        else
689
 
                setDeferralLimit(mEvent);    // ensure that button is disabled when alarm can't be deferred any more
690
 
 
691
 
        if (!mAudioFile.isEmpty()  &&  (mVolume || mFadeVolume > 0))
692
 
        {
693
 
                // Silence button to stop sound repetition
694
 
                QPixmap pixmap = MainBarIcon("media-playback-stop");
695
 
                mSilenceButton = new PushButton(topWidget);
696
 
                mSilenceButton->setIcon(KIcon(pixmap));
697
 
                grid->addWidget(mSilenceButton, 0, gridIndex++, Qt::AlignHCenter);
698
 
                mSilenceButton->setToolTip(i18nc("@info:tooltip", "Stop sound"));
699
 
                mSilenceButton->setWhatsThis(i18nc("@info:whatsthis", "Stop playing the sound"));
700
 
                // To avoid getting in a mess, disable the button until sound playing has been set up
701
 
                mSilenceButton->setEnabled(false);
702
 
        }
703
 
 
704
 
        KIconLoader iconLoader;
705
 
        if (mKMailSerialNumber)
706
 
        {
707
 
                // KMail button
708
 
                QPixmap pixmap = iconLoader.loadIcon(QLatin1String("internet-mail"), KIconLoader::MainToolbar);
709
 
                mKMailButton = new PushButton(topWidget);
710
 
                mKMailButton->setIcon(KIcon(pixmap));
711
 
                connect(mKMailButton, SIGNAL(clicked()), SLOT(slotShowKMailMessage()));
712
 
                grid->addWidget(mKMailButton, 0, gridIndex++, Qt::AlignHCenter);
713
 
                mKMailButton->setToolTip(i18nc("@info:tooltip Locate this email in KMail", "Locate in <application>KMail</application>"));
714
 
                mKMailButton->setWhatsThis(i18nc("@info:whatsthis", "Locate and highlight this email in <application>KMail</application>"));
715
 
        }
716
 
 
717
 
        // KAlarm button
718
 
        QPixmap pixmap = iconLoader.loadIcon(KGlobal::mainComponent().aboutData()->appName(), KIconLoader::MainToolbar);
719
 
        mKAlarmButton = new PushButton(topWidget);
720
 
        mKAlarmButton->setIcon(KIcon(pixmap));
721
 
        connect(mKAlarmButton, SIGNAL(clicked()), SLOT(displayMainWindow()));
722
 
        grid->addWidget(mKAlarmButton, 0, gridIndex++, Qt::AlignHCenter);
723
 
        mKAlarmButton->setToolTip(i18nc("@info:tooltip", "Activate <application>KAlarm</application>"));
724
 
        mKAlarmButton->setWhatsThis(i18nc("@info:whatsthis", "Activate <application>KAlarm</application>"));
725
 
 
726
 
        int butsize = mKAlarmButton->sizeHint().height();
727
 
        if (mSilenceButton)
728
 
                butsize = qMax(butsize, mSilenceButton->sizeHint().height());
729
 
        if (mKMailButton)
730
 
                butsize = qMax(butsize, mKMailButton->sizeHint().height());
731
 
        mKAlarmButton->setFixedSize(butsize, butsize);
732
 
        if (mSilenceButton)
733
 
                mSilenceButton->setFixedSize(butsize, butsize);
734
 
        if (mKMailButton)
735
 
                mKMailButton->setFixedSize(butsize, butsize);
736
 
 
737
 
        // Disable all buttons initially, to prevent accidental clicking on if they happen to be
738
 
        // under the mouse just as the window appears.
739
 
        mOkButton->setEnabled(false);
740
 
        if (mDeferButton->isVisible())
741
 
                mDeferButton->setEnabled(false);
742
 
        if (mEditButton)
743
 
                mEditButton->setEnabled(false);
744
 
        if (mKMailButton)
745
 
                mKMailButton->setEnabled(false);
746
 
        mKAlarmButton->setEnabled(false);
747
 
 
748
 
        topLayout->activate();
749
 
        setMinimumSize(QSize(grid->sizeHint().width() + 2*KDialog::marginHint(), sizeHint().height()));
750
 
        bool modal = !(windowFlags() & Qt::X11BypassWindowManagerHint);
751
 
        unsigned long wstate = (modal ? NET::Modal : 0) | NET::Sticky | NET::StaysOnTop;
752
 
        WId winid = winId();
753
 
        KWindowSystem::setState(winid, wstate);
754
 
        KWindowSystem::setOnAllDesktops(winid, true);
755
 
 
756
 
        mInitialised = true;   // the window's widgets have been created
 
417
    bool reminder = (!mErrorWindow  &&  (mAlarmType & KAAlarm::REMINDER_ALARM));
 
418
    int leading = fontMetrics().leading();
 
419
    setCaption((mAlarmType & KAAlarm::REMINDER_ALARM) ? i18nc("@title:window", "Reminder") : i18nc("@title:window", "Message"));
 
420
    QWidget* topWidget = new QWidget(this);
 
421
    setCentralWidget(topWidget);
 
422
    QVBoxLayout* topLayout = new QVBoxLayout(topWidget);
 
423
    topLayout->setMargin(KDialog::marginHint());
 
424
    topLayout->setSpacing(KDialog::spacingHint());
 
425
 
 
426
    QPalette labelPalette = palette();
 
427
    labelPalette.setColor(backgroundRole(), labelPalette.color(QPalette::Window));
 
428
 
 
429
    // Show the alarm date/time, together with a reminder text where appropriate.
 
430
    // Alarm date/time: display time zone if not local time zone.
 
431
    mTimeLabel = new QLabel(topWidget);
 
432
    mTimeLabel->setText(dateTimeToDisplay());
 
433
    mTimeLabel->setFrameStyle(QFrame::StyledPanel);
 
434
    mTimeLabel->setPalette(labelPalette);
 
435
    mTimeLabel->setAutoFillBackground(true);
 
436
    topLayout->addWidget(mTimeLabel, 0, Qt::AlignHCenter);
 
437
    mTimeLabel->setWhatsThis(i18nc("@info:whatsthis", "The scheduled date/time for the message (as opposed to the actual time of display)."));
 
438
 
 
439
    if (mDateTime.isValid())
 
440
    {
 
441
        // Reminder
 
442
        if (reminder)
 
443
        {
 
444
            QString s = i18nc("@info", "Reminder");
 
445
            QRegExp re("^(<[^>]+>)*");
 
446
            re.indexIn(s);
 
447
            s.insert(re.matchedLength(), mTimeLabel->text() + "<br/>");
 
448
            mTimeLabel->setText(s);
 
449
            mTimeLabel->setAlignment(Qt::AlignHCenter);
 
450
        }
 
451
    }
 
452
    else
 
453
        mTimeLabel->hide();
 
454
 
 
455
    if (!mErrorWindow)
 
456
    {
 
457
        // It's a normal alarm message window
 
458
        switch (mAction)
 
459
        {
 
460
            case KAEvent::FILE:
 
461
            {
 
462
                // Display the file name
 
463
                KSqueezedTextLabel* label = new KSqueezedTextLabel(mMessage, topWidget);
 
464
                label->setFrameStyle(QFrame::StyledPanel);
 
465
                label->setTextInteractionFlags(Qt::TextSelectableByMouse | Qt::TextSelectableByKeyboard);
 
466
                label->setPalette(labelPalette);
 
467
                label->setAutoFillBackground(true);
 
468
                label->setWhatsThis(i18nc("@info:whatsthis", "The file whose contents are displayed below"));
 
469
                topLayout->addWidget(label, 0, Qt::AlignHCenter);
 
470
 
 
471
                // Display contents of file
 
472
                bool opened = false;
 
473
                bool dir = false;
 
474
                QString tmpFile;
 
475
                KUrl url(mMessage);
 
476
                if (KIO::NetAccess::download(url, tmpFile, MainWindow::mainMainWindow()))
 
477
                {
 
478
                    QFile qfile(tmpFile);
 
479
                    QFileInfo info(qfile);
 
480
                    if (!(dir = info.isDir()))
 
481
                    {
 
482
                        opened = true;
 
483
                        KTextBrowser* view = new KTextBrowser(topWidget);
 
484
                        view->setFrameStyle(QFrame::NoFrame);
 
485
                        view->setWordWrapMode(QTextOption::NoWrap);
 
486
                        QPalette pal = view->viewport()->palette();
 
487
                        pal.setColor(view->viewport()->backgroundRole(), mBgColour);
 
488
                        view->viewport()->setPalette(pal);
 
489
                        view->setTextColor(mFgColour);
 
490
                        view->setCurrentFont(mFont);
 
491
                        KMimeType::Ptr mime = KMimeType::findByUrl(url);
 
492
                        if (mime->is("application/octet-stream"))
 
493
                            mime = KMimeType::findByFileContent(tmpFile);
 
494
                        switch (KAlarm::fileType(mime))
 
495
                        {
 
496
                            case KAlarm::Image:
 
497
                                view->setHtml("<img source=\"" + tmpFile + "\">");
 
498
                                break;
 
499
                            case KAlarm::TextFormatted:
 
500
                                view->QTextBrowser::setSource(tmpFile);   //krazy:exclude=qclasses
 
501
                                break;
 
502
                            default:
 
503
                            {
 
504
                                // Assume a plain text file
 
505
                                if (qfile.open(QIODevice::ReadOnly))
 
506
                                {
 
507
                                    QTextStream str(&qfile);
 
508
 
 
509
                                    view->setPlainText(str.readAll());
 
510
                                    qfile.close();
 
511
                                }
 
512
                                break;
 
513
                            }
 
514
                        }
 
515
                        view->setMinimumSize(view->sizeHint());
 
516
                        topLayout->addWidget(view);
 
517
 
 
518
                        // Set the default size to 20 lines square.
 
519
                        // Note that after the first file has been displayed, this size
 
520
                        // is overridden by the user-set default stored in the config file.
 
521
                        // So there is no need to calculate an accurate size.
 
522
                        int h = 20*view->fontMetrics().lineSpacing() + 2*view->frameWidth();
 
523
                        view->resize(QSize(h, h).expandedTo(view->sizeHint()));
 
524
                        view->setWhatsThis(i18nc("@info:whatsthis", "The contents of the file to be displayed"));
 
525
                    }
 
526
                    KIO::NetAccess::removeTempFile(tmpFile);
 
527
                }
 
528
                if (!opened)
 
529
                {
 
530
                    // File couldn't be opened
 
531
                    bool exists = KIO::NetAccess::exists(url, KIO::NetAccess::SourceSide, MainWindow::mainMainWindow());
 
532
                    mErrorMsgs += dir ? i18nc("@info", "File is a folder") : exists ? i18nc("@info", "Failed to open file") : i18nc("@info", "File not found");
 
533
                }
 
534
                break;
 
535
            }
 
536
            case KAEvent::MESSAGE:
 
537
            {
 
538
                // Message label
 
539
                // Using MessageText instead of QLabel allows scrolling and mouse copying
 
540
                MessageText* text = new MessageText(topWidget);
 
541
                text->setAutoFillBackground(true);
 
542
                text->setBackgroundColour(mBgColour);
 
543
                text->setTextColor(mFgColour);
 
544
                text->setCurrentFont(mFont);
 
545
                text->insertPlainText(mMessage);
 
546
                int lineSpacing = text->fontMetrics().lineSpacing();
 
547
                QSize s = text->sizeHint();
 
548
                int h = s.height();
 
549
                text->setMaximumHeight(h + text->scrollBarHeight());
 
550
                text->setMinimumHeight(qMin(h, lineSpacing*4));
 
551
                text->setMaximumWidth(s.width() + text->scrollBarWidth());
 
552
                text->setWhatsThis(i18nc("@info:whatsthis", "The alarm message"));
 
553
                int vspace = lineSpacing/2;
 
554
                int hspace = lineSpacing - KDialog::marginHint();
 
555
                topLayout->addSpacing(vspace);
 
556
                topLayout->addStretch();
 
557
                // Don't include any horizontal margins if message is 2/3 screen width
 
558
                if (text->sizeHint().width() >= KAlarm::desktopWorkArea(mScreenNumber).width()*2/3)
 
559
                    topLayout->addWidget(text, 1, Qt::AlignHCenter);
 
560
                else
 
561
                {
 
562
                    QHBoxLayout* layout = new QHBoxLayout();
 
563
                    layout->addSpacing(hspace);
 
564
                    layout->addWidget(text, 1, Qt::AlignHCenter);
 
565
                    layout->addSpacing(hspace);
 
566
                    topLayout->addLayout(layout);
 
567
                }
 
568
                if (!reminder)
 
569
                    topLayout->addStretch();
 
570
                break;
 
571
            }
 
572
            case KAEvent::COMMAND:
 
573
            {
 
574
                mCommandText = new MessageText(topWidget);
 
575
                mCommandText->setBackgroundColour(mBgColour);
 
576
                mCommandText->setTextColor(mFgColour);
 
577
                mCommandText->setCurrentFont(mFont);
 
578
                topLayout->addWidget(mCommandText);
 
579
                mCommandText->setWhatsThis(i18nc("@info:whatsthis", "The output of the alarm's command"));
 
580
                theApp()->execCommandAlarm(mEvent, mEvent.alarm(mAlarmType), this, SLOT(readProcessOutput(ShellProcess*)));
 
581
                break;
 
582
            }
 
583
            case KAEvent::EMAIL:
 
584
            default:
 
585
                break;
 
586
        }
 
587
 
 
588
        if (reminder  &&  mEvent.reminderMinutes() > 0)
 
589
        {
 
590
            // Advance reminder: show remaining time until the actual alarm
 
591
            mRemainingText = new QLabel(topWidget);
 
592
            mRemainingText->setFrameStyle(QFrame::Box | QFrame::Raised);
 
593
            mRemainingText->setMargin(leading);
 
594
            mRemainingText->setPalette(labelPalette);
 
595
            mRemainingText->setAutoFillBackground(true);
 
596
            if (mDateTime.isDateOnly()  ||  KDateTime::currentLocalDate().daysTo(mDateTime.date()) > 0)
 
597
            {
 
598
                setRemainingTextDay();
 
599
                MidnightTimer::connect(this, SLOT(setRemainingTextDay()));    // update every day
 
600
            }
 
601
            else
 
602
            {
 
603
                setRemainingTextMinute();
 
604
                MinuteTimer::connect(this, SLOT(setRemainingTextMinute()));   // update every minute
 
605
            }
 
606
            topLayout->addWidget(mRemainingText, 0, Qt::AlignHCenter);
 
607
            topLayout->addSpacing(KDialog::spacingHint());
 
608
            topLayout->addStretch();
 
609
        }
 
610
    }
 
611
    else
 
612
    {
 
613
        // It's an error message
 
614
        switch (mAction)
 
615
        {
 
616
            case KAEvent::EMAIL:
 
617
            {
 
618
                // Display the email addresses and subject.
 
619
                QFrame* frame = new QFrame(topWidget);
 
620
                frame->setFrameStyle(QFrame::Box | QFrame::Raised);
 
621
                frame->setWhatsThis(i18nc("@info:whatsthis", "The email to send"));
 
622
                topLayout->addWidget(frame, 0, Qt::AlignHCenter);
 
623
                QGridLayout* grid = new QGridLayout(frame);
 
624
                grid->setMargin(KDialog::marginHint());
 
625
                grid->setSpacing(KDialog::spacingHint());
 
626
 
 
627
                QLabel* label = new QLabel(i18nc("@info Email addressee", "To:"), frame);
 
628
                label->setFixedSize(label->sizeHint());
 
629
                grid->addWidget(label, 0, 0, Qt::AlignLeft);
 
630
                label = new QLabel(mEvent.emailAddresses("\n"), frame);
 
631
                label->setFixedSize(label->sizeHint());
 
632
                grid->addWidget(label, 0, 1, Qt::AlignLeft);
 
633
 
 
634
                label = new QLabel(i18nc("@info Email subject", "Subject:"), frame);
 
635
                label->setFixedSize(label->sizeHint());
 
636
                grid->addWidget(label, 1, 0, Qt::AlignLeft);
 
637
                label = new QLabel(mEvent.emailSubject(), frame);
 
638
                label->setFixedSize(label->sizeHint());
 
639
                grid->addWidget(label, 1, 1, Qt::AlignLeft);
 
640
                break;
 
641
            }
 
642
            case KAEvent::COMMAND:
 
643
            case KAEvent::FILE:
 
644
            case KAEvent::MESSAGE:
 
645
            default:
 
646
                // Just display the error message strings
 
647
                break;
 
648
        }
 
649
    }
 
650
 
 
651
    if (!mErrorMsgs.count())
 
652
    {
 
653
        topWidget->setAutoFillBackground(true);
 
654
        QPalette palette = topWidget->palette();
 
655
        palette.setColor(topWidget->backgroundRole(), mBgColour);
 
656
        topWidget->setPalette(palette);
 
657
    }
 
658
    else
 
659
    {
 
660
        setCaption(i18nc("@title:window", "Error"));
 
661
        QHBoxLayout* layout = new QHBoxLayout();
 
662
        layout->setMargin(2*KDialog::marginHint());
 
663
        layout->addStretch();
 
664
        topLayout->addLayout(layout);
 
665
        QLabel* label = new QLabel(topWidget);
 
666
        label->setPixmap(DesktopIcon("dialog-error"));
 
667
        label->setFixedSize(label->sizeHint());
 
668
        layout->addWidget(label, 0, Qt::AlignRight);
 
669
        QVBoxLayout* vlayout = new QVBoxLayout();
 
670
        layout->addLayout(vlayout);
 
671
        for (QStringList::Iterator it = mErrorMsgs.begin();  it != mErrorMsgs.end();  ++it)
 
672
        {
 
673
            label = new QLabel(*it, topWidget);
 
674
            label->setFixedSize(label->sizeHint());
 
675
            vlayout->addWidget(label, 0, Qt::AlignLeft);
 
676
        }
 
677
        layout->addStretch();
 
678
        if (!mDontShowAgain.isEmpty())
 
679
        {
 
680
            mDontShowAgainCheck = new QCheckBox(i18nc("@option:check", "Do not display this error message again for this alarm"), topWidget);
 
681
            mDontShowAgainCheck->setFixedSize(mDontShowAgainCheck->sizeHint());
 
682
            topLayout->addWidget(mDontShowAgainCheck, 0, Qt::AlignLeft);
 
683
        }
 
684
    }
 
685
 
 
686
    QGridLayout* grid = new QGridLayout();
 
687
    grid->setColumnStretch(0, 1);     // keep the buttons right-adjusted in the window
 
688
    topLayout->addLayout(grid);
 
689
    int gridIndex = 1;
 
690
 
 
691
    // Close button
 
692
    mOkButton = new PushButton(KStandardGuiItem::close(), topWidget);
 
693
    // Prevent accidental acknowledgement of the message if the user is typing when the window appears
 
694
    mOkButton->clearFocus();
 
695
    mOkButton->setFocusPolicy(Qt::ClickFocus);    // don't allow keyboard selection
 
696
    mOkButton->setFixedSize(mOkButton->sizeHint());
 
697
    connect(mOkButton, SIGNAL(clicked()), SLOT(slotOk()));
 
698
    grid->addWidget(mOkButton, 0, gridIndex++, Qt::AlignHCenter);
 
699
    mOkButton->setWhatsThis(i18nc("@info:whatsthis", "Acknowledge the alarm"));
 
700
 
 
701
    if (mShowEdit)
 
702
    {
 
703
        // Edit button
 
704
        mEditButton = new PushButton(i18nc("@action:button", "&Edit..."), topWidget);
 
705
        mEditButton->setFocusPolicy(Qt::ClickFocus);    // don't allow keyboard selection
 
706
        mEditButton->setFixedSize(mEditButton->sizeHint());
 
707
        connect(mEditButton, SIGNAL(clicked()), SLOT(slotEdit()));
 
708
        grid->addWidget(mEditButton, 0, gridIndex++, Qt::AlignHCenter);
 
709
        mEditButton->setWhatsThis(i18nc("@info:whatsthis", "Edit the alarm."));
 
710
    }
 
711
 
 
712
    // Defer button
 
713
    mDeferButton = new PushButton(i18nc("@action:button", "&Defer..."), topWidget);
 
714
    mDeferButton->setFocusPolicy(Qt::ClickFocus);    // don't allow keyboard selection
 
715
    mDeferButton->setFixedSize(mDeferButton->sizeHint());
 
716
    connect(mDeferButton, SIGNAL(clicked()), SLOT(slotDefer()));
 
717
    grid->addWidget(mDeferButton, 0, gridIndex++, Qt::AlignHCenter);
 
718
    mDeferButton->setWhatsThis(i18nc("@info:whatsthis", "<para>Defer the alarm until later.</para>"
 
719
                                    "<para>You will be prompted to specify when the alarm should be redisplayed.</para>"));
 
720
 
 
721
    if (mNoDefer)
 
722
        mDeferButton->hide();
 
723
    else
 
724
        setDeferralLimit(mEvent);    // ensure that button is disabled when alarm can't be deferred any more
 
725
 
 
726
    if (!mAudioFile.isEmpty()  &&  (mVolume || mFadeVolume > 0))
 
727
    {
 
728
        // Silence button to stop sound repetition
 
729
        QPixmap pixmap = MainBarIcon("media-playback-stop");
 
730
        mSilenceButton = new PushButton(topWidget);
 
731
        mSilenceButton->setIcon(KIcon(pixmap));
 
732
        grid->addWidget(mSilenceButton, 0, gridIndex++, Qt::AlignHCenter);
 
733
        mSilenceButton->setToolTip(i18nc("@info:tooltip", "Stop sound"));
 
734
        mSilenceButton->setWhatsThis(i18nc("@info:whatsthis", "Stop playing the sound"));
 
735
        // To avoid getting in a mess, disable the button until sound playing has been set up
 
736
        mSilenceButton->setEnabled(false);
 
737
    }
 
738
 
 
739
    KIconLoader iconLoader;
 
740
    if (mKMailSerialNumber)
 
741
    {
 
742
        // KMail button
 
743
        QPixmap pixmap = iconLoader.loadIcon(QLatin1String("internet-mail"), KIconLoader::MainToolbar);
 
744
        mKMailButton = new PushButton(topWidget);
 
745
        mKMailButton->setIcon(KIcon(pixmap));
 
746
        connect(mKMailButton, SIGNAL(clicked()), SLOT(slotShowKMailMessage()));
 
747
        grid->addWidget(mKMailButton, 0, gridIndex++, Qt::AlignHCenter);
 
748
        mKMailButton->setToolTip(i18nc("@info:tooltip Locate this email in KMail", "Locate in <application>KMail</application>"));
 
749
        mKMailButton->setWhatsThis(i18nc("@info:whatsthis", "Locate and highlight this email in <application>KMail</application>"));
 
750
    }
 
751
 
 
752
    // KAlarm button
 
753
    QPixmap pixmap = iconLoader.loadIcon(KGlobal::mainComponent().aboutData()->appName(), KIconLoader::MainToolbar);
 
754
    mKAlarmButton = new PushButton(topWidget);
 
755
    mKAlarmButton->setIcon(KIcon(pixmap));
 
756
    connect(mKAlarmButton, SIGNAL(clicked()), SLOT(displayMainWindow()));
 
757
    grid->addWidget(mKAlarmButton, 0, gridIndex++, Qt::AlignHCenter);
 
758
    mKAlarmButton->setToolTip(i18nc("@info:tooltip", "Activate <application>KAlarm</application>"));
 
759
    mKAlarmButton->setWhatsThis(i18nc("@info:whatsthis", "Activate <application>KAlarm</application>"));
 
760
 
 
761
    int butsize = mKAlarmButton->sizeHint().height();
 
762
    if (mSilenceButton)
 
763
        butsize = qMax(butsize, mSilenceButton->sizeHint().height());
 
764
    if (mKMailButton)
 
765
        butsize = qMax(butsize, mKMailButton->sizeHint().height());
 
766
    mKAlarmButton->setFixedSize(butsize, butsize);
 
767
    if (mSilenceButton)
 
768
        mSilenceButton->setFixedSize(butsize, butsize);
 
769
    if (mKMailButton)
 
770
        mKMailButton->setFixedSize(butsize, butsize);
 
771
 
 
772
    // Disable all buttons initially, to prevent accidental clicking on if they happen to be
 
773
    // under the mouse just as the window appears.
 
774
    mOkButton->setEnabled(false);
 
775
    if (mDeferButton->isVisible())
 
776
        mDeferButton->setEnabled(false);
 
777
    if (mEditButton)
 
778
        mEditButton->setEnabled(false);
 
779
    if (mKMailButton)
 
780
        mKMailButton->setEnabled(false);
 
781
    mKAlarmButton->setEnabled(false);
 
782
 
 
783
    topLayout->activate();
 
784
    setMinimumSize(QSize(grid->sizeHint().width() + 2*KDialog::marginHint(), sizeHint().height()));
 
785
    bool modal = !(windowFlags() & Qt::X11BypassWindowManagerHint);
 
786
    unsigned long wstate = (modal ? NET::Modal : 0) | NET::Sticky | NET::StaysOnTop;
 
787
    WId winid = winId();
 
788
    KWindowSystem::setState(winid, wstate);
 
789
    KWindowSystem::setOnAllDesktops(winid, true);
 
790
 
 
791
    mInitialised = true;   // the window's widgets have been created
757
792
}
758
793
 
759
794
/******************************************************************************
761
796
*/
762
797
int MessageWin::instanceCount(bool excludeAlwaysHidden)
763
798
{
764
 
        int count = mWindowList.count();
765
 
        if (excludeAlwaysHidden)
766
 
        {
767
 
                foreach (MessageWin* win, mWindowList)
768
 
                {
769
 
                        if (win->mAlwaysHide)
770
 
                                --count;
771
 
                }
772
 
        }
773
 
        return count;
 
799
    int count = mWindowList.count();
 
800
    if (excludeAlwaysHidden)
 
801
    {
 
802
        foreach (MessageWin* win, mWindowList)
 
803
        {
 
804
            if (win->mAlwaysHide)
 
805
                --count;
 
806
        }
 
807
    }
 
808
    return count;
774
809
}
775
810
 
776
811
bool MessageWin::hasDefer() const
777
812
{
778
 
        return mDeferButton && mDeferButton->isVisible();
 
813
    return mDeferButton && mDeferButton->isVisible();
779
814
}
780
815
 
781
816
/******************************************************************************
783
818
*/
784
819
void MessageWin::showDefer()
785
820
{
786
 
        if (mDeferButton)
787
 
        {
788
 
                mNoDefer = false;
789
 
                mDeferButton->show();
790
 
                setDeferralLimit(mEvent);    // ensure that button is disabled when alarm can't be deferred any more
791
 
                resize(sizeHint());
792
 
        }
 
821
    if (mDeferButton)
 
822
    {
 
823
        mNoDefer = false;
 
824
        mDeferButton->show();
 
825
        setDeferralLimit(mEvent);    // ensure that button is disabled when alarm can't be deferred any more
 
826
        resize(sizeHint());
 
827
    }
793
828
}
794
829
 
795
830
/******************************************************************************
797
832
*/
798
833
void MessageWin::cancelReminder(const KAEvent& event, const KAAlarm& alarm)
799
834
{
800
 
        if (!mInitialised)
801
 
                return;
802
 
        mDateTime = alarm.dateTime(true);
803
 
        mNoPostAction = false;
804
 
        mAlarmType = alarm.type();
805
 
        if (event.autoClose())
806
 
                mCloseTime = alarm.dateTime().effectiveDateTime().addSecs(event.lateCancel() * 60);
807
 
        setCaption(i18nc("@title:window", "Message"));
808
 
        mTimeLabel->setText(dateTimeToDisplay());
809
 
        if (mRemainingText)
810
 
                mRemainingText->hide();
811
 
        MidnightTimer::disconnect(this, SLOT(setRemainingTextDay()));
812
 
        MinuteTimer::disconnect(this, SLOT(setRemainingTextMinute()));
813
 
        setMinimumHeight(0);
814
 
        centralWidget()->layout()->activate();
815
 
        setMinimumHeight(sizeHint().height());
816
 
        resize(sizeHint());
 
835
    if (!mInitialised)
 
836
        return;
 
837
    mDateTime = alarm.dateTime(true);
 
838
    mNoPostAction = false;
 
839
    mAlarmType = alarm.type();
 
840
    if (event.autoClose())
 
841
        mCloseTime = alarm.dateTime().effectiveDateTime().addSecs(event.lateCancel() * 60);
 
842
    setCaption(i18nc("@title:window", "Message"));
 
843
    mTimeLabel->setText(dateTimeToDisplay());
 
844
    if (mRemainingText)
 
845
        mRemainingText->hide();
 
846
    MidnightTimer::disconnect(this, SLOT(setRemainingTextDay()));
 
847
    MinuteTimer::disconnect(this, SLOT(setRemainingTextMinute()));
 
848
    setMinimumHeight(0);
 
849
    centralWidget()->layout()->activate();
 
850
    setMinimumHeight(sizeHint().height());
 
851
    resize(sizeHint());
817
852
}
818
853
 
819
854
/******************************************************************************
822
857
*/
823
858
void MessageWin::showDateTime(const KAEvent& event, const KAAlarm& alarm)
824
859
{
825
 
        if (!mTimeLabel)
826
 
                return;
827
 
        mDateTime = (alarm.type() & KAAlarm::REMINDER_ALARM) ? event.mainDateTime(true) : alarm.dateTime(true);
828
 
        if (mDateTime.isValid())
829
 
        {
830
 
                mTimeLabel->setText(dateTimeToDisplay());
831
 
                mTimeLabel->show();
832
 
        }
 
860
    if (!mTimeLabel)
 
861
        return;
 
862
    mDateTime = (alarm.type() & KAAlarm::REMINDER_ALARM) ? event.mainDateTime(true) : alarm.dateTime(true);
 
863
    if (mDateTime.isValid())
 
864
    {
 
865
        mTimeLabel->setText(dateTimeToDisplay());
 
866
        mTimeLabel->show();
 
867
    }
833
868
}
834
869
 
835
870
/******************************************************************************
837
872
*/
838
873
QString MessageWin::dateTimeToDisplay()
839
874
{
840
 
        QString tm;
841
 
        if (mDateTime.isValid())
842
 
        {
843
 
                if (mDateTime.isDateOnly())
844
 
                        tm = KGlobal::locale()->formatDate(mDateTime.date(), KLocale::ShortDate);
845
 
                else
846
 
                {
847
 
                        bool showZone = false;
848
 
                        if (mDateTime.timeType() == KDateTime::UTC
849
 
                        ||  (mDateTime.timeType() == KDateTime::TimeZone && !mDateTime.isLocalZone()))
850
 
                        {
851
 
                                // Display time zone abbreviation if it's different from the local
852
 
                                // zone. Note that the iCalendar time zone might represent the local
853
 
                                // time zone in a slightly different way from the system time zone,
854
 
                                // so the zone comparison above might not produce the desired result.
855
 
                                QString tz = mDateTime.kDateTime().toString(QString::fromLatin1("%Z"));
856
 
                                KDateTime local = mDateTime.kDateTime();
857
 
                                local.setTimeSpec(KDateTime::Spec::LocalZone());
858
 
                                showZone = (local.toString(QString::fromLatin1("%Z")) != tz);
859
 
                        }
860
 
                        tm = KGlobal::locale()->formatDateTime(mDateTime.kDateTime(), KLocale::ShortDate, KLocale::DateTimeFormatOptions(showZone ? KLocale::TimeZone : 0));
861
 
                }
862
 
        }
863
 
        return tm;
 
875
    QString tm;
 
876
    if (mDateTime.isValid())
 
877
    {
 
878
        if (mDateTime.isDateOnly())
 
879
            tm = KGlobal::locale()->formatDate(mDateTime.date(), KLocale::ShortDate);
 
880
        else
 
881
        {
 
882
            bool showZone = false;
 
883
            if (mDateTime.timeType() == KDateTime::UTC
 
884
            ||  (mDateTime.timeType() == KDateTime::TimeZone && !mDateTime.isLocalZone()))
 
885
            {
 
886
                // Display time zone abbreviation if it's different from the local
 
887
                // zone. Note that the iCalendar time zone might represent the local
 
888
                // time zone in a slightly different way from the system time zone,
 
889
                // so the zone comparison above might not produce the desired result.
 
890
                QString tz = mDateTime.kDateTime().toString(QString::fromLatin1("%Z"));
 
891
                KDateTime local = mDateTime.kDateTime();
 
892
                local.setTimeSpec(KDateTime::Spec::LocalZone());
 
893
                showZone = (local.toString(QString::fromLatin1("%Z")) != tz);
 
894
            }
 
895
            tm = KGlobal::locale()->formatDateTime(mDateTime.kDateTime(), KLocale::ShortDate, KLocale::DateTimeFormatOptions(showZone ? KLocale::TimeZone : 0));
 
896
        }
 
897
    }
 
898
    return tm;
864
899
}
865
900
 
866
901
/******************************************************************************
869
904
*/
870
905
void MessageWin::setRemainingTextDay()
871
906
{
872
 
        QString text;
873
 
        int days = KDateTime::currentLocalDate().daysTo(mDateTime.date());
874
 
        if (days <= 0  &&  !mDateTime.isDateOnly())
875
 
        {
876
 
                // The alarm is due today, so start refreshing every minute
877
 
                MidnightTimer::disconnect(this, SLOT(setRemainingTextDay()));
878
 
                setRemainingTextMinute();
879
 
                MinuteTimer::connect(this, SLOT(setRemainingTextMinute()));   // update every minute
880
 
        }
881
 
        else
882
 
        {
883
 
                if (days <= 0)
884
 
                        text = i18nc("@info", "Today");
885
 
                else if (days % 7)
886
 
                        text = i18ncp("@info", "Tomorrow", "in %1 days' time", days);
887
 
                else
888
 
                        text = i18ncp("@info", "in 1 week's time", "in %1 weeks' time", days/7);
889
 
        }
890
 
        mRemainingText->setText(text);
 
907
    QString text;
 
908
    int days = KDateTime::currentLocalDate().daysTo(mDateTime.date());
 
909
    if (days <= 0  &&  !mDateTime.isDateOnly())
 
910
    {
 
911
        // The alarm is due today, so start refreshing every minute
 
912
        MidnightTimer::disconnect(this, SLOT(setRemainingTextDay()));
 
913
        setRemainingTextMinute();
 
914
        MinuteTimer::connect(this, SLOT(setRemainingTextMinute()));   // update every minute
 
915
    }
 
916
    else
 
917
    {
 
918
        if (days <= 0)
 
919
            text = i18nc("@info", "Today");
 
920
        else if (days % 7)
 
921
            text = i18ncp("@info", "Tomorrow", "in %1 days' time", days);
 
922
        else
 
923
            text = i18ncp("@info", "in 1 week's time", "in %1 weeks' time", days/7);
 
924
    }
 
925
    mRemainingText->setText(text);
891
926
}
892
927
 
893
928
/******************************************************************************
896
931
*/
897
932
void MessageWin::setRemainingTextMinute()
898
933
{
899
 
        QString text;
900
 
        int mins = (KDateTime::currentUtcDateTime().secsTo(mDateTime.effectiveKDateTime()) + 59) / 60;
901
 
        if (mins < 60)
902
 
                text = i18ncp("@info", "in 1 minute's time", "in %1 minutes' time", (mins > 0 ? mins : 0));
903
 
        else if (mins % 60 == 0)
904
 
                text = i18ncp("@info", "in 1 hour's time", "in %1 hours' time", mins/60);
905
 
        else if (mins % 60 == 1)
906
 
                text = i18ncp("@info", "in 1 hour 1 minute's time", "in %1 hours 1 minute's time", mins/60);
907
 
        else
908
 
                text = i18ncp("@info", "in 1 hour %2 minutes' time", "in %1 hours %2 minutes' time", mins/60, mins%60);
909
 
        mRemainingText->setText(text);
 
934
    QString text;
 
935
    int mins = (KDateTime::currentUtcDateTime().secsTo(mDateTime.effectiveKDateTime()) + 59) / 60;
 
936
    if (mins < 60)
 
937
        text = i18ncp("@info", "in 1 minute's time", "in %1 minutes' time", (mins > 0 ? mins : 0));
 
938
    else if (mins % 60 == 0)
 
939
        text = i18ncp("@info", "in 1 hour's time", "in %1 hours' time", mins/60);
 
940
    else
 
941
    {
 
942
        QString hourText = i18ncp("@item:intext inserted into 'in ... %1 minute's time' below", "1 hour", "%1 hours", mins/60);
 
943
        text = i18ncp("@info '%2' is the previous message '1 hour'/'%1 hours'", "in %2 1 minute's time", "in %2 %1 minutes' time", mins%60, hourText);
 
944
    }
 
945
    mRemainingText->setText(text);
910
946
}
911
947
 
912
948
/******************************************************************************
915
951
*/
916
952
void MessageWin::readProcessOutput(ShellProcess* proc)
917
953
{
918
 
        QByteArray data = proc->readAll();
919
 
        if (!data.isEmpty())
920
 
        {
921
 
                // Strip any trailing newline, to avoid showing trailing blank line
922
 
                // in message window.
923
 
                if (mCommandText->newLine())
924
 
                        mCommandText->append("\n");
925
 
                int nl = data.endsWith('\n') ? 1 : 0;
926
 
                mCommandText->setNewLine(nl);
927
 
                mCommandText->insertPlainText(QString::fromLocal8Bit(data.data(), data.length() - nl));
928
 
                resize(sizeHint());
929
 
        }
 
954
    QByteArray data = proc->readAll();
 
955
    if (!data.isEmpty())
 
956
    {
 
957
        // Strip any trailing newline, to avoid showing trailing blank line
 
958
        // in message window.
 
959
        if (mCommandText->newLine())
 
960
            mCommandText->append("\n");
 
961
        int nl = data.endsWith('\n') ? 1 : 0;
 
962
        mCommandText->setNewLine(nl);
 
963
        mCommandText->insertPlainText(QString::fromLocal8Bit(data.data(), data.length() - nl));
 
964
        resize(sizeHint());
 
965
    }
930
966
}
931
967
 
932
968
/******************************************************************************
935
971
*/
936
972
void MessageWin::saveProperties(KConfigGroup& config)
937
973
{
938
 
        if (mShown  &&  !mErrorWindow  &&  !mAlwaysHide)
939
 
        {
940
 
                config.writeEntry("EventID", mEventID);
941
 
                config.writeEntry("AlarmType", static_cast<int>(mAlarmType));
942
 
                if (mAlarmType == KAAlarm::INVALID_ALARM)
943
 
                        kError() << "Invalid alarm: id=" << mEventID << ", alarm count=" << mEvent.alarmCount();
944
 
                config.writeEntry("Message", mMessage);
945
 
                config.writeEntry("Type", static_cast<int>(mAction));
946
 
                config.writeEntry("Font", mFont);
947
 
                config.writeEntry("BgColour", mBgColour);
948
 
                config.writeEntry("FgColour", mFgColour);
949
 
                config.writeEntry("ConfirmAck", mConfirmAck);
950
 
                if (mDateTime.isValid())
951
 
                {
 
974
    if (mShown  &&  !mErrorWindow  &&  !mAlwaysHide)
 
975
    {
 
976
        config.writeEntry("EventID", mEventID);
 
977
#ifdef USE_AKONADI
 
978
        config.writeEntry("EventItemID", mEventItemId);
 
979
#endif
 
980
        config.writeEntry("AlarmType", static_cast<int>(mAlarmType));
 
981
        if (mAlarmType == KAAlarm::INVALID_ALARM)
 
982
            kError() << "Invalid alarm: id=" << mEventID << ", alarm count=" << mEvent.alarmCount();
 
983
        config.writeEntry("Message", mMessage);
 
984
        config.writeEntry("Type", static_cast<int>(mAction));
 
985
        config.writeEntry("Font", mFont);
 
986
        config.writeEntry("BgColour", mBgColour);
 
987
        config.writeEntry("FgColour", mFgColour);
 
988
        config.writeEntry("ConfirmAck", mConfirmAck);
 
989
        if (mDateTime.isValid())
 
990
        {
952
991
//TODO: Write KDateTime when it becomes possible
953
 
                        config.writeEntry("Time", mDateTime.effectiveDateTime());
954
 
                        config.writeEntry("DateOnly", mDateTime.isDateOnly());
955
 
                        QString zone;
956
 
                        if (mDateTime.isUtc())
957
 
                                zone = QLatin1String("UTC");
958
 
                        else
959
 
                        {
960
 
                                KTimeZone tz = mDateTime.timeZone();
961
 
                                if (tz.isValid())
962
 
                                        zone = tz.name();
963
 
                        }
964
 
                        config.writeEntry("TimeZone", zone);
965
 
                }
966
 
                if (mCloseTime.isValid())
967
 
                        config.writeEntry("Expiry", mCloseTime);
968
 
                if (mAudioRepeat  &&  mSilenceButton  &&  mSilenceButton->isEnabled())
969
 
                {
970
 
                        // Only need to restart sound file playing if it's being repeated
971
 
                        config.writePathEntry("AudioFile", mAudioFile);
972
 
                        config.writeEntry("Volume", static_cast<int>(mVolume * 100));
973
 
                }
974
 
                config.writeEntry("Speak", mSpeak);
975
 
                config.writeEntry("Height", height());
976
 
                config.writeEntry("DeferMins", mDefaultDeferMinutes);
977
 
                config.writeEntry("NoDefer", mNoDefer);
978
 
                config.writeEntry("NoPostAction", mNoPostAction);
979
 
                config.writeEntry("KMailSerial", static_cast<qulonglong>(mKMailSerialNumber));
980
 
                config.writeEntry("CmdErr", static_cast<int>(mCommandError));
981
 
                config.writeEntry("DontShowAgain", mDontShowAgain);
982
 
        }
983
 
        else
984
 
                config.writeEntry("Invalid", true);
 
992
            config.writeEntry("Time", mDateTime.effectiveDateTime());
 
993
            config.writeEntry("DateOnly", mDateTime.isDateOnly());
 
994
            QString zone;
 
995
            if (mDateTime.isUtc())
 
996
                zone = QLatin1String("UTC");
 
997
            else
 
998
            {
 
999
                KTimeZone tz = mDateTime.timeZone();
 
1000
                if (tz.isValid())
 
1001
                    zone = tz.name();
 
1002
            }
 
1003
            config.writeEntry("TimeZone", zone);
 
1004
        }
 
1005
        if (mCloseTime.isValid())
 
1006
            config.writeEntry("Expiry", mCloseTime);
 
1007
        if (mAudioRepeat  &&  mSilenceButton  &&  mSilenceButton->isEnabled())
 
1008
        {
 
1009
            // Only need to restart sound file playing if it's being repeated
 
1010
            config.writePathEntry("AudioFile", mAudioFile);
 
1011
            config.writeEntry("Volume", static_cast<int>(mVolume * 100));
 
1012
        }
 
1013
        config.writeEntry("Speak", mSpeak);
 
1014
        config.writeEntry("Height", height());
 
1015
        config.writeEntry("DeferMins", mDefaultDeferMinutes);
 
1016
        config.writeEntry("NoDefer", mNoDefer);
 
1017
        config.writeEntry("NoPostAction", mNoPostAction);
 
1018
        config.writeEntry("KMailSerial", static_cast<qulonglong>(mKMailSerialNumber));
 
1019
        config.writeEntry("CmdErr", static_cast<int>(mCommandError));
 
1020
        config.writeEntry("DontShowAgain", mDontShowAgain);
 
1021
    }
 
1022
    else
 
1023
        config.writeEntry("Invalid", true);
985
1024
}
986
1025
 
987
1026
/******************************************************************************
991
1030
*/
992
1031
void MessageWin::readProperties(const KConfigGroup& config)
993
1032
{
994
 
        mInvalid             = config.readEntry("Invalid", false);
995
 
        mEventID             = config.readEntry("EventID");
996
 
        mAlarmType           = static_cast<KAAlarm::Type>(config.readEntry("AlarmType", 0));
997
 
        if (mAlarmType == KAAlarm::INVALID_ALARM)
998
 
        {
999
 
                mInvalid = true;
1000
 
                kError() << "Invalid alarm: id=" << mEventID;
1001
 
        }
1002
 
        mMessage             = config.readEntry("Message");
1003
 
        mAction              = static_cast<KAEventData::Action>(config.readEntry("Type", 0));
1004
 
        mFont                = config.readEntry("Font", QFont());
1005
 
        mBgColour            = config.readEntry("BgColour", QColor(Qt::white));
1006
 
        mFgColour            = config.readEntry("FgColour", QColor(Qt::black));
1007
 
        mConfirmAck          = config.readEntry("ConfirmAck", false);
1008
 
        QDateTime invalidDateTime;
1009
 
        QDateTime dt         = config.readEntry("Time", invalidDateTime);
1010
 
        QString zone         = config.readEntry("TimeZone");
1011
 
        if (zone.isEmpty())
1012
 
                mDateTime = KDateTime(dt, KDateTime::ClockTime);
1013
 
        else if (zone == QLatin1String("UTC"))
1014
 
        {
1015
 
                dt.setTimeSpec(Qt::UTC);
1016
 
                mDateTime = KDateTime(dt, KDateTime::UTC);
1017
 
        }
1018
 
        else
1019
 
        {
1020
 
                KTimeZone tz = KSystemTimeZones::zone(zone);
1021
 
                mDateTime = KDateTime(dt, (tz.isValid() ? tz : KSystemTimeZones::local()));
1022
 
        }
1023
 
        bool dateOnly        = config.readEntry("DateOnly", false);
1024
 
        if (dateOnly)
1025
 
                mDateTime.setDateOnly(true);
1026
 
        mCloseTime           = config.readEntry("Expiry", invalidDateTime);
1027
 
        mAudioFile           = config.readPathEntry("AudioFile", QString());
1028
 
        mVolume              = static_cast<float>(config.readEntry("Volume", 0)) / 100;
1029
 
        mFadeVolume          = -1;
1030
 
        mFadeSeconds         = 0;
1031
 
        if (!mAudioFile.isEmpty())
1032
 
                mAudioRepeat = true;
1033
 
        mSpeak               = config.readEntry("Speak", false);
1034
 
        mRestoreHeight       = config.readEntry("Height", 0);
1035
 
        mDefaultDeferMinutes = config.readEntry("DeferMins", 0);
1036
 
        mNoDefer             = config.readEntry("NoDefer", false);
1037
 
        mNoPostAction        = config.readEntry("NoPostAction", true);
1038
 
        mKMailSerialNumber   = static_cast<unsigned long>(config.readEntry("KMailSerial", QVariant(QVariant::ULongLong)).toULongLong());
1039
 
        mCommandError        = KAEvent::CmdErrType(config.readEntry("CmdErr", static_cast<int>(KAEvent::CMD_NO_ERROR)));
1040
 
        mDontShowAgain       = config.readEntry("DontShowAgain", QString());
1041
 
        mShowEdit            = false;
1042
 
        mResource            = 0;
1043
 
        kDebug() << mEventID;
1044
 
        if (mAlarmType != KAAlarm::INVALID_ALARM)
1045
 
        {
1046
 
                // Recreate the event from the calendar file (if possible)
1047
 
                if (!mEventID.isEmpty())
1048
 
                {
1049
 
                        AlarmCalendar* resources = AlarmCalendar::resources();
1050
 
                        KAEvent* event = resources->event(mEventID);
1051
 
                        if (event)
1052
 
                        {
1053
 
                                mEvent = *event;
1054
 
                                mResource = resources->resourceForEvent(mEventID);
1055
 
                                mShowEdit = true;
1056
 
                        }
1057
 
                        else
1058
 
                        {
1059
 
                                // It's not in the active calendar, so try the displaying or archive calendars
1060
 
                                retrieveEvent(mEvent, mResource, mShowEdit, mNoDefer);
1061
 
                                mNoDefer = !mNoDefer;
1062
 
                        }
1063
 
                }
1064
 
                initView();
1065
 
        }
 
1033
    mInvalid             = config.readEntry("Invalid", false);
 
1034
    mEventID             = config.readEntry("EventID");
 
1035
#ifdef USE_AKONADI
 
1036
    mEventItemId         = config.readEntry("EventItemID", Akonadi::Item::Id(-1));
 
1037
#endif
 
1038
    mAlarmType           = static_cast<KAAlarm::Type>(config.readEntry("AlarmType", 0));
 
1039
    if (mAlarmType == KAAlarm::INVALID_ALARM)
 
1040
    {
 
1041
        mInvalid = true;
 
1042
        kError() << "Invalid alarm: id=" << mEventID;
 
1043
    }
 
1044
    mMessage             = config.readEntry("Message");
 
1045
    mAction              = static_cast<KAEvent::Action>(config.readEntry("Type", 0));
 
1046
    mFont                = config.readEntry("Font", QFont());
 
1047
    mBgColour            = config.readEntry("BgColour", QColor(Qt::white));
 
1048
    mFgColour            = config.readEntry("FgColour", QColor(Qt::black));
 
1049
    mConfirmAck          = config.readEntry("ConfirmAck", false);
 
1050
    QDateTime invalidDateTime;
 
1051
    QDateTime dt         = config.readEntry("Time", invalidDateTime);
 
1052
    QString zone         = config.readEntry("TimeZone");
 
1053
    if (zone.isEmpty())
 
1054
        mDateTime = KDateTime(dt, KDateTime::ClockTime);
 
1055
    else if (zone == QLatin1String("UTC"))
 
1056
    {
 
1057
        dt.setTimeSpec(Qt::UTC);
 
1058
        mDateTime = KDateTime(dt, KDateTime::UTC);
 
1059
    }
 
1060
    else
 
1061
    {
 
1062
        KTimeZone tz = KSystemTimeZones::zone(zone);
 
1063
        mDateTime = KDateTime(dt, (tz.isValid() ? tz : KSystemTimeZones::local()));
 
1064
    }
 
1065
    bool dateOnly        = config.readEntry("DateOnly", false);
 
1066
    if (dateOnly)
 
1067
        mDateTime.setDateOnly(true);
 
1068
    mCloseTime           = config.readEntry("Expiry", invalidDateTime);
 
1069
    mAudioFile           = config.readPathEntry("AudioFile", QString());
 
1070
    mVolume              = static_cast<float>(config.readEntry("Volume", 0)) / 100;
 
1071
    mFadeVolume          = -1;
 
1072
    mFadeSeconds         = 0;
 
1073
    if (!mAudioFile.isEmpty())
 
1074
        mAudioRepeat = true;
 
1075
    mSpeak               = config.readEntry("Speak", false);
 
1076
    mRestoreHeight       = config.readEntry("Height", 0);
 
1077
    mDefaultDeferMinutes = config.readEntry("DeferMins", 0);
 
1078
    mNoDefer             = config.readEntry("NoDefer", false);
 
1079
    mNoPostAction        = config.readEntry("NoPostAction", true);
 
1080
    mKMailSerialNumber   = static_cast<unsigned long>(config.readEntry("KMailSerial", QVariant(QVariant::ULongLong)).toULongLong());
 
1081
    mCommandError        = KAEvent::CmdErrType(config.readEntry("CmdErr", static_cast<int>(KAEvent::CMD_NO_ERROR)));
 
1082
    mDontShowAgain       = config.readEntry("DontShowAgain", QString());
 
1083
    mShowEdit            = false;
 
1084
#ifdef USE_AKONADI
 
1085
    mCollection          = Akonadi::Collection();
 
1086
#else
 
1087
    mResource            = 0;
 
1088
#endif
 
1089
    kDebug() << mEventID;
 
1090
    if (mAlarmType != KAAlarm::INVALID_ALARM)
 
1091
    {
 
1092
        // Recreate the event from the calendar file (if possible)
 
1093
        if (!mEventID.isEmpty())
 
1094
        {
 
1095
            KAEvent* event = AlarmCalendar::resources()->event(mEventID);
 
1096
            if (event)
 
1097
            {
 
1098
                mEvent = *event;
 
1099
#ifdef USE_AKONADI
 
1100
                mCollection = AkonadiModel::instance()->collectionForItem(mEventItemId);
 
1101
#else
 
1102
                mResource = AlarmCalendar::resources()->resourceForEvent(mEventID);
 
1103
#endif
 
1104
                mShowEdit = true;
 
1105
            }
 
1106
            else
 
1107
            {
 
1108
                // It's not in the active calendar, so try the displaying or archive calendars
 
1109
#ifdef USE_AKONADI
 
1110
                retrieveEvent(mEvent, mCollection, mShowEdit, mNoDefer);
 
1111
#else
 
1112
                retrieveEvent(mEvent, mResource, mShowEdit, mNoDefer);
 
1113
#endif
 
1114
                mNoDefer = !mNoDefer;
 
1115
            }
 
1116
        }
 
1117
        initView();
 
1118
    }
1066
1119
}
1067
1120
 
1068
1121
/******************************************************************************
1073
1126
*/
1074
1127
void MessageWin::redisplayAlarms()
1075
1128
{
1076
 
        AlarmCalendar* cal = AlarmCalendar::displayCalendar();
1077
 
        if (cal->isOpen())
1078
 
        {
1079
 
                KAEvent event;
1080
 
                AlarmResource* resource;
1081
 
                KCal::Event::List events = cal->kcalEvents();
1082
 
                for (int i = 0, end = events.count();  i < end;  ++i)
1083
 
                {
1084
 
                        bool showDefer, showEdit;
1085
 
                        reinstateFromDisplaying(events[i], event, resource, showEdit, showDefer);
1086
 
                        if (!findEvent(event.id()))
1087
 
                        {
1088
 
                                // This event should be displayed, but currently isn't being
1089
 
                                KAAlarm alarm = event.convertDisplayingAlarm();
1090
 
                                if (alarm.type() == KAAlarm::INVALID_ALARM)
1091
 
                                {
1092
 
                                        kError() << "Invalid alarm: id=" << event.id();
1093
 
                                        continue;
1094
 
                                }
1095
 
                                kDebug() << event.id();
1096
 
                                bool login = alarm.repeatAtLogin();
1097
 
                                int flags = NO_RESCHEDULE | (login ? NO_DEFER : 0) | NO_INIT_VIEW;
1098
 
                                MessageWin* win = new MessageWin(&event, alarm, flags);
1099
 
                                win->mResource = resource;
1100
 
                                bool rw = resource  &&  resource->writable();
1101
 
                                win->mShowEdit = rw ? showEdit : false;
1102
 
                                win->mNoDefer  = (rw && !login) ? !showDefer : true;
1103
 
                                win->initView();
1104
 
                                win->show();
1105
 
                        }
1106
 
                }
1107
 
        }
 
1129
    AlarmCalendar* cal = AlarmCalendar::displayCalendar();
 
1130
    if (cal->isOpen())
 
1131
    {
 
1132
        KAEvent event;
 
1133
#ifdef USE_AKONADI
 
1134
        Akonadi::Collection collection;
 
1135
#else
 
1136
        AlarmResource* resource;
 
1137
#endif
 
1138
        Event::List events = cal->kcalEvents();
 
1139
        for (int i = 0, end = events.count();  i < end;  ++i)
 
1140
        {
 
1141
            bool showDefer, showEdit;
 
1142
#ifdef USE_AKONADI
 
1143
            reinstateFromDisplaying(events[i], event, collection, showEdit, showDefer);
 
1144
#else
 
1145
            reinstateFromDisplaying(events[i], event, resource, showEdit, showDefer);
 
1146
#endif
 
1147
            if (!findEvent(event.id()))
 
1148
            {
 
1149
                // This event should be displayed, but currently isn't being
 
1150
                KAAlarm alarm = event.convertDisplayingAlarm();
 
1151
                if (alarm.type() == KAAlarm::INVALID_ALARM)
 
1152
                {
 
1153
                    kError() << "Invalid alarm: id=" << event.id();
 
1154
                    continue;
 
1155
                }
 
1156
                kDebug() << event.id();
 
1157
                bool login = alarm.repeatAtLogin();
 
1158
                int flags = NO_RESCHEDULE | (login ? NO_DEFER : 0) | NO_INIT_VIEW;
 
1159
                MessageWin* win = new MessageWin(&event, alarm, flags);
 
1160
#ifdef USE_AKONADI
 
1161
                win->mCollection = collection;
 
1162
                bool rw = CollectionControlModel::isWritable(collection, event.category());
 
1163
#else
 
1164
                win->mResource = resource;
 
1165
                bool rw = resource  &&  resource->writable();
 
1166
#endif
 
1167
                win->mShowEdit = rw ? showEdit : false;
 
1168
                win->mNoDefer  = (rw && !login) ? !showDefer : true;
 
1169
                win->initView();
 
1170
                win->show();
 
1171
            }
 
1172
        }
 
1173
    }
1108
1174
}
1109
1175
 
1110
1176
/******************************************************************************
1111
1177
*  Retrieves the event with the current ID from the displaying calendar file,
1112
1178
*  or if not found there, from the archive calendar.
1113
1179
*/
 
1180
#ifdef USE_AKONADI
 
1181
bool MessageWin::retrieveEvent(KAEvent& event, Akonadi::Collection& resource, bool& showEdit, bool& showDefer)
 
1182
#else
1114
1183
bool MessageWin::retrieveEvent(KAEvent& event, AlarmResource*& resource, bool& showEdit, bool& showDefer)
 
1184
#endif
1115
1185
{
1116
 
        const Event* kcalEvent = AlarmCalendar::displayCalendar()->kcalEvent(KCalEvent::uid(mEventID, KCalEvent::DISPLAYING));
1117
 
        if (!reinstateFromDisplaying(kcalEvent, event, resource, showEdit, showDefer))
1118
 
        {
1119
 
                // The event isn't in the displaying calendar.
1120
 
                // Try to retrieve it from the archive calendar.
1121
 
                KAEvent* ev = AlarmCalendar::resources()->event(KCalEvent::uid(mEventID, KCalEvent::ARCHIVED));
1122
 
                if (!ev)
1123
 
                        return false;
1124
 
                event = *ev;
1125
 
                event.setArchive();     // ensure that it gets re-archived if it's saved
1126
 
                event.setCategory(KCalEvent::ACTIVE);
1127
 
                if (mEventID != event.id())
1128
 
                        kError() << "Wrong event ID";
1129
 
                event.setEventId(mEventID);
1130
 
                resource  = 0;
1131
 
                showEdit  = true;
1132
 
                showDefer = true;
1133
 
                kDebug() << event.id() << ": success";
1134
 
        }
1135
 
        return true;
 
1186
#ifdef USE_AKONADI
 
1187
    ConstEventPtr kcalEvent = AlarmCalendar::displayCalendar()->kcalEvent(KAlarm::CalEvent::uid(mEventID, KAlarm::CalEvent::DISPLAYING));
 
1188
#else
 
1189
    const Event* kcalEvent = AlarmCalendar::displayCalendar()->kcalEvent(KAlarm::CalEvent::uid(mEventID, KAlarm::CalEvent::DISPLAYING));
 
1190
#endif
 
1191
    if (!reinstateFromDisplaying(kcalEvent, event, resource, showEdit, showDefer))
 
1192
    {
 
1193
        // The event isn't in the displaying calendar.
 
1194
        // Try to retrieve it from the archive calendar.
 
1195
        KAEvent* ev = AlarmCalendar::resources()->event(KAlarm::CalEvent::uid(mEventID, KAlarm::CalEvent::ARCHIVED));
 
1196
        if (!ev)
 
1197
            return false;
 
1198
        event = *ev;
 
1199
        event.setArchive();     // ensure that it gets re-archived if it's saved
 
1200
        event.setCategory(KAlarm::CalEvent::ACTIVE);
 
1201
        if (mEventID != event.id())
 
1202
            kError() << "Wrong event ID";
 
1203
        event.setEventId(mEventID);
 
1204
#ifdef USE_AKONADI
 
1205
        resource  = Akonadi::Collection();
 
1206
#else
 
1207
        resource  = 0;
 
1208
#endif
 
1209
        showEdit  = true;
 
1210
        showDefer = true;
 
1211
        kDebug() << event.id() << ": success";
 
1212
    }
 
1213
    return true;
1136
1214
}
1137
1215
 
1138
1216
/******************************************************************************
1139
1217
*  Retrieves the displayed event from the calendar file, or if not found there,
1140
1218
*  from the displaying calendar.
1141
1219
*/
 
1220
#ifdef USE_AKONADI
 
1221
bool MessageWin::reinstateFromDisplaying(const ConstEventPtr& kcalEvent, KAEvent& event, Akonadi::Collection& collection, bool& showEdit, bool& showDefer)
 
1222
#else
1142
1223
bool MessageWin::reinstateFromDisplaying(const Event* kcalEvent, KAEvent& event, AlarmResource*& resource, bool& showEdit, bool& showDefer)
 
1224
#endif
1143
1225
{
1144
 
        if (!kcalEvent)
1145
 
                return false;
1146
 
        QString resourceID;
1147
 
        event.reinstateFromDisplaying(kcalEvent, resourceID, showEdit, showDefer);
1148
 
        resource = AlarmResources::instance()->resourceWithId(resourceID);
1149
 
        if (resource  &&  !resource->isOpen())
1150
 
                resource = 0;
1151
 
        event.clearResourceId();
1152
 
        kDebug() << event.id() << ": success";
1153
 
        return true;
 
1226
    if (!kcalEvent)
 
1227
        return false;
 
1228
#ifdef USE_AKONADI
 
1229
    Akonadi::Collection::Id collectionId;
 
1230
    event.reinstateFromDisplaying(kcalEvent, collectionId, showEdit, showDefer);
 
1231
    collection = AkonadiModel::instance()->collectionById(collectionId);
 
1232
    event.clearCollectionId();
 
1233
#else
 
1234
    QString resourceID;
 
1235
    event.reinstateFromDisplaying(kcalEvent, resourceID, showEdit, showDefer);
 
1236
    resource = AlarmResources::instance()->resourceWithId(resourceID);
 
1237
    if (resource  &&  !resource->isOpen())
 
1238
        resource = 0;
 
1239
    event.clearResourceId();
 
1240
#endif
 
1241
    kDebug() << event.id() << ": success";
 
1242
    return true;
1154
1243
}
1155
1244
 
1156
1245
/******************************************************************************
1158
1247
* alarm in the displaying calendar, and to reschedule it for its next repetition.
1159
1248
* If no repetitions remain, cancel it.
1160
1249
*/
1161
 
void MessageWin::alarmShowing(KAEvent& event, const KCal::Event* kcalEvent)
 
1250
void MessageWin::alarmShowing(KAEvent& event)
1162
1251
{
1163
 
        kDebug() << event.id() << "," << KAAlarm::debugType(mAlarmType);
1164
 
        if (!kcalEvent)
1165
 
                kcalEvent = AlarmCalendar::resources()->kcalEvent(event.id());
1166
 
        if (!kcalEvent)
1167
 
                kError() << "Event ID not found:" << event.id();
1168
 
        else
1169
 
        {
1170
 
                KAAlarm alarm = event.alarm(mAlarmType);
1171
 
                if (!alarm.valid())
1172
 
                        kError() << "Alarm type not found:" << event.id() << ":" << mAlarmType;
1173
 
                else
1174
 
                {
1175
 
                        if (!mAlwaysHide)
1176
 
                        {
1177
 
                                // Copy the alarm to the displaying calendar in case of a crash, etc.
1178
 
                                AlarmResource* resource = AlarmResources::instance()->resource(kcalEvent);
1179
 
                                KAEvent* dispEvent = new KAEvent;
1180
 
                                dispEvent->setDisplaying(event, mAlarmType, (resource ? resource->identifier() : QString()),
1181
 
                                                        mDateTime.effectiveKDateTime(), mShowEdit, !mNoDefer);
1182
 
                                AlarmCalendar* cal = AlarmCalendar::displayCalendarOpen();
1183
 
                                if (cal)
1184
 
                                {
1185
 
                                        cal->deleteEvent(dispEvent->id());   // in case it already exists
1186
 
                                        if (!cal->addEvent(dispEvent))
1187
 
                                                delete dispEvent;
1188
 
                                        cal->save();
1189
 
                                }
1190
 
                                else
1191
 
                                        delete dispEvent;
1192
 
                        }
1193
 
                        theApp()->rescheduleAlarm(event, alarm);
1194
 
                }
1195
 
        }
 
1252
    kDebug() << event.id() << "," << KAAlarm::debugType(mAlarmType);
 
1253
#ifndef USE_AKONADI
 
1254
    const KCal::Event* kcalEvent = AlarmCalendar::resources()->kcalEvent(event.id());
 
1255
    if (!kcalEvent)
 
1256
    {
 
1257
        kError() << "Event ID not found:" << event.id();
 
1258
        return;
 
1259
    }
 
1260
#endif
 
1261
    KAAlarm alarm = event.alarm(mAlarmType);
 
1262
    if (!alarm.isValid())
 
1263
    {
 
1264
        kError() << "Alarm type not found:" << event.id() << ":" << mAlarmType;
 
1265
        return;
 
1266
    }
 
1267
    if (!mAlwaysHide)
 
1268
    {
 
1269
        // Copy the alarm to the displaying calendar in case of a crash, etc.
 
1270
        KAEvent* dispEvent = new KAEvent;
 
1271
#ifdef USE_AKONADI
 
1272
        Akonadi::Collection collection = AkonadiModel::instance()->collectionForItem(event.itemId());
 
1273
        dispEvent->setDisplaying(event, mAlarmType, collection.id(),
 
1274
                    mDateTime.effectiveKDateTime(), mShowEdit, !mNoDefer);
 
1275
#else
 
1276
        AlarmResource* resource = AlarmResources::instance()->resource(kcalEvent);
 
1277
        dispEvent->setDisplaying(event, mAlarmType, (resource ? resource->identifier() : QString()),
 
1278
                    mDateTime.effectiveKDateTime(), mShowEdit, !mNoDefer);
 
1279
#endif
 
1280
        AlarmCalendar* cal = AlarmCalendar::displayCalendarOpen();
 
1281
        if (cal)
 
1282
        {
 
1283
#ifdef USE_AKONADI
 
1284
            cal->deleteDisplayEvent(dispEvent->id());   // in case it already exists
 
1285
            if (!cal->addEvent(*dispEvent))
 
1286
#else
 
1287
            cal->deleteEvent(dispEvent->id());   // in case it already exists
 
1288
            if (!cal->addEvent(dispEvent))
 
1289
#endif
 
1290
                delete dispEvent;
 
1291
            cal->save();
 
1292
        }
 
1293
        else
 
1294
            delete dispEvent;
 
1295
    }
 
1296
    theApp()->rescheduleAlarm(event, alarm);
1196
1297
}
1197
1298
 
1198
1299
/******************************************************************************
1202
1303
*/
1203
1304
bool MessageWin::spread(bool scatter)
1204
1305
{
1205
 
        if (instanceCount(true) <= 1)    // ignore always-hidden windows
1206
 
                return false;
1207
 
 
1208
 
        QRect desk = KAlarm::desktopWorkArea();   // get the usable area of the desktop
1209
 
        if (scatter == isSpread(desk.topLeft()))
1210
 
                return scatter;
1211
 
 
1212
 
        if (scatter)
1213
 
        {
1214
 
                // Usually there won't be many windows, so a crude
1215
 
                // scattering algorithm should suffice.
1216
 
                int x = desk.left();
1217
 
                int y = desk.top();
1218
 
                int ynext = y;
1219
 
                for (int errmsgs = 0;  errmsgs < 2;  ++errmsgs)
1220
 
                {
1221
 
                        // Display alarm messages first, then error messages, since most
1222
 
                        // error messages tend to be the same height.
1223
 
                        for (int i = 0, end = mWindowList.count();  i < end;  ++i)
1224
 
                        {
1225
 
                                MessageWin* w = mWindowList[i];
1226
 
                                if ((!errmsgs && w->mErrorWindow)
1227
 
                                ||  (errmsgs && !w->mErrorWindow))
1228
 
                                        continue;
1229
 
                                QSize sz = w->frameGeometry().size();
1230
 
                                if (x + sz.width() > desk.right())
1231
 
                                {
1232
 
                                        x = desk.left();
1233
 
                                        y = ynext;
1234
 
                                }
1235
 
                                int ytmp = y;
1236
 
                                if (y + sz.height() > desk.bottom())
1237
 
                                {
1238
 
                                        ytmp = desk.bottom() - sz.height();
1239
 
                                        if (ytmp < desk.top())
1240
 
                                                ytmp = desk.top();
1241
 
                                }
1242
 
                                w->move(x, ytmp);
1243
 
                                x += sz.width();
1244
 
                                if (ytmp + sz.height() > ynext)
1245
 
                                        ynext = ytmp + sz.height();
1246
 
                        }
1247
 
                }
1248
 
        }
1249
 
        else
1250
 
        {
1251
 
                // Move all windows to the top left corner
1252
 
                for (int i = 0, end = mWindowList.count();  i < end;  ++i)
1253
 
                        mWindowList[i]->move(desk.topLeft());
1254
 
        }
1255
 
        return scatter;
 
1306
    if (instanceCount(true) <= 1)    // ignore always-hidden windows
 
1307
        return false;
 
1308
 
 
1309
    QRect desk = KAlarm::desktopWorkArea();   // get the usable area of the desktop
 
1310
    if (scatter == isSpread(desk.topLeft()))
 
1311
        return scatter;
 
1312
 
 
1313
    if (scatter)
 
1314
    {
 
1315
        // Usually there won't be many windows, so a crude
 
1316
        // scattering algorithm should suffice.
 
1317
        int x = desk.left();
 
1318
        int y = desk.top();
 
1319
        int ynext = y;
 
1320
        for (int errmsgs = 0;  errmsgs < 2;  ++errmsgs)
 
1321
        {
 
1322
            // Display alarm messages first, then error messages, since most
 
1323
            // error messages tend to be the same height.
 
1324
            for (int i = 0, end = mWindowList.count();  i < end;  ++i)
 
1325
            {
 
1326
                MessageWin* w = mWindowList[i];
 
1327
                if ((!errmsgs && w->mErrorWindow)
 
1328
                ||  (errmsgs && !w->mErrorWindow))
 
1329
                    continue;
 
1330
                QSize sz = w->frameGeometry().size();
 
1331
                if (x + sz.width() > desk.right())
 
1332
                {
 
1333
                    x = desk.left();
 
1334
                    y = ynext;
 
1335
                }
 
1336
                int ytmp = y;
 
1337
                if (y + sz.height() > desk.bottom())
 
1338
                {
 
1339
                    ytmp = desk.bottom() - sz.height();
 
1340
                    if (ytmp < desk.top())
 
1341
                        ytmp = desk.top();
 
1342
                }
 
1343
                w->move(x, ytmp);
 
1344
                x += sz.width();
 
1345
                if (ytmp + sz.height() > ynext)
 
1346
                    ynext = ytmp + sz.height();
 
1347
            }
 
1348
        }
 
1349
    }
 
1350
    else
 
1351
    {
 
1352
        // Move all windows to the top left corner
 
1353
        for (int i = 0, end = mWindowList.count();  i < end;  ++i)
 
1354
            mWindowList[i]->move(desk.topLeft());
 
1355
    }
 
1356
    return scatter;
1256
1357
}
1257
1358
 
1258
1359
/******************************************************************************
1261
1362
*/
1262
1363
bool MessageWin::isSpread(const QPoint& topLeft)
1263
1364
{
1264
 
        for (int i = 0, end = mWindowList.count();  i < end;  ++i)
1265
 
        {
1266
 
                if (mWindowList[i]->pos() != topLeft)
1267
 
                        return true;
1268
 
        }
1269
 
        return false;
 
1365
    for (int i = 0, end = mWindowList.count();  i < end;  ++i)
 
1366
    {
 
1367
        if (mWindowList[i]->pos() != topLeft)
 
1368
            return true;
 
1369
    }
 
1370
    return false;
1270
1371
}
1271
1372
 
1272
1373
/******************************************************************************
1275
1376
*/
1276
1377
MessageWin* MessageWin::findEvent(const QString& eventID)
1277
1378
{
1278
 
        if (!eventID.isEmpty())
1279
 
        {
1280
 
                for (int i = 0, end = mWindowList.count();  i < end;  ++i)
1281
 
                {
1282
 
                        MessageWin* w = mWindowList[i];
1283
 
                        if (w->mEventID == eventID  &&  !w->mErrorWindow)
1284
 
                                return w;
1285
 
                }
1286
 
        }
1287
 
        return 0;
 
1379
    if (!eventID.isEmpty())
 
1380
    {
 
1381
        for (int i = 0, end = mWindowList.count();  i < end;  ++i)
 
1382
        {
 
1383
            MessageWin* w = mWindowList[i];
 
1384
            if (w->mEventID == eventID  &&  !w->mErrorWindow)
 
1385
                return w;
 
1386
        }
 
1387
    }
 
1388
    return 0;
1288
1389
}
1289
1390
 
1290
1391
/******************************************************************************
1292
1393
*/
1293
1394
void MessageWin::playAudio()
1294
1395
{
1295
 
        if (mBeep)
1296
 
        {
1297
 
                // Beep using two methods, in case the sound card/speakers are switched off or not working
1298
 
                QApplication::beep();      // beep through the internal speaker
1299
 
                KNotification::beep();     // beep through the sound card & speakers
1300
 
        }
1301
 
        if (!mAudioFile.isEmpty())
1302
 
        {
1303
 
                if (!mVolume  &&  mFadeVolume <= 0)
1304
 
                        return;    // ensure zero volume doesn't play anything
1305
 
                startAudio();    // play the audio file
1306
 
        }
1307
 
        else if (mSpeak)
1308
 
        {
1309
 
                // The message is to be spoken. In case of error messges,
1310
 
                // call it on a timer to allow the window to display first.
1311
 
                QTimer::singleShot(0, this, SLOT(slotSpeak()));
1312
 
        }
 
1396
    if (mBeep)
 
1397
    {
 
1398
        // Beep using two methods, in case the sound card/speakers are switched off or not working
 
1399
        QApplication::beep();      // beep through the internal speaker
 
1400
        KNotification::beep();     // beep through the sound card & speakers
 
1401
    }
 
1402
    if (!mAudioFile.isEmpty())
 
1403
    {
 
1404
        if (!mVolume  &&  mFadeVolume <= 0)
 
1405
            return;    // ensure zero volume doesn't play anything
 
1406
        startAudio();    // play the audio file
 
1407
    }
 
1408
    else if (mSpeak)
 
1409
    {
 
1410
        // The message is to be spoken. In case of error messges,
 
1411
        // call it on a timer to allow the window to display first.
 
1412
        QTimer::singleShot(0, this, SLOT(slotSpeak()));
 
1413
    }
1313
1414
}
1314
1415
 
1315
1416
/******************************************************************************
1318
1419
*/
1319
1420
void MessageWin::slotSpeak()
1320
1421
{
1321
 
        QString error;
1322
 
        OrgKdeKSpeechInterface* kspeech = theApp()->kspeechInterface(error);
1323
 
        if (!kspeech)
1324
 
        {
1325
 
                if (!haveErrorMessage(ErrMsg_Speak))
1326
 
                {
1327
 
                        KMessageBox::detailedError(0, i18nc("@info", "Unable to speak message"), error);
1328
 
                        clearErrorMessage(ErrMsg_Speak);
1329
 
                }
1330
 
                return;
1331
 
        }
1332
 
        if (!kspeech->say(mMessage, 0))
1333
 
        {
1334
 
                kDebug() << "SayMessage() D-Bus error";
1335
 
                if (!haveErrorMessage(ErrMsg_Speak))
1336
 
                {
1337
 
                        KMessageBox::detailedError(0, i18nc("@info", "Unable to speak message"), i18nc("@info", "D-Bus call say() failed"));
1338
 
                        clearErrorMessage(ErrMsg_Speak);
1339
 
                }
1340
 
        }
 
1422
    QString error;
 
1423
    OrgKdeKSpeechInterface* kspeech = theApp()->kspeechInterface(error);
 
1424
    if (!kspeech)
 
1425
    {
 
1426
        if (!haveErrorMessage(ErrMsg_Speak))
 
1427
        {
 
1428
            KMessageBox::detailedError(0, i18nc("@info", "Unable to speak message"), error);
 
1429
            clearErrorMessage(ErrMsg_Speak);
 
1430
        }
 
1431
        return;
 
1432
    }
 
1433
    if (!kspeech->say(mMessage, 0))
 
1434
    {
 
1435
        kDebug() << "SayMessage() D-Bus error";
 
1436
        if (!haveErrorMessage(ErrMsg_Speak))
 
1437
        {
 
1438
            KMessageBox::detailedError(0, i18nc("@info", "Unable to speak message"), i18nc("@info", "D-Bus call say() failed"));
 
1439
            clearErrorMessage(ErrMsg_Speak);
 
1440
        }
 
1441
    }
1341
1442
}
1342
1443
 
1343
1444
/******************************************************************************
1348
1449
*/
1349
1450
void MessageWin::startAudio()
1350
1451
{
1351
 
        if (mAudioThread)
1352
 
        {
1353
 
                // An audio file is already playing for another message
1354
 
                // window, so wait until it has finished.
1355
 
                connect(mAudioThread, SIGNAL(destroyed(QObject*)), SLOT(audioTerminating()));
1356
 
        }
1357
 
        else
1358
 
        {
1359
 
                kDebug() << QThread::currentThread();
1360
 
                theApp()->notifyAudioPlaying(true);
1361
 
                mAudioThread = new AudioThread(this, mAudioFile, mVolume, mFadeVolume, mFadeSeconds, mAudioRepeat);
1362
 
                mAudioOwner = this;
1363
 
                connect(mAudioThread, SIGNAL(readyToPlay()), SLOT(playReady()));
1364
 
                connect(mAudioThread, SIGNAL(finished()), SLOT(playFinished()));
1365
 
                if (mSilenceButton)
1366
 
                        connect(mSilenceButton, SIGNAL(clicked()), mAudioThread, SLOT(quit()));
1367
 
                mAudioThread->start();
1368
 
        }
 
1452
    if (mAudioThread)
 
1453
    {
 
1454
        // An audio file is already playing for another message
 
1455
        // window, so wait until it has finished.
 
1456
        connect(mAudioThread, SIGNAL(destroyed(QObject*)), SLOT(audioTerminating()));
 
1457
    }
 
1458
    else
 
1459
    {
 
1460
        kDebug() << QThread::currentThread();
 
1461
        theApp()->notifyAudioPlaying(true);
 
1462
        mAudioThread = new AudioThread(this, mAudioFile, mVolume, mFadeVolume, mFadeSeconds, mAudioRepeat);
 
1463
        mAudioOwner = this;
 
1464
        connect(mAudioThread, SIGNAL(readyToPlay()), SLOT(playReady()));
 
1465
        connect(mAudioThread, SIGNAL(finished()), SLOT(playFinished()));
 
1466
        if (mSilenceButton)
 
1467
            connect(mSilenceButton, SIGNAL(clicked()), mAudioThread, SLOT(quit()));
 
1468
        mAudioThread->start();
 
1469
    }
1369
1470
}
1370
1471
 
1371
1472
/******************************************************************************
1373
1474
*/
1374
1475
bool MessageWin::isAudioPlaying()
1375
1476
{
1376
 
        return mAudioThread;
 
1477
    return mAudioThread;
1377
1478
}
1378
1479
 
1379
1480
/******************************************************************************
1381
1482
*/
1382
1483
void MessageWin::stopAudio(bool wait)
1383
1484
{
1384
 
        kDebug();
1385
 
        if (mAudioThread)
1386
 
                mAudioThread->stop(wait);
 
1485
    kDebug();
 
1486
    if (mAudioThread)
 
1487
        mAudioThread->stop(wait);
1387
1488
}
1388
1489
 
1389
1490
/******************************************************************************
1392
1493
*/
1393
1494
void MessageWin::audioTerminating()
1394
1495
{
1395
 
        QTimer::singleShot(0, this, SLOT(startAudio()));
 
1496
    QTimer::singleShot(0, this, SLOT(startAudio()));
1396
1497
}
1397
1498
 
1398
1499
/******************************************************************************
1400
1501
*/
1401
1502
void MessageWin::playReady()
1402
1503
{
1403
 
        if (mSilenceButton)
1404
 
                mSilenceButton->setEnabled(true);
 
1504
    if (mSilenceButton)
 
1505
        mSilenceButton->setEnabled(true);
1405
1506
}
1406
1507
 
1407
1508
/******************************************************************************
1409
1510
*/
1410
1511
void MessageWin::playFinished()
1411
1512
{
1412
 
        if (mSilenceButton)
1413
 
                mSilenceButton->setEnabled(false);
1414
 
        if (!mAudioThread->error().isEmpty())
1415
 
        {
1416
 
                if (!haveErrorMessage(ErrMsg_AudioFile))
1417
 
                {
1418
 
                        KMessageBox::error(this, mAudioThread->error());
1419
 
                        clearErrorMessage(ErrMsg_AudioFile);
1420
 
                }
1421
 
        }
1422
 
        theApp()->notifyAudioPlaying(false);
1423
 
        delete mAudioThread;
1424
 
        mAudioOwner = 0;
1425
 
        if (mAlwaysHide)
1426
 
                close();
 
1513
    if (mSilenceButton)
 
1514
        mSilenceButton->setEnabled(false);
 
1515
    if (!mAudioThread->error().isEmpty())
 
1516
    {
 
1517
        if (!haveErrorMessage(ErrMsg_AudioFile))
 
1518
        {
 
1519
            KMessageBox::error(this, mAudioThread->error());
 
1520
            clearErrorMessage(ErrMsg_AudioFile);
 
1521
        }
 
1522
    }
 
1523
    theApp()->notifyAudioPlaying(false);
 
1524
    delete mAudioThread;
 
1525
    mAudioOwner = 0;
 
1526
    if (mAlwaysHide)
 
1527
        close();
1427
1528
}
1428
1529
 
1429
1530
/******************************************************************************
1432
1533
*/
1433
1534
AudioThread::~AudioThread()
1434
1535
{
1435
 
        kDebug();
1436
 
        stop(true);   // stop playing and tidy up (timeout 3 seconds)
1437
 
        delete mAudioObject;
1438
 
        mAudioObject = 0;
 
1536
    kDebug();
 
1537
    stop(true);   // stop playing and tidy up (timeout 3 seconds)
 
1538
    delete mAudioObject;
 
1539
    mAudioObject = 0;
1439
1540
}
1440
1541
 
1441
1542
/******************************************************************************
1443
1544
*/
1444
1545
void AudioThread::stop(bool waiT)
1445
1546
{
1446
 
        kDebug();
1447
 
        quit();       // stop playing and tidy up
1448
 
        wait(3000);   // wait for run() to exit (timeout 3 seconds)
1449
 
        if (!isFinished())
1450
 
        {
1451
 
                // Something has gone wrong - forcibly kill the thread
1452
 
                terminate();
1453
 
                if (waiT)
1454
 
                        wait();
1455
 
        }
 
1547
    kDebug();
 
1548
    quit();       // stop playing and tidy up
 
1549
    wait(3000);   // wait for run() to exit (timeout 3 seconds)
 
1550
    if (!isFinished())
 
1551
    {
 
1552
        // Something has gone wrong - forcibly kill the thread
 
1553
        terminate();
 
1554
        if (waiT)
 
1555
            wait();
 
1556
    }
1456
1557
}
1457
1558
 
1458
1559
/******************************************************************************
1460
1561
*/
1461
1562
void AudioThread::run()
1462
1563
{
1463
 
        mMutex.lock();
1464
 
        if (mAudioObject)
1465
 
        {
1466
 
                mMutex.unlock();
1467
 
                return;
1468
 
        }
1469
 
        kDebug() << QThread::currentThread() << mFile;
1470
 
        QString audioFile = mFile;
1471
 
        mFile = KAlarm::pathOrUrl(mFile);
1472
 
        Phonon::MediaSource source(audioFile);
1473
 
        if (source.type() == Phonon::MediaSource::Invalid)
1474
 
        {
1475
 
                mError = i18nc("@info", "Cannot open audio file: <filename>%1</filename>", audioFile);
1476
 
                mMutex.unlock();
1477
 
                kError() << "Open failure:" << audioFile;
1478
 
                return;
1479
 
        }
1480
 
        mAudioObject = new Phonon::MediaObject();
1481
 
        mAudioObject->setCurrentSource(source);
1482
 
        mAudioObject->setTransitionTime(100);   // workaround to prevent clipping of end of files in Xine backend
1483
 
        Phonon::AudioOutput* output = new Phonon::AudioOutput(Phonon::NotificationCategory, mAudioObject);
1484
 
        mPath = Phonon::createPath(mAudioObject, output);
1485
 
        if (mVolume >= 0  ||  mFadeVolume >= 0)
1486
 
        {
1487
 
                float vol = (mVolume >= 0) ? mVolume : output->volume();
1488
 
                float maxvol = qMax(vol, mFadeVolume);
1489
 
                output->setVolume(maxvol);
1490
 
                if (mFadeVolume >= 0  &&  mFadeSeconds > 0)
1491
 
                {
1492
 
                        Phonon::VolumeFaderEffect* fader = new Phonon::VolumeFaderEffect(mAudioObject);
1493
 
                        fader->setVolume(mFadeVolume / maxvol);
1494
 
                        fader->fadeTo(mVolume / maxvol, mFadeSeconds * 1000);
1495
 
                        mPath.insertEffect(fader);
1496
 
                }
1497
 
        }
1498
 
        connect(mAudioObject, SIGNAL(stateChanged(Phonon::State, Phonon::State)), SLOT(playStateChanged(Phonon::State)), Qt::DirectConnection);
1499
 
        connect(mAudioObject, SIGNAL(finished()), SLOT(checkAudioPlay()), Qt::DirectConnection);
1500
 
        mPlayedOnce = false;
1501
 
        mMutex.unlock();
1502
 
        emit readyToPlay();
1503
 
        checkAudioPlay();
 
1564
    mMutex.lock();
 
1565
    if (mAudioObject)
 
1566
    {
 
1567
        mMutex.unlock();
 
1568
        return;
 
1569
    }
 
1570
    kDebug() << QThread::currentThread() << mFile;
 
1571
    QString audioFile = mFile;
 
1572
    mFile = KAlarm::pathOrUrl(mFile);
 
1573
    Phonon::MediaSource source(audioFile);
 
1574
    if (source.type() == Phonon::MediaSource::Invalid)
 
1575
    {
 
1576
        mError = i18nc("@info", "Cannot open audio file: <filename>%1</filename>", audioFile);
 
1577
        mMutex.unlock();
 
1578
        kError() << "Open failure:" << audioFile;
 
1579
        return;
 
1580
    }
 
1581
    mAudioObject = new Phonon::MediaObject();
 
1582
    mAudioObject->setCurrentSource(source);
 
1583
    mAudioObject->setTransitionTime(100);   // workaround to prevent clipping of end of files in Xine backend
 
1584
    Phonon::AudioOutput* output = new Phonon::AudioOutput(Phonon::NotificationCategory, mAudioObject);
 
1585
    mPath = Phonon::createPath(mAudioObject, output);
 
1586
    if (mVolume >= 0  ||  mFadeVolume >= 0)
 
1587
    {
 
1588
        float vol = (mVolume >= 0) ? mVolume : output->volume();
 
1589
        float maxvol = qMax(vol, mFadeVolume);
 
1590
        output->setVolume(maxvol);
 
1591
        if (mFadeVolume >= 0  &&  mFadeSeconds > 0)
 
1592
        {
 
1593
            Phonon::VolumeFaderEffect* fader = new Phonon::VolumeFaderEffect(mAudioObject);
 
1594
            fader->setVolume(mFadeVolume / maxvol);
 
1595
            fader->fadeTo(mVolume / maxvol, mFadeSeconds * 1000);
 
1596
            mPath.insertEffect(fader);
 
1597
        }
 
1598
    }
 
1599
    connect(mAudioObject, SIGNAL(stateChanged(Phonon::State, Phonon::State)), SLOT(playStateChanged(Phonon::State)), Qt::DirectConnection);
 
1600
    connect(mAudioObject, SIGNAL(finished()), SLOT(checkAudioPlay()), Qt::DirectConnection);
 
1601
    mPlayedOnce = false;
 
1602
    mMutex.unlock();
 
1603
    emit readyToPlay();
 
1604
    checkAudioPlay();
1504
1605
 
1505
 
        // Start an event loop.
1506
 
        // The function will exit once exit() or quit() is called.
1507
 
        exec();
1508
 
        stopPlay();
 
1606
    // Start an event loop.
 
1607
    // The function will exit once exit() or quit() is called.
 
1608
    exec();
 
1609
    stopPlay();
1509
1610
}
1510
1611
 
1511
1612
/******************************************************************************
1516
1617
*/
1517
1618
void AudioThread::checkAudioPlay()
1518
1619
{
1519
 
        mMutex.lock();
1520
 
        if (!mAudioObject)
1521
 
        {
1522
 
                mMutex.unlock();
1523
 
                return;
1524
 
        }
1525
 
        // The file has loaded and is ready to play, or play has completed
1526
 
        if (mPlayedOnce  &&  !mRepeat)
1527
 
        {
1528
 
                // Play has completed
1529
 
                mMutex.unlock();
1530
 
                stopPlay();
1531
 
                return;
1532
 
        }
1533
 
        mPlayedOnce = true;
 
1620
    mMutex.lock();
 
1621
    if (!mAudioObject)
 
1622
    {
 
1623
        mMutex.unlock();
 
1624
        return;
 
1625
    }
 
1626
    // The file has loaded and is ready to play, or play has completed
 
1627
    if (mPlayedOnce  &&  !mRepeat)
 
1628
    {
 
1629
        // Play has completed
 
1630
        mMutex.unlock();
 
1631
        stopPlay();
 
1632
        return;
 
1633
    }
 
1634
    mPlayedOnce = true;
1534
1635
 
1535
 
        // Start playing the file, either for the first time or again
1536
 
        kDebug() << "start";
1537
 
        mAudioObject->play();
1538
 
        mMutex.unlock();
 
1636
    // Start playing the file, either for the first time or again
 
1637
    kDebug() << "start";
 
1638
    mAudioObject->play();
 
1639
    mMutex.unlock();
1539
1640
}
1540
1641
 
1541
1642
/******************************************************************************
1544
1645
*/
1545
1646
void AudioThread::playStateChanged(Phonon::State newState)
1546
1647
{
1547
 
        if (newState == Phonon::ErrorState)
1548
 
        {
1549
 
                QMutexLocker locker(&mMutex);
1550
 
                QString err = mAudioObject->errorString();
1551
 
                if (!err.isEmpty())
1552
 
                {
1553
 
                        kError() << "Play failure:" << mFile << ":" << err;
1554
 
                        mError = i18nc("@info", "<para>Error playing audio file: <filename>%1</filename></para><para>%2</para>", mFile, err);
1555
 
                        exit(1);
1556
 
                }
1557
 
        }
 
1648
    if (newState == Phonon::ErrorState)
 
1649
    {
 
1650
        QMutexLocker locker(&mMutex);
 
1651
        QString err = mAudioObject->errorString();
 
1652
        if (!err.isEmpty())
 
1653
        {
 
1654
            kError() << "Play failure:" << mFile << ":" << err;
 
1655
            mError = i18nc("@info", "<para>Error playing audio file: <filename>%1</filename></para><para>%2</para>", mFile, err);
 
1656
            exit(1);
 
1657
        }
 
1658
    }
1558
1659
}
1559
1660
 
1560
1661
/******************************************************************************
1563
1664
*/
1564
1665
void AudioThread::stopPlay()
1565
1666
{
1566
 
        mMutex.lock();
1567
 
        if (mAudioObject)
1568
 
        {
1569
 
                mAudioObject->stop();
1570
 
                QList<Phonon::Effect*> effects = mPath.effects();
1571
 
                for (int i = 0;  i < effects.count();  ++i)
1572
 
                {
1573
 
                        mPath.removeEffect(effects[i]);
1574
 
                        delete effects[i];
1575
 
                }
1576
 
                delete mAudioObject;
1577
 
                mAudioObject = 0;
1578
 
        }
1579
 
        mMutex.unlock();
1580
 
        quit();   // exit the event loop, if it's still running
 
1667
    mMutex.lock();
 
1668
    if (mAudioObject)
 
1669
    {
 
1670
        mAudioObject->stop();
 
1671
        QList<Phonon::Effect*> effects = mPath.effects();
 
1672
        for (int i = 0;  i < effects.count();  ++i)
 
1673
        {
 
1674
            mPath.removeEffect(effects[i]);
 
1675
            delete effects[i];
 
1676
        }
 
1677
        delete mAudioObject;
 
1678
        mAudioObject = 0;
 
1679
    }
 
1680
    mMutex.unlock();
 
1681
    quit();   // exit the event loop, if it's still running
1581
1682
}
1582
1683
 
1583
1684
QString AudioThread::error() const
1584
1685
{
1585
 
        QMutexLocker locker(&mMutex);
1586
 
        return mError;
 
1686
    QMutexLocker locker(&mMutex);
 
1687
    return mError;
1587
1688
}
1588
1689
 
1589
1690
/******************************************************************************
1592
1693
*/
1593
1694
void MessageWin::repeat(const KAAlarm& alarm)
1594
1695
{
1595
 
        if (!mInitialised)
1596
 
                return;
1597
 
        if (mDeferDlg)
1598
 
        {
1599
 
                // Cancel any deferral dialog so that the user notices something's going on,
1600
 
                // and also because the deferral time limit will have changed.
1601
 
                delete mDeferDlg;
1602
 
                mDeferDlg = 0;
1603
 
        }
1604
 
        KAEvent* event = mEventID.isNull() ? 0 : AlarmCalendar::resources()->event(mEventID);
1605
 
        if (event)
1606
 
        {
1607
 
                mAlarmType = alarm.type();    // store new alarm type for use if it is later deferred
1608
 
                if (mAlwaysHide)
1609
 
                        playAudio();
1610
 
                else
1611
 
                {
1612
 
                        if (!mDeferDlg  ||  Preferences::modalMessages())
1613
 
                        {
1614
 
                                raise();
1615
 
                                playAudio();
1616
 
                        }
1617
 
                        if (mDeferButton->isVisible())
1618
 
                        {
1619
 
                                mDeferButton->setEnabled(true);
1620
 
                                setDeferralLimit(*event);    // ensure that button is disabled when alarm can't be deferred any more
1621
 
                        }
1622
 
                }
1623
 
                alarmShowing(*event);
1624
 
        }
 
1696
    if (!mInitialised)
 
1697
        return;
 
1698
    if (mDeferDlg)
 
1699
    {
 
1700
        // Cancel any deferral dialog so that the user notices something's going on,
 
1701
        // and also because the deferral time limit will have changed.
 
1702
        delete mDeferDlg;
 
1703
        mDeferDlg = 0;
 
1704
    }
 
1705
    KAEvent* event = mEventID.isNull() ? 0 : AlarmCalendar::resources()->event(mEventID);
 
1706
    if (event)
 
1707
    {
 
1708
        mAlarmType = alarm.type();    // store new alarm type for use if it is later deferred
 
1709
        if (mAlwaysHide)
 
1710
            playAudio();
 
1711
        else
 
1712
        {
 
1713
            if (!mDeferDlg  ||  Preferences::modalMessages())
 
1714
            {
 
1715
                raise();
 
1716
                playAudio();
 
1717
            }
 
1718
            if (mDeferButton->isVisible())
 
1719
            {
 
1720
                mDeferButton->setEnabled(true);
 
1721
                setDeferralLimit(*event);    // ensure that button is disabled when alarm can't be deferred any more
 
1722
            }
 
1723
        }
 
1724
        alarmShowing(*event);
 
1725
    }
1625
1726
}
1626
1727
 
1627
1728
/******************************************************************************
1632
1733
*/
1633
1734
void MessageWin::show()
1634
1735
{
1635
 
        if (mCloseTime.isValid())
1636
 
        {
1637
 
                // Set a timer to auto-close the window
1638
 
                int delay = KDateTime::currentLocalDateTime().dateTime().secsTo(mCloseTime);
1639
 
                if (delay < 0)
1640
 
                        delay = 0;
1641
 
                QTimer::singleShot(delay * 1000, this, SLOT(close()));
1642
 
                if (!delay)
1643
 
                        return;    // don't show the window if auto-closing is already due
1644
 
        }
1645
 
        if (Preferences::messageButtonDelay() == 0)
1646
 
                move(0, 0);
1647
 
        MainWindowBase::show();
 
1736
    if (mCloseTime.isValid())
 
1737
    {
 
1738
        // Set a timer to auto-close the window
 
1739
        int delay = KDateTime::currentLocalDateTime().dateTime().secsTo(mCloseTime);
 
1740
        if (delay < 0)
 
1741
            delay = 0;
 
1742
        QTimer::singleShot(delay * 1000, this, SLOT(close()));
 
1743
        if (!delay)
 
1744
            return;    // don't show the window if auto-closing is already due
 
1745
    }
 
1746
    if (Preferences::messageButtonDelay() == 0)
 
1747
        move(0, 0);
 
1748
    MainWindowBase::show();
1648
1749
}
1649
1750
 
1650
1751
/******************************************************************************
1652
1753
*/
1653
1754
QSize MessageWin::sizeHint() const
1654
1755
{
1655
 
        QSize desired;
1656
 
        switch (mAction)
1657
 
        {
1658
 
                case KAEventData::MESSAGE:
1659
 
                        desired = MainWindowBase::sizeHint();
1660
 
                        break;
1661
 
                case KAEventData::COMMAND:
1662
 
                        if (mShown)
1663
 
                        {
1664
 
                                // For command output, expand the window to accommodate the text
1665
 
                                QSize texthint = mCommandText->sizeHint();
1666
 
                                int w = texthint.width() + 2*KDialog::marginHint();
1667
 
                                if (w < width())
1668
 
                                        w = width();
1669
 
                                int ypadding = height() - mCommandText->height();
1670
 
                                desired = QSize(w, texthint.height() + ypadding);
1671
 
                                break;
1672
 
                        }
1673
 
                        // fall through to default
1674
 
                default:
1675
 
                        return MainWindowBase::sizeHint();
1676
 
        }
 
1756
    QSize desired;
 
1757
    switch (mAction)
 
1758
    {
 
1759
        case KAEvent::MESSAGE:
 
1760
            desired = MainWindowBase::sizeHint();
 
1761
            break;
 
1762
        case KAEvent::COMMAND:
 
1763
            if (mShown)
 
1764
            {
 
1765
                // For command output, expand the window to accommodate the text
 
1766
                QSize texthint = mCommandText->sizeHint();
 
1767
                int w = texthint.width() + 2*KDialog::marginHint();
 
1768
                if (w < width())
 
1769
                    w = width();
 
1770
                int ypadding = height() - mCommandText->height();
 
1771
                desired = QSize(w, texthint.height() + ypadding);
 
1772
                break;
 
1773
            }
 
1774
            // fall through to default
 
1775
        default:
 
1776
            return MainWindowBase::sizeHint();
 
1777
    }
1677
1778
 
1678
 
        // Limit the size to fit inside the working area of the desktop
1679
 
        QSize desktop  = KAlarm::desktopWorkArea(mScreenNumber).size();
1680
 
        QSize frameThickness = frameGeometry().size() - geometry().size();  // title bar & window frame
1681
 
        return desired.boundedTo(desktop - frameThickness);
 
1779
    // Limit the size to fit inside the working area of the desktop
 
1780
    QSize desktop  = KAlarm::desktopWorkArea(mScreenNumber).size();
 
1781
    QSize frameThickness = frameGeometry().size() - geometry().size();  // title bar & window frame
 
1782
    return desired.boundedTo(desktop - frameThickness);
1682
1783
}
1683
1784
 
1684
1785
/******************************************************************************
1688
1789
*/
1689
1790
void MessageWin::showEvent(QShowEvent* se)
1690
1791
{
1691
 
        MainWindowBase::showEvent(se);
1692
 
        if (mShown)
1693
 
                return;
1694
 
        if (mErrorWindow  ||  mAlarmType == KAAlarm::INVALID_ALARM)
1695
 
        {
1696
 
                // Don't bother repositioning error messages,
1697
 
                // and invalid alarms should be deleted anyway.
1698
 
                enableButtons();
1699
 
        }
1700
 
        else
1701
 
        {
1702
 
                /* Set the window size.
1703
 
                 * Note that the frame thickness is not yet known when this
1704
 
                 * method is called, so for large windows the size needs to be
1705
 
                 * set again later.
1706
 
                 */
1707
 
                bool execComplete = true;
1708
 
                QSize s = sizeHint();     // fit the window round the message
1709
 
                if (mAction == KAEventData::FILE  &&  !mErrorMsgs.count())
1710
 
                        KAlarm::readConfigWindowSize("FileMessage", s);
1711
 
                resize(s);
1712
 
 
1713
 
                QRect desk = KAlarm::desktopWorkArea(mScreenNumber);
1714
 
                QRect frame = frameGeometry();
1715
 
 
1716
 
                mButtonDelay = Preferences::messageButtonDelay() * 1000;
1717
 
                if (mButtonDelay)
1718
 
                {
1719
 
                        // Position the window in the middle of the screen, and
1720
 
                        // delay enabling the buttons.
1721
 
                        mPositioning = true;
1722
 
                        move((desk.width() - frame.width())/2, (desk.height() - frame.height())/2);
1723
 
                        execComplete = false;
1724
 
                }
1725
 
                else
1726
 
                {
1727
 
                        /* Try to ensure that the window can't accidentally be acknowledged
1728
 
                         * by the user clicking the mouse just as it appears.
1729
 
                         * To achieve this, move the window so that the OK button is as far away
1730
 
                         * from the cursor as possible. If the buttons are still too close to the
1731
 
                         * cursor, disable the buttons for a short time.
1732
 
                         * N.B. This can't be done in show(), since the geometry of the window
1733
 
                         *      is not known until it is displayed. Unfortunately by moving the
1734
 
                         *      window in showEvent(), a flicker is unavoidable.
1735
 
                         *      See the Qt documentation on window geometry for more details.
1736
 
                         */
1737
 
                        // PROBLEM: The frame size is not known yet!
1738
 
                        QPoint cursor = QCursor::pos();
1739
 
                        QRect rect  = geometry();
1740
 
                        // Find the offsets from the outside of the frame to the edges of the OK button
1741
 
                        QRect button(mOkButton->mapToParent(QPoint(0, 0)), mOkButton->mapToParent(mOkButton->rect().bottomRight()));
1742
 
                        int buttonLeft   = button.left() + rect.left() - frame.left();
1743
 
                        int buttonRight  = width() - button.right() + frame.right() - rect.right();
1744
 
                        int buttonTop    = button.top() + rect.top() - frame.top();
1745
 
                        int buttonBottom = height() - button.bottom() + frame.bottom() - rect.bottom();
1746
 
 
1747
 
                        int centrex = (desk.width() + buttonLeft - buttonRight) / 2;
1748
 
                        int centrey = (desk.height() + buttonTop - buttonBottom) / 2;
1749
 
                        int x = (cursor.x() < centrex) ? desk.right() - frame.width() : desk.left();
1750
 
                        int y = (cursor.y() < centrey) ? desk.bottom() - frame.height() : desk.top();
1751
 
 
1752
 
                        // Find the enclosing rectangle for the new button positions
1753
 
                        // and check if the cursor is too near
1754
 
                        QRect buttons = mOkButton->geometry().unite(mKAlarmButton->geometry());
1755
 
                        buttons.translate(rect.left() + x - frame.left(), rect.top() + y - frame.top());
1756
 
                        int minDistance = proximityMultiple * mOkButton->height();
1757
 
                        if ((abs(cursor.x() - buttons.left()) < minDistance
1758
 
                          || abs(cursor.x() - buttons.right()) < minDistance)
1759
 
                        &&  (abs(cursor.y() - buttons.top()) < minDistance
1760
 
                          || abs(cursor.y() - buttons.bottom()) < minDistance))
1761
 
                                mButtonDelay = proximityButtonDelay;    // too near - disable buttons initially
1762
 
 
1763
 
                        if (x != frame.left()  ||  y != frame.top())
1764
 
                        {
1765
 
                                mPositioning = true;
1766
 
                                move(x, y);
1767
 
                                execComplete = false;
1768
 
                        }
1769
 
                }
1770
 
                if (execComplete)
1771
 
                        displayComplete();    // play audio, etc.
1772
 
        }
1773
 
 
1774
 
        // Set the window size etc. once the frame size is known
1775
 
        QTimer::singleShot(0, this, SLOT(frameDrawn()));
1776
 
 
1777
 
        mShown = true;
 
1792
    MainWindowBase::showEvent(se);
 
1793
    if (mShown)
 
1794
        return;
 
1795
    if (mErrorWindow  ||  mAlarmType == KAAlarm::INVALID_ALARM)
 
1796
    {
 
1797
        // Don't bother repositioning error messages,
 
1798
        // and invalid alarms should be deleted anyway.
 
1799
        enableButtons();
 
1800
    }
 
1801
    else
 
1802
    {
 
1803
        /* Set the window size.
 
1804
         * Note that the frame thickness is not yet known when this
 
1805
         * method is called, so for large windows the size needs to be
 
1806
         * set again later.
 
1807
         */
 
1808
        bool execComplete = true;
 
1809
        QSize s = sizeHint();     // fit the window round the message
 
1810
        if (mAction == KAEvent::FILE  &&  !mErrorMsgs.count())
 
1811
            KAlarm::readConfigWindowSize("FileMessage", s);
 
1812
        resize(s);
 
1813
 
 
1814
        QRect desk = KAlarm::desktopWorkArea(mScreenNumber);
 
1815
        QRect frame = frameGeometry();
 
1816
 
 
1817
        mButtonDelay = Preferences::messageButtonDelay() * 1000;
 
1818
        if (mButtonDelay)
 
1819
        {
 
1820
            // Position the window in the middle of the screen, and
 
1821
            // delay enabling the buttons.
 
1822
            mPositioning = true;
 
1823
            move((desk.width() - frame.width())/2, (desk.height() - frame.height())/2);
 
1824
            execComplete = false;
 
1825
        }
 
1826
        else
 
1827
        {
 
1828
            /* Try to ensure that the window can't accidentally be acknowledged
 
1829
             * by the user clicking the mouse just as it appears.
 
1830
             * To achieve this, move the window so that the OK button is as far away
 
1831
             * from the cursor as possible. If the buttons are still too close to the
 
1832
             * cursor, disable the buttons for a short time.
 
1833
             * N.B. This can't be done in show(), since the geometry of the window
 
1834
             *      is not known until it is displayed. Unfortunately by moving the
 
1835
             *      window in showEvent(), a flicker is unavoidable.
 
1836
             *      See the Qt documentation on window geometry for more details.
 
1837
             */
 
1838
            // PROBLEM: The frame size is not known yet!
 
1839
            QPoint cursor = QCursor::pos();
 
1840
            QRect rect  = geometry();
 
1841
            // Find the offsets from the outside of the frame to the edges of the OK button
 
1842
            QRect button(mOkButton->mapToParent(QPoint(0, 0)), mOkButton->mapToParent(mOkButton->rect().bottomRight()));
 
1843
            int buttonLeft   = button.left() + rect.left() - frame.left();
 
1844
            int buttonRight  = width() - button.right() + frame.right() - rect.right();
 
1845
            int buttonTop    = button.top() + rect.top() - frame.top();
 
1846
            int buttonBottom = height() - button.bottom() + frame.bottom() - rect.bottom();
 
1847
 
 
1848
            int centrex = (desk.width() + buttonLeft - buttonRight) / 2;
 
1849
            int centrey = (desk.height() + buttonTop - buttonBottom) / 2;
 
1850
            int x = (cursor.x() < centrex) ? desk.right() - frame.width() : desk.left();
 
1851
            int y = (cursor.y() < centrey) ? desk.bottom() - frame.height() : desk.top();
 
1852
 
 
1853
            // Find the enclosing rectangle for the new button positions
 
1854
            // and check if the cursor is too near
 
1855
            QRect buttons = mOkButton->geometry().unite(mKAlarmButton->geometry());
 
1856
            buttons.translate(rect.left() + x - frame.left(), rect.top() + y - frame.top());
 
1857
            int minDistance = proximityMultiple * mOkButton->height();
 
1858
            if ((abs(cursor.x() - buttons.left()) < minDistance
 
1859
              || abs(cursor.x() - buttons.right()) < minDistance)
 
1860
            &&  (abs(cursor.y() - buttons.top()) < minDistance
 
1861
              || abs(cursor.y() - buttons.bottom()) < minDistance))
 
1862
                mButtonDelay = proximityButtonDelay;    // too near - disable buttons initially
 
1863
 
 
1864
            if (x != frame.left()  ||  y != frame.top())
 
1865
            {
 
1866
                mPositioning = true;
 
1867
                move(x, y);
 
1868
                execComplete = false;
 
1869
            }
 
1870
        }
 
1871
        if (execComplete)
 
1872
            displayComplete();    // play audio, etc.
 
1873
    }
 
1874
 
 
1875
    // Set the window size etc. once the frame size is known
 
1876
    QTimer::singleShot(0, this, SLOT(frameDrawn()));
 
1877
 
 
1878
    mShown = true;
1778
1879
}
1779
1880
 
1780
1881
/******************************************************************************
1782
1883
*/
1783
1884
void MessageWin::moveEvent(QMoveEvent* e)
1784
1885
{
1785
 
        MainWindowBase::moveEvent(e);
1786
 
        theApp()->setSpreadWindowsState(isSpread(KAlarm::desktopWorkArea(mScreenNumber).topLeft()));
1787
 
        if (mPositioning)
1788
 
        {
1789
 
                // The window has just been initially positioned
1790
 
                mPositioning = false;
1791
 
                displayComplete();    // play audio, etc.
1792
 
        }
 
1886
    MainWindowBase::moveEvent(e);
 
1887
    theApp()->setSpreadWindowsState(isSpread(KAlarm::desktopWorkArea(mScreenNumber).topLeft()));
 
1888
    if (mPositioning)
 
1889
    {
 
1890
        // The window has just been initially positioned
 
1891
        mPositioning = false;
 
1892
        displayComplete();    // play audio, etc.
 
1893
    }
1793
1894
}
1794
1895
 
1795
1896
/******************************************************************************
1799
1900
*/
1800
1901
void MessageWin::frameDrawn()
1801
1902
{
1802
 
        if (!mErrorWindow  &&  mAction == KAEventData::MESSAGE)
1803
 
        {
1804
 
                QSize s = sizeHint();
1805
 
                if (width() > s.width()  ||  height() > s.height())
1806
 
                        resize(s);
1807
 
        }
1808
 
        theApp()->setSpreadWindowsState(isSpread(KAlarm::desktopWorkArea(mScreenNumber).topLeft()));
 
1903
    if (!mErrorWindow  &&  mAction == KAEvent::MESSAGE)
 
1904
    {
 
1905
        QSize s = sizeHint();
 
1906
        if (width() > s.width()  ||  height() > s.height())
 
1907
            resize(s);
 
1908
    }
 
1909
    theApp()->setSpreadWindowsState(isSpread(KAlarm::desktopWorkArea(mScreenNumber).topLeft()));
1809
1910
}
1810
1911
 
1811
1912
/******************************************************************************
1814
1915
*/
1815
1916
void MessageWin::displayComplete()
1816
1917
{
1817
 
        playAudio();
1818
 
        if (mRescheduleEvent)
1819
 
                alarmShowing(mEvent);
 
1918
    playAudio();
 
1919
    if (mRescheduleEvent)
 
1920
        alarmShowing(mEvent);
1820
1921
 
1821
 
        if (!mAlwaysHide)
1822
 
        {
1823
 
                // Enable the window's buttons either now or after the configured delay
1824
 
                if (mButtonDelay > 0)
1825
 
                        QTimer::singleShot(mButtonDelay, this, SLOT(enableButtons()));
1826
 
                else
1827
 
                        enableButtons();
1828
 
        }
 
1922
    if (!mAlwaysHide)
 
1923
    {
 
1924
        // Enable the window's buttons either now or after the configured delay
 
1925
        if (mButtonDelay > 0)
 
1926
            QTimer::singleShot(mButtonDelay, this, SLOT(enableButtons()));
 
1927
        else
 
1928
            enableButtons();
 
1929
    }
1829
1930
}
1830
1931
 
1831
1932
/******************************************************************************
1833
1934
*/
1834
1935
void MessageWin::enableButtons()
1835
1936
{
1836
 
        mOkButton->setEnabled(true);
1837
 
        mKAlarmButton->setEnabled(true);
1838
 
        if (mDeferButton->isVisible()  &&  !mDisableDeferral)
1839
 
                mDeferButton->setEnabled(true);
1840
 
        if (mEditButton)
1841
 
                mEditButton->setEnabled(true);
1842
 
        if (mKMailButton)
1843
 
                mKMailButton->setEnabled(true);
 
1937
    mOkButton->setEnabled(true);
 
1938
    mKAlarmButton->setEnabled(true);
 
1939
    if (mDeferButton->isVisible()  &&  !mDisableDeferral)
 
1940
        mDeferButton->setEnabled(true);
 
1941
    if (mEditButton)
 
1942
        mEditButton->setEnabled(true);
 
1943
    if (mKMailButton)
 
1944
        mKMailButton->setEnabled(true);
1844
1945
}
1845
1946
 
1846
1947
/******************************************************************************
1848
1949
*/
1849
1950
void MessageWin::resizeEvent(QResizeEvent* re)
1850
1951
{
1851
 
        if (mRestoreHeight)
1852
 
        {
1853
 
                // Restore the window height on session restoration
1854
 
                if (mRestoreHeight != re->size().height())
1855
 
                {
1856
 
                        QSize size = re->size();
1857
 
                        size.setHeight(mRestoreHeight);
1858
 
                        resize(size);
1859
 
                }
1860
 
                else if (isVisible())
1861
 
                        mRestoreHeight = 0;
1862
 
        }
1863
 
        else
1864
 
        {
1865
 
                if (mShown  &&  mAction == KAEventData::FILE  &&  !mErrorMsgs.count())
1866
 
                        KAlarm::writeConfigWindowSize("FileMessage", re->size());
1867
 
                MainWindowBase::resizeEvent(re);
1868
 
        }
 
1952
    if (mRestoreHeight)
 
1953
    {
 
1954
        // Restore the window height on session restoration
 
1955
        if (mRestoreHeight != re->size().height())
 
1956
        {
 
1957
            QSize size = re->size();
 
1958
            size.setHeight(mRestoreHeight);
 
1959
            resize(size);
 
1960
        }
 
1961
        else if (isVisible())
 
1962
            mRestoreHeight = 0;
 
1963
    }
 
1964
    else
 
1965
    {
 
1966
        if (mShown  &&  mAction == KAEvent::FILE  &&  !mErrorMsgs.count())
 
1967
            KAlarm::writeConfigWindowSize("FileMessage", re->size());
 
1968
        MainWindowBase::resizeEvent(re);
 
1969
    }
1869
1970
}
1870
1971
 
1871
1972
/******************************************************************************
1874
1975
*/
1875
1976
void MessageWin::closeEvent(QCloseEvent* ce)
1876
1977
{
1877
 
        // Don't prompt or delete the alarm from the display calendar if the session is closing
1878
 
        if (!mErrorWindow  &&  !theApp()->sessionClosingDown())
1879
 
        {
1880
 
                if (mConfirmAck  &&  !mNoCloseConfirm)
1881
 
                {
1882
 
                        // Ask for confirmation of acknowledgement. Use warningYesNo() because its default is No.
1883
 
                        if (KMessageBox::warningYesNo(this, i18nc("@info", "Do you really want to acknowledge this alarm?"),
1884
 
                                                            i18nc("@action:button", "Acknowledge Alarm"), KGuiItem(i18nc("@action:button", "Acknowledge")), KStandardGuiItem::cancel())
1885
 
                            != KMessageBox::Yes)
1886
 
                        {
1887
 
                                ce->ignore();
1888
 
                                return;
1889
 
                        }
1890
 
                }
1891
 
                if (!mEventID.isNull())
1892
 
                {
1893
 
                        // Delete from the display calendar
1894
 
                        KAlarm::deleteDisplayEvent(KCalEvent::uid(mEventID, KCalEvent::DISPLAYING));
1895
 
                }
1896
 
        }
1897
 
        MainWindowBase::closeEvent(ce);
 
1978
    // Don't prompt or delete the alarm from the display calendar if the session is closing
 
1979
    if (!mErrorWindow  &&  !theApp()->sessionClosingDown())
 
1980
    {
 
1981
        if (mConfirmAck  &&  !mNoCloseConfirm)
 
1982
        {
 
1983
            // Ask for confirmation of acknowledgement. Use warningYesNo() because its default is No.
 
1984
            if (KMessageBox::warningYesNo(this, i18nc("@info", "Do you really want to acknowledge this alarm?"),
 
1985
                                                i18nc("@action:button", "Acknowledge Alarm"), KGuiItem(i18nc("@action:button", "Acknowledge")), KStandardGuiItem::cancel())
 
1986
                != KMessageBox::Yes)
 
1987
            {
 
1988
                ce->ignore();
 
1989
                return;
 
1990
            }
 
1991
        }
 
1992
        if (!mEventID.isNull())
 
1993
        {
 
1994
            // Delete from the display calendar
 
1995
            KAlarm::deleteDisplayEvent(KAlarm::CalEvent::uid(mEventID, KAlarm::CalEvent::DISPLAYING));
 
1996
        }
 
1997
    }
 
1998
    MainWindowBase::closeEvent(ce);
1898
1999
}
1899
2000
 
1900
2001
/******************************************************************************
1902
2003
*/
1903
2004
void MessageWin::slotOk()
1904
2005
{
1905
 
        if (mDontShowAgainCheck  &&  mDontShowAgainCheck->isChecked())
1906
 
                KAlarm::setDontShowErrors(mEventID, mDontShowAgain);
1907
 
        close();
 
2006
    if (mDontShowAgainCheck  &&  mDontShowAgainCheck->isChecked())
 
2007
        KAlarm::setDontShowErrors(mEventID, mDontShowAgain);
 
2008
    close();
1908
2009
}
1909
2010
 
1910
2011
#ifdef KMAIL_SUPPORTED
1914
2015
*/
1915
2016
void MessageWin::slotShowKMailMessage()
1916
2017
{
1917
 
        kDebug();
1918
 
        if (!mKMailSerialNumber)
1919
 
                return;
1920
 
        QString err = KAlarm::runKMail(false);
1921
 
        if (!err.isNull())
1922
 
        {
1923
 
                KMessageBox::sorry(this, err);
1924
 
                return;
1925
 
        }
1926
 
        org::kde::kmail::kmail kmail(KMAIL_DBUS_SERVICE, KMAIL_DBUS_PATH, QDBusConnection::sessionBus());
1927
 
        QDBusReply<bool> reply = kmail.showMail((qulonglong)mKMailSerialNumber, QString());
1928
 
        if (!reply.isValid())
1929
 
                kError() << "kmail D-Bus call failed:" << reply.error().message();
1930
 
        else if (!reply.value())
1931
 
                KMessageBox::sorry(this, i18nc("@info", "Unable to locate this email in <application>KMail</application>"));
 
2018
    kDebug();
 
2019
    if (!mKMailSerialNumber)
 
2020
        return;
 
2021
    QString err = KAlarm::runKMail(false);
 
2022
    if (!err.isNull())
 
2023
    {
 
2024
        KMessageBox::sorry(this, err);
 
2025
        return;
 
2026
    }
 
2027
    org::kde::kmail::kmail kmail(KMAIL_DBUS_SERVICE, KMAIL_DBUS_PATH, QDBusConnection::sessionBus());
 
2028
    QDBusReply<bool> reply = kmail.showMail((qulonglong)mKMailSerialNumber, QString());
 
2029
    if (!reply.isValid())
 
2030
        kError() << "kmail D-Bus call failed:" << reply.error().message();
 
2031
    else if (!reply.value())
 
2032
        KMessageBox::sorry(this, i18nc("@info", "Unable to locate this email in <application>KMail</application>"));
1932
2033
}
1933
2034
#endif
1934
2035
 
1944
2045
*/
1945
2046
void MessageWin::slotEdit()
1946
2047
{
1947
 
        kDebug();
1948
 
        MainWindow* mainWin = MainWindow::mainMainWindow();
1949
 
        mEditDlg = EditAlarmDlg::create(false, &mEvent, false, mainWin, EditAlarmDlg::RES_IGNORE);
1950
 
        KWindowSystem::setMainWindow(mEditDlg, winId());
1951
 
        KWindowSystem::setOnAllDesktops(mEditDlg->winId(), false);
1952
 
        setButtonsReadOnly(true);
1953
 
        connect(mEditDlg, SIGNAL(accepted()), SLOT(editCloseOk()));
1954
 
        connect(mEditDlg, SIGNAL(rejected()), SLOT(editCloseCancel()));
1955
 
        connect(mEditDlg, SIGNAL(destroyed(QObject*)), SLOT(editCloseCancel()));
1956
 
        connect(KWindowSystem::self(), SIGNAL(activeWindowChanged(WId)), SLOT(activeWindowChanged(WId)));
1957
 
        mainWin->editAlarm(mEditDlg, mEvent, mResource);
 
2048
    kDebug();
 
2049
    MainWindow* mainWin = MainWindow::mainMainWindow();
 
2050
    mEditDlg = EditAlarmDlg::create(false, &mEvent, false, mainWin, EditAlarmDlg::RES_IGNORE);
 
2051
    KWindowSystem::setMainWindow(mEditDlg, winId());
 
2052
    KWindowSystem::setOnAllDesktops(mEditDlg->winId(), false);
 
2053
    setButtonsReadOnly(true);
 
2054
    connect(mEditDlg, SIGNAL(accepted()), SLOT(editCloseOk()));
 
2055
    connect(mEditDlg, SIGNAL(rejected()), SLOT(editCloseCancel()));
 
2056
    connect(mEditDlg, SIGNAL(destroyed(QObject*)), SLOT(editCloseCancel()));
 
2057
    connect(KWindowSystem::self(), SIGNAL(activeWindowChanged(WId)), SLOT(activeWindowChanged(WId)));
 
2058
#ifdef USE_AKONADI
 
2059
    mainWin->editAlarm(mEditDlg, mEvent);
 
2060
#else
 
2061
    mainWin->editAlarm(mEditDlg, mEvent, mResource);
 
2062
#endif
1958
2063
}
1959
2064
 
1960
2065
/******************************************************************************
1963
2068
*/
1964
2069
void MessageWin::editCloseOk()
1965
2070
{
1966
 
        mEditDlg = 0;
1967
 
        mNoCloseConfirm = true;   // allow window to close without confirmation prompt
1968
 
        close();
 
2071
    mEditDlg = 0;
 
2072
    mNoCloseConfirm = true;   // allow window to close without confirmation prompt
 
2073
    close();
1969
2074
}
1970
2075
 
1971
2076
/******************************************************************************
1974
2079
*/
1975
2080
void MessageWin::editCloseCancel()
1976
2081
{
1977
 
        mEditDlg = 0;
1978
 
        setButtonsReadOnly(false);
 
2082
    mEditDlg = 0;
 
2083
    setButtonsReadOnly(false);
1979
2084
}
1980
2085
 
1981
2086
/******************************************************************************
1985
2090
*/
1986
2091
void MessageWin::activeWindowChanged(WId win)
1987
2092
{
1988
 
        if (mEditDlg  &&  win == winId())
1989
 
                KWindowSystem::activateWindow(mEditDlg->winId());
 
2093
    if (mEditDlg  &&  win == winId())
 
2094
        KWindowSystem::activateWindow(mEditDlg->winId());
1990
2095
}
1991
2096
 
1992
2097
/******************************************************************************
1994
2099
*/
1995
2100
void MessageWin::setButtonsReadOnly(bool ro)
1996
2101
{
1997
 
        mOkButton->setReadOnly(ro, true);
1998
 
        mDeferButton->setReadOnly(ro, true);
1999
 
        mEditButton->setReadOnly(ro, true);
2000
 
        if (mSilenceButton)
2001
 
                mSilenceButton->setReadOnly(ro, true);
2002
 
        if (mKMailButton)
2003
 
                mKMailButton->setReadOnly(ro, true);
2004
 
        mKAlarmButton->setReadOnly(ro, true);
 
2102
    mOkButton->setReadOnly(ro, true);
 
2103
    mDeferButton->setReadOnly(ro, true);
 
2104
    mEditButton->setReadOnly(ro, true);
 
2105
    if (mSilenceButton)
 
2106
        mSilenceButton->setReadOnly(ro, true);
 
2107
    if (mKMailButton)
 
2108
        mKMailButton->setReadOnly(ro, true);
 
2109
    mKAlarmButton->setReadOnly(ro, true);
2005
2110
}
2006
2111
 
2007
2112
/******************************************************************************
2009
2114
*/
2010
2115
void MessageWin::setDeferralLimit(const KAEvent& event)
2011
2116
{
2012
 
        mDeferLimit = event.deferralLimit().effectiveDateTime();
2013
 
        MidnightTimer::connect(this, SLOT(checkDeferralLimit()));   // check every day
2014
 
        mDisableDeferral = false;
2015
 
        checkDeferralLimit();
 
2117
    mDeferLimit = event.deferralLimit().effectiveKDateTime().toLocalZone().dateTime();
 
2118
    MidnightTimer::connect(this, SLOT(checkDeferralLimit()));   // check every day
 
2119
    mDisableDeferral = false;
 
2120
    checkDeferralLimit();
2016
2121
}
2017
2122
 
2018
2123
/******************************************************************************
2026
2131
*/
2027
2132
void MessageWin::checkDeferralLimit()
2028
2133
{
2029
 
        if (!mDeferButton->isEnabled()  ||  !mDeferLimit.isValid())
2030
 
                return;
2031
 
        int n = KDateTime::currentLocalDate().daysTo(mDeferLimit.date());
2032
 
        if (n > 0)
2033
 
                return;
2034
 
        MidnightTimer::disconnect(this, SLOT(checkDeferralLimit()));
2035
 
        if (n == 0)
2036
 
        {
2037
 
                // The deferral limit will be reached today
2038
 
                n = KDateTime::currentLocalTime().secsTo(mDeferLimit.time());
2039
 
                if (n > 0)
2040
 
                {
2041
 
                        QTimer::singleShot(n * 1000, this, SLOT(checkDeferralLimit()));
2042
 
                        return;
2043
 
                }
2044
 
        }
2045
 
        mDeferButton->setEnabled(false);
2046
 
        mDisableDeferral = true;
 
2134
    if (!mDeferButton->isEnabled()  ||  !mDeferLimit.isValid())
 
2135
        return;
 
2136
    int n = KDateTime::currentLocalDate().daysTo(mDeferLimit.date());
 
2137
    if (n > 0)
 
2138
        return;
 
2139
    MidnightTimer::disconnect(this, SLOT(checkDeferralLimit()));
 
2140
    if (n == 0)
 
2141
    {
 
2142
        // The deferral limit will be reached today
 
2143
        n = KDateTime::currentLocalTime().secsTo(mDeferLimit.time());
 
2144
        if (n > 0)
 
2145
        {
 
2146
            QTimer::singleShot(n * 1000, this, SLOT(checkDeferralLimit()));
 
2147
            return;
 
2148
        }
 
2149
    }
 
2150
    mDeferButton->setEnabled(false);
 
2151
    mDisableDeferral = true;
2047
2152
}
2048
2153
 
2049
2154
/******************************************************************************
2052
2157
*/
2053
2158
void MessageWin::slotDefer()
2054
2159
{
2055
 
        mDeferDlg = new DeferAlarmDlg(KDateTime::currentDateTime(Preferences::timeZone()).addSecs(60), mDateTime.isDateOnly(), false, this);
2056
 
        mDeferDlg->setObjectName("DeferDlg");    // used by LikeBack
2057
 
        mDeferDlg->setDeferMinutes(mDefaultDeferMinutes > 0 ? mDefaultDeferMinutes : Preferences::defaultDeferTime());
2058
 
        mDeferDlg->setLimit(mEventID);
2059
 
        if (!Preferences::modalMessages())
2060
 
                lower();
2061
 
        if (mDeferDlg->exec() == QDialog::Accepted)
2062
 
        {
2063
 
                DateTime dateTime  = mDeferDlg->getDateTime();
2064
 
                int      delayMins = mDeferDlg->deferMinutes();
2065
 
                // Fetch the up-to-date alarm from the calendar. Note that it could have
2066
 
                // changed since it was displayed.
2067
 
                const KAEvent* event = mEventID.isNull() ? 0 : AlarmCalendar::resources()->event(mEventID);
2068
 
                if (event)
2069
 
                {
2070
 
                        // The event still exists in the active calendar
2071
 
                        kDebug() << "Deferring event" << mEventID;
2072
 
                        KAEvent newev(*event);
2073
 
                        newev.defer(dateTime, (mAlarmType & KAAlarm::REMINDER_ALARM), true);
2074
 
                        newev.setDeferDefaultMinutes(delayMins);
2075
 
                        KAlarm::updateEvent(newev, mDeferDlg, true);
2076
 
                        if (newev.deferred())
2077
 
                                mNoPostAction = true;
2078
 
                }
2079
 
                else
2080
 
                {
2081
 
                        // Try to retrieve the event from the displaying or archive calendars
2082
 
                        AlarmResource* resource = 0;
2083
 
                        KAEvent event;
2084
 
                        bool showEdit, showDefer;
2085
 
                        if (!retrieveEvent(event, resource, showEdit, showDefer))
2086
 
                        {
2087
 
                                // The event doesn't exist any more !?!, so recurrence data,
2088
 
                                // flags, and more, have been lost.
2089
 
                                KMessageBox::error(this, i18nc("@info", "<para>Cannot defer alarm:</para><para>Alarm not found.</para>"));
2090
 
                                raise();
2091
 
                                delete mDeferDlg;
2092
 
                                mDeferDlg = 0;
2093
 
                                mDeferButton->setEnabled(false);
2094
 
                                mEditButton->setEnabled(false);
2095
 
                                return;
2096
 
                        }
2097
 
                        kDebug() << "Deferring retrieved event" << mEventID;
2098
 
                        event.defer(dateTime, (mAlarmType & KAAlarm::REMINDER_ALARM), true);
2099
 
                        event.setDeferDefaultMinutes(delayMins);
2100
 
                        event.setCommandError(mCommandError);
2101
 
                        // Add the event back into the calendar file, retaining its ID
2102
 
                        // and not updating KOrganizer.
2103
 
                        KAlarm::addEvent(event, resource, mDeferDlg, KAlarm::USE_EVENT_ID);
2104
 
                        if (event.deferred())
2105
 
                                mNoPostAction = true;
2106
 
                        // Finally delete it from the archived calendar now that it has
2107
 
                        // been reactivated.
2108
 
                        event.setCategory(KCalEvent::ARCHIVED);
2109
 
                        KAlarm::deleteEvent(event, false);
2110
 
                }
2111
 
                if (theApp()->wantShowInSystemTray())
2112
 
                {
2113
 
                        // Alarms are to be displayed only if the system tray icon is running,
2114
 
                        // so start it if necessary so that the deferred alarm will be shown.
2115
 
                        theApp()->displayTrayIcon(true);
2116
 
                }
2117
 
                mNoCloseConfirm = true;   // allow window to close without confirmation prompt
2118
 
                close();
2119
 
        }
2120
 
        else
2121
 
                raise();
2122
 
        delete mDeferDlg;
2123
 
        mDeferDlg = 0;
 
2160
    mDeferDlg = new DeferAlarmDlg(KDateTime::currentDateTime(Preferences::timeZone()).addSecs(60), mDateTime.isDateOnly(), false, this);
 
2161
    mDeferDlg->setObjectName("DeferDlg");    // used by LikeBack
 
2162
    mDeferDlg->setDeferMinutes(mDefaultDeferMinutes > 0 ? mDefaultDeferMinutes : Preferences::defaultDeferTime());
 
2163
    mDeferDlg->setLimit(mEventID);
 
2164
    if (!Preferences::modalMessages())
 
2165
        lower();
 
2166
    if (mDeferDlg->exec() == QDialog::Accepted)
 
2167
    {
 
2168
        DateTime dateTime  = mDeferDlg->getDateTime();
 
2169
        int      delayMins = mDeferDlg->deferMinutes();
 
2170
        // Fetch the up-to-date alarm from the calendar. Note that it could have
 
2171
        // changed since it was displayed.
 
2172
        const KAEvent* event = mEventID.isNull() ? 0 : AlarmCalendar::resources()->event(mEventID);
 
2173
        if (event)
 
2174
        {
 
2175
            // The event still exists in the active calendar
 
2176
            kDebug() << "Deferring event" << mEventID;
 
2177
            KAEvent newev(*event);
 
2178
            newev.defer(dateTime, (mAlarmType & KAAlarm::REMINDER_ALARM), true);
 
2179
            newev.setDeferDefaultMinutes(delayMins);
 
2180
            KAlarm::updateEvent(newev, mDeferDlg, true);
 
2181
            if (newev.deferred())
 
2182
                mNoPostAction = true;
 
2183
        }
 
2184
        else
 
2185
        {
 
2186
            // Try to retrieve the event from the displaying or archive calendars
 
2187
#ifdef USE_AKONADI
 
2188
            Akonadi::Collection collection;
 
2189
#else
 
2190
            AlarmResource* resource = 0;
 
2191
#endif
 
2192
            KAEvent event;
 
2193
            bool showEdit, showDefer;
 
2194
#ifdef USE_AKONADI
 
2195
            if (!retrieveEvent(event, collection, showEdit, showDefer))
 
2196
#else
 
2197
            if (!retrieveEvent(event, resource, showEdit, showDefer))
 
2198
#endif
 
2199
            {
 
2200
                // The event doesn't exist any more !?!, so recurrence data,
 
2201
                // flags, and more, have been lost.
 
2202
                KMessageBox::error(this, i18nc("@info", "<para>Cannot defer alarm:</para><para>Alarm not found.</para>"));
 
2203
                raise();
 
2204
                delete mDeferDlg;
 
2205
                mDeferDlg = 0;
 
2206
                mDeferButton->setEnabled(false);
 
2207
                mEditButton->setEnabled(false);
 
2208
                return;
 
2209
            }
 
2210
            kDebug() << "Deferring retrieved event" << mEventID;
 
2211
            event.defer(dateTime, (mAlarmType & KAAlarm::REMINDER_ALARM), true);
 
2212
            event.setDeferDefaultMinutes(delayMins);
 
2213
            event.setCommandError(mCommandError);
 
2214
            // Add the event back into the calendar file, retaining its ID
 
2215
            // and not updating KOrganizer.
 
2216
#ifdef USE_AKONADI
 
2217
            KAlarm::addEvent(event, &collection, mDeferDlg, KAlarm::USE_EVENT_ID);
 
2218
#else
 
2219
            KAlarm::addEvent(event, resource, mDeferDlg, KAlarm::USE_EVENT_ID);
 
2220
#endif
 
2221
            if (event.deferred())
 
2222
                mNoPostAction = true;
 
2223
            // Finally delete it from the archived calendar now that it has
 
2224
            // been reactivated.
 
2225
            event.setCategory(KAlarm::CalEvent::ARCHIVED);
 
2226
            KAlarm::deleteEvent(event, false);
 
2227
        }
 
2228
        if (theApp()->wantShowInSystemTray())
 
2229
        {
 
2230
            // Alarms are to be displayed only if the system tray icon is running,
 
2231
            // so start it if necessary so that the deferred alarm will be shown.
 
2232
            theApp()->displayTrayIcon(true);
 
2233
        }
 
2234
        mNoCloseConfirm = true;   // allow window to close without confirmation prompt
 
2235
        close();
 
2236
    }
 
2237
    else
 
2238
        raise();
 
2239
    delete mDeferDlg;
 
2240
    mDeferDlg = 0;
2124
2241
}
2125
2242
 
2126
2243
/******************************************************************************
2129
2246
*/
2130
2247
void MessageWin::displayMainWindow()
2131
2248
{
2132
 
        KAlarm::displayMainWindowSelected(mEventID);
 
2249
#ifdef USE_AKONADI
 
2250
    KAlarm::displayMainWindowSelected(mEventItemId);
 
2251
#else
 
2252
    KAlarm::displayMainWindowSelected(mEventID);
 
2253
#endif
2133
2254
}
2134
2255
 
2135
2256
/******************************************************************************
2139
2260
*/
2140
2261
bool MessageWin::haveErrorMessage(unsigned msg) const
2141
2262
{
2142
 
        if (!mErrorMessages.contains(mEventID))
2143
 
                mErrorMessages.insert(mEventID, 0);
2144
 
        bool result = (mErrorMessages[mEventID] & msg);
2145
 
        mErrorMessages[mEventID] |= msg;
2146
 
        return result;
 
2263
    if (!mErrorMessages.contains(mEventID))
 
2264
        mErrorMessages.insert(mEventID, 0);
 
2265
    bool result = (mErrorMessages[mEventID] & msg);
 
2266
    mErrorMessages[mEventID] |= msg;
 
2267
    return result;
2147
2268
}
2148
2269
 
2149
2270
void MessageWin::clearErrorMessage(unsigned msg) const
2150
2271
{
2151
 
        if (mErrorMessages.contains(mEventID))
2152
 
        {
2153
 
                if (mErrorMessages[mEventID] == msg)
2154
 
                        mErrorMessages.remove(mEventID);
2155
 
                else
2156
 
                        mErrorMessages[mEventID] &= ~msg;
2157
 
        }
 
2272
    if (mErrorMessages.contains(mEventID))
 
2273
    {
 
2274
        if (mErrorMessages[mEventID] == msg)
 
2275
            mErrorMessages.remove(mEventID);
 
2276
        else
 
2277
            mErrorMessages[mEventID] &= ~msg;
 
2278
    }
2158
2279
}
2159
2280
 
2160
2281
 
2170
2291
*/
2171
2292
bool MessageWin::getWorkAreaAndModal()
2172
2293
{
2173
 
        mScreenNumber = -1;
2174
 
        bool modal = Preferences::modalMessages();
 
2294
    mScreenNumber = -1;
 
2295
    bool modal = Preferences::modalMessages();
2175
2296
#ifdef Q_WS_X11
2176
 
        QDesktopWidget* desktop = qApp->desktop();
2177
 
        int numScreens = desktop->numScreens();
2178
 
        if (numScreens > 1)
2179
 
        {
2180
 
                // There are multiple screens.
2181
 
                // Check for any full screen windows, even if they are not the active
2182
 
                // window, and try not to show the alarm message their screens.
2183
 
                mScreenNumber = desktop->screenNumber(MainWindow::mainMainWindow());  // default = KAlarm's screen
2184
 
                if (desktop->isVirtualDesktop())
2185
 
                {
2186
 
                        // The screens form a single virtual desktop.
2187
 
                        // Xinerama, for example, uses this scheme.
2188
 
                        QVector<FullScreenType> screenTypes(numScreens);
2189
 
                        QVector<QRect> screenRects(numScreens);
2190
 
                        for (int s = 0;  s < numScreens;  ++s)
2191
 
                                screenRects[s] = desktop->screenGeometry(s);
2192
 
                        FullScreenType full = findFullScreenWindows(screenRects, screenTypes);
2193
 
                        if (full == NoFullScreen  ||  screenTypes[mScreenNumber] == NoFullScreen)
2194
 
                                return modal;
2195
 
                        for (int s = 0;  s < numScreens;  ++s)
2196
 
                        {
2197
 
                                if (screenTypes[s] == NoFullScreen)
 
2297
    QDesktopWidget* desktop = qApp->desktop();
 
2298
    int numScreens = desktop->numScreens();
 
2299
    if (numScreens > 1)
 
2300
    {
 
2301
        // There are multiple screens.
 
2302
        // Check for any full screen windows, even if they are not the active
 
2303
        // window, and try not to show the alarm message their screens.
 
2304
        mScreenNumber = desktop->screenNumber(MainWindow::mainMainWindow());  // default = KAlarm's screen
 
2305
        if (desktop->isVirtualDesktop())
 
2306
        {
 
2307
            // The screens form a single virtual desktop.
 
2308
            // Xinerama, for example, uses this scheme.
 
2309
            QVector<FullScreenType> screenTypes(numScreens);
 
2310
            QVector<QRect> screenRects(numScreens);
 
2311
            for (int s = 0;  s < numScreens;  ++s)
 
2312
                screenRects[s] = desktop->screenGeometry(s);
 
2313
            FullScreenType full = findFullScreenWindows(screenRects, screenTypes);
 
2314
            if (full == NoFullScreen  ||  screenTypes[mScreenNumber] == NoFullScreen)
 
2315
                return modal;
 
2316
            for (int s = 0;  s < numScreens;  ++s)
 
2317
            {
 
2318
                if (screenTypes[s] == NoFullScreen)
2198
2319
 
2199
 
                                {
2200
 
                                        // There is no full screen window on this screen
2201
 
                                        mScreenNumber = s;
2202
 
                                        return modal;
2203
 
                                }
2204
 
                        }
2205
 
                        // All screens contain a full screen window: use one without
2206
 
                        // an active full screen window.
2207
 
                        for (int s = 0;  s < numScreens;  ++s)
2208
 
                        {
2209
 
                                if (screenTypes[s] == FullScreen)
2210
 
                                {
2211
 
                                        mScreenNumber = s;
2212
 
                                        return modal;
2213
 
                                }
2214
 
                        }
2215
 
                }
2216
 
                else
2217
 
                {
2218
 
                        // The screens are completely separate from each other.
2219
 
                        int inactiveScreen = -1;
2220
 
                        FullScreenType full = haveFullScreenWindow(mScreenNumber);
 
2320
                {
 
2321
                    // There is no full screen window on this screen
 
2322
                    mScreenNumber = s;
 
2323
                    return modal;
 
2324
                }
 
2325
            }
 
2326
            // All screens contain a full screen window: use one without
 
2327
            // an active full screen window.
 
2328
            for (int s = 0;  s < numScreens;  ++s)
 
2329
            {
 
2330
                if (screenTypes[s] == FullScreen)
 
2331
                {
 
2332
                    mScreenNumber = s;
 
2333
                    return modal;
 
2334
                }
 
2335
            }
 
2336
        }
 
2337
        else
 
2338
        {
 
2339
            // The screens are completely separate from each other.
 
2340
            int inactiveScreen = -1;
 
2341
            FullScreenType full = haveFullScreenWindow(mScreenNumber);
2221
2342
kDebug()<<"full="<<full<<", screen="<<mScreenNumber;
2222
 
                        if (full == NoFullScreen)
2223
 
                                return modal;   // KAlarm's screen doesn't contain a full screen window
2224
 
                        if (full == FullScreen)
2225
 
                                inactiveScreen = mScreenNumber;
2226
 
                        for (int s = 0;  s < numScreens;  ++s)
2227
 
                        {
2228
 
                                if (s != mScreenNumber)
2229
 
                                {
2230
 
                                        full = haveFullScreenWindow(s);
2231
 
                                        if (full == NoFullScreen)
2232
 
                                        {
2233
 
                                                // There is no full screen window on this screen
2234
 
                                                mScreenNumber = s;
2235
 
                                                return modal;
2236
 
                                        }
2237
 
                                        if (full == FullScreen  &&  inactiveScreen < 0)
2238
 
                                                inactiveScreen = s;
2239
 
                                }
2240
 
                        }
2241
 
                        if (inactiveScreen >= 0)
2242
 
                        {
2243
 
                                // All screens contain a full screen window: use one without
2244
 
                                // an active full screen window.
2245
 
                                mScreenNumber = inactiveScreen;
2246
 
                                return modal;
2247
 
                        }
2248
 
                }
2249
 
                return false;  // can't logically get here, since there can only be one active window...
2250
 
        }
 
2343
            if (full == NoFullScreen)
 
2344
                return modal;   // KAlarm's screen doesn't contain a full screen window
 
2345
            if (full == FullScreen)
 
2346
                inactiveScreen = mScreenNumber;
 
2347
            for (int s = 0;  s < numScreens;  ++s)
 
2348
            {
 
2349
                if (s != mScreenNumber)
 
2350
                {
 
2351
                    full = haveFullScreenWindow(s);
 
2352
                    if (full == NoFullScreen)
 
2353
                    {
 
2354
                        // There is no full screen window on this screen
 
2355
                        mScreenNumber = s;
 
2356
                        return modal;
 
2357
                    }
 
2358
                    if (full == FullScreen  &&  inactiveScreen < 0)
 
2359
                        inactiveScreen = s;
 
2360
                }
 
2361
            }
 
2362
            if (inactiveScreen >= 0)
 
2363
            {
 
2364
                // All screens contain a full screen window: use one without
 
2365
                // an active full screen window.
 
2366
                mScreenNumber = inactiveScreen;
 
2367
                return modal;
 
2368
            }
 
2369
        }
 
2370
        return false;  // can't logically get here, since there can only be one active window...
 
2371
    }
2251
2372
#endif
2252
 
        if (modal)
2253
 
        {
2254
 
                WId activeId = KWindowSystem::activeWindow();
2255
 
                KWindowInfo wi = KWindowSystem::windowInfo(activeId, NET::WMState);
2256
 
                if (wi.valid()  &&  wi.hasState(NET::FullScreen))
2257
 
                        return false;    // the active window is full screen.
2258
 
        }
2259
 
        return modal;
 
2373
    if (modal)
 
2374
    {
 
2375
        WId activeId = KWindowSystem::activeWindow();
 
2376
        KWindowInfo wi = KWindowSystem::windowInfo(activeId, NET::WMState);
 
2377
        if (wi.valid()  &&  wi.hasState(NET::FullScreen))
 
2378
            return false;    // the active window is full screen.
 
2379
    }
 
2380
    return modal;
2260
2381
}
2261
2382
 
2262
2383
#ifdef Q_WS_X11
2316
2437
        NETWinInfo winInfo(display, windows[w], rootWindow, NET::WMState | NET::WMGeometry);
2317
2438
        if (winInfo.state() & NET::FullScreen)
2318
2439
        {
2319
 
            // Found a full screen window - find which screen it's on
 
2440
            // Found a full screen window - find which screen it's on
2320
2441
            bool active = (windows[w] == activeWindow);
2321
2442
            winInfo.kdeGeometry(netframe, netgeom);
2322
2443
            QRect winRect(netgeom.pos.x, netgeom.pos.y, netgeom.size.width, netgeom.size.height);
2323
2444
kDebug()<<"Found FULL SCREEN: "<<windows[w]<<", geom="<<winRect;
2324
 
            for (int s = 0, count = screenRects.count();  s < count;  ++s)
2325
 
            {
2326
 
                if (screenRects[s].contains(winRect))
2327
 
                {
 
2445
            for (int s = 0, count = screenRects.count();  s < count;  ++s)
 
2446
            {
 
2447
                if (screenRects[s].contains(winRect))
 
2448
                {
2328
2449
kDebug()<<"FULL SCREEN on screen"<<s<<", active="<<active;
2329
 
                    if (active)
2330
 
                        screenTypes[s] = result = FullScreenActive;
2331
 
                    else
2332
 
                    {
2333
 
                        if (screenTypes[s] == NoFullScreen)
2334
 
                            screenTypes[s] = FullScreen;
2335
 
                        if (result == NoFullScreen)
2336
 
                            result = FullScreen;
2337
 
                    }
2338
 
                    break;
2339
 
                }
2340
 
            }
 
2450
                    if (active)
 
2451
                        screenTypes[s] = result = FullScreenActive;
 
2452
                    else
 
2453
                    {
 
2454
                        if (screenTypes[s] == NoFullScreen)
 
2455
                            screenTypes[s] = FullScreen;
 
2456
                        if (result == NoFullScreen)
 
2457
                            result = FullScreen;
 
2458
                    }
 
2459
                    break;
 
2460
                }
 
2461
            }
2341
2462
        }
2342
2463
    }
2343
2464
    return result;
2344
2465
}
2345
2466
#endif
 
2467
 
 
2468
// vim: et sw=4: