Initial commit
This commit is contained in:
commit
b7d90b9afe
16245 files changed
+3396666
No files matched your search
@@ -0,0 +1,11 @@
|
||||
#
|
||||
# $Id$
|
||||
# $HeadURL$
|
||||
# $Author$
|
||||
#
|
||||
# Created by Mike Wille, SLSE, 2017-04-21
|
||||
#
|
||||
|
||||
ADD_SUBDIRECTORY(Common)
|
||||
#ADD_SUBDIRECTORY(ScriptEditor)
|
||||
ADD_SUBDIRECTORY(ScriptTimelineEditor)
|
||||
@@ -0,0 +1,83 @@
|
||||
#
|
||||
# $Id$
|
||||
# $HeadURL$
|
||||
# $Author$
|
||||
#
|
||||
# Created by Mike Wille, SLSE, 2017-04-21
|
||||
#
|
||||
|
||||
#
|
||||
# Common
|
||||
#
|
||||
SET(pre_script_common_SRCS
|
||||
script_transport_ifc.h
|
||||
topic_designer.h
|
||||
topic_designer.cpp
|
||||
|
||||
ScriptChooser/script_chooser.h
|
||||
ScriptChooser/script_chooser.cpp
|
||||
|
||||
TakeHomePackageGenerator/db_reader.cpp
|
||||
TakeHomePackageGenerator/db_reader.h
|
||||
TakeHomePackageGenerator/dvd_writer.cpp
|
||||
TakeHomePackageGenerator/dvd_writer.h
|
||||
TakeHomePackageGenerator/export.cpp
|
||||
TakeHomePackageGenerator/export.h
|
||||
TakeHomePackageGenerator/export_process.cpp
|
||||
TakeHomePackageGenerator/export_process.h
|
||||
TakeHomePackageGenerator/export_step.cpp
|
||||
TakeHomePackageGenerator/export_step.h
|
||||
TakeHomePackageGenerator/situation_exporter.cpp
|
||||
TakeHomePackageGenerator/situation_exporter.h
|
||||
)
|
||||
|
||||
QT5_WRAP_UI(pre_script_common_SRCS
|
||||
ScriptChooser/script_chooser.ui
|
||||
)
|
||||
INSTALL_SHARED_FILES(pre_script_common_SRCS
|
||||
FILES thp/index.html
|
||||
thp/index_de_DE.html
|
||||
thp/angular.min.js
|
||||
thp/angular.min.js.license
|
||||
thp/logo.svg
|
||||
thp/main.js
|
||||
thp/style.css
|
||||
thp/autorun.inf
|
||||
DESTINATION "thp"
|
||||
WS
|
||||
)
|
||||
|
||||
INSTALL_SHARED_FILES(pre_script_common_SRCS
|
||||
FILES thp/standalone/index.html
|
||||
thp/standalone/index_de_DE.html
|
||||
thp/angular.min.js
|
||||
thp/angular.min.js.license
|
||||
DESTINATION "thp_standalone"
|
||||
WS
|
||||
)
|
||||
|
||||
NGL_ADD_LIBRARY2(WS PreGuiScriptCommon SHARED ${pre_script_common_SRCS})
|
||||
NGL_TARGET_LINK_LIBRARIES(PreGuiScriptCommon
|
||||
Qt5::Widgets
|
||||
Qt5::Network
|
||||
PreGuiCommon # topic assignments
|
||||
NGLLogger
|
||||
LtsWidgets
|
||||
LtsSession
|
||||
LtsDataView
|
||||
PreScriptTimelineGuiPluginInterface
|
||||
|
||||
# TakeHomePackageGenerator
|
||||
AsmDataPluginInterface
|
||||
ExmDataPluginInterface
|
||||
LtsPluginLoader
|
||||
nglcompression
|
||||
ngldb
|
||||
nglsettings
|
||||
ngltools
|
||||
|
||||
svcCoreClient
|
||||
TopicEditorBase
|
||||
ExportBdvTopicSetting
|
||||
)
|
||||
|
||||
+283
@@ -0,0 +1,283 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* ScriptChooser Payload UI
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*
|
||||
* Created by Mike Wille, SLSE, 2017-03-21
|
||||
*/
|
||||
|
||||
#include "script_chooser.h"
|
||||
#include "ui_script_chooser.h"
|
||||
|
||||
#include <ConnectDialog/connect_dialog_nt.h>
|
||||
#include <LtsDataView/search_model.h>
|
||||
#include <LtsSession/lts_session_data.h>
|
||||
#include <LtsWidgets/lts_global_wait_dialog.h>
|
||||
#include <LtsWidgets/lts_message_dialog.h>
|
||||
#include <Plugins/PresentationManagement/Gui/Common/pre_model.h>
|
||||
#include <QMessageBox>
|
||||
#include <QCloseEvent>
|
||||
#include <QTimer>
|
||||
|
||||
|
||||
namespace PresentationManagement
|
||||
{
|
||||
|
||||
ScriptChooser::ScriptChooser(const std::shared_ptr<Interface::Dtc> &dtc,
|
||||
const std::shared_ptr<PresentationManagement::Interface::Ftc> &ftc,
|
||||
const std::shared_ptr<OperatorManagement::Interface::Dtc> &opmDtc,
|
||||
bool isPlayerMode,
|
||||
bool isImportDialog,
|
||||
QWidget *parent)
|
||||
: LtsWidgets::LtsFramelessDialog(parent, LtsWidgets::Behaviour::Modal)
|
||||
, m_model(new PresentationManagementDialogModel(this))
|
||||
, m_proxy(new PresentationManagementDialogProxyModel(this))
|
||||
, m_selected(false)
|
||||
, m_isImportDialog(isImportDialog)
|
||||
, m_ui(new Ui::ScriptChooser)
|
||||
, m_logger(getLogger(QStringLiteral("ScriptChooser")))
|
||||
, m_ftc(ftc)
|
||||
, m_requestHelper(new LtsUtils::RequestHelper(this))
|
||||
{
|
||||
if (!m_isImportDialog)
|
||||
LtsWidgets::LtsGlobalWaitDialog::getInstance()->setVisible(false);
|
||||
|
||||
m_ui->setupUi(this);
|
||||
setWindowFlags( Qt::Dialog | Qt::WindowStaysOnTopHint | Qt::CustomizeWindowHint | Qt::WindowTitleHint ); // hints..
|
||||
|
||||
// only show Valid (= not deleted) scripts
|
||||
auto predicate = [](const PresentationManagement::Presentation & p)
|
||||
{
|
||||
return (!p.isDeleted() && p.fileStatus() == FileStatus::Valid);
|
||||
};
|
||||
m_model->initModel(dtc, opmDtc, predicate);
|
||||
m_proxy->setSourceModel(m_model);
|
||||
|
||||
m_ui->ltsDataView->seamless();
|
||||
// m_ui->ltsDataView->selectCustomView();
|
||||
m_ui->ltsDataView->setSelectionMode(QAbstractItemView::SelectionMode::SingleSelection);
|
||||
m_ui->ltsDataView->setModel(m_proxy);//, [this]() { return new CustomViewExercise(this); }); TODO: custom widgets!
|
||||
int operatorId = LtsSessionData::LtsSessionData::getInstance()->getOperatorId();
|
||||
bool bSetOperator = m_ui->ltsDataView->setInitialSearchContent(
|
||||
PresentationManagementDialogModel::Columns::Operator, QVariant(LtsSessionData::LtsSessionData::getInstance()->getOperatorId())
|
||||
);
|
||||
if (!bSetOperator)
|
||||
WARNING_LOG(m_logger) << "could not set initial operator id to " << operatorId;
|
||||
|
||||
connect(m_ui->ltsDataView, &LtsDataView::LtsDataView::signalSelectionChanged,
|
||||
this, &ScriptChooser::onEnaDisa, Qt::QueuedConnection);
|
||||
connect(m_ui->ltsDataView, &LtsDataView::LtsDataView::signalDoubleClicked,
|
||||
this, &ScriptChooser::onScriptSelected, Qt::QueuedConnection);
|
||||
connect(m_ui->ltsDataView, &LtsDataView::LtsDataView::signalEnterPressed,
|
||||
this, &ScriptChooser::onScriptSelected, Qt::QueuedConnection);
|
||||
connect(m_ui->pbSelect, &QPushButton::clicked,
|
||||
this, &ScriptChooser::onScriptSelected, Qt::QueuedConnection);
|
||||
connect(m_ui->pbDeleteScript, &QPushButton::clicked,
|
||||
this, &ScriptChooser::onDeleteScript, Qt::QueuedConnection);
|
||||
|
||||
setSelectorMode(isPlayerMode); // has to be called BEFORE manually setVisible on the buttons!
|
||||
|
||||
if (!isImportDialog)
|
||||
{
|
||||
connect(m_ui->pbQuit, &QPushButton::clicked,
|
||||
this, &ScriptChooser::signalQuit, Qt::QueuedConnection);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_ui->pbNewScript->setVisible(false);
|
||||
m_ui->pbEditQuit->setVisible(false);
|
||||
}
|
||||
|
||||
connect(m_ui->pbQuit, &QPushButton::clicked, this, [this]()
|
||||
{
|
||||
LtsWidgets::LtsGlobalWaitDialog::getInstance()->setVisible(true);
|
||||
m_close = true;
|
||||
close();
|
||||
});
|
||||
|
||||
connect(m_ui->pbNewScript, &QPushButton::clicked,
|
||||
this, &ScriptChooser::signalNewScript, Qt::QueuedConnection);
|
||||
|
||||
connect(m_ui->pbEditQuit, &QPushButton::clicked,
|
||||
this, &ScriptChooser::signalEditQuit);
|
||||
|
||||
#ifndef LTS_DEBUG
|
||||
m_ui->ltsDataView->hideColumn(PresentationManagementDialogModel::Id);
|
||||
#endif
|
||||
m_ui->ltsDataView->setSortIndicator(PresentationManagementDialogModel::Name, Qt::AscendingOrder);
|
||||
|
||||
if (!m_isImportDialog)
|
||||
{
|
||||
qint32 scriptId = LtsSessionData::LtsSessionData::getInstance()->getScriptId();
|
||||
|
||||
if (scriptId == 0)
|
||||
return;
|
||||
|
||||
LtsSessionData::LtsSessionData::getInstance()->setScriptId(0);
|
||||
|
||||
if (scriptId < 0)
|
||||
{
|
||||
FATAL_LOG(m_logger) << "ScriptIdPreset " << scriptId << " is invalid!";
|
||||
Q_ASSERT(false);
|
||||
return;
|
||||
}
|
||||
|
||||
bool isExistingScriptId = false;
|
||||
qint32 rowCounter;
|
||||
|
||||
for (rowCounter = 0; rowCounter < m_model->rowCount(); ++rowCounter)
|
||||
{
|
||||
if (m_model->getRowData(rowCounter).id() == scriptId)
|
||||
{
|
||||
isExistingScriptId = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (scriptId < 0 || !isExistingScriptId)
|
||||
{
|
||||
FATAL_LOG(m_logger) << "ScriptIdPreset " << scriptId << " is invalid!";
|
||||
Q_ASSERT(false);
|
||||
return;
|
||||
}
|
||||
|
||||
QTimer::singleShot(100, this, [this, rowCounter]()
|
||||
{
|
||||
const Presentation p = m_model->getRowData(rowCounter);
|
||||
|
||||
if (p.id() <= 0)
|
||||
return;
|
||||
|
||||
setEnabled(false);
|
||||
|
||||
if (!m_isImportDialog)
|
||||
LtsWidgets::LtsGlobalWaitDialog::getInstance()->setVisible(true);
|
||||
|
||||
emit signalSelectScript(p.id());
|
||||
m_close = true;
|
||||
close();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
ScriptChooser::~ScriptChooser()
|
||||
{
|
||||
delete m_ui;
|
||||
}
|
||||
|
||||
|
||||
void ScriptChooser::reject()
|
||||
{
|
||||
if (!m_selected && !m_isImportDialog /* do not quit session if this dialog is misused as import dialog for a running app */)
|
||||
emit signalQuit();
|
||||
|
||||
QDialog::reject();
|
||||
}
|
||||
|
||||
void ScriptChooser::onDeleteScript()
|
||||
{
|
||||
int ret = QMessageBox::warning(this, tr("DELETE SCRIPT"),
|
||||
tr("Do you really want to delete the selected script?"),
|
||||
QMessageBox::Yes | QMessageBox::Cancel);
|
||||
if(ret == QMessageBox::Yes)
|
||||
{
|
||||
const QModelIndex idx = m_ui->ltsDataView->currentIndex();
|
||||
const Presentation pre = m_model->getRowData(idx.row());
|
||||
const FileStatus fs = FileStatus::Deleted;
|
||||
PresentationChangeStatusRequest req;
|
||||
|
||||
req.id(pre.id());
|
||||
req.fileStatus(fs);
|
||||
req.operatorId(LtsSessionData::LtsSessionData::getInstance()->getOperatorId());
|
||||
req.lastModified(QDateTime::currentMSecsSinceEpoch());
|
||||
DEBUG_LOG(m_logger) << "Changing status for presentation id = " << pre.id();
|
||||
|
||||
m_requestHelper->startSingleRequest([this, req]()
|
||||
{
|
||||
return m_ftc->presentationChangeStatusRequest(PresentationChangeStatusRequest(req), this);
|
||||
});
|
||||
|
||||
auto srcIdx = m_ui->ltsDataView->proxyModel()->mapFromSource(idx);
|
||||
m_ui->ltsDataView->proxyModel()->removeRow(srcIdx.row());
|
||||
|
||||
if (m_requestHelper->failed())
|
||||
ERROR_LOG(m_logger) << "Failed to change status for presentation-script_chooser";
|
||||
}
|
||||
|
||||
}
|
||||
void ScriptChooser::onScriptSelected()
|
||||
{
|
||||
if (m_isImportDialog)
|
||||
{
|
||||
connect(new LtsWidgets::LtsMessageDialogNew(this, tr("You are about to import the selected script to the currently open script.<br />"
|
||||
"The import script will be inserted at the indicated position and moves all topics after the indicated position to after the to-be imported script's content.<br/>"
|
||||
"Info: The indicated position is indicated by the light blue vertical line. Its position can be changed by clicking on a topic or by clicking at the desired position in the header (where the time texts are drawn on).<br />"
|
||||
"This operation can't be reversed.<br />"
|
||||
"<br />"
|
||||
"Are you sure you want to import the selected script?<br />"
|
||||
"Click yes to import the script.<br />"
|
||||
"Click no to cancel this operation and don't import."), tr("Import script"), LtsWidgets::Behaviour::Modal, LtsWidgets::Button::Yes | LtsWidgets::Button::No),
|
||||
&LtsWidgets::LtsMessageDialogNew::yes,
|
||||
this, &ScriptChooser::onImportScript, Qt::QueuedConnection);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
onImportScript();
|
||||
}
|
||||
|
||||
|
||||
void ScriptChooser::onImportScript()
|
||||
{
|
||||
if (m_selected)
|
||||
return;
|
||||
|
||||
m_selected = true;
|
||||
|
||||
const QModelIndex idx = m_ui->ltsDataView->currentIndex();
|
||||
const Presentation p = m_model->getRowData(idx.row());
|
||||
|
||||
if (p.id() <= 0)
|
||||
return;
|
||||
|
||||
setEnabled(false);
|
||||
|
||||
if (!m_isImportDialog)
|
||||
LtsWidgets::LtsGlobalWaitDialog::getInstance()->setVisible(true);
|
||||
|
||||
emit signalSelectScript(p.id());
|
||||
m_close = true;
|
||||
close();
|
||||
}
|
||||
|
||||
|
||||
void ScriptChooser::onEnaDisa()
|
||||
{
|
||||
m_ui->pbSelect->setEnabled(m_ui->ltsDataView->selectedRows().size() == 1);
|
||||
m_ui->pbDeleteScript->setEnabled(m_ui->ltsDataView->selectedRows().size() == 1);
|
||||
}
|
||||
|
||||
|
||||
void ScriptChooser::closeEvent(QCloseEvent *event)
|
||||
{
|
||||
if (!m_close)
|
||||
{
|
||||
event->ignore();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!m_isImportDialog)
|
||||
LtsWidgets::LtsGlobalWaitDialog::getInstance()->setVisible(true);
|
||||
}
|
||||
|
||||
|
||||
void ScriptChooser::setSelectorMode(bool isPlayer)
|
||||
{
|
||||
m_ui->pbNewScript->setVisible(!isPlayer);
|
||||
m_ui->pbEditQuit->setVisible(isPlayer);
|
||||
}
|
||||
|
||||
} // namespace PresentationManagement
|
||||
+84
@@ -0,0 +1,84 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* ScriptChooser Payload UI
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*
|
||||
* Created by Mike Wille, SLSE, 2017-03-21
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <Plugins/PresentationManagement/Gui/Script/Common/preguiscriptcommon_export.h>
|
||||
#include <Plugins/PresentationManagement/pre_data_plugin_interface.h>
|
||||
#include <Services/OperatorManagement/opm_dtc.h>
|
||||
#include <LtsWidgets/lts_frameless_dialog.h>
|
||||
#include <LtsUtilsGuiDds/request_helper.h>
|
||||
#include <Services/PresentationManagement/pre_ftc.h>
|
||||
#include <QDialog>
|
||||
|
||||
|
||||
namespace Ui { class ScriptChooser; }
|
||||
|
||||
|
||||
namespace PresentationManagement
|
||||
{
|
||||
|
||||
class PresentationManagementDialogModel;
|
||||
class PresentationManagementDialogProxyModel;
|
||||
|
||||
|
||||
class PREGUISCRIPTCOMMON_EXPORT ScriptChooser : public LtsWidgets::LtsFramelessDialog
|
||||
, protected Interface::Ftc::PresentationRemoveReplyHandler
|
||||
, protected Interface::Ftc::PresentationChangeStatusReplyHandler
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit ScriptChooser(const std::shared_ptr<Interface::Dtc> &dtc,
|
||||
const std::shared_ptr<PresentationManagement::Interface::Ftc> &ftc,
|
||||
const std::shared_ptr<OperatorManagement::Interface::Dtc> &opmDtc,
|
||||
bool isPlayerMode,
|
||||
bool isImportDialog = false,
|
||||
QWidget *parent = nullptr);
|
||||
~ScriptChooser();
|
||||
|
||||
protected:
|
||||
void closeEvent(QCloseEvent *event) override;
|
||||
void onPresentationRemoveReply(const Core::FunctionReplyObject &replyObject) override final { m_requestHelper->requestReply(replyObject); }
|
||||
void onPresentationChangeStatusReply(const Core::FunctionReplyObject &replyObject) override final { m_requestHelper->requestReply(replyObject); }
|
||||
|
||||
private:
|
||||
void setSelectorMode(bool isPlayer);
|
||||
|
||||
private slots:
|
||||
void reject() override;
|
||||
|
||||
void onDeleteScript();
|
||||
void onScriptSelected();
|
||||
void onImportScript();
|
||||
void onEnaDisa();
|
||||
|
||||
signals:
|
||||
void signalQuit();
|
||||
void signalSelectScript(int scriptId);
|
||||
void signalNewScript();
|
||||
void signalEditQuit();
|
||||
|
||||
private:
|
||||
PresentationManagementDialogModel *m_model { nullptr };
|
||||
PresentationManagementDialogProxyModel *m_proxy { nullptr };
|
||||
bool m_selected;
|
||||
bool m_close { false };
|
||||
bool m_isImportDialog;
|
||||
|
||||
Ui::ScriptChooser *m_ui { nullptr };
|
||||
NGL::INGLLogger &m_logger;
|
||||
|
||||
std::shared_ptr<PresentationManagement::Interface::Ftc> m_ftc;
|
||||
LtsUtils::RequestHelper *m_requestHelper;
|
||||
|
||||
};
|
||||
|
||||
} // namespace PresentationManagement
|
||||
+133
@@ -0,0 +1,133 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>ScriptChooser</class>
|
||||
<widget class="QDialog" name="ScriptChooser">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>800</width>
|
||||
<height>600</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="MinimumExpanding" vsizetype="MinimumExpanding">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Select Script</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout" stretch="0,0">
|
||||
<item>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_2" stretch="0,0,0">
|
||||
<item>
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="font">
|
||||
<font>
|
||||
<weight>75</weight>
|
||||
<bold>true</bold>
|
||||
</font>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Select Script:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="LtsDataView::LtsDataView" name="ltsDataView" native="true">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Minimum" vsizetype="MinimumExpanding">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>600</width>
|
||||
<height>300</height>
|
||||
</size>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="Line" name="line">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<spacer name="horizontalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="pbNewScript">
|
||||
<property name="text">
|
||||
<string>Add new Script</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="pbDeleteScript">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Delete Script</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="pbSelect">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Select</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="pbEditQuit">
|
||||
<property name="text">
|
||||
<string>Start Script Editor && Quit</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="pbQuit">
|
||||
<property name="text">
|
||||
<string>Quit</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
<class>LtsDataView::LtsDataView</class>
|
||||
<extends>QWidget</extends>
|
||||
<header>LtsDataView/lts_data_view.h</header>
|
||||
<container>1</container>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
Executable
+212
@@ -0,0 +1,212 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* DbReader for RecordingManagement
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Christian Ehrlicher, NLSE, 2018-03-14
|
||||
*/
|
||||
#include "db_reader.h"
|
||||
|
||||
#include <DDS/DDSConnector/dds_connector.h>
|
||||
|
||||
#include <LtsPluginManager/lts_plugin_loader.h>
|
||||
#include <ngldb/nsqlquery.h>
|
||||
#include <ngldb/dbtransaction.h>
|
||||
#include <QSqlDriver>
|
||||
#include <QSqlError>
|
||||
#include <QSqlField>
|
||||
#include <QSqlIndex>
|
||||
#include <QSqlRecord>
|
||||
#include <QVariant>
|
||||
|
||||
namespace TakeHomePackageGenerator
|
||||
{
|
||||
|
||||
DbReader::DbReader(int exerciseId)
|
||||
: m_exerciseId(exerciseId)
|
||||
, m_queryFrom(nullptr)
|
||||
, m_queryTo(nullptr)
|
||||
, m_bSupportsSchemasFrom(false)
|
||||
, m_bSupportsSchemasTo(false)
|
||||
, m_logger(PresentationManagement::getLogger("DbReader"))
|
||||
{}
|
||||
|
||||
DbReader::~DbReader()
|
||||
{
|
||||
delete m_queryFrom;
|
||||
delete m_queryTo;
|
||||
// Todo: crashes OperatorApplication. Required to unload?
|
||||
// LtsPluginManager::LtsPluginLoader::getInstance()->unloadAllPlugins();
|
||||
m_plugins.clear();
|
||||
}
|
||||
|
||||
bool DbReader::loadPlugin(const LtsPluginManager::PluginInstance &pi)
|
||||
{
|
||||
RecordReplay::RecordReplayPlugin *recPlugin = qobject_cast<RecordReplay::RecordReplayPlugin*>(pi.plugin);
|
||||
if (!recPlugin)
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Cannot load RecordReplayPlugin " << pi.fileName;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!recPlugin->initCopy(m_exerciseId, m_bSupportsSchemasFrom, m_bSupportsSchemasTo))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Initialisation for RecordReplayPlugin " << pi.fileName << " failed ";
|
||||
return false;
|
||||
}
|
||||
|
||||
INFO_LOG(m_logger) << "Loaded record replay plugin " << recPlugin->pluginName();
|
||||
m_plugins += recPlugin;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DbReader::init(const QSqlDatabase &dbFrom, const QSqlDatabase &dbTo)
|
||||
{
|
||||
m_dbFrom = dbFrom;
|
||||
delete m_queryFrom;
|
||||
m_queryFrom = new NSqlQuery(dbFrom);
|
||||
m_bSupportsSchemasFrom = dbFrom.driverName() != QStringLiteral("QSQLITE");
|
||||
|
||||
m_dbTo = dbTo;
|
||||
delete m_queryTo;
|
||||
m_queryTo = new NSqlQuery(dbTo);
|
||||
m_bSupportsSchemasTo = dbTo.driverName() != QStringLiteral("QSQLITE");
|
||||
|
||||
auto cb = [this](const LtsPluginManager::PluginInstance &pi) { return loadPlugin(pi);};
|
||||
LtsPluginManager::LtsPluginLoader::getInstance()->loadPlugins(LtsPluginManager::PluginType::SPECIAL,
|
||||
cb,
|
||||
QStringList(),
|
||||
QStringLiteral("recordreplay"));
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DbReader::createTables()
|
||||
{
|
||||
for(RecordReplay::RecordReplayPlugin *recPlugin : qAsConst(m_plugins))
|
||||
{
|
||||
const QVector<QString> tableNames = recPlugin->getRecordTableNames();
|
||||
for (const QString &name : tableNames)
|
||||
{
|
||||
const QString fqTableName = DBCommon::getExerciseTableName(name, m_exerciseId);
|
||||
const QSqlRecord record = m_dbFrom.record(fqTableName);
|
||||
|
||||
if (record.isEmpty())
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Empty record for " << fqTableName;
|
||||
return false;
|
||||
}
|
||||
|
||||
const QSqlIndex pk = m_dbFrom.primaryIndex(fqTableName);
|
||||
createTable(*m_queryTo, name, record, pk, m_logger);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DbReader::copyData(qint64 fromTime, qint64 toTime)
|
||||
{
|
||||
INFO_LOG(m_logger) << "IN readData";
|
||||
if (!m_queryFrom || !m_queryTo)
|
||||
return false;
|
||||
// for each plugin
|
||||
for(RecordReplay::RecordReplayPlugin *recPlugin : qAsConst(m_plugins))
|
||||
{
|
||||
if (!recPlugin->copyData(*m_queryFrom, *m_queryTo, fromTime, toTime))
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static QString sqliteTypeFromVariant(QVariant::Type t)
|
||||
{
|
||||
switch (t)
|
||||
{
|
||||
case QVariant::Bool:
|
||||
return QStringLiteral("boolean");
|
||||
case QVariant::Int:
|
||||
return QStringLiteral("integer");
|
||||
case QVariant::UInt:
|
||||
case QVariant::LongLong:
|
||||
case QVariant::ULongLong: // mhhh
|
||||
return QStringLiteral("bigint");
|
||||
case QVariant::Double:
|
||||
return QStringLiteral("double precision");
|
||||
case QVariant::String:
|
||||
return QStringLiteral("text");
|
||||
case QVariant::ByteArray:
|
||||
return QStringLiteral("blob");
|
||||
case QVariant::Date:
|
||||
case QVariant::Time:
|
||||
case QVariant::DateTime:
|
||||
return QStringLiteral("text");
|
||||
default:
|
||||
Q_ASSERT(false);
|
||||
}
|
||||
return QString();
|
||||
}
|
||||
|
||||
bool DbReader::createTable(NSqlQuery &q, const QString &tableName, const QSqlRecord &record, const QSqlIndex &pk, NGL::INGLLogger &logger)
|
||||
{
|
||||
QStringList createTableColumns;
|
||||
createTableColumns.reserve(record.count());
|
||||
|
||||
QStringList pks;
|
||||
pks.reserve(pk.count());
|
||||
for (int i = 0; i < pk.count(); ++i)
|
||||
pks += pk.field(i).name();
|
||||
|
||||
bool bCreateIdxOnId = false;
|
||||
bool bCreateIdxOnSampleTime = false;
|
||||
for (int i = 0; i < record.count(); ++i)
|
||||
{
|
||||
const QSqlField f = record.field(i);
|
||||
if (!bCreateIdxOnId && f.name() == QLatin1String("id"))
|
||||
bCreateIdxOnId = true;
|
||||
if (!bCreateIdxOnSampleTime && f.name() == QLatin1String("sample_time"))
|
||||
bCreateIdxOnSampleTime = true;
|
||||
|
||||
QString type = sqliteTypeFromVariant(f.type());
|
||||
const int idx = pks.indexOf(f.name());
|
||||
if (idx >= 0)
|
||||
{
|
||||
pks.removeAt(i);
|
||||
type = QStringLiteral("INTEGER PRIMARY KEY");
|
||||
}
|
||||
|
||||
createTableColumns += f.name() + QLatin1Char(' ') + type;
|
||||
}
|
||||
if (bCreateIdxOnSampleTime)
|
||||
bCreateIdxOnId = false;
|
||||
|
||||
const QString createTableCommand(QStringLiteral("CREATE TABLE %1 (%2)").arg(tableName, createTableColumns.join(QStringLiteral(",\n"))));
|
||||
const QString indexIdTableCommand(QStringLiteral("CREATE INDEX IDX_%1_id ON %1 (id)").arg(tableName));
|
||||
const QString indexStTableCommand(QStringLiteral("CREATE INDEX IDX_%1_sampleTime ON %1 (sample_time)").arg(tableName));
|
||||
DEBUG_LOG(logger) << createTableCommand;
|
||||
DEBUG_LOG(logger) << indexIdTableCommand;
|
||||
DEBUG_LOG(logger) << indexStTableCommand;
|
||||
|
||||
q.exec(QStringLiteral("DROP TABLE IF EXISTS %1").arg(tableName));
|
||||
|
||||
if (!q.exec(createTableCommand))
|
||||
{
|
||||
ERROR_LOG(logger) << "qOut create table failed... " << q.lastError().text();
|
||||
return false;
|
||||
}
|
||||
if (bCreateIdxOnId && !q.exec(indexIdTableCommand))
|
||||
{
|
||||
ERROR_LOG(logger) << "qOut create index on table... " << q.lastError().text();
|
||||
return false;
|
||||
}
|
||||
if (bCreateIdxOnSampleTime && !q.exec(indexStTableCommand))
|
||||
{
|
||||
ERROR_LOG(logger) << "qOut create index on table... " << q.lastError().text();
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // TakeHomePackageGenerator
|
||||
Executable
+53
@@ -0,0 +1,53 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* DbReader for SituationReplay
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Christian Ehrlicher, NLSE, 2018-03-14
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <QVector>
|
||||
#include <QSqlDatabase>
|
||||
|
||||
#include <PluginInterfaces/record_replay_plugin.h>
|
||||
#include <PresentationManagement/logger.h>
|
||||
|
||||
class NSqlQuery;
|
||||
namespace LtsPluginManager
|
||||
{
|
||||
struct PluginInstance;
|
||||
}
|
||||
namespace TakeHomePackageGenerator
|
||||
{
|
||||
|
||||
class DbReader final
|
||||
{
|
||||
public:
|
||||
explicit DbReader(int exerciseId);
|
||||
~DbReader();
|
||||
|
||||
bool init(const QSqlDatabase &dbFrom, const QSqlDatabase &dbTo);
|
||||
|
||||
bool createTables();
|
||||
bool copyData(qint64 fromTime, qint64 toTime);
|
||||
|
||||
|
||||
static bool createTable(NSqlQuery &q, const QString &tableName, const QSqlRecord &record, const QSqlIndex &pk, NGL::INGLLogger &logger);
|
||||
private:
|
||||
bool loadPlugin(const LtsPluginManager::PluginInstance &pi);
|
||||
private:
|
||||
int m_exerciseId;
|
||||
QSqlDatabase m_dbFrom;
|
||||
QSqlDatabase m_dbTo;
|
||||
NSqlQuery *m_queryFrom;
|
||||
NSqlQuery *m_queryTo;
|
||||
bool m_bSupportsSchemasFrom;
|
||||
bool m_bSupportsSchemasTo;
|
||||
|
||||
QVector<RecordReplay::RecordReplayPlugin*> m_plugins;
|
||||
|
||||
NGL::INGLLogger &m_logger;
|
||||
};
|
||||
} // namespace TakeHomePackageGenerator
|
||||
Executable
+254
@@ -0,0 +1,254 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* Burn data to dvd
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Philipp Last, NLSE, 2018-07-09
|
||||
*/
|
||||
|
||||
#include "dvd_writer.h"
|
||||
#include <LtsWidgets/lts_message_dialog.h>
|
||||
#include <QFileInfo>
|
||||
|
||||
namespace TakeHomePackageGenerator
|
||||
{
|
||||
DVDWriter::DVDWriter(const QString &packageDir, QObject *pParent)
|
||||
: QObject(pParent)
|
||||
, m_pProgressDlg(new QProgressDialog(tr("Burning files..."), tr("Abort"), 0, 100, nullptr))
|
||||
, m_packageDir(packageDir)
|
||||
, m_logger(PresentationManagement::getLogger("DbReader"))
|
||||
{
|
||||
connect(m_pProgressDlg, &QProgressDialog::canceled, this, &DVDWriter::slotCancel);
|
||||
}
|
||||
|
||||
|
||||
void DVDWriter::slotCancel()
|
||||
{
|
||||
cleanupProcess();
|
||||
m_pProgressDlg->setLabelText(tr("Cancelling burning process..."));
|
||||
m_pProgressDlg->setCancelButton(nullptr);
|
||||
m_pProgressDlg->setMaximum(0);
|
||||
}
|
||||
|
||||
|
||||
DVDWriter::~DVDWriter()
|
||||
{
|
||||
if (m_pProgressDlg)
|
||||
m_pProgressDlg->deleteLater();
|
||||
}
|
||||
|
||||
|
||||
void DVDWriter::slotWriteDVD()
|
||||
{
|
||||
cleanupProcess();
|
||||
|
||||
m_dvdBurnProcess = new QProcess(this);
|
||||
|
||||
m_pProgressDlg->setMinimumDuration(0);
|
||||
m_pProgressDlg->setWindowTitle(tr("Burning..."));
|
||||
m_pProgressDlg->setWindowModality(Qt::WindowModal);
|
||||
|
||||
QStringList args;
|
||||
args << QStringLiteral("-Z") << dvdDevice() << QStringLiteral("-R") << QStringLiteral("-J") << QStringLiteral("-udf") << m_packageDir;
|
||||
|
||||
connect(m_dvdBurnProcess.data(), &QProcess::readyRead,
|
||||
this, &DVDWriter::incomingDataAvailable);
|
||||
connect(m_dvdBurnProcess.data(), QOverload<int, QProcess::ExitStatus>::of(&QProcess::finished),
|
||||
this, &DVDWriter::dvdFinished);
|
||||
|
||||
m_dvdBurnProcess->setProcessChannelMode(QProcess::MergedChannels);
|
||||
m_dvdBurnProcess->start(dvdProgram(), args);
|
||||
}
|
||||
|
||||
|
||||
void DVDWriter::incomingDataAvailable()
|
||||
{
|
||||
while (m_dvdBurnProcess && m_dvdBurnProcess->canReadLine())
|
||||
{
|
||||
const QByteArray qB = m_dvdBurnProcess->readLine().trimmed();
|
||||
INFO_LOG(m_logger) << "qb = " << qB.data()
|
||||
<< " m_packageDir=" << m_packageDir;
|
||||
|
||||
if (qB.contains(":-["))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "growisofs error: '" << qB << "'";
|
||||
cleanupProcess();
|
||||
|
||||
QString errString = QString::fromUtf8(qB.mid(3));
|
||||
|
||||
if (LtsWidgets::LtsMessageDialog::showMessage(qobject_cast<QWidget *>(parent()), tr("No DVD in drive / error burning dvd. Try again?"),
|
||||
errString,
|
||||
LtsWidgets::Behaviour::Modal,
|
||||
LtsWidgets::Button::Yes | LtsWidgets::Button::No) == LtsWidgets::Button::Yes)
|
||||
slotWriteDVD();
|
||||
else
|
||||
{
|
||||
cleanup(false);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Example Text:
|
||||
if (qB.contains("estimate finish")) // " 6.31% done, estimate finish Thu Sep 1 12:09:05 2011"
|
||||
m_pProgressDlg->setValue((int) qB.left(qB.indexOf("%")).toDouble() * 0.9); // 90% for processes %age, 10% for lead out & Co.
|
||||
else if (qB.contains("Total translation table size")) // "Total translation table size: 0"
|
||||
m_pProgressDlg->setValue(91);
|
||||
else if (qB.contains("Total rockridge attributes bytes")) // "Total rockridge attributes bytes: 92758"
|
||||
m_pProgressDlg->setValue(92);
|
||||
else if (qB.contains("Total directory bytes")) // "Total directory bytes: 165888"
|
||||
m_pProgressDlg->setValue(93);
|
||||
else if (qB.contains("Path table size(bytes)")) // "Path table size(bytes): 244"
|
||||
m_pProgressDlg->setValue(94);
|
||||
else if (qB.contains("Max brk space used")) // "Max brk space used ea000"
|
||||
m_pProgressDlg->setValue(95);
|
||||
else if (qB.contains("extents written")) // "79377 extents written (155 MB)"
|
||||
m_pProgressDlg->setValue(96);
|
||||
else if (qB.contains("builtin_dd")) // "builtin_dd: 79392*2KB out @ average 5.6x1352KBps"
|
||||
m_pProgressDlg->setValue(97);
|
||||
else if (qB.contains("flushing cache")) // "/dev/dvd: flushing cache"
|
||||
m_pProgressDlg->setValue(98);
|
||||
else if (qB.contains("updating RMA")) // "/dev/dvd: updating RMA"
|
||||
m_pProgressDlg->setValue(99);
|
||||
else if (qB.contains("closing session")) // "/dev/dvd: closing session"
|
||||
m_pProgressDlg->setValue(100);
|
||||
else if (qB.contains("media is not recognized"))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "growisofs error: '" << qB << "'";
|
||||
cleanupProcess();
|
||||
|
||||
if (LtsWidgets::LtsMessageDialog::showMessage(qobject_cast<QWidget *>(parent()), tr("No DVD in drive. Try again?"),
|
||||
tr("Media is not recognized"),
|
||||
LtsWidgets::Behaviour::Modal,
|
||||
LtsWidgets::Button::Yes | LtsWidgets::Button::No) == LtsWidgets::Button::Yes)
|
||||
slotWriteDVD();
|
||||
else
|
||||
cleanup(false);
|
||||
return;
|
||||
}
|
||||
else if (qB.contains(":-( unable to open"))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "growisofs error: '" << qB << "'";
|
||||
cleanupProcess();
|
||||
|
||||
if (LtsWidgets::LtsMessageDialog::showMessage(qobject_cast<QWidget *>(parent()), tr("Unable to open DVD device. Try again?"),
|
||||
tr("Unable to open DVD device"),
|
||||
LtsWidgets::Behaviour::Modal,
|
||||
LtsWidgets::Button::Yes | LtsWidgets::Button::No) == LtsWidgets::Button::Yes)
|
||||
slotWriteDVD();
|
||||
else
|
||||
cleanup(false);
|
||||
return;
|
||||
}
|
||||
else if (qB.contains(":-("))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "growisofs error: '" << qB << "'";
|
||||
cleanupProcess();
|
||||
|
||||
QString strError(tr("Unable to open DVD device"));
|
||||
|
||||
QString strErrorReason(QString::fromUtf8(qB));
|
||||
int index = strErrorReason.indexOf(QLatin1Char(':'), 1); // Skip eyes of the sad smiley (':-(')
|
||||
if (index > 0)
|
||||
{
|
||||
strError += QStringLiteral("<br>Error:");
|
||||
strError += strErrorReason.remove(0, index + 1);
|
||||
}
|
||||
|
||||
LtsWidgets::LtsMessageDialog::showMessage(qobject_cast<QWidget *>(parent()), strError);
|
||||
cleanup(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void DVDWriter::dvdFinished(int exitCode, QProcess::ExitStatus exitStatus)
|
||||
{
|
||||
// TODO: exitCode und exitStatus korrekt auswerten
|
||||
INFO_LOG(m_logger) << "growisofs ends with extitCode : '" << exitCode << " and ExitStatus '" << exitStatus;
|
||||
|
||||
//Closing Down DVD Process
|
||||
if (!m_dvdBurnProcess)
|
||||
{
|
||||
WARNING_LOG(m_logger) << "dvdFinished with error code: " << exitCode << ", status: " << exitStatus
|
||||
<< " process is already cleaned up";
|
||||
return;
|
||||
}
|
||||
|
||||
m_dvdBurnProcess->close();
|
||||
m_dvdBurnProcess->deleteLater();
|
||||
m_dvdBurnProcess = nullptr;
|
||||
if (exitCode == 0 && exitStatus == QProcess::NormalExit)
|
||||
{
|
||||
m_pProgressDlg->setValue(100);
|
||||
LtsWidgets::LtsMessageDialog::showMessage(qobject_cast<QWidget *>(parent()), tr("Burning complete"));
|
||||
cleanup(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
ERROR_LOG(m_logger) << "dvdFinished with error code: " << exitCode << ", status: " << exitStatus;
|
||||
LtsWidgets::LtsMessageDialog::showMessage(qobject_cast<QWidget *>(parent()), tr("Burning aborted with an unkown error %1").arg(exitCode));
|
||||
cleanup(false);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void DVDWriter::cleanup(bool success)
|
||||
{
|
||||
if (m_pProgressDlg)
|
||||
{
|
||||
m_pProgressDlg->deleteLater();
|
||||
m_pProgressDlg = nullptr;
|
||||
}
|
||||
emit signalBurningFinished(success);
|
||||
}
|
||||
|
||||
|
||||
void DVDWriter::cleanupProcess()
|
||||
{
|
||||
if (m_dvdBurnProcess)
|
||||
{
|
||||
m_dvdBurnProcess->disconnect();
|
||||
m_dvdBurnProcess->terminate();
|
||||
if (!m_dvdBurnProcess->waitForFinished(1000))
|
||||
m_dvdBurnProcess->kill();
|
||||
m_dvdBurnProcess->deleteLater();
|
||||
m_dvdBurnProcess = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool DVDWriter::checkBuringCapabilities()
|
||||
{
|
||||
QFileInfo fi1(dvdProgram());
|
||||
if (!fi1.exists() || !fi1.isFile() || !fi1.isExecutable())
|
||||
{
|
||||
LtsWidgets::LtsMessageDialog::showMessage(qobject_cast<QWidget *>(parent()), tr("Unable to locate burning executable (%1)").arg(dvdProgram()));
|
||||
return false;
|
||||
}
|
||||
|
||||
QFileInfo fi2(dvdDevice());
|
||||
if (!fi2.exists() || !fi2.isReadable() || !fi2.isWritable())
|
||||
{
|
||||
LtsWidgets::LtsMessageDialog::showMessage(qobject_cast<QWidget *>(parent()), tr("Unable to find DVD device (%1)").arg(dvdDevice()));
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
QString DVDWriter::dvdProgram() const
|
||||
{
|
||||
return QStringLiteral("/usr/bin/growisofs");
|
||||
}
|
||||
|
||||
QString DVDWriter::dvdDevice() const
|
||||
{
|
||||
#ifdef LTS_DEBUG
|
||||
return QStringLiteral("/dev/sr0");
|
||||
#else
|
||||
return QStringLiteral("/dev/rde/dvd");
|
||||
#endif
|
||||
}
|
||||
}
|
||||
Executable
+54
@@ -0,0 +1,54 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* Burn data to dvd
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Philipp Last, NLSE, 2018-07-09
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <PresentationManagement/logger.h>
|
||||
#include "export.h"
|
||||
|
||||
#include <QObject>
|
||||
#include <QString>
|
||||
#include <QProcess>
|
||||
#include <QPointer>
|
||||
#include <QProgressDialog>
|
||||
|
||||
namespace TakeHomePackageGenerator
|
||||
{
|
||||
class PREGUISCRIPTCOMMON_EXPORT DVDWriter : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit DVDWriter(const QString &packageDir, QObject *pParent = nullptr);
|
||||
~DVDWriter();
|
||||
|
||||
signals:
|
||||
void signalBurningFinished(bool success);
|
||||
|
||||
public slots:
|
||||
void slotWriteDVD();
|
||||
|
||||
private slots:
|
||||
void slotCancel();
|
||||
void incomingDataAvailable();
|
||||
void dvdFinished(int exitCode, QProcess::ExitStatus exitStatus);
|
||||
|
||||
private:
|
||||
void cleanup(bool success);
|
||||
void cleanupProcess();
|
||||
bool checkBuringCapabilities();
|
||||
QString dvdProgram() const;
|
||||
QString dvdDevice() const;
|
||||
|
||||
QProgressDialog *m_pProgressDlg;
|
||||
|
||||
QString m_packageDir;
|
||||
QPointer<QProcess> m_dvdBurnProcess;
|
||||
NGL::INGLLogger &m_logger;
|
||||
};
|
||||
}
|
||||
+25
@@ -0,0 +1,25 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Philipp Last, NLSE, 2018-07-09
|
||||
*/
|
||||
|
||||
#include "export.h"
|
||||
#include "situation_exporter.h"
|
||||
#include <DDS/DDSConnector/dds_connector.h>
|
||||
|
||||
namespace TakeHomePackageGenerator
|
||||
{
|
||||
bool exportSituationMapData(int exerciseId, const QString& strPathToFile, qint64 fromTime, qint64 toTime)
|
||||
{
|
||||
SituationExporter se(exerciseId);
|
||||
if (!se.exportStaticData(strPathToFile))
|
||||
return false;
|
||||
if (!se.exportDynamicData(fromTime, toTime))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
} // namespace TakeHomePackageGenerator
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Philipp Last, NLSE, 2018-07-09
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include <QtGlobal>
|
||||
#include <Plugins/PresentationManagement/Gui/Script/Common/preguiscriptcommon_export.h>
|
||||
|
||||
namespace TakeHomePackageGenerator
|
||||
{
|
||||
PREGUISCRIPTCOMMON_EXPORT bool exportSituationMapData(int exerciseId, const QString& strPathToFile, qint64 fromTime = 0, qint64 toTime = 1822159491 * 1000LL);
|
||||
}
|
||||
|
||||
Executable
+637
@@ -0,0 +1,637 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Philipp Last, NLSE, 2018-07-09
|
||||
*/
|
||||
|
||||
#include "export_process.h"
|
||||
#include "export_step.h"
|
||||
#include <QDir>
|
||||
#include <QJsonDocument>
|
||||
#include <QJsonParseError>
|
||||
#include <QProgressDialog>
|
||||
#include <Plugins/ExerciseManagement/exm_data_plugin_interface.h>
|
||||
#include <Plugins/AssetManagement/asm_data_plugin_interface.h>
|
||||
#include <ngltools/ngltools_filesystem.h>
|
||||
|
||||
|
||||
namespace TakeHomePackageGenerator
|
||||
{
|
||||
//
|
||||
// ExportedScriptInformation
|
||||
//
|
||||
QJsonValue ExportedScriptInformation::toJson() const
|
||||
{
|
||||
// THP-Export: In der Übersichts-Website 'Take Home Package werden einige
|
||||
// Übungsparameter angezeigt, aber auch die Präsenmtationen mit ihrem
|
||||
// Namen aufgelistet. Dort gab es wohl in Hin und Her zw.
|
||||
// 'presentations.name' und 'presentations.displayName'.
|
||||
// Daher schreiben wir nun den ScriptName doppelt, damit es für beiden
|
||||
// Varianten funktioniert:
|
||||
return QJsonObject({{QStringLiteral("name"), scriptName},
|
||||
{QStringLiteral("displayName"), scriptName}, // write {name and displayName} with identical value (not clear which will be used at index_de_DE.html @ thp_viewer)
|
||||
{QStringLiteral("path"), jsonPath},
|
||||
{QStringLiteral("scriptId"), scriptId},
|
||||
{QStringLiteral("exportTime"), exportTime},
|
||||
{QStringLiteral("exerciseName"), exerciseName}
|
||||
});
|
||||
}
|
||||
|
||||
ExportProcess::ExportProcess(LtsSession::LtsSession *pSession,
|
||||
const std::shared_ptr<SituationReplay::ForeignGuiInterface> &replayGuiIfc,
|
||||
QProgressDialog *pProgressDlg,
|
||||
const QString &strScriptName,
|
||||
const QString &strExerciseName,
|
||||
int scriptId,
|
||||
const std::vector<PresentationManagement::PresentationContent> &contentList,
|
||||
const QMap<QString, PresentationManagement::TopicAssignment> &trackEntryAssignments,
|
||||
QObject *parent)
|
||||
: QObject(parent)
|
||||
, m_contentList(contentList)
|
||||
, m_trackEntryAssignments(trackEntryAssignments)
|
||||
, m_strScriptName(strScriptName)
|
||||
, m_strExerciseName(strExerciseName)
|
||||
, m_scriptId(scriptId)
|
||||
, m_pSession(pSession)
|
||||
, m_replayGuiIfc(replayGuiIfc)
|
||||
, m_pProgressDlg(pProgressDlg)
|
||||
, m_cntTopicsToExport(0)
|
||||
, m_logger(PresentationManagement::getLogger("ExportProcess"))
|
||||
{
|
||||
QDir().mkpath(contentPath());
|
||||
}
|
||||
|
||||
|
||||
ExportProcess::~ExportProcess()
|
||||
{
|
||||
for (auto e : qAsConst(m_vecExportSteps))
|
||||
e->deleteLater();
|
||||
|
||||
for (auto e : qAsConst(m_vecExportStepsExecuted))
|
||||
e->deleteLater();
|
||||
}
|
||||
|
||||
QString ExportProcess::exportPath(const int exerciseId)
|
||||
{
|
||||
return exportRootPath() + QStringLiteral("Exercise_%1/").arg(exerciseId);
|
||||
}
|
||||
|
||||
QString ExportProcess::exportRootPath()
|
||||
{
|
||||
return QDir::tempPath() + QLatin1String("/THP-Export/");
|
||||
}
|
||||
|
||||
static QVector<TopicReplay::Interface::SituationReplayTime> extractUsedSitReplayTimes(
|
||||
const TopicEditorBase::TopicData &data, const QVector<TopicReplay::Interface::SituationReplayTime> &allSitReplayTimes
|
||||
)
|
||||
{
|
||||
// Add replay information (not necessarily available) to attributes
|
||||
QVector<TopicReplay::Interface::SituationReplayTime> ret;
|
||||
ret.reserve(5);
|
||||
for (const TopicReplay::Interface::SituationReplayTime &sitReplayTime : allSitReplayTimes)
|
||||
{
|
||||
bool collides = LtsScriptTimeline::isCollision(data.startTime, data.startTime + data.duration, sitReplayTime.topicStart_s, sitReplayTime.topicEnd_s);
|
||||
if (collides)
|
||||
ret.push_back(sitReplayTime);
|
||||
}
|
||||
// Order chronologically
|
||||
std::sort(ret.begin(), ret.end(),
|
||||
[](const TopicReplay::Interface::SituationReplayTime &a, const TopicReplay::Interface::SituationReplayTime &b)
|
||||
{
|
||||
return a.topicStart_s < b.topicStart_s;
|
||||
});
|
||||
return ret;
|
||||
}
|
||||
|
||||
void ExportProcess::slotStartExport()
|
||||
{
|
||||
/*
|
||||
* Identify all replay topics, save their start and end times (topic start/end and actual replay start/end time).
|
||||
* Replay topics are used when exporting, e.g. Building Topics since they may be placed parallel to one or more ReplayTopics
|
||||
*/
|
||||
QVector<TopicReplay::Interface::SituationReplayTime> allSitReplayTimes;
|
||||
|
||||
for (const PresentationManagement::PresentationContent &content : qAsConst(m_contentList))
|
||||
{
|
||||
auto it = m_trackEntryAssignments.constFind(QString::fromStdString(content.presentationTopicType()));
|
||||
if (it == m_trackEntryAssignments.constEnd())
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Invalid content for type (" << content.presentationTopicType() << "): " << QString::fromStdString(content.presentationTopicType());
|
||||
continue;
|
||||
}
|
||||
|
||||
const PresentationManagement::TopicAssignment &ta = it.value();
|
||||
if (ta.topicType == TopicEditorBase::TopicType::SituationReplay ||
|
||||
ta.topicType == TopicEditorBase::TopicType::Situation)
|
||||
{
|
||||
// Verify content
|
||||
if (content.attributes().size() == 0)
|
||||
continue;
|
||||
|
||||
QJsonParseError parseError;
|
||||
const QJsonDocument doc(QJsonDocument::fromJson(QByteArray(content.attributes().c_str(), content.attributes().size()), &parseError));
|
||||
if (parseError.error != QJsonParseError::NoError)
|
||||
continue;
|
||||
const QJsonObject detailData = doc.object();
|
||||
|
||||
TopicReplay::Interface::SituationReplayTime sitReplayTime;
|
||||
sitReplayTime.id = content.id();
|
||||
sitReplayTime.topicStart_s = content.startTime();
|
||||
sitReplayTime.topicEnd_s = content.startTime() + content.duration();
|
||||
sitReplayTime.replaySpeedFactor = qRound64(detailData.value(QStringLiteral("speed")).toDouble(1.0));
|
||||
sitReplayTime.replayStart_ms = qRound64(detailData.value(QStringLiteral("start")).toDouble());
|
||||
sitReplayTime.replayEnd_ms = sitReplayTime.replayStart_ms + (content.duration() * sitReplayTime.replaySpeedFactor * 1000); // do not use 'end' json object
|
||||
allSitReplayTimes.push_back(std::move(sitReplayTime));
|
||||
}
|
||||
}
|
||||
|
||||
for (const PresentationManagement::PresentationContent &content : m_contentList)
|
||||
{
|
||||
auto it = m_trackEntryAssignments.constFind(QString::fromStdString(content.presentationTopicType()));
|
||||
|
||||
if (it == m_trackEntryAssignments.constEnd())
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Invalid content for presentation type " << content.presentationTopicType();
|
||||
continue;
|
||||
}
|
||||
|
||||
// Verify content
|
||||
if (content.attributes().size() == 0)
|
||||
continue;
|
||||
|
||||
QJsonParseError parseError;
|
||||
const QJsonDocument doc(QJsonDocument::fromJson(QByteArray(content.attributes().c_str(), content.attributes().size()), &parseError));
|
||||
if (parseError.error != QJsonParseError::NoError)
|
||||
continue;
|
||||
QJsonObject detailData = doc.object();
|
||||
|
||||
const PresentationManagement::TopicAssignment &ta = *it;
|
||||
|
||||
// Get export interface
|
||||
TopicReplay::Interface *topicExportIfc = ta.topicExportFactory->createInterface(ta.topicType);
|
||||
|
||||
if (!topicExportIfc)
|
||||
{
|
||||
//WARNING_LOG(m_logger) << "Warning: Export for topic id " << te->m_topicId << " failed";
|
||||
continue;
|
||||
}
|
||||
|
||||
// add the filter steps
|
||||
m_vecExportSteps += parseFilterSteps(content.id(), detailData, allSitReplayTimes);
|
||||
|
||||
// TrackEntry is used when all topics have been exported and the html table is created (start time, duration)
|
||||
// after filter steps to make sure we use the updated detailData
|
||||
TopicEditorBase::TopicData data(
|
||||
content.id(), ta.topicType, content.startTime(), content.duration(), QString::fromStdString(content.description()),
|
||||
QString::fromStdString(content.channel()), detailData
|
||||
);
|
||||
QJsonArray unused;
|
||||
bool keepOriginalTopic = false;
|
||||
m_vecExportSteps += checkAdditionalExportEntries(content.id(), data, unused, topicExportIfc, allSitReplayTimes, keepOriginalTopic);
|
||||
if (keepOriginalTopic)
|
||||
m_vecExportSteps += createExportStep(content.id(), data, topicExportIfc, allSitReplayTimes);
|
||||
}
|
||||
|
||||
connect(m_pProgressDlg, &QProgressDialog::canceled, this, &ExportProcess::slotCancel);
|
||||
m_cntTopicsToExport = m_vecExportSteps.size();
|
||||
m_pProgressDlg->setMaximum(m_cntTopicsToExport);
|
||||
slotRunExportStep();
|
||||
}
|
||||
|
||||
QVector<ExportStep *> ExportProcess::parseFilterSteps(
|
||||
int parentTopicId, QJsonObject &detailData, const QVector<TopicReplay::Interface::SituationReplayTime> &allSitReplayTimes
|
||||
)
|
||||
{
|
||||
QVector<ExportStep *> ret;
|
||||
const QJsonArray filters = detailData.value(QStringLiteral("Filters")).toArray();
|
||||
QJsonArray newFilterLines;
|
||||
for (const QJsonValue &filterLineValue : qAsConst(filters))
|
||||
{
|
||||
TopicEditorBase::TopicData data;
|
||||
auto temp = filterLineValue.toObject();
|
||||
data.fromJson(temp);
|
||||
|
||||
if (data.topicType != TopicEditorBase::TopicType::TacticalPlan &&
|
||||
data.topicType != TopicEditorBase::TopicType::SituationMapFilter &&
|
||||
data.topicType != TopicEditorBase::TopicType::Pdf &&
|
||||
data.topicType != TopicEditorBase::TopicType::Image &&
|
||||
data.topicType != TopicEditorBase::TopicType::Text)
|
||||
continue;
|
||||
|
||||
auto topicExportIfc = topicIfcFromType(data.topicType, ExportOrReplay::Export);
|
||||
if (!topicExportIfc)
|
||||
continue;
|
||||
auto topicReplayIfc = topicIfcFromType(data.topicType, ExportOrReplay::Replay);
|
||||
if (!topicReplayIfc)
|
||||
{
|
||||
delete topicExportIfc;
|
||||
continue;
|
||||
}
|
||||
|
||||
bool keepOriginalTopic = true;
|
||||
ret += checkAdditionalExportEntries(parentTopicId, data, newFilterLines, topicReplayIfc, allSitReplayTimes, keepOriginalTopic);
|
||||
if (keepOriginalTopic)
|
||||
ret += createExportStep(parentTopicId, data, topicExportIfc, allSitReplayTimes);
|
||||
|
||||
// delete topicExportIfc; // ownership is transfered to TakeHomePackageGenerator::ExportStep within createExportStep
|
||||
delete topicReplayIfc;
|
||||
newFilterLines += temp;
|
||||
}
|
||||
detailData[QStringLiteral("Filters")] = newFilterLines;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
QVector<ExportStep *> ExportProcess::checkAdditionalExportEntries(
|
||||
int realParentId, const TopicEditorBase::TopicData &parentData, QJsonArray &filterLines,
|
||||
TopicReplay::Interface *parentTopicReplayIfc, const QVector<TopicReplay::Interface::SituationReplayTime> &allSitReplayTimes,
|
||||
bool &keepOriginalTopic
|
||||
)
|
||||
{
|
||||
QVector<TakeHomePackageGenerator::ExportStep *> ret;
|
||||
// add possible additional export entries
|
||||
const auto addTrackEntries = parentTopicReplayIfc->additionalTrackEntries(parentData.properties, keepOriginalTopic);
|
||||
for (const TopicEditorBase::TopicData &data : addTrackEntries)
|
||||
{
|
||||
TopicEditorBase::TopicData addData(data);
|
||||
addData.description = parentData.description;
|
||||
addData.startTime = parentData.startTime;
|
||||
addData.duration = parentData.duration;
|
||||
addData.id = parentData.id;
|
||||
|
||||
auto topicExportIfc = topicIfcFromType(addData.topicType, ExportOrReplay::Export);
|
||||
DEBUG_LOG(m_logger) << "addEntry type: " << addData.topicType << ", ifc: " << topicExportIfc;
|
||||
if (!topicExportIfc)
|
||||
continue;
|
||||
|
||||
filterLines += addData.toJson();
|
||||
ret += createExportStep(realParentId, addData, topicExportIfc, allSitReplayTimes);
|
||||
m_cntTopicsToExport++;
|
||||
}
|
||||
DEBUG_LOG(m_logger) << "topic count: " << m_cntTopicsToExport;
|
||||
return ret;
|
||||
}
|
||||
|
||||
ExportStep *ExportProcess::createExportStep(
|
||||
int parentTopicId, const TopicEditorBase::TopicData &data, TopicReplay::Interface *topicExportIfc,
|
||||
const QVector<TopicReplay::Interface::SituationReplayTime> &allSitReplayTimes
|
||||
)
|
||||
{
|
||||
TakeHomePackageGenerator::ExportStep *pExportStep = new TakeHomePackageGenerator::ExportStep(this, data, topicExportIfc);
|
||||
|
||||
pExportStep->setSituationReplayTimes(extractUsedSitReplayTimes(data, allSitReplayTimes));
|
||||
pExportStep->setParentTopicId(parentTopicId);
|
||||
pExportStep->setBasePath(exportPath(m_pSession->exerciseId()));
|
||||
|
||||
connect(pExportStep, &TakeHomePackageGenerator::ExportStep::signalExportSuccessful,
|
||||
this, &ExportProcess::slotRunExportStep, Qt::QueuedConnection);
|
||||
|
||||
connect(pExportStep, &TakeHomePackageGenerator::ExportStep::signalExportFailed,
|
||||
this, &ExportProcess::slotRunExportStep, Qt::QueuedConnection);
|
||||
|
||||
DEBUG_LOG(m_logger) << "Adding filter step " << data.topicType;
|
||||
return pExportStep;
|
||||
}
|
||||
|
||||
TopicReplay::Interface *ExportProcess::topicIfcFromType(TopicEditorBase::TopicType type, ExportOrReplay exportOrReplay) const
|
||||
{
|
||||
auto it = m_trackEntryAssignments.constFind(TopicEditorBase::topicTypeString(type));
|
||||
if (it == m_trackEntryAssignments.constEnd())
|
||||
{
|
||||
WARNING_LOG(m_logger) << "Invalid content for presentation type " << type;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const PresentationManagement::TopicAssignment &ta = *it;
|
||||
TopicReplay::Interface *topicIfc = exportOrReplay == ExportOrReplay::Export ? ta.topicExportFactory->createInterface(ta.topicType)
|
||||
: ta.topicReplayFactory->createInterface(ta.topicType);
|
||||
if (!topicIfc)
|
||||
WARNING_LOG(m_logger) << "Could not find replay interface for " << type;
|
||||
return topicIfc;
|
||||
}
|
||||
|
||||
void ExportProcess::slotCancel()
|
||||
{
|
||||
m_pProgressDlg->setLabelText(tr("Export cancelled, waiting for current\ntopic export to finish..."));
|
||||
m_pProgressDlg->setCancelButton(nullptr);
|
||||
m_pProgressDlg->setMaximum(0);
|
||||
m_pProgressDlg->show();
|
||||
}
|
||||
|
||||
|
||||
void ExportProcess::slotRunExportStep()
|
||||
{
|
||||
if (m_logger.isDebugEnabled())
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "ExportProcess::slotRunExportStep() CALLED, m_vecExportSteps.size(): " << m_vecExportSteps.size()
|
||||
<< ", m_vecExportStepsExecuted.size(): " << m_vecExportStepsExecuted.size();
|
||||
|
||||
for (const auto &s : qAsConst(m_vecExportSteps))
|
||||
DEBUG_LOG(m_logger) << "m_vecExportSteps: " << s << " compare: " << (s == sender());
|
||||
for (const auto &s : qAsConst(m_vecExportStepsExecuted))
|
||||
DEBUG_LOG(m_logger) << "m_vecExportStepsExecuted: " << s << " compare: " << (s == sender());
|
||||
}
|
||||
|
||||
if (m_pProgressDlg->wasCanceled())
|
||||
{
|
||||
m_pProgressDlg->hide();
|
||||
m_pProgressDlg->deleteLater();
|
||||
return;
|
||||
}
|
||||
|
||||
m_pProgressDlg->setValue(m_vecExportStepsExecuted.size());
|
||||
|
||||
if (m_vecExportSteps.size())
|
||||
{
|
||||
TakeHomePackageGenerator::ExportStep *pExportStep = m_vecExportSteps.takeFirst();
|
||||
m_vecExportStepsExecuted.push_back(pExportStep);
|
||||
|
||||
QString strExportLabel(tr("Exporting topic of type \"%1\" (Topic %2 / %3)")
|
||||
.arg(TopicEditorBase::topicTypeString(pExportStep->m_topicData.topicType))
|
||||
.arg(m_vecExportStepsExecuted.size())
|
||||
.arg(m_cntTopicsToExport));
|
||||
DEBUG_LOG(m_logger) << strExportLabel;
|
||||
m_pProgressDlg->setLabelText(strExportLabel);
|
||||
|
||||
QString strExportPath(contentPath() + QString::number(pExportStep->topicId()) + QLatin1Char('/'));
|
||||
QDir dir(strExportPath);
|
||||
dir.mkdir(strExportPath);
|
||||
pExportStep->startExport(strExportPath);
|
||||
}
|
||||
else
|
||||
exportDone();
|
||||
}
|
||||
|
||||
|
||||
void ExportProcess::exportDone()
|
||||
{
|
||||
createJsonFiles();
|
||||
createPresentationTable();
|
||||
copyStaticContent();
|
||||
|
||||
QStringList sl;
|
||||
for (const auto &step : qAsConst(m_vecExportStepsExecuted))
|
||||
{
|
||||
if (step->exportFailed())
|
||||
sl << QStringLiteral("%1 (%2)").arg(step->m_topicData.description, TopicEditorBase::topicTypeTranslation(step->m_topicData.topicType));
|
||||
}
|
||||
|
||||
|
||||
emit exportSuccessful(exportPath(m_pSession->exerciseId()), sl.join(QStringLiteral(",<br />")));
|
||||
|
||||
m_pProgressDlg->deleteLater();
|
||||
deleteLater();
|
||||
}
|
||||
|
||||
static inline QJsonArray descVecToArray(const std::vector<AssetManagement::MapDescription> &descriptions,
|
||||
const QString &layerBaseName)
|
||||
{
|
||||
QJsonArray arr;
|
||||
QJsonObject obj;
|
||||
for (size_t i = 0; i < descriptions.size(); ++i)
|
||||
{
|
||||
// must be in sync with SituationMap::BaseUrl
|
||||
const AssetManagement::MapDescription &desc = descriptions.at(i);
|
||||
const bool isElevation = desc.mapDescriptionTypeId() == AssetManagement::MapDescriptionType::Elevation;
|
||||
obj[QStringLiteral("name")] = QString::fromStdString(desc.name());
|
||||
obj[QStringLiteral("description")] = QString::fromStdString(desc.description());
|
||||
obj[QStringLiteral("url")] = QString(layerBaseName + QLatin1Char('_') + QString::number(i) + (isElevation ? QStringLiteral(".tiff") : QStringLiteral(".tpk")));
|
||||
obj[QStringLiteral("minScale")] = desc.minScale();
|
||||
obj[QStringLiteral("maxScale")] = desc.maxScale();
|
||||
|
||||
arr.append(obj);
|
||||
}
|
||||
return arr;
|
||||
}
|
||||
|
||||
void ExportProcess::createJsonFiles()
|
||||
{
|
||||
std::shared_ptr<ExerciseManagement::Interface::Dtc> exmDtc = nullptr;
|
||||
std::shared_ptr<AssetManagement::Interface::Dtc> asmDtc = nullptr;
|
||||
if (!m_pSession->getDtc<AssetManagement::DataInterface>(asmDtc) ||
|
||||
!m_pSession->getDtc<ExerciseManagement::DataInterface>(exmDtc))
|
||||
return;
|
||||
createLayerMappings(exmDtc, asmDtc);
|
||||
createDataJson(exmDtc, asmDtc);
|
||||
}
|
||||
|
||||
void ExportProcess::createLayerMappings(const std::shared_ptr<ExerciseManagement::Interface::Dtc> &exmDtc,
|
||||
const std::shared_ptr<AssetManagement::Interface::Dtc> &asmDtc) const
|
||||
{
|
||||
QFile file(exportPath(m_pSession->exerciseId()) + QStringLiteral("layerMapping.json"));
|
||||
if (!file.open(QIODevice::WriteOnly))
|
||||
return;
|
||||
|
||||
const ExerciseManagement::Exercise exercise = exmDtc->exercise(m_pSession->exerciseId());
|
||||
const AssetManagement::TrainingArea ta = asmDtc->trainingArea(exercise.trainingAreaId());
|
||||
|
||||
// must be in sync with MapSettingsJson::fromJsonObject
|
||||
QJsonObject obj;
|
||||
obj[QStringLiteral("mapUrls")] = descVecToArray(ta.map2D(), QStringLiteral("map2D"));
|
||||
obj[QStringLiteral("sceneUrls")] = descVecToArray(ta.scene3D(), QStringLiteral("scene3D"));
|
||||
obj[QStringLiteral("elevationUrls")] = descVecToArray(ta.elevation(), QStringLiteral("elevation"));
|
||||
obj[QStringLiteral("sceneObjectUrls")] = descVecToArray(ta.sceneObjects(), QStringLiteral("sceneObjects"));
|
||||
|
||||
file.write(QJsonDocument(obj).toJson(QJsonDocument::Indented));
|
||||
file.close();
|
||||
}
|
||||
|
||||
|
||||
void ExportProcess::createDataJson(const std::shared_ptr<ExerciseManagement::Interface::Dtc> &exmDtc,
|
||||
const std::shared_ptr<AssetManagement::Interface::Dtc> &asmDtc) const
|
||||
{
|
||||
// Add exercise to ExportRootPath
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "Add exercise to ExportRootPath";
|
||||
QFile file(exportRootPath() + QStringLiteral("exercises.json"));
|
||||
if (!file.open(QFile::ReadWrite))
|
||||
{
|
||||
WARNING_LOG(m_logger) << "Can not open " << file.fileName() << " for read/write: " << file.errorString();
|
||||
return;
|
||||
}
|
||||
QJsonDocument doc(QJsonDocument::fromJson(file.readAll()));
|
||||
QJsonObject obj = doc.object();
|
||||
QJsonArray arr = obj[QStringLiteral("Exercises")].toArray();
|
||||
if (!arr.contains(m_pSession->exerciseId()) )
|
||||
arr.append(m_pSession->exerciseId());
|
||||
obj[QStringLiteral("Exercises")] = arr;
|
||||
file.resize(0);
|
||||
file.write(QJsonDocument(obj).toJson(QJsonDocument::Indented));
|
||||
INFO_LOG(m_logger) << " file.write " << QJsonDocument(obj).toJson(QJsonDocument::Indented);
|
||||
file.close();
|
||||
}
|
||||
//
|
||||
QFile file(exportPath(m_pSession->exerciseId()) + QStringLiteral("data.json"));
|
||||
INFO_LOG(m_logger) << "ExportProcess::createDataJson " << exportPath(m_pSession->exerciseId()) + QStringLiteral("data.json");
|
||||
if (!file.open(QFile::ReadWrite))
|
||||
return;
|
||||
|
||||
QJsonDocument doc(QJsonDocument::fromJson(file.readAll()));
|
||||
QJsonObject obj = doc.object();
|
||||
|
||||
const ExerciseManagement::Exercise exercise = exmDtc->exercise(m_pSession->exerciseId());
|
||||
const AssetManagement::TrainingArea ta = asmDtc->trainingArea(exercise.trainingAreaId());
|
||||
|
||||
obj[QStringLiteral("title")] = QString::fromStdString(exercise.name());
|
||||
obj[QStringLiteral("exerciseName")] = QString::fromStdString(exercise.name());
|
||||
obj[QStringLiteral("exerciseId")] = exercise.id();
|
||||
obj[QStringLiteral("exerciseArea")] = QString::fromStdString(ta.name());
|
||||
obj[QStringLiteral("cycleTime")] = QString(QDateTime::fromMSecsSinceEpoch(exercise.startTime()).toString() +
|
||||
QStringLiteral(" - ") + QDateTime::fromMSecsSinceEpoch(exercise.stopTime()).toString());
|
||||
obj[QStringLiteral("exerciseStart")] = exercise.startTime();
|
||||
obj[QStringLiteral("exerciseEnd")] = exercise.stopTime();
|
||||
obj[QStringLiteral("exercisingForces")] = QString::fromStdString(exercise.forces());
|
||||
obj[QStringLiteral("exercisingPurpose")] = QString::fromStdString(exercise.description());
|
||||
|
||||
// TODO: administrativeInstructions, exerciseIncidents
|
||||
|
||||
QJsonArray presentations = obj[QStringLiteral("presentations")].toArray();
|
||||
const QString presPath = QString(QString::number(m_scriptId) + QStringLiteral("/presentation.json"));
|
||||
bool bPresFound = false;
|
||||
for (const QJsonValue &val : qAsConst(presentations))
|
||||
{
|
||||
const QJsonObject arrObj = val.toObject();
|
||||
if (arrObj[QStringLiteral("path")].toString() == presPath)
|
||||
{
|
||||
bPresFound = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!bPresFound)
|
||||
{
|
||||
ExportedScriptInformation esi;
|
||||
esi.scriptId = m_scriptId;
|
||||
esi.scriptName = m_strScriptName;
|
||||
esi.exerciseName = m_strExerciseName;
|
||||
esi.jsonPath = presPath;
|
||||
esi.exportTime = QDateTime::currentDateTimeUtc().toMSecsSinceEpoch();
|
||||
|
||||
presentations += esi.toJson();
|
||||
obj[QStringLiteral("presentations")] = presentations;
|
||||
}
|
||||
file.resize(0);
|
||||
file.write(QJsonDocument(obj).toJson(QJsonDocument::Indented));
|
||||
INFO_LOG(m_logger) << " file.write " << QJsonDocument(obj).toJson(QJsonDocument::Indented);
|
||||
file.close();
|
||||
}
|
||||
|
||||
void ExportProcess::createPresentationTable()
|
||||
{
|
||||
// Order chronologically
|
||||
std::sort(m_vecExportStepsExecuted.begin(), m_vecExportStepsExecuted.end(),
|
||||
[](const TakeHomePackageGenerator::ExportStep * a, const TakeHomePackageGenerator::ExportStep * b) -> bool
|
||||
{
|
||||
return a->m_topicData.startTime < b->m_topicData.startTime;
|
||||
});
|
||||
QString presentationTableDirName = contentPath();
|
||||
presentationTableDirName.truncate(presentationTableDirName.size() - 1);
|
||||
QDir presentationDir(presentationTableDirName);
|
||||
if (!presentationDir.exists())
|
||||
{
|
||||
bool succ = presentationDir.mkdir(presentationTableDirName);
|
||||
if (!succ)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
QFile file(contentPath() + QStringLiteral("presentation.json"));
|
||||
if (!file.open(QFile::WriteOnly | QFile::Truncate))
|
||||
return;
|
||||
|
||||
QJsonObject obj;
|
||||
obj[QStringLiteral("title")] = m_strScriptName;
|
||||
obj[QStringLiteral("exerciseName")] = m_strExerciseName;
|
||||
|
||||
QJsonArray topicArray;
|
||||
int topicId = 1;
|
||||
for (const TakeHomePackageGenerator::ExportStep *s : qAsConst(m_vecExportStepsExecuted))
|
||||
{
|
||||
if (s->exportFailed())
|
||||
{
|
||||
WARNING_LOG(m_logger) << "Export failed for " << s->topicId();
|
||||
continue;
|
||||
}
|
||||
|
||||
if (s->m_topicData.topicType == TopicEditorBase::TopicType::SituationReplay ||
|
||||
s->m_topicData.topicType == TopicEditorBase::TopicType::TacticalPlan ||
|
||||
s->m_topicData.topicType == TopicEditorBase::TopicType::Situation ||
|
||||
s->filename().isEmpty())
|
||||
{
|
||||
/* these topics exported their data into an existing topic - e.g.:
|
||||
* Replay is put into a SituationMap topic, because a Replay topic
|
||||
* alone doesn't make sense in the THP, as to play a topic, all topic
|
||||
* information (Map, Replay, Filters, etc.) need to be inside ONE topic */
|
||||
continue;
|
||||
}
|
||||
|
||||
QJsonObject topicObj;
|
||||
topicObj[QStringLiteral("topicId")] = topicId++;
|
||||
topicObj[QStringLiteral("topicStart")] = QTime::fromMSecsSinceStartOfDay(s->m_topicData.startTime * 1000).toString();
|
||||
topicObj[QStringLiteral("duration")] = QTime::fromMSecsSinceStartOfDay(s->m_topicData.duration * 1000).toString();
|
||||
topicObj[QStringLiteral("type")] = TopicEditorBase::topicTypeString(s->m_topicData.topicType);
|
||||
|
||||
#ifndef EXPORT_BDV_TOPIC_AS_JSON
|
||||
if (s->m_topicData.topicType == TopicEditorBase::TopicType::Building)
|
||||
{
|
||||
QDir dir(s->filename());
|
||||
const auto listVideos = dir.entryList({QStringLiteral("*.mpg")}, QDir::Files, QDir::Name);
|
||||
for (const QString &strVideo : listVideos)
|
||||
{
|
||||
const QString relPath = QString::number(m_scriptId) + QLatin1Char('/') + dir.dirName() + QLatin1Char('/') + strVideo;
|
||||
topicObj[QStringLiteral("description")] = QJsonObject({{QStringLiteral("displayName"), strVideo},
|
||||
{QStringLiteral("href"), relPath}});
|
||||
topicArray += topicObj;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
|
||||
QString dispName(s->m_topicData.description.isEmpty() ?
|
||||
TopicEditorBase::topicTypeString(s->m_topicData.topicType) :
|
||||
s->m_topicData.description);
|
||||
|
||||
if (s->m_topicData.topicType == TopicEditorBase::TopicType::Audio || s->m_topicData.topicType == TopicEditorBase::TopicType::Video)
|
||||
dispName = s->filename().splitRef(QLatin1Char('/')).last().toString();
|
||||
|
||||
if (!s->filename().isEmpty())
|
||||
{
|
||||
const QString stRelativeLinkToExportedFile(QString::number(m_scriptId) + QLatin1Char('/') +
|
||||
QString::number(s->topicId()) + QLatin1Char('/') +
|
||||
s->filename());
|
||||
|
||||
const QString stRelativeLinkToLocalExportedFile(QString::number(s->topicId()) + QLatin1Char('/') + s->filename());
|
||||
topicObj[QStringLiteral("description")] = QJsonObject({{QStringLiteral("displayName"), dispName},
|
||||
{QStringLiteral("href"), stRelativeLinkToExportedFile},
|
||||
{QStringLiteral("href_local"), stRelativeLinkToLocalExportedFile}
|
||||
});
|
||||
// topicObj[QStringLiteral("href")] = stRelativeLinkToExportedFile;
|
||||
// topicObj[QStringLiteral("href_local")] = stRelativeLinkToLocalExportedFile;
|
||||
}else
|
||||
{
|
||||
topicObj[QStringLiteral("description")] = QJsonObject({{ QStringLiteral("displayName"), dispName }});
|
||||
}
|
||||
|
||||
|
||||
topicArray += topicObj;
|
||||
}
|
||||
|
||||
obj[QStringLiteral("content")] = topicArray;
|
||||
file.write(QJsonDocument(obj).toJson(QJsonDocument::Indented));
|
||||
file.close();
|
||||
}
|
||||
|
||||
void ExportProcess::copyStaticContent() const
|
||||
{
|
||||
QString exportPathStr = exportPath(m_pSession->exerciseId());
|
||||
exportPathStr.truncate(exportPathStr.size() - 1);
|
||||
if (!NGL::copyDirContentsToDir(QStringLiteral("thp"), exportPathStr, true))
|
||||
WARNING_LOG(m_logger) << "Could not find thp static content directory exportPath=" << exportPathStr;
|
||||
if (!NGL::copyDirContentsToDir(QStringLiteral("thp_standalone"), exportPathStr + QDir::separator() + QString::number(m_scriptId), true))
|
||||
WARNING_LOG(m_logger) << "Could not find thp_standalone static content directory exportPath=" << exportPathStr + QDir::separator() + QString::number(m_scriptId);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
Executable
+125
@@ -0,0 +1,125 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Philipp Last, NLSE, 2018-07-09
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QObject>
|
||||
#include <QJsonArray>
|
||||
|
||||
#include <Plugins/PresentationManagement/Gui/Script/Common/preguiscriptcommon_export.h>
|
||||
#include <Plugins/PresentationManagement/Gui/Common/topic_assignment.h>
|
||||
#include <Plugins/SituationReplay/srp_gui_plugin_interface.h>
|
||||
#include <PresentationManagement/pre_dtc.h>
|
||||
#include <PresentationManagement/logger.h>
|
||||
#include <AssetManagement/asm_dtc.h>
|
||||
#include <ExerciseManagement/exm_dtc.h>
|
||||
|
||||
#include <LtsSession/lts_session.h>
|
||||
#include <LtsScriptTimeline/track_content_widget.h>
|
||||
|
||||
|
||||
class QProgressDialog;
|
||||
|
||||
|
||||
namespace TakeHomePackageGenerator
|
||||
{
|
||||
|
||||
class ExportStep;
|
||||
|
||||
struct ExportedScriptInformation
|
||||
{
|
||||
QString scriptName;
|
||||
QString exerciseName;
|
||||
QString jsonPath;
|
||||
qint64 exportTime = 0;
|
||||
int scriptId = 0;
|
||||
|
||||
int id() const { return scriptId; }
|
||||
|
||||
QJsonValue toJson() const;
|
||||
};
|
||||
|
||||
|
||||
class PREGUISCRIPTCOMMON_EXPORT ExportProcess : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
ExportProcess(LtsSession::LtsSession *pSession,
|
||||
const std::shared_ptr<SituationReplay::ForeignGuiInterface> &replayGuiIfc,
|
||||
QProgressDialog *pProgressDlg,
|
||||
const QString &strScriptName,
|
||||
const QString &strExerciseName,
|
||||
int scriptId,
|
||||
const std::vector<PresentationManagement::PresentationContent> &contentList,
|
||||
const QMap<QString, PresentationManagement::TopicAssignment> &trackEntryAssignments,
|
||||
QObject *parent);
|
||||
~ExportProcess();
|
||||
|
||||
static QString exportPath(const int exerciseId);
|
||||
static QString exportRootPath();
|
||||
|
||||
signals:
|
||||
void exportSuccessful(const QString &m_strExportPath, const QString &failedTopicsDescription);
|
||||
|
||||
public slots:
|
||||
void slotStartExport();
|
||||
|
||||
private slots:
|
||||
void slotCancel();
|
||||
void slotRunExportStep();
|
||||
|
||||
private:
|
||||
QVector<ExportStep *> parseFilterSteps(
|
||||
int parentTopicId, QJsonObject &detailData, const QVector<TopicReplay::Interface::SituationReplayTime> &allSitReplayTimes
|
||||
);
|
||||
QVector<ExportStep *> checkAdditionalExportEntries(
|
||||
int realParentId, const TopicEditorBase::TopicData &parentData, QJsonArray &filterLines,
|
||||
TopicReplay::Interface *parentTopicReplayIfc, const QVector<TopicReplay::Interface::SituationReplayTime> &allSitReplayTimes,
|
||||
bool &keepOriginalTopic
|
||||
);
|
||||
ExportStep *createExportStep(
|
||||
int parentTopicId, const TopicEditorBase::TopicData &data, TopicReplay::Interface *topicExportIfc,
|
||||
const QVector<TopicReplay::Interface::SituationReplayTime> &allSitReplayTimes
|
||||
);
|
||||
|
||||
enum class ExportOrReplay
|
||||
{
|
||||
Export,
|
||||
Replay
|
||||
};
|
||||
|
||||
TopicReplay::Interface *topicIfcFromType(TopicEditorBase::TopicType type, ExportOrReplay exportOrReplay) const;
|
||||
QString contentPath() const { return exportPath(m_pSession->exerciseId()) + QString::number(m_scriptId) + QLatin1Char('/'); }
|
||||
void exportDone();
|
||||
void createJsonFiles();
|
||||
void createLayerMappings(const std::shared_ptr<ExerciseManagement::Interface::Dtc> &exmDtc,
|
||||
const std::shared_ptr<AssetManagement::Interface::Dtc> &asmDtc) const;
|
||||
void createDataJson(const std::shared_ptr<ExerciseManagement::Interface::Dtc> &exmDtc,
|
||||
const std::shared_ptr<AssetManagement::Interface::Dtc> &asmDtc) const;
|
||||
void createPresentationTable();
|
||||
void copyStaticContent() const;
|
||||
|
||||
private:
|
||||
QVector<ExportStep *> m_vecExportSteps;
|
||||
QVector<ExportStep *> m_vecExportStepsExecuted;
|
||||
|
||||
std::vector<PresentationManagement::PresentationContent> m_contentList;
|
||||
QMap<QString, PresentationManagement::TopicAssignment> m_trackEntryAssignments;
|
||||
QString m_strScriptName;
|
||||
QString m_strExerciseName;
|
||||
int m_scriptId;
|
||||
|
||||
LtsSession::LtsSession *m_pSession;
|
||||
std::shared_ptr<SituationReplay::ForeignGuiInterface> m_replayGuiIfc;
|
||||
QProgressDialog *m_pProgressDlg;
|
||||
int m_cntTopicsToExport;
|
||||
|
||||
NGL::INGLLogger &m_logger;
|
||||
};
|
||||
}
|
||||
Executable
+70
@@ -0,0 +1,70 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Philipp Last, NLSE, 2018-07-09
|
||||
*/
|
||||
|
||||
#include "export_step.h"
|
||||
|
||||
namespace TakeHomePackageGenerator
|
||||
{
|
||||
ExportStep::ExportStep(QObject *parent, const TopicEditorBase::TopicData &data, TopicReplay::Interface *topicReplayIfc)
|
||||
: QObject(parent)
|
||||
, m_topicData(data)
|
||||
, m_notifier(this)
|
||||
, m_topicReplayIfc(topicReplayIfc)
|
||||
, m_timer(new QTimer(this))
|
||||
, m_parentTopicId(-1)
|
||||
, m_exportFailed(false)
|
||||
{
|
||||
m_timer->setSingleShot(true);
|
||||
m_timer->setInterval(30 * 1000); // 30s timeout
|
||||
connect(m_timer, &QTimer::timeout, this, &ExportStep::slotExportFailed);
|
||||
|
||||
connect(&m_notifier, &TopicEditorBase::ExportNotifier::stillAlive, this, &ExportStep::slotResetTimer);
|
||||
connect(&m_notifier, &TopicEditorBase::ExportNotifier::exportSuccessful, this, &ExportStep::slotExportSuccessful);
|
||||
connect(&m_notifier, &TopicEditorBase::ExportNotifier::exportFailed, this, &ExportStep::slotExportFailed);
|
||||
}
|
||||
|
||||
|
||||
ExportStep::~ExportStep()
|
||||
{
|
||||
m_timer->stop();
|
||||
delete m_topicReplayIfc;
|
||||
}
|
||||
|
||||
|
||||
void ExportStep::startExport(const QString &strExportPath)
|
||||
{
|
||||
m_timer->start();
|
||||
m_topicReplayIfc->setExportPlaybackTimes(m_topicData.startTime, m_topicData.duration, m_sitReplayTimes);
|
||||
m_topicReplayIfc->setBasePath(m_basePath);
|
||||
m_topicReplayIfc->exportTopic(m_topicData.properties, strExportPath, &m_notifier);
|
||||
}
|
||||
|
||||
|
||||
void ExportStep::slotResetTimer()
|
||||
{
|
||||
m_timer->start();
|
||||
}
|
||||
|
||||
|
||||
void ExportStep::slotExportFailed()
|
||||
{
|
||||
m_timer->stop();
|
||||
m_exportFailed = true;
|
||||
m_notifier.disconnect(); // Export failed e.g. due to timeout. We do not want to get a "success signal" seconds later. Timeout is timeout, fail is fail, later success does not matter
|
||||
emit signalExportFailed();
|
||||
}
|
||||
|
||||
|
||||
void ExportStep::slotExportSuccessful(const QString &strFilename)
|
||||
{
|
||||
m_timer->stop();
|
||||
m_strFileName = strFilename;
|
||||
m_notifier.disconnect();
|
||||
emit signalExportSuccessful();
|
||||
}
|
||||
}
|
||||
Executable
+60
@@ -0,0 +1,60 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Philipp Last, NLSE, 2018-07-09
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <Plugins/PresentationManagement/Gui/Script/Common/preguiscriptcommon_export.h>
|
||||
#include <QObject>
|
||||
#include <QTimer>
|
||||
|
||||
#include <LtsScriptTimeline/track_entry.h>
|
||||
#include <PluginInterfaces/topic_replay_interface.h>
|
||||
#include <Common/TopicEditorBase/topic_editor_base.h>
|
||||
|
||||
namespace TakeHomePackageGenerator
|
||||
{
|
||||
class PREGUISCRIPTCOMMON_EXPORT ExportStep : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
ExportStep(QObject *parent, const TopicEditorBase::TopicData &data, TopicReplay::Interface *topicReplayIfc);
|
||||
~ExportStep();
|
||||
|
||||
void startExport(const QString &strExportPath);
|
||||
void setSituationReplayTimes(const QVector<TopicReplay::Interface::SituationReplayTime> ×) { m_sitReplayTimes = times; }
|
||||
void setParentTopicId(int parentId) { m_parentTopicId = parentId; }
|
||||
void setBasePath(const QString &basePath) { m_basePath = basePath; }
|
||||
int topicId() const { return m_parentTopicId < 0 ? m_topicData.id : m_parentTopicId; }
|
||||
bool exportFailed() const { return m_exportFailed; }
|
||||
QString filename() const { return m_strFileName; }
|
||||
|
||||
// wtf?
|
||||
TopicEditorBase::TopicData m_topicData;
|
||||
|
||||
signals:
|
||||
void signalExportSuccessful();
|
||||
void signalExportFailed();
|
||||
|
||||
private slots:
|
||||
void slotResetTimer();
|
||||
void slotExportSuccessful(const QString &strFilename);
|
||||
void slotExportFailed();
|
||||
|
||||
private:
|
||||
QVector<TopicReplay::Interface::SituationReplayTime> m_sitReplayTimes;
|
||||
QString m_strFileName;
|
||||
QString m_basePath;
|
||||
TopicEditorBase::ExportNotifier m_notifier;
|
||||
TopicReplay::Interface *m_topicReplayIfc;
|
||||
|
||||
QTimer *m_timer;
|
||||
int m_parentTopicId;
|
||||
bool m_exportFailed;
|
||||
};
|
||||
}
|
||||
Lts/Plugins/PresentationManagement/Gui/Script/Common/TakeHomePackageGenerator/situation_exporter.cpp
Executable
+234
@@ -0,0 +1,234 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* Export data from postgresql database to sqlite
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Christian Ehrlicher, NLSE, 2018-03-14
|
||||
*/
|
||||
|
||||
|
||||
#include "situation_exporter.h"
|
||||
#include "db_reader.h"
|
||||
#include <nglsettings/nglsettings_settings.h>
|
||||
#include <ngldb/dbconnection.h>
|
||||
#include <ngldb/dbtransaction.h>
|
||||
#include <ngldb/nsqlquery.h>
|
||||
|
||||
#include <QFile>
|
||||
#include <QSqlRecord>
|
||||
#include <QSqlError>
|
||||
#include <QSqlField>
|
||||
#include <QSqlIndex>
|
||||
#include <QSqlDatabase>
|
||||
#include <QVariant>
|
||||
|
||||
|
||||
namespace TakeHomePackageGenerator
|
||||
{
|
||||
SituationExporter::SituationExporter(int exerciseId)
|
||||
: m_exerciseId(exerciseId)
|
||||
, m_logger(PresentationManagement::getLogger("SituationExporter"))
|
||||
{}
|
||||
|
||||
SituationExporter::~SituationExporter()
|
||||
{
|
||||
const QString dbConInName = m_dbIn.connectionName();
|
||||
const QString dbConOutName = m_dbOut.connectionName();
|
||||
m_dbIn.close();
|
||||
m_dbOut.close();
|
||||
m_dbIn = QSqlDatabase();
|
||||
m_dbOut = QSqlDatabase();
|
||||
if (!dbConInName.isEmpty())
|
||||
QSqlDatabase::removeDatabase(dbConInName);
|
||||
if (!dbConOutName.isEmpty())
|
||||
QSqlDatabase::removeDatabase(dbConOutName);
|
||||
}
|
||||
|
||||
bool SituationExporter::exportStaticData(const QString &strPathToFile)
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "Exporting static data to " << strPathToFile;
|
||||
m_dbIn.close();
|
||||
m_dbOut.close();
|
||||
|
||||
QString str;
|
||||
NGL::Settings s(str); // FIXME
|
||||
// open postgres db, read table structure, read static data
|
||||
const QString dbUser(QStringLiteral("postgres"));
|
||||
const QString dbPasswd(QStringLiteral("postgres"));
|
||||
m_dbIn = DBConnection::open(m_logger,
|
||||
dbUser,
|
||||
dbPasswd,
|
||||
s.databaseDriver(),
|
||||
s.databaseHostname(),
|
||||
s.databaseName());
|
||||
if (!m_dbIn.isOpen())
|
||||
return false;
|
||||
|
||||
// open sqlite db, create tables, write static data
|
||||
QFile::remove(strPathToFile);
|
||||
m_dbOut = DBConnection::open(m_logger,
|
||||
QString(),
|
||||
QString(),
|
||||
QStringLiteral("QSQLITE"),
|
||||
QString(),
|
||||
strPathToFile);
|
||||
if (!m_dbOut.isOpen())
|
||||
return false;
|
||||
|
||||
DBTransaction transOut(m_dbOut);
|
||||
|
||||
//const int fileTypeId = FileManagement::FileType::TacticalPlan;
|
||||
constexpr int fileTypeTacticalPlan = 6;
|
||||
constexpr int fileTypeOperatorDefinedSymbol = 8;
|
||||
const QVector<StaticTableToCopy> staticTables =
|
||||
{{QStringLiteral("asm"), QStringLiteral("asm_training_area"), QString()},
|
||||
|
||||
{QStringLiteral("exm"), QStringLiteral("exercise"), QStringLiteral("id = %1").arg(m_exerciseId)},
|
||||
{QStringLiteral("exm"), QStringLiteral("exercise_phase"), QStringLiteral("exercise_id = %1").arg(m_exerciseId)},
|
||||
|
||||
{QStringLiteral("flm"), QStringLiteral("flm_file_content"), QStringLiteral("(file_type_id = %1 OR file_type_id = %2) AND file_status_id = 0").arg(fileTypeTacticalPlan).arg(fileTypeOperatorDefinedSymbol)},
|
||||
{QStringLiteral("flm"), QStringLiteral("flm_file_type_info"), QString()},
|
||||
{QStringLiteral("flm"), QStringLiteral("flm_folder"), QString()},
|
||||
|
||||
{QStringLiteral("ism"), QStringLiteral("ism_main_structure_element"), QString()},
|
||||
{QStringLiteral("ism"), QStringLiteral("ism_structure_element"), QString()},
|
||||
{QStringLiteral("ism"), QStringLiteral("ism_structure_element_type"), QString()},
|
||||
{QStringLiteral("ism"), QStringLiteral("ism_mounting_point_type"), QString()},
|
||||
{QStringLiteral("ism"), QStringLiteral("ism_structure_element_footprint"), QString()},
|
||||
|
||||
{QStringLiteral("ppm"), QStringLiteral("ppm_type"), QString()},
|
||||
|
||||
{QStringLiteral("pdm"), QStringLiteral("pdm_can_component_string"), QString()},
|
||||
{QStringLiteral("pdm"), QStringLiteral("pdm_charge_type"), QString()},
|
||||
{QStringLiteral("pdm"), QStringLiteral("pdm_fire_purpose"), QString()},
|
||||
{QStringLiteral("pdm"), QStringLiteral("pdm_gear_type"), QString()},
|
||||
{QStringLiteral("pdm"), QStringLiteral("pdm_gear_type_charge_type"), QString()},
|
||||
{QStringLiteral("pdm"), QStringLiteral("pdm_language_hmi"), QString()},
|
||||
{QStringLiteral("pdm"), QStringLiteral("pdm_translation"), QString()},
|
||||
{QStringLiteral("pdm"), QStringLiteral("pdm_vulnerability_kind"), QString()}
|
||||
};
|
||||
for (const auto &t : staticTables)
|
||||
{
|
||||
if (!copyTable(t, false))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Copying table " << t.schema << "." << t.table << " failed... ";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
const QString exerciseSchema = DBCommon::getExerciseSchemaName(m_exerciseId);
|
||||
const QVector<StaticTableToCopy> srpTables =
|
||||
{{exerciseSchema, QStringLiteral("flt_aes_filter"), QString()},
|
||||
{exerciseSchema, QStringLiteral("flt_symbol_appearance"), QString()},
|
||||
{exerciseSchema, QStringLiteral("srp_situation_replay"), QString()},
|
||||
{exerciseSchema, QStringLiteral("srp_replay_journal"), QString()},
|
||||
{exerciseSchema, QStringLiteral("rec_snapshot"), QString()}
|
||||
};
|
||||
for (const auto &t : srpTables)
|
||||
{
|
||||
if (!copyTable(t, true))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Copying table " << t.schema << "." << t.table << " failed... ";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
transOut.commit();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SituationExporter::exportDynamicData(qint64 fromTime, qint64 toTime)
|
||||
{
|
||||
DbReader dbReader(m_exerciseId);
|
||||
if (!dbReader.init(m_dbIn, m_dbOut))
|
||||
return false;
|
||||
|
||||
DBTransaction trans(m_dbOut);
|
||||
if (!dbReader.createTables() || !dbReader.copyData(fromTime, toTime)) // todo: !
|
||||
return false;
|
||||
QString stmtUpdateExercise = QStringLiteral("UPDATE exercise SET begin_time = :begin_time, end_time = :end_time");
|
||||
NSqlQuery q(m_dbOut);
|
||||
if (!q.prepare(stmtUpdateExercise))
|
||||
return false;
|
||||
q.bindValue(QStringLiteral("begin_time"), fromTime);
|
||||
q.bindValue(QStringLiteral("end_time"), toTime);
|
||||
if (!q.exec())
|
||||
return false;
|
||||
trans.commit();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SituationExporter::copyTable(const StaticTableToCopy &t, bool bOnlyCreateSchema)
|
||||
{
|
||||
NSqlQuery qIn(m_dbIn);
|
||||
NSqlQuery qOut(m_dbOut);
|
||||
|
||||
const QString fqTableName(t.schema.isEmpty() ? t.table : (t.schema + QLatin1Char('.') + t.table));
|
||||
|
||||
DEBUG_LOG(m_logger) << "Copying " << fqTableName << " started";
|
||||
const QSqlRecord record = m_dbIn.record(fqTableName);
|
||||
if (record.isEmpty())
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Empty record for " << fqTableName;
|
||||
return false;
|
||||
}
|
||||
QStringList selectTableColumns;
|
||||
QStringList insertTablePlaceholder;
|
||||
selectTableColumns.reserve(record.count());
|
||||
insertTablePlaceholder.reserve(record.count());
|
||||
for (int i = 0; i < record.count(); ++i)
|
||||
{
|
||||
const QSqlField &f = record.field(i);
|
||||
selectTableColumns += f.name();
|
||||
insertTablePlaceholder += QLatin1Char(':') + f.name();
|
||||
}
|
||||
|
||||
const QSqlIndex pk = m_dbIn.primaryIndex(fqTableName);
|
||||
if (!DbReader::createTable(qOut, t.table, record, pk, m_logger))
|
||||
return false;
|
||||
|
||||
if (bOnlyCreateSchema)
|
||||
return true;
|
||||
|
||||
// do not copy tables without schemaName
|
||||
if (t.schema.isEmpty())
|
||||
return true;
|
||||
|
||||
const QString whereStmt(t.where.isEmpty() ? QString() : QStringLiteral(" WHERE %1").arg(t.where));
|
||||
const QString selectTableCommand(QStringLiteral("SELECT %1 FROM %2%3")
|
||||
.arg(selectTableColumns.join(QStringLiteral(", ")), fqTableName, whereStmt));
|
||||
const QString insertTableCommand(QStringLiteral("INSERT INTO %1 (%2) VALUES (%3)")
|
||||
.arg(t.table,
|
||||
selectTableColumns.join(QStringLiteral(", ")),
|
||||
insertTablePlaceholder.join(QStringLiteral(", "))));
|
||||
|
||||
DEBUG_LOG(m_logger) << selectTableCommand;
|
||||
DEBUG_LOG(m_logger) << insertTableCommand;
|
||||
|
||||
if (!qOut.prepare(insertTableCommand))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "qOut prepare failed... " << qOut.lastError().text();
|
||||
return false;
|
||||
}
|
||||
if (!qIn.exec(selectTableCommand))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "qIn select failed... " << qIn.lastError().text();
|
||||
return false;
|
||||
}
|
||||
while (qIn.next())
|
||||
{
|
||||
for (int i = 0; i < insertTablePlaceholder.size(); ++i)
|
||||
qOut.bindValue(insertTablePlaceholder.at(i), qIn.value(i));
|
||||
if (!qOut.exec())
|
||||
{
|
||||
ERROR_LOG(m_logger) << "qOut insert failed.. " << qOut.lastError().text();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
DEBUG_LOG(m_logger) << "Copying " << fqTableName << " finished";
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace TakeHomePackageGenerator
|
||||
Executable
+41
@@ -0,0 +1,41 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* Export data from postgresql database to sqlite
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Christian Ehrlicher, NLSE, 2018-03-14
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <PresentationManagement/logger.h>
|
||||
#include <QString>
|
||||
#include <QSqlDatabase>
|
||||
|
||||
namespace TakeHomePackageGenerator
|
||||
{
|
||||
class SituationExporter
|
||||
{
|
||||
public:
|
||||
explicit SituationExporter(int exerciseId);
|
||||
~SituationExporter();
|
||||
|
||||
bool exportStaticData(const QString& strPathToFile);
|
||||
bool exportDynamicData(qint64 fromTime, qint64 toTime);
|
||||
|
||||
private:
|
||||
struct StaticTableToCopy
|
||||
{
|
||||
QString schema;
|
||||
QString table;
|
||||
QString where;
|
||||
};
|
||||
|
||||
bool copyTable(const StaticTableToCopy &t, bool bOnlyCreateSchema);
|
||||
private:
|
||||
int m_exerciseId;
|
||||
QSqlDatabase m_dbIn;
|
||||
QSqlDatabase m_dbOut;
|
||||
NGL::INGLLogger &m_logger;
|
||||
};
|
||||
} // namespace TakeHomePackageGenerator
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Philipp Last, NLSE, 2018-07-09
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <LtsScriptTimeline/track_entry.h>
|
||||
|
||||
class ScriptTransferIfc
|
||||
{
|
||||
public:
|
||||
virtual bool transferScript(const QVector<LtsScriptTimeline::TrackEntry *> &topicVector,
|
||||
int exerciseId) = 0;
|
||||
};
|
||||
+350
@@ -0,0 +1,350 @@
|
||||
/*
|
||||
AngularJS v1.7.7
|
||||
(c) 2010-2018 Google, Inc. http://angularjs.org
|
||||
License: MIT
|
||||
*/
|
||||
(function(C){'use strict';function re(a){if(D(a))w(a.objectMaxDepth)&&(Wb.objectMaxDepth=Xb(a.objectMaxDepth)?a.objectMaxDepth:NaN),w(a.urlErrorParamsEnabled)&&Ga(a.urlErrorParamsEnabled)&&(Wb.urlErrorParamsEnabled=a.urlErrorParamsEnabled);else return Wb}function Xb(a){return W(a)&&0<a}function F(a,b){b=b||Error;return function(){var d=arguments[0],c;c="["+(a?a+":":"")+d+"] http://errors.angularjs.org/1.7.7/"+(a?a+"/":"")+d;for(d=1;d<arguments.length;d++){c=c+(1==d?"?":"&")+"p"+(d-1)+"=";var e=encodeURIComponent,
|
||||
f;f=arguments[d];f="function"==typeof f?f.toString().replace(/ \{[\s\S]*$/,""):"undefined"==typeof f?"undefined":"string"!=typeof f?JSON.stringify(f):f;c+=e(f)}return new b(c)}}function ya(a){if(null==a||$a(a))return!1;if(H(a)||A(a)||x&&a instanceof x)return!0;var b="length"in Object(a)&&a.length;return W(b)&&(0<=b&&b-1 in a||"function"===typeof a.item)}function r(a,b,d){var c,e;if(a)if(B(a))for(c in a)"prototype"!==c&&"length"!==c&&"name"!==c&&a.hasOwnProperty(c)&&b.call(d,a[c],c,a);else if(H(a)||
|
||||
ya(a)){var f="object"!==typeof a;c=0;for(e=a.length;c<e;c++)(f||c in a)&&b.call(d,a[c],c,a)}else if(a.forEach&&a.forEach!==r)a.forEach(b,d,a);else if(Nc(a))for(c in a)b.call(d,a[c],c,a);else if("function"===typeof a.hasOwnProperty)for(c in a)a.hasOwnProperty(c)&&b.call(d,a[c],c,a);else for(c in a)ta.call(a,c)&&b.call(d,a[c],c,a);return a}function Oc(a,b,d){for(var c=Object.keys(a).sort(),e=0;e<c.length;e++)b.call(d,a[c[e]],c[e]);return c}function Yb(a){return function(b,d){a(d,b)}}function se(){return++pb}
|
||||
function Zb(a,b,d){for(var c=a.$$hashKey,e=0,f=b.length;e<f;++e){var g=b[e];if(D(g)||B(g))for(var k=Object.keys(g),h=0,l=k.length;h<l;h++){var m=k[h],p=g[m];d&&D(p)?ha(p)?a[m]=new Date(p.valueOf()):ab(p)?a[m]=new RegExp(p):p.nodeName?a[m]=p.cloneNode(!0):$b(p)?a[m]=p.clone():(D(a[m])||(a[m]=H(p)?[]:{}),Zb(a[m],[p],!0)):a[m]=p}}c?a.$$hashKey=c:delete a.$$hashKey;return a}function S(a){return Zb(a,Ha.call(arguments,1),!1)}function te(a){return Zb(a,Ha.call(arguments,1),!0)}function fa(a){return parseInt(a,
|
||||
10)}function ac(a,b){return S(Object.create(a),b)}function E(){}function Ta(a){return a}function ia(a){return function(){return a}}function bc(a){return B(a.toString)&&a.toString!==la}function z(a){return"undefined"===typeof a}function w(a){return"undefined"!==typeof a}function D(a){return null!==a&&"object"===typeof a}function Nc(a){return null!==a&&"object"===typeof a&&!Pc(a)}function A(a){return"string"===typeof a}function W(a){return"number"===typeof a}function ha(a){return"[object Date]"===la.call(a)}
|
||||
function H(a){return Array.isArray(a)||a instanceof Array}function cc(a){switch(la.call(a)){case "[object Error]":return!0;case "[object Exception]":return!0;case "[object DOMException]":return!0;default:return a instanceof Error}}function B(a){return"function"===typeof a}function ab(a){return"[object RegExp]"===la.call(a)}function $a(a){return a&&a.window===a}function bb(a){return a&&a.$evalAsync&&a.$watch}function Ga(a){return"boolean"===typeof a}function ue(a){return a&&W(a.length)&&ve.test(la.call(a))}
|
||||
function $b(a){return!(!a||!(a.nodeName||a.prop&&a.attr&&a.find))}function we(a){var b={};a=a.split(",");var d;for(d=0;d<a.length;d++)b[a[d]]=!0;return b}function ua(a){return K(a.nodeName||a[0]&&a[0].nodeName)}function cb(a,b){var d=a.indexOf(b);0<=d&&a.splice(d,1);return d}function Ia(a,b,d){function c(a,b,c){c--;if(0>c)return"...";var d=b.$$hashKey,f;if(H(a)){f=0;for(var g=a.length;f<g;f++)b.push(e(a[f],c))}else if(Nc(a))for(f in a)b[f]=e(a[f],c);else if(a&&"function"===typeof a.hasOwnProperty)for(f in a)a.hasOwnProperty(f)&&
|
||||
(b[f]=e(a[f],c));else for(f in a)ta.call(a,f)&&(b[f]=e(a[f],c));d?b.$$hashKey=d:delete b.$$hashKey;return b}function e(a,b){if(!D(a))return a;var d=g.indexOf(a);if(-1!==d)return k[d];if($a(a)||bb(a))throw pa("cpws");var d=!1,e=f(a);void 0===e&&(e=H(a)?[]:Object.create(Pc(a)),d=!0);g.push(a);k.push(e);return d?c(a,e,b):e}function f(a){switch(la.call(a)){case "[object Int8Array]":case "[object Int16Array]":case "[object Int32Array]":case "[object Float32Array]":case "[object Float64Array]":case "[object Uint8Array]":case "[object Uint8ClampedArray]":case "[object Uint16Array]":case "[object Uint32Array]":return new a.constructor(e(a.buffer),
|
||||
a.byteOffset,a.length);case "[object ArrayBuffer]":if(!a.slice){var b=new ArrayBuffer(a.byteLength);(new Uint8Array(b)).set(new Uint8Array(a));return b}return a.slice(0);case "[object Boolean]":case "[object Number]":case "[object String]":case "[object Date]":return new a.constructor(a.valueOf());case "[object RegExp]":return b=new RegExp(a.source,a.toString().match(/[^/]*$/)[0]),b.lastIndex=a.lastIndex,b;case "[object Blob]":return new a.constructor([a],{type:a.type})}if(B(a.cloneNode))return a.cloneNode(!0)}
|
||||
var g=[],k=[];d=Xb(d)?d:NaN;if(b){if(ue(b)||"[object ArrayBuffer]"===la.call(b))throw pa("cpta");if(a===b)throw pa("cpi");H(b)?b.length=0:r(b,function(a,c){"$$hashKey"!==c&&delete b[c]});g.push(a);k.push(b);return c(a,b,d)}return e(a,d)}function dc(a,b){return a===b||a!==a&&b!==b}function va(a,b){if(a===b)return!0;if(null===a||null===b)return!1;if(a!==a&&b!==b)return!0;var d=typeof a,c;if(d===typeof b&&"object"===d)if(H(a)){if(!H(b))return!1;if((d=a.length)===b.length){for(c=0;c<d;c++)if(!va(a[c],
|
||||
b[c]))return!1;return!0}}else{if(ha(a))return ha(b)?dc(a.getTime(),b.getTime()):!1;if(ab(a))return ab(b)?a.toString()===b.toString():!1;if(bb(a)||bb(b)||$a(a)||$a(b)||H(b)||ha(b)||ab(b))return!1;d=T();for(c in a)if("$"!==c.charAt(0)&&!B(a[c])){if(!va(a[c],b[c]))return!1;d[c]=!0}for(c in b)if(!(c in d)&&"$"!==c.charAt(0)&&w(b[c])&&!B(b[c]))return!1;return!0}return!1}function db(a,b,d){return a.concat(Ha.call(b,d))}function Va(a,b){var d=2<arguments.length?Ha.call(arguments,2):[];return!B(b)||b instanceof
|
||||
RegExp?b:d.length?function(){return arguments.length?b.apply(a,db(d,arguments,0)):b.apply(a,d)}:function(){return arguments.length?b.apply(a,arguments):b.call(a)}}function Qc(a,b){var d=b;"string"===typeof a&&"$"===a.charAt(0)&&"$"===a.charAt(1)?d=void 0:$a(b)?d="$WINDOW":b&&C.document===b?d="$DOCUMENT":bb(b)&&(d="$SCOPE");return d}function eb(a,b){if(!z(a))return W(b)||(b=b?2:null),JSON.stringify(a,Qc,b)}function Rc(a){return A(a)?JSON.parse(a):a}function ec(a,b){a=a.replace(xe,"");var d=Date.parse("Jan 01, 1970 00:00:00 "+
|
||||
a)/6E4;return X(d)?b:d}function Sc(a,b){a=new Date(a.getTime());a.setMinutes(a.getMinutes()+b);return a}function fc(a,b,d){d=d?-1:1;var c=a.getTimezoneOffset();b=ec(b,c);return Sc(a,d*(b-c))}function za(a){a=x(a).clone().empty();var b=x("<div></div>").append(a).html();try{return a[0].nodeType===Pa?K(b):b.match(/^(<[^>]+>)/)[1].replace(/^<([\w-]+)/,function(a,b){return"<"+K(b)})}catch(d){return K(b)}}function Tc(a){try{return decodeURIComponent(a)}catch(b){}}function gc(a){var b={};r((a||"").split("&"),
|
||||
function(a){var c,e,f;a&&(e=a=a.replace(/\+/g,"%20"),c=a.indexOf("="),-1!==c&&(e=a.substring(0,c),f=a.substring(c+1)),e=Tc(e),w(e)&&(f=w(f)?Tc(f):!0,ta.call(b,e)?H(b[e])?b[e].push(f):b[e]=[b[e],f]:b[e]=f))});return b}function ye(a){var b=[];r(a,function(a,c){H(a)?r(a,function(a){b.push(ba(c,!0)+(!0===a?"":"="+ba(a,!0)))}):b.push(ba(c,!0)+(!0===a?"":"="+ba(a,!0)))});return b.length?b.join("&"):""}function hc(a){return ba(a,!0).replace(/%26/gi,"&").replace(/%3D/gi,"=").replace(/%2B/gi,"+")}function ba(a,
|
||||
b){return encodeURIComponent(a).replace(/%40/gi,"@").replace(/%3A/gi,":").replace(/%24/g,"$").replace(/%2C/gi,",").replace(/%3B/gi,";").replace(/%20/g,b?"%20":"+")}function ze(a,b){var d,c,e=Qa.length;for(c=0;c<e;++c)if(d=Qa[c]+b,A(d=a.getAttribute(d)))return d;return null}function Ae(a,b){var d,c,e={};r(Qa,function(b){b+="app";!d&&a.hasAttribute&&a.hasAttribute(b)&&(d=a,c=a.getAttribute(b))});r(Qa,function(b){b+="app";var e;!d&&(e=a.querySelector("["+b.replace(":","\\:")+"]"))&&(d=e,c=e.getAttribute(b))});
|
||||
d&&(Be?(e.strictDi=null!==ze(d,"strict-di"),b(d,c?[c]:[],e)):C.console.error("AngularJS: disabling automatic bootstrap. <script> protocol indicates an extension, document.location.href does not match."))}function Uc(a,b,d){D(d)||(d={});d=S({strictDi:!1},d);var c=function(){a=x(a);if(a.injector()){var c=a[0]===C.document?"document":za(a);throw pa("btstrpd",c.replace(/</,"<").replace(/>/,">"));}b=b||[];b.unshift(["$provide",function(b){b.value("$rootElement",a)}]);d.debugInfoEnabled&&b.push(["$compileProvider",
|
||||
function(a){a.debugInfoEnabled(!0)}]);b.unshift("ng");c=fb(b,d.strictDi);c.invoke(["$rootScope","$rootElement","$compile","$injector",function(a,b,c,d){a.$apply(function(){b.data("$injector",d);c(b)(a)})}]);return c},e=/^NG_ENABLE_DEBUG_INFO!/,f=/^NG_DEFER_BOOTSTRAP!/;C&&e.test(C.name)&&(d.debugInfoEnabled=!0,C.name=C.name.replace(e,""));if(C&&!f.test(C.name))return c();C.name=C.name.replace(f,"");ca.resumeBootstrap=function(a){r(a,function(a){b.push(a)});return c()};B(ca.resumeDeferredBootstrap)&&
|
||||
ca.resumeDeferredBootstrap()}function Ce(){C.name="NG_ENABLE_DEBUG_INFO!"+C.name;C.location.reload()}function De(a){a=ca.element(a).injector();if(!a)throw pa("test");return a.get("$$testability")}function Vc(a,b){b=b||"_";return a.replace(Ee,function(a,c){return(c?b:"")+a.toLowerCase()})}function Fe(){var a;if(!Wc){var b=qb();(rb=z(b)?C.jQuery:b?C[b]:void 0)&&rb.fn.on?(x=rb,S(rb.fn,{scope:Wa.scope,isolateScope:Wa.isolateScope,controller:Wa.controller,injector:Wa.injector,inheritedData:Wa.inheritedData})):
|
||||
x=Y;a=x.cleanData;x.cleanData=function(b){for(var c,e=0,f;null!=(f=b[e]);e++)(c=(x._data(f)||{}).events)&&c.$destroy&&x(f).triggerHandler("$destroy");a(b)};ca.element=x;Wc=!0}}function gb(a,b,d){if(!a)throw pa("areq",b||"?",d||"required");return a}function sb(a,b,d){d&&H(a)&&(a=a[a.length-1]);gb(B(a),b,"not a function, got "+(a&&"object"===typeof a?a.constructor.name||"Object":typeof a));return a}function Ja(a,b){if("hasOwnProperty"===a)throw pa("badname",b);}function Ge(a,b,d){if(!b)return a;b=b.split(".");
|
||||
for(var c,e=a,f=b.length,g=0;g<f;g++)c=b[g],a&&(a=(e=a)[c]);return!d&&B(a)?Va(e,a):a}function tb(a){for(var b=a[0],d=a[a.length-1],c,e=1;b!==d&&(b=b.nextSibling);e++)if(c||a[e]!==b)c||(c=x(Ha.call(a,0,e))),c.push(b);return c||a}function T(){return Object.create(null)}function ic(a){if(null==a)return"";switch(typeof a){case "string":break;case "number":a=""+a;break;default:a=!bc(a)||H(a)||ha(a)?eb(a):a.toString()}return a}function He(a){function b(a,b,c){return a[b]||(a[b]=c())}var d=F("$injector"),
|
||||
c=F("ng");a=b(a,"angular",Object);a.$$minErr=a.$$minErr||F;return b(a,"module",function(){var a={};return function(f,g,k){var h={};if("hasOwnProperty"===f)throw c("badname","module");g&&a.hasOwnProperty(f)&&(a[f]=null);return b(a,f,function(){function a(b,c,d,f){f||(f=e);return function(){f[d||"push"]([b,c,arguments]);return t}}function b(a,c,d){d||(d=e);return function(b,e){e&&B(e)&&(e.$$moduleName=f);d.push([a,c,arguments]);return t}}if(!g)throw d("nomod",f);var e=[],n=[],s=[],G=a("$injector","invoke",
|
||||
"push",n),t={_invokeQueue:e,_configBlocks:n,_runBlocks:s,info:function(a){if(w(a)){if(!D(a))throw c("aobj","value");h=a;return this}return h},requires:g,name:f,provider:b("$provide","provider"),factory:b("$provide","factory"),service:b("$provide","service"),value:a("$provide","value"),constant:a("$provide","constant","unshift"),decorator:b("$provide","decorator",n),animation:b("$animateProvider","register"),filter:b("$filterProvider","register"),controller:b("$controllerProvider","register"),directive:b("$compileProvider",
|
||||
"directive"),component:b("$compileProvider","component"),config:G,run:function(a){s.push(a);return this}};k&&G(k);return t})}})}function ja(a,b){if(H(a)){b=b||[];for(var d=0,c=a.length;d<c;d++)b[d]=a[d]}else if(D(a))for(d in b=b||{},a)if("$"!==d.charAt(0)||"$"!==d.charAt(1))b[d]=a[d];return b||a}function Ie(a,b){var d=[];Xb(b)&&(a=ca.copy(a,null,b));return JSON.stringify(a,function(a,b){b=Qc(a,b);if(D(b)){if(0<=d.indexOf(b))return"...";d.push(b)}return b})}function Je(a){S(a,{errorHandlingConfig:re,
|
||||
bootstrap:Uc,copy:Ia,extend:S,merge:te,equals:va,element:x,forEach:r,injector:fb,noop:E,bind:Va,toJson:eb,fromJson:Rc,identity:Ta,isUndefined:z,isDefined:w,isString:A,isFunction:B,isObject:D,isNumber:W,isElement:$b,isArray:H,version:Ke,isDate:ha,callbacks:{$$counter:0},getTestability:De,reloadWithDebugInfo:Ce,$$minErr:F,$$csp:Aa,$$encodeUriSegment:hc,$$encodeUriQuery:ba,$$lowercase:K,$$stringify:ic,$$uppercase:ub});kc=He(C);kc("ng",["ngLocale"],["$provide",function(a){a.provider({$$sanitizeUri:Le});
|
||||
a.provider("$compile",Xc).directive({a:Me,input:Yc,textarea:Yc,form:Ne,script:Oe,select:Pe,option:Qe,ngBind:Re,ngBindHtml:Se,ngBindTemplate:Te,ngClass:Ue,ngClassEven:Ve,ngClassOdd:We,ngCloak:Xe,ngController:Ye,ngForm:Ze,ngHide:$e,ngIf:af,ngInclude:bf,ngInit:cf,ngNonBindable:df,ngPluralize:ef,ngRef:ff,ngRepeat:gf,ngShow:hf,ngStyle:jf,ngSwitch:kf,ngSwitchWhen:lf,ngSwitchDefault:mf,ngOptions:nf,ngTransclude:of,ngModel:pf,ngList:qf,ngChange:rf,pattern:Zc,ngPattern:Zc,required:$c,ngRequired:$c,minlength:ad,
|
||||
ngMinlength:ad,maxlength:bd,ngMaxlength:bd,ngValue:sf,ngModelOptions:tf}).directive({ngInclude:uf,input:vf}).directive(vb).directive(cd);a.provider({$anchorScroll:wf,$animate:xf,$animateCss:yf,$$animateJs:zf,$$animateQueue:Af,$$AnimateRunner:Bf,$$animateAsyncRun:Cf,$browser:Df,$cacheFactory:Ef,$controller:Ff,$document:Gf,$$isDocumentHidden:Hf,$exceptionHandler:If,$filter:dd,$$forceReflow:Jf,$interpolate:Kf,$interval:Lf,$$intervalFactory:Mf,$http:Nf,$httpParamSerializer:Of,$httpParamSerializerJQLike:Pf,
|
||||
$httpBackend:Qf,$xhrFactory:Rf,$jsonpCallbacks:Sf,$location:Tf,$log:Uf,$parse:Vf,$rootScope:Wf,$q:Xf,$$q:Yf,$sce:Zf,$sceDelegate:$f,$sniffer:ag,$$taskTrackerFactory:bg,$templateCache:cg,$templateRequest:dg,$$testability:eg,$timeout:fg,$window:gg,$$rAF:hg,$$jqLite:ig,$$Map:jg,$$cookieReader:kg})}]).info({angularVersion:"1.7.7"})}function wb(a,b){return b.toUpperCase()}function xb(a){return a.replace(lg,wb)}function lc(a){a=a.nodeType;return 1===a||!a||9===a}function ed(a,b){var d,c,e=b.createDocumentFragment(),
|
||||
f=[];if(mc.test(a)){d=e.appendChild(b.createElement("div"));c=(mg.exec(a)||["",""])[1].toLowerCase();c=oa[c]||oa._default;d.innerHTML=c[1]+a.replace(ng,"<$1></$2>")+c[2];for(c=c[0];c--;)d=d.lastChild;f=db(f,d.childNodes);d=e.firstChild;d.textContent=""}else f.push(b.createTextNode(a));e.textContent="";e.innerHTML="";r(f,function(a){e.appendChild(a)});return e}function Y(a){if(a instanceof Y)return a;var b;A(a)&&(a=U(a),b=!0);if(!(this instanceof Y)){if(b&&"<"!==a.charAt(0))throw nc("nosel");return new Y(a)}if(b){b=
|
||||
C.document;var d;a=(d=og.exec(a))?[b.createElement(d[1])]:(d=ed(a,b))?d.childNodes:[];oc(this,a)}else B(a)?fd(a):oc(this,a)}function pc(a){return a.cloneNode(!0)}function yb(a,b){!b&&lc(a)&&x.cleanData([a]);a.querySelectorAll&&x.cleanData(a.querySelectorAll("*"))}function gd(a){for(var b in a)return!1;return!0}function hd(a){var b=a.ng339,d=b&&Ka[b],c=d&&d.events,d=d&&d.data;d&&!gd(d)||c&&!gd(c)||(delete Ka[b],a.ng339=void 0)}function id(a,b,d,c){if(w(c))throw nc("offargs");var e=(c=zb(a))&&c.events,
|
||||
f=c&&c.handle;if(f){if(b){var g=function(b){var c=e[b];w(d)&&cb(c||[],d);w(d)&&c&&0<c.length||(a.removeEventListener(b,f),delete e[b])};r(b.split(" "),function(a){g(a);Ab[a]&&g(Ab[a])})}else for(b in e)"$destroy"!==b&&a.removeEventListener(b,f),delete e[b];hd(a)}}function qc(a,b){var d=a.ng339;if(d=d&&Ka[d])b?delete d.data[b]:d.data={},hd(a)}function zb(a,b){var d=a.ng339,d=d&&Ka[d];b&&!d&&(a.ng339=d=++pg,d=Ka[d]={events:{},data:{},handle:void 0});return d}function rc(a,b,d){if(lc(a)){var c,e=w(d),
|
||||
f=!e&&b&&!D(b),g=!b;a=(a=zb(a,!f))&&a.data;if(e)a[xb(b)]=d;else{if(g)return a;if(f)return a&&a[xb(b)];for(c in b)a[xb(c)]=b[c]}}}function Bb(a,b){return a.getAttribute?-1<(" "+(a.getAttribute("class")||"")+" ").replace(/[\n\t]/g," ").indexOf(" "+b+" "):!1}function Cb(a,b){if(b&&a.setAttribute){var d=(" "+(a.getAttribute("class")||"")+" ").replace(/[\n\t]/g," "),c=d;r(b.split(" "),function(a){a=U(a);c=c.replace(" "+a+" "," ")});c!==d&&a.setAttribute("class",U(c))}}function Db(a,b){if(b&&a.setAttribute){var d=
|
||||
(" "+(a.getAttribute("class")||"")+" ").replace(/[\n\t]/g," "),c=d;r(b.split(" "),function(a){a=U(a);-1===c.indexOf(" "+a+" ")&&(c+=a+" ")});c!==d&&a.setAttribute("class",U(c))}}function oc(a,b){if(b)if(b.nodeType)a[a.length++]=b;else{var d=b.length;if("number"===typeof d&&b.window!==b){if(d)for(var c=0;c<d;c++)a[a.length++]=b[c]}else a[a.length++]=b}}function jd(a,b){return Eb(a,"$"+(b||"ngController")+"Controller")}function Eb(a,b,d){9===a.nodeType&&(a=a.documentElement);for(b=H(b)?b:[b];a;){for(var c=
|
||||
0,e=b.length;c<e;c++)if(w(d=x.data(a,b[c])))return d;a=a.parentNode||11===a.nodeType&&a.host}}function kd(a){for(yb(a,!0);a.firstChild;)a.removeChild(a.firstChild)}function Fb(a,b){b||yb(a);var d=a.parentNode;d&&d.removeChild(a)}function qg(a,b){b=b||C;if("complete"===b.document.readyState)b.setTimeout(a);else x(b).on("load",a)}function fd(a){function b(){C.document.removeEventListener("DOMContentLoaded",b);C.removeEventListener("load",b);a()}"complete"===C.document.readyState?C.setTimeout(a):(C.document.addEventListener("DOMContentLoaded",
|
||||
b),C.addEventListener("load",b))}function ld(a,b){var d=Gb[b.toLowerCase()];return d&&md[ua(a)]&&d}function rg(a,b){var d=function(c,d){c.isDefaultPrevented=function(){return c.defaultPrevented};var f=b[d||c.type],g=f?f.length:0;if(g){if(z(c.immediatePropagationStopped)){var k=c.stopImmediatePropagation;c.stopImmediatePropagation=function(){c.immediatePropagationStopped=!0;c.stopPropagation&&c.stopPropagation();k&&k.call(c)}}c.isImmediatePropagationStopped=function(){return!0===c.immediatePropagationStopped};
|
||||
var h=f.specialHandlerWrapper||sg;1<g&&(f=ja(f));for(var l=0;l<g;l++)c.isImmediatePropagationStopped()||h(a,c,f[l])}};d.elem=a;return d}function sg(a,b,d){d.call(a,b)}function tg(a,b,d){var c=b.relatedTarget;c&&(c===a||ug.call(a,c))||d.call(a,b)}function ig(){this.$get=function(){return S(Y,{hasClass:function(a,b){a.attr&&(a=a[0]);return Bb(a,b)},addClass:function(a,b){a.attr&&(a=a[0]);return Db(a,b)},removeClass:function(a,b){a.attr&&(a=a[0]);return Cb(a,b)}})}}function La(a,b){var d=a&&a.$$hashKey;
|
||||
if(d)return"function"===typeof d&&(d=a.$$hashKey()),d;d=typeof a;return d="function"===d||"object"===d&&null!==a?a.$$hashKey=d+":"+(b||se)():d+":"+a}function nd(){this._keys=[];this._values=[];this._lastKey=NaN;this._lastIndex=-1}function od(a){a=Function.prototype.toString.call(a).replace(vg,"");return a.match(wg)||a.match(xg)}function yg(a){return(a=od(a))?"function("+(a[1]||"").replace(/[\s\r\n]+/," ")+")":"fn"}function fb(a,b){function d(a){return function(b,c){if(D(b))r(b,Yb(a));else return a(b,
|
||||
c)}}function c(a,b){Ja(a,"service");if(B(b)||H(b))b=n.instantiate(b);if(!b.$get)throw Ba("pget",a);return p[a+"Provider"]=b}function e(a,b){return function(){var c=t.invoke(b,this);if(z(c))throw Ba("undef",a);return c}}function f(a,b,d){return c(a,{$get:!1!==d?e(a,b):b})}function g(a){gb(z(a)||H(a),"modulesToLoad","not an array");var b=[],c;r(a,function(a){function d(a){var b,c;b=0;for(c=a.length;b<c;b++){var e=a[b],f=n.get(e[0]);f[e[1]].apply(f,e[2])}}if(!m.get(a)){m.set(a,!0);try{A(a)?(c=kc(a),
|
||||
t.modules[a]=c,b=b.concat(g(c.requires)).concat(c._runBlocks),d(c._invokeQueue),d(c._configBlocks)):B(a)?b.push(n.invoke(a)):H(a)?b.push(n.invoke(a)):sb(a,"module")}catch(e){throw H(a)&&(a=a[a.length-1]),e.message&&e.stack&&-1===e.stack.indexOf(e.message)&&(e=e.message+"\n"+e.stack),Ba("modulerr",a,e.stack||e.message||e);}}});return b}function k(a,c){function d(b,e){if(a.hasOwnProperty(b)){if(a[b]===h)throw Ba("cdep",b+" <- "+l.join(" <- "));return a[b]}try{return l.unshift(b),a[b]=h,a[b]=c(b,e),
|
||||
a[b]}catch(f){throw a[b]===h&&delete a[b],f;}finally{l.shift()}}function e(a,c,f){var g=[];a=fb.$$annotate(a,b,f);for(var h=0,k=a.length;h<k;h++){var l=a[h];if("string"!==typeof l)throw Ba("itkn",l);g.push(c&&c.hasOwnProperty(l)?c[l]:d(l,f))}return g}return{invoke:function(a,b,c,d){"string"===typeof c&&(d=c,c=null);c=e(a,c,d);H(a)&&(a=a[a.length-1]);d=a;if(Ca||"function"!==typeof d)d=!1;else{var f=d.$$ngIsClass;Ga(f)||(f=d.$$ngIsClass=/^class\b/.test(Function.prototype.toString.call(d)));d=f}return d?
|
||||
(c.unshift(null),new (Function.prototype.bind.apply(a,c))):a.apply(b,c)},instantiate:function(a,b,c){var d=H(a)?a[a.length-1]:a;a=e(a,b,c);a.unshift(null);return new (Function.prototype.bind.apply(d,a))},get:d,annotate:fb.$$annotate,has:function(b){return p.hasOwnProperty(b+"Provider")||a.hasOwnProperty(b)}}}b=!0===b;var h={},l=[],m=new Hb,p={$provide:{provider:d(c),factory:d(f),service:d(function(a,b){return f(a,["$injector",function(a){return a.instantiate(b)}])}),value:d(function(a,b){return f(a,
|
||||
ia(b),!1)}),constant:d(function(a,b){Ja(a,"constant");p[a]=b;s[a]=b}),decorator:function(a,b){var c=n.get(a+"Provider"),d=c.$get;c.$get=function(){var a=t.invoke(d,c);return t.invoke(b,null,{$delegate:a})}}}},n=p.$injector=k(p,function(a,b){ca.isString(b)&&l.push(b);throw Ba("unpr",l.join(" <- "));}),s={},G=k(s,function(a,b){var c=n.get(a+"Provider",b);return t.invoke(c.$get,c,void 0,a)}),t=G;p.$injectorProvider={$get:ia(G)};t.modules=n.modules=T();var N=g(a),t=G.get("$injector");t.strictDi=b;r(N,
|
||||
function(a){a&&t.invoke(a)});t.loadNewModules=function(a){r(g(a),function(a){a&&t.invoke(a)})};return t}function wf(){var a=!0;this.disableAutoScrolling=function(){a=!1};this.$get=["$window","$location","$rootScope",function(b,d,c){function e(a){var b=null;Array.prototype.some.call(a,function(a){if("a"===ua(a))return b=a,!0});return b}function f(a){if(a){a.scrollIntoView();var c;c=g.yOffset;B(c)?c=c():$b(c)?(c=c[0],c="fixed"!==b.getComputedStyle(c).position?0:c.getBoundingClientRect().bottom):W(c)||
|
||||
(c=0);c&&(a=a.getBoundingClientRect().top,b.scrollBy(0,a-c))}else b.scrollTo(0,0)}function g(a){a=A(a)?a:W(a)?a.toString():d.hash();var b;a?(b=k.getElementById(a))?f(b):(b=e(k.getElementsByName(a)))?f(b):"top"===a&&f(null):f(null)}var k=b.document;a&&c.$watch(function(){return d.hash()},function(a,b){a===b&&""===a||qg(function(){c.$evalAsync(g)})});return g}]}function hb(a,b){if(!a&&!b)return"";if(!a)return b;if(!b)return a;H(a)&&(a=a.join(" "));H(b)&&(b=b.join(" "));return a+" "+b}function zg(a){A(a)&&
|
||||
(a=a.split(" "));var b=T();r(a,function(a){a.length&&(b[a]=!0)});return b}function ra(a){return D(a)?a:{}}function Ag(a,b,d,c,e){function f(){qa=null;k()}function g(){t=y();t=z(t)?null:t;va(t,P)&&(t=P);N=P=t}function k(){var a=N;g();if(v!==h.url()||a!==t)v=h.url(),N=t,r(J,function(a){a(h.url(),t)})}var h=this,l=a.location,m=a.history,p=a.setTimeout,n=a.clearTimeout,s={},G=e(d);h.isMock=!1;h.$$completeOutstandingRequest=G.completeTask;h.$$incOutstandingRequestCount=G.incTaskCount;h.notifyWhenNoOutstandingRequests=
|
||||
G.notifyWhenNoPendingTasks;var t,N,v=l.href,jc=b.find("base"),qa=null,y=c.history?function(){try{return m.state}catch(a){}}:E;g();h.url=function(b,d,e){z(e)&&(e=null);l!==a.location&&(l=a.location);m!==a.history&&(m=a.history);if(b){var f=N===e;b=ga(b).href;if(v===b&&(!c.history||f))return h;var k=v&&Da(v)===Da(b);v=b;N=e;!c.history||k&&f?(k||(qa=b),d?l.replace(b):k?(d=l,e=b,f=e.indexOf("#"),e=-1===f?"":e.substr(f),d.hash=e):l.href=b,l.href!==b&&(qa=b)):(m[d?"replaceState":"pushState"](e,"",b),g());
|
||||
qa&&(qa=b);return h}return(qa||l.href).replace(/#$/,"")};h.state=function(){return t};var J=[],I=!1,P=null;h.onUrlChange=function(b){if(!I){if(c.history)x(a).on("popstate",f);x(a).on("hashchange",f);I=!0}J.push(b);return b};h.$$applicationDestroyed=function(){x(a).off("hashchange popstate",f)};h.$$checkUrlChange=k;h.baseHref=function(){var a=jc.attr("href");return a?a.replace(/^(https?:)?\/\/[^/]*/,""):""};h.defer=function(a,b,c){var d;b=b||0;c=c||G.DEFAULT_TASK_TYPE;G.incTaskCount(c);d=p(function(){delete s[d];
|
||||
G.completeTask(a,c)},b);s[d]=c;return d};h.defer.cancel=function(a){if(s.hasOwnProperty(a)){var b=s[a];delete s[a];n(a);G.completeTask(E,b);return!0}return!1}}function Df(){this.$get=["$window","$log","$sniffer","$document","$$taskTrackerFactory",function(a,b,d,c,e){return new Ag(a,c,b,d,e)}]}function Ef(){this.$get=function(){function a(a,c){function e(a){a!==p&&(n?n===a&&(n=a.n):n=a,f(a.n,a.p),f(a,p),p=a,p.n=null)}function f(a,b){a!==b&&(a&&(a.p=b),b&&(b.n=a))}if(a in b)throw F("$cacheFactory")("iid",
|
||||
a);var g=0,k=S({},c,{id:a}),h=T(),l=c&&c.capacity||Number.MAX_VALUE,m=T(),p=null,n=null;return b[a]={put:function(a,b){if(!z(b)){if(l<Number.MAX_VALUE){var c=m[a]||(m[a]={key:a});e(c)}a in h||g++;h[a]=b;g>l&&this.remove(n.key);return b}},get:function(a){if(l<Number.MAX_VALUE){var b=m[a];if(!b)return;e(b)}return h[a]},remove:function(a){if(l<Number.MAX_VALUE){var b=m[a];if(!b)return;b===p&&(p=b.p);b===n&&(n=b.n);f(b.n,b.p);delete m[a]}a in h&&(delete h[a],g--)},removeAll:function(){h=T();g=0;m=T();
|
||||
p=n=null},destroy:function(){m=k=h=null;delete b[a]},info:function(){return S({},k,{size:g})}}}var b={};a.info=function(){var a={};r(b,function(b,e){a[e]=b.info()});return a};a.get=function(a){return b[a]};return a}}function cg(){this.$get=["$cacheFactory",function(a){return a("templates")}]}function Xc(a,b){function d(a,b,c){var d=/^([@&]|[=<](\*?))(\??)\s*([\w$]*)$/,e=T();r(a,function(a,f){a=a.trim();if(a in p)e[f]=p[a];else{var g=a.match(d);if(!g)throw $("iscp",b,f,a,c?"controller bindings definition":
|
||||
"isolate scope definition");e[f]={mode:g[1][0],collection:"*"===g[2],optional:"?"===g[3],attrName:g[4]||f};g[4]&&(p[a]=e[f])}});return e}function c(a){var b=a.charAt(0);if(!b||b!==K(b))throw $("baddir",a);if(a!==a.trim())throw $("baddir",a);}function e(a){var b=a.require||a.controller&&a.name;!H(b)&&D(b)&&r(b,function(a,c){var d=a.match(l);a.substring(d[0].length)||(b[c]=d[0]+c)});return b}var f={},g=/^\s*directive:\s*([\w-]+)\s+(.*)$/,k=/(([\w-]+)(?::([^;]+))?;?)/,h=we("ngSrc,ngSrcset,src,srcset"),
|
||||
l=/^(?:(\^\^?)?(\?)?(\^\^?)?)?/,m=/^(on[a-z]+|formaction)$/,p=T();this.directive=function qa(b,d){gb(b,"name");Ja(b,"directive");A(b)?(c(b),gb(d,"directiveFactory"),f.hasOwnProperty(b)||(f[b]=[],a.factory(b+"Directive",["$injector","$exceptionHandler",function(a,c){var d=[];r(f[b],function(f,g){try{var h=a.invoke(f);B(h)?h={compile:ia(h)}:!h.compile&&h.link&&(h.compile=ia(h.link));h.priority=h.priority||0;h.index=g;h.name=h.name||b;h.require=e(h);var k=h,l=h.restrict;if(l&&(!A(l)||!/[EACM]/.test(l)))throw $("badrestrict",
|
||||
l,b);k.restrict=l||"EA";h.$$moduleName=f.$$moduleName;d.push(h)}catch(m){c(m)}});return d}])),f[b].push(d)):r(b,Yb(qa));return this};this.component=function y(a,b){function c(a){function e(b){return B(b)||H(b)?function(c,d){return a.invoke(b,this,{$element:c,$attrs:d})}:b}var f=b.template||b.templateUrl?b.template:"",g={controller:d,controllerAs:Bg(b.controller)||b.controllerAs||"$ctrl",template:e(f),templateUrl:e(b.templateUrl),transclude:b.transclude,scope:{},bindToController:b.bindings||{},restrict:"E",
|
||||
require:b.require};r(b,function(a,b){"$"===b.charAt(0)&&(g[b]=a)});return g}if(!A(a))return r(a,Yb(Va(this,y))),this;var d=b.controller||function(){};r(b,function(a,b){"$"===b.charAt(0)&&(c[b]=a,B(d)&&(d[b]=a))});c.$inject=["$injector"];return this.directive(a,c)};this.aHrefSanitizationWhitelist=function(a){return w(a)?(b.aHrefSanitizationWhitelist(a),this):b.aHrefSanitizationWhitelist()};this.imgSrcSanitizationWhitelist=function(a){return w(a)?(b.imgSrcSanitizationWhitelist(a),this):b.imgSrcSanitizationWhitelist()};
|
||||
var n=!0;this.debugInfoEnabled=function(a){return w(a)?(n=a,this):n};var s=!1;this.strictComponentBindingsEnabled=function(a){return w(a)?(s=a,this):s};var G=10;this.onChangesTtl=function(a){return arguments.length?(G=a,this):G};var t=!0;this.commentDirectivesEnabled=function(a){return arguments.length?(t=a,this):t};var N=!0;this.cssClassDirectivesEnabled=function(a){return arguments.length?(N=a,this):N};var v=T();this.addPropertySecurityContext=function(a,b,c){var d=a.toLowerCase()+"|"+b.toLowerCase();
|
||||
if(d in v&&v[d]!==c)throw $("ctxoverride",a,b,v[d],c);v[d]=c;return this};(function(){function a(b,c){r(c,function(a){v[a.toLowerCase()]=b})}a(V.HTML,["iframe|srcdoc","*|innerHTML","*|outerHTML"]);a(V.CSS,["*|style"]);a(V.URL,"area|href area|ping a|href a|ping blockquote|cite body|background del|cite input|src ins|cite q|cite".split(" "));a(V.MEDIA_URL,"audio|src img|src img|srcset source|src source|srcset track|src video|src video|poster".split(" "));a(V.RESOURCE_URL,"*|formAction applet|code applet|codebase base|href embed|src frame|src form|action head|profile html|manifest iframe|src link|href media|src object|codebase object|data script|src".split(" "))})();
|
||||
this.$get=["$injector","$interpolate","$exceptionHandler","$templateRequest","$parse","$controller","$rootScope","$sce","$animate",function(a,b,c,e,p,M,L,u,R){function q(){try{if(!--Ja)throw Ua=void 0,$("infchng",G);L.$apply(function(){for(var a=0,b=Ua.length;a<b;++a)try{Ua[a]()}catch(d){c(d)}Ua=void 0})}finally{Ja++}}function ma(a,b){if(!a)return a;if(!A(a))throw $("srcset",b,a.toString());for(var c="",d=U(a),e=/(\s+\d+x\s*,|\s+\d+w\s*,|\s+,|,\s+)/,e=/\s/.test(d)?e:/(,)/,d=d.split(e),e=Math.floor(d.length/
|
||||
2),f=0;f<e;f++)var g=2*f,c=c+u.getTrustedMediaUrl(U(d[g])),c=c+(" "+U(d[g+1]));d=U(d[2*f]).split(/\s/);c+=u.getTrustedMediaUrl(U(d[0]));2===d.length&&(c+=" "+U(d[1]));return c}function w(a,b){if(b){var c=Object.keys(b),d,e,f;d=0;for(e=c.length;d<e;d++)f=c[d],this[f]=b[f]}else this.$attr={};this.$$element=a}function O(a,b,c){Fa.innerHTML="<span "+b+">";b=Fa.firstChild.attributes;var d=b[0];b.removeNamedItem(d.name);d.value=c;a.attributes.setNamedItem(d)}function sa(a,b){try{a.addClass(b)}catch(c){}}
|
||||
function da(a,b,c,d,e){a instanceof x||(a=x(a));var f=Xa(a,b,a,c,d,e);da.$$addScopeClass(a);var g=null;return function(b,c,d){if(!a)throw $("multilink");gb(b,"scope");e&&e.needsNewScope&&(b=b.$parent.$new());d=d||{};var h=d.parentBoundTranscludeFn,k=d.transcludeControllers;d=d.futureParentElement;h&&h.$$boundTransclude&&(h=h.$$boundTransclude);g||(g=(d=d&&d[0])?"foreignobject"!==ua(d)&&la.call(d).match(/SVG/)?"svg":"html":"html");d="html"!==g?x(ja(g,x("<div></div>").append(a).html())):c?Wa.clone.call(a):
|
||||
a;if(k)for(var l in k)d.data("$"+l+"Controller",k[l].instance);da.$$addScopeInfo(d,b);c&&c(d,b);f&&f(b,d,d,h);c||(a=f=null);return d}}function Xa(a,b,c,d,e,f){function g(a,c,d,e){var f,k,l,m,p,I,t;if(n)for(t=Array(c.length),m=0;m<h.length;m+=3)f=h[m],t[f]=c[f];else t=c;m=0;for(p=h.length;m<p;)k=t[h[m++]],c=h[m++],f=h[m++],c?(c.scope?(l=a.$new(),da.$$addScopeInfo(x(k),l)):l=a,I=c.transcludeOnThisElement?ka(a,c.transclude,e):!c.templateOnThisElement&&e?e:!e&&b?ka(a,b):null,c(f,l,k,d,I)):f&&f(a,k.childNodes,
|
||||
void 0,e)}for(var h=[],k=H(a)||a instanceof x,l,m,p,I,n,t=0;t<a.length;t++){l=new w;11===Ca&&ib(a,t,k);m=sc(a[t],[],l,0===t?d:void 0,e);(f=m.length?aa(m,a[t],l,b,c,null,[],[],f):null)&&f.scope&&da.$$addScopeClass(l.$$element);l=f&&f.terminal||!(p=a[t].childNodes)||!p.length?null:Xa(p,f?(f.transcludeOnThisElement||!f.templateOnThisElement)&&f.transclude:b);if(f||l)h.push(t,f,l),I=!0,n=n||f;f=null}return I?g:null}function ib(a,b,c){var d=a[b],e=d.parentNode,f;if(d.nodeType===Pa)for(;;){f=e?d.nextSibling:
|
||||
a[b+1];if(!f||f.nodeType!==Pa)break;d.nodeValue+=f.nodeValue;f.parentNode&&f.parentNode.removeChild(f);c&&f===a[b+1]&&a.splice(b+1,1)}}function ka(a,b,c){function d(e,f,g,h,k){e||(e=a.$new(!1,k),e.$$transcluded=!0);return b(e,f,{parentBoundTranscludeFn:c,transcludeControllers:g,futureParentElement:h})}var e=d.$$slots=T(),f;for(f in b.$$slots)e[f]=b.$$slots[f]?ka(a,b.$$slots[f],c):null;return d}function sc(a,b,d,e,f){var g=d.$attr,h;switch(a.nodeType){case 1:h=ua(a);X(b,wa(h),"E",e,f);for(var l,m,
|
||||
n,t,J,s=a.attributes,v=0,G=s&&s.length;v<G;v++){var P=!1,N=!1,r=!1,y=!1,u=!1,M;l=s[v];m=l.name;t=l.value;n=wa(m.toLowerCase());(J=n.match(Ra))?(r="Attr"===J[1],y="Prop"===J[1],u="On"===J[1],m=m.replace(pd,"").toLowerCase().substr(4+J[1].length).replace(/_(.)/g,function(a,b){return b.toUpperCase()})):(M=n.match(Sa))&&ca(M[1])&&(P=m,N=m.substr(0,m.length-5)+"end",m=m.substr(0,m.length-6));if(y||u)d[n]=t,g[n]=l.name,y?Ea(a,b,n,m):b.push(qd(p,L,c,n,m,!1));else{n=wa(m.toLowerCase());g[n]=m;if(r||!d.hasOwnProperty(n))d[n]=
|
||||
t,ld(a,n)&&(d[n]=!0);Ia(a,b,t,n,r);X(b,n,"A",e,f,P,N)}}"input"===h&&"hidden"===a.getAttribute("type")&&a.setAttribute("autocomplete","off");if(!Qa)break;g=a.className;D(g)&&(g=g.animVal);if(A(g)&&""!==g)for(;a=k.exec(g);)n=wa(a[2]),X(b,n,"C",e,f)&&(d[n]=U(a[3])),g=g.substr(a.index+a[0].length);break;case Pa:na(b,a.nodeValue);break;case 8:if(!Oa)break;F(a,b,d,e,f)}b.sort(ia);return b}function F(a,b,c,d,e){try{var f=g.exec(a.nodeValue);if(f){var h=wa(f[1]);X(b,h,"M",d,e)&&(c[h]=U(f[2]))}}catch(k){}}
|
||||
function V(a,b,c){var d=[],e=0;if(b&&a.hasAttribute&&a.hasAttribute(b)){do{if(!a)throw $("uterdir",b,c);1===a.nodeType&&(a.hasAttribute(b)&&e++,a.hasAttribute(c)&&e--);d.push(a);a=a.nextSibling}while(0<e)}else d.push(a);return x(d)}function Y(a,b,c){return function(d,e,f,g,h){e=V(e[0],b,c);return a(d,e,f,g,h)}}function Z(a,b,c,d,e,f){var g;return a?da(b,c,d,e,f):function(){g||(g=da(b,c,d,e,f),b=c=f=null);return g.apply(this,arguments)}}function aa(a,b,d,e,f,g,h,k,l){function m(a,b,c,d){if(a){c&&(a=
|
||||
Y(a,c,d));a.require=u.require;a.directiveName=Q;if(s===u||u.$$isolateScope)a=Aa(a,{isolateScope:!0});h.push(a)}if(b){c&&(b=Y(b,c,d));b.require=u.require;b.directiveName=Q;if(s===u||u.$$isolateScope)b=Aa(b,{isolateScope:!0});k.push(b)}}function p(a,e,f,g,l){function m(a,b,c,d){var e;bb(a)||(d=c,c=b,b=a,a=void 0);N&&(e=P);c||(c=N?Q.parent():Q);if(d){var f=l.$$slots[d];if(f)return f(a,b,e,c,R);if(z(f))throw $("noslot",d,za(Q));}else return l(a,b,e,c,R)}var n,u,L,y,G,P,M,Q;b===f?(g=d,Q=d.$$element):(Q=
|
||||
x(f),g=new w(Q,d));G=e;s?y=e.$new(!0):t&&(G=e.$parent);l&&(M=m,M.$$boundTransclude=l,M.isSlotFilled=function(a){return!!l.$$slots[a]});J&&(P=ea(Q,g,M,J,y,e,s));s&&(da.$$addScopeInfo(Q,y,!0,!(v&&(v===s||v===s.$$originalDirective))),da.$$addScopeClass(Q,!0),y.$$isolateBindings=s.$$isolateBindings,u=Da(e,g,y,y.$$isolateBindings,s),u.removeWatches&&y.$on("$destroy",u.removeWatches));for(n in P){u=J[n];L=P[n];var Cg=u.$$bindings.bindToController;L.instance=L();Q.data("$"+u.name+"Controller",L.instance);
|
||||
L.bindingInfo=Da(G,g,L.instance,Cg,u)}r(J,function(a,b){var c=a.require;a.bindToController&&!H(c)&&D(c)&&S(P[b].instance,W(b,c,Q,P))});r(P,function(a){var b=a.instance;if(B(b.$onChanges))try{b.$onChanges(a.bindingInfo.initialChanges)}catch(d){c(d)}if(B(b.$onInit))try{b.$onInit()}catch(e){c(e)}B(b.$doCheck)&&(G.$watch(function(){b.$doCheck()}),b.$doCheck());B(b.$onDestroy)&&G.$on("$destroy",function(){b.$onDestroy()})});n=0;for(u=h.length;n<u;n++)L=h[n],Ba(L,L.isolateScope?y:e,Q,g,L.require&&W(L.directiveName,
|
||||
L.require,Q,P),M);var R=e;s&&(s.template||null===s.templateUrl)&&(R=y);a&&a(R,f.childNodes,void 0,l);for(n=k.length-1;0<=n;n--)L=k[n],Ba(L,L.isolateScope?y:e,Q,g,L.require&&W(L.directiveName,L.require,Q,P),M);r(P,function(a){a=a.instance;B(a.$postLink)&&a.$postLink()})}l=l||{};for(var n=-Number.MAX_VALUE,t=l.newScopeDirective,J=l.controllerDirectives,s=l.newIsolateScopeDirective,v=l.templateDirective,L=l.nonTlbTranscludeDirective,G=!1,P=!1,N=l.hasElementTranscludeDirective,y=d.$$element=x(b),u,Q,
|
||||
M,R=e,q,ma=!1,Ib=!1,O,sa=0,A=a.length;sa<A;sa++){u=a[sa];var E=u.$$start,ib=u.$$end;E&&(y=V(b,E,ib));M=void 0;if(n>u.priority)break;if(O=u.scope)u.templateUrl||(D(O)?(ba("new/isolated scope",s||t,u,y),s=u):ba("new/isolated scope",s,u,y)),t=t||u;Q=u.name;if(!ma&&(u.replace&&(u.templateUrl||u.template)||u.transclude&&!u.$$tlb)){for(O=sa+1;ma=a[O++];)if(ma.transclude&&!ma.$$tlb||ma.replace&&(ma.templateUrl||ma.template)){Ib=!0;break}ma=!0}!u.templateUrl&&u.controller&&(J=J||T(),ba("'"+Q+"' controller",
|
||||
J[Q],u,y),J[Q]=u);if(O=u.transclude)if(G=!0,u.$$tlb||(ba("transclusion",L,u,y),L=u),"element"===O)N=!0,n=u.priority,M=y,y=d.$$element=x(da.$$createComment(Q,d[Q])),b=y[0],pa(f,Ha.call(M,0),b),R=Z(Ib,M,e,n,g&&g.name,{nonTlbTranscludeDirective:L});else{var ka=T();if(D(O)){M=C.document.createDocumentFragment();var Xa=T(),F=T();r(O,function(a,b){var c="?"===a.charAt(0);a=c?a.substring(1):a;Xa[a]=b;ka[b]=null;F[b]=c});r(y.contents(),function(a){var b=Xa[wa(ua(a))];b?(F[b]=!0,ka[b]=ka[b]||C.document.createDocumentFragment(),
|
||||
ka[b].appendChild(a)):M.appendChild(a)});r(F,function(a,b){if(!a)throw $("reqslot",b);});for(var K in ka)ka[K]&&(R=x(ka[K].childNodes),ka[K]=Z(Ib,R,e));M=x(M.childNodes)}else M=x(pc(b)).contents();y.empty();R=Z(Ib,M,e,void 0,void 0,{needsNewScope:u.$$isolateScope||u.$$newScope});R.$$slots=ka}if(u.template)if(P=!0,ba("template",v,u,y),v=u,O=B(u.template)?u.template(y,d):u.template,O=Na(O),u.replace){g=u;M=mc.test(O)?rd(ja(u.templateNamespace,U(O))):[];b=M[0];if(1!==M.length||1!==b.nodeType)throw $("tplrt",
|
||||
Q,"");pa(f,y,b);A={$attr:{}};O=sc(b,[],A);var Dg=a.splice(sa+1,a.length-(sa+1));(s||t)&&fa(O,s,t);a=a.concat(O).concat(Dg);ga(d,A);A=a.length}else y.html(O);if(u.templateUrl)P=!0,ba("template",v,u,y),v=u,u.replace&&(g=u),p=ha(a.splice(sa,a.length-sa),y,d,f,G&&R,h,k,{controllerDirectives:J,newScopeDirective:t!==u&&t,newIsolateScopeDirective:s,templateDirective:v,nonTlbTranscludeDirective:L}),A=a.length;else if(u.compile)try{q=u.compile(y,d,R);var X=u.$$originalDirective||u;B(q)?m(null,Va(X,q),E,ib):
|
||||
q&&m(Va(X,q.pre),Va(X,q.post),E,ib)}catch(ca){c(ca,za(y))}u.terminal&&(p.terminal=!0,n=Math.max(n,u.priority))}p.scope=t&&!0===t.scope;p.transcludeOnThisElement=G;p.templateOnThisElement=P;p.transclude=R;l.hasElementTranscludeDirective=N;return p}function W(a,b,c,d){var e;if(A(b)){var f=b.match(l);b=b.substring(f[0].length);var g=f[1]||f[3],f="?"===f[2];"^^"===g?c=c.parent():e=(e=d&&d[b])&&e.instance;if(!e){var h="$"+b+"Controller";e="^^"===g&&c[0]&&9===c[0].nodeType?null:g?c.inheritedData(h):c.data(h)}if(!e&&
|
||||
!f)throw $("ctreq",b,a);}else if(H(b))for(e=[],g=0,f=b.length;g<f;g++)e[g]=W(a,b[g],c,d);else D(b)&&(e={},r(b,function(b,f){e[f]=W(a,b,c,d)}));return e||null}function ea(a,b,c,d,e,f,g){var h=T(),k;for(k in d){var l=d[k],m={$scope:l===g||l.$$isolateScope?e:f,$element:a,$attrs:b,$transclude:c},p=l.controller;"@"===p&&(p=b[l.name]);m=M(p,m,!0,l.controllerAs);h[l.name]=m;a.data("$"+l.name+"Controller",m.instance)}return h}function fa(a,b,c){for(var d=0,e=a.length;d<e;d++)a[d]=ac(a[d],{$$isolateScope:b,
|
||||
$$newScope:c})}function X(b,c,e,g,h,k,l){if(c===h)return null;var m=null;if(f.hasOwnProperty(c)){h=a.get(c+"Directive");for(var p=0,n=h.length;p<n;p++)if(c=h[p],(z(g)||g>c.priority)&&-1!==c.restrict.indexOf(e)){k&&(c=ac(c,{$$start:k,$$end:l}));if(!c.$$bindings){var I=m=c,t=c.name,u={isolateScope:null,bindToController:null};D(I.scope)&&(!0===I.bindToController?(u.bindToController=d(I.scope,t,!0),u.isolateScope={}):u.isolateScope=d(I.scope,t,!1));D(I.bindToController)&&(u.bindToController=d(I.bindToController,
|
||||
t,!0));if(u.bindToController&&!I.controller)throw $("noctrl",t);m=m.$$bindings=u;D(m.isolateScope)&&(c.$$isolateBindings=m.isolateScope)}b.push(c);m=c}}return m}function ca(b){if(f.hasOwnProperty(b))for(var c=a.get(b+"Directive"),d=0,e=c.length;d<e;d++)if(b=c[d],b.multiElement)return!0;return!1}function ga(a,b){var c=b.$attr,d=a.$attr;r(a,function(d,e){"$"!==e.charAt(0)&&(b[e]&&b[e]!==d&&(d=d.length?d+(("style"===e?";":" ")+b[e]):b[e]),a.$set(e,d,!0,c[e]))});r(b,function(b,e){a.hasOwnProperty(e)||
|
||||
"$"===e.charAt(0)||(a[e]=b,"class"!==e&&"style"!==e&&(d[e]=c[e]))})}function ha(a,b,d,f,g,h,k,l){var m=[],p,n,t=b[0],u=a.shift(),J=ac(u,{templateUrl:null,transclude:null,replace:null,$$originalDirective:u}),s=B(u.templateUrl)?u.templateUrl(b,d):u.templateUrl,L=u.templateNamespace;b.empty();e(s).then(function(c){var e,I;c=Na(c);if(u.replace){c=mc.test(c)?rd(ja(L,U(c))):[];e=c[0];if(1!==c.length||1!==e.nodeType)throw $("tplrt",u.name,s);c={$attr:{}};pa(f,b,e);var v=sc(e,[],c);D(u.scope)&&fa(v,!0);a=
|
||||
v.concat(a);ga(d,c)}else e=t,b.html(c);a.unshift(J);p=aa(a,e,d,g,b,u,h,k,l);r(f,function(a,c){a===e&&(f[c]=b[0])});for(n=Xa(b[0].childNodes,g);m.length;){c=m.shift();I=m.shift();var y=m.shift(),P=m.shift(),v=b[0];if(!c.$$destroyed){if(I!==t){var G=I.className;l.hasElementTranscludeDirective&&u.replace||(v=pc(e));pa(y,x(I),v);sa(x(v),G)}I=p.transcludeOnThisElement?ka(c,p.transclude,P):P;p(n,c,v,f,I)}}m=null}).catch(function(a){cc(a)&&c(a)});return function(a,b,c,d,e){a=e;b.$$destroyed||(m?m.push(b,
|
||||
c,d,a):(p.transcludeOnThisElement&&(a=ka(b,p.transclude,e)),p(n,b,c,d,a)))}}function ia(a,b){var c=b.priority-a.priority;return 0!==c?c:a.name!==b.name?a.name<b.name?-1:1:a.index-b.index}function ba(a,b,c,d){function e(a){return a?" (module: "+a+")":""}if(b)throw $("multidir",b.name,e(b.$$moduleName),c.name,e(c.$$moduleName),a,za(d));}function na(a,c){var d=b(c,!0);d&&a.push({priority:0,compile:function(a){a=a.parent();var b=!!a.length;b&&da.$$addBindingClass(a);return function(a,c){var e=c.parent();
|
||||
b||da.$$addBindingClass(e);da.$$addBindingInfo(e,d.expressions);a.$watch(d,function(a){c[0].nodeValue=a})}}})}function ja(a,b){a=K(a||"html");switch(a){case "svg":case "math":var c=C.document.createElement("div");c.innerHTML="<"+a+">"+b+"</"+a+">";return c.childNodes[0].childNodes;default:return b}}function oa(a,b){if("srcdoc"===b)return u.HTML;if("src"===b||"ngSrc"===b)return-1===["img","video","audio","source","track"].indexOf(a)?u.RESOURCE_URL:u.MEDIA_URL;if("xlinkHref"===b)return"image"===a?u.MEDIA_URL:
|
||||
"a"===a?u.URL:u.RESOURCE_URL;if("form"===a&&"action"===b||"base"===a&&"href"===b||"link"===a&&"href"===b)return u.RESOURCE_URL;if("a"===a&&("href"===b||"ngHref"===b))return u.URL}function xa(a,b){var c=b.toLowerCase();return v[a+"|"+c]||v["*|"+c]}function ya(a){return ma(u.valueOf(a),"ng-prop-srcset")}function Ea(a,b,c,d){if(m.test(d))throw $("nodomevents");a=ua(a);var e=xa(a,d),f=Ta;"srcset"!==d||"img"!==a&&"source"!==a?e&&(f=u.getTrusted.bind(u,e)):f=ya;b.push({priority:100,compile:function(a,b){var e=
|
||||
p(b[c]),g=p(b[c],function(a){return u.valueOf(a)});return{pre:function(a,b){function c(){var g=e(a);b[0][d]=f(g)}c();a.$watch(g,c)}}}})}function Ia(a,c,d,e,f){var g=ua(a),k=oa(g,e),l=h[e]||f,p=b(d,!f,k,l);if(p){if("multiple"===e&&"select"===g)throw $("selmulti",za(a));if(m.test(e))throw $("nodomevents");c.push({priority:100,compile:function(){return{pre:function(a,c,f){c=f.$$observers||(f.$$observers=T());var g=f[e];g!==d&&(p=g&&b(g,!0,k,l),d=g);p&&(f[e]=p(a),(c[e]||(c[e]=[])).$$inter=!0,(f.$$observers&&
|
||||
f.$$observers[e].$$scope||a).$watch(p,function(a,b){"class"===e&&a!==b?f.$updateClass(a,b):f.$set(e,a)}))}}}})}}function pa(a,b,c){var d=b[0],e=b.length,f=d.parentNode,g,h;if(a)for(g=0,h=a.length;g<h;g++)if(a[g]===d){a[g++]=c;h=g+e-1;for(var k=a.length;g<k;g++,h++)h<k?a[g]=a[h]:delete a[g];a.length-=e-1;a.context===d&&(a.context=c);break}f&&f.replaceChild(c,d);a=C.document.createDocumentFragment();for(g=0;g<e;g++)a.appendChild(b[g]);x.hasData(d)&&(x.data(c,x.data(d)),x(d).off("$destroy"));x.cleanData(a.querySelectorAll("*"));
|
||||
for(g=1;g<e;g++)delete b[g];b[0]=c;b.length=1}function Aa(a,b){return S(function(){return a.apply(null,arguments)},a,b)}function Ba(a,b,d,e,f,g){try{a(b,d,e,f,g)}catch(h){c(h,za(d))}}function ra(a,b){if(s)throw $("missingattr",a,b);}function Da(a,c,d,e,f){function g(b,c,e){B(d.$onChanges)&&!dc(c,e)&&(Ua||(a.$$postDigest(q),Ua=[]),m||(m={},Ua.push(h)),m[b]&&(e=m[b].previousValue),m[b]=new Jb(e,c))}function h(){d.$onChanges(m);m=void 0}var k=[],l={},m;r(e,function(e,h){var m=e.attrName,n=e.optional,
|
||||
I,t,u,s;switch(e.mode){case "@":n||ta.call(c,m)||(ra(m,f.name),d[h]=c[m]=void 0);n=c.$observe(m,function(a){if(A(a)||Ga(a))g(h,a,d[h]),d[h]=a});c.$$observers[m].$$scope=a;I=c[m];A(I)?d[h]=b(I)(a):Ga(I)&&(d[h]=I);l[h]=new Jb(tc,d[h]);k.push(n);break;case "=":if(!ta.call(c,m)){if(n)break;ra(m,f.name);c[m]=void 0}if(n&&!c[m])break;t=p(c[m]);s=t.literal?va:dc;u=t.assign||function(){I=d[h]=t(a);throw $("nonassign",c[m],m,f.name);};I=d[h]=t(a);n=function(b){s(b,d[h])||(s(b,I)?u(a,b=d[h]):d[h]=b);return I=
|
||||
b};n.$stateful=!0;n=e.collection?a.$watchCollection(c[m],n):a.$watch(p(c[m],n),null,t.literal);k.push(n);break;case "<":if(!ta.call(c,m)){if(n)break;ra(m,f.name);c[m]=void 0}if(n&&!c[m])break;t=p(c[m]);var v=t.literal,L=d[h]=t(a);l[h]=new Jb(tc,d[h]);n=a[e.collection?"$watchCollection":"$watch"](t,function(a,b){if(b===a){if(b===L||v&&va(b,L))return;b=L}g(h,a,b);d[h]=a});k.push(n);break;case "&":n||ta.call(c,m)||ra(m,f.name);t=c.hasOwnProperty(m)?p(c[m]):E;if(t===E&&n)break;d[h]=function(b){return t(a,
|
||||
b)}}});return{initialChanges:l,removeWatches:k.length&&function(){for(var a=0,b=k.length;a<b;++a)k[a]()}}}var Ma=/^\w/,Fa=C.document.createElement("div"),Oa=t,Qa=N,Ja=G,Ua;w.prototype={$normalize:wa,$addClass:function(a){a&&0<a.length&&R.addClass(this.$$element,a)},$removeClass:function(a){a&&0<a.length&&R.removeClass(this.$$element,a)},$updateClass:function(a,b){var c=sd(a,b);c&&c.length&&R.addClass(this.$$element,c);(c=sd(b,a))&&c.length&&R.removeClass(this.$$element,c)},$set:function(a,b,d,e){var f=
|
||||
ld(this.$$element[0],a),g=td[a],h=a;f?(this.$$element.prop(a,b),e=f):g&&(this[g]=b,h=g);this[a]=b;e?this.$attr[a]=e:(e=this.$attr[a])||(this.$attr[a]=e=Vc(a,"-"));"img"===ua(this.$$element)&&"srcset"===a&&(this[a]=b=ma(b,"$set('srcset', value)"));!1!==d&&(null===b||z(b)?this.$$element.removeAttr(e):Ma.test(e)?f&&!1===b?this.$$element.removeAttr(e):this.$$element.attr(e,b):O(this.$$element[0],e,b));(a=this.$$observers)&&r(a[h],function(a){try{a(b)}catch(d){c(d)}})},$observe:function(a,b){var c=this,
|
||||
d=c.$$observers||(c.$$observers=T()),e=d[a]||(d[a]=[]);e.push(b);L.$evalAsync(function(){e.$$inter||!c.hasOwnProperty(a)||z(c[a])||b(c[a])});return function(){cb(e,b)}}};var Ka=b.startSymbol(),La=b.endSymbol(),Na="{{"===Ka&&"}}"===La?Ta:function(a){return a.replace(/\{\{/g,Ka).replace(/}}/g,La)},Ra=/^ng(Attr|Prop|On)([A-Z].*)$/,Sa=/^(.+)Start$/;da.$$addBindingInfo=n?function(a,b){var c=a.data("$binding")||[];H(b)?c=c.concat(b):c.push(b);a.data("$binding",c)}:E;da.$$addBindingClass=n?function(a){sa(a,
|
||||
"ng-binding")}:E;da.$$addScopeInfo=n?function(a,b,c,d){a.data(c?d?"$isolateScopeNoTemplate":"$isolateScope":"$scope",b)}:E;da.$$addScopeClass=n?function(a,b){sa(a,b?"ng-isolate-scope":"ng-scope")}:E;da.$$createComment=function(a,b){var c="";n&&(c=" "+(a||"")+": ",b&&(c+=b+" "));return C.document.createComment(c)};return da}]}function Jb(a,b){this.previousValue=a;this.currentValue=b}function wa(a){return a.replace(pd,"").replace(Eg,function(a,d,c){return c?d.toUpperCase():d})}function sd(a,b){var d=
|
||||
"",c=a.split(/\s+/),e=b.split(/\s+/),f=0;a:for(;f<c.length;f++){for(var g=c[f],k=0;k<e.length;k++)if(g===e[k])continue a;d+=(0<d.length?" ":"")+g}return d}function rd(a){a=x(a);var b=a.length;if(1>=b)return a;for(;b--;){var d=a[b];(8===d.nodeType||d.nodeType===Pa&&""===d.nodeValue.trim())&&Fg.call(a,b,1)}return a}function Bg(a,b){if(b&&A(b))return b;if(A(a)){var d=ud.exec(a);if(d)return d[3]}}function Ff(){var a={};this.has=function(b){return a.hasOwnProperty(b)};this.register=function(b,d){Ja(b,
|
||||
"controller");D(b)?S(a,b):a[b]=d};this.$get=["$injector",function(b){function d(a,b,d,g){if(!a||!D(a.$scope))throw F("$controller")("noscp",g,b);a.$scope[b]=d}return function(c,e,f,g){var k,h,l;f=!0===f;g&&A(g)&&(l=g);if(A(c)){g=c.match(ud);if(!g)throw vd("ctrlfmt",c);h=g[1];l=l||g[3];c=a.hasOwnProperty(h)?a[h]:Ge(e.$scope,h,!0);if(!c)throw vd("ctrlreg",h);sb(c,h,!0)}if(f)return f=(H(c)?c[c.length-1]:c).prototype,k=Object.create(f||null),l&&d(e,l,k,h||c.name),S(function(){var a=b.invoke(c,k,e,h);
|
||||
a!==k&&(D(a)||B(a))&&(k=a,l&&d(e,l,k,h||c.name));return k},{instance:k,identifier:l});k=b.instantiate(c,e,h);l&&d(e,l,k,h||c.name);return k}}]}function Gf(){this.$get=["$window",function(a){return x(a.document)}]}function Hf(){this.$get=["$document","$rootScope",function(a,b){function d(){e=c.hidden}var c=a[0],e=c&&c.hidden;a.on("visibilitychange",d);b.$on("$destroy",function(){a.off("visibilitychange",d)});return function(){return e}}]}function If(){this.$get=["$log",function(a){return function(b,
|
||||
d){a.error.apply(a,arguments)}}]}function uc(a){return D(a)?ha(a)?a.toISOString():eb(a):a}function Of(){this.$get=function(){return function(a){if(!a)return"";var b=[];Oc(a,function(a,c){null===a||z(a)||B(a)||(H(a)?r(a,function(a){b.push(ba(c)+"="+ba(uc(a)))}):b.push(ba(c)+"="+ba(uc(a))))});return b.join("&")}}}function Pf(){this.$get=function(){return function(a){function b(a,e,f){H(a)?r(a,function(a,c){b(a,e+"["+(D(a)?c:"")+"]")}):D(a)&&!ha(a)?Oc(a,function(a,c){b(a,e+(f?"":"[")+c+(f?"":"]"))}):
|
||||
(B(a)&&(a=a()),d.push(ba(e)+"="+(null==a?"":ba(uc(a)))))}if(!a)return"";var d=[];b(a,"",!0);return d.join("&")}}}function vc(a,b){if(A(a)){var d=a.replace(Gg,"").trim();if(d){var c=b("Content-Type"),c=c&&0===c.indexOf(wd),e;(e=c)||(e=(e=d.match(Hg))&&Ig[e[0]].test(d));if(e)try{a=Rc(d)}catch(f){if(!c)return a;throw Kb("baddata",a,f);}}}return a}function xd(a){var b=T(),d;A(a)?r(a.split("\n"),function(a){d=a.indexOf(":");var e=K(U(a.substr(0,d)));a=U(a.substr(d+1));e&&(b[e]=b[e]?b[e]+", "+a:a)}):D(a)&&
|
||||
r(a,function(a,d){var f=K(d),g=U(a);f&&(b[f]=b[f]?b[f]+", "+g:g)});return b}function yd(a){var b;return function(d){b||(b=xd(a));return d?(d=b[K(d)],void 0===d&&(d=null),d):b}}function zd(a,b,d,c){if(B(c))return c(a,b,d);r(c,function(c){a=c(a,b,d)});return a}function Nf(){var a=this.defaults={transformResponse:[vc],transformRequest:[function(a){return D(a)&&"[object File]"!==la.call(a)&&"[object Blob]"!==la.call(a)&&"[object FormData]"!==la.call(a)?eb(a):a}],headers:{common:{Accept:"application/json, text/plain, */*"},
|
||||
post:ja(wc),put:ja(wc),patch:ja(wc)},xsrfCookieName:"XSRF-TOKEN",xsrfHeaderName:"X-XSRF-TOKEN",paramSerializer:"$httpParamSerializer",jsonpCallbackParam:"callback"},b=!1;this.useApplyAsync=function(a){return w(a)?(b=!!a,this):b};var d=this.interceptors=[],c=this.xsrfWhitelistedOrigins=[];this.$get=["$browser","$httpBackend","$$cookieReader","$cacheFactory","$rootScope","$q","$injector","$sce",function(e,f,g,k,h,l,m,p){function n(b){function c(a,b){for(var d=0,e=b.length;d<e;){var f=b[d++],g=b[d++];
|
||||
a=a.then(f,g)}b.length=0;return a}function d(a,b){var c,e={};r(a,function(a,d){B(a)?(c=a(b),null!=c&&(e[d]=c)):e[d]=a});return e}function f(a){var b=S({},a);b.data=zd(a.data,a.headers,a.status,g.transformResponse);a=a.status;return 200<=a&&300>a?b:l.reject(b)}if(!D(b))throw F("$http")("badreq",b);if(!A(p.valueOf(b.url)))throw F("$http")("badreq",b.url);var g=S({method:"get",transformRequest:a.transformRequest,transformResponse:a.transformResponse,paramSerializer:a.paramSerializer,jsonpCallbackParam:a.jsonpCallbackParam},
|
||||
b);g.headers=function(b){var c=a.headers,e=S({},b.headers),f,g,h,c=S({},c.common,c[K(b.method)]);a:for(f in c){g=K(f);for(h in e)if(K(h)===g)continue a;e[f]=c[f]}return d(e,ja(b))}(b);g.method=ub(g.method);g.paramSerializer=A(g.paramSerializer)?m.get(g.paramSerializer):g.paramSerializer;e.$$incOutstandingRequestCount("$http");var h=[],k=[];b=l.resolve(g);r(v,function(a){(a.request||a.requestError)&&h.unshift(a.request,a.requestError);(a.response||a.responseError)&&k.push(a.response,a.responseError)});
|
||||
b=c(b,h);b=b.then(function(b){var c=b.headers,d=zd(b.data,yd(c),void 0,b.transformRequest);z(d)&&r(c,function(a,b){"content-type"===K(b)&&delete c[b]});z(b.withCredentials)&&!z(a.withCredentials)&&(b.withCredentials=a.withCredentials);return s(b,d).then(f,f)});b=c(b,k);return b=b.finally(function(){e.$$completeOutstandingRequest(E,"$http")})}function s(c,d){function e(a){if(a){var c={};r(a,function(a,d){c[d]=function(c){function d(){a(c)}b?h.$applyAsync(d):h.$$phase?d():h.$apply(d)}});return c}}function k(a,
|
||||
c,d,e,f){function g(){m(c,a,d,e,f)}R&&(200<=a&&300>a?R.put(O,[a,c,xd(d),e,f]):R.remove(O));b?h.$applyAsync(g):(g(),h.$$phase||h.$apply())}function m(a,b,d,e,f){b=-1<=b?b:0;(200<=b&&300>b?L.resolve:L.reject)({data:a,status:b,headers:yd(d),config:c,statusText:e,xhrStatus:f})}function s(a){m(a.data,a.status,ja(a.headers()),a.statusText,a.xhrStatus)}function v(){var a=n.pendingRequests.indexOf(c);-1!==a&&n.pendingRequests.splice(a,1)}var L=l.defer(),u=L.promise,R,q,ma=c.headers,x="jsonp"===K(c.method),
|
||||
O=c.url;x?O=p.getTrustedResourceUrl(O):A(O)||(O=p.valueOf(O));O=G(O,c.paramSerializer(c.params));x&&(O=t(O,c.jsonpCallbackParam));n.pendingRequests.push(c);u.then(v,v);!c.cache&&!a.cache||!1===c.cache||"GET"!==c.method&&"JSONP"!==c.method||(R=D(c.cache)?c.cache:D(a.cache)?a.cache:N);R&&(q=R.get(O),w(q)?q&&B(q.then)?q.then(s,s):H(q)?m(q[1],q[0],ja(q[2]),q[3],q[4]):m(q,200,{},"OK","complete"):R.put(O,u));z(q)&&((q=jc(c.url)?g()[c.xsrfCookieName||a.xsrfCookieName]:void 0)&&(ma[c.xsrfHeaderName||a.xsrfHeaderName]=
|
||||
q),f(c.method,O,d,k,ma,c.timeout,c.withCredentials,c.responseType,e(c.eventHandlers),e(c.uploadEventHandlers)));return u}function G(a,b){0<b.length&&(a+=(-1===a.indexOf("?")?"?":"&")+b);return a}function t(a,b){var c=a.split("?");if(2<c.length)throw Kb("badjsonp",a);c=gc(c[1]);r(c,function(c,d){if("JSON_CALLBACK"===c)throw Kb("badjsonp",a);if(d===b)throw Kb("badjsonp",b,a);});return a+=(-1===a.indexOf("?")?"?":"&")+b+"=JSON_CALLBACK"}var N=k("$http");a.paramSerializer=A(a.paramSerializer)?m.get(a.paramSerializer):
|
||||
a.paramSerializer;var v=[];r(d,function(a){v.unshift(A(a)?m.get(a):m.invoke(a))});var jc=Jg(c);n.pendingRequests=[];(function(a){r(arguments,function(a){n[a]=function(b,c){return n(S({},c||{},{method:a,url:b}))}})})("get","delete","head","jsonp");(function(a){r(arguments,function(a){n[a]=function(b,c,d){return n(S({},d||{},{method:a,url:b,data:c}))}})})("post","put","patch");n.defaults=a;return n}]}function Rf(){this.$get=function(){return function(){return new C.XMLHttpRequest}}}function Qf(){this.$get=
|
||||
["$browser","$jsonpCallbacks","$document","$xhrFactory",function(a,b,d,c){return Kg(a,c,a.defer,b,d[0])}]}function Kg(a,b,d,c,e){function f(a,b,d){a=a.replace("JSON_CALLBACK",b);var f=e.createElement("script"),m=null;f.type="text/javascript";f.src=a;f.async=!0;m=function(a){f.removeEventListener("load",m);f.removeEventListener("error",m);e.body.removeChild(f);f=null;var g=-1,s="unknown";a&&("load"!==a.type||c.wasCalled(b)||(a={type:"error"}),s=a.type,g="error"===a.type?404:200);d&&d(g,s)};f.addEventListener("load",
|
||||
m);f.addEventListener("error",m);e.body.appendChild(f);return m}return function(e,k,h,l,m,p,n,s,G,t){function N(a){J="timeout"===a;qa&&qa();y&&y.abort()}function v(a,b,c,e,f,g){w(P)&&d.cancel(P);qa=y=null;a(b,c,e,f,g)}k=k||a.url();if("jsonp"===K(e))var q=c.createCallback(k),qa=f(k,q,function(a,b){var d=200===a&&c.getResponse(q);v(l,a,d,"",b,"complete");c.removeCallback(q)});else{var y=b(e,k),J=!1;y.open(e,k,!0);r(m,function(a,b){w(a)&&y.setRequestHeader(b,a)});y.onload=function(){var a=y.statusText||
|
||||
"",b="response"in y?y.response:y.responseText,c=1223===y.status?204:y.status;0===c&&(c=b?200:"file"===ga(k).protocol?404:0);v(l,c,b,y.getAllResponseHeaders(),a,"complete")};y.onerror=function(){v(l,-1,null,null,"","error")};y.ontimeout=function(){v(l,-1,null,null,"","timeout")};y.onabort=function(){v(l,-1,null,null,"",J?"timeout":"abort")};r(G,function(a,b){y.addEventListener(b,a)});r(t,function(a,b){y.upload.addEventListener(b,a)});n&&(y.withCredentials=!0);if(s)try{y.responseType=s}catch(I){if("json"!==
|
||||
s)throw I;}y.send(z(h)?null:h)}if(0<p)var P=d(function(){N("timeout")},p);else p&&B(p.then)&&p.then(function(){N(w(p.$$timeoutId)?"timeout":"abort")})}}function Kf(){var a="{{",b="}}";this.startSymbol=function(b){return b?(a=b,this):a};this.endSymbol=function(a){return a?(b=a,this):b};this.$get=["$parse","$exceptionHandler","$sce",function(d,c,e){function f(a){return"\\\\\\"+a}function g(c){return c.replace(p,a).replace(n,b)}function k(a,b,c,d){var e=a.$watch(function(a){e();return d(a)},b,c);return e}
|
||||
function h(f,h,n,p){function v(a){try{return a=n&&!r?e.getTrusted(n,a):e.valueOf(a),p&&!w(a)?a:ic(a)}catch(b){c(Ma.interr(f,b))}}var r=n===e.URL||n===e.MEDIA_URL;if(!f.length||-1===f.indexOf(a)){if(h)return;h=g(f);r&&(h=e.getTrusted(n,h));h=ia(h);h.exp=f;h.expressions=[];h.$$watchDelegate=k;return h}p=!!p;for(var q,y,J=0,I=[],P,Q=f.length,M=[],L=[],u;J<Q;)if(-1!==(q=f.indexOf(a,J))&&-1!==(y=f.indexOf(b,q+l)))J!==q&&M.push(g(f.substring(J,q))),J=f.substring(q+l,y),I.push(J),J=y+m,L.push(M.length),
|
||||
M.push("");else{J!==Q&&M.push(g(f.substring(J)));break}u=1===M.length&&1===L.length;var R=r&&u?void 0:v;P=I.map(function(a){return d(a,R)});if(!h||I.length){var x=function(a){for(var b=0,c=I.length;b<c;b++){if(p&&z(a[b]))return;M[L[b]]=a[b]}if(r)return e.getTrusted(n,u?M[0]:M.join(""));n&&1<M.length&&Ma.throwNoconcat(f);return M.join("")};return S(function(a){var b=0,d=I.length,e=Array(d);try{for(;b<d;b++)e[b]=P[b](a);return x(e)}catch(g){c(Ma.interr(f,g))}},{exp:f,expressions:I,$$watchDelegate:function(a,
|
||||
b){var c;return a.$watchGroup(P,function(d,e){var f=x(d);b.call(this,f,d!==e?c:f,a);c=f})}})}}var l=a.length,m=b.length,p=new RegExp(a.replace(/./g,f),"g"),n=new RegExp(b.replace(/./g,f),"g");h.startSymbol=function(){return a};h.endSymbol=function(){return b};return h}]}function Lf(){this.$get=["$$intervalFactory","$window",function(a,b){var d={},c=function(a){b.clearInterval(a);delete d[a]},e=a(function(a,c,e){a=b.setInterval(a,c);d[a]=e;return a},c);e.cancel=function(a){if(!a)return!1;if(!a.hasOwnProperty("$$intervalId"))throw Lg("badprom");
|
||||
if(!d.hasOwnProperty(a.$$intervalId))return!1;a=a.$$intervalId;var b=d[a],e=b.promise;e.$$state&&(e.$$state.pur=!0);b.reject("canceled");c(a);return!0};return e}]}function Mf(){this.$get=["$browser","$q","$$q","$rootScope",function(a,b,d,c){return function(e,f){return function(g,k,h,l){function m(){p?g.apply(null,n):g(s)}var p=4<arguments.length,n=p?Ha.call(arguments,4):[],s=0,G=w(l)&&!l,t=(G?d:b).defer(),r=t.promise;h=w(h)?h:0;r.$$intervalId=e(function(){G?a.defer(m):c.$evalAsync(m);t.notify(s++);
|
||||
0<h&&s>=h&&(t.resolve(s),f(r.$$intervalId));G||c.$apply()},k,t,G);return r}}}]}function Ad(a,b){var d=ga(a);b.$$protocol=d.protocol;b.$$host=d.hostname;b.$$port=fa(d.port)||Mg[d.protocol]||null}function Bd(a,b,d){if(Ng.test(a))throw jb("badpath",a);var c="/"!==a.charAt(0);c&&(a="/"+a);a=ga(a);for(var c=(c&&"/"===a.pathname.charAt(0)?a.pathname.substring(1):a.pathname).split("/"),e=c.length;e--;)c[e]=decodeURIComponent(c[e]),d&&(c[e]=c[e].replace(/\//g,"%2F"));d=c.join("/");b.$$path=d;b.$$search=gc(a.search);
|
||||
b.$$hash=decodeURIComponent(a.hash);b.$$path&&"/"!==b.$$path.charAt(0)&&(b.$$path="/"+b.$$path)}function xc(a,b){return a.slice(0,b.length)===b}function xa(a,b){if(xc(b,a))return b.substr(a.length)}function Da(a){var b=a.indexOf("#");return-1===b?a:a.substr(0,b)}function yc(a,b,d){this.$$html5=!0;d=d||"";Ad(a,this);this.$$parse=function(a){var d=xa(b,a);if(!A(d))throw jb("ipthprfx",a,b);Bd(d,this,!0);this.$$path||(this.$$path="/");this.$$compose()};this.$$normalizeUrl=function(a){return b+a.substr(1)};
|
||||
this.$$parseLinkUrl=function(c,e){if(e&&"#"===e[0])return this.hash(e.slice(1)),!0;var f,g;w(f=xa(a,c))?(g=f,g=d&&w(f=xa(d,f))?b+(xa("/",f)||f):a+g):w(f=xa(b,c))?g=b+f:b===c+"/"&&(g=b);g&&this.$$parse(g);return!!g}}function zc(a,b,d){Ad(a,this);this.$$parse=function(c){var e=xa(a,c)||xa(b,c),f;z(e)||"#"!==e.charAt(0)?this.$$html5?f=e:(f="",z(e)&&(a=c,this.replace())):(f=xa(d,e),z(f)&&(f=e));Bd(f,this,!1);c=this.$$path;var e=a,g=/^\/[A-Z]:(\/.*)/;xc(f,e)&&(f=f.replace(e,""));g.exec(f)||(c=(f=g.exec(c))?
|
||||
f[1]:c);this.$$path=c;this.$$compose()};this.$$normalizeUrl=function(b){return a+(b?d+b:"")};this.$$parseLinkUrl=function(b,d){return Da(a)===Da(b)?(this.$$parse(b),!0):!1}}function Cd(a,b,d){this.$$html5=!0;zc.apply(this,arguments);this.$$parseLinkUrl=function(c,e){if(e&&"#"===e[0])return this.hash(e.slice(1)),!0;var f,g;a===Da(c)?f=c:(g=xa(b,c))?f=a+d+g:b===c+"/"&&(f=b);f&&this.$$parse(f);return!!f};this.$$normalizeUrl=function(b){return a+d+b}}function Lb(a){return function(){return this[a]}}function Dd(a,
|
||||
b){return function(d){if(z(d))return this[a];this[a]=b(d);this.$$compose();return this}}function Tf(){var a="!",b={enabled:!1,requireBase:!0,rewriteLinks:!0};this.hashPrefix=function(b){return w(b)?(a=b,this):a};this.html5Mode=function(a){if(Ga(a))return b.enabled=a,this;if(D(a)){Ga(a.enabled)&&(b.enabled=a.enabled);Ga(a.requireBase)&&(b.requireBase=a.requireBase);if(Ga(a.rewriteLinks)||A(a.rewriteLinks))b.rewriteLinks=a.rewriteLinks;return this}return b};this.$get=["$rootScope","$browser","$sniffer",
|
||||
"$rootElement","$window",function(d,c,e,f,g){function k(a,b){return a===b||ga(a).href===ga(b).href}function h(a,b,d){var e=m.url(),f=m.$$state;try{c.url(a,b,d),m.$$state=c.state()}catch(g){throw m.url(e),m.$$state=f,g;}}function l(a,b){d.$broadcast("$locationChangeSuccess",m.absUrl(),a,m.$$state,b)}var m,p;p=c.baseHref();var n=c.url(),s;if(b.enabled){if(!p&&b.requireBase)throw jb("nobase");s=n.substring(0,n.indexOf("/",n.indexOf("//")+2))+(p||"/");p=e.history?yc:Cd}else s=Da(n),p=zc;var r=s.substr(0,
|
||||
Da(s).lastIndexOf("/")+1);m=new p(s,r,"#"+a);m.$$parseLinkUrl(n,n);m.$$state=c.state();var t=/^\s*(javascript|mailto):/i;f.on("click",function(a){var e=b.rewriteLinks;if(e&&!a.ctrlKey&&!a.metaKey&&!a.shiftKey&&2!==a.which&&2!==a.button){for(var g=x(a.target);"a"!==ua(g[0]);)if(g[0]===f[0]||!(g=g.parent())[0])return;if(!A(e)||!z(g.attr(e))){var e=g.prop("href"),h=g.attr("href")||g.attr("xlink:href");D(e)&&"[object SVGAnimatedString]"===e.toString()&&(e=ga(e.animVal).href);t.test(e)||!e||g.attr("target")||
|
||||
a.isDefaultPrevented()||!m.$$parseLinkUrl(e,h)||(a.preventDefault(),m.absUrl()!==c.url()&&d.$apply())}}});m.absUrl()!==n&&c.url(m.absUrl(),!0);var N=!0;c.onUrlChange(function(a,b){xc(a,r)?(d.$evalAsync(function(){var c=m.absUrl(),e=m.$$state,f;m.$$parse(a);m.$$state=b;f=d.$broadcast("$locationChangeStart",a,c,b,e).defaultPrevented;m.absUrl()===a&&(f?(m.$$parse(c),m.$$state=e,h(c,!1,e)):(N=!1,l(c,e)))}),d.$$phase||d.$digest()):g.location.href=a});d.$watch(function(){if(N||m.$$urlUpdatedByLocation){m.$$urlUpdatedByLocation=
|
||||
!1;var a=c.url(),b=m.absUrl(),f=c.state(),g=m.$$replace,n=!k(a,b)||m.$$html5&&e.history&&f!==m.$$state;if(N||n)N=!1,d.$evalAsync(function(){var b=m.absUrl(),c=d.$broadcast("$locationChangeStart",b,a,m.$$state,f).defaultPrevented;m.absUrl()===b&&(c?(m.$$parse(a),m.$$state=f):(n&&h(b,g,f===m.$$state?null:m.$$state),l(a,f)))})}m.$$replace=!1});return m}]}function Uf(){var a=!0,b=this;this.debugEnabled=function(b){return w(b)?(a=b,this):a};this.$get=["$window",function(d){function c(a){cc(a)&&(a.stack&&
|
||||
f?a=a.message&&-1===a.stack.indexOf(a.message)?"Error: "+a.message+"\n"+a.stack:a.stack:a.sourceURL&&(a=a.message+"\n"+a.sourceURL+":"+a.line));return a}function e(a){var b=d.console||{},e=b[a]||b.log||E;return function(){var a=[];r(arguments,function(b){a.push(c(b))});return Function.prototype.apply.call(e,b,a)}}var f=Ca||/\bEdge\//.test(d.navigator&&d.navigator.userAgent);return{log:e("log"),info:e("info"),warn:e("warn"),error:e("error"),debug:function(){var c=e("debug");return function(){a&&c.apply(b,
|
||||
arguments)}}()}}]}function Og(a){return a+""}function Pg(a,b){return"undefined"!==typeof a?a:b}function Ed(a,b){return"undefined"===typeof a?b:"undefined"===typeof b?a:a+b}function Qg(a,b){switch(a.type){case q.MemberExpression:if(a.computed)return!1;break;case q.UnaryExpression:return 1;case q.BinaryExpression:return"+"!==a.operator?1:!1;case q.CallExpression:return!1}return void 0===b?Fd:b}function Z(a,b,d){var c,e,f=a.isPure=Qg(a,d);switch(a.type){case q.Program:c=!0;r(a.body,function(a){Z(a.expression,
|
||||
b,f);c=c&&a.expression.constant});a.constant=c;break;case q.Literal:a.constant=!0;a.toWatch=[];break;case q.UnaryExpression:Z(a.argument,b,f);a.constant=a.argument.constant;a.toWatch=a.argument.toWatch;break;case q.BinaryExpression:Z(a.left,b,f);Z(a.right,b,f);a.constant=a.left.constant&&a.right.constant;a.toWatch=a.left.toWatch.concat(a.right.toWatch);break;case q.LogicalExpression:Z(a.left,b,f);Z(a.right,b,f);a.constant=a.left.constant&&a.right.constant;a.toWatch=a.constant?[]:[a];break;case q.ConditionalExpression:Z(a.test,
|
||||
b,f);Z(a.alternate,b,f);Z(a.consequent,b,f);a.constant=a.test.constant&&a.alternate.constant&&a.consequent.constant;a.toWatch=a.constant?[]:[a];break;case q.Identifier:a.constant=!1;a.toWatch=[a];break;case q.MemberExpression:Z(a.object,b,f);a.computed&&Z(a.property,b,f);a.constant=a.object.constant&&(!a.computed||a.property.constant);a.toWatch=a.constant?[]:[a];break;case q.CallExpression:c=d=a.filter?!b(a.callee.name).$stateful:!1;e=[];r(a.arguments,function(a){Z(a,b,f);c=c&&a.constant;e.push.apply(e,
|
||||
a.toWatch)});a.constant=c;a.toWatch=d?e:[a];break;case q.AssignmentExpression:Z(a.left,b,f);Z(a.right,b,f);a.constant=a.left.constant&&a.right.constant;a.toWatch=[a];break;case q.ArrayExpression:c=!0;e=[];r(a.elements,function(a){Z(a,b,f);c=c&&a.constant;e.push.apply(e,a.toWatch)});a.constant=c;a.toWatch=e;break;case q.ObjectExpression:c=!0;e=[];r(a.properties,function(a){Z(a.value,b,f);c=c&&a.value.constant;e.push.apply(e,a.value.toWatch);a.computed&&(Z(a.key,b,!1),c=c&&a.key.constant,e.push.apply(e,
|
||||
a.key.toWatch))});a.constant=c;a.toWatch=e;break;case q.ThisExpression:a.constant=!1;a.toWatch=[];break;case q.LocalsExpression:a.constant=!1,a.toWatch=[]}}function Gd(a){if(1===a.length){a=a[0].expression;var b=a.toWatch;return 1!==b.length?b:b[0]!==a?b:void 0}}function Hd(a){return a.type===q.Identifier||a.type===q.MemberExpression}function Id(a){if(1===a.body.length&&Hd(a.body[0].expression))return{type:q.AssignmentExpression,left:a.body[0].expression,right:{type:q.NGValueParameter},operator:"="}}
|
||||
function Jd(a){this.$filter=a}function Kd(a){this.$filter=a}function Mb(a,b,d){this.ast=new q(a,d);this.astCompiler=d.csp?new Kd(b):new Jd(b)}function Ac(a){return B(a.valueOf)?a.valueOf():Rg.call(a)}function Vf(){var a=T(),b={"true":!0,"false":!1,"null":null,undefined:void 0},d,c;this.addLiteral=function(a,c){b[a]=c};this.setIdentifierFns=function(a,b){d=a;c=b;return this};this.$get=["$filter",function(e){function f(b,c){var d,f;switch(typeof b){case "string":return f=b=b.trim(),d=a[f],d||(d=new Nb(G),
|
||||
d=(new Mb(d,e,G)).parse(b),a[f]=p(d)),s(d,c);case "function":return s(b,c);default:return s(E,c)}}function g(a,b,c){return null==a||null==b?a===b:"object"!==typeof a||(a=Ac(a),"object"!==typeof a||c)?a===b||a!==a&&b!==b:!1}function k(a,b,c,d,e){var f=d.inputs,h;if(1===f.length){var k=g,f=f[0];return a.$watch(function(a){var b=f(a);g(b,k,f.isPure)||(h=d(a,void 0,void 0,[b]),k=b&&Ac(b));return h},b,c,e)}for(var l=[],m=[],n=0,p=f.length;n<p;n++)l[n]=g,m[n]=null;return a.$watch(function(a){for(var b=
|
||||
!1,c=0,e=f.length;c<e;c++){var k=f[c](a);if(b||(b=!g(k,l[c],f[c].isPure)))m[c]=k,l[c]=k&&Ac(k)}b&&(h=d(a,void 0,void 0,m));return h},b,c,e)}function h(a,b,c,d,e){function f(){h(m)&&k()}function g(a,b,c,d){m=u&&d?d[0]:n(a,b,c,d);h(m)&&a.$$postDigest(f);return s(m)}var h=d.literal?l:w,k,m,n=d.$$intercepted||d,s=d.$$interceptor||Ta,u=d.inputs&&!n.inputs;g.literal=d.literal;g.constant=d.constant;g.inputs=d.inputs;p(g);return k=a.$watch(g,b,c,e)}function l(a){var b=!0;r(a,function(a){w(a)||(b=!1)});return b}
|
||||
function m(a,b,c,d){var e=a.$watch(function(a){e();return d(a)},b,c);return e}function p(a){a.constant?a.$$watchDelegate=m:a.oneTime?a.$$watchDelegate=h:a.inputs&&(a.$$watchDelegate=k);return a}function n(a,b){function c(d){return b(a(d))}c.$stateful=a.$stateful||b.$stateful;c.$$pure=a.$$pure&&b.$$pure;return c}function s(a,b){if(!b)return a;a.$$interceptor&&(b=n(a.$$interceptor,b),a=a.$$intercepted);var c=!1,d=function(d,e,f,g){d=c&&g?g[0]:a(d,e,f,g);return b(d)};d.$$intercepted=a;d.$$interceptor=
|
||||
b;d.literal=a.literal;d.oneTime=a.oneTime;d.constant=a.constant;b.$stateful||(c=!a.inputs,d.inputs=a.inputs?a.inputs:[a],b.$$pure||(d.inputs=d.inputs.map(function(a){return a.isPure===Fd?function(b){return a(b)}:a})));return p(d)}var G={csp:Aa().noUnsafeEval,literals:Ia(b),isIdentifierStart:B(d)&&d,isIdentifierContinue:B(c)&&c};f.$$getAst=function(a){var b=new Nb(G);return(new Mb(b,e,G)).getAst(a).ast};return f}]}function Xf(){var a=!0;this.$get=["$rootScope","$exceptionHandler",function(b,d){return Ld(function(a){b.$evalAsync(a)},
|
||||
d,a)}];this.errorOnUnhandledRejections=function(b){return w(b)?(a=b,this):a}}function Yf(){var a=!0;this.$get=["$browser","$exceptionHandler",function(b,d){return Ld(function(a){b.defer(a)},d,a)}];this.errorOnUnhandledRejections=function(b){return w(b)?(a=b,this):a}}function Ld(a,b,d){function c(){return new e}function e(){var a=this.promise=new f;this.resolve=function(b){h(a,b)};this.reject=function(b){m(a,b)};this.notify=function(b){n(a,b)}}function f(){this.$$state={status:0}}function g(){for(;!w&&
|
||||
x.length;){var a=x.shift();if(!a.pur){a.pur=!0;var c=a.value,c="Possibly unhandled rejection: "+("function"===typeof c?c.toString().replace(/ \{[\s\S]*$/,""):z(c)?"undefined":"string"!==typeof c?Ie(c,void 0):c);cc(a.value)?b(a.value,c):b(c)}}}function k(c){!d||c.pending||2!==c.status||c.pur||(0===w&&0===x.length&&a(g),x.push(c));!c.processScheduled&&c.pending&&(c.processScheduled=!0,++w,a(function(){var e,f,k;k=c.pending;c.processScheduled=!1;c.pending=void 0;try{for(var l=0,n=k.length;l<n;++l){c.pur=
|
||||
!0;f=k[l][0];e=k[l][c.status];try{B(e)?h(f,e(c.value)):1===c.status?h(f,c.value):m(f,c.value)}catch(p){m(f,p),p&&!0===p.$$passToExceptionHandler&&b(p)}}}finally{--w,d&&0===w&&a(g)}}))}function h(a,b){a.$$state.status||(b===a?p(a,v("qcycle",b)):l(a,b))}function l(a,b){function c(b){g||(g=!0,l(a,b))}function d(b){g||(g=!0,p(a,b))}function e(b){n(a,b)}var f,g=!1;try{if(D(b)||B(b))f=b.then;B(f)?(a.$$state.status=-1,f.call(b,c,d,e)):(a.$$state.value=b,a.$$state.status=1,k(a.$$state))}catch(h){d(h)}}function m(a,
|
||||
b){a.$$state.status||p(a,b)}function p(a,b){a.$$state.value=b;a.$$state.status=2;k(a.$$state)}function n(c,d){var e=c.$$state.pending;0>=c.$$state.status&&e&&e.length&&a(function(){for(var a,c,f=0,g=e.length;f<g;f++){c=e[f][0];a=e[f][3];try{n(c,B(a)?a(d):d)}catch(h){b(h)}}})}function s(a){var b=new f;m(b,a);return b}function G(a,b,c){var d=null;try{B(c)&&(d=c())}catch(e){return s(e)}return d&&B(d.then)?d.then(function(){return b(a)},s):b(a)}function t(a,b,c,d){var e=new f;h(e,a);return e.then(b,c,
|
||||
d)}function q(a){if(!B(a))throw v("norslvr",a);var b=new f;a(function(a){h(b,a)},function(a){m(b,a)});return b}var v=F("$q",TypeError),w=0,x=[];S(f.prototype,{then:function(a,b,c){if(z(a)&&z(b)&&z(c))return this;var d=new f;this.$$state.pending=this.$$state.pending||[];this.$$state.pending.push([d,a,b,c]);0<this.$$state.status&&k(this.$$state);return d},"catch":function(a){return this.then(null,a)},"finally":function(a,b){return this.then(function(b){return G(b,y,a)},function(b){return G(b,s,a)},
|
||||
b)}});var y=t;q.prototype=f.prototype;q.defer=c;q.reject=s;q.when=t;q.resolve=y;q.all=function(a){var b=new f,c=0,d=H(a)?[]:{};r(a,function(a,e){c++;t(a).then(function(a){d[e]=a;--c||h(b,d)},function(a){m(b,a)})});0===c&&h(b,d);return b};q.race=function(a){var b=c();r(a,function(a){t(a).then(b.resolve,b.reject)});return b.promise};return q}function hg(){this.$get=["$window","$timeout",function(a,b){var d=a.requestAnimationFrame||a.webkitRequestAnimationFrame,c=a.cancelAnimationFrame||a.webkitCancelAnimationFrame||
|
||||
a.webkitCancelRequestAnimationFrame,e=!!d,f=e?function(a){var b=d(a);return function(){c(b)}}:function(a){var c=b(a,16.66,!1);return function(){b.cancel(c)}};f.supported=e;return f}]}function Wf(){function a(a){function b(){this.$$watchers=this.$$nextSibling=this.$$childHead=this.$$childTail=null;this.$$listeners={};this.$$listenerCount={};this.$$watchersCount=0;this.$id=++pb;this.$$ChildScope=null;this.$$suspended=!1}b.prototype=a;return b}var b=10,d=F("$rootScope"),c=null,e=null;this.digestTtl=
|
||||
function(a){arguments.length&&(b=a);return b};this.$get=["$exceptionHandler","$parse","$browser",function(f,g,k){function h(a){a.currentScope.$$destroyed=!0}function l(a){9===Ca&&(a.$$childHead&&l(a.$$childHead),a.$$nextSibling&&l(a.$$nextSibling));a.$parent=a.$$nextSibling=a.$$prevSibling=a.$$childHead=a.$$childTail=a.$root=a.$$watchers=null}function m(){this.$id=++pb;this.$$phase=this.$parent=this.$$watchers=this.$$nextSibling=this.$$prevSibling=this.$$childHead=this.$$childTail=null;this.$root=
|
||||
this;this.$$suspended=this.$$destroyed=!1;this.$$listeners={};this.$$listenerCount={};this.$$watchersCount=0;this.$$isolateBindings=null}function p(a){if(v.$$phase)throw d("inprog",v.$$phase);v.$$phase=a}function n(a,b){do a.$$watchersCount+=b;while(a=a.$parent)}function s(a,b,c){do a.$$listenerCount[c]-=b,0===a.$$listenerCount[c]&&delete a.$$listenerCount[c];while(a=a.$parent)}function G(){}function t(){for(;y.length;)try{y.shift()()}catch(a){f(a)}e=null}function q(){null===e&&(e=k.defer(function(){v.$apply(t)},
|
||||
null,"$applyAsync"))}m.prototype={constructor:m,$new:function(b,c){var d;c=c||this;b?(d=new m,d.$root=this.$root):(this.$$ChildScope||(this.$$ChildScope=a(this)),d=new this.$$ChildScope);d.$parent=c;d.$$prevSibling=c.$$childTail;c.$$childHead?(c.$$childTail.$$nextSibling=d,c.$$childTail=d):c.$$childHead=c.$$childTail=d;(b||c!==this)&&d.$on("$destroy",h);return d},$watch:function(a,b,d,e){var f=g(a);b=B(b)?b:E;if(f.$$watchDelegate)return f.$$watchDelegate(this,b,d,f,a);var h=this,k=h.$$watchers,l=
|
||||
{fn:b,last:G,get:f,exp:e||a,eq:!!d};c=null;k||(k=h.$$watchers=[],k.$$digestWatchIndex=-1);k.unshift(l);k.$$digestWatchIndex++;n(this,1);return function(){var a=cb(k,l);0<=a&&(n(h,-1),a<k.$$digestWatchIndex&&k.$$digestWatchIndex--);c=null}},$watchGroup:function(a,b){function c(){h=!1;try{k?(k=!1,b(e,e,g)):b(e,d,g)}finally{for(var f=0;f<a.length;f++)d[f]=e[f]}}var d=Array(a.length),e=Array(a.length),f=[],g=this,h=!1,k=!0;if(!a.length){var l=!0;g.$evalAsync(function(){l&&b(e,e,g)});return function(){l=
|
||||
!1}}if(1===a.length)return this.$watch(a[0],function(a,c,f){e[0]=a;d[0]=c;b(e,a===c?e:d,f)});r(a,function(a,b){var d=g.$watch(a,function(a){e[b]=a;h||(h=!0,g.$evalAsync(c))});f.push(d)});return function(){for(;f.length;)f.shift()()}},$watchCollection:function(a,b){function c(a){e=a;var b,d,g,h;if(!z(e)){if(D(e))if(ya(e))for(f!==n&&(f=n,t=f.length=0,l++),a=e.length,t!==a&&(l++,f.length=t=a),b=0;b<a;b++)h=f[b],g=e[b],d=h!==h&&g!==g,d||h===g||(l++,f[b]=g);else{f!==p&&(f=p={},t=0,l++);a=0;for(b in e)ta.call(e,
|
||||
b)&&(a++,g=e[b],h=f[b],b in f?(d=h!==h&&g!==g,d||h===g||(l++,f[b]=g)):(t++,f[b]=g,l++));if(t>a)for(b in l++,f)ta.call(e,b)||(t--,delete f[b])}else f!==e&&(f=e,l++);return l}}c.$$pure=g(a).literal;c.$stateful=!c.$$pure;var d=this,e,f,h,k=1<b.length,l=0,m=g(a,c),n=[],p={},s=!0,t=0;return this.$watch(m,function(){s?(s=!1,b(e,e,d)):b(e,h,d);if(k)if(D(e))if(ya(e)){h=Array(e.length);for(var a=0;a<e.length;a++)h[a]=e[a]}else for(a in h={},e)ta.call(e,a)&&(h[a]=e[a]);else h=e})},$digest:function(){var a,
|
||||
g,h,l,m,n,s,r=b,q,y=w.length?v:this,N=[],z,A;p("$digest");k.$$checkUrlChange();this===v&&null!==e&&(k.defer.cancel(e),t());c=null;do{s=!1;q=y;for(n=0;n<w.length;n++){try{A=w[n],l=A.fn,l(A.scope,A.locals)}catch(C){f(C)}c=null}w.length=0;a:do{if(n=!q.$$suspended&&q.$$watchers)for(n.$$digestWatchIndex=n.length;n.$$digestWatchIndex--;)try{if(a=n[n.$$digestWatchIndex])if(m=a.get,(g=m(q))!==(h=a.last)&&!(a.eq?va(g,h):X(g)&&X(h)))s=!0,c=a,a.last=a.eq?Ia(g,null):g,l=a.fn,l(g,h===G?g:h,q),5>r&&(z=4-r,N[z]||
|
||||
(N[z]=[]),N[z].push({msg:B(a.exp)?"fn: "+(a.exp.name||a.exp.toString()):a.exp,newVal:g,oldVal:h}));else if(a===c){s=!1;break a}}catch(E){f(E)}if(!(n=!q.$$suspended&&q.$$watchersCount&&q.$$childHead||q!==y&&q.$$nextSibling))for(;q!==y&&!(n=q.$$nextSibling);)q=q.$parent}while(q=n);if((s||w.length)&&!r--)throw v.$$phase=null,d("infdig",b,N);}while(s||w.length);for(v.$$phase=null;J<x.length;)try{x[J++]()}catch(D){f(D)}x.length=J=0;k.$$checkUrlChange()},$suspend:function(){this.$$suspended=!0},$isSuspended:function(){return this.$$suspended},
|
||||
$resume:function(){this.$$suspended=!1},$destroy:function(){if(!this.$$destroyed){var a=this.$parent;this.$broadcast("$destroy");this.$$destroyed=!0;this===v&&k.$$applicationDestroyed();n(this,-this.$$watchersCount);for(var b in this.$$listenerCount)s(this,this.$$listenerCount[b],b);a&&a.$$childHead===this&&(a.$$childHead=this.$$nextSibling);a&&a.$$childTail===this&&(a.$$childTail=this.$$prevSibling);this.$$prevSibling&&(this.$$prevSibling.$$nextSibling=this.$$nextSibling);this.$$nextSibling&&(this.$$nextSibling.$$prevSibling=
|
||||
this.$$prevSibling);this.$destroy=this.$digest=this.$apply=this.$evalAsync=this.$applyAsync=E;this.$on=this.$watch=this.$watchGroup=function(){return E};this.$$listeners={};this.$$nextSibling=null;l(this)}},$eval:function(a,b){return g(a)(this,b)},$evalAsync:function(a,b){v.$$phase||w.length||k.defer(function(){w.length&&v.$digest()},null,"$evalAsync");w.push({scope:this,fn:g(a),locals:b})},$$postDigest:function(a){x.push(a)},$apply:function(a){try{p("$apply");try{return this.$eval(a)}finally{v.$$phase=
|
||||
null}}catch(b){f(b)}finally{try{v.$digest()}catch(c){throw f(c),c;}}},$applyAsync:function(a){function b(){c.$eval(a)}var c=this;a&&y.push(b);a=g(a);q()},$on:function(a,b){var c=this.$$listeners[a];c||(this.$$listeners[a]=c=[]);c.push(b);var d=this;do d.$$listenerCount[a]||(d.$$listenerCount[a]=0),d.$$listenerCount[a]++;while(d=d.$parent);var e=this;return function(){var d=c.indexOf(b);-1!==d&&(delete c[d],s(e,1,a))}},$emit:function(a,b){var c=[],d,e=this,g=!1,h={name:a,targetScope:e,stopPropagation:function(){g=
|
||||
!0},preventDefault:function(){h.defaultPrevented=!0},defaultPrevented:!1},k=db([h],arguments,1),l,m;do{d=e.$$listeners[a]||c;h.currentScope=e;l=0;for(m=d.length;l<m;l++)if(d[l])try{d[l].apply(null,k)}catch(n){f(n)}else d.splice(l,1),l--,m--;if(g)break;e=e.$parent}while(e);h.currentScope=null;return h},$broadcast:function(a,b){var c=this,d=this,e={name:a,targetScope:this,preventDefault:function(){e.defaultPrevented=!0},defaultPrevented:!1};if(!this.$$listenerCount[a])return e;for(var g=db([e],arguments,
|
||||
1),h,k;c=d;){e.currentScope=c;d=c.$$listeners[a]||[];h=0;for(k=d.length;h<k;h++)if(d[h])try{d[h].apply(null,g)}catch(l){f(l)}else d.splice(h,1),h--,k--;if(!(d=c.$$listenerCount[a]&&c.$$childHead||c!==this&&c.$$nextSibling))for(;c!==this&&!(d=c.$$nextSibling);)c=c.$parent}e.currentScope=null;return e}};var v=new m,w=v.$$asyncQueue=[],x=v.$$postDigestQueue=[],y=v.$$applyAsyncQueue=[],J=0;return v}]}function Le(){var a=/^\s*(https?|s?ftp|mailto|tel|file):/,b=/^\s*((https?|ftp|file|blob):|data:image\/)/;
|
||||
this.aHrefSanitizationWhitelist=function(b){return w(b)?(a=b,this):a};this.imgSrcSanitizationWhitelist=function(a){return w(a)?(b=a,this):b};this.$get=function(){return function(d,c){var e=c?b:a,f=ga(d&&d.trim()).href;return""===f||f.match(e)?d:"unsafe:"+f}}}function Sg(a){if("self"===a)return a;if(A(a)){if(-1<a.indexOf("***"))throw Ea("iwcard",a);a=Md(a).replace(/\\\*\\\*/g,".*").replace(/\\\*/g,"[^:/.?&;]*");return new RegExp("^"+a+"$")}if(ab(a))return new RegExp("^"+a.source+"$");throw Ea("imatcher");
|
||||
}function Nd(a){var b=[];w(a)&&r(a,function(a){b.push(Sg(a))});return b}function $f(){this.SCE_CONTEXTS=V;var a=["self"],b=[];this.resourceUrlWhitelist=function(b){arguments.length&&(a=Nd(b));return a};this.resourceUrlBlacklist=function(a){arguments.length&&(b=Nd(a));return b};this.$get=["$injector","$$sanitizeUri",function(d,c){function e(a,b){var c;"self"===a?(c=Bc(b,Od))||(C.document.baseURI?c=C.document.baseURI:(Na||(Na=C.document.createElement("a"),Na.href=".",Na=Na.cloneNode(!1)),c=Na.href),
|
||||
c=Bc(b,c)):c=!!a.exec(b.href);return c}function f(a){var b=function(a){this.$$unwrapTrustedValue=function(){return a}};a&&(b.prototype=new a);b.prototype.valueOf=function(){return this.$$unwrapTrustedValue()};b.prototype.toString=function(){return this.$$unwrapTrustedValue().toString()};return b}var g=function(a){throw Ea("unsafe");};d.has("$sanitize")&&(g=d.get("$sanitize"));var k=f(),h={};h[V.HTML]=f(k);h[V.CSS]=f(k);h[V.MEDIA_URL]=f(k);h[V.URL]=f(h[V.MEDIA_URL]);h[V.JS]=f(k);h[V.RESOURCE_URL]=
|
||||
f(h[V.URL]);return{trustAs:function(a,b){var c=h.hasOwnProperty(a)?h[a]:null;if(!c)throw Ea("icontext",a,b);if(null===b||z(b)||""===b)return b;if("string"!==typeof b)throw Ea("itype",a);return new c(b)},getTrusted:function(d,f){if(null===f||z(f)||""===f)return f;var k=h.hasOwnProperty(d)?h[d]:null;if(k&&f instanceof k)return f.$$unwrapTrustedValue();B(f.$$unwrapTrustedValue)&&(f=f.$$unwrapTrustedValue());if(d===V.MEDIA_URL||d===V.URL)return c(f.toString(),d===V.MEDIA_URL);if(d===V.RESOURCE_URL){var k=
|
||||
ga(f.toString()),n,s,r=!1;n=0;for(s=a.length;n<s;n++)if(e(a[n],k)){r=!0;break}if(r)for(n=0,s=b.length;n<s;n++)if(e(b[n],k)){r=!1;break}if(r)return f;throw Ea("insecurl",f.toString());}if(d===V.HTML)return g(f);throw Ea("unsafe");},valueOf:function(a){return a instanceof k?a.$$unwrapTrustedValue():a}}}]}function Zf(){var a=!0;this.enabled=function(b){arguments.length&&(a=!!b);return a};this.$get=["$parse","$sceDelegate",function(b,d){if(a&&8>Ca)throw Ea("iequirks");var c=ja(V);c.isEnabled=function(){return a};
|
||||
c.trustAs=d.trustAs;c.getTrusted=d.getTrusted;c.valueOf=d.valueOf;a||(c.trustAs=c.getTrusted=function(a,b){return b},c.valueOf=Ta);c.parseAs=function(a,d){var e=b(d);return e.literal&&e.constant?e:b(d,function(b){return c.getTrusted(a,b)})};var e=c.parseAs,f=c.getTrusted,g=c.trustAs;r(V,function(a,b){var d=K(b);c[("parse_as_"+d).replace(Cc,wb)]=function(b){return e(a,b)};c[("get_trusted_"+d).replace(Cc,wb)]=function(b){return f(a,b)};c[("trust_as_"+d).replace(Cc,wb)]=function(b){return g(a,b)}});
|
||||
return c}]}function ag(){this.$get=["$window","$document",function(a,b){var d={},c=!((!a.nw||!a.nw.process)&&a.chrome&&(a.chrome.app&&a.chrome.app.runtime||!a.chrome.app&&a.chrome.runtime&&a.chrome.runtime.id))&&a.history&&a.history.pushState,e=fa((/android (\d+)/.exec(K((a.navigator||{}).userAgent))||[])[1]),f=/Boxee/i.test((a.navigator||{}).userAgent),g=b[0]||{},k=g.body&&g.body.style,h=!1,l=!1;k&&(h=!!("transition"in k||"webkitTransition"in k),l=!!("animation"in k||"webkitAnimation"in k));return{history:!(!c||
|
||||
4>e||f),hasEvent:function(a){if("input"===a&&Ca)return!1;if(z(d[a])){var b=g.createElement("div");d[a]="on"+a in b}return d[a]},csp:Aa(),transitions:h,animations:l,android:e}}]}function bg(){this.$get=ia(function(a){return new Tg(a)})}function Tg(a){function b(){var a=e.pop();return a&&a.cb}function d(a){for(var b=e.length-1;0<=b;--b){var c=e[b];if(c.type===a)return e.splice(b,1),c.cb}}var c={},e=[],f=this.ALL_TASKS_TYPE="$$all$$",g=this.DEFAULT_TASK_TYPE="$$default$$";this.completeTask=function(e,
|
||||
h){h=h||g;try{e()}finally{var l;l=h||g;c[l]&&(c[l]--,c[f]--);l=c[h];var m=c[f];if(!m||!l)for(l=m?d:b;m=l(h);)try{m()}catch(p){a.error(p)}}};this.incTaskCount=function(a){a=a||g;c[a]=(c[a]||0)+1;c[f]=(c[f]||0)+1};this.notifyWhenNoPendingTasks=function(a,b){b=b||f;c[b]?e.push({type:b,cb:a}):a()}}function dg(){var a;this.httpOptions=function(b){return b?(a=b,this):a};this.$get=["$exceptionHandler","$templateCache","$http","$q","$sce",function(b,d,c,e,f){function g(k,h){g.totalPendingRequests++;if(!A(k)||
|
||||
z(d.get(k)))k=f.getTrustedResourceUrl(k);var l=c.defaults&&c.defaults.transformResponse;H(l)?l=l.filter(function(a){return a!==vc}):l===vc&&(l=null);return c.get(k,S({cache:d,transformResponse:l},a)).finally(function(){g.totalPendingRequests--}).then(function(a){return d.put(k,a.data)},function(a){h||(a=Ug("tpload",k,a.status,a.statusText),b(a));return e.reject(a)})}g.totalPendingRequests=0;return g}]}function eg(){this.$get=["$rootScope","$browser","$location",function(a,b,d){return{findBindings:function(a,
|
||||
b,d){a=a.getElementsByClassName("ng-binding");var g=[];r(a,function(a){var c=ca.element(a).data("$binding");c&&r(c,function(c){d?(new RegExp("(^|\\s)"+Md(b)+"(\\s|\\||$)")).test(c)&&g.push(a):-1!==c.indexOf(b)&&g.push(a)})});return g},findModels:function(a,b,d){for(var g=["ng-","data-ng-","ng\\:"],k=0;k<g.length;++k){var h=a.querySelectorAll("["+g[k]+"model"+(d?"=":"*=")+'"'+b+'"]');if(h.length)return h}},getLocation:function(){return d.url()},setLocation:function(b){b!==d.url()&&(d.url(b),a.$digest())},
|
||||
whenStable:function(a){b.notifyWhenNoOutstandingRequests(a)}}}]}function fg(){this.$get=["$rootScope","$browser","$q","$$q","$exceptionHandler",function(a,b,d,c,e){function f(f,h,l){B(f)||(l=h,h=f,f=E);var m=Ha.call(arguments,3),p=w(l)&&!l,n=(p?c:d).defer(),s=n.promise,r;r=b.defer(function(){try{n.resolve(f.apply(null,m))}catch(b){n.reject(b),e(b)}finally{delete g[s.$$timeoutId]}p||a.$apply()},h,"$timeout");s.$$timeoutId=r;g[r]=n;return s}var g={};f.cancel=function(a){if(!a)return!1;if(!a.hasOwnProperty("$$timeoutId"))throw Vg("badprom");
|
||||
if(!g.hasOwnProperty(a.$$timeoutId))return!1;a=a.$$timeoutId;var c=g[a],d=c.promise;d.$$state&&(d.$$state.pur=!0);c.reject("canceled");delete g[a];return b.defer.cancel(a)};return f}]}function ga(a){if(!A(a))return a;Ca&&(aa.setAttribute("href",a),a=aa.href);aa.setAttribute("href",a);a=aa.hostname;!Wg&&-1<a.indexOf(":")&&(a="["+a+"]");return{href:aa.href,protocol:aa.protocol?aa.protocol.replace(/:$/,""):"",host:aa.host,search:aa.search?aa.search.replace(/^\?/,""):"",hash:aa.hash?aa.hash.replace(/^#/,
|
||||
""):"",hostname:a,port:aa.port,pathname:"/"===aa.pathname.charAt(0)?aa.pathname:"/"+aa.pathname}}function Jg(a){var b=[Od].concat(a.map(ga));return function(a){a=ga(a);return b.some(Bc.bind(null,a))}}function Bc(a,b){a=ga(a);b=ga(b);return a.protocol===b.protocol&&a.host===b.host}function gg(){this.$get=ia(C)}function Pd(a){function b(a){try{return decodeURIComponent(a)}catch(b){return a}}var d=a[0]||{},c={},e="";return function(){var a,g,k,h,l;try{a=d.cookie||""}catch(m){a=""}if(a!==e)for(e=a,a=
|
||||
e.split("; "),c={},k=0;k<a.length;k++)g=a[k],h=g.indexOf("="),0<h&&(l=b(g.substring(0,h)),z(c[l])&&(c[l]=b(g.substring(h+1))));return c}}function kg(){this.$get=Pd}function dd(a){function b(d,c){if(D(d)){var e={};r(d,function(a,c){e[c]=b(c,a)});return e}return a.factory(d+"Filter",c)}this.register=b;this.$get=["$injector",function(a){return function(b){return a.get(b+"Filter")}}];b("currency",Qd);b("date",Rd);b("filter",Xg);b("json",Yg);b("limitTo",Zg);b("lowercase",$g);b("number",Sd);b("orderBy",
|
||||
Td);b("uppercase",ah)}function Xg(){return function(a,b,d,c){if(!ya(a)){if(null==a)return a;throw F("filter")("notarray",a);}c=c||"$";var e;switch(Dc(b)){case "function":break;case "boolean":case "null":case "number":case "string":e=!0;case "object":b=bh(b,d,c,e);break;default:return a}return Array.prototype.filter.call(a,b)}}function bh(a,b,d,c){var e=D(a)&&d in a;!0===b?b=va:B(b)||(b=function(a,b){if(z(a))return!1;if(null===a||null===b)return a===b;if(D(b)||D(a)&&!bc(a))return!1;a=K(""+a);b=K(""+
|
||||
b);return-1!==a.indexOf(b)});return function(f){return e&&!D(f)?Fa(f,a[d],b,d,!1):Fa(f,a,b,d,c)}}function Fa(a,b,d,c,e,f){var g=Dc(a),k=Dc(b);if("string"===k&&"!"===b.charAt(0))return!Fa(a,b.substring(1),d,c,e);if(H(a))return a.some(function(a){return Fa(a,b,d,c,e)});switch(g){case "object":var h;if(e){for(h in a)if(h.charAt&&"$"!==h.charAt(0)&&Fa(a[h],b,d,c,!0))return!0;return f?!1:Fa(a,b,d,c,!1)}if("object"===k){for(h in b)if(f=b[h],!B(f)&&!z(f)&&(g=h===c,!Fa(g?a:a[h],f,d,c,g,g)))return!1;return!0}return d(a,
|
||||
b);case "function":return!1;default:return d(a,b)}}function Dc(a){return null===a?"null":typeof a}function Qd(a){var b=a.NUMBER_FORMATS;return function(a,c,e){z(c)&&(c=b.CURRENCY_SYM);z(e)&&(e=b.PATTERNS[1].maxFrac);var f=c?/\u00A4/g:/\s*\u00A4\s*/g;return null==a?a:Ud(a,b.PATTERNS[1],b.GROUP_SEP,b.DECIMAL_SEP,e).replace(f,c)}}function Sd(a){var b=a.NUMBER_FORMATS;return function(a,c){return null==a?a:Ud(a,b.PATTERNS[0],b.GROUP_SEP,b.DECIMAL_SEP,c)}}function ch(a){var b=0,d,c,e,f,g;-1<(c=a.indexOf(Vd))&&
|
||||
(a=a.replace(Vd,""));0<(e=a.search(/e/i))?(0>c&&(c=e),c+=+a.slice(e+1),a=a.substring(0,e)):0>c&&(c=a.length);for(e=0;a.charAt(e)===Ec;e++);if(e===(g=a.length))d=[0],c=1;else{for(g--;a.charAt(g)===Ec;)g--;c-=e;d=[];for(f=0;e<=g;e++,f++)d[f]=+a.charAt(e)}c>Wd&&(d=d.splice(0,Wd-1),b=c-1,c=1);return{d:d,e:b,i:c}}function dh(a,b,d,c){var e=a.d,f=e.length-a.i;b=z(b)?Math.min(Math.max(d,f),c):+b;d=b+a.i;c=e[d];if(0<d){e.splice(Math.max(a.i,d));for(var g=d;g<e.length;g++)e[g]=0}else for(f=Math.max(0,f),a.i=
|
||||
1,e.length=Math.max(1,d=b+1),e[0]=0,g=1;g<d;g++)e[g]=0;if(5<=c)if(0>d-1){for(c=0;c>d;c--)e.unshift(0),a.i++;e.unshift(1);a.i++}else e[d-1]++;for(;f<Math.max(0,b);f++)e.push(0);if(b=e.reduceRight(function(a,b,c,d){b+=a;d[c]=b%10;return Math.floor(b/10)},0))e.unshift(b),a.i++}function Ud(a,b,d,c,e){if(!A(a)&&!W(a)||isNaN(a))return"";var f=!isFinite(a),g=!1,k=Math.abs(a)+"",h="";if(f)h="\u221e";else{g=ch(k);dh(g,e,b.minFrac,b.maxFrac);h=g.d;k=g.i;e=g.e;f=[];for(g=h.reduce(function(a,b){return a&&!b},
|
||||
!0);0>k;)h.unshift(0),k++;0<k?f=h.splice(k,h.length):(f=h,h=[0]);k=[];for(h.length>=b.lgSize&&k.unshift(h.splice(-b.lgSize,h.length).join(""));h.length>b.gSize;)k.unshift(h.splice(-b.gSize,h.length).join(""));h.length&&k.unshift(h.join(""));h=k.join(d);f.length&&(h+=c+f.join(""));e&&(h+="e+"+e)}return 0>a&&!g?b.negPre+h+b.negSuf:b.posPre+h+b.posSuf}function Ob(a,b,d,c){var e="";if(0>a||c&&0>=a)c?a=-a+1:(a=-a,e="-");for(a=""+a;a.length<b;)a=Ec+a;d&&(a=a.substr(a.length-b));return e+a}function ea(a,
|
||||
b,d,c,e){d=d||0;return function(f){f=f["get"+a]();if(0<d||f>-d)f+=d;0===f&&-12===d&&(f=12);return Ob(f,b,c,e)}}function kb(a,b,d){return function(c,e){var f=c["get"+a](),g=ub((d?"STANDALONE":"")+(b?"SHORT":"")+a);return e[g][f]}}function Xd(a){var b=(new Date(a,0,1)).getDay();return new Date(a,0,(4>=b?5:12)-b)}function Yd(a){return function(b){var d=Xd(b.getFullYear());b=+new Date(b.getFullYear(),b.getMonth(),b.getDate()+(4-b.getDay()))-+d;b=1+Math.round(b/6048E5);return Ob(b,a)}}function Fc(a,b){return 0>=
|
||||
a.getFullYear()?b.ERAS[0]:b.ERAS[1]}function Rd(a){function b(a){var b;if(b=a.match(d)){a=new Date(0);var f=0,g=0,k=b[8]?a.setUTCFullYear:a.setFullYear,h=b[8]?a.setUTCHours:a.setHours;b[9]&&(f=fa(b[9]+b[10]),g=fa(b[9]+b[11]));k.call(a,fa(b[1]),fa(b[2])-1,fa(b[3]));f=fa(b[4]||0)-f;g=fa(b[5]||0)-g;k=fa(b[6]||0);b=Math.round(1E3*parseFloat("0."+(b[7]||0)));h.call(a,f,g,k,b)}return a}var d=/^(\d{4})-?(\d\d)-?(\d\d)(?:T(\d\d)(?::?(\d\d)(?::?(\d\d)(?:\.(\d+))?)?)?(Z|([+-])(\d\d):?(\d\d))?)?$/;return function(c,
|
||||
d,f){var g="",k=[],h,l;d=d||"mediumDate";d=a.DATETIME_FORMATS[d]||d;A(c)&&(c=eh.test(c)?fa(c):b(c));W(c)&&(c=new Date(c));if(!ha(c)||!isFinite(c.getTime()))return c;for(;d;)(l=fh.exec(d))?(k=db(k,l,1),d=k.pop()):(k.push(d),d=null);var m=c.getTimezoneOffset();f&&(m=ec(f,m),c=fc(c,f,!0));r(k,function(b){h=gh[b];g+=h?h(c,a.DATETIME_FORMATS,m):"''"===b?"'":b.replace(/(^'|'$)/g,"").replace(/''/g,"'")});return g}}function Yg(){return function(a,b){z(b)&&(b=2);return eb(a,b)}}function Zg(){return function(a,
|
||||
b,d){b=Infinity===Math.abs(Number(b))?Number(b):fa(b);if(X(b))return a;W(a)&&(a=a.toString());if(!ya(a))return a;d=!d||isNaN(d)?0:fa(d);d=0>d?Math.max(0,a.length+d):d;return 0<=b?Gc(a,d,d+b):0===d?Gc(a,b,a.length):Gc(a,Math.max(0,d+b),d)}}function Gc(a,b,d){return A(a)?a.slice(b,d):Ha.call(a,b,d)}function Td(a){function b(b){return b.map(function(b){var c=1,d=Ta;if(B(b))d=b;else if(A(b)){if("+"===b.charAt(0)||"-"===b.charAt(0))c="-"===b.charAt(0)?-1:1,b=b.substring(1);if(""!==b&&(d=a(b),d.constant))var e=
|
||||
d(),d=function(a){return a[e]}}return{get:d,descending:c}})}function d(a){switch(typeof a){case "number":case "boolean":case "string":return!0;default:return!1}}function c(a,b){var c=0,d=a.type,h=b.type;if(d===h){var h=a.value,l=b.value;"string"===d?(h=h.toLowerCase(),l=l.toLowerCase()):"object"===d&&(D(h)&&(h=a.index),D(l)&&(l=b.index));h!==l&&(c=h<l?-1:1)}else c="undefined"===d?1:"undefined"===h?-1:"null"===d?1:"null"===h?-1:d<h?-1:1;return c}return function(a,f,g,k){if(null==a)return a;if(!ya(a))throw F("orderBy")("notarray",
|
||||
a);H(f)||(f=[f]);0===f.length&&(f=["+"]);var h=b(f),l=g?-1:1,m=B(k)?k:c;a=Array.prototype.map.call(a,function(a,b){return{value:a,tieBreaker:{value:b,type:"number",index:b},predicateValues:h.map(function(c){var e=c.get(a);c=typeof e;if(null===e)c="null";else if("object"===c)a:{if(B(e.valueOf)&&(e=e.valueOf(),d(e)))break a;bc(e)&&(e=e.toString(),d(e))}return{value:e,type:c,index:b}})}});a.sort(function(a,b){for(var d=0,e=h.length;d<e;d++){var f=m(a.predicateValues[d],b.predicateValues[d]);if(f)return f*
|
||||
h[d].descending*l}return(m(a.tieBreaker,b.tieBreaker)||c(a.tieBreaker,b.tieBreaker))*l});return a=a.map(function(a){return a.value})}}function Ra(a){B(a)&&(a={link:a});a.restrict=a.restrict||"AC";return ia(a)}function Pb(a,b,d,c,e){this.$$controls=[];this.$error={};this.$$success={};this.$pending=void 0;this.$name=e(b.name||b.ngForm||"")(d);this.$dirty=!1;this.$valid=this.$pristine=!0;this.$submitted=this.$invalid=!1;this.$$parentForm=lb;this.$$element=a;this.$$animate=c;Zd(this)}function Zd(a){a.$$classCache=
|
||||
{};a.$$classCache[$d]=!(a.$$classCache[mb]=a.$$element.hasClass(mb))}function ae(a){function b(a,b,c){c&&!a.$$classCache[b]?(a.$$animate.addClass(a.$$element,b),a.$$classCache[b]=!0):!c&&a.$$classCache[b]&&(a.$$animate.removeClass(a.$$element,b),a.$$classCache[b]=!1)}function d(a,c,d){c=c?"-"+Vc(c,"-"):"";b(a,mb+c,!0===d);b(a,$d+c,!1===d)}var c=a.set,e=a.unset;a.clazz.prototype.$setValidity=function(a,g,k){z(g)?(this.$pending||(this.$pending={}),c(this.$pending,a,k)):(this.$pending&&e(this.$pending,
|
||||
a,k),be(this.$pending)&&(this.$pending=void 0));Ga(g)?g?(e(this.$error,a,k),c(this.$$success,a,k)):(c(this.$error,a,k),e(this.$$success,a,k)):(e(this.$error,a,k),e(this.$$success,a,k));this.$pending?(b(this,"ng-pending",!0),this.$valid=this.$invalid=void 0,d(this,"",null)):(b(this,"ng-pending",!1),this.$valid=be(this.$error),this.$invalid=!this.$valid,d(this,"",this.$valid));g=this.$pending&&this.$pending[a]?void 0:this.$error[a]?!1:this.$$success[a]?!0:null;d(this,a,g);this.$$parentForm.$setValidity(a,
|
||||
g,this)}}function be(a){if(a)for(var b in a)if(a.hasOwnProperty(b))return!1;return!0}function Hc(a){a.$formatters.push(function(b){return a.$isEmpty(b)?b:b.toString()})}function Sa(a,b,d,c,e,f){var g=K(b[0].type);if(!e.android){var k=!1;b.on("compositionstart",function(){k=!0});b.on("compositionupdate",function(a){if(z(a.data)||""===a.data)k=!1});b.on("compositionend",function(){k=!1;l()})}var h,l=function(a){h&&(f.defer.cancel(h),h=null);if(!k){var e=b.val();a=a&&a.type;"password"===g||d.ngTrim&&
|
||||
"false"===d.ngTrim||(e=U(e));(c.$viewValue!==e||""===e&&c.$$hasNativeValidators)&&c.$setViewValue(e,a)}};if(e.hasEvent("input"))b.on("input",l);else{var m=function(a,b,c){h||(h=f.defer(function(){h=null;b&&b.value===c||l(a)}))};b.on("keydown",function(a){var b=a.keyCode;91===b||15<b&&19>b||37<=b&&40>=b||m(a,this,this.value)});if(e.hasEvent("paste"))b.on("paste cut drop",m)}b.on("change",l);if(ce[g]&&c.$$hasNativeValidators&&g===d.type)b.on("keydown wheel mousedown",function(a){if(!h){var b=this.validity,
|
||||
c=b.badInput,d=b.typeMismatch;h=f.defer(function(){h=null;b.badInput===c&&b.typeMismatch===d||l(a)})}});c.$render=function(){var a=c.$isEmpty(c.$viewValue)?"":c.$viewValue;b.val()!==a&&b.val(a)}}function Qb(a,b){return function(d,c){var e,f;if(ha(d))return d;if(A(d)){'"'===d.charAt(0)&&'"'===d.charAt(d.length-1)&&(d=d.substring(1,d.length-1));if(hh.test(d))return new Date(d);a.lastIndex=0;if(e=a.exec(d))return e.shift(),f=c?{yyyy:c.getFullYear(),MM:c.getMonth()+1,dd:c.getDate(),HH:c.getHours(),mm:c.getMinutes(),
|
||||
ss:c.getSeconds(),sss:c.getMilliseconds()/1E3}:{yyyy:1970,MM:1,dd:1,HH:0,mm:0,ss:0,sss:0},r(e,function(a,c){c<b.length&&(f[b[c]]=+a)}),e=new Date(f.yyyy,f.MM-1,f.dd,f.HH,f.mm,f.ss||0,1E3*f.sss||0),100>f.yyyy&&e.setFullYear(f.yyyy),e}return NaN}}function nb(a,b,d,c){return function(e,f,g,k,h,l,m,p){function n(a){return a&&!(a.getTime&&a.getTime()!==a.getTime())}function s(a){return w(a)&&!ha(a)?r(a)||void 0:a}function r(a,b){var c=k.$options.getOption("timezone");v&&v!==c&&(b=Sc(b,ec(v)));var e=d(a,
|
||||
b);!isNaN(e)&&c&&(e=fc(e,c));return e}Ic(e,f,g,k,a);Sa(e,f,g,k,h,l);var t="time"===a||"datetimelocal"===a,q,v;k.$parsers.push(function(c){if(k.$isEmpty(c))return null;if(b.test(c))return r(c,q);k.$$parserName=a});k.$formatters.push(function(a){if(a&&!ha(a))throw ob("datefmt",a);if(n(a)){q=a;var b=k.$options.getOption("timezone");b&&(v=b,q=fc(q,b,!0));var d=c;t&&A(k.$options.getOption("timeSecondsFormat"))&&(d=c.replace("ss.sss",k.$options.getOption("timeSecondsFormat")).replace(/:$/,""));a=m("date")(a,
|
||||
d,b);t&&k.$options.getOption("timeStripZeroSeconds")&&(a=a.replace(/(?::00)?(?:\.000)?$/,""));return a}v=q=null;return""});if(w(g.min)||g.ngMin){var x=g.min||p(g.ngMin)(e),B=s(x);k.$validators.min=function(a){return!n(a)||z(B)||d(a)>=B};g.$observe("min",function(a){a!==x&&(B=s(a),x=a,k.$validate())})}if(w(g.max)||g.ngMax){var y=g.max||p(g.ngMax)(e),J=s(y);k.$validators.max=function(a){return!n(a)||z(J)||d(a)<=J};g.$observe("max",function(a){a!==y&&(J=s(a),y=a,k.$validate())})}}}function Ic(a,b,d,
|
||||
c,e){(c.$$hasNativeValidators=D(b[0].validity))&&c.$parsers.push(function(a){var d=b.prop("validity")||{};if(d.badInput||d.typeMismatch)c.$$parserName=e;else return a})}function de(a){a.$parsers.push(function(b){if(a.$isEmpty(b))return null;if(ih.test(b))return parseFloat(b);a.$$parserName="number"});a.$formatters.push(function(b){if(!a.$isEmpty(b)){if(!W(b))throw ob("numfmt",b);b=b.toString()}return b})}function na(a){w(a)&&!W(a)&&(a=parseFloat(a));return X(a)?void 0:a}function Jc(a){var b=a.toString(),
|
||||
d=b.indexOf(".");return-1===d?-1<a&&1>a&&(a=/e-(\d+)$/.exec(b))?Number(a[1]):0:b.length-d-1}function ee(a,b,d){a=Number(a);var c=(a|0)!==a,e=(b|0)!==b,f=(d|0)!==d;if(c||e||f){var g=c?Jc(a):0,k=e?Jc(b):0,h=f?Jc(d):0,g=Math.max(g,k,h),g=Math.pow(10,g);a*=g;b*=g;d*=g;c&&(a=Math.round(a));e&&(b=Math.round(b));f&&(d=Math.round(d))}return 0===(a-b)%d}function fe(a,b,d,c,e){if(w(c)){a=a(c);if(!a.constant)throw ob("constexpr",d,c);return a(b)}return e}function Kc(a,b){function d(a,b){if(!a||!a.length)return[];
|
||||
if(!b||!b.length)return a;var c=[],d=0;a:for(;d<a.length;d++){for(var e=a[d],m=0;m<b.length;m++)if(e===b[m])continue a;c.push(e)}return c}function c(a){if(!a)return a;var b=a;H(a)?b=a.map(c).join(" "):D(a)?b=Object.keys(a).filter(function(b){return a[b]}).join(" "):A(a)||(b=a+"");return b}a="ngClass"+a;var e;return["$parse",function(f){return{restrict:"AC",link:function(g,k,h){function l(a,b){var c=[];r(a,function(a){if(0<b||p[a])p[a]=(p[a]||0)+b,p[a]===+(0<b)&&c.push(a)});return c.join(" ")}function m(a){if(a===
|
||||
b){var c=s,c=l(c&&c.split(" "),1);h.$addClass(c)}else c=s,c=l(c&&c.split(" "),-1),h.$removeClass(c);n=a}var p=k.data("$classCounts"),n=!0,s;p||(p=T(),k.data("$classCounts",p));"ngClass"!==a&&(e||(e=f("$index",function(a){return a&1})),g.$watch(e,m));g.$watch(f(h[a],c),function(a){if(n===b){var c=s&&s.split(" "),e=a&&a.split(" "),f=d(c,e),c=d(e,c),f=l(f,-1),c=l(c,1);h.$addClass(c);h.$removeClass(f)}s=a})}}}]}function qd(a,b,d,c,e,f){return{restrict:"A",compile:function(g,k){var h=a(k[c]);return function(a,
|
||||
c){c.on(e,function(c){var e=function(){h(a,{$event:c})};if(b.$$phase)if(f)a.$evalAsync(e);else try{e()}catch(g){d(g)}else a.$apply(e)})}}}}function Rb(a,b,d,c,e,f,g,k,h){this.$modelValue=this.$viewValue=Number.NaN;this.$$rawModelValue=void 0;this.$validators={};this.$asyncValidators={};this.$parsers=[];this.$formatters=[];this.$viewChangeListeners=[];this.$untouched=!0;this.$touched=!1;this.$pristine=!0;this.$dirty=!1;this.$valid=!0;this.$invalid=!1;this.$error={};this.$$success={};this.$pending=
|
||||
void 0;this.$name=h(d.name||"",!1)(a);this.$$parentForm=lb;this.$options=Sb;this.$$updateEvents="";this.$$updateEventHandler=this.$$updateEventHandler.bind(this);this.$$parsedNgModel=e(d.ngModel);this.$$parsedNgModelAssign=this.$$parsedNgModel.assign;this.$$ngModelGet=this.$$parsedNgModel;this.$$ngModelSet=this.$$parsedNgModelAssign;this.$$pendingDebounce=null;this.$$parserValid=void 0;this.$$parserName="parse";this.$$currentValidationRunId=0;this.$$scope=a;this.$$rootScope=a.$root;this.$$attr=d;
|
||||
this.$$element=c;this.$$animate=f;this.$$timeout=g;this.$$parse=e;this.$$q=k;this.$$exceptionHandler=b;Zd(this);jh(this)}function jh(a){a.$$scope.$watch(function(b){b=a.$$ngModelGet(b);b===a.$modelValue||a.$modelValue!==a.$modelValue&&b!==b||a.$$setModelValue(b);return b})}function Lc(a){this.$$options=a}function ge(a,b){r(b,function(b,c){w(a[c])||(a[c]=b)})}function Oa(a,b){a.prop("selected",b);a.attr("selected",b)}function he(a,b,d){if(a){A(a)&&(a=new RegExp("^"+a+"$"));if(!a.test)throw F("ngPattern")("noregexp",
|
||||
b,a,za(d));return a}}function Tb(a){a=fa(a);return X(a)?-1:a}var Wb={objectMaxDepth:5,urlErrorParamsEnabled:!0},ie=/^\/(.+)\/([a-z]*)$/,ta=Object.prototype.hasOwnProperty,K=function(a){return A(a)?a.toLowerCase():a},ub=function(a){return A(a)?a.toUpperCase():a},Ca,x,rb,Ha=[].slice,Fg=[].splice,kh=[].push,la=Object.prototype.toString,Pc=Object.getPrototypeOf,pa=F("ng"),ca=C.angular||(C.angular={}),kc,pb=0;Ca=C.document.documentMode;var X=Number.isNaN||function(a){return a!==a};E.$inject=[];Ta.$inject=
|
||||
[];var ve=/^\[object (?:Uint8|Uint8Clamped|Uint16|Uint32|Int8|Int16|Int32|Float32|Float64)Array]$/,U=function(a){return A(a)?a.trim():a},Md=function(a){return a.replace(/([-()[\]{}+?*.$^|,:#<!\\])/g,"\\$1").replace(/\x08/g,"\\x08")},Aa=function(){if(!w(Aa.rules)){var a=C.document.querySelector("[ng-csp]")||C.document.querySelector("[data-ng-csp]");if(a){var b=a.getAttribute("ng-csp")||a.getAttribute("data-ng-csp");Aa.rules={noUnsafeEval:!b||-1!==b.indexOf("no-unsafe-eval"),noInlineStyle:!b||-1!==
|
||||
b.indexOf("no-inline-style")}}else{a=Aa;try{new Function(""),b=!1}catch(d){b=!0}a.rules={noUnsafeEval:b,noInlineStyle:!1}}}return Aa.rules},qb=function(){if(w(qb.name_))return qb.name_;var a,b,d=Qa.length,c,e;for(b=0;b<d;++b)if(c=Qa[b],a=C.document.querySelector("["+c.replace(":","\\:")+"jq]")){e=a.getAttribute(c+"jq");break}return qb.name_=e},xe=/:/g,Qa=["ng-","data-ng-","ng:","x-ng-"],Be=function(a){var b=a.currentScript;if(!b)return!0;if(!(b instanceof C.HTMLScriptElement||b instanceof C.SVGScriptElement))return!1;
|
||||
b=b.attributes;return[b.getNamedItem("src"),b.getNamedItem("href"),b.getNamedItem("xlink:href")].every(function(b){if(!b)return!0;if(!b.value)return!1;var c=a.createElement("a");c.href=b.value;if(a.location.origin===c.origin)return!0;switch(c.protocol){case "http:":case "https:":case "ftp:":case "blob:":case "file:":case "data:":return!0;default:return!1}})}(C.document),Ee=/[A-Z]/g,Wc=!1,Pa=3,Ke={full:"1.7.7",major:1,minor:7,dot:7,codeName:"kingly-exiting"};Y.expando="ng339";var Ka=Y.cache={},pg=
|
||||
1;Y._data=function(a){return this.cache[a[this.expando]]||{}};var lg=/-([a-z])/g,lh=/^-ms-/,Ab={mouseleave:"mouseout",mouseenter:"mouseover"},nc=F("jqLite"),og=/^<([\w-]+)\s*\/?>(?:<\/\1>|)$/,mc=/<|&#?\w+;/,mg=/<([\w:-]+)/,ng=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:-]+)[^>]*)\/>/gi,oa={option:[1,'<select multiple="multiple">',"</select>"],thead:[1,"<table>","</table>"],col:[2,"<table><colgroup>","</colgroup></table>"],tr:[2,"<table><tbody>","</tbody></table>"],td:[3,"<table><tbody><tr>",
|
||||
"</tr></tbody></table>"],_default:[0,"",""]};oa.optgroup=oa.option;oa.tbody=oa.tfoot=oa.colgroup=oa.caption=oa.thead;oa.th=oa.td;var ug=C.Node.prototype.contains||function(a){return!!(this.compareDocumentPosition(a)&16)},Wa=Y.prototype={ready:fd,toString:function(){var a=[];r(this,function(b){a.push(""+b)});return"["+a.join(", ")+"]"},eq:function(a){return 0<=a?x(this[a]):x(this[this.length+a])},length:0,push:kh,sort:[].sort,splice:[].splice},Gb={};r("multiple selected checked disabled readOnly required open".split(" "),
|
||||
function(a){Gb[K(a)]=a});var md={};r("input select option textarea button form details".split(" "),function(a){md[a]=!0});var td={ngMinlength:"minlength",ngMaxlength:"maxlength",ngMin:"min",ngMax:"max",ngPattern:"pattern",ngStep:"step"};r({data:rc,removeData:qc,hasData:function(a){for(var b in Ka[a.ng339])return!0;return!1},cleanData:function(a){for(var b=0,d=a.length;b<d;b++)qc(a[b]),id(a[b])}},function(a,b){Y[b]=a});r({data:rc,inheritedData:Eb,scope:function(a){return x.data(a,"$scope")||Eb(a.parentNode||
|
||||
a,["$isolateScope","$scope"])},isolateScope:function(a){return x.data(a,"$isolateScope")||x.data(a,"$isolateScopeNoTemplate")},controller:jd,injector:function(a){return Eb(a,"$injector")},removeAttr:function(a,b){a.removeAttribute(b)},hasClass:Bb,css:function(a,b,d){b=xb(b.replace(lh,"ms-"));if(w(d))a.style[b]=d;else return a.style[b]},attr:function(a,b,d){var c=a.nodeType;if(c!==Pa&&2!==c&&8!==c&&a.getAttribute){var c=K(b),e=Gb[c];if(w(d))null===d||!1===d&&e?a.removeAttribute(b):a.setAttribute(b,
|
||||
e?c:d);else return a=a.getAttribute(b),e&&null!==a&&(a=c),null===a?void 0:a}},prop:function(a,b,d){if(w(d))a[b]=d;else return a[b]},text:function(){function a(a,d){if(z(d)){var c=a.nodeType;return 1===c||c===Pa?a.textContent:""}a.textContent=d}a.$dv="";return a}(),val:function(a,b){if(z(b)){if(a.multiple&&"select"===ua(a)){var d=[];r(a.options,function(a){a.selected&&d.push(a.value||a.text)});return d}return a.value}a.value=b},html:function(a,b){if(z(b))return a.innerHTML;yb(a,!0);a.innerHTML=b},
|
||||
empty:kd},function(a,b){Y.prototype[b]=function(b,c){var e,f,g=this.length;if(a!==kd&&z(2===a.length&&a!==Bb&&a!==jd?b:c)){if(D(b)){for(e=0;e<g;e++)if(a===rc)a(this[e],b);else for(f in b)a(this[e],f,b[f]);return this}e=a.$dv;g=z(e)?Math.min(g,1):g;for(f=0;f<g;f++){var k=a(this[f],b,c);e=e?e+k:k}return e}for(e=0;e<g;e++)a(this[e],b,c);return this}});r({removeData:qc,on:function(a,b,d,c){if(w(c))throw nc("onargs");if(lc(a)){c=zb(a,!0);var e=c.events,f=c.handle;f||(f=c.handle=rg(a,e));c=0<=b.indexOf(" ")?
|
||||
b.split(" "):[b];for(var g=c.length,k=function(b,c,g){var k=e[b];k||(k=e[b]=[],k.specialHandlerWrapper=c,"$destroy"===b||g||a.addEventListener(b,f));k.push(d)};g--;)b=c[g],Ab[b]?(k(Ab[b],tg),k(b,void 0,!0)):k(b)}},off:id,one:function(a,b,d){a=x(a);a.on(b,function e(){a.off(b,d);a.off(b,e)});a.on(b,d)},replaceWith:function(a,b){var d,c=a.parentNode;yb(a);r(new Y(b),function(b){d?c.insertBefore(b,d.nextSibling):c.replaceChild(b,a);d=b})},children:function(a){var b=[];r(a.childNodes,function(a){1===
|
||||
a.nodeType&&b.push(a)});return b},contents:function(a){return a.contentDocument||a.childNodes||[]},append:function(a,b){var d=a.nodeType;if(1===d||11===d){b=new Y(b);for(var d=0,c=b.length;d<c;d++)a.appendChild(b[d])}},prepend:function(a,b){if(1===a.nodeType){var d=a.firstChild;r(new Y(b),function(b){a.insertBefore(b,d)})}},wrap:function(a,b){var d=x(b).eq(0).clone()[0],c=a.parentNode;c&&c.replaceChild(d,a);d.appendChild(a)},remove:Fb,detach:function(a){Fb(a,!0)},after:function(a,b){var d=a,c=a.parentNode;
|
||||
if(c){b=new Y(b);for(var e=0,f=b.length;e<f;e++){var g=b[e];c.insertBefore(g,d.nextSibling);d=g}}},addClass:Db,removeClass:Cb,toggleClass:function(a,b,d){b&&r(b.split(" "),function(b){var e=d;z(e)&&(e=!Bb(a,b));(e?Db:Cb)(a,b)})},parent:function(a){return(a=a.parentNode)&&11!==a.nodeType?a:null},next:function(a){return a.nextElementSibling},find:function(a,b){return a.getElementsByTagName?a.getElementsByTagName(b):[]},clone:pc,triggerHandler:function(a,b,d){var c,e,f=b.type||b,g=zb(a);if(g=(g=g&&g.events)&&
|
||||
g[f])c={preventDefault:function(){this.defaultPrevented=!0},isDefaultPrevented:function(){return!0===this.defaultPrevented},stopImmediatePropagation:function(){this.immediatePropagationStopped=!0},isImmediatePropagationStopped:function(){return!0===this.immediatePropagationStopped},stopPropagation:E,type:f,target:a},b.type&&(c=S(c,b)),b=ja(g),e=d?[c].concat(d):[c],r(b,function(b){c.isImmediatePropagationStopped()||b.apply(a,e)})}},function(a,b){Y.prototype[b]=function(b,c,e){for(var f,g=0,k=this.length;g<
|
||||
k;g++)z(f)?(f=a(this[g],b,c,e),w(f)&&(f=x(f))):oc(f,a(this[g],b,c,e));return w(f)?f:this}});Y.prototype.bind=Y.prototype.on;Y.prototype.unbind=Y.prototype.off;var mh=Object.create(null);nd.prototype={_idx:function(a){a!==this._lastKey&&(this._lastKey=a,this._lastIndex=this._keys.indexOf(a));return this._lastIndex},_transformKey:function(a){return X(a)?mh:a},get:function(a){a=this._transformKey(a);a=this._idx(a);if(-1!==a)return this._values[a]},has:function(a){a=this._transformKey(a);return-1!==this._idx(a)},
|
||||
set:function(a,b){a=this._transformKey(a);var d=this._idx(a);-1===d&&(d=this._lastIndex=this._keys.length);this._keys[d]=a;this._values[d]=b},delete:function(a){a=this._transformKey(a);a=this._idx(a);if(-1===a)return!1;this._keys.splice(a,1);this._values.splice(a,1);this._lastKey=NaN;this._lastIndex=-1;return!0}};var Hb=nd,jg=[function(){this.$get=[function(){return Hb}]}],wg=/^([^(]+?)=>/,xg=/^[^(]*\(\s*([^)]*)\)/m,nh=/,/,oh=/^\s*(_?)(\S+?)\1\s*$/,vg=/((\/\/.*$)|(\/\*[\s\S]*?\*\/))/mg,Ba=F("$injector");
|
||||
fb.$$annotate=function(a,b,d){var c;if("function"===typeof a){if(!(c=a.$inject)){c=[];if(a.length){if(b)throw A(d)&&d||(d=a.name||yg(a)),Ba("strictdi",d);b=od(a);r(b[1].split(nh),function(a){a.replace(oh,function(a,b,d){c.push(d)})})}a.$inject=c}}else H(a)?(b=a.length-1,sb(a[b],"fn"),c=a.slice(0,b)):sb(a,"fn",!0);return c};var je=F("$animate"),zf=function(){this.$get=E},Af=function(){var a=new Hb,b=[];this.$get=["$$AnimateRunner","$rootScope",function(d,c){function e(a,b,c){var d=!1;b&&(b=A(b)?b.split(" "):
|
||||
H(b)?b:[],r(b,function(b){b&&(d=!0,a[b]=c)}));return d}function f(){r(b,function(b){var c=a.get(b);if(c){var d=zg(b.attr("class")),e="",f="";r(c,function(a,b){a!==!!d[b]&&(a?e+=(e.length?" ":"")+b:f+=(f.length?" ":"")+b)});r(b,function(a){e&&Db(a,e);f&&Cb(a,f)});a.delete(b)}});b.length=0}return{enabled:E,on:E,off:E,pin:E,push:function(g,k,h,l){l&&l();h=h||{};h.from&&g.css(h.from);h.to&&g.css(h.to);if(h.addClass||h.removeClass)if(k=h.addClass,l=h.removeClass,h=a.get(g)||{},k=e(h,k,!0),l=e(h,l,!1),
|
||||
k||l)a.set(g,h),b.push(g),1===b.length&&c.$$postDigest(f);g=new d;g.complete();return g}}}]},xf=["$provide",function(a){var b=this,d=null,c=null;this.$$registeredAnimations=Object.create(null);this.register=function(c,d){if(c&&"."!==c.charAt(0))throw je("notcsel",c);var g=c+"-animation";b.$$registeredAnimations[c.substr(1)]=g;a.factory(g,d)};this.customFilter=function(a){1===arguments.length&&(c=B(a)?a:null);return c};this.classNameFilter=function(a){if(1===arguments.length&&(d=a instanceof RegExp?
|
||||
a:null)&&/[(\s|\/)]ng-animate[(\s|\/)]/.test(d.toString()))throw d=null,je("nongcls","ng-animate");return d};this.$get=["$$animateQueue",function(a){function b(a,c,d){if(d){var e;a:{for(e=0;e<d.length;e++){var f=d[e];if(1===f.nodeType){e=f;break a}}e=void 0}!e||e.parentNode||e.previousElementSibling||(d=null)}d?d.after(a):c.prepend(a)}return{on:a.on,off:a.off,pin:a.pin,enabled:a.enabled,cancel:function(a){a.cancel&&a.cancel()},enter:function(c,d,h,l){d=d&&x(d);h=h&&x(h);d=d||h.parent();b(c,d,h);return a.push(c,
|
||||
"enter",ra(l))},move:function(c,d,h,l){d=d&&x(d);h=h&&x(h);d=d||h.parent();b(c,d,h);return a.push(c,"move",ra(l))},leave:function(b,c){return a.push(b,"leave",ra(c),function(){b.remove()})},addClass:function(b,c,d){d=ra(d);d.addClass=hb(d.addclass,c);return a.push(b,"addClass",d)},removeClass:function(b,c,d){d=ra(d);d.removeClass=hb(d.removeClass,c);return a.push(b,"removeClass",d)},setClass:function(b,c,d,f){f=ra(f);f.addClass=hb(f.addClass,c);f.removeClass=hb(f.removeClass,d);return a.push(b,"setClass",
|
||||
f)},animate:function(b,c,d,f,m){m=ra(m);m.from=m.from?S(m.from,c):c;m.to=m.to?S(m.to,d):d;m.tempClasses=hb(m.tempClasses,f||"ng-inline-animate");return a.push(b,"animate",m)}}}]}],Cf=function(){this.$get=["$$rAF",function(a){function b(b){d.push(b);1<d.length||a(function(){for(var a=0;a<d.length;a++)d[a]();d=[]})}var d=[];return function(){var a=!1;b(function(){a=!0});return function(d){a?d():b(d)}}}]},Bf=function(){this.$get=["$q","$sniffer","$$animateAsyncRun","$$isDocumentHidden","$timeout",function(a,
|
||||
b,d,c,e){function f(a){this.setHost(a);var b=d();this._doneCallbacks=[];this._tick=function(a){c()?e(a,0,!1):b(a)};this._state=0}f.chain=function(a,b){function c(){if(d===a.length)b(!0);else a[d](function(a){!1===a?b(!1):(d++,c())})}var d=0;c()};f.all=function(a,b){function c(f){e=e&&f;++d===a.length&&b(e)}var d=0,e=!0;r(a,function(a){a.done(c)})};f.prototype={setHost:function(a){this.host=a||{}},done:function(a){2===this._state?a():this._doneCallbacks.push(a)},progress:E,getPromise:function(){if(!this.promise){var b=
|
||||
this;this.promise=a(function(a,c){b.done(function(b){!1===b?c():a()})})}return this.promise},then:function(a,b){return this.getPromise().then(a,b)},"catch":function(a){return this.getPromise()["catch"](a)},"finally":function(a){return this.getPromise()["finally"](a)},pause:function(){this.host.pause&&this.host.pause()},resume:function(){this.host.resume&&this.host.resume()},end:function(){this.host.end&&this.host.end();this._resolve(!0)},cancel:function(){this.host.cancel&&this.host.cancel();this._resolve(!1)},
|
||||
complete:function(a){var b=this;0===b._state&&(b._state=1,b._tick(function(){b._resolve(a)}))},_resolve:function(a){2!==this._state&&(r(this._doneCallbacks,function(b){b(a)}),this._doneCallbacks.length=0,this._state=2)}};return f}]},yf=function(){this.$get=["$$rAF","$q","$$AnimateRunner",function(a,b,d){return function(b,e){function f(){a(function(){g.addClass&&(b.addClass(g.addClass),g.addClass=null);g.removeClass&&(b.removeClass(g.removeClass),g.removeClass=null);g.to&&(b.css(g.to),g.to=null);k||
|
||||
h.complete();k=!0});return h}var g=e||{};g.$$prepared||(g=Ia(g));g.cleanupStyles&&(g.from=g.to=null);g.from&&(b.css(g.from),g.from=null);var k,h=new d;return{start:f,end:f}}}]},$=F("$compile"),tc=new function(){};Xc.$inject=["$provide","$$sanitizeUriProvider"];Jb.prototype.isFirstChange=function(){return this.previousValue===tc};var pd=/^((?:x|data)[:\-_])/i,Eg=/[:\-_]+(.)/g,vd=F("$controller"),ud=/^(\S+)(\s+as\s+([\w$]+))?$/,Jf=function(){this.$get=["$document",function(a){return function(b){b?!b.nodeType&&
|
||||
b instanceof x&&(b=b[0]):b=a[0].body;return b.offsetWidth+1}}]},wd="application/json",wc={"Content-Type":wd+";charset=utf-8"},Hg=/^\[|^\{(?!\{)/,Ig={"[":/]$/,"{":/}$/},Gg=/^\)]\}',?\n/,Kb=F("$http"),Ma=ca.$interpolateMinErr=F("$interpolate");Ma.throwNoconcat=function(a){throw Ma("noconcat",a);};Ma.interr=function(a,b){return Ma("interr",a,b.toString())};var Lg=F("$interval"),Sf=function(){this.$get=function(){function a(a){var b=function(a){b.data=a;b.called=!0};b.id=a;return b}var b=ca.callbacks,
|
||||
d={};return{createCallback:function(c){c="_"+(b.$$counter++).toString(36);var e="angular.callbacks."+c,f=a(c);d[e]=b[c]=f;return e},wasCalled:function(a){return d[a].called},getResponse:function(a){return d[a].data},removeCallback:function(a){delete b[d[a].id];delete d[a]}}}},ph=/^([^?#]*)(\?([^#]*))?(#(.*))?$/,Mg={http:80,https:443,ftp:21},jb=F("$location"),Ng=/^\s*[\\/]{2,}/,qh={$$absUrl:"",$$html5:!1,$$replace:!1,$$compose:function(){for(var a=this.$$path,b=this.$$hash,d=ye(this.$$search),b=b?
|
||||
"#"+hc(b):"",a=a.split("/"),c=a.length;c--;)a[c]=hc(a[c].replace(/%2F/g,"/"));this.$$url=a.join("/")+(d?"?"+d:"")+b;this.$$absUrl=this.$$normalizeUrl(this.$$url);this.$$urlUpdatedByLocation=!0},absUrl:Lb("$$absUrl"),url:function(a){if(z(a))return this.$$url;var b=ph.exec(a);(b[1]||""===a)&&this.path(decodeURIComponent(b[1]));(b[2]||b[1]||""===a)&&this.search(b[3]||"");this.hash(b[5]||"");return this},protocol:Lb("$$protocol"),host:Lb("$$host"),port:Lb("$$port"),path:Dd("$$path",function(a){a=null!==
|
||||
a?a.toString():"";return"/"===a.charAt(0)?a:"/"+a}),search:function(a,b){switch(arguments.length){case 0:return this.$$search;case 1:if(A(a)||W(a))a=a.toString(),this.$$search=gc(a);else if(D(a))a=Ia(a,{}),r(a,function(b,c){null==b&&delete a[c]}),this.$$search=a;else throw jb("isrcharg");break;default:z(b)||null===b?delete this.$$search[a]:this.$$search[a]=b}this.$$compose();return this},hash:Dd("$$hash",function(a){return null!==a?a.toString():""}),replace:function(){this.$$replace=!0;return this}};
|
||||
r([Cd,zc,yc],function(a){a.prototype=Object.create(qh);a.prototype.state=function(b){if(!arguments.length)return this.$$state;if(a!==yc||!this.$$html5)throw jb("nostate");this.$$state=z(b)?null:b;this.$$urlUpdatedByLocation=!0;return this}});var Ya=F("$parse"),Rg={}.constructor.prototype.valueOf,Ub=T();r("+ - * / % === !== == != < > <= >= && || ! = |".split(" "),function(a){Ub[a]=!0});var rh={n:"\n",f:"\f",r:"\r",t:"\t",v:"\v","'":"'",'"':'"'},Nb=function(a){this.options=a};Nb.prototype={constructor:Nb,
|
||||
lex:function(a){this.text=a;this.index=0;for(this.tokens=[];this.index<this.text.length;)if(a=this.text.charAt(this.index),'"'===a||"'"===a)this.readString(a);else if(this.isNumber(a)||"."===a&&this.isNumber(this.peek()))this.readNumber();else if(this.isIdentifierStart(this.peekMultichar()))this.readIdent();else if(this.is(a,"(){}[].,;:?"))this.tokens.push({index:this.index,text:a}),this.index++;else if(this.isWhitespace(a))this.index++;else{var b=a+this.peek(),d=b+this.peek(2),c=Ub[b],e=Ub[d];Ub[a]||
|
||||
c||e?(a=e?d:c?b:a,this.tokens.push({index:this.index,text:a,operator:!0}),this.index+=a.length):this.throwError("Unexpected next character ",this.index,this.index+1)}return this.tokens},is:function(a,b){return-1!==b.indexOf(a)},peek:function(a){a=a||1;return this.index+a<this.text.length?this.text.charAt(this.index+a):!1},isNumber:function(a){return"0"<=a&&"9">=a&&"string"===typeof a},isWhitespace:function(a){return" "===a||"\r"===a||"\t"===a||"\n"===a||"\v"===a||"\u00a0"===a},isIdentifierStart:function(a){return this.options.isIdentifierStart?
|
||||
this.options.isIdentifierStart(a,this.codePointAt(a)):this.isValidIdentifierStart(a)},isValidIdentifierStart:function(a){return"a"<=a&&"z">=a||"A"<=a&&"Z">=a||"_"===a||"$"===a},isIdentifierContinue:function(a){return this.options.isIdentifierContinue?this.options.isIdentifierContinue(a,this.codePointAt(a)):this.isValidIdentifierContinue(a)},isValidIdentifierContinue:function(a,b){return this.isValidIdentifierStart(a,b)||this.isNumber(a)},codePointAt:function(a){return 1===a.length?a.charCodeAt(0):
|
||||
(a.charCodeAt(0)<<10)+a.charCodeAt(1)-56613888},peekMultichar:function(){var a=this.text.charAt(this.index),b=this.peek();if(!b)return a;var d=a.charCodeAt(0),c=b.charCodeAt(0);return 55296<=d&&56319>=d&&56320<=c&&57343>=c?a+b:a},isExpOperator:function(a){return"-"===a||"+"===a||this.isNumber(a)},throwError:function(a,b,d){d=d||this.index;b=w(b)?"s "+b+"-"+this.index+" ["+this.text.substring(b,d)+"]":" "+d;throw Ya("lexerr",a,b,this.text);},readNumber:function(){for(var a="",b=this.index;this.index<
|
||||
this.text.length;){var d=K(this.text.charAt(this.index));if("."===d||this.isNumber(d))a+=d;else{var c=this.peek();if("e"===d&&this.isExpOperator(c))a+=d;else if(this.isExpOperator(d)&&c&&this.isNumber(c)&&"e"===a.charAt(a.length-1))a+=d;else if(!this.isExpOperator(d)||c&&this.isNumber(c)||"e"!==a.charAt(a.length-1))break;else this.throwError("Invalid exponent")}this.index++}this.tokens.push({index:b,text:a,constant:!0,value:Number(a)})},readIdent:function(){var a=this.index;for(this.index+=this.peekMultichar().length;this.index<
|
||||
this.text.length;){var b=this.peekMultichar();if(!this.isIdentifierContinue(b))break;this.index+=b.length}this.tokens.push({index:a,text:this.text.slice(a,this.index),identifier:!0})},readString:function(a){var b=this.index;this.index++;for(var d="",c=a,e=!1;this.index<this.text.length;){var f=this.text.charAt(this.index),c=c+f;if(e)"u"===f?(e=this.text.substring(this.index+1,this.index+5),e.match(/[\da-f]{4}/i)||this.throwError("Invalid unicode escape [\\u"+e+"]"),this.index+=4,d+=String.fromCharCode(parseInt(e,
|
||||
16))):d+=rh[f]||f,e=!1;else if("\\"===f)e=!0;else{if(f===a){this.index++;this.tokens.push({index:b,text:c,constant:!0,value:d});return}d+=f}this.index++}this.throwError("Unterminated quote",b)}};var q=function(a,b){this.lexer=a;this.options=b};q.Program="Program";q.ExpressionStatement="ExpressionStatement";q.AssignmentExpression="AssignmentExpression";q.ConditionalExpression="ConditionalExpression";q.LogicalExpression="LogicalExpression";q.BinaryExpression="BinaryExpression";q.UnaryExpression="UnaryExpression";
|
||||
q.CallExpression="CallExpression";q.MemberExpression="MemberExpression";q.Identifier="Identifier";q.Literal="Literal";q.ArrayExpression="ArrayExpression";q.Property="Property";q.ObjectExpression="ObjectExpression";q.ThisExpression="ThisExpression";q.LocalsExpression="LocalsExpression";q.NGValueParameter="NGValueParameter";q.prototype={ast:function(a){this.text=a;this.tokens=this.lexer.lex(a);a=this.program();0!==this.tokens.length&&this.throwError("is an unexpected token",this.tokens[0]);return a},
|
||||
program:function(){for(var a=[];;)if(0<this.tokens.length&&!this.peek("}",")",";","]")&&a.push(this.expressionStatement()),!this.expect(";"))return{type:q.Program,body:a}},expressionStatement:function(){return{type:q.ExpressionStatement,expression:this.filterChain()}},filterChain:function(){for(var a=this.expression();this.expect("|");)a=this.filter(a);return a},expression:function(){return this.assignment()},assignment:function(){var a=this.ternary();if(this.expect("=")){if(!Hd(a))throw Ya("lval");
|
||||
a={type:q.AssignmentExpression,left:a,right:this.assignment(),operator:"="}}return a},ternary:function(){var a=this.logicalOR(),b,d;return this.expect("?")&&(b=this.expression(),this.consume(":"))?(d=this.expression(),{type:q.ConditionalExpression,test:a,alternate:b,consequent:d}):a},logicalOR:function(){for(var a=this.logicalAND();this.expect("||");)a={type:q.LogicalExpression,operator:"||",left:a,right:this.logicalAND()};return a},logicalAND:function(){for(var a=this.equality();this.expect("&&");)a=
|
||||
{type:q.LogicalExpression,operator:"&&",left:a,right:this.equality()};return a},equality:function(){for(var a=this.relational(),b;b=this.expect("==","!=","===","!==");)a={type:q.BinaryExpression,operator:b.text,left:a,right:this.relational()};return a},relational:function(){for(var a=this.additive(),b;b=this.expect("<",">","<=",">=");)a={type:q.BinaryExpression,operator:b.text,left:a,right:this.additive()};return a},additive:function(){for(var a=this.multiplicative(),b;b=this.expect("+","-");)a={type:q.BinaryExpression,
|
||||
operator:b.text,left:a,right:this.multiplicative()};return a},multiplicative:function(){for(var a=this.unary(),b;b=this.expect("*","/","%");)a={type:q.BinaryExpression,operator:b.text,left:a,right:this.unary()};return a},unary:function(){var a;return(a=this.expect("+","-","!"))?{type:q.UnaryExpression,operator:a.text,prefix:!0,argument:this.unary()}:this.primary()},primary:function(){var a;this.expect("(")?(a=this.filterChain(),this.consume(")")):this.expect("[")?a=this.arrayDeclaration():this.expect("{")?
|
||||
a=this.object():this.selfReferential.hasOwnProperty(this.peek().text)?a=Ia(this.selfReferential[this.consume().text]):this.options.literals.hasOwnProperty(this.peek().text)?a={type:q.Literal,value:this.options.literals[this.consume().text]}:this.peek().identifier?a=this.identifier():this.peek().constant?a=this.constant():this.throwError("not a primary expression",this.peek());for(var b;b=this.expect("(","[",".");)"("===b.text?(a={type:q.CallExpression,callee:a,arguments:this.parseArguments()},this.consume(")")):
|
||||
"["===b.text?(a={type:q.MemberExpression,object:a,property:this.expression(),computed:!0},this.consume("]")):"."===b.text?a={type:q.MemberExpression,object:a,property:this.identifier(),computed:!1}:this.throwError("IMPOSSIBLE");return a},filter:function(a){a=[a];for(var b={type:q.CallExpression,callee:this.identifier(),arguments:a,filter:!0};this.expect(":");)a.push(this.expression());return b},parseArguments:function(){var a=[];if(")"!==this.peekToken().text){do a.push(this.filterChain());while(this.expect(","))
|
||||
}return a},identifier:function(){var a=this.consume();a.identifier||this.throwError("is not a valid identifier",a);return{type:q.Identifier,name:a.text}},constant:function(){return{type:q.Literal,value:this.consume().value}},arrayDeclaration:function(){var a=[];if("]"!==this.peekToken().text){do{if(this.peek("]"))break;a.push(this.expression())}while(this.expect(","))}this.consume("]");return{type:q.ArrayExpression,elements:a}},object:function(){var a=[],b;if("}"!==this.peekToken().text){do{if(this.peek("}"))break;
|
||||
b={type:q.Property,kind:"init"};this.peek().constant?(b.key=this.constant(),b.computed=!1,this.consume(":"),b.value=this.expression()):this.peek().identifier?(b.key=this.identifier(),b.computed=!1,this.peek(":")?(this.consume(":"),b.value=this.expression()):b.value=b.key):this.peek("[")?(this.consume("["),b.key=this.expression(),this.consume("]"),b.computed=!0,this.consume(":"),b.value=this.expression()):this.throwError("invalid key",this.peek());a.push(b)}while(this.expect(","))}this.consume("}");
|
||||
return{type:q.ObjectExpression,properties:a}},throwError:function(a,b){throw Ya("syntax",b.text,a,b.index+1,this.text,this.text.substring(b.index));},consume:function(a){if(0===this.tokens.length)throw Ya("ueoe",this.text);var b=this.expect(a);b||this.throwError("is unexpected, expecting ["+a+"]",this.peek());return b},peekToken:function(){if(0===this.tokens.length)throw Ya("ueoe",this.text);return this.tokens[0]},peek:function(a,b,d,c){return this.peekAhead(0,a,b,d,c)},peekAhead:function(a,b,d,c,
|
||||
e){if(this.tokens.length>a){a=this.tokens[a];var f=a.text;if(f===b||f===d||f===c||f===e||!(b||d||c||e))return a}return!1},expect:function(a,b,d,c){return(a=this.peek(a,b,d,c))?(this.tokens.shift(),a):!1},selfReferential:{"this":{type:q.ThisExpression},$locals:{type:q.LocalsExpression}}};var Fd=2;Jd.prototype={compile:function(a){var b=this;this.state={nextId:0,filters:{},fn:{vars:[],body:[],own:{}},assign:{vars:[],body:[],own:{}},inputs:[]};Z(a,b.$filter);var d="",c;this.stage="assign";if(c=Id(a))this.state.computing=
|
||||
"assign",d=this.nextId(),this.recurse(c,d),this.return_(d),d="fn.assign="+this.generateFunction("assign","s,v,l");c=Gd(a.body);b.stage="inputs";r(c,function(a,c){var d="fn"+c;b.state[d]={vars:[],body:[],own:{}};b.state.computing=d;var k=b.nextId();b.recurse(a,k);b.return_(k);b.state.inputs.push({name:d,isPure:a.isPure});a.watchId=c});this.state.computing="fn";this.stage="main";this.recurse(a);a='"'+this.USE+" "+this.STRICT+'";\n'+this.filterPrefix()+"var fn="+this.generateFunction("fn","s,l,a,i")+
|
||||
d+this.watchFns()+"return fn;";a=(new Function("$filter","getStringValue","ifDefined","plus",a))(this.$filter,Og,Pg,Ed);this.state=this.stage=void 0;return a},USE:"use",STRICT:"strict",watchFns:function(){var a=[],b=this.state.inputs,d=this;r(b,function(b){a.push("var "+b.name+"="+d.generateFunction(b.name,"s"));b.isPure&&a.push(b.name,".isPure="+JSON.stringify(b.isPure)+";")});b.length&&a.push("fn.inputs=["+b.map(function(a){return a.name}).join(",")+"];");return a.join("")},generateFunction:function(a,
|
||||
b){return"function("+b+"){"+this.varsPrefix(a)+this.body(a)+"};"},filterPrefix:function(){var a=[],b=this;r(this.state.filters,function(d,c){a.push(d+"=$filter("+b.escape(c)+")")});return a.length?"var "+a.join(",")+";":""},varsPrefix:function(a){return this.state[a].vars.length?"var "+this.state[a].vars.join(",")+";":""},body:function(a){return this.state[a].body.join("")},recurse:function(a,b,d,c,e,f){var g,k,h=this,l,m,p;c=c||E;if(!f&&w(a.watchId))b=b||this.nextId(),this.if_("i",this.lazyAssign(b,
|
||||
this.computedMember("i",a.watchId)),this.lazyRecurse(a,b,d,c,e,!0));else switch(a.type){case q.Program:r(a.body,function(b,c){h.recurse(b.expression,void 0,void 0,function(a){k=a});c!==a.body.length-1?h.current().body.push(k,";"):h.return_(k)});break;case q.Literal:m=this.escape(a.value);this.assign(b,m);c(b||m);break;case q.UnaryExpression:this.recurse(a.argument,void 0,void 0,function(a){k=a});m=a.operator+"("+this.ifDefined(k,0)+")";this.assign(b,m);c(m);break;case q.BinaryExpression:this.recurse(a.left,
|
||||
void 0,void 0,function(a){g=a});this.recurse(a.right,void 0,void 0,function(a){k=a});m="+"===a.operator?this.plus(g,k):"-"===a.operator?this.ifDefined(g,0)+a.operator+this.ifDefined(k,0):"("+g+")"+a.operator+"("+k+")";this.assign(b,m);c(m);break;case q.LogicalExpression:b=b||this.nextId();h.recurse(a.left,b);h.if_("&&"===a.operator?b:h.not(b),h.lazyRecurse(a.right,b));c(b);break;case q.ConditionalExpression:b=b||this.nextId();h.recurse(a.test,b);h.if_(b,h.lazyRecurse(a.alternate,b),h.lazyRecurse(a.consequent,
|
||||
b));c(b);break;case q.Identifier:b=b||this.nextId();d&&(d.context="inputs"===h.stage?"s":this.assign(this.nextId(),this.getHasOwnProperty("l",a.name)+"?l:s"),d.computed=!1,d.name=a.name);h.if_("inputs"===h.stage||h.not(h.getHasOwnProperty("l",a.name)),function(){h.if_("inputs"===h.stage||"s",function(){e&&1!==e&&h.if_(h.isNull(h.nonComputedMember("s",a.name)),h.lazyAssign(h.nonComputedMember("s",a.name),"{}"));h.assign(b,h.nonComputedMember("s",a.name))})},b&&h.lazyAssign(b,h.nonComputedMember("l",
|
||||
a.name)));c(b);break;case q.MemberExpression:g=d&&(d.context=this.nextId())||this.nextId();b=b||this.nextId();h.recurse(a.object,g,void 0,function(){h.if_(h.notNull(g),function(){a.computed?(k=h.nextId(),h.recurse(a.property,k),h.getStringValue(k),e&&1!==e&&h.if_(h.not(h.computedMember(g,k)),h.lazyAssign(h.computedMember(g,k),"{}")),m=h.computedMember(g,k),h.assign(b,m),d&&(d.computed=!0,d.name=k)):(e&&1!==e&&h.if_(h.isNull(h.nonComputedMember(g,a.property.name)),h.lazyAssign(h.nonComputedMember(g,
|
||||
a.property.name),"{}")),m=h.nonComputedMember(g,a.property.name),h.assign(b,m),d&&(d.computed=!1,d.name=a.property.name))},function(){h.assign(b,"undefined")});c(b)},!!e);break;case q.CallExpression:b=b||this.nextId();a.filter?(k=h.filter(a.callee.name),l=[],r(a.arguments,function(a){var b=h.nextId();h.recurse(a,b);l.push(b)}),m=k+"("+l.join(",")+")",h.assign(b,m),c(b)):(k=h.nextId(),g={},l=[],h.recurse(a.callee,k,g,function(){h.if_(h.notNull(k),function(){r(a.arguments,function(b){h.recurse(b,a.constant?
|
||||
void 0:h.nextId(),void 0,function(a){l.push(a)})});m=g.name?h.member(g.context,g.name,g.computed)+"("+l.join(",")+")":k+"("+l.join(",")+")";h.assign(b,m)},function(){h.assign(b,"undefined")});c(b)}));break;case q.AssignmentExpression:k=this.nextId();g={};this.recurse(a.left,void 0,g,function(){h.if_(h.notNull(g.context),function(){h.recurse(a.right,k);m=h.member(g.context,g.name,g.computed)+a.operator+k;h.assign(b,m);c(b||m)})},1);break;case q.ArrayExpression:l=[];r(a.elements,function(b){h.recurse(b,
|
||||
a.constant?void 0:h.nextId(),void 0,function(a){l.push(a)})});m="["+l.join(",")+"]";this.assign(b,m);c(b||m);break;case q.ObjectExpression:l=[];p=!1;r(a.properties,function(a){a.computed&&(p=!0)});p?(b=b||this.nextId(),this.assign(b,"{}"),r(a.properties,function(a){a.computed?(g=h.nextId(),h.recurse(a.key,g)):g=a.key.type===q.Identifier?a.key.name:""+a.key.value;k=h.nextId();h.recurse(a.value,k);h.assign(h.member(b,g,a.computed),k)})):(r(a.properties,function(b){h.recurse(b.value,a.constant?void 0:
|
||||
h.nextId(),void 0,function(a){l.push(h.escape(b.key.type===q.Identifier?b.key.name:""+b.key.value)+":"+a)})}),m="{"+l.join(",")+"}",this.assign(b,m));c(b||m);break;case q.ThisExpression:this.assign(b,"s");c(b||"s");break;case q.LocalsExpression:this.assign(b,"l");c(b||"l");break;case q.NGValueParameter:this.assign(b,"v"),c(b||"v")}},getHasOwnProperty:function(a,b){var d=a+"."+b,c=this.current().own;c.hasOwnProperty(d)||(c[d]=this.nextId(!1,a+"&&("+this.escape(b)+" in "+a+")"));return c[d]},assign:function(a,
|
||||
b){if(a)return this.current().body.push(a,"=",b,";"),a},filter:function(a){this.state.filters.hasOwnProperty(a)||(this.state.filters[a]=this.nextId(!0));return this.state.filters[a]},ifDefined:function(a,b){return"ifDefined("+a+","+this.escape(b)+")"},plus:function(a,b){return"plus("+a+","+b+")"},return_:function(a){this.current().body.push("return ",a,";")},if_:function(a,b,d){if(!0===a)b();else{var c=this.current().body;c.push("if(",a,"){");b();c.push("}");d&&(c.push("else{"),d(),c.push("}"))}},
|
||||
not:function(a){return"!("+a+")"},isNull:function(a){return a+"==null"},notNull:function(a){return a+"!=null"},nonComputedMember:function(a,b){var d=/[^$_a-zA-Z0-9]/g;return/^[$_a-zA-Z][$_a-zA-Z0-9]*$/.test(b)?a+"."+b:a+'["'+b.replace(d,this.stringEscapeFn)+'"]'},computedMember:function(a,b){return a+"["+b+"]"},member:function(a,b,d){return d?this.computedMember(a,b):this.nonComputedMember(a,b)},getStringValue:function(a){this.assign(a,"getStringValue("+a+")")},lazyRecurse:function(a,b,d,c,e,f){var g=
|
||||
this;return function(){g.recurse(a,b,d,c,e,f)}},lazyAssign:function(a,b){var d=this;return function(){d.assign(a,b)}},stringEscapeRegex:/[^ a-zA-Z0-9]/g,stringEscapeFn:function(a){return"\\u"+("0000"+a.charCodeAt(0).toString(16)).slice(-4)},escape:function(a){if(A(a))return"'"+a.replace(this.stringEscapeRegex,this.stringEscapeFn)+"'";if(W(a))return a.toString();if(!0===a)return"true";if(!1===a)return"false";if(null===a)return"null";if("undefined"===typeof a)return"undefined";throw Ya("esc");},nextId:function(a,
|
||||
b){var d="v"+this.state.nextId++;a||this.current().vars.push(d+(b?"="+b:""));return d},current:function(){return this.state[this.state.computing]}};Kd.prototype={compile:function(a){var b=this;Z(a,b.$filter);var d,c;if(d=Id(a))c=this.recurse(d);d=Gd(a.body);var e;d&&(e=[],r(d,function(a,c){var d=b.recurse(a);d.isPure=a.isPure;a.input=d;e.push(d);a.watchId=c}));var f=[];r(a.body,function(a){f.push(b.recurse(a.expression))});a=0===a.body.length?E:1===a.body.length?f[0]:function(a,b){var c;r(f,function(d){c=
|
||||
d(a,b)});return c};c&&(a.assign=function(a,b,d){return c(a,d,b)});e&&(a.inputs=e);return a},recurse:function(a,b,d){var c,e,f=this,g;if(a.input)return this.inputs(a.input,a.watchId);switch(a.type){case q.Literal:return this.value(a.value,b);case q.UnaryExpression:return e=this.recurse(a.argument),this["unary"+a.operator](e,b);case q.BinaryExpression:return c=this.recurse(a.left),e=this.recurse(a.right),this["binary"+a.operator](c,e,b);case q.LogicalExpression:return c=this.recurse(a.left),e=this.recurse(a.right),
|
||||
this["binary"+a.operator](c,e,b);case q.ConditionalExpression:return this["ternary?:"](this.recurse(a.test),this.recurse(a.alternate),this.recurse(a.consequent),b);case q.Identifier:return f.identifier(a.name,b,d);case q.MemberExpression:return c=this.recurse(a.object,!1,!!d),a.computed||(e=a.property.name),a.computed&&(e=this.recurse(a.property)),a.computed?this.computedMember(c,e,b,d):this.nonComputedMember(c,e,b,d);case q.CallExpression:return g=[],r(a.arguments,function(a){g.push(f.recurse(a))}),
|
||||
a.filter&&(e=this.$filter(a.callee.name)),a.filter||(e=this.recurse(a.callee,!0)),a.filter?function(a,c,d,f){for(var p=[],n=0;n<g.length;++n)p.push(g[n](a,c,d,f));a=e.apply(void 0,p,f);return b?{context:void 0,name:void 0,value:a}:a}:function(a,c,d,f){var p=e(a,c,d,f),n;if(null!=p.value){n=[];for(var s=0;s<g.length;++s)n.push(g[s](a,c,d,f));n=p.value.apply(p.context,n)}return b?{value:n}:n};case q.AssignmentExpression:return c=this.recurse(a.left,!0,1),e=this.recurse(a.right),function(a,d,f,g){var p=
|
||||
c(a,d,f,g);a=e(a,d,f,g);p.context[p.name]=a;return b?{value:a}:a};case q.ArrayExpression:return g=[],r(a.elements,function(a){g.push(f.recurse(a))}),function(a,c,d,e){for(var f=[],n=0;n<g.length;++n)f.push(g[n](a,c,d,e));return b?{value:f}:f};case q.ObjectExpression:return g=[],r(a.properties,function(a){a.computed?g.push({key:f.recurse(a.key),computed:!0,value:f.recurse(a.value)}):g.push({key:a.key.type===q.Identifier?a.key.name:""+a.key.value,computed:!1,value:f.recurse(a.value)})}),function(a,
|
||||
c,d,e){for(var f={},n=0;n<g.length;++n)g[n].computed?f[g[n].key(a,c,d,e)]=g[n].value(a,c,d,e):f[g[n].key]=g[n].value(a,c,d,e);return b?{value:f}:f};case q.ThisExpression:return function(a){return b?{value:a}:a};case q.LocalsExpression:return function(a,c){return b?{value:c}:c};case q.NGValueParameter:return function(a,c,d){return b?{value:d}:d}}},"unary+":function(a,b){return function(d,c,e,f){d=a(d,c,e,f);d=w(d)?+d:0;return b?{value:d}:d}},"unary-":function(a,b){return function(d,c,e,f){d=a(d,c,
|
||||
e,f);d=w(d)?-d:-0;return b?{value:d}:d}},"unary!":function(a,b){return function(d,c,e,f){d=!a(d,c,e,f);return b?{value:d}:d}},"binary+":function(a,b,d){return function(c,e,f,g){var k=a(c,e,f,g);c=b(c,e,f,g);k=Ed(k,c);return d?{value:k}:k}},"binary-":function(a,b,d){return function(c,e,f,g){var k=a(c,e,f,g);c=b(c,e,f,g);k=(w(k)?k:0)-(w(c)?c:0);return d?{value:k}:k}},"binary*":function(a,b,d){return function(c,e,f,g){c=a(c,e,f,g)*b(c,e,f,g);return d?{value:c}:c}},"binary/":function(a,b,d){return function(c,
|
||||
e,f,g){c=a(c,e,f,g)/b(c,e,f,g);return d?{value:c}:c}},"binary%":function(a,b,d){return function(c,e,f,g){c=a(c,e,f,g)%b(c,e,f,g);return d?{value:c}:c}},"binary===":function(a,b,d){return function(c,e,f,g){c=a(c,e,f,g)===b(c,e,f,g);return d?{value:c}:c}},"binary!==":function(a,b,d){return function(c,e,f,g){c=a(c,e,f,g)!==b(c,e,f,g);return d?{value:c}:c}},"binary==":function(a,b,d){return function(c,e,f,g){c=a(c,e,f,g)==b(c,e,f,g);return d?{value:c}:c}},"binary!=":function(a,b,d){return function(c,
|
||||
e,f,g){c=a(c,e,f,g)!=b(c,e,f,g);return d?{value:c}:c}},"binary<":function(a,b,d){return function(c,e,f,g){c=a(c,e,f,g)<b(c,e,f,g);return d?{value:c}:c}},"binary>":function(a,b,d){return function(c,e,f,g){c=a(c,e,f,g)>b(c,e,f,g);return d?{value:c}:c}},"binary<=":function(a,b,d){return function(c,e,f,g){c=a(c,e,f,g)<=b(c,e,f,g);return d?{value:c}:c}},"binary>=":function(a,b,d){return function(c,e,f,g){c=a(c,e,f,g)>=b(c,e,f,g);return d?{value:c}:c}},"binary&&":function(a,b,d){return function(c,e,f,g){c=
|
||||
a(c,e,f,g)&&b(c,e,f,g);return d?{value:c}:c}},"binary||":function(a,b,d){return function(c,e,f,g){c=a(c,e,f,g)||b(c,e,f,g);return d?{value:c}:c}},"ternary?:":function(a,b,d,c){return function(e,f,g,k){e=a(e,f,g,k)?b(e,f,g,k):d(e,f,g,k);return c?{value:e}:e}},value:function(a,b){return function(){return b?{context:void 0,name:void 0,value:a}:a}},identifier:function(a,b,d){return function(c,e,f,g){c=e&&a in e?e:c;d&&1!==d&&c&&null==c[a]&&(c[a]={});e=c?c[a]:void 0;return b?{context:c,name:a,value:e}:
|
||||
e}},computedMember:function(a,b,d,c){return function(e,f,g,k){var h=a(e,f,g,k),l,m;null!=h&&(l=b(e,f,g,k),l+="",c&&1!==c&&h&&!h[l]&&(h[l]={}),m=h[l]);return d?{context:h,name:l,value:m}:m}},nonComputedMember:function(a,b,d,c){return function(e,f,g,k){e=a(e,f,g,k);c&&1!==c&&e&&null==e[b]&&(e[b]={});f=null!=e?e[b]:void 0;return d?{context:e,name:b,value:f}:f}},inputs:function(a,b){return function(d,c,e,f){return f?f[b]:a(d,c,e)}}};Mb.prototype={constructor:Mb,parse:function(a){a=this.getAst(a);var b=
|
||||
this.astCompiler.compile(a.ast),d=a.ast;b.literal=0===d.body.length||1===d.body.length&&(d.body[0].expression.type===q.Literal||d.body[0].expression.type===q.ArrayExpression||d.body[0].expression.type===q.ObjectExpression);b.constant=a.ast.constant;b.oneTime=a.oneTime;return b},getAst:function(a){var b=!1;a=a.trim();":"===a.charAt(0)&&":"===a.charAt(1)&&(b=!0,a=a.substring(2));return{ast:this.ast.ast(a),oneTime:b}}};var Ea=F("$sce"),V={HTML:"html",CSS:"css",MEDIA_URL:"mediaUrl",URL:"url",RESOURCE_URL:"resourceUrl",
|
||||
JS:"js"},Cc=/_([a-z])/g,Ug=F("$templateRequest"),Vg=F("$timeout"),aa=C.document.createElement("a"),Od=ga(C.location.href),Na;aa.href="http://[::1]";var Wg="[::1]"===aa.hostname;Pd.$inject=["$document"];dd.$inject=["$provide"];var Wd=22,Vd=".",Ec="0";Qd.$inject=["$locale"];Sd.$inject=["$locale"];var gh={yyyy:ea("FullYear",4,0,!1,!0),yy:ea("FullYear",2,0,!0,!0),y:ea("FullYear",1,0,!1,!0),MMMM:kb("Month"),MMM:kb("Month",!0),MM:ea("Month",2,1),M:ea("Month",1,1),LLLL:kb("Month",!1,!0),dd:ea("Date",2),
|
||||
d:ea("Date",1),HH:ea("Hours",2),H:ea("Hours",1),hh:ea("Hours",2,-12),h:ea("Hours",1,-12),mm:ea("Minutes",2),m:ea("Minutes",1),ss:ea("Seconds",2),s:ea("Seconds",1),sss:ea("Milliseconds",3),EEEE:kb("Day"),EEE:kb("Day",!0),a:function(a,b){return 12>a.getHours()?b.AMPMS[0]:b.AMPMS[1]},Z:function(a,b,d){a=-1*d;return a=(0<=a?"+":"")+(Ob(Math[0<a?"floor":"ceil"](a/60),2)+Ob(Math.abs(a%60),2))},ww:Yd(2),w:Yd(1),G:Fc,GG:Fc,GGG:Fc,GGGG:function(a,b){return 0>=a.getFullYear()?b.ERANAMES[0]:b.ERANAMES[1]}},
|
||||
fh=/((?:[^yMLdHhmsaZEwG']+)|(?:'(?:[^']|'')*')|(?:E+|y+|M+|L+|d+|H+|h+|m+|s+|a|Z|G+|w+))([\s\S]*)/,eh=/^-?\d+$/;Rd.$inject=["$locale"];var $g=ia(K),ah=ia(ub);Td.$inject=["$parse"];var Me=ia({restrict:"E",compile:function(a,b){if(!b.href&&!b.xlinkHref)return function(a,b){if("a"===b[0].nodeName.toLowerCase()){var e="[object SVGAnimatedString]"===la.call(b.prop("href"))?"xlink:href":"href";b.on("click",function(a){b.attr(e)||a.preventDefault()})}}}}),vb={};r(Gb,function(a,b){function d(a,d,e){a.$watch(e[c],
|
||||
function(a){e.$set(b,!!a)})}if("multiple"!==a){var c=wa("ng-"+b),e=d;"checked"===a&&(e=function(a,b,e){e.ngModel!==e[c]&&d(a,b,e)});vb[c]=function(){return{restrict:"A",priority:100,link:e}}}});r(td,function(a,b){vb[b]=function(){return{priority:100,link:function(a,c,e){if("ngPattern"===b&&"/"===e.ngPattern.charAt(0)&&(c=e.ngPattern.match(ie))){e.$set("ngPattern",new RegExp(c[1],c[2]));return}a.$watch(e[b],function(a){e.$set(b,a)})}}}});r(["src","srcset","href"],function(a){var b=wa("ng-"+a);vb[b]=
|
||||
["$sce",function(d){return{priority:99,link:function(c,e,f){var g=a,k=a;"href"===a&&"[object SVGAnimatedString]"===la.call(e.prop("href"))&&(k="xlinkHref",f.$attr[k]="xlink:href",g=null);f.$set(b,d.getTrustedMediaUrl(f[b]));f.$observe(b,function(b){b?(f.$set(k,b),Ca&&g&&e.prop(g,f[k])):"href"===a&&f.$set(k,null)})}}}]});var lb={$addControl:E,$getControls:ia([]),$$renameControl:function(a,b){a.$name=b},$removeControl:E,$setValidity:E,$setDirty:E,$setPristine:E,$setSubmitted:E,$$setSubmitted:E};Pb.$inject=
|
||||
["$element","$attrs","$scope","$animate","$interpolate"];Pb.prototype={$rollbackViewValue:function(){r(this.$$controls,function(a){a.$rollbackViewValue()})},$commitViewValue:function(){r(this.$$controls,function(a){a.$commitViewValue()})},$addControl:function(a){Ja(a.$name,"input");this.$$controls.push(a);a.$name&&(this[a.$name]=a);a.$$parentForm=this},$getControls:function(){return ja(this.$$controls)},$$renameControl:function(a,b){var d=a.$name;this[d]===a&&delete this[d];this[b]=a;a.$name=b},$removeControl:function(a){a.$name&&
|
||||
this[a.$name]===a&&delete this[a.$name];r(this.$pending,function(b,d){this.$setValidity(d,null,a)},this);r(this.$error,function(b,d){this.$setValidity(d,null,a)},this);r(this.$$success,function(b,d){this.$setValidity(d,null,a)},this);cb(this.$$controls,a);a.$$parentForm=lb},$setDirty:function(){this.$$animate.removeClass(this.$$element,Za);this.$$animate.addClass(this.$$element,Vb);this.$dirty=!0;this.$pristine=!1;this.$$parentForm.$setDirty()},$setPristine:function(){this.$$animate.setClass(this.$$element,
|
||||
Za,Vb+" ng-submitted");this.$dirty=!1;this.$pristine=!0;this.$submitted=!1;r(this.$$controls,function(a){a.$setPristine()})},$setUntouched:function(){r(this.$$controls,function(a){a.$setUntouched()})},$setSubmitted:function(){for(var a=this;a.$$parentForm&&a.$$parentForm!==lb;)a=a.$$parentForm;a.$$setSubmitted()},$$setSubmitted:function(){this.$$animate.addClass(this.$$element,"ng-submitted");this.$submitted=!0;r(this.$$controls,function(a){a.$$setSubmitted&&a.$$setSubmitted()})}};ae({clazz:Pb,set:function(a,
|
||||
b,d){var c=a[b];c?-1===c.indexOf(d)&&c.push(d):a[b]=[d]},unset:function(a,b,d){var c=a[b];c&&(cb(c,d),0===c.length&&delete a[b])}});var ke=function(a){return["$timeout","$parse",function(b,d){function c(a){return""===a?d('this[""]').assign:d(a).assign||E}return{name:"form",restrict:a?"EAC":"E",require:["form","^^?form"],controller:Pb,compile:function(d,f){d.addClass(Za).addClass(mb);var g=f.name?"name":a&&f.ngForm?"ngForm":!1;return{pre:function(a,d,e,f){var p=f[0];if(!("action"in e)){var n=function(b){a.$apply(function(){p.$commitViewValue();
|
||||
p.$setSubmitted()});b.preventDefault()};d[0].addEventListener("submit",n);d.on("$destroy",function(){b(function(){d[0].removeEventListener("submit",n)},0,!1)})}(f[1]||p.$$parentForm).$addControl(p);var s=g?c(p.$name):E;g&&(s(a,p),e.$observe(g,function(b){p.$name!==b&&(s(a,void 0),p.$$parentForm.$$renameControl(p,b),s=c(p.$name),s(a,p))}));d.on("$destroy",function(){p.$$parentForm.$removeControl(p);s(a,void 0);S(p,lb)})}}}}}]},Ne=ke(),Ze=ke(!0),hh=/^\d{4,}-[01]\d-[0-3]\dT[0-2]\d:[0-5]\d:[0-5]\d\.\d+(?:[+-][0-2]\d:[0-5]\d|Z)$/,
|
||||
sh=/^[a-z][a-z\d.+-]*:\/*(?:[^:@]+(?::[^@]+)?@)?(?:[^\s:/?#]+|\[[a-f\d:]+])(?::\d+)?(?:\/[^?#]*)?(?:\?[^#]*)?(?:#.*)?$/i,th=/^(?=.{1,254}$)(?=.{1,64}@)[-!#$%&'*+/0-9=?A-Z^_`a-z{|}~]+(\.[-!#$%&'*+/0-9=?A-Z^_`a-z{|}~]+)*@[A-Za-z0-9]([A-Za-z0-9-]{0,61}[A-Za-z0-9])?(\.[A-Za-z0-9]([A-Za-z0-9-]{0,61}[A-Za-z0-9])?)*$/,ih=/^\s*(-|\+)?(\d+|(\d*(\.\d*)))([eE][+-]?\d+)?\s*$/,le=/^(\d{4,})-(\d{2})-(\d{2})$/,me=/^(\d{4,})-(\d\d)-(\d\d)T(\d\d):(\d\d)(?::(\d\d)(\.\d{1,3})?)?$/,Mc=/^(\d{4,})-W(\d\d)$/,ne=/^(\d{4,})-(\d\d)$/,
|
||||
oe=/^(\d\d):(\d\d)(?::(\d\d)(\.\d{1,3})?)?$/,ce=T();r(["date","datetime-local","month","time","week"],function(a){ce[a]=!0});var pe={text:function(a,b,d,c,e,f){Sa(a,b,d,c,e,f);Hc(c)},date:nb("date",le,Qb(le,["yyyy","MM","dd"]),"yyyy-MM-dd"),"datetime-local":nb("datetimelocal",me,Qb(me,"yyyy MM dd HH mm ss sss".split(" ")),"yyyy-MM-ddTHH:mm:ss.sss"),time:nb("time",oe,Qb(oe,["HH","mm","ss","sss"]),"HH:mm:ss.sss"),week:nb("week",Mc,function(a,b){if(ha(a))return a;if(A(a)){Mc.lastIndex=0;var d=Mc.exec(a);
|
||||
if(d){var c=+d[1],e=+d[2],f=d=0,g=0,k=0,h=Xd(c),e=7*(e-1);b&&(d=b.getHours(),f=b.getMinutes(),g=b.getSeconds(),k=b.getMilliseconds());return new Date(c,0,h.getDate()+e,d,f,g,k)}}return NaN},"yyyy-Www"),month:nb("month",ne,Qb(ne,["yyyy","MM"]),"yyyy-MM"),number:function(a,b,d,c,e,f,g,k){Ic(a,b,d,c,"number");de(c);Sa(a,b,d,c,e,f);var h;if(w(d.min)||d.ngMin){var l=d.min||k(d.ngMin)(a);h=na(l);c.$validators.min=function(a,b){return c.$isEmpty(b)||z(h)||b>=h};d.$observe("min",function(a){a!==l&&(h=na(a),
|
||||
l=a,c.$validate())})}if(w(d.max)||d.ngMax){var m=d.max||k(d.ngMax)(a),p=na(m);c.$validators.max=function(a,b){return c.$isEmpty(b)||z(p)||b<=p};d.$observe("max",function(a){a!==m&&(p=na(a),m=a,c.$validate())})}if(w(d.step)||d.ngStep){var n=d.step||k(d.ngStep)(a),s=na(n);c.$validators.step=function(a,b){return c.$isEmpty(b)||z(s)||ee(b,h||0,s)};d.$observe("step",function(a){a!==n&&(s=na(a),n=a,c.$validate())})}},url:function(a,b,d,c,e,f){Sa(a,b,d,c,e,f);Hc(c);c.$validators.url=function(a,b){var d=
|
||||
a||b;return c.$isEmpty(d)||sh.test(d)}},email:function(a,b,d,c,e,f){Sa(a,b,d,c,e,f);Hc(c);c.$validators.email=function(a,b){var d=a||b;return c.$isEmpty(d)||th.test(d)}},radio:function(a,b,d,c){var e=!d.ngTrim||"false"!==U(d.ngTrim);z(d.name)&&b.attr("name",++pb);b.on("change",function(a){var g;b[0].checked&&(g=d.value,e&&(g=U(g)),c.$setViewValue(g,a&&a.type))});c.$render=function(){var a=d.value;e&&(a=U(a));b[0].checked=a===c.$viewValue};d.$observe("value",c.$render)},range:function(a,b,d,c,e,f){function g(a,
|
||||
c){b.attr(a,d[a]);var e=d[a];d.$observe(a,function(a){a!==e&&(e=a,c(a))})}function k(a){p=na(a);X(c.$modelValue)||(m?(a=b.val(),p>a&&(a=p,b.val(a)),c.$setViewValue(a)):c.$validate())}function h(a){n=na(a);X(c.$modelValue)||(m?(a=b.val(),n<a&&(b.val(n),a=n<p?p:n),c.$setViewValue(a)):c.$validate())}function l(a){s=na(a);X(c.$modelValue)||(m?c.$viewValue!==b.val()&&c.$setViewValue(b.val()):c.$validate())}Ic(a,b,d,c,"range");de(c);Sa(a,b,d,c,e,f);var m=c.$$hasNativeValidators&&"range"===b[0].type,p=m?
|
||||
0:void 0,n=m?100:void 0,s=m?1:void 0,r=b[0].validity;a=w(d.min);e=w(d.max);f=w(d.step);var q=c.$render;c.$render=m&&w(r.rangeUnderflow)&&w(r.rangeOverflow)?function(){q();c.$setViewValue(b.val())}:q;a&&(p=na(d.min),c.$validators.min=m?function(){return!0}:function(a,b){return c.$isEmpty(b)||z(p)||b>=p},g("min",k));e&&(n=na(d.max),c.$validators.max=m?function(){return!0}:function(a,b){return c.$isEmpty(b)||z(n)||b<=n},g("max",h));f&&(s=na(d.step),c.$validators.step=m?function(){return!r.stepMismatch}:
|
||||
function(a,b){return c.$isEmpty(b)||z(s)||ee(b,p||0,s)},g("step",l))},checkbox:function(a,b,d,c,e,f,g,k){var h=fe(k,a,"ngTrueValue",d.ngTrueValue,!0),l=fe(k,a,"ngFalseValue",d.ngFalseValue,!1);b.on("change",function(a){c.$setViewValue(b[0].checked,a&&a.type)});c.$render=function(){b[0].checked=c.$viewValue};c.$isEmpty=function(a){return!1===a};c.$formatters.push(function(a){return va(a,h)});c.$parsers.push(function(a){return a?h:l})},hidden:E,button:E,submit:E,reset:E,file:E},Yc=["$browser","$sniffer",
|
||||
"$filter","$parse",function(a,b,d,c){return{restrict:"E",require:["?ngModel"],link:{pre:function(e,f,g,k){k[0]&&(pe[K(g.type)]||pe.text)(e,f,g,k[0],b,a,d,c)}}}}],vf=function(){var a={configurable:!0,enumerable:!1,get:function(){return this.getAttribute("value")||""},set:function(a){this.setAttribute("value",a)}};return{restrict:"E",priority:200,compile:function(b,d){if("hidden"===K(d.type))return{pre:function(b,d,f,g){b=d[0];b.parentNode&&b.parentNode.insertBefore(b,b.nextSibling);Object.defineProperty&&
|
||||
Object.defineProperty(b,"value",a)}}}}},uh=/^(true|false|\d+)$/,sf=function(){function a(a,d,c){var e=w(c)?c:9===Ca?"":null;a.prop("value",e);d.$set("value",c)}return{restrict:"A",priority:100,compile:function(b,d){return uh.test(d.ngValue)?function(b,d,f){b=b.$eval(f.ngValue);a(d,f,b)}:function(b,d,f){b.$watch(f.ngValue,function(b){a(d,f,b)})}}}},Re=["$compile",function(a){return{restrict:"AC",compile:function(b){a.$$addBindingClass(b);return function(b,c,e){a.$$addBindingInfo(c,e.ngBind);c=c[0];
|
||||
b.$watch(e.ngBind,function(a){c.textContent=ic(a)})}}}}],Te=["$interpolate","$compile",function(a,b){return{compile:function(d){b.$$addBindingClass(d);return function(c,d,f){c=a(d.attr(f.$attr.ngBindTemplate));b.$$addBindingInfo(d,c.expressions);d=d[0];f.$observe("ngBindTemplate",function(a){d.textContent=z(a)?"":a})}}}}],Se=["$sce","$parse","$compile",function(a,b,d){return{restrict:"A",compile:function(c,e){var f=b(e.ngBindHtml),g=b(e.ngBindHtml,function(b){return a.valueOf(b)});d.$$addBindingClass(c);
|
||||
return function(b,c,e){d.$$addBindingInfo(c,e.ngBindHtml);b.$watch(g,function(){var d=f(b);c.html(a.getTrustedHtml(d)||"")})}}}}],rf=ia({restrict:"A",require:"ngModel",link:function(a,b,d,c){c.$viewChangeListeners.push(function(){a.$eval(d.ngChange)})}}),Ue=Kc("",!0),We=Kc("Odd",0),Ve=Kc("Even",1),Xe=Ra({compile:function(a,b){b.$set("ngCloak",void 0);a.removeClass("ng-cloak")}}),Ye=[function(){return{restrict:"A",scope:!0,controller:"@",priority:500}}],cd={},vh={blur:!0,focus:!0};r("click dblclick mousedown mouseup mouseover mouseout mousemove mouseenter mouseleave keydown keyup keypress submit focus blur copy cut paste".split(" "),
|
||||
function(a){var b=wa("ng-"+a);cd[b]=["$parse","$rootScope","$exceptionHandler",function(d,c,e){return qd(d,c,e,b,a,vh[a])}]});var af=["$animate","$compile",function(a,b){return{multiElement:!0,transclude:"element",priority:600,terminal:!0,restrict:"A",$$tlb:!0,link:function(d,c,e,f,g){var k,h,l;d.$watch(e.ngIf,function(d){d?h||g(function(d,f){h=f;d[d.length++]=b.$$createComment("end ngIf",e.ngIf);k={clone:d};a.enter(d,c.parent(),c)}):(l&&(l.remove(),l=null),h&&(h.$destroy(),h=null),k&&(l=tb(k.clone),
|
||||
a.leave(l).done(function(a){!1!==a&&(l=null)}),k=null))})}}}],bf=["$templateRequest","$anchorScroll","$animate",function(a,b,d){return{restrict:"ECA",priority:400,terminal:!0,transclude:"element",controller:ca.noop,compile:function(c,e){var f=e.ngInclude||e.src,g=e.onload||"",k=e.autoscroll;return function(c,e,m,p,n){var r=0,q,t,x,v=function(){t&&(t.remove(),t=null);q&&(q.$destroy(),q=null);x&&(d.leave(x).done(function(a){!1!==a&&(t=null)}),t=x,x=null)};c.$watch(f,function(f){var m=function(a){!1===
|
||||
a||!w(k)||k&&!c.$eval(k)||b()},t=++r;f?(a(f,!0).then(function(a){if(!c.$$destroyed&&t===r){var b=c.$new();p.template=a;a=n(b,function(a){v();d.enter(a,null,e).done(m)});q=b;x=a;q.$emit("$includeContentLoaded",f);c.$eval(g)}},function(){c.$$destroyed||t!==r||(v(),c.$emit("$includeContentError",f))}),c.$emit("$includeContentRequested",f)):(v(),p.template=null)})}}}}],uf=["$compile",function(a){return{restrict:"ECA",priority:-400,require:"ngInclude",link:function(b,d,c,e){la.call(d[0]).match(/SVG/)?
|
||||
(d.empty(),a(ed(e.template,C.document).childNodes)(b,function(a){d.append(a)},{futureParentElement:d})):(d.html(e.template),a(d.contents())(b))}}}],cf=Ra({priority:450,compile:function(){return{pre:function(a,b,d){a.$eval(d.ngInit)}}}}),qf=function(){return{restrict:"A",priority:100,require:"ngModel",link:function(a,b,d,c){var e=d.ngList||", ",f="false"!==d.ngTrim,g=f?U(e):e;c.$parsers.push(function(a){if(!z(a)){var b=[];a&&r(a.split(g),function(a){a&&b.push(f?U(a):a)});return b}});c.$formatters.push(function(a){if(H(a))return a.join(e)});
|
||||
c.$isEmpty=function(a){return!a||!a.length}}}},mb="ng-valid",$d="ng-invalid",Za="ng-pristine",Vb="ng-dirty",ob=F("ngModel");Rb.$inject="$scope $exceptionHandler $attrs $element $parse $animate $timeout $q $interpolate".split(" ");Rb.prototype={$$initGetterSetters:function(){if(this.$options.getOption("getterSetter")){var a=this.$$parse(this.$$attr.ngModel+"()"),b=this.$$parse(this.$$attr.ngModel+"($$$p)");this.$$ngModelGet=function(b){var c=this.$$parsedNgModel(b);B(c)&&(c=a(b));return c};this.$$ngModelSet=
|
||||
function(a,c){B(this.$$parsedNgModel(a))?b(a,{$$$p:c}):this.$$parsedNgModelAssign(a,c)}}else if(!this.$$parsedNgModel.assign)throw ob("nonassign",this.$$attr.ngModel,za(this.$$element));},$render:E,$isEmpty:function(a){return z(a)||""===a||null===a||a!==a},$$updateEmptyClasses:function(a){this.$isEmpty(a)?(this.$$animate.removeClass(this.$$element,"ng-not-empty"),this.$$animate.addClass(this.$$element,"ng-empty")):(this.$$animate.removeClass(this.$$element,"ng-empty"),this.$$animate.addClass(this.$$element,
|
||||
"ng-not-empty"))},$setPristine:function(){this.$dirty=!1;this.$pristine=!0;this.$$animate.removeClass(this.$$element,Vb);this.$$animate.addClass(this.$$element,Za)},$setDirty:function(){this.$dirty=!0;this.$pristine=!1;this.$$animate.removeClass(this.$$element,Za);this.$$animate.addClass(this.$$element,Vb);this.$$parentForm.$setDirty()},$setUntouched:function(){this.$touched=!1;this.$untouched=!0;this.$$animate.setClass(this.$$element,"ng-untouched","ng-touched")},$setTouched:function(){this.$touched=
|
||||
!0;this.$untouched=!1;this.$$animate.setClass(this.$$element,"ng-touched","ng-untouched")},$rollbackViewValue:function(){this.$$timeout.cancel(this.$$pendingDebounce);this.$viewValue=this.$$lastCommittedViewValue;this.$render()},$validate:function(){if(!X(this.$modelValue)){var a=this.$$lastCommittedViewValue,b=this.$$rawModelValue,d=this.$valid,c=this.$modelValue,e=this.$options.getOption("allowInvalid"),f=this;this.$$runValidators(b,a,function(a){e||d===a||(f.$modelValue=a?b:void 0,f.$modelValue!==
|
||||
c&&f.$$writeModelToScope())})}},$$runValidators:function(a,b,d){function c(){var c=!0;r(h.$validators,function(d,e){var g=Boolean(d(a,b));c=c&&g;f(e,g)});return c?!0:(r(h.$asyncValidators,function(a,b){f(b,null)}),!1)}function e(){var c=[],d=!0;r(h.$asyncValidators,function(e,g){var h=e(a,b);if(!h||!B(h.then))throw ob("nopromise",h);f(g,void 0);c.push(h.then(function(){f(g,!0)},function(){d=!1;f(g,!1)}))});c.length?h.$$q.all(c).then(function(){g(d)},E):g(!0)}function f(a,b){k===h.$$currentValidationRunId&&
|
||||
h.$setValidity(a,b)}function g(a){k===h.$$currentValidationRunId&&d(a)}this.$$currentValidationRunId++;var k=this.$$currentValidationRunId,h=this;(function(){var a=h.$$parserName;if(z(h.$$parserValid))f(a,null);else return h.$$parserValid||(r(h.$validators,function(a,b){f(b,null)}),r(h.$asyncValidators,function(a,b){f(b,null)})),f(a,h.$$parserValid),h.$$parserValid;return!0})()?c()?e():g(!1):g(!1)},$commitViewValue:function(){var a=this.$viewValue;this.$$timeout.cancel(this.$$pendingDebounce);if(this.$$lastCommittedViewValue!==
|
||||
a||""===a&&this.$$hasNativeValidators)this.$$updateEmptyClasses(a),this.$$lastCommittedViewValue=a,this.$pristine&&this.$setDirty(),this.$$parseAndValidate()},$$parseAndValidate:function(){var a=this.$$lastCommittedViewValue,b=this;this.$$parserValid=z(a)?void 0:!0;this.$setValidity(this.$$parserName,null);this.$$parserName="parse";if(this.$$parserValid)for(var d=0;d<this.$parsers.length;d++)if(a=this.$parsers[d](a),z(a)){this.$$parserValid=!1;break}X(this.$modelValue)&&(this.$modelValue=this.$$ngModelGet(this.$$scope));
|
||||
var c=this.$modelValue,e=this.$options.getOption("allowInvalid");this.$$rawModelValue=a;e&&(this.$modelValue=a,b.$modelValue!==c&&b.$$writeModelToScope());this.$$runValidators(a,this.$$lastCommittedViewValue,function(d){e||(b.$modelValue=d?a:void 0,b.$modelValue!==c&&b.$$writeModelToScope())})},$$writeModelToScope:function(){this.$$ngModelSet(this.$$scope,this.$modelValue);r(this.$viewChangeListeners,function(a){try{a()}catch(b){this.$$exceptionHandler(b)}},this)},$setViewValue:function(a,b){this.$viewValue=
|
||||
a;this.$options.getOption("updateOnDefault")&&this.$$debounceViewValueCommit(b)},$$debounceViewValueCommit:function(a){var b=this.$options.getOption("debounce");W(b[a])?b=b[a]:W(b["default"])&&-1===this.$options.getOption("updateOn").indexOf(a)?b=b["default"]:W(b["*"])&&(b=b["*"]);this.$$timeout.cancel(this.$$pendingDebounce);var d=this;0<b?this.$$pendingDebounce=this.$$timeout(function(){d.$commitViewValue()},b):this.$$rootScope.$$phase?this.$commitViewValue():this.$$scope.$apply(function(){d.$commitViewValue()})},
|
||||
$overrideModelOptions:function(a){this.$options=this.$options.createChild(a);this.$$setUpdateOnEvents()},$processModelValue:function(){var a=this.$$format();this.$viewValue!==a&&(this.$$updateEmptyClasses(a),this.$viewValue=this.$$lastCommittedViewValue=a,this.$render(),this.$$runValidators(this.$modelValue,this.$viewValue,E))},$$format:function(){for(var a=this.$formatters,b=a.length,d=this.$modelValue;b--;)d=a[b](d);return d},$$setModelValue:function(a){this.$modelValue=this.$$rawModelValue=a;this.$$parserValid=
|
||||
void 0;this.$processModelValue()},$$setUpdateOnEvents:function(){this.$$updateEvents&&this.$$element.off(this.$$updateEvents,this.$$updateEventHandler);if(this.$$updateEvents=this.$options.getOption("updateOn"))this.$$element.on(this.$$updateEvents,this.$$updateEventHandler)},$$updateEventHandler:function(a){this.$$debounceViewValueCommit(a&&a.type)}};ae({clazz:Rb,set:function(a,b){a[b]=!0},unset:function(a,b){delete a[b]}});var pf=["$rootScope",function(a){return{restrict:"A",require:["ngModel",
|
||||
"^?form","^?ngModelOptions"],controller:Rb,priority:1,compile:function(b){b.addClass(Za).addClass("ng-untouched").addClass(mb);return{pre:function(a,b,e,f){var g=f[0];b=f[1]||g.$$parentForm;if(f=f[2])g.$options=f.$options;g.$$initGetterSetters();b.$addControl(g);e.$observe("name",function(a){g.$name!==a&&g.$$parentForm.$$renameControl(g,a)});a.$on("$destroy",function(){g.$$parentForm.$removeControl(g)})},post:function(b,c,e,f){function g(){k.$setTouched()}var k=f[0];k.$$setUpdateOnEvents();c.on("blur",
|
||||
function(){k.$touched||(a.$$phase?b.$evalAsync(g):b.$apply(g))})}}}}}],Sb,wh=/(\s+|^)default(\s+|$)/;Lc.prototype={getOption:function(a){return this.$$options[a]},createChild:function(a){var b=!1;a=S({},a);r(a,function(d,c){"$inherit"===d?"*"===c?b=!0:(a[c]=this.$$options[c],"updateOn"===c&&(a.updateOnDefault=this.$$options.updateOnDefault)):"updateOn"===c&&(a.updateOnDefault=!1,a[c]=U(d.replace(wh,function(){a.updateOnDefault=!0;return" "})))},this);b&&(delete a["*"],ge(a,this.$$options));ge(a,Sb.$$options);
|
||||
return new Lc(a)}};Sb=new Lc({updateOn:"",updateOnDefault:!0,debounce:0,getterSetter:!1,allowInvalid:!1,timezone:null});var tf=function(){function a(a,d){this.$$attrs=a;this.$$scope=d}a.$inject=["$attrs","$scope"];a.prototype={$onInit:function(){var a=this.parentCtrl?this.parentCtrl.$options:Sb,d=this.$$scope.$eval(this.$$attrs.ngModelOptions);this.$options=a.createChild(d)}};return{restrict:"A",priority:10,require:{parentCtrl:"?^^ngModelOptions"},bindToController:!0,controller:a}},df=Ra({terminal:!0,
|
||||
priority:1E3}),xh=F("ngOptions"),yh=/^\s*([\s\S]+?)(?:\s+as\s+([\s\S]+?))?(?:\s+group\s+by\s+([\s\S]+?))?(?:\s+disable\s+when\s+([\s\S]+?))?\s+for\s+(?:([$\w][$\w]*)|(?:\(\s*([$\w][$\w]*)\s*,\s*([$\w][$\w]*)\s*\)))\s+in\s+([\s\S]+?)(?:\s+track\s+by\s+([\s\S]+?))?$/,nf=["$compile","$document","$parse",function(a,b,d){function c(a,b,c){function e(a,b,c,d,f){this.selectValue=a;this.viewValue=b;this.label=c;this.group=d;this.disabled=f}function f(a){var b;if(!r&&ya(a))b=a;else{b=[];for(var c in a)a.hasOwnProperty(c)&&
|
||||
"$"!==c.charAt(0)&&b.push(c)}return b}var p=a.match(yh);if(!p)throw xh("iexp",a,za(b));var n=p[5]||p[7],r=p[6];a=/ as /.test(p[0])&&p[1];var q=p[9];b=d(p[2]?p[1]:n);var t=a&&d(a)||b,w=q&&d(q),v=q?function(a,b){return w(c,b)}:function(a){return La(a)},x=function(a,b){return v(a,A(a,b))},z=d(p[2]||p[1]),y=d(p[3]||""),J=d(p[4]||""),I=d(p[8]),B={},A=r?function(a,b){B[r]=b;B[n]=a;return B}:function(a){B[n]=a;return B};return{trackBy:q,getTrackByValue:x,getWatchables:d(I,function(a){var b=[];a=a||[];for(var d=
|
||||
f(a),e=d.length,g=0;g<e;g++){var k=a===d?g:d[g],l=a[k],k=A(l,k),l=v(l,k);b.push(l);if(p[2]||p[1])l=z(c,k),b.push(l);p[4]&&(k=J(c,k),b.push(k))}return b}),getOptions:function(){for(var a=[],b={},d=I(c)||[],g=f(d),k=g.length,n=0;n<k;n++){var p=d===g?n:g[n],r=A(d[p],p),s=t(c,r),p=v(s,r),w=z(c,r),B=y(c,r),r=J(c,r),s=new e(p,s,w,B,r);a.push(s);b[p]=s}return{items:a,selectValueMap:b,getOptionFromViewValue:function(a){return b[x(a)]},getViewValueFromOption:function(a){return q?Ia(a.viewValue):a.viewValue}}}}}
|
||||
var e=C.document.createElement("option"),f=C.document.createElement("optgroup");return{restrict:"A",terminal:!0,require:["select","ngModel"],link:{pre:function(a,b,c,d){d[0].registerOption=E},post:function(d,k,h,l){function m(a){var b=(a=v.getOptionFromViewValue(a))&&a.element;b&&!b.selected&&(b.selected=!0);return a}function p(a,b){a.element=b;b.disabled=a.disabled;a.label!==b.label&&(b.label=a.label,b.textContent=a.label);b.value=a.selectValue}var n=l[0],q=l[1],z=h.multiple;l=0;for(var t=k.children(),
|
||||
B=t.length;l<B;l++)if(""===t[l].value){n.hasEmptyOption=!0;n.emptyOption=t.eq(l);break}k.empty();l=!!n.emptyOption;x(e.cloneNode(!1)).val("?");var v,A=c(h.ngOptions,k,d),C=b[0].createDocumentFragment();n.generateUnknownOptionValue=function(a){return"?"};z?(n.writeValue=function(a){if(v){var b=a&&a.map(m)||[];v.items.forEach(function(a){a.element.selected&&-1===Array.prototype.indexOf.call(b,a)&&(a.element.selected=!1)})}},n.readValue=function(){var a=k.val()||[],b=[];r(a,function(a){(a=v.selectValueMap[a])&&
|
||||
!a.disabled&&b.push(v.getViewValueFromOption(a))});return b},A.trackBy&&d.$watchCollection(function(){if(H(q.$viewValue))return q.$viewValue.map(function(a){return A.getTrackByValue(a)})},function(){q.$render()})):(n.writeValue=function(a){if(v){var b=k[0].options[k[0].selectedIndex],c=v.getOptionFromViewValue(a);b&&b.removeAttribute("selected");c?(k[0].value!==c.selectValue&&(n.removeUnknownOption(),k[0].value=c.selectValue,c.element.selected=!0),c.element.setAttribute("selected","selected")):n.selectUnknownOrEmptyOption(a)}},
|
||||
n.readValue=function(){var a=v.selectValueMap[k.val()];return a&&!a.disabled?(n.unselectEmptyOption(),n.removeUnknownOption(),v.getViewValueFromOption(a)):null},A.trackBy&&d.$watch(function(){return A.getTrackByValue(q.$viewValue)},function(){q.$render()}));l&&(a(n.emptyOption)(d),k.prepend(n.emptyOption),8===n.emptyOption[0].nodeType?(n.hasEmptyOption=!1,n.registerOption=function(a,b){""===b.val()&&(n.hasEmptyOption=!0,n.emptyOption=b,n.emptyOption.removeClass("ng-scope"),q.$render(),b.on("$destroy",
|
||||
function(){var a=n.$isEmptyOptionSelected();n.hasEmptyOption=!1;n.emptyOption=void 0;a&&q.$render()}))}):n.emptyOption.removeClass("ng-scope"));d.$watchCollection(A.getWatchables,function(){var a=v&&n.readValue();if(v)for(var b=v.items.length-1;0<=b;b--){var c=v.items[b];w(c.group)?Fb(c.element.parentNode):Fb(c.element)}v=A.getOptions();var d={};v.items.forEach(function(a){var b;if(w(a.group)){b=d[a.group];b||(b=f.cloneNode(!1),C.appendChild(b),b.label=null===a.group?"null":a.group,d[a.group]=b);
|
||||
var c=e.cloneNode(!1);b.appendChild(c);p(a,c)}else b=e.cloneNode(!1),C.appendChild(b),p(a,b)});k[0].appendChild(C);q.$render();q.$isEmpty(a)||(b=n.readValue(),(A.trackBy||z?va(a,b):a===b)||(q.$setViewValue(b),q.$render()))})}}}}],ef=["$locale","$interpolate","$log",function(a,b,d){var c=/{}/g,e=/^when(Minus)?(.+)$/;return{link:function(f,g,k){function h(a){g.text(a||"")}var l=k.count,m=k.$attr.when&&g.attr(k.$attr.when),p=k.offset||0,n=f.$eval(m)||{},q={},w=b.startSymbol(),t=b.endSymbol(),x=w+l+"-"+
|
||||
p+t,v=ca.noop,A;r(k,function(a,b){var c=e.exec(b);c&&(c=(c[1]?"-":"")+K(c[2]),n[c]=g.attr(k.$attr[b]))});r(n,function(a,d){q[d]=b(a.replace(c,x))});f.$watch(l,function(b){var c=parseFloat(b),e=X(c);e||c in n||(c=a.pluralCat(c-p));c===A||e&&X(A)||(v(),e=q[c],z(e)?(null!=b&&d.debug("ngPluralize: no rule defined for '"+c+"' in "+m),v=E,h()):v=f.$watch(e,h),A=c)})}}}],qe=F("ngRef"),ff=["$parse",function(a){return{priority:-1,restrict:"A",compile:function(b,d){var c=wa(ua(b)),e=a(d.ngRef),f=e.assign||
|
||||
function(){throw qe("nonassign",d.ngRef);};return function(a,b,h){var l;if(h.hasOwnProperty("ngRefRead"))if("$element"===h.ngRefRead)l=b;else{if(l=b.data("$"+h.ngRefRead+"Controller"),!l)throw qe("noctrl",h.ngRefRead,d.ngRef);}else l=b.data("$"+c+"Controller");l=l||b;f(a,l);b.on("$destroy",function(){e(a)===l&&f(a,null)})}}}}],gf=["$parse","$animate","$compile",function(a,b,d){var c=F("ngRepeat"),e=function(a,b,c,d,e,f,g){a[c]=d;e&&(a[e]=f);a.$index=b;a.$first=0===b;a.$last=b===g-1;a.$middle=!(a.$first||
|
||||
a.$last);a.$odd=!(a.$even=0===(b&1))},f=function(a,b,c){return La(c)},g=function(a,b){return b};return{restrict:"A",multiElement:!0,transclude:"element",priority:1E3,terminal:!0,$$tlb:!0,compile:function(k,h){var l=h.ngRepeat,m=d.$$createComment("end ngRepeat",l),p=l.match(/^\s*([\s\S]+?)\s+in\s+([\s\S]+?)(?:\s+as\s+([\s\S]+?))?(?:\s+track\s+by\s+([\s\S]+?))?\s*$/);if(!p)throw c("iexp",l);var n=p[1],q=p[2],w=p[3],t=p[4],p=n.match(/^(?:(\s*[$\w]+)|\(\s*([$\w]+)\s*,\s*([$\w]+)\s*\))$/);if(!p)throw c("iidexp",
|
||||
n);var x=p[3]||p[1],v=p[2];if(w&&(!/^[$a-zA-Z_][$a-zA-Z0-9_]*$/.test(w)||/^(null|undefined|this|\$index|\$first|\$middle|\$last|\$even|\$odd|\$parent|\$root|\$id)$/.test(w)))throw c("badident",w);var z;if(t){var A={$id:La},y=a(t);z=function(a,b,c,d){v&&(A[v]=b);A[x]=c;A.$index=d;return y(a,A)}}return function(a,d,h,k,n){var p=T();a.$watchCollection(q,function(h){var k,q,t=d[0],s,y=T(),B,C,E,D,H,F,K;w&&(a[w]=h);if(ya(h))H=h,q=z||f;else for(K in q=z||g,H=[],h)ta.call(h,K)&&"$"!==K.charAt(0)&&H.push(K);
|
||||
B=H.length;K=Array(B);for(k=0;k<B;k++)if(C=h===H?k:H[k],E=h[C],D=q(a,C,E,k),p[D])F=p[D],delete p[D],y[D]=F,K[k]=F;else{if(y[D])throw r(K,function(a){a&&a.scope&&(p[a.id]=a)}),c("dupes",l,D,E);K[k]={id:D,scope:void 0,clone:void 0};y[D]=!0}A&&(A[x]=void 0);for(s in p){F=p[s];D=tb(F.clone);b.leave(D);if(D[0].parentNode)for(k=0,q=D.length;k<q;k++)D[k].$$NG_REMOVED=!0;F.scope.$destroy()}for(k=0;k<B;k++)if(C=h===H?k:H[k],E=h[C],F=K[k],F.scope){s=t;do s=s.nextSibling;while(s&&s.$$NG_REMOVED);F.clone[0]!==
|
||||
s&&b.move(tb(F.clone),null,t);t=F.clone[F.clone.length-1];e(F.scope,k,x,E,v,C,B)}else n(function(a,c){F.scope=c;var d=m.cloneNode(!1);a[a.length++]=d;b.enter(a,null,t);t=d;F.clone=a;y[F.id]=F;e(F.scope,k,x,E,v,C,B)});p=y})}}}}],hf=["$animate",function(a){return{restrict:"A",multiElement:!0,link:function(b,d,c){b.$watch(c.ngShow,function(b){a[b?"removeClass":"addClass"](d,"ng-hide",{tempClasses:"ng-hide-animate"})})}}}],$e=["$animate",function(a){return{restrict:"A",multiElement:!0,link:function(b,
|
||||
d,c){b.$watch(c.ngHide,function(b){a[b?"addClass":"removeClass"](d,"ng-hide",{tempClasses:"ng-hide-animate"})})}}}],jf=Ra(function(a,b,d){a.$watchCollection(d.ngStyle,function(a,d){d&&a!==d&&(a||(a={}),r(d,function(b,d){null==a[d]&&(a[d]="")}));a&&b.css(a)})}),kf=["$animate","$compile",function(a,b){return{require:"ngSwitch",controller:["$scope",function(){this.cases={}}],link:function(d,c,e,f){var g=[],k=[],h=[],l=[],m=function(a,b){return function(c){!1!==c&&a.splice(b,1)}};d.$watch(e.ngSwitch||
|
||||
e.on,function(c){for(var d,e;h.length;)a.cancel(h.pop());d=0;for(e=l.length;d<e;++d){var q=tb(k[d].clone);l[d].$destroy();(h[d]=a.leave(q)).done(m(h,d))}k.length=0;l.length=0;(g=f.cases["!"+c]||f.cases["?"])&&r(g,function(c){c.transclude(function(d,e){l.push(e);var f=c.element;d[d.length++]=b.$$createComment("end ngSwitchWhen");k.push({clone:d});a.enter(d,f.parent(),f)})})})}}}],lf=Ra({transclude:"element",priority:1200,require:"^ngSwitch",multiElement:!0,link:function(a,b,d,c,e){a=d.ngSwitchWhen.split(d.ngSwitchWhenSeparator).sort().filter(function(a,
|
||||
b,c){return c[b-1]!==a});r(a,function(a){c.cases["!"+a]=c.cases["!"+a]||[];c.cases["!"+a].push({transclude:e,element:b})})}}),mf=Ra({transclude:"element",priority:1200,require:"^ngSwitch",multiElement:!0,link:function(a,b,d,c,e){c.cases["?"]=c.cases["?"]||[];c.cases["?"].push({transclude:e,element:b})}}),zh=F("ngTransclude"),of=["$compile",function(a){return{restrict:"EAC",compile:function(b){var d=a(b.contents());b.empty();return function(a,b,f,g,k){function h(){d(a,function(a){b.append(a)})}if(!k)throw zh("orphan",
|
||||
za(b));f.ngTransclude===f.$attr.ngTransclude&&(f.ngTransclude="");f=f.ngTransclude||f.ngTranscludeSlot;k(function(a,c){var d;if(d=a.length)a:{d=0;for(var f=a.length;d<f;d++){var g=a[d];if(g.nodeType!==Pa||g.nodeValue.trim()){d=!0;break a}}d=void 0}d?b.append(a):(h(),c.$destroy())},null,f);f&&!k.isSlotFilled(f)&&h()}}}}],Oe=["$templateCache",function(a){return{restrict:"E",terminal:!0,compile:function(b,d){"text/ng-template"===d.type&&a.put(d.id,b[0].text)}}}],Ah={$setViewValue:E,$render:E},Bh=["$element",
|
||||
"$scope",function(a,b){function d(){g||(g=!0,b.$$postDigest(function(){g=!1;e.ngModelCtrl.$render()}))}function c(a){k||(k=!0,b.$$postDigest(function(){b.$$destroyed||(k=!1,e.ngModelCtrl.$setViewValue(e.readValue()),a&&e.ngModelCtrl.$render())}))}var e=this,f=new Hb;e.selectValueMap={};e.ngModelCtrl=Ah;e.multiple=!1;e.unknownOption=x(C.document.createElement("option"));e.hasEmptyOption=!1;e.emptyOption=void 0;e.renderUnknownOption=function(b){b=e.generateUnknownOptionValue(b);e.unknownOption.val(b);
|
||||
a.prepend(e.unknownOption);Oa(e.unknownOption,!0);a.val(b)};e.updateUnknownOption=function(b){b=e.generateUnknownOptionValue(b);e.unknownOption.val(b);Oa(e.unknownOption,!0);a.val(b)};e.generateUnknownOptionValue=function(a){return"? "+La(a)+" ?"};e.removeUnknownOption=function(){e.unknownOption.parent()&&e.unknownOption.remove()};e.selectEmptyOption=function(){e.emptyOption&&(a.val(""),Oa(e.emptyOption,!0))};e.unselectEmptyOption=function(){e.hasEmptyOption&&Oa(e.emptyOption,!1)};b.$on("$destroy",
|
||||
function(){e.renderUnknownOption=E});e.readValue=function(){var b=a.val(),b=b in e.selectValueMap?e.selectValueMap[b]:b;return e.hasOption(b)?b:null};e.writeValue=function(b){var c=a[0].options[a[0].selectedIndex];c&&Oa(x(c),!1);e.hasOption(b)?(e.removeUnknownOption(),c=La(b),a.val(c in e.selectValueMap?c:b),Oa(x(a[0].options[a[0].selectedIndex]),!0)):e.selectUnknownOrEmptyOption(b)};e.addOption=function(a,b){if(8!==b[0].nodeType){Ja(a,'"option value"');""===a&&(e.hasEmptyOption=!0,e.emptyOption=
|
||||
b);var c=f.get(a)||0;f.set(a,c+1);d()}};e.removeOption=function(a){var b=f.get(a);b&&(1===b?(f.delete(a),""===a&&(e.hasEmptyOption=!1,e.emptyOption=void 0)):f.set(a,b-1))};e.hasOption=function(a){return!!f.get(a)};e.$hasEmptyOption=function(){return e.hasEmptyOption};e.$isUnknownOptionSelected=function(){return a[0].options[0]===e.unknownOption[0]};e.$isEmptyOptionSelected=function(){return e.hasEmptyOption&&a[0].options[a[0].selectedIndex]===e.emptyOption[0]};e.selectUnknownOrEmptyOption=function(a){null==
|
||||
a&&e.emptyOption?(e.removeUnknownOption(),e.selectEmptyOption()):e.unknownOption.parent().length?e.updateUnknownOption(a):e.renderUnknownOption(a)};var g=!1,k=!1;e.registerOption=function(a,b,f,g,k){if(f.$attr.ngValue){var q,r;f.$observe("value",function(a){var d,f=b.prop("selected");w(r)&&(e.removeOption(q),delete e.selectValueMap[r],d=!0);r=La(a);q=a;e.selectValueMap[r]=a;e.addOption(a,b);b.attr("value",r);d&&f&&c()})}else g?f.$observe("value",function(a){e.readValue();var d,f=b.prop("selected");
|
||||
w(q)&&(e.removeOption(q),d=!0);q=a;e.addOption(a,b);d&&f&&c()}):k?a.$watch(k,function(a,d){f.$set("value",a);var g=b.prop("selected");d!==a&&e.removeOption(d);e.addOption(a,b);d&&g&&c()}):e.addOption(f.value,b);f.$observe("disabled",function(a){if("true"===a||a&&b.prop("selected"))e.multiple?c(!0):(e.ngModelCtrl.$setViewValue(null),e.ngModelCtrl.$render())});b.on("$destroy",function(){var a=e.readValue(),b=f.value;e.removeOption(b);d();(e.multiple&&a&&-1!==a.indexOf(b)||a===b)&&c(!0)})}}],Pe=function(){return{restrict:"E",
|
||||
require:["select","?ngModel"],controller:Bh,priority:1,link:{pre:function(a,b,d,c){var e=c[0],f=c[1];if(f){if(e.ngModelCtrl=f,b.on("change",function(){e.removeUnknownOption();a.$apply(function(){f.$setViewValue(e.readValue())})}),d.multiple){e.multiple=!0;e.readValue=function(){var a=[];r(b.find("option"),function(b){b.selected&&!b.disabled&&(b=b.value,a.push(b in e.selectValueMap?e.selectValueMap[b]:b))});return a};e.writeValue=function(a){r(b.find("option"),function(b){var c=!!a&&(-1!==Array.prototype.indexOf.call(a,
|
||||
b.value)||-1!==Array.prototype.indexOf.call(a,e.selectValueMap[b.value]));c!==b.selected&&Oa(x(b),c)})};var g,k=NaN;a.$watch(function(){k!==f.$viewValue||va(g,f.$viewValue)||(g=ja(f.$viewValue),f.$render());k=f.$viewValue});f.$isEmpty=function(a){return!a||0===a.length}}}else e.registerOption=E},post:function(a,b,d,c){var e=c[1];if(e){var f=c[0];e.$render=function(){f.writeValue(e.$viewValue)}}}}}},Qe=["$interpolate",function(a){return{restrict:"E",priority:100,compile:function(b,d){var c,e;w(d.ngValue)||
|
||||
(w(d.value)?c=a(d.value,!0):(e=a(b.text(),!0))||d.$set("value",b.text()));return function(a,b,d){var h=b.parent();(h=h.data("$selectController")||h.parent().data("$selectController"))&&h.registerOption(a,b,d,c,e)}}}}],$c=["$parse",function(a){return{restrict:"A",require:"?ngModel",link:function(b,d,c,e){if(e){var f=c.required||a(c.ngRequired)(b);c.required=!0;e.$validators.required=function(a,b){return!f||!e.$isEmpty(b)};c.$observe("required",function(a){f!==a&&(f=a,e.$validate())})}}}}],Zc=["$parse",
|
||||
function(a){return{restrict:"A",require:"?ngModel",compile:function(b,d){var c,e;d.ngPattern&&(c=d.ngPattern,e="/"===d.ngPattern.charAt(0)&&ie.test(d.ngPattern)?function(){return d.ngPattern}:a(d.ngPattern));return function(a,b,d,h){if(h){var l=d.pattern;d.ngPattern?l=e(a):c=d.pattern;var m=he(l,c,b);d.$observe("pattern",function(a){var d=m;m=he(a,c,b);(d&&d.toString())!==(m&&m.toString())&&h.$validate()});h.$validators.pattern=function(a,b){return h.$isEmpty(b)||z(m)||m.test(b)}}}}}}],bd=["$parse",
|
||||
function(a){return{restrict:"A",require:"?ngModel",link:function(b,d,c,e){if(e){var f=c.maxlength||a(c.ngMaxlength)(b),g=Tb(f);c.$observe("maxlength",function(a){f!==a&&(g=Tb(a),f=a,e.$validate())});e.$validators.maxlength=function(a,b){return 0>g||e.$isEmpty(b)||b.length<=g}}}}}],ad=["$parse",function(a){return{restrict:"A",require:"?ngModel",link:function(b,d,c,e){if(e){var f=c.minlength||a(c.ngMinlength)(b),g=Tb(f)||-1;c.$observe("minlength",function(a){f!==a&&(g=Tb(a)||-1,f=a,e.$validate())});
|
||||
e.$validators.minlength=function(a,b){return e.$isEmpty(b)||b.length>=g}}}}}];C.angular.bootstrap?C.console&&console.log("WARNING: Tried to load AngularJS more than once."):(Fe(),Je(ca),ca.module("ngLocale",[],["$provide",function(a){function b(a){a+="";var b=a.indexOf(".");return-1==b?0:a.length-b-1}a.value("$locale",{DATETIME_FORMATS:{AMPMS:["AM","PM"],DAY:"Sunday Monday Tuesday Wednesday Thursday Friday Saturday".split(" "),ERANAMES:["Before Christ","Anno Domini"],ERAS:["BC","AD"],FIRSTDAYOFWEEK:6,
|
||||
MONTH:"January February March April May June July August September October November December".split(" "),SHORTDAY:"Sun Mon Tue Wed Thu Fri Sat".split(" "),SHORTMONTH:"Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec".split(" "),STANDALONEMONTH:"January February March April May June July August September October November December".split(" "),WEEKENDRANGE:[5,6],fullDate:"EEEE, MMMM d, y",longDate:"MMMM d, y",medium:"MMM d, y h:mm:ss a",mediumDate:"MMM d, y",mediumTime:"h:mm:ss a","short":"M/d/yy h:mm a",
|
||||
shortDate:"M/d/yy",shortTime:"h:mm a"},NUMBER_FORMATS:{CURRENCY_SYM:"$",DECIMAL_SEP:".",GROUP_SEP:",",PATTERNS:[{gSize:3,lgSize:3,maxFrac:3,minFrac:0,minInt:1,negPre:"-",negSuf:"",posPre:"",posSuf:""},{gSize:3,lgSize:3,maxFrac:2,minFrac:2,minInt:1,negPre:"-\u00a4",negSuf:"",posPre:"\u00a4",posSuf:""}]},id:"en-us",localeID:"en_US",pluralCat:function(a,c){var e=a|0,f=c;void 0===f&&(f=Math.min(b(a),3));Math.pow(10,f);return 1==e&&0==f?"one":"other"}})}]),x(function(){Ae(C.document,Uc)}))})(window);
|
||||
!window.angular.$$csp().noInlineStyle&&window.angular.element(document.head).prepend('<style type="text/css">@charset "UTF-8";[ng\\:cloak],[ng-cloak],[data-ng-cloak],[x-ng-cloak],.ng-cloak,.x-ng-cloak,.ng-hide:not(.ng-hide-animate){display:none !important;}ng\\:form{display:block;}.ng-animate-shim{visibility:hidden;}.ng-anchor{position:absolute;}</style>');
|
||||
//# sourceMappingURL=angular.min.js.map
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
The MIT License
|
||||
|
||||
Copyright (c) 2010-2019 Google LLC. http://angular.io/license
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
[autorun]
|
||||
OPEN=thp\thp_viewer.exe
|
||||
ICON=thp\thp_viewer.exe,0
|
||||
SHELL=readit
|
||||
SHELL\readit="THP-Viewer starten"
|
||||
SHELL\readit\command=thp\thp_viewer.exe
|
||||
@@ -0,0 +1,147 @@
|
||||
<!DOCTYPE html>
|
||||
|
||||
<html ng-app="main">
|
||||
|
||||
<head>
|
||||
|
||||
<meta charset="utf-8">
|
||||
|
||||
<title>"Take Home Package"</title>
|
||||
|
||||
<link href="style.css" rel="stylesheet" />
|
||||
|
||||
<script src="angular.min.js"></script>
|
||||
<script src="main.js"></script>
|
||||
|
||||
</head>
|
||||
|
||||
<body ng-controller="ctrl">
|
||||
|
||||
<img src="logo.svg" id="logo" />
|
||||
|
||||
<h1>
|
||||
<a href="index.html">
|
||||
{{ strCheck(data.title) }}
|
||||
</a>
|
||||
</h1>
|
||||
|
||||
<div ng-hide="showTable">
|
||||
|
||||
<img
|
||||
src="wappen.png"
|
||||
id="emblem"
|
||||
onerror="this.style.display='none'"
|
||||
/>
|
||||
|
||||
<table class="rowTable">
|
||||
<tr>
|
||||
<td>
|
||||
Exercise Area
|
||||
</td>
|
||||
<td>
|
||||
{{ strCheck(data.exerciseArea) }}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
Cycle Time
|
||||
</td>
|
||||
<td>
|
||||
{{ strCheck(data.cycleTime) }}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
Exercising Forces
|
||||
</td>
|
||||
<td>
|
||||
{{ strCheck(data.exercisingForces) }}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
Exercising Purpose
|
||||
</td>
|
||||
<td>
|
||||
{{ strCheck(data.exercisingPurpose )}}
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<hr />
|
||||
|
||||
<table class="columnTable">
|
||||
<tr>
|
||||
<th>
|
||||
Presentations
|
||||
</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<ul ng-show="data.presentations.length > 0">
|
||||
<li ng-repeat="presentation in data.presentations">
|
||||
<a href ng-click="displayTable(presentation.path)">
|
||||
{{ strCheck(presentation.displayName) }}
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
<span ng-hide="data.presentations.length > 0">N/A</span>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
</div>
|
||||
|
||||
<div id="tableContainer" ng-show="showTable">
|
||||
|
||||
<table class="rowTable">
|
||||
<tr>
|
||||
<th colspan="5">
|
||||
<u>
|
||||
{{ strCheck(sPresentation.title) }}
|
||||
</u>
|
||||
</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>
|
||||
Topic ID
|
||||
</th>
|
||||
<th>
|
||||
Topic Start
|
||||
</th>
|
||||
<th>
|
||||
Duration
|
||||
</th>
|
||||
<th>
|
||||
Type
|
||||
</th>
|
||||
<th>
|
||||
Description
|
||||
</th>
|
||||
</tr>
|
||||
<tr ng-repeat="entry in sPresentation.content">
|
||||
<td>
|
||||
{{ strCheck(entry.topicId) }}
|
||||
</td>
|
||||
<td>
|
||||
{{ strCheck(entry.topicStart) }}
|
||||
</td>
|
||||
<td>
|
||||
{{ strCheck(entry.duration) }}
|
||||
</td>
|
||||
<td>
|
||||
{{ strCheck(entry.type) }}
|
||||
</td>
|
||||
<td>
|
||||
<a ng-href="{{ entry.description.href }}">
|
||||
{{ strCheck(entry.description.displayName) }}
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
</div>
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
||||
@@ -0,0 +1,173 @@
|
||||
<!DOCTYPE html>
|
||||
|
||||
<html ng-app="main">
|
||||
|
||||
<head>
|
||||
|
||||
<meta charset="utf-8">
|
||||
|
||||
<title>"Take Home Package"</title>
|
||||
|
||||
<link href="style.css" rel="stylesheet" />
|
||||
|
||||
<script src="angular.min.js"></script>
|
||||
<script src="main.js"></script>
|
||||
|
||||
</head>
|
||||
|
||||
<body ng-controller="ctrl">
|
||||
|
||||
<img src="logo.svg" id="logo" />
|
||||
|
||||
<h1>
|
||||
<a href="index.html">
|
||||
{{ strCheck(data.title) }}
|
||||
</a>
|
||||
</h1>
|
||||
|
||||
<div ng-hide="showTable">
|
||||
|
||||
<img
|
||||
src="wappen.png"
|
||||
id="emblem"
|
||||
onerror="this.style.display='none'"
|
||||
/>
|
||||
|
||||
<table class="rowTable">
|
||||
<tr>
|
||||
<td>
|
||||
Übungsgebiet
|
||||
</td>
|
||||
<td>
|
||||
{{ strCheck(data.exerciseArea) }}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
Übungszeit
|
||||
</td>
|
||||
<td>
|
||||
{{ strCheck(data.cycleTime) }}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
Übungstruppe
|
||||
</td>
|
||||
<td>
|
||||
{{ strCheck(data.exercisingForces) }}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
Zweck der Übung
|
||||
</td>
|
||||
<td>
|
||||
{{ strCheck(data.exercisingPurpose )}}
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<hr />
|
||||
|
||||
<table class="columnTable">
|
||||
<tr>
|
||||
<th>
|
||||
Übungseinlagen
|
||||
</th>
|
||||
<th>
|
||||
Übungsanweisungen
|
||||
</th>
|
||||
<th>
|
||||
Präsentationen
|
||||
</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<ul ng-show="data.administrativeInstructions.length > 0">
|
||||
<li ng-repeat="instruction in data.administrativeInstructions">
|
||||
<a ng-href="{{ instruction.href }}">
|
||||
{{ strCheck(instruction.displayName) }}
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
<span ng-hide="data.administrativeInstructions.length > 0">N/A</span>
|
||||
</td>
|
||||
<td>
|
||||
<ul ng-show="data.exerciseIncidents.length > 0">
|
||||
<li ng-repeat="incident in data.exerciseIncidents">
|
||||
<a ng-href="{{ incident.href }}">
|
||||
{{ strCheck(incident.displayName) }}
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
<span ng-hide="data.exerciseIncidents.length > 0">N/A</span>
|
||||
</td>
|
||||
<td>
|
||||
<ul ng-show="data.presentations.length > 0">
|
||||
<li ng-repeat="presentation in data.presentations">
|
||||
<a href ng-click="displayTable(presentation.path)">
|
||||
{{ strCheck(presentation.displayName) }}
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
<span ng-hide="data.presentations.length > 0">N/A</span>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
</div>
|
||||
|
||||
<div id="tableContainer" ng-show="showTable">
|
||||
|
||||
<table class="rowTable">
|
||||
<tr>
|
||||
<th colspan="5">
|
||||
<u>
|
||||
{{ strCheck(sPresentation.title) }}
|
||||
</u>
|
||||
</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>
|
||||
Topic Id
|
||||
</th>
|
||||
<th>
|
||||
Startzeit
|
||||
</th>
|
||||
<th>
|
||||
Dauer
|
||||
</th>
|
||||
<th>
|
||||
Typ
|
||||
</th>
|
||||
<th>
|
||||
Beschreibung
|
||||
</th>
|
||||
</tr>
|
||||
<tr ng-repeat="entry in sPresentation.content">
|
||||
<td>
|
||||
{{ strCheck(entry.topicId) }}
|
||||
</td>
|
||||
<td>
|
||||
{{ strCheck(entry.topicStart) }}
|
||||
</td>
|
||||
<td>
|
||||
{{ strCheck(entry.duration) }}
|
||||
</td>
|
||||
<td>
|
||||
{{ strCheck(entry.type) }}
|
||||
</td>
|
||||
<td>
|
||||
<a ng-href="{{ entry.description.href }}">
|
||||
{{ strCheck(entry.description.displayName) }}
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
</div>
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
||||
@@ -0,0 +1,12 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!-- Generator: Adobe Illustrator 15.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<svg version="1.1" id="Rheinmetall_Group_4c_positiv" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="184.252px" height="53.941px" viewBox="0 0 184.252 53.941" enable-background="new 0 0 184.252 53.941" xml:space="preserve">
|
||||
<g>
|
||||
<path fill="#007EC1" d="M34.827,0.048c0,0-31.6,14.071-31.601,14.072C0.635,15.27,0,16.995,0,18.211v14.875v16.626 c0,0.324,0.328,0.589,0.673,0.44l16.395-7.296c0.981-0.479,2.277-1.595,2.277-3.82v-17.49l13.696-6.104 c1.42-0.671,2.424-2.536,2.424-4.999c0-0.005,0-8.333,0-9.948C35.466,0.098,35.187-0.097,34.827,0.048z"/>
|
||||
<path fill="#00406E" d="M0.673,50.152l16.395-7.296c0.981-0.479,2.277-1.595,2.277-3.82v-17.49c0,0-16.124,7.271-16.123,7.271h0 C0.546,30.004,0.027,31.777,0,33.085v16.626C0,50.036,0.328,50.301,0.673,50.152z"/>
|
||||
<path fill="#001836" d="M0,33.085c0.027-1.308,0.546-3.082,3.223-4.269h0c-0.001,0,16.123-7.271,16.123-7.271v2.863L3.223,30.401 c-2.399,0.9-3.196,2.645-3.223,3.953V33.085z"/>
|
||||
<path id="RHEINMETALL_1_" fill="#3E3D40" d="M37.798,41.33H35.87c-0.373,0-0.604-0.208-0.604-0.698V27.545 c0-1.766,0.65-2.649,2.58-2.649h1.765c2.279,0,3.837,0.21,4.72,0.559c1.766,0.72,2.371,2.348,2.371,4.346 c0,2-0.675,3.672-2.627,4.486l3.162,5.719c0.139,0.255,0.324,0.558,0.324,0.837c0,0.233-0.162,0.395-0.347,0.418 c-0.209,0.047-1.838,0.116-2.326,0.116c-0.418,0-0.65-0.209-0.813-0.534l-3.045-5.974c-0.395,0.023-0.814,0.023-1.278,0.023h-1.279 v5.74C38.472,41.098,38.193,41.33,37.798,41.33z M39.844,32.334c0.999,0,1.813-0.092,2.348-0.279 c0.744-0.278,1.208-1.045,1.208-2.091c0-1.232-0.373-1.905-1.163-2.185c-0.465-0.164-1.186-0.21-2.092-0.21h-0.907 c-0.558,0-0.767,0.256-0.767,0.768v3.998H39.844z M52.582,41.33h-1.951c-0.373,0-0.604-0.208-0.604-0.698V25.57 c0-0.418,0.186-0.697,0.627-0.697h2c0.441,0,0.581,0.256,0.581,0.675v5.857h6.369V25.57c0-0.418,0.186-0.697,0.652-0.697h1.974 c0.442,0,0.581,0.256,0.581,0.675v15.084c0,0.443-0.254,0.698-0.65,0.698h-1.93c-0.372,0-0.627-0.208-0.627-0.698v-6.415h-6.369 v6.415C53.233,41.075,52.978,41.33,52.582,41.33z M69.11,41.307c-1.627,0-2.487-0.651-2.487-2.487V27.453 c0-1.744,0.791-2.557,2.487-2.557h6.972c0.443,0,0.652,0.14,0.652,0.628v1.627c0,0.395-0.209,0.535-0.652,0.535h-5.508 c-0.488,0-0.744,0.256-0.744,0.86v2.859h5.672c0.418,0,0.65,0.139,0.65,0.626v1.628c0,0.395-0.231,0.557-0.65,0.557H69.83v3.394 c0,0.627,0.233,0.907,0.883,0.907h5.766c0.417,0,0.65,0.116,0.65,0.627v1.604c0,0.396-0.21,0.559-0.65,0.559H69.11z M82.747,41.33 h-1.952c-0.373,0-0.604-0.208-0.604-0.698V25.57c0-0.418,0.186-0.697,0.627-0.697h1.999c0.442,0,0.582,0.256,0.582,0.675v15.084 C83.399,41.075,83.144,41.33,82.747,41.33z M89.868,41.33h-1.86c-0.372,0-0.604-0.208-0.604-0.698V26.989 c0-1.465,0.58-2.186,2.138-2.186h0.883c1.325,0,1.628,0.581,2.092,1.557c3.742,7.671,4.416,9.229,5.137,10.972 c-0.07-2.115-0.07-4.138-0.07-11.6c0-0.511,0.233-0.86,0.698-0.86h1.744c0.465,0,0.626,0.326,0.626,0.791v13.994 c0,1.534-0.859,1.813-1.812,1.813H98.12c-1.349,0-1.744-0.465-2.395-1.79c-4.161-8.508-4.532-9.392-5.253-11.111 c0.023,1.603,0.046,3.184,0.046,12.063C90.519,41.075,90.263,41.33,89.868,41.33z M107.182,41.33h-1.975 c-0.373,0-0.558-0.255-0.558-0.698V27.151c0-1.209,0.301-2.348,2.278-2.348h0.698c1.626,0,1.743,0.418,2.532,2.417 c1.604,4.113,2.07,5.348,2.534,6.764c0.511-1.463,0.884-2.603,2.488-6.811c0.65-1.719,0.883-2.371,2.65-2.371h0.79 c1.884,0,2,0.929,2,2.348v13.412c0,0.559-0.232,0.767-0.652,0.767h-1.954c-0.371,0-0.603-0.208-0.603-0.744 c0-8.368,0.023-10.227,0.093-12.528c-0.582,1.905-1.046,3.275-3.208,8.972c-0.372,0.975-0.626,1.37-1.44,1.37h-0.373 c-0.767,0-1.115-0.372-1.441-1.278c-2.068-5.579-2.602-7.02-3.3-9.064c0.07,2.301,0.07,4.299,0.07,12.598 C107.811,41.028,107.648,41.33,107.182,41.33z M126.918,41.307c-1.627,0-2.486-0.651-2.486-2.487V27.453 c0-1.744,0.79-2.557,2.486-2.557h6.973c0.441,0,0.65,0.14,0.65,0.628v1.627c0,0.395-0.209,0.535-0.65,0.535h-5.509 c-0.488,0-0.744,0.256-0.744,0.86v2.859h5.672c0.418,0,0.651,0.139,0.651,0.626v1.628c0,0.395-0.233,0.557-0.651,0.557h-5.672 v3.394c0,0.627,0.231,0.907,0.883,0.907h5.765c0.417,0,0.652,0.116,0.652,0.627v1.604c0,0.396-0.211,0.559-0.652,0.559H126.918z M143.236,41.33h-1.974c-0.374,0-0.628-0.231-0.628-0.698V27.686h-3.009c-0.44,0-0.651-0.14-0.651-0.535v-1.627 c0-0.488,0.211-0.628,0.651-0.628h10.025c0.441,0,0.652,0.158,0.493,0.628l-0.572,1.627c-0.122,0.39-0.33,0.535-0.773,0.535h-2.911 v12.946C143.887,41.098,143.609,41.33,143.236,41.33z M150.361,40.586c-0.185,0.559-0.324,0.79-0.791,0.79 c-0.463,0-1.998-0.046-2.3-0.116c-0.256-0.07-0.325-0.279-0.325-0.465c0-0.209,0.069-0.489,0.162-0.744l4.556-13.25 c0.464-1.347,0.813-1.999,2.487-1.999h0.744c1.558,0,1.79,0.605,2.232,1.929l4.463,13.272c0.093,0.255,0.163,0.511,0.163,0.767 c0,0.186-0.093,0.395-0.304,0.488c-0.278,0.116-1.626,0.116-2.3,0.116c-0.464,0-0.628-0.231-0.813-0.79l-1.185-3.509h-5.649 L150.361,40.586z M156.429,34.357c-1.279-4.091-1.675-5.393-2.046-6.765c-0.373,1.349-0.79,2.696-2.092,6.765H156.429z M166.193,41.307c-1.58,0-2.438-0.699-2.438-2.372V25.57c0-0.418,0.185-0.697,0.625-0.697h1.999c0.443,0,0.582,0.256,0.582,0.675 v12.109c0,0.558,0.232,0.86,0.859,0.86h4.661c0.417,0,0.649,0.116,0.649,0.627v1.604c0,0.396-0.232,0.559-0.649,0.559H166.193z M177.315,41.307c-1.582,0-2.441-0.699-2.441-2.372V25.57c0-0.418,0.185-0.697,0.627-0.697h2c0.441,0,0.58,0.256,0.58,0.675v12.109 c0,0.558,0.233,0.86,0.858,0.86h4.661c0.419,0,0.651,0.116,0.651,0.627v1.604c0,0.396-0.232,0.559-0.651,0.559H177.315z"/>
|
||||
<path id="Group_2_" fill="#3E3D40" d="M41.283,53.271c-0.061,0.097-0.183,0.17-0.305,0.231c-0.45,0.195-1.496,0.426-2.785,0.426 c-2.225,0-3.417-1.009-3.417-4.318c0-3.186,0.937-4.585,3.771-4.585c0.802,0,1.63,0.073,2.116,0.195 c0.22,0.061,0.292,0.146,0.292,0.279c0,0.122-0.048,0.402-0.121,0.597c-0.025,0.084-0.098,0.133-0.195,0.133 c-0.097,0-0.231-0.024-0.414-0.061c-0.34-0.061-0.949-0.157-1.751-0.157c-2.116,0-2.53,1.423-2.53,3.417 c0,1.996,0.292,3.528,2.383,3.528c0.851,0,1.35-0.098,1.752-0.208c0.195-0.049,0.279-0.134,0.279-0.389v-2.141H38.57 c-0.158,0-0.219-0.085-0.219-0.218v-0.573c0-0.158,0.073-0.231,0.231-0.231h2.53c0.183,0,0.267,0.085,0.267,0.292v3.358 C41.38,53.027,41.368,53.149,41.283,53.271z M44.132,53.794h-0.596c-0.17,0-0.254-0.098-0.254-0.292v-7.103 c0-0.803,0.279-1.217,1.167-1.217h0.948c1.035,0,1.8,0.085,2.262,0.268c0.924,0.365,1.229,1.13,1.229,2.166 c0,1.18-0.511,1.982-1.582,2.334l1.849,3.272c0.061,0.122,0.146,0.231,0.146,0.364c0,0.085-0.061,0.159-0.134,0.171 c-0.097,0.024-0.584,0.049-0.754,0.049c-0.17,0-0.267-0.073-0.365-0.256l-1.837-3.417c-0.231,0.025-0.486,0.025-0.741,0.025h-1.058 v3.344C44.412,53.685,44.314,53.794,44.132,53.794z M45.519,49.208c0.669,0,1.131-0.072,1.447-0.194 c0.461-0.182,0.754-0.644,0.754-1.338c0-0.839-0.28-1.179-0.73-1.35c-0.279-0.109-0.754-0.158-1.435-0.158h-0.693 c-0.329,0-0.45,0.146-0.45,0.45v2.591H45.519z M53.755,53.928c-2.36,0-3.491-0.925-3.491-4.501c0-3.636,1.532-4.403,3.587-4.403 c2.347,0,3.491,0.645,3.491,4.392C57.342,52.979,56.199,53.928,53.755,53.928z M53.815,46.011c-1.533,0-2.383,0.583-2.383,3.417 c0,2.993,0.814,3.515,2.347,3.515c1.496,0,2.383-0.461,2.383-3.502C56.162,46.521,55.519,46.011,53.815,46.011z M65.312,50.34 c0,1.228-0.049,1.885-0.353,2.42c-0.438,0.779-1.374,1.18-2.833,1.18c-1.277,0-2.335-0.268-2.798-1.266 c-0.242-0.535-0.267-1.362-0.267-2.311v-4.927c0-0.145,0.072-0.279,0.267-0.279h0.633c0.17,0,0.231,0.11,0.231,0.279v5.267 c0,0.693,0.049,1.228,0.268,1.569c0.279,0.438,0.839,0.668,1.727,0.668c0.621,0,1.435-0.097,1.751-0.632 c0.207-0.34,0.28-0.802,0.28-1.569v-5.304c0-0.145,0.073-0.279,0.267-0.279h0.596c0.17,0,0.231,0.11,0.231,0.279V50.34z M68.367,53.794h-0.596c-0.17,0-0.255-0.098-0.255-0.292v-7.103c0-0.815,0.268-1.217,1.155-1.217h1.083 c1.033,0,1.8,0.098,2.262,0.28c0.912,0.377,1.228,1.191,1.228,2.213c0,1.18-0.499,1.995-1.618,2.335 c-0.414,0.122-1.046,0.195-1.8,0.195h-1.179v3.296C68.647,53.685,68.549,53.794,68.367,53.794z M69.899,49.257 c0.668,0,1.119-0.061,1.423-0.182c0.462-0.195,0.753-0.657,0.753-1.338c0-0.839-0.304-1.216-0.742-1.399 c-0.268-0.109-0.778-0.17-1.495-0.17h-0.791c-0.28,0-0.401,0.11-0.401,0.45v2.64H69.899z"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 8.2 KiB |
@@ -0,0 +1,44 @@
|
||||
const dataSource = "data.json"; // JSON input file
|
||||
|
||||
angular
|
||||
.module("main", [])
|
||||
.controller("ctrl", ($scope, $http, $rootScope, $location) => {
|
||||
$scope.showTable = false;
|
||||
$scope.sPresentation = undefined;
|
||||
|
||||
$scope.strCheck = str => {
|
||||
return str == "" || str == undefined || str == null
|
||||
? "N/A"
|
||||
: str;
|
||||
};
|
||||
|
||||
$http.get(dataSource).then(response => {
|
||||
$scope.data = response.data;
|
||||
$rootScope.title = $scope.strCheck($scope.data.title);
|
||||
$scope.$watch(
|
||||
() => location.hash,
|
||||
value => {
|
||||
if (value == "" || value == undefined || value == null || value == "#!/") {
|
||||
$scope.showTable = false;
|
||||
$scope.sPresentation = undefined;
|
||||
$rootScope.title = $scope.strCheck(
|
||||
$scope.data.title
|
||||
);
|
||||
} else {
|
||||
$scope.displayTable($location.hash());
|
||||
}
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
$scope.displayTable = path => {
|
||||
$http.get(path).then(response => {
|
||||
$location.hash(path);
|
||||
$scope.sPresentation = response.data;
|
||||
$scope.showTable = true;
|
||||
$rootScope.title = $scope.strCheck(
|
||||
$scope.sPresentation.title
|
||||
);
|
||||
});
|
||||
};
|
||||
});
|
||||
+114
@@ -0,0 +1,114 @@
|
||||
<!DOCTYPE html>
|
||||
<html ng-app="main">
|
||||
<meta charset="utf-8">
|
||||
<head>
|
||||
<title ng-bind="$root.title"></title>
|
||||
|
||||
<script src="angular.min.js"></script>
|
||||
<script>
|
||||
const dataSource = "presentation.json"; // JSON input file
|
||||
|
||||
angular
|
||||
.module("main", [])
|
||||
.controller("ctrl", ($scope, $http, $rootScope, $location) => {
|
||||
$scope.showTable = false;
|
||||
$scope.sPresentation = undefined;
|
||||
|
||||
$scope.strCheck = str => {
|
||||
return str == "" || str == undefined || str == null
|
||||
? "N/A"
|
||||
: str;
|
||||
};
|
||||
|
||||
$http.get(dataSource).then(response => {
|
||||
$scope.sPresentation = response.data;
|
||||
$scope.showTable = true;
|
||||
$rootScope.title = $scope.strCheck(
|
||||
$scope.sPresentation.title
|
||||
);
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
<style>
|
||||
body {
|
||||
font-family: "Calibri", "Arial";
|
||||
}
|
||||
table {
|
||||
border-collapse: collapse;
|
||||
}
|
||||
td,
|
||||
th {
|
||||
padding: 5px;
|
||||
text-align: center;
|
||||
border: 1px solid black;
|
||||
}
|
||||
.section {
|
||||
font-weight: bold;
|
||||
text-decoration: underline;
|
||||
}
|
||||
#tableContainer {
|
||||
position: absolute;
|
||||
top: 10px;
|
||||
left: 10px;
|
||||
}
|
||||
#logo {
|
||||
position: absolute;
|
||||
top: 10px;
|
||||
right: 10px;
|
||||
max-height: 500px;
|
||||
max-width: 50%;
|
||||
border: 5px solid white;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body ng-controller="ctrl">
|
||||
<div id="tableContainer" ng-show="showTable">
|
||||
<br />
|
||||
<br />
|
||||
<table>
|
||||
<tr>
|
||||
<th colspan="5">
|
||||
{{ strCheck(sPresentation.title) }}
|
||||
</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>
|
||||
Topic ID
|
||||
</th>
|
||||
<th>
|
||||
Topic Start
|
||||
</th>
|
||||
<th>
|
||||
Duration
|
||||
</th>
|
||||
<th>
|
||||
Type
|
||||
</th>
|
||||
<th>
|
||||
Description
|
||||
</th>
|
||||
</tr>
|
||||
<tr ng-repeat="entry in sPresentation.content">
|
||||
<td>
|
||||
{{ strCheck(entry.topicId) }}
|
||||
</td>
|
||||
<td>
|
||||
{{ strCheck(entry.topicStart) }}
|
||||
</td>
|
||||
<td>
|
||||
{{ strCheck(entry.duration) }}
|
||||
</td>
|
||||
<td>
|
||||
{{ strCheck(entry.type) }}
|
||||
</td>
|
||||
<td>
|
||||
<a ng-href="{{ entry.description.href_local }}">
|
||||
{{ strCheck(entry.description.displayName) }}
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
+114
@@ -0,0 +1,114 @@
|
||||
<!DOCTYPE html>
|
||||
<html ng-app="main">
|
||||
<meta charset="utf-8">
|
||||
<head>
|
||||
<title ng-bind="$root.title"></title>
|
||||
|
||||
<script src="angular.min.js"></script>
|
||||
<script>
|
||||
const dataSource = "presentation.json"; // JSON input file
|
||||
|
||||
angular
|
||||
.module("main", [])
|
||||
.controller("ctrl", ($scope, $http, $rootScope, $location) => {
|
||||
$scope.showTable = false;
|
||||
$scope.sPresentation = undefined;
|
||||
|
||||
$scope.strCheck = str => {
|
||||
return str == "" || str == undefined || str == null
|
||||
? "N/A"
|
||||
: str;
|
||||
};
|
||||
|
||||
$http.get(dataSource).then(response => {
|
||||
$scope.sPresentation = response.data;
|
||||
$scope.showTable = true;
|
||||
$rootScope.title = $scope.strCheck(
|
||||
$scope.sPresentation.title
|
||||
);
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
<style>
|
||||
body {
|
||||
font-family: "Calibri", "Arial";
|
||||
}
|
||||
table {
|
||||
border-collapse: collapse;
|
||||
}
|
||||
td,
|
||||
th {
|
||||
padding: 5px;
|
||||
text-align: center;
|
||||
border: 1px solid black;
|
||||
}
|
||||
.section {
|
||||
font-weight: bold;
|
||||
text-decoration: underline;
|
||||
}
|
||||
#tableContainer {
|
||||
position: absolute;
|
||||
top: 10px;
|
||||
left: 10px;
|
||||
}
|
||||
#logo {
|
||||
position: absolute;
|
||||
top: 10px;
|
||||
right: 10px;
|
||||
max-height: 500px;
|
||||
max-width: 50%;
|
||||
border: 5px solid white;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body ng-controller="ctrl">
|
||||
<div id="tableContainer" ng-show="showTable">
|
||||
<br />
|
||||
<br />
|
||||
<table>
|
||||
<tr>
|
||||
<th colspan="5">
|
||||
{{ strCheck(sPresentation.title) }}
|
||||
</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>
|
||||
Topic Id
|
||||
</th>
|
||||
<th>
|
||||
Startzeit
|
||||
</th>
|
||||
<th>
|
||||
Dauer
|
||||
</th>
|
||||
<th>
|
||||
Typ
|
||||
</th>
|
||||
<th>
|
||||
Beschreibung
|
||||
</th>
|
||||
</tr>
|
||||
<tr ng-repeat="entry in sPresentation.content">
|
||||
<td>
|
||||
{{ strCheck(entry.topicId) }}
|
||||
</td>
|
||||
<td>
|
||||
{{ strCheck(entry.topicStart) }}
|
||||
</td>
|
||||
<td>
|
||||
{{ strCheck(entry.duration) }}
|
||||
</td>
|
||||
<td>
|
||||
{{ strCheck(entry.type) }}
|
||||
</td>
|
||||
<td>
|
||||
<a ng-href="{{ entry.description.href_local }}">
|
||||
{{ strCheck(entry.description.displayName) }}
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,86 @@
|
||||
body {
|
||||
font-family: "Calibri", "Arial";
|
||||
font-size: x-large;
|
||||
}
|
||||
|
||||
table {
|
||||
border-collapse: collapse;
|
||||
margin: 25px;
|
||||
width: calc(100% - 50px);
|
||||
}
|
||||
|
||||
ul {
|
||||
padding-left: 0px;
|
||||
list-style: square inside;
|
||||
}
|
||||
|
||||
h1 {
|
||||
margin: 20px;
|
||||
}
|
||||
h1 a {
|
||||
text-decoration: none;
|
||||
}
|
||||
h1 a:visited {
|
||||
color: black;
|
||||
}
|
||||
|
||||
table.rowTable td,
|
||||
table.rowTable th {
|
||||
padding: 10px;
|
||||
text-align: center;
|
||||
border: none;
|
||||
}
|
||||
table.rowTable td {
|
||||
border-bottom: 1px solid #0F72B5;
|
||||
border-top: 1px solid #0F72B5;
|
||||
}
|
||||
table.rowTable td:first-child {
|
||||
color: white;
|
||||
background-color: #0F72B5;
|
||||
}
|
||||
table.rowTable th {
|
||||
color: white;
|
||||
background-color: #00406E;
|
||||
}
|
||||
table.rowTable tr:first-child td:first-child,
|
||||
table.rowTable tr:first-child th:first-child {
|
||||
border-top-left-radius: 25px;
|
||||
border-top: 0px solid transparent;
|
||||
}
|
||||
|
||||
table.columnTable {
|
||||
table-layout: fixed;
|
||||
}
|
||||
table.columnTable td,
|
||||
table.columnTable th {
|
||||
padding: 10px;
|
||||
text-align: center;
|
||||
border: none;
|
||||
border-left: 1px solid #00406E;
|
||||
border-right: 1px solid #00406E;
|
||||
width: auto;
|
||||
}
|
||||
table.columnTable th {
|
||||
color: white;
|
||||
background-color: #00406E;
|
||||
}
|
||||
table.columnTable tr:first-child td:first-child,
|
||||
table.columnTable tr:first-child th:first-child {
|
||||
border-top-left-radius: 25px;
|
||||
border-left: 0px solid transparent;
|
||||
}
|
||||
|
||||
#emblem {
|
||||
position: absolute;
|
||||
top: 10px;
|
||||
right: 10px;
|
||||
max-height: 3em;
|
||||
background-color: white;
|
||||
}
|
||||
#logo {
|
||||
position: absolute;
|
||||
bottom: 10px;
|
||||
right: 10px;
|
||||
max-height: 500px;
|
||||
background-color: white;
|
||||
}
|
||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,100 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* Topic Designer for the Script Editor - Set Geometry & Z-Index, delete Topics, etc.
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*
|
||||
* Created by Mike Wille, SLSE, 2017-06-09
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <Plugins/PresentationManagement/Gui/Script/Common/preguiscriptcommon_export.h>
|
||||
#include <TopicEditorBase/topic_editor_utils.h>
|
||||
|
||||
#include <QWidget>
|
||||
#include <QVector>
|
||||
#include <QLinkedList>
|
||||
#include <QPointer>
|
||||
#include <QScrollArea>
|
||||
|
||||
|
||||
namespace PresentationManagement
|
||||
{
|
||||
|
||||
class PREGUISCRIPTCOMMON_EXPORT TopicDesigner: public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
enum class HandleType
|
||||
{
|
||||
None, Whole,
|
||||
TopLeft, TopCenter, TopRight,
|
||||
CenterLeft, CenterRight,
|
||||
BottomLeft, BottomCenter, BottomRight
|
||||
};
|
||||
|
||||
explicit TopicDesigner(QWidget *parent = nullptr, QWidget* previewWidget = nullptr);
|
||||
~TopicDesigner();
|
||||
|
||||
void loadTopicList(const QVector<TopicEditorBase::TopicData> &topicsList); // also clears
|
||||
QVector<TopicEditorBase::TopicData> exportTopicList() const;
|
||||
void selectTopic(int topicId);
|
||||
TopicEditorBase::TopicData &selectedTopicData() noexcept(false);
|
||||
void setTopicData(const TopicEditorBase::TopicData &data);
|
||||
|
||||
private:
|
||||
enum class Affection { x, y, w, h, Whole, };
|
||||
|
||||
void paintEvent(QPaintEvent *event) override;
|
||||
void mouseMoveEvent(QMouseEvent *event) override;
|
||||
void mousePressEvent(QMouseEvent *event) override;
|
||||
void mouseReleaseEvent(QMouseEvent *event) override;
|
||||
void keyPressEvent(QKeyEvent *event) override;
|
||||
int heightForWidth(int width) const override;
|
||||
|
||||
void paintSelectedTopicItem(QPainter *p, const TopicEditorBase::TopicData &data);
|
||||
QRect handleRect(const TopicEditorBase::TopicData &data, const HandleType &ht);
|
||||
QRect topicItemRect(const TopicEditorBase::TopicData &data);
|
||||
|
||||
bool checkConstraints(TopicEditorBase::TopicData &selected);
|
||||
void setCursorFromHandleType(const HandleType &ht);
|
||||
double oneWidthPixelInPercent();
|
||||
double oneHeightPixelInPercent();
|
||||
|
||||
void unselect();
|
||||
void findSelection(const QPoint &pos); // looks for Topic(s) on the clicked position and selects those Topics
|
||||
void internalSelectTopic(int topicId);
|
||||
|
||||
void setValues(const TopicEditorBase::TopicData &data, const QPoint &pos);
|
||||
void affect(TopicEditorBase::TopicData &selected, const Affection &affection, const QPoint &pos);
|
||||
void deleteTopicItem(const TopicEditorBase::TopicData &data);
|
||||
|
||||
public slots:
|
||||
void incIndex(const TopicEditorBase::TopicData &selected);
|
||||
void decIndex(const TopicEditorBase::TopicData &selected);
|
||||
void toFront(const TopicEditorBase::TopicData &selected);
|
||||
void toBack(const TopicEditorBase::TopicData &selected);
|
||||
|
||||
signals:
|
||||
void deleteTopicItem(int topicId);
|
||||
void topicSelected(int topicId);
|
||||
void unselected();
|
||||
void changesMade();
|
||||
|
||||
private:
|
||||
QLinkedList<TopicEditorBase::TopicData> m_topicDataList;
|
||||
int m_selectedTopicId; // must be inside the list....
|
||||
int m_lowestImportIndex;
|
||||
|
||||
HandleType m_currentResizeHandle;
|
||||
HandleType m_resizeHandleActive; // saves us code dups
|
||||
QPointF m_wholeOrgPos;
|
||||
QPointer<QWidget> m_drawWidgetPreviewContent;
|
||||
QScrollArea *m_scrollArea{nullptr};
|
||||
|
||||
};
|
||||
|
||||
} // namespace PresentationManagement
|
||||
@@ -0,0 +1,81 @@
|
||||
#
|
||||
# $Id$
|
||||
# $HeadURL$
|
||||
# $Author$
|
||||
#
|
||||
# Created by Mike Wille, SLSE, 2016-03-17
|
||||
#
|
||||
|
||||
SET(pre_script_gui_SRCS
|
||||
pre_script_gui_plugin.cpp
|
||||
pre_script_gui_plugin.h
|
||||
pre_script_dialog.h
|
||||
pre_script_dialog.cpp
|
||||
pre_storyboard.cpp
|
||||
pre_storyboard.h
|
||||
pre_journal_types.h
|
||||
pre_journal_types.cpp
|
||||
pre_journal_dialog.h
|
||||
pre_journal_dialog.cpp
|
||||
pre_screen.h
|
||||
pre_screen.cpp
|
||||
filter_topic.h
|
||||
filter_topic.cpp
|
||||
)
|
||||
|
||||
QT5_WRAP_UI(pre_script_gui_SRCS
|
||||
pre_storyboard.ui
|
||||
pre_script_dialog.ui
|
||||
pre_journal_dialog.ui
|
||||
)
|
||||
|
||||
NGL_ADD_LIBRARY(WS PreScriptGuiPlugin MODULE ${pre_script_gui_SRCS})
|
||||
NGL_TARGET_LINK_LIBRARIES(PreScriptGuiPlugin
|
||||
NGLLogger
|
||||
LtsSession
|
||||
PreDataPluginInterface
|
||||
PrePresentationGuiPluginInterface
|
||||
PreGuiCommon
|
||||
PreGuiScriptCommon
|
||||
svcPreCommon
|
||||
Qt5::Widgets
|
||||
LtsWidgets
|
||||
LtsDataView
|
||||
LtsUtilsGuiDds
|
||||
LtsSessionData
|
||||
ProjectConfig
|
||||
LtsScriptTimeline
|
||||
LtsMultiMonitor
|
||||
|
||||
LtsAppManager # start replay app
|
||||
LtsSessionData # set partition preset for replay app
|
||||
TopicEditorInterface
|
||||
TopicEditorBase
|
||||
LtsPluginManager # manipulate apps
|
||||
|
||||
# for Topics
|
||||
EvlGuiPluginInterface
|
||||
|
||||
|
||||
SrmDataPluginInterface # start playback
|
||||
LtsPrinting
|
||||
SituationMapGuiPluginInterface
|
||||
|
||||
# Script Player Controls:
|
||||
SrpGuiPluginInterface
|
||||
|
||||
# file topic
|
||||
FlmExplorerGuiPluginInterface
|
||||
# building topic
|
||||
BdvViewerGuiPluginInterface
|
||||
# report topic
|
||||
RepGuiPluginInterface
|
||||
LtsReportDisplay
|
||||
MrkCommon # for ApplyFilter @ SitmapFilter
|
||||
LtsUtilsSettings
|
||||
ngltools # DTG
|
||||
situationMap # set time string on map
|
||||
ExportBdvTopicSetting
|
||||
)
|
||||
|
||||
NGL_INSTALL_TARGET(PreScriptGuiPlugin)
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
#include "filter_topic.h"
|
||||
|
||||
|
||||
namespace PresentationManagement
|
||||
{
|
||||
FilterTopic::~FilterTopic()
|
||||
{
|
||||
//delete filterTopic;
|
||||
}
|
||||
|
||||
|
||||
FilterTopic::FilterTopic(const FilterTopic &other)
|
||||
{
|
||||
mainTopicId = other.mainTopicId;
|
||||
filterTopic = other.filterTopic;//new LtsScriptTimeline::TrackEntry(other.filterTopic);
|
||||
}
|
||||
} // namespace PresentationManagement
|
||||
@@ -0,0 +1,28 @@
|
||||
#pragma once
|
||||
|
||||
#include <LtsScriptTimeline/track_entry.h>
|
||||
|
||||
|
||||
namespace PresentationManagement
|
||||
{
|
||||
class FilterTopic
|
||||
{
|
||||
public:
|
||||
FilterTopic()
|
||||
: mainTopicId(-1)
|
||||
, filterTopic(nullptr)
|
||||
{}
|
||||
|
||||
FilterTopic(int _mainTopicId, LtsScriptTimeline::TrackEntry *_filterTopic)
|
||||
: mainTopicId(_mainTopicId)
|
||||
, filterTopic(_filterTopic)
|
||||
{}
|
||||
|
||||
FilterTopic(const FilterTopic &other);
|
||||
|
||||
~FilterTopic();
|
||||
|
||||
int mainTopicId;
|
||||
LtsScriptTimeline::TrackEntry *filterTopic;
|
||||
};
|
||||
} // namespace PresentationManagement
|
||||
+81
@@ -0,0 +1,81 @@
|
||||
#include "pre_journal_dialog.h"
|
||||
#include "ui_pre_journal_dialog.h"
|
||||
|
||||
#include <LtsPrinting/printing.h>
|
||||
|
||||
|
||||
namespace PresentationManagement
|
||||
{
|
||||
|
||||
JournalDialog::JournalDialog(LtsSession::LtsSession *session, QWidget *parent)
|
||||
: LtsWidgets::LtsDialog(parent)
|
||||
, m_ui(new Ui::JournalDialog)
|
||||
, m_journal(nullptr)
|
||||
, m_session(session)
|
||||
{
|
||||
m_ui->setupUi(this);
|
||||
|
||||
m_buttonBox->connectButton(LtsWidgets::DialogButton::Print, this, &JournalDialog::slotPrint);
|
||||
}
|
||||
|
||||
|
||||
JournalDialog::~JournalDialog()
|
||||
{
|
||||
delete m_ui;
|
||||
}
|
||||
|
||||
|
||||
void JournalDialog::slotPrint()
|
||||
{
|
||||
LtsPrinting::printView(m_session, this, m_ui->listWidget);
|
||||
}
|
||||
|
||||
|
||||
bool JournalDialog::init(MainJournal *journal)
|
||||
{
|
||||
m_journal = journal;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void JournalDialog::retranslate()
|
||||
{
|
||||
translate(m_ui, tr("Script Journal"));
|
||||
fillJournal();
|
||||
}
|
||||
|
||||
|
||||
void JournalDialog::fillJournal()
|
||||
{
|
||||
m_ui->listWidget->clear();
|
||||
|
||||
if (!m_journal)
|
||||
return;
|
||||
|
||||
m_ui->listWidget->addItem(m_journal->getText());
|
||||
for (const Journal *j : qAsConst(m_journal->journalList))
|
||||
m_ui->listWidget->addItem(j->getText());
|
||||
}
|
||||
|
||||
} // namespace PresentationManagement
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
+37
@@ -0,0 +1,37 @@
|
||||
#pragma once
|
||||
|
||||
#include "pre_journal_types.h"
|
||||
|
||||
#include <LtsWidgets/lts_dialog.h>
|
||||
#include <LtsSession/lts_session.h>
|
||||
|
||||
|
||||
namespace Ui
|
||||
{
|
||||
class JournalDialog;
|
||||
}
|
||||
|
||||
namespace PresentationManagement
|
||||
{
|
||||
|
||||
class JournalDialog : public LtsWidgets::LtsDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit JournalDialog(LtsSession::LtsSession *session, QWidget *parent);
|
||||
~JournalDialog();
|
||||
bool init(MainJournal *journal);
|
||||
void retranslate() override final;
|
||||
|
||||
private slots:
|
||||
void slotPrint();
|
||||
|
||||
private:
|
||||
void fillJournal();
|
||||
|
||||
Ui::JournalDialog *m_ui;
|
||||
MainJournal *m_journal;
|
||||
LtsSession::LtsSession *m_session;
|
||||
};
|
||||
|
||||
} // namespace PresentationManagement
|
||||
+49
@@ -0,0 +1,49 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>JournalDialog</class>
|
||||
<widget class="QWidget" name="JournalDialog">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>707</width>
|
||||
<height>464</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="MinimumExpanding" vsizetype="MinimumExpanding">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string notr="true">Script Editor</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<property name="spacing">
|
||||
<number>9</number>
|
||||
</property>
|
||||
<property name="leftMargin">
|
||||
<number>9</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>9</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>9</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>9</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QListWidget" name="listWidget">
|
||||
<property name="alternatingRowColors">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
+90
@@ -0,0 +1,90 @@
|
||||
#include "pre_journal_types.h"
|
||||
|
||||
#include <QDateTime>
|
||||
#include <ngltools/ngltools_dtg.h>
|
||||
|
||||
|
||||
namespace PresentationManagement
|
||||
{
|
||||
|
||||
QString ttt(qint64 msecsSinceEpoch)
|
||||
{
|
||||
return DTG::toStringMSec(msecsSinceEpoch);
|
||||
}
|
||||
|
||||
|
||||
QString pttt(int presentationTime)
|
||||
{
|
||||
return QTime::fromMSecsSinceStartOfDay(presentationTime * 1000).toString();
|
||||
}
|
||||
|
||||
|
||||
Journal::Journal()
|
||||
: m_started(QDateTime::currentMSecsSinceEpoch())
|
||||
{}
|
||||
|
||||
|
||||
QString Journal::started() const
|
||||
{
|
||||
return ttt(m_started);
|
||||
}
|
||||
|
||||
|
||||
MainJournal::~MainJournal()
|
||||
{
|
||||
qDeleteAll(journalList);
|
||||
}
|
||||
|
||||
|
||||
QString MainJournal::getText() const
|
||||
{
|
||||
return Journal::tr("Script Player started on %1").arg(ttt(started));
|
||||
}
|
||||
|
||||
|
||||
NextTopicJournal::NextTopicJournal(int presentationTime, bool isFilter, const QString &topicTypeName, int length)
|
||||
: Journal()
|
||||
, m_isFilter(isFilter)
|
||||
, m_topicTypeName(topicTypeName)
|
||||
, m_length(length)
|
||||
, m_presentationTime(presentationTime)
|
||||
{}
|
||||
|
||||
|
||||
QString NextTopicJournal::getText() const
|
||||
{
|
||||
return Journal::tr("%1 '%2' started at %3 for %4 seconds on %5").arg(m_isFilter ? tr("FilterTopic") : tr("Topic"),
|
||||
m_topicTypeName, pttt(m_presentationTime)).arg(m_length).arg(started());
|
||||
}
|
||||
|
||||
|
||||
QString PlayJournal::getText() const
|
||||
{
|
||||
return Journal::tr("Started / resumed script at %1 on %2").arg(pttt(m_presentationTime), started());
|
||||
}
|
||||
|
||||
|
||||
QString PauseJournal::getText() const
|
||||
{
|
||||
return Journal::tr("Paused script at %1 on %2").arg(pttt(m_presentationTime), started());
|
||||
}
|
||||
|
||||
|
||||
QString EndedJournal::getText() const
|
||||
{
|
||||
return Journal::tr("Script ended at %1 on %2").arg(pttt(m_presentationTime), started());
|
||||
}
|
||||
|
||||
|
||||
QString StopJournal::getText() const
|
||||
{
|
||||
return Journal::tr("Script stopped at %1 on %2").arg(pttt(m_presentationTime), started());
|
||||
}
|
||||
|
||||
|
||||
QString SetTimeJournal::getText() const
|
||||
{
|
||||
return Journal::tr("Position time set to %1 on %2").arg(pttt(m_toPresentationTime), started());
|
||||
}
|
||||
|
||||
} // namespace PresentationManagement
|
||||
+131
@@ -0,0 +1,131 @@
|
||||
#pragma once
|
||||
|
||||
#include <QCoreApplication>
|
||||
#include <QVector>
|
||||
|
||||
|
||||
namespace PresentationManagement
|
||||
{
|
||||
|
||||
class Journal
|
||||
{
|
||||
Q_DECLARE_TR_FUNCTIONS(Journal)
|
||||
|
||||
public:
|
||||
Journal();
|
||||
virtual ~Journal() = default;
|
||||
QString started() const;
|
||||
virtual QString getText() const = 0;
|
||||
qint64 m_started;
|
||||
};
|
||||
|
||||
|
||||
class MainJournal
|
||||
{
|
||||
public:
|
||||
~MainJournal();
|
||||
QString getText() const;
|
||||
|
||||
qint64 started = 0;
|
||||
QVector<Journal *> journalList;
|
||||
};
|
||||
|
||||
|
||||
class NextTopicJournal : public Journal
|
||||
{
|
||||
public:
|
||||
NextTopicJournal(int presentationTime, bool isFilter, /*int topicId, */const QString &topicTypeName, int length);
|
||||
QString getText() const override final;
|
||||
|
||||
bool m_isFilter;
|
||||
//int m_topicId;
|
||||
QString m_topicTypeName;
|
||||
int m_length;
|
||||
int m_presentationTime;
|
||||
};
|
||||
|
||||
|
||||
class PlayJournal : public Journal
|
||||
{
|
||||
public:
|
||||
explicit PlayJournal(int presentationTime)
|
||||
: Journal()
|
||||
, m_presentationTime(presentationTime)
|
||||
{}
|
||||
|
||||
QString getText() const override final;
|
||||
|
||||
int m_presentationTime;
|
||||
};
|
||||
|
||||
|
||||
class PauseJournal : public Journal
|
||||
{
|
||||
public:
|
||||
explicit PauseJournal(int presentationTime)
|
||||
: Journal()
|
||||
, m_presentationTime(presentationTime)
|
||||
{}
|
||||
|
||||
QString getText() const override final;
|
||||
|
||||
int m_presentationTime;
|
||||
};
|
||||
|
||||
|
||||
class EndedJournal : public Journal
|
||||
{
|
||||
public:
|
||||
explicit EndedJournal(int presentationTime)
|
||||
: Journal()
|
||||
, m_presentationTime(presentationTime)
|
||||
{}
|
||||
|
||||
QString getText() const override final;
|
||||
|
||||
int m_presentationTime;
|
||||
};
|
||||
|
||||
|
||||
class StopJournal : public Journal
|
||||
{
|
||||
public:
|
||||
explicit StopJournal(int presentationTime)
|
||||
: Journal()
|
||||
, m_presentationTime(presentationTime)
|
||||
{}
|
||||
|
||||
QString getText() const override final;
|
||||
|
||||
int m_presentationTime;
|
||||
};
|
||||
|
||||
|
||||
class SetTimeJournal : public Journal
|
||||
{
|
||||
public:
|
||||
explicit SetTimeJournal(int toPresentationTime)
|
||||
: Journal()
|
||||
, m_toPresentationTime(toPresentationTime)
|
||||
{}
|
||||
|
||||
QString getText() const override final;
|
||||
|
||||
int m_toPresentationTime;
|
||||
};
|
||||
|
||||
} // namespace PresentationManagement
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
#include "pre_screen.h"
|
||||
|
||||
#include <QStyleOption>
|
||||
#include <QPainter>
|
||||
|
||||
|
||||
Screen::Screen()
|
||||
: QWidget()
|
||||
{
|
||||
setBgColor(QColor("black"));
|
||||
setContentsMargins(0, 0, 0, 0);
|
||||
}
|
||||
|
||||
|
||||
Screen::~Screen()
|
||||
{
|
||||
const auto p1Widgets = findChildren<QWidget *>(QString(), Qt::FindDirectChildrenOnly);
|
||||
for (QWidget *w : p1Widgets)
|
||||
w->setParent(nullptr);
|
||||
}
|
||||
|
||||
|
||||
void Screen::setBgColor(const QColor &color)
|
||||
{
|
||||
setStyleSheet(QStringLiteral("Screen { background: %1; background-color: %1; }").arg(color.name()));
|
||||
}
|
||||
|
||||
|
||||
void Screen::paintEvent(QPaintEvent *) // needed to apply the style sheet...........
|
||||
{
|
||||
QStyleOption opt;
|
||||
opt.init(this);
|
||||
QPainter p(this);
|
||||
style()->drawPrimitive(QStyle::PE_Widget, &opt, &p, this);
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
#pragma once
|
||||
|
||||
#include <QWidget>
|
||||
|
||||
|
||||
class Screen : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
Screen();
|
||||
virtual ~Screen();
|
||||
|
||||
void setBgColor(const QColor &color);
|
||||
|
||||
private:
|
||||
void paintEvent(QPaintEvent *) override;
|
||||
};
|
||||
+3377
File diff suppressed because it is too large.
Load diff
+402
@@ -0,0 +1,402 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* PresentationManagement - Script Editor
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*
|
||||
* Created by Mike Wille, SLSE, 2017-03-17
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "pre_screen.h"
|
||||
#include "pre_journal_types.h"
|
||||
#include "pre_storyboard.h" // QPointer
|
||||
#include "filter_topic.h"
|
||||
|
||||
#include <DDS/Core/core_dtc.h>
|
||||
#include <PluginInterfaces/topic_replay_interface.h>
|
||||
#include <LtsPluginManager/lts_plugin_manager.h>
|
||||
#include <LtsWidgets/lts_dialog.h>
|
||||
#include <LtsUtilsGuiDds/request_helper.h>
|
||||
#include <LtsScriptTimeline/track_entry_painters.h> // TET
|
||||
#include <LtsScriptTimeline/temporary_pointer_vector.h>
|
||||
#include <LtsSession/lts_session.h>
|
||||
#include <Plugins/PresentationManagement/Gui/Common/topic_assignment.h>
|
||||
#include <Services/PresentationManagement/pre_dtc.h>
|
||||
#include <Services/PresentationManagement/pre_ftc.h>
|
||||
#include <Services/PresentationManagement/logger.h>
|
||||
#include <Services/SituationReplayManagement/srm_ftc.h>
|
||||
#include <Services/OperatorManagement/opm_dtc.h>
|
||||
|
||||
|
||||
// foreign gui plugins for the topic playback
|
||||
#include <Plugins/SituationReplay/srp_gui_plugin_interface.h>
|
||||
#include <Plugins/SituationMapPlugin/situation_map_gui_plugin_interface.h>
|
||||
|
||||
#include <QString>
|
||||
#include <QStringList>
|
||||
#include <QMap>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
|
||||
|
||||
namespace TakeHomePackageGenerator
|
||||
{
|
||||
class ExportProcess;
|
||||
}
|
||||
namespace Ui
|
||||
{
|
||||
class ScriptDialog;
|
||||
}
|
||||
namespace LtsScriptTimeline
|
||||
{
|
||||
class TrackEntry;
|
||||
}
|
||||
namespace SituationReplayManagement
|
||||
{
|
||||
class ForeignDataInterface;
|
||||
}
|
||||
namespace LtsPluginManager
|
||||
{
|
||||
class LtsPluginManager;
|
||||
}
|
||||
namespace Ui
|
||||
{
|
||||
class ScriptPlayerDialog;
|
||||
}
|
||||
namespace LtsScriptTimeline
|
||||
{
|
||||
class TrackEntry;
|
||||
}
|
||||
namespace LtsUtils
|
||||
{
|
||||
class Promise;
|
||||
}
|
||||
|
||||
|
||||
namespace PresentationManagement
|
||||
{
|
||||
class TopicDesigner;
|
||||
|
||||
namespace Interface
|
||||
{
|
||||
class Ftc;
|
||||
}
|
||||
|
||||
|
||||
class ScriptDialog : public LtsWidgets::LtsDialog
|
||||
, protected PresentationManagement::Interface::Ftc::PresentationModifyReplyHandler
|
||||
, protected PresentationManagement::Interface::Ftc::GetPresentationContentReplyHandler
|
||||
, protected SituationReplayManagement::Interface::Ftc::ReplayPartitionCreateReplyHandler
|
||||
, protected SituationReplayManagement::Interface::Ftc::ReplayPartitionRemoveReplyHandler
|
||||
{
|
||||
public:
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit ScriptDialog(const QString &menuGroup, QWidget *parent = nullptr);
|
||||
~ScriptDialog();
|
||||
|
||||
LtsSession::LtsSession *eVSession() { return m_essentialsViewSession; }
|
||||
|
||||
bool init(LtsSession::LtsSession *session,
|
||||
const int scriptId,
|
||||
const std::shared_ptr<Interface::Dtc> &dtc,
|
||||
const std::shared_ptr<Interface::Ftc> &ftc,
|
||||
const std::shared_ptr<SituationReplayManagement::ForeignDataInterface> &srmForeign,
|
||||
const std::shared_ptr<Core::Interface::Dtc> &coreDtc,
|
||||
const std::shared_ptr<OperatorManagement::Interface::Dtc> &opmDtc);
|
||||
|
||||
void loadScript();
|
||||
TopicEditorBase::TopicEditor *createTopic(const TopicAssignment &ta);
|
||||
TopicEditorBase::TopicEditor *createTopic(const LtsScriptTimeline::TrackEntry &data);
|
||||
void createTopicFromTrackEntry(LtsScriptTimeline::TrackEntry *data);
|
||||
|
||||
bool topicStringToType(const QString &typeName, LtsScriptTimeline::TrackEntryType &tet) const;
|
||||
int getCurrentScriptEndTime() const;
|
||||
bool isEssentialsViewOpened() const;
|
||||
|
||||
static LtsScriptTimeline::TrackEntry *trackEntryFromContent(const PresentationManagement::PresentationContent &content,
|
||||
int topicId,
|
||||
LtsScriptTimeline::TrackEntryType trackType);
|
||||
|
||||
bool importTrackEntries(const QVector<LtsScriptTimeline::TrackEntry *> &tes);
|
||||
|
||||
std::shared_ptr<SituationReplay::ForeignGuiInterface> getReplayGuiIfc() const
|
||||
{
|
||||
return m_essentialsViewsSrpGuiIfc;
|
||||
}
|
||||
|
||||
private:
|
||||
enum class ProjectionWidget
|
||||
{
|
||||
Unknown = 0,
|
||||
Screen1,
|
||||
Screen2,
|
||||
};
|
||||
|
||||
|
||||
enum class SpecialTopicType
|
||||
{
|
||||
NonSpecial = 0,
|
||||
ReplayTopic,
|
||||
FilterTopic,
|
||||
};
|
||||
|
||||
|
||||
class PlayingTopic
|
||||
{
|
||||
public:
|
||||
PlayingTopic() = default;
|
||||
|
||||
~PlayingTopic()
|
||||
{
|
||||
if (topicReplayIfc != nullptr)
|
||||
{
|
||||
topicReplayIfc->playbackStop();
|
||||
delete topicReplayIfc;
|
||||
}
|
||||
// if (replayWidget) HACK: FIXME: trading memory for security BUT dont delete if it's the situation map app's base layout !
|
||||
// delete replayWidget;
|
||||
}
|
||||
|
||||
QString topicTypeName;
|
||||
LtsScriptTimeline::TrackEntry *topic = nullptr;
|
||||
TopicReplay::Interface *topicReplayIfc = nullptr; // 1 instance per 1 currently playing topic
|
||||
QWidget *replayWidget = nullptr;
|
||||
LtsScriptTimeline::TrackEntryType trackEntryType = LtsScriptTimeline::TrackEntryType::INVALID;
|
||||
bool isFilter = false;
|
||||
};
|
||||
|
||||
|
||||
void onPresentationModifyReply(const Core::FunctionReplyObject &replyObject) override { if (m_requestHelper != nullptr) m_requestHelper->requestReply(replyObject); }
|
||||
void onGetPresentationContentReply(const GetPresentationContentReply &reply) override { if (m_requestHelper != nullptr) m_requestHelper->requestReply(reply); }
|
||||
void onReplayPartitionCreateReply(const Core::FunctionReplyObject &reply) override { if (m_requestHelper != nullptr) m_requestHelper->requestReply(reply); }
|
||||
void onReplayPartitionRemoveReply(const Core::FunctionReplyObject &) override { /* ignore */ }
|
||||
|
||||
void retranslate() override;
|
||||
bool apply() override;
|
||||
void aboutToClose() override;
|
||||
void getPresentationContent(); // tryAddTopics has to be called first to populate m_trackEntryAssignments
|
||||
TopicEditorBase::TopicEditor *createTopicEditor(LtsScriptTimeline::TrackEntry *te);
|
||||
bool topicTypeOnEssentialsView(LtsScriptTimeline::TrackEntryType tet) const;
|
||||
void startEssentialsViewStage2(const Core::ReplayPartition &replay);
|
||||
bool tryAddTopics(QStringList &resultList);
|
||||
void fillTopicVector();
|
||||
void createSitMapApp();
|
||||
void startReplaySession();
|
||||
void exportPresentationContent(const Core::FunctionReply &baseReply);
|
||||
void disableSessionDialog(LtsSession::LtsSession *pSession, bool disable);
|
||||
void deletePlayingTopic(PlayingTopic *playingTopic); // WARNING: use a mutable iterator while iterating over m_currentlyPlayingTopics and remove the entry before calling this method!
|
||||
static QString toReadableTime(qint64 seconds);
|
||||
ProjectionWidget identifyProjectionWidget(LtsScriptTimeline::TrackEntry *topic) const;
|
||||
bool usesAvsWindow(LtsScriptTimeline::TrackEntryType trackEntryType) const;
|
||||
void playTopic(LtsScriptTimeline::TrackEntry *topic);
|
||||
bool enableFireEventFlash(bool enable);
|
||||
void pausePlayingTopics();
|
||||
static bool isFilter(LtsScriptTimeline::TrackEntryType tet);
|
||||
void initProjectionWidget(Screen **pointerToWidgetPointer);
|
||||
void deleteProjectionWidget(Screen **pointerToWidgetPointer);
|
||||
bool _tryAddTopic(LtsScriptTimeline::TrackEntryType trackEntryType,
|
||||
const std::shared_ptr<TopicEditorBase::Interface> &topicEditorIfc,
|
||||
const std::shared_ptr<TopicReplay::Factory> &topicReplayFactory,
|
||||
const std::shared_ptr<TopicReplay::Factory> &topicExportFactory,
|
||||
QStringList &resultList,
|
||||
const SpecialTopicType &specialTopicType = SpecialTopicType::NonSpecial);
|
||||
void initFailed(int reason);
|
||||
void setFreestanding(bool freestanding, const ProjectionWidget &pw);
|
||||
void setReplayWidgetFreestanding(PlayingTopic *playingTopic, bool freestanding);
|
||||
void printCurrentlyPlayingTopics();
|
||||
void addReplayWidget(PlayingTopic *playingTopic, QWidget *replayWidget);
|
||||
Screen *getProjectionWidget(const ScriptDialog::ProjectionWidget &projectionWidget);
|
||||
bool isScreenFreestanding(const ProjectionWidget &pw) const;
|
||||
void previewSecond(int time, int ignoreTopicForReplay = -1);
|
||||
void setReplayWidgetPosition(PlayingTopic *playingTopic);
|
||||
void avsFreestandingHack(bool freestanding, QWidget *projectionWidget, QWidget **parentForScreen);
|
||||
void avsVisibilityHack(QWidget *parentForScreen, bool visible);
|
||||
void stop(bool ended = false, bool ignoreFireEventFlashing = false);
|
||||
void changelogCheck();
|
||||
int previousTopicTime() const;
|
||||
bool hasPreviousTopic() const { return previousTopicTime() > -1; }
|
||||
int nextTopicTime() const;
|
||||
bool hasNextTopic() const { return nextTopicTime() > -1; }
|
||||
void setPositionTime(int positionTime, bool setByUser = false);
|
||||
void setPositionTimeActive(int positionTime, bool setByUser = false); // setPositionTime, but, if playing, also ticks and resets timeout
|
||||
|
||||
|
||||
template <typename TopicEditorInterface>
|
||||
std::shared_ptr<TopicEditorBase::Interface> getTopicEditorIfc(LtsScriptTimeline::TrackEntryType trackEntryType)
|
||||
{
|
||||
std::shared_ptr<TopicEditorBase::Interface> topicEditorIfc;
|
||||
|
||||
if (!m_exerciseSession->interfaceFromGui<TopicEditorInterface>(topicEditorIfc))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "getTopicEditorIfc failed: Cannot add topic type "
|
||||
<< LtsScriptTimeline::trackEntryTypeName(trackEntryType)
|
||||
<< " because topic editor ifc is missing.";
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return topicEditorIfc;
|
||||
}
|
||||
|
||||
|
||||
template <typename TopicReplayInterface>
|
||||
std::shared_ptr<TopicReplay::Factory> getTopicReplayFactory(LtsScriptTimeline::TrackEntryType trackEntryType)
|
||||
{
|
||||
std::shared_ptr<TopicReplay::Factory> topicReplayFactory;
|
||||
|
||||
if (!m_replaySession->interfaceFromGui<TopicReplayInterface>(topicReplayFactory))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "getTopicIfcFactory failed: Cannot add topic type "
|
||||
<< LtsScriptTimeline::trackEntryTypeName(trackEntryType)
|
||||
<< " because topic ifc factory is missing.";
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return topicReplayFactory;
|
||||
}
|
||||
|
||||
|
||||
template <typename TopicEditorGuiInterface,
|
||||
typename TopicReplayFactory = TopicReplay::Factory,
|
||||
typename TopicExportFactory = TopicReplayFactory>
|
||||
bool tryAddTopic(LtsScriptTimeline::TrackEntryType trackEntryType,
|
||||
QStringList &resultList,
|
||||
const SpecialTopicType &specialTopicType = SpecialTopicType::NonSpecial)
|
||||
{
|
||||
std::shared_ptr<TopicEditorBase::Interface> topicEditorIfc;
|
||||
std::shared_ptr<TopicReplay::Factory> topicReplayFactory;
|
||||
std::shared_ptr<TopicReplay::Factory> topicExportFactory;
|
||||
|
||||
if (!std::is_same<TopicEditorBase::Interface, TopicEditorGuiInterface>::value)
|
||||
{
|
||||
topicEditorIfc = getTopicEditorIfc<TopicEditorGuiInterface>(trackEntryType);
|
||||
|
||||
if (topicEditorIfc == nullptr)
|
||||
{
|
||||
resultList.append(LtsScriptTimeline::trackEntryTypeName(trackEntryType));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (!std::is_same<TopicReplay::Factory, TopicReplayFactory>::value)
|
||||
{
|
||||
topicReplayFactory = getTopicReplayFactory<TopicReplayFactory>(trackEntryType);
|
||||
|
||||
if (topicReplayFactory == nullptr)
|
||||
{
|
||||
resultList.append(LtsScriptTimeline::trackEntryTypeName(trackEntryType));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (!std::is_same<TopicReplay::Factory, TopicExportFactory>::value)
|
||||
{
|
||||
topicExportFactory = getTopicReplayFactory<TopicExportFactory>(trackEntryType);
|
||||
|
||||
if (topicExportFactory == nullptr)
|
||||
{
|
||||
resultList.append(LtsScriptTimeline::trackEntryTypeName(trackEntryType));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
topicExportFactory = topicReplayFactory;
|
||||
|
||||
return _tryAddTopic(trackEntryType, topicEditorIfc, topicReplayFactory, topicExportFactory, resultList, specialTopicType);
|
||||
}
|
||||
|
||||
|
||||
Ui::ScriptDialog *m_ui;
|
||||
LtsSession::LtsSession *m_essentialsViewSession;
|
||||
std::shared_ptr<SituationReplay::ForeignGuiInterface> m_essentialsViewsSrpGuiIfc;
|
||||
std::shared_ptr<PresentationManagement::Interface::Dtc> m_dtc;
|
||||
std::shared_ptr<PresentationManagement::Interface::Ftc> m_ftc;
|
||||
std::shared_ptr<SituationReplayManagement::ForeignDataInterface> m_srmForeign;
|
||||
std::shared_ptr<Core::Interface::Dtc> m_coreDtc;
|
||||
std::shared_ptr<OperatorManagement::Interface::Dtc> m_opmDtc;
|
||||
QString m_menuGroup;
|
||||
LtsUtils::RequestHelper *m_requestHelper;
|
||||
int m_selectedTeId;
|
||||
TopicEditorBase::TopicEditor *m_currentTopicEditor;
|
||||
int m_scriptId;
|
||||
QMap<QString, TopicAssignment> m_trackEntryAssignments;
|
||||
QMap<LtsScriptTimeline::TrackEntryType, TopicAssignment> m_trackEntryToTopicAssignment;
|
||||
LtsPluginManager::LtsPluginManager *m_essentialsViewApp;
|
||||
QString m_scriptName;
|
||||
QString m_scriptOwner;
|
||||
qint64 m_lastModified = 0;
|
||||
QVector<LtsScriptTimeline::TrackEntry *> m_topicVector;
|
||||
QMultiMap<int, LtsScriptTimeline::TrackEntry *> m_topicMap; // <seconds, trackEntry>
|
||||
QVector<FilterTopic> m_filterTopicVector;
|
||||
TakeHomePackageGenerator::ExportProcess *m_exportProcess;
|
||||
LtsSession::LtsSession *m_exerciseSession; // aka. script editor app
|
||||
LtsSession::LtsSession *m_replaySession;
|
||||
QTimer *m_presentationTimer;
|
||||
int m_lowestTime;
|
||||
int m_highestTime;
|
||||
int m_positionTime;
|
||||
int m_duration;
|
||||
int m_nextPauseTime;
|
||||
QVector<PlayingTopic *> m_currentlyPlayingTopics; // also indicates that the script is either playing or in paused state if NOT empty
|
||||
Screen *m_projectionWidget1;
|
||||
Screen *m_projectionWidget2;
|
||||
MainJournal m_journal;
|
||||
int m_scriptsExerciseId;
|
||||
QString m_exerciseName;
|
||||
LtsPluginManager::LtsPluginManager *m_sitMapApp;
|
||||
LtsSession::LtsSession *m_sitMapSession;
|
||||
bool m_currentlyFreestandingTopicsScreen1;
|
||||
bool m_currentlyFreestandingTopicsScreen2;
|
||||
TopicReplay::Interface *m_sitMapTopicIfc;
|
||||
bool m_firstPlayAfterStop;
|
||||
bool m_enableApply;
|
||||
bool m_stopAfterPlayingFilterTopic;
|
||||
QWidget *m_previousParentForScreen1;
|
||||
QWidget *m_previousParentForScreen2;
|
||||
int m_ignoreTopicForReplay;
|
||||
QPointer<TopicDesigner> m_currentTopicDesigner;
|
||||
bool m_avsVisibilityHackActive;
|
||||
QPointer<StoryboardDialog> m_storyboardDialog;
|
||||
bool m_ignoreChanges;
|
||||
bool m_scriptRunning;
|
||||
bool m_bTimerTickRecursionGuard;
|
||||
bool m_isPlayTopicMethodStillRunning;
|
||||
|
||||
LOGGER_T m_logger;
|
||||
|
||||
private slots:
|
||||
void slotEditEntry(const int topicId);
|
||||
void slotTrackEntrySelectionChanged(LtsScriptTimeline::TrackEntry *);
|
||||
void slotChangesWereMade();
|
||||
void slotTrackEntryModified();
|
||||
void slotNull(QObject *obj);
|
||||
void slotDiscard();
|
||||
void slotStartEssentialsView();
|
||||
void slotLoadScript();
|
||||
void slotExportScript();
|
||||
void slotExportSuccessful(const QString &path, const QString &failedTopics);
|
||||
void slotBurnDvD(const QString &strExportPath);
|
||||
void slotBurningFinished(bool success);
|
||||
void slotPlay();
|
||||
void slotPause();
|
||||
void slotStop();
|
||||
void slotTimerTick();
|
||||
void slotShowStoryboard();
|
||||
void slotShowJournal();
|
||||
void slotToNextTopic();
|
||||
void slotToPreviousTopic();
|
||||
void slotPlayUntilNextTopic();
|
||||
void slotSetTopicPosition(QWidget *previewWidget, int ignoreTopicForReplay);
|
||||
void slotTrackEntryDeleted(const int topicId);
|
||||
void slotEditSelectedEntry();
|
||||
void slotCheckNewTopicLength(int newLength, LtsUtils::Promise *promise);
|
||||
void slotAddFakeLegacyPlanTopic();
|
||||
|
||||
void slotChangesMade();
|
||||
};
|
||||
|
||||
} // namespace PresentationManagement
|
||||
+320
@@ -0,0 +1,320 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>ScriptDialog</class>
|
||||
<widget class="QWidget" name="ScriptDialog">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>1010</width>
|
||||
<height>587</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="MinimumExpanding" vsizetype="MinimumExpanding">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Script Editor</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout" stretch="999,0">
|
||||
<property name="spacing">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="leftMargin">
|
||||
<number>9</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>9</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>9</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>9</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="LtsScriptTimeline::ScriptTimeline" name="widget" native="true">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="MinimumExpanding" vsizetype="MinimumExpanding">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="replayControls">
|
||||
<property name="title">
|
||||
<string>Replay Controls</string>
|
||||
</property>
|
||||
<property name="checkable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_5">
|
||||
<item>
|
||||
<widget class="QWidget" name="replayControlsWidget" native="true">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout" stretch="0,0,999">
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="replayControlsLayout">
|
||||
<item>
|
||||
<layout class="QVBoxLayout" name="replayControlsMainLayout">
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="replayControlsScreensLayout">
|
||||
<item>
|
||||
<widget class="QPushButton" name="pbInitScr1">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Set Screen 1</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="pbInitScr2">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Set Screen 2</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="pbStop">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Stop</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="pbPause">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Pause</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="pbPlay">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Play</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QVBoxLayout" name="replayControlsJumpLayout">
|
||||
<item>
|
||||
<widget class="QPushButton" name="pbUntilNextTopic">
|
||||
<property name="text">
|
||||
<string>Play Until Next Topic</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="pbPreviousTopic">
|
||||
<property name="text">
|
||||
<string>Previous Topic</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="pbNextTopic">
|
||||
<property name="text">
|
||||
<string>Next Topic</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QFormLayout" name="replayInfoLayout">
|
||||
<property name="horizontalSpacing">
|
||||
<number>9</number>
|
||||
</property>
|
||||
<property name="verticalSpacing">
|
||||
<number>9</number>
|
||||
</property>
|
||||
<property name="leftMargin">
|
||||
<number>9</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>9</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>9</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>9</number>
|
||||
</property>
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="durationLabel">
|
||||
<property name="text">
|
||||
<string>Presentation duration:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QLabel" name="lblDuration">
|
||||
<property name="text">
|
||||
<string notr="true"> - </string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="posLabel">
|
||||
<property name="text">
|
||||
<string>Pos:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QSlider" name="posSlider">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="tickPosition">
|
||||
<enum>QSlider::TicksBelow</enum>
|
||||
</property>
|
||||
<property name="const" stdset="0">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="currentPosLabel">
|
||||
<property name="text">
|
||||
<string>Current position:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<layout class="QHBoxLayout" name="currentositionLayout">
|
||||
<item>
|
||||
<widget class="QLabel" name="lblPos">
|
||||
<property name="text">
|
||||
<string notr="true">0</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="slashLabel">
|
||||
<property name="text">
|
||||
<string>/</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="lblMax">
|
||||
<property name="text">
|
||||
<string notr="true">0</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer_3">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QVBoxLayout" name="statusLayout">
|
||||
<item>
|
||||
<widget class="QLabel" name="statusLabel">
|
||||
<property name="text">
|
||||
<string>Status:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QListWidget" name="lwStatus">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="MinimumExpanding" vsizetype="MinimumExpanding">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="sizeAdjustPolicy">
|
||||
<enum>QAbstractScrollArea::AdjustToContentsOnFirstShow</enum>
|
||||
</property>
|
||||
<property name="editTriggers">
|
||||
<set>QAbstractItemView::NoEditTriggers</set>
|
||||
</property>
|
||||
<property name="showDropIndicator" stdset="0">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="alternatingRowColors">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="selectionMode">
|
||||
<enum>QAbstractItemView::NoSelection</enum>
|
||||
</property>
|
||||
<property name="verticalScrollMode">
|
||||
<enum>QAbstractItemView::ScrollPerPixel</enum>
|
||||
</property>
|
||||
<property name="movement">
|
||||
<enum>QListView::Free</enum>
|
||||
</property>
|
||||
<property name="isWrapping" stdset="0">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
<class>LtsScriptTimeline::ScriptTimeline</class>
|
||||
<extends>QWidget</extends>
|
||||
<header location="global">LtsScriptTimeline/script_timeline.h</header>
|
||||
<container>1</container>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
+376
@@ -0,0 +1,376 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* GUI Plugin for Script Editor
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*
|
||||
* Created by Mike Wille, SLSE, 2017-03-17
|
||||
*/
|
||||
|
||||
#include "pre_script_gui_plugin.h"
|
||||
#include "pre_script_dialog.h"
|
||||
|
||||
#include <Plugins/OperatorManagement/opm_data_plugin_interface.h>
|
||||
#include <Plugins/PresentationManagement/Gui/Script/Common/ScriptChooser/script_chooser.h>
|
||||
#include <Plugins/PresentationManagement/Gui/Common/pre_edit_dialog.h>
|
||||
#include <LtsWidgets/lts_base_layout_widget.h>
|
||||
#include <LtsSession/lts_session.h>
|
||||
#include <LtsSession/lts_session_manager.h>
|
||||
#include <LtsSession/lts_session_data.h>
|
||||
#include <LtsWidgets/lts_background_widget.h>
|
||||
#include <LtsWidgets/lts_message_dialog.h>
|
||||
#include <LtsScriptTimeline/track_entry.h>
|
||||
#include <LtsScriptTimeline/temporary_pointer_vector.h>
|
||||
#include <Common/TopicEditorBase/topic_editor_base.h>
|
||||
|
||||
// Control- & Widget-Ifcs:
|
||||
#include <Plugins/SituationReplay/srp_gui_plugin_interface.h>
|
||||
#include <Plugins/SituationMapPlugin/situation_map_gui_plugin_interface.h>
|
||||
#include <Plugins/FileManagement/flm_explorer_gui_plugin_interface.h>
|
||||
#include <Plugins/BuildingViewer/bdv_viewer_gui_plugin_interface.h>
|
||||
#include <Plugins/AudioVideoManagement/avm_menu_edit_gui_plugin_interface.h>
|
||||
#include <Plugins/SituationMapPlugin/situation_map_script_filter_gui_plugin_interface.h>
|
||||
#include <Plugins/MarkerManagement/mrk_gui_plugin_interface.h>
|
||||
#include <Plugins/Evaluations/evl_gui_plugin_interface.h>
|
||||
#include <Plugins/ReportManagement/rep_gui_plugin_interface.h>
|
||||
#include <Plugins/PlanOverlays/plan_overlays_plugin_interface.h>
|
||||
#include <Services/PresentationManagement/pre_operator_rights.h>
|
||||
#include <Services/PresentationManagement/pre_dtc.h>
|
||||
|
||||
#include <QDir>
|
||||
#include <QJsonParseError>
|
||||
#include <QJsonDocument>
|
||||
#include <QProgressDialog>
|
||||
#include <QTimer>
|
||||
#include <QFileDialog>
|
||||
#include <QVBoxLayout>
|
||||
#include <QDateTime>
|
||||
|
||||
#include <stdlib.h> // for abort
|
||||
|
||||
|
||||
namespace PresentationManagement
|
||||
{
|
||||
std::shared_ptr<GuiPluginBase::Interface> GuiPlugin::createGuiInterface(LtsSession::LtsSession *session)
|
||||
{
|
||||
return std::make_shared<InterfaceImpl>(session);
|
||||
}
|
||||
|
||||
|
||||
InterfaceImpl::InterfaceImpl(LtsSession::LtsSession *session)
|
||||
: GuiPluginBase::Interface(session, getLogger("Plugins.Gui.Pre.Script"))
|
||||
, m_dtc(nullptr)
|
||||
, m_opmDtc(nullptr)
|
||||
, m_ftc(nullptr)
|
||||
, m_repForeign(nullptr)
|
||||
, m_scriptDialog(nullptr)
|
||||
, m_scriptId(0) // invalid
|
||||
, m_requestHelper(new LtsUtils::RequestHelper(this))
|
||||
{
|
||||
connect(this, &InterfaceImpl::signalSuccess, m_session, &LtsSession::LtsSession::slotExecuteNextPayload, Qt::QueuedConnection);
|
||||
}
|
||||
|
||||
|
||||
QVector<LtsWidgets::PluginData> InterfaceImpl::getActions()
|
||||
{
|
||||
QVector<LtsWidgets::PluginData> ret;
|
||||
{
|
||||
LtsWidgets::PluginData data;
|
||||
data.menuGroup = menuGroup();
|
||||
data.identifier = QStringLiteral("PresentationManagement.ScriptDialog");
|
||||
data.menuText = tr("Show Script Editor");
|
||||
|
||||
if (getFlags().testFlag(LtsAppDescriptor::PluginInfo::Flag::MAIN))
|
||||
{
|
||||
data.layoutArea = LtsWidgets::LayoutArea::eMainTab;
|
||||
data.createInstant = LtsWidgets::CreateInstantType::CreateInstantAndDiscardAction;
|
||||
data.closable = false;
|
||||
}
|
||||
else // (as dialog) = rather unlikely..
|
||||
{
|
||||
data.layoutArea = LtsWidgets::LayoutArea::eDialogTab;
|
||||
}
|
||||
data.operatorRight = OperatorRights::ScriptEditorShow;
|
||||
data.createWidgetFunc = [this](QWidget *parent)
|
||||
{
|
||||
return onShowScriptDialog(parent);
|
||||
};
|
||||
|
||||
ret.append(data);
|
||||
}
|
||||
|
||||
{
|
||||
LtsWidgets::PluginData data;
|
||||
data.menuGroup = menuGroup();
|
||||
data.identifier = QLatin1String("PresentationManagement.ScriptDialog.ImportScript");
|
||||
data.menuIcon = QIcon(QLatin1String("icon:import_documents.svg"));
|
||||
data.menuText = tr("Insert Script");
|
||||
data.operatorRight = OperatorRights::ScriptEditorEdit;
|
||||
data.directFunc = [this](const LtsWidgets::PluginData &)
|
||||
{
|
||||
return onImportScript();
|
||||
};
|
||||
data.createWidgetFunc = nullptr;
|
||||
|
||||
ret.append(data);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
bool InterfaceImpl::fetchInterfaces()
|
||||
{
|
||||
if (!m_session->getDtc<PresentationManagement::DataInterface>(m_dtc))
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "getDtc for PresentationManagement::DataInterface failed.";
|
||||
return false;
|
||||
}
|
||||
if (!m_session->getFtc<PresentationManagement::DataInterface>(m_ftc))
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "getFtc for PresentationManagement::DataInterface failed.";
|
||||
return false;
|
||||
}
|
||||
if (!m_session->getDtc<OperatorManagement::DataInterface>(m_opmDtc))
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "getDtc for OperatorManagement::DataInterface failed.";
|
||||
return false;
|
||||
}
|
||||
if (!m_session->getDtc<SituationReplayManagement::DataInterface>(m_coreDtc))
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "getDtc for SituationReplayManagement::DataInterface failed.";
|
||||
return false;
|
||||
}
|
||||
if (!m_session->getForeignDataInterface<SituationReplayManagement::DataInterface>(m_repForeign))
|
||||
{
|
||||
WARNING_LOG(m_logger) << "getForeignDataInterface for SituationReplayManagement::DataInterface failed.";
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void InterfaceImpl::clearInterfaces()
|
||||
{
|
||||
m_repForeign = nullptr;
|
||||
m_coreDtc = nullptr;
|
||||
m_opmDtc = nullptr;
|
||||
m_ftc = nullptr;
|
||||
m_dtc = nullptr;
|
||||
}
|
||||
|
||||
|
||||
QString InterfaceImpl::menuGroup() const
|
||||
{
|
||||
return tr("Presentation");
|
||||
}
|
||||
|
||||
|
||||
LtsWidgets::LtsDialog *InterfaceImpl::onShowScriptDialog(QWidget *parent)
|
||||
{
|
||||
m_scriptDialog = new ScriptDialog(menuGroup(), parent);
|
||||
|
||||
if (!m_scriptDialog->init(m_session, m_scriptId, m_dtc, m_ftc, m_repForeign, m_coreDtc, m_opmDtc))
|
||||
{
|
||||
m_scriptDialog->deleteLater();
|
||||
m_scriptDialog = nullptr;
|
||||
|
||||
// dialog is app's main dialog, close app if dialog cannot initialize
|
||||
emit m_session->signalClose();
|
||||
}
|
||||
|
||||
return m_scriptDialog.data();
|
||||
}
|
||||
|
||||
|
||||
void InterfaceImpl::onImportScript()
|
||||
{
|
||||
ScriptChooser *scriptChooser = new ScriptChooser(m_dtc, m_opmDtc, false, true);
|
||||
scriptChooser->setAttribute(Qt::WA_DeleteOnClose);
|
||||
|
||||
connect(scriptChooser, &ScriptChooser::signalSelectScript,
|
||||
this, &InterfaceImpl::slotImportScript, Qt::QueuedConnection);
|
||||
|
||||
connect(scriptChooser, &ScriptChooser::signalQuit,
|
||||
m_session, &LtsSession::LtsSession::signalQuit);
|
||||
|
||||
if (!LtsSessionData::LtsSessionData::getInstance()->isTablet())
|
||||
scriptChooser->setModal(true);
|
||||
scriptChooser->show();
|
||||
}
|
||||
|
||||
|
||||
void InterfaceImpl::slotNewScript()
|
||||
{
|
||||
// prepare request
|
||||
PresentationModifyRequest req;
|
||||
req.name(tr("New Script").toStdString());
|
||||
req.description(tr("No description available.").toStdString());
|
||||
req.operatorId(LtsSessionData::LtsSessionData::getInstance()->getOperatorId());
|
||||
req.lastModified(QDateTime::currentMSecsSinceEpoch());
|
||||
req.fileStatus(FileStatus::Valid);
|
||||
|
||||
if (m_requestHelper->startSingleRequest([this, req]()
|
||||
{
|
||||
return m_ftc->presentationModifyRequest(req, this);
|
||||
}))
|
||||
{
|
||||
//slotSelectScript(m_requestHelper->getRepliedId());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void InterfaceImpl::slotAddScript()
|
||||
{
|
||||
PresentationEditDialog *dialog = new PresentationEditDialog(nullptr);
|
||||
if (!dialog->init(-1 /* new presentation */, m_dtc, m_ftc, m_opmDtc))
|
||||
{
|
||||
delete dialog;
|
||||
return;
|
||||
}
|
||||
|
||||
QObject::connect(dialog, &PresentationEditDialog::rejected, dialog, &PresentationEditDialog::deleteLater);
|
||||
|
||||
dialog->show();
|
||||
}
|
||||
|
||||
|
||||
void InterfaceImpl::executePayload(LtsWidgets::LtsBackgroundWidget *mainBackground)
|
||||
{
|
||||
Q_UNUSED(mainBackground);
|
||||
|
||||
if (m_session->partitionType() != IDL::PartitionType::Exercise) // only on valid exercise
|
||||
{
|
||||
emit signalSuccess();
|
||||
return;
|
||||
}
|
||||
|
||||
int scriptId = m_session->getSavegame()[QStringLiteral("ScriptId")].toInt();
|
||||
if (scriptId > 0)
|
||||
{
|
||||
slotSelectScript(scriptId);
|
||||
return;
|
||||
}
|
||||
|
||||
ScriptChooser *scriptChooser = new ScriptChooser(m_dtc, m_opmDtc, false, false, mainBackground);
|
||||
scriptChooser->setAttribute(Qt::WA_DeleteOnClose);
|
||||
|
||||
connect(scriptChooser, &ScriptChooser::signalSelectScript,
|
||||
this, &InterfaceImpl::slotSelectScript, Qt::QueuedConnection);
|
||||
|
||||
connect(scriptChooser, &ScriptChooser::signalQuit,
|
||||
m_session, &LtsSession::LtsSession::signalQuit);
|
||||
|
||||
connect(scriptChooser, &ScriptChooser::signalNewScript,
|
||||
this, &InterfaceImpl::slotAddScript);
|
||||
|
||||
if (!LtsSessionData::LtsSessionData::getInstance()->isTablet())
|
||||
scriptChooser->setModal(true);
|
||||
|
||||
scriptChooser->show();
|
||||
}
|
||||
|
||||
|
||||
void InterfaceImpl::slotSelectScript(int scriptId)
|
||||
{
|
||||
m_scriptId = scriptId;
|
||||
|
||||
// std::shared_ptr<ForeignGuiInterface> preGuiIfc;
|
||||
|
||||
// if (!m_session->getForeignGuiInterface<ForeignGuiInterface>(preGuiIfc))
|
||||
// {
|
||||
// // TODO: MSG !!1
|
||||
// return;
|
||||
// }
|
||||
|
||||
// preGuiIfc->setScriptId(scriptId);
|
||||
|
||||
emit signalSuccess();
|
||||
}
|
||||
|
||||
|
||||
void InterfaceImpl::slotImportScript(int scriptId)
|
||||
{
|
||||
if (m_scriptId == scriptId)
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Not possible to import same script!";
|
||||
LtsWidgets::LtsMessageDialog::showMessage(m_session->baseLayout(), tr("Not possible to import same script!"));
|
||||
return;
|
||||
}
|
||||
|
||||
if (!importScript(scriptId))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Failed to import script Id " << scriptId;
|
||||
LtsWidgets::LtsMessageDialog::showMessage(m_session->baseLayout(), tr("Failed to import Script Id %1").arg(scriptId));
|
||||
return;
|
||||
}
|
||||
|
||||
DEBUG_LOG(m_logger) << "Succesfully imported script Id " << scriptId ;
|
||||
|
||||
//LtsWidgets::LtsMessageDialog::showMessage(nullptr, tr("Successfully imported Script Id %1").arg(scriptId));
|
||||
}
|
||||
|
||||
|
||||
bool InterfaceImpl::importScript(int idSource)
|
||||
{
|
||||
if (!m_scriptDialog)
|
||||
{
|
||||
ERROR_LOG(m_logger) << "no script dialog open for import script";
|
||||
return false;
|
||||
}
|
||||
|
||||
PresentationManagement::Presentation preSource = m_dtc->presentation(idSource);
|
||||
|
||||
if (preSource.id() < 1)
|
||||
return false;
|
||||
|
||||
// import topics
|
||||
std::function<void(const Core::FunctionReply &baseReply)> importPresentationContent = [&](const Core::FunctionReply &baseReply)
|
||||
{
|
||||
const GetPresentationContentReply &reply = static_cast<const GetPresentationContentReply &>(baseReply);
|
||||
const auto &contentList = reply.content();
|
||||
|
||||
if (contentList.size() < 1)
|
||||
{
|
||||
ERROR_LOG(m_logger) << "No Presentation Content for Script Id " << reply.id();
|
||||
return;
|
||||
}
|
||||
|
||||
LtsScriptTimeline::TemporaryPointerVector<LtsScriptTimeline::TrackEntry *> importedTes;
|
||||
|
||||
for (const PresentationManagement::PresentationContent &content : contentList)
|
||||
{
|
||||
LtsScriptTimeline::TrackEntryType tet = LtsScriptTimeline::TrackEntryType::INVALID;
|
||||
|
||||
if (!m_scriptDialog->topicStringToType(QString::fromStdString(content.presentationTopicType()), tet))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Topic ignored - invalid topic type for presentation's content id " << content.id();
|
||||
continue;
|
||||
}
|
||||
|
||||
importedTes.append(ScriptDialog::trackEntryFromContent(content, 0, tet));
|
||||
}
|
||||
|
||||
if (m_scriptDialog->importTrackEntries(importedTes))
|
||||
importedTes.setDiscardable(false); // don't delete tes if they could be imported and finally be managed by the script timeline
|
||||
};
|
||||
|
||||
|
||||
GetPresentationContentRequest req(idSource);
|
||||
req.presentationId(idSource);
|
||||
|
||||
if (!m_requestHelper->startSingleRequest([req, this]()
|
||||
{
|
||||
return m_ftc->getPresentationContentRequest(req, this);
|
||||
}, importPresentationContent))
|
||||
{
|
||||
LtsWidgets::LtsMessageDialog::showMessage(m_session->baseLayout(), tr("There is no content to import for this script."));
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace PresentationManagement
|
||||
+100
@@ -0,0 +1,100 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* GUI Plugin for Script Editor
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*
|
||||
* Created by Mike Wille, SLSE, 2017-03-17
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <PresentationManagement/logger.h>
|
||||
#include <PluginInterfaces/gui_plugin_interface.h>
|
||||
#include <Plugins/PresentationManagement/pre_data_plugin_interface.h>
|
||||
#include <Plugins/PresentationManagement/pre_script_gui_plugin_interface.h>
|
||||
#include <Services/PresentationManagement/pre_ftc.h> // reply handler
|
||||
#include <Services/OperatorManagement/opm_dtc.h>
|
||||
#include <Plugins/SituationReplayManagement/srm_data_plugin_interface.h>
|
||||
#include <Common/ProjectConfig/project_defines.h>
|
||||
#include <LtsUtilsGuiDds/request_helper.h>
|
||||
|
||||
// test:
|
||||
#include <LtsScriptTimeline/track_entry_painters.h>
|
||||
#include "pre_script_dialog.h"
|
||||
#include <LtsSession/lts_session.h>
|
||||
#include <PluginInterfaces/gui_plugin_interface.h>
|
||||
#include <PluginInterfaces/topic_replay_interface.h>
|
||||
#include <Plugins/PresentationManagement/Gui/Common/topic_assignment.h>
|
||||
|
||||
|
||||
namespace PresentationManagement
|
||||
{
|
||||
class GuiPlugin final : public QObject, public GuiPluginBase::Plugin
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PLUGIN_METADATA(IID "gui:3:pre.script.edit")
|
||||
Q_INTERFACES(GuiPluginBase::Plugin)
|
||||
|
||||
public:
|
||||
explicit GuiPlugin() = default;
|
||||
~GuiPlugin() = default;
|
||||
|
||||
QString pluginName() override { return ForeignScriptDialogGuiInterface::pluginName(); }
|
||||
std::shared_ptr<GuiPluginBase::Interface> createGuiInterface(LtsSession::LtsSession *session) override;
|
||||
bool availableInPartition(IDL::PartitionType partition) const override
|
||||
{ return (partition == IDL::PartitionType::Exercise); }
|
||||
};
|
||||
|
||||
|
||||
class InterfaceImpl final : public QObject, public GuiPluginBase::Interface
|
||||
, protected PresentationManagement::Interface::Ftc::PresentationModifyReplyHandler
|
||||
, protected PresentationManagement::Interface::Ftc::GetPresentationContentReplyHandler
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit InterfaceImpl(LtsSession::LtsSession *session);
|
||||
|
||||
QVector<LtsWidgets::PluginData> getActions() override;
|
||||
QString menuGroup() const override;
|
||||
bool fetchInterfaces() override;
|
||||
void clearInterfaces() override;
|
||||
bool availableInPartition(IDL::PartitionType partition) const override
|
||||
{ return partition == IDL::PartitionType::Exercise; }
|
||||
|
||||
// be able to show script chooser
|
||||
int executionPriority() const override { return 9999; }
|
||||
void executePayload(LtsWidgets::LtsBackgroundWidget *mainBackground) override;
|
||||
|
||||
protected:
|
||||
void onPresentationModifyReply(const Core::FunctionReplyObject &replyObject) override final { m_requestHelper->requestReply(replyObject); }
|
||||
void onGetPresentationContentReply(const GetPresentationContentReply &reply) override { m_requestHelper->requestReply(reply); }
|
||||
|
||||
private:
|
||||
LtsWidgets::LtsDialog *onShowScriptDialog(QWidget *parent);
|
||||
void onImportScript();
|
||||
bool importScript(/*int idDest, */int idSource);
|
||||
|
||||
std::shared_ptr<PresentationManagement::Interface::Dtc> m_dtc;
|
||||
std::shared_ptr<OperatorManagement::Interface::Dtc> m_opmDtc;
|
||||
std::shared_ptr<PresentationManagement::Interface::Ftc> m_ftc;
|
||||
std::shared_ptr<SituationReplayManagement::ForeignDataInterface> m_repForeign;
|
||||
std::shared_ptr<Core::Interface::Dtc> m_coreDtc;
|
||||
|
||||
QPointer<PresentationManagement::ScriptDialog> m_scriptDialog;
|
||||
int m_scriptId;
|
||||
LtsUtils::RequestHelper *m_requestHelper;
|
||||
|
||||
signals:
|
||||
void signalSuccess();
|
||||
|
||||
private slots:
|
||||
void slotSelectScript(int scriptId);
|
||||
void slotNewScript();
|
||||
void slotImportScript(int scriptId);
|
||||
void slotAddScript();
|
||||
};
|
||||
|
||||
} // namespace PresentationManagement
|
||||
+152
@@ -0,0 +1,152 @@
|
||||
#include "pre_storyboard.h"
|
||||
#include "ui_pre_storyboard.h"
|
||||
|
||||
#include <LtsPrinting/printing.h>
|
||||
#include <LtsScriptTimeline/track_entry.h>
|
||||
#include <ngltools/ngltools_dtg.h>
|
||||
|
||||
using namespace LtsScriptTimeline;
|
||||
|
||||
|
||||
namespace PresentationManagement
|
||||
{
|
||||
|
||||
StoryboardDialog::StoryboardDialog(QWidget *parent, LtsSession::LtsSession *session)
|
||||
: LtsWidgets::LtsDialog(parent)
|
||||
, m_ui(new Ui::StoryboardDialog)
|
||||
, m_session(session)
|
||||
, m_alreadyTranslated(false)
|
||||
{
|
||||
m_ui->setupUi(this);
|
||||
m_buttonBox->connectButton(LtsWidgets::DialogButton::Print, this, &StoryboardDialog::slotPrint);
|
||||
}
|
||||
|
||||
|
||||
StoryboardDialog::~StoryboardDialog()
|
||||
{
|
||||
delete m_ui;
|
||||
}
|
||||
|
||||
|
||||
void StoryboardDialog::slotPrint()
|
||||
{
|
||||
QString headingHtml = (QStringLiteral("<H1>"));
|
||||
headingHtml.append (tr("Scriptname:"));
|
||||
headingHtml.append(m_scriptName);
|
||||
headingHtml.append(QStringLiteral("</H1>"));
|
||||
headingHtml.append(QStringLiteral("<H3>"));
|
||||
headingHtml.append(tr("Script Owner: "));
|
||||
headingHtml.append(m_scriptOwner);
|
||||
headingHtml.append(QStringLiteral("</H3>"));
|
||||
headingHtml.append(QStringLiteral("<H3>"));
|
||||
headingHtml.append(tr("Last modified: "));
|
||||
headingHtml.append(DTG::toStringMSec(m_lastModified));
|
||||
headingHtml.append(QStringLiteral("<br>"));
|
||||
headingHtml.append(tr("Duration: "));
|
||||
QString durationStr = m_duration;
|
||||
headingHtml.append(durationStr);
|
||||
headingHtml.append(QStringLiteral("</H3><br>"));
|
||||
|
||||
LtsPrinting::printView(m_session, this, m_ui->listWidget, headingHtml);
|
||||
}
|
||||
|
||||
|
||||
bool StoryboardDialog::init(const QVector<LtsScriptTimeline::TrackEntry *> &topicVector,
|
||||
const QVector<FilterTopic> &filterTopicVector,
|
||||
const QString &scriptName,
|
||||
const QString &scriptOwner,
|
||||
const qint64 lastModified,
|
||||
const QString duration)
|
||||
{
|
||||
m_topicVector = topicVector; // cpy
|
||||
m_filterTopicVector = filterTopicVector; // cpy
|
||||
m_scriptName = scriptName; // cpy
|
||||
m_scriptOwner = scriptOwner;
|
||||
m_lastModified = lastModified;
|
||||
m_duration = duration;
|
||||
|
||||
// sort storyboard by time
|
||||
std::sort(m_topicVector.begin(), m_topicVector.end(), [](const TrackEntry *a, const TrackEntry *b) -> bool
|
||||
{
|
||||
return a->m_startTime < b->m_startTime;
|
||||
});
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void StoryboardDialog::retranslate()
|
||||
{
|
||||
translate(m_ui, tr("Script Storyboard"));
|
||||
|
||||
if (m_alreadyTranslated)
|
||||
return;
|
||||
|
||||
fillStoryboard();
|
||||
m_alreadyTranslated = true;
|
||||
}
|
||||
|
||||
|
||||
void StoryboardDialog::fillStoryboard()
|
||||
{
|
||||
m_ui->listWidget->clear();
|
||||
|
||||
QVector<FilterTopic> correspondingFilterTopics;
|
||||
int ii1 = 1;
|
||||
for (const LtsScriptTimeline::TrackEntry *te : qAsConst(m_topicVector))
|
||||
{
|
||||
QString itemText = tr("Topic %1: %2 - %3 (%4 seconds)\n Type: %5").arg(
|
||||
ii1).arg(QTime::fromMSecsSinceStartOfDay(te->m_startTime * 1000).toString(),
|
||||
QTime::fromMSecsSinceStartOfDay((te->m_startTime + te->m_length) * 1000).toString()).arg(
|
||||
te->m_length).arg(LtsScriptTimeline::translateTrackEntryType(te->m_type));
|
||||
|
||||
if (!te->m_description.isEmpty())
|
||||
itemText += QStringLiteral("\n ") + tr("Description: %1").arg(te->m_description);
|
||||
|
||||
m_ui->listWidget->addItem(itemText);
|
||||
|
||||
|
||||
// look for filters for this topic:
|
||||
correspondingFilterTopics.clear();
|
||||
for (const FilterTopic &_ft : qAsConst(m_filterTopicVector))
|
||||
{
|
||||
if (_ft.mainTopicId != te->m_topicId)
|
||||
continue;
|
||||
|
||||
correspondingFilterTopics.append(_ft);
|
||||
}
|
||||
|
||||
|
||||
// sort filter topics by start time
|
||||
std::sort(correspondingFilterTopics.begin(), correspondingFilterTopics.end(), [](const FilterTopic &a, const FilterTopic &b) -> bool
|
||||
{
|
||||
return a.filterTopic->m_startTime < b.filterTopic->m_startTime;
|
||||
});
|
||||
|
||||
|
||||
int ii2 = 1;
|
||||
for (const FilterTopic &_ft : qAsConst(correspondingFilterTopics))
|
||||
{
|
||||
if (_ft.mainTopicId != te->m_topicId)
|
||||
continue;
|
||||
|
||||
const LtsScriptTimeline::TrackEntry *fte = _ft.filterTopic;
|
||||
|
||||
QString filterItemText = tr(" > Filter %1: %2 - %3 (%4 seconds)\n Type: %5").arg(
|
||||
ii2).arg(QTime::fromMSecsSinceStartOfDay(fte->m_startTime * 1000).toString(),
|
||||
QTime::fromMSecsSinceStartOfDay((fte->m_startTime + te->m_length) * 1000).toString()).arg(
|
||||
fte->m_length).arg(LtsScriptTimeline::translateTrackEntryType(te->m_type));
|
||||
|
||||
if (!fte->m_description.isEmpty())
|
||||
filterItemText += QStringLiteral("\n ") + tr("Description: %1").arg(fte->m_description);
|
||||
|
||||
m_ui->listWidget->addItem(filterItemText);
|
||||
|
||||
ii2++;
|
||||
}
|
||||
|
||||
ii1++;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace PresentationManagement
|
||||
+50
@@ -0,0 +1,50 @@
|
||||
#pragma once
|
||||
|
||||
#include "filter_topic.h"
|
||||
|
||||
#include <LtsWidgets/lts_dialog.h>
|
||||
#include <LtsScriptTimeline/track_entry.h>
|
||||
#include <LtsSession/lts_session.h>
|
||||
|
||||
#include <QVector>
|
||||
|
||||
|
||||
namespace Ui
|
||||
{
|
||||
class StoryboardDialog;
|
||||
}
|
||||
|
||||
namespace PresentationManagement
|
||||
{
|
||||
|
||||
class StoryboardDialog : public LtsWidgets::LtsDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
StoryboardDialog(QWidget *parent, LtsSession::LtsSession *session);
|
||||
~StoryboardDialog();
|
||||
bool init(const QVector<LtsScriptTimeline::TrackEntry *> &topicVector,
|
||||
const QVector<FilterTopic> &filterTopicVector,
|
||||
const QString &scriptName,
|
||||
const QString &scriptOwner,
|
||||
const qint64 lastModified,
|
||||
const QString duration);
|
||||
void fillStoryboard();
|
||||
void retranslate() override final;
|
||||
|
||||
private:
|
||||
Ui::StoryboardDialog *m_ui;
|
||||
QVector<LtsScriptTimeline::TrackEntry *> m_topicVector;
|
||||
QVector<FilterTopic> m_filterTopicVector;
|
||||
LtsSession::LtsSession *m_session;
|
||||
QString m_scriptName = QString();
|
||||
QString m_scriptOwner = QString();
|
||||
qint64 m_lastModified = 0;
|
||||
QString m_duration = QString();
|
||||
bool m_alreadyTranslated;
|
||||
|
||||
public slots:
|
||||
void slotPrint();
|
||||
};
|
||||
|
||||
} // namespace PresentationManagement
|
||||
+49
@@ -0,0 +1,49 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>StoryboardDialog</class>
|
||||
<widget class="QWidget" name="StoryboardDialog">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>707</width>
|
||||
<height>464</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="MinimumExpanding" vsizetype="MinimumExpanding">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string notr="true">Script Editor</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<property name="spacing">
|
||||
<number>9</number>
|
||||
</property>
|
||||
<property name="leftMargin">
|
||||
<number>9</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>9</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>9</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>9</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QListWidget" name="listWidget">
|
||||
<property name="alternatingRowColors">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
+69
@@ -0,0 +1,69 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* Dialog for the Topic Designer
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*
|
||||
* Created by Mike Wille, SLSE, 2017-06-09
|
||||
*/
|
||||
|
||||
#include "pre_topic_designer_dialog.h"
|
||||
#include "ui_pre_topic_designer_dialog.h"
|
||||
|
||||
|
||||
namespace PresentationManagement
|
||||
{
|
||||
|
||||
TopicDesignerDialog::TopicDesignerDialog(QWidget *parent)
|
||||
: LtsDialog(parent)
|
||||
, m_ui(new Ui::TopicDesignerDialog)
|
||||
{
|
||||
m_ui->setupUi(this);
|
||||
setFocusPolicy(Qt::StrongFocus);
|
||||
|
||||
connect(m_ui->widget, &TopicDesigner::signalTopicSelected,
|
||||
this, &TopicDesignerDialog::signalTopicSelected);
|
||||
connect(m_ui->widget, &TopicDesigner::signalDeleteTrackEntry,
|
||||
this, &TopicDesignerDialog::signalDeleteTrackEntry);
|
||||
connect(m_ui->widget, &TopicDesigner::signalUnselect,
|
||||
this, &TopicDesignerDialog::signalUnselect);
|
||||
connect(m_ui->widget, &TopicDesigner::signalChangesMade,
|
||||
this, &LtsWidgets::LtsDialog::signalChangesMade);
|
||||
|
||||
// connect(m_ui->pbToFront, &QPushButton::clicked,
|
||||
// m_ui->widget, &TopicDesigner::to)
|
||||
}
|
||||
|
||||
|
||||
void TopicDesignerDialog::retranslate()
|
||||
{
|
||||
translate(m_ui, tr("Topic Designer"));
|
||||
}
|
||||
|
||||
|
||||
TopicDesignerDialog::~TopicDesignerDialog()
|
||||
{
|
||||
delete m_ui;
|
||||
}
|
||||
|
||||
|
||||
QVector<LtsScriptTimeline::TrackEntry *> TopicDesignerDialog::exportTopicList() const
|
||||
{
|
||||
return m_ui->widget->exportTopicList();
|
||||
}
|
||||
|
||||
|
||||
void TopicDesignerDialog::selectTopic(int topicId)
|
||||
{
|
||||
m_ui->widget->selectTopic(topicId);
|
||||
}
|
||||
|
||||
|
||||
void TopicDesignerDialog::loadTopicList(const QVector<LtsScriptTimeline::TrackEntry *> &topicsList)
|
||||
{
|
||||
m_ui->widget->loadTopicList(topicsList);
|
||||
}
|
||||
|
||||
} // namespace PresentationManagement
|
||||
|
||||
+57
@@ -0,0 +1,57 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* Dialog for the Topic Designer
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*
|
||||
* Created by Mike Wille, SLSE, 2017-06-09
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <LtsWidgets/lts_dialog.h>
|
||||
|
||||
#include <QVector>
|
||||
|
||||
|
||||
namespace Ui
|
||||
{
|
||||
class TopicDesignerDialog;
|
||||
}
|
||||
|
||||
namespace LtsScriptTimeline
|
||||
{
|
||||
class TrackEntry;
|
||||
}
|
||||
|
||||
|
||||
namespace PresentationManagement
|
||||
{
|
||||
|
||||
class TopicDesignerDialog : public LtsWidgets::LtsDialog
|
||||
{
|
||||
public:
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit TopicDesignerDialog(QWidget *parent = nullptr);
|
||||
~TopicDesignerDialog();
|
||||
|
||||
void loadTopicList(const QVector<LtsScriptTimeline::TrackEntry *> &topicsList);
|
||||
QVector<LtsScriptTimeline::TrackEntry *> exportTopicList() const;
|
||||
void selectTopic(int topicId);
|
||||
|
||||
signals:
|
||||
void signalTopicSelected(int topicId);
|
||||
void signalDeleteTrackEntry(int topicId);
|
||||
void signalUnselect();
|
||||
|
||||
private:
|
||||
void retranslate() override;
|
||||
|
||||
Ui::TopicDesignerDialog *m_ui;
|
||||
|
||||
};
|
||||
|
||||
} // namespace PresentationManagement
|
||||
+122
@@ -0,0 +1,122 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>TopicDesignerDialog</class>
|
||||
<widget class="QWidget" name="TopicDesignerDialog">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>600</width>
|
||||
<height>338</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="MinimumExpanding" vsizetype="MinimumExpanding">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string notr="true">Script Editor</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<property name="spacing">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="leftMargin">
|
||||
<number>9</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>9</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>9</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>9</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string notr="true">Some text</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||
<item>
|
||||
<widget class="QPushButton" name="pbToFront">
|
||||
<property name="text">
|
||||
<string>To Front</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="pbIncIdx">
|
||||
<property name="text">
|
||||
<string>Inc Idx</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="pbDecIdx">
|
||||
<property name="text">
|
||||
<string>Dec Idx</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="pbToBack">
|
||||
<property name="text">
|
||||
<string>To Back</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>40</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="PresentationManagement::TopicDesigner" name="widget" native="true">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="MinimumExpanding" vsizetype="MinimumExpanding">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>300</height>
|
||||
</size>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
<class>PresentationManagement::TopicDesigner</class>
|
||||
<extends>QWidget</extends>
|
||||
<header>topic_designer.h</header>
|
||||
<container>1</container>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
+107
@@ -0,0 +1,107 @@
|
||||
#
|
||||
# $Id$
|
||||
# $HeadURL$
|
||||
# $Author$
|
||||
#
|
||||
# Created by Mike Wille, SLSE, 2016-03-17
|
||||
#
|
||||
|
||||
add_library(ExportBdvTopicSetting INTERFACE)
|
||||
target_compile_definitions(ExportBdvTopicSetting INTERFACE EXPORT_BDV_TOPIC_AS_JSON)
|
||||
|
||||
SET(pre_script_gui_SRCS
|
||||
pre_journal_dialog.h
|
||||
pre_journal_dialog.cpp
|
||||
pre_journal_types.h
|
||||
pre_journal_types.cpp
|
||||
pre_screen.h
|
||||
pre_screen.cpp
|
||||
pre_screen_recorder.h
|
||||
pre_screen_recorder.cpp
|
||||
pre_screen_shotter.h
|
||||
pre_screen_shotter.cpp
|
||||
pre_script_timeline_gui_plugin.cpp
|
||||
pre_script_timeline_gui_plugin.h
|
||||
pre_script_delegate.cpp
|
||||
pre_script_delegate.h
|
||||
pre_script_dialog.h
|
||||
pre_script_dialog.cpp
|
||||
pre_script_dialog_drag_handler.cpp
|
||||
pre_script_dialog_drag_handler.h
|
||||
pre_script_dialog_resize_handler.cpp
|
||||
pre_script_dialog_resize_handler.h
|
||||
pre_script_dialog_select_handler.cpp
|
||||
pre_script_dialog_select_handler.h
|
||||
pre_script_model.cpp
|
||||
pre_script_model.h
|
||||
pre_topic_recorder.cpp
|
||||
pre_topic_recorder.h
|
||||
pre_topic_shotter.cpp
|
||||
pre_topic_shotter.h
|
||||
pre_storyboard.cpp
|
||||
pre_storyboard.h
|
||||
pre_topic_item.cpp
|
||||
pre_topic_item.h
|
||||
pre_topic_track.cpp
|
||||
pre_topic_track.h
|
||||
pre_utils.cpp
|
||||
pre_utils.h
|
||||
)
|
||||
|
||||
QT5_WRAP_UI(pre_script_gui_SRCS
|
||||
pre_storyboard.ui
|
||||
pre_script_dialog.ui
|
||||
pre_journal_dialog.ui
|
||||
)
|
||||
|
||||
NGL_ADD_LIBRARY(WS PreScriptTimelineGuiPlugin MODULE ${pre_script_gui_SRCS})
|
||||
NGL_TARGET_COMPILE_DEFINITIONS(PreScriptTimelineGuiPlugin PRIVATE L=QStringLiteral)
|
||||
NGL_TARGET_LINK_LIBRARIES(PreScriptTimelineGuiPlugin
|
||||
NGLLogger
|
||||
LtsSession
|
||||
PreDataPluginInterface
|
||||
PreScriptTimelineGuiPluginInterface
|
||||
PreGuiCommon
|
||||
PreGuiScriptCommon
|
||||
LtsTimeline
|
||||
svcPreCommon
|
||||
Qt5::Widgets
|
||||
LtsWidgets
|
||||
LtsDataView
|
||||
LtsSessionData
|
||||
ProjectConfig
|
||||
LtsScriptTimeline
|
||||
LtsUtilsCoreHeaderOnly
|
||||
LtsMultiMonitor
|
||||
Thp2Common
|
||||
|
||||
LtsAppManager # start replay app
|
||||
LtsSessionData # set partition preset for replay app
|
||||
TopicEditorInterface
|
||||
TopicEditorBase
|
||||
LtsPluginManager # manipulate apps
|
||||
|
||||
# for Topics
|
||||
EvlGuiPluginInterface
|
||||
SrmDataPluginInterface # start playback
|
||||
LtsPrinting
|
||||
SituationMapGuiPluginInterface
|
||||
|
||||
# Script Player Controls:
|
||||
SrpGuiPluginInterface
|
||||
|
||||
# file topic
|
||||
FlmExplorerGuiPluginInterface
|
||||
# building topic
|
||||
BdvViewerGuiPluginInterface
|
||||
# report topic
|
||||
RepGuiPluginInterface
|
||||
LtsReportDisplay
|
||||
MrkCommon # for ApplyFilter @ SitmapFilter
|
||||
LtsUtilsSettings
|
||||
ngltools # DTG
|
||||
situationMap # set time string on map
|
||||
ExportBdvTopicSetting
|
||||
)
|
||||
|
||||
NGL_INSTALL_TARGET(PreScriptTimelineGuiPlugin)
|
||||
Executable
+73
@@ -0,0 +1,73 @@
|
||||
#include "pre_journal_dialog.h"
|
||||
#include "ui_pre_journal_dialog.h"
|
||||
|
||||
#include <LtsPrinting/printing.h>
|
||||
#include <Services/PresentationManagement/logger.h>
|
||||
|
||||
|
||||
namespace PresentationManagement
|
||||
{
|
||||
|
||||
JournalDialog::JournalDialog(LtsSession::LtsSession *session, QWidget *parent)
|
||||
: LtsWidgets::LtsDialog(parent)
|
||||
, m_session(session)
|
||||
, m_ui(new Ui::JournalDialog)
|
||||
, m_logger(getLogger(QStringLiteral("JournalDialog")))
|
||||
{
|
||||
m_ui->setupUi(this);
|
||||
m_buttonBox->connectButton(LtsWidgets::DialogButton::Print, this, &JournalDialog::onPrint);
|
||||
setOnlineHelpFilename(QStringLiteral("Script_Editor-Journal"));
|
||||
}
|
||||
|
||||
|
||||
JournalDialog::~JournalDialog()
|
||||
{
|
||||
delete m_ui;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// PUBLIC
|
||||
|
||||
/**
|
||||
* @brief
|
||||
*
|
||||
* @param journal
|
||||
* @return bool
|
||||
*/
|
||||
bool JournalDialog::init(MainJournal *journal)
|
||||
{
|
||||
m_journal = journal;
|
||||
return true;
|
||||
}
|
||||
|
||||
void JournalDialog::retranslate()
|
||||
{
|
||||
translate(m_ui, tr("Script Journal"));
|
||||
fillJournal();
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// PRIVATE
|
||||
|
||||
void JournalDialog::fillJournal()
|
||||
{
|
||||
m_ui->listWidget->clear();
|
||||
|
||||
if (!m_journal)
|
||||
return;
|
||||
|
||||
m_ui->listWidget->addItem(m_journal->getText());
|
||||
for (const Journal *j : qAsConst(m_journal->journalList))
|
||||
m_ui->listWidget->addItem(j->getText());
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// PRIVATE SLOTS
|
||||
|
||||
void JournalDialog::onPrint()
|
||||
{
|
||||
LtsPrinting::printView(m_session, this, m_ui->listWidget);
|
||||
}
|
||||
|
||||
} // namespace PresentationManagement
|
||||
+44
@@ -0,0 +1,44 @@
|
||||
#pragma once
|
||||
|
||||
#include "pre_journal_types.h"
|
||||
|
||||
#include <LtsWidgets/lts_dialog.h>
|
||||
#include <LtsSession/lts_session.h>
|
||||
|
||||
|
||||
namespace Ui
|
||||
{
|
||||
class JournalDialog;
|
||||
}
|
||||
|
||||
|
||||
namespace PresentationManagement
|
||||
{
|
||||
|
||||
class JournalDialog : public LtsWidgets::LtsDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit JournalDialog(LtsSession::LtsSession *session, QWidget *parent);
|
||||
~JournalDialog();
|
||||
|
||||
bool init(MainJournal *journal);
|
||||
|
||||
void retranslate() override final;
|
||||
|
||||
private:
|
||||
void fillJournal();
|
||||
|
||||
private slots:
|
||||
void onPrint();
|
||||
|
||||
private:
|
||||
LtsSession::LtsSession *m_session { nullptr };
|
||||
MainJournal *m_journal { nullptr };
|
||||
|
||||
Ui::JournalDialog *m_ui { nullptr };
|
||||
NGL::INGLLogger &m_logger;
|
||||
|
||||
};
|
||||
|
||||
} // namespace PresentationManagement
|
||||
+49
@@ -0,0 +1,49 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>JournalDialog</class>
|
||||
<widget class="QWidget" name="JournalDialog">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>707</width>
|
||||
<height>464</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="MinimumExpanding" vsizetype="MinimumExpanding">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string notr="true">Script Editor</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<property name="spacing">
|
||||
<number>9</number>
|
||||
</property>
|
||||
<property name="leftMargin">
|
||||
<number>9</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>9</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>9</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>9</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QListWidget" name="listWidget">
|
||||
<property name="alternatingRowColors">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
+105
@@ -0,0 +1,105 @@
|
||||
#include "pre_journal_types.h"
|
||||
|
||||
#include <QDateTime>
|
||||
#include <ngltools/ngltools_dtg.h>
|
||||
#include <Common/LtsTimeline/timeline_utils.h>
|
||||
|
||||
namespace PresentationManagement
|
||||
{
|
||||
|
||||
QString timeSinceEpochInDTG(qint64 msecsSinceEpoch)
|
||||
{
|
||||
return LtsTimeline::DateTime::toString(msecsSinceEpoch,LtsTimeline::DateTime::DTG);
|
||||
}
|
||||
|
||||
|
||||
//QString presentationTimeToTime(int presentationTime)
|
||||
//{
|
||||
// return QTime::fromMSecsSinceStartOfDay(presentationTime * 1000).toString();
|
||||
//}
|
||||
|
||||
QString msecsToString(int presentationTime)
|
||||
{
|
||||
int milliseconds = presentationTime;
|
||||
int seconds = milliseconds / 1000;
|
||||
milliseconds = milliseconds % 1000;
|
||||
int minutes = seconds / 60;
|
||||
seconds = seconds % 60;
|
||||
int hours = minutes / 60;
|
||||
minutes = minutes % 60;
|
||||
|
||||
QTime time;
|
||||
time.setHMS(hours, minutes, seconds, milliseconds);
|
||||
|
||||
return time.toString(QStringLiteral("hh:mm:ss"));
|
||||
}
|
||||
|
||||
Journal::Journal()
|
||||
: m_started(QDateTime::currentMSecsSinceEpoch())
|
||||
{}
|
||||
|
||||
|
||||
QString Journal::started() const
|
||||
{
|
||||
return timeSinceEpochInDTG(m_started);
|
||||
}
|
||||
|
||||
|
||||
MainJournal::~MainJournal()
|
||||
{
|
||||
qDeleteAll(journalList);
|
||||
}
|
||||
|
||||
|
||||
QString MainJournal::getText() const
|
||||
{
|
||||
return Journal::tr("Script Player started on %1").arg(timeSinceEpochInDTG(started));
|
||||
}
|
||||
|
||||
|
||||
NextTopicJournal::NextTopicJournal(int presentationTime, bool isFilter, const QString &topicTypeName, int length)
|
||||
: Journal()
|
||||
, m_isFilter(isFilter)
|
||||
, m_topicTypeName(topicTypeName)
|
||||
, m_length(length)
|
||||
, m_presentationTime(presentationTime)
|
||||
{}
|
||||
|
||||
|
||||
QString NextTopicJournal::getText() const
|
||||
{
|
||||
return Journal::tr("%1 '%2' started at %3 for %4 seconds on %5").arg(m_isFilter ? tr("FilterTopic") : tr("Topic"),
|
||||
m_topicTypeName, msecsToString(m_presentationTime)).arg(m_length).arg(started());
|
||||
}
|
||||
|
||||
|
||||
QString PlayJournal::getText() const
|
||||
{
|
||||
return Journal::tr("Started / resumed script at %1 on %2").arg(msecsToString(m_presentationTime), started());
|
||||
}
|
||||
|
||||
|
||||
QString PauseJournal::getText() const
|
||||
{
|
||||
return Journal::tr("Paused script at %1 on %2").arg(msecsToString(m_presentationTime), started());
|
||||
}
|
||||
|
||||
|
||||
QString EndedJournal::getText() const
|
||||
{
|
||||
return Journal::tr("Script ended at %1 on %2").arg(msecsToString(m_presentationTime), started());
|
||||
}
|
||||
|
||||
|
||||
QString StopJournal::getText() const
|
||||
{
|
||||
return Journal::tr("Script stopped at %1 on %2").arg(msecsToString(m_presentationTime), started());
|
||||
}
|
||||
|
||||
|
||||
QString SetTimeJournal::getText() const
|
||||
{
|
||||
return Journal::tr("Position time set to %1 on %2").arg(msecsToString(m_toPresentationTime), started());
|
||||
}
|
||||
|
||||
} // namespace PresentationManagement
|
||||
+117
@@ -0,0 +1,117 @@
|
||||
#pragma once
|
||||
|
||||
#include <QCoreApplication>
|
||||
#include <QVector>
|
||||
|
||||
|
||||
namespace PresentationManagement
|
||||
{
|
||||
|
||||
class Journal
|
||||
{
|
||||
Q_DECLARE_TR_FUNCTIONS(Journal)
|
||||
|
||||
public:
|
||||
Journal();
|
||||
virtual ~Journal() = default;
|
||||
QString started() const;
|
||||
virtual QString getText() const = 0;
|
||||
qint64 m_started;
|
||||
};
|
||||
|
||||
|
||||
class MainJournal
|
||||
{
|
||||
public:
|
||||
~MainJournal();
|
||||
QString getText() const;
|
||||
|
||||
qint64 started = 0;
|
||||
QVector<Journal *> journalList;
|
||||
};
|
||||
|
||||
|
||||
class NextTopicJournal : public Journal
|
||||
{
|
||||
public:
|
||||
NextTopicJournal(int presentationTime, bool isFilter, /*int topicId, */const QString &topicTypeName, int length);
|
||||
QString getText() const override final;
|
||||
|
||||
bool m_isFilter;
|
||||
//int m_topicId;
|
||||
QString m_topicTypeName;
|
||||
int m_length;
|
||||
int m_presentationTime;
|
||||
};
|
||||
|
||||
|
||||
class PlayJournal : public Journal
|
||||
{
|
||||
public:
|
||||
explicit PlayJournal(int presentationTime)
|
||||
: Journal()
|
||||
, m_presentationTime(presentationTime)
|
||||
{}
|
||||
|
||||
QString getText() const override final;
|
||||
|
||||
int m_presentationTime;
|
||||
};
|
||||
|
||||
|
||||
class PauseJournal : public Journal
|
||||
{
|
||||
public:
|
||||
explicit PauseJournal(int presentationTime)
|
||||
: Journal()
|
||||
, m_presentationTime(presentationTime)
|
||||
{}
|
||||
|
||||
QString getText() const override final;
|
||||
|
||||
int m_presentationTime;
|
||||
};
|
||||
|
||||
|
||||
class EndedJournal : public Journal
|
||||
{
|
||||
public:
|
||||
explicit EndedJournal(int presentationTime)
|
||||
: Journal()
|
||||
, m_presentationTime(presentationTime)
|
||||
{}
|
||||
|
||||
QString getText() const override final;
|
||||
|
||||
int m_presentationTime;
|
||||
};
|
||||
|
||||
|
||||
class StopJournal : public Journal
|
||||
{
|
||||
public:
|
||||
explicit StopJournal(int presentationTime)
|
||||
: Journal()
|
||||
, m_presentationTime(presentationTime)
|
||||
{}
|
||||
|
||||
QString getText() const override final;
|
||||
|
||||
int m_presentationTime;
|
||||
};
|
||||
|
||||
|
||||
class SetTimeJournal : public Journal
|
||||
{
|
||||
public:
|
||||
explicit SetTimeJournal(int toPresentationTime)
|
||||
: Journal()
|
||||
, m_toPresentationTime(toPresentationTime)
|
||||
{}
|
||||
|
||||
QString getText() const override final;
|
||||
|
||||
int m_toPresentationTime;
|
||||
};
|
||||
|
||||
} // namespace PresentationManagement
|
||||
+39
@@ -0,0 +1,39 @@
|
||||
#include "pre_screen.h"
|
||||
|
||||
#include <LtsUtilsGui/LtsUtilsGuiDds/dds_vector_to_pixmap.h>
|
||||
|
||||
#include <QPainter>
|
||||
#include <QStyleOption>
|
||||
|
||||
|
||||
Screen::Screen()
|
||||
{
|
||||
setBgColor(QColor("black"));
|
||||
setContentsMargins(0, 0, 0, 0);
|
||||
|
||||
setWindowIcon(LtsUtils::iconFromSvg(QStringLiteral(":/style/execute_presentation.svg")));
|
||||
setWindowTitle(tr("Presentation Screen"));
|
||||
}
|
||||
|
||||
|
||||
Screen::~Screen()
|
||||
{
|
||||
const auto p1Widgets = findChildren<QWidget *>(QString(), Qt::FindDirectChildrenOnly);
|
||||
for (QWidget *w : p1Widgets)
|
||||
w->setParent(nullptr);
|
||||
}
|
||||
|
||||
|
||||
void Screen::setBgColor(const QColor &color)
|
||||
{
|
||||
setStyleSheet(QStringLiteral("Screen { background: %1; background-color: %1; }").arg(color.name()));
|
||||
}
|
||||
|
||||
|
||||
void Screen::paintEvent(QPaintEvent *) // needed to apply the style sheet...........
|
||||
{
|
||||
QStyleOption opt;
|
||||
opt.init(this);
|
||||
QPainter p(this);
|
||||
style()->drawPrimitive(QStyle::PE_Widget, &opt, &p, this);
|
||||
}
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
#pragma once
|
||||
|
||||
#include <LtsMultiMonitor/lts_dummy_widget.h>
|
||||
|
||||
|
||||
class Screen : public LtsMultiMonitor::SecondaryWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
Screen();
|
||||
virtual ~Screen();
|
||||
|
||||
void setBgColor(const QColor &color);
|
||||
|
||||
private:
|
||||
void paintEvent(QPaintEvent *) override;
|
||||
};
|
||||
Executable
+146
@@ -0,0 +1,146 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* class for recording topics on a screen
|
||||
* $Id:
|
||||
* $HeadURL:
|
||||
* $Author:
|
||||
* Created by Hannes Fritsche, SLTE, 2023-01-18
|
||||
*/
|
||||
|
||||
#include "pre_screen_recorder.h"
|
||||
#include "pre_screen.h"
|
||||
#include "pre_topic_item.h"
|
||||
#include <QProcess>
|
||||
#include <QJsonDocument>
|
||||
#include <QJsonArray>
|
||||
#include <QJsonObject>
|
||||
|
||||
namespace PresentationManagement
|
||||
{
|
||||
|
||||
ScreenRecorder::ScreenRecorder(QObject *parent)
|
||||
: QObject(parent)
|
||||
, m_logger(getLogger(QStringLiteral("ScreenRecorder")))
|
||||
{
|
||||
connect(this, &ScreenRecorder::newTime, this, [this](qint64 _t1){ DEBUG_LOG(m_logger) << "newTime: " << _t1; });
|
||||
}
|
||||
|
||||
|
||||
void ScreenRecorder::cut()
|
||||
{
|
||||
for (TopicRecorder *tr : qAsConst(m_topicRecorder))
|
||||
{
|
||||
if (tr->isFailed()) // skip, plus already in m_failedExportTopicIds by exportFailed signal
|
||||
continue;
|
||||
|
||||
try
|
||||
{
|
||||
tr->cut();
|
||||
}
|
||||
catch (const QString &msg)
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Cutting recording of topic '" << tr->topicName() << "', id: " << tr->topicId() << " failed! " << msg;
|
||||
m_failedExportTopicIds += tr->topicId();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void ScreenRecorder::save(const QString &tmpDirPath)
|
||||
{
|
||||
for (TopicRecorder *tr : qAsConst(m_topicRecorder))
|
||||
{
|
||||
if (tr->isFailed()) // skip, plus already in m_failedExportTopicIds by exportFailed signal
|
||||
continue;
|
||||
|
||||
try
|
||||
{
|
||||
tr->save(tmpDirPath);
|
||||
}
|
||||
catch (const QString &msg)
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Saving recording of topic '" << tr->topicName() << "', id: " << tr->topicId() << " failed! " << msg;
|
||||
m_failedExportTopicIds += tr->topicId();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void ScreenRecorder::addTopicsForScreen(Screen *screen, const std::vector<TopicItem> &topicItems)
|
||||
{
|
||||
m_topicRecorder.reserve(m_topicRecorder.size() + topicItems.size());
|
||||
const qint32 startTimeOffset = -10000;
|
||||
|
||||
for (const TopicItem ¤tTopicItem : topicItems)
|
||||
{
|
||||
const auto id = currentTopicItem.topicId();
|
||||
const qint64 startTime = currentTopicItem.startTime() + startTimeOffset;
|
||||
const qint64 stopTime = currentTopicItem.startTime() + currentTopicItem.duration();
|
||||
const QString name(currentTopicItem.channel().replace(QStringLiteral(" "), QStringLiteral("_")) + QString::number(currentTopicItem.id()));
|
||||
TopicRecorder *topicRecorder = new TopicRecorder(id, name, screen, startTimeOffset, startTime, stopTime,
|
||||
currentTopicItem.topicData().x, currentTopicItem.topicData().y,
|
||||
currentTopicItem.topicData().w, currentTopicItem.topicData().h, this);
|
||||
|
||||
connect(this, &ScreenRecorder::newTime, topicRecorder, &TopicRecorder::onNewTime);
|
||||
connect(this, &ScreenRecorder::cancel, topicRecorder, &TopicRecorder::cancel);
|
||||
connect(topicRecorder, &TopicRecorder::exportFailed, this, [this, id]() { emit topicExportFailed(id); });
|
||||
connect(topicRecorder, &TopicRecorder::exportFailed, this, [this, name, id]()
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Export failed for topic '" << name << "', id: " << id;
|
||||
m_failedExportTopicIds += id;
|
||||
});
|
||||
|
||||
m_topicRecorder.append(topicRecorder);
|
||||
}
|
||||
|
||||
DEBUG_LOG(m_logger) << "Added " << topicItems.size() << " TopicRecorder.";
|
||||
}
|
||||
|
||||
//void ScreenRecorder::saveRecordings(const QString &tmpDirPath)
|
||||
//{
|
||||
// for (TopicRecorder *tr : qAsConst(m_topicRecorder))
|
||||
// {
|
||||
// if (tr->isFailed()) // skip, plus already in m_failedExportTopicIds by exportFailed signal
|
||||
// continue;
|
||||
|
||||
// try
|
||||
// {
|
||||
// tr->saveRecording(tmpDirPath);
|
||||
// }
|
||||
// catch (const QString &msg)
|
||||
// {
|
||||
// ERROR_LOG(m_logger) << "Saving recording of topic '" << tr->topicName() << "', id: " << tr->topicId() << " failed! " << msg;
|
||||
// m_failedExportTopicIds += tr->topicId();
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
|
||||
void ScreenRecorder::setCurrentTime(qint64 currentTime)
|
||||
{
|
||||
emit newTime(currentTime);
|
||||
}
|
||||
|
||||
void ScreenRecorder::clear()
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "Clearing TopicRecorder.";
|
||||
|
||||
for (TopicRecorder *currentTopicRecorder : qAsConst(m_topicRecorder))
|
||||
{
|
||||
currentTopicRecorder->killAndClear();
|
||||
delete currentTopicRecorder;
|
||||
}
|
||||
|
||||
m_topicRecorder.clear();
|
||||
}
|
||||
|
||||
void ScreenRecorder::waitForFinishedRecording()
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "Waiting for TopicRecorder to finish ...";
|
||||
|
||||
for (TopicRecorder *currentTopicRecorder : qAsConst(m_topicRecorder))
|
||||
currentTopicRecorder->waitForFinishedRecording();
|
||||
|
||||
DEBUG_LOG(m_logger) << "... all TopicRecorder finished.";
|
||||
}
|
||||
|
||||
} // namespace PresentationManagement
|
||||
+63
@@ -0,0 +1,63 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* class for recording topics on a screen
|
||||
* $Id:
|
||||
* $HeadURL:
|
||||
* $Author:
|
||||
* Created by Hannes Fritsche, SLTE, 2023-01-18
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QObject>
|
||||
#include <QTemporaryDir>
|
||||
#include <QSet>
|
||||
#include <Services/PresentationManagement/logger.h>
|
||||
#include "pre_topic_recorder.h"
|
||||
|
||||
|
||||
class QProcess;
|
||||
class Screen;
|
||||
|
||||
namespace PresentationManagement
|
||||
{
|
||||
|
||||
class TopicItem;
|
||||
|
||||
class ScreenRecorder : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public: // methods
|
||||
ScreenRecorder(QObject *parent = nullptr);
|
||||
~ScreenRecorder() { clear(); }
|
||||
|
||||
|
||||
|
||||
|
||||
void cut();
|
||||
void save(const QString &tmpDirPath);
|
||||
|
||||
|
||||
|
||||
|
||||
void addTopicsForScreen(Screen *screen, const std::vector<TopicItem> &topicItems);
|
||||
void setCurrentTime(qint64 currentTime);
|
||||
|
||||
void clear();
|
||||
void waitForFinishedRecording();
|
||||
void saveRecordings(const QString &tmpDirPath); // old
|
||||
const QSet<int> &failedExportTopicIds() const { return m_failedExportTopicIds; }
|
||||
|
||||
signals:
|
||||
void newTime(qint64 time);
|
||||
void topicExportFailed(const int failedTopicId);
|
||||
void cancel();
|
||||
|
||||
private: // attributes
|
||||
QVector<TopicRecorder *> m_topicRecorder;
|
||||
QSet<int> m_failedExportTopicIds;
|
||||
LOGGER_T m_logger;
|
||||
}; // class ScreenRecorder
|
||||
|
||||
} // namespace PresentationManagement
|
||||
Executable
+84
@@ -0,0 +1,84 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* class for recording topics on a screen
|
||||
* $Id:
|
||||
* $HeadURL:
|
||||
* $Author:
|
||||
* Created by Hannes Fritsche, SLTE, 2023-01-18
|
||||
*/
|
||||
|
||||
#include "pre_screen_shotter.h"
|
||||
#include <QProcess>
|
||||
#include "pre_screen.h"
|
||||
#include <limits>
|
||||
#include "pre_topic_item.h"
|
||||
#include <QJsonDocument>
|
||||
#include <QJsonArray>
|
||||
#include <QJsonObject>
|
||||
|
||||
namespace PresentationManagement
|
||||
{
|
||||
|
||||
ScreenShotter::ScreenShotter(QObject *parent)
|
||||
: QObject(parent)
|
||||
, m_logger(getLogger(QStringLiteral("ScreenShotter")))
|
||||
{}
|
||||
|
||||
void ScreenShotter::addTopicsForScreen(Screen *screen, const std::vector<TopicItem> &topicItems)
|
||||
{
|
||||
m_topicShotter.reserve(m_topicShotter.size() + topicItems.size());
|
||||
|
||||
for (const TopicItem ¤tTopicItem : topicItems)
|
||||
{
|
||||
const auto id = currentTopicItem.topicId();
|
||||
const qint64 startTime = currentTopicItem.startTime();
|
||||
const qint64 stopTime = currentTopicItem.startTime() + currentTopicItem.duration();
|
||||
const QString name(currentTopicItem.channel().replace(QStringLiteral(" "), QStringLiteral("_")) + QString::number(currentTopicItem.id()));
|
||||
const double topicX = currentTopicItem.topicData().x;
|
||||
const double topicY = currentTopicItem.topicData().y;
|
||||
const double topicW = currentTopicItem.topicData().w;
|
||||
const double topicH = currentTopicItem.topicData().h;
|
||||
ERROR_LOG(m_logger) << "ScreenShotter::addTopicsForScreen: x: " << topicX << ", y: " << topicY << ", w: " << topicW << ", h: " << topicH;
|
||||
TopicShotter *topicShotter = new TopicShotter(id, name, screen, 0, startTime, stopTime, topicX, topicY,
|
||||
topicW, topicH, (!currentTopicItem.parentChannel().isEmpty()),
|
||||
currentTopicItem.description(), this);
|
||||
|
||||
connect(this, &ScreenShotter::newTime, topicShotter, &TopicShotter::onNewTime);
|
||||
connect(topicShotter, &TopicShotter::exportFailed, this, [this, id]() { emit topicExportFailed(id); });
|
||||
connect(topicShotter, &TopicShotter::exportFailed, this, [this, name, id]()
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Export failed for topic '" << name << "', id: " << id;
|
||||
m_failedExportTopicIds += id;
|
||||
});
|
||||
|
||||
m_topicShotter.append(topicShotter);
|
||||
}
|
||||
|
||||
DEBUG_LOG(m_logger) << "Added " << topicItems.size() << " TopicShotter.";
|
||||
}
|
||||
|
||||
void ScreenShotter::saveRecordings(const QString &tmpDirPath)
|
||||
{
|
||||
for (TopicShotter *tr : qAsConst(m_topicShotter))
|
||||
{
|
||||
if (tr->isFailed())
|
||||
continue;
|
||||
|
||||
try
|
||||
{
|
||||
tr->saveRecording(tmpDirPath);
|
||||
}
|
||||
catch (const QString &msg)
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Saving screenshot of topic '" << tr->topicName() << "', id: " << tr->topicId() << " failed! " << msg;
|
||||
m_failedExportTopicIds += tr->topicId();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ScreenShotter::setCurrentTime(qint64 currentTime)
|
||||
{
|
||||
emit newTime(currentTime);
|
||||
}
|
||||
|
||||
} // namespace PresentationManagement
|
||||
+50
@@ -0,0 +1,50 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* class for recording topics on a screen
|
||||
* $Id:
|
||||
* $HeadURL:
|
||||
* $Author:
|
||||
* Created by Hannes Fritsche, SLTE, 2023-01-18
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QObject>
|
||||
#include <QTemporaryDir>
|
||||
#include <QSet>
|
||||
#include <Services/PresentationManagement/logger.h>
|
||||
#include "pre_topic_shotter.h"
|
||||
|
||||
|
||||
class QProcess;
|
||||
class Screen;
|
||||
|
||||
namespace PresentationManagement
|
||||
{
|
||||
|
||||
class TopicItem;
|
||||
|
||||
class ScreenShotter : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public: // methods
|
||||
ScreenShotter(QObject *parent = nullptr);
|
||||
|
||||
void addTopicsForScreen(Screen *screen, const std::vector<TopicItem> &topicItems);
|
||||
void setCurrentTime(qint64 currentTime);
|
||||
|
||||
void saveRecordings(const QString &tmpDirPath);
|
||||
const QSet<int> &failedExportTopicIds() const { return m_failedExportTopicIds; }
|
||||
|
||||
signals:
|
||||
void newTime(qint64 time);
|
||||
void topicExportFailed(const int failedTopicId);
|
||||
|
||||
private: // attributes
|
||||
QVector<TopicShotter *> m_topicShotter;
|
||||
QSet<int> m_failedExportTopicIds;
|
||||
LOGGER_T m_logger;
|
||||
}; // class ScreenShotter
|
||||
|
||||
} // namespace PresentationManagement
|
||||
Executable
+210
@@ -0,0 +1,210 @@
|
||||
#include "pre_script_delegate.h"
|
||||
#include "pre_script_dialog_drag_handler.h"
|
||||
#include "pre_script_model.h"
|
||||
|
||||
#include <LtsTimeline/timeline_header_view.h>
|
||||
#include <LtsTimeline/timeline_view.h>
|
||||
|
||||
#include <QApplication>
|
||||
#include <QGuiApplication>
|
||||
#include <QPainter>
|
||||
#include <QDebug>
|
||||
|
||||
|
||||
namespace PresentationManagement
|
||||
{
|
||||
|
||||
QColor ScriptDelegate::s_blockedBackgroundColor = QGuiApplication::palette().color(QPalette::Disabled, QPalette::Base);
|
||||
|
||||
QColor ScriptDelegate::s_validDragColor = QRgb(0x00FF66);
|
||||
|
||||
QColor ScriptDelegate::s_invalidDragColor = QRgb(0xFF3333);
|
||||
|
||||
|
||||
ScriptDelegate::ScriptDelegate(LtsTimeline::TimelineView *parent)
|
||||
: LtsTimeline::ItemDelegate(parent)
|
||||
{
|
||||
m_model = static_cast<ScriptModel *>(m_view->timelineModel());
|
||||
Q_ASSERT(m_model);
|
||||
m_dragHandler = static_cast<ScriptDialogDragHandler *>(m_view->dragHandler());
|
||||
Q_ASSERT(m_dragHandler);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// PUBLIC
|
||||
|
||||
void ScriptDelegate::paintDragItems(QPainter *painter) const
|
||||
{
|
||||
if (!m_dragHandler->isActive() && !m_dragHandler->m_isDragEventFromTopicEditor)
|
||||
return;
|
||||
|
||||
if (m_dragHandler->m_isDragEventFromTopicEditor)
|
||||
{
|
||||
paintDragItemFromEditor(painter);
|
||||
return;
|
||||
}
|
||||
|
||||
paintDragItemsFromView(painter);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// PRIVATE
|
||||
|
||||
void ScriptDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
|
||||
{
|
||||
if (index.column() == LtsTimeline::Section::eActuator)
|
||||
{
|
||||
painter->save();
|
||||
QStyledItemDelegate::paint(painter, option, index);
|
||||
paintTrackButtons(painter, option, index);
|
||||
painter->restore();
|
||||
return;
|
||||
}
|
||||
|
||||
auto drawItem = [this, &option, &painter, &index](const TopicItem &topicItem)
|
||||
{
|
||||
QStyleOptionViewItem opt = option;
|
||||
opt.rect.setLeft(std::max(m_view->toPixel(topicItem.startTime()), option.rect.left()));
|
||||
opt.rect.setRight(std::min(m_view->toPixel(topicItem.startTime() + topicItem.duration()), option.rect.right()) - 1);
|
||||
opt.rect.setBottom(opt.rect.bottom() - 1);
|
||||
topicItem.paint(painter, opt, index, m_view->selectedItemIds().contains(topicItem.id()));
|
||||
};
|
||||
|
||||
try
|
||||
{
|
||||
const TopicTrack &track = static_cast<const TopicTrack &>(m_view->timelineModel()->track(index.internalId()));
|
||||
painter->save();
|
||||
painter->setPen(Qt::black);
|
||||
painter->drawRect(option.rect);
|
||||
painter->setClipping(true);
|
||||
painter->setClipRect(option.rect);
|
||||
|
||||
if (m_model->isFilterTrack(track.id()))
|
||||
{
|
||||
try
|
||||
{
|
||||
const TopicTrack &parentTrack = static_cast<const TopicTrack &>(m_view->timelineModel()->track(track.parentId()));
|
||||
const LtsTimeline::Items &parentItems = parentTrack.items();
|
||||
Q_ASSERT(m_model->isMainTrack(parentTrack.id()));
|
||||
QRect blockedBackgroundRect = option.rect;
|
||||
blockedBackgroundRect.setLeft(blockedBackgroundRect.left() + 1);
|
||||
blockedBackgroundRect.setTop(blockedBackgroundRect.top() + 1);
|
||||
blockedBackgroundRect.setBottom(blockedBackgroundRect.bottom() - 1);
|
||||
painter->setPen(s_blockedBackgroundColor);
|
||||
painter->setBrush(QBrush(s_blockedBackgroundColor));
|
||||
for (const LtsTimeline::ItemPtr &itemPtr : parentItems)
|
||||
{
|
||||
blockedBackgroundRect.setRight(m_view->toPixel(itemPtr->startTime()) - 1);
|
||||
if (blockedBackgroundRect.width() > 0)
|
||||
painter->drawRect(blockedBackgroundRect);
|
||||
blockedBackgroundRect.setLeft(m_view->toPixel(itemPtr->startTime() + itemPtr->duration()) + 1);
|
||||
}
|
||||
blockedBackgroundRect.setRight(option.rect.right() - 1);
|
||||
if (blockedBackgroundRect.width() > 0)
|
||||
painter->drawRect(blockedBackgroundRect);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
qCritical() << "ItemDelegate::paint -> painting background failed";
|
||||
}
|
||||
}
|
||||
|
||||
painter->setPen(Qt::black);
|
||||
const LtsTimeline::Items &items = track.items();
|
||||
for (const LtsTimeline::ItemPtr &item : items)
|
||||
drawItem(static_cast<const TopicItem &>(*item.get()));
|
||||
|
||||
painter->restore();
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
qCritical() << "ItemDelegate::paint -> CATCH";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void ScriptDelegate::paintDragItemsFromView(QPainter *painter) const
|
||||
{
|
||||
if (m_dragHandler->m_dragItemIds.isEmpty() || !m_dragHandler->m_canDropTopicTypes)
|
||||
return;
|
||||
|
||||
const QModelIndex index = m_view->indexAt(m_dragHandler->m_dragPos);
|
||||
if (!index.isValid() || index.column() == LtsTimeline::Section::eActuator)
|
||||
return;
|
||||
|
||||
painter->save();
|
||||
|
||||
const QRect rightSectionRect = QRect(
|
||||
QPoint(m_view->header()->sectionPosition(LtsTimeline::Section::eItems), 0), m_view->geometry().bottomRight()
|
||||
);
|
||||
painter->setClipRect(rightSectionRect);
|
||||
int dx = m_dragHandler->deltaX();
|
||||
int dy = m_dragHandler->deltaY();
|
||||
try
|
||||
{
|
||||
if (index == m_dragHandler->m_dragStartIndex)
|
||||
{
|
||||
if (m_dragHandler->canMoveItemsTo(m_dragHandler->m_dragPos))
|
||||
painter->setBrush(QBrush(s_validDragColor));
|
||||
else
|
||||
painter->setBrush(QBrush(s_invalidDragColor));
|
||||
}
|
||||
else
|
||||
{
|
||||
if (m_dragHandler->canDragItemsTo(m_dragHandler->m_dragPos))
|
||||
painter->setBrush(QBrush(s_validDragColor));
|
||||
else
|
||||
painter->setBrush(QBrush(s_invalidDragColor));
|
||||
}
|
||||
for (const int &itemId : m_dragHandler->m_dragItemIds)
|
||||
{
|
||||
LtsTimeline::Item &item = m_view->timelineModel()->item(itemId);
|
||||
QModelIndex idx = m_view->timelineModel()->indexOfTrack(item.parentTrackId());
|
||||
QRect visualRect = m_view->visualRect(idx);
|
||||
int left = m_view->toPixel(item.startTime()) + dx;
|
||||
int right = m_view->toPixel(item.startTime() + item.duration()) + dx;
|
||||
int top = visualRect.top() + dy;
|
||||
int bottom = visualRect.bottom() + dy;
|
||||
if (m_view->selectedItemIds().contains(itemId))
|
||||
painter->setPen(QPen(LtsTimeline::Item::s_highlightColor, 5));
|
||||
painter->drawRect(QRect(left, top, right - left - 1, bottom - top));
|
||||
}
|
||||
} catch (...) {}
|
||||
|
||||
painter->restore();
|
||||
}
|
||||
|
||||
void ScriptDelegate::paintDragItemFromEditor(QPainter *painter) const
|
||||
{
|
||||
try
|
||||
{
|
||||
const QModelIndex index = m_view->indexAt(m_dragHandler->m_dragPos);
|
||||
if (!index.isValid())// || index.column() != LtsTimeline::Section::eItems)
|
||||
return;
|
||||
|
||||
ScriptModel *model = static_cast<ScriptModel *>(m_view->timelineModel());
|
||||
if (!model)
|
||||
return;
|
||||
|
||||
if (!model->canDropTopicType(m_dragHandler->m_dragItem->topicType(), index.internalId()))
|
||||
return;
|
||||
|
||||
painter->save();
|
||||
|
||||
QCursor *cursor = QApplication::overrideCursor();
|
||||
if (cursor)
|
||||
painter->setBrush(QBrush(cursor->shape() == Qt::ForbiddenCursor ? s_invalidDragColor : s_validDragColor));
|
||||
else // extremely rare, but possible ...
|
||||
painter->setBrush(QBrush(m_view->cursor().shape() == Qt::ForbiddenCursor ? s_invalidDragColor : s_validDragColor));
|
||||
QRect rect = m_view->visualRect(index);
|
||||
painter->setClipRect(rect);
|
||||
rect.setLeft(m_dragHandler->m_dragPos.x() - m_dragHandler->m_dragItemOffset + m_dragHandler->deltaX());
|
||||
rect.setRight(rect.left() + m_dragHandler->dragItemFromTopicEditorWidth());
|
||||
rect.setBottom(rect.top() + m_dragHandler->deltaY() - 1);
|
||||
painter->drawRect(rect);
|
||||
|
||||
painter->restore();
|
||||
} catch (...) {}
|
||||
}
|
||||
|
||||
} // namespace PresentationManagement
|
||||
+43
@@ -0,0 +1,43 @@
|
||||
#pragma once
|
||||
|
||||
#include <LtsTimeline/item_delegate.h>
|
||||
|
||||
|
||||
namespace PresentationManagement
|
||||
{
|
||||
|
||||
class ScriptDialogDragHandler;
|
||||
class ScriptModel;
|
||||
class ScriptTimelineDialog;
|
||||
|
||||
|
||||
class ScriptDelegate : public LtsTimeline::ItemDelegate
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
static QColor s_blockedBackgroundColor;
|
||||
static QColor s_validDragColor;
|
||||
static QColor s_invalidDragColor;
|
||||
|
||||
explicit ScriptDelegate(LtsTimeline::TimelineView *parent = nullptr);
|
||||
|
||||
/**
|
||||
* @brief paintDragItems paints dragged items over the view
|
||||
* @param painter painter to draw all dragged items on the view
|
||||
*/
|
||||
void paintDragItems(QPainter *painter) const override;
|
||||
|
||||
private:
|
||||
void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const override;
|
||||
|
||||
void paintDragItemsFromView(QPainter *painter) const;
|
||||
void paintDragItemFromEditor(QPainter *painter) const;
|
||||
|
||||
private:
|
||||
ScriptModel *m_model { nullptr };
|
||||
ScriptDialogDragHandler *m_dragHandler { nullptr };
|
||||
|
||||
};
|
||||
|
||||
} // namespace PresentationManagement
|
||||
+4833
File diff suppressed because it is too large.
Load diff
Executable
+3539
File diff suppressed because it is too large.
Load diff
+470
@@ -0,0 +1,470 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* PresentationManagement - Script Editor
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*
|
||||
* Created by Mike Wille, SLSE, 2017-03-17
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "pre_screen.h"
|
||||
#include "pre_journal_types.h"
|
||||
#include "pre_utils.h"
|
||||
|
||||
#include <DDS/Core/core_dtc.h>
|
||||
#include <LtsPluginManager/lts_plugin_manager.h>
|
||||
#include <LtsSession/lts_session.h>
|
||||
#include <LtsUtilsGuiDds/request_helper.h>
|
||||
#include <LtsWidgets/lts_dialog.h>
|
||||
#include <PluginInterfaces/topic_replay_interface.h>
|
||||
#include <Plugins/PresentationManagement/Gui/Common/topic_assignment.h>
|
||||
#include <Plugins/SituationMapPlugin/situation_map_gui_plugin_interface.h>
|
||||
#include <Plugins/SituationReplay/srp_gui_plugin_interface.h>
|
||||
#include <Services/OperatorManagement/opm_dtc.h>
|
||||
#include <Services/ExerciseManagement/exm_dtc.h>
|
||||
#include <Services/PresentationManagement/pre_dtc.h>
|
||||
#include <Services/PresentationManagement/pre_ftc.h>
|
||||
#include <Services/SituationReplayManagement/srm_ftc.h>
|
||||
#include <TopicEditorBase/topic_editor_utils.h>
|
||||
#include <LtsWidgets/lts_overlay_loading.h>
|
||||
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
|
||||
#include <QString>
|
||||
#include <QStringList>
|
||||
#include <QMap>
|
||||
#include <QTemporaryDir>
|
||||
|
||||
|
||||
namespace Ui
|
||||
{
|
||||
class ScriptDialog;
|
||||
class ScriptPlayerDialog;
|
||||
}
|
||||
namespace LtsPluginManager { class LtsPluginManager; }
|
||||
namespace LtsSession { class LtsSession; }
|
||||
namespace LtsTimeline { class TimelineWidget; }
|
||||
namespace LtsUtils { class Promise; }
|
||||
namespace SituationReplayManagement { class ForeignDataInterface; }
|
||||
namespace TakeHomePackageGenerator { class ExportProcess; }
|
||||
|
||||
|
||||
namespace PresentationManagement
|
||||
{
|
||||
|
||||
class ScreenShotter;
|
||||
class ScreenRecorder;
|
||||
class ScriptModel;
|
||||
class StoryboardDialog;
|
||||
class TopicDesigner;
|
||||
class TopicItem;
|
||||
class CoolExporter;
|
||||
|
||||
namespace Interface { class Ftc; }
|
||||
|
||||
|
||||
//template<typename Type = void *>
|
||||
class Scope
|
||||
{
|
||||
public:
|
||||
explicit Scope(const std::function<void (void)> &ctor, const std::function<void (void)> &dtor)
|
||||
//: m_fn(fn)
|
||||
//: m_data(ctor())
|
||||
: m_dtor(dtor)
|
||||
{
|
||||
ctor();
|
||||
}
|
||||
|
||||
~Scope()
|
||||
{
|
||||
m_dtor();
|
||||
}
|
||||
|
||||
// Scope(const std::function<Type (void)> &ctor, const std::function<void (Type)> &dtor)
|
||||
// //: m_fn(fn)
|
||||
// : m_data({})
|
||||
// {
|
||||
|
||||
// }
|
||||
|
||||
private:
|
||||
//Type m_data;
|
||||
std::function<void (void)> m_dtor;
|
||||
};
|
||||
|
||||
|
||||
class ScriptTimelineDialog : public LtsWidgets::LtsDialog
|
||||
{
|
||||
public:
|
||||
Q_OBJECT
|
||||
|
||||
friend class ScriptDelegate;
|
||||
|
||||
public:
|
||||
friend class CoolExporter;
|
||||
|
||||
enum class ProjectionWidget { Unknown = 0, Screen1, Screen2, };
|
||||
enum class SpecialTopicType { Normal = 0, Replay, Filter, };
|
||||
|
||||
static TopicEditorBase::TopicData topicDataFromContent(
|
||||
const PresentationManagement::PresentationContent &content, int topicId, TopicEditorBase::TopicType topicType
|
||||
);
|
||||
static bool isFilter(TopicEditorBase::TopicType topicType);
|
||||
static bool isUsingAvsWindow(TopicEditorBase::TopicType topicType);
|
||||
static QString toReadableTime(qint64 msecs);
|
||||
|
||||
explicit ScriptTimelineDialog(const QString &menuGroup, QWidget *parent = nullptr);
|
||||
~ScriptTimelineDialog();
|
||||
|
||||
bool init(
|
||||
LtsSession::LtsSession *session, const int scriptId, const std::shared_ptr<Interface::Dtc> &dtc,
|
||||
const std::shared_ptr<Interface::Ftc> &ftc,
|
||||
const std::shared_ptr<SituationReplayManagement::ForeignDataInterface> &srmForeign,
|
||||
const std::shared_ptr<Core::Interface::Dtc> &coreDtc, const std::shared_ptr<OperatorManagement::Interface::Dtc> &opmDtc,
|
||||
const std::shared_ptr<ExerciseManagement::Interface::Dtc> &exmDtc
|
||||
);
|
||||
|
||||
void initInternal();
|
||||
|
||||
LtsTimeline::TimelineWidget *timeline();
|
||||
ScriptModel *model() { return m_model; }
|
||||
|
||||
int scriptId() const { return m_scriptId; }
|
||||
|
||||
bool isScriptRunning() const { return m_isScriptRunning; }
|
||||
qint64 scriptEndTime() const;
|
||||
|
||||
LtsSession::LtsSession *essentialsViewSession() { return m_essentialsViewSession; }
|
||||
bool isEssentialsViewOpen() const;
|
||||
|
||||
bool import(const QVector<PresentationContent> &contents);
|
||||
void load();
|
||||
|
||||
TopicEditorBase::TopicEditor *getTopicEditor(const TopicAssignment &topicAssignment);
|
||||
TopicEditorBase::TopicEditor *getTopicEditor(const TopicEditorBase::TopicData &data);
|
||||
|
||||
bool topicStringToType(const QString &typeName, TopicEditorBase::TopicType &topicType) const;
|
||||
|
||||
std::shared_ptr<SituationReplay::ForeignGuiInterface> getReplayGuiIfc() const
|
||||
{
|
||||
return m_essentialsViewsSrpIfc;
|
||||
}
|
||||
|
||||
private:
|
||||
// LtsDialog override
|
||||
void retranslate() override;
|
||||
bool apply() override;
|
||||
void aboutToClose() override;
|
||||
|
||||
void getReplaySession() noexcept(false);
|
||||
bool getTopics(QStringList &resultList);
|
||||
bool getTopic(
|
||||
TopicEditorBase::TopicType topicType, const std::shared_ptr<TopicEditorBase::Interface> &topicEditorIfc,
|
||||
const std::shared_ptr<TopicReplay::Factory> &topicReplayFactory,
|
||||
const std::shared_ptr<TopicReplay::Factory> &topicExportFactory, QStringList &resultList,
|
||||
const SpecialTopicType &specialTopicType = SpecialTopicType::Normal
|
||||
);
|
||||
bool getTopicItems();
|
||||
void getSitMapApp() noexcept(false);
|
||||
void getPresentationContent(); // tryAddTopics has to be called first to populate m_topicAssignments
|
||||
void getProjectionWidget(Screen **pointerToWidgetPointer, bool placeAutomatically = false);
|
||||
|
||||
// dds stuff
|
||||
bool enableFireEventFlash(bool enable);
|
||||
|
||||
// io stuff
|
||||
void exportPresentationContent(const Core::FunctionReply &baseReply);
|
||||
|
||||
// ui stuff
|
||||
void disableSessionDialog(LtsSession::LtsSession *session, bool disable);
|
||||
void startEssentialsViewStage2(const Core::ReplayPartition &replay, bool openTopicEditor, int topicType, int topicItemId);
|
||||
static bool hasEssentialsViewTopicType(TopicEditorBase::TopicType topicType);
|
||||
void previewSecond(qint64 time, int ignoreTopicForReplay = -1);
|
||||
TopicEditorBase::TopicEditor *createTopicEditor(const TopicEditorBase::TopicData &data);
|
||||
Screen *getProjectionWidget(const ProjectionWidget &projectionWidget);
|
||||
ProjectionWidget identifyProjectionWidget(const TopicItem &topicItem) const;
|
||||
static void deleteProjectionWidget(Screen **pointerToWidgetPointer);
|
||||
void addReplayWidget(int topicItemId, QWidget *replayWidget);
|
||||
void setReplayWidgetPosition(int topicItemId);
|
||||
void setReplayWidgetFreestanding(int topicItemId, bool freestanding);
|
||||
void displayPlaylist();
|
||||
bool isScreenFreestanding(const ProjectionWidget &projectionWidget) const;
|
||||
void setProjectionWidgetFreestanding(bool freestanding, const ProjectionWidget &projectionWidget);
|
||||
void avsVisibilityHack(QWidget *parentForScreen, bool visible);
|
||||
void avsFreestandingHack(bool freestanding, QWidget *projectionWidget, QWidget **parentForScreen);
|
||||
void enaDisa();
|
||||
void startEssentialsView(int topicItemId = -1, int topicType = -1, bool openTopicEditor = false);
|
||||
|
||||
// topic stuff
|
||||
void openContextMenu(QPoint pos, int topicItemId);
|
||||
void setTopicDescription(int topicItemId);
|
||||
void enableTopicEditors(bool enable);
|
||||
|
||||
// replay stuff
|
||||
qint64 positionTime() const;
|
||||
void setPositionTime(qint64 time, bool setByUser = false);
|
||||
void setPositionTimeActive(qint64 time, bool setByUser = false); // setPositionTime, but, if playing, also ticks and resets timeout
|
||||
void playTopic(int topicItemId);
|
||||
void pause();
|
||||
void stop(bool ended = false, bool ignoreFireEventFlashing = false);
|
||||
qint64 previousTopicTime() const;
|
||||
qint64 nextTopicTime() const;
|
||||
bool hasPreviousTopic() const { return previousTopicTime() > -1; }
|
||||
bool hasNextTopic() const { return nextTopicTime() > -1; }
|
||||
void removeTopicItemFromPlaylist(int topicItemId); // WARNING: use a mutable iterator while iterating over m_currentlyPlayingTopics and remove the entry before calling this method!
|
||||
|
||||
bool isTopicAlreadyOpened(const TopicEditorBase::TopicData &data);
|
||||
template <typename TopicEditorInterface>
|
||||
std::shared_ptr<TopicEditorBase::Interface> getTopicEditorIfc(TopicEditorBase::TopicType topicType)
|
||||
{
|
||||
std::shared_ptr<TopicEditorBase::Interface> topicEditorIfc;
|
||||
|
||||
if (!m_exerciseSession->interfaceFromGui<TopicEditorInterface>(topicEditorIfc))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "getTopicEditorIfc failed: Cannot add topic type "
|
||||
<< TopicEditorBase::topicTypeString(topicType)
|
||||
<< " because topic editor ifc is missing.";
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return topicEditorIfc;
|
||||
}
|
||||
|
||||
template <typename TopicReplayInterface>
|
||||
std::shared_ptr<TopicReplay::Factory> getTopicReplayFactory(TopicEditorBase::TopicType topicType)
|
||||
{
|
||||
std::shared_ptr<TopicReplay::Factory> topicReplayFactory;
|
||||
|
||||
if (!m_replaySession->interfaceFromGui<TopicReplayInterface>(topicReplayFactory))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "getTopicIfcFactory failed: Cannot add topic type "
|
||||
<< TopicEditorBase::topicTypeString(topicType)
|
||||
<< " because topic ifc factory is missing.";
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return topicReplayFactory;
|
||||
}
|
||||
|
||||
bool isTopicDisabled(TopicEditorBase::TopicType topicType) const;
|
||||
|
||||
template <typename TopicEditorGuiInterface,
|
||||
typename TopicReplayFactory = TopicReplay::Factory,
|
||||
typename TopicExportFactory = TopicReplayFactory>
|
||||
bool tryAddTopic(TopicEditorBase::TopicType topicType,
|
||||
QStringList &resultList,
|
||||
const SpecialTopicType &specialTopicType = SpecialTopicType::Normal)
|
||||
{
|
||||
// qWarning() << "mep" << QStringLiteral("%1:%2").arg(QString::fromUtf8(__FILE__).split(QStringLiteral("/")).last()).arg(__LINE__);
|
||||
|
||||
if (isTopicDisabled(topicType))
|
||||
return true;
|
||||
|
||||
std::shared_ptr<TopicEditorBase::Interface> topicEditorIfc;
|
||||
std::shared_ptr<TopicReplay::Factory> topicReplayFactory;
|
||||
std::shared_ptr<TopicReplay::Factory> topicExportFactory;
|
||||
|
||||
if (!std::is_same<TopicEditorBase::Interface, TopicEditorGuiInterface>::value)
|
||||
{
|
||||
topicEditorIfc = getTopicEditorIfc<TopicEditorGuiInterface>(topicType);
|
||||
|
||||
if (topicEditorIfc == nullptr)
|
||||
{
|
||||
resultList.append(TopicEditorBase::topicTypeString(topicType));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (!std::is_same<TopicReplay::Factory, TopicReplayFactory>::value)
|
||||
{
|
||||
topicReplayFactory = getTopicReplayFactory<TopicReplayFactory>(topicType);
|
||||
|
||||
if (topicReplayFactory == nullptr)
|
||||
{
|
||||
resultList.append(TopicEditorBase::topicTypeString(topicType));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (!std::is_same<TopicReplay::Factory, TopicExportFactory>::value)
|
||||
{
|
||||
topicExportFactory = getTopicReplayFactory<TopicExportFactory>(topicType);
|
||||
|
||||
if (topicExportFactory == nullptr)
|
||||
{
|
||||
resultList.append(TopicEditorBase::topicTypeString(topicType));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
topicExportFactory = topicReplayFactory;
|
||||
|
||||
return getTopic(topicType, topicEditorIfc, topicReplayFactory, topicExportFactory, resultList, specialTopicType);
|
||||
}
|
||||
|
||||
bool hasPlacedBothProjectionWidgets() const;
|
||||
|
||||
private slots:
|
||||
void onChangesMade();
|
||||
void onChangesWereMade();
|
||||
void onDiscard();
|
||||
void onNull(QObject *obj);
|
||||
|
||||
// io stuff
|
||||
void onLoad();
|
||||
void onExport();
|
||||
void onExport2();
|
||||
void onExportSuccessful(const QString &path, const QString &failedTopics);
|
||||
void onBurnDvD(const QString &strExportPath);
|
||||
void onBurningFinished(bool success);
|
||||
|
||||
// ui stuff
|
||||
void onPresentationContent(const GetPresentationContentReply &reply);
|
||||
void onEssentialsView();
|
||||
void onTopicItemPositionChanged(QWidget *previewWidget, int ignoreTopicForReplay);
|
||||
void onCheckTopicItemDuration(int duration, LtsUtils::Promise *promise);
|
||||
void onTopicItemModified();
|
||||
void onTopicItemRemoved(int topicItemId);
|
||||
void onTopicItemSelectionChanged(const QVector<int> &selectedItemIds);
|
||||
void onUpdateTopicEditor(int topicItemId);
|
||||
void onTopicDesignerChangesMade();
|
||||
void onTopicEditorChangesSaved(const TopicEditorBase::TopicData &data);
|
||||
|
||||
// topic stuff
|
||||
void onGetTopicEditor(const TopicEditorBase::TopicData &data);
|
||||
void onEditSelectedTopicItem();
|
||||
void onEditTopicItem(int itemId);
|
||||
void onRemoveSelectedTopics();
|
||||
void onContextMenu(QPoint pos);
|
||||
// void onMergeTopics();
|
||||
// void onSplitTopic();
|
||||
|
||||
// replay stuff
|
||||
void onTimeout();
|
||||
void onPlay();
|
||||
void onPause();
|
||||
void onStop();
|
||||
void onNextTopic();
|
||||
void onPreviousTopic();
|
||||
void onPlayUntilNextTopic();
|
||||
|
||||
void onShowStoryboard();
|
||||
void onShowJournal();
|
||||
|
||||
// other stuff
|
||||
bool checkBuildingViewerAndEssentialsView();
|
||||
|
||||
signals:
|
||||
void scriptChanged(int);
|
||||
void isPlaying(bool);
|
||||
void stopped(bool ended);
|
||||
void scriptTick(qint64 positionTime);
|
||||
|
||||
private:
|
||||
LtsSession::LtsSession *m_exerciseSession { nullptr }; // aka. script editor app
|
||||
LtsSession::LtsSession *m_replaySession { nullptr };
|
||||
LtsSession::LtsSession *m_sitMapSession { nullptr };
|
||||
LtsSession::LtsSession *m_essentialsViewSession { nullptr };
|
||||
LtsPluginManager::LtsPluginManager *m_essentialsViewApp { nullptr };
|
||||
LtsPluginManager::LtsPluginManager *m_sitMapApp { nullptr };
|
||||
LtsUtils::RequestHelper *m_requestHelper { nullptr };
|
||||
TakeHomePackageGenerator::ExportProcess *m_exportProcess { nullptr }; // OLD exporter!
|
||||
|
||||
std::shared_ptr<Core::Interface::Dtc> m_coreDtc { nullptr };
|
||||
std::shared_ptr<PresentationManagement::Interface::Dtc> m_dtc { nullptr };
|
||||
std::shared_ptr<PresentationManagement::Interface::Ftc> m_ftc { nullptr };
|
||||
std::shared_ptr<OperatorManagement::Interface::Dtc> m_opmDtc { nullptr };
|
||||
std::shared_ptr<ExerciseManagement::Interface::Dtc> m_exmDtc { nullptr };
|
||||
|
||||
|
||||
std::shared_ptr<SituationReplay::ForeignGuiInterface> m_essentialsViewsSrpIfc;
|
||||
std::shared_ptr<SituationMap::ForeignGuiInterface> m_essentialsViewsSitMapIfc;
|
||||
|
||||
std::shared_ptr<SituationReplayManagement::ForeignDataInterface> m_srmForeignDataIfc { nullptr };
|
||||
|
||||
TopicEditorBase::TopicEditor *m_currentTopicEditor { nullptr };
|
||||
QPointer<TopicDesigner> m_currentTopicDesigner;
|
||||
QPointer<StoryboardDialog> m_storyboardDialog;
|
||||
QWidget *m_previousParentForScreen1 { nullptr };
|
||||
QWidget *m_previousParentForScreen2 { nullptr };
|
||||
Screen *m_projectionWidget1 { nullptr };
|
||||
Screen *m_projectionWidget2 { nullptr };
|
||||
|
||||
QString m_menuGroup;
|
||||
QString m_exerciseName;
|
||||
int m_scriptId { 0 };
|
||||
int m_scriptsExerciseId { 0 };
|
||||
QString m_scriptName;
|
||||
QString m_scriptOwner;
|
||||
qint64 m_lastModified { 0 };
|
||||
|
||||
bool m_ignoreChanges { false };
|
||||
bool m_isApplyEnabled { true };
|
||||
bool m_isContextMenuOpen { false };
|
||||
|
||||
int m_selectedTeId;
|
||||
QMap<QString, TopicAssignment> m_topicAssignments;
|
||||
QMap<TopicEditorBase::TopicType, TopicAssignment> m_trackEntryToTopicAssignment;
|
||||
QMultiMap<int, LtsScriptTimeline::TrackEntry *> m_topicMap; // <seconds, trackEntry>
|
||||
|
||||
QTimer *m_presentationTimer { nullptr };
|
||||
qint64 m_firstTopicTime { -1 };
|
||||
qint64 m_lastTopicTime { -1 };
|
||||
qint64 m_nextPauseTime { -1 };
|
||||
int m_duration { 0 };
|
||||
int m_ignoreTopicForReplay { -1 };
|
||||
bool m_isFirstPlayAfterStop { true };
|
||||
bool m_isScriptRunning { false };
|
||||
bool m_doNotAllowPrevNext { false };
|
||||
bool m_isPlayTopicMethodStillRunning { false };
|
||||
bool m_stopAfterPlayingFilterTopic { false };
|
||||
|
||||
MainJournal m_journal;
|
||||
|
||||
bool m_isTopicsScreen1Freestanding { false };
|
||||
bool m_isTopicsScreen2Freestanding { false };
|
||||
bool m_isAvsVisibilityHackActive { false };
|
||||
bool m_isPaused { false };
|
||||
|
||||
ScriptModel *m_model { nullptr };
|
||||
|
||||
QVector<int> m_playlistTopicItemIds;
|
||||
QVector<int> m_mainTopicItemIds;
|
||||
QVector<int> m_filterTopicItemIds;
|
||||
|
||||
Ui::ScriptDialog *m_ui { nullptr };
|
||||
bool m_lastScriptHasEnded { false };
|
||||
NGL::INGLLogger &m_logger;
|
||||
QMap<TopicEditorBase::TopicType, int> m_avaibleTopics{}; // <data.topicType, data.id>
|
||||
QVector<TopicEditorBase::TopicType> m_modifiedTopicTypesList;
|
||||
|
||||
LtsSession::LtsSession *m_session { nullptr };
|
||||
};
|
||||
|
||||
|
||||
class CoolExporter : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit CoolExporter(ScriptTimelineDialog &dialog);
|
||||
QSet<int> go() noexcept(false);
|
||||
|
||||
signals:
|
||||
void scriptTick(qint64 positionTime);
|
||||
void cancel();
|
||||
|
||||
private:
|
||||
void cancelationPoint() noexcept(false);
|
||||
|
||||
ScriptTimelineDialog &m_this;
|
||||
std::unique_ptr<LtsWidgets::LtsOverlayLoading> m_loading;
|
||||
bool m_stoppedPrematurely { false };
|
||||
NGL::INGLLogger &m_logger;
|
||||
};
|
||||
|
||||
} // namespace PresentationManagement
|
||||
+332
@@ -0,0 +1,332 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>ScriptDialog</class>
|
||||
<widget class="QWidget" name="ScriptDialog">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>1010</width>
|
||||
<height>215</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="MinimumExpanding" vsizetype="MinimumExpanding">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Script Editor</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout" stretch="0,0">
|
||||
<property name="spacing">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="leftMargin">
|
||||
<number>9</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>9</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>9</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>9</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="LtsTimeline::TimelineWidget" name="timeline" native="true">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="MinimumExpanding">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="gbReplayControls">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Maximum">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="title">
|
||||
<string>Replay Controls</string>
|
||||
</property>
|
||||
<property name="checkable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_5">
|
||||
<item>
|
||||
<widget class="QWidget" name="wReplayControls" native="true">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Maximum">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout" stretch="0,0,999">
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="hboxReplayControls">
|
||||
<item>
|
||||
<layout class="QVBoxLayout" name="vboxReplayControlsMain">
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="hboxReplayControlsScreens">
|
||||
<item>
|
||||
<widget class="QPushButton" name="pbInitScreen1">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Set Screen 1</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="pbInitScreen2">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Set Screen 2</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="pbStop">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Stop</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="pbPause">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Pause</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="pbPlay">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Play</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QVBoxLayout" name="vboxReplayControlsJump">
|
||||
<item>
|
||||
<widget class="QPushButton" name="pbUntilNextTopic">
|
||||
<property name="text">
|
||||
<string>Play Until Next Topic</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="pbPreviousTopic">
|
||||
<property name="text">
|
||||
<string>Previous Topic</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="pbNextTopic">
|
||||
<property name="text">
|
||||
<string>Next Topic</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QFormLayout" name="formReplayInfo">
|
||||
<property name="horizontalSpacing">
|
||||
<number>9</number>
|
||||
</property>
|
||||
<property name="verticalSpacing">
|
||||
<number>9</number>
|
||||
</property>
|
||||
<property name="leftMargin">
|
||||
<number>9</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>9</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>9</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>9</number>
|
||||
</property>
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="durationLabel">
|
||||
<property name="text">
|
||||
<string>Presentation duration:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QLabel" name="lblDuration">
|
||||
<property name="text">
|
||||
<string notr="true"> - </string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="lbxPos">
|
||||
<property name="text">
|
||||
<string>Pos:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QSlider" name="sPos">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="tickPosition">
|
||||
<enum>QSlider::TicksBelow</enum>
|
||||
</property>
|
||||
<property name="const" stdset="0">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="lbxCurrentPosition">
|
||||
<property name="text">
|
||||
<string>Current position:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<layout class="QHBoxLayout" name="hboxCurrentPosition">
|
||||
<item>
|
||||
<widget class="QLabel" name="lblPos">
|
||||
<property name="text">
|
||||
<string notr="true">0</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="lbxSlash">
|
||||
<property name="text">
|
||||
<string>/</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="lblMax">
|
||||
<property name="text">
|
||||
<string notr="true">0</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer_3">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QVBoxLayout" name="vboxStatus">
|
||||
<item>
|
||||
<widget class="QLabel" name="lbxStatus">
|
||||
<property name="text">
|
||||
<string>Status:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QListWidget" name="lwStatus">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="MinimumExpanding" vsizetype="MinimumExpanding">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="sizeAdjustPolicy">
|
||||
<enum>QAbstractScrollArea::AdjustToContentsOnFirstShow</enum>
|
||||
</property>
|
||||
<property name="editTriggers">
|
||||
<set>QAbstractItemView::NoEditTriggers</set>
|
||||
</property>
|
||||
<property name="showDropIndicator" stdset="0">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="alternatingRowColors">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="selectionMode">
|
||||
<enum>QAbstractItemView::NoSelection</enum>
|
||||
</property>
|
||||
<property name="verticalScrollMode">
|
||||
<enum>QAbstractItemView::ScrollPerPixel</enum>
|
||||
</property>
|
||||
<property name="movement">
|
||||
<enum>QListView::Free</enum>
|
||||
</property>
|
||||
<property name="isWrapping" stdset="0">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
<class>LtsTimeline::TimelineWidget</class>
|
||||
<extends>QWidget</extends>
|
||||
<header>LtsTimeline/timeline_widget.h</header>
|
||||
<container>1</container>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
+495
@@ -0,0 +1,495 @@
|
||||
#include "pre_script_dialog_drag_handler.h"
|
||||
#include "pre_script_model.h"
|
||||
|
||||
#include <LtsTimeline/item_delegate.h>
|
||||
#include <LtsTimeline/timeline_widget.h>
|
||||
#include <TopicEditorBase/topic_editor_utils.h>
|
||||
|
||||
#include <QApplication>
|
||||
#include <QDebug>
|
||||
#include <QDrag>
|
||||
#include <QMimeData>
|
||||
#include <QMouseEvent>
|
||||
#include <QTimer>
|
||||
|
||||
|
||||
namespace PresentationManagement
|
||||
{
|
||||
|
||||
ScriptDialogDragHandler::ScriptDialogDragHandler(TimelineView *view)
|
||||
: TimelineViewDragHandler(view)
|
||||
, m_timer(new QTimer(this))
|
||||
{
|
||||
m_model = qobject_cast<ScriptModel *>(m_view->timelineModel());
|
||||
Q_ASSERT(m_model);
|
||||
|
||||
m_timer->setSingleShot(true);
|
||||
connect(m_timer, &QTimer::timeout, this, [this]()
|
||||
{
|
||||
m_mutex = false;
|
||||
});
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// PUBLIC
|
||||
|
||||
void ScriptDialogDragHandler::dragEnterEvent(QDragEnterEvent *e)
|
||||
{
|
||||
if (!m_model->isEditable())
|
||||
{
|
||||
e->setAccepted(false);
|
||||
return;
|
||||
}
|
||||
|
||||
if (e->source() == m_view)
|
||||
{
|
||||
TimelineViewDragHandler::dragEnterEvent(e);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!e->mimeData()->hasFormat(TopicEditorBase::TopicData::mime))
|
||||
{
|
||||
e->ignore();
|
||||
return;
|
||||
}
|
||||
|
||||
QDataStream dataStream(e->mimeData()->data(TopicEditorBase::TopicData::mime));
|
||||
dataStream >> m_dragTopicData;
|
||||
m_dragItem = std::make_unique<TopicItem>(TopicItem(m_dragTopicData));
|
||||
m_isDragEventFromTopicEditor = true;
|
||||
m_dragPos = e->pos();
|
||||
if (m_dragItem->duration() > m_view->zoomFactor())
|
||||
{
|
||||
ZoomFactor zoom = Zoom::ceil(m_dragItem->duration());
|
||||
if (m_dragItem->duration() > m_view->duration())
|
||||
m_view->setDuration(zoom);
|
||||
m_view->setZoomFactor(zoom);
|
||||
}
|
||||
e->acceptProposedAction();
|
||||
}
|
||||
|
||||
void ScriptDialogDragHandler::dragMoveEvent(QDragMoveEvent *e)
|
||||
{
|
||||
if (!m_isDragEventFromTopicEditor)
|
||||
{
|
||||
TimelineViewDragHandler::dragMoveEvent(e);
|
||||
setCanDropTopicTypes();
|
||||
try
|
||||
{
|
||||
adjust();
|
||||
}
|
||||
catch (const QString &errMsg) { qCritical() << LOGFUNCTION <<"zoom and scroll failed:" << errMsg; }
|
||||
catch (...) { qCritical() << LOGFUNCTION <<"zoom and scroll failed:"; }
|
||||
return;
|
||||
}
|
||||
|
||||
m_dragPos = e->pos();
|
||||
setCanDropTopicTypes();
|
||||
m_view->header()->setHoverPosition(m_dragPos.x());
|
||||
e->setAccepted(canDropTopicItemAt(e->pos()));
|
||||
|
||||
try
|
||||
{
|
||||
adjust();
|
||||
}
|
||||
catch (const QString &errMsg) { qCritical() << LOGFUNCTION <<"zoom and scroll failed:" << errMsg; }
|
||||
catch (...) { qCritical() << LOGFUNCTION <<"zoom and scroll failed:"; }
|
||||
|
||||
m_view->viewport()->update();
|
||||
}
|
||||
|
||||
void ScriptDialogDragHandler::dragLeaveEvent(QDragLeaveEvent *e)
|
||||
{
|
||||
if (!m_isDragEventFromTopicEditor)
|
||||
{
|
||||
TimelineViewDragHandler::dragLeaveEvent(e);
|
||||
m_view->setEndTime(std::max(ScriptModel::s_minScriptDuration, m_model->lastTopicEnd() + ScriptModel::s_scriptEndOffset));
|
||||
return;
|
||||
}
|
||||
|
||||
qint64 end = -1;
|
||||
try
|
||||
{
|
||||
end = maxDragItemEnd();
|
||||
}
|
||||
catch (const QString &errMsg) { qCritical() << LOGFUNCTION << "obtaining end time failed:" << errMsg; }
|
||||
catch (...) { qCritical() << LOGFUNCTION << "obtaining end time failed:"; }
|
||||
m_view->setEndTime(std::max(ScriptModel::s_minScriptDuration, m_model->lastTopicEnd() + ScriptModel::s_scriptEndOffset));
|
||||
if (end != -1 && m_view->currentTime() + m_view->zoomFactor() < end)
|
||||
m_view->setCurrentTime(end + scrollOffset() - m_view->zoomFactor());
|
||||
|
||||
m_dragPos = {};
|
||||
m_isDragEventFromTopicEditor = false;
|
||||
m_dragTopicData = TopicEditorBase::TopicData();
|
||||
m_dragItemOffset = 0;
|
||||
}
|
||||
|
||||
void ScriptDialogDragHandler::dropEvent(QDropEvent *e)
|
||||
{
|
||||
if (!m_isDragEventFromTopicEditor)
|
||||
{
|
||||
const QVector<int> dragItemIdsCopy = m_dragItemIds;
|
||||
TimelineViewDragHandler::dropEvent(e);
|
||||
for (int dragItemId : dragItemIdsCopy)
|
||||
{
|
||||
try
|
||||
{
|
||||
TopicItem &topicItem = m_model->topicItem(dragItemId);
|
||||
const TopicTrack &track = static_cast<const TopicTrack &>(m_model->track(topicItem.parentTrackId()));
|
||||
topicItem.topicData().startTime = topicItem.startTime() / 1000LL;
|
||||
topicItem.setChannel(track.internalName());
|
||||
if (track.parentId() != m_model->rootTrack().id())
|
||||
topicItem.setParentChannel(static_cast<const TopicTrack &>(m_model->track(track.parentId())).internalName());
|
||||
}
|
||||
catch (const QString &errMsg) { qCritical() << LOGFUNCTION << "failed for item with id =" << dragItemId << ": " << errMsg; }
|
||||
catch (...) { qCritical() << LOGFUNCTION << "failed for item with id =" << dragItemId; }
|
||||
}
|
||||
m_view->setEndTime(std::max(ScriptModel::s_minScriptDuration, m_model->lastTopicEnd() + ScriptModel::s_scriptEndOffset));
|
||||
return;
|
||||
}
|
||||
|
||||
if (canDropTopicItemAt(e->pos()))
|
||||
{
|
||||
try
|
||||
{
|
||||
const QModelIndex index = m_view->indexAt(e->pos());
|
||||
m_dragTopicData.startTime = m_view->toTime(m_dragPos.x() - m_dragItemOffset) / 1000;
|
||||
m_model->insertTopicItem(index.internalId(), std::move(TopicItem(m_dragTopicData)));
|
||||
emit m_view->timelineModel()->dataChanged(index, index);
|
||||
e->accept();
|
||||
}
|
||||
catch (const QString &errMsg)
|
||||
{
|
||||
qCritical() << errMsg;
|
||||
e->ignore();
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
qDebug() << "drop of item failed";
|
||||
e->ignore();
|
||||
}
|
||||
}
|
||||
else
|
||||
e->ignore();
|
||||
|
||||
qint64 end = -1;
|
||||
try
|
||||
{
|
||||
end = maxDragItemEnd();
|
||||
}
|
||||
catch (const QString &errMsg) { qCritical() << LOGFUNCTION << "obtaining end time failed:" << errMsg; }
|
||||
catch (...) { qCritical() << LOGFUNCTION << "obtaining end time failed:"; }
|
||||
m_view->setEndTime(std::max(ScriptModel::s_minScriptDuration, m_model->lastTopicEnd() + ScriptModel::s_scriptEndOffset));
|
||||
if (end != -1 && m_view->currentTime() + m_view->zoomFactor() < end)
|
||||
m_view->setCurrentTime(end + scrollOffset() - m_view->zoomFactor());
|
||||
|
||||
m_dragPos = {};
|
||||
m_isDragEventFromTopicEditor = false;
|
||||
m_dragTopicData = TopicEditorBase::TopicData();
|
||||
m_dragItemOffset = 0;
|
||||
}
|
||||
|
||||
void ScriptDialogDragHandler::mousePressEvent(QMouseEvent *e)
|
||||
{
|
||||
TimelineViewDragHandler::mousePressEvent(e);
|
||||
addFilterItemsToDragItems();
|
||||
}
|
||||
|
||||
void ScriptDialogDragHandler::mouseMoveEvent(QMouseEvent *e)
|
||||
{
|
||||
TimelineViewDragHandler::mouseMoveEvent(e);
|
||||
|
||||
try
|
||||
{
|
||||
if (e->buttons() == Qt::LeftButton)
|
||||
adjust();
|
||||
}
|
||||
catch (const QString &errMsg) { qCritical() << LOGFUNCTION << "zoom and scroll failed:" << errMsg; }
|
||||
catch (...) { qCritical() << LOGFUNCTION <<"zoom and scroll failed:"; }
|
||||
|
||||
try
|
||||
{
|
||||
QModelIndex index = m_view->indexAt(e->pos());
|
||||
qint64 time = m_view->toTime(e->pos().x());
|
||||
const Track &track = m_model->track(index.internalId());
|
||||
TopicItem &topicItem = m_model->topicItem(track.itemAt(time).id());
|
||||
qint64 replayTime = topicItem.replayTime(time);
|
||||
if (replayTime != -1)
|
||||
{
|
||||
m_view->setCursorTextVisible(true);
|
||||
m_view->setCursorText(DateTime::toString(replayTime, DateTimeFormat::DTG));
|
||||
}
|
||||
else
|
||||
m_view->setCursorTextVisible(false);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
m_view->setCursorTextVisible(false);
|
||||
}
|
||||
}
|
||||
|
||||
void ScriptDialogDragHandler::mouseReleaseEvent(QMouseEvent *e)
|
||||
{
|
||||
if (m_timer->isActive())
|
||||
m_timer->stop();
|
||||
m_mutex = false;
|
||||
|
||||
qint64 end = -1;
|
||||
try
|
||||
{
|
||||
end = maxDragItemEnd();
|
||||
}
|
||||
catch (const QString &errMsg) { qCritical() << LOGFUNCTION << "obtaining end time failed:" << errMsg; }
|
||||
catch (...) { qCritical() << LOGFUNCTION << "obtaining end time failed:"; }
|
||||
|
||||
const QVector<int> dragIds = m_dragItemIds;
|
||||
TimelineViewDragHandler::mouseReleaseEvent(e);
|
||||
for (int dragId : dragIds)
|
||||
{
|
||||
try
|
||||
{
|
||||
TopicItem &topicItem = m_model->topicItem(dragId);
|
||||
topicItem.topicData().startTime = topicItem.startTime() / 1000LL;
|
||||
}
|
||||
catch (const QString &errMsg) { qCritical() << LOGFUNCTION << "adjusting topic data failed:" << errMsg; }
|
||||
catch (...) { qCritical() << LOGFUNCTION << "adjusting topic data failed"; }
|
||||
}
|
||||
|
||||
m_view->setEndTime(std::max(ScriptModel::s_minScriptDuration, m_model->lastTopicEnd() + ScriptModel::s_scriptEndOffset));
|
||||
if (end != -1 && m_view->currentTime() + m_view->zoomFactor() < end)
|
||||
m_view->setCurrentTime(end + scrollOffset() - m_view->zoomFactor());
|
||||
}
|
||||
|
||||
|
||||
int ScriptDialogDragHandler::deltaX() const
|
||||
{
|
||||
if (!m_isDragEventFromTopicEditor)
|
||||
return TimelineViewDragHandler::deltaX();
|
||||
|
||||
int xCursor = m_dragPos.x();
|
||||
qint64 t = m_view->toTime(xCursor);
|
||||
t -= (t % m_view->timelineModel()->snapStep());
|
||||
int x = m_view->toPixel(t);
|
||||
return x - xCursor;
|
||||
}
|
||||
|
||||
int ScriptDialogDragHandler::deltaY() const
|
||||
{
|
||||
Q_ASSERT(m_view->itemDelegate());
|
||||
return m_isDragEventFromTopicEditor ? m_view->itemDelegate()->sizeHint().height() : TimelineViewDragHandler::deltaY();
|
||||
}
|
||||
|
||||
|
||||
int ScriptDialogDragHandler::dragItemFromTopicEditorWidth() const
|
||||
{
|
||||
int xStart = m_view->toPixel(static_cast<qint64>(m_dragTopicData.startTime) * 1000);
|
||||
int xEnd = m_view->toPixel(static_cast<qint64>(m_dragTopicData.startTime + m_dragTopicData.duration) * 1000);
|
||||
return xEnd - xStart;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// PRIVATE
|
||||
|
||||
void ScriptDialogDragHandler::moveItemsLeft(const QVector<int> &, int dt)
|
||||
{
|
||||
m_dragItemIds = m_view->selectedItemIds();
|
||||
addFilterItemsToDragItems();
|
||||
TimelineViewDragHandler::moveItemsLeft(m_dragItemIds, dt);
|
||||
try
|
||||
{
|
||||
auto iter = std::min_element(m_dragItemIds.begin(), m_dragItemIds.end(), [this](int leftItemId, int rightItemId)
|
||||
{
|
||||
const Item &leftItem = m_model->item(leftItemId);
|
||||
const Item &rightItem = m_model->item(rightItemId);
|
||||
return leftItem.startTime() + leftItem.duration() < rightItem.startTime() + rightItem.duration();
|
||||
});
|
||||
const Item &startItem = m_model->item(*iter);
|
||||
adjustLeft(std::max(m_view->startTime(), startItem.startTime() - scrollOffset()));
|
||||
}
|
||||
catch (...) {}
|
||||
m_dragItemIds.clear();
|
||||
}
|
||||
|
||||
void ScriptDialogDragHandler::moveItemsRight(const QVector<int> &, int dt)
|
||||
{
|
||||
m_dragItemIds = m_view->selectedItemIds();
|
||||
addFilterItemsToDragItems();
|
||||
TimelineViewDragHandler::moveItemsRight(m_dragItemIds, dt);
|
||||
try
|
||||
{
|
||||
auto iter = std::max_element(m_dragItemIds.begin(), m_dragItemIds.end(), [this](int leftItemId, int rightItemId)
|
||||
{
|
||||
const Item &leftItem = m_model->item(leftItemId);
|
||||
const Item &rightItem = m_model->item(rightItemId);
|
||||
return leftItem.startTime() + leftItem.duration() < rightItem.startTime() + rightItem.duration();
|
||||
});
|
||||
const Item &endItem = m_model->item(*iter);
|
||||
adjustRight(endItem.startTime() + endItem.duration() + scrollOffset());
|
||||
}
|
||||
catch (...) {}
|
||||
m_dragItemIds.clear();
|
||||
}
|
||||
|
||||
|
||||
int ScriptDialogDragHandler::scrollOffset() const
|
||||
{
|
||||
return static_cast<qint64>(m_view->zoomFactor()) * 5 / 100;
|
||||
}
|
||||
|
||||
qint64 ScriptDialogDragHandler::minDragItemStart() const noexcept(false)
|
||||
{
|
||||
qint64 start = m_view->endTime();
|
||||
if (!m_dragItemIds.isEmpty())
|
||||
{
|
||||
auto iter = std::min_element(m_dragItemIds.begin(), m_dragItemIds.end(), [this](int leftItemId, int rightItemId)
|
||||
{
|
||||
const Item &leftItem = m_model->item(leftItemId);
|
||||
const Item &rightItem = m_model->item(rightItemId);
|
||||
return leftItem.startTime() + leftItem.duration() < rightItem.startTime() + rightItem.duration();
|
||||
});
|
||||
const Item &startItem = m_model->item(*iter);
|
||||
start = std::max(m_view->startTime(), startItem.startTime() + deltaTime());
|
||||
}
|
||||
else if (m_isDragEventFromTopicEditor)
|
||||
start = m_view->toTime(m_dragPos.x());
|
||||
return start;
|
||||
}
|
||||
|
||||
qint64 ScriptDialogDragHandler::maxDragItemEnd() const noexcept(false)
|
||||
{
|
||||
qint64 end = m_view->startTime();
|
||||
if (!m_dragItemIds.isEmpty())
|
||||
{
|
||||
auto iter = std::max_element(m_dragItemIds.begin(), m_dragItemIds.end(), [this](int leftItemId, int rightItemId)
|
||||
{
|
||||
const Item &leftItem = m_model->item(leftItemId);
|
||||
const Item &rightItem = m_model->item(rightItemId);
|
||||
return leftItem.startTime() + leftItem.duration() < rightItem.startTime() + rightItem.duration();
|
||||
});
|
||||
const Item &endItem = m_model->item(*iter);
|
||||
end = endItem.startTime() + endItem.duration() + deltaTime();
|
||||
}
|
||||
else if (m_isDragEventFromTopicEditor)
|
||||
end = m_view->toTime(m_dragPos.x()) + static_cast<qint64>(m_dragTopicData.duration) * 1000LL;
|
||||
return end;
|
||||
}
|
||||
|
||||
void ScriptDialogDragHandler::adjust() noexcept(false)
|
||||
{
|
||||
qint64 start = std::max(m_view->startTime(), minDragItemStart() - scrollOffset());
|
||||
qint64 end = maxDragItemEnd() + scrollOffset();
|
||||
if (end > m_view->currentTime() + m_view->zoomFactor())
|
||||
{
|
||||
qDebug() << "adjusting right";
|
||||
adjustRight(end);
|
||||
}
|
||||
else if (start < m_view->currentTime())
|
||||
{
|
||||
qDebug() << "adjusting left";
|
||||
adjustLeft(start);
|
||||
}
|
||||
}
|
||||
|
||||
void ScriptDialogDragHandler::adjustLeft(qint64 start) noexcept(false)
|
||||
{
|
||||
if (start >= m_view->currentTime())
|
||||
return;
|
||||
|
||||
ZoomFactor newZoom = Zoom::increment(m_view->zoomFactor());
|
||||
if (m_view->zoomFactor() < newZoom && newZoom <= m_view->upperZoomFactor())
|
||||
{
|
||||
m_view->setCurrentTime(m_view->currentTime() - (newZoom - m_view->zoomFactor()));
|
||||
m_view->setZoomFactor(newZoom);
|
||||
return;
|
||||
}
|
||||
|
||||
m_view->setCurrentTime(m_view->currentTime() - scrollOffset());
|
||||
}
|
||||
|
||||
void ScriptDialogDragHandler::adjustRight(qint64 end) noexcept(false)
|
||||
{
|
||||
if (end <= m_view->currentTime() + m_view->zoomFactor())
|
||||
return;
|
||||
|
||||
ZoomFactor newZoom = Zoom::increment(m_view->zoomFactor());
|
||||
if (m_view->zoomFactor() < newZoom && newZoom <= m_view->maximumZoomFactor())
|
||||
{
|
||||
if (m_view->currentTime() + newZoom > m_view->zoomFactor() && !m_mutex)
|
||||
{
|
||||
m_mutex = true;
|
||||
m_timer->start(1000);
|
||||
m_view->setEndTime(m_view->currentTime() + newZoom);
|
||||
}
|
||||
m_view->setZoomFactor(newZoom);
|
||||
return;
|
||||
}
|
||||
|
||||
m_view->setEndTime(std::max(m_view->endTime(), end));
|
||||
m_view->setCurrentTime(m_view->endTime() - m_view->zoomFactor());
|
||||
}
|
||||
|
||||
|
||||
void ScriptDialogDragHandler::addFilterItemsToDragItems()
|
||||
{
|
||||
for (const int &itemId : qAsConst(m_dragItemIds))
|
||||
{
|
||||
try
|
||||
{
|
||||
const Item &item = m_model->item(itemId);
|
||||
const Track &track = m_model->track(item.parentTrackId());
|
||||
if (track.hasTracks())
|
||||
{
|
||||
for (const TrackPtr &trackPtr : track.tracks())
|
||||
{
|
||||
const QVector<int> itemIds = trackPtr->itemIdsBetween(item.startTime(), item.startTime() + item.duration(), false, true);
|
||||
for (const int &id : qAsConst(itemIds))
|
||||
if (!m_dragItemIds.contains(id))
|
||||
m_dragItemIds.append(id);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (...) {}
|
||||
}
|
||||
}
|
||||
|
||||
void ScriptDialogDragHandler::setCanDropTopicTypes()
|
||||
{
|
||||
m_canDropTopicTypes = true;
|
||||
for (const int &itemId : qAsConst(m_dragItemIds))
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!m_model->canDropTopicType(m_model->topicItem(itemId).topicType(), dragItemTrackId(m_model->item(itemId))))
|
||||
{
|
||||
m_canDropTopicTypes = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
catch (...) {}
|
||||
}
|
||||
}
|
||||
|
||||
bool ScriptDialogDragHandler::canDropTopicItemAt(const QPoint &point) const
|
||||
{
|
||||
if (!m_isDragEventFromTopicEditor)
|
||||
return TimelineViewDragHandler::canDragItemsTo(point);
|
||||
|
||||
const QModelIndex index = m_view->indexAt(point);
|
||||
if (!index.isValid() || index.column() == Section::eActuator)
|
||||
return false;
|
||||
|
||||
try
|
||||
{
|
||||
qint64 start = m_model->snapTime(m_view->toTime(point.x() - m_dragItemOffset));
|
||||
if (m_model->track(index.internalId()).isItemsBetween(start, start + m_dragItem->duration(), QVector<int>(), true))
|
||||
return false;
|
||||
return m_model->canDropItem(*m_dragItem.get(), index.internalId(), start);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
Q_UNREACHABLE();
|
||||
}
|
||||
|
||||
} // namespace PresentationManagement
|
||||
Executable
+71
@@ -0,0 +1,71 @@
|
||||
#pragma once
|
||||
|
||||
#include "pre_topic_item.h"
|
||||
#include "pre_utils.h"
|
||||
|
||||
#include <LtsTimeline/timeline_view_drag_handler.h>
|
||||
|
||||
|
||||
namespace PresentationManagement
|
||||
{
|
||||
|
||||
class ScriptDelegate;
|
||||
class ScriptModel;
|
||||
|
||||
|
||||
class ScriptDialogDragHandler : public QObject, public LtsTimeline::TimelineViewDragHandler
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
friend class ScriptDelegate;
|
||||
|
||||
public:
|
||||
explicit ScriptDialogDragHandler(LtsTimeline::TimelineView *view);
|
||||
|
||||
void dragEnterEvent(QDragEnterEvent *e) override;
|
||||
void dragMoveEvent(QDragMoveEvent *e) override;
|
||||
void dragLeaveEvent(QDragLeaveEvent *e) override;
|
||||
void dropEvent(QDropEvent *e) override;
|
||||
void mousePressEvent(QMouseEvent *e) override;
|
||||
void mouseMoveEvent(QMouseEvent *e) override;
|
||||
void mouseReleaseEvent(QMouseEvent *e) override;
|
||||
|
||||
int deltaX() const override;
|
||||
int deltaY() const override;
|
||||
|
||||
int dragItemFromTopicEditorWidth() const;
|
||||
|
||||
const QVector<int> &dragItemIds() const { return m_dragItemIds; }
|
||||
|
||||
bool isDragEventFromTopicEditor() const { return m_isDragEventFromTopicEditor; }
|
||||
|
||||
private:
|
||||
void moveItemsLeft(const QVector<int> &, int dt) override;
|
||||
void moveItemsRight(const QVector<int> &, int dt) override;
|
||||
|
||||
int scrollOffset() const;
|
||||
qint64 minDragItemStart() const noexcept(false);
|
||||
qint64 maxDragItemEnd() const noexcept(false);
|
||||
void adjust() noexcept(false);
|
||||
void adjustLeft(qint64 start) noexcept(false);
|
||||
void adjustRight(qint64 end) noexcept(false);
|
||||
|
||||
void addFilterItemsToDragItems();
|
||||
void setCanDropTopicTypes();
|
||||
bool canDropTopicItemAt(const QPoint &point) const;
|
||||
|
||||
private:
|
||||
ScriptModel *m_model{nullptr};
|
||||
|
||||
TopicItemPtr m_dragItem;
|
||||
TopicEditorBase::TopicData m_dragTopicData;
|
||||
int m_dragItemOffset{0};
|
||||
bool m_isDragEventFromTopicEditor{false};
|
||||
bool m_canDropTopicTypes{true};
|
||||
|
||||
bool m_mutex{false};
|
||||
QTimer *m_timer{nullptr};
|
||||
|
||||
};
|
||||
|
||||
} // namespace PresentationManagement
|
||||
+136
@@ -0,0 +1,136 @@
|
||||
#include "pre_script_dialog_resize_handler.h"
|
||||
#include "pre_script_dialog.h"
|
||||
#include "pre_script_model.h"
|
||||
#include "pre_topic_item.h"
|
||||
|
||||
#include <LtsTimeline/timeline_view.h>
|
||||
|
||||
#include <QDebug>
|
||||
#include <QTimer>
|
||||
|
||||
|
||||
namespace PresentationManagement
|
||||
{
|
||||
|
||||
ScriptDialogResizeHandler::ScriptDialogResizeHandler(LtsTimeline::TimelineView *view)
|
||||
: LtsTimeline::TimelineViewResizeHandler(view)
|
||||
, m_timer(new QTimer(m_view))
|
||||
{
|
||||
m_model = qobject_cast<ScriptModel *>(m_view->model());
|
||||
Q_ASSERT(m_model);
|
||||
|
||||
m_timer->setSingleShot(true);
|
||||
connect(m_timer, &QTimer::timeout, this, [this]()
|
||||
{
|
||||
m_mutex = false;
|
||||
});
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// PUBLIC
|
||||
|
||||
void ScriptDialogResizeHandler::mouseMoveEvent(QMouseEvent *e)
|
||||
{
|
||||
LtsTimeline::TimelineViewResizeHandler::mouseMoveEvent(e);
|
||||
if (m_currentItemId == -1)
|
||||
return;
|
||||
|
||||
try
|
||||
{
|
||||
TopicItem &topicItem = m_model->topicItem(m_currentItemId);
|
||||
topicItem.topicData().duration = topicItem.duration() / 1000;
|
||||
emit m_model->topicItemChanged(topicItem.id());
|
||||
}
|
||||
catch (const QString &errMsg) { qCritical() << errMsg; }
|
||||
catch (...) { qCritical() << "could not update topic item with id =" << m_currentItemId; }
|
||||
|
||||
if (e->buttons() != Qt::LeftButton)
|
||||
return;
|
||||
|
||||
try
|
||||
{
|
||||
const LtsTimeline::Item &item = m_model->item(m_currentItemId);
|
||||
if (m_resizePos == ResizePosition::eStart)
|
||||
{
|
||||
if (item.startTime() < m_view->currentTime() + scrollOffset() && m_view->startTime() < m_view->currentTime())
|
||||
adjustLeft();
|
||||
}
|
||||
else if (m_resizePos == ResizePosition::eEnd)
|
||||
{
|
||||
if (item.startTime() + item.duration() > m_view->currentTime() + m_view->zoomFactor() - scrollOffset())
|
||||
adjustRight(item);
|
||||
}
|
||||
}
|
||||
catch (const QString &errMsg) { qCritical() << LOGFUNCTION << "adjusting zoom failed:" << errMsg; }
|
||||
catch (...) { qCritical() << LOGFUNCTION << "adjusting zoom failed"; }
|
||||
}
|
||||
|
||||
void ScriptDialogResizeHandler::mouseReleaseEvent(QMouseEvent *e)
|
||||
{
|
||||
if (m_timer->isActive())
|
||||
m_timer->stop();
|
||||
m_mutex = false;
|
||||
|
||||
try
|
||||
{
|
||||
m_view->setEndTime(std::max(ScriptModel::s_minScriptDuration,
|
||||
static_cast<ScriptModel *>(m_view->model())->lastTopicEnd() + ScriptModel::s_scriptEndOffset));
|
||||
const LtsTimeline::Item &item = m_model->item(m_currentItemId);
|
||||
qint64 end = item.startTime() + item.duration() + scrollOffset();
|
||||
if (end > m_view->currentTime() + m_view->zoomFactor())
|
||||
{
|
||||
ZoomFactor newZoom = Zoom::increment(m_view->zoomFactor());
|
||||
if (newZoom < m_view->maximumZoomFactor() && newZoom <= m_view->duration())
|
||||
m_view->setZoomFactor(newZoom);
|
||||
else
|
||||
m_view->setCurrentTime(end - m_view->zoomFactor());
|
||||
}
|
||||
}
|
||||
catch (const QString &errMsg) { qCritical() << LOGFUNCTION << "adjusting zoom failed:" << errMsg; }
|
||||
catch (...) { qCritical() << LOGFUNCTION << "adjusting zoom failed";}
|
||||
|
||||
TimelineViewResizeHandler::mouseReleaseEvent(e);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// PRIVATE
|
||||
|
||||
int ScriptDialogResizeHandler::scrollOffset() const
|
||||
{
|
||||
return m_view->zoomFactor() * 5 / 100;
|
||||
}
|
||||
|
||||
void ScriptDialogResizeHandler::adjustLeft()
|
||||
{
|
||||
ZoomFactor newZoom = Zoom::increment(m_view->zoomFactor());
|
||||
if (m_view->zoomFactor() < newZoom && newZoom <= m_view->maximumZoomFactor())
|
||||
{
|
||||
m_view->setCurrentTime(m_view->currentTime() - (newZoom - m_view->zoomFactor()));
|
||||
m_view->setZoomFactor(newZoom);
|
||||
return;
|
||||
}
|
||||
|
||||
m_view->setCurrentTime(m_view->currentTime() - m_view->zoomFactor() * 2 / 100);
|
||||
}
|
||||
|
||||
void ScriptDialogResizeHandler::adjustRight(const LtsTimeline::Item &item)
|
||||
{
|
||||
ZoomFactor newZoom = Zoom::increment(m_view->zoomFactor());
|
||||
if (m_view->zoomFactor() < newZoom && newZoom <= m_view->maximumZoomFactor())
|
||||
{
|
||||
if (m_view->currentTime() + newZoom > m_view->endTime() && !m_mutex)
|
||||
{
|
||||
m_mutex = true;
|
||||
m_timer->start(1000);
|
||||
m_view->setEndTime(std::max(ScriptModel::s_minScriptDuration, m_view->currentTime() + newZoom));
|
||||
}
|
||||
m_view->setZoomFactor(newZoom);
|
||||
return;
|
||||
}
|
||||
|
||||
m_view->setEndTime(std::max(std::max(ScriptModel::s_minScriptDuration, m_view->endTime()),
|
||||
item.startTime() + item.duration() + ScriptModel::s_scriptEndOffset));
|
||||
m_view->setCurrentTime(m_view->endTime() - m_view->zoomFactor());
|
||||
}
|
||||
|
||||
} // namespace PresentationManagement
|
||||
+38
@@ -0,0 +1,38 @@
|
||||
#pragma once
|
||||
|
||||
#include <LtsTimeline/timeline_view_resize_handler.h>
|
||||
|
||||
|
||||
namespace LtsTimeline { class Item; }
|
||||
|
||||
|
||||
namespace PresentationManagement
|
||||
{
|
||||
|
||||
class ScriptModel;
|
||||
|
||||
|
||||
class ScriptDialogResizeHandler : public QObject, public LtsTimeline::TimelineViewResizeHandler
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit ScriptDialogResizeHandler(LtsTimeline::TimelineView *view);
|
||||
|
||||
void mouseMoveEvent(QMouseEvent *e) override;
|
||||
void mouseReleaseEvent(QMouseEvent *e) override;
|
||||
|
||||
private:
|
||||
int scrollOffset() const;
|
||||
void adjustLeft();
|
||||
void adjustRight(const LtsTimeline::Item &item);
|
||||
|
||||
private:
|
||||
ScriptModel *m_model{nullptr};
|
||||
|
||||
QTimer *m_timer{nullptr};
|
||||
bool m_mutex{false};
|
||||
|
||||
};
|
||||
|
||||
} // namespace PresentationManagement
|
||||
+73
@@ -0,0 +1,73 @@
|
||||
#include "pre_script_dialog_select_handler.h"
|
||||
#include "pre_script_model.h"
|
||||
|
||||
#include <QToolTip>
|
||||
|
||||
|
||||
#include <QDebug>
|
||||
|
||||
|
||||
namespace PresentationManagement
|
||||
{
|
||||
|
||||
ScriptDialogSelectHandler::ScriptDialogSelectHandler(LtsTimeline::TimelineView *view)
|
||||
: TimelineViewSelectHandler(view)
|
||||
{}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// PUBLC
|
||||
|
||||
void ScriptDialogSelectHandler::mouseMoveEvent(QMouseEvent *e)
|
||||
{
|
||||
LtsTimeline::TimelineViewSelectHandler::mouseMoveEvent(e);
|
||||
|
||||
// hover text
|
||||
ScriptModel *model = static_cast<ScriptModel *>(m_view->timelineModel());
|
||||
if (!model)
|
||||
return;
|
||||
|
||||
QModelIndex index = m_view->indexAt(e->pos());
|
||||
if (!index.isValid() || index.column() == LtsTimeline::Section::eActuator)
|
||||
{
|
||||
m_view->setCursorTextVisible(false);
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
qint64 time = m_view->toTime(e->pos().x());
|
||||
const LtsTimeline::Track &track = model->track(index.internalId());
|
||||
TopicItem &topicItem = model->topicItem(track.itemAt(time).id());
|
||||
qint64 replayTime = topicItem.replayTime(time);
|
||||
if (replayTime != -1)
|
||||
{
|
||||
m_view->setCursorTextVisible(true);
|
||||
m_view->setCursorText(LtsTimeline::DateTime::toString(replayTime, LtsTimeline::DateTimeFormat::DTG));
|
||||
}
|
||||
else
|
||||
m_view->setCursorTextVisible(false);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
m_view->setCursorTextVisible(false);
|
||||
}
|
||||
|
||||
// tooltip
|
||||
try
|
||||
{
|
||||
const LtsTimeline::Track &track = m_view->timelineModel()->track(index.internalId());
|
||||
const LtsTimeline::Item &item = track.itemAt(m_view->toTime(e->pos().x()));
|
||||
m_view->setToolTip(LtsTimeline::DateTime::toString(item.startTime(), LtsTimeline::DateTimeFormat::TimeOnly));
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
if (!m_view->toolTip().isEmpty())
|
||||
{
|
||||
QToolTip::hideText();
|
||||
m_view->setToolTip({});
|
||||
m_view->update();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace PresentationManagement
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
#pragma once
|
||||
|
||||
#include <LtsTimeline/timeline_view_selection_handler.h>
|
||||
|
||||
|
||||
namespace PresentationManagement
|
||||
{
|
||||
|
||||
class ScriptDialogSelectHandler : public LtsTimeline::TimelineViewSelectHandler
|
||||
{
|
||||
|
||||
public:
|
||||
explicit ScriptDialogSelectHandler(LtsTimeline::TimelineView *view);
|
||||
|
||||
void mouseMoveEvent(QMouseEvent *e) override;
|
||||
|
||||
};
|
||||
|
||||
} // namespace PresentationManagement
|
||||
+1561
File diff suppressed because it is too large.
Load diff
+146
@@ -0,0 +1,146 @@
|
||||
#pragma once
|
||||
|
||||
#include "pre_topic_item.h"
|
||||
#include "pre_topic_track.h"
|
||||
|
||||
#include <LtsTimeline/timeline_model.h>
|
||||
|
||||
|
||||
namespace LtsSession { class LtsSession; }
|
||||
|
||||
using namespace LtsTimeline;
|
||||
using namespace TopicEditorBase;
|
||||
|
||||
|
||||
namespace PresentationManagement
|
||||
{
|
||||
|
||||
class PresentationContent;
|
||||
class ScriptTimelineDialog;
|
||||
|
||||
|
||||
class ScriptModel : public LtsTimeline::TimelineModel
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
enum class PasteTestResult { No = 0, Yes, YesWithShift };
|
||||
|
||||
static bool isReplayTopic(TopicType topicType);
|
||||
static bool isScreenTopic(TopicType topicType);
|
||||
static bool isFilterTopic(TopicType topicType);
|
||||
static bool hasReplayTime(TopicType topicType);
|
||||
|
||||
static const qint64 s_minScriptDuration;
|
||||
static const int s_scriptEndOffset;
|
||||
|
||||
explicit ScriptModel(LtsSession::LtsSession *session, ScriptTimelineDialog *dialog, QObject *parent = nullptr);
|
||||
~ScriptModel() = default;
|
||||
|
||||
void clear();
|
||||
|
||||
int addItem(int _trackId, TopicItem &&_topicItem) noexcept(false);
|
||||
int addItem(const QString &trackName, TopicItem &&_topicItem, qint64 offset = 0) noexcept(false);
|
||||
int nextUniqueId() { return m_currentItemId + 1; }
|
||||
|
||||
TopicItem &topicItem(int _topicItemId) noexcept(false);
|
||||
const TopicItem &topicItem(int _topicItemId) const noexcept(false);
|
||||
std::vector<TopicItem> topicItems() const;
|
||||
std::vector<TopicItem> topicItemsByTrackId(int trackId) const;
|
||||
QVector<int> topicItemIds() const { return mainTopicItemIds() + filterTopicItemIds(); }
|
||||
|
||||
QVector<int> mainTopicItemIds() const;
|
||||
int mainTopicItemId(const Track &_track, qint64 start, qint64 end) const noexcept(false);
|
||||
int mainTopicItemId(const Track &_track, const TopicItem &_topicItem) const noexcept(false)
|
||||
{
|
||||
return mainTopicItemId(_track, _topicItem.startTime(), _topicItem.startTime() + _topicItem.duration());
|
||||
}
|
||||
int mainTopicItemId(const TopicItem &_topicItem) const noexcept(false);
|
||||
int mainTopicItemId(int _topicItemId) const noexcept(false)
|
||||
{
|
||||
return mainTopicItemId(topicItem(_topicItemId));
|
||||
}
|
||||
|
||||
QVector<int> filterTopicItemIds() const;
|
||||
QVector<int> filterTopicItemIds(int _topicItemId) const;
|
||||
|
||||
qint64 firstTopicStart() const;
|
||||
qint64 lastTopicEnd() const;
|
||||
|
||||
TopicTrack &audioTrack() noexcept(false) { return static_cast<TopicTrack &>(track(m_audioTrackId)); }
|
||||
const TopicTrack &audioTrack() const noexcept(false) { return static_cast<const TopicTrack &>(track(m_audioTrackId)); }
|
||||
TopicTrack &replayTrack() noexcept(false) { return static_cast<TopicTrack &>(track(m_replayTrackId)); }
|
||||
const TopicTrack &replayTrack() const noexcept(false) { return static_cast<const TopicTrack &>(track(m_replayTrackId)); }
|
||||
TopicTrack &screen1Track() noexcept(false) { return static_cast<TopicTrack &>(track(m_screen1TrackId)); }
|
||||
const TopicTrack &screen1Track() const noexcept(false) { return static_cast<const TopicTrack &>(track(m_screen1TrackId)); }
|
||||
TopicTrack &screen2Track() noexcept(false) { return static_cast<TopicTrack &>(track(m_screen2TrackId)); }
|
||||
const TopicTrack &screen2Track() const noexcept(false) { return static_cast<const TopicTrack &>(track(m_screen2TrackId)); }
|
||||
|
||||
int channelToId(const QString &channel) const;
|
||||
int audioTrackId() const { return m_audioTrackId; }
|
||||
int replayTrackId() const { return m_replayTrackId; }
|
||||
int screen1TrackId() const { return m_screen1TrackId; }
|
||||
int screen2TrackId() const { return m_screen2TrackId; }
|
||||
|
||||
bool isMainTrack(int _trackId) const;
|
||||
bool isScreenTrack(int _trackId) const;
|
||||
bool isFilterTrack(int _trackId) const;
|
||||
|
||||
bool isReplayTopic(const TopicItem &_topicItem) const { return isReplayTopic(_topicItem.topicType()); }
|
||||
bool isScreenTopic(const TopicItem &_topicItem) const { return isScreenTopic(_topicItem.topicType()); }
|
||||
bool isFilterTopic(const TopicItem &_topicItem) const { return isFilterTopic(_topicItem.topicType()); }
|
||||
|
||||
// bool canBeMerged(const TopicItem &_firstTopicItem, const TopicItem &_secondTopicItem, const TopicItem &_thirdTopicItem) const;
|
||||
// bool canBeSplit(const TopicItem &_topicItem) const;
|
||||
// void mergeTopicItems(int _firstTopicItemId, int _secondTopicItemId, int _thirdTopicItemId) noexcept(false);
|
||||
// void splitTopicItem(int _topicItemId) noexcept(false);
|
||||
|
||||
bool import(const QVector<PresentationContent> &contents) noexcept(false);
|
||||
PresentationContent topicItemPresentationContent(int topicItemId) noexcept(false);
|
||||
|
||||
void insertTopicItem(int _trackId, TopicItem &&__topicItem);
|
||||
|
||||
void moveItemToTrack(int _itemId, int _trackId, qint64 time) noexcept(false) override;
|
||||
void removeItem(int _itemId) noexcept(false) override;
|
||||
void setItemStartTime(Track &_track, Item &_item, qint64 newStart) override;
|
||||
void setItemDuration(Track &_track, Item &_item, int duration) override;
|
||||
|
||||
bool canDropItem(const Item &_item, int _trackId, qint64 start) const override;
|
||||
bool canMoveItem(const Item &_item, qint64 start) const override;
|
||||
bool canResizeItem(const Item &_item, qint64 start, int duration) const override;
|
||||
|
||||
void copyToClipboard(const QVector<int> &_itemIds) noexcept(false) override;
|
||||
void cutToClipboard(const QVector<int> &_itemIds) noexcept(false) override;
|
||||
void pasteFromClipboard(qint64 time) noexcept(false) override;
|
||||
PasteTestResult canPasteFromClipboard(qint64 time) const;
|
||||
|
||||
bool canDropTopicType(TopicType _topicType, int _trackId) const;
|
||||
|
||||
private:
|
||||
bool isTopicItemBlocked(const TopicItem &_topicItem, const TopicTrack &_topicTrack, qint64 start, int duration) const;
|
||||
|
||||
void getActualFilterTopicRange(int parentTrackId, TopicItem &_topicItem) const noexcept(false);
|
||||
|
||||
public slots:
|
||||
void onInsertTrack(const QModelIndex &idx) override;
|
||||
void onRemoveTrack(const QModelIndex &idx) override;
|
||||
|
||||
signals:
|
||||
void topicItemChanged(int);
|
||||
void pasteFailed();
|
||||
|
||||
private:
|
||||
LtsSession::LtsSession *m_session{nullptr};
|
||||
|
||||
ScriptTimelineDialog *m_dialog{nullptr};
|
||||
|
||||
int m_audioTrackId{-1};
|
||||
int m_replayTrackId{-1};
|
||||
int m_screen1TrackId{-1};
|
||||
int m_screen2TrackId{-1};
|
||||
|
||||
NGL::INGLLogger &m_logger;
|
||||
|
||||
};
|
||||
|
||||
} // namespace PresentationManagement
|
||||
+341
@@ -0,0 +1,341 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* GUI Plugin for Script Editor
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*
|
||||
* Created by Mike Wille, SLSE, 2017-03-17
|
||||
*/
|
||||
|
||||
#include "pre_script_timeline_gui_plugin.h"
|
||||
#include "pre_script_dialog.h"
|
||||
#include "pre_script_model.h"
|
||||
|
||||
#include <Common/TopicEditorBase/topic_editor_base.h>
|
||||
#include <Plugins/OperatorManagement/opm_data_plugin_interface.h>
|
||||
#include <Plugins/PresentationManagement/Gui/Script/Common/ScriptChooser/script_chooser.h>
|
||||
#include <Plugins/PresentationManagement/Gui/Common/pre_edit_dialog.h>
|
||||
#include <LtsWidgets/lts_base_layout_widget.h>
|
||||
#include <LtsSession/lts_session.h>
|
||||
#include <LtsSession/lts_session_manager.h>
|
||||
#include <LtsSession/lts_session_data.h>
|
||||
#include <LtsWidgets/lts_background_widget.h>
|
||||
#include <LtsWidgets/lts_message_dialog.h>
|
||||
#include <LtsScriptTimeline/track_entry.h>
|
||||
#include <LtsScriptTimeline/temporary_pointer_vector.h>
|
||||
#include <TopicEditorBase/topic_editor_utils.h>
|
||||
|
||||
// Control- & Widget-Ifcs:
|
||||
#include <Plugins/SituationReplay/srp_gui_plugin_interface.h>
|
||||
#include <Plugins/SituationMapPlugin/situation_map_gui_plugin_interface.h>
|
||||
#include <Plugins/FileManagement/flm_explorer_gui_plugin_interface.h>
|
||||
#include <Plugins/BuildingViewer/bdv_viewer_gui_plugin_interface.h>
|
||||
#include <Plugins/AudioVideoManagement/avm_menu_edit_gui_plugin_interface.h>
|
||||
#include <Plugins/SituationMapPlugin/situation_map_script_filter_gui_plugin_interface.h>
|
||||
#include <Plugins/MarkerManagement/mrk_gui_plugin_interface.h>
|
||||
#include <Plugins/Evaluations/evl_gui_plugin_interface.h>
|
||||
#include <Plugins/ReportManagement/rep_gui_plugin_interface.h>
|
||||
#include <Plugins/PlanOverlays/plan_overlays_plugin_interface.h>
|
||||
|
||||
#include <Services/PresentationManagement/pre_operator_rights.h>
|
||||
#include <Services/PresentationManagement/pre_dtc.h>
|
||||
|
||||
#include <stdlib.h> // for abort
|
||||
|
||||
#include <QDir>
|
||||
#include <QJsonParseError>
|
||||
#include <QJsonDocument>
|
||||
#include <QProgressDialog>
|
||||
#include <QTimer>
|
||||
#include <QFileDialog>
|
||||
#include <QVBoxLayout>
|
||||
#include <QDateTime>
|
||||
#include <QDebug>
|
||||
|
||||
|
||||
namespace PresentationManagement
|
||||
{
|
||||
|
||||
std::shared_ptr<GuiPluginBase::Interface> GuiPlugin::createGuiInterface(LtsSession::LtsSession *session)
|
||||
{
|
||||
return std::make_shared<InterfaceImpl>(session);
|
||||
}
|
||||
|
||||
|
||||
InterfaceImpl::InterfaceImpl(LtsSession::LtsSession *session)
|
||||
: GuiPluginBase::Interface(session, getLogger("Plugins.Gui.Pre.ScriptTimeline"))
|
||||
, m_preDtc(nullptr)
|
||||
, m_preFtc(nullptr)
|
||||
, m_opmDtc(nullptr)
|
||||
, m_srpIfc(nullptr)
|
||||
, m_scriptId(0) // invalid
|
||||
, m_scriptDialog(nullptr)
|
||||
, m_requestHelper(new LtsUtils::RequestHelper(this))
|
||||
{
|
||||
connect(this, &InterfaceImpl::success, m_session, &LtsSession::LtsSession::slotExecuteNextPayload, Qt::QueuedConnection);
|
||||
}
|
||||
|
||||
|
||||
QVector<LtsWidgets::PluginData> InterfaceImpl::getActions()
|
||||
{
|
||||
QVector<LtsWidgets::PluginData> ret;
|
||||
|
||||
{
|
||||
LtsWidgets::PluginData data;
|
||||
data.menuGroup = menuGroup();
|
||||
data.identifier = QStringLiteral("PresentationManagement.ScriptTimelineDialog");
|
||||
data.menuText = tr("Show Script Timeline Editor");
|
||||
if (getFlags().testFlag(LtsAppDescriptor::PluginInfo::Flag::MAIN))
|
||||
{
|
||||
data.layoutArea = LtsWidgets::LayoutArea::eMainTab;
|
||||
data.createInstant = LtsWidgets::CreateInstantType::CreateInstantAndDiscardAction;
|
||||
data.closable = false;
|
||||
}
|
||||
else // (as dialog) = rather unlikely..
|
||||
{
|
||||
data.layoutArea = LtsWidgets::LayoutArea::eDialogTab;
|
||||
}
|
||||
data.operatorRight = OperatorRights::ScriptEditorShow;
|
||||
data.createWidgetFunc = [this](QWidget *parent)
|
||||
{
|
||||
return onShowScriptDialog(parent);
|
||||
};
|
||||
ret.append(data);
|
||||
}
|
||||
|
||||
{
|
||||
LtsWidgets::PluginData data;
|
||||
data.menuGroup = menuGroup();
|
||||
data.identifier = QStringLiteral("PresentationManagement.ScriptDialog.ImportScript");
|
||||
data.menuIcon = QIcon(QStringLiteral("icon:import_documents.svg"));
|
||||
data.menuText = tr("Insert Script");
|
||||
data.operatorRight = OperatorRights::ScriptEditorEdit;
|
||||
data.directFunc = [this](const LtsWidgets::PluginData &)
|
||||
{
|
||||
return onImportScript();
|
||||
};
|
||||
data.createWidgetFunc = nullptr;
|
||||
ret.append(data);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
bool InterfaceImpl::fetchInterfaces()
|
||||
{
|
||||
if (!m_session->getDtc<PresentationManagement::DataInterface>(m_preDtc))
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "getDtc for PresentationManagement::DataInterface failed.";
|
||||
return false;
|
||||
}
|
||||
if (!m_session->getFtc<PresentationManagement::DataInterface>(m_preFtc))
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "getFtc for PresentationManagement::DataInterface failed.";
|
||||
return false;
|
||||
}
|
||||
if (!m_session->getDtc<SituationReplayManagement::DataInterface>(m_coreDtc))
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "getDtc for SituationReplayManagement::DataInterface failed.";
|
||||
return false;
|
||||
}
|
||||
if (!m_session->getDtc<OperatorManagement::DataInterface>(m_opmDtc))
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "getDtc for OperatorManagement::DataInterface failed.";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!m_session->getDtc<ExerciseManagement::DataInterface>(m_exmDtc))
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "getDtc for OperatorManagement::DataInterface failed.";
|
||||
return false;
|
||||
}
|
||||
m_exmDtc->enableExercise();
|
||||
|
||||
if (!m_session->getForeignDataInterface<SituationReplayManagement::DataInterface>(m_srpIfc))
|
||||
{
|
||||
WARNING_LOG(m_logger) << "getForeignDataInterface for SituationReplayManagement::DataInterface failed.";
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void InterfaceImpl::clearInterfaces()
|
||||
{
|
||||
m_preDtc = nullptr;
|
||||
m_preFtc = nullptr;
|
||||
m_coreDtc = nullptr;
|
||||
m_opmDtc = nullptr;
|
||||
m_exmDtc = nullptr;
|
||||
m_srpIfc = nullptr;
|
||||
}
|
||||
|
||||
QString InterfaceImpl::menuGroup() const
|
||||
{
|
||||
return tr("Presentation");
|
||||
}
|
||||
|
||||
|
||||
void InterfaceImpl::executePayload(LtsWidgets::LtsBackgroundWidget *mainBackground)
|
||||
{
|
||||
Q_UNUSED(mainBackground);
|
||||
|
||||
if (m_session->partitionType() != IDL::PartitionType::Exercise) // only on valid exercise
|
||||
{
|
||||
emit success();
|
||||
return;
|
||||
}
|
||||
|
||||
int scriptId = m_session->getSavegame()[QStringLiteral("ScriptId")].toInt();
|
||||
if (scriptId > 0)
|
||||
{
|
||||
onSelectScript(scriptId);
|
||||
return;
|
||||
}
|
||||
|
||||
ScriptChooser *scriptChooser = new ScriptChooser(m_preDtc,m_preFtc, m_opmDtc, false, false, mainBackground);
|
||||
scriptChooser->setAttribute(Qt::WA_DeleteOnClose);
|
||||
|
||||
connect(scriptChooser, &ScriptChooser::signalSelectScript,
|
||||
this, &InterfaceImpl::onSelectScript, Qt::QueuedConnection);
|
||||
|
||||
connect(scriptChooser, &ScriptChooser::signalQuit,
|
||||
m_session, &LtsSession::LtsSession::signalQuit);
|
||||
|
||||
connect(scriptChooser, &ScriptChooser::signalNewScript,
|
||||
this, [this, scriptChooser]()
|
||||
{
|
||||
PresentationEditDialog *dialog = new PresentationEditDialog(nullptr);
|
||||
if (!dialog->init(-1 /* new presentation */, m_preDtc, m_preFtc, m_opmDtc))
|
||||
{
|
||||
delete dialog;
|
||||
return;
|
||||
}
|
||||
QObject::connect(dialog, &PresentationEditDialog::rejected, dialog, &PresentationEditDialog::deleteLater);
|
||||
QObject::connect(dialog, &PresentationEditDialog::newScript, this, &InterfaceImpl::onSelectScript, Qt::QueuedConnection);
|
||||
QObject::connect(dialog, &PresentationEditDialog::newScript, scriptChooser, &QObject::deleteLater);
|
||||
dialog->show();
|
||||
});
|
||||
|
||||
if (!LtsSessionData::LtsSessionData::getInstance()->isTablet())
|
||||
scriptChooser->setModal(true);
|
||||
|
||||
scriptChooser->show();
|
||||
}
|
||||
|
||||
|
||||
bool InterfaceImpl::importScript(int iSource)
|
||||
{
|
||||
if (!m_scriptDialog)
|
||||
{
|
||||
ERROR_LOG(m_logger) << "no script dialog open for import script";
|
||||
return false;
|
||||
}
|
||||
|
||||
PresentationManagement::Presentation presentation = m_preDtc->presentation(iSource);
|
||||
if (presentation.id() < 1)
|
||||
return false;
|
||||
|
||||
// import topics
|
||||
std::function<void(const Core::FunctionReply &baseReply)> importPresentationContent = [&](const Core::FunctionReply &baseReply)
|
||||
{
|
||||
const GetPresentationContentReply &reply = static_cast<const GetPresentationContentReply &>(baseReply);
|
||||
const auto &contentList = reply.content();
|
||||
|
||||
if (contentList.empty())
|
||||
{
|
||||
ERROR_LOG(m_logger) << "No Presentation Content for Script Id " << reply.id();
|
||||
return;
|
||||
}
|
||||
|
||||
QVector<PresentationContent> contents;
|
||||
contents.reserve(contentList.size());
|
||||
for (const PresentationContent &content : contentList)
|
||||
{
|
||||
TopicEditorBase::TopicType topicType = TopicEditorBase::topicTypeFromString(QString::fromStdString(content.presentationTopicType()));
|
||||
if (topicType == TopicEditorBase::TopicType::Invalid)
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Topic ignored - invalid topic type for presentation's content id = " << content.id();
|
||||
continue;
|
||||
}
|
||||
contents.append(content);
|
||||
}
|
||||
m_scriptDialog->import(contents);
|
||||
};
|
||||
|
||||
GetPresentationContentRequest req(iSource);
|
||||
req.presentationId(iSource);
|
||||
if (!m_requestHelper->startSingleRequest([req, this](){ return m_preFtc->getPresentationContentRequest(req, this); }, importPresentationContent))
|
||||
{
|
||||
LtsWidgets::LtsMessageDialog::showMessage(m_session->baseLayout(), tr("There is no content to import for this script."));
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
LtsWidgets::LtsDialog *InterfaceImpl::onShowScriptDialog(QWidget *parent)
|
||||
{
|
||||
|
||||
m_scriptDialog = new ScriptTimelineDialog(menuGroup(), parent);
|
||||
// m_scriptDialog = new ScriptTimelineDialog(
|
||||
// menuGroup(), m_session, m_scriptId, m_coreDtc, m_opmDtc, m_preDtc, m_preFtc, m_srpIfc, parent
|
||||
// );
|
||||
//const int exId = m_session->exerciseId();
|
||||
//ExerciseManagement::Exercise exercise = m_exmDtc->exercise(exId);
|
||||
|
||||
//DEBUG_LOG(m_logger) << "### ###ExId: " << exId << " ExName: " << exercise.name();
|
||||
m_scriptDialog->init(m_session, m_scriptId, m_preDtc, m_preFtc, m_srpIfc, m_coreDtc, m_opmDtc, m_exmDtc);
|
||||
connect(m_scriptDialog, &ScriptTimelineDialog::scriptChanged, this, [this](int scriptId) { m_scriptId = scriptId; });
|
||||
return m_scriptDialog.data();
|
||||
}
|
||||
|
||||
|
||||
void InterfaceImpl::onImportScript()
|
||||
{
|
||||
ScriptChooser *scriptChooser = new ScriptChooser(m_preDtc, m_preFtc, m_opmDtc, false, true, m_session->baseLayout());
|
||||
scriptChooser->setAttribute(Qt::WA_DeleteOnClose);
|
||||
connect(scriptChooser, &ScriptChooser::signalSelectScript, this, &InterfaceImpl::onImportSpecificScript, Qt::QueuedConnection);
|
||||
connect(scriptChooser, &ScriptChooser::signalQuit, m_session, &LtsSession::LtsSession::signalQuit);
|
||||
if (!LtsSessionData::LtsSessionData::getInstance()->isTablet())
|
||||
scriptChooser->setModal(true);
|
||||
scriptChooser->show();
|
||||
}
|
||||
|
||||
void InterfaceImpl::onImportSpecificScript(int scriptId)
|
||||
{
|
||||
if (m_scriptId == scriptId)
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Not possible to import same script!";
|
||||
new LtsWidgets::LtsMessageDialogNew(m_session->baseLayout(), tr("Not possible to import same script!"));
|
||||
return;
|
||||
}
|
||||
|
||||
if (!importScript(scriptId))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Import of script with id = " << scriptId << " failed";
|
||||
new LtsWidgets::LtsMessageDialogNew(m_session->baseLayout(), tr("Failed to import Script with Id: %1").arg(scriptId));
|
||||
return;
|
||||
}
|
||||
|
||||
DEBUG_LOG(m_logger) << "Succesfully imported script with id = " << scriptId;
|
||||
//LtsWidgets::LtsMessageDialog::showMessage(nullptr, tr("Successfully imported Script Id %1").arg(scriptId));
|
||||
}
|
||||
|
||||
void InterfaceImpl::onSelectScript(int scriptId)
|
||||
{
|
||||
m_scriptId = scriptId;
|
||||
// std::shared_ptr<ForeignGuiInterface> preGuiIfc;
|
||||
// if (!m_session->getForeignGuiInterface<ForeignGuiInterface>(preGuiIfc))
|
||||
// {
|
||||
// // TODO: MSG !!1
|
||||
// return;
|
||||
// }
|
||||
// preGuiIfc->setScriptId(scriptId);
|
||||
emit success();
|
||||
}
|
||||
|
||||
|
||||
} // namespace PresentationManagement
|
||||
Executable
+105
@@ -0,0 +1,105 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* GUI Plugin for Script Editor
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*
|
||||
* Created by Mike Wille, SLSE, 2017-03-17
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <PresentationManagement/logger.h>
|
||||
#include <PluginInterfaces/gui_plugin_interface.h>
|
||||
#include <Plugins/PresentationManagement/pre_data_plugin_interface.h>
|
||||
#include <Plugins/PresentationManagement/pre_script_timeline_gui_plugin_interface.h>
|
||||
#include <Services/PresentationManagement/pre_ftc.h> // reply handler
|
||||
#include <Services/OperatorManagement/opm_dtc.h>
|
||||
#include <ExerciseManagement/exm_data_plugin_interface.h>
|
||||
#include <ExerciseManagement/exm_dtc.h>
|
||||
#include <Plugins/SituationReplayManagement/srm_data_plugin_interface.h>
|
||||
#include <Common/ProjectConfig/project_defines.h>
|
||||
#include <LtsUtilsGuiDds/request_helper.h>
|
||||
// test:
|
||||
#include <LtsScriptTimeline/track_entry_painters.h>
|
||||
#include "pre_script_dialog.h"
|
||||
#include <LtsSession/lts_session.h>
|
||||
#include <PluginInterfaces/gui_plugin_interface.h>
|
||||
#include <PluginInterfaces/topic_replay_interface.h>
|
||||
#include <Plugins/PresentationManagement/Gui/Common/topic_assignment.h>
|
||||
|
||||
|
||||
namespace PresentationManagement
|
||||
{
|
||||
|
||||
class GuiPlugin final : public QObject, public GuiPluginBase::Plugin
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PLUGIN_METADATA(IID "gui:3:pre.script_timeline_edit")
|
||||
Q_INTERFACES(GuiPluginBase::Plugin)
|
||||
|
||||
public:
|
||||
explicit GuiPlugin() = default;
|
||||
~GuiPlugin() = default;
|
||||
|
||||
QString pluginName() override { return ForeignScriptTimelineDialogGuiInterface::pluginName(); }
|
||||
std::shared_ptr<GuiPluginBase::Interface> createGuiInterface(LtsSession::LtsSession *session) override;
|
||||
bool availableInPartition(IDL::PartitionType partition) const override { return (partition == IDL::PartitionType::Exercise); }
|
||||
};
|
||||
|
||||
|
||||
class InterfaceImpl final : public QObject, public GuiPluginBase::Interface
|
||||
, protected PresentationManagement::Interface::Ftc::PresentationModifyReplyHandler
|
||||
, protected PresentationManagement::Interface::Ftc::GetPresentationContentReplyHandler
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit InterfaceImpl(LtsSession::LtsSession *session);
|
||||
|
||||
QVector<LtsWidgets::PluginData> getActions() override;
|
||||
QString menuGroup() const override;
|
||||
bool fetchInterfaces() override;
|
||||
void clearInterfaces() override;
|
||||
bool availableInPartition(IDL::PartitionType partition) const override { return partition == IDL::PartitionType::Exercise; }
|
||||
|
||||
// be able to show script chooser
|
||||
int executionPriority() const override { return 9999; }
|
||||
void executePayload(LtsWidgets::LtsBackgroundWidget *mainBackground) override;
|
||||
|
||||
private:
|
||||
void onImportScript();
|
||||
bool importScript(/*int iDestination, */int iSource);
|
||||
|
||||
protected slots:
|
||||
void onPresentationModifyReply(const Core::FunctionReplyObject &replyObject) override final { m_requestHelper->requestReply(replyObject); }
|
||||
void onGetPresentationContentReply(const GetPresentationContentReply &reply) override { m_requestHelper->requestReply(reply); }
|
||||
|
||||
private slots:
|
||||
LtsWidgets::LtsDialog *onShowScriptDialog(QWidget *parent);
|
||||
|
||||
void onSelectScript(int scriptId);
|
||||
void onImportSpecificScript(int scriptId);
|
||||
|
||||
signals:
|
||||
void success();
|
||||
|
||||
private:
|
||||
std::shared_ptr<PresentationManagement::Interface::Dtc> m_preDtc { nullptr };
|
||||
std::shared_ptr<PresentationManagement::Interface::Ftc> m_preFtc { nullptr };
|
||||
std::shared_ptr<Core::Interface::Dtc> m_coreDtc { nullptr };
|
||||
std::shared_ptr<OperatorManagement::Interface::Dtc> m_opmDtc { nullptr };
|
||||
std::shared_ptr<ExerciseManagement::Interface::Dtc> m_exmDtc { nullptr };
|
||||
|
||||
|
||||
std::shared_ptr<SituationReplayManagement::ForeignDataInterface> m_srpIfc { nullptr };
|
||||
|
||||
|
||||
int m_scriptId { 0 };
|
||||
QPointer<PresentationManagement::ScriptTimelineDialog> m_scriptDialog { nullptr };
|
||||
LtsUtils::RequestHelper *m_requestHelper { nullptr };
|
||||
|
||||
};
|
||||
|
||||
} // namespace PresentationManagement
|
||||
+265
@@ -0,0 +1,265 @@
|
||||
#include "pre_storyboard.h"
|
||||
#include "ui_pre_storyboard.h"
|
||||
#include "LtsPrinting/printing_base.h"
|
||||
#include <LtsPrinting/printing.h>
|
||||
#include "pre_script_dialog_select_handler.h"
|
||||
|
||||
#include <QDir>
|
||||
#include <QLabel>
|
||||
#include <QJsonArray>
|
||||
#include <QTextTable>
|
||||
#include <QFileDialog>
|
||||
#include <QPrinter>
|
||||
#include <QPainter>
|
||||
#include <QPrintDialog>
|
||||
#include <LtsSession/lts_session.h>
|
||||
#include <LtsSession/lts_session_data.h>
|
||||
#include <LtsWidgets/lts_base_layout_widget.h>
|
||||
|
||||
#include <LtsScriptTimeline/track_entry.h>
|
||||
#include <ngltools/ngltools_dtg.h>
|
||||
#include <Services/PresentationManagement/logger.h>
|
||||
|
||||
namespace PresentationManagement
|
||||
{
|
||||
|
||||
StoryboardDialog::StoryboardDialog(
|
||||
QWidget *parent, LtsSession::LtsSession *session, const QString &scriptName, const QString &scriptOwner,
|
||||
const QString &maxTopicTimeString, qint64 lastModified, std::vector<TopicItem> topicItems
|
||||
)
|
||||
: LtsWidgets::LtsDialog(parent)
|
||||
, m_session(session)
|
||||
, m_scriptName(scriptName)
|
||||
, m_scriptOwner(scriptOwner)
|
||||
, m_maxTopicTimeString(maxTopicTimeString)
|
||||
, m_lastModified(lastModified)
|
||||
, m_isAlreadyTranslated(false)
|
||||
, m_ui(new Ui::StoryboardDialog)
|
||||
, m_logger(getLogger(QStringLiteral("StoryboardDialog")))
|
||||
{
|
||||
setOnlineHelpFilename(QStringLiteral("Script_Editor-Storyboard"));
|
||||
|
||||
m_ui->setupUi(this);
|
||||
m_ui->tableWidget->horizontalHeader()->setSectionResizeMode(QHeaderView::Fixed);
|
||||
m_ui->tableWidget->horizontalHeader()->setSectionResizeMode(2, QHeaderView::Stretch);
|
||||
m_ui->tableWidget->setHorizontalScrollMode(QAbstractItemView::ScrollPerPixel);
|
||||
m_buttonBox->connectButton(LtsWidgets::DialogButton::Print, this, &StoryboardDialog::onPrint);
|
||||
|
||||
onColumnWidthChanged();
|
||||
connect(m_ui->tableWidget->horizontalHeader(), &QHeaderView::sectionResized, this, &StoryboardDialog::onColumnWidthChanged);
|
||||
fillStoryboard(std::move(topicItems));
|
||||
}
|
||||
|
||||
StoryboardDialog::~StoryboardDialog()
|
||||
{
|
||||
delete m_ui;
|
||||
}
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// PUBLIC
|
||||
|
||||
void StoryboardDialog::retranslate()
|
||||
{
|
||||
translate(m_ui, tr("Script Storyboard"));
|
||||
if (m_isAlreadyTranslated)
|
||||
return;
|
||||
m_isAlreadyTranslated = true;
|
||||
}
|
||||
|
||||
void StoryboardDialog::setScriptData(const QString &scriptName, const QString &scriptOwner, const QString &maxTopicTimeString, qint64 lastModified)
|
||||
{
|
||||
m_scriptName = scriptName;
|
||||
m_scriptOwner = scriptOwner;
|
||||
m_maxTopicTimeString = maxTopicTimeString;
|
||||
m_lastModified = lastModified;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @details Fill the Storyboard with Data from Model, Sort the vector by time of topic
|
||||
* @param topicItems
|
||||
*/
|
||||
void StoryboardDialog::fillStoryboard(std::vector<TopicItem> topicItems)
|
||||
{
|
||||
m_ui->tableWidget->clear();
|
||||
m_ui->tableWidget->clearContents();
|
||||
m_ui->tableWidget->setRowCount(0);
|
||||
m_topicItems.clear();
|
||||
m_topicItems.reserve(topicItems.size());
|
||||
std::vector<TopicEditorBase::TopicData> dataVector;
|
||||
dataVector.reserve(topicItems.size());
|
||||
|
||||
for (TopicItem &topicItem : topicItems)
|
||||
m_topicItems.push_back(std::move(topicItem));
|
||||
|
||||
for (TopicItem &topicItem : m_topicItems)
|
||||
dataVector.push_back(topicItem.topicData());
|
||||
|
||||
std::sort(dataVector.begin(), dataVector.end(), [](const TopicEditorBase::TopicData &leftValue, const TopicEditorBase::TopicData &rightValue)
|
||||
{
|
||||
if (leftValue.startTime == rightValue.startTime)
|
||||
{
|
||||
if (leftValue.channel == QStringLiteral("Audio"))
|
||||
return true;
|
||||
else if (leftValue.channel == QStringLiteral("Replay") && rightValue.channel == QStringLiteral("Audio"))
|
||||
return false;
|
||||
else if (leftValue.channel == QStringLiteral("Screen 1") && (rightValue.channel == QStringLiteral("Replay") || rightValue.channel == QStringLiteral("Audio")))
|
||||
return false;
|
||||
else if (leftValue.channel == QStringLiteral("Screen 2") && (rightValue.channel == QStringLiteral("Replay") || rightValue.channel == QStringLiteral("Audio") || rightValue.channel == QStringLiteral("Screen 1")))
|
||||
return false;
|
||||
else
|
||||
return true;
|
||||
}
|
||||
return leftValue.startTime < rightValue.startTime;
|
||||
});
|
||||
|
||||
int topicCounter = 1;
|
||||
|
||||
for (TopicEditorBase::TopicData &data : dataVector)
|
||||
{
|
||||
if (!data.parentChannel.isEmpty() || data.state != true || data.channel.isEmpty() || data.topicType == TopicEditorBase::TopicType::Invalid)
|
||||
continue;
|
||||
|
||||
QString firstColumnText = QStringLiteral("<big><b>[ %1 ]</b></big><br>%2").arg(topicCounter).arg(QTime::fromMSecsSinceStartOfDay(
|
||||
((dataVector.at(dataVector.size()-1).startTime * 1000) + (dataVector.at(dataVector.size()-1).duration * 1000)) -
|
||||
(data.startTime * 1000)).toString());
|
||||
QString secondColumnText = QStringLiteral("<big><b>%1</b></big>").arg(TopicEditorBase::topicTypeString(data.topicType));
|
||||
QString thirdColumnText = QStringLiteral("<big><b>​</b></big>"); // Creates empty line with the same height than the other columns
|
||||
QJsonObject jsonObjectProperties;
|
||||
QJsonArray jsonArrayProperties;
|
||||
if (!data.properties.value(QStringLiteral("Sequences")).toArray().isEmpty())
|
||||
jsonArrayProperties = data.properties.value(QStringLiteral("Sequences")).toArray();
|
||||
else
|
||||
jsonObjectProperties = data.properties;
|
||||
|
||||
secondColumnText += QStringLiteral("<br>- ") + tr("Description");
|
||||
thirdColumnText += QStringLiteral("<br>%1").arg(data.description);
|
||||
|
||||
if (jsonArrayProperties.isEmpty())
|
||||
{
|
||||
if (jsonObjectProperties.value(QStringLiteral("start")).toDouble() > 0)
|
||||
{
|
||||
secondColumnText += QStringLiteral("<br>- ") + tr("Start");
|
||||
thirdColumnText += QStringLiteral("<br>%1").arg(LtsTimeline::DateTime::toString(jsonObjectProperties.value(QStringLiteral("start")).toDouble() * 1000, LtsTimeline::DateTime::DTG));
|
||||
}
|
||||
if (data.duration > 0)
|
||||
{
|
||||
secondColumnText += QStringLiteral("<br>- ") + tr("Duration");
|
||||
thirdColumnText += QStringLiteral("<br>%1").arg(QTime::fromMSecsSinceStartOfDay(data.duration * 1000).toString());
|
||||
}
|
||||
if (jsonObjectProperties.value(QStringLiteral("speed")).toDouble() > 0)
|
||||
{
|
||||
secondColumnText += QStringLiteral("<br>- ") + tr("Speed");
|
||||
thirdColumnText += QStringLiteral("<br>%1").arg(jsonObjectProperties.value(QStringLiteral("speed")).toDouble());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (jsonArrayProperties.first().toObject().value(QStringLiteral("start")).toDouble() > 0)
|
||||
{
|
||||
secondColumnText += QStringLiteral("<br>- ") + tr("Start");
|
||||
thirdColumnText += QStringLiteral("<br>%1").arg(LtsTimeline::DateTime::toString(jsonArrayProperties.first().toObject().value(QStringLiteral("start")).toDouble() * 1000, LtsTimeline::DateTime::DTG));
|
||||
}
|
||||
if (jsonArrayProperties.first().toObject().value(QStringLiteral("start")).toDouble() > 0)
|
||||
{
|
||||
secondColumnText += QStringLiteral("<br>- ") + tr("End");
|
||||
thirdColumnText += QStringLiteral("<br>%1").arg(LtsTimeline::DateTime::toString(jsonArrayProperties.last().toObject().value(QStringLiteral("start")).toDouble() * 1000 + jsonArrayProperties.last().toObject().value(QStringLiteral("duration")).toDouble() * 1000 ,LtsTimeline::DateTime::DTG ));
|
||||
}
|
||||
if (data.duration > 0)
|
||||
{
|
||||
secondColumnText += QStringLiteral("<br>- ") + tr("Duration");
|
||||
thirdColumnText += QStringLiteral("<br>%1").arg(QTime::fromMSecsSinceStartOfDay(data.duration * 1000).toString());
|
||||
}
|
||||
if (jsonArrayProperties.size() > 1)
|
||||
{
|
||||
QJsonValue tempProperty;
|
||||
for(QJsonValue property : jsonArrayProperties)
|
||||
{
|
||||
if (tempProperty.toObject().value(QStringLiteral("speed")).isNull())
|
||||
tempProperty = property;
|
||||
else
|
||||
if (tempProperty != property)
|
||||
{
|
||||
secondColumnText += QStringLiteral("<br>- ") + tr("Speed");
|
||||
thirdColumnText += QStringLiteral("<br>") + tr("variable");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
secondColumnText += QStringLiteral("<br>- ") + tr("Speed");
|
||||
thirdColumnText += QStringLiteral("<br>%1").arg(jsonArrayProperties.first().toObject().value(QStringLiteral("speed")).toDouble());
|
||||
}
|
||||
}
|
||||
m_ui->tableWidget->insertRow(topicCounter-1);
|
||||
|
||||
QTextEdit *firstColumnItem = new QTextEdit();
|
||||
firstColumnItem->setReadOnly(true);
|
||||
firstColumnItem->setStyleSheet(QStringLiteral("border : 0"));
|
||||
firstColumnItem->setWordWrapMode(QTextOption::NoWrap);
|
||||
firstColumnItem->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
|
||||
firstColumnItem->setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded);
|
||||
firstColumnItem->setText(firstColumnText);
|
||||
firstColumnItem->setAlignment(Qt::AlignTop);
|
||||
m_ui->tableWidget->setCellWidget(topicCounter-1, 0, firstColumnItem);
|
||||
|
||||
QTextEdit *secondColumnItem = new QTextEdit();
|
||||
secondColumnItem->setReadOnly(true);
|
||||
secondColumnItem->setStyleSheet(QStringLiteral("border : 0"));
|
||||
secondColumnItem->setWordWrapMode(QTextOption::NoWrap);
|
||||
secondColumnItem->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
|
||||
secondColumnItem->setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded);
|
||||
secondColumnItem->setText(secondColumnText);
|
||||
secondColumnItem->setAlignment(Qt::AlignTop);
|
||||
m_ui->tableWidget->setCellWidget(topicCounter-1, 1, secondColumnItem);
|
||||
|
||||
QTextEdit *thirdColumnItem = new QTextEdit;
|
||||
|
||||
thirdColumnItem->setReadOnly(true);
|
||||
thirdColumnItem->setStyleSheet(QStringLiteral("border : 0"));
|
||||
thirdColumnItem->setWordWrapMode(QTextOption::NoWrap);
|
||||
thirdColumnItem->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
|
||||
thirdColumnItem->setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded);
|
||||
thirdColumnItem->setText(thirdColumnText);
|
||||
thirdColumnItem->setAlignment(Qt::AlignTop);
|
||||
m_ui->tableWidget->setCellWidget(topicCounter-1, 2, thirdColumnItem);
|
||||
|
||||
++topicCounter;
|
||||
}
|
||||
m_ui->tableWidget->resizeRowsToContents();
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// PUBLIC SLOTS
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @details Print Storyboard with own printing Method
|
||||
*/
|
||||
void StoryboardDialog::onPrint()
|
||||
{
|
||||
QString headingHtml = (QStringLiteral("<H1>"));
|
||||
headingHtml.append (tr("Scriptname:"));
|
||||
headingHtml.append(m_scriptName);
|
||||
headingHtml.append(QStringLiteral("</H1>"));
|
||||
headingHtml.append(QStringLiteral("<H3>"));
|
||||
headingHtml.append(tr("Script Owner: "));
|
||||
headingHtml.append(m_scriptOwner);
|
||||
headingHtml.append(QStringLiteral("</H3>"));
|
||||
headingHtml.append(QStringLiteral("<H3>"));
|
||||
headingHtml.append(tr("Last modified: "));
|
||||
headingHtml.append(DTG::toStringMSec(m_lastModified));
|
||||
headingHtml.append(QStringLiteral("<br>"));
|
||||
headingHtml.append(tr("Duration: "));
|
||||
headingHtml.append(m_maxTopicTimeString);
|
||||
headingHtml.append(QStringLiteral("</H3><br>"));
|
||||
LtsPrinting::printStoryboard(m_session, this, m_ui->tableWidget, headingHtml);
|
||||
}
|
||||
|
||||
void StoryboardDialog::onColumnWidthChanged()
|
||||
{
|
||||
m_ui->tableWidget->setColumnWidth(0,this->width() * 0.25);
|
||||
m_ui->tableWidget->setColumnWidth(1,this->width() * 0.40);
|
||||
}
|
||||
|
||||
} // namespace PresentationManagement
|
||||
+60
@@ -0,0 +1,60 @@
|
||||
#pragma once
|
||||
|
||||
#include <LtsScriptTimeline/track_entry.h>
|
||||
#include <LtsSession/lts_session.h>
|
||||
#include <LtsTimeline/item.h>
|
||||
#include <LtsWidgets/lts_dialog.h>
|
||||
#include "pre_topic_item.h"
|
||||
|
||||
#include <QTableWidget>
|
||||
#include <QVector>
|
||||
|
||||
namespace Ui
|
||||
{
|
||||
class StoryboardDialog;
|
||||
}
|
||||
|
||||
|
||||
namespace PresentationManagement
|
||||
{
|
||||
|
||||
class TopicItem;
|
||||
|
||||
|
||||
class StoryboardDialog : public LtsWidgets::LtsDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
StoryboardDialog(
|
||||
QWidget *parent, LtsSession::LtsSession *session, const QString &scriptName, const QString &scriptOwner,
|
||||
const QString &maxTopicTimeString, qint64 lastModified, std::vector<TopicItem> topicItems
|
||||
);
|
||||
~StoryboardDialog();
|
||||
|
||||
void retranslate() override final;
|
||||
|
||||
void setScriptData(
|
||||
const QString &scriptName, const QString &scriptOwner, const QString &maxTopicTimeString, qint64 lastModified
|
||||
);
|
||||
void fillStoryboard(std::vector<TopicItem> topicItems);
|
||||
|
||||
public slots:
|
||||
void onPrint();
|
||||
void onColumnWidthChanged();
|
||||
private:
|
||||
LtsSession::LtsSession *m_session;
|
||||
|
||||
std::vector<TopicItem> m_topicItems;
|
||||
QString m_scriptName;
|
||||
QString m_scriptOwner;
|
||||
QString m_maxTopicTimeString;
|
||||
qint64 m_lastModified { 0 };
|
||||
bool m_isAlreadyTranslated { false };
|
||||
|
||||
Ui::StoryboardDialog *m_ui { nullptr };
|
||||
NGL::INGLLogger &m_logger;
|
||||
|
||||
};
|
||||
|
||||
} // namespace PresentationManagement
|
||||
+109
@@ -0,0 +1,109 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>StoryboardDialog</class>
|
||||
<widget class="QWidget" name="StoryboardDialog">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>707</width>
|
||||
<height>464</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="MinimumExpanding" vsizetype="MinimumExpanding">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string notr="true">Script Editor</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout" stretch="0">
|
||||
<property name="spacing">
|
||||
<number>9</number>
|
||||
</property>
|
||||
<property name="leftMargin">
|
||||
<number>9</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>9</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>9</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>9</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QTableWidget" name="tableWidget">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="sizeAdjustPolicy">
|
||||
<enum>QAbstractScrollArea::AdjustIgnored</enum>
|
||||
</property>
|
||||
<property name="editTriggers">
|
||||
<set>QAbstractItemView::NoEditTriggers</set>
|
||||
</property>
|
||||
<property name="alternatingRowColors">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="textElideMode">
|
||||
<enum>Qt::ElideNone</enum>
|
||||
</property>
|
||||
<property name="showGrid">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="wordWrap">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="rowCount">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="columnCount">
|
||||
<number>3</number>
|
||||
</property>
|
||||
<attribute name="horizontalHeaderVisible">
|
||||
<bool>false</bool>
|
||||
</attribute>
|
||||
<attribute name="horizontalHeaderMinimumSectionSize">
|
||||
<number>100</number>
|
||||
</attribute>
|
||||
<attribute name="horizontalHeaderDefaultSectionSize">
|
||||
<number>120</number>
|
||||
</attribute>
|
||||
<attribute name="horizontalHeaderHighlightSections">
|
||||
<bool>false</bool>
|
||||
</attribute>
|
||||
<attribute name="horizontalHeaderStretchLastSection">
|
||||
<bool>false</bool>
|
||||
</attribute>
|
||||
<attribute name="verticalHeaderVisible">
|
||||
<bool>false</bool>
|
||||
</attribute>
|
||||
<attribute name="verticalHeaderMinimumSectionSize">
|
||||
<number>0</number>
|
||||
</attribute>
|
||||
<attribute name="verticalHeaderDefaultSectionSize">
|
||||
<number>150</number>
|
||||
</attribute>
|
||||
<attribute name="verticalHeaderHighlightSections">
|
||||
<bool>false</bool>
|
||||
</attribute>
|
||||
<attribute name="verticalHeaderStretchLastSection">
|
||||
<bool>false</bool>
|
||||
</attribute>
|
||||
<column/>
|
||||
<column/>
|
||||
<column/>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
Executable
+71
@@ -0,0 +1,71 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* Dialog for the Topic Designer
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*
|
||||
* Created by Mike Wille, SLSE, 2017-06-09
|
||||
*/
|
||||
|
||||
#include "pre_topic_designer_dialog.h"
|
||||
#include "ui_pre_topic_designer_dialog.h"
|
||||
|
||||
|
||||
namespace PresentationManagement
|
||||
{
|
||||
|
||||
TopicDesignerDialog::TopicDesignerDialog(QWidget *parent)
|
||||
: LtsDialog(parent)
|
||||
, m_ui(new Ui::TopicDesignerDialog)
|
||||
{
|
||||
|
||||
setOnlineHelpFilename(QStringLiteral("Script_Editor-Designer"));
|
||||
m_ui->setupUi(this);
|
||||
setFocusPolicy(Qt::StrongFocus);
|
||||
|
||||
connect(m_ui->widget, &TopicDesigner::signalTopicSelected,
|
||||
this, &TopicDesignerDialog::signalTopicSelected);
|
||||
connect(m_ui->widget, &TopicDesigner::signalDeleteTrackEntry,
|
||||
this, &TopicDesignerDialog::signalDeleteTrackEntry);
|
||||
connect(m_ui->widget, &TopicDesigner::signalUnselect,
|
||||
this, &TopicDesignerDialog::signalUnselect);
|
||||
connect(m_ui->widget, &TopicDesigner::signalChangesMade,
|
||||
this, &LtsWidgets::LtsDialog::signalChangesMade);
|
||||
|
||||
// connect(m_ui->pbToFront, &QPushButton::clicked,
|
||||
// m_ui->widget, &TopicDesigner::to)
|
||||
}
|
||||
|
||||
|
||||
void TopicDesignerDialog::retranslate()
|
||||
{
|
||||
translate(m_ui, tr("Topic Designer"));
|
||||
}
|
||||
|
||||
|
||||
TopicDesignerDialog::~TopicDesignerDialog()
|
||||
{
|
||||
delete m_ui;
|
||||
}
|
||||
|
||||
|
||||
QVector<LtsScriptTimeline::TrackEntry *> TopicDesignerDialog::exportTopicList() const
|
||||
{
|
||||
return m_ui->widget->exportTopicList();
|
||||
}
|
||||
|
||||
|
||||
void TopicDesignerDialog::selectTopic(int topicId)
|
||||
{
|
||||
m_ui->widget->selectTopic(topicId);
|
||||
}
|
||||
|
||||
|
||||
void TopicDesignerDialog::loadTopicList(const QVector<LtsScriptTimeline::TrackEntry *> &topicsList)
|
||||
{
|
||||
m_ui->widget->loadTopicList(topicsList);
|
||||
}
|
||||
|
||||
} // namespace PresentationManagement
|
||||
|
||||
Executable
+57
@@ -0,0 +1,57 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* Dialog for the Topic Designer
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*
|
||||
* Created by Mike Wille, SLSE, 2017-06-09
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <LtsWidgets/lts_dialog.h>
|
||||
|
||||
#include <QVector>
|
||||
|
||||
|
||||
namespace Ui
|
||||
{
|
||||
class TopicDesignerDialog;
|
||||
}
|
||||
|
||||
namespace LtsScriptTimeline
|
||||
{
|
||||
class TrackEntry;
|
||||
}
|
||||
|
||||
|
||||
namespace PresentationManagement
|
||||
{
|
||||
|
||||
class TopicDesignerDialog : public LtsWidgets::LtsDialog
|
||||
{
|
||||
public:
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit TopicDesignerDialog(QWidget *parent = nullptr);
|
||||
~TopicDesignerDialog();
|
||||
|
||||
void loadTopicList(const QVector<LtsScriptTimeline::TrackEntry *> &topicsList);
|
||||
QVector<LtsScriptTimeline::TrackEntry *> exportTopicList() const;
|
||||
void selectTopic(int topicId);
|
||||
|
||||
signals:
|
||||
void signalTopicSelected(int topicId);
|
||||
void signalDeleteTrackEntry(int topicId);
|
||||
void signalUnselect();
|
||||
|
||||
private:
|
||||
void retranslate() override;
|
||||
|
||||
Ui::TopicDesignerDialog *m_ui;
|
||||
|
||||
};
|
||||
|
||||
} // namespace PresentationManagement
|
||||
Executable
+122
@@ -0,0 +1,122 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>TopicDesignerDialog</class>
|
||||
<widget class="QWidget" name="TopicDesignerDialog">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>600</width>
|
||||
<height>338</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="MinimumExpanding" vsizetype="MinimumExpanding">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string notr="true">Script Editor</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<property name="spacing">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="leftMargin">
|
||||
<number>9</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>9</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>9</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>9</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string notr="true">Some text</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||
<item>
|
||||
<widget class="QPushButton" name="pbToFront">
|
||||
<property name="text">
|
||||
<string>To Front</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="pbIncIdx">
|
||||
<property name="text">
|
||||
<string>Inc Idx</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="pbDecIdx">
|
||||
<property name="text">
|
||||
<string>Dec Idx</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="pbToBack">
|
||||
<property name="text">
|
||||
<string>To Back</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>40</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="PresentationManagement::TopicDesigner" name="widget" native="true">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="MinimumExpanding" vsizetype="MinimumExpanding">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>300</height>
|
||||
</size>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
<class>PresentationManagement::TopicDesigner</class>
|
||||
<extends>QWidget</extends>
|
||||
<header>topic_designer.h</header>
|
||||
<container>1</container>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
+213
@@ -0,0 +1,213 @@
|
||||
#include "pre_topic_item.h"
|
||||
#include "pre_script_model.h"
|
||||
|
||||
#include <PresentationManagement/pre.hpp>
|
||||
|
||||
#include <QJsonArray>
|
||||
#include <QJsonDocument>
|
||||
#include <QJsonObject>
|
||||
#include <QPainter>
|
||||
#include <QStyleOptionViewItem>
|
||||
|
||||
|
||||
#include <LtsTimeline/timeline_utils.h>
|
||||
#include <QDebug>
|
||||
|
||||
|
||||
namespace PresentationManagement
|
||||
{
|
||||
|
||||
int TopicItem::s_gradientSize = 20;
|
||||
|
||||
const QString TopicItem::s_sequencesKey = QStringLiteral("Sequences");
|
||||
const QString TopicItem::s_posKey = QStringLiteral("pos");
|
||||
const QString TopicItem::s_startKey = QStringLiteral("start");
|
||||
const QString TopicItem::s_durationKey = QStringLiteral("duration");
|
||||
const QString TopicItem::s_speedKey = QStringLiteral("speed");
|
||||
|
||||
|
||||
TopicItem::TopicItem(const TopicEditorBase::TopicData &data)
|
||||
: LtsTimeline::Item(static_cast<qint64>(data.startTime) * 1000, static_cast<qint64>(data.duration) * 1000, topicTypeColor(data.topicType), true)
|
||||
, m_topicType(data.topicType)
|
||||
, m_topicData(data)
|
||||
{
|
||||
sortSequences();
|
||||
}
|
||||
|
||||
TopicItem::TopicItem(const PresentationContent &content)
|
||||
: LtsTimeline::Item(static_cast<qint64>(content.startTime()) * 1000, static_cast<qint64>(content.duration()) * 1000, TopicEditorBase::topicTypeColor(TopicEditorBase::topicTypeFromString(QString::fromStdString(content.presentationTopicType()))), true)
|
||||
, m_topicType(TopicEditorBase::topicTypeFromString(QString::fromStdString(content.presentationTopicType())))
|
||||
{
|
||||
m_topicData.id = content.id();
|
||||
m_topicData.topicType = m_topicType;
|
||||
m_topicData.startTime = m_startTime / 1000;
|
||||
m_topicData.duration = m_duration / 1000;
|
||||
m_topicData.state = true;
|
||||
m_topicData.index = content.index();
|
||||
m_topicData.description = QString::fromStdString(content.description());
|
||||
m_topicData.channel = QString::fromStdString(content.channel());
|
||||
m_topicData.properties = QJsonDocument::fromJson(QByteArray(content.attributes().c_str(), content.attributes().size())).object();
|
||||
m_topicData.x = content.x();
|
||||
m_topicData.y = content.y();
|
||||
m_topicData.w = content.width();
|
||||
m_topicData.h = content.height();
|
||||
sortSequences();
|
||||
}
|
||||
|
||||
TopicItem::TopicItem(
|
||||
qint64 startTime, int duration, TopicEditorBase::TopicType topicType, const QString &description,
|
||||
const QJsonObject &properties, const QString &channel, const QString &parentChannel
|
||||
)
|
||||
: LtsTimeline::Item(startTime, duration, topicTypeColor(topicType))
|
||||
, m_topicType(topicType)
|
||||
{
|
||||
m_topicData.topicType = m_topicType;
|
||||
m_topicData.startTime = m_startTime / 1000;
|
||||
m_topicData.duration = m_duration / 1000;
|
||||
m_topicData.description = description;
|
||||
m_topicData.channel = channel;
|
||||
m_topicData.parentChannel = parentChannel;
|
||||
m_topicData.properties = properties;
|
||||
sortSequences();
|
||||
}
|
||||
|
||||
TopicItem::~TopicItem()
|
||||
{
|
||||
delete m_replayInterface;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// PUBLIC
|
||||
|
||||
TopicItem TopicItem::copy() const
|
||||
{
|
||||
return TopicItem(m_topicData);
|
||||
}
|
||||
|
||||
|
||||
qint64 TopicItem::replayTime(qint64 time) const
|
||||
{
|
||||
if (m_startTime > time || time > m_startTime + m_duration)
|
||||
return -1;
|
||||
|
||||
if (ScriptModel::hasReplayTime(m_topicType))
|
||||
{
|
||||
if (m_topicData.properties.contains(s_sequencesKey))
|
||||
{
|
||||
QJsonArray sequences = m_topicData.properties.value(s_sequencesKey).toArray({});
|
||||
if (sequences.isEmpty())
|
||||
return -1;
|
||||
|
||||
qint64 relTime = time - m_startTime;
|
||||
qint64 relSequenceStart = 0;
|
||||
for (const QJsonValue &sequence : qAsConst(sequences))
|
||||
{
|
||||
QJsonObject obj = sequence.toObject();
|
||||
qint64 start = obj.value(s_startKey).toDouble();
|
||||
double speed = obj.value(s_speedKey).toDouble() / 100.;
|
||||
int duration = speed * obj.value(s_durationKey).toInt();
|
||||
if (relTime <= relSequenceStart + speed * duration)
|
||||
return start + speed * (relTime - relSequenceStart);
|
||||
|
||||
relSequenceStart += speed * duration;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
qint64 start = static_cast<qint64>(m_topicData.properties.value(QStringLiteral("start")).toDouble(-1));
|
||||
if (start < 0)
|
||||
return -1;
|
||||
|
||||
qint64 end = static_cast<qint64>(m_topicData.properties.value(QStringLiteral("end")).toDouble(-1));
|
||||
if (end < 0)
|
||||
return -1;
|
||||
|
||||
return start + (end - start) * (time - m_startTime) / m_duration;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
QJsonObject TopicItem::toJson() const
|
||||
{
|
||||
return QJsonObject({{QStringLiteral("topicId"), id()},
|
||||
{QStringLiteral("startTime"), m_startTime / 1000},
|
||||
{QStringLiteral("length"), m_duration / 1000},
|
||||
{QStringLiteral("type"), static_cast<int>(m_topicType)},
|
||||
{QStringLiteral("x"), m_topicData.x},
|
||||
{QStringLiteral("y"), m_topicData.y},
|
||||
{QStringLiteral("w"), m_topicData.w},
|
||||
{QStringLiteral("h"), m_topicData.h},
|
||||
{QStringLiteral("detailData"), m_topicData.properties},
|
||||
{QStringLiteral("channelName"), m_topicData.channel},
|
||||
{QStringLiteral("description"), m_topicData.description},
|
||||
{QStringLiteral("filterParentChannel"), m_topicData.parentChannel}
|
||||
});
|
||||
}
|
||||
|
||||
PresentationContent TopicItem::toPresentationContent(int scriptId) const
|
||||
{
|
||||
PresentationManagement::PresentationContent content;
|
||||
content.id(id());
|
||||
content.presentationId(scriptId);
|
||||
content.presentationTopicType(topicTypeString(m_topicType).toStdString());
|
||||
content.channel(m_topicData.channel.toStdString());
|
||||
content.startTime(m_startTime / 1000);
|
||||
content.duration(m_duration / 1000);
|
||||
const QByteArray attributes = QJsonDocument(m_topicData.properties).toJson(QJsonDocument::Compact);
|
||||
content.attributes(attributes.data());
|
||||
content.description(m_topicData.description.toStdString());
|
||||
content.x(m_topicData.x);
|
||||
content.y(m_topicData.y);
|
||||
content.height(m_topicData.h);
|
||||
content.width(m_topicData.w);
|
||||
return content;
|
||||
}
|
||||
|
||||
|
||||
void TopicItem::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index, bool highlight) const
|
||||
{
|
||||
painter->save();
|
||||
|
||||
LtsTimeline::Item::paint(painter, option, index, highlight);
|
||||
if (option.rect.width() >= 20)
|
||||
{
|
||||
QRect boundingRect = option.rect.adjusted(1, 1, -1, -1);
|
||||
QRect labelRect = boundingRect.adjusted(3, 16, 0, 0);
|
||||
painter->drawText(labelRect, Qt::AlignLeft, description(), &boundingRect);
|
||||
|
||||
int penWidth = highlight ? 5 : 1;
|
||||
QRect gradientRect = QRect(
|
||||
option.rect.right() - s_gradientSize, option.rect.top() + penWidth, s_gradientSize, option.rect.height() - 2 * penWidth
|
||||
);
|
||||
QLinearGradient gradient(gradientRect.bottomRight(), gradientRect.bottomLeft());
|
||||
gradient.setColorAt(0, QColor(m_color.red(), m_color.green(), m_color.blue(), 255));
|
||||
gradient.setColorAt(1, QColor(m_color.red(), m_color.green(), m_color.blue(), 0));
|
||||
painter->fillRect(gradientRect, gradient);
|
||||
}
|
||||
|
||||
painter->restore();
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// PRIVATE
|
||||
|
||||
void TopicItem::sortSequences()
|
||||
{
|
||||
if (!m_topicData.properties.contains(s_sequencesKey))
|
||||
return;
|
||||
|
||||
QJsonArray sequences = m_topicData.properties.value(s_sequencesKey).toArray({});
|
||||
if (sequences.isEmpty())
|
||||
return;
|
||||
|
||||
QVariantList variantList = sequences.toVariantList();
|
||||
std::sort(variantList.begin(), variantList.end(), [](const QVariant &left, const QVariant &right)
|
||||
{
|
||||
return left.toJsonObject().value(s_posKey).toInt() <= right.toJsonObject().value(s_posKey).toInt();
|
||||
});
|
||||
m_topicData.properties[s_sequencesKey] = QJsonValue::fromVariant(variantList);
|
||||
}
|
||||
|
||||
} // namespace PresentationManagement
|
||||
+100
@@ -0,0 +1,100 @@
|
||||
#pragma once
|
||||
|
||||
#include "pre_utils.h"
|
||||
|
||||
#include <LtsScriptTimeline/track_entry.h>
|
||||
#include <LtsTimeline/item.h>
|
||||
#include <PluginInterfaces/topic_replay_interface.h>
|
||||
#include <TopicEditorBase/topic_editor_utils.h>
|
||||
|
||||
#include <QWidget>
|
||||
|
||||
|
||||
namespace PresentationManagement
|
||||
{
|
||||
|
||||
class PresentationContent;
|
||||
|
||||
|
||||
class TopicItem : public LtsTimeline::Item
|
||||
{
|
||||
friend class ScriptModel;
|
||||
|
||||
public:
|
||||
static int s_gradientSize;
|
||||
|
||||
static const QString s_sequencesKey;
|
||||
static const QString s_posKey;
|
||||
static const QString s_startKey;
|
||||
static const QString s_durationKey;
|
||||
static const QString s_speedKey;
|
||||
|
||||
explicit TopicItem(const TopicEditorBase::TopicData &data);
|
||||
explicit TopicItem(const PresentationContent &content);
|
||||
TopicItem(TopicItem &&) = default;
|
||||
explicit TopicItem(
|
||||
qint64 startTime, int duration, TopicEditorBase::TopicType topicType, const QString &description,
|
||||
const QJsonObject &properties, const QString &channel, const QString &parentChannel = {}
|
||||
);
|
||||
~TopicItem();
|
||||
|
||||
TopicItem copy() const;
|
||||
|
||||
TopicReplay::Interface *replayInterface() { return m_replayInterface; }
|
||||
void setReplayInterface(TopicReplay::Interface *replayInterface) { m_replayInterface = replayInterface; }
|
||||
bool hasReplayInterface() const { return bool(m_replayInterface); }
|
||||
|
||||
QWidget *replayWidget() { return m_replayWidget; }
|
||||
void setReplayWidget(QWidget *widget) { m_replayWidget = widget; }
|
||||
bool hasReplayWidget() const { return bool(m_replayWidget); }
|
||||
|
||||
TopicEditorBase::TopicType topicType() const { return m_topicType; }
|
||||
TopicEditorBase::TopicData &topicData() { return m_topicData; }
|
||||
const TopicEditorBase::TopicData &topicData() const { return m_topicData; }
|
||||
|
||||
qint64 replayTime(qint64 time) const;
|
||||
|
||||
int topicId() const { return m_topicData.id; }
|
||||
void setTopicId(int id) { m_topicData.id = id; }
|
||||
|
||||
QString description() const { return m_topicData.description; }
|
||||
void setDescription(const QString &description) { m_topicData.description = description; }
|
||||
|
||||
QString channel() const { return m_topicData.channel; }
|
||||
void setChannel(const QString &channelName) { m_topicData.channel = channelName; }
|
||||
QString parentChannel() const { return m_topicData.parentChannel; }
|
||||
void setParentChannel(const QString &channelName) { m_topicData.parentChannel = channelName; }
|
||||
|
||||
QJsonObject properties() const { return m_topicData.properties; }
|
||||
void setProperties(const QJsonObject &properties) { m_topicData.properties = properties; }
|
||||
|
||||
bool state() const { return m_topicData.state; }
|
||||
void setState(bool state) { m_topicData.state = state; }
|
||||
|
||||
QJsonObject toJson() const;
|
||||
PresentationContent toPresentationContent(int scriptId = -1) const;
|
||||
|
||||
void paint(
|
||||
QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index, bool highlight = false
|
||||
) const override;
|
||||
|
||||
private:
|
||||
void sortSequences();
|
||||
|
||||
private:
|
||||
TopicReplay::Interface *m_replayInterface { nullptr }; // NOTE: because of this raw pointer, we can't follow the rule-of-zero here - but because the pointer address just needs to be copied, defaulted move constructor is enough
|
||||
QWidget *m_replayWidget { nullptr };
|
||||
|
||||
TopicEditorBase::TopicType m_topicType;
|
||||
TopicEditorBase::TopicData m_topicData;
|
||||
|
||||
};
|
||||
typedef std::unique_ptr<TopicItem> TopicItemPtr;
|
||||
typedef std::vector<TopicItemPtr> TopicItems;
|
||||
typedef std::reference_wrapper<const TopicItem /* TODO: make Item, also! */> TopicItemPtrRef;
|
||||
//typedef std::reference_wrapper<TopicItem> TopicItemPtrNCVRef;
|
||||
typedef std::reference_wrapper<TopicItemPtr> TopicItemPtrNCVRef;
|
||||
typedef std::vector<TopicItemPtrNCVRef> TopicItemPtrNCVRefs;
|
||||
typedef std::vector<TopicItemPtrRef> TopicItemPtrRefs;
|
||||
|
||||
} // namespace PresentationManagement
|
||||
Executable
+308
@@ -0,0 +1,308 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* class for recording a single topic on a screen
|
||||
* $Id:
|
||||
* $HeadURL:
|
||||
* $Author:
|
||||
* Created by Hannes Fritsche, SLTE, 2023-11-06
|
||||
*/
|
||||
|
||||
#include "pre_topic_recorder.h"
|
||||
#include "pre_screen.h"
|
||||
|
||||
#include <LtsUtilsCore/await.h>
|
||||
|
||||
#include <QFile>
|
||||
#include <QThread>
|
||||
|
||||
|
||||
|
||||
#ifdef Q_OS_UNIX
|
||||
#define _compiler_warning(x) _Pragma(#x)
|
||||
#define compiler_warning(x) _compiler_warning(GCC warning x)
|
||||
#else
|
||||
#define compiler_warning(x)
|
||||
#endif
|
||||
|
||||
|
||||
namespace PresentationManagement
|
||||
{
|
||||
static QString s_container(L("mp4"));
|
||||
static QString s_program(L("ffmpeg"));
|
||||
|
||||
TopicRecorder::TopicRecorder(const int topicId, const QString &topicName, const Screen *screen, qint32 offset,
|
||||
qint64 startTime, qint64 stopTime, const double topicX, const double topicY,
|
||||
const double topicW, const double topicH, QObject *parent)
|
||||
: QObject(parent)
|
||||
, m_recordingProcess(new QProcess(this))
|
||||
, m_startTime(startTime)
|
||||
, m_stopTime(stopTime)
|
||||
, m_topicName(topicName)
|
||||
, m_topicId(topicId)
|
||||
, m_length((m_stopTime - (m_startTime - offset)) / 1000)
|
||||
, m_logger(getLogger("TopicRecorder"))
|
||||
{
|
||||
const auto screenGlobalPos = screen->mapToGlobal({0,0});
|
||||
const auto screenGeo = screen->geometry();
|
||||
|
||||
const double screenX = screenGlobalPos.x() + screenGeo.x();
|
||||
const double screenY = screenGlobalPos.y() + screenGeo.y();
|
||||
const double screenW = screenGeo.width();
|
||||
const double screenH = screenGeo.height();
|
||||
|
||||
const bool fullscreen = (topicW < 0.0002 || topicH < 0.0002); // if w or h are too small, record the whole screen...
|
||||
|
||||
const QPoint globalPos(fullscreen ? screenX : screenX + (screenW * topicX),
|
||||
fullscreen ? screenY : screenY + (screenH * topicY));
|
||||
|
||||
const qint32 inputX = globalPos.x();
|
||||
const qint32 inputY = globalPos.y();
|
||||
const qint32 inputW = (qint32)(fullscreen ? screenW : screenW * topicW);
|
||||
const qint32 inputH = (qint32)(fullscreen ? screenH : screenH * topicH);
|
||||
|
||||
ERROR_LOG(m_logger) << "TopicRecorder: fullscreen? " << fullscreen;
|
||||
ERROR_LOG(m_logger) << "TopicRecorder: topic - x: " << topicX << ", y: " << topicY << ", w: " << topicW << ", h: " << topicH;
|
||||
ERROR_LOG(m_logger) << "TopicRecorder: screen - x: " << screenX << ", y: " << screenY << ", w: " << screenW << ", h: " << screenH;
|
||||
ERROR_LOG(m_logger) << "TopicRecorder: input - x: " << inputX << ", y: " << inputY << ", w: " << inputW << ", h: " << inputH;
|
||||
|
||||
if (!m_tmpRecordingFile.open()) // create file
|
||||
throw std::runtime_error(L("Failed to open temporary recording file: %1").arg(m_tmpRecordingFile.errorString()).toStdString());
|
||||
|
||||
m_recordingProcess->setProgram(s_program);
|
||||
m_recordingProcess->setArguments(L("-hide_banner -f x11grab -s %1x%2 -i :0.0+%3,%4 -c:v libx264 -y -map 0 -movflags +faststart -f %5 %6").arg(inputW).arg(inputH).arg(inputX).arg(inputY).arg(s_container).arg(m_tmpRecordingFile.fileName()).split(L(" ")));
|
||||
/*DEBUG*/ERROR_LOG(m_logger) << "args: " << m_recordingProcess->arguments().join(L(" "));
|
||||
connect(m_recordingProcess, &QProcess::readyReadStandardOutput, [this]() { /*DEBUG*/ERROR_LOG(m_logger) << "REC [ ]: " << QString::fromUtf8(m_recordingProcess->readAllStandardOutput()); });
|
||||
connect(m_recordingProcess, &QProcess::readyReadStandardError, [this]() { /*DEBUG*/ERROR_LOG(m_logger) << "REC [!]: " << QString::fromUtf8(m_recordingProcess->readAllStandardError()); });
|
||||
connect(m_recordingProcess, &QProcess::started, [this]() { /*DEBUG*/ERROR_LOG(m_logger) << "REC started successfully!"; });
|
||||
|
||||
if (!m_tmpCuttingFile.open()) // create file
|
||||
throw std::runtime_error(L("Failed to open temporary cutting file: %1").arg(m_tmpCuttingFile.errorString()).toStdString());
|
||||
|
||||
connect(m_recordingProcess, QOverload<int, QProcess::ExitStatus>::of(&QProcess::finished),
|
||||
this, &TopicRecorder::onRecordingProcessFinished);
|
||||
connect(m_recordingProcess, &QProcess::errorOccurred,
|
||||
this, QOverload<QProcess::ProcessError>::of(&TopicRecorder::onExportFailed));
|
||||
}
|
||||
|
||||
TopicRecorder::~TopicRecorder()
|
||||
{
|
||||
if (m_recordingProcess->state() != QProcess::NotRunning)
|
||||
m_recordingProcess->kill();
|
||||
//m_recordingProcess->waitForFinished();
|
||||
|
||||
// if (m_cuttingProcess->state() == QProcess::Running)
|
||||
// m_cuttingProcess->terminate();
|
||||
// m_cuttingProcess->waitForFinished();
|
||||
}
|
||||
|
||||
|
||||
void TopicRecorder::cut()
|
||||
{
|
||||
auto *cuttingProcess = new QProcess(this);
|
||||
|
||||
cuttingProcess->setProgram(s_program);
|
||||
// cut with only 1 thread: cuttingProcess->setArguments(L("-threads 1 -hide_banner -y -sseof -%1 -threads 1 -i %2 -c:v libx264 -x264-params threads=1 -f %3 %4").arg(m_length).arg(m_tmpRecordingFile.fileName(), s_container, m_tmpCuttingFile.fileName()).split(L(" ")));
|
||||
cuttingProcess->setArguments(L("-hide_banner -y -sseof -%1 -i %2 -c:v libx264 -f %3 %4").arg(m_length).arg(m_tmpRecordingFile.fileName(), s_container, m_tmpCuttingFile.fileName()).split(L(" ")));
|
||||
connect(cuttingProcess, &QProcess::readyReadStandardOutput, this, [this, cuttingProcess]() { /*DEBUG*/ERROR_LOG(m_logger) << "CUT [ ]: " << QString::fromUtf8(cuttingProcess->readAllStandardOutput()); });
|
||||
connect(cuttingProcess, &QProcess::readyReadStandardError, this, [this, cuttingProcess]() { /*DEBUG*/ERROR_LOG(m_logger) << "CUT [!]: " << QString::fromUtf8(cuttingProcess->readAllStandardError()); });
|
||||
connect(cuttingProcess, &QProcess::started, this, [this]() { /*DEBUG*/ERROR_LOG(m_logger) << "CUT started successfully!"; });
|
||||
|
||||
ERROR_LOG(m_logger) << "start cut";
|
||||
|
||||
cuttingProcess->start();
|
||||
|
||||
// if (m_recordingProcess->state() == QProcess::NotRunning)
|
||||
// {
|
||||
// return;
|
||||
// }
|
||||
|
||||
try
|
||||
{
|
||||
LtsUtils::await(
|
||||
cuttingProcess, QOverload<int, QProcess::ExitStatus>::of(&QProcess::finished), true,
|
||||
cuttingProcess, &QProcess::errorOccurred, false,
|
||||
this, &TopicRecorder::cancel, false
|
||||
);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
ERROR_LOG(m_logger) << "cut failed (error) with exitCode=" << cuttingProcess->exitCode() << " and exitStatus=" << (cuttingProcess->exitStatus() == QProcess::ExitStatus::CrashExit ? "Crash" : "Normal Exit");
|
||||
m_failed = true;
|
||||
cuttingProcess->deleteLater();
|
||||
return;
|
||||
}
|
||||
|
||||
if (cuttingProcess->exitCode() != 0)
|
||||
{
|
||||
ERROR_LOG(m_logger) << "cut failed with non-zero exitCode=" << cuttingProcess->exitCode() << " and exitStatus=" << (cuttingProcess->exitStatus() == QProcess::ExitStatus::CrashExit ? "Crash" : "Normal Exit");
|
||||
m_failed = true;
|
||||
cuttingProcess->deleteLater();
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
ERROR_LOG(m_logger) << "cut done";
|
||||
cuttingProcess->deleteLater();
|
||||
}
|
||||
|
||||
|
||||
void TopicRecorder::save(const QString &saveToPath) noexcept(false)
|
||||
{
|
||||
const QString newFilename(L("%1/%2.%3").arg(saveToPath).arg(m_topicId).arg(s_container));
|
||||
if (!m_tmpCuttingFile.rename(newFilename))
|
||||
{
|
||||
throw L("Failed to move recording from '%1' to '%2' ('%3')").arg(m_tmpCuttingFile.fileName(), saveToPath, newFilename);
|
||||
}
|
||||
|
||||
m_tmpCuttingFile.setAutoRemove(false); // keep file
|
||||
}
|
||||
|
||||
|
||||
//void TopicRecorder::saveRecording(const QString &saveToPath)
|
||||
//{
|
||||
// const QString newFilename(L("%1/%2.%3").arg(saveToPath).arg(m_topicId).arg(s_container));
|
||||
// if (!m_tmpCuttingFile.rename(newFilename))
|
||||
// {
|
||||
// throw L("Failed to move recording from '%1' to '%2' ('%3')").arg(m_tmpCuttingFile.fileName(), saveToPath, newFilename);
|
||||
// return;
|
||||
// }
|
||||
|
||||
// m_tmpCuttingFile.setAutoRemove(false); // keep file
|
||||
//}
|
||||
|
||||
|
||||
void TopicRecorder::onExportFailed(const QProcess::ProcessError error)
|
||||
{
|
||||
m_failed = true;
|
||||
onExportFailed(L("Process: '%1' - Process error: %2").arg(processToString(static_cast<QProcess*>(sender()))).arg((int)error));
|
||||
}
|
||||
|
||||
|
||||
void TopicRecorder::onExportFailed(const QString &errorMessage)
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Export failed for topic '" << m_topicName << "': " << errorMessage;
|
||||
emit exportFailed(errorMessage);
|
||||
}
|
||||
|
||||
|
||||
void TopicRecorder::killAndClear()
|
||||
{
|
||||
switch (m_recordingState)
|
||||
{
|
||||
case RecordingState::Done:
|
||||
// m_cuttingProcess->kill();
|
||||
|
||||
Q_FALLTHROUGH();
|
||||
case RecordingState::InProgress:
|
||||
m_recordingProcess->kill();
|
||||
|
||||
return;
|
||||
case RecordingState::Waiting:
|
||||
default:
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void TopicRecorder::waitForFinishedRecording()
|
||||
{
|
||||
if (m_recordingProcess->state() == QProcess::NotRunning)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
LtsUtils::await(
|
||||
m_recordingProcess, QOverload<int, QProcess::ExitStatus>::of(&QProcess::finished), true,
|
||||
m_recordingProcess, &QProcess::errorOccurred, false,
|
||||
this, &TopicRecorder::cancel, false
|
||||
);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
ERROR_LOG(m_logger) << "waitForFinishedRecording: catch!";
|
||||
}
|
||||
|
||||
ERROR_LOG(m_logger) << "waitForFinishedRecording: done waiting!";
|
||||
}
|
||||
|
||||
|
||||
void TopicRecorder::onNewTime(qint64 time)
|
||||
{
|
||||
ERROR_LOG(m_logger) << "onNewTime: " << time << ", startTime: " << m_startTime;
|
||||
|
||||
switch (m_recordingState)
|
||||
{
|
||||
case RecordingState::Waiting:
|
||||
if (time < m_startTime)
|
||||
return;
|
||||
|
||||
ERROR_LOG(m_logger) << "onNewTime: started at " << time << " while startTime is " << m_startTime;
|
||||
|
||||
/*DEBUG*/ERROR_LOG(m_logger) << "Starting \"" << processToString(m_recordingProcess) << "\"";
|
||||
|
||||
m_recordingProcess->start();
|
||||
|
||||
m_recordingState = RecordingState::InProgress;
|
||||
|
||||
return;
|
||||
case RecordingState::InProgress:
|
||||
if (time < m_stopTime)
|
||||
return;
|
||||
|
||||
/*DEBUG*/ERROR_LOG(m_logger) << "Stopping recording for " << m_topicName;
|
||||
|
||||
m_recordingProcess->terminate();
|
||||
|
||||
m_recordingState = RecordingState::Done;
|
||||
|
||||
return;
|
||||
case RecordingState::Done:
|
||||
default:
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void TopicRecorder::onRecordingProcessFinished(int exitCode, QProcess::ExitStatus exitStatus)
|
||||
{
|
||||
m_recordingState = RecordingState::Done;
|
||||
/*DEBUG*/ERROR_LOG(m_logger) << "Recording finished for " << m_topicName << ", with exitCode=" << exitCode << " and exitStatus=" << exitStatus;
|
||||
|
||||
// if (exitStatus != QProcess::ExitStatus::NormalExit)
|
||||
// {
|
||||
// onExportFailed(L("Recording process crashed!"));
|
||||
// return;
|
||||
// }
|
||||
|
||||
// if (exitCode != 0)
|
||||
// {
|
||||
// onExportFailed(L("Recording process exited with exitCode %1").arg(exitCode));
|
||||
// return;
|
||||
// }
|
||||
|
||||
// /*DEBUG*/ERROR_LOG(m_logger) << "Starting \"" << processToString(m_cuttingProcess) << "\"";
|
||||
|
||||
// m_cuttingProcess->start();
|
||||
}
|
||||
|
||||
|
||||
//void TopicRecorder::onCuttingProcessFinished(int exitCode, QProcess::ExitStatus exitStatus)
|
||||
//{
|
||||
// /*DEBUG*/ERROR_LOG(m_logger) << "Cutting finished for " << m_topicName << ", with exitCode=" << exitCode << " and exitStatus=" << exitStatus;
|
||||
|
||||
//// if (exitCode != 0)
|
||||
//// {
|
||||
//// onExportFailed(L("Cutting process exited with exitCode %1").arg(exitCode));
|
||||
//// return;
|
||||
//// }
|
||||
//}
|
||||
|
||||
|
||||
QString TopicRecorder::processToString(QProcess *process)
|
||||
{
|
||||
return L("%1 %2").arg(process->program(), process->arguments().join(L(" ")));
|
||||
}
|
||||
|
||||
} // namespace PresentationManagement
|
||||
+93
@@ -0,0 +1,93 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* class for recording a single topic on a screen
|
||||
* $Id:
|
||||
* $HeadURL:
|
||||
* $Author:
|
||||
* Created by Hannes Fritsche, SLTE, 2023-11-06
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QObject>
|
||||
#include <QTemporaryFile>
|
||||
#include <QProcess>
|
||||
#include <Services/PresentationManagement/logger.h>
|
||||
|
||||
class Screen;
|
||||
|
||||
namespace PresentationManagement
|
||||
{
|
||||
|
||||
class TopicItem;
|
||||
|
||||
class TopicRecorder : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public: // methods
|
||||
TopicRecorder(const int topicId, const QString &topicName, const Screen *screen, qint32 offset,
|
||||
qint64 startTime, qint64 stopTime, const double topicX, const double topicY,
|
||||
const double topicW, const double topicH, QObject *parent = nullptr);
|
||||
~TopicRecorder();
|
||||
|
||||
|
||||
|
||||
|
||||
void cut();
|
||||
void save(const QString &saveToPath) noexcept(false);
|
||||
|
||||
|
||||
|
||||
void killAndClear();
|
||||
void waitForFinishedRecording();
|
||||
// void saveRecording(const QString &saveToPath);
|
||||
bool isFailed() const { return m_failed; }
|
||||
const QString &topicName() const { return m_topicName; }
|
||||
int topicId() const { return m_topicId; }
|
||||
|
||||
public Q_SLOTS:
|
||||
void onNewTime(qint64 time);
|
||||
|
||||
private: // other
|
||||
enum class RecordingState
|
||||
{
|
||||
Waiting,
|
||||
InProgress,
|
||||
Done
|
||||
};
|
||||
|
||||
signals:
|
||||
void exportFailed(const QString &errorMessage);
|
||||
void cancel();
|
||||
|
||||
private Q_SLOTS:
|
||||
void onRecordingProcessFinished(int exitCode, QProcess::ExitStatus exitStatus);
|
||||
// void onCuttingProcessFinished(int exitCode, QProcess::ExitStatus exitStatus);
|
||||
void onExportFailed(const QProcess::ProcessError error);
|
||||
void onExportFailed(const QString &errorMessage);
|
||||
|
||||
private: // methods
|
||||
static QString processToString(QProcess *process);
|
||||
|
||||
private: // attributes
|
||||
QProcess *m_recordingProcess { nullptr };
|
||||
// QProcess *m_cuttingProcess { nullptr };
|
||||
|
||||
bool m_hasRecordingDone { false };
|
||||
bool m_isWorking { false };
|
||||
|
||||
const qint64 m_startTime;
|
||||
const qint64 m_stopTime;
|
||||
const QString m_topicName;
|
||||
QTemporaryFile m_tmpRecordingFile;
|
||||
QTemporaryFile m_tmpCuttingFile;
|
||||
RecordingState m_recordingState { RecordingState::Waiting };
|
||||
const int m_topicId;
|
||||
bool m_failed { false };
|
||||
qint32 m_length;
|
||||
|
||||
LOGGER_T m_logger;
|
||||
}; // class TopicRecorder
|
||||
|
||||
} // namespace PresentationManagement
|
||||
+122
@@ -0,0 +1,122 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* class for recording a single topic on a screen
|
||||
* $Id:
|
||||
* $HeadURL:
|
||||
* $Author:
|
||||
* Created by Hannes Fritsche, SLTE, 2023-11-06
|
||||
*/
|
||||
|
||||
#include "pre_topic_shotter.h"
|
||||
#include "pre_screen.h"
|
||||
#include <QFile>
|
||||
#include <QThread>
|
||||
#include <QScreen>
|
||||
#include <QTimer>
|
||||
|
||||
|
||||
namespace PresentationManagement
|
||||
{
|
||||
|
||||
TopicShotter::TopicShotter(const int topicId, const QString &topicName, const Screen *screen, qint32 offset,
|
||||
qint64 startTime, qint64 stopTime, const double topicX, const double topicY,
|
||||
const double topicW, const double topicH, const bool isFilterTopic, const QString &desc, QObject *parent)
|
||||
: QObject(parent)
|
||||
, m_startTime(startTime)
|
||||
, m_topicName(topicName)
|
||||
, m_topicId(topicId)
|
||||
, m_screen(screen)
|
||||
, m_topicX(topicX)
|
||||
, m_topicY(topicY)
|
||||
, m_topicW(topicW)
|
||||
, m_topicH(topicH)
|
||||
, m_desc(desc)
|
||||
, m_isFilterTopic(isFilterTopic)
|
||||
, m_logger(getLogger("TopicShotter"))
|
||||
{}
|
||||
|
||||
|
||||
TopicShotter::~TopicShotter()
|
||||
{}
|
||||
|
||||
|
||||
void TopicShotter::saveRecording(const QString &saveToPath)
|
||||
{
|
||||
const QString newFilename(QStringLiteral("%1/%2.png").arg(saveToPath).arg(m_topicId));
|
||||
if (!m_tmpFile.rename(newFilename))
|
||||
{
|
||||
throw QStringLiteral("Failed to move screenshot from '%1' to '%2' ('%3')").arg(m_tmpFile.fileName(), saveToPath, newFilename);
|
||||
return;
|
||||
}
|
||||
|
||||
m_tmpFile.setAutoRemove(false); // keep file
|
||||
}
|
||||
|
||||
|
||||
void TopicShotter::onExportFailed(const QString &errorMessage)
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Export failed for topic '" << m_topicName << "': " << errorMessage;
|
||||
emit exportFailed(errorMessage);
|
||||
}
|
||||
|
||||
|
||||
void TopicShotter::onNewTime(qint64 time)
|
||||
{
|
||||
// filter topics start a second later (loading issues), so start time needs to be adjusted for them:
|
||||
const qint64 filterTopicDelay = (m_isFilterTopic ? 1000 : 0);
|
||||
const qint64 startTime = m_startTime + filterTopicDelay + 1000 /* + 1000 because onNewTime is triggered *before* all the playTopic calls >_> */;
|
||||
|
||||
DEBUG_LOG(m_logger) << "onNewTime: " << time << ", startTime: " << startTime << ", isFilterTopic? " << m_isFilterTopic << ", desc: " << m_desc;
|
||||
|
||||
if (time < startTime)
|
||||
return;
|
||||
|
||||
if (isStarted)
|
||||
return;
|
||||
isStarted = true;
|
||||
|
||||
DEBUG_LOG(m_logger) << "onNewTime: started at " << time << " while startTime is " << startTime;
|
||||
|
||||
if (!m_tmpFile.open()) // create file
|
||||
{
|
||||
onExportFailed(QStringLiteral("Can't create temporary file for screenshot at %1: %2").arg(m_tmpFile.fileName(), m_tmpFile.errorString()));
|
||||
return;
|
||||
}
|
||||
|
||||
const auto geo = m_screen->geometry();
|
||||
const double screenW = geo.width();
|
||||
const double screenH = geo.height();
|
||||
const qint32 inputX = geo.x() + (screenW * m_topicX);
|
||||
const qint32 inputY = geo.y() + (screenH * m_topicY);
|
||||
const qint32 inputW = (qint32)(screenW * m_topicW);
|
||||
const qint32 inputH = (qint32)(screenH * m_topicH);
|
||||
|
||||
QScreen *_screen = m_screen->window()->screen();
|
||||
if (!_screen)
|
||||
{
|
||||
onExportFailed(QStringLiteral("Can't get system window of screen!"));
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// defered start of grabWindow as the to-be-shotted widget needs to initialize first
|
||||
auto *t = new QTimer(this);
|
||||
t->setInterval(750);
|
||||
t->setSingleShot(true);
|
||||
t->start();
|
||||
|
||||
connect(t, &QTimer::timeout, this, [this, inputX, inputY, inputW, inputH, _screen]() // =>
|
||||
{
|
||||
const WId winId = m_screen->winId();
|
||||
DEBUG_LOG(m_logger) << "## CHEESE! ## grabWindow: x: " << inputX << ", y: " << inputY << ", w: " << inputW << ", h: " << inputH << ", name: " << m_topicName << ", id: " << m_topicId << ", desc: " << m_desc;
|
||||
const QPixmap pix = _screen->grabWindow(winId, inputX, inputY, inputW, inputH); // NOTE: LOCAL position for grabWindow!
|
||||
|
||||
if (!pix.save(&m_tmpFile, "PNG"))
|
||||
{
|
||||
onExportFailed(QStringLiteral("Can't save screenshot to file: %1").arg(m_tmpFile.errorString()));
|
||||
return;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
} // namespace PresentationManagement
|
||||
+67
@@ -0,0 +1,67 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* class for recording a single topic on a screen
|
||||
* $Id:
|
||||
* $HeadURL:
|
||||
* $Author:
|
||||
* Created by Hannes Fritsche, SLTE, 2023-11-06
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QObject>
|
||||
#include <QTemporaryFile>
|
||||
#include <QProcess>
|
||||
#include <Services/PresentationManagement/logger.h>
|
||||
|
||||
class Screen;
|
||||
|
||||
namespace PresentationManagement
|
||||
{
|
||||
|
||||
class TopicItem;
|
||||
|
||||
class TopicShotter : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public: // methods
|
||||
TopicShotter(const int topicId, const QString &topicName, const Screen *screen, qint32 offset,
|
||||
qint64 startTime, qint64 stopTime, const double topicX, const double topicY,
|
||||
const double topicW, const double topicH, const bool isFilterTopic,
|
||||
const QString &desc, QObject *parent = nullptr);
|
||||
~TopicShotter();
|
||||
|
||||
void saveRecording(const QString &saveToPath);
|
||||
bool isFailed() const { return m_failed; }
|
||||
const QString &topicName() const { return m_topicName; }
|
||||
int topicId() const { return m_topicId; }
|
||||
|
||||
public Q_SLOTS:
|
||||
void onNewTime(qint64 time);
|
||||
|
||||
signals:
|
||||
void exportFailed(const QString &errorMessage);
|
||||
|
||||
private Q_SLOTS:
|
||||
void onExportFailed(const QString &errorMessage);
|
||||
|
||||
private: // attributes
|
||||
const qint64 m_startTime;
|
||||
const QString m_topicName;
|
||||
QTemporaryFile m_tmpFile;
|
||||
const int m_topicId;
|
||||
bool m_failed { false };
|
||||
const Screen *m_screen;
|
||||
const double m_topicX;
|
||||
const double m_topicY;
|
||||
const double m_topicW;
|
||||
const double m_topicH;
|
||||
bool isStarted { false };
|
||||
const bool m_isFilterTopic;
|
||||
QString m_desc;
|
||||
|
||||
LOGGER_T m_logger;
|
||||
}; // class TopicShotter
|
||||
|
||||
} // namespace PresentationManagement
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
#include "pre_topic_track.h"
|
||||
|
||||
|
||||
namespace PresentationManagement
|
||||
{
|
||||
|
||||
TopicTrack::TopicTrack(const QString &text, const QString &internalName, TrackType trackType)
|
||||
: LtsTimeline::Track(text)
|
||||
, m_trackType(trackType)
|
||||
, m_internalName(internalName)
|
||||
{}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// PUBLIC
|
||||
|
||||
qint64 TopicTrack::firstTopicStart() const
|
||||
{
|
||||
return items().empty() ? -1 : items().front()->startTime();
|
||||
}
|
||||
|
||||
qint64 TopicTrack::lastTopicEnd() const
|
||||
{
|
||||
return items().empty() ? -1 : items().back()->startTime() + items().back()->duration();
|
||||
}
|
||||
|
||||
} // namespace PresentationManagement
|
||||
+31
@@ -0,0 +1,31 @@
|
||||
#pragma once
|
||||
|
||||
#include "pre_utils.h"
|
||||
|
||||
#include <LtsTimeline/track.h>
|
||||
|
||||
|
||||
namespace PresentationManagement
|
||||
{
|
||||
|
||||
class TopicTrack : public LtsTimeline::Track
|
||||
{
|
||||
|
||||
public:
|
||||
TopicTrack(const QString &text, const QString &internalName, TrackType trackType);
|
||||
|
||||
TrackType trackType() const { return m_trackType; }
|
||||
|
||||
QString internalName() const { return m_internalName; }
|
||||
void setInternalName(const QString &name) { m_internalName = name; }
|
||||
|
||||
qint64 firstTopicStart() const;
|
||||
qint64 lastTopicEnd() const;
|
||||
|
||||
private:
|
||||
TrackType m_trackType;
|
||||
QString m_internalName;
|
||||
|
||||
};
|
||||
|
||||
} // namespace PresentationManagement
|
||||
+30
@@ -0,0 +1,30 @@
|
||||
#include "pre_utils.h"
|
||||
|
||||
|
||||
namespace PresentationManagement
|
||||
{
|
||||
|
||||
QString trackTypeString(TrackType trackType)
|
||||
{
|
||||
switch (trackType)
|
||||
{
|
||||
case TrackType::Audio:
|
||||
return QStringLiteral("Audio");
|
||||
case TrackType::Replay:
|
||||
return QStringLiteral("Playback");
|
||||
case TrackType::Screen:
|
||||
return QStringLiteral("Screen");
|
||||
case TrackType::Filter:
|
||||
return QStringLiteral("Filter");
|
||||
}
|
||||
Q_UNREACHABLE();
|
||||
return {};
|
||||
}
|
||||
|
||||
std::ostream& operator<<(std::ostream& stream, TrackType trackType)
|
||||
{
|
||||
stream << "TrackType::" << trackTypeString(trackType).toStdString().c_str();
|
||||
return stream;
|
||||
}
|
||||
|
||||
}
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
#pragma once
|
||||
|
||||
#include <QVector>
|
||||
|
||||
|
||||
namespace PresentationManagement
|
||||
{
|
||||
|
||||
enum class TrackType
|
||||
{
|
||||
Audio,
|
||||
Replay,
|
||||
Screen,
|
||||
Filter
|
||||
};
|
||||
typedef QVector<TrackType> TrackTypes;
|
||||
|
||||
QString trackTypeString(TrackType trackType);
|
||||
|
||||
std::ostream& operator<<(std::ostream& stream, TrackType trackType);
|
||||
|
||||
} // PresentationManagement
|
||||
Reference in new issue
Block a user