00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025 #include "kalarm.h"
00026
00027 #include <qfile.h>
00028 #include <qfileinfo.h>
00029 #include <qlayout.h>
00030 #include <qpushbutton.h>
00031 #include <qtextedit.h>
00032 #include <qlabel.h>
00033 #include <qwhatsthis.h>
00034
00035 #include <kstandarddirs.h>
00036 #include <kaction.h>
00037 #include <kstdguiitem.h>
00038 #include <kaboutdata.h>
00039 #include <klocale.h>
00040 #include <kconfig.h>
00041 #include <kiconloader.h>
00042 #include <kdialog.h>
00043 #include <kmessagebox.h>
00044 #include <kwin.h>
00045 #include <kwinmodule.h>
00046 #include <kprocess.h>
00047 #include <kio/netaccess.h>
00048 #include <knotifyclient.h>
00049 #include <kaudioplayer.h>
00050 #include <kdebug.h>
00051
00052 #include "kalarmapp.h"
00053 #include "alarmcalendar.h"
00054 #include "prefsettings.h"
00055 #include "deferdlg.h"
00056 #include "messagewin.moc"
00057
00058
00059 static const int MAX_LINE_LENGTH = 80;
00060
00061 QPtrList<MessageWin> MessageWin::windowList;
00062
00063
00064
00065
00066
00067
00068
00069
00070 MessageWin::MessageWin(const KAlarmEvent& evnt, const KAlarmAlarm& alarm, bool reschedule_event, bool allowDefer)
00071 : MainWindowBase(0L, "MessageWin", WStyle_StaysOnTop | WDestructiveClose | WGroupLeader | WStyle_ContextHelp),
00072 event(evnt),
00073 message(alarm.cleanText()),
00074 font(theApp()->settings()->messageFont()),
00075 colour(alarm.colour()),
00076 dateTime(alarm.repeatAtLogin() ? evnt.firstAlarm().dateTime() : alarm.dateTime()),
00077 eventID(evnt.id()),
00078 audioFile(evnt.audioFile()),
00079 alarmID(alarm.id()),
00080 flags(alarm.flags()),
00081 beep(alarm.beep()),
00082 confirmAck(event.confirmAck()),
00083 dateOnly(event.anyTime()),
00084 type(alarm.type()),
00085 noDefer(!allowDefer || alarm.repeatAtLogin()),
00086 deferButton(0L),
00087 restoreHeight(0),
00088 rescheduleEvent(reschedule_event),
00089 shown(false),
00090 deferClosing(false)
00091 {
00092 kdDebug(5950) << "MessageWin::MessageWin(event)" << endl;
00093 setAutoSaveSettings(QString::fromLatin1("MessageWin"));
00094 QSize size = initView();
00095 if (type == KAlarmAlarm::FILE && errorMsg.isNull())
00096 size = theApp()->readConfigWindowSize("FileMessage", size);
00097 resize(size);
00098 windowList.append(this);
00099 }
00100
00101
00102
00103
00104
00105
00106
00107 MessageWin::MessageWin(const QString& errmsg, const KAlarmEvent& evnt, const KAlarmAlarm& alarm, bool reschedule_event)
00108 : MainWindowBase(0L, "MessageWin", WStyle_StaysOnTop | WDestructiveClose | WGroupLeader | WStyle_ContextHelp),
00109 event(evnt),
00110 message(alarm.cleanText()),
00111 font(theApp()->settings()->messageFont()),
00112 colour(Qt::white),
00113 dateTime(alarm.repeatAtLogin() ? evnt.firstAlarm().dateTime() : alarm.dateTime()),
00114 eventID(evnt.id()),
00115 audioFile(evnt.audioFile()),
00116 alarmID(alarm.id()),
00117 flags(alarm.flags()),
00118 beep(false),
00119 confirmAck(evnt.confirmAck()),
00120 dateOnly(evnt.anyTime()),
00121 type(alarm.type()),
00122 errorMsg(errmsg),
00123 noDefer(true),
00124 deferButton(0L),
00125 restoreHeight(0),
00126 rescheduleEvent(reschedule_event),
00127 shown(false),
00128 deferClosing(false)
00129 {
00130 kdDebug(5950) << "MessageWin::MessageWin(event)" << endl;
00131 setAutoSaveSettings(QString::fromLatin1("MessageWin"));
00132 QSize size = initView();
00133 resize(size);
00134 windowList.append(this);
00135 }
00136
00137
00138
00139
00140
00141 MessageWin::MessageWin()
00142 : MainWindowBase(0L, "MessageWin", WStyle_StaysOnTop | WDestructiveClose),
00143 rescheduleEvent(false),
00144 shown(true),
00145 deferClosing(false)
00146 {
00147 kdDebug(5950) << "MessageWin::MessageWin()\n";
00148 windowList.append(this);
00149 }
00150
00151 MessageWin::~MessageWin()
00152 {
00153 kdDebug(5950) << "MessageWin::~MessageWin()\n";
00154 for (MessageWin* w = windowList.first(); w; w = windowList.next())
00155 if (w == this)
00156 {
00157 windowList.remove();
00158 break;
00159 }
00160 }
00161
00162
00163
00164
00165 QSize MessageWin::initView()
00166 {
00167 setCaption(i18n("Message"));
00168 QWidget* topWidget = new QWidget(this, "messageWinTop");
00169 setCentralWidget(topWidget);
00170 QVBoxLayout* topLayout = new QVBoxLayout(topWidget, KDialog::marginHint(), KDialog::spacingHint());
00171
00172 if (dateTime.isValid())
00173 {
00174
00175 QLabel* label = new QLabel(topWidget);
00176 label->setText(dateOnly ? KGlobal::locale()->formatDate(dateTime.date(), true)
00177 : KGlobal::locale()->formatDateTime(dateTime));
00178 label->setFrameStyle(QFrame::Box | QFrame::Raised);
00179 label->setFixedSize(label->sizeHint());
00180 topLayout->addWidget(label, 0, Qt::AlignHCenter);
00181 QWhatsThis::add(label,
00182 i18n("The scheduled date/time for the message (as opposed to the actual time of display)."));
00183 }
00184
00185 QLabel* fileCommandLabel = 0;
00186 if (type == KAlarmAlarm::FILE || type == KAlarmAlarm::COMMAND)
00187 {
00188
00189 fileCommandLabel = new QLabel(message, topWidget);
00190 fileCommandLabel->setFrameStyle(QFrame::Box | QFrame::Raised);
00191 fileCommandLabel->setFixedSize(fileCommandLabel->sizeHint());
00192 topLayout->addWidget(fileCommandLabel, 0, Qt::AlignHCenter);
00193 }
00194 switch (type)
00195 {
00196 case KAlarmAlarm::COMMAND:
00197 {
00198 QWhatsThis::add(fileCommandLabel, i18n("The command to execute"));
00199 break;
00200 }
00201 case KAlarmAlarm::FILE:
00202 {
00203 QWhatsThis::add(fileCommandLabel, i18n("The file whose contents are displayed below"));
00204
00205
00206 bool opened = false;
00207 bool dir = false;
00208 QString tmpFile;
00209 KURL url(message);
00210 if (KIO::NetAccess::download(url, tmpFile))
00211 {
00212 QFile qfile(tmpFile);
00213 QFileInfo info(qfile);
00214 if (!(dir = info.isDir())
00215 && qfile.open(IO_ReadOnly|IO_Translate))
00216 {
00217 opened = true;
00218 QTextEdit* view = new QTextEdit(topWidget, "fileContents");
00219 view->setReadOnly(true);
00220 topLayout->addWidget(view);
00221 QFontMetrics fm = view->fontMetrics();
00222 QString line;
00223 int n;
00224 for (n = 0; qfile.readLine(line, 4096) > 0; ++n)
00225 {
00226 int nl = line.find('\n');
00227 if (nl >= 0)
00228 line = line.left(nl);
00229 view->append(line);
00230 }
00231 qfile.close();
00232 view->setMinimumSize(view->sizeHint());
00233
00234
00235
00236
00237
00238 int h = fm.lineSpacing() * (n <= 20 ? n : 20) + 2*view->frameWidth();
00239 view->resize(QSize(h, h).expandedTo(view->sizeHint()));
00240 QWhatsThis::add(view, i18n("The contents of the file to be displayed"));
00241 }
00242 KIO::NetAccess::removeTempFile(tmpFile);
00243 }
00244 if (!opened)
00245 {
00246
00247 bool exists = KIO::NetAccess::exists(url);
00248 errorMsg = dir ? i18n("File is a directory") : exists ? i18n("Failed to open file") : i18n("File not found");
00249 }
00250 break;
00251 }
00252 #ifdef KALARM_EMAIL
00253 case KAlarmAlarm::EMAIL:
00254 {
00255
00256 QFrame* frame = new QFrame(topWidget);
00257 frame->setFrameStyle(QFrame::Box | QFrame::Raised);
00258 QWhatsThis::add(frame, i18n("The email to send"));
00259 topLayout->addWidget(frame, 0, Qt::AlignHCenter);
00260 QGridLayout* grid = new QGridLayout(frame, 2, 2, KDialog::marginHint(), KDialog::spacingHint());
00261
00262 QLabel* label = new QLabel(i18n("To:"), frame);
00263 label->setFixedSize(label->sizeHint());
00264 grid->addWidget(label, 0, 0, Qt::AlignLeft);
00265 label = new QLabel(emailAddresses, frame);
00266 label->setFixedSize(label->sizeHint());
00267 grid->addWidget(label, 0, 1, Qt::AlignLeft);
00268
00269 label = new QLabel(i18n("Subject:"), frame);
00270 label->setFixedSize(label->sizeHint());
00271 grid->addWidget(label, 1, 0, Qt::AlignLeft);
00272 label = new QLabel(emailSubject, frame);
00273 label->setFixedSize(label->sizeHint());
00274 grid->addWidget(label, 1, 1, Qt::AlignLeft);
00275 break;
00276 }
00277 #endif
00278 case KAlarmAlarm::MESSAGE:
00279 default:
00280 {
00281
00282 QLabel* label = new QLabel(message, topWidget);
00283 label->setFont(font);
00284 label->setPalette(QPalette(colour, colour));
00285 label->setFixedSize(label->sizeHint());
00286 QWhatsThis::add(label, i18n("The alarm message"));
00287 int lineSpacing = label->fontMetrics().lineSpacing();
00288 int vspace = lineSpacing/2 - marginKDE2;
00289 int hspace = lineSpacing - marginKDE2 - KDialog::marginHint();
00290 topLayout->addSpacing(vspace);
00291 QBoxLayout* layout = new QHBoxLayout(topLayout);
00292 layout->addSpacing(hspace);
00293 layout->addWidget(label, 0, Qt::AlignHCenter);
00294 layout->addSpacing(hspace);
00295 topLayout->addSpacing(vspace);
00296 break;
00297 }
00298 }
00299 if (errorMsg.isNull())
00300 topWidget->setBackgroundColor(colour);
00301 else
00302 {
00303 setCaption(i18n("Error"));
00304 QHBoxLayout* layout = new QHBoxLayout(topLayout);
00305 layout->setMargin(2*KDialog::marginHint());
00306 layout->addStretch();
00307 QLabel* label = new QLabel(topWidget);
00308 label->setPixmap(DesktopIcon("error"));
00309 label->setFixedSize(label->sizeHint());
00310 layout->addWidget(label, 0, Qt::AlignRight);
00311 label = new QLabel(errorMsg, topWidget);
00312 label->setFixedSize(label->sizeHint());
00313 layout->addWidget(label, 0, Qt::AlignLeft);
00314 layout->addStretch();
00315 }
00316
00317 QGridLayout* grid = new QGridLayout(1, 4);
00318 topLayout->addLayout(grid);
00319 grid->setColStretch(0, 1);
00320
00321
00322 QPushButton* okButton = new QPushButton(KStdGuiItem::close().text(), topWidget);
00323
00324 okButton->clearFocus();
00325 okButton->setFocusPolicy(QWidget::ClickFocus);
00326 connect(okButton, SIGNAL(clicked()), SLOT(close()));
00327 grid->addWidget(okButton, 0, 1, AlignHCenter);
00328 QWhatsThis::add(okButton, i18n("Acknowledge the alarm"));
00329
00330 if (!noDefer)
00331 {
00332
00333 deferButton = new QPushButton(i18n("&Defer..."), topWidget);
00334 deferButton->setFocusPolicy(QWidget::ClickFocus);
00335 connect(deferButton, SIGNAL(clicked()), SLOT(slotDefer()));
00336 grid->addWidget(deferButton, 0, 2, AlignHCenter);
00337 QWhatsThis::add(deferButton,
00338 i18n("Defer the alarm until later.\n"
00339 "You will be prompted to specify when the alarm should be redisplayed."));
00340 }
00341
00342
00343 KIconLoader iconLoader;
00344 QPixmap pixmap = iconLoader.loadIcon(QString::fromLatin1(kapp->aboutData()->appName()), KIcon::MainToolbar);
00345 QPushButton* button = new QPushButton(topWidget);
00346 button->setPixmap(pixmap);
00347 button->setFixedSize(button->sizeHint());
00348 connect(button, SIGNAL(clicked()), theApp(), SLOT(displayMainWindow()));
00349 grid->addWidget(button, 0, 3, AlignHCenter);
00350 QWhatsThis::add(button, i18n("Activate %1").arg(kapp->aboutData()->programName()));
00351
00352
00353 QSize minbutsize = okButton->sizeHint();
00354 if (!noDefer)
00355 {
00356 minbutsize = minbutsize.expandedTo(deferButton->sizeHint());
00357 deferButton->setFixedSize(minbutsize);
00358 }
00359 okButton->setFixedSize(minbutsize);
00360
00361 topLayout->activate();
00362 QSize size(minbutsize.width()*3, topLayout->sizeHint().height());
00363 setMinimumSize(size);
00364
00365 KWin::setState(winId(), NET::Modal | NET::Sticky | NET::StaysOnTop);
00366 KWin::setOnAllDesktops(winId(), true);
00367 return size;
00368 }
00369
00370
00371
00372
00373
00374 void MessageWin::saveProperties(KConfig* config)
00375 {
00376 if (shown)
00377 {
00378 config->writeEntry(QString::fromLatin1("EventID"), eventID);
00379 config->writeEntry(QString::fromLatin1("AlarmID"), alarmID);
00380 config->writeEntry(QString::fromLatin1("Message"), message);
00381 config->writeEntry(QString::fromLatin1("Type"), (errorMsg.isNull() ? type : -1));
00382 config->writeEntry(QString::fromLatin1("Font"), font);
00383 config->writeEntry(QString::fromLatin1("Colour"), colour);
00384 config->writeEntry(QString::fromLatin1("ConfirmAck"), confirmAck);
00385 if (dateTime.isValid())
00386 {
00387 config->writeEntry(QString::fromLatin1("Time"), dateTime);
00388 config->writeEntry(QString::fromLatin1("DateOnly"), dateOnly);
00389 }
00390 config->writeEntry(QString::fromLatin1("Height"), height());
00391 config->writeEntry(QString::fromLatin1("NoDefer"), noDefer);
00392 }
00393 else
00394 config->writeEntry(QString::fromLatin1("AlarmID"), -1);
00395 }
00396
00397
00398
00399
00400
00401
00402 void MessageWin::readProperties(KConfig* config)
00403 {
00404 eventID = config->readEntry(QString::fromLatin1("EventID"));
00405 alarmID = config->readNumEntry(QString::fromLatin1("AlarmID"));
00406 message = config->readEntry(QString::fromLatin1("Message"));
00407 int t = config->readNumEntry(QString::fromLatin1("Type"));
00408 if (t < 0)
00409 errorMsg = "";
00410 type = KAlarmAlarm::Type(t);
00411 font = config->readFontEntry(QString::fromLatin1("Font"));
00412 colour = config->readColorEntry(QString::fromLatin1("Colour"));
00413 confirmAck = config->readBoolEntry(QString::fromLatin1("ConfirmAck"));
00414 QDateTime invalidDateTime;
00415 dateTime = config->readDateTimeEntry(QString::fromLatin1("Time"), &invalidDateTime);
00416 dateOnly = config->readBoolEntry(QString::fromLatin1("DateOnly"));
00417 restoreHeight = config->readNumEntry(QString::fromLatin1("Height"));
00418 noDefer = config->readBoolEntry(QString::fromLatin1("NoDefer"));
00419 if (errorMsg.isNull() && alarmID > 0)
00420 initView();
00421 }
00422
00423
00424
00425
00426
00427 MessageWin* MessageWin::findEvent(const QString& eventID)
00428 {
00429 for (MessageWin* w = windowList.first(); w; w = windowList.next())
00430 if (w->eventID == eventID)
00431 return w;
00432 return 0L;
00433 }
00434
00435
00436
00437
00438 void MessageWin::playAudio()
00439 {
00440 if (beep)
00441 {
00442
00443 KNotifyClient::beep();
00444 QApplication::beep();
00445 }
00446 if (!audioFile.isEmpty())
00447 {
00448 QString play = audioFile;
00449 QString file = QString::fromLatin1("file:");
00450 if (audioFile.startsWith(file))
00451 play = audioFile.mid(file.length());
00452 KAudioPlayer::play(QFile::encodeName(play));
00453 }
00454 }
00455
00456
00457
00458
00459
00460 void MessageWin::repeat()
00461 {
00462 const Event* kcalEvent = eventID.isNull() ? 0L : theApp()->getCalendar().event(eventID);
00463 if (kcalEvent)
00464 {
00465 raise();
00466 playAudio();
00467 KAlarmEvent event(*kcalEvent);
00468 theApp()->rescheduleAlarm(event, alarmID);
00469 }
00470 }
00471
00472
00473
00474
00475
00476
00477 void MessageWin::showEvent(QShowEvent* se)
00478 {
00479 MainWindowBase::showEvent(se);
00480 if (!shown)
00481 {
00482 playAudio();
00483 if (rescheduleEvent)
00484 theApp()->rescheduleAlarm(event, alarmID);
00485 shown = true;
00486 }
00487 }
00488
00489
00490
00491
00492 void MessageWin::resizeEvent(QResizeEvent* re)
00493 {
00494 if (restoreHeight)
00495 {
00496 if (restoreHeight != re->size().height())
00497 {
00498 QSize size = re->size();
00499 size.setHeight(restoreHeight);
00500 resize(size);
00501 }
00502 else if (isVisible())
00503 restoreHeight = 0;
00504 }
00505 else
00506 {
00507 if (type == KAlarmAlarm::FILE && errorMsg.isNull())
00508 theApp()->writeConfigWindowSize("FileMessage", re->size());
00509 MainWindowBase::resizeEvent(re);
00510 }
00511 }
00512
00513
00514
00515
00516
00517 void MessageWin::closeEvent(QCloseEvent* ce)
00518 {
00519
00520 if (confirmAck && !deferClosing && !theApp()->sessionClosingDown())
00521 {
00522
00523 if (KMessageBox::warningYesNo(this, i18n("Do you really want to acknowledge this alarm?"),
00524 i18n("Acknowledge Alarm"), i18n("&Acknowledge"), KStdGuiItem::cancel().text())
00525 != KMessageBox::Yes)
00526 {
00527 ce->ignore();
00528 return;
00529 }
00530 }
00531 MainWindowBase::closeEvent(ce);
00532 }
00533
00534
00535
00536
00537
00538 void MessageWin::slotDefer()
00539 {
00540 KAlarmEvent event;
00541 QDateTime endTime;
00542
00543 const Event* kcalEvent = eventID.isNull() ? 0L : theApp()->getCalendar().event(eventID);
00544 if (kcalEvent)
00545 {
00546
00547
00548 event.set(*kcalEvent);
00549 event.nextOccurrence(QDateTime::currentDateTime(), endTime);
00550 }
00551 DeferAlarmDlg* deferDlg = new DeferAlarmDlg(i18n("Defer Alarm"), QDateTime::currentDateTime().addSecs(60),
00552 endTime, false, this, "deferDlg");
00553 if (deferDlg->exec() == QDialog::Accepted)
00554 {
00555 QDateTime dateTime = deferDlg->getDateTime();
00556 if (kcalEvent)
00557 {
00558
00559 event.defer(dateTime);
00560 theApp()->updateEvent(event, 0L);
00561 }
00562 else
00563 {
00564
00565 KAlarmEvent event(dateTime, message, colour, type, flags);
00566 event.setAudioFile(audioFile);
00567 theApp()->addEvent(event, 0L);
00568 }
00569 if (theApp()->runInSystemTray())
00570 {
00571
00572
00573 theApp()->displayTrayIcon(true);
00574 }
00575 deferClosing = true;
00576 close();
00577 }
00578 }