Index: libs/libmythui/myththemedmenu.cpp
===================================================================
--- libs/libmythui/myththemedmenu.cpp	(revision 19940)
+++ libs/libmythui/myththemedmenu.cpp	(working copy)
@@ -2,6 +2,7 @@
 #include <QDir>
 #include <QKeyEvent>
 #include <QDomDocument>
+#include <QProcess>
 
 #include "myththemedmenu.h"
 #include "mythmainwindow.h"
@@ -85,18 +86,18 @@
                                MythScreenStack *parent, const QString &name,
                                bool allowreorder, MythThemedMenuState *state)
     : MythThemedMenuState(parent, name),
-      m_state(state), m_allocedstate(false), m_foundtheme(false),
+      m_parent(parent), m_state(state),
+      m_allocedstate(false), m_foundtheme(false),
       m_exitModifier(-1), m_ignorekeys(false), m_wantpop(false)
 {
-    if (!m_state)
-    {
-        m_state = new MythThemedMenuState(parent, "themedmenustate");
-        m_allocedstate = true;
-    }
 
     Init(menufile);
+
+    if (!findAndParseMenu(menufile))
+        m_foundtheme = false;  // We don't have separate vars for theme & menu
 }
 
+
 /** \brief Loads the main UI theme, and a menu theme.
  *
  *  See also foundtheme(void), it will return true when called after
@@ -106,6 +107,12 @@
  */
 void MythThemedMenu::Init(const QString &menufile)
 {
+    if (!m_state)
+    {
+        m_state = new MythThemedMenuState(m_parent, "themedmenustate");
+        m_allocedstate = true;
+    }
+
     ReloadExitKey();
 
     if (!m_state->m_loaded)
@@ -125,9 +132,6 @@
             SLOT(setButtonActive(MythUIButtonListItem*)));
     connect(m_buttonList, SIGNAL(itemClicked(MythUIButtonListItem*)),
             SLOT(buttonAction(MythUIButtonListItem*)));
-
-    if (!parseMenu(menufile))
-        m_foundtheme = false;
 }
 
 MythThemedMenu::~MythThemedMenu(void)
@@ -136,6 +140,64 @@
         delete m_state;
 }
 
+/** \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),
+      m_parent(parent), m_state(state),
+      m_allocedstate(false), m_foundtheme(false),
+      m_exitModifier(-1), m_ignorekeys(false), m_wantpop(false)
+{
+    if (command.isEmpty())
+    {
+        VERBOSE(VB_IMPORTANT, "Empty MENUEXEC action?");
+
+        m_foundtheme = false;
+        return;
+    }
+
+    Init(command);
+
+    QProcess process;
+    process.start(command);
+    if (!process.waitForFinished())
+    {
+        process.kill();
+        VERBOSE(VB_IMPORTANT, "Command '" + command + "' returned error");
+        ShowOkPopup(QObject::tr("Couldn't execute %1").arg(command));
+
+        m_foundtheme = false;
+        return;
+    }
+
+    QString errorMsg;
+    int errorLine = 0;
+    int errorColumn = 0;
+
+    QDomDocument doc;
+    if (!doc.setContent(process.readAllStandardOutput(),
+                        false, &errorMsg, &errorLine, &errorColumn))
+    {
+        VERBOSE(VB_IMPORTANT, "Error parsing output of: " + command +
+                              QString("\nat line: %1  column: %2 msg: %3")
+                              .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;  // We don't have separate vars for theme & menu
+}
 /// \brief Returns true iff a theme has been found by a previous call to Init()
 bool MythThemedMenu::foundTheme(void)
 {
@@ -411,7 +473,7 @@
  *  non-essential portion of MythTV which the theme does not support.
  *
  */
-bool MythThemedMenu::parseMenu(const QString &menuname)
+bool MythThemedMenu::findAndParseMenu(const QString &menuname)
 {
     QString filename = findMenuFile(menuname);
 
@@ -450,6 +512,14 @@
 
     VERBOSE(VB_GENERAL, QString("Loading menu theme from %1").arg(filename));
 
+    return parseMenu(doc, menuname);
+}
+
+/** \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");
@@ -652,6 +722,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;
Index: libs/libmythui/myththemedmenu.h
===================================================================
--- libs/libmythui/myththemedmenu.h	(revision 19940)
+++ libs/libmythui/myththemedmenu.h	(working copy)
@@ -9,6 +9,7 @@
 class MythMainWindow;
 class MythThemedMenuState;
 
+class QDomDocument;
 class QKeyEvent;
 
 struct ThemedButton
@@ -66,7 +67,8 @@
   public:
     MythThemedMenu(const QString &cdir, const QString &menufile,
                     MythScreenStack *parent, const QString &name,
-                    bool allowreorder = false, MythThemedMenuState *state = NULL);
+                    bool allowreorder = false,
+                    MythThemedMenuState *state = NULL);
    ~MythThemedMenu();
 
     bool foundTheme(void);
@@ -89,7 +91,12 @@
   private:
     void Init(const QString &menufile);
 
-    bool parseMenu(const QString &menuname);
+    bool findAndParseMenu(const QString &menuname);
+
+    MythThemedMenu(const QString &command,
+                   MythScreenStack *parent, MythThemedMenuState *state);
+
+    bool parseMenu(const QDomDocument &doc, const QString &menuname);
     void parseThemeButton(QDomElement &element);
 
     void addButton(const QString &type, const QString &text,
@@ -106,7 +113,7 @@
 
     void updateLCD(void);
 
-    MythThemedMenu *m_parent;
+    MythScreenStack *m_parent;
 
     MythThemedMenuState *m_state;
     bool m_allocedstate;
Index: contrib/menus/random-menu.pl
===================================================================
--- contrib/menus/random-menu.pl	(revision 0)
+++ contrib/menus/random-menu.pl	(revision 0)
@@ -0,0 +1,18 @@
+#!/usr/bin/perl
+
+# random-menu.pl - Hacky test script for MENUEXEC action
+#
+# When attached to a button, like this:
+#   <button>
+#      <type>RANDOM</type>
+#      <text>Random Menu</text>
+#      <action>MENUEXEC /home/nigel/random-menu.pl</action>
+#   </button>
+#
+# it creates a sub-menu randomly chosen from the installed menus.
+
+my $menudir = '/usr/local/share/mythtv/*menu.xml';
+my @menus   = glob($menudir);
+my $chosen  = $menus[rand($#menus + 1)];  # 10 menus, $#menus=9, rand=0..9.9999
+
+print `cat $chosen`;

Property changes on: contrib/menus/random-menu.pl
___________________________________________________________________
Name: svn:executable
   + *

