Browse Source

Refactor host commands

Removes the ugly if statement in KonvergoWindow and instead makes each
component call InputComponent::registerHostCommand() if they want to
handle a host command.
Tobias Hieta 9 years ago
parent
commit
1fa34ec9aa

+ 4 - 1
src/ComponentManager.cpp

@@ -55,8 +55,8 @@ void ComponentManager::initialize()
   // might have some settings
   //
   registerComponent(&SettingsComponent::Get());
-  registerComponent(&SystemComponent::Get());
   registerComponent(&InputComponent::Get());
+  registerComponent(&SystemComponent::Get());
   registerComponent(&DisplayComponent::Get());
   registerComponent(&UpdaterComponent::Get());
   registerComponent(&RemoteComponent::Get());
@@ -66,6 +66,9 @@ void ComponentManager::initialize()
 #if KONVERGO_OPENELEC
   registerComponent(&OESystemComponent::Get());
 #endif
+
+  foreach(ComponentBase* component, m_components.values())
+    component->componentPostInitialize();
 }
 
 /////////////////////////////////////////////////////////////////////////////////////////

+ 4 - 0
src/ComponentManager.h

@@ -18,12 +18,16 @@ public:
   virtual bool componentInitialize() = 0;
   virtual const char* componentName() = 0;
   virtual bool componentExport() = 0;
+
+  // executed after ALL components are initialized
+  virtual void componentPostInitialize() { }
 };
 
 class ComponentManager : public QObject
 {
   Q_OBJECT
   DEFINE_SINGLETON(ComponentManager);
+
 public:
   void initialize();
   inline QQmlPropertyMap &getQmlPropertyMap() { return m_qmlProperyMap; }

+ 10 - 0
src/display/DisplayComponent.cpp

@@ -17,6 +17,7 @@
 #endif
 
 #include "dummy/DisplayManagerDummy.h"
+#include "input/InputComponent.h"
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 DisplayComponent::DisplayComponent(QObject* parent) : ComponentBase(parent), m_initTimer(this)
@@ -385,3 +386,12 @@ void DisplayComponent::switchCommand(QString command)
 
   QLOG_INFO() << "Requested mode not found.";
 }
+
+/////////////////////////////////////////////////////////////////////////////////////////
+void DisplayComponent::componentPostInitialize()
+{
+  InputComponent::Get().registerHostCommand("switch", this, "switchCommand");
+
+  if (m_displayManager)
+    InputComponent::Get().registerHostCommand("recreateRpiUI", m_displayManager, "resetRendering");
+}

+ 1 - 0
src/display/DisplayComponent.h

@@ -17,6 +17,7 @@ public:
   virtual const char* componentName() { return "display"; }
   virtual bool componentExport() { return true; }
   virtual bool componentInitialize();
+  virtual void componentPostInitialize();
 
   inline DisplayManager* getDisplayManager() { return m_displayManager; }
   int getApplicationDisplay(bool silent = false);

+ 46 - 2
src/input/InputComponent.cpp

@@ -88,8 +88,40 @@ void InputComponent::remapInput(const QString &source, const QString &keycode, f
   {
     if (action.startsWith("host:"))
     {
-      QLOG_DEBUG() << "Handling host command:" << action.mid(5);
-      emit receivedHostCommand(action.mid(5));
+      QStringList argList = action.mid(5).split(" ");
+      QString hostCommand = argList.value(0);
+      QString hostArguments;
+
+      if (argList.size() > 1)
+      {
+        argList.pop_front();
+        hostArguments = argList.join(" ");
+      }
+
+      QLOG_DEBUG() << "Got host command:" << hostCommand << "arguments:" << hostArguments;
+      if (m_hostCommands.contains(hostCommand))
+      {
+        ReceiverSlot* recvSlot = m_hostCommands.value(hostCommand);
+        if (recvSlot)
+        {
+          QString slotWithArgs = QString("%1(QString)").arg(QString::fromLatin1(recvSlot->slot));
+          QLOG_DEBUG() << "Looking for method:" << slotWithArgs;
+          if (recvSlot->receiver->metaObject()->indexOfMethod(slotWithArgs.toLatin1().data()) != -1)
+          {
+            QMetaObject::invokeMethod(recvSlot->receiver, recvSlot->slot.data(),
+                                      Qt::AutoConnection, Q_ARG(const QString&, hostArguments));
+          }
+          else
+          {
+            QLOG_DEBUG() << "Method has no arguments:" << recvSlot->slot.data();
+            QMetaObject::invokeMethod(recvSlot->receiver, recvSlot->slot.data(), Qt::AutoConnection);
+          }
+        }
+      }
+      else
+      {
+        QLOG_WARN() << "No such host command:" << hostCommand;
+      }
     }
     else
     {
@@ -102,3 +134,15 @@ void InputComponent::remapInput(const QString &source, const QString &keycode, f
     QLOG_WARN() << "Could not map:" << source << keycode << "to any useful action";
   }
 }
+
+/////////////////////////////////////////////////////////////////////////////////////////
+void InputComponent::registerHostCommand(const QString& command, QObject* receiver, const char* slot)
+{
+  ReceiverSlot* recvSlot = new ReceiverSlot;
+  recvSlot->receiver = receiver;
+  recvSlot->slot = QMetaObject::normalizedSignature(slot);
+
+  QLOG_DEBUG() << "Adding host command:" << qPrintable(command) << "mapped to" << qPrintable(QString(receiver->metaObject()->className()) + "::" + recvSlot->slot);
+
+  m_hostCommands.insert(command, recvSlot);
+}

+ 9 - 1
src/input/InputComponent.h

@@ -66,6 +66,12 @@ signals:
 #define INPUT_KEY_DOWN_LONG    "KEY_DOWN_LONG"
 
 
+struct ReceiverSlot
+{
+  QObject* receiver;
+  QByteArray slot;
+};
+
 class InputComponent : public ComponentBase
 {
   Q_OBJECT
@@ -76,9 +82,10 @@ public:
   virtual bool componentExport() { return true; }
   virtual bool componentInitialize();
 
+  void registerHostCommand(const QString& command, QObject* receiver, const char* slot);
+
 signals:
   void receivedAction(const QString& action);
-  void receivedHostCommand(const QString& hostCommand);
 
 private Q_SLOTS:
   void remapInput(const QString& source, const QString& keycode, float amount = 1.0);
@@ -87,6 +94,7 @@ private:
   InputComponent(QObject *parent = 0);
   bool addInput(InputBase* input);
 
+  QHash<QString, ReceiverSlot*> m_hostCommands;
   QList<InputBase*> m_inputs;
   InputMapping* m_mappings;
 };

+ 8 - 0
src/player/PlayerComponent.cpp

@@ -11,6 +11,7 @@
 #include "settings/SettingsSection.h"
 
 #include "PlayerQuickItem.h"
+#include "input/InputComponent.h"
 
 #include "QsLog.h"
 
@@ -43,6 +44,12 @@ PlayerComponent::PlayerComponent(QObject* parent)
   connect(&m_reloadAudioTimer, &QTimer::timeout, this, &PlayerComponent::onReloadAudio);
 }
 
+/////////////////////////////////////////////////////////////////////////////////////////
+void PlayerComponent::componentPostInitialize()
+{
+  InputComponent::Get().registerHostCommand("player", this, "userCommand");
+}
+
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 PlayerComponent::~PlayerComponent()
 {
@@ -861,3 +868,4 @@ QString PlayerComponent::videoInformation() const
   info << flush;
   return infoStr;
 }
+

+ 1 - 0
src/player/PlayerComponent.h

@@ -25,6 +25,7 @@ public:
   virtual const char* componentName() { return "player"; }
   virtual bool componentExport() { return true; }
   virtual bool componentInitialize();
+  virtual void componentPostInitialize();
   
   explicit PlayerComponent(QObject* parent = 0);
   virtual ~PlayerComponent();

+ 8 - 1
src/power/PowerComponent.cpp

@@ -4,6 +4,7 @@
 
 #include "PowerComponent.h"
 #include "player/PlayerComponent.h"
+#include "input/InputComponent.h"
 
 #ifdef Q_OS_MAC
 #include "PowerComponentMac.h"
@@ -94,4 +95,10 @@ void PowerComponent::playbackEnded()
   redecideScreeensaverState();
 }
 
-
+/////////////////////////////////////////////////////////////////////////////////////////
+void PowerComponent::componentPostInitialize()
+{
+  InputComponent::Get().registerHostCommand("poweroff", this, "PowerOff");
+  InputComponent::Get().registerHostCommand("reboot", this, "Reboot");
+  InputComponent::Get().registerHostCommand("suspend", this, "Suspend");
+}

+ 1 - 0
src/power/PowerComponent.h

@@ -20,6 +20,7 @@ public:
   virtual bool componentInitialize();
   virtual bool componentExport() { return true; }
   virtual const char* componentName() { return "power"; }
+  virtual void componentPostInitialize();
 
   void setFullscreenState(bool fullscreen);
 

+ 13 - 0
src/settings/SettingsComponent.cpp

@@ -11,12 +11,25 @@
 #include <QJsonObject>
 #include <QJsonArray>
 #include <QList>
+#include "input/InputComponent.h"
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 SettingsComponent::SettingsComponent(QObject *parent) : ComponentBase(parent), m_settingsVersion(-1)
 {
 }
 
+/////////////////////////////////////////////////////////////////////////////////////////
+void SettingsComponent::componentPostInitalize()
+{
+  InputComponent::Get().registerHostCommand("fullscreen", this, "toggleFullScreen");
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+void SettingsComponent::toggleFullScreen(const QString& args)
+{
+  setValue(SETTINGS_SECTION_MAIN, "fullscreen", !value(SETTINGS_SECTION_MAIN, "fullscreen").toBool());
+}
+
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 void SettingsComponent::updatePossibleValues(const QString &sectionID, const QString &key, const QVariantList &possibleValues)
 {

+ 4 - 0
src/settings/SettingsComponent.h

@@ -32,6 +32,7 @@ class SettingsComponent : public ComponentBase
 
 public:
   bool componentInitialize();
+  void componentPostInitalize();
 
   const char* componentName() { return "settings"; }
   bool componentExport() { return true; }
@@ -53,6 +54,9 @@ public:
   Q_INVOKABLE void resetToDefault();
   Q_INVOKABLE QVariantList settingDescriptions();
 
+  // host commands
+  Q_SLOT void toggleFullScreen(const QString& args);
+
   void updatePossibleValues(const QString& sectionID, const QString& key, const QVariantList& possibleValues);
 
   void saveSettings();

+ 13 - 0
src/system/SystemComponent.cpp

@@ -4,6 +4,7 @@
 #include <QtNetwork/qnetworkinterface.h>
 #include <QGuiApplication>
 #include <QDesktopServices>
+#include <input/InputComponent.h>
 
 #include "SystemComponent.h"
 #include "Version.h"
@@ -65,6 +66,18 @@ SystemComponent::SystemComponent(QObject* parent) : ComponentBase(parent), m_pla
 #endif
 }
 
+/////////////////////////////////////////////////////////////////////////////////////////
+void SystemComponent::crashApp()
+{
+  *(volatile int*)0=0;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+void SystemComponent::componentPostInitialize()
+{
+  InputComponent::Get().registerHostCommand("crash!", this, "crashApp");
+}
+
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 QString SystemComponent::getPlatformTypeString() const
 {

+ 4 - 1
src/system/SystemComponent.h

@@ -19,6 +19,7 @@ public:
   virtual bool componentExport() { return true; }
   virtual const char* componentName() { return "system"; }
   virtual bool componentInitialize() { return true; }
+  virtual void componentPostInitialize();
 
   Q_INVOKABLE QVariantMap systemInformation() const;
   Q_INVOKABLE void exit();
@@ -68,9 +69,10 @@ public:
 
   inline bool isOpenELEC() { return m_platformType == platformTypeOpenELEC; }
 
+  Q_INVOKABLE void crashApp();
+
 private:
   SystemComponent(QObject* parent = 0);
-
   static QMap<QString, QString> networkInterfaces();
 
   QTimer* m_mouseOutTimer;
@@ -78,6 +80,7 @@ private:
   PlatformArch m_platformArch;
   QString m_overridePlatform;
   bool m_doLogMessages;
+
 };
 
 #endif

+ 11 - 68
src/ui/KonvergoWindow.cpp

@@ -81,6 +81,10 @@ KonvergoWindow::KonvergoWindow(QWindow* parent) : QQuickWindow(parent), m_debugL
 
   connect(m_infoTimer, &QTimer::timeout, this, &KonvergoWindow::updateDebugInfo);
 
+  InputComponent::Get().registerHostCommand("close", this, "close");
+  InputComponent::Get().registerHostCommand("toggleDebug", this, "toggleDebug");
+  InputComponent::Get().registerHostCommand("reload", this, "reloadWeb");
+
 #ifdef TARGET_RPI
   // On RPI, we use dispmanx layering - the video is on a layer below Konvergo,
   // and during playback the Konvergo window is partially transparent. The OSD
@@ -113,10 +117,6 @@ KonvergoWindow::KonvergoWindow(QWindow* parent) : QQuickWindow(parent), m_debugL
   // this is using old syntax because ... reasons. QQuickCloseEvent is not public class
   connect(this, SIGNAL(closing(QQuickCloseEvent*)), this, SLOT(closingWindow()));
 
-  // make sure that we handle some of the host commands that can be emitted
-  connect(&InputComponent::Get(), &InputComponent::receivedHostCommand,
-          this, &KonvergoWindow::handleHostCommand);
-
   connect(qApp, &QCoreApplication::aboutToQuit, this, &KonvergoWindow::saveGeometry);
 
 #ifdef Q_OS_MAC
@@ -326,74 +326,17 @@ void KonvergoWindow::updateDebugInfo()
 }
 
 /////////////////////////////////////////////////////////////////////////////////////////
-void KonvergoWindow::handleHostCommand(QString hostCommand)
+void KonvergoWindow::toggleDebug()
 {
-  QLOG_DEBUG() << "Got command:" << hostCommand;
-  QString arguments = "";
-  int arguments_start = hostCommand.indexOf(":");
-  if (arguments_start > 0)
-  {
-    arguments = hostCommand.mid(arguments_start + 1);
-    hostCommand = hostCommand.mid(0, arguments_start);
-  }
-  if (hostCommand == "fullscreen")
-  {
-    SettingsComponent::Get().setValue(SETTINGS_SECTION_MAIN, "fullscreen", !SettingsComponent::Get().value(SETTINGS_SECTION_MAIN, "fullscreen").toBool());
-  }
-  else if (hostCommand == "close")
-  {
-    close();
-  }
-  else if (hostCommand == "player")
-  {
-    PlayerComponent::Get().userCommand(arguments);
-  }
-  else if (hostCommand == "switch")
-  {
-    DisplayComponent::Get().switchCommand(arguments);
-  }
-  else if (hostCommand == "toggleDebug")
-  {
-    if (property("showDebugLayer").toBool())
-    {
-      m_infoTimer->stop();
-      setProperty("showDebugLayer", false);
-    }
-    else
-    {
-      m_infoTimer->start();
-      updateDebugInfo();
-      setProperty("showDebugLayer", true);
-    }
-  }
-  else if (hostCommand == "recreateRpiUi")
-  {
-    DisplayManager* display_manager = DisplayComponent::Get().getDisplayManager();
-    if (display_manager)
-      display_manager->resetRendering();
-  }
-  else if (hostCommand == "reload")
-  {
-    emit reloadWebClient();
-  }
-  else if (hostCommand == "crash!")
-  {
-    *(volatile int*)0=0;
-  }
-  else if (hostCommand == "poweroff")
-  {
-    PowerComponent::Get().PowerOff();
-  }
-  else if (hostCommand == "suspend")
-  {
-    PowerComponent::Get().Suspend();
-  }
-  else if (hostCommand == "reboot")
+  if (property("showDebugLayer").toBool())
   {
-    PowerComponent::Get().Reboot();
+    m_infoTimer->stop();
+    setProperty("showDebugLayer", false);
   }
   else
   {
-    QLOG_WARN() << "unknown host command" << hostCommand;
+    m_infoTimer->start();
+    updateDebugInfo();
+    setProperty("showDebugLayer", true);
   }
 }

+ 7 - 1
src/ui/KonvergoWindow.h

@@ -42,6 +42,11 @@ public:
     raise();
   }
 
+  void reloadWeb()
+  {
+    emit reloadWebClient();
+  }
+
 Q_SIGNALS:
   void fullScreenSwitched();
   void enableVideoWindowSignal();
@@ -59,7 +64,6 @@ private slots:
   void updateMainSectionSettings(const QVariantMap& values);
   void updateFullscreenState();
   void onScreenCountChanged(int newCount);
-  void handleHostCommand(QString hostCommand);
   void updateDebugInfo();
   void playerWindowVisible(bool visible);
   void playerPlaybackStarting();
@@ -74,6 +78,8 @@ private:
   MouseEventFilter* m_eventFilter;
   QTimer* m_infoTimer;
   QString m_debugInfo, m_systemDebugInfo, m_videoInfo;
+
+  void toggleDebug();
 };
 
 #endif // KONVERGOWINDOW_H