|
MythTV
0.26-pre
|
00001 // ANSI C includes 00002 #include <cstdio> 00003 #include <cstring> 00004 00005 // Unix C includes 00006 #include <sys/types.h> 00007 #include <fcntl.h> 00008 00009 #include "config.h" 00010 #ifdef HAVE_CDIO 00011 # include <cdio/cdda.h> 00012 # include <cdio/paranoia.h> 00013 #endif //def HAVE_CDIO 00014 00015 // C++ includes 00016 #include <iostream> 00017 #include <memory> 00018 using namespace std; 00019 00020 // Qt includes 00021 #include <QApplication> 00022 #include <QDir> 00023 #include <QRegExp> 00024 #include <QKeyEvent> 00025 #include <QEvent> 00026 #include <QFile> 00027 00028 // MythTV plugin includes 00029 #include <mythcontext.h> 00030 #include <mythdb.h> 00031 #include <lcddevice.h> 00032 #include <mythmediamonitor.h> 00033 00034 // MythUI 00035 #include <mythdialogbox.h> 00036 #include <mythuitext.h> 00037 #include <mythuicheckbox.h> 00038 #include <mythuitextedit.h> 00039 #include <mythuibutton.h> 00040 #include <mythuiprogressbar.h> 00041 #include <mythuibuttonlist.h> 00042 #include <mythsystem.h> 00043 00044 // MythUI headers 00045 #include <mythtv/libmythui/mythscreenstack.h> 00046 #include <mythtv/libmythui/mythprogressdialog.h> 00047 00048 // MythMusic includes 00049 #include "cdrip.h" 00050 #ifdef HAVE_CDIO 00051 #include "cddecoder.h" 00052 #endif 00053 #include "encoder.h" 00054 #include "vorbisencoder.h" 00055 #include "lameencoder.h" 00056 #include "flacencoder.h" 00057 #include "genres.h" 00058 #include "editmetadata.h" 00059 #include "mythlogging.h" 00060 #include "musicutils.h" 00061 00062 #ifdef HAVE_CDIO 00063 // libparanoia compatibility 00064 #ifndef cdrom_paranoia 00065 #define cdrom_paranoia cdrom_paranoia_t 00066 #endif 00067 00068 #ifndef CD_FRAMESIZE_RAW 00069 # define CD_FRAMESIZE_RAW CDIO_CD_FRAMESIZE_RAW 00070 #endif 00071 #endif 00072 00073 QEvent::Type RipStatusEvent::kTrackTextEvent = 00074 (QEvent::Type) QEvent::registerEventType(); 00075 QEvent::Type RipStatusEvent::kOverallTextEvent = 00076 (QEvent::Type) QEvent::registerEventType(); 00077 QEvent::Type RipStatusEvent::kStatusTextEvent = 00078 (QEvent::Type) QEvent::registerEventType(); 00079 QEvent::Type RipStatusEvent::kTrackProgressEvent = 00080 (QEvent::Type) QEvent::registerEventType(); 00081 QEvent::Type RipStatusEvent::kTrackPercentEvent = 00082 (QEvent::Type) QEvent::registerEventType(); 00083 QEvent::Type RipStatusEvent::kTrackStartEvent = 00084 (QEvent::Type) QEvent::registerEventType(); 00085 QEvent::Type RipStatusEvent::kOverallProgressEvent = 00086 (QEvent::Type) QEvent::registerEventType(); 00087 QEvent::Type RipStatusEvent::kOverallPercentEvent = 00088 (QEvent::Type) QEvent::registerEventType(); 00089 QEvent::Type RipStatusEvent::kOverallStartEvent = 00090 (QEvent::Type) QEvent::registerEventType(); 00091 QEvent::Type RipStatusEvent::kFinishedEvent = 00092 (QEvent::Type) QEvent::registerEventType(); 00093 QEvent::Type RipStatusEvent::kEncoderErrorEvent = 00094 (QEvent::Type) QEvent::registerEventType(); 00095 00096 CDScannerThread::CDScannerThread(Ripper *ripper) : 00097 MThread("CDScanner"), m_parent(ripper) 00098 { 00099 } 00100 00101 void CDScannerThread::run() 00102 { 00103 RunProlog(); 00104 m_parent->scanCD(); 00105 RunEpilog(); 00106 } 00107 00109 00110 CDEjectorThread::CDEjectorThread(Ripper *ripper) : 00111 MThread("CDEjector"), m_parent(ripper) 00112 { 00113 } 00114 00115 void CDEjectorThread::run() 00116 { 00117 RunProlog(); 00118 m_parent->ejectCD(); 00119 RunEpilog(); 00120 } 00121 00123 00124 static long int getSectorCount (QString &cddevice, int tracknum) 00125 { 00126 #if defined HAVE_CDIO 00127 QByteArray devname = cddevice.toAscii(); 00128 cdrom_drive *device = cdda_identify(devname.constData(), 0, NULL); 00129 00130 if (!device) 00131 { 00132 LOG(VB_GENERAL, LOG_ERR, 00133 QString("Error: %1('%2',track=%3) failed at cdda_identify()"). 00134 arg(__func__).arg(cddevice).arg(tracknum)); 00135 return -1; 00136 } 00137 00138 if (cdda_open(device)) 00139 { 00140 LOG(VB_GENERAL, LOG_ERR, 00141 QString("Error: %1('%2',track=%3) failed at cdda_open() - cdda not supported"). 00142 arg(__func__).arg(cddevice).arg(tracknum)); 00143 cdda_close(device); 00144 return -1; 00145 } 00146 00147 // we only care about audio tracks 00148 if (cdda_track_audiop (device, tracknum)) 00149 { 00150 cdda_verbose_set(device, CDDA_MESSAGE_FORGETIT, CDDA_MESSAGE_FORGETIT); 00151 long int start = cdda_track_firstsector(device, tracknum); 00152 long int end = cdda_track_lastsector( device, tracknum); 00153 cdda_close(device); 00154 return end - start + 1; 00155 } 00156 LOG(VB_GENERAL, LOG_ERR, 00157 QString("Error: cdrip - cdda_track_audiop(%1) returned 0").arg(cddevice)); 00158 00159 cdda_close(device); 00160 #else 00161 (void)cddevice; (void)tracknum; 00162 #endif 00163 return 0; 00164 } 00165 00166 #ifdef HAVE_CDIO 00167 static void paranoia_cb(long, paranoia_cb_mode_t) 00168 { 00169 } 00170 #endif 00171 00172 CDRipperThread::CDRipperThread(RipStatus *parent, QString device, 00173 QVector<RipTrack*> *tracks, int quality) : 00174 MThread("CDRipper"), 00175 m_parent(parent), m_quit(false), 00176 m_CDdevice(device), m_quality(quality), 00177 m_tracks(tracks), m_totalSectors(0), 00178 m_totalSectorsDone(0), m_lastTrackPct(0), 00179 m_lastOverallPct(0) 00180 { 00181 #ifdef WIN32 // libcdio needs the drive letter with no path 00182 if (m_CDdevice.endsWith('\\')) 00183 m_CDdevice.chop(1); 00184 #endif 00185 } 00186 00187 CDRipperThread::~CDRipperThread(void) 00188 { 00189 cancel(); 00190 wait(); 00191 } 00192 00193 void CDRipperThread::cancel(void) 00194 { 00195 m_quit = true; 00196 } 00197 00198 bool CDRipperThread::isCancelled(void) 00199 { 00200 return m_quit; 00201 } 00202 00203 void CDRipperThread::run(void) 00204 { 00205 RunProlog(); 00206 if (!m_tracks->size() > 0) 00207 { 00208 RunEpilog(); 00209 return; 00210 } 00211 00212 Metadata *track = m_tracks->at(0)->metadata; 00213 QString tots; 00214 00215 if (track->Compilation()) 00216 { 00217 tots = track->CompilationArtist() + " ~ " + track->Album(); 00218 } 00219 else 00220 { 00221 tots = track->Artist() + " ~ " + track->Album(); 00222 } 00223 00224 QApplication::postEvent( 00225 m_parent, 00226 new RipStatusEvent(RipStatusEvent::kOverallTextEvent, tots)); 00227 QApplication::postEvent( 00228 m_parent, 00229 new RipStatusEvent(RipStatusEvent::kOverallProgressEvent, 0)); 00230 QApplication::postEvent( 00231 m_parent, 00232 new RipStatusEvent(RipStatusEvent::kTrackProgressEvent, 0)); 00233 00234 QString textstatus; 00235 QString encodertype = gCoreContext->GetSetting("EncoderType"); 00236 bool mp3usevbr = gCoreContext->GetNumSetting("Mp3UseVBR", 0); 00237 00238 m_totalSectors = 0; 00239 m_totalSectorsDone = 0; 00240 for (int trackno = 0; trackno < m_tracks->size(); trackno++) 00241 { 00242 m_totalSectors += getSectorCount(m_CDdevice, trackno + 1); 00243 } 00244 00245 QApplication::postEvent(m_parent, 00246 new RipStatusEvent(RipStatusEvent::kOverallStartEvent, m_totalSectors)); 00247 00248 if (LCD *lcd = LCD::Get()) 00249 { 00250 QString lcd_tots = QObject::tr("Importing ") + tots; 00251 QList<LCDTextItem> textItems; 00252 textItems.append(LCDTextItem(1, ALIGN_CENTERED, 00253 lcd_tots, "Generic", false)); 00254 lcd->switchToGeneric(textItems); 00255 } 00256 00257 Metadata *titleTrack = NULL; 00258 QString outfile; 00259 00260 std::auto_ptr<Encoder> encoder; 00261 00262 for (int trackno = 0; trackno < m_tracks->size(); trackno++) 00263 { 00264 if (isCancelled()) 00265 break; 00266 00267 QApplication::postEvent( 00268 m_parent, 00269 new RipStatusEvent(RipStatusEvent::kStatusTextEvent, 00270 QString("Track %1 of %2") 00271 .arg(trackno + 1).arg(m_tracks->size()))); 00272 00273 QApplication::postEvent( 00274 m_parent, 00275 new RipStatusEvent(RipStatusEvent::kTrackProgressEvent, 0)); 00276 00277 track = m_tracks->at(trackno)->metadata; 00278 00279 if (track) 00280 { 00281 textstatus = track->Title(); 00282 QApplication::postEvent( 00283 m_parent, 00284 new RipStatusEvent( 00285 RipStatusEvent::kTrackTextEvent, textstatus)); 00286 QApplication::postEvent( 00287 m_parent, 00288 new RipStatusEvent(RipStatusEvent::kTrackProgressEvent, 0)); 00289 QApplication::postEvent( 00290 m_parent, 00291 new RipStatusEvent(RipStatusEvent::kTrackPercentEvent, 0)); 00292 00293 // do we need to start a new file? 00294 if (m_tracks->at(trackno)->active) 00295 { 00296 titleTrack = track; 00297 titleTrack->setLength(m_tracks->at(trackno)->length); 00298 00299 outfile = filenameFromMetadata(track); 00300 00301 if (m_quality < 3) 00302 { 00303 if (encodertype == "mp3") 00304 { 00305 outfile += ".mp3"; 00306 encoder.reset(new LameEncoder(gMusicData->musicDir + outfile, m_quality, 00307 titleTrack, mp3usevbr)); 00308 } 00309 else // ogg 00310 { 00311 outfile += ".ogg"; 00312 encoder.reset(new VorbisEncoder(gMusicData->musicDir + outfile, m_quality, 00313 titleTrack)); 00314 } 00315 } 00316 else 00317 { 00318 outfile += ".flac"; 00319 encoder.reset(new FlacEncoder(gMusicData->musicDir + outfile, m_quality, 00320 titleTrack)); 00321 } 00322 00323 if (!encoder->isValid()) 00324 { 00325 QApplication::postEvent( 00326 m_parent, 00327 new RipStatusEvent( 00328 RipStatusEvent::kEncoderErrorEvent, 00329 "Encoder failed to open file for writing")); 00330 LOG(VB_GENERAL, LOG_ERR, "MythMusic: Encoder failed" 00331 " to open file for writing"); 00332 00333 RunEpilog(); 00334 return; 00335 } 00336 } 00337 00338 if (!encoder.get()) 00339 { 00340 // This should never happen. 00341 QApplication::postEvent( 00342 m_parent, 00343 new RipStatusEvent(RipStatusEvent::kEncoderErrorEvent, 00344 "Failed to create encoder")); 00345 LOG(VB_GENERAL, LOG_ERR, "MythMusic: No encoder, failing"); 00346 RunEpilog(); 00347 return; 00348 } 00349 ripTrack(m_CDdevice, encoder.get(), trackno + 1); 00350 00351 if (isCancelled()) 00352 { 00353 RunEpilog(); 00354 return; 00355 } 00356 00357 // save the metadata to the DB 00358 if (m_tracks->at(trackno)->active) 00359 { 00360 titleTrack->setFilename(outfile); 00361 titleTrack->dumpToDatabase(); 00362 } 00363 } 00364 } 00365 00366 QString PostRipCDScript = gCoreContext->GetSetting("PostCDRipScript"); 00367 00368 if (!PostRipCDScript.isEmpty()) 00369 myth_system(PostRipCDScript); 00370 00371 QApplication::postEvent( 00372 m_parent, new RipStatusEvent(RipStatusEvent::kFinishedEvent, "")); 00373 00374 RunEpilog(); 00375 } 00376 00377 int CDRipperThread::ripTrack(QString &cddevice, Encoder *encoder, int tracknum) 00378 { 00379 #if defined HAVE_CDIO 00380 QByteArray devname = cddevice.toAscii(); 00381 cdrom_drive *device = cdda_identify(devname.constData(), 0, NULL); 00382 00383 if (!device) 00384 { 00385 LOG(VB_GENERAL, LOG_ERR, 00386 QString("cdda_identify failed for device '%1', " 00387 "CDRipperThread::ripTrack(tracknum = %2) exiting.") 00388 .arg(cddevice).arg(tracknum)); 00389 return -1; 00390 } 00391 00392 if (cdda_open(device)) 00393 { 00394 LOG(VB_MEDIA, LOG_INFO, 00395 QString("Error: %1('%2',track=%3) failed at cdda_open() - cdda not supported") 00396 .arg(__func__).arg(cddevice).arg(tracknum)); 00397 cdda_close(device); 00398 return -1; 00399 } 00400 00401 cdda_verbose_set(device, CDDA_MESSAGE_FORGETIT, CDDA_MESSAGE_FORGETIT); 00402 long int start = cdda_track_firstsector(device, tracknum); 00403 long int end = cdda_track_lastsector(device, tracknum); 00404 LOG(VB_MEDIA, LOG_INFO, QString("%1(%2,track=%3) start=%4 end=%5") 00405 .arg(__func__).arg(cddevice).arg(tracknum).arg(start).arg(end)); 00406 00407 cdrom_paranoia *paranoia = paranoia_init(device); 00408 if (gCoreContext->GetSetting("ParanoiaLevel") == "full") 00409 paranoia_modeset(paranoia, PARANOIA_MODE_FULL | 00410 PARANOIA_MODE_NEVERSKIP); 00411 else 00412 paranoia_modeset(paranoia, PARANOIA_MODE_OVERLAP); 00413 00414 paranoia_seek(paranoia, start, SEEK_SET); 00415 00416 long int curpos = start; 00417 int16_t *buffer; 00418 00419 QApplication::postEvent( 00420 m_parent, 00421 new RipStatusEvent(RipStatusEvent::kTrackStartEvent, end - start + 1)); 00422 m_lastTrackPct = -1; 00423 m_lastOverallPct = -1; 00424 00425 int every15 = 15; 00426 while (curpos < end) 00427 { 00428 buffer = paranoia_read(paranoia, paranoia_cb); 00429 00430 if (encoder->addSamples(buffer, CD_FRAMESIZE_RAW)) 00431 break; 00432 00433 curpos++; 00434 00435 every15--; 00436 00437 if (every15 <= 0) 00438 { 00439 every15 = 15; 00440 00441 // updating the UITypes can be slow - only update if we need to: 00442 int newOverallPct = (int) (100.0 / (double) ((double) m_totalSectors / 00443 (double) (m_totalSectorsDone + curpos - start))); 00444 if (newOverallPct != m_lastOverallPct) 00445 { 00446 m_lastOverallPct = newOverallPct; 00447 QApplication::postEvent( 00448 m_parent, 00449 new RipStatusEvent(RipStatusEvent::kOverallPercentEvent, 00450 newOverallPct)); 00451 QApplication::postEvent( 00452 m_parent, 00453 new RipStatusEvent(RipStatusEvent::kOverallProgressEvent, 00454 m_totalSectorsDone + curpos - start)); 00455 } 00456 00457 int newTrackPct = (int) (100.0 / (double) ((double) (end - start + 1) / 00458 (double) (curpos - start))); 00459 if (newTrackPct != m_lastTrackPct) 00460 { 00461 m_lastTrackPct = newTrackPct; 00462 QApplication::postEvent( 00463 m_parent, 00464 new RipStatusEvent(RipStatusEvent::kTrackPercentEvent, 00465 newTrackPct)); 00466 QApplication::postEvent( 00467 m_parent, 00468 new RipStatusEvent(RipStatusEvent::kTrackProgressEvent, 00469 curpos - start)); 00470 } 00471 00472 if (LCD *lcd = LCD::Get()) 00473 { 00474 float fProgress = (float)(m_totalSectorsDone + (curpos - start)) 00475 / m_totalSectors; 00476 lcd->setGenericProgress(fProgress); 00477 } 00478 } 00479 00480 if (isCancelled()) 00481 { 00482 break; 00483 } 00484 } 00485 00486 m_totalSectorsDone += end - start + 1; 00487 00488 paranoia_free(paranoia); 00489 cdda_close(device); 00490 00491 return (curpos - start + 1) * CD_FRAMESIZE_RAW; 00492 #else 00493 (void)cddevice; (void)encoder; (void)tracknum; 00494 return 0; 00495 #endif 00496 } 00497 00499 00500 Ripper::Ripper(MythScreenStack *parent, QString device) : 00501 MythScreenType(parent, "ripcd"), 00502 m_decoder(NULL), 00503 00504 m_artistEdit(NULL), 00505 m_albumEdit(NULL), 00506 m_genreEdit(NULL), 00507 m_yearEdit(NULL), 00508 00509 m_compilationCheck(NULL), 00510 00511 m_trackList(NULL), 00512 m_qualityList(NULL), 00513 00514 m_switchTitleArtist(NULL), 00515 m_scanButton(NULL), 00516 m_ripButton(NULL), 00517 m_searchArtistButton(NULL), 00518 m_searchAlbumButton(NULL), 00519 m_searchGenreButton(NULL), 00520 00521 m_tracks(new QVector<RipTrack*>), 00522 00523 m_somethingwasripped(false), 00524 m_mediaMonitorActive(false), 00525 00526 m_CDdevice(device), 00527 00528 m_ejectThread(NULL), m_scanThread(NULL) 00529 { 00530 #ifndef _WIN32 00531 // if the MediaMonitor is running stop it 00532 m_mediaMonitorActive = false; 00533 MediaMonitor *mon = MediaMonitor::GetMediaMonitor(); 00534 if (mon && mon->IsActive()) 00535 { 00536 m_mediaMonitorActive = true; 00537 mon->StopMonitoring(); 00538 } 00539 #endif 00540 } 00541 00542 Ripper::~Ripper(void) 00543 { 00544 if (m_decoder) 00545 delete m_decoder; 00546 00547 #ifndef _WIN32 00548 // if the MediaMonitor was active when we started then restart it 00549 if (m_mediaMonitorActive) 00550 { 00551 MediaMonitor *mon = MediaMonitor::GetMediaMonitor(); 00552 if (mon) 00553 mon->StartMonitoring(); 00554 } 00555 #endif 00556 00557 if (m_somethingwasripped) 00558 emit ripFinished(); 00559 } 00560 00561 bool Ripper::Create(void) 00562 { 00563 if (!LoadWindowFromXML("music-ui.xml", "cdripper", this)) 00564 return false; 00565 00566 m_qualityList = dynamic_cast<MythUIButtonList *>(GetChild("quality")); 00567 m_artistEdit = dynamic_cast<MythUITextEdit *>(GetChild("artist")); 00568 m_searchArtistButton = dynamic_cast<MythUIButton *>(GetChild("searchartist")); 00569 m_albumEdit = dynamic_cast<MythUITextEdit *>(GetChild("album")); 00570 m_searchAlbumButton = dynamic_cast<MythUIButton *>(GetChild("searchalbum")); 00571 m_genreEdit = dynamic_cast<MythUITextEdit *>(GetChild("genre")); 00572 m_yearEdit = dynamic_cast<MythUITextEdit *>(GetChild("year")); 00573 m_searchGenreButton = dynamic_cast<MythUIButton *>(GetChild("searchgenre")); 00574 m_compilationCheck = dynamic_cast<MythUICheckBox *>(GetChild("compilation")); 00575 m_switchTitleArtist = dynamic_cast<MythUIButton *>(GetChild("switch")); 00576 m_scanButton = dynamic_cast<MythUIButton *>(GetChild("scan")); 00577 m_ripButton = dynamic_cast<MythUIButton *>(GetChild("rip")); 00578 m_trackList = dynamic_cast<MythUIButtonList *>(GetChild("tracks")); 00579 00580 BuildFocusList(); 00581 00582 if (!m_artistEdit || !m_scanButton || !m_ripButton || !m_switchTitleArtist 00583 || !m_trackList || !m_compilationCheck || !m_searchGenreButton 00584 || !m_yearEdit || !m_genreEdit || !m_searchArtistButton 00585 || !m_albumEdit || !m_searchAlbumButton || !m_qualityList) 00586 { 00587 LOG(VB_GENERAL, LOG_ERR, 00588 "Missing theme elements for screen 'cdripper'"); 00589 return false; 00590 } 00591 00592 connect(m_trackList, SIGNAL(itemClicked(MythUIButtonListItem *)), 00593 SLOT(toggleTrackActive(MythUIButtonListItem *))); 00594 connect(m_ripButton, SIGNAL(Clicked()), SLOT(startRipper())); 00595 connect(m_scanButton, SIGNAL(Clicked()), SLOT(startScanCD())); 00596 connect(m_switchTitleArtist, SIGNAL(Clicked()), 00597 SLOT(switchTitlesAndArtists())); 00598 connect(m_compilationCheck, SIGNAL(toggled(bool)), 00599 SLOT(compilationChanged(bool))); 00600 connect(m_searchGenreButton, SIGNAL(Clicked()), SLOT(searchGenre())); 00601 connect(m_genreEdit, SIGNAL(valueChanged()), SLOT(genreChanged())); 00602 m_yearEdit->SetFilter((InputFilter)(FilterAlpha | FilterSymbols | FilterPunct)); 00603 m_yearEdit->SetMaxLength(4); 00604 connect(m_yearEdit, SIGNAL(valueChanged()), SLOT(yearChanged())); 00605 connect(m_artistEdit, SIGNAL(valueChanged()), SLOT(artistChanged())); 00606 connect(m_searchArtistButton, SIGNAL(Clicked()), SLOT(searchArtist())); 00607 connect(m_albumEdit, SIGNAL(valueChanged()), SLOT(albumChanged())); 00608 connect(m_searchAlbumButton, SIGNAL(Clicked()), SLOT(searchAlbum())); 00609 00610 // Populate Quality List 00611 new MythUIButtonListItem(m_qualityList, tr("Low"), qVariantFromValue(0)); 00612 new MythUIButtonListItem(m_qualityList, tr("Medium"), qVariantFromValue(1)); 00613 new MythUIButtonListItem(m_qualityList, tr("High"), qVariantFromValue(2)); 00614 new MythUIButtonListItem(m_qualityList, tr("Perfect"), qVariantFromValue(3)); 00615 m_qualityList->SetValueByData(qVariantFromValue( 00616 gCoreContext->GetNumSetting("DefaultRipQuality", 1))); 00617 00618 QTimer::singleShot(500, this, SLOT(startScanCD())); 00619 00620 return true; 00621 } 00622 00623 bool Ripper::keyPressEvent(QKeyEvent *event) 00624 { 00625 if (GetFocusWidget() && GetFocusWidget()->keyPressEvent(event)) 00626 return true; 00627 00628 bool handled = false; 00629 QStringList actions; 00630 handled = GetMythMainWindow()->TranslateKeyPress("Global", event, actions); 00631 00632 for (int i = 0; i < actions.size() && !handled; i++) 00633 { 00634 QString action = actions[i]; 00635 handled = true; 00636 00637 if (action == "INFO") 00638 { 00639 showEditMetadataDialog(m_trackList->GetItemCurrent()); 00640 } 00641 else 00642 handled = false; 00643 } 00644 00645 if (!handled && MythScreenType::keyPressEvent(event)) 00646 handled = true; 00647 00648 return handled; 00649 } 00650 00651 void Ripper::startScanCD(void) 00652 { 00653 if (m_scanThread) 00654 return; 00655 00656 QString message = QObject::tr("Scanning CD. Please Wait ..."); 00657 OpenBusyPopup(message); 00658 00659 m_scanThread = new CDScannerThread(this); 00660 connect(m_scanThread->qthread(), SIGNAL(finished()), SLOT(ScanFinished())); 00661 m_scanThread->start(); 00662 } 00663 00664 void Ripper::ScanFinished() 00665 { 00666 delete m_scanThread; 00667 m_scanThread = NULL; 00668 00669 m_tracks->clear(); 00670 00671 bool isCompilation = false; 00672 if (m_decoder) 00673 { 00674 QString label; 00675 Metadata *metadata; 00676 00677 m_artistName.clear(); 00678 m_albumName.clear(); 00679 m_genreName.clear(); 00680 m_year.clear(); 00681 00682 for (int trackno = 0; trackno < m_decoder->getNumTracks(); trackno++) 00683 { 00684 RipTrack *ripTrack = new RipTrack; 00685 00686 metadata = m_decoder->getMetadata(trackno + 1); 00687 if (metadata) 00688 { 00689 ripTrack->metadata = metadata; 00690 ripTrack->length = metadata->Length(); 00691 00692 if (metadata->Compilation()) 00693 { 00694 isCompilation = true; 00695 m_artistName = metadata->CompilationArtist(); 00696 } 00697 else if (m_artistName.isEmpty()) 00698 { 00699 m_artistName = metadata->Artist(); 00700 } 00701 00702 if (m_albumName.isEmpty()) 00703 m_albumName = metadata->Album(); 00704 00705 if (m_genreName.isEmpty() && !metadata->Genre().isEmpty()) 00706 m_genreName = metadata->Genre(); 00707 00708 if (m_year.isEmpty() && metadata->Year() > 0) 00709 m_year = QString::number(metadata->Year()); 00710 00711 QString title = metadata->Title(); 00712 ripTrack->isNew = isNewTune(m_artistName, m_albumName, title); 00713 00714 ripTrack->active = ripTrack->isNew; 00715 00716 m_tracks->push_back(ripTrack); 00717 00718 } 00719 else 00720 delete ripTrack; 00721 } 00722 00723 m_artistEdit->SetText(m_artistName); 00724 m_albumEdit->SetText(m_albumName); 00725 m_genreEdit->SetText(m_genreName); 00726 m_yearEdit->SetText(m_year); 00727 m_compilationCheck->SetCheckState(isCompilation); 00728 00729 if (!isCompilation) 00730 m_switchTitleArtist->SetVisible(false); 00731 else 00732 m_switchTitleArtist->SetVisible(true); 00733 } 00734 00735 BuildFocusList(); 00736 updateTrackList(); 00737 00738 CloseBusyPopup(); 00739 } 00740 00741 void Ripper::scanCD(void) 00742 { 00743 #ifdef HAVE_CDIO 00744 { 00745 LOG(VB_MEDIA, LOG_INFO, QString("Ripper::%1 CD='%2'"). 00746 arg(__func__).arg(m_CDdevice)); 00747 (void)cdio_close_tray(m_CDdevice.toAscii().constData(), NULL); 00748 } 00749 #endif 00750 00751 if (m_decoder) 00752 delete m_decoder; 00753 00754 m_decoder = new CdDecoder("cda", NULL, NULL, NULL); 00755 if (m_decoder) 00756 m_decoder->setDevice(m_CDdevice); 00757 } 00758 00759 void Ripper::deleteAllExistingTracks(void) 00760 { 00761 QVector<RipTrack*>::iterator it; 00762 for (it = m_tracks->begin(); it < m_tracks->end(); ++it) 00763 { 00764 RipTrack *track = (*it); 00765 if (track && !track->isNew) 00766 { 00767 if (deleteExistingTrack(track)) 00768 { 00769 track->isNew = true; 00770 toggleTrackActive(track); 00771 } 00772 } 00773 } 00774 } 00775 00776 bool Ripper::deleteExistingTrack(RipTrack *track) 00777 { 00778 if (!track) 00779 return false; 00780 00781 Metadata *metadata = track->metadata; 00782 00783 if (!metadata) 00784 return false; 00785 00786 QString artist = metadata->Artist(); 00787 QString album = metadata->Album(); 00788 QString title = metadata->Title(); 00789 00790 MSqlQuery query(MSqlQuery::InitCon()); 00791 QString queryString("SELECT song_id, " 00792 "CONCAT_WS('/', music_directories.path, music_songs.filename) AS filename " 00793 "FROM music_songs " 00794 "LEFT JOIN music_artists" 00795 " ON music_songs.artist_id=music_artists.artist_id " 00796 "LEFT JOIN music_albums" 00797 " ON music_songs.album_id=music_albums.album_id " 00798 "LEFT JOIN music_directories " 00799 " ON music_songs.directory_id=music_directories.directory_id " 00800 "WHERE artist_name REGEXP \'"); 00801 QString token = artist; 00802 token.replace(QRegExp("(/|\\\\|:|\'|\\,|\\!|\\(|\\)|\"|\\?|\\|)"), 00803 QString(".")); 00804 00805 queryString += token + "\' AND " + "album_name REGEXP \'"; 00806 token = album; 00807 token.replace(QRegExp("(/|\\\\|:|\'|\\,|\\!|\\(|\\)|\"|\\?|\\|)"), 00808 QString(".")); 00809 queryString += token + "\' AND " + "name REGEXP \'"; 00810 token = title; 00811 token.replace(QRegExp("(/|\\\\|:|\'|\\,|\\!|\\(|\\)|\"|\\?|\\|)"), 00812 QString(".")); 00813 queryString += token + "\' ORDER BY artist_name, album_name," 00814 " name, song_id, filename LIMIT 1"; 00815 query.prepare(queryString); 00816 00817 if (!query.exec() || !query.isActive()) 00818 { 00819 MythDB::DBError("Search music database", query); 00820 return false; 00821 } 00822 00823 if (query.next()) 00824 { 00825 int trackID = query.value(0).toInt(); 00826 QString filename = gMusicData->musicDir + query.value(1).toString(); 00827 00828 // delete file 00829 if (!QFile::remove(filename)) 00830 { 00831 LOG(VB_GENERAL, LOG_NOTICE, QString("Ripper::deleteExistingTrack() " 00832 "Could not delete %1") 00833 .arg(filename)); 00834 return false; 00835 } 00836 00837 // remove database entry 00838 MSqlQuery deleteQuery(MSqlQuery::InitCon()); 00839 deleteQuery.prepare("DELETE FROM music_songs" 00840 " WHERE song_id = :SONG_ID"); 00841 deleteQuery.bindValue(":SONG_ID", trackID); 00842 if (!deleteQuery.exec()) 00843 { 00844 MythDB::DBError("Delete Track", deleteQuery); 00845 return false; 00846 } 00847 return true; 00848 } 00849 00850 return false; 00851 } 00852 00853 bool Ripper::somethingWasRipped() 00854 { 00855 return m_somethingwasripped; 00856 } 00857 00858 void Ripper::artistChanged() 00859 { 00860 QString newartist = m_artistEdit->GetText(); 00861 Metadata *data; 00862 00863 if (m_tracks->size() > 0) 00864 { 00865 for (int trackno = 0; trackno < m_tracks->size(); ++trackno) 00866 { 00867 data = m_tracks->at(trackno)->metadata; 00868 00869 if (data) 00870 { 00871 if (m_compilationCheck->GetBooleanCheckState()) 00872 { 00873 data->setCompilationArtist(newartist); 00874 } 00875 else 00876 { 00877 data->setArtist(newartist); 00878 data->setCompilationArtist(""); 00879 } 00880 } 00881 } 00882 00883 updateTrackList(); 00884 } 00885 00886 m_artistName = newartist; 00887 } 00888 00889 void Ripper::albumChanged() 00890 { 00891 QString newalbum = m_albumEdit->GetText(); 00892 Metadata *data; 00893 00894 if (m_tracks->size() > 0) 00895 { 00896 for (int trackno = 0; trackno < m_tracks->size(); ++trackno) 00897 { 00898 data = m_tracks->at(trackno)->metadata; 00899 00900 if (data) 00901 data->setAlbum(newalbum); 00902 } 00903 } 00904 00905 m_albumName = newalbum; 00906 } 00907 00908 void Ripper::genreChanged() 00909 { 00910 QString newgenre = m_genreEdit->GetText(); 00911 Metadata *data; 00912 00913 if (m_tracks->size() > 0) 00914 { 00915 for (int trackno = 0; trackno < m_tracks->size(); ++trackno) 00916 { 00917 data = m_tracks->at(trackno)->metadata; 00918 00919 if (data) 00920 data->setGenre(newgenre); 00921 } 00922 } 00923 00924 m_genreName = newgenre; 00925 } 00926 00927 void Ripper::yearChanged() 00928 { 00929 QString newyear = m_yearEdit->GetText(); 00930 00931 Metadata *data; 00932 00933 if (m_tracks->size() > 0) 00934 { 00935 for (int trackno = 0; trackno < m_tracks->size(); ++trackno) 00936 { 00937 data = m_tracks->at(trackno)->metadata; 00938 00939 if (data) 00940 data->setYear(newyear.toInt()); 00941 } 00942 } 00943 00944 m_year = newyear; 00945 } 00946 00947 void Ripper::compilationChanged(bool state) 00948 { 00949 if (!state) 00950 { 00951 Metadata *data; 00952 if (m_tracks->size() > 0) 00953 { 00954 // Update artist MetaData of each track on the ablum... 00955 for (int trackno = 0; trackno < m_tracks->size(); ++trackno) 00956 { 00957 data = m_tracks->at(trackno)->metadata; 00958 00959 if (data) 00960 { 00961 data->setCompilationArtist(""); 00962 data->setArtist(m_artistName); 00963 data->setCompilation(false); 00964 } 00965 } 00966 } 00967 00968 m_switchTitleArtist->SetVisible(false); 00969 } 00970 else 00971 { 00972 if (m_tracks->size() > 0) 00973 { 00974 // Update artist MetaData of each track on the album... 00975 for (int trackno = 0; trackno < m_tracks->size(); ++trackno) 00976 { 00977 Metadata *data; 00978 data = m_tracks->at(trackno)->metadata; 00979 00980 if (data) 00981 { 00982 data->setCompilationArtist(m_artistName); 00983 data->setCompilation(true); 00984 } 00985 } 00986 } 00987 00988 m_switchTitleArtist->SetVisible(true); 00989 } 00990 00991 BuildFocusList(); 00992 updateTrackList(); 00993 } 00994 00995 void Ripper::switchTitlesAndArtists() 00996 { 00997 if (!m_compilationCheck->GetBooleanCheckState()) 00998 return; 00999 01000 Metadata *data; 01001 01002 // Switch title and artist for each track 01003 QString tmp; 01004 if (m_tracks->size() > 0) 01005 { 01006 for (int track = 0; track < m_tracks->size(); ++track) 01007 { 01008 data = m_tracks->at(track)->metadata; 01009 01010 if (data) 01011 { 01012 tmp = data->Artist(); 01013 data->setArtist(data->Title()); 01014 data->setTitle(tmp); 01015 } 01016 } 01017 01018 updateTrackList(); 01019 } 01020 } 01021 01022 void Ripper::startRipper(void) 01023 { 01024 if (m_tracks->isEmpty()) 01025 { 01026 ShowOkPopup(tr("There are no tracks to rip?")); 01027 return; 01028 } 01029 01030 MythScreenStack *mainStack = GetMythMainWindow()->GetMainStack(); 01031 01032 int quality = m_qualityList->GetItemCurrent()->GetData().toInt(); 01033 01034 RipStatus *statusDialog = new RipStatus(mainStack, m_CDdevice, m_tracks, 01035 quality); 01036 01037 if (statusDialog->Create()) 01038 { 01039 connect(statusDialog, SIGNAL(Result(bool)), SLOT(RipComplete(bool))); 01040 mainStack->AddScreen(statusDialog); 01041 } 01042 else 01043 delete statusDialog; 01044 } 01045 01046 void Ripper::RipComplete(bool result) 01047 { 01048 if (result == true) 01049 { 01050 bool EjectCD = gCoreContext->GetNumSetting("EjectCDAfterRipping", 1); 01051 if (EjectCD) 01052 startEjectCD(); 01053 01054 ShowOkPopup(tr("Rip completed successfully.")); 01055 01056 m_somethingwasripped = true; 01057 } 01058 01059 if (LCD *lcd = LCD::Get()) 01060 lcd->switchToTime(); 01061 } 01062 01063 01064 void Ripper::startEjectCD() 01065 { 01066 if (m_ejectThread) 01067 return; 01068 01069 QString message = tr("Ejecting CD. Please Wait ..."); 01070 01071 OpenBusyPopup(message); 01072 01073 m_ejectThread = new CDEjectorThread(this); 01074 connect(m_ejectThread->qthread(), 01075 SIGNAL(finished()), SLOT(EjectFinished())); 01076 m_ejectThread->start(); 01077 } 01078 01079 void Ripper::EjectFinished() 01080 { 01081 delete m_ejectThread; 01082 m_ejectThread = NULL; 01083 01084 CloseBusyPopup(); 01085 } 01086 01087 void Ripper::ejectCD() 01088 { 01089 LOG(VB_MEDIA, LOG_INFO, __PRETTY_FUNCTION__); 01090 bool bEjectCD = gCoreContext->GetNumSetting("EjectCDAfterRipping",1); 01091 if (bEjectCD) 01092 { 01093 #ifdef HAVE_CDIO 01094 LOG(VB_MEDIA, LOG_INFO, QString("Ripper::%1 '%2'"). 01095 arg(__func__).arg(m_CDdevice)); 01096 (void)cdio_eject_media_drive(m_CDdevice.toAscii().constData()); 01097 #else 01098 MediaMonitor *mon = MediaMonitor::GetMediaMonitor(); 01099 if (mon) 01100 { 01101 QByteArray devname = m_CDdevice.toAscii(); 01102 MythMediaDevice *pMedia = mon->GetMedia(devname.constData()); 01103 if (pMedia && mon->ValidateAndLock(pMedia)) 01104 { 01105 pMedia->eject(); 01106 mon->Unlock(pMedia); 01107 } 01108 } 01109 #endif 01110 } 01111 } 01112 01113 void Ripper::updateTrackList(void) 01114 { 01115 if (m_tracks->isEmpty()) 01116 return; 01117 01118 QString tmptitle; 01119 if (m_trackList) 01120 { 01121 m_trackList->Reset(); 01122 01123 int i; 01124 for (i = 0; i < (int)m_tracks->size(); i++) 01125 { 01126 if (i >= m_tracks->size()) 01127 break; 01128 01129 RipTrack *track = m_tracks->at(i); 01130 Metadata *metadata = track->metadata; 01131 01132 MythUIButtonListItem *item = new MythUIButtonListItem(m_trackList,""); 01133 01134 item->setCheckable(true); 01135 01136 item->SetData(qVariantFromValue(track)); 01137 01138 if (track->isNew) 01139 item->DisplayState("new", "yes"); 01140 else 01141 item->DisplayState("new", "no"); 01142 01143 if (track->active) 01144 item->setChecked(MythUIButtonListItem::FullChecked); 01145 else 01146 item->setChecked(MythUIButtonListItem::NotChecked); 01147 01148 item->SetText(QString::number(metadata->Track()), "track"); 01149 item->SetText(metadata->Title(), "title"); 01150 item->SetText(metadata->Artist(), "artist"); 01151 01152 int length = track->length / 1000; 01153 if (length > 0) 01154 { 01155 int min, sec; 01156 min = length / 60; 01157 sec = length % 60; 01158 QString s; 01159 s.sprintf("%02d:%02d", min, sec); 01160 item->SetText(s, "length"); 01161 } 01162 else 01163 item->SetText("", "length"); 01164 01165 // if (i == m_currentTrack) 01166 // m_trackList->SetItemCurrent(i); 01167 } 01168 } 01169 } 01170 01171 void Ripper::searchArtist() 01172 { 01173 QString msg = tr("Select an Artist"); 01174 QStringList searchList = Metadata::fillFieldList("artist"); 01175 01176 MythScreenStack *popupStack = GetMythMainWindow()->GetStack("popup stack"); 01177 MythUISearchDialog *searchDlg = new MythUISearchDialog(popupStack, msg, searchList, false, ""); 01178 01179 if (!searchDlg->Create()) 01180 { 01181 delete searchDlg; 01182 return; 01183 } 01184 01185 connect(searchDlg, SIGNAL(haveResult(QString)), SLOT(setArtist(QString))); 01186 01187 popupStack->AddScreen(searchDlg); 01188 } 01189 01190 void Ripper::setArtist(QString artist) 01191 { 01192 m_artistEdit->SetText(artist); 01193 } 01194 01195 void Ripper::searchAlbum() 01196 { 01197 QString msg = tr("Select an Album"); 01198 QStringList searchList = Metadata::fillFieldList("album"); 01199 01200 MythScreenStack *popupStack = GetMythMainWindow()->GetStack("popup stack"); 01201 MythUISearchDialog *searchDlg = new MythUISearchDialog(popupStack, msg, searchList, false, ""); 01202 01203 if (!searchDlg->Create()) 01204 { 01205 delete searchDlg; 01206 return; 01207 } 01208 01209 connect(searchDlg, SIGNAL(haveResult(QString)), SLOT(setAlbum(QString))); 01210 01211 popupStack->AddScreen(searchDlg); 01212 } 01213 01214 void Ripper::setAlbum(QString album) 01215 { 01216 m_albumEdit->SetText(album); 01217 } 01218 01219 void Ripper::searchGenre() 01220 { 01221 QString msg = tr("Select a Genre"); 01222 QStringList searchList = Metadata::fillFieldList("genre"); 01223 // load genre list 01224 m_searchList.clear(); 01225 for (int x = 0; x < genre_table_size; x++) 01226 m_searchList.push_back(QString(genre_table[x])); 01227 m_searchList.sort(); 01228 01229 MythScreenStack *popupStack = GetMythMainWindow()->GetStack("popup stack"); 01230 MythUISearchDialog *searchDlg = new MythUISearchDialog(popupStack, msg, searchList, false, ""); 01231 01232 if (!searchDlg->Create()) 01233 { 01234 delete searchDlg; 01235 return; 01236 } 01237 01238 connect(searchDlg, SIGNAL(haveResult(QString)), SLOT(setGenre(QString))); 01239 01240 popupStack->AddScreen(searchDlg); 01241 } 01242 01243 void Ripper::setGenre(QString genre) 01244 { 01245 m_genreEdit->SetText(genre); 01246 } 01247 01248 void Ripper::showEditMetadataDialog(MythUIButtonListItem *item) 01249 { 01250 if (!item || m_tracks->isEmpty()) 01251 return; 01252 01253 RipTrack *track = qVariantValue<RipTrack *>(item->GetData()); 01254 01255 if (!track) 01256 return; 01257 01258 Metadata *editMeta = track->metadata; 01259 01260 MythScreenStack *mainStack = GetMythMainWindow()->GetMainStack(); 01261 01262 EditMetadataDialog *editDialog = new EditMetadataDialog(mainStack, editMeta); 01263 editDialog->setSaveMetadataOnly(); 01264 01265 if (!editDialog->Create()) 01266 { 01267 delete editDialog; 01268 return; 01269 } 01270 01271 connect(editDialog, SIGNAL(metadataChanged()), this, SLOT(metadataChanged())); 01272 01273 mainStack->AddScreen(editDialog); 01274 } 01275 01276 void Ripper::metadataChanged(void) 01277 { 01278 updateTrackList(); 01279 } 01280 01281 void Ripper::toggleTrackActive(RipTrack* track) 01282 { 01283 QVariant data = QVariant::fromValue(track); 01284 MythUIButtonListItem *item = m_trackList->GetItemByData(data); 01285 if (item) 01286 { 01287 toggleTrackActive(item); 01288 } 01289 } 01290 01291 void Ripper::toggleTrackActive(MythUIButtonListItem *item) 01292 { 01293 if (m_tracks->isEmpty() || !item) 01294 return; 01295 01296 RipTrack *track = m_tracks->at(m_trackList->GetItemPos(item)); 01297 01298 if (!track->active && !track->isNew) 01299 { 01300 ShowConflictMenu(track); 01301 return; 01302 } 01303 01304 track->active = !track->active; 01305 01306 if (track->active) 01307 item->setChecked(MythUIButtonListItem::FullChecked); 01308 else 01309 item->setChecked(MythUIButtonListItem::NotChecked); 01310 01311 updateTrackLengths(); 01312 } 01313 01314 void Ripper::ShowConflictMenu(RipTrack* track) 01315 { 01316 MythScreenStack *popupStack = GetMythMainWindow()->GetStack("popup stack"); 01317 01318 QString msg = tr("This track has been disabled because it is already " 01319 "present in the database.\n" 01320 "Do you want to permanently delete the existing " 01321 "file(s)?"); 01322 MythDialogBox *menu = new MythDialogBox(msg, popupStack, "conflictmenu", 01323 true); 01324 01325 if (menu->Create()) 01326 popupStack->AddScreen(menu); 01327 else 01328 { 01329 delete menu; 01330 return; 01331 } 01332 01333 menu->SetReturnEvent(this, "conflictmenu"); 01334 menu->AddButton(tr("No, Cancel")); 01335 menu->AddButton(tr("Yes, Delete"), QVariant::fromValue(track)); 01336 menu->AddButton(tr("Yes, Delete All")); 01337 } 01338 01339 void Ripper::updateTrackLengths() 01340 { 01341 QVector<RipTrack*>::iterator it; 01342 RipTrack *track; 01343 int length = 0; 01344 01345 for (it = m_tracks->end() - 1; it == m_tracks->begin(); --it) 01346 { 01347 track = *it; 01348 if (track->active) 01349 { 01350 track->length = length + track->metadata->Length(); 01351 length = 0; 01352 } 01353 else 01354 { 01355 track->length = 0; 01356 length += track->metadata->Length(); 01357 } 01358 } 01359 } 01360 01361 void Ripper::customEvent(QEvent* event) 01362 { 01363 if (event->type() == DialogCompletionEvent::kEventType) 01364 { 01365 DialogCompletionEvent *dce = static_cast<DialogCompletionEvent *>(event); 01366 01367 if (dce->GetId() == "conflictmenu") 01368 { 01369 int buttonNum = dce->GetResult(); 01370 RipTrack *track = qVariantValue<RipTrack *>(dce->GetData()); 01371 01372 switch (buttonNum) 01373 { 01374 case 0: 01375 // Do nothing 01376 break; 01377 case 1: 01378 if (deleteExistingTrack(track)) 01379 { 01380 track->isNew = true; 01381 toggleTrackActive(track); 01382 } 01383 break; 01384 case 2: 01385 deleteAllExistingTracks(); 01386 break; 01387 default: 01388 break; 01389 } 01390 } 01391 01392 return; 01393 } 01394 01395 MythUIType::customEvent(event); 01396 } 01397 01398 01400 01401 RipStatus::RipStatus(MythScreenStack *parent, const QString &device, 01402 QVector<RipTrack*> *tracks, int quality) 01403 : MythScreenType(parent, "ripstatus") 01404 { 01405 m_CDdevice = device; 01406 m_tracks = tracks; 01407 m_quality = quality; 01408 m_ripperThread = NULL; 01409 01410 m_overallText = m_trackText = m_statusText = m_trackPctText = 01411 m_overallPctText = NULL; 01412 01413 m_overallProgress = m_trackProgress = NULL; 01414 } 01415 01416 RipStatus::~RipStatus(void) 01417 { 01418 if (m_ripperThread) 01419 delete m_ripperThread; 01420 01421 if (LCD *lcd = LCD::Get()) 01422 lcd->switchToTime(); 01423 } 01424 01425 bool RipStatus::Create(void) 01426 { 01427 if (!LoadWindowFromXML("music-ui.xml", "ripstatus", this)) 01428 return false; 01429 01430 m_overallText = dynamic_cast<MythUIText *>(GetChild("overall")); 01431 m_trackText = dynamic_cast<MythUIText *>(GetChild("track")); 01432 m_statusText = dynamic_cast<MythUIText *>(GetChild("status")); 01433 m_trackPctText = dynamic_cast<MythUIText *>(GetChild("trackpct")); 01434 m_overallPctText = dynamic_cast<MythUIText *>(GetChild("overallpct")); 01435 01436 m_overallProgress = dynamic_cast<MythUIProgressBar *>(GetChild("overall_progress")); 01437 m_trackProgress = dynamic_cast<MythUIProgressBar *>(GetChild("track_progress")); 01438 01439 BuildFocusList(); 01440 01441 startRip(); 01442 01443 return true; 01444 } 01445 01446 bool RipStatus::keyPressEvent(QKeyEvent *event) 01447 { 01448 if (GetFocusWidget() && GetFocusWidget()->keyPressEvent(event)) 01449 return true; 01450 01451 bool handled = false; 01452 QStringList actions; 01453 handled = GetMythMainWindow()->TranslateKeyPress("Global", event, actions); 01454 01455 for (int i = 0; i < actions.size() && !handled; i++) 01456 { 01457 QString action = actions[i]; 01458 handled = true; 01459 01460 01461 if (action == "ESCAPE" && 01462 m_ripperThread && m_ripperThread->isRunning()) 01463 { 01464 MythConfirmationDialog *dialog = 01465 ShowOkPopup(tr("Cancel ripping the CD?"), this, NULL, true); 01466 if (dialog) 01467 dialog->SetReturnEvent(this, "stop_ripping"); 01468 } 01469 else 01470 handled = false; 01471 } 01472 01473 if (!handled && MythScreenType::keyPressEvent(event)) 01474 handled = true; 01475 01476 return handled; 01477 } 01478 01479 void RipStatus::customEvent(QEvent *event) 01480 { 01481 if (event->type() == DialogCompletionEvent::kEventType) 01482 { 01483 DialogCompletionEvent *dce = static_cast<DialogCompletionEvent *>(event); 01484 01485 if (dce->GetId() == "stop_ripping" && dce->GetResult()) 01486 { 01487 m_ripperThread->cancel(); 01488 m_ripperThread->wait(); 01489 Close(); 01490 } 01491 01492 return; 01493 } 01494 01495 RipStatusEvent *rse = dynamic_cast<RipStatusEvent *> (event); 01496 01497 if (!rse) 01498 return; 01499 01500 if (event->type() == RipStatusEvent::kTrackTextEvent) 01501 { 01502 if (m_trackText) 01503 m_trackText->SetText(rse->text); 01504 } 01505 else if (event->type() == RipStatusEvent::kOverallTextEvent) 01506 { 01507 if (m_overallText) 01508 m_overallText->SetText(rse->text); 01509 } 01510 else if (event->type() == RipStatusEvent::kStatusTextEvent) 01511 { 01512 if (m_statusText) 01513 m_statusText->SetText(rse->text); 01514 } 01515 else if (event->type() == RipStatusEvent::kTrackProgressEvent) 01516 { 01517 if (m_trackProgress) 01518 m_trackProgress->SetUsed(rse->value); 01519 } 01520 else if (event->type() == RipStatusEvent::kTrackPercentEvent) 01521 { 01522 if (m_trackPctText) 01523 m_trackPctText->SetText(QString("%1%").arg(rse->value)); 01524 } 01525 else if (event->type() == RipStatusEvent::kTrackStartEvent) 01526 { 01527 if (m_trackProgress) 01528 m_trackProgress->SetTotal(rse->value); 01529 } 01530 else if (event->type() == RipStatusEvent::kOverallProgressEvent) 01531 { 01532 if (m_overallProgress) 01533 m_overallProgress->SetUsed(rse->value); 01534 } 01535 else if (event->type() == RipStatusEvent::kOverallStartEvent) 01536 { 01537 if (m_overallProgress) 01538 m_overallProgress->SetTotal(rse->value); 01539 } 01540 else if (event->type() == RipStatusEvent::kOverallPercentEvent) 01541 { 01542 if (m_overallPctText) 01543 m_overallPctText->SetText(QString("%1%").arg(rse->value)); 01544 } 01545 else if (event->type() == RipStatusEvent::kFinishedEvent) 01546 { 01547 emit Result(true); 01548 Close(); 01549 } 01550 else if (event->type() == RipStatusEvent::kEncoderErrorEvent) 01551 { 01552 ShowOkPopup(tr("The encoder failed to create the file.\n" 01553 "Do you have write permissions" 01554 " for the music directory?")); 01555 Close(); 01556 } 01557 else 01558 { 01559 LOG(VB_GENERAL, LOG_ERR, "Received an unknown event type!"); 01560 } 01561 } 01562 01563 void RipStatus::startRip(void) 01564 { 01565 if (m_ripperThread) 01566 delete m_ripperThread; 01567 01568 m_ripperThread = new CDRipperThread(this, m_CDdevice, m_tracks, m_quality); 01569 m_ripperThread->start(); 01570 }
1.7.6.1