|
MythTV
0.26-pre
|
00001 #include <unistd.h> 00002 00003 #include <stdlib.h> 00004 #include <unistd.h> 00005 #include <iostream> 00006 #include <cstdlib> 00007 #include <sys/wait.h> // for WIFEXITED and WEXITSTATUS 00008 00009 // qt 00010 #include <QDir> 00011 #include <QDomDocument> 00012 #include <QApplication> 00013 #include <QKeyEvent> 00014 #include <QTextStream> 00015 00016 // myth 00017 #include <mythcontext.h> 00018 #include <mythdb.h> 00019 #include <mythdirs.h> 00020 #include <mythprogressdialog.h> 00021 #include <mythuihelper.h> 00022 #include <mythdialogbox.h> 00023 #include <mythuitext.h> 00024 #include <mythuibutton.h> 00025 #include <mythuicheckbox.h> 00026 #include <mythuibuttonlist.h> 00027 #include <mythuiprogressbar.h> 00028 #include <mythmiscutil.h> 00029 #include <mythsystem.h> 00030 #include <exitcodes.h> 00031 00032 // mytharchive 00033 #include "archiveutil.h" 00034 #include "mythburn.h" 00035 #include "editmetadata.h" 00036 #include "fileselector.h" 00037 #include "thumbfinder.h" 00038 #include "recordingselector.h" 00039 #include "videoselector.h" 00040 #include "logviewer.h" 00041 00042 using namespace std; 00043 00044 MythBurn::MythBurn(MythScreenStack *parent, 00045 MythScreenType *destinationScreen, 00046 MythScreenType *themeScreen, 00047 ArchiveDestination archiveDestination, QString name) : 00048 MythScreenType(parent, name), 00049 m_destinationScreen(destinationScreen), 00050 m_themeScreen(themeScreen), 00051 m_archiveDestination(archiveDestination), 00052 m_bCreateISO(false), 00053 m_bDoBurn(false), 00054 m_bEraseDvdRw(false), 00055 m_saveFilename(""), 00056 m_theme(), 00057 m_moveMode(false), 00058 m_nextButton(NULL), 00059 m_prevButton(NULL), 00060 m_cancelButton(NULL), 00061 m_archiveButtonList(NULL), 00062 m_nofilesText(NULL), 00063 m_addrecordingButton(NULL), 00064 m_addvideoButton(NULL), 00065 m_addfileButton(NULL), 00066 m_sizeBar(NULL), 00067 m_maxsizeText(NULL), 00068 m_minsizeText(NULL), 00069 m_currentsizeErrorText(NULL), 00070 m_currentsizeText(NULL) 00071 { 00072 // remove any old thumb images 00073 QString thumbDir = getTempDirectory() + "/config/thumbs"; 00074 QDir dir(thumbDir); 00075 if (dir.exists() && !MythRemoveDirectory(dir)) 00076 LOG(VB_GENERAL, LOG_ERR, "MythBurn: Failed to clear thumb directory"); 00077 } 00078 00079 MythBurn::~MythBurn(void) 00080 { 00081 saveConfiguration(); 00082 00083 while (!m_profileList.isEmpty()) 00084 delete m_profileList.takeFirst(); 00085 m_profileList.clear(); 00086 00087 while (!m_archiveList.isEmpty()) 00088 delete m_archiveList.takeFirst(); 00089 m_archiveList.clear(); 00090 } 00091 00092 bool MythBurn::Create(void) 00093 { 00094 bool foundtheme = false; 00095 00096 // Load the theme for this screen 00097 foundtheme = LoadWindowFromXML("mythburn-ui.xml", "mythburn", this); 00098 00099 if (!foundtheme) 00100 return false; 00101 00102 bool err = false; 00103 UIUtilE::Assign(this, m_nextButton, "next_button", &err); 00104 UIUtilE::Assign(this, m_prevButton, "prev_button", &err); 00105 UIUtilE::Assign(this, m_cancelButton, "cancel_button", &err); 00106 UIUtilE::Assign(this, m_nofilesText, "nofiles", &err); 00107 UIUtilE::Assign(this, m_archiveButtonList, "archivelist", &err); 00108 UIUtilE::Assign(this, m_addrecordingButton, "addrecording_button", &err); 00109 UIUtilE::Assign(this, m_addvideoButton, "addvideo_button", &err); 00110 UIUtilE::Assign(this, m_addfileButton, "addfile_button", &err); 00111 UIUtilE::Assign(this, m_maxsizeText, "maxsize", &err); 00112 UIUtilE::Assign(this, m_minsizeText, "minsize", &err); 00113 UIUtilE::Assign(this, m_currentsizeErrorText, "currentsize_error", &err); 00114 UIUtilE::Assign(this, m_currentsizeText, "currentsize", &err); 00115 UIUtilE::Assign(this, m_sizeBar, "size_bar", &err); 00116 00117 if (err) 00118 { 00119 LOG(VB_GENERAL, LOG_ERR, "Cannot load screen 'mythburn'"); 00120 return false; 00121 } 00122 00123 connect(m_nextButton, SIGNAL(Clicked()), this, SLOT(handleNextPage())); 00124 connect(m_prevButton, SIGNAL(Clicked()), this, SLOT(handlePrevPage())); 00125 connect(m_cancelButton, SIGNAL(Clicked()), this, SLOT(handleCancel())); 00126 00127 00128 loadEncoderProfiles(); 00129 loadConfiguration(); 00130 00131 updateArchiveList(); 00132 00133 connect(m_addrecordingButton, SIGNAL(Clicked()), 00134 this, SLOT(handleAddRecording())); 00135 00136 connect(m_addvideoButton, SIGNAL(Clicked()), this, SLOT(handleAddVideo())); 00137 connect(m_addfileButton, SIGNAL(Clicked()), this, SLOT(handleAddFile())); 00138 connect(m_archiveButtonList, SIGNAL(itemClicked(MythUIButtonListItem *)), 00139 this, SLOT(itemClicked(MythUIButtonListItem *))); 00140 00141 BuildFocusList(); 00142 00143 SetFocusWidget(m_nextButton); 00144 00145 return true; 00146 } 00147 00148 bool MythBurn::keyPressEvent(QKeyEvent *event) 00149 { 00150 if (!m_moveMode && GetFocusWidget()->keyPressEvent(event)) 00151 return true; 00152 00153 bool handled = false; 00154 QStringList actions; 00155 handled = GetMythMainWindow()->TranslateKeyPress("Archive", event, actions); 00156 00157 for (int i = 0; i < actions.size() && !handled; i++) 00158 { 00159 QString action = actions[i]; 00160 handled = true; 00161 00162 // if we are currently moving an item, 00163 // we only accept UP/DOWN/SELECT/ESCAPE 00164 if (m_moveMode) 00165 { 00166 MythUIButtonListItem *item = m_archiveButtonList->GetItemCurrent(); 00167 if (!item) 00168 return false; 00169 00170 if (action == "SELECT" || action == "ESCAPE") 00171 { 00172 m_moveMode = false; 00173 item->DisplayState("off", "movestate"); 00174 } 00175 else if (action == "UP") 00176 { 00177 item->MoveUpDown(true); 00178 } 00179 else if (action == "DOWN") 00180 { 00181 item->MoveUpDown(false); 00182 } 00183 00184 return true; 00185 } 00186 00187 if (action == "MENU") 00188 { 00189 showMenu(); 00190 } 00191 else if (action == "DELETE") 00192 { 00193 removeItem(); 00194 } 00195 else if (action == "INFO") 00196 { 00197 editThumbnails(); 00198 } 00199 else if (action == "TOGGLECUT") 00200 { 00201 toggleUseCutlist(); 00202 } 00203 else 00204 handled = false; 00205 } 00206 00207 if (!handled && MythScreenType::keyPressEvent(event)) 00208 handled = true; 00209 00210 return handled; 00211 } 00212 00213 void MythBurn::updateSizeBar(void) 00214 { 00215 int64_t size = 0; 00216 ArchiveItem *a; 00217 for (int x = 0; x < m_archiveList.size(); x++) 00218 { 00219 a = m_archiveList.at(x); 00220 size += a->newsize; 00221 } 00222 00223 uint usedSpace = size / 1024 / 1024; 00224 00225 QString tmpSize; 00226 00227 m_sizeBar->SetTotal(m_archiveDestination.freeSpace / 1024); 00228 m_sizeBar->SetUsed(usedSpace); 00229 00230 tmpSize = QString("%1 Mb").arg(m_archiveDestination.freeSpace / 1024); 00231 00232 m_maxsizeText->SetText(tmpSize); 00233 00234 m_minsizeText->SetText("0 Mb"); 00235 00236 tmpSize = QString("%1 Mb").arg(usedSpace); 00237 00238 if (usedSpace > m_archiveDestination.freeSpace / 1024) 00239 { 00240 m_currentsizeText->Hide(); 00241 00242 m_currentsizeErrorText->SetText(tmpSize); 00243 m_currentsizeErrorText->Show(); 00244 } 00245 else 00246 { 00247 m_currentsizeErrorText->Hide(); 00248 00249 m_currentsizeText->SetText(tmpSize); 00250 m_currentsizeText->Show(); 00251 } 00252 } 00253 00254 void MythBurn::loadEncoderProfiles() 00255 { 00256 EncoderProfile *item = new EncoderProfile; 00257 item->name = "NONE"; 00258 item->description = ""; 00259 item->bitrate = 0.0f; 00260 m_profileList.append(item); 00261 00262 // find the encoding profiles 00263 // first look in the ConfDir (~/.mythtv) 00264 QString filename = GetConfDir() + 00265 "/MythArchive/ffmpeg_dvd_" + 00266 ((gCoreContext->GetSetting("MythArchiveVideoFormat", "pal") 00267 .toLower() == "ntsc") ? "ntsc" : "pal") + ".xml"; 00268 00269 if (!QFile::exists(filename)) 00270 { 00271 // not found yet so use the default profiles 00272 filename = GetShareDir() + 00273 "mytharchive/encoder_profiles/ffmpeg_dvd_" + 00274 ((gCoreContext->GetSetting("MythArchiveVideoFormat", "pal") 00275 .toLower() == "ntsc") ? "ntsc" : "pal") + ".xml"; 00276 } 00277 00278 LOG(VB_GENERAL, LOG_NOTICE, 00279 "MythArchive: Loading encoding profiles from " + filename); 00280 00281 QDomDocument doc("mydocument"); 00282 QFile file(filename); 00283 if (!file.open(QIODevice::ReadOnly)) 00284 return; 00285 00286 if (!doc.setContent( &file )) 00287 { 00288 file.close(); 00289 return; 00290 } 00291 file.close(); 00292 00293 QDomElement docElem = doc.documentElement(); 00294 QDomNodeList profileNodeList = doc.elementsByTagName("profile"); 00295 QString name, desc, bitrate; 00296 00297 for (int x = 0; x < (int) profileNodeList.count(); x++) 00298 { 00299 QDomNode n = profileNodeList.item(x); 00300 QDomElement e = n.toElement(); 00301 QDomNode n2 = e.firstChild(); 00302 while (!n2.isNull()) 00303 { 00304 QDomElement e2 = n2.toElement(); 00305 if(!e2.isNull()) 00306 { 00307 if (e2.tagName() == "name") 00308 name = e2.text(); 00309 if (e2.tagName() == "description") 00310 desc = e2.text(); 00311 if (e2.tagName() == "bitrate") 00312 bitrate = e2.text(); 00313 00314 } 00315 n2 = n2.nextSibling(); 00316 00317 } 00318 00319 EncoderProfile *item = new EncoderProfile; 00320 item->name = name; 00321 item->description = desc; 00322 item->bitrate = bitrate.toFloat(); 00323 m_profileList.append(item); 00324 } 00325 } 00326 00327 void MythBurn::toggleUseCutlist(void) 00328 { 00329 MythUIButtonListItem *item = m_archiveButtonList->GetItemCurrent(); 00330 ArchiveItem *a = qVariantValue<ArchiveItem *>(item->GetData()); 00331 00332 if (!a) 00333 return; 00334 00335 if (!a->hasCutlist) 00336 return; 00337 00338 a->useCutlist = !a->useCutlist; 00339 00340 if (a->hasCutlist) 00341 { 00342 if (a->useCutlist) 00343 { 00344 item->SetText(tr("Using Cut List"), "cutlist"); 00345 item->DisplayState("using", "cutliststatus"); 00346 } 00347 else 00348 { 00349 item->SetText(tr("Not Using Cut List"), "cutlist"); 00350 item->DisplayState("notusing", "cutliststatus"); 00351 } 00352 } 00353 else 00354 { 00355 item->SetText(tr("No Cut List"), "cutlist"); 00356 item->DisplayState("none", "cutliststatus"); 00357 } 00358 recalcItemSize(a); 00359 updateSizeBar(); 00360 } 00361 00362 void MythBurn::handleNextPage() 00363 { 00364 if (m_archiveList.size() == 0) 00365 { 00366 ShowOkPopup(tr("You need to add at least one item to archive!")); 00367 return; 00368 } 00369 00370 runScript(); 00371 } 00372 00373 void MythBurn::handlePrevPage() 00374 { 00375 Close(); 00376 } 00377 00378 void MythBurn::handleCancel() 00379 { 00380 m_destinationScreen->Close(); 00381 m_themeScreen->Close(); 00382 Close(); 00383 } 00384 00385 QString MythBurn::loadFile(const QString &filename) 00386 { 00387 QString res = ""; 00388 00389 QFile file(filename); 00390 00391 if (!file.exists()) 00392 return ""; 00393 00394 if (file.open( QIODevice::ReadOnly )) 00395 { 00396 QTextStream stream(&file); 00397 00398 while ( !stream.atEnd() ) 00399 { 00400 res = res + stream.readLine(); 00401 } 00402 file.close(); 00403 } 00404 else 00405 return ""; 00406 00407 return res; 00408 } 00409 00410 void MythBurn::updateArchiveList(void) 00411 { 00412 QString message = tr("Retrieving File Information. Please Wait..."); 00413 00414 MythScreenStack *popupStack = GetMythMainWindow()->GetStack("popup stack"); 00415 00416 MythUIBusyDialog *busyPopup = new 00417 MythUIBusyDialog(message, popupStack, "mythburnbusydialog"); 00418 00419 if (busyPopup->Create()) 00420 popupStack->AddScreen(busyPopup, false); 00421 else 00422 { 00423 delete busyPopup; 00424 busyPopup = NULL; 00425 } 00426 00427 qApp->processEvents(); 00428 00429 m_archiveButtonList->Reset(); 00430 00431 if (m_archiveList.size() == 0) 00432 { 00433 m_nofilesText->Show(); 00434 } 00435 else 00436 { 00437 ArchiveItem *a; 00438 for (int x = 0; x < m_archiveList.size(); x++) 00439 { 00440 qApp->processEvents(); 00441 a = m_archiveList.at(x); 00442 00443 // get duration of this file 00444 if (a->duration == 0) 00445 { 00446 if (!getFileDetails(a)) 00447 LOG(VB_GENERAL, LOG_ERR, 00448 QString("MythBurn: failed to get file details for: %1").arg(a->filename)); 00449 } 00450 00451 // get default encoding profile if needed 00452 00453 if (a->encoderProfile == NULL) 00454 a->encoderProfile = getDefaultProfile(a); 00455 00456 recalcItemSize(a); 00457 00458 MythUIButtonListItem* item = new 00459 MythUIButtonListItem(m_archiveButtonList, a->title); 00460 item->SetData(qVariantFromValue(a)); 00461 item->SetText(a->subtitle, "subtitle"); 00462 item->SetText(a->startDate + " " + a->startTime, "date"); 00463 item->SetText(formatSize(a->newsize / 1024, 2), "size"); 00464 if (a->hasCutlist) 00465 { 00466 if (a->useCutlist) 00467 { 00468 item->SetText(tr("Using Cut List"), "cutlist"); 00469 item->DisplayState("using", "cutliststatus"); 00470 } 00471 else 00472 { 00473 item->SetText(tr("Not Using Cut List"), "cutlist"); 00474 item->DisplayState("notusing", "cutliststatus"); 00475 } 00476 } 00477 else 00478 { 00479 item->SetText(tr("No Cut List"), "cutlist"); 00480 item->DisplayState("none", "cutliststatus"); 00481 } 00482 item->SetText(tr("Encoder: ") + a->encoderProfile->name, "profile"); 00483 } 00484 00485 m_nofilesText->Hide(); 00486 00487 m_archiveButtonList->SetItemCurrent( 00488 m_archiveButtonList->GetItemFirst()); 00489 } 00490 00491 updateSizeBar(); 00492 00493 if (busyPopup) 00494 busyPopup->Close(); 00495 } 00496 00497 bool MythBurn::isArchiveItemValid(const QString &type, const QString &filename) 00498 { 00499 if (type == "Recording") 00500 { 00501 QString baseName = getBaseName(filename); 00502 00503 MSqlQuery query(MSqlQuery::InitCon()); 00504 query.prepare("SELECT title FROM recorded WHERE basename = :FILENAME"); 00505 query.bindValue(":FILENAME", baseName); 00506 if (query.exec() && query.size()) 00507 return true; 00508 else 00509 { 00510 LOG(VB_GENERAL, LOG_ERR, 00511 QString("MythArchive: Recording not found (%1)") 00512 .arg(filename)); 00513 } 00514 } 00515 else if (type == "Video") 00516 { 00517 MSqlQuery query(MSqlQuery::InitCon()); 00518 query.prepare("SELECT title FROM videometadata" 00519 " WHERE filename = :FILENAME"); 00520 query.bindValue(":FILENAME", filename); 00521 if (query.exec() && query.size()) 00522 return true; 00523 else 00524 { 00525 LOG(VB_GENERAL, LOG_ERR, 00526 QString("MythArchive: Video not found (%1)").arg(filename)); 00527 } 00528 } 00529 else if (type == "File") 00530 { 00531 if (QFile::exists(filename)) 00532 return true; 00533 else 00534 { 00535 LOG(VB_GENERAL, LOG_ERR, 00536 QString("MythArchive: File not found (%1)").arg(filename)); 00537 } 00538 } 00539 00540 LOG(VB_GENERAL, LOG_NOTICE, "MythArchive: Archive item removed from list"); 00541 00542 return false; 00543 } 00544 00545 EncoderProfile *MythBurn::getDefaultProfile(ArchiveItem *item) 00546 { 00547 if (!item) 00548 return m_profileList.at(0); 00549 00550 EncoderProfile *profile = NULL; 00551 00552 // is the file an mpeg2 file? 00553 if (item->videoCodec.toLower() == "mpeg2video") 00554 { 00555 // does the file already have a valid DVD resolution? 00556 if (gCoreContext->GetSetting("MythArchiveVideoFormat", "pal").toLower() 00557 == "ntsc") 00558 { 00559 if ((item->videoWidth == 720 && item->videoHeight == 480) || 00560 (item->videoWidth == 704 && item->videoHeight == 480) || 00561 (item->videoWidth == 352 && item->videoHeight == 480) || 00562 (item->videoWidth == 352 && item->videoHeight == 240)) 00563 { 00564 // don't need to re-encode 00565 profile = m_profileList.at(0); 00566 } 00567 } 00568 else 00569 { 00570 if ((item->videoWidth == 720 && item->videoHeight == 576) || 00571 (item->videoWidth == 704 && item->videoHeight == 576) || 00572 (item->videoWidth == 352 && item->videoHeight == 576) || 00573 (item->videoWidth == 352 && item->videoHeight == 288)) 00574 { 00575 // don't need to re-encode 00576 profile = m_profileList.at(0); 00577 } 00578 } 00579 } 00580 00581 if (!profile) 00582 { 00583 // file needs re-encoding - use default profile setting 00584 QString defaultProfile = 00585 gCoreContext->GetSetting("MythArchiveDefaultEncProfile", "SP"); 00586 00587 for (int x = 0; x < m_profileList.size(); x++) 00588 if (m_profileList.at(x)->name == defaultProfile) 00589 profile = m_profileList.at(x); 00590 } 00591 00592 return profile; 00593 } 00594 00595 void MythBurn::createConfigFile(const QString &filename) 00596 { 00597 QDomDocument doc("mythburn"); 00598 00599 QDomElement root = doc.createElement("mythburn"); 00600 doc.appendChild(root); 00601 00602 QDomElement job = doc.createElement("job"); 00603 job.setAttribute("theme", m_theme); 00604 root.appendChild(job); 00605 00606 QDomElement media = doc.createElement("media"); 00607 job.appendChild(media); 00608 00609 // now loop though selected archive items and add them to the xml file 00610 ArchiveItem *a; 00611 MythUIButtonListItem *item; 00612 for (int x = 0; x < m_archiveButtonList->GetCount(); x++) 00613 { 00614 item = m_archiveButtonList->GetItemAt(x); 00615 if (!item) 00616 continue; 00617 00618 a = qVariantValue<ArchiveItem *>(item->GetData()); 00619 if (!a) 00620 continue; 00621 00622 QDomElement file = doc.createElement("file"); 00623 file.setAttribute("type", a->type.toLower() ); 00624 file.setAttribute("usecutlist", a->useCutlist); 00625 file.setAttribute("filename", a->filename); 00626 file.setAttribute("encodingprofile", a->encoderProfile->name); 00627 if (a->editedDetails) 00628 { 00629 QDomElement details = doc.createElement("details"); 00630 file.appendChild(details); 00631 details.setAttribute("title", a->title); 00632 details.setAttribute("subtitle", a->subtitle); 00633 details.setAttribute("startdate", a->startDate); 00634 details.setAttribute("starttime", a->startTime); 00635 QDomText desc = doc.createTextNode(a->description); 00636 details.appendChild(desc); 00637 } 00638 00639 if (a->thumbList.size() > 0) 00640 { 00641 QDomElement thumbs = doc.createElement("thumbimages"); 00642 file.appendChild(thumbs); 00643 00644 for (int x = 0; x < a->thumbList.size(); x++) 00645 { 00646 QDomElement thumb = doc.createElement("thumb"); 00647 thumbs.appendChild(thumb); 00648 ThumbImage *thumbImage = a->thumbList.at(x); 00649 thumb.setAttribute("caption", thumbImage->caption); 00650 thumb.setAttribute("filename", thumbImage->filename); 00651 thumb.setAttribute("frame", (int) thumbImage->frame); 00652 } 00653 } 00654 00655 media.appendChild(file); 00656 } 00657 00658 // add the options to the xml file 00659 QDomElement options = doc.createElement("options"); 00660 options.setAttribute("createiso", m_bCreateISO); 00661 options.setAttribute("doburn", m_bDoBurn); 00662 options.setAttribute("mediatype", m_archiveDestination.type); 00663 options.setAttribute("dvdrsize", (qint64)m_archiveDestination.freeSpace); 00664 options.setAttribute("erasedvdrw", m_bEraseDvdRw); 00665 options.setAttribute("savefilename", m_saveFilename); 00666 job.appendChild(options); 00667 00668 // finally save the xml to the file 00669 QFile f(filename); 00670 if (!f.open(QIODevice::WriteOnly)) 00671 { 00672 LOG(VB_GENERAL, LOG_ERR, 00673 QString("MythBurn::createConfigFile: " 00674 "Failed to open file for writing - %1") .arg(filename)); 00675 return; 00676 } 00677 00678 QTextStream t(&f); 00679 t << doc.toString(4); 00680 f.close(); 00681 } 00682 00683 void MythBurn::loadConfiguration(void) 00684 { 00685 m_theme = gCoreContext->GetSetting("MythBurnMenuTheme", ""); 00686 m_bCreateISO = (gCoreContext->GetSetting("MythBurnCreateISO", "0") == "1"); 00687 m_bDoBurn = (gCoreContext->GetSetting("MythBurnBurnDVDr", "1") == "1"); 00688 m_bEraseDvdRw = (gCoreContext->GetSetting("MythBurnEraseDvdRw", "0") == "1"); 00689 m_saveFilename = gCoreContext->GetSetting("MythBurnSaveFilename", ""); 00690 00691 while (!m_archiveList.isEmpty()) 00692 delete m_archiveList.takeFirst(); 00693 m_archiveList.clear(); 00694 00695 // load selected file list 00696 MSqlQuery query(MSqlQuery::InitCon()); 00697 query.prepare("SELECT type, title, subtitle, description, startdate, " 00698 "starttime, size, filename, hascutlist, duration, " 00699 "cutduration, videowidth, videoheight, filecodec, " 00700 "videocodec, encoderprofile FROM archiveitems " 00701 "ORDER BY intid;"); 00702 00703 if (!query.exec()) 00704 { 00705 MythDB::DBError("archive item insert", query); 00706 return; 00707 } 00708 00709 while (query.next()) 00710 { 00711 ArchiveItem *a = new ArchiveItem; 00712 a->type = query.value(0).toString(); 00713 a->title = query.value(1).toString(); 00714 a->subtitle = query.value(2).toString(); 00715 a->description = query.value(3).toString(); 00716 a->startDate = query.value(4).toString(); 00717 a->startTime = query.value(5).toString(); 00718 a->size = query.value(6).toLongLong(); 00719 a->filename = query.value(7).toString(); 00720 a->hasCutlist = (query.value(8).toInt() == 1); 00721 a->useCutlist = false; 00722 a->duration = query.value(9).toInt(); 00723 a->cutDuration = query.value(10).toInt(); 00724 a->videoWidth = query.value(11).toInt(); 00725 a->videoHeight = query.value(12).toInt(); 00726 a->fileCodec = query.value(13).toString(); 00727 a->videoCodec = query.value(14).toString(); 00728 a->encoderProfile = getProfileFromName(query.value(15).toString()); 00729 a->editedDetails = false; 00730 m_archiveList.append(a); 00731 } 00732 } 00733 00734 EncoderProfile *MythBurn::getProfileFromName(const QString &profileName) 00735 { 00736 for (int x = 0; x < m_profileList.size(); x++) 00737 if (m_profileList.at(x)->name == profileName) 00738 return m_profileList.at(x); 00739 00740 return NULL; 00741 } 00742 00743 void MythBurn::saveConfiguration(void) 00744 { 00745 // remove all old archive items from DB 00746 MSqlQuery query(MSqlQuery::InitCon()); 00747 query.prepare("DELETE FROM archiveitems;"); 00748 if (!query.exec()) 00749 MythDB::DBError("MythBurn::saveConfiguration - deleting archiveitems", 00750 query); 00751 00752 // save new list of archive items to DB 00753 ArchiveItem *a; 00754 MythUIButtonListItem *item; 00755 for (int x = 0; x < m_archiveButtonList->GetCount(); x++) 00756 { 00757 item = m_archiveButtonList->GetItemAt(x); 00758 if (!item) 00759 continue; 00760 00761 a = qVariantValue<ArchiveItem *>(item->GetData()); 00762 if (!a) 00763 continue; 00764 00765 query.prepare("INSERT INTO archiveitems (type, title, subtitle, " 00766 "description, startdate, starttime, size, filename, " 00767 "hascutlist, duration, cutduration, videowidth, " 00768 "videoheight, filecodec, videocodec, encoderprofile) " 00769 "VALUES(:TYPE, :TITLE, :SUBTITLE, :DESCRIPTION, :STARTDATE, " 00770 ":STARTTIME, :SIZE, :FILENAME, :HASCUTLIST, :DURATION, " 00771 ":CUTDURATION, :VIDEOWIDTH, :VIDEOHEIGHT, :FILECODEC, " 00772 ":VIDEOCODEC, :ENCODERPROFILE);"); 00773 query.bindValue(":TYPE", a->type); 00774 query.bindValue(":TITLE", a->title); 00775 query.bindValue(":SUBTITLE", a->subtitle); 00776 query.bindValue(":DESCRIPTION", a->description); 00777 query.bindValue(":STARTDATE", a->startDate); 00778 query.bindValue(":STARTTIME", a->startTime); 00779 query.bindValue(":SIZE", (qint64)a->size); 00780 query.bindValue(":FILENAME", a->filename); 00781 query.bindValue(":HASCUTLIST", a->hasCutlist); 00782 query.bindValue(":DURATION", a->duration); 00783 query.bindValue(":CUTDURATION", a->cutDuration); 00784 query.bindValue(":VIDEOWIDTH", a->videoWidth); 00785 query.bindValue(":VIDEOHEIGHT", a->videoHeight); 00786 query.bindValue(":FILECODEC", a->fileCodec); 00787 query.bindValue(":VIDEOCODEC", a->videoCodec); 00788 query.bindValue(":ENCODERPROFILE", a->encoderProfile->name); 00789 00790 if (!query.exec()) 00791 MythDB::DBError("archive item insert", query); 00792 } 00793 } 00794 00795 void MythBurn::showMenu() 00796 { 00797 if (m_archiveList.size() == 0) 00798 return; 00799 00800 MythUIButtonListItem *item = m_archiveButtonList->GetItemCurrent(); 00801 ArchiveItem *curItem = qVariantValue<ArchiveItem *>(item->GetData()); 00802 00803 if (!curItem) 00804 return; 00805 00806 MythScreenStack *popupStack = GetMythMainWindow()->GetStack("popup stack"); 00807 00808 MythDialogBox *menuPopup = new MythDialogBox(tr("Menu"), 00809 popupStack, "actionmenu"); 00810 00811 if (menuPopup->Create()) 00812 popupStack->AddScreen(menuPopup); 00813 00814 menuPopup->SetReturnEvent(this, "action"); 00815 00816 if (curItem->hasCutlist) 00817 { 00818 if (curItem->useCutlist) 00819 menuPopup->AddButton(tr("Don't Use Cut List"), 00820 SLOT(toggleUseCutlist())); 00821 else 00822 menuPopup->AddButton(tr("Use Cut List"), 00823 SLOT(toggleUseCutlist())); 00824 } 00825 00826 menuPopup->AddButton(tr("Remove Item"), SLOT(removeItem())); 00827 menuPopup->AddButton(tr("Edit Details"), SLOT(editDetails())); 00828 menuPopup->AddButton(tr("Change Encoding Profile"), SLOT(changeProfile())); 00829 menuPopup->AddButton(tr("Edit Thumbnails"), SLOT(editThumbnails())); 00830 } 00831 00832 void MythBurn::removeItem() 00833 { 00834 MythUIButtonListItem *item = m_archiveButtonList->GetItemCurrent(); 00835 ArchiveItem *curItem = qVariantValue<ArchiveItem *>(item->GetData()); 00836 00837 if (!curItem) 00838 return; 00839 00840 m_archiveList.removeAll(curItem); 00841 00842 updateArchiveList(); 00843 } 00844 00845 void MythBurn::editDetails() 00846 { 00847 MythUIButtonListItem *item = m_archiveButtonList->GetItemCurrent(); 00848 ArchiveItem *curItem = qVariantValue<ArchiveItem *>(item->GetData()); 00849 00850 if (!curItem) 00851 return; 00852 00853 MythScreenStack *mainStack = GetMythMainWindow()->GetMainStack(); 00854 00855 EditMetadataDialog *editor = new EditMetadataDialog(mainStack, curItem); 00856 00857 connect(editor, SIGNAL(haveResult(bool, ArchiveItem *)), 00858 this, SLOT(editorClosed(bool, ArchiveItem *))); 00859 00860 if (editor->Create()) 00861 mainStack->AddScreen(editor); 00862 } 00863 00864 void MythBurn::editThumbnails() 00865 { 00866 MythUIButtonListItem *item = m_archiveButtonList->GetItemCurrent(); 00867 ArchiveItem *curItem = qVariantValue<ArchiveItem *>(item->GetData()); 00868 00869 if (!curItem) 00870 return; 00871 00872 MythScreenStack *mainStack = GetMythMainWindow()->GetMainStack(); 00873 00874 ThumbFinder *finder = new ThumbFinder(mainStack, curItem, m_theme); 00875 00876 if (finder->Create()) 00877 mainStack->AddScreen(finder); 00878 } 00879 00880 void MythBurn::editorClosed(bool ok, ArchiveItem *item) 00881 { 00882 MythUIButtonListItem *gridItem = m_archiveButtonList->GetItemCurrent(); 00883 00884 if (ok && item && gridItem) 00885 { 00886 // update the grid to reflect any changes 00887 gridItem->SetText(item->title); 00888 gridItem->SetText(item->subtitle, "subtitle"); 00889 gridItem->SetText(item->startDate + " " + item->startTime, "date"); 00890 } 00891 } 00892 00893 void MythBurn::changeProfile() 00894 { 00895 MythUIButtonListItem *item = m_archiveButtonList->GetItemCurrent(); 00896 ArchiveItem *curItem = qVariantValue<ArchiveItem *>(item->GetData()); 00897 00898 if (!curItem) 00899 return; 00900 00901 MythScreenStack *popupStack = GetMythMainWindow()->GetStack("popup stack"); 00902 00903 ProfileDialog *profileDialog = new ProfileDialog(popupStack, 00904 curItem, m_profileList); 00905 00906 if (profileDialog->Create()) 00907 { 00908 popupStack->AddScreen(profileDialog, false); 00909 connect(profileDialog, SIGNAL(haveResult(int)), 00910 this, SLOT(profileChanged(int))); 00911 } 00912 } 00913 00914 void MythBurn::profileChanged(int profileNo) 00915 { 00916 if (profileNo > m_profileList.size() - 1) 00917 return; 00918 00919 EncoderProfile *profile = m_profileList.at(profileNo); 00920 00921 MythUIButtonListItem *item = m_archiveButtonList->GetItemCurrent(); 00922 if (!item) 00923 return; 00924 00925 ArchiveItem *archiveItem = qVariantValue<ArchiveItem *>(item->GetData()); 00926 if (!archiveItem) 00927 return; 00928 00929 archiveItem->encoderProfile = profile; 00930 00931 item->SetText(profile->name, "profile"); 00932 item->SetText(formatSize(archiveItem->newsize / 1024, 2), "size"); 00933 00934 updateSizeBar(); 00935 } 00936 00937 void MythBurn::runScript() 00938 { 00939 QString tempDir = getTempDirectory(); 00940 QString logDir = tempDir + "logs"; 00941 QString configDir = tempDir + "config"; 00942 QString commandline; 00943 00944 // remove existing progress.log if present 00945 if (QFile::exists(logDir + "/progress.log")) 00946 QFile::remove(logDir + "/progress.log"); 00947 00948 // remove cancel flag file if present 00949 if (QFile::exists(logDir + "/mythburncancel.lck")) 00950 QFile::remove(logDir + "/mythburncancel.lck"); 00951 00952 createConfigFile(configDir + "/mydata.xml"); 00953 commandline = "python " + GetShareDir() + "mytharchive/scripts/mythburn.py"; 00954 commandline += " -j " + configDir + "/mydata.xml"; // job file 00955 commandline += " -l " + logDir + "/progress.log"; // progress log 00956 commandline += " > " + logDir + "/mythburn.log 2>&1 &"; // Logs 00957 00958 gCoreContext->SaveSetting("MythArchiveLastRunStatus", "Running"); 00959 00960 uint flags = kMSRunBackground | kMSDontBlockInputDevs | 00961 kMSDontDisableDrawing; 00962 uint retval = myth_system(commandline, flags); 00963 if (retval != GENERIC_EXIT_RUNNING && retval != GENERIC_EXIT_OK) 00964 { 00965 ShowOkPopup(tr("It was not possible to create the DVD. " 00966 " An error occured when running the scripts")); 00967 } 00968 else 00969 { 00970 // now show the log viewer 00971 showLogViewer(); 00972 } 00973 00974 m_destinationScreen->Close(); 00975 m_themeScreen->Close(); 00976 Close(); 00977 } 00978 00979 void MythBurn::handleAddRecording() 00980 { 00981 MythScreenStack *mainStack = GetMythMainWindow()->GetMainStack(); 00982 00983 RecordingSelector *selector = new RecordingSelector(mainStack, 00984 &m_archiveList); 00985 00986 connect(selector, SIGNAL(haveResult(bool)), 00987 this, SLOT(selectorClosed(bool))); 00988 00989 if (selector->Create()) 00990 mainStack->AddScreen(selector); 00991 } 00992 00993 void MythBurn::selectorClosed(bool ok) 00994 { 00995 if (ok) 00996 updateArchiveList(); 00997 } 00998 00999 void MythBurn::handleAddVideo() 01000 { 01001 MSqlQuery query(MSqlQuery::InitCon()); 01002 query.prepare("SELECT title FROM videometadata"); 01003 if (query.exec() && query.size()) 01004 { 01005 } 01006 else 01007 { 01008 ShowOkPopup(QObject::tr("You don't have any videos!")); 01009 return; 01010 } 01011 01012 MythScreenStack *mainStack = GetMythMainWindow()->GetMainStack(); 01013 01014 VideoSelector *selector = new VideoSelector(mainStack, &m_archiveList); 01015 01016 connect(selector, SIGNAL(haveResult(bool)), 01017 this, SLOT(selectorClosed(bool))); 01018 01019 if (selector->Create()) 01020 mainStack->AddScreen(selector); 01021 } 01022 01023 void MythBurn::handleAddFile() 01024 { 01025 QString filter = gCoreContext->GetSetting("MythArchiveFileFilter", 01026 "*.mpg *.mpeg *.mov *.avi *.nuv"); 01027 01028 MythScreenStack *mainStack = GetMythMainWindow()->GetMainStack(); 01029 01030 FileSelector *selector = new FileSelector(mainStack, &m_archiveList, 01031 FSTYPE_FILELIST, "/", filter); 01032 01033 connect(selector, SIGNAL(haveResult(bool)), 01034 this, SLOT(selectorClosed(bool))); 01035 01036 if (selector->Create()) 01037 mainStack->AddScreen(selector); 01038 } 01039 01040 void MythBurn::itemClicked(MythUIButtonListItem *item) 01041 { 01042 m_moveMode = !m_moveMode; 01043 01044 if (m_moveMode) 01045 item->DisplayState("on", "movestate"); 01046 else 01047 item->DisplayState("off", "movestate"); 01048 } 01049 01051 01052 ProfileDialog::ProfileDialog( 01053 MythScreenStack *parent, ArchiveItem *archiveItem, 01054 QList<EncoderProfile *> profileList) : 01055 MythScreenType(parent, "functionpopup"), 01056 m_archiveItem(archiveItem), 01057 m_profileList(profileList), 01058 m_captionText(NULL), 01059 m_descriptionText(NULL), 01060 m_oldSizeText(NULL), 01061 m_newSizeText(NULL), 01062 m_profile_list(NULL), 01063 m_enabledCheck(NULL), 01064 m_okButton(NULL) 01065 { 01066 } 01067 01068 bool ProfileDialog::Create() 01069 { 01070 if (!LoadWindowFromXML("mythburn-ui.xml", "profilepopup", this)) 01071 return false; 01072 01073 bool err = false; 01074 UIUtilE::Assign(this, m_captionText, "caption_text", &err); 01075 UIUtilE::Assign(this, m_descriptionText, "description_text", &err); 01076 UIUtilE::Assign(this, m_oldSizeText, "oldsize_text", &err); 01077 UIUtilE::Assign(this, m_newSizeText, "newsize_text", &err); 01078 UIUtilE::Assign(this, m_profile_list, "profile_list", &err); 01079 UIUtilE::Assign(this, m_okButton, "ok_button", &err); 01080 01081 if (err) 01082 { 01083 LOG(VB_GENERAL, LOG_ERR, "Cannot load screen 'profilepopup'"); 01084 return false; 01085 } 01086 01087 for (int x = 0; x < m_profileList.size(); x++) 01088 { 01089 MythUIButtonListItem *item = new 01090 MythUIButtonListItem(m_profile_list, m_profileList.at(x)->name); 01091 item->SetData(qVariantFromValue(m_profileList.at(x))); 01092 } 01093 01094 connect(m_profile_list, SIGNAL(itemSelected(MythUIButtonListItem*)), 01095 this, SLOT(profileChanged(MythUIButtonListItem*))); 01096 01097 01098 m_profile_list->MoveToNamedPosition(m_archiveItem->encoderProfile->name); 01099 01100 m_captionText->SetText(m_archiveItem->title); 01101 m_oldSizeText->SetText(formatSize(m_archiveItem->size / 1024, 2)); 01102 01103 connect(m_okButton, SIGNAL(Clicked()), this, SLOT(save())); 01104 01105 BuildFocusList(); 01106 01107 SetFocusWidget(m_profile_list); 01108 01109 return true; 01110 } 01111 01112 void ProfileDialog::profileChanged(MythUIButtonListItem *item) 01113 { 01114 if (!item) 01115 return; 01116 01117 EncoderProfile *profile = qVariantValue<EncoderProfile *>(item->GetData()); 01118 if (!profile) 01119 return; 01120 01121 m_descriptionText->SetText(profile->description); 01122 01123 m_archiveItem->encoderProfile = profile; 01124 01125 // calc new size 01126 recalcItemSize(m_archiveItem); 01127 01128 m_newSizeText->SetText(formatSize(m_archiveItem->newsize / 1024, 2)); 01129 } 01130 01131 01132 void ProfileDialog::save(void) 01133 { 01134 emit haveResult(m_profile_list->GetCurrentPos()); 01135 01136 Close(); 01137 } 01138 01140 01141 BurnMenu::BurnMenu(void) 01142 :QObject(NULL) 01143 { 01144 setObjectName("BurnMenu"); 01145 } 01146 01147 BurnMenu::~BurnMenu(void) 01148 { 01149 } 01150 01151 void BurnMenu::start(void) 01152 { 01153 if (!gCoreContext->GetSetting("MythArchiveLastRunStatus").startsWith("Success")) 01154 { 01155 showWarningDialog(QObject::tr("Cannot burn a DVD.\n" 01156 "The last run failed to create a DVD.")); 01157 return; 01158 } 01159 01160 // ask the user what type of disk to burn to 01161 QString title = QObject::tr("Burn DVD"); 01162 QString msg = QObject::tr("\nPlace a blank DVD in the" 01163 " drive and select an option below."); 01164 MythScreenStack *mainStack = GetMythMainWindow()->GetStack("main stack"); 01165 MythDialogBox *menuPopup = new MythDialogBox(title, msg, mainStack, 01166 "actionmenu", true); 01167 01168 if (menuPopup->Create()) 01169 mainStack->AddScreen(menuPopup); 01170 01171 menuPopup->SetReturnEvent(this, "action"); 01172 01173 menuPopup->AddButton(QObject::tr("Burn DVD")); 01174 menuPopup->AddButton(QObject::tr("Burn DVD Rewritable")); 01175 menuPopup->AddButton(QObject::tr("Burn DVD Rewritable (Force Erase)")); 01176 } 01177 01178 void BurnMenu::customEvent(QEvent *event) 01179 { 01180 if (event->type() == DialogCompletionEvent::kEventType) 01181 { 01182 DialogCompletionEvent *dce = (DialogCompletionEvent*)(event); 01183 if (dce->GetId() == "action") 01184 { 01185 doBurn(dce->GetResult()); 01186 deleteLater(); 01187 } 01188 } 01189 } 01190 01191 void BurnMenu::doBurn(int mode) 01192 { 01193 if ((mode < 0) || (mode > 2)) 01194 return; 01195 01196 QString tempDir = getTempDirectory(true); 01197 01198 if (tempDir == "") 01199 return; 01200 01201 QString logDir = tempDir + "logs"; 01202 QString configDir = tempDir + "config"; 01203 QString commandline; 01204 01205 // remove existing progress.log if present 01206 if (QFile::exists(logDir + "/progress.log")) 01207 QFile::remove(logDir + "/progress.log"); 01208 01209 // remove cancel flag file if present 01210 if (QFile::exists(logDir + "/mythburncancel.lck")) 01211 QFile::remove(logDir + "/mythburncancel.lck"); 01212 01213 QString sArchiveFormat = QString::number(mode); 01214 bool bEraseDVDRW = (mode == 2); 01215 bool bNativeFormat = gCoreContext->GetSetting("MythArchiveLastRunType") 01216 .startsWith("Native"); 01217 01218 commandline = "mytharchivehelper --burndvd --mediatype " + sArchiveFormat + 01219 (bEraseDVDRW ? " --erasedvdrw" : "") + 01220 (bNativeFormat ? " --nativeformat" : ""); 01221 commandline += logPropagateArgs; 01222 if (!logPropagateQuiet()) 01223 commandline += " --quiet"; 01224 commandline += " > " + logDir + "/progress.log 2>&1 &"; 01225 01226 uint flags = kMSRunBackground | kMSDontBlockInputDevs | 01227 kMSDontDisableDrawing; 01228 uint retval = myth_system(commandline, flags); 01229 if (retval != GENERIC_EXIT_RUNNING && retval != GENERIC_EXIT_OK) 01230 { 01231 showWarningDialog(QObject::tr("It was not possible to run " 01232 "mytharchivehelper to burn the DVD.")); 01233 return; 01234 } 01235 01236 // now show the log viewer 01237 showLogViewer(); 01238 } 01239 01240 /* vim: set expandtab tabstop=4 shiftwidth=4: */
1.7.6.1