Index: libs/libmythui/myththemedmenu.cpp
===================================================================
--- libs/libmythui/myththemedmenu.cpp	(revision 19163)
+++ libs/libmythui/myththemedmenu.cpp	(working copy)
@@ -2,6 +2,7 @@
 #include <QDir>
 #include <QKeyEvent>
 #include <QDomDocument>
+#include <QProcess>
 
 #include "myththemedmenu.h"
 #include "mythmainwindow.h"
@@ -90,6 +91,70 @@
                                bool allowreorder, MythThemedMenuState *state)
               : MythThemedMenuState(parent, name)
 {
+    Init(parent, state);
+
+    if (!parseMenu(menufile))
+        m_foundtheme = false;
+}
+
+/** \brief Creates a dynamic themed menu.
+ *
+ *  \param command      external command to execute
+ *  \param parent       the screen stack that owns this UI type
+ *  \param state        theme state associated with this menu
+ */
+MythThemedMenu::MythThemedMenu(const QString command, MythScreenStack *parent,
+                               MythThemedMenuState *state)
+              : MythThemedMenuState(parent, command)
+{
+    Init(parent, state);
+
+    QProcess process;
+    process.start(command);
+    if (!process.waitForFinished())
+    {
+        process.kill();
+        VERBOSE(VB_IMPORTANT,
+                QString("Command \"%1\" returned error\n").arg(command));
+        ShowOkPopup(QObject::tr("Couldn't execute %1")
+                    .arg(command));
+
+        m_foundtheme = false;
+        return;
+    }
+    else
+    {
+        QString errorMsg;
+        int errorLine = 0;
+        int errorColumn = 0;
+
+        QDomDocument doc;
+        if (!doc.setContent(process.readAllStandardOutput(), false,
+            &errorMsg, &errorLine, &errorColumn))
+        {
+            VERBOSE(VB_IMPORTANT,
+                    QString("Error parsing output of: %1\nat line: %2  column: %3 msg: %4").
+                    arg(command).arg(errorLine).arg(errorColumn).arg(errorMsg));
+
+            ShowOkPopup(QObject::tr("Command %1 returned incomplete menu.")
+                    .arg(command));
+
+            m_foundtheme = false;
+            return;
+        }
+
+        if (!parseMenu(doc, command))
+            m_foundtheme = false;
+    }
+}
+
+/** \brief Initializes the menu state.
+ *
+ *  \param parent       the screen stack that owns this UI type
+ *  \param state        theme state associated with this menu
+*/
+void MythThemedMenu::Init(MythScreenStack *parent, MythThemedMenuState *state)
+{
     m_state = state;
     m_allocedstate = m_foundtheme = m_ignorekeys = m_wantpop = false;
     m_exitModifier = -1;
@@ -102,18 +167,6 @@
         m_allocedstate = true;
     }
 
-    Init(menufile);
-}
-
-/** \brief Loads the main UI theme, and a menu theme.
- *
- *  See also foundtheme(void), it will return true when called after
- *  this method if this method was successful.
- *
- *  \param menufile name of menu item xml file
- */
-void MythThemedMenu::Init(const QString &menufile)
-{
     ReloadExitKey();
 
     if (!m_state->m_loaded)
@@ -133,9 +186,6 @@
             SLOT(setButtonActive(MythUIButtonListItem*)));
     connect(m_buttonList, SIGNAL(itemClicked(MythUIButtonListItem*)),
             SLOT(buttonAction(MythUIButtonListItem*)));
-
-    if (!parseMenu(menufile))
-        m_foundtheme = false;
 }
 
 MythThemedMenu::~MythThemedMenu(void)
@@ -395,6 +443,55 @@
         addButton(type, text, alttext, action);
 }
 
+/** \brief Parse the themebuttons to be added based on the contents
+ *         of the provided XML document.
+ */
+bool MythThemedMenu::parseMenu(const QDomDocument &doc, const QString &menuname)
+{
+    QDomElement docElem = doc.documentElement();
+
+    m_menumode = docElem.attribute("name", "MAIN");
+
+    QDomNode n = docElem.firstChild();
+    while (!n.isNull())
+    {
+        QDomElement e = n.toElement();
+        if (!e.isNull())
+        {
+            if (e.tagName() == "button")
+            {
+                parseThemeButton(e);
+            }
+            else
+            {
+                VERBOSE(VB_IMPORTANT, QString("MythThemedMenu: Unknown "
+                                              "element %1").arg(e.tagName()));
+                return false;
+            }
+        }
+        n = n.nextSibling();
+    }
+
+    if (m_buttonList->GetCount() == 0)
+    {
+        VERBOSE(VB_IMPORTANT, QString("MythThemedMenu: No buttons "
+                                      "for menu %1").arg(menuname));
+        return false;
+    }
+
+    if (LCD::Get())
+    {
+        m_titleText = "MYTH-";
+        m_titleText += m_menumode;
+    }
+
+    if (m_titleState)
+        m_titleState->DisplayState(m_menumode);
+
+    m_selection = "";
+    return true;
+}
+
 /** \brief Parse the themebuttons to be added based on the name of
  *         the menu file provided.
  *
@@ -412,7 +509,6 @@
 {
     QString filename = findMenuFile(menuname);
 
-    QDomDocument doc;
     QFile f(filename);
 
     if (!f.exists() || !f.open(QIODevice::ReadOnly))
@@ -430,6 +526,8 @@
     int errorLine = 0;
     int errorColumn = 0;
 
+    QDomDocument doc;
+
     if (!doc.setContent(&f, false, &errorMsg, &errorLine, &errorColumn))
     {
         VERBOSE(VB_IMPORTANT,
@@ -445,48 +543,7 @@
 
     f.close();
 
-    QDomElement docElem = doc.documentElement();
-
-    m_menumode = docElem.attribute("name", "MAIN");
-
-    QDomNode n = docElem.firstChild();
-    while (!n.isNull())
-    {
-        QDomElement e = n.toElement();
-        if (!e.isNull())
-        {
-            if (e.tagName() == "button")
-            {
-                parseThemeButton(e);
-            }
-            else
-            {
-                VERBOSE(VB_IMPORTANT, QString("MythThemedMenu: Unknown "
-                                              "element %1").arg(e.tagName()));
-                return false;
-            }
-        }
-        n = n.nextSibling();
-    }
-
-    if (m_buttonList->GetCount() == 0)
-    {
-        VERBOSE(VB_IMPORTANT, QString("MythThemedMenu: No buttons "
-                                      "for menu %1").arg(menuname));
-        return false;
-    }
-
-    if (LCD::Get())
-    {
-        m_titleText = "MYTH-";
-        m_titleText += m_menumode;
-    }
-
-    if (m_titleState)
-        m_titleState->DisplayState(m_menumode);
-
-    m_selection = "";
-    return true;
+    return parseMenu(doc, menuname);
 }
 
 void MythThemedMenu::updateLCD(void)
@@ -629,6 +686,19 @@
         else
             delete newmenu;
     }
+    else if (action.left(9) == "MENUEXEC ")
+    {
+        QString command = action.mid(9);
+
+        MythScreenStack *stack = GetScreenStack();
+
+        MythThemedMenu *newmenu = new MythThemedMenu(command, stack, m_state);
+
+        if (newmenu->foundTheme())
+            stack->AddScreen(newmenu);
+        else
+            delete newmenu;
+    }
     else if (action.left(6) == "UPMENU")
     {
         m_wantpop = true;
