00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021 #include "kalarm.h"
00022
00023 #include <stdlib.h>
00024 #include <string.h>
00025
00026 #include <qfile.h>
00027 #include <qfileinfo.h>
00028 #include <qlayout.h>
00029 #include <qpushbutton.h>
00030 #include <qlabel.h>
00031 #include <qwhatsthis.h>
00032 #include <qtooltip.h>
00033 #include <qdragobject.h>
00034 #include <qtextedit.h>
00035 #include <qtimer.h>
00036
00037 #include <kstandarddirs.h>
00038 #include <kaction.h>
00039 #include <kstdguiitem.h>
00040 #include <kaboutdata.h>
00041 #include <klocale.h>
00042 #include <kconfig.h>
00043 #include <kiconloader.h>
00044 #include <kdialog.h>
00045 #include <ktextbrowser.h>
00046 #include <kglobalsettings.h>
00047 #include <kmimetype.h>
00048 #include <kmessagebox.h>
00049 #include <kwin.h>
00050 #include <kwinmodule.h>
00051 #include <kprocess.h>
00052 #include <kio/netaccess.h>
00053 #include <knotifyclient.h>
00054 #include <kpushbutton.h>
00055 #ifdef WITHOUT_ARTS
00056 #include <kaudioplayer.h>
00057 #else
00058 #include <arts/kartsdispatcher.h>
00059 #include <arts/kartsserver.h>
00060 #include <arts/kplayobjectfactory.h>
00061 #include <arts/kplayobject.h>
00062 #endif
00063 #include <dcopclient.h>
00064 #include <kdebug.h>
00065
00066 #include "alarmcalendar.h"
00067 #include "deferdlg.h"
00068 #include "editdlg.h"
00069 #include "functions.h"
00070 #include "kalarmapp.h"
00071 #include "mainwindow.h"
00072 #include "preferences.h"
00073 #include "synchtimer.h"
00074 #include "messagewin.moc"
00075
00076 using namespace KCal;
00077
00078 #ifndef WITHOUT_ARTS
00079 static const char* KMIX_APP_NAME = "kmix";
00080 static const char* KMIX_DCOP_OBJECT = "Mixer0";
00081 static const char* KMIX_DCOP_WINDOW = "kmix-mainwindow#1";
00082 #endif
00083 static const char* KMAIL_DCOP_OBJECT = "KMailIface";
00084
00085
00086
00087 static const int proximityButtonDelay = 1000;
00088 static const int proximityMultiple = 10;
00089
00090 static bool wantModal();
00091
00092
00093 class MessageText : public QTextEdit
00094 {
00095 public:
00096 MessageText(const QString& text, const QString& context = QString::null, QWidget* parent = 0, const char* name = 0)
00097 : QTextEdit(text, context, parent, name)
00098 {
00099 setReadOnly(true);
00100 setWordWrap(QTextEdit::NoWrap);
00101 }
00102 int scrollBarHeight() const { return horizontalScrollBar()->height(); }
00103 int scrollBarWidth() const { return verticalScrollBar()->width(); }
00104 virtual QSize sizeHint() const { return QSize(contentsWidth() + scrollBarWidth(), contentsHeight() + scrollBarHeight()); }
00105 };
00106
00107
00108 class MWMimeSourceFactory : public QMimeSourceFactory
00109 {
00110 public:
00111 MWMimeSourceFactory(const QString& absPath, KTextBrowser*);
00112 virtual ~MWMimeSourceFactory();
00113 virtual const QMimeSource* data(const QString& abs_name) const;
00114 private:
00115
00116 virtual void setData(const QString&, QMimeSource*) {}
00117 virtual void setExtensionType(const QString&, const char*) {}
00118
00119 QString mTextFile;
00120 QCString mMimeType;
00121 mutable const QMimeSource* mLast;
00122 };
00123
00124
00125
00126 static const Qt::WFlags WFLAGS = Qt::WStyle_StaysOnTop | Qt::WDestructiveClose;
00127
00128
00129 enum {
00130 ErrMsg_Speak = 0x01,
00131 ErrMsg_AudioFile = 0x02,
00132 ErrMsg_Volume = 0x04
00133 };
00134
00135
00136 QValueList<MessageWin*> MessageWin::mWindowList;
00137 QMap<QString, unsigned> MessageWin::mErrorMessages;
00138
00139
00140
00141
00142
00143
00144
00145
00146 MessageWin::MessageWin(const KAEvent& event, const KAAlarm& alarm, bool reschedule_event, bool allowDefer)
00147 : MainWindowBase(0, "MessageWin", WFLAGS | Qt::WGroupLeader | Qt::WStyle_ContextHelp
00148 | (wantModal() ? 0 : Qt::WX11BypassWM)),
00149 mMessage(event.cleanText()),
00150 mFont(event.font()),
00151 mBgColour(event.bgColour()),
00152 mFgColour(event.fgColour()),
00153 mDateTime((alarm.type() & KAAlarm::REMINDER_ALARM) ? event.mainDateTime(true) : alarm.dateTime(true)),
00154 mEventID(event.id()),
00155 mAudioFile(event.audioFile()),
00156 mVolume(event.soundVolume()),
00157 mFadeVolume(event.fadeVolume()),
00158 mFadeSeconds(QMIN(event.fadeSeconds(), 86400)),
00159 mDefaultDeferMinutes(event.deferDefaultMinutes()),
00160 mAlarmType(alarm.type()),
00161 mAction(event.action()),
00162 mKMailSerialNumber(event.kmailSerialNumber()),
00163 mRestoreHeight(0),
00164 mAudioRepeat(event.repeatSound()),
00165 mConfirmAck(event.confirmAck()),
00166 mShowEdit(!mEventID.isEmpty()),
00167 mNoDefer(!allowDefer || alarm.repeatAtLogin()),
00168 mInvalid(false),
00169 mArtsDispatcher(0),
00170 mPlayObject(0),
00171 mOldVolume(-1),
00172 mEvent(event),
00173 mEditButton(0),
00174 mDeferButton(0),
00175 mSilenceButton(0),
00176 mDeferDlg(0),
00177 mWinModule(0),
00178 mFlags(event.flags()),
00179 mLateCancel(event.lateCancel()),
00180 mErrorWindow(false),
00181 mNoPostAction(alarm.type() & KAAlarm::REMINDER_ALARM),
00182 mRecreating(false),
00183 mBeep(event.beep()),
00184 mSpeak(event.speak()),
00185 mRescheduleEvent(reschedule_event),
00186 mShown(false),
00187 mPositioning(false),
00188 mNoCloseConfirm(false),
00189 mDisableDeferral(false)
00190 {
00191 kdDebug(5950) << "MessageWin::MessageWin(event)" << endl;
00192
00193
00194 setAutoSaveSettings(QString::fromLatin1("MessageWin"), false);
00195 initView();
00196 mWindowList.append(this);
00197 if (event.autoClose())
00198 mCloseTime = alarm.dateTime().dateTime().addSecs(event.lateCancel() * 60);
00199 }
00200
00201
00202
00203
00204 MessageWin::MessageWin(const KAEvent& event, const DateTime& alarmDateTime, const QStringList& errmsgs)
00205 : MainWindowBase(0, "MessageWin", WFLAGS | Qt::WGroupLeader | Qt::WStyle_ContextHelp),
00206 mMessage(event.cleanText()),
00207 mDateTime(alarmDateTime),
00208 mEventID(event.id()),
00209 mAlarmType(KAAlarm::MAIN_ALARM),
00210 mAction(event.action()),
00211 mKMailSerialNumber(0),
00212 mErrorMsgs(errmsgs),
00213 mRestoreHeight(0),
00214 mConfirmAck(false),
00215 mShowEdit(false),
00216 mNoDefer(true),
00217 mInvalid(false),
00218 mArtsDispatcher(0),
00219 mPlayObject(0),
00220 mEvent(event),
00221 mEditButton(0),
00222 mDeferButton(0),
00223 mSilenceButton(0),
00224 mDeferDlg(0),
00225 mWinModule(0),
00226 mErrorWindow(true),
00227 mNoPostAction(true),
00228 mRecreating(false),
00229 mRescheduleEvent(false),
00230 mShown(false),
00231 mPositioning(false),
00232 mNoCloseConfirm(false),
00233 mDisableDeferral(false)
00234 {
00235 kdDebug(5950) << "MessageWin::MessageWin(errmsg)" << endl;
00236 initView();
00237 mWindowList.append(this);
00238 }
00239
00240
00241
00242
00243
00244 MessageWin::MessageWin()
00245 : MainWindowBase(0, "MessageWin", WFLAGS),
00246 mArtsDispatcher(0),
00247 mPlayObject(0),
00248 mEditButton(0),
00249 mDeferButton(0),
00250 mSilenceButton(0),
00251 mDeferDlg(0),
00252 mWinModule(0),
00253 mErrorWindow(false),
00254 mRecreating(false),
00255 mRescheduleEvent(false),
00256 mShown(false),
00257 mPositioning(false),
00258 mNoCloseConfirm(false),
00259 mDisableDeferral(false)
00260 {
00261 kdDebug(5950) << "MessageWin::MessageWin(restore)\n";
00262 mWindowList.append(this);
00263 }
00264
00265
00266
00267
00268 MessageWin::~MessageWin()
00269 {
00270 kdDebug(5950) << "MessageWin::~MessageWin(" << mEventID << ")" << endl;
00271 stopPlay();
00272 delete mWinModule;
00273 mWinModule = 0;
00274 mErrorMessages.remove(mEventID);
00275 mWindowList.remove(this);
00276 if (!mRecreating)
00277 {
00278 if (!mNoPostAction && !mEvent.postAction().isEmpty())
00279 theApp()->alarmCompleted(mEvent);
00280 if (!mWindowList.count())
00281 theApp()->quitIf();
00282 }
00283 }
00284
00285
00286
00287
00288 void MessageWin::initView()
00289 {
00290 bool reminder = (!mErrorWindow && (mAlarmType & KAAlarm::REMINDER_ALARM));
00291 int leading = fontMetrics().leading();
00292 setCaption((mAlarmType & KAAlarm::REMINDER_ALARM) ? i18n("Reminder") : i18n("Message"));
00293 QWidget* topWidget = new QWidget(this, "messageWinTop");
00294 setCentralWidget(topWidget);
00295 QVBoxLayout* topLayout = new QVBoxLayout(topWidget, KDialog::marginHint(), KDialog::spacingHint());
00296
00297 if (mDateTime.isValid())
00298 {
00299
00300 QFrame* frame = 0;
00301 QVBoxLayout* layout = topLayout;
00302 if (reminder)
00303 {
00304 frame = new QFrame(topWidget);
00305 frame->setFrameStyle(QFrame::Box | QFrame::Raised);
00306 topLayout->addWidget(frame, 0, Qt::AlignHCenter);
00307 layout = new QVBoxLayout(frame, leading + frame->frameWidth(), leading);
00308 }
00309
00310
00311 QLabel* label = new QLabel(frame ? frame : topWidget);
00312 label->setText(mDateTime.isDateOnly()
00313 ? KGlobal::locale()->formatDate(mDateTime.date(), true)
00314 : KGlobal::locale()->formatDateTime(mDateTime.dateTime()));
00315 if (!frame)
00316 label->setFrameStyle(QFrame::Box | QFrame::Raised);
00317 label->setFixedSize(label->sizeHint());
00318 layout->addWidget(label, 0, Qt::AlignHCenter);
00319 QWhatsThis::add(label,
00320 i18n("The scheduled date/time for the message (as opposed to the actual time of display)."));
00321
00322 if (frame)
00323 {
00324 label = new QLabel(frame);
00325 label->setText(i18n("Reminder"));
00326 label->setFixedSize(label->sizeHint());
00327 layout->addWidget(label, 0, Qt::AlignHCenter);
00328 frame->setFixedSize(frame->sizeHint());
00329 }
00330 }
00331
00332 if (!mErrorWindow)
00333 {
00334
00335 switch (mAction)
00336 {
00337 case KAEvent::FILE:
00338 {
00339
00340 QLabel* label = new QLabel(mMessage, topWidget);
00341 label->setFrameStyle(QFrame::Box | QFrame::Raised);
00342 label->setFixedSize(label->sizeHint());
00343 QWhatsThis::add(label, i18n("The file whose contents are displayed below"));
00344 topLayout->addWidget(label, 0, Qt::AlignHCenter);
00345
00346
00347 bool opened = false;
00348 bool dir = false;
00349 QString tmpFile;
00350 KURL url(mMessage);
00351 if (KIO::NetAccess::download(url, tmpFile, MainWindow::mainMainWindow()))
00352 {
00353 QFile qfile(tmpFile);
00354 QFileInfo info(qfile);
00355 if (!(dir = info.isDir()))
00356 {
00357 opened = true;
00358 KTextBrowser* view = new KTextBrowser(topWidget, "fileContents");
00359 MWMimeSourceFactory msf(tmpFile, view);
00360 view->setMinimumSize(view->sizeHint());
00361 topLayout->addWidget(view);
00362
00363
00364
00365
00366
00367 int h = 20*view->fontMetrics().lineSpacing() + 2*view->frameWidth();
00368 view->resize(QSize(h, h).expandedTo(view->sizeHint()));
00369 QWhatsThis::add(view, i18n("The contents of the file to be displayed"));
00370 }
00371 KIO::NetAccess::removeTempFile(tmpFile);
00372 }
00373 if (!opened)
00374 {
00375
00376 bool exists = KIO::NetAccess::exists(url, true, MainWindow::mainMainWindow());
00377 mErrorMsgs += dir ? i18n("File is a folder") : exists ? i18n("Failed to open file") : i18n("File not found");
00378 }
00379 break;
00380 }
00381 case KAEvent::MESSAGE:
00382 {
00383
00384
00385 MessageText* text = new MessageText(mMessage, QString::null, topWidget);
00386 text->setFrameStyle(QFrame::NoFrame);
00387 text->setPaper(mBgColour);
00388 text->setPaletteForegroundColor(mFgColour);
00389 text->setFont(mFont);
00390 int lineSpacing = text->fontMetrics().lineSpacing();
00391 QSize s = text->sizeHint();
00392 int h = s.height();
00393 text->setMaximumHeight(h + text->scrollBarHeight());
00394 text->setMinimumHeight(QMIN(h, lineSpacing*4));
00395 text->setMaximumWidth(s.width() + text->scrollBarWidth());
00396 QWhatsThis::add(text, i18n("The alarm message"));
00397 int vspace = lineSpacing/2;
00398 int hspace = lineSpacing - KDialog::marginHint();
00399 topLayout->addSpacing(vspace);
00400 topLayout->addStretch();
00401
00402 if (!mWinModule)
00403 mWinModule = new KWinModule(0, KWinModule::INFO_DESKTOP);
00404 if (text->sizeHint().width() >= mWinModule->workArea().width()*2/3)
00405 topLayout->addWidget(text, 1, Qt::AlignHCenter);
00406 else
00407 {
00408 QBoxLayout* layout = new QHBoxLayout(topLayout);
00409 layout->addSpacing(hspace);
00410 layout->addWidget(text, 1, Qt::AlignHCenter);
00411 layout->addSpacing(hspace);
00412 }
00413 if (!reminder)
00414 topLayout->addStretch();
00415 break;
00416 }
00417 case KAEvent::COMMAND:
00418 case KAEvent::EMAIL:
00419 default:
00420 break;
00421 }
00422
00423 if (reminder)
00424 {
00425
00426 mRemainingText = new QLabel(topWidget);
00427 mRemainingText->setFrameStyle(QFrame::Box | QFrame::Raised);
00428 mRemainingText->setMargin(leading);
00429 if (mDateTime.isDateOnly() || QDate::currentDate().daysTo(mDateTime.date()) > 0)
00430 {
00431 setRemainingTextDay();
00432 MidnightTimer::connect(this, SLOT(setRemainingTextDay()));
00433 }
00434 else
00435 {
00436 setRemainingTextMinute();
00437 MinuteTimer::connect(this, SLOT(setRemainingTextMinute()));
00438 }
00439 topLayout->addWidget(mRemainingText, 0, Qt::AlignHCenter);
00440 topLayout->addSpacing(KDialog::spacingHint());
00441 topLayout->addStretch();
00442 }
00443 }
00444 else
00445 {
00446
00447 switch (mAction)
00448 {
00449 case KAEvent::EMAIL:
00450 {
00451
00452 QFrame* frame = new QFrame(topWidget);
00453 frame->setFrameStyle(QFrame::Box | QFrame::Raised);
00454 QWhatsThis::add(frame, i18n("The email to send"));
00455 topLayout->addWidget(frame, 0, Qt::AlignHCenter);
00456 QGridLayout* grid = new QGridLayout(frame, 2, 2, KDialog::marginHint(), KDialog::spacingHint());
00457
00458 QLabel* label = new QLabel(i18n("Email addressee", "To:"), frame);
00459 label->setFixedSize(label->sizeHint());
00460 grid->addWidget(label, 0, 0, Qt::AlignLeft);
00461 label = new QLabel(mEvent.emailAddresses("\n"), frame);
00462 label->setFixedSize(label->sizeHint());
00463 grid->addWidget(label, 0, 1, Qt::AlignLeft);
00464
00465 label = new QLabel(i18n("Email subject", "Subject:"), frame);
00466 label->setFixedSize(label->sizeHint());
00467 grid->addWidget(label, 1, 0, Qt::AlignLeft);
00468 label = new QLabel(mEvent.emailSubject(), frame);
00469 label->setFixedSize(label->sizeHint());
00470 grid->addWidget(label, 1, 1, Qt::AlignLeft);
00471 break;
00472 }
00473 case KAEvent::COMMAND:
00474 case KAEvent::FILE:
00475 case KAEvent::MESSAGE:
00476 default:
00477
00478 break;
00479 }
00480 }
00481
00482 if (!mErrorMsgs.count())
00483 topWidget->setBackgroundColor(mBgColour);
00484 else
00485 {
00486 setCaption(i18n("Error"));
00487 QBoxLayout* layout = new QHBoxLayout(topLayout);
00488 layout->setMargin(2*KDialog::marginHint());
00489 layout->addStretch();
00490 QLabel* label = new QLabel(topWidget);
00491 label->setPixmap(DesktopIcon("error"));
00492 label->setFixedSize(label->sizeHint());
00493 layout->addWidget(label, 0, Qt::AlignRight);
00494 QBoxLayout* vlayout = new QVBoxLayout(layout);
00495 for (QStringList::Iterator it = mErrorMsgs.begin(); it != mErrorMsgs.end(); ++it)
00496 {
00497 label = new QLabel(*it, topWidget);
00498 label->setFixedSize(label->sizeHint());
00499 vlayout->addWidget(label, 0, Qt::AlignLeft);
00500 }
00501 layout->addStretch();
00502 }
00503
00504 QGridLayout* grid = new QGridLayout(1, 4);
00505 topLayout->addLayout(grid);
00506 grid->setColStretch(0, 1);
00507 int gridIndex = 1;
00508
00509
00510 mOkButton = new KPushButton(KStdGuiItem::close(), topWidget);
00511
00512 mOkButton->clearFocus();
00513 mOkButton->setFocusPolicy(QWidget::ClickFocus);
00514 mOkButton->setFixedSize(mOkButton->sizeHint());
00515 connect(mOkButton, SIGNAL(clicked()), SLOT(close()));
00516 grid->addWidget(mOkButton, 0, gridIndex++, AlignHCenter);
00517 QWhatsThis::add(mOkButton, i18n("Acknowledge the alarm"));
00518
00519 if (mShowEdit)
00520 {
00521
00522 mEditButton = new QPushButton(i18n("&Edit..."), topWidget);
00523 mEditButton->setFocusPolicy(QWidget::ClickFocus);
00524 mEditButton->setFixedSize(mEditButton->sizeHint());
00525 connect(mEditButton, SIGNAL(clicked()), SLOT(slotEdit()));
00526 grid->addWidget(mEditButton, 0, gridIndex++, AlignHCenter);
00527 QWhatsThis::add(mEditButton, i18n("Edit the alarm."));
00528 }
00529
00530 if (!mNoDefer)
00531 {
00532
00533 mDeferButton = new QPushButton(i18n("&Defer..."), topWidget);
00534 mDeferButton->setFocusPolicy(QWidget::ClickFocus);
00535 mDeferButton->setFixedSize(mDeferButton->sizeHint());
00536 connect(mDeferButton, SIGNAL(clicked()), SLOT(slotDefer()));
00537 grid->addWidget(mDeferButton, 0, gridIndex++, AlignHCenter);
00538 QWhatsThis::add(mDeferButton,
00539 i18n("Defer the alarm until later.\n"
00540 "You will be prompted to specify when the alarm should be redisplayed."));
00541
00542 setDeferralLimit(mEvent);
00543 }
00544
00545 #ifndef WITHOUT_ARTS
00546 if (!mAudioFile.isEmpty() && (mVolume || mFadeVolume > 0))
00547 {
00548
00549 QPixmap pixmap = MainBarIcon("player_stop");
00550 mSilenceButton = new QPushButton(topWidget);
00551 mSilenceButton->setPixmap(pixmap);
00552 mSilenceButton->setFixedSize(mSilenceButton->sizeHint());
00553 connect(mSilenceButton, SIGNAL(clicked()), SLOT(stopPlay()));
00554 grid->addWidget(mSilenceButton, 0, gridIndex++, AlignHCenter);
00555 QToolTip::add(mSilenceButton, i18n("Stop sound"));
00556 QWhatsThis::add(mSilenceButton, i18n("Stop playing the sound"));
00557
00558 mSilenceButton->setEnabled(false);
00559 }
00560 #endif
00561
00562 KIconLoader iconLoader;
00563 if (mKMailSerialNumber)
00564 {
00565
00566 QPixmap pixmap = iconLoader.loadIcon(QString::fromLatin1("kmail"), KIcon::MainToolbar);
00567 mKMailButton = new QPushButton(topWidget);
00568 mKMailButton->setPixmap(pixmap);
00569 mKMailButton->setFixedSize(mKMailButton->sizeHint());
00570 connect(mKMailButton, SIGNAL(clicked()), SLOT(slotShowKMailMessage()));
00571 grid->addWidget(mKMailButton, 0, gridIndex++, AlignHCenter);
00572 QToolTip::add(mKMailButton, i18n("Locate this email in KMail", "Locate in KMail"));
00573 QWhatsThis::add(mKMailButton, i18n("Locate and highlight this email in KMail"));
00574 }
00575 else
00576 mKMailButton = 0;
00577
00578
00579 QPixmap pixmap = iconLoader.loadIcon(QString::fromLatin1(kapp->aboutData()->appName()), KIcon::MainToolbar);
00580 mKAlarmButton = new QPushButton(topWidget);
00581 mKAlarmButton->setPixmap(pixmap);
00582 mKAlarmButton->setFixedSize(mKAlarmButton->sizeHint());
00583 connect(mKAlarmButton, SIGNAL(clicked()), SLOT(displayMainWindow()));
00584 grid->addWidget(mKAlarmButton, 0, gridIndex++, AlignHCenter);
00585 QString actKAlarm = i18n("Activate KAlarm");
00586 QToolTip::add(mKAlarmButton, actKAlarm);
00587 QWhatsThis::add(mKAlarmButton, actKAlarm);
00588
00589
00590
00591 mOkButton->setEnabled(false);
00592 if (mDeferButton)
00593 mDeferButton->setEnabled(false);
00594 if (mEditButton)
00595 mEditButton->setEnabled(false);
00596 if (mKMailButton)
00597 mKMailButton->setEnabled(false);
00598 mKAlarmButton->setEnabled(false);
00599
00600 topLayout->activate();
00601 setMinimumSize(QSize(grid->sizeHint().width() + 2*KDialog::marginHint(), sizeHint().height()));
00602
00603 bool modal = !(getWFlags() & Qt::WX11BypassWM);
00604
00605 unsigned long wstate = (modal ? NET::Modal : 0) | NET::Sticky | NET::KeepAbove;
00606 WId winid = winId();
00607 KWin::setState(winid, wstate);
00608 KWin::setOnAllDesktops(winid, true);
00609 }
00610
00611
00612
00613
00614
00615 void MessageWin::setRemainingTextDay()
00616 {
00617 QString text;
00618 int days = QDate::currentDate().daysTo(mDateTime.date());
00619 if (days <= 0 && !mDateTime.isDateOnly())
00620 {
00621
00622 MidnightTimer::disconnect(this, SLOT(setRemainingTextDay()));
00623 setRemainingTextMinute();
00624 MinuteTimer::connect(this, SLOT(setRemainingTextMinute()));
00625 }
00626 else
00627 {
00628 if (days <= 0)
00629 text = i18n("Today");
00630 else if (days % 7)
00631 text = i18n("Tomorrow", "in %n days' time", days);
00632 else
00633 text = i18n("in 1 week's time", "in %n weeks' time", days/7);
00634 }
00635 mRemainingText->setText(text);
00636 }
00637
00638
00639
00640
00641
00642 void MessageWin::setRemainingTextMinute()
00643 {
00644 QString text;
00645 int mins = (QDateTime::currentDateTime().secsTo(mDateTime.dateTime()) + 59) / 60;
00646 if (mins < 60)
00647 text = i18n("in 1 minute's time", "in %n minutes' time", (mins > 0 ? mins : 0));
00648 else if (mins % 60 == 0)
00649 text = i18n("in 1 hour's time", "in %n hours' time", mins/60);
00650 else if (mins % 60 == 1)
00651 text = i18n("in 1 hour 1 minute's time", "in %n hours 1 minute's time", mins/60);
00652 else
00653 text = i18n("in 1 hour %1 minutes' time", "in %n hours %1 minutes' time", mins/60).arg(mins%60);
00654 mRemainingText->setText(text);
00655 }
00656
00657
00658
00659
00660
00661 void MessageWin::saveProperties(KConfig* config)
00662 {
00663 if (mShown && !mErrorWindow)
00664 {
00665 config->writeEntry(QString::fromLatin1("EventID"), mEventID);
00666 config->writeEntry(QString::fromLatin1("AlarmType"), mAlarmType);
00667 config->writeEntry(QString::fromLatin1("Message"), mMessage);
00668 config->writeEntry(QString::fromLatin1("Type"), mAction);
00669 config->writeEntry(QString::fromLatin1("Font"), mFont);
00670 config->writeEntry(QString::fromLatin1("BgColour"), mBgColour);
00671 config->writeEntry(QString::fromLatin1("FgColour"), mFgColour);
00672 config->writeEntry(QString::fromLatin1("ConfirmAck"), mConfirmAck);
00673 if (mDateTime.isValid())
00674 {
00675 config->writeEntry(QString::fromLatin1("Time"), mDateTime.dateTime());
00676 config->writeEntry(QString::fromLatin1("DateOnly"), mDateTime.isDateOnly());
00677 }
00678 if (mCloseTime.isValid())
00679 config->writeEntry(QString::fromLatin1("Expiry"), mCloseTime);
00680 #ifndef WITHOUT_ARTS
00681 if (mAudioRepeat && mSilenceButton && mSilenceButton->isEnabled())
00682 {
00683
00684 config->writePathEntry(QString::fromLatin1("AudioFile"), mAudioFile);
00685 config->writeEntry(QString::fromLatin1("Volume"), static_cast<int>(mVolume * 100));
00686 }
00687 #endif
00688 config->writeEntry(QString::fromLatin1("Speak"), mSpeak);
00689 config->writeEntry(QString::fromLatin1("Height"), height());
00690 config->writeEntry(QString::fromLatin1("DeferMins"), mDefaultDeferMinutes);
00691 config->writeEntry(QString::fromLatin1("NoDefer"), mNoDefer);
00692 config->writeEntry(QString::fromLatin1("NoPostAction"), mNoPostAction);
00693 config->writeEntry(QString::fromLatin1("KMailSerial"), mKMailSerialNumber);
00694 }
00695 else
00696 config->writeEntry(QString::fromLatin1("Invalid"), true);
00697 }
00698
00699
00700
00701
00702
00703
00704 void MessageWin::readProperties(KConfig* config)
00705 {
00706 mInvalid = config->readBoolEntry(QString::fromLatin1("Invalid"), false);
00707 mEventID = config->readEntry(QString::fromLatin1("EventID"));
00708 mAlarmType = KAAlarm::Type(config->readNumEntry(QString::fromLatin1("AlarmType")));
00709 mMessage = config->readEntry(QString::fromLatin1("Message"));
00710 mAction = KAEvent::Action(config->readNumEntry(QString::fromLatin1("Type")));
00711 mFont = config->readFontEntry(QString::fromLatin1("Font"));
00712 mBgColour = config->readColorEntry(QString::fromLatin1("BgColour"));
00713 mFgColour = config->readColorEntry(QString::fromLatin1("FgColour"));
00714 mConfirmAck = config->readBoolEntry(QString::fromLatin1("ConfirmAck"));
00715 QDateTime invalidDateTime;
00716 QDateTime dt = config->readDateTimeEntry(QString::fromLatin1("Time"), &invalidDateTime);
00717 bool dateOnly = config->readBoolEntry(QString::fromLatin1("DateOnly"));
00718 mDateTime.set(dt, dateOnly);
00719 mCloseTime = config->readDateTimeEntry(QString::fromLatin1("Expiry"), &invalidDateTime);
00720 #ifndef WITHOUT_ARTS
00721 mAudioFile = config->readPathEntry(QString::fromLatin1("AudioFile"));
00722 mVolume = static_cast<float>(config->readNumEntry(QString::fromLatin1("Volume"))) / 100;
00723 mFadeVolume = -1;
00724 mFadeSeconds = 0;
00725 if (!mAudioFile.isEmpty())
00726 mAudioRepeat = true;
00727 #endif
00728 mSpeak = config->readBoolEntry(QString::fromLatin1("Speak"));
00729 mRestoreHeight = config->readNumEntry(QString::fromLatin1("Height"));
00730 mDefaultDeferMinutes = config->readNumEntry(QString::fromLatin1("DeferMins"));
00731 mNoDefer = config->readBoolEntry(QString::fromLatin1("NoDefer"));
00732 mNoPostAction = config->readBoolEntry(QString::fromLatin1("NoPostAction"));
00733 mKMailSerialNumber = config->readUnsignedLongNumEntry(QString::fromLatin1("KMailSerial"));
00734 mShowEdit = false;
00735 kdDebug(5950) << "MessageWin::readProperties(" << mEventID << ")" << endl;
00736 if (mAlarmType != KAAlarm::INVALID_ALARM)
00737 {
00738
00739 if (!mEventID.isEmpty())
00740 {
00741 const Event* kcalEvent = AlarmCalendar::activeCalendar()->event(mEventID);
00742 if (!kcalEvent)
00743 {
00744
00745 AlarmCalendar* cal = AlarmCalendar::displayCalendar();
00746 if (cal->isOpen())
00747 kcalEvent = cal->event(KAEvent::uid(mEventID, KAEvent::DISPLAYING));
00748 }
00749 if (kcalEvent)
00750 {
00751 mEvent.set(*kcalEvent);
00752 mEvent.setUid(KAEvent::ACTIVE);
00753 mShowEdit = true;
00754 }
00755 }
00756 initView();
00757 }
00758 }
00759
00760
00761
00762
00763
00764 MessageWin* MessageWin::findEvent(const QString& eventID)
00765 {
00766 for (QValueList<MessageWin*>::Iterator it = mWindowList.begin(); it != mWindowList.end(); ++it)
00767 {
00768 MessageWin* w = *it;
00769 if (w->mEventID == eventID && !w->mErrorWindow)
00770 return w;
00771 }
00772 return 0;
00773 }
00774
00775
00776
00777
00778 void MessageWin::playAudio()
00779 {
00780 if (mBeep)
00781 {
00782
00783 KNotifyClient::beep();
00784 QApplication::beep();
00785 }
00786 if (!mAudioFile.isEmpty())
00787 {
00788 if (!mVolume && mFadeVolume <= 0)
00789 return;
00790 #ifdef WITHOUT_ARTS
00791 QString play = mAudioFile;
00792 QString file = QString::fromLatin1("file:");
00793 if (mAudioFile.startsWith(file))
00794 play = mAudioFile.mid(file.length());
00795 KAudioPlayer::play(QFile::encodeName(play));
00796 #else
00797
00798
00799 QTimer::singleShot(0, this, SLOT(slotPlayAudio()));
00800 #endif
00801 }
00802 else if (mSpeak)
00803 {
00804
00805
00806 QTimer::singleShot(0, this, SLOT(slotSpeak()));
00807 }
00808 }
00809
00810
00811
00812
00813
00814 void MessageWin::slotSpeak()
00815 {
00816 DCOPClient* client = kapp->dcopClient();
00817 if (!client->isApplicationRegistered("kttsd"))
00818 {
00819
00820 QString error;
00821 if (kapp->startServiceByDesktopName("kttsd", QStringList(), &error))
00822 {
00823 kdDebug(5950) << "MessageWin::slotSpeak(): failed to start kttsd: " << error << endl;
00824 if (!haveErrorMessage(ErrMsg_Speak))
00825 {
00826 KMessageBox::detailedError(0, i18n("Unable to speak message"), error);
00827 clearErrorMessage(ErrMsg_Speak);
00828 }
00829 return;
00830 }
00831 }
00832 QByteArray data;
00833 QDataStream arg(data, IO_WriteOnly);
00834 arg << mMessage << "";
00835 if (!client->send("kttsd", "KSpeech", "sayMessage(QString,QString)", data))
00836 {
00837 kdDebug(5950) << "MessageWin::slotSpeak(): sayMessage() DCOP error" << endl;
00838 if (!haveErrorMessage(ErrMsg_Speak))
00839 {
00840 KMessageBox::detailedError(0, i18n("Unable to speak message"), i18n("DCOP Call sayMessage failed"));
00841 clearErrorMessage(ErrMsg_Speak);
00842 }
00843 }
00844 }
00845
00846
00847
00848
00849
00850 void MessageWin::slotPlayAudio()
00851 {
00852 #ifndef WITHOUT_ARTS
00853
00854 MainWindow* mmw = MainWindow::mainMainWindow();
00855 KURL url(mAudioFile);
00856 if (!url.isValid() || !KIO::NetAccess::exists(url, true, mmw)
00857 || !KIO::NetAccess::download(url, mLocalAudioFile, mmw))
00858 {
00859 kdError(5950) << "MessageWin::playAudio(): Open failure: " << mAudioFile << endl;
00860 if (!haveErrorMessage(ErrMsg_AudioFile))
00861 {
00862 KMessageBox::error(this, i18n("Cannot open audio file:\n%1").arg(mAudioFile));
00863 clearErrorMessage(ErrMsg_AudioFile);
00864 }
00865 return;
00866 }
00867 if (!mArtsDispatcher)
00868 {
00869 mFadeTimer = 0;
00870 mPlayTimer = new QTimer(this);
00871 connect(mPlayTimer, SIGNAL(timeout()), SLOT(checkAudioPlay()));
00872 mArtsDispatcher = new KArtsDispatcher;
00873 mPlayedOnce = false;
00874 mAudioFileStart = QTime::currentTime();
00875 initAudio(true);
00876 if (!mPlayObject->object().isNull())
00877 checkAudioPlay();
00878 if (!mUsingKMix && mVolume >= 0)
00879 {
00880
00881
00882 kdWarning(5950) << "Unable to set master volume (KMix: " << mKMixError << ")\n";
00883 if (!haveErrorMessage(ErrMsg_Volume))
00884 {
00885 KMessageBox::information(this, i18n("Unable to set master volume\n(Error accessing KMix:\n%1)").arg(mKMixError),
00886 QString::null, QString::fromLatin1("KMixError"));
00887 clearErrorMessage(ErrMsg_Volume);
00888 }
00889 }
00890 }
00891 #endif
00892 }
00893
00894 #ifndef WITHOUT_ARTS
00895
00896
00897
00898 void MessageWin::initAudio(bool firstTime)
00899 {
00900 KArtsServer aserver;
00901 Arts::SoundServerV2 sserver = aserver.server();
00902 KDE::PlayObjectFactory factory(sserver);
00903 mPlayObject = factory.createPlayObject(mLocalAudioFile, true);
00904 if (firstTime)
00905 {
00906
00907
00908 mUsingKMix = false;
00909 float volume = mVolume;
00910 if (volume >= 0)
00911 {
00912
00913 if (mFadeVolume >= 0)
00914 volume = mFadeVolume;
00915
00916
00917 int vol = getKMixVolume();
00918 if (vol >= 0)
00919 {
00920 mOldVolume = vol;
00921 mUsingKMix = true;
00922 setKMixVolume(static_cast<int>(volume * 100));
00923 }
00924 }
00925 if (!mUsingKMix)
00926 {
00927
00928
00929
00930
00931
00932 mOldVolume = sserver.outVolume().scaleFactor();
00933 sserver.outVolume().scaleFactor(volume >= 0 ? volume : 1);
00934 }
00935 }
00936 mSilenceButton->setEnabled(true);
00937 mPlayed = false;
00938 connect(mPlayObject, SIGNAL(playObjectCreated()), SLOT(checkAudioPlay()));
00939 if (!mPlayObject->object().isNull())
00940 checkAudioPlay();
00941 }
00942 #endif
00943
00944
00945
00946
00947
00948
00949
00950 void MessageWin::checkAudioPlay()
00951 {
00952 #ifndef WITHOUT_ARTS
00953 if (!mPlayObject)
00954 return;
00955 if (mPlayObject->state() == Arts::posIdle)
00956 {
00957
00958 if (mPlayedOnce && !mAudioRepeat)
00959 {
00960
00961 stopPlay();
00962 return;
00963 }
00964
00965
00966 kdDebug(5950) << "MessageWin::checkAudioPlay(): start\n";
00967 if (!mPlayedOnce)
00968 {
00969
00970 QTime now = QTime::currentTime();
00971 mAudioFileLoadSecs = mAudioFileStart.secsTo(now);
00972 if (mAudioFileLoadSecs < 0)
00973 mAudioFileLoadSecs += 86400;
00974 if (mVolume >= 0 && mFadeVolume >= 0 && mFadeSeconds > 0)
00975 {
00976
00977 mAudioFileStart = now;
00978 mFadeTimer = new QTimer(this);
00979 connect(mFadeTimer, SIGNAL(timeout()), SLOT(slotFade()));
00980 mFadeTimer->start(1000);
00981 }
00982 mPlayedOnce = true;
00983 }
00984 if (mAudioFileLoadSecs < 3)
00985 {
00986
00987
00988
00989
00990
00991 if (mPlayed)
00992 {
00993
00994 delete mPlayObject;
00995 initAudio(false);
00996 if (mPlayObject->object().isNull())
00997 return;
00998 }
00999 mPlayed = true;
01000 mPlayObject->play();
01001 }
01002 else
01003 {
01004
01005 static Arts::poTime t0((long)0, (long)0, 0, std::string());
01006 Arts::poTime current = mPlayObject->currentTime();
01007 if (current.seconds || current.ms)
01008 mPlayObject->seek(t0);
01009 else
01010 mPlayObject->play();
01011 }
01012 }
01013
01014
01015 Arts::poTime overall = mPlayObject->overallTime();
01016 Arts::poTime current = mPlayObject->currentTime();
01017 int time = 1000*(overall.seconds - current.seconds) + overall.ms - current.ms;
01018 if (time < 0)
01019 time = 0;
01020 kdDebug(5950) << "MessageWin::checkAudioPlay(): wait for " << (time+100) << "ms\n";
01021 mPlayTimer->start(time + 100, true);
01022 #endif
01023 }
01024
01025
01026
01027
01028
01029 void MessageWin::stopPlay()
01030 {
01031 #ifndef WITHOUT_ARTS
01032 if (mArtsDispatcher)
01033 {
01034
01035
01036 if (!mUsingKMix)
01037 {
01038 KArtsServer aserver;
01039 Arts::StereoVolumeControl svc = aserver.server().outVolume();
01040 float currentVolume = svc.scaleFactor();
01041 float eventVolume = mVolume;
01042 if (eventVolume < 0)
01043 eventVolume = 1;
01044 if (currentVolume == eventVolume)
01045 svc.scaleFactor(mOldVolume);
01046 }
01047 else if (mVolume >= 0)
01048 {
01049 int eventVolume = static_cast<int>(mVolume * 100);
01050 int currentVolume = getKMixVolume();
01051
01052 if (currentVolume < 0 || abs(currentVolume - eventVolume) < 5)
01053 setKMixVolume(static_cast<int>(mOldVolume));
01054 }
01055 }
01056 delete mPlayObject; mPlayObject = 0;
01057 delete mArtsDispatcher; mArtsDispatcher = 0;
01058 if (!mLocalAudioFile.isEmpty())
01059 {
01060 KIO::NetAccess::removeTempFile(mLocalAudioFile);
01061 mLocalAudioFile = QString::null;
01062 }
01063 if (mSilenceButton)
01064 mSilenceButton->setEnabled(false);
01065 #endif
01066 }
01067
01068
01069
01070
01071 void MessageWin::slotFade()
01072 {
01073 #ifndef WITHOUT_ARTS
01074 QTime now = QTime::currentTime();
01075 int elapsed = mAudioFileStart.secsTo(now);
01076 if (elapsed < 0)
01077 elapsed += 86400;
01078 float volume;
01079 if (elapsed >= mFadeSeconds)
01080 {
01081
01082 volume = mVolume;
01083 delete mFadeTimer;
01084 mFadeTimer = 0;
01085 if (!mVolume)
01086 {
01087 kdDebug(5950) << "MessageWin::slotFade(0)\n";
01088 stopPlay();
01089 return;
01090 }
01091 }
01092 else
01093 volume = mFadeVolume + ((mVolume - mFadeVolume) * elapsed) / mFadeSeconds;
01094 kdDebug(5950) << "MessageWin::slotFade(" << volume << ")\n";
01095 if (mArtsDispatcher)
01096 {
01097 if (mUsingKMix)
01098 setKMixVolume(static_cast<int>(volume * 100));
01099 else if (mArtsDispatcher)
01100 {
01101 KArtsServer aserver;
01102 aserver.server().outVolume().scaleFactor(volume);
01103 }
01104 }
01105 #endif
01106 }
01107
01108 #ifndef WITHOUT_ARTS
01109
01110
01111
01112
01113 int MessageWin::getKMixVolume()
01114 {
01115 if (!KAlarm::runProgram(KMIX_APP_NAME, KMIX_DCOP_WINDOW, mKMixName, mKMixError))
01116 return -1;
01117 QByteArray data, replyData;
01118 QCString replyType;
01119 QDataStream arg(data, IO_WriteOnly);
01120 if (!kapp->dcopClient()->call(mKMixName, KMIX_DCOP_OBJECT, "masterVolume()", data, replyType, replyData)
01121 || replyType != "int")
01122 return -1;
01123 int result;
01124 QDataStream reply(replyData, IO_ReadOnly);
01125 reply >> result;
01126 return (result >= 0) ? result : 0;
01127 }
01128
01129
01130
01131
01132 void MessageWin::setKMixVolume(int percent)
01133 {
01134 if (!mUsingKMix)
01135 return;
01136 if (!KAlarm::runProgram(KMIX_APP_NAME, KMIX_DCOP_WINDOW, mKMixName, mKMixError))
01137 return;
01138 QByteArray data;
01139 QDataStream arg(data, IO_WriteOnly);
01140 arg << percent;
01141 if (!kapp->dcopClient()->send(mKMixName, KMIX_DCOP_OBJECT, "setMasterVolume(int)", data))
01142 kdError(5950) << "MessageWin::setKMixVolume(): kmix dcop call failed\n";
01143 }
01144 #endif
01145
01146
01147
01148
01149
01150 void MessageWin::repeat(const KAAlarm& alarm)
01151 {
01152 if (mDeferDlg)
01153 {
01154
01155
01156 delete mDeferDlg;
01157 mDeferDlg = 0;
01158 }
01159 const Event* kcalEvent = mEventID.isNull() ? 0 : AlarmCalendar::activeCalendar()->event(mEventID);
01160 if (kcalEvent)
01161 {
01162 mAlarmType = alarm.type();
01163 if (!mDeferDlg || Preferences::modalMessages())
01164 {
01165 raise();
01166 playAudio();
01167 }
01168 KAEvent event(*kcalEvent);
01169 mDeferButton->setEnabled(true);
01170 setDeferralLimit(event);
01171 theApp()->alarmShowing(event, mAlarmType, mDateTime);
01172 }
01173 }
01174
01175
01176
01177
01178
01179
01180
01181 void MessageWin::show()
01182 {
01183 if (mCloseTime.isValid())
01184 {
01185
01186 int delay = QDateTime::currentDateTime().secsTo(mCloseTime);
01187 if (delay < 0)
01188 delay = 0;
01189 QTimer::singleShot(delay * 1000, this, SLOT(close()));
01190 if (!delay)
01191 return;
01192 }
01193 if (Preferences::messageButtonDelay() == 0)
01194 move(0, 0);
01195 MainWindowBase::show();
01196 }
01197
01198
01199
01200
01201
01202
01203 QSize MessageWin::sizeHint() const
01204 {
01205 if (mAction != KAEvent::MESSAGE)
01206 return MainWindowBase::sizeHint();
01207 if (!mWinModule)
01208 mWinModule = new KWinModule(0, KWinModule::INFO_DESKTOP);
01209 QSize frame = frameGeometry().size();
01210 QSize contents = geometry().size();
01211 QSize desktop = mWinModule->workArea().size();
01212 QSize maxSize(desktop.width() - (frame.width() - contents.width()),
01213 desktop.height() - (frame.height() - contents.height()));
01214 return MainWindowBase::sizeHint().boundedTo(maxSize);
01215 }
01216
01217
01218
01219
01220
01221
01222 void MessageWin::showEvent(QShowEvent* se)
01223 {
01224 MainWindowBase::showEvent(se);
01225 if (!mShown)
01226 {
01227 if (mErrorWindow)
01228 enableButtons();
01229 else
01230 {
01231
01232
01233
01234
01235
01236 QSize s = sizeHint();
01237 if (mAction == KAEvent::FILE && !mErrorMsgs.count())
01238 KAlarm::readConfigWindowSize("FileMessage", s);
01239 resize(s);
01240
01241 mButtonDelay = Preferences::messageButtonDelay() * 1000;
01242 if (!mButtonDelay)
01243 {
01244
01245
01246
01247
01248
01249
01250
01251
01252
01253
01254
01255
01256
01257
01258
01259
01260
01261 QPoint cursor = QCursor::pos();
01262 if (!mWinModule)
01263 mWinModule = new KWinModule(0, KWinModule::INFO_DESKTOP);
01264 QRect desk = mWinModule->workArea();
01265 QDesktopWidget* dw = QApplication::desktop();
01266 if (dw->numScreens() > 1)
01267 desk &= dw->screenGeometry(dw->screenNumber(cursor));
01268
01269 QRect frame = frameGeometry();
01270 QRect rect = geometry();
01271
01272 QRect button(mOkButton->mapToParent(QPoint(0, 0)), mOkButton->mapToParent(mOkButton->rect().bottomRight()));
01273 int buttonLeft = button.left() + rect.left() - frame.left();
01274 int buttonRight = width() - button.right() + frame.right() - rect.right();
01275 int buttonTop = button.top() + rect.top() - frame.top();
01276 int buttonBottom = height() - button.bottom() + frame.bottom() - rect.bottom();
01277
01278 int centrex = (desk.width() + buttonLeft - buttonRight) / 2;
01279 int centrey = (desk.height() + buttonTop - buttonBottom) / 2;
01280 int x = (cursor.x() < centrex) ? desk.right() - frame.width() : desk.left();
01281 int y = (cursor.y() < centrey) ? desk.bottom() - frame.height() : desk.top();
01282
01283
01284
01285 QRect buttons = mOkButton->geometry().unite(mKAlarmButton->geometry());
01286 buttons.moveBy(rect.left() + x - frame.left(), rect.top() + y - frame.top());
01287 int minDistance = proximityMultiple * mOkButton->height();
01288 if ((abs(cursor.x() - buttons.left()) < minDistance
01289 || abs(cursor.x() - buttons.right()) < minDistance)
01290 && (abs(cursor.y() - buttons.top()) < minDistance
01291 || abs(cursor.y() - buttons.bottom()) < minDistance))
01292 mButtonDelay = proximityButtonDelay;
01293
01294 if (x != frame.left() || y != frame.top())
01295 {
01296 mPositioning = true;
01297 move(x, y);
01298 }
01299 }
01300 if (!mPositioning)
01301 displayComplete();
01302 if (mAction == KAEvent::MESSAGE)
01303 {
01304
01305 QTimer::singleShot(0, this, SLOT(setMaxSize()));
01306 }
01307 }
01308 mShown = true;
01309 }
01310 }
01311
01312
01313
01314
01315 void MessageWin::moveEvent(QMoveEvent* e)
01316 {
01317 MainWindowBase::moveEvent(e);
01318 if (mPositioning)
01319 {
01320
01321 mPositioning = false;
01322 displayComplete();
01323 }
01324 }
01325
01326
01327
01328
01329 void MessageWin::setMaxSize()
01330 {
01331 QSize s = sizeHint();
01332 if (width() > s.width() || height() > s.height())
01333 resize(s);
01334 }
01335
01336
01337
01338
01339
01340 void MessageWin::displayComplete()
01341 {
01342 playAudio();
01343 if (mRescheduleEvent)
01344 theApp()->alarmShowing(mEvent, mAlarmType, mDateTime);
01345
01346
01347 if (mButtonDelay > 0)
01348 QTimer::singleShot(mButtonDelay, this, SLOT(enableButtons()));
01349 else
01350 enableButtons();
01351 }
01352
01353
01354
01355
01356 void MessageWin::enableButtons()
01357 {
01358 mOkButton->setEnabled(true);
01359 mKAlarmButton->setEnabled(true);
01360 if (mDeferButton && !mDisableDeferral)
01361 mDeferButton->setEnabled(true);
01362 if (mEditButton)
01363 mEditButton->setEnabled(true);
01364 if (mKMailButton)
01365 mKMailButton->setEnabled(true);
01366 }
01367
01368
01369
01370
01371 void MessageWin::resizeEvent(QResizeEvent* re)
01372 {
01373 if (mRestoreHeight)
01374 {
01375
01376 if (mRestoreHeight != re->size().height())
01377 {
01378 QSize size = re->size();
01379 size.setHeight(mRestoreHeight);
01380 resize(size);
01381 }
01382 else if (isVisible())
01383 mRestoreHeight = 0;
01384 }
01385 else
01386 {
01387 if (mShown && mAction == KAEvent::FILE && !mErrorMsgs.count())
01388 KAlarm::writeConfigWindowSize("FileMessage", re->size());
01389 MainWindowBase::resizeEvent(re);
01390 }
01391 }
01392
01393
01394
01395
01396
01397 void MessageWin::closeEvent(QCloseEvent* ce)
01398 {
01399
01400 if (!mErrorWindow && !theApp()->sessionClosingDown())
01401 {
01402 if (mConfirmAck && !mNoCloseConfirm)
01403 {
01404
01405 if (KMessageBox::warningYesNo(this, i18n("Do you really want to acknowledge this alarm?"),
01406 i18n("Acknowledge Alarm"), i18n("&Acknowledge"), KStdGuiItem::cancel())
01407 != KMessageBox::Yes)
01408 {
01409 ce->ignore();
01410 return;
01411 }
01412 }
01413 if (!mEventID.isNull())
01414 {
01415
01416 KAlarm::deleteDisplayEvent(KAEvent::uid(mEventID, KAEvent::DISPLAYING));
01417 }
01418 }
01419 MainWindowBase::closeEvent(ce);
01420 }
01421
01422
01423
01424
01425
01426 void MessageWin::slotShowKMailMessage()
01427 {
01428 kdDebug(5950) << "MessageWin::slotShowKMailMessage()\n";
01429 if (!mKMailSerialNumber)
01430 return;
01431 QString err = KAlarm::runKMail(false);
01432 if (!err.isNull())
01433 {
01434 KMessageBox::sorry(this, err);
01435 return;
01436 }
01437 QCString replyType;
01438 QByteArray data, replyData;
01439 QDataStream arg(data, IO_WriteOnly);
01440 arg << (Q_UINT32)mKMailSerialNumber << QString::null;
01441 if (kapp->dcopClient()->call("kmail", KMAIL_DCOP_OBJECT, "showMail(Q_UINT32,QString)", data, replyType, replyData)
01442 && replyType == "bool")
01443 {
01444 bool result;
01445 QDataStream replyStream(replyData, IO_ReadOnly);
01446 replyStream >> result;
01447 if (result)
01448 return;
01449 }
01450 kdError(5950) << "MessageWin::slotShowKMailMessage(): kmail dcop call failed\n";
01451 KMessageBox::sorry(this, i18n("Unable to locate this email in KMail"));
01452 }
01453
01454
01455
01456
01457
01458 void MessageWin::slotEdit()
01459 {
01460 kdDebug(5950) << "MessageWin::slotEdit()" << endl;
01461 EditAlarmDlg editDlg(false, i18n("Edit Alarm"), this, "editDlg", &mEvent);
01462 if (editDlg.exec() == QDialog::Accepted)
01463 {
01464 KAEvent event;
01465 editDlg.getEvent(event);
01466
01467
01468 KAlarm::UpdateStatus status;
01469 if (AlarmCalendar::activeCalendar()->event(mEventID))
01470 {
01471
01472 status = KAlarm::modifyEvent(mEvent, event, 0, &editDlg);
01473 Undo::saveEdit(mEvent, event);
01474 }
01475 else
01476 {
01477
01478 status = KAlarm::addEvent(event, 0, &editDlg);
01479 Undo::saveAdd(event);
01480 }
01481
01482 if (status == KAlarm::UPDATE_KORG_ERR)
01483 KAlarm::displayKOrgUpdateError(&editDlg, KAlarm::KORG_ERR_MODIFY, 1);
01484 KAlarm::outputAlarmWarnings(&editDlg, &event);
01485
01486
01487 mNoCloseConfirm = true;
01488 close();
01489 }
01490 }
01491
01492
01493
01494
01495 void MessageWin::setDeferralLimit(const KAEvent& event)
01496 {
01497 if (mDeferButton)
01498 {
01499 mDeferLimit = event.deferralLimit().dateTime();
01500 MidnightTimer::connect(this, SLOT(checkDeferralLimit()));
01501 mDisableDeferral = false;
01502 checkDeferralLimit();
01503 }
01504 }
01505
01506
01507
01508
01509
01510
01511
01512
01513
01514
01515 void MessageWin::checkDeferralLimit()
01516 {
01517 if (!mDeferButton || !mDeferLimit.isValid())
01518 return;
01519 int n = QDate::currentDate().daysTo(mDeferLimit.date());
01520 if (n > 0)
01521 return;
01522 MidnightTimer::disconnect(this, SLOT(checkDeferralLimit()));
01523 if (n == 0)
01524 {
01525
01526 n = QTime::currentTime().secsTo(mDeferLimit.time());
01527 if (n > 0)
01528 {
01529 QTimer::singleShot(n * 1000, this, SLOT(checkDeferralLimit()));
01530 return;
01531 }
01532 }
01533 mDeferButton->setEnabled(false);
01534 mDisableDeferral = true;
01535 }
01536
01537
01538
01539
01540
01541 void MessageWin::slotDefer()
01542 {
01543 mDeferDlg = new DeferAlarmDlg(i18n("Defer Alarm"), QDateTime::currentDateTime().addSecs(60),
01544 false, this, "deferDlg");
01545 if (mDefaultDeferMinutes > 0)
01546 mDeferDlg->setDeferMinutes(mDefaultDeferMinutes);
01547 mDeferDlg->setLimit(mEventID);
01548 if (!Preferences::modalMessages())
01549 lower();
01550 if (mDeferDlg->exec() == QDialog::Accepted)
01551 {
01552 DateTime dateTime = mDeferDlg->getDateTime();
01553 int delayMins = mDeferDlg->deferMinutes();
01554 const Event* kcalEvent = mEventID.isNull() ? 0 : AlarmCalendar::activeCalendar()->event(mEventID);
01555 if (kcalEvent)
01556 {
01557
01558 KAEvent event(*kcalEvent);
01559 bool repeat = event.defer(dateTime, (mAlarmType & KAAlarm::REMINDER_ALARM), true);
01560 event.setDeferDefaultMinutes(delayMins);
01561 KAlarm::updateEvent(event, 0, mDeferDlg, true, !repeat);
01562 if (event.deferred())
01563 mNoPostAction = true;
01564 }
01565 else
01566 {
01567 KAEvent event;
01568 kcalEvent = AlarmCalendar::displayCalendar()->event(KAEvent::uid(mEventID, KAEvent::DISPLAYING));
01569 if (kcalEvent)
01570 {
01571 event.reinstateFromDisplaying(KAEvent(*kcalEvent));
01572 event.defer(dateTime, (mAlarmType & KAAlarm::REMINDER_ALARM), true);
01573 }
01574 else
01575 {
01576
01577 event.set(dateTime.dateTime(), mMessage, mBgColour, mFgColour, mFont, mAction, mLateCancel, mFlags);
01578 event.setAudioFile(mAudioFile, mVolume, mFadeVolume, mFadeSeconds);
01579 event.setArchive();
01580 event.setEventID(mEventID);
01581 }
01582 event.setDeferDefaultMinutes(delayMins);
01583
01584
01585 KAlarm::addEvent(event, 0, mDeferDlg, true, false);
01586 if (event.deferred())
01587 mNoPostAction = true;
01588 if (kcalEvent)
01589 {
01590 event.setUid(KAEvent::EXPIRED);
01591 KAlarm::deleteEvent(event, false);
01592 }
01593 }
01594 if (theApp()->wantRunInSystemTray())
01595 {
01596
01597
01598 theApp()->displayTrayIcon(true);
01599 }
01600 mNoCloseConfirm = true;
01601 close();
01602 }
01603 else
01604 raise();
01605 delete mDeferDlg;
01606 mDeferDlg = 0;
01607 }
01608
01609
01610
01611
01612
01613 void MessageWin::displayMainWindow()
01614 {
01615 KAlarm::displayMainWindowSelected(mEventID);
01616 }
01617
01618
01619
01620
01621
01622
01623 bool MessageWin::haveErrorMessage(unsigned msg) const
01624 {
01625 if (!mErrorMessages.contains(mEventID))
01626 mErrorMessages.insert(mEventID, 0);
01627 bool result = (mErrorMessages[mEventID] & msg);
01628 mErrorMessages[mEventID] |= msg;
01629 return result;
01630 }
01631
01632 void MessageWin::clearErrorMessage(unsigned msg) const
01633 {
01634 if (mErrorMessages.contains(mEventID))
01635 {
01636 if (mErrorMessages[mEventID] == msg)
01637 mErrorMessages.remove(mEventID);
01638 else
01639 mErrorMessages[mEventID] &= ~msg;
01640 }
01641 }
01642
01643
01644
01645
01646
01647
01648
01649
01650
01651 bool wantModal()
01652 {
01653 bool modal = Preferences::modalMessages();
01654 if (modal)
01655 {
01656 KWinModule wm(0, KWinModule::INFO_DESKTOP);
01657 KWin::WindowInfo wi = KWin::windowInfo(wm.activeWindow(), NET::WMState);
01658 modal = !(wi.valid() && wi.hasState(NET::FullScreen));
01659 }
01660 return modal;
01661 }
01662
01663
01664
01665
01666
01667
01668
01669
01670 MWMimeSourceFactory::MWMimeSourceFactory(const QString& absPath, KTextBrowser* view)
01671 : QMimeSourceFactory(),
01672 mMimeType("text/plain"),
01673 mLast(0)
01674 {
01675 view->setMimeSourceFactory(this);
01676 QString type = KMimeType::findByPath(absPath)->name();
01677 switch (KAlarm::fileType(type))
01678 {
01679 case KAlarm::TextPlain:
01680 case KAlarm::TextFormatted:
01681 mMimeType = type.latin1();
01682
01683 case KAlarm::TextApplication:
01684 default:
01685
01686 mTextFile = absPath;
01687 view->QTextBrowser::setSource(absPath);
01688 break;
01689
01690 case KAlarm::Image:
01691
01692 QString text = "<img source=\"";
01693 text += absPath;
01694 text += "\">";
01695 view->setText(text);
01696 break;
01697 }
01698 setFilePath(QFileInfo(absPath).dirPath(true));
01699 }
01700
01701 MWMimeSourceFactory::~MWMimeSourceFactory()
01702 {
01703 delete mLast;
01704 }
01705
01706 const QMimeSource* MWMimeSourceFactory::data(const QString& abs_name) const
01707 {
01708 if (abs_name == mTextFile)
01709 {
01710 QFileInfo fi(abs_name);
01711 if (fi.isReadable())
01712 {
01713 QFile f(abs_name);
01714 if (f.open(IO_ReadOnly) && f.size())
01715 {
01716 QByteArray ba(f.size());
01717 f.readBlock(ba.data(), ba.size());
01718 QStoredDrag* sr = new QStoredDrag(mMimeType);
01719 sr->setEncodedData(ba);
01720 delete mLast;
01721 mLast = sr;
01722 return sr;
01723 }
01724 }
01725 }
01726 return QMimeSourceFactory::data(abs_name);
01727 }