2 * Kscd - A simple cd player for the KDE Project
4 * Copyright (c) 1997 Bernd Johannes wuebben@math.cornell.edu
5 * Copyright (c) 2002-2003 Aaron J. Seigo <aseigo@kde.org>
6 * Copyright (c) 2004 Alexander Kern <alex.kern@gmx.de>
7 * Copyright (c) 2003-2006 Richard Lärkäng <nouseforaname@home.se>
8 * Copyright (c) 2007 Benjamin K. Stuhl <benjamin.stuhl@colorado.edu>
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2, or (at your option)
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
29 #include "configWidget.h"
30 #include "kcompactdisc.h"
32 #include <config-alsa.h>
34 #include <QCloseEvent>
40 #include <kaboutdata.h>
41 #include <kactioncollection.h>
42 #include <kcmdlineargs.h>
43 #include <khelpmenu.h>
44 #include <kshortcutsdialog.h>
45 #include <kiconloader.h>
46 #include <kinputdialog.h>
47 #include <kmessagebox.h>
50 #include <kstandardaction.h>
51 #include <kstringhandler.h>
52 #include <kuniqueapplication.h>
53 #include <kcmoduleloader.h>
54 #include <ktoolinvocation.h>
56 using namespace KCDDB
;
58 static const char description
[] = I18N_NOOP("KDE CD player");
60 bool stoppedByUser
= true;
63 /****************************************************************************
65 *****************************************************************************/
67 KSCD::KSCD( QWidget
*parent
)
75 QDBusConnection::sessionBus().registerObject("/CDPlayer", this, QDBusConnection::ExportScriptableSlots
);
77 m_cd
= new KCompactDisc();
78 cddbInfo
.clear(); // The first freedb revision is "0" //!!!!
79 cddb
= new KCDDB::Client();
80 connect(cddb
, SIGNAL(finished(KCDDB::Result
)), this, SLOT(lookupCDDBDone(KCDDB::Result
)));
87 timeIcon
->setPixmap(SmallIcon("player-time"));
88 connect(timeSlider
, SIGNAL(sliderPressed()), SLOT(timeSliderPressed()));
89 connect(timeSlider
, SIGNAL(sliderReleased()), SLOT(timeSliderReleased()));
90 connect(timeSlider
, SIGNAL(sliderMoved(int)), SLOT(timeSliderMoved(int)));
91 connect(timeSlider
, SIGNAL(valueChanged(int)), SLOT(jumpToTime(int)));
94 volumeIcon
->setPixmap(SmallIcon("player-volume"));
95 volumeSlider
->setValue(Prefs::volume());
97 connect(volumeSlider
, SIGNAL(valueChanged(int)), SLOT(volChanged(int)));
99 connect(m_cd
, SIGNAL(discChanged(unsigned int)), this, SLOT(discChanged(unsigned int)));
100 connect(m_cd
, SIGNAL(discInformation(KCompactDisc::DiscInfo
)), this, SLOT(discInformation(KCompactDisc::DiscInfo
)));
101 connect(m_cd
, SIGNAL(discStatusChanged(KCompactDisc::DiscStatus
)), this,
102 SLOT(discStatusChanged(KCompactDisc::DiscStatus
)));
104 connect(m_cd
, SIGNAL(playoutTrackChanged(unsigned int)), this, SLOT(trackChanged(unsigned int)));
105 connect(m_cd
, SIGNAL(playoutPositionChanged(unsigned int)), this, SLOT(trackPosition(unsigned int)));
107 connect(&queryledtimer
, SIGNAL(timeout()), SLOT(togglequeryled()) );
108 connect(&titlelabeltimer
, SIGNAL(timeout()), SLOT(titlelabeltimeout()) );
110 connect(playPB
, SIGNAL(clicked()), SLOT(playClicked()) );
111 connect(nextPB
, SIGNAL(clicked()), SLOT(nextClicked()) );
112 connect(prevPB
, SIGNAL(clicked()), SLOT(prevClicked()) );
113 connect(stopPB
, SIGNAL(clicked()), SLOT(stopClicked()) );
114 connect(ejectPB
, SIGNAL(clicked()), SLOT(ejectClicked()) );
115 connect(songListCB
, SIGNAL(activated(int)), SLOT(trackSelected(int)));
117 connect(shufflePB
, SIGNAL(clicked()), SLOT(randomClicked()));
118 connect(repeatPB
, SIGNAL(clicked()), SLOT(loopClicked()) );
119 connect(m_cd
, SIGNAL(randomPlaylistChanged(bool)), this, SLOT(randomChanged(bool)));
120 connect(m_cd
, SIGNAL(loopPlaylistChanged(bool)), this, SLOT(loopChanged(bool)));
122 connect(cddbPB
, SIGNAL(clicked()), SLOT(CDDialogSelected()));
123 connect(KGlobalSettings::self(), SIGNAL(kdisplayPaletteChanged()), this, SLOT(setColors()));
124 connect(KGlobalSettings::self(), SIGNAL(iconChanged(int)), this, SLOT(setIcons()));
125 songListCB
->setToolTip(i18n("Track list"));
128 // set up the actions and keyboard accels
129 m_actions
= new KActionCollection(this);
130 m_actions
->setConfigGroup("Shortcuts");
133 action
= m_actions
->addAction(i18n("Play/Pause"), this, SLOT(playClicked()));
134 action
->setShortcut(Qt::Key_P
);
135 qobject_cast
<KAction
*>(action
)->setGlobalShortcut(KShortcut(Qt::META
+ Qt::Key_P
));
137 action
= m_actions
->addAction(i18n("Stop"), this, SLOT(stopClicked()));
138 action
->setShortcut(Qt::Key_S
);
139 qobject_cast
<KAction
*>(action
)->setGlobalShortcut(KShortcut(Qt::META
+ Qt::Key_S
));
141 action
= m_actions
->addAction(i18n("Previous"), this, SLOT(prevClicked()));
142 action
->setShortcut(Qt::Key_B
);
143 //NOTE: WIN+B collidates with amarok's default global shortcut.
144 qobject_cast
<KAction
*>(action
)->setGlobalShortcut(KShortcut(Qt::META
+ Qt::Key_B
));
146 action
= m_actions
->addAction(i18n("Next"), this, SLOT(nextClicked()));
147 action
->setShortcut(Qt::Key_N
);
148 qobject_cast
<KAction
*>(action
)->setGlobalShortcut(KShortcut(Qt::META
+ Qt::Key_N
));
150 action
= m_actions
->addAction(KStandardAction::Quit
, this, SLOT(quitClicked()));
152 action
= m_actions
->addAction(KStandardAction::KeyBindings
, this, SLOT(configureKeys()));
154 action
= m_actions
->addAction(KStandardAction::Preferences
, this, SLOT(showConfig()));
156 action
= m_actions
->addAction(i18n("Loop"), this, SLOT(loopClicked()));
157 action
->setShortcut(Qt::Key_L
);
158 action
= m_actions
->addAction(i18n("Eject"), this, SLOT(ejectClicked()));
159 action
->setShortcut(Qt::CTRL
+ Qt::Key_E
);
160 action
= m_actions
->addAction(i18n("Increase Volume"), this, SLOT(incVolume()));
161 action
->setShortcuts(KShortcut(QKeySequence(Qt::Key_Plus
), QKeySequence(Qt::Key_Equal
)));
162 qobject_cast
<KAction
*>(action
)->setGlobalShortcut(KShortcut(Qt::META
+ Qt::Key_Plus
));
164 action
= m_actions
->addAction(i18n("Decrease Volume"), this, SLOT(decVolume()));
165 action
->setShortcut(Qt::Key_Minus
);
166 qobject_cast
<KAction
*>(action
)->setGlobalShortcut(KShortcut(Qt::META
+ Qt::Key_Minus
));
168 action
= m_actions
->addAction(i18n("Options"), this, SLOT(showConfig()));
169 action
->setShortcut(Qt::CTRL
+ Qt::Key_T
);
170 action
= m_actions
->addAction(i18n("Shuffle"), this, SLOT(randomClicked()));
171 action
->setShortcut(Qt::Key_R
);
172 qobject_cast
<KAction
*>(action
)->setGlobalShortcut(KShortcut(Qt::META
+ Qt::Key_R
));
174 action
= m_actions
->addAction(i18n("CDDB"), this, SLOT(CDDialogSelected()));
175 action
->setShortcut(Qt::CTRL
+ Qt::Key_D
);
177 m_actions
->readSettings();
181 m_cd
->setLoopPlaylist(Prefs::looping());
182 m_cd
->setRandomPlaylist(Prefs::randomPlay());
184 setDocking(Prefs::docking());
185 setFocusPolicy(Qt::NoFocus
);
187 songListCB
->setSizePolicy(QSizePolicy::Ignored
, QSizePolicy::Fixed
);
189 setFixedHeight(this->height());
191 /* FIXME check for return value */
201 void KSCD::setVolume(int v
)
204 volumeSlider
->setValue(v
);
207 void KSCD::setDevice(const QString
& dev
)
209 Prefs::setCdDevice(dev
);
214 * drawPanel() constructs KSCD's little black LED area
215 * all settings are made via panel.ui
217 void KSCD::drawPanel()
222 connect(lcdNumber
, SIGNAL(clicked()), this, SLOT(cycleplaytimemode()));
226 queryled
->setVisible(false);
227 totaltimelabel
->hide();
230 void KSCD::setIcons()
232 playPB
->setIcon(KIcon(SmallIcon("media-playback-start")));
233 stopPB
->setIcon(KIcon(SmallIcon("media-playback-stop")));
234 ejectPB
->setIcon(KIcon(SmallIcon("media-eject")));
235 prevPB
->setIcon(KIcon(SmallIcon("media-skip-backward")));
236 nextPB
->setIcon(KIcon(SmallIcon("media-skip-forward")));
237 cddbPB
->setIcon(KIcon(SmallIcon("fileview-text")));
238 infoPB
->setIcon(KIcon(SmallIcon("system-run")));
241 void KSCD::setupPopups()
243 QMenu
*infoPopup
, *mainPopup
;
245 mainPopup
= new QMenu(this);
246 infoPB
->setMenu(mainPopup
);
247 infoPopup
= mainPopup
->addMenu(i18n("Artist Information"));
249 connect(infoPopup
, SIGNAL(triggered(QAction
*)), SLOT(information(QAction
*)));
251 infoPopup
->addAction("MusicMoz");
252 infoPopup
->addAction("Ultimate Bandlist");
253 infoPopup
->addAction("CD Universe");
254 infoPopup
->addSeparator();
255 infoPopup
->addAction("AlltheWeb");
256 infoPopup
->addAction("Altavista");
257 infoPopup
->addAction("Excite");
258 infoPopup
->addAction("Google");
259 infoPopup
->addAction("Google Groups");
260 infoPopup
->addAction("HotBot");
261 infoPopup
->addAction("Lycos");
262 infoPopup
->addAction("Open Directory");
263 infoPopup
->addAction("Yahoo!");
265 mainPopup
->addAction(m_actions
->action(KStandardAction::name(KStandardAction::Preferences
)));
266 mainPopup
->addAction(m_actions
->action(KStandardAction::name(KStandardAction::KeyBindings
)));
267 mainPopup
->addSeparator();
269 KHelpMenu
* helpMenu
= new KHelpMenu(this, KGlobal::mainComponent().aboutData(), false);
270 mainPopup
->addMenu(helpMenu
->menu());
271 mainPopup
->addSeparator();
272 mainPopup
->addAction(m_actions
->action(KStandardAction::name(KStandardAction::Quit
)));
275 void KSCD::playClicked()
277 if (m_cd
->isPlaying() || m_cd
->isPaused())
283 void KSCD::stopClicked()
285 stoppedByUser
= true;
290 void KSCD::prevClicked()
295 void KSCD::nextClicked()
300 void KSCD::jumpToTime(int seconds
)
302 m_cd
->playPosition(seconds
);
305 void KSCD::timeSliderPressed()
310 void KSCD::timeSliderMoved(int seconds
)
316 void KSCD::timeSliderReleased()
321 void KSCD::quitClicked()
323 // ensure nothing else starts happening
324 queryledtimer
.stop();
325 titlelabeltimer
.stop();
336 bool KSCD::event( QEvent
*e
)
338 return QWidget::event(e
);
342 * Do everything needed if the user requested to eject the disc.
345 void KSCD::ejectClicked()
350 void KSCD::closeEvent(QCloseEvent
*e
)
352 if (Prefs::docking() && !kapp
->sessionSaving())
361 void KSCD::randomClicked()
363 Prefs::setRandomPlay(!Prefs::randomPlay());
364 m_cd
->setRandomPlaylist(Prefs::randomPlay());
367 void KSCD::randomChanged(bool on
)
369 randomled
->setVisible(on
);
370 shufflePB
->setChecked(on
);
373 void KSCD::loopClicked()
375 Prefs::setLooping(!Prefs::looping()) ;
376 m_cd
->setLoopPlaylist(Prefs::looping());
379 void KSCD::loopChanged(bool on
)
381 loopled
->setVisible(on
);
382 repeatPB
->setChecked(on
);
386 * A Track was selected for playback from the drop down box.
389 void KSCD::trackSelected(int cb_index
)
391 m_cd
->playTrack(cb_index
+ 1);
394 void KSCD::updateConfigDialog(configWidget
* widget
)
399 static QString originalTitleOfGroupBox
= widget
->groupBox3
->title();
400 if(m_cd
->isPlaying()) {
401 widget
->groupBox3
->setEnabled(false);
402 widget
->groupBox3
->setTitle( i18n( "CD Drive (you must stop playing to change this)" ) );
404 widget
->groupBox3
->setEnabled(true);
405 widget
->groupBox3
->setTitle(originalTitleOfGroupBox
);
409 void KSCD::showConfig()
411 static configWidget
* confWidget
= 0;
413 if (KConfigDialog::showDialog("settings")) {
414 updateConfigDialog(confWidget
);
418 configDialog
= new KConfigDialog(this, "settings", Prefs::self());
420 configDialog
->setHelp(QString());
422 confWidget
= new configWidget(this, 0);
425 configDialog
->addPage(confWidget
, i18n("CD Player"), "kscd", i18n("Settings & Behavior"));
428 KService::Ptr libkcddb
= KService::serviceByDesktopName("libkcddb");
429 if (libkcddb
&& libkcddb
->isValid())
431 KCModuleInfo
info(libkcddb
->entryPath());
432 if (info
.service()->isValid())
434 KCModule
*m
= KCModuleLoader::loadModule(info
, KCModuleLoader::Inline
);
438 KCDDB::Config
* cfg
= new KCDDB::Config();
440 configDialog
-> addPage(m
, cfg
, QString("CDDB"), "text-xmcd", i18n("Configure Fetching Items"));
442 connect(configDialog
, SIGNAL(okClicked()), m
, SLOT(save()));
443 connect(configDialog
, SIGNAL(applyClicked()), m
, SLOT(save()));
444 connect(configDialog
, SIGNAL(defaultClicked()), m
, SLOT(defaults()));
449 updateConfigDialog(confWidget
);
451 connect(configDialog
, SIGNAL(settingsChanged(const QString
&)), this, SLOT(configDone()));
452 configDialog
-> show();
455 void KSCD::configDone()
457 Prefs::self()->writeConfig();
460 setDocking(Prefs::docking());
463 // dialog deletes itself
467 void KSCD::configureKeys()
469 KShortcutsDialog::configure(m_actions
, KShortcutsEditor::LetterShortcutsAllowed
, this);
472 void KSCD::setDevicePaths()
475 if(!Prefs::digitalPlayback()) {
476 audioSystem
= QString("cdin");
478 switch(Prefs::audioSystem())
480 case Prefs::EnumAudioSystem::phonon
:
481 audioSystem
= QString("phonon");
483 case Prefs::EnumAudioSystem::arts
:
484 audioSystem
= QString("arts");
486 case Prefs::EnumAudioSystem::alsa
:
487 audioSystem
= QString("alsa");
489 case Prefs::EnumAudioSystem::sun
:
490 audioSystem
= QString("sun");
497 if (!m_cd
->setDevice(Prefs::cdDevice(), Prefs::volume(), Prefs::digitalPlayback(),
498 audioSystem
, Prefs::audioDevice()))
500 // This device did not seem usable.
501 QString str
= i18n("CD-ROM access error (or error in startup of audio system).\n"\
502 "Please make sure you have access permissions to cdrom device:\n"\
503 "device '%1'(%2), audio system '%3'",
504 Prefs::cdDevice(), KCompactDisc::urlToDevice(Prefs::cdDevice()), audioSystem
);
505 KMessageBox::error(this, str
, i18n("Error"));
508 kDebug(67000) << "Vendor: " << m_cd
->deviceVendor();
509 kDebug(67000) << "Model: " << m_cd
->deviceModel();
510 kDebug(67000) << "Revision: " << m_cd
->deviceRevision();
513 m_cd
->setRandomPlaylist(Prefs::randomPlay());
514 m_cd
->setLoopPlaylist(Prefs::looping());
517 void KSCD::setDocking(bool dock
)
519 Prefs::setDocking(dock
);
520 if (Prefs::docking())
524 m_dockWidget
= new DockWidget(this, "dockw");
525 connect(m_dockWidget
, SIGNAL(quitSelected()), this, SLOT(quitClicked()));
528 m_dockWidget
->show();
529 connect(this, SIGNAL(tooltipCurrentTrackChanged(const QString
&)),
530 m_dockWidget
, SLOT(setToolTip(const QString
&)));
531 connect(this, SIGNAL(tooltipCurrentTrackChanged(const QString
&)),
532 m_dockWidget
, SLOT(createPopup(const QString
&)));
542 void KSCD::incVolume()
544 int v
= Prefs::volume() + 5;
552 volumeSlider
->setValue(v
);
555 void KSCD::decVolume()
557 int v
= Prefs::volume() - 5;
565 volumeSlider
->setValue(v
);
568 void KSCD::volChanged(int vol
)
570 m_cd
->setVolume(vol
);
571 Prefs::setVolume(vol
);
575 void KSCD::setLEDs(int seconds
)
587 mymin
= seconds
/ 60;
588 mysec
= (seconds
% 60);
589 symbols
.sprintf("%02d:%02d", mymin
, mysec
);
592 lcdNumber
->display(symbols
);
595 void KSCD::resetTimeSlider(bool enabled
)
597 timeSlider
->setEnabled(enabled
);
598 timeSlider
->blockSignals(true);
599 timeSlider
->setValue(0);
600 timeSlider
->blockSignals(false);
603 void KSCD::setColors()
605 QColor led_color
= Prefs::ledColor();
606 QColor background_color
= Prefs::backColor();
607 QPalette
pal(led_color
, background_color
,
608 led_color
, led_color
,
609 led_color
, led_color
, Qt::white
);
611 backdrop
->setPalette(pal
);
613 titlelabel
->setFont(Prefs::ledFont());
614 artistlabel
->setFont(Prefs::ledFont());
615 volumelabel
->setFont(Prefs::ledFont());
616 statuslabel
->setFont(Prefs::ledFont());
617 tracklabel
->setFont(Prefs::ledFont());
618 totaltimelabel
->setFont(Prefs::ledFont());
621 void KSCD::readSettings()
623 if (Prefs::cdDevice().isEmpty())
624 Prefs::setCdDevice(KCompactDisc::defaultCdromDeviceName());
627 void KSCD::writeSettings()
629 Prefs::self()->writeConfig();
632 void KSCD::CDDialogSelected()
636 cddialog
= new CDDBDlg(this);
638 connect(cddialog
,SIGNAL(cddbQuery()),SLOT(lookupCDDB()));
639 connect(cddialog
,SIGNAL(newCDInfoStored(KCDDB::CDInfo
)),
640 SLOT(setCDInfo(KCDDB::CDInfo
)));
641 connect(cddialog
,SIGNAL(finished()),SLOT(CDDialogDone()));
642 connect(cddialog
,SIGNAL(play(int)),SLOT(trackSelected(int)));
649 void KSCD::CDDialogDone()
651 cddialog
->delayedDestruct();
655 void KSCD::lookupCDDB()
657 if (m_cd
->isNoDisc() || m_cd
->discId() == 0)
660 kDebug(67000) << "lookupCDDB() called";
662 showArtistLabel(i18n("Start freedb lookup."));
666 cddb
->config().reparse();
667 cddb
->setBlockingMode(false);
668 cddb
->lookup(m_cd
->discSignature());
671 void KSCD::lookupCDDBDone(Result result
)
674 if ((result
!= KCDDB::Success
) &&
675 (result
!= KCDDB::MultipleRecordFound
))
677 showArtistLabel(result
== NoRecordFound
? i18n("No matching freedb entry found.") :
678 i18n("Error getting freedb entry."));
679 QTimer::singleShot(3000, this, SLOT(restoreArtistLabel()));
683 // The intent of the original code here seems to have been to perform the
684 // lookup, and then to convert all the string data within the CDDB response
685 // using the use Prefs::selectedEncoding() and a QTextCodec. However, that
686 // seems to be irrelevant these days.
687 KCDDB::CDInfo info
= cddb
->lookupResponse().first();
688 // TODO Why doesn't libcddb not return MultipleRecordFound?
689 //if( result == KCDDB::MultipleRecordFound ) {
690 if(cddb
->lookupResponse().count() > 1) {
691 CDInfoList cddb_info
= cddb
->lookupResponse();
692 CDInfoList::iterator it
;
694 for ( it
= cddb_info
.begin(); it
!= cddb_info
.end(); ++it
) {
695 list
.append( QString("%1, %2, %3").arg((*it
).get(Artist
).toString())
696 .arg((*it
).get(Title
).toString()).arg((*it
).get(Genre
).toString()));
700 QString res
= KInputDialog::getItem(
701 i18n("Select CDDB Entry"),
702 i18n("Select a CDDB entry:"), list
, 0, false, &ok
,
705 // The user selected and item and pressed OK
707 for ( QStringList::Iterator it
= list
.begin(); it
!= list
.end(); ++it
) {
708 if( *it
== res
) break;
711 if( c
< cddb_info
.size() )
715 // user pressed Cancel
722 void KSCD::setCDInfo(KCDDB::CDInfo info
)
724 // Some sanity provisions to ensure that the number of records matches what
725 // the CD actually contains.
727 Q_ASSERT(info
.numberOfTracks() == m_cd
->tracks());
731 restoreArtistLabel();
736 queryledtimer
.stop();
737 queryled
->setVisible(false);
738 totaltimelabel
->raise();
739 totaltimelabel
->show();
744 totaltimelabel
->hide();
745 totaltimelabel
->lower();
746 queryledtimer
.start(800);
747 queryled
->setVisible(true);
750 void KSCD::togglequeryled()
752 queryled
->setVisible(!queryled
->isVisible());
755 void KSCD::titlelabeltimeout()
757 // clear the cddb error message on the title label.
758 titlelabeltimer
.stop();
762 int KSCD::currentTrack()
764 return m_cd
->track();
767 int KSCD::currentTrackLength()
769 return m_cd
->trackLength();
772 int KSCD::currentPosition()
774 return m_cd
->trackPosition();
777 int KSCD::getStatus()
779 if (m_cd
->isPlaying())
781 else if (m_cd
->isPaused())
783 else if (!m_cd
->isNoDisc())
791 return m_cd
->isPlaying();
794 void KSCD::trackPosition(unsigned trackPosition
)
798 kDebug(67000) << "trackPosition(" << trackPosition
<< ")";
799 switch (Prefs::timeDisplayMode())
801 case Prefs::EnumTimeDisplayMode::TRACK_REM
:
802 tmp
= m_cd
->trackLength() - trackPosition
;
805 case Prefs::EnumTimeDisplayMode::TOTAL_SEC
:
806 tmp
= m_cd
->discPosition();
809 case Prefs::EnumTimeDisplayMode::TOTAL_REM
:
810 tmp
= m_cd
->discLength() - m_cd
->discPosition();
813 case Prefs::EnumTimeDisplayMode::TRACK_SEC
:
821 timeSlider
->blockSignals(true);
822 timeSlider
->setValue(trackPosition
);
823 timeSlider
->blockSignals(false);
827 void KSCD::discChanged(unsigned tracks
)
829 kDebug(67000) << "discChanged(" << tracks
<< ")";
833 // Set the total time.
835 dml
= dml
.addSecs(m_cd
->discLength());
839 fmt
.sprintf("%02d:%02d:%02d", dml
.hour(), dml
.minute(), dml
.second());
841 fmt
.sprintf("%02d:%02d", dml
.minute(), dml
.second());
842 totaltimelabel
->setText(fmt
);
844 if ((Prefs::autoplay() || KCmdLineArgs::parsedArgs()->isSet("start"))
845 && !m_cd
->isPlaying())
848 // We just populated the GUI with what we got from the CD. Now look for
849 // more from the Internet...
850 showArtistLabel(i18n("Start freedb lookup."));
854 cddb
->config().reparse();
855 cddb
->setBlockingMode(false);
856 cddb
->lookup(m_cd
->discSignature());
860 restoreArtistLabel();
861 totaltimelabel
->hide();
865 void KSCD::discInformation(KCompactDisc::DiscInfo info
)
868 restoreArtistLabel();
871 void KSCD::discStatusChanged(KCompactDisc::DiscStatus status
)
873 kDebug(67000) << "discStatusChanged(" << m_cd
->discStatusString(status
) << ")";
874 statuslabel
->setText(m_cd
->discStatusString(status
));
878 case KCompactDisc::Stopped
:
881 if (Prefs::ejectOnFinish() && !stoppedByUser
)
884 playPB
->setText(i18n("Play"));
885 playPB
->setIcon(KIcon(SmallIcon("media-playback-start")));
887 /* reset to initial value, only stopclicked() sets this to true */
888 stoppedByUser
= false;
891 case KCompactDisc::Playing
:
892 playPB
->setIcon(KIcon(SmallIcon("media-playback-pause")));
893 playPB
->setText(i18n("Pause"));
896 case KCompactDisc::Paused
:
897 playPB
->setIcon(KIcon(SmallIcon("media-playback-start")));
898 playPB
->setText(i18n("Play"));
906 void KSCD::trackChanged(unsigned track
)
908 kDebug(67000) << "trackChanged(" << track
<< ")";
909 QString tooltip
= artistlabel
->text();
914 resetTimeSlider(true);
915 tracklabel
->setText("--/--");
917 if (songListCB
->count())
919 songListCB
->setCurrentIndex(0);
924 if (songListCB
->count())
926 songListCB
->setCurrentIndex(track
- 1);
928 // for Mahlah, a picky though otherwise wonderful person - AJS
929 QString justTheName
= songListCB
->currentText();
930 justTheName
= justTheName
.right(justTheName
.length() - 4);
932 songListCB
->setToolTip( i18n("Current track: %1", justTheName
));
934 timeSlider
->blockSignals(true);
935 timeSlider
->setRange(0, m_cd
->trackLength(track
));
936 timeSlider
->blockSignals(false);
938 str
.sprintf("%02d/%02d", track
, m_cd
->tracks());
939 tracklabel
->setText(str
);
942 if (m_cd
->trackArtist() != m_cd
->discArtist())
943 title
.append(m_cd
->trackArtist()).append(" - ");
944 title
.append(m_cd
->trackTitle());
945 titlelabel
->setText(title
);
946 tooltip
+= '/' + KStringHandler::rsqueeze(title
, 30);
948 emit
tooltipCurrentTrackChanged(tooltip
);
951 void KSCD::cycleplaytimemode()
953 /* switch to the next mode */
954 switch (Prefs::timeDisplayMode())
956 case Prefs::EnumTimeDisplayMode::TRACK_SEC
:
957 Prefs::setTimeDisplayMode(Prefs::EnumTimeDisplayMode::TRACK_REM
);
960 case Prefs::EnumTimeDisplayMode::TRACK_REM
:
961 Prefs::setTimeDisplayMode(Prefs::EnumTimeDisplayMode::TOTAL_SEC
);
964 case Prefs::EnumTimeDisplayMode::TOTAL_SEC
:
965 Prefs::setTimeDisplayMode(Prefs::EnumTimeDisplayMode::TOTAL_REM
);
968 case Prefs::EnumTimeDisplayMode::TOTAL_REM
:
970 Prefs::setTimeDisplayMode(Prefs::EnumTimeDisplayMode::TRACK_SEC
);
975 switch(Prefs::timeDisplayMode())
977 case Prefs::EnumTimeDisplayMode::TRACK_REM
:
978 volumelabel
->setText(i18n("Tra Rem"));
981 case Prefs::EnumTimeDisplayMode::TOTAL_SEC
:
982 volumelabel
->setText(i18n("Tot Sec"));
985 case Prefs::EnumTimeDisplayMode::TOTAL_REM
:
986 volumelabel
->setText(i18n("Tot Rem"));
989 case Prefs::EnumTimeDisplayMode::TRACK_SEC
:
991 volumelabel
->setText(i18n("Tra Sec"));
995 QTimer::singleShot(3000, this, SLOT(showVolumeInLabel()));
998 void KSCD::showVolumeInLabel()
1001 str
= ki18n("Vol: %1%").subs(Prefs::volume(), 2).toString();
1002 volumelabel
->setText(str
);
1005 void KSCD::showArtistLabel(QString infoStatus
)
1007 artistlabel
->setText(infoStatus
);
1011 * KDE 4.0 quick fix: it looks like the conversion to mode
1012 * CDDB info into KCompactDisc wasn't finished, so we work around
1013 * it here for now by explicitly overriding data from m_cd with
1014 * data from cddbInfo iff cddbInfo.isValid() &&
1015 * cddbInfo.numberOfTracks() == m_cd->tracks()
1018 void KSCD::restoreArtistLabel()
1020 if(m_cd
->tracks()) {
1021 QString artist
, title
;
1023 if (cddbInfo
.isValid() && cddbInfo
.numberOfTracks() == m_cd
->tracks()) {
1024 artist
= cddbInfo
.get(KCDDB::Artist
).toString();
1025 title
= cddbInfo
.get(KCDDB::Title
).toString();
1027 artist
= m_cd
->discArtist();
1028 title
= m_cd
->discTitle();
1031 showArtistLabel(QString("%1 - %2").arg(artist
, title
));
1033 showArtistLabel(i18n("NO DISC"));
1037 void KSCD::information(QAction
*action
)
1039 QString artist
= m_cd
->trackArtist();
1041 // see comment before restoreArtistLabel()
1042 if (cddbInfo
.isValid() && cddbInfo
.numberOfTracks() == m_cd
->tracks()) {
1043 const KCDDB::TrackInfo
& t
= cddbInfo
.track(m_cd
->track() - 1);
1044 artist
= t
.get(KCDDB::Artist
).toString();
1047 if(artist
.isEmpty())
1050 //QString encodedArtist = KUrl::encode_string_no_slash(cddbInfo.get(Artist).toString());
1053 QString server
= action
->text();
1055 if(server
== "MusicMoz") {
1056 url
= KUrl("http://musicmoz.org/cgi-bin/ext.cgi");
1057 url
.addQueryItem( "artist", artist
);
1058 } else if (server
== "Ultimate Bandlist") {
1059 url
= KUrl("http://ubl.artistdirect.com/cgi-bin/gx.cgi/AppLogic+Search?select=MusicArtist&searchtype=NormalSearch");
1060 url
.addQueryItem( "searchstr", artist
);
1061 } else if (server
== "CD Universe") {
1062 url
= KUrl( QString( "http://www.cduniverse.com/cgi-bin/cdubin.exe/rlinka/ean=%1" ).arg( QString::fromLatin1(KUrl::toPercentEncoding(artist
)) ) );
1063 } else if (server
== "AlltheWeb") {
1064 url
= KUrl("http://www.alltheweb.com/search?cat=web");
1065 url
.addQueryItem( "q", artist
);
1066 } else if (server
== "Altavista") {
1067 url
= KUrl("http://altavista.com/web/results?kgs=0&kls=1&avkw=xytx");
1068 url
.addQueryItem( "q", artist
);
1069 } else if (server
== "Excite") {
1070 url
= KUrl("http://msxml.excite.com/_1_2UDOUB70SVHVHR__info.xcite/dog/results?otmpl=dog/webresults.htm&qcat=web&qk=20&top=1&start=&ver=14060");
1071 url
.addQueryItem( "qkw", artist
);
1072 } else if (server
== "Google") {
1073 url
= KUrl("http://www.google.com/search");
1074 url
.addQueryItem( "q", artist
);
1075 } else if (server
== "Google Groups") {
1076 url
= KUrl("http://groups.google.com/groups?oi=djq&num=20");
1077 url
.addQueryItem( "as_q", artist
);
1078 } else if (server
== "HotBot") {
1079 url
= KUrl("http://www.hotbot.com/default.asp?prov=Inktomi&ps=&loc=searchbox&tab=web");
1080 url
.addQueryItem( "query", artist
);
1081 } else if (server
== "Lycos") {
1082 url
= KUrl("http://search.lycos.com/default.asp?lpv=1&loc=searchhp&tab=web");
1083 url
.addQueryItem( "query", artist
);
1084 } else if (server
== "Open Directory") {
1085 url
= KUrl("http://search.dmoz.org/cgi-bin/search");
1086 url
.addQueryItem( "search", artist
);
1087 } else if (server
== "Yahoo!") {
1088 url
= KUrl("http://search.yahoo.com/bin/search");
1089 url
.addQueryItem( "p", artist
);
1094 KRun::runUrl( url
, "text/html", 0L);
1098 * Save state on session termination
1100 bool KSCD::saveState(QSessionManager
& /*sm*/)
1103 KConfigGroup
config(KApplication::kApplication()->sessionConfig(), "General");
1104 config
.writeEntry("Show", isVisible());
1109 * Allow the user to type in the number of the track
1111 void KSCD::keyPressEvent(QKeyEvent
* e
)
1114 uint value
= e
->text().toUInt(&isNum
);
1116 if (e
->key() == Qt::Key_F1
)
1118 KToolInvocation::invokeHelp();
1122 if (0 < value
&& value
<= m_cd
->tracks())
1123 songListCB
->setCurrentIndex(value
- 1);
1127 QWidget::keyPressEvent(e
);
1131 QString
KSCD::currentTrackTitle()
1133 // see comment before restoreArtistLabel()
1134 if (cddbInfo
.isValid() && cddbInfo
.numberOfTracks() == m_cd
->tracks()) {
1135 const KCDDB::TrackInfo
& t
= cddbInfo
.track(m_cd
->track() - 1);
1136 return t
.get(KCDDB::Title
).toString();
1139 return m_cd
->trackTitle();
1142 QString
KSCD::currentAlbum()
1144 // see comment before restoreArtistLabel()
1145 if (cddbInfo
.isValid() && cddbInfo
.numberOfTracks() == m_cd
->tracks()) {
1146 return cddbInfo
.get(KCDDB::Title
).toString();
1149 return m_cd
->discTitle();
1152 QString
KSCD::currentArtist()
1154 // see comment before restoreArtistLabel()
1155 if (cddbInfo
.isValid() && cddbInfo
.numberOfTracks() == m_cd
->tracks()) {
1156 const KCDDB::TrackInfo
& t
= cddbInfo
.track(m_cd
->track() - 1);
1157 return t
.get(KCDDB::Artist
).toString();
1160 return m_cd
->trackArtist();
1163 QStringList
KSCD::trackList()
1167 // see comment before restoreArtistLabel()
1168 if (cddbInfo
.isValid() && cddbInfo
.numberOfTracks() == m_cd
->tracks()) {
1169 for (uint i
= 0; i
< m_cd
->tracks(); ++i
) {
1170 const KCDDB::TrackInfo
& t
= cddbInfo
.track(i
);
1171 tracks
<< t
.get(KCDDB::Artist
).toString();
1174 for (uint i
= 0; i
< m_cd
->tracks(); ++i
)
1175 tracks
<< m_cd
->trackTitle(i
);
1181 void KSCD::populateSongList()
1183 songListCB
->clear();
1184 for (uint i
= 1; i
<= m_cd
->tracks(); ++i
)
1186 unsigned tmp
= m_cd
->trackLength(i
);
1192 str1
.sprintf("%02u: ", i
);
1195 str2
.sprintf(" (%02u:%02u) ", mymin
, mysec
);
1196 // see comment before restoreArtistLabel()
1197 if (cddbInfo
.isValid() && cddbInfo
.numberOfTracks() == m_cd
->tracks()) {
1198 const KCDDB::TrackInfo
& t
= cddbInfo
.track(i
- 1);
1200 if (cddbInfo
.get(KCDDB::Artist
).toString() != t
.get(KCDDB::Artist
).toString())
1201 str1
.append(t
.get(KCDDB::Artist
).toString()).append(" - ");
1202 str1
.append(t
.get(KCDDB::Title
).toString());
1204 if (m_cd
->discArtist() != m_cd
->trackArtist(i
))
1205 str1
.append(m_cd
->trackArtist(i
)).append(" - ");
1206 str1
.append(m_cd
->trackTitle(i
));
1209 songListCB
->addItem(str1
);
1217 int main( int argc
, char *argv
[] )
1219 KAboutData
aboutData("kscd", 0, ki18n("KsCD"),
1220 "1.5", ki18n(description
),
1221 KAboutData::License_GPL
,
1222 ki18n("(c) 2001, Dirk Försterling\n(c) 2003, Aaron J. Seigo"));
1223 aboutData
.addAuthor(ki18n("Aaron J. Seigo"), ki18n("Current maintainer"), "aseigo@kde.org");
1224 aboutData
.addAuthor(ki18n("Alexander Kern"),ki18n("Workman library update, CDTEXT, CDDA"), "kernalex@kde.org");
1225 aboutData
.addAuthor(ki18n("Bernd Johannes Wuebben"),KLocalizedString(), "wuebben@kde.org");
1226 aboutData
.addAuthor(ki18n("Dirk Försterling"), ki18n("Workman library, previous maintainer"), "milliByte@gmx.net");
1227 aboutData
.addCredit(ki18n("Wilfried Huss"), ki18n("Patches galore"));
1228 aboutData
.addCredit(ki18n("Steven Grimm"), ki18n("Workman library"));
1229 aboutData
.addCredit(ki18n("Sven Lueppken"), ki18n("UI Work"));
1230 aboutData
.addCredit(ki18n("freedb.org"), ki18n("Special thanks to freedb.org for providing a free CDDB-like CD database"), 0, "http://freedb.org");
1232 KCmdLineArgs::init( argc
, argv
, &aboutData
);
1234 KCmdLineOptions options
;
1236 options
.add("start", ki18n("Start playing"));
1237 options
.add("+[device]", ki18n("CD device, can be a path or a media:/ URL"));
1238 KCmdLineArgs::addCmdLineOptions(options
);
1239 KUniqueApplication::addCmdLineOptions();
1241 KCmdLineArgs
* args
= KCmdLineArgs::parsedArgs();
1242 if (!KUniqueApplication::start())
1244 fprintf(stderr
, "kscd is already running\n");
1245 if (args
->count() > 0 || args
->isSet("start"))
1247 QDBusInterface
kscd("org.kde.kscd", "/CDPlayer", "org.kde.kscd.CDPlayer");
1248 // Forward the command line args to the running instance.
1249 if (args
->count() > 0)
1251 kscd
.call( "setDevice", QString(args
->arg(0)));
1253 if (args
->isSet("start"))
1255 kscd
.call( "play" );
1260 KUniqueApplication a
;
1262 KSCD
*k
= new KSCD();
1264 a
.setTopWidget( k
);
1265 a
.setMainWidget( k
);
1267 k
->setWindowTitle(KGlobal::caption());
1269 if (kapp
->isSessionRestored())
1271 KConfigGroup
group(KApplication::kApplication()->sessionConfig(), "General");
1272 if (group
.readEntry("Show", false))
1280 if (args
->count() > 0)
1281 Prefs::self()->setCdDevice(args
->arg(0));