27 #include <tqfileinfo.h>
29 #include <tqpushbutton.h>
31 #include <tqwhatsthis.h>
32 #include <tqtooltip.h>
33 #include <tqdragobject.h>
34 #include <tqtextedit.h>
37 #include <kstandarddirs.h>
38 #include <tdeaction.h>
39 #include <kstdguiitem.h>
40 #include <tdeaboutdata.h>
41 #include <tdelocale.h>
42 #include <tdeconfig.h>
43 #include <kiconloader.h>
45 #include <ktextbrowser.h>
46 #include <tdeglobalsettings.h>
47 #include <kmimetype.h>
48 #include <tdemessagebox.h>
50 #include <twinmodule.h>
51 #include <tdeprocess.h>
52 #include <tdeio/netaccess.h>
53 #include <knotifyclient.h>
54 #include <kpushbutton.h>
56 #include <kaudioplayer.h>
58 #include <arts/kartsdispatcher.h>
59 #include <arts/kartsserver.h>
60 #include <arts/kplayobjectfactory.h>
61 #include <arts/kplayobject.h>
63 #include <dcopclient.h>
66 #include "alarmcalendar.h"
72 #include "preferences.h"
73 #include "synchtimer.h"
74 #include "messagewin.moc"
79 static const char* KMIX_APP_NAME =
"kmix";
80 static const char* KMIX_DCOP_OBJECT =
"Mixer0";
81 static const char* KMIX_DCOP_WINDOW =
"kmix-mainwindow#1";
83 static const char* KMAIL_DCOP_OBJECT =
"KMailIface";
87 static const int proximityButtonDelay = 1000;
88 static const int proximityMultiple = 10;
90 static bool wantModal();
93 class MessageText :
public TQTextEdit
96 MessageText(
const TQString& text,
const TQString& context = TQString(), TQWidget* parent = 0,
const char* name = 0)
97 : TQTextEdit(text, context, parent, name)
100 setWordWrap(TQTextEdit::NoWrap);
102 int scrollBarHeight()
const {
return horizontalScrollBar()->height(); }
103 int scrollBarWidth()
const {
return verticalScrollBar()->width(); }
104 virtual TQSize sizeHint()
const {
return TQSize(contentsWidth() + scrollBarWidth(), contentsHeight() + scrollBarHeight()); }
108 class MWMimeSourceFactory :
public TQMimeSourceFactory
111 MWMimeSourceFactory(
const TQString& absPath, KTextBrowser*);
112 virtual ~MWMimeSourceFactory();
113 virtual const TQMimeSource* data(
const TQString& abs_name)
const;
116 virtual void setData(
const TQString&, TQMimeSource*) {}
117 virtual void setExtensionType(
const TQString&,
const char*) {}
121 mutable const TQMimeSource* mLast;
126 static const TQt::WFlags WFLAGS = TQt::WStyle_StaysOnTop | TQt::WDestructiveClose;
131 ErrMsg_AudioFile = 0x02,
136 TQValueList<MessageWin*> MessageWin::mWindowList;
137 TQMap<TQString, unsigned> MessageWin::mErrorMessages;
146 MessageWin::MessageWin(
const KAEvent& event,
const KAAlarm& alarm,
bool reschedule_event,
bool allowDefer)
147 :
MainWindowBase(0,
"MessageWin", WFLAGS | TQt::WGroupLeader | TQt::WStyle_ContextHelp
148 | (wantModal() ? 0 : TQt::WX11BypassWM)),
149 mMessage(event.cleanText()),
151 mBgColour(event.bgColour()),
152 mFgColour(event.fgColour()),
153 mDateTime((alarm.type() & KAAlarm::REMINDER_ALARM) ? event.mainDateTime(true) : alarm.dateTime(true)),
154 mEventID(event.id()),
155 mAudioFile(event.audioFile()),
156 mVolume(event.soundVolume()),
157 mFadeVolume(event.fadeVolume()),
158 mFadeSeconds(TQMIN(event.fadeSeconds(), 86400)),
159 mDefaultDeferMinutes(event.deferDefaultMinutes()),
160 mAlarmType(alarm.type()),
161 mAction(event.action()),
162 mKMailSerialNumber(event.kmailSerialNumber()),
164 mAudioRepeat(event.repeatSound()),
165 mConfirmAck(event.confirmAck()),
166 mShowEdit(!mEventID.isEmpty()),
167 mNoDefer(!allowDefer || alarm.repeatAtLogin()),
178 mFlags(event.flags()),
179 mLateCancel(event.lateCancel()),
181 mNoPostAction(alarm.type() & KAAlarm::REMINDER_ALARM),
184 mSpeak(event.speak()),
185 mRescheduleEvent(reschedule_event),
188 mNoCloseConfirm(false),
189 mDisableDeferral(false)
191 kdDebug(5950) <<
"MessageWin::MessageWin(event)" << endl;
194 setAutoSaveSettings(TQString::fromLatin1(
"MessageWin"),
false);
196 mWindowList.append(
this);
197 if (event.autoClose())
198 mCloseTime = alarm.dateTime().dateTime().addSecs(event.lateCancel() * 60);
204 MessageWin::MessageWin(
const KAEvent& event,
const DateTime& alarmDateTime,
const TQStringList& errmsgs)
205 :
MainWindowBase(0,
"MessageWin", WFLAGS | TQt::WGroupLeader | TQt::WStyle_ContextHelp),
206 mMessage(event.cleanText()),
207 mDateTime(alarmDateTime),
208 mEventID(event.id()),
209 mAlarmType(KAAlarm::MAIN_ALARM),
210 mAction(event.action()),
211 mKMailSerialNumber(0),
229 mRescheduleEvent(false),
232 mNoCloseConfirm(false),
233 mDisableDeferral(false)
235 kdDebug(5950) <<
"MessageWin::MessageWin(errmsg)" << endl;
237 mWindowList.append(
this);
244 MessageWin::MessageWin()
255 mRescheduleEvent(false),
258 mNoCloseConfirm(false),
259 mDisableDeferral(false)
261 kdDebug(5950) <<
"MessageWin::MessageWin(restore)\n";
262 mWindowList.append(
this);
268 MessageWin::~MessageWin()
270 kdDebug(5950) <<
"MessageWin::~MessageWin(" << mEventID <<
")" << endl;
274 mErrorMessages.remove(mEventID);
275 mWindowList.remove(
this);
278 if (!mNoPostAction && !mEvent.postAction().isEmpty())
279 theApp()->alarmCompleted(mEvent);
280 if (!mWindowList.count())
288 void MessageWin::initView()
290 bool reminder = (!mErrorWindow && (mAlarmType & KAAlarm::REMINDER_ALARM));
291 int leading = fontMetrics().leading();
292 setCaption((mAlarmType & KAAlarm::REMINDER_ALARM) ? i18n(
"Reminder") : i18n(
"Message"));
293 TQWidget* topWidget =
new TQWidget(
this,
"messageWinTop");
294 setCentralWidget(topWidget);
295 TQVBoxLayout* topLayout =
new TQVBoxLayout(topWidget, KDialog::marginHint(), KDialog::spacingHint());
297 if (mDateTime.isValid())
301 TQVBoxLayout* layout = topLayout;
304 frame =
new TQFrame(topWidget);
305 frame->setFrameStyle(TQFrame::Box | TQFrame::Raised);
306 topLayout->addWidget(frame, 0, TQt::AlignHCenter);
307 layout =
new TQVBoxLayout(frame, leading + frame->frameWidth(), leading);
311 TQLabel* label =
new TQLabel(frame ? frame : topWidget);
312 label->setText(mDateTime.isDateOnly()
313 ? TDEGlobal::locale()->formatDate(mDateTime.date(),
true)
314 : TDEGlobal::locale()->formatDateTime(mDateTime.dateTime()));
316 label->setFrameStyle(TQFrame::Box | TQFrame::Raised);
317 label->setFixedSize(label->sizeHint());
318 layout->addWidget(label, 0, TQt::AlignHCenter);
319 TQWhatsThis::add(label,
320 i18n(
"The scheduled date/time for the message (as opposed to the actual time of display)."));
324 label =
new TQLabel(frame);
325 label->setText(i18n(
"Reminder"));
326 label->setFixedSize(label->sizeHint());
327 layout->addWidget(label, 0, TQt::AlignHCenter);
328 frame->setFixedSize(frame->sizeHint());
340 TQLabel* label =
new TQLabel(mMessage, topWidget);
341 label->setFrameStyle(TQFrame::Box | TQFrame::Raised);
342 label->setFixedSize(label->sizeHint());
343 TQWhatsThis::add(label, i18n(
"The file whose contents are displayed below"));
344 topLayout->addWidget(label, 0, TQt::AlignHCenter);
351 if (TDEIO::NetAccess::download(url, tmpFile, MainWindow::mainMainWindow()))
353 TQFile qfile(tmpFile);
354 TQFileInfo info(qfile);
355 if (!(dir = info.isDir()))
358 KTextBrowser*
view =
new KTextBrowser(topWidget,
"fileContents");
359 MWMimeSourceFactory msf(tmpFile, view);
360 view->setMinimumSize(
view->sizeHint());
361 topLayout->addWidget(view);
367 int h = 20*
view->fontMetrics().lineSpacing() + 2*
view->frameWidth();
368 view->resize(TQSize(h, h).expandedTo(
view->sizeHint()));
369 TQWhatsThis::add(view, i18n(
"The contents of the file to be displayed"));
371 TDEIO::NetAccess::removeTempFile(tmpFile);
376 bool exists = TDEIO::NetAccess::exists(url,
true, MainWindow::mainMainWindow());
377 mErrorMsgs += dir ? i18n(
"File is a folder") : exists ? i18n(
"Failed to open file") : i18n(
"File not found");
381 case KAEvent::MESSAGE:
385 MessageText* text =
new MessageText(mMessage, TQString(), topWidget);
386 text->setFrameStyle(TQFrame::NoFrame);
387 text->setPaper(mBgColour);
388 text->setPaletteForegroundColor(mFgColour);
389 text->setFont(mFont);
390 int lineSpacing = text->fontMetrics().lineSpacing();
391 TQSize s = text->sizeHint();
393 text->setMaximumHeight(h + text->scrollBarHeight());
394 text->setMinimumHeight(TQMIN(h, lineSpacing*4));
395 text->setMaximumWidth(s.width() + text->scrollBarWidth());
396 TQWhatsThis::add(text, i18n(
"The alarm message"));
397 int vspace = lineSpacing/2;
398 int hspace = lineSpacing - KDialog::marginHint();
399 topLayout->addSpacing(vspace);
400 topLayout->addStretch();
403 mWinModule =
new KWinModule(0, KWinModule::INFO_DESKTOP);
404 if (text->sizeHint().width() >= mWinModule->workArea().width()*2/3)
405 topLayout->addWidget(text, 1, TQt::AlignHCenter);
408 TQBoxLayout* layout =
new TQHBoxLayout(topLayout);
409 layout->addSpacing(hspace);
410 layout->addWidget(text, 1, TQt::AlignHCenter);
411 layout->addSpacing(hspace);
414 topLayout->addStretch();
417 case KAEvent::COMMAND:
426 mRemainingText =
new TQLabel(topWidget);
427 mRemainingText->setFrameStyle(TQFrame::Box | TQFrame::Raised);
428 mRemainingText->setMargin(leading);
429 if (mDateTime.isDateOnly() || TQDate::currentDate().daysTo(mDateTime.date()) > 0)
431 setRemainingTextDay();
432 MidnightTimer::connect(
this, TQ_SLOT(setRemainingTextDay()));
436 setRemainingTextMinute();
437 MinuteTimer::connect(
this, TQ_SLOT(setRemainingTextMinute()));
439 topLayout->addWidget(mRemainingText, 0, TQt::AlignHCenter);
440 topLayout->addSpacing(KDialog::spacingHint());
441 topLayout->addStretch();
452 TQFrame* frame =
new TQFrame(topWidget);
453 frame->setFrameStyle(TQFrame::Box | TQFrame::Raised);
454 TQWhatsThis::add(frame, i18n(
"The email to send"));
455 topLayout->addWidget(frame, 0, TQt::AlignHCenter);
456 TQGridLayout* grid =
new TQGridLayout(frame, 2, 2, KDialog::marginHint(), KDialog::spacingHint());
458 TQLabel* label =
new TQLabel(i18n(
"Email addressee",
"To:"), frame);
459 label->setFixedSize(label->sizeHint());
460 grid->addWidget(label, 0, 0, TQt::AlignLeft);
461 label =
new TQLabel(mEvent.emailAddresses(
"\n"), frame);
462 label->setFixedSize(label->sizeHint());
463 grid->addWidget(label, 0, 1, TQt::AlignLeft);
465 label =
new TQLabel(i18n(
"Email subject",
"Subject:"), frame);
466 label->setFixedSize(label->sizeHint());
467 grid->addWidget(label, 1, 0, TQt::AlignLeft);
468 label =
new TQLabel(mEvent.emailSubject(), frame);
469 label->setFixedSize(label->sizeHint());
470 grid->addWidget(label, 1, 1, TQt::AlignLeft);
473 case KAEvent::COMMAND:
475 case KAEvent::MESSAGE:
482 if (!mErrorMsgs.count())
483 topWidget->setBackgroundColor(mBgColour);
486 setCaption(i18n(
"Error"));
487 TQBoxLayout* layout =
new TQHBoxLayout(topLayout);
488 layout->setMargin(2*KDialog::marginHint());
489 layout->addStretch();
490 TQLabel* label =
new TQLabel(topWidget);
491 label->setPixmap(DesktopIcon(
"error"));
492 label->setFixedSize(label->sizeHint());
493 layout->addWidget(label, 0, TQt::AlignRight);
494 TQBoxLayout* vlayout =
new TQVBoxLayout(layout);
495 for (TQStringList::Iterator it = mErrorMsgs.begin(); it != mErrorMsgs.end(); ++it)
497 label =
new TQLabel(*it, topWidget);
498 label->setFixedSize(label->sizeHint());
499 vlayout->addWidget(label, 0, TQt::AlignLeft);
501 layout->addStretch();
504 TQGridLayout* grid =
new TQGridLayout(1, 4);
505 topLayout->addLayout(grid);
506 grid->setColStretch(0, 1);
510 mOkButton =
new KPushButton(KStdGuiItem::close(), topWidget);
512 mOkButton->clearFocus();
513 mOkButton->setFocusPolicy(TQWidget::ClickFocus);
514 mOkButton->setFixedSize(mOkButton->sizeHint());
515 connect(mOkButton, TQ_SIGNAL(clicked()), TQ_SLOT(close()));
516 grid->addWidget(mOkButton, 0, gridIndex++, AlignHCenter);
517 TQWhatsThis::add(mOkButton, i18n(
"Acknowledge the alarm"));
522 mEditButton =
new TQPushButton(i18n(
"&Edit..."), topWidget);
523 mEditButton->setFocusPolicy(TQWidget::ClickFocus);
524 mEditButton->setFixedSize(mEditButton->sizeHint());
525 connect(mEditButton, TQ_SIGNAL(clicked()), TQ_SLOT(slotEdit()));
526 grid->addWidget(mEditButton, 0, gridIndex++, AlignHCenter);
527 TQWhatsThis::add(mEditButton, i18n(
"Edit the alarm."));
533 mDeferButton =
new TQPushButton(i18n(
"&Defer..."), topWidget);
534 mDeferButton->setFocusPolicy(TQWidget::ClickFocus);
535 mDeferButton->setFixedSize(mDeferButton->sizeHint());
536 connect(mDeferButton, TQ_SIGNAL(clicked()), TQ_SLOT(slotDefer()));
537 grid->addWidget(mDeferButton, 0, gridIndex++, AlignHCenter);
538 TQWhatsThis::add(mDeferButton,
539 i18n(
"Defer the alarm until later.\n"
540 "You will be prompted to specify when the alarm should be redisplayed."));
542 setDeferralLimit(mEvent);
546 if (!mAudioFile.isEmpty() && (mVolume || mFadeVolume > 0))
549 TQPixmap pixmap = MainBarIcon(
"media-playback-stop");
550 mSilenceButton =
new TQPushButton(topWidget);
551 mSilenceButton->setPixmap(pixmap);
552 mSilenceButton->setFixedSize(mSilenceButton->sizeHint());
553 connect(mSilenceButton, TQ_SIGNAL(clicked()), TQ_SLOT(stopPlay()));
554 grid->addWidget(mSilenceButton, 0, gridIndex++, AlignHCenter);
555 TQToolTip::add(mSilenceButton, i18n(
"Stop sound"));
556 TQWhatsThis::add(mSilenceButton, i18n(
"Stop playing the sound"));
558 mSilenceButton->setEnabled(
false);
562 TDEIconLoader iconLoader;
563 if (mKMailSerialNumber)
566 TQPixmap pixmap = iconLoader.loadIcon(TQString::fromLatin1(
"kmail"), TDEIcon::MainToolbar);
567 mKMailButton =
new TQPushButton(topWidget);
568 mKMailButton->setPixmap(pixmap);
569 mKMailButton->setFixedSize(mKMailButton->sizeHint());
570 connect(mKMailButton, TQ_SIGNAL(clicked()), TQ_SLOT(slotShowKMailMessage()));
571 grid->addWidget(mKMailButton, 0, gridIndex++, AlignHCenter);
572 TQToolTip::add(mKMailButton, i18n(
"Locate this email in KMail",
"Locate in KMail"));
573 TQWhatsThis::add(mKMailButton, i18n(
"Locate and highlight this email in KMail"));
579 TQPixmap pixmap = iconLoader.loadIcon(TQString::fromLatin1(kapp->aboutData()->appName()), TDEIcon::MainToolbar);
580 mKAlarmButton =
new TQPushButton(topWidget);
581 mKAlarmButton->setPixmap(pixmap);
582 mKAlarmButton->setFixedSize(mKAlarmButton->sizeHint());
583 connect(mKAlarmButton, TQ_SIGNAL(clicked()), TQ_SLOT(displayMainWindow()));
584 grid->addWidget(mKAlarmButton, 0, gridIndex++, AlignHCenter);
585 TQString actKAlarm = i18n(
"Activate KAlarm");
586 TQToolTip::add(mKAlarmButton, actKAlarm);
587 TQWhatsThis::add(mKAlarmButton, actKAlarm);
591 mOkButton->setEnabled(
false);
593 mDeferButton->setEnabled(
false);
595 mEditButton->setEnabled(
false);
597 mKMailButton->setEnabled(
false);
598 mKAlarmButton->setEnabled(
false);
600 topLayout->activate();
601 setMinimumSize(TQSize(grid->sizeHint().width() + 2*KDialog::marginHint(), sizeHint().height()));
603 bool modal = !(getWFlags() & TQt::WX11BypassWM);
605 unsigned long wstate = (modal ? NET::Modal : 0) | NET::Sticky | NET::KeepAbove;
607 KWin::setState(winid, wstate);
608 KWin::setOnAllDesktops(winid,
true);
615 void MessageWin::setRemainingTextDay()
618 int days = TQDate::currentDate().daysTo(mDateTime.date());
619 if (days <= 0 && !mDateTime.isDateOnly())
622 MidnightTimer::disconnect(
this, TQ_SLOT(setRemainingTextDay()));
623 setRemainingTextMinute();
624 MinuteTimer::connect(
this, TQ_SLOT(setRemainingTextMinute()));
629 text = i18n(
"Today");
631 text = i18n(
"Tomorrow",
"in %n days' time", days);
633 text = i18n(
"in 1 week's time",
"in %n weeks' time", days/7);
635 mRemainingText->setText(text);
642 void MessageWin::setRemainingTextMinute()
645 int mins = (TQDateTime::currentDateTime().secsTo(mDateTime.dateTime()) + 59) / 60;
647 text = i18n(
"in 1 minute's time",
"in %n minutes' time", (mins > 0 ? mins : 0));
648 else if (mins % 60 == 0)
649 text = i18n(
"in 1 hour's time",
"in %n hours' time", mins/60);
650 else if (mins % 60 == 1)
651 text = i18n(
"in 1 hour 1 minute's time",
"in %n hours 1 minute's time", mins/60);
653 text = i18n(
"in 1 hour %1 minutes' time",
"in %n hours %1 minutes' time", mins/60).arg(mins%60);
654 mRemainingText->setText(text);
661 void MessageWin::saveProperties(TDEConfig* config)
663 if (mShown && !mErrorWindow)
665 config->writeEntry(TQString::fromLatin1(
"EventID"), mEventID);
666 config->writeEntry(TQString::fromLatin1(
"AlarmType"), mAlarmType);
667 config->writeEntry(TQString::fromLatin1(
"Message"), mMessage);
668 config->writeEntry(TQString::fromLatin1(
"Type"), mAction);
669 config->writeEntry(TQString::fromLatin1(
"Font"), mFont);
670 config->writeEntry(TQString::fromLatin1(
"BgColour"), mBgColour);
671 config->writeEntry(TQString::fromLatin1(
"FgColour"), mFgColour);
672 config->writeEntry(TQString::fromLatin1(
"ConfirmAck"), mConfirmAck);
673 if (mDateTime.isValid())
675 config->writeEntry(TQString::fromLatin1(
"Time"), mDateTime.dateTime());
676 config->writeEntry(TQString::fromLatin1(
"DateOnly"), mDateTime.isDateOnly());
678 if (mCloseTime.isValid())
679 config->writeEntry(TQString::fromLatin1(
"Expiry"), mCloseTime);
681 if (mAudioRepeat && mSilenceButton && mSilenceButton->isEnabled())
684 config->writePathEntry(TQString::fromLatin1(
"AudioFile"), mAudioFile);
685 config->writeEntry(TQString::fromLatin1(
"Volume"),
static_cast<int>(mVolume * 100));
688 config->writeEntry(TQString::fromLatin1(
"Speak"), mSpeak);
689 config->writeEntry(TQString::fromLatin1(
"Height"), height());
690 config->writeEntry(TQString::fromLatin1(
"DeferMins"), mDefaultDeferMinutes);
691 config->writeEntry(TQString::fromLatin1(
"NoDefer"), mNoDefer);
692 config->writeEntry(TQString::fromLatin1(
"NoPostAction"), mNoPostAction);
693 config->writeEntry(TQString::fromLatin1(
"KMailSerial"), mKMailSerialNumber);
696 config->writeEntry(TQString::fromLatin1(
"Invalid"),
true);
704 void MessageWin::readProperties(TDEConfig* config)
706 mInvalid = config->readBoolEntry(TQString::fromLatin1(
"Invalid"),
false);
707 mEventID = config->readEntry(TQString::fromLatin1(
"EventID"));
708 mAlarmType = KAAlarm::Type(config->readNumEntry(TQString::fromLatin1(
"AlarmType")));
709 mMessage = config->readEntry(TQString::fromLatin1(
"Message"));
710 mAction = KAEvent::Action(config->readNumEntry(TQString::fromLatin1(
"Type")));
711 mFont = config->readFontEntry(TQString::fromLatin1(
"Font"));
712 mBgColour = config->readColorEntry(TQString::fromLatin1(
"BgColour"));
713 mFgColour = config->readColorEntry(TQString::fromLatin1(
"FgColour"));
714 mConfirmAck = config->readBoolEntry(TQString::fromLatin1(
"ConfirmAck"));
715 TQDateTime invalidDateTime;
716 TQDateTime dt = config->readDateTimeEntry(TQString::fromLatin1(
"Time"), &invalidDateTime);
717 bool dateOnly = config->readBoolEntry(TQString::fromLatin1(
"DateOnly"));
718 mDateTime.set(dt, dateOnly);
719 mCloseTime = config->readDateTimeEntry(TQString::fromLatin1(
"Expiry"), &invalidDateTime);
721 mAudioFile = config->readPathEntry(TQString::fromLatin1(
"AudioFile"));
722 mVolume =
static_cast<float>(config->readNumEntry(TQString::fromLatin1(
"Volume"))) / 100;
725 if (!mAudioFile.isEmpty())
728 mSpeak = config->readBoolEntry(TQString::fromLatin1(
"Speak"));
729 mRestoreHeight = config->readNumEntry(TQString::fromLatin1(
"Height"));
730 mDefaultDeferMinutes = config->readNumEntry(TQString::fromLatin1(
"DeferMins"));
731 mNoDefer = config->readBoolEntry(TQString::fromLatin1(
"NoDefer"));
732 mNoPostAction = config->readBoolEntry(TQString::fromLatin1(
"NoPostAction"));
733 mKMailSerialNumber = config->readUnsignedLongNumEntry(TQString::fromLatin1(
"KMailSerial"));
735 kdDebug(5950) <<
"MessageWin::readProperties(" << mEventID <<
")" << endl;
736 if (mAlarmType != KAAlarm::INVALID_ALARM)
739 if (!mEventID.isEmpty())
741 const Event* kcalEvent = AlarmCalendar::activeCalendar()->event(mEventID);
747 kcalEvent = cal->event(KAEvent::uid(mEventID, KAEvent::DISPLAYING));
751 mEvent.set(*kcalEvent);
752 mEvent.setUid(KAEvent::ACTIVE);
764 MessageWin* MessageWin::findEvent(
const TQString& eventID)
766 for (TQValueList<MessageWin*>::Iterator it = mWindowList.begin(); it != mWindowList.end(); ++it)
769 if (w->mEventID == eventID && !w->mErrorWindow)
778 void MessageWin::playAudio()
783 KNotifyClient::beep();
784 TQApplication::beep();
786 if (!mAudioFile.isEmpty())
788 if (!mVolume && mFadeVolume <= 0)
791 TQString play = mAudioFile;
792 TQString file = TQString::fromLatin1(
"file:");
793 if (mAudioFile.startsWith(file))
794 play = mAudioFile.mid(file.length());
795 KAudioPlayer::play(TQFile::encodeName(play));
799 TQTimer::singleShot(0,
this, TQ_SLOT(slotPlayAudio()));
806 TQTimer::singleShot(0,
this, TQ_SLOT(slotSpeak()));
814 void MessageWin::slotSpeak()
816 DCOPClient* client = kapp->dcopClient();
817 if (!client->isApplicationRegistered(
"kttsd"))
821 if (kapp->startServiceByDesktopName(
"kttsd", TQStringList(), &error))
823 kdDebug(5950) <<
"MessageWin::slotSpeak(): failed to start kttsd: " << error << endl;
824 if (!haveErrorMessage(ErrMsg_Speak))
826 KMessageBox::detailedError(0, i18n(
"Unable to speak message"), error);
827 clearErrorMessage(ErrMsg_Speak);
833 TQDataStream arg(data, IO_WriteOnly);
834 arg << mMessage <<
"";
835 if (!client->send(
"kttsd",
"KSpeech",
"sayMessage(TQString,TQString)", data))
837 kdDebug(5950) <<
"MessageWin::slotSpeak(): sayMessage() DCOP error" << endl;
838 if (!haveErrorMessage(ErrMsg_Speak))
840 KMessageBox::detailedError(0, i18n(
"Unable to speak message"), i18n(
"DCOP Call sayMessage failed"));
841 clearErrorMessage(ErrMsg_Speak);
850 void MessageWin::slotPlayAudio()
854 MainWindow* mmw = MainWindow::mainMainWindow();
855 KURL url(mAudioFile);
856 if (!url.isValid() || !TDEIO::NetAccess::exists(url,
true, mmw)
857 || !TDEIO::NetAccess::download(url, mLocalAudioFile, mmw))
859 kdError(5950) <<
"MessageWin::playAudio(): Open failure: " << mAudioFile << endl;
860 if (!haveErrorMessage(ErrMsg_AudioFile))
862 KMessageBox::error(
this, i18n(
"Cannot open audio file:\n%1").arg(mAudioFile));
863 clearErrorMessage(ErrMsg_AudioFile);
867 if (!mArtsDispatcher)
870 mPlayTimer =
new TQTimer(
this);
871 connect(mPlayTimer, TQ_SIGNAL(timeout()), TQ_SLOT(checkAudioPlay()));
872 mArtsDispatcher =
new KArtsDispatcher;
874 mAudioFileStart = TQTime::currentTime();
876 if (!mPlayObject->object().isNull())
878 if (!mUsingKMix && mVolume >= 0)
882 kdWarning(5950) <<
"Unable to set master volume (KMix: " << mKMixError <<
")\n";
883 if (!haveErrorMessage(ErrMsg_Volume))
885 KMessageBox::information(
this, i18n(
"Unable to set master volume\n(Error accessing KMix:\n%1)").arg(mKMixError),
886 TQString(), TQString::fromLatin1(
"KMixError"));
887 clearErrorMessage(ErrMsg_Volume);
898 void MessageWin::initAudio(
bool firstTime)
901 Arts::SoundServerV2 sserver = aserver.server();
902 KDE::PlayObjectFactory factory(sserver);
903 mPlayObject = factory.createPlayObject(mLocalAudioFile,
true);
909 float volume = mVolume;
913 if (mFadeVolume >= 0)
914 volume = mFadeVolume;
917 int vol = getKMixVolume();
922 setKMixVolume(
static_cast<int>(volume * 100));
932 mOldVolume = sserver.outVolume().scaleFactor();
933 sserver.outVolume().scaleFactor(volume >= 0 ? volume : 1);
936 mSilenceButton->setEnabled(
true);
938 connect(mPlayObject, TQ_SIGNAL(playObjectCreated()), TQ_SLOT(checkAudioPlay()));
939 if (!mPlayObject->object().isNull())
950 void MessageWin::checkAudioPlay()
955 if (mPlayObject->state() == Arts::posIdle)
958 if (mPlayedOnce && !mAudioRepeat)
966 kdDebug(5950) <<
"MessageWin::checkAudioPlay(): start\n";
970 TQTime now = TQTime::currentTime();
971 mAudioFileLoadSecs = mAudioFileStart.secsTo(now);
972 if (mAudioFileLoadSecs < 0)
973 mAudioFileLoadSecs += 86400;
974 if (mVolume >= 0 && mFadeVolume >= 0 && mFadeSeconds > 0)
977 mAudioFileStart = now;
978 mFadeTimer =
new TQTimer(
this);
979 connect(mFadeTimer, TQ_SIGNAL(timeout()), TQ_SLOT(slotFade()));
980 mFadeTimer->start(1000);
984 if (mAudioFileLoadSecs < 3)
996 if (mPlayObject->object().isNull())
1000 mPlayObject->play();
1005 static Arts::poTime t0((
long)0, (
long)0, 0, std::string());
1006 Arts::poTime current = mPlayObject->currentTime();
1007 if (current.seconds || current.ms)
1008 mPlayObject->seek(t0);
1010 mPlayObject->play();
1015 Arts::poTime overall = mPlayObject->overallTime();
1016 Arts::poTime current = mPlayObject->currentTime();
1017 int time = 1000*(overall.seconds - current.seconds) + overall.ms - current.ms;
1020 kdDebug(5950) <<
"MessageWin::checkAudioPlay(): wait for " << (time+100) <<
"ms\n";
1021 mPlayTimer->start(time + 100,
true);
1029 void MessageWin::stopPlay()
1031 #ifndef WITHOUT_ARTS
1032 if (mArtsDispatcher)
1038 KArtsServer aserver;
1039 Arts::StereoVolumeControl svc = aserver.server().outVolume();
1040 float currentVolume = svc.scaleFactor();
1041 float eventVolume = mVolume;
1042 if (eventVolume < 0)
1044 if (currentVolume == eventVolume)
1045 svc.scaleFactor(mOldVolume);
1047 else if (mVolume >= 0)
1049 int eventVolume =
static_cast<int>(mVolume * 100);
1050 int currentVolume = getKMixVolume();
1052 if (currentVolume < 0 || abs(currentVolume - eventVolume) < 5)
1053 setKMixVolume(
static_cast<int>(mOldVolume));
1056 delete mPlayObject; mPlayObject = 0;
1057 delete mArtsDispatcher; mArtsDispatcher = 0;
1058 if (!mLocalAudioFile.isEmpty())
1060 TDEIO::NetAccess::removeTempFile(mLocalAudioFile);
1061 mLocalAudioFile = TQString();
1064 mSilenceButton->setEnabled(
false);
1071 void MessageWin::slotFade()
1073 #ifndef WITHOUT_ARTS
1074 TQTime now = TQTime::currentTime();
1075 int elapsed = mAudioFileStart.secsTo(now);
1079 if (elapsed >= mFadeSeconds)
1087 kdDebug(5950) <<
"MessageWin::slotFade(0)\n";
1093 volume = mFadeVolume + ((mVolume - mFadeVolume) * elapsed) / mFadeSeconds;
1094 kdDebug(5950) <<
"MessageWin::slotFade(" << volume <<
")\n";
1095 if (mArtsDispatcher)
1098 setKMixVolume(
static_cast<int>(volume * 100));
1099 else if (mArtsDispatcher)
1101 KArtsServer aserver;
1102 aserver.server().outVolume().scaleFactor(volume);
1108 #ifndef WITHOUT_ARTS
1113 int MessageWin::getKMixVolume()
1115 if (!KAlarm::runProgram(KMIX_APP_NAME, KMIX_DCOP_WINDOW, mKMixName, mKMixError))
1117 TQByteArray data, replyData;
1118 TQCString replyType;
1119 TQDataStream arg(data, IO_WriteOnly);
1120 if (!kapp->dcopClient()->call(mKMixName, KMIX_DCOP_OBJECT,
"masterVolume()", data, replyType, replyData)
1121 || replyType !=
"int")
1124 TQDataStream reply(replyData, IO_ReadOnly);
1126 return (result >= 0) ? result : 0;
1132 void MessageWin::setKMixVolume(
int percent)
1136 if (!KAlarm::runProgram(KMIX_APP_NAME, KMIX_DCOP_WINDOW, mKMixName, mKMixError))
1139 TQDataStream arg(data, IO_WriteOnly);
1141 if (!kapp->dcopClient()->send(mKMixName, KMIX_DCOP_OBJECT,
"setMasterVolume(int)", data))
1142 kdError(5950) <<
"MessageWin::setKMixVolume(): kmix dcop call failed\n";
1150 void MessageWin::repeat(
const KAAlarm& alarm)
1159 const Event* kcalEvent = mEventID.isNull() ? 0 : AlarmCalendar::activeCalendar()->event(mEventID);
1162 mAlarmType = alarm.type();
1163 if (!mDeferDlg || Preferences::modalMessages())
1169 mDeferButton->setEnabled(
true);
1170 setDeferralLimit(event);
1171 theApp()->alarmShowing(event, mAlarmType, mDateTime);
1181 void MessageWin::show()
1183 if (mCloseTime.isValid())
1186 int delay = TQDateTime::currentDateTime().secsTo(mCloseTime);
1189 TQTimer::singleShot(delay * 1000,
this, TQ_SLOT(close()));
1193 if (Preferences::messageButtonDelay() == 0)
1195 MainWindowBase::show();
1203 TQSize MessageWin::sizeHint()
const
1205 if (mAction != KAEvent::MESSAGE)
1206 return MainWindowBase::sizeHint();
1208 mWinModule =
new KWinModule(0, KWinModule::INFO_DESKTOP);
1209 TQSize frame = frameGeometry().size();
1210 TQSize contents = geometry().size();
1211 TQSize desktop = mWinModule->workArea().size();
1212 TQSize maxSize(desktop.width() - (frame.width() - contents.width()),
1213 desktop.height() - (frame.height() - contents.height()));
1214 return MainWindowBase::sizeHint().boundedTo(maxSize);
1222 void MessageWin::showEvent(TQShowEvent* se)
1224 MainWindowBase::showEvent(se);
1236 TQSize s = sizeHint();
1237 if (mAction == KAEvent::FILE && !mErrorMsgs.count())
1238 KAlarm::readConfigWindowSize(
"FileMessage", s);
1241 mButtonDelay = Preferences::messageButtonDelay() * 1000;
1261 TQPoint cursor = TQCursor::pos();
1263 mWinModule =
new KWinModule(0, KWinModule::INFO_DESKTOP);
1264 TQRect desk = mWinModule->workArea();
1265 TQDesktopWidget* dw = TQApplication::desktop();
1266 if (dw->numScreens() > 1)
1267 desk &= dw->screenGeometry(dw->screenNumber(cursor));
1269 TQRect frame = frameGeometry();
1270 TQRect rect = geometry();
1272 TQRect button(mOkButton->mapToParent(TQPoint(0, 0)), mOkButton->mapToParent(mOkButton->rect().bottomRight()));
1273 int buttonLeft = button.left() + rect.left() - frame.left();
1274 int buttonRight = width() - button.right() + frame.right() - rect.right();
1275 int buttonTop = button.top() + rect.top() - frame.top();
1276 int buttonBottom = height() - button.bottom() + frame.bottom() - rect.bottom();
1278 int centrex = (desk.width() + buttonLeft - buttonRight) / 2;
1279 int centrey = (desk.height() + buttonTop - buttonBottom) / 2;
1280 int x = (cursor.x() < centrex) ? desk.right() - frame.width() : desk.left();
1281 int y = (cursor.y() < centrey) ? desk.bottom() - frame.height() : desk.top();
1285 TQRect buttons = mOkButton->geometry().unite(mKAlarmButton->geometry());
1286 buttons.moveBy(rect.left() + x - frame.left(), rect.top() + y - frame.top());
1287 int minDistance = proximityMultiple * mOkButton->height();
1288 if ((abs(cursor.x() - buttons.left()) < minDistance
1289 || abs(cursor.x() - buttons.right()) < minDistance)
1290 && (abs(cursor.y() - buttons.top()) < minDistance
1291 || abs(cursor.y() - buttons.bottom()) < minDistance))
1292 mButtonDelay = proximityButtonDelay;
1294 if (x != frame.left() || y != frame.top())
1296 mPositioning =
true;
1302 if (mAction == KAEvent::MESSAGE)
1305 TQTimer::singleShot(0,
this, TQ_SLOT(setMaxSize()));
1315 void MessageWin::moveEvent(TQMoveEvent* e)
1317 MainWindowBase::moveEvent(e);
1321 mPositioning =
false;
1329 void MessageWin::setMaxSize()
1331 TQSize s = sizeHint();
1332 if (width() > s.width() || height() > s.height())
1340 void MessageWin::displayComplete()
1343 if (mRescheduleEvent)
1344 theApp()->alarmShowing(mEvent, mAlarmType, mDateTime);
1347 if (mButtonDelay > 0)
1348 TQTimer::singleShot(mButtonDelay,
this, TQ_SLOT(enableButtons()));
1356 void MessageWin::enableButtons()
1358 mOkButton->setEnabled(
true);
1359 mKAlarmButton->setEnabled(
true);
1360 if (mDeferButton && !mDisableDeferral)
1361 mDeferButton->setEnabled(
true);
1363 mEditButton->setEnabled(
true);
1365 mKMailButton->setEnabled(
true);
1371 void MessageWin::resizeEvent(TQResizeEvent* re)
1376 if (mRestoreHeight != re->size().height())
1378 TQSize size = re->size();
1379 size.setHeight(mRestoreHeight);
1382 else if (isVisible())
1387 if (mShown && mAction == KAEvent::FILE && !mErrorMsgs.count())
1388 KAlarm::writeConfigWindowSize(
"FileMessage", re->size());
1389 MainWindowBase::resizeEvent(re);
1397 void MessageWin::closeEvent(TQCloseEvent* ce)
1400 if (!mErrorWindow && !theApp()->sessionClosingDown())
1402 if (mConfirmAck && !mNoCloseConfirm)
1405 if (KMessageBox::warningYesNo(
this, i18n(
"Do you really want to acknowledge this alarm?"),
1406 i18n(
"Acknowledge Alarm"), i18n(
"&Acknowledge"), KStdGuiItem::cancel())
1407 != KMessageBox::Yes)
1413 if (!mEventID.isNull())
1416 KAlarm::deleteDisplayEvent(KAEvent::uid(mEventID, KAEvent::DISPLAYING));
1419 MainWindowBase::closeEvent(ce);
1426 void MessageWin::slotShowKMailMessage()
1428 kdDebug(5950) <<
"MessageWin::slotShowKMailMessage()\n";
1429 if (!mKMailSerialNumber)
1431 TQString err = KAlarm::runKMail(
false);
1434 KMessageBox::sorry(
this, err);
1437 TQCString replyType;
1438 TQByteArray data, replyData;
1439 TQDataStream arg(data, IO_WriteOnly);
1440 arg << (TQ_UINT32)mKMailSerialNumber << TQString();
1441 if (kapp->dcopClient()->call(
"kmail", KMAIL_DCOP_OBJECT,
"showMail(TQ_UINT32,TQString)", data, replyType, replyData)
1442 && replyType ==
"bool")
1445 TQDataStream replyStream(replyData, IO_ReadOnly);
1446 replyStream >> result;
1450 kdError(5950) <<
"MessageWin::slotShowKMailMessage(): kmail dcop call failed\n";
1451 KMessageBox::sorry(
this, i18n(
"Unable to locate this email in KMail"));
1458 void MessageWin::slotEdit()
1460 kdDebug(5950) <<
"MessageWin::slotEdit()" << endl;
1461 EditAlarmDlg editDlg(
false, i18n(
"Edit Alarm"),
this,
"editDlg", &mEvent);
1462 if (editDlg.exec() == TQDialog::Accepted)
1465 editDlg.getEvent(event);
1469 if (AlarmCalendar::activeCalendar()->event(mEventID))
1472 status = KAlarm::modifyEvent(mEvent, event, 0, &editDlg);
1473 Undo::saveEdit(mEvent, event);
1478 status = KAlarm::addEvent(event, 0, &editDlg);
1479 Undo::saveAdd(event);
1482 if (status == KAlarm::UPDATE_KORG_ERR)
1483 KAlarm::displayKOrgUpdateError(&editDlg, KAlarm::KORG_ERR_MODIFY, 1);
1484 KAlarm::outputAlarmWarnings(&editDlg, &event);
1487 mNoCloseConfirm =
true;
1495 void MessageWin::setDeferralLimit(
const KAEvent& event)
1499 mDeferLimit =
event.deferralLimit().dateTime();
1500 MidnightTimer::connect(
this, TQ_SLOT(checkDeferralLimit()));
1501 mDisableDeferral =
false;
1502 checkDeferralLimit();
1515 void MessageWin::checkDeferralLimit()
1517 if (!mDeferButton || !mDeferLimit.isValid())
1519 int n = TQDate::currentDate().daysTo(mDeferLimit.date());
1522 MidnightTimer::disconnect(
this, TQ_SLOT(checkDeferralLimit()));
1526 n = TQTime::currentTime().secsTo(mDeferLimit.time());
1529 TQTimer::singleShot(n * 1000,
this, TQ_SLOT(checkDeferralLimit()));
1533 mDeferButton->setEnabled(
false);
1534 mDisableDeferral =
true;
1541 void MessageWin::slotDefer()
1543 mDeferDlg =
new DeferAlarmDlg(i18n(
"Defer Alarm"), TQDateTime(TQDateTime::currentDateTime().addSecs(60)),
1544 false,
this,
"deferDlg");
1545 if (mDefaultDeferMinutes > 0)
1546 mDeferDlg->setDeferMinutes(mDefaultDeferMinutes);
1547 mDeferDlg->setLimit(mEventID);
1548 if (!Preferences::modalMessages())
1550 if (mDeferDlg->exec() == TQDialog::Accepted)
1552 DateTime dateTime = mDeferDlg->getDateTime();
1553 int delayMins = mDeferDlg->deferMinutes();
1554 const Event* kcalEvent = mEventID.isNull() ? 0 : AlarmCalendar::activeCalendar()->event(mEventID);
1559 bool repeat =
event.defer(dateTime, (mAlarmType & KAAlarm::REMINDER_ALARM),
true);
1560 event.setDeferDefaultMinutes(delayMins);
1561 KAlarm::updateEvent(event, 0, mDeferDlg,
true, !repeat);
1562 if (event.deferred())
1563 mNoPostAction =
true;
1568 kcalEvent = AlarmCalendar::displayCalendar()->event(KAEvent::uid(mEventID, KAEvent::DISPLAYING));
1571 event.reinstateFromDisplaying(
KAEvent(*kcalEvent));
1572 event.defer(dateTime, (mAlarmType & KAAlarm::REMINDER_ALARM),
true);
1577 event.set(dateTime.dateTime(), mMessage, mBgColour, mFgColour, mFont, mAction, mLateCancel, mFlags);
1578 event.setAudioFile(mAudioFile, mVolume, mFadeVolume, mFadeSeconds);
1580 event.setEventID(mEventID);
1582 event.setDeferDefaultMinutes(delayMins);
1585 KAlarm::addEvent(event, 0, mDeferDlg,
true,
false);
1586 if (event.deferred())
1587 mNoPostAction =
true;
1590 event.setUid(KAEvent::EXPIRED);
1591 KAlarm::deleteEvent(event,
false);
1594 if (theApp()->wantRunInSystemTray())
1598 theApp()->displayTrayIcon(
true);
1600 mNoCloseConfirm =
true;
1613 void MessageWin::displayMainWindow()
1615 KAlarm::displayMainWindowSelected(mEventID);
1623 bool MessageWin::haveErrorMessage(
unsigned msg)
const
1625 if (!mErrorMessages.contains(mEventID))
1626 mErrorMessages.insert(mEventID, 0);
1627 bool result = (mErrorMessages[mEventID] & msg);
1628 mErrorMessages[mEventID] |= msg;
1632 void MessageWin::clearErrorMessage(
unsigned msg)
const
1634 if (mErrorMessages.contains(mEventID))
1636 if (mErrorMessages[mEventID] == msg)
1637 mErrorMessages.remove(mEventID);
1639 mErrorMessages[mEventID] &= ~msg;
1653 bool modal = Preferences::modalMessages();
1656 KWinModule wm(0, KWinModule::INFO_DESKTOP);
1657 KWin::WindowInfo wi = KWin::windowInfo(wm.activeWindow(), NET::WMState);
1658 modal = !(wi.valid() && wi.hasState(NET::FullScreen));
1670 MWMimeSourceFactory::MWMimeSourceFactory(
const TQString& absPath, KTextBrowser* view)
1671 : TQMimeSourceFactory(),
1672 mMimeType(
"text/plain"),
1675 view->setMimeSourceFactory(
this);
1676 TQString type = KMimeType::findByPath(absPath)->name();
1677 switch (KAlarm::fileType(type))
1679 case KAlarm::TextPlain:
1680 case KAlarm::TextFormatted:
1681 mMimeType = type.latin1();
1683 case KAlarm::TextApplication:
1686 mTextFile = absPath;
1687 view->TQTextBrowser::setSource(absPath);
1692 TQString text =
"<img source=\"";
1695 view->setText(text);
1698 setFilePath(TQFileInfo(absPath).dirPath(
true));
1701 MWMimeSourceFactory::~MWMimeSourceFactory()
1706 const TQMimeSource* MWMimeSourceFactory::data(
const TQString& abs_name)
const
1708 if (abs_name == mTextFile)
1710 TQFileInfo fi(abs_name);
1711 if (fi.isReadable())
1714 if (f.open(IO_ReadOnly) && f.size())
1716 TQByteArray ba(f.size());
1717 f.readBlock(ba.data(), ba.size());
1718 TQStoredDrag* sr =
new TQStoredDrag(mMimeType);
1719 sr->setEncodedData(ba);
1726 return TQMimeSourceFactory::data(abs_name);
Provides read and write access to calendar files.
KAEvent corresponds to a KCal::Event instance.
The MainWindowBase class is a base class for KAlarm's main window and message window.
MessageWin: A window to display an alarm message.
UpdateStatus
Return codes from calendar update functions.
the KAlarm application object
bool view(TQWidget *parent, Attachment *attachment)