kalarm

traywindow.cpp
1/*
2 * traywindow.cpp - the KDE system tray applet
3 * Program: kalarm
4 * Copyright © 2002-2005,2007 by David Jarvie <software@astrojar.org.uk>
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"
22
23#include <stdlib.h>
24
25#include <tqtooltip.h>
26
27#include <tdeapplication.h>
28#include <tdelocale.h>
29#include <tdeaboutdata.h>
30#include <tdepopupmenu.h>
31#include <tdemessagebox.h>
32#include <tdestandarddirs.h>
33#include <kstdaction.h>
34#include <kstdguiitem.h>
35#include <tdeaccel.h>
36#include <tdeconfig.h>
37#include <kdebug.h>
38
39#include "alarmcalendar.h"
40#include "alarmlistview.h"
41#include "alarmtext.h"
42#include "daemon.h"
43#include "functions.h"
44#include "kalarmapp.h"
45#include "mainwindow.h"
46#include "messagewin.h"
47#include "prefdlg.h"
48#include "preferences.h"
49#include "templatemenuaction.h"
50#include "traywindow.moc"
51
52
53class TrayTooltip : public TQToolTip
54{
55 public:
56 TrayTooltip(TQWidget* parent) : TQToolTip(parent) { }
57 virtual ~TrayTooltip() {}
58 protected:
59 virtual void maybeTip(const TQPoint&);
60};
61
62struct TipItem
63{
64 TQDateTime dateTime;
65 TQString text;
66};
67
68
69/*=============================================================================
70= Class: TrayWindow
71= The KDE system tray window.
72=============================================================================*/
73
74TrayWindow::TrayWindow(MainWindow* parent, const char* name)
75 : KSystemTray((theApp()->wantRunInSystemTray() ? parent : 0), name),
76 mAssocMainWindow(parent)
77{
78 kdDebug(5950) << "TrayWindow::TrayWindow()\n";
79 // Set up GUI icons
80 mPixmapEnabled = loadIcon("kalarm");
81 mPixmapDisabled = loadIcon("kalarm_disabled");
82 if (mPixmapEnabled.isNull() || mPixmapDisabled.isNull())
83 KMessageBox::sorry(this, i18n("Cannot load system tray icon."));
84 setAcceptDrops(true); // allow drag-and-drop onto this window
85
86 // Set up the context menu
87 TDEActionCollection* actcol = actionCollection();
88 AlarmEnableAction* a = Daemon::createAlarmEnableAction(actcol, "tAlarmEnable");
89 a->plug(contextMenu());
90 connect(a, TQ_SIGNAL(switched(bool)), TQ_SLOT(setEnabledStatus(bool)));
91 KAlarm::createNewAlarmAction(i18n("&New Alarm..."), this, TQ_SLOT(slotNewAlarm()), actcol, "tNew")->plug(contextMenu());
92 KAlarm::createNewFromTemplateAction(i18n("New Alarm From &Template"), this, TQ_SLOT(slotNewFromTemplate(const KAEvent&)), actcol, "tNewFromTempl")->plug(contextMenu());
93 KStdAction::preferences(this, TQ_SLOT(slotPreferences()), actcol)->plug(contextMenu());
94
95 // Replace the default handler for the Quit context menu item
96 const char* quitName = KStdAction::name(KStdAction::Quit);
97 actcol->remove(actcol->action(quitName));
98 actcol->tdeaccel()->remove(quitName);
99 KStdAction::quit(this, TQ_SLOT(slotQuit()), actcol);
100
101 // Set icon to correspond with the alarms enabled menu status
102 Daemon::checkStatus();
103 setEnabledStatus(Daemon::monitoringAlarms());
104
105 mTooltip = new TrayTooltip(this);
106}
107
108TrayWindow::~TrayWindow()
109{
110 kdDebug(5950) << "TrayWindow::~TrayWindow()\n";
111 delete mTooltip;
112 mTooltip = 0;
113 theApp()->removeWindow(this);
114 emit deleted();
115}
116
117/******************************************************************************
118* Called just before the context menu is displayed.
119* Update the Alarms Enabled item status.
120*/
121void TrayWindow::contextMenuAboutToShow(TDEPopupMenu* menu)
122{
123 KSystemTray::contextMenuAboutToShow(menu); // needed for KDE <= 3.1 compatibility
124 Daemon::checkStatus();
125}
126
127/******************************************************************************
128* Called when the "New Alarm" menu item is selected to edit a new alarm.
129*/
130void TrayWindow::slotNewAlarm()
131{
132 MainWindow::executeNew();
133}
134
135/******************************************************************************
136* Called when the "New Alarm" menu item is selected to edit a new alarm.
137*/
138void TrayWindow::slotNewFromTemplate(const KAEvent& event)
139{
140 MainWindow::executeNew(event);
141}
142
143/******************************************************************************
144* Called when the "Configure KAlarm" menu item is selected.
145*/
146void TrayWindow::slotPreferences()
147{
148 KAlarmPrefDlg::display();
149}
150
151/******************************************************************************
152* Called when the Quit context menu item is selected.
153*/
154void TrayWindow::slotQuit()
155{
156 theApp()->doQuit(this);
157}
158
159/******************************************************************************
160* Called when the Alarms Enabled action status has changed.
161* Updates the alarms enabled menu item check state, and the icon pixmap.
162*/
163void TrayWindow::setEnabledStatus(bool status)
164{
165 kdDebug(5950) << "TrayWindow::setEnabledStatus(" << (int)status << ")\n";
166 setPixmap(status ? mPixmapEnabled : mPixmapDisabled);
167}
168
169/******************************************************************************
170* Called when the mouse is clicked over the panel icon.
171* A left click displays the KAlarm main window.
172* A middle button click displays the New Alarm window.
173*/
174void TrayWindow::mousePressEvent(TQMouseEvent* e)
175{
176 if (e->button() == TQt::LeftButton && !theApp()->wantRunInSystemTray())
177 {
178 // Left click: display/hide the first main window
179 mAssocMainWindow = MainWindow::toggleWindow(mAssocMainWindow);
180 }
181 else if (e->button() == TQt::MidButton)
182 MainWindow::executeNew(); // display a New Alarm dialog
183 else
184 KSystemTray::mousePressEvent(e);
185}
186
187/******************************************************************************
188* Called when the mouse is released over the panel icon.
189* The main window (if not hidden) is raised and made the active window.
190* If this is done in mousePressEvent(), it doesn't work.
191*/
192void TrayWindow::mouseReleaseEvent(TQMouseEvent* e)
193{
194 if (e->button() == TQt::LeftButton && mAssocMainWindow && mAssocMainWindow->isVisible())
195 {
196 mAssocMainWindow->raise();
197 mAssocMainWindow->setActiveWindow();
198 }
199 else
200 KSystemTray::mouseReleaseEvent(e);
201}
202
203/******************************************************************************
204* Called when the drag cursor enters the panel icon.
205*/
206void TrayWindow::dragEnterEvent(TQDragEnterEvent* e)
207{
208 MainWindow::executeDragEnterEvent(e);
209}
210
211/******************************************************************************
212* Called when an object is dropped on the panel icon.
213* If the object is recognised, the edit alarm dialog is opened appropriately.
214*/
215void TrayWindow::dropEvent(TQDropEvent* e)
216{
217 MainWindow::executeDropEvent(0, e);
218}
219
220/******************************************************************************
221* Return the tooltip text showing alarms due in the next 24 hours.
222* The limit of 24 hours is because only times, not dates, are displayed.
223*/
224void TrayWindow::tooltipAlarmText(TQString& text) const
225{
226 KAEvent event;
227 const TQString& prefix = Preferences::tooltipTimeToPrefix();
228 int maxCount = Preferences::tooltipAlarmCount();
229 TQDateTime now = TQDateTime::currentDateTime();
230
231 // Get today's and tomorrow's alarms, sorted in time order
232 TQValueList<TipItem> items;
233 TQValueList<TipItem>::Iterator iit;
234 KCal::Event::List events = AlarmCalendar::activeCalendar()->eventsWithAlarms(now.date(), now.addDays(1));
235 for (KCal::Event::List::ConstIterator it = events.begin(); it != events.end(); ++it)
236 {
237 KCal::Event* kcalEvent = *it;
238 event.set(*kcalEvent);
239 if (event.enabled() && !event.expired() && event.action() == KAEvent::MESSAGE)
240 {
241 TipItem item;
242 DateTime dateTime = event.displayDateTime();
243 if (dateTime.date() > now.date())
244 {
245 // Ignore alarms after tomorrow at the current clock time
246 if (dateTime.date() != now.date().addDays(1)
247 || dateTime.time() >= now.time())
248 continue;
249 }
250 item.dateTime = dateTime.dateTime();
251
252 // The alarm is due today, or early tomorrow
253 bool space = false;
254 if (Preferences::showTooltipAlarmTime())
255 {
256 item.text += TDEGlobal::locale()->formatTime(item.dateTime.time());
257 item.text += ' ';
258 space = true;
259 }
260 if (Preferences::showTooltipTimeToAlarm())
261 {
262 int mins = (now.secsTo(item.dateTime) + 59) / 60;
263 if (mins < 0)
264 mins = 0;
265 char minutes[3] = "00";
266 minutes[0] = (mins%60) / 10 + '0';
267 minutes[1] = (mins%60) % 10 + '0';
268 if (Preferences::showTooltipAlarmTime())
269 item.text += i18n("prefix + hours:minutes", "(%1%2:%3)").arg(prefix).arg(mins/60).arg(minutes);
270 else
271 item.text += i18n("prefix + hours:minutes", "%1%2:%3").arg(prefix).arg(mins/60).arg(minutes);
272 item.text += ' ';
273 space = true;
274 }
275 if (space)
276 item.text += ' ';
277 item.text += AlarmText::summary(event);
278
279 // Insert the item into the list in time-sorted order
280 for (iit = items.begin(); iit != items.end(); ++iit)
281 {
282 if (item.dateTime <= (*iit).dateTime)
283 break;
284 }
285 items.insert(iit, item);
286 }
287 }
288 kdDebug(5950) << "TrayWindow::tooltipAlarmText():\n";
289 int count = 0;
290 for (iit = items.begin(); iit != items.end(); ++iit)
291 {
292 kdDebug(5950) << "-- " << (count+1) << ") " << (*iit).text << endl;
293 text += '\n';
294 text += (*iit).text;
295 if (++count == maxCount)
296 break;
297 }
298}
299
300/******************************************************************************
301* Called when the associated main window is closed.
302*/
303void TrayWindow::removeWindow(MainWindow* win)
304{
305 if (win == mAssocMainWindow)
306 mAssocMainWindow = 0;
307}
308
309
310#ifdef HAVE_X11_HEADERS
311 #include <X11/X.h>
312 #include <X11/Xlib.h>
313 #include <X11/Xutil.h>
314#endif
315
316/******************************************************************************
317* Check whether the widget is in the system tray.
318* Note that it is only sometime AFTER the show event that the system tray
319* becomes the widget's parent. So for a definitive status, call this method
320* only after waiting a bit...
321* Reply = true if the widget is in the system tray, or its status can't be determined.
322* = false if it is not currently in the system tray.
323*/
324bool TrayWindow::inSystemTray() const
325{
326#ifdef HAVE_X11_HEADERS
327 Window xParent; // receives parent window
328 Window root;
329 Window* children = 0;
330 unsigned int nchildren;
331 // Find the X parent window of the widget. This is not the same as the TQt parent widget.
332 if (!XQueryTree(tqt_xdisplay(), winId(), &root, &xParent, &children, &nchildren))
333 return true; // error determining its parent X window
334 if (children)
335 XFree(children);
336
337 // If it is in the system tray, the system tray window will be its X parent.
338 // Otherwise, the root window will be its X parent.
339 return xParent != root;
340#else
341 return true;
342#endif // HAVE_X11_HEADERS
343}
344
345
346/******************************************************************************
347* Displays the appropriate tooltip depending on preference settings.
348*/
349void TrayTooltip::maybeTip(const TQPoint&)
350{
351 TrayWindow* parent = (TrayWindow*)parentWidget();
352 TQString text;
353 if (Daemon::monitoringAlarms())
354 text = tdeApp->aboutData()->programName();
355 else
356 text = i18n("%1 - disabled").arg(tdeApp->aboutData()->programName());
357 kdDebug(5950) << "TrayTooltip::maybeTip(): " << text << endl;
358 if (Preferences::tooltipAlarmCount())
359 parent->tooltipAlarmText(text);
360 tip(parent->rect(), text);
361}
KAEvent corresponds to a KCal::Event instance.
Definition: alarmevent.h:232
miscellaneous functions
the KAlarm application object
main application window
displays an alarm message