add mp3 and ogg torrent url info to JamendoAlbum
[amarok.git] / src / smartplaylisteditor.cpp
blob877b3e32354e5cb19a7e776deb1e0324c96f97eb
1 /// (c) Pierpaolo Di Panfilo 2004
2 // (c) Alexandre Pereira de Oliveira 2005
3 // (c) 2005 Isaiah Damron <xepo@trifault.net>
4 // (c) 2006 Peter C. Ndikuwera <pndiku@gmail.com>
5 // See COPYING file for licensing information
7 #define DEBUG_PREFIX "SmartPlaylistEditor"
9 #include "smartplaylisteditor.h"
11 #include "amarok.h" //oldForeach
12 #include "debug.h"
13 #include "querybuilder.h"
14 #include "metabundle.h"
15 #include "mountpointmanager.h"
17 #include <KComboBox>
18 #include <KLineEdit>
19 #include <KLocale>
20 #include <kmountpoint.h>
21 #include <KNumInput>
22 #include <KVBox>
24 #include <QCheckBox>
25 #include <QDateTime>
26 #include <q3datetimeedit.h> //loadEditWidgets()
27 #include <QFrame>
28 #include <QLabel>
29 #include <QLayout>
30 #include <QObject>
31 #include <QStringList>
32 #include <QToolButton>
33 #include <q3vgroupbox.h>
36 enum Fields
38 FArtist = 0,
39 FComposer,
40 FAlbum,
41 FGenre,
42 FTitle,
43 FLength,
44 FTrack,
45 FYear,
46 FComment,
47 FPlayCounter,
48 FScore,
49 FRating,
50 FFirstPlay,
51 FLastPlay,
52 FModfiedDate,
53 FFilePath,
54 FBPM,
55 FMountPoint,
56 FBitRate,
57 FLabel
61 QStringList m_fields;
62 QStringList m_dbFields;
63 QStringList m_expandableFields;
64 QStringList m_expandableDbFields;
68 SmartPlaylistEditor::SmartPlaylistEditor( QString defaultName, QWidget *parent, const char *name )
69 : KDialog( parent )
71 setObjectName( name );
72 setCaption( i18n("Create Smart Playlist") );
73 setModal( true );
74 setButtons( Ok | Cancel );
75 setDefaultButton( Ok );
76 showButtonSeparator( true );
78 init(defaultName);
79 addCriteriaAny();
80 addCriteriaAll();
84 SmartPlaylistEditor::SmartPlaylistEditor( QWidget *parent, QDomElement xml, const char *name)
85 : KDialog( parent )
87 setObjectName( name );
88 setCaption( i18n("Edit Smart Playlist") );
89 setModal( true );
90 setButtons( Ok | Cancel );
91 setDefaultButton( Ok );
92 showButtonSeparator( true );
95 init( xml.attribute( "name" ) );
96 // matches
97 QDomNodeList matchesList = xml.elementsByTagName( "matches" );
98 bool matchedANY = false, matchedALL = false;
100 m_matchAllCheck->setChecked( true );
101 m_matchAnyCheck->setChecked( true );
103 for (int i = 0, m = matchesList.count(); i<m; i++) {
104 QDomElement matches = matchesList.item(i).toElement();
105 QDomNodeList criteriaList = matches.elementsByTagName( "criteria" );
107 if ( criteriaList.count() ) {
108 for (int j = 0, c=criteriaList.count() ; j<c; ++j ) {
109 QDomElement criteria = criteriaList.item(j).toElement();
111 if (matches.attribute( "glue" ) == "OR") {
112 matchedANY = true;
113 addCriteriaAny( criteria );
115 else {
116 matchedALL = true;
117 addCriteriaAll( criteria );
123 if ( !matchedALL ) {
124 addCriteriaAll();
125 m_matchAllCheck->setChecked( false );
128 if ( !matchedANY ) {
129 m_matchAnyCheck->setChecked( false );
130 addCriteriaAny( );
133 // orderby
134 QDomNodeList orderbyList = xml.elementsByTagName( "orderby" );
135 if ( orderbyList.count() ) {
136 m_orderCheck->setChecked( true );
137 QDomElement orderby = orderbyList.item(0).toElement(); // we only allow one orderby node
139 //random is always the last one.
140 int dbfield = orderby.attribute( "field" ) == "random" ? m_dbFields.count() : m_dbFields.indexOf( orderby.attribute( "field" ) );
142 m_orderCombo->setCurrentIndex( dbfield );
143 updateOrderTypes( dbfield );
144 if ( orderby.attribute( "order" ) == "DESC" || orderby.attribute( "order" ) == "weighted" )
145 m_orderTypeCombo->setCurrentIndex( 1 );
146 else if ( orderby.attribute( "order" ) == "ratingweighted" )
147 m_orderTypeCombo->setCurrentIndex( 2 );
148 else
149 m_orderTypeCombo->setCurrentIndex( 0 );
151 // limit
152 if ( xml.hasAttribute( "maxresults" ) ) {
153 m_limitCheck->setChecked( true );
154 m_limitSpin->setValue( xml.attribute( "maxresults" ).toInt() );
157 // expand by
158 QDomNodeList expandbyList = xml.elementsByTagName( "expandby" );
159 if ( expandbyList.count() ) {
160 m_expandCheck->setChecked( true );
161 QDomElement expandby = expandbyList.item(0).toElement(); // we only allow one orderby node
163 int dbfield = m_expandableFields.indexOf( expandby.attribute( "field" ) );
164 m_expandCombo->setCurrentIndex( dbfield );
169 void SmartPlaylistEditor::init(QString defaultName)
171 KVBox *vbox = new KVBox( this );
172 setMainWidget( vbox );
175 m_fields.clear();
176 m_fields << i18n("Artist") << i18n("Composer") << i18n("Album") << i18n("Genre") << i18n("Title") << i18n("Length")
177 << i18n("Track #") << i18n("Year") << i18n("Comment") << i18n("Play Counter")
178 << i18n("Score") << i18n( "Rating" ) << i18n("First Play")
179 << i18n("Last Play") << i18n("Modified Date") << i18n("File Path")
180 << i18n("BPM") << i18n("Mount Point") << i18n( "Bitrate" ) << i18n( "Label" );
182 m_dbFields.clear();
183 m_dbFields << "artist.name" << "composer.name" << "album.name" << "genre.name" << "tags.title" << "tags.length"
184 << "tags.track" << "year.name" << "tags.comment" << "statistics.playcounter"
185 << "statistics.percentage" << "statistics.rating" << "statistics.createdate"
186 << "statistics.accessdate" << "tags.createdate" << "tags.url"
187 << "tags.bpm" << "devices.lastmountpoint" << "tags.bitrate" << "labels.name";
189 m_expandableFields.clear();
190 m_expandableFields << i18n("Artist") << i18n("Composer") << i18n("Album") << i18n("Genre") << i18n("Year") << i18n( "Label" );
192 m_expandableDbFields.clear();
193 m_expandableDbFields << "artist.name" << "composer.name" << "album.name" << "genre.name" << "year.name" << "labels.name";
195 KHBox *hbox = new KHBox( mainWidget() );
196 hbox->setSpacing( 5 );
197 new QLabel( i18n("Playlist name:"), hbox );
198 m_nameLineEdit = new KLineEdit( defaultName, hbox );
200 QFrame *sep = new QFrame( mainWidget() );
201 sep->setFrameStyle( QFrame::HLine | QFrame::Sunken );
203 //match box (any)
204 KHBox *matchAnyBox = new KHBox( mainWidget() );
205 m_matchAnyCheck = new QCheckBox( i18n("Match Any of the following conditions" ), matchAnyBox );
206 matchAnyBox->setStretchFactor( new QWidget( matchAnyBox ), 1 );
208 //criteria box
209 m_criteriaAnyGroupBox = new Q3VGroupBox( QString(), mainWidget() );
211 //match box (all)
212 KHBox *matchAllBox = new KHBox( mainWidget() );
213 m_matchAllCheck = new QCheckBox( i18n("Match All of the following conditions" ), matchAllBox );
214 matchAllBox->setStretchFactor( new QWidget( matchAllBox ), 1 );
216 //criteria box
217 m_criteriaAllGroupBox = new Q3VGroupBox( QString(), mainWidget() );
219 //order box
220 KHBox *hbox2 = new KHBox( mainWidget() );
221 m_orderCheck = new QCheckBox( i18n("Order by"), hbox2 );
222 KHBox *orderBox = new KHBox( hbox2 );
223 orderBox->setSpacing( 5 );
224 //fields combo
225 m_orderCombo = new KComboBox( orderBox );
226 m_orderCombo->insertItems( 0, m_fields );
227 m_orderCombo->addItem( i18n("Random") );
228 //order type
229 m_orderTypeCombo = new KComboBox( orderBox );
230 updateOrderTypes(0); // populate the new m_orderTypeCombo
231 hbox2->setStretchFactor( new QWidget( hbox2 ), 1 );
233 //limit box
234 KHBox *hbox1 = new KHBox( mainWidget() );
235 m_limitCheck = new QCheckBox( i18n("Limit to"), hbox1 );
236 KHBox *limitBox = new KHBox( hbox1 );
237 limitBox->setSpacing( 5 );
238 m_limitSpin = new QSpinBox( limitBox );
239 m_limitSpin->setMinimum( 1 );
240 m_limitSpin->setMaximum( 100000 );
241 m_limitSpin->setValue( 15 );
242 new QLabel( i18n("tracks"), limitBox );
243 hbox1->setStretchFactor( new QWidget( hbox1 ), 1 );
245 //Expand By
246 KHBox *hbox3 = new KHBox( mainWidget() );
247 m_expandCheck = new QCheckBox( i18n("Expand by"), hbox3 );
248 KHBox *expandBox = new KHBox( hbox3 );
249 expandBox->setSpacing( 5 );
250 m_expandCombo = new KComboBox( expandBox );
251 m_expandCombo->insertItems( 0, m_expandableFields );
252 hbox3->setStretchFactor( new QWidget( hbox3 ), 1 );
254 //add stretch
255 static_cast<KHBox *>(mainWidget())->setStretchFactor(new QWidget(mainWidget()), 1);
257 connect( m_matchAnyCheck, SIGNAL( toggled(bool) ), m_criteriaAnyGroupBox, SLOT( setEnabled(bool) ) );
258 connect( m_matchAllCheck, SIGNAL( toggled(bool) ), m_criteriaAllGroupBox, SLOT( setEnabled(bool) ) );
259 connect( m_orderCheck, SIGNAL( toggled(bool) ), orderBox, SLOT( setEnabled(bool) ) );
260 connect( m_limitCheck, SIGNAL( toggled(bool) ), limitBox, SLOT( setEnabled(bool) ) );
261 connect( m_expandCheck, SIGNAL( toggled(bool) ), expandBox, SLOT( setEnabled(bool) ) );
262 connect( m_orderCombo, SIGNAL( activated(int) ), this, SLOT( updateOrderTypes(int) ) );
264 m_criteriaAnyGroupBox->setEnabled( false );
265 m_criteriaAllGroupBox->setEnabled( false );
267 orderBox->setEnabled( false );
268 limitBox->setEnabled( false );
269 expandBox->setEnabled( false );
271 m_nameLineEdit->setFocus();
273 resize( 550, 200 );
277 void SmartPlaylistEditor::addCriteriaAny()
279 CriteriaEditor *criteria= new CriteriaEditor( this, m_criteriaAnyGroupBox, criteriaAny );
280 m_criteriaEditorAnyList.append( criteria );
281 m_criteriaEditorAnyList.first()->enableRemove( m_criteriaEditorAnyList.count() > 1 );
284 void SmartPlaylistEditor::addCriteriaAll()
286 CriteriaEditor *criteria= new CriteriaEditor( this, m_criteriaAllGroupBox, criteriaAll );
287 m_criteriaEditorAllList.append( criteria );
288 m_criteriaEditorAllList.first()->enableRemove( m_criteriaEditorAllList.count() > 1 );
291 void SmartPlaylistEditor::addCriteriaAny( QDomElement &xml )
293 CriteriaEditor *criteria = new CriteriaEditor( this, m_criteriaAnyGroupBox, criteriaAny, xml );
294 m_criteriaEditorAnyList.append( criteria );
295 m_criteriaEditorAnyList.first()->enableRemove( m_criteriaEditorAnyList.count() > 1 );
298 void SmartPlaylistEditor::addCriteriaAll( QDomElement &xml )
300 CriteriaEditor *criteria = new CriteriaEditor( this, m_criteriaAllGroupBox, criteriaAll, xml );
301 m_criteriaEditorAllList.append( criteria );
302 m_criteriaEditorAllList.first()->enableRemove( m_criteriaEditorAllList.count() > 1 );
305 void SmartPlaylistEditor::removeCriteriaAny( CriteriaEditor *criteria )
307 m_criteriaEditorAnyList.remove( criteria );
308 criteria->deleteLater();
309 resize( size().width(), sizeHint().height() );
311 if( m_criteriaEditorAnyList.count() == 1 )
312 m_criteriaEditorAnyList.first()->enableRemove( false );
315 void SmartPlaylistEditor::removeCriteriaAll( CriteriaEditor *criteria )
317 m_criteriaEditorAllList.remove( criteria );
318 criteria->deleteLater();
319 resize( size().width(), sizeHint().height() );
321 if( m_criteriaEditorAllList.count() == 1 )
322 m_criteriaEditorAllList.first()->enableRemove( false );
325 void SmartPlaylistEditor::updateOrderTypes( int index )
327 int currentOrderType = m_orderTypeCombo->currentIndex();
328 if( index == m_orderCombo->count()-1 ) { // random order selected
329 m_orderTypeCombo->clear();
330 m_orderTypeCombo->addItem( i18n("Completely Random") );
331 m_orderTypeCombo->addItem( i18n("Score Weighted") );
332 m_orderTypeCombo->addItem( i18n("Rating Weighted") );
334 else { // ordinary order column selected
335 m_orderTypeCombo->clear();
336 m_orderTypeCombo->addItem( i18n("Ascending") );
337 m_orderTypeCombo->addItem( i18n("Descending") );
339 if( currentOrderType < m_orderTypeCombo->count() )
340 m_orderTypeCombo->setCurrentIndex( currentOrderType );
341 m_orderTypeCombo->setFont(m_orderTypeCombo->font()); // invalidate size hint
342 m_orderTypeCombo->updateGeometry();
345 QDomElement SmartPlaylistEditor::result()
347 QDomDocument doc;
348 QDomNode node = doc.namedItem( "smartplaylists" );
349 QDomElement nodeE;
350 nodeE = node.toElement();
352 QDomElement smartplaylist = doc.createElement( "smartplaylist" );
354 smartplaylist.setAttribute( "name", name() );
356 // Limit
357 if ( m_limitCheck->isChecked() )
358 smartplaylist.setAttribute( "maxresults", m_limitSpin->value() );
360 nodeE.appendChild( smartplaylist );
361 // Matches
362 if( m_matchAnyCheck->isChecked() )
364 QDomElement matches = doc.createElement("matches");
365 smartplaylist.appendChild( matches );
366 // Iterate through all criteria list
367 CriteriaEditor *criteriaeditor = m_criteriaEditorAnyList.first();
368 for( int i=0; criteriaeditor; criteriaeditor = m_criteriaEditorAnyList.next(), ++i )
369 matches.appendChild( doc.importNode( criteriaeditor->getDomSearchCriteria( doc ), true ) );
371 matches.setAttribute( "glue", "OR" );
372 smartplaylist.appendChild( matches );
375 if( m_matchAllCheck->isChecked() )
377 QDomElement matches = doc.createElement("matches");
378 smartplaylist.appendChild( matches );
379 // Iterate through all criteria list
380 CriteriaEditor *criteriaeditor = m_criteriaEditorAllList.first();
381 for( int i=0; criteriaeditor; criteriaeditor = m_criteriaEditorAllList.next(), ++i )
382 matches.appendChild( doc.importNode( criteriaeditor->getDomSearchCriteria( doc ), true ) );
384 matches.setAttribute( "glue", "AND" );
385 smartplaylist.appendChild( matches );
388 // Order By
389 if( m_orderCheck->isChecked() ) {
390 QDomElement orderby = doc.createElement("orderby");
391 if (m_orderCombo->currentIndex() != m_orderCombo->count()-1) {
392 orderby.setAttribute( "field", m_dbFields[ m_orderCombo->currentIndex() ] );
393 orderby.setAttribute( "order", m_orderTypeCombo->currentIndex() == 1 ? "DESC" : "ASC" );
394 } else {
395 orderby.setAttribute( "field", "random" );
396 QString order;
397 if ( m_orderTypeCombo->currentIndex() == 0 )
398 order = "random";
399 else if ( m_orderTypeCombo->currentIndex() == 1 )
400 order = "weighted";
401 else
402 order = "ratingweighted";
403 orderby.setAttribute( "order", order );
406 smartplaylist.appendChild( orderby );
409 if( m_expandCheck->isChecked() ) {
410 QDomElement expandBy = doc.createElement("expandby");
411 expandBy.setAttribute( "field", m_expandableFields[ m_expandCombo->currentIndex() ] );
412 smartplaylist.appendChild( expandBy );
415 return (smartplaylist);
418 /////////////////////////////////////////////////////////////////////////////
419 // CLASS CriteriaEditor
420 ////////////////////////////////////////////////////////////////////////////
422 CriteriaEditor::CriteriaEditor( SmartPlaylistEditor *editor, QWidget *parent, int criteriaType, QDomElement criteria )
423 : KHBox( parent )
424 , m_playlistEditor( editor )
425 , m_currentValueType( -1 )
427 setSpacing( 5 );
429 m_fieldCombo = new KComboBox( this );
430 m_fieldCombo->insertItems( 0, m_fields );
432 m_criteriaCombo = new KComboBox( this );
434 m_editBox = new KHBox( this );
435 m_editBox->setSpacing( 5 );
436 setStretchFactor( m_editBox, 1 );
438 m_addButton = new QToolButton( this );
439 m_addButton->setToolButtonStyle( Qt::ToolButtonTextOnly );
440 m_addButton->setText( "+" );
441 m_removeButton = new QToolButton( this );
442 m_removeButton->setToolButtonStyle( Qt::ToolButtonTextOnly );
443 m_removeButton->setText( "-" );
445 connect( m_fieldCombo, SIGNAL( activated(int) ), SLOT( slotFieldSelected(int) ) );
446 connect( m_criteriaCombo, SIGNAL( activated(int) ), SLOT( loadEditWidgets() ) );
447 if (criteriaType == SmartPlaylistEditor::criteriaAny) {
448 connect( m_addButton, SIGNAL( clicked() ), editor, SLOT( addCriteriaAny() ) );
449 connect( m_removeButton, SIGNAL( clicked() ), SLOT( slotRemoveCriteriaAny() ) );
451 else {
452 connect( m_addButton, SIGNAL( clicked() ), editor, SLOT( addCriteriaAll() ) );
453 connect( m_removeButton, SIGNAL( clicked() ), SLOT( slotRemoveCriteriaAll() ) );
456 if ( !criteria.isNull() ) {
457 int field = m_dbFields.indexOf( criteria.attribute( "field" ) );
458 QString condition = criteria.attribute("condition");
461 QStringList values; //List of the values (only one item, unless condition is "is between")
462 QDomNodeList domvalueList = criteria.elementsByTagName( "value" );
463 for (int j = 0, c=domvalueList.count() ; j<c; ++j ) {
464 values << domvalueList.item(j).toElement().text();
467 //Set the selected field
469 m_fieldCombo->setCurrentIndex( field );
470 slotFieldSelected( field );
471 int valueType = getValueType( field );
472 //Load the right set of criterias for this type, in the dialog
473 loadCriteriaList( valueType, condition );
475 loadEditWidgets();
477 switch( valueType ) {
478 case String: //fall through
479 case AutoCompletionString:
481 m_lineEdit->setText( values.first() );
482 break;
484 case Year: //fall through
485 case Number:
487 m_intSpinBox1->setValue( values.first().toInt() );
488 if( condition == i18n("is between") )
489 m_intSpinBox2->setValue( values.last().toInt() );
490 break;
492 case Rating:
494 m_comboBox->setCurrentIndex( ratingToIndex( values.first().toInt() ) );
495 if( condition == i18n("is between") )
496 m_comboBox2->setCurrentIndex( ratingToIndex( values.last().toInt() ) );
497 break;
499 case Date:
501 if( condition == i18n("is in the last") || condition == i18n("is not in the last") ) {
502 m_intSpinBox1->setValue( values.first().toInt() );
503 QString period = criteria.attribute("period");
504 if (period=="days" || period.isEmpty() )
505 m_dateCombo->setCurrentIndex(0);
506 else if (period=="months")
507 m_dateCombo->setCurrentIndex(1);
508 else
509 m_dateCombo->setCurrentIndex(2);
511 else {
512 QDateTime dt;
513 dt.setTime_t( values.first().toUInt() );
514 m_dateEdit1->setDate( dt.date() );
515 if( condition == i18n("is between") ) {
516 dt.setTime_t( values.last().toUInt() );
517 m_dateEdit2->setDate( dt.date() );
520 break;
522 case Length:
524 m_intSpinBox1->setValue( values.first().toInt() );
525 if( condition == i18n("is between") )
526 m_intSpinBox2->setValue( values.last().toInt() );
527 QString period = criteria.attribute( "period" );
528 if ( period == "seconds" || period.isEmpty() ) //for compatibility
529 m_lengthCombo->setCurrentIndex( 0 );
530 else if ( period == "minutes" )
531 m_lengthCombo->setCurrentIndex( 1 );
532 else
533 m_lengthCombo->setCurrentIndex( 2 );
534 break;
536 default: ;
539 else
540 slotFieldSelected( 0 );
541 show();
545 CriteriaEditor::~CriteriaEditor()
549 QDomElement CriteriaEditor::getDomSearchCriteria( QDomDocument &doc )
551 QDomElement criteria = doc.createElement( "criteria" );
552 QString field = m_dbFields[ m_fieldCombo->currentIndex() ];
553 QString condition = m_criteriaCombo->currentText();
555 criteria.setAttribute( "condition", condition );
556 criteria.setAttribute( "field", field );
558 QStringList values;
559 // Get the proper value(s)
560 switch( getValueType( m_fieldCombo->currentIndex() ) ) {
561 case String: // fall through
562 case AutoCompletionString:
563 values << m_lineEdit->text();
564 break;
565 case Year: // fall through
566 case Number:
568 values << QString::number( m_intSpinBox1->value() );
569 if( condition == i18n("is between") )
570 values << QString::number( m_intSpinBox2->value() );
571 break;
573 case Rating:
575 values << QString::number( indexToRating( m_comboBox->currentIndex() ) );
576 if( condition == i18n("is between") )
577 values << QString::number( indexToRating( m_comboBox2->currentIndex() ) );
578 break;
580 case Date:
582 if( condition == i18n("is in the last") || condition == i18n("is not in the last") ) {
583 values << QString::number( m_intSpinBox1->value() );
584 // 0 = days; 1=months; 2=years
585 criteria.setAttribute( "period", !m_dateCombo->currentIndex() ? "days" : (m_dateCombo->currentIndex() == 1 ? "months" : "years") );
587 else {
588 values << QString::number( QDateTime( m_dateEdit1->date() ).toTime_t() );
589 if( condition == i18n("is between") ) {
590 values << QString::number( QDateTime( m_dateEdit2->date() ).toTime_t() );
593 break;
595 case Length:
597 values << QString::number( m_intSpinBox1->value() );
598 // 0 = seconds, 1=minutes, 2=hours
599 criteria.setAttribute( "period", !m_lengthCombo->currentIndex() ? "seconds" : (m_lengthCombo->currentIndex() == 1 ? "minutes" : "hours") );
600 if( condition == i18n( "is between" ) ) {
601 values << QString::number( m_intSpinBox2->value() );
603 break;
605 default: ;
607 oldForeach( values ) {
608 QDomElement value = doc.createElement( "value" );
609 QDomText t = doc.createTextNode( *it );
610 value.appendChild( t );
611 criteria.appendChild( value );
613 return (criteria);
617 QString CriteriaEditor::getSearchCriteria()
619 QString searchCriteria;
620 QString field = m_dbFields[ m_fieldCombo->currentIndex() ];
621 QString criteria = m_criteriaCombo->currentText();
623 if( field.isEmpty() )
624 return QString();
626 if ( ( field=="statistics.playcounter" || field=="statistics.rating" || field=="statistics.percentage" || field=="statistics.accessdate" || field=="statistics.createdate") )
627 searchCriteria += "COALESCE(" + field + ",0)";
628 else
629 searchCriteria += field;
631 QString value;
632 switch( getValueType( m_fieldCombo->currentIndex() ) ) {
633 case String:
634 case AutoCompletionString:
635 value = m_lineEdit->text();
636 break;
637 case Year: //fall through
638 case Number:
639 value = QString::number( m_intSpinBox1->value() );
640 if( criteria == i18n("is between") )
641 value += " AND " + QString::number( m_intSpinBox2->value() );
642 break;
643 case Rating:
645 value = QString::number( indexToRating( m_comboBox->currentIndex() ) );
646 if( criteria == i18n("is between") )
647 value += " AND " + QString::number( indexToRating( m_comboBox2->currentIndex() ) );
648 break;
650 case Date:
652 if( criteria == i18n("is in the last") || criteria == i18n("is not in the last") ) {
653 int n = m_intSpinBox1->value();
654 int time;
655 if( m_dateCombo->currentIndex() == 0 ) //days
656 time=86400*n;
657 else if( m_dateCombo->currentIndex() == 1 ) //months
658 time=86400*30*n;
659 else time=86400*365*n; //years
660 value += "(*CurrentTimeT*)" + QString(" - %1 AND ").arg(time) + "(*CurrentTimeT*)";
662 else {
663 QDateTime datetime1( m_dateEdit1->date() );
664 value += QString::number( datetime1.toTime_t() );
665 if( criteria == i18n("is between") ) {
666 QDateTime datetime2( m_dateEdit2->date() );
667 value += " AND " + QString::number( datetime2.toTime_t() );
669 else
670 value += " AND " + QString::number( datetime1.addDays( 1 ).toTime_t() );
672 break;
674 case Length:
676 int n = m_intSpinBox1->value();
677 int time;
678 if( m_lengthCombo->currentIndex() == 0 ) //seconds
679 time = n;
680 else if( m_lengthCombo->currentIndex() == 1 ) //minutes
681 time = 60*n;
682 else
683 time = 3600*n; //hours
684 value = QString::number( time );
685 if( criteria == i18n("is between") ) {
686 int n2 = m_intSpinBox2->value();
687 int time2;
688 if( m_lengthCombo->currentIndex() == 0 ) //seconds
689 time2 = n2;
690 else if( m_lengthCombo->currentIndex() == 1 ) //minutes
691 time2 = 60*n2;
692 else
693 time2 = 3600*n2; //hours
694 value += " AND " + QString::number( time2 );
696 break;
698 default: ;
702 if( criteria == i18n("contains") )
703 searchCriteria += CollectionDB::likeCondition( value, true, true );
704 else if( criteria == i18n("does not contain") )
705 searchCriteria += " NOT " + CollectionDB::likeCondition( value, true, true );
706 else if( criteria == i18n("is") ) {
707 if( m_currentValueType == Date )
708 searchCriteria += " BETWEEN ";
709 else
710 searchCriteria += " = ";
711 if( m_currentValueType == String || m_currentValueType == AutoCompletionString )
712 value.prepend("'").append("'");
713 searchCriteria += value;
715 else if( criteria == i18n("is not") ) {
716 if( m_currentValueType == Date )
717 searchCriteria += " NOT BETWEEN ";
718 else
719 searchCriteria += " <> ";
720 if( m_currentValueType == String || m_currentValueType == AutoCompletionString )
721 value.prepend("'").append("'");
722 searchCriteria += value;
724 else if( criteria == i18n("starts with") )
726 if( field == "tags.url" )
728 if( value.startsWith( '/' ) )
729 value = '.' + value;
730 if( !value.startsWith( "./" ) )
731 value = "./" + value;
733 searchCriteria += CollectionDB::likeCondition( value, false, true );
735 else if( criteria == i18n("does not start with") )
737 if( field == "tags.url" )
739 if( value.startsWith( '/' ) )
740 value = '.' + value;
741 if( !value.startsWith( "./" ) )
742 value = "./" + value;
744 searchCriteria += " NOT " + CollectionDB::likeCondition( value, false, true );
746 else if( criteria == i18n("ends with") )
747 searchCriteria += CollectionDB::likeCondition( value, true, false );
748 else if( criteria == i18n("does not end with") )
749 searchCriteria += " NOT " + CollectionDB::likeCondition( value, true, false );
750 else if( criteria == i18n("is greater than") || criteria == i18n("is after") )
751 searchCriteria += " > " + value;
752 else if( criteria == i18n("is smaller than") || criteria == i18n("is before" ) )
753 searchCriteria += " < " + value;
754 else if( criteria == i18n("is between") || criteria == i18n("is in the last") )
755 searchCriteria += " BETWEEN " + value;
756 else if( criteria == i18n("is not in the last") )
757 searchCriteria += " NOT BETWEEN " + value;
759 return searchCriteria;
763 void CriteriaEditor::setSearchCriteria( const QString & )
765 //TODO
769 void CriteriaEditor::enableRemove( bool enable )
771 m_removeButton->setEnabled( enable );
775 void CriteriaEditor::slotRemoveCriteriaAny()
777 m_playlistEditor->removeCriteriaAny( this );
780 void CriteriaEditor::slotRemoveCriteriaAll()
782 m_playlistEditor->removeCriteriaAll( this );
785 void CriteriaEditor::slotAddCriteriaAny()
787 m_playlistEditor->addCriteriaAny();
790 void CriteriaEditor::slotAddCriteriaAll()
792 m_playlistEditor->addCriteriaAll();
795 void CriteriaEditor::slotFieldSelected( int field )
797 int valueType = getValueType( field );
798 loadCriteriaList( valueType );
799 loadEditWidgets();
800 m_currentValueType = valueType;
802 //enable auto-completion for artist, album, composer, label, mountpoint and genre
803 if( valueType == AutoCompletionString ) {
804 QStringList items;
805 m_comboBox->clear();
806 m_comboBox->completionObject()->clear();
808 int currentField = m_fieldCombo->currentIndex();
809 if( currentField == FArtist ) //artist
810 items = CollectionDB::instance()->artistList();
811 else if( currentField == FComposer ) //composer
812 items = CollectionDB::instance()->composerList();
813 else if( currentField == FAlbum ) //album
814 items = CollectionDB::instance()->albumList();
815 else if (currentField == FLabel ) //label
816 items = CollectionDB::instance()->labelList();
817 else if (currentField == FMountPoint ) //mount point
819 KMountPoint::List mountpoints = KMountPoint::currentMountPoints( KMountPoint::NeedRealDeviceName );
820 oldForeachType( KMountPoint::List, mountpoints )
822 /* This code is adapted from KDE mediamanager's fstabbackend.cpp
823 * Copyright Kévin Ottens, Bernhard Rosenkraenzer, and from looking
824 * at the commit messages a few other guys who didn't add their name to the header.
826 QString device = (*it)->realDeviceName();
827 QString fs = (*it)->mountType();
828 QString mountpoint = (*it)->mountPoint();
829 if ( fs != "swap"
830 && fs != "tmpfs"
831 && fs != "sysfs"
832 && fs != "fdescfs"
833 && fs != "kernfs"
834 && fs != "usbfs"
835 && !fs.contains( "proc" )
836 && fs != "unknown"
837 && fs != "none"
838 && fs != "sunrpc"
839 && fs != "none"
840 && device != "tmpfs"
841 && device.indexOf("shm") == -1
842 && mountpoint != "/dev/swap"
843 && mountpoint != "/dev/pts"
844 && mountpoint.indexOf("/proc") != 0
845 && mountpoint.indexOf("/sys") != 0
846 || fs.indexOf( "smb" ) != -1
847 || fs.indexOf( "cifs" ) != -1
848 || fs.indexOf( "nfs" ) != -1
850 items << mountpoint;
853 else //genre
854 items = CollectionDB::instance()->genreList();
856 m_comboBox->insertItems( 0, items );
857 m_comboBox->completionObject()->insertItems( items );
858 m_comboBox->completionObject()->setIgnoreCase( true );
859 m_comboBox->setItemText( m_comboBox->currentIndex(), "" );
860 m_comboBox->setFocus();
865 void CriteriaEditor::loadEditWidgets()
867 int valueType = getValueType( m_fieldCombo->currentIndex() );
869 if( m_currentValueType == valueType && !(
870 m_criteriaCombo->currentText() == i18n( "is between" ) ||
871 m_criteriaCombo->currentText() == i18n( "is in the last" ) ||
872 m_criteriaCombo->currentText() == i18n( "is not in the last" ) ||
873 m_lastCriteria == i18n( "is between" ) ||
874 m_lastCriteria == i18n( "is in the last" ) ||
875 m_lastCriteria == i18n( "is not in the last" ) ) )
876 return;
878 /* Store lastCriteria. This information is used above to decide whether it's necessary to change the Widgets */
879 m_lastCriteria = m_criteriaCombo->currentText();
881 QList<QWidget *> list = qFindChildren<QWidget *>( m_editBox );
882 foreach( QWidget *w, list )
883 w->deleteLater();
885 switch( valueType ) {
887 case String:
889 m_lineEdit = new KLineEdit( m_editBox );
890 m_lineEdit->setFocus();
891 m_lineEdit->show();
892 break;
895 case AutoCompletionString: //artist, composer, album, genre, label
897 m_comboBox = new KComboBox( true, m_editBox );
898 m_lineEdit = static_cast<KLineEdit*>( m_comboBox->lineEdit() );
899 m_lineEdit->setFocus();
900 m_comboBox->setMinimumSize( QSize( 240, 20 ) );
901 m_comboBox->show();
902 break;
905 case Year: //fall through
906 case Number:
908 bool yearField = m_fieldCombo->currentText() == i18n("Year");
910 m_intSpinBox1 = new QSpinBox( m_editBox );
911 int maxValue = 1000;
912 if( yearField ) {
913 maxValue = QDate::currentDate().year();
914 m_intSpinBox1->setValue( maxValue );
916 m_intSpinBox1->setMaximum( maxValue );
917 m_intSpinBox1->setFocus();
918 m_intSpinBox1->show();
920 if( m_criteriaCombo->currentText() == i18n("is between") ) {
921 m_rangeLabel = new QLabel( i18n("and"), m_editBox );
922 m_rangeLabel->setAlignment( Qt::AlignHCenter );
923 m_rangeLabel->show();
924 m_intSpinBox2 = new QSpinBox( m_editBox );
925 if( yearField ) {
926 maxValue = QDate::currentDate().year();
927 m_intSpinBox2->setValue( maxValue );
929 m_intSpinBox2->setMaximum( maxValue );
930 m_intSpinBox2->show();
932 break;
935 case Rating:
937 const QStringList list = MetaBundle::ratingList();
938 m_comboBox = new KComboBox( false, m_editBox );
939 m_comboBox->insertItems( 0, list );
940 m_comboBox->show();
942 if( m_criteriaCombo->currentText() == i18n("is between") ) {
943 m_rangeLabel = new QLabel( i18n("and"), m_editBox );
944 m_rangeLabel->setAlignment( Qt::AlignHCenter );
945 m_rangeLabel->show();
946 m_comboBox2 = new KComboBox( false, m_editBox );
947 m_comboBox2->insertItems( 0, list );
948 m_comboBox2->show();
950 break;
953 case Date:
955 if( m_criteriaCombo->currentText() == i18n("is in the last") ||
956 m_criteriaCombo->currentText() == i18n("is not in the last") ) {
957 m_intSpinBox1 = new QSpinBox( m_editBox );
958 m_intSpinBox1->setMinimum( 1 );
959 m_intSpinBox1->show();
960 m_dateCombo = new KComboBox( m_editBox );
961 m_dateCombo->addItem( i18n("Days") );
962 m_dateCombo->addItem( i18n("Months") );
963 m_dateCombo->addItem( i18n("Years") );
964 m_dateCombo->show();
966 else {
967 m_dateEdit1 = new Q3DateEdit( QDate::currentDate(), m_editBox);
968 m_dateEdit1->setFocus();
969 m_dateEdit1->show();
970 if( m_criteriaCombo->currentText() == i18n("is between") ) {
971 m_rangeLabel = new QLabel( i18n("and"), m_editBox );
972 m_rangeLabel->setAlignment( Qt::AlignHCenter );
973 m_rangeLabel->show();
974 m_dateEdit2 = new Q3DateEdit( QDate::currentDate(), m_editBox);
975 m_dateEdit2->show();
979 break;
982 case Length:
984 m_intSpinBox1 = new QSpinBox( m_editBox );
985 int maxValue = 1000;
986 m_intSpinBox1->setMaximum( maxValue );
987 m_intSpinBox1->setFocus();
988 m_intSpinBox1->show();
989 if( m_criteriaCombo->currentText() == i18n("is between") ) {
990 m_rangeLabel = new QLabel( i18n("and"), m_editBox );
991 m_rangeLabel->setAlignment( Qt::AlignHCenter );
992 m_rangeLabel->show();
993 m_intSpinBox2 = new QSpinBox( m_editBox );
994 m_intSpinBox2->setMaximum( maxValue );
995 m_intSpinBox2->show();
997 m_lengthCombo = new KComboBox( m_editBox );
998 m_lengthCombo->addItem( i18n( "Seconds" ) );
999 m_lengthCombo->addItem( i18n( "Minutes" ) );
1000 m_lengthCombo->addItem( i18n( "Hours" ) );
1001 m_lengthCombo->show();
1004 default: ;
1010 void CriteriaEditor::loadCriteriaList( int valueType, QString condition )
1012 if( m_currentValueType == valueType && condition.isNull() )
1013 return;
1015 QStringList items;
1017 switch( valueType ) {
1018 case String:
1019 case AutoCompletionString:
1020 items << i18n( "contains" ) << i18n( "does not contain" ) << i18n( "is" ) << i18n( "is not" )
1021 << i18n( "starts with" ) << i18n( "does not start with" )
1022 << i18n( "ends with" ) << i18n( "does not end with" );
1023 break;
1025 case Rating:
1026 case Length:
1027 case Number:
1028 items << i18n( "is" ) << i18n( "is not" ) << i18n( "is greater than" ) << i18n( "is smaller than" )
1029 << i18n( "is between" );
1030 break;
1032 case Year: //fall through
1033 case Date:
1034 items << i18n( "is" ) << i18n( "is not" ) << i18n( "is before" ) << i18n( "is after" )
1035 << i18n( "is in the last" ) << i18n( "is not in the last" ) << i18n( "is between" );
1036 break;
1037 default: ;
1040 m_criteriaCombo->clear();
1041 m_criteriaCombo->insertItems( 0, items );
1043 if( !condition.isEmpty() )
1045 int index = items.indexOf( condition );
1046 if( index != -1 )
1047 m_criteriaCombo->setCurrentIndex( index );
1052 int CriteriaEditor::getValueType( int index )
1054 int valueType;
1056 switch( index ) {
1057 case FArtist:
1058 case FComposer:
1059 case FAlbum:
1060 case FGenre:
1061 case FLabel:
1062 case FMountPoint:
1063 valueType = AutoCompletionString;
1064 break;
1065 case FTitle:
1066 case FComment:
1067 case FFilePath:
1068 valueType = String;
1069 break;
1070 case FLength:
1071 valueType = Length;
1072 break;
1073 case FTrack:
1074 case FScore:
1075 case FPlayCounter:
1076 case FBPM:
1077 case FBitRate:
1078 valueType = Number;
1079 break;
1080 case FRating:
1081 valueType = Rating;
1082 break;
1083 case FYear:
1084 valueType = Year;
1085 break;
1086 default: valueType = Date;
1089 return valueType;
1093 #include "smartplaylisteditor.moc"