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

kalarm

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

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