<commit_before>#include "pch.h"
#include "RoomScene.h"
#include "NetworkScene.h"
#include "TcpClient.h"
#include "MultiGameScene.h"

#define GET_ROOM_STATE_LABEL dynamic_cast<Label*>(this->getChildByName("RoomStateLabel"))

Scene* RoomScene::createScene()
{
    auto scene = Scene::create();
    auto layer = RoomScene::create();
    scene->addChild(layer, 0, "RoomScene");
    return scene;
}

bool RoomScene::init()
{
    if (!LayerColor::initWithColor(Color4B(100, 100, 200, 255)))
    {
        return false;
    }

    m_RoomID = -1;
    m_IsReady = false;

    auto label1 = Label::createWithSystemFont("게임 시작", "Thonburi", 50);
    auto label2 = Label::createWithSystemFont("나가기", "Thonburi", 50);

    auto menuItem1 = MenuItemLabel::create(label1, CC_CALLBACK_1(RoomScene::menuCallback1, this));
    auto menuItem2 = MenuItemLabel::create(label2, CC_CALLBACK_1(RoomScene::menuCallback2, this));

    auto menu = Menu::create(menuItem1, menuItem2, NULL);
    menu->alignItemsVertically();
    this->addChild(menu, 0, "RoomMenu");

    auto label = Label::createWithSystemFont("연결 중...", "Thonburi", 50);
    label->setAnchorPoint(Vec2::ZERO);
    label->setHorizontalAlignment(TextHAlignment::CENTER);
    this->addChild(label, 0, "RoomStateLabel");

    // 1초 마다 Tick 함수를 호출한다.
    this->schedule(schedule_selector(RoomScene::Tick), 1.0f);
    return true;
}

void RoomScene::menuCallback1(Ref* sender)	// 게임 시작
{
    if (TcpClient::getInstance()->checkSocket() == NULL || m_IsReady)
        return;

    m_IsReady = true;
    TcpClient::getInstance()->startGameRequest(m_RoomID);
}

void RoomScene::menuCallback2(Ref* sender)	// 나가기
{
	if (TcpClient::getInstance()->checkSocket() != NULL)
		TcpClient::getInstance()->outRoomRequest(m_RoomID);

    m_IsReady = false;
    Director::getInstance()->popScene();
}

//////////////////////////////////////////////////////////////////////////
void RoomScene::Tick(float dt)
{
    auto label = GET_ROOM_STATE_LABEL;
    if(label == nullptr)
        return;

    // 방 번호를 문자열로 변환 후 라벨에 적용
    char buf[32];
    _itoa(m_RoomID, buf, 32);
    std::string roomNum = buf;
    roomNum += "번 방";
    label->setString(roomNum.c_str());
}
//////////////////////////////////////////////////////////////////////////

void RoomScene::GameStartComplete()
{
    auto scene = MultiGameScene::createScene();

    auto layer = dynamic_cast<MultiGameScene*>(scene->getChildByName("MultiGameScene"));
    layer->SetRoomID(m_RoomID);

    m_IsReady = false;
    Director::getInstance()->pushScene(scene);
}
<commit_msg>[C] roomscene 변경 . 지금은 캐릭터 고른데로 안됨<commit_after>#include "pch.h"
#include "RoomScene.h"
#include "NetworkScene.h"
#include "TcpClient.h"
#include "MultiGameScene.h"
#include "CharacterSelectLayer.h"

#define GET_ROOM_STATE_LABEL dynamic_cast<Label*>(this->getChildByName("RoomStateLabel"))

Scene* RoomScene::createScene()
{
    auto scene = Scene::create();
    auto layer = RoomScene::create();
    scene->addChild(layer, 0, "RoomScene");
    return scene;
}

bool RoomScene::init()
{
    if (!LayerColor::initWithColor(Color4B(100, 100, 200, 255)))
    {
        return false;
    }

    m_RoomID = -1;
    m_IsReady = false;
    auto winSize = Director::getInstance()->getWinSize();

    auto label1 = Label::createWithSystemFont("게임 시작", "Thonburi", 50);
    auto label2 = Label::createWithSystemFont("나가기", "Thonburi", 50);

    auto menuItem1 = MenuItemLabel::create(label1, CC_CALLBACK_1(RoomScene::menuCallback1, this));
    auto menuItem2 = MenuItemLabel::create(label2, CC_CALLBACK_1(RoomScene::menuCallback2, this));
    menuItem2->setPositionX(winSize.width * 1 / 8);

    auto menu = Menu::create(menuItem1, menuItem2, NULL);
    menu->alignItemsHorizontally();
    menu->setPosition(winSize.width * 3 / 8, winSize.height * 7 / 8);
    this->addChild(menu, 0, "RoomMenu");

    auto layer = CharacterSelectLayer::create();
    this->addChild(layer, 10, "CharacterSelectLayer");

    auto label = Label::createWithSystemFont("연결 중...", "Thonburi", 50);
    label->setAnchorPoint(Vec2::ZERO);
    label->setHorizontalAlignment(TextHAlignment::CENTER);
    this->addChild(label, 0, "RoomStateLabel");

    // 1초 마다 Tick 함수를 호출한다.
    this->schedule(schedule_selector(RoomScene::Tick), 1.0f);
    return true;
}

void RoomScene::menuCallback1(Ref* sender)	// 게임 시작
{
    if (TcpClient::getInstance()->checkSocket() == NULL || m_IsReady)
        return;

    m_IsReady = true;
    TcpClient::getInstance()->startGameRequest(m_RoomID);
}

void RoomScene::menuCallback2(Ref* sender)	// 나가기
{
    if (TcpClient::getInstance()->checkSocket() != NULL)
        TcpClient::getInstance()->outRoomRequest(m_RoomID);

    m_IsReady = false;
    Director::getInstance()->popScene();
}

//////////////////////////////////////////////////////////////////////////
void RoomScene::Tick(float dt)
{
    auto label = GET_ROOM_STATE_LABEL;
    if(label == nullptr)
        return;

    // 방 번호를 문자열로 변환 후 라벨에 적용
    char buf[32];
    _itoa(m_RoomID, buf, 32);
    std::string roomNum = buf;
    roomNum += "번 방";
    label->setString(roomNum.c_str());
}
//////////////////////////////////////////////////////////////////////////

void RoomScene::GameStartComplete()
{
    auto scene = MultiGameScene::createScene();

    auto layer = dynamic_cast<MultiGameScene*>(scene->getChildByName("MultiGameScene"));
    layer->SetRoomID(m_RoomID);

    m_IsReady = false;
    Director::getInstance()->pushScene(scene);
}
<|endoftext|>


<commit_before>#include "pdfview.h"

#include <QKeyEvent>
#include <QPainter>
#include <QDebug>
#include <stdio.h>

#include <iostream>

class FitPageScaler : public ScalingStrategy {
public:
  virtual QImage scaleAndRender(const Poppler::Page *page, const QWidget *widget) {
    QSizeF pageSize = page->pageSizeF();
    qreal win = pageSize.width() / 72., hin = pageSize.height() / 72.;
    qreal xsc = widget->width() / win, ysc = widget->height() / hin;

    qreal scale = qMin(xsc, ysc);

    return page->renderToImage(scale, scale);
  }
};

class TextScaler : public ScalingStrategy {
public:
  virtual QImage scaleAndRender(const Poppler::Page *page, const QWidget *widget) {
    QList<Poppler::TextBox *> textBoxen = page->textList();
    QRectF bounds;
     while (!textBoxen.isEmpty()) {
        Poppler::TextBox *box = textBoxen.takeFirst();
        bounds = bounds.united(box->boundingBox());
        delete box;
     }

    bounds.adjust(-4, -4, 8, 8);

     qreal win = bounds.width() / 72., hin = bounds.height() / 72.;
     qreal xsc = widget->width() / win, ysc = widget->height() / hin;

    qreal scale = qMin(xsc, ysc);
    QRectF viewRect(bounds.left() / 72. * scale, bounds.top() / 72. * scale,
        bounds.width() / 72. * scale, bounds.height() / 72. * scale);

/*    viewRect.adjust(
        widget->width() - viewRect.width() / 2,
        widget->height() - viewRect.height() / 2,
        widget->width() - viewRect.width(),
        widget->height() - viewRect.height());*/

    return page->renderToImage(scale, scale,
         viewRect.left(), viewRect.top(), viewRect.width(), viewRect.height());
  }
};

PdfView::PdfView(QWidget *parent)
    : QLabel(parent) {
  pageIndex = 0;
  pageIndexEntry = 0;
  doc = 0;

  scalingStrategies << new FitPageScaler() << new TextScaler();
  scalerIndex = 0;
}

PdfView::~PdfView() {
  while (!scalingStrategies.isEmpty()) {
    delete scalingStrategies.takeFirst();
  }

  delete doc;
}

Poppler::Document *PdfView::document() {
  return doc;
}

ScalingStrategy *PdfView::scaler() {
  return scalingStrategies[scalerIndex];
}

void PdfView::zoomIn() {
  if (scalerIndex < scalingStrategies.size() - 1) {
    scalerIndex++;
    showPage(pageIndex);
  }
}

void PdfView::zoomOut() {
  if (scalerIndex > 0) {
    scalerIndex--;
    showPage(pageIndex);
  }
}

void PdfView::resizeEvent(QResizeEvent *event) {
  QLabel::resizeEvent(event);
  showPage(pageIndex);
}

void PdfView::showPage(int newPage) {
  if (newPage != pageIndex) {
    pageIndex = newPage;
    emit pageChanged(newPage);
  }

  Poppler::Page *page = doc->page(newPage);
  QImage image = scaler()->scaleAndRender(page, this);

  setPixmap(QPixmap::fromImage(image));
}

void PdfView::paintEvent(QPaintEvent *event) {
  QLabel::paintEvent(event);

  if (pageIndexEntry > 0) {
    QPainter painter;
    painter.begin(this);
    QFont font("Arial", 72);
    painter.setFont(font);
    painter.drawText(0, 200, "Goto page:");
    painter.drawText(0, 400, QString::number(pageIndexEntry));

    painter.end();
  }
}

bool PdfView::setDocument(const QString &path) {
  Poppler::Document *oldDoc = doc;

  doc = Poppler::Document::load(path);
  delete oldDoc;

  if (doc) {
    doc->setRenderHint(Poppler::Document::Antialiasing);
    doc->setRenderHint(Poppler::Document::TextAntialiasing);
    showPage(0);
  }

  return doc;
}

void PdfView::keyPressEvent(QKeyEvent *event) {
  if (event->key() == Qt::Key_Down && pageIndex < doc->numPages()) {
    showPage(pageIndex + 1);
  } else if (event->key() == Qt::Key_Up && pageIndex > 0) {
    showPage(pageIndex - 1);
  } else if (event->key() == Qt::Key_Plus) {
    zoomIn();
  } else if (event->key() == Qt::Key_Minus) {
    zoomOut();
  } else if (event->key() >= Qt::Key_0 && event->key() <= Qt::Key_9) {
    pageIndexEntry = (pageIndexEntry * 10) + (event->key() - Qt::Key_0);
    update();
  } else if (event->key() == Qt::Key_Escape) {
    emit back();
  } else if (event->key() == Qt::Key_Return && pageIndexEntry > 0) {
    showPage(pageIndexEntry - 1);
    pageIndexEntry = 0;
  } else {
    QLabel::keyPressEvent(event);
  }
}
<commit_msg>Fixed a truncating real->int conversion in PDF scaling.<commit_after>#include "pdfview.h"

#include <QKeyEvent>
#include <QPainter>
#include <QDebug>
#include <stdio.h>

#include <iostream>

class FitPageScaler : public ScalingStrategy {
public:
  virtual QImage scaleAndRender(const Poppler::Page *page, const QWidget *widget) {
    QSizeF pageSize = page->pageSizeF();
    qreal win = pageSize.width() / 72., hin = pageSize.height() / 72.;
    qreal xsc = widget->width() / win, ysc = widget->height() / hin;

    qreal scale = qMin(xsc, ysc);

    return page->renderToImage(scale, scale);
  }
};

class TextScaler : public ScalingStrategy {
public:
  virtual QImage scaleAndRender(const Poppler::Page *page, const QWidget *widget) {
    QList<Poppler::TextBox *> textBoxen = page->textList();
    QRectF bounds;
     while (!textBoxen.isEmpty()) {
        Poppler::TextBox *box = textBoxen.takeFirst();
        bounds = bounds.united(box->boundingBox());
        delete box;
     }

    bounds.adjust(-4, -4, 8, 8);

     qreal win = bounds.width() / 72., hin = bounds.height() / 72.;
     qreal xsc = widget->width() / win, ysc = widget->height() / hin;

    qreal scale = qMin(xsc, ysc);
    QRectF viewRect(bounds.left() / 72. * scale, bounds.top() / 72. * scale,
        bounds.width() / 72. * scale, bounds.height() / 72. * scale);

    QRect iRect = viewRect.toAlignedRect();

    return page->renderToImage(scale, scale,
         iRect.left(), iRect.top(), iRect.width(), iRect.height());
  }
};

PdfView::PdfView(QWidget *parent)
    : QLabel(parent) {
  pageIndex = 0;
  pageIndexEntry = 0;
  doc = 0;

  scalingStrategies << new FitPageScaler() << new TextScaler();
  scalerIndex = 0;
}

PdfView::~PdfView() {
  while (!scalingStrategies.isEmpty()) {
    delete scalingStrategies.takeFirst();
  }

  delete doc;
}

Poppler::Document *PdfView::document() {
  return doc;
}

ScalingStrategy *PdfView::scaler() {
  return scalingStrategies[scalerIndex];
}

void PdfView::zoomIn() {
  if (scalerIndex < scalingStrategies.size() - 1) {
    scalerIndex++;
    showPage(pageIndex);
  }
}

void PdfView::zoomOut() {
  if (scalerIndex > 0) {
    scalerIndex--;
    showPage(pageIndex);
  }
}

void PdfView::resizeEvent(QResizeEvent *event) {
  QLabel::resizeEvent(event);
  showPage(pageIndex);
}

void PdfView::showPage(int newPage) {
  if (newPage != pageIndex) {
    pageIndex = newPage;
    emit pageChanged(newPage);
  }

  Poppler::Page *page = doc->page(newPage);
  QImage image = scaler()->scaleAndRender(page, this);

  setPixmap(QPixmap::fromImage(image));
}

void PdfView::paintEvent(QPaintEvent *event) {
  QLabel::paintEvent(event);

  if (pageIndexEntry > 0) {
    QPainter painter;
    painter.begin(this);
    QFont font("Arial", 72);
    painter.setFont(font);
    painter.drawText(0, 200, "Goto page:");
    painter.drawText(0, 400, QString::number(pageIndexEntry));

    painter.end();
  }
}

bool PdfView::setDocument(const QString &path) {
  Poppler::Document *oldDoc = doc;

  doc = Poppler::Document::load(path);
  delete oldDoc;

  if (doc) {
    doc->setRenderHint(Poppler::Document::Antialiasing);
    doc->setRenderHint(Poppler::Document::TextAntialiasing);
    showPage(0);
  }

  return doc;
}

void PdfView::keyPressEvent(QKeyEvent *event) {
  if (event->key() == Qt::Key_Down && pageIndex < doc->numPages()) {
    showPage(pageIndex + 1);
  } else if (event->key() == Qt::Key_Up && pageIndex > 0) {
    showPage(pageIndex - 1);
  } else if (event->key() == Qt::Key_Plus) {
    zoomIn();
  } else if (event->key() == Qt::Key_Minus) {
    zoomOut();
  } else if (event->key() >= Qt::Key_0 && event->key() <= Qt::Key_9) {
    pageIndexEntry = (pageIndexEntry * 10) + (event->key() - Qt::Key_0);
    update();
  } else if (event->key() == Qt::Key_Escape) {
    emit back();
  } else if (event->key() == Qt::Key_Return && pageIndexEntry > 0) {
    showPage(pageIndexEntry - 1);
    pageIndexEntry = 0;
  } else {
    QLabel::keyPressEvent(event);
  }
}
<|endoftext|>


<commit_before>// https://github.com/KubaO/stackoverflown/tree/master/questions/scene-print-37708423
#include <QtWidgets>
#include <QtPrintSupport>

int main(int argc, char *argv[])
{
   QApplication app(argc, argv);
   QGraphicsScene scene;
   QGraphicsView view(&scene);

   auto in = 72.0f;
   auto pen = QPen(Qt::black, 0.01*in);
   QRectF canvasRect(0, 0, 4*in, 4*in);
   // this is to show actual scene
   QGraphicsRectItem sss(canvasRect);
   sss.setPen(pen);
   sss.setBrush(Qt::blue);
   scene.addItem(&sss);
   // this item is partially outside top left
   QGraphicsEllipseItem e1(-0.5*in, -0.5*in, 1*in, 1*in);
   e1.setPen(pen);
   e1.setBrush(Qt::yellow);
   scene.addItem(&e1);
   // this item is partially outside center
   QGraphicsEllipseItem e2(2*in, 2*in, 2.5*in, 1*in);
   e2.setPen(pen);
   e2.setBrush(Qt::yellow);
   scene.addItem(&e2);
   // this item is partially outside right
   QGraphicsEllipseItem e3(3.5*in, 3.5*in, 1*in, 1*in);
   e3.setPen(pen);
   e3.setBrush(Qt::yellow);
   scene.addItem(&e3);

   view.fitInView(scene.sceneRect(), Qt::KeepAspectRatio);
   view.show();

   QPrinter printer;
   QPrintDialog printDialog(&printer);
   QObject::connect(&printDialog, &QDialog::accepted, [&]{
      printer.setOrientation(QPrinter::Landscape);
      QPainter painter(&printer);

      auto source = canvasRect;
      auto scale = printer.resolution()/in;
      auto page = printer.pageRect(QPrinter::DevicePixel);
      auto target = QRectF(page.topLeft(), source.size()*scale);
      target &= page; // clip target rect to page
      qDebug() << page << scale << source << target;
      scene.render(&painter, target, source);
   });
   printDialog.show(); // modal on OS X thus must succeed `connect` above
   return app.exec();
}
<commit_msg>Comment fix.<commit_after>// https://github.com/KubaO/stackoverflown/tree/master/questions/scene-print-37708423
#include <QtWidgets>
#include <QtPrintSupport>

int main(int argc, char *argv[])
{
   QApplication app(argc, argv);
   QGraphicsScene scene;
   QGraphicsView view(&scene);

   auto in = 72.0f;
   auto pen = QPen(Qt::black, 0.01*in);
   QRectF canvasRect(0, 0, 4*in, 4*in);
   // this is to show actual scene
   QGraphicsRectItem sss(canvasRect);
   sss.setPen(pen);
   sss.setBrush(Qt::blue);
   scene.addItem(&sss);
   // this item is partially outside top left
   QGraphicsEllipseItem e1(-0.5*in, -0.5*in, 1*in, 1*in);
   e1.setPen(pen);
   e1.setBrush(Qt::yellow);
   scene.addItem(&e1);
   // this item is partially outside center
   QGraphicsEllipseItem e2(2*in, 2*in, 2.5*in, 1*in);
   e2.setPen(pen);
   e2.setBrush(Qt::yellow);
   scene.addItem(&e2);
   // this item is partially outside right
   QGraphicsEllipseItem e3(3.5*in, 3.5*in, 1*in, 1*in);
   e3.setPen(pen);
   e3.setBrush(Qt::yellow);
   scene.addItem(&e3);

   view.fitInView(scene.sceneRect(), Qt::KeepAspectRatio);
   view.show();

   QPrinter printer;
   QPrintDialog printDialog(&printer);
   QObject::connect(&printDialog, &QDialog::accepted, [&]{
      printer.setOrientation(QPrinter::Landscape);
      QPainter painter(&printer);

      auto source = canvasRect;
      auto scale = printer.resolution()/in;
      auto page = printer.pageRect(QPrinter::DevicePixel);
      auto target = QRectF(page.topLeft(), source.size()*scale);
      target &= page; // clip target rect to page
      qDebug() << page << scale << source << target;
      scene.render(&painter, target, source);
   });
   printDialog.show(); // modal on OS X thus must follow `connect` above
   return app.exec();
}
<|endoftext|>


<commit_before>/* main.cpp - main entry point for the command-line tool `dm`
 *
 * The current implementation is specific to chains of integrators;
 * however, the design is intended to be general to facilitate later
 * treatment of other kinds of systems.
 *
 * While some infrastructure is in place for building without ROS, it
 * is as yet not operational.
 *
 *
 * SCL; 2015
 */

#ifdef USE_ROS
#include <ros/ros.h>
#include "dynamaestro/VectorStamped.h"
#include "dynamaestro/LabelStamped.h"
#include "dynamaestro/DMMode.h"
#endif

#include "problem.h"

#include <cstdlib>
#include <cstdio>
#include <assert.h>

#include <Eigen/Dense>
#include <boost/thread/thread.hpp>

/* The trajectories are the solutions of a linear time-invariant control
   system. Control input is applied using a zero-order hold, i.e., applied
   constantly during the duration given as the first parameter of step().

   Let m be the highest order of derivative, and let n be the dimension of the
   output space.  The state variable indexing is such that the first output
   variable is the first state variable, the second output variable is the
   second state variable, etc. Thus the component systems are interleaved in the
   sense that the first subsystem is formed from state variable indices 1, 1+n,
   1+2n, ..., 1+(m-1)n, and the input to this subsystem is applied at state
   variable index 1+(m-1)n.
*/
/** \ingroup integrator_chains */
class TrajectoryGenerator {
private:
	Eigen::VectorXd X;
	double t;  // Current time
	int highest_order_deriv;
	int numdim_output;

	Eigen::VectorXd Xinit;

public:
	TrajectoryGenerator( int numdim_output, int highest_order_deriv );

	/* Consult the class description regarding the assumed arrangement of the
	   state variables, i.e., the indexing and the assumption that the system is
	   a chain of integrators. */
	TrajectoryGenerator( Eigen::VectorXd Xinit, int numdim_output );

	void clear();

	/* Forward Euler integration for duration dt using constant input U */
	double step( double dt, const Eigen::VectorXd &U );

	double getTime() const
		{ return t; }
	double getStateDim() const
		{ return X.size(); }
	double getOutputDim() const
		{ return numdim_output; }

	// Output vector
	double operator[]( int i ) const;

	/* Access to full, current state vector */
	double getState( int i ) const
		{ return X[i]; }
};

TrajectoryGenerator::TrajectoryGenerator( int numdim_output, int highest_order_deriv )
	: t(0.0),
	  highest_order_deriv(highest_order_deriv), numdim_output(numdim_output)
{
	X.resize( numdim_output*highest_order_deriv );
	X.setZero();
	Xinit = X;
}

TrajectoryGenerator::TrajectoryGenerator( Eigen::VectorXd Xinit, int numdim_output  )
	: t(0.0), Xinit(Xinit), X(Xinit), numdim_output(numdim_output)
{
	assert( X.size() % numdim_output == 0 );
	highest_order_deriv = X.size()/numdim_output;
}

void TrajectoryGenerator::clear()
{
	X = Xinit;
	t = 0.0;
}

double TrajectoryGenerator::step( double dt, const Eigen::VectorXd &U )
{
	if (U.size() > numdim_output) {
		ROS_ERROR( "Input vector has too many elements." );
		return 0.0/0.0;
	}

	int numdim_state = X.size();

	int i, j;
	for (j = 0; j < numdim_output; j++) {
		for (i = 0; i <= highest_order_deriv-2; i++) {
			X[i*numdim_output+j] += dt*X[(i+1)*numdim_output+j];
		}
		X[(highest_order_deriv-1)*numdim_output+j] += dt*U[j];
	}

	t += dt;
	return t;
}

double TrajectoryGenerator::operator[]( int i ) const
{
	if (i < numdim_output) {
		return X[i];
	} else {
		ROS_ERROR( "Invalid index into output vector: %d", i );
		return 0.0/0.0;
	}
}

/** \ingroup integrator_chains */
class TGThread {
private:
	boost::mutex mtx_;
	bool fresh_input;
	Eigen::VectorXd U;

	Problem *probinstance;
	Labeler labeler;

	enum DMMode { ready, waiting, running, paused, resetting, restarting };
	DMMode dmmode;

	ros::NodeHandle &nh_;
	ros::ServiceServer mode_srv;
	ros::Publisher statepub;
	ros::Publisher loutpub;
	ros::Subscriber inputsub;

public:
	TGThread( ros::NodeHandle &nh );
	~TGThread();
	void inputcb( const dynamaestro::VectorStamped &vs );
	bool mode_request( dynamaestro::DMMode::Request &req,
					   dynamaestro::DMMode::Response &res );
	void run();
	void pubstate( const TrajectoryGenerator &tg, Eigen::VectorXd &Y );
};

TGThread::TGThread( ros::NodeHandle &nh )
	: nh_(nh),
	  fresh_input(false),
	  U(),
	  probinstance(NULL),
	  labeler(),
	  dmmode(paused)
{
	mode_srv = nh_.advertiseService( "mode", &TGThread::mode_request, this );
	statepub = nh_.advertise<dynamaestro::VectorStamped>( "output", 10, true );
	loutpub = nh_.advertise<dynamaestro::LabelStamped>( "loutput", 10, true );
	inputsub = nh_.subscribe( "input", 1, &TGThread::inputcb, this );
}

TGThread::~TGThread()
{
	if (probinstance)
		delete probinstance;
}

void TGThread::pubstate( const TrajectoryGenerator &tg, Eigen::VectorXd &Y )
{
	dynamaestro::VectorStamped pt;
	pt.header.frame_id = std::string( "map" );
	pt.header.stamp = ros::Time::now();
	for (int i = 0; i < tg.getStateDim(); i++) {
		pt.v.point.push_back( tg.getState( i ) );
		if (i < tg.getOutputDim())
			Y(i) = tg[i];
	}
	statepub.publish( pt );

	std::list<std::string> label = labeler.get_label( Y );
	dynamaestro::LabelStamped lbl;
	lbl.header.frame_id = pt.header.frame_id;
	lbl.header.stamp = pt.header.stamp;
	lbl.label.resize( label.size() );
	int i = 0;
	for (std::list<std::string>::iterator it_label = label.begin();
		 it_label != label.end(); it_label++) {
		lbl.label[i] = *it_label;
		i++;
	}
	loutpub.publish( lbl );
}

bool TGThread::mode_request( dynamaestro::DMMode::Request &req,
							 dynamaestro::DMMode::Response &res )
{
	switch (req.mode) {
	case dynamaestro::DMMode::Request::UNPAUSE:
		if (dmmode != running)
			dmmode = running;
		res.result = true;
		break;

	case dynamaestro::DMMode::Request::READY:
		if (dmmode == ready) {
			res.result = true;
		} else {
			res.result = false;
		}
		break;

	case dynamaestro::DMMode::Request::START:
		if (dmmode == ready) {
			dmmode = waiting;
			res.result = true;
		} else {
			res.result = false;
		}
		break;

	case dynamaestro::DMMode::Request::PAUSE:
		if (dmmode == running) {
			dmmode = paused;
			fresh_input = false;
		}
		res.result = true;
		break;

	case dynamaestro::DMMode::Request::RESTART:
		dmmode = restarting;
		ROS_INFO( "dynamaestro: Restarting trial..." );
		res.result = true;
		break;

	case dynamaestro::DMMode::Request::RESET:
		dmmode = resetting;
		ROS_INFO( "dynamaestro: Stopping current trial and generating a new instance..." );
		res.result = true;
		break;

	default:
		return false;
	}

	return true;
}

void TGThread::inputcb( const dynamaestro::VectorStamped &vs )
{
	assert( probinstance != NULL );

	mtx_.lock();

	fresh_input = true;
	for (int i = 0; i < probinstance->get_numdim_output(); i++)
		U[i] = vs.v.point[i];

	mtx_.unlock();
}

void TGThread::run()
{
	Eigen::Vector2i numdim_output_bounds( 1, 3 );
	Eigen::Vector2i num_integrators_bounds( 1, 3 );

	Eigen::VectorXd Y_max( 2*numdim_output_bounds(1) );
	for (int i = 0; i < numdim_output_bounds(1); i++) {
		Y_max(2*i+1) = 10;
		Y_max(2*i) = -Y_max(2*i+1);
	}

	Eigen::VectorXd U_max( 2*numdim_output_bounds(1) );
	for (int i = 0; i < numdim_output_bounds(1); i++) {
		U_max(2*i+1) = 1;
		U_max(2*i) = -U_max(2*i+1);
	}

	Eigen::Vector2d period_bounds( 0.05, 0.1 );

	probinstance = Problem::random( numdim_output_bounds,
									num_integrators_bounds,
									Y_max, U_max, 2, 1, period_bounds );
	labeler.importProblem( *probinstance );

	U.resize( probinstance->get_numdim_output() );
	U.setZero();

	Eigen::VectorXd Y( probinstance->get_numdim_output() );

	TrajectoryGenerator tg( probinstance->Xinit,
							probinstance->get_numdim_output() );

	ros::Rate rate( 1/probinstance->period );
	Eigen::VectorXd defaultU( U );
	defaultU.setZero();

	ros::Rate polling_rate( 100 );
	dmmode = ready;
	while (dmmode == ready) {
		ros::spinOnce();
		polling_rate.sleep();
	}
	assert( dmmode == waiting );

	nh_.setParam( "probleminstance", probinstance->dumpJSON() );

	nh_.setParam( "number_integrators",
				  probinstance->get_highest_order_deriv() );
	ROS_INFO( "dynamaestro: Using %d as number of integrators.",
			  probinstance->get_highest_order_deriv() );

	nh_.setParam( "output_dim", probinstance->get_numdim_output() );
	ROS_INFO( "dynamaestro: Using %d as dimension of the output space.",
			  probinstance->get_numdim_output() );

	nh_.setParam( "period", probinstance->period );
	ROS_INFO( "dynamaestro: Using %f seconds as the period.",
			  probinstance->period );

	// Send initial output, before any input is applied or time has begun.
	pubstate( tg, Y );
	ros::spinOnce();

	while (ros::ok() && dmmode != resetting) {
		if (dmmode == running) {
			if (fresh_input) {
				mtx_.lock();

				fresh_input = false;
				tg.step( probinstance->period, U );

				mtx_.unlock();
			} else {
				tg.step( probinstance->period, defaultU );
			}

			pubstate( tg, Y );

		} else if (dmmode == restarting) {
			dmmode = paused;
			mtx_.lock();
			fresh_input = false;
			mtx_.unlock();
			tg.clear();
			U.setZero();
			pubstate( tg, Y );
			dmmode = waiting;
		} else if (dmmode == waiting) {
			if (fresh_input) {
				dmmode = running;
			} else {
				pubstate( tg, Y );
			}
		}
		ros::spinOnce();
		rate.sleep();
	}

	// Clear registered instance
	ROS_INFO( "dynamaestro: Clearing problem instance from Parameter Server." );
	nh_.setParam( "probleminstance", "" );
	nh_.setParam( "number_integrators", -1 );
	nh_.setParam( "output_dim", -1 );
	nh_.setParam( "period", -1.0 );
}

void tgthread( ros::NodeHandle &nhp )
{
	TGThread tgt( nhp );
	tgt.run();
}

int main( int argc, char **argv )
{
#ifdef USE_ROS
	ros::init( argc, argv, "dynamaestro" );
	ros::NodeHandle nh( "~" );

	time_t seed = time( NULL );
	srand( seed );
	ROS_INFO( "dynamaestro: Using %ld as the PRNG seed.", seed );

	boost::thread *tgmain = NULL;
	while (ros::ok()) {
		tgmain = new boost::thread( tgthread, nh );
		tgmain->join();
		delete tgmain;
	}

#endif
	return 0;
}
<commit_msg>Random trial durations for integrator_chains<commit_after>/* main.cpp - main entry point for the command-line tool `dm`
 *
 * The current implementation is specific to chains of integrators;
 * however, the design is intended to be general to facilitate later
 * treatment of other kinds of systems.
 *
 * While some infrastructure is in place for building without ROS, it
 * is as yet not operational.
 *
 *
 * SCL; 2015
 */

#ifdef USE_ROS
#include <ros/ros.h>
#include "dynamaestro/VectorStamped.h"
#include "dynamaestro/LabelStamped.h"
#include "dynamaestro/DMMode.h"
#endif

#include "problem.h"

#include <cstdlib>
#include <cstdio>
#include <assert.h>

#include <Eigen/Dense>
#include <boost/thread/thread.hpp>

/* The trajectories are the solutions of a linear time-invariant control
   system. Control input is applied using a zero-order hold, i.e., applied
   constantly during the duration given as the first parameter of step().

   Let m be the highest order of derivative, and let n be the dimension of the
   output space.  The state variable indexing is such that the first output
   variable is the first state variable, the second output variable is the
   second state variable, etc. Thus the component systems are interleaved in the
   sense that the first subsystem is formed from state variable indices 1, 1+n,
   1+2n, ..., 1+(m-1)n, and the input to this subsystem is applied at state
   variable index 1+(m-1)n.
*/
/** \ingroup integrator_chains */
class TrajectoryGenerator {
private:
	Eigen::VectorXd X;
	double t;  // Current time
	int highest_order_deriv;
	int numdim_output;

	Eigen::VectorXd Xinit;

public:
	TrajectoryGenerator( int numdim_output, int highest_order_deriv );

	/* Consult the class description regarding the assumed arrangement of the
	   state variables, i.e., the indexing and the assumption that the system is
	   a chain of integrators. */
	TrajectoryGenerator( Eigen::VectorXd Xinit, int numdim_output );

	void clear();

	/* Forward Euler integration for duration dt using constant input U */
	double step( double dt, const Eigen::VectorXd &U );

	double getTime() const
		{ return t; }
	double getStateDim() const
		{ return X.size(); }
	double getOutputDim() const
		{ return numdim_output; }

	// Output vector
	double operator[]( int i ) const;

	/* Access to full, current state vector */
	double getState( int i ) const
		{ return X[i]; }
};

TrajectoryGenerator::TrajectoryGenerator( int numdim_output, int highest_order_deriv )
	: t(0.0),
	  highest_order_deriv(highest_order_deriv), numdim_output(numdim_output)
{
	X.resize( numdim_output*highest_order_deriv );
	X.setZero();
	Xinit = X;
}

TrajectoryGenerator::TrajectoryGenerator( Eigen::VectorXd Xinit, int numdim_output  )
	: t(0.0), Xinit(Xinit), X(Xinit), numdim_output(numdim_output)
{
	assert( X.size() % numdim_output == 0 );
	highest_order_deriv = X.size()/numdim_output;
}

void TrajectoryGenerator::clear()
{
	X = Xinit;
	t = 0.0;
}

double TrajectoryGenerator::step( double dt, const Eigen::VectorXd &U )
{
	if (U.size() > numdim_output) {
		ROS_ERROR( "Input vector has too many elements." );
		return 0.0/0.0;
	}

	int numdim_state = X.size();

	int i, j;
	for (j = 0; j < numdim_output; j++) {
		for (i = 0; i <= highest_order_deriv-2; i++) {
			X[i*numdim_output+j] += dt*X[(i+1)*numdim_output+j];
		}
		X[(highest_order_deriv-1)*numdim_output+j] += dt*U[j];
	}

	t += dt;
	return t;
}

double TrajectoryGenerator::operator[]( int i ) const
{
	if (i < numdim_output) {
		return X[i];
	} else {
		ROS_ERROR( "Invalid index into output vector: %d", i );
		return 0.0/0.0;
	}
}

/** \ingroup integrator_chains */
class TGThread {
private:
	boost::mutex mtx_;
	bool fresh_input;
	Eigen::VectorXd U;

	Problem *probinstance;
	Labeler labeler;

	enum DMMode { ready, waiting, running, paused, resetting, restarting };
	DMMode dmmode;

	ros::NodeHandle &nh_;
	ros::ServiceServer mode_srv;
	ros::Publisher statepub;
	ros::Publisher loutpub;
	ros::Subscriber inputsub;

public:
	TGThread( ros::NodeHandle &nh );
	~TGThread();
	void inputcb( const dynamaestro::VectorStamped &vs );
	bool mode_request( dynamaestro::DMMode::Request &req,
					   dynamaestro::DMMode::Response &res );
	void run();
	void pubstate( const TrajectoryGenerator &tg, Eigen::VectorXd &Y );
};

TGThread::TGThread( ros::NodeHandle &nh )
	: nh_(nh),
	  fresh_input(false),
	  U(),
	  probinstance(NULL),
	  labeler(),
	  dmmode(paused)
{
	mode_srv = nh_.advertiseService( "mode", &TGThread::mode_request, this );
	statepub = nh_.advertise<dynamaestro::VectorStamped>( "output", 10, true );
	loutpub = nh_.advertise<dynamaestro::LabelStamped>( "loutput", 10, true );
	inputsub = nh_.subscribe( "input", 1, &TGThread::inputcb, this );
}

TGThread::~TGThread()
{
	if (probinstance)
		delete probinstance;
}

void TGThread::pubstate( const TrajectoryGenerator &tg, Eigen::VectorXd &Y )
{
	dynamaestro::VectorStamped pt;
	pt.header.frame_id = std::string( "map" );
	pt.header.stamp = ros::Time::now();
	for (int i = 0; i < tg.getStateDim(); i++) {
		pt.v.point.push_back( tg.getState( i ) );
		if (i < tg.getOutputDim())
			Y(i) = tg[i];
	}
	statepub.publish( pt );

	std::list<std::string> label = labeler.get_label( Y );
	dynamaestro::LabelStamped lbl;
	lbl.header.frame_id = pt.header.frame_id;
	lbl.header.stamp = pt.header.stamp;
	lbl.label.resize( label.size() );
	int i = 0;
	for (std::list<std::string>::iterator it_label = label.begin();
		 it_label != label.end(); it_label++) {
		lbl.label[i] = *it_label;
		i++;
	}
	loutpub.publish( lbl );
}

bool TGThread::mode_request( dynamaestro::DMMode::Request &req,
							 dynamaestro::DMMode::Response &res )
{
	switch (req.mode) {
	case dynamaestro::DMMode::Request::UNPAUSE:
		if (dmmode != running)
			dmmode = running;
		res.result = true;
		break;

	case dynamaestro::DMMode::Request::READY:
		if (dmmode == ready) {
			res.result = true;
		} else {
			res.result = false;
		}
		break;

	case dynamaestro::DMMode::Request::START:
		if (dmmode == ready) {
			dmmode = waiting;
			res.result = true;
		} else {
			res.result = false;
		}
		break;

	case dynamaestro::DMMode::Request::PAUSE:
		if (dmmode == running) {
			dmmode = paused;
			fresh_input = false;
		}
		res.result = true;
		break;

	case dynamaestro::DMMode::Request::RESTART:
		dmmode = restarting;
		ROS_INFO( "dynamaestro: Restarting trial..." );
		res.result = true;
		break;

	case dynamaestro::DMMode::Request::RESET:
		dmmode = resetting;
		ROS_INFO( "dynamaestro: Stopping current trial and generating a new instance..." );
		res.result = true;
		break;

	default:
		return false;
	}

	return true;
}

void TGThread::inputcb( const dynamaestro::VectorStamped &vs )
{
	assert( probinstance != NULL );

	mtx_.lock();

	fresh_input = true;
	for (int i = 0; i < probinstance->get_numdim_output(); i++)
		U[i] = vs.v.point[i];

	mtx_.unlock();
}

void TGThread::run()
{
	int nominal_duration = rand() % 61 + 30;

	Eigen::Vector2i numdim_output_bounds( 1, 3 );
	Eigen::Vector2i num_integrators_bounds( 1, 3 );

	Eigen::VectorXd Y_max( 2*numdim_output_bounds(1) );
	for (int i = 0; i < numdim_output_bounds(1); i++) {
		Y_max(2*i+1) = 10;
		Y_max(2*i) = -Y_max(2*i+1);
	}

	Eigen::VectorXd U_max( 2*numdim_output_bounds(1) );
	for (int i = 0; i < numdim_output_bounds(1); i++) {
		U_max(2*i+1) = 1;
		U_max(2*i) = -U_max(2*i+1);
	}

	Eigen::Vector2d period_bounds( 0.05, 0.1 );

	probinstance = Problem::random( numdim_output_bounds,
									num_integrators_bounds,
									Y_max, U_max, 2, 1, period_bounds );
	labeler.importProblem( *probinstance );

	U.resize( probinstance->get_numdim_output() );
	U.setZero();

	Eigen::VectorXd Y( probinstance->get_numdim_output() );

	TrajectoryGenerator tg( probinstance->Xinit,
							probinstance->get_numdim_output() );

	ros::Rate rate( 1/probinstance->period );
	Eigen::VectorXd defaultU( U );
	defaultU.setZero();

	ros::Duration trial_duration;

	ros::Rate polling_rate( 100 );
	dmmode = ready;
	while (dmmode == ready) {
		ros::spinOnce();
		polling_rate.sleep();
	}
	assert( dmmode == waiting );
	ros::Time startt = ros::Time::now();

	nh_.setParam( "probleminstance", probinstance->dumpJSON() );

	nh_.setParam( "number_integrators",
				  probinstance->get_highest_order_deriv() );
	ROS_INFO( "dynamaestro: Using %d as number of integrators.",
			  probinstance->get_highest_order_deriv() );

	nh_.setParam( "output_dim", probinstance->get_numdim_output() );
	ROS_INFO( "dynamaestro: Using %d as dimension of the output space.",
			  probinstance->get_numdim_output() );

	nh_.setParam( "period", probinstance->period );
	ROS_INFO( "dynamaestro: Using %f seconds as the period.",
			  probinstance->period );

	// Send initial output, before any input is applied or time has begun.
	pubstate( tg, Y );
	ros::spinOnce();

	while (ros::ok() && dmmode != resetting && (trial_duration = ros::Time::now() - startt).toSec() < nominal_duration) {
		if (dmmode == running) {
			if (fresh_input) {
				mtx_.lock();

				fresh_input = false;
				tg.step( probinstance->period, U );

				mtx_.unlock();
			} else {
				tg.step( probinstance->period, defaultU );
			}

			pubstate( tg, Y );

		} else if (dmmode == restarting) {
			dmmode = paused;
			mtx_.lock();
			fresh_input = false;
			mtx_.unlock();
			tg.clear();
			U.setZero();
			pubstate( tg, Y );
			dmmode = waiting;
		} else if (dmmode == waiting) {
			if (fresh_input) {
				dmmode = running;
			} else {
				pubstate( tg, Y );
			}
		}
		ros::spinOnce();
		rate.sleep();
	}

	// Did the trial end because the nominal (hidden) duration was reached?
	if (ros::ok() && trial_duration.toSec() >= nominal_duration) {
		ROS_INFO( "dynamaestro: Trial ended after %f s (threshold is %d s).", trial_duration.toSec(), nominal_duration );
	}

	// Clear registered instance
	ROS_INFO( "dynamaestro: Clearing problem instance from Parameter Server." );
	nh_.setParam( "probleminstance", "" );
	nh_.setParam( "number_integrators", -1 );
	nh_.setParam( "output_dim", -1 );
	nh_.setParam( "period", -1.0 );
}

void tgthread( ros::NodeHandle &nhp )
{
	TGThread tgt( nhp );
	tgt.run();
}

int main( int argc, char **argv )
{
#ifdef USE_ROS
	ros::init( argc, argv, "dynamaestro" );
	ros::NodeHandle nh( "~" );

	time_t seed = time( NULL );
	srand( seed );
	ROS_INFO( "dynamaestro: Using %ld as the PRNG seed.", seed );

	boost::thread *tgmain = NULL;
	while (ros::ok()) {
		tgmain = new boost::thread( tgthread, nh );
		tgmain->join();
		delete tgmain;
	}

#endif
	return 0;
}
<|endoftext|>


<commit_before>// Copyright 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/chromeos/app_mode/startup_app_launcher.h"

#include "base/command_line.h"
#include "base/files/file_path.h"
#include "base/json/json_file_value_serializer.h"
#include "base/path_service.h"
#include "base/time/time.h"
#include "base/values.h"
#include "chrome/browser/chrome_notification_types.h"
#include "chrome/browser/chromeos/app_mode/app_session_lifetime.h"
#include "chrome/browser/chromeos/app_mode/kiosk_app_manager.h"
#include "chrome/browser/chromeos/app_mode/kiosk_diagnosis_runner.h"
#include "chrome/browser/chromeos/login/user_manager.h"
#include "chrome/browser/extensions/extension_service.h"
#include "chrome/browser/extensions/updater/extension_updater.h"
#include "chrome/browser/extensions/webstore_startup_installer.h"
#include "chrome/browser/lifetime/application_lifetime.h"
#include "chrome/browser/signin/profile_oauth2_token_service.h"
#include "chrome/browser/signin/profile_oauth2_token_service_factory.h"
#include "chrome/browser/signin/signin_manager.h"
#include "chrome/browser/signin/signin_manager_factory.h"
#include "chrome/browser/ui/extensions/application_launch.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/chrome_version_info.h"
#include "chrome/common/extensions/manifest_url_handler.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/notification_service.h"
#include "extensions/browser/extension_system.h"
#include "extensions/common/extension.h"
#include "extensions/common/manifest_handlers/kiosk_mode_info.h"
#include "extensions/common/manifest_handlers/offline_enabled_info.h"
#include "google_apis/gaia/gaia_auth_consumer.h"
#include "google_apis/gaia/gaia_constants.h"
#include "net/base/load_flags.h"
#include "net/url_request/url_fetcher.h"
#include "net/url_request/url_fetcher_delegate.h"
#include "net/url_request/url_request_context_getter.h"
#include "net/url_request/url_request_status.h"
#include "url/gurl.h"

using content::BrowserThread;
using extensions::Extension;
using extensions::WebstoreStartupInstaller;

namespace chromeos {

namespace {

const char kOAuthRefreshToken[] = "refresh_token";
const char kOAuthClientId[] = "client_id";
const char kOAuthClientSecret[] = "client_secret";

const base::FilePath::CharType kOAuthFileName[] =
    FILE_PATH_LITERAL("kiosk_auth");

}  // namespace

StartupAppLauncher::StartupAppLauncher(Profile* profile,
                                       const std::string& app_id,
                                       bool diagnostic_mode,
                                       StartupAppLauncher::Delegate* delegate)
    : profile_(profile),
      app_id_(app_id),
      diagnostic_mode_(diagnostic_mode),
      delegate_(delegate),
      install_attempted_(false),
      ready_to_launch_(false) {
  DCHECK(profile_);
  DCHECK(Extension::IdIsValid(app_id_));
}

StartupAppLauncher::~StartupAppLauncher() {
  // StartupAppLauncher can be deleted at anytime during the launch process
  // through a user bailout shortcut.
  ProfileOAuth2TokenServiceFactory::GetForProfile(profile_)
      ->RemoveObserver(this);
}

void StartupAppLauncher::Initialize() {
  StartLoadingOAuthFile();
}

void StartupAppLauncher::ContinueWithNetworkReady() {
  // Starts install if it is not started.
  if (!install_attempted_) {
    install_attempted_ = true;
    MaybeInstall();
  }
}

void StartupAppLauncher::StartLoadingOAuthFile() {
  delegate_->OnLoadingOAuthFile();

  KioskOAuthParams* auth_params = new KioskOAuthParams();
  BrowserThread::PostBlockingPoolTaskAndReply(
      FROM_HERE,
      base::Bind(&StartupAppLauncher::LoadOAuthFileOnBlockingPool,
                 auth_params),
      base::Bind(&StartupAppLauncher::OnOAuthFileLoaded,
                 AsWeakPtr(),
                 base::Owned(auth_params)));
}

// static.
void StartupAppLauncher::LoadOAuthFileOnBlockingPool(
    KioskOAuthParams* auth_params) {
  int error_code = JSONFileValueSerializer::JSON_NO_ERROR;
  std::string error_msg;
  base::FilePath user_data_dir;
  CHECK(PathService::Get(chrome::DIR_USER_DATA, &user_data_dir));
  base::FilePath auth_file = user_data_dir.Append(kOAuthFileName);
  scoped_ptr<JSONFileValueSerializer> serializer(
      new JSONFileValueSerializer(user_data_dir.Append(kOAuthFileName)));
  scoped_ptr<base::Value> value(
      serializer->Deserialize(&error_code, &error_msg));
  base::DictionaryValue* dict = NULL;
  if (error_code != JSONFileValueSerializer::JSON_NO_ERROR ||
      !value.get() || !value->GetAsDictionary(&dict)) {
    LOG(WARNING) << "Can't find auth file at " << auth_file.value();
    return;
  }

  dict->GetString(kOAuthRefreshToken, &auth_params->refresh_token);
  dict->GetString(kOAuthClientId, &auth_params->client_id);
  dict->GetString(kOAuthClientSecret, &auth_params->client_secret);
}

void StartupAppLauncher::OnOAuthFileLoaded(KioskOAuthParams* auth_params) {
  auth_params_ = *auth_params;
  // Override chrome client_id and secret that will be used for identity
  // API token minting.
  if (!auth_params_.client_id.empty() && !auth_params_.client_secret.empty()) {
    UserManager::Get()->SetAppModeChromeClientOAuthInfo(
            auth_params_.client_id,
            auth_params_.client_secret);
  }

  // If we are restarting chrome (i.e. on crash), we need to initialize
  // OAuth2TokenService as well.
  InitializeTokenService();
}

void StartupAppLauncher::MaybeInitializeNetwork() {
  const Extension* extension = extensions::ExtensionSystem::Get(profile_)->
      extension_service()->GetInstalledExtension(app_id_);
  const bool requires_network = !extension ||
      !extensions::OfflineEnabledInfo::IsOfflineEnabled(extension);

  if (requires_network) {
    delegate_->InitializeNetwork();
    return;
  }

  // Offline enabled app attempts update if network is ready. Otherwise,
  // go directly to launch.
  if (delegate_->IsNetworkReady())
    ContinueWithNetworkReady();
  else
    OnReadyToLaunch();
}

void StartupAppLauncher::InitializeTokenService() {
  delegate_->OnInitializingTokenService();

  ProfileOAuth2TokenService* profile_token_service =
      ProfileOAuth2TokenServiceFactory::GetForProfile(profile_);
  SigninManagerBase* signin_manager =
      SigninManagerFactory::GetForProfile(profile_);
  if (profile_token_service->RefreshTokenIsAvailable(
          signin_manager->GetAuthenticatedAccountId()) ||
      auth_params_.refresh_token.empty()) {
    MaybeInitializeNetwork();
  } else {
    // Pass oauth2 refresh token from the auth file.
    // TODO(zelidrag): We should probably remove this option after M27.
    // TODO(fgorski): This can go when we have persistence implemented on PO2TS.
    // Unless the code is no longer needed.
    // TODO(rogerta): Now that this CL implements token persistence in PO2TS, is
    // this code still needed?  See above two TODOs.
    //
    // ProfileOAuth2TokenService triggers either OnRefreshTokenAvailable or
    // OnRefreshTokensLoaded. Given that we want to handle exactly one event,
    // whichever comes first, both handlers call RemoveObserver on PO2TS.
    // Handling any of the two events is the only way to resume the execution
    // and enable Cleanup method to be called, self-invoking a destructor.
    profile_token_service->AddObserver(this);

    profile_token_service->UpdateCredentials(
        "kiosk_mode@localhost",
        auth_params_.refresh_token);
  }
}

void StartupAppLauncher::OnRefreshTokenAvailable(
    const std::string& account_id) {
  ProfileOAuth2TokenServiceFactory::GetForProfile(profile_)
      ->RemoveObserver(this);
  MaybeInitializeNetwork();
}

void StartupAppLauncher::OnRefreshTokensLoaded() {
  ProfileOAuth2TokenServiceFactory::GetForProfile(profile_)
      ->RemoveObserver(this);
  MaybeInitializeNetwork();
}

void StartupAppLauncher::LaunchApp() {
  if (!ready_to_launch_) {
    NOTREACHED();
    LOG(ERROR) << "LaunchApp() called but launcher is not initialized.";
  }

  const Extension* extension = extensions::ExtensionSystem::Get(profile_)->
      extension_service()->GetInstalledExtension(app_id_);
  CHECK(extension);

  if (!extensions::KioskModeInfo::IsKioskEnabled(extension)) {
    OnLaunchFailure(KioskAppLaunchError::NOT_KIOSK_ENABLED);
    return;
  }

  // Always open the app in a window.
  OpenApplication(AppLaunchParams(profile_, extension,
                                  extensions::LAUNCH_CONTAINER_WINDOW,
                                  NEW_WINDOW));
  InitAppSession(profile_, app_id_);

  UserManager::Get()->SessionStarted();

  content::NotificationService::current()->Notify(
      chrome::NOTIFICATION_KIOSK_APP_LAUNCHED,
      content::NotificationService::AllSources(),
      content::NotificationService::NoDetails());

  OnLaunchSuccess();

  if (diagnostic_mode_)
    KioskDiagnosisRunner::Run(profile_, app_id_);
}

void StartupAppLauncher::OnLaunchSuccess() {
  delegate_->OnLaunchSucceeded();
}

void StartupAppLauncher::OnLaunchFailure(KioskAppLaunchError::Error error) {
  LOG(ERROR) << "App launch failed, error: " << error;
  DCHECK_NE(KioskAppLaunchError::NONE, error);

  delegate_->OnLaunchFailed(error);
}

void StartupAppLauncher::MaybeInstall() {
  delegate_->OnInstallingApp();

  ExtensionService* extension_service =
      extensions::ExtensionSystem::Get(profile_)->extension_service();
  if (!extension_service->GetInstalledExtension(app_id_)) {
    BeginInstall();
    return;
  }

  extensions::ExtensionUpdater::CheckParams check_params;
  check_params.ids.push_back(app_id_);
  check_params.install_immediately = true;
  check_params.callback =
      base::Bind(&StartupAppLauncher::OnUpdateCheckFinished, AsWeakPtr());
  extension_service->updater()->CheckNow(check_params);
}

void StartupAppLauncher::OnUpdateCheckFinished() {
  OnReadyToLaunch();
  UpdateAppData();
}

void StartupAppLauncher::BeginInstall() {
  installer_ = new WebstoreStartupInstaller(
      app_id_,
      profile_,
      false,
      base::Bind(&StartupAppLauncher::InstallCallback, AsWeakPtr()));
  installer_->BeginInstall();
}

void StartupAppLauncher::InstallCallback(bool success,
                                         const std::string& error) {
  installer_ = NULL;
  if (success) {
    // Finish initialization after the callback returns.
    // So that the app finishes its installation.
    BrowserThread::PostTask(
        BrowserThread::UI,
        FROM_HERE,
        base::Bind(&StartupAppLauncher::OnReadyToLaunch,
                   AsWeakPtr()));
    return;
  }

  LOG(ERROR) << "App install failed: " << error;
  OnLaunchFailure(KioskAppLaunchError::UNABLE_TO_INSTALL);
}

void StartupAppLauncher::OnReadyToLaunch() {
  ready_to_launch_ = true;
  delegate_->OnReadyToLaunch();
}

void StartupAppLauncher::UpdateAppData() {
  KioskAppManager::Get()->ClearAppData(app_id_);
  KioskAppManager::Get()->UpdateAppDataFromProfile(app_id_, profile_, NULL);
}

}   // namespace chromeos
<commit_msg>kiosk: Use kiosk_auth token for primary account id.<commit_after>// Copyright 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/chromeos/app_mode/startup_app_launcher.h"

#include "base/command_line.h"
#include "base/files/file_path.h"
#include "base/json/json_file_value_serializer.h"
#include "base/path_service.h"
#include "base/time/time.h"
#include "base/values.h"
#include "chrome/browser/chrome_notification_types.h"
#include "chrome/browser/chromeos/app_mode/app_session_lifetime.h"
#include "chrome/browser/chromeos/app_mode/kiosk_app_manager.h"
#include "chrome/browser/chromeos/app_mode/kiosk_diagnosis_runner.h"
#include "chrome/browser/chromeos/login/user_manager.h"
#include "chrome/browser/extensions/extension_service.h"
#include "chrome/browser/extensions/updater/extension_updater.h"
#include "chrome/browser/extensions/webstore_startup_installer.h"
#include "chrome/browser/lifetime/application_lifetime.h"
#include "chrome/browser/signin/profile_oauth2_token_service.h"
#include "chrome/browser/signin/profile_oauth2_token_service_factory.h"
#include "chrome/browser/signin/signin_manager.h"
#include "chrome/browser/signin/signin_manager_factory.h"
#include "chrome/browser/ui/extensions/application_launch.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/chrome_version_info.h"
#include "chrome/common/extensions/manifest_url_handler.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/notification_service.h"
#include "extensions/browser/extension_system.h"
#include "extensions/common/extension.h"
#include "extensions/common/manifest_handlers/kiosk_mode_info.h"
#include "extensions/common/manifest_handlers/offline_enabled_info.h"
#include "google_apis/gaia/gaia_auth_consumer.h"
#include "google_apis/gaia/gaia_constants.h"
#include "net/base/load_flags.h"
#include "net/url_request/url_fetcher.h"
#include "net/url_request/url_fetcher_delegate.h"
#include "net/url_request/url_request_context_getter.h"
#include "net/url_request/url_request_status.h"
#include "url/gurl.h"

using content::BrowserThread;
using extensions::Extension;
using extensions::WebstoreStartupInstaller;

namespace chromeos {

namespace {

const char kOAuthRefreshToken[] = "refresh_token";
const char kOAuthClientId[] = "client_id";
const char kOAuthClientSecret[] = "client_secret";

const base::FilePath::CharType kOAuthFileName[] =
    FILE_PATH_LITERAL("kiosk_auth");

}  // namespace

StartupAppLauncher::StartupAppLauncher(Profile* profile,
                                       const std::string& app_id,
                                       bool diagnostic_mode,
                                       StartupAppLauncher::Delegate* delegate)
    : profile_(profile),
      app_id_(app_id),
      diagnostic_mode_(diagnostic_mode),
      delegate_(delegate),
      install_attempted_(false),
      ready_to_launch_(false) {
  DCHECK(profile_);
  DCHECK(Extension::IdIsValid(app_id_));
}

StartupAppLauncher::~StartupAppLauncher() {
  // StartupAppLauncher can be deleted at anytime during the launch process
  // through a user bailout shortcut.
  ProfileOAuth2TokenServiceFactory::GetForProfile(profile_)
      ->RemoveObserver(this);
}

void StartupAppLauncher::Initialize() {
  StartLoadingOAuthFile();
}

void StartupAppLauncher::ContinueWithNetworkReady() {
  // Starts install if it is not started.
  if (!install_attempted_) {
    install_attempted_ = true;
    MaybeInstall();
  }
}

void StartupAppLauncher::StartLoadingOAuthFile() {
  delegate_->OnLoadingOAuthFile();

  KioskOAuthParams* auth_params = new KioskOAuthParams();
  BrowserThread::PostBlockingPoolTaskAndReply(
      FROM_HERE,
      base::Bind(&StartupAppLauncher::LoadOAuthFileOnBlockingPool,
                 auth_params),
      base::Bind(&StartupAppLauncher::OnOAuthFileLoaded,
                 AsWeakPtr(),
                 base::Owned(auth_params)));
}

// static.
void StartupAppLauncher::LoadOAuthFileOnBlockingPool(
    KioskOAuthParams* auth_params) {
  int error_code = JSONFileValueSerializer::JSON_NO_ERROR;
  std::string error_msg;
  base::FilePath user_data_dir;
  CHECK(PathService::Get(chrome::DIR_USER_DATA, &user_data_dir));
  base::FilePath auth_file = user_data_dir.Append(kOAuthFileName);
  scoped_ptr<JSONFileValueSerializer> serializer(
      new JSONFileValueSerializer(user_data_dir.Append(kOAuthFileName)));
  scoped_ptr<base::Value> value(
      serializer->Deserialize(&error_code, &error_msg));
  base::DictionaryValue* dict = NULL;
  if (error_code != JSONFileValueSerializer::JSON_NO_ERROR ||
      !value.get() || !value->GetAsDictionary(&dict)) {
    LOG(WARNING) << "Can't find auth file at " << auth_file.value();
    return;
  }

  dict->GetString(kOAuthRefreshToken, &auth_params->refresh_token);
  dict->GetString(kOAuthClientId, &auth_params->client_id);
  dict->GetString(kOAuthClientSecret, &auth_params->client_secret);
}

void StartupAppLauncher::OnOAuthFileLoaded(KioskOAuthParams* auth_params) {
  auth_params_ = *auth_params;
  // Override chrome client_id and secret that will be used for identity
  // API token minting.
  if (!auth_params_.client_id.empty() && !auth_params_.client_secret.empty()) {
    UserManager::Get()->SetAppModeChromeClientOAuthInfo(
            auth_params_.client_id,
            auth_params_.client_secret);
  }

  // If we are restarting chrome (i.e. on crash), we need to initialize
  // OAuth2TokenService as well.
  InitializeTokenService();
}

void StartupAppLauncher::MaybeInitializeNetwork() {
  const Extension* extension = extensions::ExtensionSystem::Get(profile_)->
      extension_service()->GetInstalledExtension(app_id_);
  const bool requires_network = !extension ||
      !extensions::OfflineEnabledInfo::IsOfflineEnabled(extension);

  if (requires_network) {
    delegate_->InitializeNetwork();
    return;
  }

  // Offline enabled app attempts update if network is ready. Otherwise,
  // go directly to launch.
  if (delegate_->IsNetworkReady())
    ContinueWithNetworkReady();
  else
    OnReadyToLaunch();
}

void StartupAppLauncher::InitializeTokenService() {
  delegate_->OnInitializingTokenService();

  ProfileOAuth2TokenService* profile_token_service =
      ProfileOAuth2TokenServiceFactory::GetForProfile(profile_);
  SigninManagerBase* signin_manager =
      SigninManagerFactory::GetForProfile(profile_);
  const std::string primary_account_id =
      signin_manager->GetAuthenticatedAccountId();
  if (profile_token_service->RefreshTokenIsAvailable(primary_account_id) ||
      auth_params_.refresh_token.empty()) {
    MaybeInitializeNetwork();
  } else {
    // Pass oauth2 refresh token from the auth file.
    // TODO(zelidrag): We should probably remove this option after M27.
    // TODO(fgorski): This can go when we have persistence implemented on PO2TS.
    // Unless the code is no longer needed.
    // TODO(rogerta): Now that this CL implements token persistence in PO2TS, is
    // this code still needed?  See above two TODOs.
    //
    // ProfileOAuth2TokenService triggers either OnRefreshTokenAvailable or
    // OnRefreshTokensLoaded. Given that we want to handle exactly one event,
    // whichever comes first, both handlers call RemoveObserver on PO2TS.
    // Handling any of the two events is the only way to resume the execution
    // and enable Cleanup method to be called, self-invoking a destructor.
    profile_token_service->AddObserver(this);

    profile_token_service->UpdateCredentials(
        primary_account_id,
        auth_params_.refresh_token);
  }
}

void StartupAppLauncher::OnRefreshTokenAvailable(
    const std::string& account_id) {
  ProfileOAuth2TokenServiceFactory::GetForProfile(profile_)
      ->RemoveObserver(this);
  MaybeInitializeNetwork();
}

void StartupAppLauncher::OnRefreshTokensLoaded() {
  ProfileOAuth2TokenServiceFactory::GetForProfile(profile_)
      ->RemoveObserver(this);
  MaybeInitializeNetwork();
}

void StartupAppLauncher::LaunchApp() {
  if (!ready_to_launch_) {
    NOTREACHED();
    LOG(ERROR) << "LaunchApp() called but launcher is not initialized.";
  }

  const Extension* extension = extensions::ExtensionSystem::Get(profile_)->
      extension_service()->GetInstalledExtension(app_id_);
  CHECK(extension);

  if (!extensions::KioskModeInfo::IsKioskEnabled(extension)) {
    OnLaunchFailure(KioskAppLaunchError::NOT_KIOSK_ENABLED);
    return;
  }

  // Always open the app in a window.
  OpenApplication(AppLaunchParams(profile_, extension,
                                  extensions::LAUNCH_CONTAINER_WINDOW,
                                  NEW_WINDOW));
  InitAppSession(profile_, app_id_);

  UserManager::Get()->SessionStarted();

  content::NotificationService::current()->Notify(
      chrome::NOTIFICATION_KIOSK_APP_LAUNCHED,
      content::NotificationService::AllSources(),
      content::NotificationService::NoDetails());

  OnLaunchSuccess();

  if (diagnostic_mode_)
    KioskDiagnosisRunner::Run(profile_, app_id_);
}

void StartupAppLauncher::OnLaunchSuccess() {
  delegate_->OnLaunchSucceeded();
}

void StartupAppLauncher::OnLaunchFailure(KioskAppLaunchError::Error error) {
  LOG(ERROR) << "App launch failed, error: " << error;
  DCHECK_NE(KioskAppLaunchError::NONE, error);

  delegate_->OnLaunchFailed(error);
}

void StartupAppLauncher::MaybeInstall() {
  delegate_->OnInstallingApp();

  ExtensionService* extension_service =
      extensions::ExtensionSystem::Get(profile_)->extension_service();
  if (!extension_service->GetInstalledExtension(app_id_)) {
    BeginInstall();
    return;
  }

  extensions::ExtensionUpdater::CheckParams check_params;
  check_params.ids.push_back(app_id_);
  check_params.install_immediately = true;
  check_params.callback =
      base::Bind(&StartupAppLauncher::OnUpdateCheckFinished, AsWeakPtr());
  extension_service->updater()->CheckNow(check_params);
}

void StartupAppLauncher::OnUpdateCheckFinished() {
  OnReadyToLaunch();
  UpdateAppData();
}

void StartupAppLauncher::BeginInstall() {
  installer_ = new WebstoreStartupInstaller(
      app_id_,
      profile_,
      false,
      base::Bind(&StartupAppLauncher::InstallCallback, AsWeakPtr()));
  installer_->BeginInstall();
}

void StartupAppLauncher::InstallCallback(bool success,
                                         const std::string& error) {
  installer_ = NULL;
  if (success) {
    // Finish initialization after the callback returns.
    // So that the app finishes its installation.
    BrowserThread::PostTask(
        BrowserThread::UI,
        FROM_HERE,
        base::Bind(&StartupAppLauncher::OnReadyToLaunch,
                   AsWeakPtr()));
    return;
  }

  LOG(ERROR) << "App install failed: " << error;
  OnLaunchFailure(KioskAppLaunchError::UNABLE_TO_INSTALL);
}

void StartupAppLauncher::OnReadyToLaunch() {
  ready_to_launch_ = true;
  delegate_->OnReadyToLaunch();
}

void StartupAppLauncher::UpdateAppData() {
  KioskAppManager::Get()->ClearAppData(app_id_);
  KioskAppManager::Get()->UpdateAppDataFromProfile(app_id_, profile_, NULL);
}

}   // namespace chromeos
<|endoftext|>


<commit_before>// Copyright (c) 2010 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// #include <algorithm>

#include <algorithm>

#include "app/resource_bundle.h"
#include "base/file_path.h"
#include "base/path_service.h"
#include "base/values.h"
#include "chrome/browser/browser_list.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/chromeos/dom_ui/login/login_ui_helpers.h"
#include "chrome/browser/profile.h"
#include "chrome/browser/profile_manager.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/common/jstemplate_builder.h"
#include "grit/browser_resources.h"

namespace chromeos {

////////////////////////////////////////////////////////////////////////////////
//
// ProfileOperationsInterface
//
////////////////////////////////////////////////////////////////////////////////
Profile* ProfileOperationsInterface::GetDefaultProfile() {
  ProfileManager* profile_manager = g_browser_process->profile_manager();
  return profile_manager->GetDefaultProfile();
}

Profile* ProfileOperationsInterface::GetDefaultProfileByPath() {
  return GetDefaultProfile(GetUserDataPath());
}

Profile* ProfileOperationsInterface::GetDefaultProfile(FilePath user_data_dir) {
  ProfileManager* profile_manager = g_browser_process->profile_manager();
  return profile_manager->GetDefaultProfile(user_data_dir);
}

FilePath ProfileOperationsInterface::GetUserDataPath() {
  FilePath user_data_dir;
  PathService::Get(chrome::DIR_USER_DATA, &user_data_dir);
  return user_data_dir;
}

////////////////////////////////////////////////////////////////////////////////
//
// BrowserOperationsInterface
//
////////////////////////////////////////////////////////////////////////////////
Browser* BrowserOperationsInterface::CreateBrowser(Profile* profile) {
  return Browser::Create(profile);
}

Browser* BrowserOperationsInterface::GetLoginBrowser(Profile* profile) {
  return BrowserList::FindBrowserWithType(profile,
                                          Browser::TYPE_ANY,
                                          true);
}

////////////////////////////////////////////////////////////////////////////////
//
// HTMLOperationsInterface
//
////////////////////////////////////////////////////////////////////////////////
base::StringPiece HTMLOperationsInterface::GetLoginHTML() {
  base::StringPiece login_html(
      ResourceBundle::GetSharedInstance().GetRawDataResource(
          IDR_LOGIN_HTML));
  return login_html;
}

std::string HTMLOperationsInterface::GetFullHTML(
    base::StringPiece login_html,
    DictionaryValue* localized_strings) {
  return jstemplate_builder::GetI18nTemplateHtml(
      login_html,
      localized_strings);
}

RefCountedBytes* HTMLOperationsInterface::CreateHTMLBytes(
    std::string full_html) {
  RefCountedBytes* html_bytes = new RefCountedBytes();
  html_bytes->data.resize(full_html.size());
  std::copy(full_html.begin(),
            full_html.end(),
            html_bytes->data.begin());
  return html_bytes;
}

}  // namespace chromeos
<commit_msg>Fix includes in stubbed login that were broken by profile.h and profile_manager.h moving.<commit_after>// Copyright (c) 2010 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// #include <algorithm>

#include <algorithm>

#include "app/resource_bundle.h"
#include "base/file_path.h"
#include "base/path_service.h"
#include "base/values.h"
#include "chrome/browser/browser_list.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/chromeos/dom_ui/login/login_ui_helpers.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/profiles/profile_manager.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/common/jstemplate_builder.h"
#include "grit/browser_resources.h"

namespace chromeos {

////////////////////////////////////////////////////////////////////////////////
//
// ProfileOperationsInterface
//
////////////////////////////////////////////////////////////////////////////////
Profile* ProfileOperationsInterface::GetDefaultProfile() {
  ProfileManager* profile_manager = g_browser_process->profile_manager();
  return profile_manager->GetDefaultProfile();
}

Profile* ProfileOperationsInterface::GetDefaultProfileByPath() {
  return GetDefaultProfile(GetUserDataPath());
}

Profile* ProfileOperationsInterface::GetDefaultProfile(FilePath user_data_dir) {
  ProfileManager* profile_manager = g_browser_process->profile_manager();
  return profile_manager->GetDefaultProfile(user_data_dir);
}

FilePath ProfileOperationsInterface::GetUserDataPath() {
  FilePath user_data_dir;
  PathService::Get(chrome::DIR_USER_DATA, &user_data_dir);
  return user_data_dir;
}

////////////////////////////////////////////////////////////////////////////////
//
// BrowserOperationsInterface
//
////////////////////////////////////////////////////////////////////////////////
Browser* BrowserOperationsInterface::CreateBrowser(Profile* profile) {
  return Browser::Create(profile);
}

Browser* BrowserOperationsInterface::GetLoginBrowser(Profile* profile) {
  return BrowserList::FindBrowserWithType(profile,
                                          Browser::TYPE_ANY,
                                          true);
}

////////////////////////////////////////////////////////////////////////////////
//
// HTMLOperationsInterface
//
////////////////////////////////////////////////////////////////////////////////
base::StringPiece HTMLOperationsInterface::GetLoginHTML() {
  base::StringPiece login_html(
      ResourceBundle::GetSharedInstance().GetRawDataResource(
          IDR_LOGIN_HTML));
  return login_html;
}

std::string HTMLOperationsInterface::GetFullHTML(
    base::StringPiece login_html,
    DictionaryValue* localized_strings) {
  return jstemplate_builder::GetI18nTemplateHtml(
      login_html,
      localized_strings);
}

RefCountedBytes* HTMLOperationsInterface::CreateHTMLBytes(
    std::string full_html) {
  RefCountedBytes* html_bytes = new RefCountedBytes();
  html_bytes->data.resize(full_html.size());
  std::copy(full_html.begin(),
            full_html.end(),
            html_bytes->data.begin());
  return html_bytes;
}

}  // namespace chromeos
<|endoftext|>


<commit_before>//
//  libavg - Media Playback Engine.
//  Copyright (C) 2003-2014 Ulrich von Zadow
//
//  This library is free software; you can redistribute it and/or
//  modify it under the terms of the GNU Lesser General Public
//  License as published by the Free Software Foundation; either
//  version 2 of the License, or (at your option) any later version.
//
//  This library is distributed in the hope that it will be useful,
//  but WITHOUT ANY WARRANTY; without even the implied warranty of
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
//  Lesser General Public License for more details.
//
//  You should have received a copy of the GNU Lesser General Public
//  License along with this library; if not, write to the Free Software
//  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
//
//  Current versions can be found at www.libavg.de
//

#include "DivNode.h"
#include "Player.h"
#include "TypeDefinition.h"
#include "TypeRegistry.h"
#include "Canvas.h"
#include "NodeChain.h"

#include "../graphics/GLContext.h"

#include "../base/Exception.h"
#include "../base/Logger.h"
#include "../base/StringHelper.h"
#include "../base/FileHelper.h"
#include "../base/MathHelper.h"
#include "../base/ObjectCounter.h"

#include <iostream>
#include <sstream>
#include <limits>

using namespace std;
using namespace boost;

namespace avg {

void DivNode::registerType()
{
    string sChildArray[] = {"image", "div", "canvas", "words", "video", "camera",
            "panoimage", "sound", "line", "rect", "curve", "polyline", "polygon",
            "circle", "mesh"};
    vector<string> sChildren = vectorFromCArray(
            sizeof(sChildArray) / sizeof(*sChildArray), sChildArray);
    TypeDefinition def = TypeDefinition("div", "areanode",
            ExportedObject::buildObject<DivNode>)
        .addChildren(sChildren)
        .addArg(Arg<bool>("crop", false, false, offsetof(DivNode, m_bCrop)))
        .addArg(Arg<UTF8String>("mediadir", "", false, offsetof(DivNode, m_sMediaDir)));
    TypeRegistry::get()->registerType(def);
}

DivNode::DivNode(const ArgList& args, const string& sPublisherName)
    : AreaNode(sPublisherName)
{
    args.setMembers(this);
    ObjectCounter::get()->incRef(&typeid(*this));
}

DivNode::~DivNode()
{
    for (unsigned i = 0; i < getNumChildren(); ++i) {
        getChild(i)->removeParent();
    }
    ObjectCounter::get()->decRef(&typeid(*this));
}

void DivNode::connectDisplay()
{
    AreaNode::connectDisplay();
    for (unsigned i = 0; i < getNumChildren(); ++i) {
        getChild(i)->connectDisplay();
    }
}

void DivNode::connect(CanvasPtr pCanvas)
{
    AreaNode::connect(pCanvas);
    for (unsigned i = 0; i < getNumChildren(); ++i) {
        getChild(i)->connect(pCanvas);
    }
}

void DivNode::disconnect(bool bKill)
{
    for (unsigned i = 0; i < getNumChildren(); ++i) {
        getChild(i)->disconnect(bKill);
    }
    AreaNode::disconnect(bKill);
}

glm::vec2 DivNode::getPivot() const
{
    glm::vec2 pivot = AreaNode::getPivot();
    return pivot;
}

unsigned DivNode::getNumChildren()
{
    return m_Children.size();
}

const NodePtr& DivNode::getChild(unsigned i)
{
    if (i >= m_Children.size()) {
        stringstream s;
        s << "Index " << i << " is out of range in Node::getChild()";
        throw(Exception(AVG_ERR_OUT_OF_RANGE, s.str()));
    }
    return m_Children[i];
}

void DivNode::appendChild(NodePtr pNewNode)
{
    insertChild(pNewNode, unsigned(m_Children.size()));
}

void DivNode::insertChildBefore(NodePtr pNewNode, NodePtr pOldChild)
{
    if (!pOldChild) {
        throw Exception(AVG_ERR_NO_NODE,
                getID()+"::insertChildBefore called without a node.");
    }
    unsigned i = indexOf(pOldChild);
    insertChild(pNewNode, i);
}

void DivNode::insertChildAfter(NodePtr pNewNode, NodePtr pOldChild)
{
    if (!pOldChild) {
        throw Exception(AVG_ERR_NO_NODE,
                getID()+"::insertChildBefore called without a node.");
    }
    unsigned i = indexOf(pOldChild);
    insertChild(pNewNode, i+1);
}

void DivNode::insertChild(NodePtr pChild, unsigned i)
{
    if (!pChild) {
        throw Exception(AVG_ERR_NO_NODE,
                getID()+"::insertChild called without a node.");
    }
    if (pChild->getState() == NS_CONNECTED || pChild->getState() == NS_CANRENDER) {
        throw(Exception(AVG_ERR_ALREADY_CONNECTED,
                "Can't connect node with id "+pChild->getID()+
                ": already connected."));
    }
    if (getState() == NS_CONNECTED || getState() == NS_CANRENDER) {
        getCanvas()->registerNode(pChild);
    }
    pChild->checkSetParentError(this);
    if (!isChildTypeAllowed(pChild->getTypeStr())) {
        throw(Exception(AVG_ERR_ALREADY_CONNECTED,
                "Can't insert a node of type "+pChild->getTypeStr()+
                " into a node of type "+getTypeStr()+"."));
    }
    if (i > m_Children.size()) {
        throw(Exception(AVG_ERR_OUT_OF_RANGE,
                pChild->getID()+"::insertChild: index out of bounds."));
    }
    std::vector<NodePtr>::iterator pos = m_Children.begin()+i;
    m_Children.insert(pos, pChild);
    try {
        pChild->setParent(this, getState(), getCanvas());
    } catch (Exception&) {
        m_Children.erase(m_Children.begin()+i);
        throw;
    }
    if (getState() == NS_CANRENDER) {
        pChild->connectDisplay();
    }
}

void DivNode::reorderChild(NodePtr pChild, unsigned j)
{
    if (j > m_Children.size()-1) {
        throw(Exception(AVG_ERR_OUT_OF_RANGE,
                getID()+"::reorderChild: index "+toString(j)+" out of bounds."));
    }
    int i = indexOf(pChild);
    m_Children.erase(m_Children.begin()+i);
    std::vector<NodePtr>::iterator pos = m_Children.begin()+j;
    m_Children.insert(pos, pChild);
}

void DivNode::reorderChild(unsigned i, unsigned j)
{
    if (i > m_Children.size()-1 || j > m_Children.size()-1) {
        throw(Exception(AVG_ERR_OUT_OF_RANGE,
                getID()+"::reorderChild: index out of bounds."));
    }
    NodePtr pChild = getChild(i);
    m_Children.erase(m_Children.begin()+i);
    std::vector<NodePtr>::iterator pos = m_Children.begin()+j;
    m_Children.insert(pos, pChild);
}

unsigned DivNode::indexOf(NodePtr pChild)
{
    if (!pChild) {
        throw Exception(AVG_ERR_NO_NODE,
                getID()+"::indexOf called without a node.");
    }
    for (unsigned i = 0; i < m_Children.size(); ++i) {
        if (m_Children[i] == pChild) {
            return i;
        }
    }
    throw(Exception(AVG_ERR_OUT_OF_RANGE,
            "indexOf: node '"+pChild->getID()+"' is not a child of node '"
            +getID()+"'"));
}

void DivNode::removeChild(NodePtr pChild)
{
    removeChild(pChild, false);
}

void DivNode::removeChild(unsigned i)
{
    removeChild(i, false);
}

void DivNode::removeChild(NodePtr pChild, bool bKill)
{
    pChild->removeParent();
    if (pChild->getState() != NS_UNCONNECTED) {
        pChild->disconnect(bKill);
    }
    unsigned i = indexOf(pChild);
    if (i > m_Children.size()-1) {
        throw(Exception(AVG_ERR_OUT_OF_RANGE,
                getID()+"::removeChild: index "+toString(i)+" out of bounds."));
    }
    m_Children.erase(m_Children.begin()+i);
}

void DivNode::removeChild(unsigned i, bool bKill)
{
    NodePtr pChild = getChild(i);
    removeChild(pChild, bKill);
}

bool DivNode::getCrop() const
{
    return m_bCrop;
}

void DivNode::setCrop(bool bCrop)
{
    m_bCrop = bCrop;
}

const UTF8String& DivNode::getMediaDir() const
{
    return m_sMediaDir;
}

void DivNode::setMediaDir(const UTF8String& sMediaDir)
{
//    avgDeprecationWarning("1.7", "DivNode.mediadir", "");
    m_sMediaDir = sMediaDir;
    checkReload();
}

void DivNode::getElementsByPos(const glm::vec2& pos, NodeChainPtr& pElements)
{
    if (reactsToMouseEvents() &&
            ((getSize() == glm::vec2(0,0) ||
             (pos.x >= 0 && pos.y >= 0 && pos.x < getSize().x && pos.y < getSize().y))))
    {
        for (int i = getNumChildren()-1; i >= 0; i--) {
            NodePtr pCurChild = getChild(i);
            glm::vec2 relPos = pCurChild->toLocal(pos);
            pCurChild->getElementsByPos(relPos, pElements);
            if (!pElements->empty()) {
                pElements->append(getSharedThis());
                return;
            }
        }
        // pos isn't in any of the children.
        if (getSize() != glm::vec2(0,0)) {
            // Explicit width/height given for div - div reacts on its own.
            pElements->append(getSharedThis());
        }
    }
}

void DivNode::preRender(const VertexArrayPtr& pVA, bool bIsParentActive,
        float parentEffectiveOpacity)
{
    AreaNode::preRender(pVA, bIsParentActive, parentEffectiveOpacity);
    if (getCrop() && getSize() != glm::vec2(0,0)) {
        pVA->startSubVA(m_ClipVA);
        glm::vec2 viewport = getSize();
        m_ClipVA.appendPos(glm::vec2(0,0), glm::vec2(0,0), Pixel32(0,0,0,0));
        m_ClipVA.appendPos(glm::vec2(0,viewport.y), glm::vec2(0,0), Pixel32(0,0,0,0));
        m_ClipVA.appendPos(glm::vec2(viewport.x,0), glm::vec2(0,0), Pixel32(0,0,0,0));
        m_ClipVA.appendPos(viewport, glm::vec2(0,0), Pixel32(0,0,0,0));
        m_ClipVA.appendQuadIndexes(0, 1, 2, 3);
    }
    for (unsigned i = 0; i < getNumChildren(); i++) {
        m_Children[i]->preRender(pVA, bIsParentActive, getEffectiveOpacity());
    }
}

void DivNode::render(GLContext* pContext, const glm::mat4& transform)
{
    if (getCrop() && getSize() != glm::vec2(0,0)) {
        getCanvas()->pushClipRect(pContext, transform, m_ClipVA);
    }
    for (unsigned i = 0; i < getNumChildren(); i++) {
        getChild(i)->maybeRender(pContext, transform);
    }
    if (getCrop() && getSize() != glm::vec2(0,0)) {
        getCanvas()->popClipRect(pContext, transform, m_ClipVA);
    }
}

void DivNode::renderOutlines(const VertexArrayPtr& pVA, Pixel32 parentColor)
{
    Pixel32 effColor = getEffectiveOutlineColor(parentColor);
    if (effColor != Pixel32(0,0,0,0)) {
        glm::vec2 size = getSize();
        if (size == glm::vec2(0,0)) {
            glm::vec2 p0 = getAbsPos(glm::vec2(-4, 0.5));
            glm::vec2 p1 = getAbsPos(glm::vec2(5, 0.5));
            glm::vec2 p2 = getAbsPos(glm::vec2(0.5, -4));
            glm::vec2 p3 = getAbsPos(glm::vec2(0.5, 5));
            pVA->addLineData(effColor, p0, p1, 1);
            pVA->addLineData(effColor, p2, p3, 1);
        } else {
            AreaNode::renderOutlines(pVA, parentColor);
        }
    }
    for (unsigned i = 0; i < getNumChildren(); i++) {
        getChild(i)->renderOutlines(pVA, effColor);
    }
}

string DivNode::getEffectiveMediaDir()
{
    // TODO: There is no test for this function.
    string sMediaDir = m_sMediaDir;
    if (!isAbsPath(sMediaDir)) {
        if (getParent()) {
            sMediaDir = getParent()->getEffectiveMediaDir()+m_sMediaDir;
        } else {
            sMediaDir = Player::get()->getRootMediaDir()+m_sMediaDir;
        }
    }
    if (sMediaDir[sMediaDir.length()-1] != '/') {
        sMediaDir += '/';
    }
    return sMediaDir;
}

void DivNode::checkReload()
{
    for(unsigned i = 0; i < getNumChildren(); ++i) {
        getChild(i)->checkReload();
    }
}

string DivNode::dump(int indent)
{
    string dumpStr = AreaNode::dump () + "\n";
    vector<NodePtr>::iterator it;
    for(unsigned i = 0; i < getNumChildren(); ++i) {
        getChild(i)->dump(indent+2)+"\n";
    }
    return dumpStr;
}

IntPoint DivNode::getMediaSize()
{
    return IntPoint(0, 0);
}

bool DivNode::isChildTypeAllowed(const string& sType)
{
    return getDefinition()->isChildAllowed(sType);
}

}
<commit_msg>Catch Null pointers in DivNode::removeChild() and throw an error.<commit_after>//
//  libavg - Media Playback Engine.
//  Copyright (C) 2003-2014 Ulrich von Zadow
//
//  This library is free software; you can redistribute it and/or
//  modify it under the terms of the GNU Lesser General Public
//  License as published by the Free Software Foundation; either
//  version 2 of the License, or (at your option) any later version.
//
//  This library is distributed in the hope that it will be useful,
//  but WITHOUT ANY WARRANTY; without even the implied warranty of
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
//  Lesser General Public License for more details.
//
//  You should have received a copy of the GNU Lesser General Public
//  License along with this library; if not, write to the Free Software
//  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
//
//  Current versions can be found at www.libavg.de
//

#include "DivNode.h"
#include "Player.h"
#include "TypeDefinition.h"
#include "TypeRegistry.h"
#include "Canvas.h"
#include "NodeChain.h"

#include "../graphics/GLContext.h"

#include "../base/Exception.h"
#include "../base/Logger.h"
#include "../base/StringHelper.h"
#include "../base/FileHelper.h"
#include "../base/MathHelper.h"
#include "../base/ObjectCounter.h"

#include <iostream>
#include <sstream>
#include <limits>

using namespace std;
using namespace boost;

namespace avg {

void DivNode::registerType()
{
    string sChildArray[] = {"image", "div", "canvas", "words", "video", "camera",
            "panoimage", "sound", "line", "rect", "curve", "polyline", "polygon",
            "circle", "mesh"};
    vector<string> sChildren = vectorFromCArray(
            sizeof(sChildArray) / sizeof(*sChildArray), sChildArray);
    TypeDefinition def = TypeDefinition("div", "areanode",
            ExportedObject::buildObject<DivNode>)
        .addChildren(sChildren)
        .addArg(Arg<bool>("crop", false, false, offsetof(DivNode, m_bCrop)))
        .addArg(Arg<UTF8String>("mediadir", "", false, offsetof(DivNode, m_sMediaDir)));
    TypeRegistry::get()->registerType(def);
}

DivNode::DivNode(const ArgList& args, const string& sPublisherName)
    : AreaNode(sPublisherName)
{
    args.setMembers(this);
    ObjectCounter::get()->incRef(&typeid(*this));
}

DivNode::~DivNode()
{
    for (unsigned i = 0; i < getNumChildren(); ++i) {
        getChild(i)->removeParent();
    }
    ObjectCounter::get()->decRef(&typeid(*this));
}

void DivNode::connectDisplay()
{
    AreaNode::connectDisplay();
    for (unsigned i = 0; i < getNumChildren(); ++i) {
        getChild(i)->connectDisplay();
    }
}

void DivNode::connect(CanvasPtr pCanvas)
{
    AreaNode::connect(pCanvas);
    for (unsigned i = 0; i < getNumChildren(); ++i) {
        getChild(i)->connect(pCanvas);
    }
}

void DivNode::disconnect(bool bKill)
{
    for (unsigned i = 0; i < getNumChildren(); ++i) {
        getChild(i)->disconnect(bKill);
    }
    AreaNode::disconnect(bKill);
}

glm::vec2 DivNode::getPivot() const
{
    glm::vec2 pivot = AreaNode::getPivot();
    return pivot;
}

unsigned DivNode::getNumChildren()
{
    return m_Children.size();
}

const NodePtr& DivNode::getChild(unsigned i)
{
    if (i >= m_Children.size()) {
        stringstream s;
        s << "Index " << i << " is out of range in Node::getChild()";
        throw(Exception(AVG_ERR_OUT_OF_RANGE, s.str()));
    }
    return m_Children[i];
}

void DivNode::appendChild(NodePtr pNewNode)
{
    insertChild(pNewNode, unsigned(m_Children.size()));
}

void DivNode::insertChildBefore(NodePtr pNewNode, NodePtr pOldChild)
{
    if (!pOldChild) {
        throw Exception(AVG_ERR_NO_NODE,
                getID()+"::insertChildBefore called without a node.");
    }
    unsigned i = indexOf(pOldChild);
    insertChild(pNewNode, i);
}

void DivNode::insertChildAfter(NodePtr pNewNode, NodePtr pOldChild)
{
    if (!pOldChild) {
        throw Exception(AVG_ERR_NO_NODE,
                getID()+"::insertChildBefore called without a node.");
    }
    unsigned i = indexOf(pOldChild);
    insertChild(pNewNode, i+1);
}

void DivNode::insertChild(NodePtr pChild, unsigned i)
{
    if (!pChild) {
        throw Exception(AVG_ERR_NO_NODE,
                getID()+"::insertChild called without a node.");
    }
    if (pChild->getState() == NS_CONNECTED || pChild->getState() == NS_CANRENDER) {
        throw(Exception(AVG_ERR_ALREADY_CONNECTED,
                "Can't connect node with id "+pChild->getID()+
                ": already connected."));
    }
    if (getState() == NS_CONNECTED || getState() == NS_CANRENDER) {
        getCanvas()->registerNode(pChild);
    }
    pChild->checkSetParentError(this);
    if (!isChildTypeAllowed(pChild->getTypeStr())) {
        throw(Exception(AVG_ERR_ALREADY_CONNECTED,
                "Can't insert a node of type "+pChild->getTypeStr()+
                " into a node of type "+getTypeStr()+"."));
    }
    if (i > m_Children.size()) {
        throw(Exception(AVG_ERR_OUT_OF_RANGE,
                pChild->getID()+"::insertChild: index out of bounds."));
    }
    std::vector<NodePtr>::iterator pos = m_Children.begin()+i;
    m_Children.insert(pos, pChild);
    try {
        pChild->setParent(this, getState(), getCanvas());
    } catch (Exception&) {
        m_Children.erase(m_Children.begin()+i);
        throw;
    }
    if (getState() == NS_CANRENDER) {
        pChild->connectDisplay();
    }
}

void DivNode::reorderChild(NodePtr pChild, unsigned j)
{
    if (j > m_Children.size()-1) {
        throw(Exception(AVG_ERR_OUT_OF_RANGE,
                getID()+"::reorderChild: index "+toString(j)+" out of bounds."));
    }
    int i = indexOf(pChild);
    m_Children.erase(m_Children.begin()+i);
    std::vector<NodePtr>::iterator pos = m_Children.begin()+j;
    m_Children.insert(pos, pChild);
}

void DivNode::reorderChild(unsigned i, unsigned j)
{
    if (i > m_Children.size()-1 || j > m_Children.size()-1) {
        throw(Exception(AVG_ERR_OUT_OF_RANGE,
                getID()+"::reorderChild: index out of bounds."));
    }
    NodePtr pChild = getChild(i);
    m_Children.erase(m_Children.begin()+i);
    std::vector<NodePtr>::iterator pos = m_Children.begin()+j;
    m_Children.insert(pos, pChild);
}

unsigned DivNode::indexOf(NodePtr pChild)
{
    if (!pChild) {
        throw Exception(AVG_ERR_NO_NODE,
                getID()+"::indexOf called without a node.");
    }
    for (unsigned i = 0; i < m_Children.size(); ++i) {
        if (m_Children[i] == pChild) {
            return i;
        }
    }
    throw(Exception(AVG_ERR_OUT_OF_RANGE,
            "indexOf: node '"+pChild->getID()+"' is not a child of node '"
            +getID()+"'"));
}

void DivNode::removeChild(NodePtr pChild)
{
    removeChild(pChild, false);
}

void DivNode::removeChild(unsigned i)
{
    removeChild(i, false);
}

void DivNode::removeChild(NodePtr pChild, bool bKill)
{
    if (!pChild) {
        throw Exception(AVG_ERR_NO_NODE,
          getID()+"::removeChild called without a node.");
    }
    pChild->removeParent();
    if (pChild->getState() != NS_UNCONNECTED) {
        pChild->disconnect(bKill);
    }
    unsigned i = indexOf(pChild);
    if (i > m_Children.size()-1) {
        throw(Exception(AVG_ERR_OUT_OF_RANGE,
                getID()+"::removeChild: index "+toString(i)+" out of bounds."));
    }
    m_Children.erase(m_Children.begin()+i);
}

void DivNode::removeChild(unsigned i, bool bKill)
{
    NodePtr pChild = getChild(i);
    removeChild(pChild, bKill);
}

bool DivNode::getCrop() const
{
    return m_bCrop;
}

void DivNode::setCrop(bool bCrop)
{
    m_bCrop = bCrop;
}

const UTF8String& DivNode::getMediaDir() const
{
    return m_sMediaDir;
}

void DivNode::setMediaDir(const UTF8String& sMediaDir)
{
//    avgDeprecationWarning("1.7", "DivNode.mediadir", "");
    m_sMediaDir = sMediaDir;
    checkReload();
}

void DivNode::getElementsByPos(const glm::vec2& pos, NodeChainPtr& pElements)
{
    if (reactsToMouseEvents() &&
            ((getSize() == glm::vec2(0,0) ||
             (pos.x >= 0 && pos.y >= 0 && pos.x < getSize().x && pos.y < getSize().y))))
    {
        for (int i = getNumChildren()-1; i >= 0; i--) {
            NodePtr pCurChild = getChild(i);
            glm::vec2 relPos = pCurChild->toLocal(pos);
            pCurChild->getElementsByPos(relPos, pElements);
            if (!pElements->empty()) {
                pElements->append(getSharedThis());
                return;
            }
        }
        // pos isn't in any of the children.
        if (getSize() != glm::vec2(0,0)) {
            // Explicit width/height given for div - div reacts on its own.
            pElements->append(getSharedThis());
        }
    }
}

void DivNode::preRender(const VertexArrayPtr& pVA, bool bIsParentActive,
        float parentEffectiveOpacity)
{
    AreaNode::preRender(pVA, bIsParentActive, parentEffectiveOpacity);
    if (getCrop() && getSize() != glm::vec2(0,0)) {
        pVA->startSubVA(m_ClipVA);
        glm::vec2 viewport = getSize();
        m_ClipVA.appendPos(glm::vec2(0,0), glm::vec2(0,0), Pixel32(0,0,0,0));
        m_ClipVA.appendPos(glm::vec2(0,viewport.y), glm::vec2(0,0), Pixel32(0,0,0,0));
        m_ClipVA.appendPos(glm::vec2(viewport.x,0), glm::vec2(0,0), Pixel32(0,0,0,0));
        m_ClipVA.appendPos(viewport, glm::vec2(0,0), Pixel32(0,0,0,0));
        m_ClipVA.appendQuadIndexes(0, 1, 2, 3);
    }
    for (unsigned i = 0; i < getNumChildren(); i++) {
        m_Children[i]->preRender(pVA, bIsParentActive, getEffectiveOpacity());
    }
}

void DivNode::render(GLContext* pContext, const glm::mat4& transform)
{
    if (getCrop() && getSize() != glm::vec2(0,0)) {
        getCanvas()->pushClipRect(pContext, transform, m_ClipVA);
    }
    for (unsigned i = 0; i < getNumChildren(); i++) {
        getChild(i)->maybeRender(pContext, transform);
    }
    if (getCrop() && getSize() != glm::vec2(0,0)) {
        getCanvas()->popClipRect(pContext, transform, m_ClipVA);
    }
}

void DivNode::renderOutlines(const VertexArrayPtr& pVA, Pixel32 parentColor)
{
    Pixel32 effColor = getEffectiveOutlineColor(parentColor);
    if (effColor != Pixel32(0,0,0,0)) {
        glm::vec2 size = getSize();
        if (size == glm::vec2(0,0)) {
            glm::vec2 p0 = getAbsPos(glm::vec2(-4, 0.5));
            glm::vec2 p1 = getAbsPos(glm::vec2(5, 0.5));
            glm::vec2 p2 = getAbsPos(glm::vec2(0.5, -4));
            glm::vec2 p3 = getAbsPos(glm::vec2(0.5, 5));
            pVA->addLineData(effColor, p0, p1, 1);
            pVA->addLineData(effColor, p2, p3, 1);
        } else {
            AreaNode::renderOutlines(pVA, parentColor);
        }
    }
    for (unsigned i = 0; i < getNumChildren(); i++) {
        getChild(i)->renderOutlines(pVA, effColor);
    }
}

string DivNode::getEffectiveMediaDir()
{
    // TODO: There is no test for this function.
    string sMediaDir = m_sMediaDir;
    if (!isAbsPath(sMediaDir)) {
        if (getParent()) {
            sMediaDir = getParent()->getEffectiveMediaDir()+m_sMediaDir;
        } else {
            sMediaDir = Player::get()->getRootMediaDir()+m_sMediaDir;
        }
    }
    if (sMediaDir[sMediaDir.length()-1] != '/') {
        sMediaDir += '/';
    }
    return sMediaDir;
}

void DivNode::checkReload()
{
    for(unsigned i = 0; i < getNumChildren(); ++i) {
        getChild(i)->checkReload();
    }
}

string DivNode::dump(int indent)
{
    string dumpStr = AreaNode::dump () + "\n";
    vector<NodePtr>::iterator it;
    for(unsigned i = 0; i < getNumChildren(); ++i) {
        getChild(i)->dump(indent+2)+"\n";
    }
    return dumpStr;
}

IntPoint DivNode::getMediaSize()
{
    return IntPoint(0, 0);
}

bool DivNode::isChildTypeAllowed(const string& sType)
{
    return getDefinition()->isChildAllowed(sType);
}

}
<|endoftext|>