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
13 #include "querybuilder.h"
14 #include "metabundle.h"
15 #include "mountpointmanager.h"
20 #include <kmountpoint.h>
26 #include <q3datetimeedit.h> //loadEditWidgets()
31 #include <QStringList>
32 #include <QToolButton>
33 #include <q3vgroupbox.h>
62 QStringList m_dbFields
;
63 QStringList m_expandableFields
;
64 QStringList m_expandableDbFields
;
68 SmartPlaylistEditor::SmartPlaylistEditor( QString defaultName
, QWidget
*parent
, const char *name
)
71 setObjectName( name
);
72 setCaption( i18n("Create Smart Playlist") );
74 setButtons( Ok
| Cancel
);
75 setDefaultButton( Ok
);
76 showButtonSeparator( true );
84 SmartPlaylistEditor::SmartPlaylistEditor( QWidget
*parent
, QDomElement xml
, const char *name
)
87 setObjectName( name
);
88 setCaption( i18n("Edit Smart Playlist") );
90 setButtons( Ok
| Cancel
);
91 setDefaultButton( Ok
);
92 showButtonSeparator( true );
95 init( xml
.attribute( "name" ) );
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") {
113 addCriteriaAny( criteria
);
117 addCriteriaAll( criteria
);
125 m_matchAllCheck
->setChecked( false );
129 m_matchAnyCheck
->setChecked( false );
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 );
149 m_orderTypeCombo
->setCurrentIndex( 0 );
152 if ( xml
.hasAttribute( "maxresults" ) ) {
153 m_limitCheck
->setChecked( true );
154 m_limitSpin
->setValue( xml
.attribute( "maxresults" ).toInt() );
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
);
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" );
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
);
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 );
209 m_criteriaAnyGroupBox
= new Q3VGroupBox( QString(), mainWidget() );
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 );
217 m_criteriaAllGroupBox
= new Q3VGroupBox( QString(), mainWidget() );
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 );
225 m_orderCombo
= new KComboBox( orderBox
);
226 m_orderCombo
->insertItems( 0, m_fields
);
227 m_orderCombo
->addItem( i18n("Random") );
229 m_orderTypeCombo
= new KComboBox( orderBox
);
230 updateOrderTypes(0); // populate the new m_orderTypeCombo
231 hbox2
->setStretchFactor( new QWidget( hbox2
), 1 );
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 );
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 );
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();
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()
348 QDomNode node
= doc
.namedItem( "smartplaylists" );
350 nodeE
= node
.toElement();
352 QDomElement smartplaylist
= doc
.createElement( "smartplaylist" );
354 smartplaylist
.setAttribute( "name", name() );
357 if ( m_limitCheck
->isChecked() )
358 smartplaylist
.setAttribute( "maxresults", m_limitSpin
->value() );
360 nodeE
.appendChild( smartplaylist
);
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
);
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" );
395 orderby
.setAttribute( "field", "random" );
397 if ( m_orderTypeCombo
->currentIndex() == 0 )
399 else if ( m_orderTypeCombo
->currentIndex() == 1 )
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
)
424 , m_playlistEditor( editor
)
425 , m_currentValueType( -1 )
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() ) );
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
);
477 switch( valueType
) {
478 case String
: //fall through
479 case AutoCompletionString
:
481 m_lineEdit
->setText( values
.first() );
484 case Year
: //fall through
487 m_intSpinBox1
->setValue( values
.first().toInt() );
488 if( condition
== i18n("is between") )
489 m_intSpinBox2
->setValue( values
.last().toInt() );
494 m_comboBox
->setCurrentIndex( ratingToIndex( values
.first().toInt() ) );
495 if( condition
== i18n("is between") )
496 m_comboBox2
->setCurrentIndex( ratingToIndex( values
.last().toInt() ) );
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);
509 m_dateCombo
->setCurrentIndex(2);
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() );
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 );
533 m_lengthCombo
->setCurrentIndex( 2 );
540 slotFieldSelected( 0 );
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
);
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();
565 case Year
: // fall through
568 values
<< QString::number( m_intSpinBox1
->value() );
569 if( condition
== i18n("is between") )
570 values
<< QString::number( m_intSpinBox2
->value() );
575 values
<< QString::number( indexToRating( m_comboBox
->currentIndex() ) );
576 if( condition
== i18n("is between") )
577 values
<< QString::number( indexToRating( m_comboBox2
->currentIndex() ) );
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") );
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() );
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() );
607 oldForeach( values
) {
608 QDomElement value
= doc
.createElement( "value" );
609 QDomText t
= doc
.createTextNode( *it
);
610 value
.appendChild( t
);
611 criteria
.appendChild( value
);
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() )
626 if ( ( field
=="statistics.playcounter" || field
=="statistics.rating" || field
=="statistics.percentage" || field
=="statistics.accessdate" || field
=="statistics.createdate") )
627 searchCriteria
+= "COALESCE(" + field
+ ",0)";
629 searchCriteria
+= field
;
632 switch( getValueType( m_fieldCombo
->currentIndex() ) ) {
634 case AutoCompletionString
:
635 value
= m_lineEdit
->text();
637 case Year
: //fall through
639 value
= QString::number( m_intSpinBox1
->value() );
640 if( criteria
== i18n("is between") )
641 value
+= " AND " + QString::number( m_intSpinBox2
->value() );
645 value
= QString::number( indexToRating( m_comboBox
->currentIndex() ) );
646 if( criteria
== i18n("is between") )
647 value
+= " AND " + QString::number( indexToRating( m_comboBox2
->currentIndex() ) );
652 if( criteria
== i18n("is in the last") || criteria
== i18n("is not in the last") ) {
653 int n
= m_intSpinBox1
->value();
655 if( m_dateCombo
->currentIndex() == 0 ) //days
657 else if( m_dateCombo
->currentIndex() == 1 ) //months
659 else time
=86400*365*n
; //years
660 value
+= "(*CurrentTimeT*)" + QString(" - %1 AND ").arg(time
) + "(*CurrentTimeT*)";
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() );
670 value
+= " AND " + QString::number( datetime1
.addDays( 1 ).toTime_t() );
676 int n
= m_intSpinBox1
->value();
678 if( m_lengthCombo
->currentIndex() == 0 ) //seconds
680 else if( m_lengthCombo
->currentIndex() == 1 ) //minutes
683 time
= 3600*n
; //hours
684 value
= QString::number( time
);
685 if( criteria
== i18n("is between") ) {
686 int n2
= m_intSpinBox2
->value();
688 if( m_lengthCombo
->currentIndex() == 0 ) //seconds
690 else if( m_lengthCombo
->currentIndex() == 1 ) //minutes
693 time2
= 3600*n2
; //hours
694 value
+= " AND " + QString::number( time2
);
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 ";
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 ";
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( '/' ) )
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( '/' ) )
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
& )
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
);
800 m_currentValueType
= valueType
;
802 //enable auto-completion for artist, album, composer, label, mountpoint and genre
803 if( valueType
== AutoCompletionString
) {
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();
835 && !fs
.contains( "proc" )
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
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" ) ) )
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
)
885 switch( valueType
) {
889 m_lineEdit
= new KLineEdit( m_editBox
);
890 m_lineEdit
->setFocus();
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 ) );
905 case Year
: //fall through
908 bool yearField
= m_fieldCombo
->currentText() == i18n("Year");
910 m_intSpinBox1
= new QSpinBox( m_editBox
);
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
);
926 maxValue
= QDate::currentDate().year();
927 m_intSpinBox2
->setValue( maxValue
);
929 m_intSpinBox2
->setMaximum( maxValue
);
930 m_intSpinBox2
->show();
937 const QStringList list
= MetaBundle::ratingList();
938 m_comboBox
= new KComboBox( false, m_editBox
);
939 m_comboBox
->insertItems( 0, list
);
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
);
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") );
967 m_dateEdit1
= new Q3DateEdit( QDate::currentDate(), m_editBox
);
968 m_dateEdit1
->setFocus();
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
);
984 m_intSpinBox1
= new QSpinBox( m_editBox
);
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();
1010 void CriteriaEditor::loadCriteriaList( int valueType
, QString condition
)
1012 if( m_currentValueType
== valueType
&& condition
.isNull() )
1017 switch( valueType
) {
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" );
1028 items
<< i18n( "is" ) << i18n( "is not" ) << i18n( "is greater than" ) << i18n( "is smaller than" )
1029 << i18n( "is between" );
1032 case Year
: //fall through
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" );
1040 m_criteriaCombo
->clear();
1041 m_criteriaCombo
->insertItems( 0, items
);
1043 if( !condition
.isEmpty() )
1045 int index
= items
.indexOf( condition
);
1047 m_criteriaCombo
->setCurrentIndex( index
);
1052 int CriteriaEditor::getValueType( int index
)
1063 valueType
= AutoCompletionString
;
1086 default: valueType
= Date
;
1093 #include "smartplaylisteditor.moc"