doc update
[kdepim.git] / korganizer / timelabels.cpp
blobe8982f73480e790b529d64bd1864cd470fc20f0c
1 /*
2 This file is part of KOrganizer.
4 Copyright (c) 2001 Cornelius Schumacher <schumacher@kde.org>
5 Copyright (C) 2003-2004 Reinhold Kainhofer <reinhold@kainhofer.com>
6 Copyright (c) 2007 Bruno Virlet <bruno@virlet.org>
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License along
19 with this program; if not, write to the Free Software Foundation, Inc.,
20 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
22 As a special exception, permission is given to link this program
23 with any edition of Qt, and distribute the resulting executable,
24 without including the source code for Qt in the source distribution.
27 #include "timelabels.h"
28 #include "timelabelszone.h"
29 #include "timescaleconfigdialog.h"
30 #include "koprefs.h"
31 #include "views/agendaview/koagenda.h"
33 #include <KIcon>
35 #include <QAction>
36 #include <QMenu>
37 #include <QPainter>
39 using namespace KOrg;
41 TimeLabels::TimeLabels( const KDateTime::Spec &spec, int rows,
42 TimeLabelsZone *parent, Qt::WFlags f )
43 : Q3ScrollView( parent, /*name*/0, f )
45 mTimeLabelsZone = parent;
46 mSpec = spec;
48 mRows = rows;
49 mMiniWidth = 0;
51 mCellHeight = KOPrefs::instance()->mHourSize * 4;
53 enableClipper( true );
55 setHScrollBarMode( AlwaysOff );
56 setVScrollBarMode( AlwaysOff );
57 setFrameStyle( Plain );
59 resizeContents( 50, int( mRows * mCellHeight ) );
61 viewport()->setBackgroundRole( QPalette::Background );
62 setBackgroundRole( QPalette::Background );
64 mMousePos = new QFrame( this );
65 mMousePos->setLineWidth( 1 );
66 mMousePos->setFrameStyle( QFrame::HLine | QFrame::Plain );
67 mMousePos->setFixedSize( width(), 1 );
68 colorMousePos();
69 addChild( mMousePos, 0, 0 );
71 mAgenda = 0;
73 if ( mSpec.isValid() ) {
74 setToolTip( i18n( "Timezone:" ) + mSpec.timeZone().name() );
78 void TimeLabels::mousePosChanged( const QPoint &pos )
80 colorMousePos();
81 moveChild( mMousePos, 0, pos.y() );
83 // The repaint somehow prevents that the red line leaves a black artifact when
84 // moved down. It's not a full solution, though.
85 repaint();
88 void TimeLabels::showMousePos()
90 mMousePos->show();
93 void TimeLabels::hideMousePos()
95 mMousePos->hide();
98 void TimeLabels::colorMousePos()
100 QPalette pal;
101 pal.setColor( QPalette::Window, // for Oxygen
102 KOPrefs::instance()->agendaMarcusBainsLineLineColor() );
103 pal.setColor( QPalette::WindowText, // for Plastique
104 KOPrefs::instance()->agendaMarcusBainsLineLineColor() );
105 mMousePos->setPalette( pal );
108 void TimeLabels::setCellHeight( double height )
110 mCellHeight = height;
114 Optimization so that only the "dirty" portion of the scroll view is redrawn.
115 Unfortunately, this is not called by default paintEvent() method.
117 void TimeLabels::drawContents( QPainter *p, int cx, int cy, int cw, int ch )
119 int beginning;
121 if ( !mSpec.isValid() ) {
122 beginning = 0;
123 } else {
124 beginning = ( mSpec.timeZone().currentOffset() -
125 KOPrefs::instance()->timeSpec().timeZone().currentOffset() ) / ( 60 * 60 );
128 p->setBrush( palette().window() ); // TODO: theming, see if we want sth here...
129 p->fillRect( cx, cy, cw, ch, p->brush() );
131 // bug: the parameters cx and cw are the areas that need to be
132 // redrawn, not the area of the widget. unfortunately, this
133 // code assumes the latter...
135 // now, for a workaround...
136 cx = contentsX() + frameWidth() * 2;
137 cw = contentsWidth();
139 // end of workaround
140 int cell = ( (int)( cy / mCellHeight ) ) + beginning; // the hour we start drawing with
141 double y = ( cell - beginning ) * mCellHeight;
142 QFontMetrics fm = fontMetrics();
143 QString hour;
144 int timeHeight = fm.ascent();
145 QFont hourFont = KOPrefs::instance()->agendaTimeLabelsFont();
146 p->setFont( font() );
148 //TODO: rewrite this using KLocale's time formats. "am/pm" doesn't make sense
149 // in some locale's
150 QString suffix;
151 if ( ! KGlobal::locale()->use12Clock() ) {
152 suffix = "00";
153 } else {
154 suffix = "am";
155 if ( cell > 11 ) {
156 suffix = "pm";
160 // We adjust the size of the hour font to keep it reasonable
161 if ( timeHeight > mCellHeight ) {
162 timeHeight = int( mCellHeight - 1 );
163 int pointS = hourFont.pointSize();
164 while ( pointS > 4 ) { // TODO: use smallestReadableFont() when added to kdelibs
165 hourFont.setPointSize( pointS );
166 fm = QFontMetrics( hourFont );
167 if ( fm.ascent() < mCellHeight ) {
168 break;
170 --pointS;
172 fm = QFontMetrics( hourFont );
173 timeHeight = fm.ascent();
175 //timeHeight -= (timeHeight/4-2);
176 QFont suffixFont = hourFont;
177 suffixFont.setPointSize( suffixFont.pointSize() / 2 );
178 QFontMetrics fmS( suffixFont );
179 int startW = mMiniWidth - frameWidth() - 2 ;
180 int tw2 = fmS.width( suffix );
181 int divTimeHeight = ( timeHeight - 1 ) / 2 - 1;
182 //testline
183 //p->drawLine(0,0,0,contentsHeight());
184 while ( y < cy + ch + mCellHeight ) {
185 QPen pen;
186 if ( cell < 0 || cell >= 24 ) {
187 pen.setColor( QColor( 150, 150, 150 ) );
188 } else {
189 pen.setColor( palette().color( QPalette::WindowText ) );
191 p->setPen( pen );
193 // hour, full line
194 p->drawLine( cx, int( y ), cw + 2, int( y ) );
196 hour.setNum( cell % 24 );
197 // handle different timezones
198 if ( cell < 0 ) {
199 hour.setNum( cell + 24 );
201 // handle 24h and am/pm time formats
202 if ( KGlobal::locale()->use12Clock() ) {
203 if ( cell == 12 ) {
204 suffix = "pm";
206 if ( cell == 0 ) {
207 hour.setNum( 12 );
209 if ( cell > 12 ) {
210 hour.setNum( cell - 12 );
214 // center and draw the time label
215 int timeWidth = fm.width( hour );
216 int offset = startW - timeWidth - tw2 -1 ;
217 p->setFont( hourFont );
218 p->drawText( offset, int( y + timeHeight ), hour );
219 p->setFont( suffixFont );
220 offset = startW - tw2;
221 p->drawText( offset, int( y + timeHeight - divTimeHeight ), suffix );
223 // increment indices
224 y += mCellHeight;
225 cell++;
230 Calculates the minimum width.
232 int TimeLabels::minimumWidth() const
234 return mMiniWidth;
237 /** updates widget's internal state */
238 void TimeLabels::updateConfig()
240 /** Can happen if all resources are disabled */
241 if ( !mAgenda ) {
242 return;
245 setFont( KOPrefs::instance()->agendaTimeLabelsFont() );
247 QString test = "20";
248 if ( KGlobal::locale()->use12Clock() ) {
249 test = "12";
251 mMiniWidth = fontMetrics().width( test );
252 if ( KGlobal::locale()->use12Clock() ) {
253 test = "pm";
254 } else {
255 test = "00";
257 QFont sFont = font();
258 sFont.setPointSize( sFont.pointSize() / 2 );
259 QFontMetrics fmS( sFont );
260 mMiniWidth += fmS.width( test ) + frameWidth() * 2 + 4 ;
261 // update geometry restrictions based on new settings
262 setFixedWidth( mMiniWidth );
264 // update HourSize
265 mCellHeight = KOPrefs::instance()->mHourSize * 4;
266 // If the agenda is zoomed out so that more than 24 would be shown,
267 // the agenda only shows 24 hours, so we need to take the cell height
268 // from the agenda, which is larger than the configured one!
269 if ( mCellHeight < 4 * mAgenda->gridSpacingY() ) {
270 mCellHeight = 4 * mAgenda->gridSpacingY();
272 resizeContents( mMiniWidth, int( mRows * mCellHeight + 1 ) );
275 /** update time label positions */
276 void TimeLabels::positionChanged()
278 if ( mAgenda ) {
279 int adjustment = mAgenda->contentsY();
280 if ( adjustment != contentsY() ) {
281 setContentsPos( 0, adjustment );
286 void TimeLabels::positionChanged( int pos )
288 if ( pos != contentsY() ) {
289 setContentsPos( 0, pos );
293 /** */
294 void TimeLabels::setAgenda( KOAgenda *agenda )
296 mAgenda = agenda;
298 connect( mAgenda, SIGNAL(mousePosSignal(const QPoint &)),
299 this, SLOT(mousePosChanged(const QPoint &)) );
300 connect( mAgenda, SIGNAL(enterAgenda()), this, SLOT(showMousePos()) );
301 connect( mAgenda, SIGNAL(leaveAgenda()), this, SLOT(hideMousePos()) );
302 connect( mAgenda, SIGNAL(gridSpacingYChanged(double)),
303 this, SLOT(setCellHeight(double)) );
306 /** This is called in response to repaint() */
307 void TimeLabels::paintEvent( QPaintEvent * )
309 QPainter painter( this );
310 drawContents( &painter, contentsX(), contentsY(), visibleWidth(), visibleHeight() );
313 void TimeLabels::contextMenuEvent( QContextMenuEvent *event )
315 Q_UNUSED( event );
317 QMenu popup( this );
318 QAction *editTimeZones =
319 popup.addAction( KIcon( "document-properties" ), i18n( "&Add Timezones..." ) );
320 QAction *removeTimeZone =
321 popup.addAction( KIcon( "edit-delete" ),
322 i18n( "&Remove Timezone %1", mSpec.timeZone().name() ) );
323 if ( !mSpec.isValid() ||
324 !KOPrefs::instance()->timeScaleTimezones().count() ||
325 mSpec == KOPrefs::instance()->timeSpec() ) {
326 removeTimeZone->setEnabled( false );
329 QAction *activatedAction = popup.exec( QCursor::pos() );
330 if ( activatedAction == editTimeZones ) {
331 QPointer<TimeScaleConfigDialog> dialog = new TimeScaleConfigDialog( this );
332 if ( dialog->exec() == QDialog::Accepted ) {
333 mTimeLabelsZone->reset();
335 delete dialog;
336 } else if ( activatedAction == removeTimeZone ) {
337 QStringList list = KOPrefs::instance()->timeScaleTimezones();
338 list.removeAll( mSpec.timeZone().name() );
339 KOPrefs::instance()->setTimeScaleTimezones( list );
340 mTimeLabelsZone->reset();
341 hide();
342 deleteLater();
346 KDateTime::Spec TimeLabels::timeSpec()
348 return mSpec;
351 QString TimeLabels::header() const
353 return mSpec.timeZone().name();
356 QString TimeLabels::headerToolTip() const
358 KTimeZone tz = mSpec.timeZone();
360 QString toolTip;
361 toolTip += "<qt>";
362 toolTip += i18n( "Timezone: %1", tz.name() );
363 if ( !tz.countryCode().isEmpty() ) {
364 toolTip += "<br/>";
365 toolTip += i18n( "Country Code: %1", tz.countryCode() );
367 if ( !tz.abbreviations().isEmpty() ) {
368 toolTip += "<br/>";
369 toolTip += i18n( "Abbreviations:" );
370 foreach ( const QByteArray &a, tz.abbreviations() ) {
371 toolTip += "<br/>";
372 toolTip += "&nbsp;" + QString::fromLocal8Bit( a );
375 if ( !tz.comment().isEmpty() ) {
376 toolTip += "<br/>";
377 toolTip += i18n( "Comment:<br/>%1", tz.comment() );
379 toolTip += "</qt>";
381 return toolTip;
384 #include "timelabels.moc"