MythTV  0.26-pre
exportnative.cpp
Go to the documentation of this file.
00001 #include <unistd.h>
00002 #include <stdlib.h>
00003 
00004 #include <iostream>
00005 #include <cstdlib>
00006 
00007 // qt
00008 #include <QFile>
00009 #include <QKeyEvent>
00010 #include <QTextStream>
00011 #include <QDomDocument>
00012 
00013 // myth
00014 #include <mythcontext.h>
00015 #include <remoteutil.h>
00016 #include <programinfo.h>
00017 #include <mythdb.h>
00018 #include <mythdialogbox.h>
00019 #include <mythuitext.h>
00020 #include <mythuibutton.h>
00021 #include <mythuicheckbox.h>
00022 #include <mythuibuttonlist.h>
00023 #include <mythuiprogressbar.h>
00024 #include <mythmainwindow.h>
00025 #include <mythsystem.h>
00026 #include <exitcodes.h>
00027 
00028 // mytharchive
00029 #include "exportnative.h"
00030 #include "fileselector.h"
00031 #include "archiveutil.h"
00032 #include "recordingselector.h"
00033 #include "videoselector.h"
00034 #include "logviewer.h"
00035 
00036 ExportNative::ExportNative(
00037     MythScreenStack *parent, MythScreenType *previousScreen,
00038     ArchiveDestination archiveDestination, QString name) :
00039     MythScreenType(parent, name),
00040     m_previousScreen(previousScreen),
00041     m_archiveDestination(archiveDestination),
00042     m_usedSpace(0),
00043     m_bCreateISO(false),
00044     m_bDoBurn(false),
00045     m_bEraseDvdRw(false),
00046     m_saveFilename(),
00047     m_archiveButtonList(NULL),
00048     m_nextButton(NULL),
00049     m_prevButton(NULL),
00050     m_cancelButton(NULL),
00051     m_addrecordingButton(NULL),
00052     m_addvideoButton(NULL),
00053     m_freespaceText(NULL),
00054     m_titleText(NULL),
00055     m_datetimeText(NULL),
00056     m_descriptionText(NULL),
00057     m_filesizeText(NULL),
00058     m_nofilesText(NULL),
00059     m_maxsizeText(NULL),
00060     m_minsizeText(NULL),
00061     m_currsizeText(NULL),
00062     m_currsizeErrText(NULL),
00063     m_sizeBar(NULL)
00064 {
00065 }
00066 
00067 ExportNative::~ExportNative(void)
00068 {
00069     saveConfiguration();
00070 
00071     while (!m_archiveList.isEmpty())
00072          delete m_archiveList.takeFirst();
00073     m_archiveList.clear();
00074 }
00075 
00076 bool ExportNative::Create(void)
00077 {
00078     bool foundtheme = false;
00079 
00080     // Load the theme for this screen
00081     foundtheme = LoadWindowFromXML("mythnative-ui.xml", "exportnative", this);
00082 
00083     if (!foundtheme)
00084         return false;
00085 
00086     bool err = false;
00087     UIUtilE::Assign(this, m_nextButton, "next_button", &err);
00088     UIUtilE::Assign(this, m_prevButton, "prev_button", &err);
00089     UIUtilE::Assign(this, m_cancelButton, "cancel_button", &err);
00090 
00091     UIUtilE::Assign(this, m_titleText, "progtitle", &err);
00092     UIUtilE::Assign(this, m_datetimeText, "progdatetime", &err);
00093     UIUtilE::Assign(this, m_descriptionText, "progdescription", &err);
00094     UIUtilE::Assign(this, m_filesizeText, "filesize", &err);
00095     UIUtilE::Assign(this, m_nofilesText, "nofiles", &err);
00096     UIUtilE::Assign(this, m_sizeBar, "size_bar", &err);
00097     UIUtilE::Assign(this, m_archiveButtonList, "archivelist", &err);
00098     UIUtilE::Assign(this, m_addrecordingButton, "addrecording_button", &err);
00099     UIUtilE::Assign(this, m_addvideoButton, "addvideo_button", &err);
00100 
00101     UIUtilW::Assign(this, m_maxsizeText, "maxsize");
00102     UIUtilW::Assign(this, m_minsizeText, "minsize");
00103     UIUtilW::Assign(this, m_currsizeText, "currentsize");
00104     UIUtilW::Assign(this, m_currsizeErrText, "currentsize_error");
00105 
00106     if (err)
00107     {
00108         LOG(VB_GENERAL, LOG_ERR, "Cannot load screen 'exportnative'");
00109         return false;
00110     }
00111 
00112     connect(m_nextButton, SIGNAL(Clicked()), this, SLOT(handleNextPage()));
00113     connect(m_prevButton, SIGNAL(Clicked()), this, SLOT(handlePrevPage()));
00114     connect(m_cancelButton, SIGNAL(Clicked()), this, SLOT(handleCancel()));
00115 
00116 
00117     getArchiveList();
00118     connect(m_archiveButtonList, SIGNAL(itemSelected(MythUIButtonListItem *)),
00119             this, SLOT(titleChanged(MythUIButtonListItem *)));
00120 
00121     connect(m_addrecordingButton, SIGNAL(Clicked()), this, SLOT(handleAddRecording()));
00122     connect(m_addvideoButton, SIGNAL(Clicked()), this, SLOT(handleAddVideo()));
00123 
00124     BuildFocusList();
00125 
00126     SetFocusWidget(m_nextButton);
00127 
00128     loadConfiguration();
00129 
00130     return true;
00131 }
00132 
00133 bool ExportNative::keyPressEvent(QKeyEvent *event)
00134 {
00135     if (GetFocusWidget()->keyPressEvent(event))
00136         return true;
00137 
00138     bool handled = false;
00139     QStringList actions;
00140     handled = GetMythMainWindow()->TranslateKeyPress("Archive", event, actions);
00141 
00142     for (int i = 0; i < actions.size() && !handled; i++)
00143     {
00144         QString action = actions[i];
00145         handled = true;
00146 
00147         if (action == "MENU")
00148         {
00149             showMenu();
00150         }
00151         else if (action == "DELETE")
00152         {
00153             removeItem();
00154         }
00155 
00156         else
00157             handled = false;
00158     }
00159 
00160     if (!handled && MythScreenType::keyPressEvent(event))
00161         handled = true;
00162 
00163     return handled;
00164 }
00165 
00166 void ExportNative::updateSizeBar()
00167 {
00168     int64_t size = 0;
00169     ArchiveItem *a;
00170 
00171     for (int x = 0; x < m_archiveList.size(); x++)
00172     {
00173         a = m_archiveList.at(x);
00174         size += a->size;
00175     }
00176 
00177     m_usedSpace = size / 1024 / 1024;
00178     uint freeSpace = m_archiveDestination.freeSpace / 1024;
00179 
00180     QString tmpSize;
00181 
00182     m_sizeBar->SetTotal(freeSpace);
00183     m_sizeBar->SetUsed(m_usedSpace);
00184 
00185     tmpSize.sprintf("%0d Mb", freeSpace);
00186 
00187     if (m_maxsizeText)
00188         m_maxsizeText->SetText(tmpSize);
00189 
00190     if (m_minsizeText)
00191         m_minsizeText->SetText("0 Mb");
00192 
00193     tmpSize.sprintf("%0d Mb", m_usedSpace);
00194 
00195     if (m_usedSpace > freeSpace)
00196     {
00197         if (m_currsizeText)
00198             m_currsizeText->Hide();
00199 
00200         if (m_currsizeErrText)
00201         {
00202             m_currsizeErrText->Show();
00203             m_currsizeErrText->SetText(tmpSize);
00204         }
00205     }
00206     else
00207     {
00208         if (m_currsizeErrText)
00209             m_currsizeErrText->Hide();
00210 
00211         if (m_currsizeText)
00212         {
00213             m_currsizeText->Show();
00214             m_currsizeText->SetText(tmpSize);
00215         }
00216     }
00217 }
00218 
00219 void ExportNative::titleChanged(MythUIButtonListItem *item)
00220 {
00221     ArchiveItem *a;
00222 
00223     a = qVariantValue<ArchiveItem *>(item->GetData());
00224 
00225     if (!a)
00226         return;
00227 
00228     m_titleText->SetText(a->title);
00229 
00230     m_datetimeText->SetText(a->startDate + " " + a->startTime);
00231 
00232     m_descriptionText->SetText(
00233                 (a->subtitle != "" ? a->subtitle + "\n" : "") + a->description);
00234 
00235     m_filesizeText->SetText(formatSize(a->size / 1024, 2));
00236 }
00237 
00238 void ExportNative::handleNextPage()
00239 {
00240     if (m_archiveList.size() == 0)
00241     {
00242         ShowOkPopup(tr("You need to add at least one item to archive!"));
00243         return;
00244     }
00245 
00246     runScript();
00247 
00248     m_previousScreen->Close();
00249     Close();
00250 }
00251 
00252 void ExportNative::handlePrevPage()
00253 {
00254     Close();
00255 }
00256 
00257 void ExportNative::handleCancel()
00258 {
00259     m_previousScreen->Close();
00260     Close();
00261 }
00262 
00263 void ExportNative::updateArchiveList(void)
00264 {
00265     m_archiveButtonList->Reset();
00266 
00267     if (m_archiveList.size() == 0)
00268     {
00269         m_titleText->Reset();
00270         m_datetimeText->Reset();
00271         m_descriptionText->Reset();
00272         m_filesizeText->Reset();
00273         m_nofilesText->Show();
00274     }
00275     else
00276     {
00277         ArchiveItem *a;
00278         for (int x = 0;  x < m_archiveList.size(); x++)
00279         {
00280             a = m_archiveList.at(x);
00281 
00282             MythUIButtonListItem* item = new MythUIButtonListItem(m_archiveButtonList, a->title);
00283             item->SetData(qVariantFromValue(a));
00284         }
00285 
00286         m_archiveButtonList->SetItemCurrent(m_archiveButtonList->GetItemFirst());
00287         titleChanged(m_archiveButtonList->GetItemCurrent());
00288         m_nofilesText->Hide();
00289     }
00290 
00291     updateSizeBar();
00292 }
00293 
00294 void ExportNative::getArchiveListFromDB(void)
00295 {
00296     while (!m_archiveList.isEmpty())
00297          delete m_archiveList.takeFirst();
00298     m_archiveList.clear();
00299 
00300     MSqlQuery query(MSqlQuery::InitCon());
00301     query.prepare("SELECT intid, type, title, subtitle, description, size, "
00302                   "startdate, starttime, filename, hascutlist "
00303                   "FROM archiveitems WHERE type = 'Recording' OR type = 'Video' "
00304                   "ORDER BY title, subtitle");
00305 
00306     if (query.exec())
00307     {
00308         while (query.next())
00309         {
00310             ArchiveItem *item = new ArchiveItem;
00311 
00312             item->id = query.value(0).toInt();
00313             item->type = query.value(1).toString();
00314             item->title = query.value(2).toString();
00315             item->subtitle = query.value(3).toString();
00316             item->description = query.value(4).toString();
00317             item->size = query.value(5).toLongLong();
00318             item->startDate = query.value(6).toString();
00319             item->startTime = query.value(7).toString();
00320             item->filename = query.value(8).toString();
00321             item->hasCutlist = (query.value(9).toInt() > 0);
00322             item->useCutlist = false;
00323             item->editedDetails = false;
00324 
00325             m_archiveList.append(item);
00326         }
00327     }
00328 }
00329 
00330 void ExportNative::getArchiveList(void)
00331 {
00332     getArchiveListFromDB();
00333     updateArchiveList();
00334 }
00335 
00336 void ExportNative::loadConfiguration(void)
00337 {
00338     m_bCreateISO = (gCoreContext->GetSetting("MythNativeCreateISO", "0") == "1");
00339     m_bDoBurn = (gCoreContext->GetSetting("MythNativeBurnDVDr", "1") == "1");
00340     m_bEraseDvdRw = (gCoreContext->GetSetting("MythNativeEraseDvdRw", "0") == "1");
00341     m_saveFilename = gCoreContext->GetSetting("MythNativeSaveFilename", "");
00342 }
00343 
00344 void ExportNative::saveConfiguration(void)
00345 {
00346     // remove all old archive items from DB
00347     MSqlQuery query(MSqlQuery::InitCon());
00348     query.prepare("DELETE FROM archiveitems;");
00349     if (!query.exec())
00350         MythDB::DBError("ExportNative::saveConfiguration - "
00351                         "deleting archiveitems", query);
00352 
00353     // save new list of archive items to DB
00354     ArchiveItem *a;
00355     for (int x = 0; x < m_archiveList.size(); x++)
00356     {
00357         a = m_archiveList.at(x);
00358 
00359         query.prepare("INSERT INTO archiveitems (type, title, subtitle, "
00360                 "description, startdate, starttime, size, filename, hascutlist, "
00361                 "duration, cutduration, videowidth, videoheight, filecodec,"
00362                 "videocodec, encoderprofile) "
00363                 "VALUES(:TYPE, :TITLE, :SUBTITLE, :DESCRIPTION, :STARTDATE, "
00364                 ":STARTTIME, :SIZE, :FILENAME, :HASCUTLIST, :DURATION, "
00365                 ":CUTDURATION, :VIDEOWIDTH, :VIDEOHEIGHT, :FILECODEC, "
00366                 ":VIDEOCODEC, :ENCODERPROFILE);");
00367         query.bindValue(":TYPE", a->type);
00368         query.bindValue(":TITLE", a->title);
00369         query.bindValue(":SUBTITLE", a->subtitle);
00370         query.bindValue(":DESCRIPTION", a->description);
00371         query.bindValue(":STARTDATE", a->startDate);
00372         query.bindValue(":STARTTIME", a->startTime);
00373         query.bindValue(":SIZE", 0);
00374         query.bindValue(":FILENAME", a->filename);
00375         query.bindValue(":HASCUTLIST", a->hasCutlist);
00376         query.bindValue(":DURATION", 0);
00377         query.bindValue(":CUTDURATION", 0);
00378         query.bindValue(":VIDEOWIDTH", 0);
00379         query.bindValue(":VIDEOHEIGHT", 0);
00380         query.bindValue(":FILECODEC", "");
00381         query.bindValue(":VIDEOCODEC", "");
00382         query.bindValue(":ENCODERPROFILE", "");
00383 
00384         if (!query.exec())
00385             MythDB::DBError("archive item insert", query);
00386     }
00387 }
00388 
00389 void ExportNative::showMenu()
00390 {
00391     MythScreenStack *popupStack = GetMythMainWindow()->GetStack("popup stack");
00392 
00393     MythDialogBox *menuPopup = new MythDialogBox(tr("Menu"), popupStack, "actionmenu");
00394 
00395     if (menuPopup->Create())
00396         popupStack->AddScreen(menuPopup);
00397 
00398     menuPopup->SetReturnEvent(this, "action");
00399 
00400     menuPopup->AddButton(tr("Remove Item"), SLOT(removeItem()));
00401 }
00402 
00403 void ExportNative::removeItem()
00404 {
00405     MythUIButtonListItem *item = m_archiveButtonList->GetItemCurrent();
00406     ArchiveItem *curItem = qVariantValue<ArchiveItem *>(item->GetData());
00407 
00408     if (!curItem)
00409         return;
00410 
00411     MSqlQuery query(MSqlQuery::InitCon());
00412     query.prepare("DELETE FROM archiveitems WHERE filename = :FILENAME;");
00413     query.bindValue(":FILENAME", curItem->filename);
00414     if (query.exec() && query.numRowsAffected())
00415     {
00416         getArchiveList();
00417     }
00418 }
00419 
00420 void ExportNative::createConfigFile(const QString &filename)
00421 {
00422     QDomDocument doc("NATIVEARCHIVEJOB");
00423 
00424     QDomElement root = doc.createElement("nativearchivejob");
00425     doc.appendChild(root);
00426 
00427     QDomElement job = doc.createElement("job");
00428     root.appendChild(job);
00429 
00430     QDomElement media = doc.createElement("media");
00431     job.appendChild(media);
00432 
00433     // now loop though selected archive items and add them to the xml file
00434     ArchiveItem *a;
00435     for (int x = 0; x < m_archiveList.size(); x++)
00436     {
00437         a = m_archiveList.at(x);
00438 
00439         QDomElement file = doc.createElement("file");
00440         file.setAttribute("type", a->type.toLower() );
00441         file.setAttribute("title", a->title);
00442         file.setAttribute("filename", a->filename);
00443         file.setAttribute("delete", "0");
00444         media.appendChild(file);
00445     }
00446 
00447     // add the options to the xml file
00448     QDomElement options = doc.createElement("options");
00449     options.setAttribute("createiso", m_bCreateISO);
00450     options.setAttribute("doburn", m_bDoBurn);
00451     options.setAttribute("mediatype", m_archiveDestination.type);
00452     options.setAttribute("dvdrsize", (qint64)m_archiveDestination.freeSpace);
00453     options.setAttribute("erasedvdrw", m_bEraseDvdRw);
00454     options.setAttribute("savedirectory", m_saveFilename);
00455     job.appendChild(options);
00456 
00457     // finally save the xml to the file
00458     QFile f(filename);
00459     if (!f.open(QIODevice::WriteOnly))
00460     {
00461         LOG(VB_GENERAL, LOG_ERR,
00462             QString("ExportNative::createConfigFile: "
00463                     "Failed to open file for writing - %1") .arg(filename));
00464         return;
00465     }
00466 
00467     QTextStream t(&f);
00468     t << doc.toString(4);
00469     f.close();
00470 }
00471 
00472 void ExportNative::runScript()
00473 {
00474     QString tempDir = getTempDirectory();
00475     QString logDir = tempDir + "logs";
00476     QString configDir = tempDir + "config";
00477     QString commandline;
00478 
00479     // remove existing progress.log if present
00480     if (QFile::exists(logDir + "/progress.log"))
00481         QFile::remove(logDir + "/progress.log");
00482 
00483     // remove cancel flag file if present
00484     if (QFile::exists(logDir + "/mythburncancel.lck"))
00485         QFile::remove(logDir + "/mythburncancel.lck");
00486 
00487     createConfigFile(configDir + "/mydata.xml");
00488     commandline = "mytharchivehelper --nativearchive --outfile " + configDir +
00489                   "/mydata.xml";  // job file
00490     commandline += logPropagateArgs;
00491     if (!logPropagateQuiet())
00492         commandline += " --quiet";
00493     commandline += " > "  + logDir + "/progress.log 2>&1 &";            // Logs
00494 
00495     uint flags = kMSRunBackground | kMSDontBlockInputDevs |
00496                  kMSDontDisableDrawing;
00497     uint retval = myth_system(commandline, flags);
00498     if (retval != GENERIC_EXIT_RUNNING && retval != GENERIC_EXIT_OK)
00499     {
00500         ShowOkPopup(QObject::tr("It was not possible to create the DVD. "
00501                                 "An error occured when running the scripts") );
00502         return;
00503     }
00504 
00505     showLogViewer();
00506 }
00507 
00508 void ExportNative::handleAddRecording()
00509 {
00510     MythScreenStack *mainStack = GetMythMainWindow()->GetMainStack();
00511 
00512     RecordingSelector *selector = new RecordingSelector(mainStack, &m_archiveList);
00513 
00514     connect(selector, SIGNAL(haveResult(bool)),
00515             this, SLOT(selectorClosed(bool)));
00516 
00517     if (selector->Create())
00518         mainStack->AddScreen(selector);
00519 }
00520 
00521 void ExportNative::selectorClosed(bool ok)
00522 {
00523     if (ok)
00524         updateArchiveList();
00525 }
00526 
00527 void ExportNative::handleAddVideo()
00528 {
00529     MSqlQuery query(MSqlQuery::InitCon());
00530     query.prepare("SELECT title FROM videometadata");
00531     if (query.exec() && query.size())
00532     {
00533     }
00534     else
00535     {
00536         ShowOkPopup(tr("You don't have any videos!"));
00537         return;
00538     }
00539 
00540     MythScreenStack *mainStack = GetMythMainWindow()->GetMainStack();
00541 
00542     VideoSelector *selector = new VideoSelector(mainStack, &m_archiveList);
00543 
00544     connect(selector, SIGNAL(haveResult(bool)),
00545             this, SLOT(selectorClosed(bool)));
00546 
00547     if (selector->Create())
00548         mainStack->AddScreen(selector);
00549 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends