MythTV  0.26-pre
mythburn.cpp
Go to the documentation of this file.
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: */
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends