1/*
2 This file is part of the kholidays library.
3
4 Copyright 2010 John Layt <john@layt.net>
5
6 This library is free software; you can redistribute it and/or
7 modify it under the terms of the GNU Library General Public
8 License as published by the Free Software Foundation; either
9 version 2 of the License, or (at your option) any later version.
10
11 This library 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 Library General Public License for more details.
15
16 You should have received a copy of the GNU Library General Public License
17 along with this library; see the file COPYING.LIB. If not, write to the
18 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19 Boston, MA 02110-1301, USA.
20*/
21
22#include "holidayregionselector.h"
23#include "ui_holidayregionselector.h"
24
25#include "holidayregion.h"
26
27#include <KDebug>
28#include <KLocale>
29#include <KLocalizedString>
30#include <KGlobal>
31#include <KComboBox>
32
33using namespace KHolidays;
34
35class HolidayRegionSelector::Private
36{
37 public:
38 Private( HolidayRegionSelector *q_ptr )
39 {
40 q = q_ptr;
41 }
42
43 ~Private()
44 {
45 }
46
47 // Reorder this to change column order
48 enum Column {
49 RegionColumn = 0,
50 LanguageColumn,
51 DescriptionColumn,
52 SelectColumn,
53 ComboColumn
54 };
55
56 void clearSelection();
57 QTreeWidgetItem *findItem( const QString &holidayRegionCode );
58 void initItem( QTreeWidgetItem *listItem, HolidayRegion *region );
59 QString itemRegion( QTreeWidgetItem *item );
60 QString itemLanguage( QTreeWidgetItem *item );
61 SelectionStatus itemSelectionStatus( QTreeWidgetItem *item );
62 void setItemStatus( QTreeWidgetItem *item, SelectionStatus status );
63 KComboBox *itemCombo( QTreeWidgetItem *item );
64 void setItemRegionUseFlags( QTreeWidgetItem *item, RegionUseFlags regionUseFlags );
65 HolidayRegionSelector::RegionUseFlags itemRegionUseFlags( QTreeWidgetItem *item );
66
67 QAbstractItemView::SelectionMode m_selectionMode;
68 bool m_enableRegionUseFlags;
69 QStringList m_languageFilter;
70 QStringList m_holidayRegionCodes;
71 Ui::holidayRegionSelector m_ui;
72 HolidayRegionSelector *q;
73};
74
75void HolidayRegionSelector::Private::clearSelection()
76{
77 m_ui.regionTreeWidget->blockSignals( true );
78 QTreeWidgetItemIterator it( m_ui.regionTreeWidget, QTreeWidgetItemIterator::Checked );
79 while ( *it ) {
80 ( *it )->setCheckState( Private::SelectColumn, Qt::Unchecked );
81 ( *it )->setData( Private::SelectColumn, Qt::UserRole, RegionAvailable );
82 itemCombo( ( *it ) )->setCurrentIndex( 0 );
83 ( *it )->setData( Private::ComboColumn, Qt::UserRole, NotUsed );
84 ++it;
85 }
86 m_ui.regionTreeWidget->blockSignals( false );
87}
88
89QTreeWidgetItem *HolidayRegionSelector::Private::findItem( const QString &holidayRegionCode )
90{
91 QTreeWidgetItemIterator it( m_ui.regionTreeWidget );
92 while ( *it ) {
93 if ( ( *it )->data( HolidayRegionSelector::Private::RegionColumn, Qt::UserRole ) ==
94 holidayRegionCode ) {
95 return ( *it );
96 }
97 ++it;
98 }
99 return 0;
100}
101
102void HolidayRegionSelector::Private::initItem( QTreeWidgetItem *listItem, HolidayRegion *region )
103{
104 m_ui.regionTreeWidget->blockSignals( true );
105 QString languageName = KGlobal::locale()->languageCodeToName( region->languageCode() );
106 listItem->setCheckState( Private::SelectColumn, Qt::Unchecked );
107 QString text = i18n( "<p>Select to use Holiday Region</p>" );
108 listItem->setToolTip( Private::SelectColumn, text );
109 listItem->setToolTip( Private::ComboColumn, text );
110 text = i18n( "<p>Select to use Holiday Region</p>" );
111 listItem->setToolTip( Private::SelectColumn, text );
112 listItem->setToolTip( Private::ComboColumn, text );
113 listItem->setText( Private::RegionColumn, region->name() );
114 QString toolTip = i18n( "<p><b>Region:</b> %1<br/>"
115 "<b>Language:</b> %2<br/>"
116 "<b>Description:</b> %3</p>",
117 region->name(), languageName, region->description() );
118 listItem->setToolTip( Private::RegionColumn, toolTip );
119 listItem->setData( Private::RegionColumn, Qt::UserRole, region->regionCode() );
120 listItem->setText( Private::LanguageColumn, languageName );
121 listItem->setData( Private::LanguageColumn, Qt::UserRole, region->languageCode() );
122 listItem->setText( Private::DescriptionColumn, region->description() );
123 listItem->setToolTip( Private::DescriptionColumn, region->description() );
124 KComboBox *combo = new KComboBox();
125 combo->setAutoFillBackground( true );
126 QString comboText = i18n( "<p>You can choose to display the Holiday Region for information only, "
127 "or to use the Holiday Region when displaying or calculating days off "
128 "such as Public Holidays. If you choose to use the Holiday Region for "
129 "Days Off, then only those Holiday Events marked in the Holiday Region "
130 "as Days Off will be used for non-work days, Holiday Events that are "
131 "not marked in the Holiday Region as Days Off will continue to be "
132 "work days.</p>" );
133 combo->setToolTip( comboText );
134 comboText = i18nc( "Combobox label, Holiday Region not used", "Not Used" );
135 combo->addItem( comboText, QVariant( NotUsed ) );
136 comboText = i18nc( "Combobox label, use Holiday Region for information only", "Information" );
137 combo->addItem( comboText, QVariant( UseInformationOnly ) );
138 comboText = i18nc( "Combobox label, use Holiday Region for days off", "Days Off" );
139 combo->addItem( comboText, QVariant( UseDaysOff ) );
140 combo->setCurrentIndex( 0 );
141 listItem->setData( Private::ComboColumn, Qt::UserRole, NotUsed );
142 m_ui.regionTreeWidget->setItemWidget( listItem, ComboColumn, combo );
143 connect( combo, SIGNAL(currentIndexChanged(int)),
144 q, SLOT(itemChanged(int)) );
145 m_ui.regionTreeWidget->blockSignals( false );
146}
147
148QString HolidayRegionSelector::Private::itemRegion( QTreeWidgetItem *item )
149{
150 return item->data( Private::RegionColumn, Qt::UserRole ).toString();
151}
152
153QString HolidayRegionSelector::Private::itemLanguage( QTreeWidgetItem *item )
154{
155 return item->data( Private::LanguageColumn, Qt::UserRole ).toString();
156}
157
158HolidayRegionSelector::SelectionStatus
159HolidayRegionSelector::Private::itemSelectionStatus( QTreeWidgetItem *item )
160{
161 return
162 ( HolidayRegionSelector::SelectionStatus )
163 item->data( Private::SelectColumn, Qt::UserRole ).toInt();
164}
165
166void HolidayRegionSelector::Private::setItemRegionUseFlags( QTreeWidgetItem *item,
167 RegionUseFlags regionUseFlags )
168{
169 // Just do simple flags for now, cheat on the index
170 item->setData( ComboColumn, Qt::UserRole, QVariant( regionUseFlags ) );
171 if ( regionUseFlags & UseDaysOff ) {
172 setItemStatus( item, RegionSelected );
173 itemCombo( item )->setCurrentIndex( 2 );
174 } else if ( regionUseFlags & UseInformationOnly ) {
175 setItemStatus( item, RegionSelected );
176 itemCombo( item )->setCurrentIndex( 1 );
177 } else { // NotUsed
178 setItemStatus( item, RegionAvailable );
179 itemCombo( item )->setCurrentIndex( 0 );
180 }
181}
182
183HolidayRegionSelector::RegionUseFlags
184HolidayRegionSelector::Private::itemRegionUseFlags( QTreeWidgetItem *item )
185{
186 return (RegionUseFlags) item->data( ComboColumn, Qt::UserRole ).toInt();
187}
188
189KComboBox *HolidayRegionSelector::Private::itemCombo( QTreeWidgetItem *item )
190{
191 return static_cast<KComboBox*>( m_ui.regionTreeWidget->itemWidget( item, ComboColumn ) );
192}
193
194void HolidayRegionSelector::Private::setItemStatus( QTreeWidgetItem *item, SelectionStatus status )
195{
196 if ( m_selectionMode == QAbstractItemView::SingleSelection &&
197 status == RegionSelected ) {
198 clearSelection();
199 }
200
201 Qt::CheckState selectStatus = Qt::Unchecked;
202 bool hidden = false;
203 bool disabled = false;
204
205 switch ( status ) {
206 case RegionHidden:
207 hidden = true;
208 disabled = true;
209 break;
210 case RegionDisabled:
211 disabled = true;
212 break;
213 case RegionAvailable:
214 break;
215 case RegionSelected:
216 {
217 if ( m_selectionMode != QAbstractItemView::NoSelection ) {
218 selectStatus = Qt::Checked;
219 }
220 break;
221 }
222 default:
223 break;
224 }
225
226 m_ui.regionTreeWidget->blockSignals( true );
227 item->setData( Private::SelectColumn, Qt::UserRole, status );
228 item->setCheckState( Private::SelectColumn, selectStatus );
229 item->setHidden( hidden );
230 item->setDisabled( disabled );
231 m_ui.regionTreeWidget->blockSignals( false );
232}
233
234HolidayRegionSelector::HolidayRegionSelector( QWidget *parent ) :
235 QWidget( parent ), d( new Private( this ) )
236{
237 d->m_ui.setupUi( this );
238
239 // Setup the columns
240 d->m_ui.regionTreeWidget->setColumnCount( 5 );
241 QTreeWidgetItem *headerItem = d->m_ui.regionTreeWidget->headerItem();
242 QString header = i18nc( "Header for Select column", "Select" );
243 QString text = i18n( "<p>This column selects to use the Holiday Region</p>" );
244 headerItem->setText( Private::SelectColumn, header );
245 headerItem->setToolTip( Private::SelectColumn, text );
246 headerItem->setWhatsThis( Private::SelectColumn, text );
247 headerItem->setText( Private::ComboColumn, header );
248 headerItem->setToolTip( Private::ComboColumn, text );
249 headerItem->setWhatsThis( Private::ComboColumn, text );
250 header = i18nc( "Header for Holiday Region column", "Region" );
251 text = i18n( "<p>This column displays the name of the Holiday Region</p>" );
252 headerItem->setText( Private::RegionColumn, header );
253 headerItem->setToolTip( Private::RegionColumn, text );
254 headerItem->setWhatsThis( Private::RegionColumn, text );
255 header = i18nc( "Header for Language column", "Language" );
256 text = i18n( "<p>This column displays the language of the Holiday Region</p>" );
257 headerItem->setText( Private::LanguageColumn, header );
258 headerItem->setToolTip( Private::LanguageColumn, text );
259 headerItem->setWhatsThis( Private::LanguageColumn, text );
260 header = i18nc( "Header for Description column", "Description" );
261 text = i18n( "<p>This column displays the description of the Holiday Region</p>" );
262 headerItem->setText( Private::DescriptionColumn, header );
263 headerItem->setToolTip( Private::DescriptionColumn, text );
264 headerItem->setWhatsThis( Private::DescriptionColumn, text );
265
266 d->m_ui.regionTreeWidget->setSelectionMode( QAbstractItemView::NoSelection );
267 d->m_ui.regionTreeWidget->setItemsExpandable( true ); //per bug 271628
268 d->m_ui.regionTreeWidget->setUniformRowHeights( true );
269 d->m_ui.regionTreeWidget->setAllColumnsShowFocus( true );
270 connect( d->m_ui.regionTreeWidget, SIGNAL(itemChanged(QTreeWidgetItem*,int)),
271 this, SLOT(itemChanged(QTreeWidgetItem*,int)) );
272
273 QMap<QString, QStringList> regionCodeMap;
274 QMap<QString, HolidayRegion*> regionMap;
275 foreach ( const QString &regionCode, HolidayRegion::regionCodes() ) {
276 regionMap[regionCode] = new HolidayRegion( regionCode );
277 QString country = regionMap[regionCode]->countryCode().split( QLatin1Char('-') ).at( 0 );
278 regionCodeMap[country].append( regionCode );
279 }
280
281 QMapIterator<QString, QStringList> it( regionCodeMap );
282 while ( it.hasNext() ) {
283 it.next();
284 // if only 1 region for country and that region is the country, then only show the country line
285 // Otherwise show a non-selectable country header and list all regions below it
286 QTreeWidgetItem *rootItem = new QTreeWidgetItem( d->m_ui.regionTreeWidget );
287 QString country = it.key();
288 if ( it.value().count() == 1 && regionMap[it.value().at( 0 )]->countryCode() == country ) {
289 d->initItem( rootItem, regionMap[ it.value().at( 0 ) ] );
290 } else {
291 rootItem->setText( Private::RegionColumn,
292 KGlobal::locale()->countryCodeToName( country ) );
293 d->m_ui.regionTreeWidget->setFirstItemColumnSpanned ( rootItem, true );
294 foreach ( const QString &regionCode, it.value() ) {
295 QTreeWidgetItem *childItem = new QTreeWidgetItem( rootItem );
296 d->initItem( childItem, regionMap[ regionCode ] );
297 }
298 }
299 }
300
301 QMapIterator<QString, HolidayRegion*> i( regionMap );
302 while ( i.hasNext() ) {
303 i.next();
304 delete i.value();
305 }
306
307 d->m_ui.regionTreeWidget->expandAll();
308 d->m_ui.regionTreeWidget->sortItems( Private::RegionColumn, Qt::AscendingOrder );
309 d->m_ui.regionTreeWidget->resizeColumnToContents( Private::SelectColumn );
310 d->m_ui.regionTreeWidget->resizeColumnToContents( Private::ComboColumn );
311 d->m_ui.regionTreeWidget->resizeColumnToContents( Private::RegionColumn );
312 d->m_ui.regionTreeWidget->resizeColumnToContents( Private::LanguageColumn );
313
314 // Setup search widget
315 d->m_ui.searchLineWidget->searchLine()->addTreeWidget( d->m_ui.regionTreeWidget );
316
317 // Default to MultiSelection mode with Region Use Flags
318 setSelectionMode( QAbstractItemView::MultiSelection );
319 setRegionUseFlagsEnabled( true );
320}
321
322HolidayRegionSelector::~HolidayRegionSelector()
323{
324 delete d;
325}
326
327QStringList HolidayRegionSelector::holidayRegions() const
328{
329 return d->m_holidayRegionCodes;
330}
331
332void HolidayRegionSelector::setSelectionMode( QAbstractItemView::SelectionMode selectionMode )
333{
334 d->m_selectionMode = selectionMode;
335
336 if ( selectionMode == QAbstractItemView::NoSelection ) {
337 setRegionUseFlagsEnabled( false );
338 }
339}
340
341QAbstractItemView::SelectionMode HolidayRegionSelector::selectionMode() const
342{
343 return d->m_selectionMode;
344}
345
346void HolidayRegionSelector::setRegionUseFlagsEnabled( bool enableRegionUseFlags )
347{
348 d->m_enableRegionUseFlags = enableRegionUseFlags;
349 d->m_ui.regionTreeWidget->setColumnHidden( Private::SelectColumn, enableRegionUseFlags );
350 d->m_ui.regionTreeWidget->setColumnHidden( Private::ComboColumn, !enableRegionUseFlags );
351}
352
353bool HolidayRegionSelector::regionUseFlagsEnabled() const
354{
355 return d->m_enableRegionUseFlags;
356}
357
358void HolidayRegionSelector::setSelectionStatus( const QString &holidayRegionCode,
359 HolidayRegionSelector::SelectionStatus status )
360{
361 QTreeWidgetItem *item = d->findItem( holidayRegionCode );
362 if ( item ) {
363 d->setItemStatus( item, status );
364 }
365}
366
367HolidayRegionSelector::SelectionStatus
368HolidayRegionSelector::selectionStatus( const QString &holidayRegionCode ) const
369{
370 QTreeWidgetItem *item = d->findItem( holidayRegionCode );
371 if ( item ) {
372 return d->itemSelectionStatus( item );
373 }
374 return HolidayRegionSelector::RegionHidden;
375}
376
377QHash<QString, HolidayRegionSelector::SelectionStatus>
378HolidayRegionSelector::selectionStatus() const
379{
380 QHash<QString, HolidayRegionSelector::SelectionStatus> selection;
381 QTreeWidgetItemIterator it( d->m_ui.regionTreeWidget );
382 while ( *it ) {
383 selection.insert( d->itemRegion( ( *it ) ), d->itemSelectionStatus( ( *it ) ) );
384 ++it;
385 }
386 return selection;
387}
388
389QStringList
390HolidayRegionSelector::selection( HolidayRegionSelector::SelectionStatus selectionStatus ) const
391{
392 if ( selectionMode() == QAbstractItemView::NoSelection ) {
393 return QStringList();
394 }
395
396 QStringList selection;
397 QTreeWidgetItemIterator it( d->m_ui.regionTreeWidget );
398 while ( *it ) {
399 if ( d->itemSelectionStatus( ( *it ) ) == selectionStatus ) {
400 selection.append( d->itemRegion( ( *it ) ) );
401 }
402 ++it;
403 }
404 return selection;
405}
406
407QStringList
408HolidayRegionSelector::selection( HolidayRegionSelector::RegionUseFlags regionUseFlags ) const
409{
410 if ( selectionMode() == QAbstractItemView::NoSelection ) {
411 return QStringList();
412 }
413
414 QStringList selection;
415 QTreeWidgetItemIterator it( d->m_ui.regionTreeWidget );
416 while ( *it ) {
417 if ( d->itemRegionUseFlags( ( *it ) ) & regionUseFlags ) {
418 selection.append( d->itemRegion( ( *it ) ) );
419 }
420 ++it;
421 }
422 return selection;
423}
424
425void
426HolidayRegionSelector::setRegionUseFlags( const QString &holidayRegionCode,
427 HolidayRegionSelector::RegionUseFlags regionUseFlags )
428{
429 QTreeWidgetItem *item = d->findItem( holidayRegionCode );
430 if ( item ) {
431 d->setItemRegionUseFlags( item, regionUseFlags );
432 }
433}
434
435HolidayRegionSelector::RegionUseFlags
436HolidayRegionSelector::regionUseFlags( const QString &holidayRegionCode ) const
437{
438 QTreeWidgetItem *item = d->findItem( holidayRegionCode );
439 if ( item ) {
440 return d->itemRegionUseFlags( item );
441 }
442 return HolidayRegionSelector::NotUsed;
443}
444
445QHash<QString, HolidayRegionSelector::RegionUseFlags> HolidayRegionSelector::regionUseFlags() const
446{
447 QHash<QString, HolidayRegionSelector::RegionUseFlags> selection;
448 QTreeWidgetItemIterator it( d->m_ui.regionTreeWidget );
449 while ( *it ) {
450 selection.insert( d->itemRegion( ( *it ) ), d->itemRegionUseFlags( ( *it ) ) );
451 ++it;
452 }
453 return selection;
454}
455
456void HolidayRegionSelector::itemChanged( QTreeWidgetItem *item, int column )
457{
458 if ( column == Private::SelectColumn ) {
459 if ( item->checkState( Private::SelectColumn ) == Qt::Unchecked ) {
460 d->setItemStatus( item, RegionAvailable );
461 } else {
462 d->setItemStatus( item, RegionSelected );
463 }
464 }
465 emit selectionChanged();
466}
467
468// The slot for the combo box when changed
469void HolidayRegionSelector::itemChanged( int index )
470{
471 KComboBox *combo = static_cast<KComboBox*>( sender() );
472 QTreeWidgetItemIterator it( d->m_ui.regionTreeWidget );
473 bool found = false;
474 while ( *it && !found ) {
475 if ( d->itemCombo( ( *it ) ) == combo ) {
476 ( *it )->setData(
477 Private::ComboColumn, Qt::UserRole, d->itemCombo( ( *it ) )->itemData( index ) );
478 if ( d->itemRegionUseFlags( ( *it ) ) == NotUsed ) {
479 d->setItemStatus( ( *it ), RegionAvailable );
480 } else {
481 d->setItemStatus( ( *it ), RegionSelected );
482 }
483 found = true;
484 }
485 ++it;
486 }
487}
488
489void HolidayRegionSelector::clearSelection()
490{
491 d->clearSelection();
492}
493
494void HolidayRegionSelector::setLanguageFilter( const QStringList &languages )
495{
496 // First reset to visible those languages previously hidden
497 QTreeWidgetItemIterator it( d->m_ui.regionTreeWidget );
498 while ( *it ) {
499 if ( !d->m_languageFilter.contains(
500 ( *it )->data( Private::LanguageColumn, Qt::UserRole ).toString() ) ) {
501 d->setItemStatus( ( *it ), RegionAvailable );
502 }
503 ++it;
504 }
505 // Now hide those languages not in the new list
506 d->m_languageFilter = languages;
507 QTreeWidgetItemIterator it2( d->m_ui.regionTreeWidget );
508 while ( *it2 ) {
509 QString language = ( *it2 )->data( Private::LanguageColumn, Qt::UserRole ).toString();
510 if ( d->m_languageFilter.contains( language ) ) {
511 // Make sure the parent is always visible, otherwise the child is not visible
512 if ( ( *it2 )->parent() &&
513 ( *it2 )->parent() != d->m_ui.regionTreeWidget->invisibleRootItem() ) {
514 d->setItemStatus( ( *it2 )->parent(), RegionAvailable );
515 }
516 } else {
517 d->setItemStatus( ( *it2 ), RegionHidden );
518 }
519 ++it2;
520 }
521}
522
523QStringList HolidayRegionSelector::languageFilter() const
524{
525 return d->m_languageFilter;
526}
527
528void HolidayRegionSelector::setSearchHidden( bool hideSearch )
529{
530 d->m_ui.searchLineWidget->setHidden( hideSearch );
531}
532
533bool HolidayRegionSelector::searchHidden() const
534{
535 return d->m_ui.searchLineWidget->isHidden();
536}
537
538void HolidayRegionSelector::setLanguageHidden( bool hideLanguage )
539{
540 d->m_ui.regionTreeWidget->setColumnHidden( Private::LanguageColumn, hideLanguage );
541}
542
543bool HolidayRegionSelector::languageHidden() const
544{
545 return d->m_ui.regionTreeWidget->isColumnHidden( Private::LanguageColumn );
546}
547
548void HolidayRegionSelector::setDescriptionHidden( bool hideDescription )
549{
550 d->m_ui.regionTreeWidget->setColumnHidden( Private::DescriptionColumn, hideDescription );
551}
552
553bool HolidayRegionSelector::descriptionHidden() const
554{
555 return d->m_ui.regionTreeWidget->isColumnHidden( Private::DescriptionColumn );
556}
557
558