gnome: rename video settings to media settings

Audio and video settings are now in the same panel.

Refs #71866

Change-Id: I5e9906b42a1160f985578438d363706c7d399548
diff --git a/src/mediasettingsview.cpp b/src/mediasettingsview.cpp
new file mode 100644
index 0000000..c216462
--- /dev/null
+++ b/src/mediasettingsview.cpp
@@ -0,0 +1,310 @@
+/*
+ *  Copyright (C) 2015 Savoir-Faire Linux Inc.
+ *  Author: Stepan Salenikovich <stepan.salenikovich@savoirfairelinux.com>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 USA.
+ *
+ *  Additional permission under GNU GPL version 3 section 7:
+ *
+ *  If you modify this program, or any covered work, by linking or
+ *  combining it with the OpenSSL project's OpenSSL library (or a
+ *  modified version of that library), containing parts covered by the
+ *  terms of the OpenSSL or SSLeay licenses, Savoir-Faire Linux Inc.
+ *  grants you additional permission to convey the resulting work.
+ *  Corresponding Source for a non-source form of such a combination
+ *  shall include the source code for the parts of OpenSSL used as well
+ *  as that of the covered work.
+ */
+
+#include "mediasettingsview.h"
+
+#include <gtk/gtk.h>
+#include "models/gtkqtreemodel.h"
+#include "video/video_widget.h"
+#include <video/previewmanager.h>
+#include <video/configurationproxy.h>
+#include <QtCore/QItemSelectionModel>
+#include <audio/settings.h>
+#include <audio/managermodel.h>
+#include <audio/alsapluginmodel.h>
+#include <audio/outputdevicemodel.h>
+#include <audio/inputdevicemodel.h>
+#include <audio/ringtonedevicemodel.h>
+
+struct _MediaSettingsView
+{
+    GtkBox parent;
+};
+
+struct _MediaSettingsViewClass
+{
+    GtkBoxClass parent_class;
+};
+
+typedef struct _MediaSettingsViewPrivate MediaSettingsViewPrivate;
+
+struct _MediaSettingsViewPrivate
+{
+    /* audio settings */
+    GtkWidget *combobox_manager;
+    GtkWidget *combobox_ringtone;
+    GtkWidget *combobox_output;
+    GtkWidget *combobox_input;
+
+    QMetaObject::Connection manager_selection;
+    QMetaObject::Connection ringtone_selection;
+    QMetaObject::Connection output_selection;
+    QMetaObject::Connection input_selection;
+
+    /* camera settings */
+    GtkWidget *combobox_device;
+    GtkWidget *combobox_channel;
+    GtkWidget *combobox_resolution;
+    GtkWidget *combobox_framerate;
+    GtkWidget *hbox_camera;
+    GtkWidget *video_widget;
+
+    /* this is used to keep track of the state of the preview when the settings
+     * are opened; if a call is in progress, then the preview should already be
+     * started and we don't want to stop it when the settings are closed, in this
+     * case */
+    gboolean video_started_by_settings;
+
+    QMetaObject::Connection local_renderer_connection;
+    QMetaObject::Connection device_selection;
+    QMetaObject::Connection channel_selection;
+    QMetaObject::Connection resolution_selection;
+    QMetaObject::Connection rate_selection;
+};
+
+G_DEFINE_TYPE_WITH_PRIVATE(MediaSettingsView, media_settings_view, GTK_TYPE_BOX);
+
+#define MEDIA_SETTINGS_VIEW_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), MEDIA_SETTINGS_VIEW_TYPE, MediaSettingsViewPrivate))
+
+static void
+media_settings_view_dispose(GObject *object)
+{
+    MediaSettingsView *view = MEDIA_SETTINGS_VIEW(object);
+    MediaSettingsViewPrivate *priv = MEDIA_SETTINGS_VIEW_GET_PRIVATE(view);
+
+    /* make sure to stop the preview if this view is getting destroyed */
+    if (priv->video_started_by_settings) {
+        Video::PreviewManager::instance()->stopPreview();
+        priv->video_started_by_settings = FALSE;
+    }
+
+    QObject::disconnect(priv->manager_selection);
+    QObject::disconnect(priv->ringtone_selection);
+    QObject::disconnect(priv->output_selection);
+    QObject::disconnect(priv->input_selection);
+
+    QObject::disconnect(priv->local_renderer_connection);
+    QObject::disconnect(priv->device_selection);
+    QObject::disconnect(priv->channel_selection);
+    QObject::disconnect(priv->resolution_selection);
+    QObject::disconnect(priv->rate_selection);
+
+    G_OBJECT_CLASS(media_settings_view_parent_class)->dispose(object);
+}
+
+static QModelIndex
+get_index_from_combobox(GtkComboBox *box)
+{
+    GtkTreeIter iter;
+    GtkTreeModel *model = gtk_combo_box_get_model(box);
+    if (gtk_combo_box_get_active_iter(box, &iter)) {
+        return gtk_q_tree_model_get_source_idx(GTK_Q_TREE_MODEL(model), &iter);
+    } else {
+        return QModelIndex();
+    }
+}
+
+static void
+update_selection(GtkComboBox *box, QItemSelectionModel *selection_model)
+{
+    QModelIndex idx = get_index_from_combobox(box);
+    if (idx.isValid())
+        selection_model->setCurrentIndex(idx, QItemSelectionModel::ClearAndSelect);
+}
+
+static QMetaObject::Connection
+connect_combo_box_qmodel(GtkComboBox *box, QAbstractItemModel *qmodel, QItemSelectionModel *selection_model)
+{
+    QMetaObject::Connection connection;
+    GtkCellRenderer *renderer;
+    GtkQTreeModel *model = gtk_q_tree_model_new(qmodel,
+                                                1,
+                                                Qt::DisplayRole, G_TYPE_STRING);
+
+    gtk_combo_box_set_model(box, GTK_TREE_MODEL(model));
+    renderer = gtk_cell_renderer_text_new();
+    gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(box), renderer, FALSE);
+    gtk_cell_layout_set_attributes(GTK_CELL_LAYOUT(box), renderer,
+                                   "text", 0, NULL);
+
+    /* connect signals to and from the selection model */
+    connection = QObject::connect(
+        selection_model,
+        &QItemSelectionModel::currentChanged,
+        [=](const QModelIndex & current, G_GNUC_UNUSED const QModelIndex & previous) {
+            /* select the current */
+            if (current.isValid()) {
+                GtkTreeIter new_iter;
+                GtkTreeModel *model = gtk_combo_box_get_model(box);
+                g_return_if_fail(model);
+                if (gtk_q_tree_model_source_index_to_iter(GTK_Q_TREE_MODEL(model), current, &new_iter)) {
+                    gtk_combo_box_set_active_iter(box, &new_iter);
+                } else {
+                    g_warning("SelectionModel changed to invalid QModelIndex?");
+                }
+            }
+        }
+    );
+    g_signal_connect(box,
+                     "changed",
+                     G_CALLBACK(update_selection),
+                     selection_model);
+
+    /* sync the initial selection */
+    QModelIndex idx = selection_model->currentIndex();
+    if (idx.isValid()) {
+        GtkTreeIter iter;
+        if (gtk_q_tree_model_source_index_to_iter(model, idx, &iter))
+            gtk_combo_box_set_active_iter(box, &iter);
+    }
+
+    return connection;
+}
+
+static void
+media_settings_view_init(MediaSettingsView *view)
+{
+    gtk_widget_init_template(GTK_WIDGET(view));
+
+    MediaSettingsViewPrivate *priv = MEDIA_SETTINGS_VIEW_GET_PRIVATE(view);
+
+    priv->device_selection = connect_combo_box_qmodel(GTK_COMBO_BOX(priv->combobox_device),
+                                                      Video::ConfigurationProxy::deviceModel(),
+                                                      Video::ConfigurationProxy::deviceSelectionModel());
+    priv->channel_selection = connect_combo_box_qmodel(GTK_COMBO_BOX(priv->combobox_channel),
+                                                       Video::ConfigurationProxy::channelModel(),
+                                                       Video::ConfigurationProxy::channelSelectionModel());
+    priv->resolution_selection = connect_combo_box_qmodel(GTK_COMBO_BOX(priv->combobox_resolution),
+                                                          Video::ConfigurationProxy::resolutionModel(),
+                                                          Video::ConfigurationProxy::resolutionSelectionModel());
+    priv->rate_selection = connect_combo_box_qmodel(GTK_COMBO_BOX(priv->combobox_framerate),
+                                                    Video::ConfigurationProxy::rateModel(),
+                                                    Video::ConfigurationProxy::rateSelectionModel());
+
+    /* audio settings */
+    /* instantiate all the models before the manager model first */
+    Audio::Settings::instance()->alsaPluginModel();
+    Audio::Settings::instance()->ringtoneDeviceModel();
+    Audio::Settings::instance()->inputDeviceModel();
+    Audio::Settings::instance()->outputDeviceModel();
+    priv->manager_selection = connect_combo_box_qmodel(GTK_COMBO_BOX(priv->combobox_manager),
+                                                       Audio::Settings::instance()->managerModel(),
+                                                       Audio::Settings::instance()->managerModel()->selectionModel());
+    priv->ringtone_selection = connect_combo_box_qmodel(GTK_COMBO_BOX(priv->combobox_ringtone),
+                                                        Audio::Settings::instance()->ringtoneDeviceModel(),
+                                                        Audio::Settings::instance()->ringtoneDeviceModel()->selectionModel());
+    priv->input_selection = connect_combo_box_qmodel(GTK_COMBO_BOX(priv->combobox_input),
+                                                     Audio::Settings::instance()->inputDeviceModel(),
+                                                     Audio::Settings::instance()->inputDeviceModel()->selectionModel());
+    priv->output_selection = connect_combo_box_qmodel(GTK_COMBO_BOX(priv->combobox_output),
+                                                      Audio::Settings::instance()->outputDeviceModel(),
+                                                      Audio::Settings::instance()->outputDeviceModel()->selectionModel());
+
+
+}
+
+static void
+media_settings_view_class_init(MediaSettingsViewClass *klass)
+{
+    G_OBJECT_CLASS(klass)->dispose = media_settings_view_dispose;
+
+    gtk_widget_class_set_template_from_resource(GTK_WIDGET_CLASS (klass),
+                                                "/cx/ring/RingGnome/mediasettingsview.ui");
+
+    gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), MediaSettingsView, combobox_manager);
+    gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), MediaSettingsView, combobox_ringtone);
+    gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), MediaSettingsView, combobox_output);
+    gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), MediaSettingsView, combobox_input);
+    gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), MediaSettingsView, combobox_device);
+    gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), MediaSettingsView, combobox_channel);
+    gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), MediaSettingsView, combobox_resolution);
+    gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), MediaSettingsView, combobox_framerate);
+    gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), MediaSettingsView, hbox_camera);
+}
+
+GtkWidget *
+media_settings_view_new()
+{
+    gpointer view = g_object_new(MEDIA_SETTINGS_VIEW_TYPE, NULL);
+
+    return (GtkWidget *)view;
+}
+
+void
+media_settings_view_show_preview(MediaSettingsView *self, gboolean show_preview)
+{
+    g_return_if_fail(IS_MEDIA_SETTINGS_VIEW(self));
+    MediaSettingsViewPrivate *priv = MEDIA_SETTINGS_VIEW_GET_PRIVATE(self);
+
+    /* if TRUE, create a VideoWidget, then check if the preview has already been
+     * started (because a call was in progress); if not, then start it.
+     * if FALSE, check if the preview was started by this function, if so
+     * then stop the preview; then destroy the VideoWidget to make sure we don't
+     * get useless frame updates */
+
+    if (show_preview) {
+        /* put video widget in */
+        priv->video_widget = video_widget_new();
+        gtk_widget_show_all(priv->video_widget);
+        gtk_box_pack_start(GTK_BOX(priv->hbox_camera), priv->video_widget, TRUE, TRUE, 0);
+
+        if (Video::PreviewManager::instance()->isPreviewing()) {
+            priv->video_started_by_settings = FALSE;
+
+            /* local renderer, but set as "remote" so that it takes up the whole screen */
+            video_widget_push_new_renderer(VIDEO_WIDGET(priv->video_widget),
+                                           Video::PreviewManager::instance()->previewRenderer(),
+                                           VIDEO_RENDERER_REMOTE);
+        } else {
+            priv->video_started_by_settings = TRUE;
+            priv->local_renderer_connection = QObject::connect(
+                Video::PreviewManager::instance(),
+                &Video::PreviewManager::previewStarted,
+                [=](Video::Renderer *renderer) {
+                    video_widget_push_new_renderer(VIDEO_WIDGET(priv->video_widget),
+                                                renderer,
+                                                VIDEO_RENDERER_REMOTE);
+                }
+            );
+            Video::PreviewManager::instance()->startPreview();
+        }
+    } else {
+        if (priv->video_started_by_settings) {
+            Video::PreviewManager::instance()->stopPreview();
+            QObject::disconnect(priv->local_renderer_connection);
+            priv->video_started_by_settings = FALSE;
+        }
+
+        if (priv->video_widget && IS_VIDEO_WIDGET(priv->video_widget))
+            gtk_container_remove(GTK_CONTAINER(priv->hbox_camera), priv->video_widget);
+        priv->video_widget = NULL;
+    }
+
+}