<commit_before>
#include "rqt_acquisition_controller/acquisition_controller.hpp"

#include <boost/filesystem.hpp>

#include <iostream>
#include <sstream>
#include <cstdlib>

#include <pluginlib/class_list_macros.h>
#include <ros/package.h>

#include <QString>
#include <QStringList>
#include <QList>
#include <QTimer>
#include <QFileDialog>
#include <QDateTime>
#include <QThread>
#include <QBrush>
#include <QPainter>

#include <rviz/load_resource.h>

using namespace rviz;
using namespace rqt_acquisition_controller;

AcquisitionController::AcquisitionController():
    rqt_gui_cpp::Plugin(),
    widget_(0),
    ACTION(Record)("start_oni_vicon_recorder", true),
    ACTION(RunDepthSensor)("run_depth_sensor", true),
    ACTION(ChangeDepthSensorMode)("change_depth_sensor_mode", true),
    ACTION(ConnectToVicon)("connect_to_vicon", true)
{
    setObjectName("AcquisitionController");
}

void AcquisitionController::initPlugin(qt_gui_cpp::PluginContext& context)
{
    // access standalone command line arguments
    QStringList argv = context.argv();

    // create QWidget
    widget_ = new QWidget();

    ui_.setupUi(widget_);
    context.addWidget(widget_);

    // create status tree items
    status_model_ = new QStandardItemModel(widget_);
    statusTreeRoot(status_model_->invisibleRootItem())
        .appendRow(createStatusRow("Recorder", "Disconnected")
            .appendRow(createStatusRow("Vicon", "Offline"))
            .appendRow(createStatusRow("Depth Sensor", "Closed")
                .appendRow(createStatusRow("Device Type", " - "))
                .appendRow(createStatusRow("Device Name", " - "))
                .appendRow(createStatusRow("Mode", " - "))))
        .appendRow(createStatusRow("Recording status", "idle"))
        .appendRow(createStatusRow("Recording duration", "0 s"))
        .appendRow(createStatusRow("Recorded Vicon frames", "0"))
        .appendRow(createStatusRow("Recorded Depth Sensor frames", "0"))
        .appendRow(createStatusRow("Object Model Dir.", " - "))
        .appendRow(createStatusRow("Display Object Model File", " - "))
        .appendRow(createStatusRow("Tracking Object Model File", " - "));

    ui_.statusTreeView->setModel(status_model_);
    ui_.statusTreeView->expandAll();
    ui_.statusTreeView->resizeColumnToContents(0);
    ui_.statusTreeView->setMinimumHeight(20 * (status_tree_container_.size() - 1) - 10);
    ui_.statusTreeView->adjustSize();
    widget_->adjustSize();

    timer_ = new QTimer(widget_);

    ui_.startGlobalCalibrationButton->setIcon(loadPixmap("package://rviz/icons/classes/TF.png"));
    ui_.startLocalCalibrationButton->setIcon(loadPixmap("package://rviz/icons/classes/TF.png"));

    QPixmap empty_map(16, 16);
    empty_map.fill(QColor(0,0,0,0));
    empty_icon_ = QIcon(empty_map);

    connect(ui_.startRecordingButton, SIGNAL(clicked()), this, SLOT(onStartRecording()));
    connect(ui_.stopRecordingButton, SIGNAL(clicked()), this, SLOT(onStopRecording()));
    connect(ui_.stopAllButton, SIGNAL(clicked()), this, SLOT(onStopAll()));
    connect(ui_.selectDirectoryButton, SIGNAL(clicked()), this, SLOT(onSelectDirectory()));
    connect(ui_.genrateNameButton, SIGNAL(clicked()), this, SLOT(onGenerateRecordName()));
    connect(ui_.startKinectButton, SIGNAL(clicked()), this, SLOT(onStartDepthSensor()));
    connect(ui_.closeKinectButton, SIGNAL(clicked()), this, SLOT(onCloseDepthSensor()));
    connect(ui_.applyModeButton, SIGNAL(clicked()), this, SLOT(onApplyDepthSensorMode()));
    connect(ui_.connectViconButton, SIGNAL(clicked()), this, SLOT(onConnectToVicon()));
    connect(ui_.disconnectViconButton, SIGNAL(clicked()), this, SLOT(onDisconnectFromVicon()));
    connect(ui_.submitSettingsButton, SIGNAL(clicked()), this, SLOT(onSubmitSettings()));
    connect(ui_.sameModelCheckBox, SIGNAL(toggled(bool)), this, SLOT(onToggleSameModel(bool)));
    connect(ui_.detectObjectNameButton, SIGNAL(clicked()), this, SLOT(onDetectViconObjects()));
    connect(timer_, SIGNAL(timeout()), this, SLOT(onUpdateStatus()));
    connect(ui_.sameModelCheckBox, SIGNAL(stateChanged(int)), this, SLOT(onSettingsChanged(int)));
    connect(ui_.viconObjectsComboBox,
            SIGNAL(editTextChanged(QString)), this, SLOT(onSettingsChanged(QString)));
    connect(ui_.recordNameLineEdit,
            SIGNAL(textChanged(QString)), this, SLOT(onSettingsChanged(QString)));
    connect(ui_.directoryLineEdit,
            SIGNAL(textChanged(QString)), this, SLOT(onSettingsChanged(QString)));
    connect(ui_.objectModelPackageLineEdit,
            SIGNAL(textChanged(QString)), this, SLOT(onSettingsChanged(QString)));
    connect(ui_.displayObjetModelLineEdit,
            SIGNAL(textChanged(QString)), this, SLOT(onSettingsChanged(QString)));
    connect(ui_.trackingObjetModelLineEdit,
            SIGNAL(textChanged(QString)), this, SLOT(onSettingsChanged(QString)));

    qRegisterMetaType<u_int64_t>("u_int64_t");

    connect(this, SIGNAL(feedbackReceived(int, int, u_int64_t)),
            this, SLOT(oUpdateFeedback(int, int, u_int64_t)));
    connect(this, SIGNAL(setStatusIcon(QString,QString)),
            this, SLOT(onSetStatusIcon(QString,QString)));

    setActivity("depth-sensor-starting", false);
    setActivity("depth-sensor-running", false);
    setActivity("chaning-mode", false);
    setActivity("changing-mode", false);
    setActivity("vicon-connected", false);
    setActivity("settings-applied", false);
    setActivity("using-single-model", false);
    setActivity("globally-calibrated", false);
    setActivity("locally-calibrated", false);
    setActivity("recording", false);
    setActivity("global-action-pending", false);

    timer_->start(40);
}

void AcquisitionController::shutdownPlugin()
{
    timer_->stop();

    ACTION(Record).cancelAllGoals();
    ACTION(RunDepthSensor).cancelAllGoals();
    ACTION(ConnectToVicon).cancelAllGoals();
    ACTION(ChangeDepthSensorMode).cancelAllGoals();

    // avoid "done" callbacks during destructor
    if (isActive("recording")) ACTION(Record).waitForResult(ros::Duration(500));
    if (isActive("changing-mode")) ACTION(ChangeDepthSensorMode).waitForResult(ros::Duration(500));
    if (isActive("depth-sensor-running")) ACTION(RunDepthSensor).waitForResult(ros::Duration(500));
    if (isActive("vicon-connected")) ACTION(ConnectToVicon).waitForResult(ros::Duration(500));
}

void AcquisitionController::saveSettings(qt_gui_cpp::Settings& plugin_settings,
                                         qt_gui_cpp::Settings& instance_settings) const
{
    instance_settings.setValue("vicon_host", ui_.viconHostIpLineEdit->text());
    instance_settings.setValue("vicon_multicast_enabled", ui_.viconMultiCastCheckBox->isChecked());
    instance_settings.setValue("vicon_multicast_address", ui_.viconMultiCastLineEdit->text());

    instance_settings.setValue("settings_object_name", ui_.viconObjectsComboBox->currentText());
    instance_settings.setValue("settings_record_directory", ui_.directoryLineEdit->text());
    instance_settings.setValue("settings_record_name", ui_.recordNameLineEdit->text());
    instance_settings.setValue("settings_model_package", ui_.objectModelPackageLineEdit->text());
    instance_settings.setValue("settings_display_model", ui_.displayObjetModelLineEdit->text());
    instance_settings.setValue("settings_tracking_model", ui_.trackingObjetModelLineEdit->text());
    instance_settings.setValue("settings_use_same_model", ui_.sameModelCheckBox->isChecked());
}

void AcquisitionController::restoreSettings(const qt_gui_cpp::Settings& plugin_settings,
                                            const qt_gui_cpp::Settings& instance_settings)
{
    ui_.viconHostIpLineEdit->setText(
                instance_settings.value("vicon_host", "localhost:801").toString());
    ui_.viconMultiCastCheckBox->setChecked(
                instance_settings.value("vicon_multicast_enabled", false).toBool());
    ui_.viconMultiCastLineEdit->setText(
                instance_settings.value("vicon_multicast_address", "244.0.0.0:44801").toString());

    ui_.viconObjectsComboBox->addItem(
                instance_settings.value("settings_object_name", "").toString());
    ui_.viconObjectsComboBox->setCurrentIndex(
                ui_.viconObjectsComboBox->findText(
                    instance_settings.value("settings_object_name", "").toString()));
    std::string default_dir = "/home/";
    default_dir += getenv("USER");
    QString cfg_value = instance_settings.value("settings_record_directory", "").toString();
    ui_.directoryLineEdit->setText(cfg_value.isEmpty() ? default_dir.c_str() : cfg_value);
    ui_.recordNameLineEdit->setText(
                instance_settings.value("settings_record_name", "").toString());
    ui_.objectModelPackageLineEdit->setText(
                instance_settings.value("settings_model_package", "").toString());
    ui_.displayObjetModelLineEdit->setText(
                instance_settings.value("settings_display_model", "").toString());
    ui_.trackingObjetModelLineEdit->setText(
                instance_settings.value("settings_tracking_model", "").toString());
    ui_.sameModelCheckBox->setChecked(
                instance_settings.value("settings_use_same_model", false).toBool());
}

// ============================================================================================== //
// == Slots ===================================================================================== //
// ============================================================================================== //

void AcquisitionController::onStartRecording()
{
    if (!validateSettings())
    {
        ROS_INFO("Settings missing.");
        return;
    }

    ROS_INFO("Initiate recording");
    if(!ACTION(Record).waitForServer(ros::Duration(0.5)))
    {
        ROS_WARN("Timeout while connect to recording node");
        return;
    }

    oni_vicon_recorder::RecordGoal recording_goal;
    ACTION_GOAL(Record).destination = ui_.directoryLineEdit->text().toStdString();
    ACTION_GOAL(Record).name = ui_.recordNameLineEdit->text().toStdString();
    ACTION_SEND_GOAL(AcquisitionController, oni_vicon_recorder, Record);
}

void AcquisitionController::onStopRecording()
{
    ACTION(Record).cancelAllGoals();
    ROS_INFO("Stopping recording ...");
}

void AcquisitionController::onStopAll()
{
    onStopRecording();
    if (isActive("recording")) ACTION(Record).waitForResult(ros::Duration(500));

    onDisconnectFromVicon();
    if (isActive("vicon-connected")) ACTION(ConnectToVicon).waitForResult(ros::Duration(500));

    onCloseDepthSensor();
    if (isActive("changing-mode")) ACTION(ChangeDepthSensorMode).waitForResult(ros::Duration(500));
    if (isActive("depth-sensor-running")) ACTION(RunDepthSensor).waitForResult(ros::Duration(500));
}

void AcquisitionController::onSettingsChanged(QString change)
{
    setActivity("settings-applied", false);
}

void AcquisitionController::onSettingsChanged(int change)
{
    setActivity("settings-applied", false);
}

void AcquisitionController::onSetStatusIcon(QString setting, QString url)
{
    if (!url.compare("none"))
    {
        statusItem(setting.toStdString()).status->setIcon(QIcon());
    }
    else if (!url.compare("empty"))
    {
        statusItem(setting.toStdString()).status->setIcon(empty_icon_);
    }
    else
    {
        statusItem(setting.toStdString()).status->setIcon(loadPixmap(url));
    }
}

void AcquisitionController::onStartDepthSensor()
{
    setActivity("depth-sensor-starting", true);

    ROS_INFO("Starting depth sensor");
    if(!ACTION(RunDepthSensor).waitForServer(ros::Duration(0.5)))
    {
        ROS_WARN("Timeout while connect to depth sensor node");
        return;
    }

    statusItem("Depth Sensor").status->setText("Connecting ...");
    ACTION_SEND_GOAL(AcquisitionController, oni_vicon_recorder, RunDepthSensor);
}

void AcquisitionController::onCloseDepthSensor()
{
    ACTION(RunDepthSensor).cancelAllGoals();
    ROS_INFO("Closing depth sensor ...");
}

void AcquisitionController::onApplyDepthSensorMode()
{
    ROS_INFO("Changing sensor mode.");
    if(!ACTION(ChangeDepthSensorMode).waitForServer(ros::Duration(0.5)))
    {
        ROS_WARN("Timeout while connect to depth sensor node");
        return;
    }    

    setActivity("global-action-pending", true);

    ACTION_GOAL(ChangeDepthSensorMode).mode = ui_.deviceModeComboBox->currentText().toStdString();
    ACTION_SEND_GOAL(AcquisitionController, oni_vicon_recorder, ChangeDepthSensorMode);

    setActivity("changing-mode", true);
}

void AcquisitionController::onConnectToVicon()
{
    ROS_INFO("Connecting to Vicon system");
    if(!ACTION(ConnectToVicon).waitForServer(ros::Duration(0.5)))
    {
        ROS_WARN("Timeout while connect to vicon node");
        return;
    }

    ACTION_GOAL(ConnectToVicon).retry = 3;
    ACTION_GOAL(ConnectToVicon).host = ui_.viconHostIpLineEdit->text().toStdString();
    ACTION_GOAL(ConnectToVicon).multicast_address =ui_.viconMultiCastLineEdit->text().toStdString();
    ACTION_GOAL(ConnectToVicon).enable_multicast = ui_.viconMultiCastCheckBox->isChecked();
    ACTION_SEND_GOAL(AcquisitionController, oni_vicon_recorder, ConnectToVicon);
}

void AcquisitionController::onDisconnectFromVicon()
{
    ACTION(ConnectToVicon).cancelAllGoals();
}

void AcquisitionController::onSubmitSettings()
{   
    if (validateSettings())
    {
        setActivity("settings-applied", true);
        ROS_INFO("Settings applied");
    }
    else
    {
        ROS_WARN("Settings not valid");
    }
}

void AcquisitionController::onToggleSameModel(bool single_model)
{
    setActivity("using-single-model", single_model);
}

void AcquisitionController::onSelectDirectory()
{
    QString dir = QFileDialog::getExistingDirectory(
                widget_,
                "Recording Directory",
                "~/",
                QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks);

    if (!dir.isEmpty())
    {
        ui_.directoryLineEdit->setText(dir);
    }
}

void AcquisitionController::onGenerateRecordName()
{
    QDateTime dateTime = QDateTime::currentDateTime();
    ui_.recordNameLineEdit->setText("ObjectName_" + dateTime.toString("MMM-dd-yyyy_HH-mm-ss"));
}

void AcquisitionController::onDetectViconObjects()
{
    oni_vicon_recorder::ViconObjects vicon_objects;
    if (ros::service::call("detect_vicon_objects", vicon_objects))
    {
        ui_.viconObjectsComboBox->clear();
        ui_.viconObjectsComboBox->addItem("");
        for (int i = 0; i < vicon_objects.response.object_names.size(); i++)
        {
            ui_.viconObjectsComboBox->addItem(vicon_objects.response.object_names[i].c_str());
        }
    }
}

void AcquisitionController::onUpdateStatus()<commit_msg>Pointcloud publishing added<commit_after>
#include "rqt_acquisition_controller/acquisition_controller.hpp"

#include <boost/filesystem.hpp>

#include <iostream>
#include <sstream>
#include <cstdlib>

#include <pluginlib/class_list_macros.h>
#include <ros/package.h>

#include <QString>
#include <QStringList>
#include <QList>
#include <QTimer>
#include <QFileDialog>
#include <QDateTime>
#include <QThread>
#include <QBrush>
#include <QPainter>

#include <rviz/load_resource.h>

using namespace rviz;
using namespace rqt_acquisition_controller;

AcquisitionController::AcquisitionController():
    rqt_gui_cpp::Plugin(),
    widget_(0),
    ACTION(Record)("start_oni_vicon_recorder", true),
    ACTION(RunDepthSensor)("run_depth_sensor", true),
    ACTION(ChangeDepthSensorMode)("change_depth_sensor_mode", true),
    ACTION(ConnectToVicon)("connect_to_vicon", true)
{
    setObjectName("AcquisitionController");
}

void AcquisitionController::initPlugin(qt_gui_cpp::PluginContext& context)
{
    // access standalone command line arguments
    QStringList argv = context.argv();

    // create QWidget
    widget_ = new QWidget();

    ui_.setupUi(widget_);
    context.addWidget(widget_);

    // create status tree items
    status_model_ = new QStandardItemModel(widget_);
    statusTreeRoot(status_model_->invisibleRootItem())
        .appendRow(createStatusRow("Recorder", "Disconnected")
            .appendRow(createStatusRow("Vicon", "Offline"))
            .appendRow(createStatusRow("Depth Sensor", "Closed")
                .appendRow(createStatusRow("Device Type", " - "))
                .appendRow(createStatusRow("Device Name", " - "))
                .appendRow(createStatusRow("Mode", " - "))))
        .appendRow(createStatusRow("Recording status", "idle"))
        .appendRow(createStatusRow("Recording duration", "0 s"))
        .appendRow(createStatusRow("Recorded Vicon frames", "0"))
        .appendRow(createStatusRow("Recorded Depth Sensor frames", "0"))
        .appendRow(createStatusRow("Object Model Dir.", " - "))
        .appendRow(createStatusRow("Display Object Model File", " - "))
        .appendRow(createStatusRow("Tracking Object Model File", " - "));

    ui_.statusTreeView->setModel(status_model_);
    ui_.statusTreeView->expandAll();
    ui_.statusTreeView->resizeColumnToContents(0);
    ui_.statusTreeView->setMinimumHeight(20 * (status_tree_container_.size() - 1) - 10);
    ui_.statusTreeView->adjustSize();
    widget_->adjustSize();

    timer_ = new QTimer(widget_);

    ui_.startGlobalCalibrationButton->setIcon(loadPixmap("package://rviz/icons/classes/TF.png"));
    ui_.startLocalCalibrationButton->setIcon(loadPixmap("package://rviz/icons/classes/TF.png"));

    QPixmap empty_map(16, 16);
    empty_map.fill(QColor(0,0,0,0));
    empty_icon_ = QIcon(empty_map);

    connect(ui_.startRecordingButton, SIGNAL(clicked()), this, SLOT(onStartRecording()));
    connect(ui_.stopRecordingButton, SIGNAL(clicked()), this, SLOT(onStopRecording()));
    connect(ui_.stopAllButton, SIGNAL(clicked()), this, SLOT(onStopAll()));
    connect(ui_.selectDirectoryButton, SIGNAL(clicked()), this, SLOT(onSelectDirectory()));
    connect(ui_.genrateNameButton, SIGNAL(clicked()), this, SLOT(onGenerateRecordName()));
    connect(ui_.startKinectButton, SIGNAL(clicked()), this, SLOT(onStartDepthSensor()));
    connect(ui_.closeKinectButton, SIGNAL(clicked()), this, SLOT(onCloseDepthSensor()));
    connect(ui_.applyModeButton, SIGNAL(clicked()), this, SLOT(onApplyDepthSensorMode()));
    connect(ui_.connectViconButton, SIGNAL(clicked()), this, SLOT(onConnectToVicon()));
    connect(ui_.disconnectViconButton, SIGNAL(clicked()), this, SLOT(onDisconnectFromVicon()));
    connect(ui_.submitSettingsButton, SIGNAL(clicked()), this, SLOT(onSubmitSettings()));
    connect(ui_.sameModelCheckBox, SIGNAL(toggled(bool)), this, SLOT(onToggleSameModel(bool)));
    connect(ui_.detectObjectNameButton, SIGNAL(clicked()), this, SLOT(onDetectViconObjects()));
    connect(timer_, SIGNAL(timeout()), this, SLOT(onUpdateStatus()));
    connect(ui_.sameModelCheckBox, SIGNAL(stateChanged(int)), this, SLOT(onSettingsChanged(int)));
    connect(ui_.viconObjectsComboBox,
            SIGNAL(editTextChanged(QString)), this, SLOT(onSettingsChanged(QString)));
    connect(ui_.recordNameLineEdit,
            SIGNAL(textChanged(QString)), this, SLOT(onSettingsChanged(QString)));
    connect(ui_.directoryLineEdit,
            SIGNAL(textChanged(QString)), this, SLOT(onSettingsChanged(QString)));
    connect(ui_.objectModelPackageLineEdit,
            SIGNAL(textChanged(QString)), this, SLOT(onSettingsChanged(QString)));
    connect(ui_.displayObjetModelLineEdit,
            SIGNAL(textChanged(QString)), this, SLOT(onSettingsChanged(QString)));
    connect(ui_.trackingObjetModelLineEdit,
            SIGNAL(textChanged(QString)), this, SLOT(onSettingsChanged(QString)));

    qRegisterMetaType<u_int64_t>("u_int64_t");

    connect(this, SIGNAL(feedbackReceived(int, int, u_int64_t)),
            this, SLOT(oUpdateFeedback(int, int, u_int64_t)));
    connect(this, SIGNAL(setStatusIcon(QString,QString)),
            this, SLOT(onSetStatusIcon(QString,QString)));

    setActivity("depth-sensor-starting", false);
    setActivity("depth-sensor-running", false);
    setActivity("chaning-mode", false);
    setActivity("changing-mode", false);
    setActivity("vicon-connected", false);
    setActivity("settings-applied", false);
    setActivity("using-single-model", false);
    setActivity("globally-calibrated", false);
    setActivity("locally-calibrated", false);
    setActivity("recording", false);
    setActivity("global-action-pending", false);

    timer_->start(40);
}

void AcquisitionController::shutdownPlugin()
{
    timer_->stop();

    ACTION(Record).cancelAllGoals();
    ACTION(RunDepthSensor).cancelAllGoals();
    ACTION(ConnectToVicon).cancelAllGoals();
    ACTION(ChangeDepthSensorMode).cancelAllGoals();

    // avoid "done" callbacks during destructor
    if (isActive("recording")) ACTION(Record).waitForResult(ros::Duration(500));
    if (isActive("changing-mode")) ACTION(ChangeDepthSensorMode).waitForResult(ros::Duration(500));
    if (isActive("depth-sensor-running")) ACTION(RunDepthSensor).waitForResult(ros::Duration(500));
    if (isActive("vicon-connected")) ACTION(ConnectToVicon).waitForResult(ros::Duration(500));
}

void AcquisitionController::saveSettings(qt_gui_cpp::Settings& plugin_settings,
                                         qt_gui_cpp::Settings& instance_settings) const
{
    instance_settings.setValue("vicon_host", ui_.viconHostIpLineEdit->text());
    instance_settings.setValue("vicon_multicast_enabled", ui_.viconMultiCastCheckBox->isChecked());
    instance_settings.setValue("vicon_multicast_address", ui_.viconMultiCastLineEdit->text());

    instance_settings.setValue("settings_object_name", ui_.viconObjectsComboBox->currentText());
    instance_settings.setValue("settings_record_directory", ui_.directoryLineEdit->text());
    instance_settings.setValue("settings_record_name", ui_.recordNameLineEdit->text());
    instance_settings.setValue("settings_model_package", ui_.objectModelPackageLineEdit->text());
    instance_settings.setValue("settings_display_model", ui_.displayObjetModelLineEdit->text());
    instance_settings.setValue("settings_tracking_model", ui_.trackingObjetModelLineEdit->text());
    instance_settings.setValue("settings_use_same_model", ui_.sameModelCheckBox->isChecked());
}

void AcquisitionController::restoreSettings(const qt_gui_cpp::Settings& plugin_settings,
                                            const qt_gui_cpp::Settings& instance_settings)
{
    ui_.viconHostIpLineEdit->setText(
                instance_settings.value("vicon_host", "localhost:801").toString());
    ui_.viconMultiCastCheckBox->setChecked(
                instance_settings.value("vicon_multicast_enabled", false).toBool());
    ui_.viconMultiCastLineEdit->setText(
                instance_settings.value("vicon_multicast_address", "244.0.0.0:44801").toString());

    ui_.viconObjectsComboBox->addItem(
                instance_settings.value("settings_object_name", "").toString());
    ui_.viconObjectsComboBox->setCurrentIndex(
                ui_.viconObjectsComboBox->findText(
                    instance_settings.value("settings_object_name", "").toString()));
    std::string default_dir = "/home/";
    default_dir += getenv("USER");
    QString cfg_value = instance_settings.value("settings_record_directory", "").toString();
    ui_.directoryLineEdit->setText(cfg_value.isEmpty() ? default_dir.c_str() : cfg_value);
    ui_.recordNameLineEdit->setText(
                instance_settings.value("settings_record_name", "").toString());
    ui_.objectModelPackageLineEdit->setText(
                instance_settings.value("settings_model_package", "").toString());
    ui_.displayObjetModelLineEdit->setText(
                instance_settings.value("settings_display_model", "").toString());
    ui_.trackingObjetModelLineEdit->setText(
                instance_settings.value("settings_tracking_model", "").toString());
    ui_.sameModelCheckBox->setChecked(
                instance_settings.value("settings_use_same_model", false).toBool());
}

// ============================================================================================== //
// == Slots ===================================================================================== //
// ============================================================================================== //

void AcquisitionController::onStartRecording()
{
    if (!validateSettings())
    {
        ROS_INFO("Settings missing.");
        return;
    }

    ROS_INFO("Initiate recording");
    if(!ACTION(Record).waitForServer(ros::Duration(0.5)))
    {
        ROS_WARN("Timeout while connect to recording node");
        return;
    }

    oni_vicon_recorder::RecordGoal recording_goal;
    ACTION_GOAL(Record).destination = ui_.directoryLineEdit->text().toStdString();
    ACTION_GOAL(Record).name = ui_.recordNameLineEdit->text().toStdString();
    ACTION_SEND_GOAL(AcquisitionController, oni_vicon_recorder, Record);
}

void AcquisitionController::onStopRecording()
{
    ACTION(Record).cancelAllGoals();
    ROS_INFO("Stopping recording ...");
}

void AcquisitionController::onStopAll()
{
    onStopRecording();
    if (isActive("recording")) ACTION(Record).waitForResult(ros::Duration(500));

    onDisconnectFromVicon();
    if (isActive("vicon-connected")) ACTION(ConnectToVicon).waitForResult(ros::Duration(500));

    onCloseDepthSensor();
    if (isActive("changing-mode")) ACTION(ChangeDepthSensorMode).waitForResult(ros::Duration(500));
    if (isActive("depth-sensor-running")) ACTION(RunDepthSensor).waitForResult(ros::Duration(500));
}

void AcquisitionController::onSettingsChanged(QString change)
{
    setActivity("settings-applied", false);
}

void AcquisitionController::onSettingsChanged(int change)
{
    setActivity("settings-applied", false);
}

void AcquisitionController::onSetStatusIcon(QString setting, QString url)
{
    if (!url.compare("none"))
    {
        statusItem(setting.toStdString()).status->setIcon(QIcon());
    }
    else if (!url.compare("empty"))
    {
        statusItem(setting.toStdString()).status->setIcon(empty_icon_);
    }
    else
    {
        statusItem(setting.toStdString()).status->setIcon(loadPixmap(url));
    }
}

void AcquisitionController::onStartDepthSensor()
{
    setActivity("depth-sensor-starting", true);

    ROS_INFO("Starting depth sensor");
    if(!ACTION(RunDepthSensor).waitForServer(ros::Duration(0.5)))
    {
        ROS_WARN("Timeout while connect to depth sensor node");
        return;
    }

    statusItem("Depth Sensor").status->setText("Connecting ...");
    ACTION_SEND_GOAL(AcquisitionController, oni_vicon_recorder, RunDepthSensor);
}

void AcquisitionController::onCloseDepthSensor()
{
    ACTION(RunDepthSensor).cancelAllGoals();
    ROS_INFO("Closing depth sensor ...");
}

void AcquisitionController::onApplyDepthSensorMode()
{
    ROS_INFO("Changing sensor mode.");
    if(!ACTION(ChangeDepthSensorMode).waitForServer(ros::Duration(0.5)))
    {
        ROS_WARN("Timeout while connect to depth sensor node");
        return;
    }    

    setActivity("global-action-pending", true);

    ACTION_GOAL(ChangeDepthSensorMode).mode = ui_.deviceModeComboBox->currentText().toStdString();
    ACTION_SEND_GOAL(AcquisitionController, oni_vicon_recorder, ChangeDepthSensorMode);

    setActivity("changing-mode", true);
}

void AcquisitionController::onConnectToVicon()
{
    ROS_INFO("Connecting to Vicon system");
    if(!ACTION(ConnectToVicon).waitForServer(ros::Duration(0.5)))
    {
        ROS_WARN("Timeout while connect to vicon node");
        return;
    }

    ACTION_GOAL(ConnectToVicon).retry = 3;
    ACTION_GOAL(ConnectToVicon).host = ui_.viconHostIpLineEdit->text().toStdString();
    ACTION_GOAL(ConnectToVicon).multicast_address =ui_.viconMultiCastLineEdit->text().toStdString();
    ACTION_GOAL(ConnectToVicon).enable_multicast = ui_.viconMultiCastCheckBox->isChecked();
    ACTION_SEND_GOAL(AcquisitionController, oni_vicon_recorder, ConnectToVicon);
}

void AcquisitionController::onDisconnectFromVicon()
{
    ACTION(ConnectToVicon).cancelAllGoals();
}

void AcquisitionController::onSubmitSettings()
{   
    if (validateSettings())
    {
        setActivity("settings-applied", true);
        ROS_INFO("Settings applied");
    }
    else
    {
        ROS_WARN("Settings not valid");
    }
}

void AcquisitionController::onToggleSameModel(bool single_model)
{
    setActivity("using-single-model", single_model);
}

void AcquisitionController::onSelectDirectory()
{
    QString dir = QFileDialog::getExistingDirectory(
                widget_,
                "Recording Directory",
                "~/",
                QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks);

    if (!dir.isEmpty())
    {
        ui_.directoryLineEdit->setText(dir);
    }
}

void AcquisitionController::onGenerateRecordName()
{
    QDateTime dateTime = QDateTime::currentDateTime();            

    QString object_name = ui_.viconObjectsComboBox->currentText();

    ui_.recordNameLineEdit->setText(
                (object_name.isEmpty() ? "ObjectName_" : object_name + "_")
                 + dateTime.toString("MMM-dd-yyyy_HH-mm-ss"));
}

void AcquisitionController::onDetectViconObjects()
{
    oni_vicon_recorder::ViconObjects vicon_objects;
    if (ros::service::call("detect_vicon_objects", vicon_objects))
    {
        ui_.viconObjectsComboBox->clear();
        ui_.viconObjectsComboBox->addItem("");
        for (int i = 0; i < vicon_objects.response.object_names.size(); i++)
        {
            ui_.viconObjectsComboBox->addItem(vicon_objects.response.object_names[i].c_str());
        }
    }
}

void AcquisitionController::onUpdateStatus()
{'fraction_non_alphanumeric': 0.15466765488663545, 'fraction_numerical': 0.005120776201866388, 'mean_word_length': 4.827247742442089, 'pattern_counts': {'":': 0, '<': 39, '<?xml version=': 0, '>': 134, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 2, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 8, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5400383', 'n_tokens_mistral': 8914, 'n_tokens_neox': 8583, 'n_words': 1137}