• Skip to content
  • Skip to link menu
KDE API Reference
  • KDE API Reference
  • kdepim API Reference
  • KDE Home
  • Contact Us
 

kalarm

  • sources
  • kde-4.14
  • kdepim
  • kalarm
traywindow.cpp
Go to the documentation of this file.
1 /*
2  * traywindow.cpp - the KDE system tray applet
3  * Program: kalarm
4  * Copyright © 2002-2012 by David Jarvie <djarvie@kde.org>
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License along
17  * with this program; if not, write to the Free Software Foundation, Inc.,
18  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19  */
20 
21 #include "kalarm.h" //krazy:exclude=includes (kalarm.h must be first)
22 #include "traywindow.h"
23 
24 #include "alarmcalendar.h"
25 #include "alarmlistview.h"
26 #include "functions.h"
27 #include "kalarmapp.h"
28 #include "mainwindow.h"
29 #include "messagewin.h"
30 #include "newalarmaction.h"
31 #include "prefdlg.h"
32 #include "preferences.h"
33 #include "synchtimer.h"
34 #include "templatemenuaction.h"
35 
36 #include <kalarmcal/alarmtext.h>
37 
38 #include <kactioncollection.h>
39 #include <ktoggleaction.h>
40 #include <kapplication.h>
41 #include <klocale.h>
42 #include <kaboutdata.h>
43 #include <kmenu.h>
44 #include <kmessagebox.h>
45 #include <kstandarddirs.h>
46 #include <kstandardaction.h>
47 #include <kstandardguiitem.h>
48 #include <kiconeffect.h>
49 #include <kconfig.h>
50 #include <kdebug.h>
51 
52 #include <QList>
53 #include <QTimer>
54 
55 #include <stdlib.h>
56 #include <limits.h>
57 
58 using namespace KAlarmCal;
59 
60 struct TipItem
61 {
62  QDateTime dateTime;
63  QString text;
64 };
65 
66 
67 /*=============================================================================
68 = Class: TrayWindow
69 = The KDE system tray window.
70 =============================================================================*/
71 
72 TrayWindow::TrayWindow(MainWindow* parent)
73  : KStatusNotifierItem(parent),
74  mAssocMainWindow(parent),
75 #ifdef USE_AKONADI
76  mAlarmsModel(0),
77 #endif
78  mStatusUpdateTimer(new QTimer(this)),
79  mHaveDisabledAlarms(false)
80 {
81  kDebug();
82  setToolTipIconByName(QLatin1String("kalarm"));
83  setToolTipTitle(KGlobal::mainComponent().aboutData()->programName());
84  setIconByName(QLatin1String("kalarm"));
85  // Load the disabled icon for use by setIconByPixmap()
86  // - setIconByName() doesn't work for this one!
87  mIconDisabled.addPixmap(KIconLoader::global()->loadIcon(QLatin1String("kalarm-disabled"), KIconLoader::Panel));
88  setStatus(KStatusNotifierItem::Active);
89 
90  // Set up the context menu
91  KActionCollection* actions = actionCollection();
92  mActionEnabled = KAlarm::createAlarmEnableAction(this);
93  actions->addAction(QLatin1String("tAlarmsEnable"), mActionEnabled);
94  contextMenu()->addAction(mActionEnabled);
95  connect(theApp(), SIGNAL(alarmEnabledToggled(bool)), SLOT(setEnabledStatus(bool)));
96  contextMenu()->addSeparator();
97 
98  mActionNew = new NewAlarmAction(false, i18nc("@action", "&New Alarm"), this);
99  actions->addAction(QLatin1String("tNew"), mActionNew);
100  contextMenu()->addAction(mActionNew);
101  connect(mActionNew, SIGNAL(selected(EditAlarmDlg::Type)), SLOT(slotNewAlarm(EditAlarmDlg::Type)));
102  connect(mActionNew->fromTemplateAlarmAction(), SIGNAL(selected(const KAEvent*)), SLOT(slotNewFromTemplate(const KAEvent*)));
103  contextMenu()->addSeparator();
104 
105  KAction* a = KAlarm::createStopPlayAction(this);
106  actions->addAction(QLatin1String("tStopPlay"), a);
107  contextMenu()->addAction(a);
108  QObject::connect(theApp(), SIGNAL(audioPlaying(bool)), a, SLOT(setVisible(bool)));
109  QObject::connect(theApp(), SIGNAL(audioPlaying(bool)), SLOT(updateStatus()));
110 
111  a = KAlarm::createSpreadWindowsAction(this);
112  actions->addAction(QLatin1String("tSpread"), a);
113  contextMenu()->addAction(a);
114  contextMenu()->addSeparator();
115  contextMenu()->addAction(KStandardAction::preferences(this, SLOT(slotPreferences()), actions));
116 
117  // Replace the default handler for the Quit context menu item
118  const char* quitName = KStandardAction::name(KStandardAction::Quit);
119  QAction* qa = actions->action(QLatin1String(quitName));
120  disconnect(qa, SIGNAL(triggered(bool)), 0, 0);
121  connect(qa, SIGNAL(triggered(bool)), SLOT(slotQuit()));
122 
123  // Set icon to correspond with the alarms enabled menu status
124  setEnabledStatus(theApp()->alarmsEnabled());
125 
126  connect(AlarmCalendar::resources(), SIGNAL(haveDisabledAlarmsChanged(bool)), SLOT(slotHaveDisabledAlarms(bool)));
127  connect(this, SIGNAL(activateRequested(bool,QPoint)), SLOT(slotActivateRequested()));
128  connect(this, SIGNAL(secondaryActivateRequested(QPoint)), SLOT(slotSecondaryActivateRequested()));
129  slotHaveDisabledAlarms(AlarmCalendar::resources()->haveDisabledAlarms());
130 
131  // Hack: KSNI does not let us know when it is about to show the tooltip,
132  // so we need to update it whenever something change in it.
133 
134  // This timer ensures that updateToolTip() is not called several times in a row
135  mToolTipUpdateTimer = new QTimer(this);
136  mToolTipUpdateTimer->setInterval(0);
137  mToolTipUpdateTimer->setSingleShot(true);
138  connect(mToolTipUpdateTimer, SIGNAL(timeout()), SLOT(updateToolTip()));
139 
140  // Update every minute to show accurate deadlines
141  MinuteTimer::connect(mToolTipUpdateTimer, SLOT(start()));
142 
143  // Update when alarms are modified
144 #ifdef USE_AKONADI
145  connect(AlarmListModel::all(), SIGNAL(dataChanged(QModelIndex,QModelIndex)),
146  mToolTipUpdateTimer, SLOT(start()));
147  connect(AlarmListModel::all(), SIGNAL(rowsInserted(QModelIndex,int,int)),
148  mToolTipUpdateTimer, SLOT(start()));
149  connect(AlarmListModel::all(), SIGNAL(rowsMoved(QModelIndex,int,int,QModelIndex,int)),
150  mToolTipUpdateTimer, SLOT(start()));
151  connect(AlarmListModel::all(), SIGNAL(rowsRemoved(QModelIndex,int,int)),
152  mToolTipUpdateTimer, SLOT(start()));
153  connect(AlarmListModel::all(), SIGNAL(modelReset()),
154  mToolTipUpdateTimer, SLOT(start()));
155 #else
156  connect(EventListModel::alarms(), SIGNAL(dataChanged(QModelIndex,QModelIndex)),
157  mToolTipUpdateTimer, SLOT(start()));
158  connect(EventListModel::alarms(), SIGNAL(rowsInserted(QModelIndex,int,int)),
159  mToolTipUpdateTimer, SLOT(start()));
160  connect(EventListModel::alarms(), SIGNAL(rowsMoved(QModelIndex,int,int,QModelIndex,int)),
161  mToolTipUpdateTimer, SLOT(start()));
162  connect(EventListModel::alarms(), SIGNAL(rowsRemoved(QModelIndex,int,int)),
163  mToolTipUpdateTimer, SLOT(start()));
164  connect(EventListModel::alarms(), SIGNAL(modelReset()),
165  mToolTipUpdateTimer, SLOT(start()));
166 #endif
167 
168  // Set auto-hide status when next alarm or preferences change
169  mStatusUpdateTimer->setSingleShot(true);
170  connect(mStatusUpdateTimer, SIGNAL(timeout()), SLOT(updateStatus()));
171  connect(AlarmCalendar::resources(), SIGNAL(earliestAlarmChanged()), SLOT(updateStatus()));
172  Preferences::connect(SIGNAL(autoHideSystemTrayChanged(int)), this, SLOT(updateStatus()));
173  updateStatus();
174 
175  // Update when tooltip preferences are modified
176  Preferences::connect(SIGNAL(tooltipPreferencesChanged()), mToolTipUpdateTimer, SLOT(start()));
177 }
178 
179 TrayWindow::~TrayWindow()
180 {
181  kDebug();
182  theApp()->removeWindow(this);
183  emit deleted();
184 }
185 
186 /******************************************************************************
187 * Called when the "New Alarm" menu item is selected to edit a new alarm.
188 */
189 void TrayWindow::slotNewAlarm(EditAlarmDlg::Type type)
190 {
191  KAlarm::editNewAlarm(type);
192 }
193 
194 /******************************************************************************
195 * Called when the "New Alarm" menu item is selected to edit a new alarm from a
196 * template.
197 */
198 void TrayWindow::slotNewFromTemplate(const KAEvent* event)
199 {
200  KAlarm::editNewAlarm(event);
201 }
202 
203 /******************************************************************************
204 * Called when the "Configure KAlarm" menu item is selected.
205 */
206 void TrayWindow::slotPreferences()
207 {
208  KAlarmPrefDlg::display();
209 }
210 
211 /******************************************************************************
212 * Called when the Quit context menu item is selected.
213 * Note that KAlarmApp::doQuit() must be called by the event loop, not directly
214 * from the menu item, since otherwise the tray icon will be deleted while still
215 * processing the menu, resulting in a crash.
216 * Ideally, the connect() call setting up this slot in the constructor would use
217 * Qt::QueuedConnection, but the slot is never called in that case.
218 */
219 void TrayWindow::slotQuit()
220 {
221  // Note: QTimer::singleShot(0, ...) never calls the slot.
222  QTimer::singleShot(1, this, SLOT(slotQuitAfter()));
223 }
224 void TrayWindow::slotQuitAfter()
225 {
226  theApp()->doQuit(static_cast<QWidget*>(parent()));
227 }
228 
229 /******************************************************************************
230 * Called when the Alarms Enabled action status has changed.
231 * Updates the alarms enabled menu item check state, and the icon pixmap.
232 */
233 void TrayWindow::setEnabledStatus(bool status)
234 {
235  kDebug() << (int)status;
236  updateIcon();
237  updateStatus();
238  updateToolTip();
239 }
240 
241 /******************************************************************************
242 * Called when individual alarms are enabled or disabled.
243 * Set the enabled icon to show or hide a disabled indication.
244 */
245 void TrayWindow::slotHaveDisabledAlarms(bool haveDisabled)
246 {
247  kDebug() << haveDisabled;
248  mHaveDisabledAlarms = haveDisabled;
249  updateIcon();
250  updateToolTip();
251 }
252 
253 /******************************************************************************
254 * A left click displays the KAlarm main window.
255 */
256 void TrayWindow::slotActivateRequested()
257 {
258  // Left click: display/hide the first main window
259  if (mAssocMainWindow && mAssocMainWindow->isVisible())
260  {
261  mAssocMainWindow->raise();
262  mAssocMainWindow->activateWindow();
263  }
264 }
265 
266 /******************************************************************************
267 * A middle button click displays the New Alarm window.
268 */
269 void TrayWindow::slotSecondaryActivateRequested()
270 {
271  if (mActionNew->isEnabled())
272  mActionNew->trigger(); // display a New Alarm dialog
273 }
274 
275 /******************************************************************************
276 * Adjust icon auto-hide status according to when the next alarm is due.
277 * The icon is always shown if audio is playing, to give access to the 'stop'
278 * menu option.
279 */
280 void TrayWindow::updateStatus()
281 {
282  mStatusUpdateTimer->stop();
283  int period = Preferences::autoHideSystemTray();
284  // If the icon is always to be shown (AutoHideSystemTray = 0),
285  // or audio is playing, show the icon.
286  bool active = !period || MessageWin::isAudioPlaying();
287  if (!active)
288  {
289  // Show the icon only if the next active alarm complies
290  active = theApp()->alarmsEnabled();
291  if (active)
292  {
293  KAEvent* event = AlarmCalendar::resources()->earliestAlarm();
294  active = static_cast<bool>(event);
295  if (event && period > 0)
296  {
297  KDateTime dt = event->nextTrigger(KAEvent::ALL_TRIGGER).effectiveKDateTime();
298  qint64 delay = KDateTime::currentLocalDateTime().secsTo_long(dt);
299  delay -= static_cast<qint64>(period) * 60; // delay until icon to be shown
300  active = (delay <= 0);
301  if (!active)
302  {
303  // First alarm trigger is too far in future, so tray icon is to
304  // be auto-hidden. Set timer for when it should be shown again.
305  delay *= 1000; // convert to msec
306  int delay_int = static_cast<int>(delay);
307  if (delay_int != delay)
308  delay_int = INT_MAX;
309  mStatusUpdateTimer->setInterval(delay_int);
310  mStatusUpdateTimer->start();
311  }
312  }
313  }
314  }
315  setStatus(active ? Active : Passive);
316 }
317 
318 /******************************************************************************
319 * Adjust tooltip according to the app state.
320 * The tooltip text shows alarms due in the next 24 hours. The limit of 24
321 * hours is because only times, not dates, are displayed.
322 */
323 void TrayWindow::updateToolTip()
324 {
325  bool enabled = theApp()->alarmsEnabled();
326  QString subTitle;
327  if (enabled && Preferences::tooltipAlarmCount())
328  subTitle = tooltipAlarmText();
329 
330  if (!enabled)
331  subTitle = i18n("Disabled");
332  else if (mHaveDisabledAlarms)
333  {
334  if (!subTitle.isEmpty())
335  subTitle += QLatin1String("<br/>");
336  subTitle += i18nc("@info:tooltip Brief: some alarms are disabled", "(Some alarms disabled)");
337  }
338  setToolTipSubTitle(subTitle);
339 }
340 
341 /******************************************************************************
342 * Adjust icon according to the app state.
343 */
344 void TrayWindow::updateIcon()
345 {
346  if (theApp()->alarmsEnabled())
347  setIconByName(mHaveDisabledAlarms ? QLatin1String("kalarm-partdisabled") : QLatin1String("kalarm"));
348  else
349  setIconByPixmap(mIconDisabled);
350 }
351 
352 /******************************************************************************
353 * Return the tooltip text showing alarms due in the next 24 hours.
354 * The limit of 24 hours is because only times, not dates, are displayed.
355 */
356 QString TrayWindow::tooltipAlarmText() const
357 {
358  KAEvent event;
359  const QString& prefix = Preferences::tooltipTimeToPrefix();
360  int maxCount = Preferences::tooltipAlarmCount();
361  KDateTime now = KDateTime::currentLocalDateTime();
362  KDateTime tomorrow = now.addDays(1);
363 
364  // Get today's and tomorrow's alarms, sorted in time order
365  int i, iend;
366  QList<TipItem> items;
367 #ifdef USE_AKONADI
368  QVector<KAEvent> events = KAlarm::getSortedActiveEvents(const_cast<TrayWindow*>(this), &mAlarmsModel);
369 #else
370  KAEvent::List events = KAlarm::getSortedActiveEvents(KDateTime(now.date(), QTime(0,0,0), KDateTime::LocalZone), tomorrow);
371 #endif
372  for (i = 0, iend = events.count(); i < iend; ++i)
373  {
374 #ifdef USE_AKONADI
375  KAEvent* event = &events[i];
376 #else
377  KAEvent* event = events[i];
378 #endif
379  if (event->actionSubType() == KAEvent::MESSAGE)
380  {
381  TipItem item;
382  QDateTime dateTime = event->nextTrigger(KAEvent::DISPLAY_TRIGGER).effectiveKDateTime().toLocalZone().dateTime();
383  if (dateTime > tomorrow.dateTime())
384 #ifdef USE_AKONADI
385  break; // ignore alarms after tomorrow at the current clock time
386 #else
387  continue; // ignore alarms after tomorrow at the current clock time
388 #endif
389  item.dateTime = dateTime;
390 
391  // The alarm is due today, or early tomorrow
392  if (Preferences::showTooltipAlarmTime())
393  {
394  item.text += KGlobal::locale()->formatTime(item.dateTime.time());
395  item.text += QLatin1Char(' ');
396  }
397  if (Preferences::showTooltipTimeToAlarm())
398  {
399  int mins = (now.dateTime().secsTo(item.dateTime) + 59) / 60;
400  if (mins < 0)
401  mins = 0;
402  char minutes[3] = "00";
403  minutes[0] = static_cast<char>((mins%60) / 10 + '0');
404  minutes[1] = static_cast<char>((mins%60) % 10 + '0');
405  if (Preferences::showTooltipAlarmTime())
406  item.text += i18nc("@info/plain prefix + hours:minutes", "(%1%2:%3)", prefix, mins/60, QLatin1String(minutes));
407  else
408  item.text += i18nc("@info/plain prefix + hours:minutes", "%1%2:%3", prefix, mins/60, QLatin1String(minutes));
409  item.text += QLatin1Char(' ');
410  }
411  item.text += AlarmText::summary(*event);
412 
413  // Insert the item into the list in time-sorted order
414  int it = 0;
415  for (int itend = items.count(); it < itend; ++it)
416  {
417  if (item.dateTime <= items[it].dateTime)
418  break;
419  }
420  items.insert(it, item);
421  }
422  }
423  kDebug();
424  QString text;
425  int count = 0;
426  for (i = 0, iend = items.count(); i < iend; ++i)
427  {
428  kDebug() << "--" << (count+1) << ")" << items[i].text;
429  if (i > 0)
430  text += QLatin1String("<br />");
431  text += items[i].text;
432  if (++count == maxCount)
433  break;
434  }
435  return text;
436 }
437 
438 /******************************************************************************
439 * Called when the associated main window is closed.
440 */
441 void TrayWindow::removeWindow(MainWindow* win)
442 {
443  if (win == mAssocMainWindow)
444  mAssocMainWindow = 0;
445 }
446 #include "moc_traywindow.cpp"
447 // vim: et sw=4:
QTimer::setInterval
void setInterval(int msec)
QModelIndex
maxCount
static int maxCount
Definition: undo.cpp:35
synchtimer.h
EventListModel::alarms
static EventListModel * alarms()
Definition: eventlistmodel.cpp:55
KAlarmApp::alarmsEnabled
bool alarmsEnabled() const
Definition: kalarmapp.h:63
MessageWin::isAudioPlaying
static bool isAudioPlaying()
Definition: messagewin.cpp:1576
text
virtual QByteArray text(quint32 serialNumber) const =0
newalarmaction.h
AlarmCalendar::resources
static AlarmCalendar * resources()
Definition: alarmcalendar.h:130
alarmcalendar.h
QPoint
NewAlarmAction::fromTemplateAlarmAction
TemplateMenuAction * fromTemplateAlarmAction() const
Definition: newalarmaction.h:41
prefdlg.h
QTime
kalarmapp.h
the KAlarm application object
TrayWindow::removeWindow
void removeWindow(MainWindow *)
Definition: traywindow.cpp:441
AlarmCalendar::earliestAlarm
KAEvent * earliestAlarm() const
Definition: alarmcalendar.cpp:2276
QList::count
int count(const T &value) const
QTimer
KAlarmApp::removeWindow
void removeWindow(TrayWindow *)
Definition: kalarmapp.cpp:989
KAlarmPrefDlg::display
static void display()
Definition: prefdlg.cpp:128
QString::isEmpty
bool isEmpty() const
messagewin.h
displays an alarm message
mainwindow.h
main application window
QIcon::addPixmap
void addPixmap(const QPixmap &pixmap, Mode mode, State state)
MinuteTimer::connect
static void connect(QObject *receiver, const char *member)
QString
QList
theApp
KAlarmApp * theApp()
Definition: kalarmapp.h:263
QLatin1Char
preferences.h
Preferences::connect
static void connect(const char *signal, const QObject *receiver, const char *member)
Definition: preferences.cpp:369
QTimer::stop
void stop()
templatemenuaction.h
traywindow.h
QVector
EditAlarmDlg::Type
Type
Definition: editdlg.h:64
QLatin1String
functions.h
miscellaneous functions
QList::insert
void insert(int i, const T &value)
alarmlistview.h
TrayWindow::TrayWindow
TrayWindow(MainWindow *parent)
Definition: traywindow.cpp:72
kalarm.h
QAction
KStatusNotifierItem
TrayWindow::~TrayWindow
~TrayWindow()
Definition: traywindow.cpp:179
QTimer::start
void start(int msec)
NewAlarmAction
Definition: newalarmaction.h:31
QObject::connect
bool connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
TrayWindow::deleted
void deleted()
MainWindow
Definition: mainwindow.h:70
KAlarmApp::doQuit
void doQuit(QWidget *parent)
Definition: kalarmapp.cpp:703
AlarmListModel::all
static AlarmListModel * all()
Return the model containing all active and archived alarms.
Definition: itemlistmodel.cpp:205
QDateTime
QTimer::setSingleShot
void setSingleShot(bool singleShot)
This file is part of the KDE documentation.
Documentation copyright © 1996-2020 The KDE developers.
Generated on Mon Jun 22 2020 13:34:51 by doxygen 1.8.7 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.

kalarm

Skip menu "kalarm"
  • Main Page
  • Namespace List
  • Namespace Members
  • Alphabetical List
  • Class List
  • Class Hierarchy
  • Class Members
  • File List
  • File Members

kdepim API Reference

Skip menu "kdepim API Reference"
  • akonadi_next
  • akregator
  • blogilo
  • calendarsupport
  • console
  •   kabcclient
  •   konsolekalendar
  • kaddressbook
  • kalarm
  •   lib
  • kdgantt2
  • kjots
  • kleopatra
  • kmail
  • knode
  • knotes
  • kontact
  • korgac
  • korganizer
  • ktimetracker
  • libkdepim
  • libkleo
  • libkpgp
  • mailcommon
  • messagelist
  • messageviewer
  • pimprint

Search



Report problems with this website to our bug tracking system.
Contact the specific authors with questions and comments about the page contents.

KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal