/*
* traywindow . cpp - the KDE system tray applet
* Program : kalarm
* Copyright © 2002 - 2005 , 2007 by David Jarvie < software @ astrojar . org . uk >
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation ; either version 2 of the License , or
* ( at your option ) any later version .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* You should have received a copy of the GNU General Public License along
* with this program ; if not , write to the Free Software Foundation , Inc . ,
* 51 Franklin Street , Fifth Floor , Boston , MA 02110 - 1301 , USA .
*/
# include "kalarm.h"
# include <stdlib.h>
# include <tqtooltip.h>
# include <kapplication.h>
# include <klocale.h>
# include <kaboutdata.h>
# include <kpopupmenu.h>
# include <kmessagebox.h>
# include <kstandarddirs.h>
# include <kstdaction.h>
# include <kstdguiitem.h>
# include <kaccel.h>
# include <kconfig.h>
# include <kdebug.h>
# include "alarmcalendar.h"
# include "alarmlistview.h"
# include "alarmtext.h"
# include "daemon.h"
# include "functions.h"
# include "kalarmapp.h"
# include "mainwindow.h"
# include "messagewin.h"
# include "prefdlg.h"
# include "preferences.h"
# include "templatemenuaction.h"
# include "traywindow.moc"
class TrayTooltip : public TQToolTip
{
public :
TrayTooltip ( TQWidget * parent ) : TQToolTip ( parent ) { }
virtual ~ TrayTooltip ( ) { }
protected :
virtual void maybeTip ( const TQPoint & ) ;
} ;
struct TipItem
{
TQDateTime dateTime ;
TQString text ;
} ;
/*=============================================================================
= Class : TrayWindow
= The KDE system tray window .
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
TrayWindow : : TrayWindow ( MainWindow * parent , const char * name )
: KSystemTray ( ( theApp ( ) - > wantRunInSystemTray ( ) ? parent : 0 ) , name ) ,
mAssocMainWindow ( parent )
{
kdDebug ( 5950 ) < < " TrayWindow::TrayWindow() \n " ;
// Set up GUI icons
mPixmapEnabled = loadIcon ( " kalarm " ) ;
mPixmapDisabled = loadIcon ( " kalarm_disabled " ) ;
if ( mPixmapEnabled . isNull ( ) | | mPixmapDisabled . isNull ( ) )
KMessageBox : : sorry ( this , i18n ( " Cannot load system tray icon. " ) ) ;
setAcceptDrops ( true ) ; // allow drag-and-drop onto this window
// Set up the context menu
KActionCollection * actcol = actionCollection ( ) ;
AlarmEnableAction * a = Daemon : : createAlarmEnableAction ( actcol , " tAlarmEnable " ) ;
a - > plug ( contextMenu ( ) ) ;
connect ( a , TQT_SIGNAL ( switched ( bool ) ) , TQT_SLOT ( setEnabledStatus ( bool ) ) ) ;
KAlarm : : createNewAlarmAction ( i18n ( " &New Alarm... " ) , TQT_TQOBJECT ( this ) , TQT_SLOT ( slotNewAlarm ( ) ) , actcol , " tNew " ) - > plug ( contextMenu ( ) ) ;
KAlarm : : createNewFromTemplateAction ( i18n ( " New Alarm From &Template " ) , TQT_TQOBJECT ( this ) , TQT_SLOT ( slotNewFromTemplate ( const KAEvent & ) ) , actcol , " tNewFromTempl " ) - > plug ( contextMenu ( ) ) ;
KStdAction : : preferences ( TQT_TQOBJECT ( this ) , TQT_SLOT ( slotPreferences ( ) ) , actcol ) - > plug ( contextMenu ( ) ) ;
// Replace the default handler for the Quit context menu item
const char * quitName = KStdAction : : name ( KStdAction : : Quit ) ;
actcol - > remove ( actcol - > action ( quitName ) ) ;
actcol - > accel ( ) - > remove ( quitName ) ;
KStdAction : : quit ( TQT_TQOBJECT ( this ) , TQT_SLOT ( slotQuit ( ) ) , actcol ) ;
// Set icon to correspond with the alarms enabled menu status
Daemon : : checkStatus ( ) ;
setEnabledStatus ( Daemon : : monitoringAlarms ( ) ) ;
mTooltip = new TrayTooltip ( this ) ;
}
TrayWindow : : ~ TrayWindow ( )
{
kdDebug ( 5950 ) < < " TrayWindow::~TrayWindow() \n " ;
delete mTooltip ;
mTooltip = 0 ;
theApp ( ) - > removeWindow ( this ) ;
emit deleted ( ) ;
}
/******************************************************************************
* Called just before the context menu is displayed .
* Update the Alarms Enabled item status .
*/
void TrayWindow : : contextMenuAboutToShow ( KPopupMenu * menu )
{
KSystemTray : : contextMenuAboutToShow ( menu ) ; // needed for KDE <= 3.1 compatibility
Daemon : : checkStatus ( ) ;
}
/******************************************************************************
* Called when the " New Alarm " menu item is selected to edit a new alarm .
*/
void TrayWindow : : slotNewAlarm ( )
{
MainWindow : : executeNew ( ) ;
}
/******************************************************************************
* Called when the " New Alarm " menu item is selected to edit a new alarm .
*/
void TrayWindow : : slotNewFromTemplate ( const KAEvent & event )
{
MainWindow : : executeNew ( event ) ;
}
/******************************************************************************
* Called when the " Configure KAlarm " menu item is selected .
*/
void TrayWindow : : slotPreferences ( )
{
KAlarmPrefDlg : : display ( ) ;
}
/******************************************************************************
* Called when the Quit context menu item is selected .
*/
void TrayWindow : : slotQuit ( )
{
theApp ( ) - > doQuit ( this ) ;
}
/******************************************************************************
* Called when the Alarms Enabled action status has changed .
* Updates the alarms enabled menu item check state , and the icon pixmap .
*/
void TrayWindow : : setEnabledStatus ( bool status )
{
kdDebug ( 5950 ) < < " TrayWindow::setEnabledStatus( " < < ( int ) status < < " ) \n " ;
setPixmap ( status ? mPixmapEnabled : mPixmapDisabled ) ;
}
/******************************************************************************
* Called when the mouse is clicked over the panel icon .
* A left click displays the KAlarm main window .
* A middle button click displays the New Alarm window .
*/
void TrayWindow : : mousePressEvent ( TQMouseEvent * e )
{
if ( e - > button ( ) = = Qt : : LeftButton & & ! theApp ( ) - > wantRunInSystemTray ( ) )
{
// Left click: display/hide the first main window
mAssocMainWindow = MainWindow : : toggleWindow ( mAssocMainWindow ) ;
}
else if ( e - > button ( ) = = Qt : : MidButton )
MainWindow : : executeNew ( ) ; // display a New Alarm dialog
else
KSystemTray : : mousePressEvent ( e ) ;
}
/******************************************************************************
* Called when the mouse is released over the panel icon .
* The main window ( if not hidden ) is raised and made the active window .
* If this is done in mousePressEvent ( ) , it doesn ' t work .
*/
void TrayWindow : : mouseReleaseEvent ( TQMouseEvent * e )
{
if ( e - > button ( ) = = Qt : : LeftButton & & mAssocMainWindow & & mAssocMainWindow - > isVisible ( ) )
{
mAssocMainWindow - > raise ( ) ;
mAssocMainWindow - > setActiveWindow ( ) ;
}
else
KSystemTray : : mouseReleaseEvent ( e ) ;
}
/******************************************************************************
* Called when the drag cursor enters the panel icon .
*/
void TrayWindow : : dragEnterEvent ( TQDragEnterEvent * e )
{
MainWindow : : executeDragEnterEvent ( e ) ;
}
/******************************************************************************
* Called when an object is dropped on the panel icon .
* If the object is recognised , the edit alarm dialog is opened appropriately .
*/
void TrayWindow : : dropEvent ( TQDropEvent * e )
{
MainWindow : : executeDropEvent ( 0 , e ) ;
}
/******************************************************************************
* Return the tooltip text showing alarms due in the next 24 hours .
* The limit of 24 hours is because only times , not dates , are displayed .
*/
void TrayWindow : : tooltipAlarmText ( TQString & text ) const
{
KAEvent event ;
const TQString & prefix = Preferences : : tooltipTimeToPrefix ( ) ;
int maxCount = Preferences : : tooltipAlarmCount ( ) ;
TQDateTime now = TQDateTime : : currentDateTime ( ) ;
// Get today's and tomorrow's alarms, sorted in time order
TQValueList < TipItem > items ;
TQValueList < TipItem > : : Iterator iit ;
KCal : : Event : : List events = AlarmCalendar : : activeCalendar ( ) - > eventsWithAlarms ( now . date ( ) , now . addDays ( 1 ) ) ;
for ( KCal : : Event : : List : : ConstIterator it = events . begin ( ) ; it ! = events . end ( ) ; + + it )
{
KCal : : Event * kcalEvent = * it ;
event . set ( * kcalEvent ) ;
if ( event . enabled ( ) & & ! event . expired ( ) & & event . action ( ) = = KAEvent : : MESSAGE )
{
TipItem item ;
DateTime dateTime = event . displayDateTime ( ) ;
if ( dateTime . date ( ) > now . date ( ) )
{
// Ignore alarms after tomorrow at the current clock time
if ( dateTime . date ( ) ! = now . date ( ) . addDays ( 1 )
| | dateTime . time ( ) > = now . time ( ) )
continue ;
}
item . dateTime = dateTime . dateTime ( ) ;
// The alarm is due today, or early tomorrow
bool space = false ;
if ( Preferences : : showTooltipAlarmTime ( ) )
{
item . text + = KGlobal : : locale ( ) - > formatTime ( item . dateTime . time ( ) ) ;
item . text + = ' ' ;
space = true ;
}
if ( Preferences : : showTooltipTimeToAlarm ( ) )
{
int mins = ( now . secsTo ( item . dateTime ) + 59 ) / 60 ;
if ( mins < 0 )
mins = 0 ;
char minutes [ 3 ] = " 00 " ;
minutes [ 0 ] = ( mins % 60 ) / 10 + ' 0 ' ;
minutes [ 1 ] = ( mins % 60 ) % 10 + ' 0 ' ;
if ( Preferences : : showTooltipAlarmTime ( ) )
item . text + = i18n ( " prefix + hours:minutes " , " (%1%2:%3) " ) . arg ( prefix ) . arg ( mins / 60 ) . arg ( minutes ) ;
else
item . text + = i18n ( " prefix + hours:minutes " , " %1%2:%3 " ) . arg ( prefix ) . arg ( mins / 60 ) . arg ( minutes ) ;
item . text + = ' ' ;
space = true ;
}
if ( space )
item . text + = ' ' ;
item . text + = AlarmText : : summary ( event ) ;
// Insert the item into the list in time-sorted order
for ( iit = items . begin ( ) ; iit ! = items . end ( ) ; + + iit )
{
if ( item . dateTime < = ( * iit ) . dateTime )
break ;
}
items . insert ( iit , item ) ;
}
}
kdDebug ( 5950 ) < < " TrayWindow::tooltipAlarmText(): \n " ;
int count = 0 ;
for ( iit = items . begin ( ) ; iit ! = items . end ( ) ; + + iit )
{
kdDebug ( 5950 ) < < " -- " < < ( count + 1 ) < < " ) " < < ( * iit ) . text < < endl ;
text + = ' \n ' ;
text + = ( * iit ) . text ;
if ( + + count = = maxCount )
break ;
}
}
/******************************************************************************
* Called when the associated main window is closed .
*/
void TrayWindow : : removeWindow ( MainWindow * win )
{
if ( win = = mAssocMainWindow )
mAssocMainWindow = 0 ;
}
# ifdef HAVE_X11_HEADERS
# include <X11/X.h>
# include <X11/Xlib.h>
# include <X11/Xutil.h>
# endif
/******************************************************************************
* Check whether the widget is in the system tray .
* Note that it is only sometime AFTER the show event that the system tray
* becomes the widget ' s parent . So for a definitive status , call this method
* only after waiting a bit . . .
* Reply = true if the widget is in the system tray , or its status can ' t be determined .
* = false if it is not currently in the system tray .
*/
bool TrayWindow : : inSystemTray ( ) const
{
# ifdef HAVE_X11_HEADERS
Window xParent ; // receives parent window
Window root ;
Window * children = 0 ;
unsigned int nchildren ;
// Find the X parent window of the widget. This is not the same as the TQt parent widget.
if ( ! XQueryTree ( tqt_xdisplay ( ) , winId ( ) , & root , & xParent , & children , & nchildren ) )
return true ; // error determining its parent X window
if ( children )
XFree ( children ) ;
// If it is in the system tray, the system tray window will be its X parent.
// Otherwise, the root window will be its X parent.
return xParent ! = root ;
# else
return true ;
# endif // HAVE_X11_HEADERS
}
/******************************************************************************
* Displays the appropriate tooltip depending on preference settings .
*/
void TrayTooltip : : maybeTip ( const TQPoint & )
{
TrayWindow * parent = ( TrayWindow * ) parentWidget ( ) ;
TQString text ;
if ( Daemon : : monitoringAlarms ( ) )
text = kapp - > aboutData ( ) - > programName ( ) ;
else
text = i18n ( " %1 - disabled " ) . arg ( kapp - > aboutData ( ) - > programName ( ) ) ;
kdDebug ( 5950 ) < < " TrayTooltip::maybeTip(): " < < text < < endl ;
if ( Preferences : : tooltipAlarmCount ( ) )
parent - > tooltipAlarmText ( text ) ;
tip ( parent - > rect ( ) , text ) ;
}