<commit_before>/**
 * @file em_fit_impl.hpp
 * @author Ryan Curtin
 *
 * Implementation of EM algorithm for fitting GMMs.
 */
#ifndef __MLPACK_METHODS_GMM_EM_FIT_IMPL_HPP
#define __MLPACK_METHODS_GMM_EM_FIT_IMPL_HPP

// In case it hasn't been included yet.
#include "em_fit.hpp"

// Definition of phi().
#include "phi.hpp"

namespace mlpack {
namespace gmm {

template<typename InitialClusteringType>
void EMFit<InitialClusteringType>::Estimate(const arma::mat& observations,
                                            std::vector<arma::vec>& means,
                                            std::vector<arma::mat>& covariances,
                                            arma::vec& weights)
{
  InitialClustering(observations, means, covariances, weights);

  double l = LogLikelihood(observations, means, covariances, weights);

  Log::Debug << "EMFit::Estimate(): initial clustering log-likelihood: "
      << l << std::endl;

  double lOld = -DBL_MAX;
  arma::mat condProb(observations.n_cols, means.size());

  // Iterate to update the model until no more improvement is found.
  size_t maxIterations = 300;
  size_t iteration = 0;
  while (std::abs(l - lOld) > 1e-10 && iteration < maxIterations)
  {
    // Calculate the conditional probabilities of choosing a particular
    // Gaussian given the observations and the present theta value.
    for (size_t i = 0; i < means.size(); i++)
    {
      // Store conditional probabilities into condProb vector for each
      // Gaussian.  First we make an alias of the condProb vector.
      arma::vec condProbAlias = condProb.unsafe_col(i);
      phi(observations, means[i], covariances[i], condProbAlias);
      condProbAlias *= weights[i];
    }

    // Normalize row-wise.
    for (size_t i = 0; i < condProb.n_rows; i++)
      condProb.row(i) /= accu(condProb.row(i));

    // Store the sum of the probability of each state over all the observations.
    arma::vec probRowSums = trans(arma::sum(condProb, 0 /* columnwise */));

    // Calculate the new value of the means using the updated conditional
    // probabilities.
    for (size_t i = 0; i < means.size(); i++)
    {
      means[i] = (observations * condProb.col(i)) / probRowSums[i];

      // Calculate the new value of the covariances using the updated
      // conditional probabilities and the updated means.
      arma::mat tmp = observations - (means[i] *
          arma::ones<arma::rowvec>(observations.n_cols));
      arma::mat tmpB = tmp % (arma::ones<arma::vec>(observations.n_rows) *
          trans(condProb.col(i)));

      covariances[i] = (tmp * trans(tmpB)) / probRowSums[i];

      if (accu(covariances[i]) == 0)
      {
        Log::Debug << "Covariance " << i << " sums to zero!  Adding "
            << " perturbation." << std::endl;
        covariances[i].diag() += 1e-50;
      }
    }

    // Calculate the new values for omega using the updated conditional
    // probabilities.
    weights = probRowSums / observations.n_cols;

    // Update values of l; calculate new log-likelihood.
    lOld = l;
    l = LogLikelihood(observations, means, covariances, weights);

    iteration++;
  }
}

template<typename InitialClusteringType>
void EMFit<InitialClusteringType>::Estimate(const arma::mat& observations,
                                            const arma::vec& probabilities,
                                            std::vector<arma::vec>& means,
                                            std::vector<arma::mat>& covariances,
                                            arma::vec& weights)
{
  InitialClustering(observations, means, covariances, weights);

  double l = LogLikelihood(observations, means, covariances, weights);

  Log::Debug << "EMFit::Estimate(): initial clustering log-likelihood: "
      << l << std::endl;

  double lOld = -DBL_MAX;
  arma::mat condProb(observations.n_cols, means.size());

  // Iterate to update the model until no more improvement is found.
  size_t maxIterations = 300;
  size_t iteration = 0;
  while (std::abs(l - lOld) > 1e-10 && iteration < maxIterations)
  {
    // Calculate the conditional probabilities of choosing a particular
    // Gaussian given the observations and the present theta value.
    for (size_t i = 0; i < means.size(); i++)
    {
      // Store conditional probabilities into condProb vector for each
      // Gaussian.  First we make an alias of the condProb vector.
      arma::vec condProbAlias = condProb.unsafe_col(i);
      phi(observations, means[i], covariances[i], condProbAlias);
      condProbAlias *= weights[i];
    }

    // Normalize row-wise.
    for (size_t i = 0; i < condProb.n_rows; i++)
      condProb.row(i) /= accu(condProb.row(i));

    // This will store the sum of probabilities of each state over all the
    // observations.
    arma::vec probRowSums(means.size());

    // Calculate the new value of the means using the updated conditional
    // probabilities.
    for (size_t i = 0; i < means.size(); i++)
    {
      // Calculate the sum of probabilities of points, which is the
      // conditional probability of each point being from Gaussian i
      // multiplied by the probability of the point being from this mixture
      // model.
      probRowSums[i] = accu(condProb.col(i) % probabilities);

      means[i] = (observations * (condProb.col(i) % probabilities)) /
        probRowSums[i];

      // Calculate the new value of the covariances using the updated
      // conditional probabilities and the updated means.
      arma::mat tmp = observations - (means[i] *
          arma::ones<arma::rowvec>(observations.n_cols));
      arma::mat tmpB = tmp % (arma::ones<arma::vec>(observations.n_rows) *
          trans(condProb.col(i) % probabilities));

      covariances[i] = (tmp * trans(tmpB)) / probRowSums[i];

      if (accu(covariances[i]) == 0)
      {
        Log::Debug << "Covariance " << i << " sums to zero!  Adding "
            << " perturbation." << std::endl;
        covariances[i].diag() += 1e-50;
      }
    }

    // Calculate the new values for omega using the updated conditional
    // probabilities.
    weights = probRowSums / accu(probabilities);

    // Update values of l; calculate new log-likelihood.
    lOld = l;
    l = LogLikelihood(observations, means, covariances, weights);

    iteration++;
  }
}

template<typename InitialClusteringType>
void EMFit<InitialClusteringType>::InitialClustering(
    const arma::mat& observations,
    std::vector<arma::vec>& means,
    std::vector<arma::mat>& covariances,
    arma::vec& weights)
{
  // Assignments from clustering.
  arma::Col<size_t> assignments;

  // Run clustering algorithm.
  clusterer.Cluster(observations, means.size(), assignments);

  // Now calculate the means, covariances, and weights.
  weights.zeros();
  for (size_t i = 0; i < means.size(); ++i)
  {
    means[i].zeros();
    covariances[i].zeros();
    covariances[i].diag().fill(1e-50);
  }

  // From the assignments, generate our means, covariances, and weights.
  for (size_t i = 0; i < observations.n_cols; ++i)
  {
    size_t cluster = assignments[i];

    // Add this to the relevant mean.
    means[cluster] += observations.col(i);

    // Add this to the relevant covariance.
    covariances[cluster] += observations.col(i) * trans(observations.col(i));

    // Now add one to the weights (we will normalize).
    weights[cluster]++;
  }

  // Now normalize the mean and covariance.
  for (size_t i = 0; i < means.size(); ++i)
  {
    covariances[i] -= means[i] * trans(means[i]) / weights[i];

    means[i] /= weights[i];
    covariances[i] /= (weights[i] > 1) ? weights[i] : 1;

    if (accu(covariances[i]) == 0)
    {
      Log::Debug << "Covariance " << i << " sums to zero!  Adding perturbation."
          << std::endl;
      covariances[i].diag() += 1e-50;
      Log::Debug << covariances[i];
    }
  }

  // Finally, normalize weights.
  weights /= accu(weights);
}

template<typename InitialClusteringType>
double EMFit<InitialClusteringType>::LogLikelihood(
    const arma::mat& observations,
    const std::vector<arma::vec>& means,
    const std::vector<arma::mat>& covariances,
    const arma::vec& weights) const
{
  double logLikelihood = 0;

  arma::vec phis;
  arma::mat likelihoods(means.size(), observations.n_cols);
  for (size_t i = 0; i < means.size(); ++i)
  {
    phi(observations, means[i], covariances[i], phis);
    likelihoods.row(i) = weights(i) * trans(phis);
  }

  // Now sum over every point.
  for (size_t j = 0; j < observations.n_cols; ++j)
    logLikelihood += log(accu(likelihoods.col(j)));

  return logLikelihood;
}

}; // namespace gmm
}; // namespace mlpack

#endif
<commit_msg>Zeroes in any element of a diagonal of a covariance matrix can cause problems.<commit_after>/**
 * @file em_fit_impl.hpp
 * @author Ryan Curtin
 *
 * Implementation of EM algorithm for fitting GMMs.
 */
#ifndef __MLPACK_METHODS_GMM_EM_FIT_IMPL_HPP
#define __MLPACK_METHODS_GMM_EM_FIT_IMPL_HPP

// In case it hasn't been included yet.
#include "em_fit.hpp"

// Definition of phi().
#include "phi.hpp"

namespace mlpack {
namespace gmm {

template<typename InitialClusteringType>
void EMFit<InitialClusteringType>::Estimate(const arma::mat& observations,
                                            std::vector<arma::vec>& means,
                                            std::vector<arma::mat>& covariances,
                                            arma::vec& weights)
{
  InitialClustering(observations, means, covariances, weights);

  double l = LogLikelihood(observations, means, covariances, weights);

  Log::Debug << "EMFit::Estimate(): initial clustering log-likelihood: "
      << l << std::endl;

  double lOld = -DBL_MAX;
  arma::mat condProb(observations.n_cols, means.size());

  // Iterate to update the model until no more improvement is found.
  size_t maxIterations = 300;
  size_t iteration = 0;
  while (std::abs(l - lOld) > 1e-10 && iteration < maxIterations)
  {
    // Calculate the conditional probabilities of choosing a particular
    // Gaussian given the observations and the present theta value.
    for (size_t i = 0; i < means.size(); i++)
    {
      // Store conditional probabilities into condProb vector for each
      // Gaussian.  First we make an alias of the condProb vector.
      arma::vec condProbAlias = condProb.unsafe_col(i);
      phi(observations, means[i], covariances[i], condProbAlias);
      condProbAlias *= weights[i];
    }

    // Normalize row-wise.
    for (size_t i = 0; i < condProb.n_rows; i++)
      condProb.row(i) /= accu(condProb.row(i));

    // Store the sum of the probability of each state over all the observations.
    arma::vec probRowSums = trans(arma::sum(condProb, 0 /* columnwise */));

    // Calculate the new value of the means using the updated conditional
    // probabilities.
    for (size_t i = 0; i < means.size(); i++)
    {
      means[i] = (observations * condProb.col(i)) / probRowSums[i];

      // Calculate the new value of the covariances using the updated
      // conditional probabilities and the updated means.
      arma::mat tmp = observations - (means[i] *
          arma::ones<arma::rowvec>(observations.n_cols));
      arma::mat tmpB = tmp % (arma::ones<arma::vec>(observations.n_rows) *
          trans(condProb.col(i)));

      covariances[i] = (tmp * trans(tmpB)) / probRowSums[i];

      for (size_t d = 0; d < covariances[i].n_rows; ++d)
      {
        if (covariances[i](d, d) == 0.0)
        {
          Log::Debug << "Covariance " << i << " has zero in diagonal element "
              << d << "!  Adding perturbation." << std::endl;
          covariances[i](d, d) += 1e-50;
        }
      }
    }

    // Calculate the new values for omega using the updated conditional
    // probabilities.
    weights = probRowSums / observations.n_cols;

    // Update values of l; calculate new log-likelihood.
    lOld = l;
    l = LogLikelihood(observations, means, covariances, weights);

    iteration++;
  }
}

template<typename InitialClusteringType>
void EMFit<InitialClusteringType>::Estimate(const arma::mat& observations,
                                            const arma::vec& probabilities,
                                            std::vector<arma::vec>& means,
                                            std::vector<arma::mat>& covariances,
                                            arma::vec& weights)
{
  InitialClustering(observations, means, covariances, weights);

  double l = LogLikelihood(observations, means, covariances, weights);

  Log::Debug << "EMFit::Estimate(): initial clustering log-likelihood: "
      << l << std::endl;

  double lOld = -DBL_MAX;
  arma::mat condProb(observations.n_cols, means.size());

  // Iterate to update the model until no more improvement is found.
  size_t maxIterations = 300;
  size_t iteration = 0;
  while (std::abs(l - lOld) > 1e-10 && iteration < maxIterations)
  {
    // Calculate the conditional probabilities of choosing a particular
    // Gaussian given the observations and the present theta value.
    for (size_t i = 0; i < means.size(); i++)
    {
      // Store conditional probabilities into condProb vector for each
      // Gaussian.  First we make an alias of the condProb vector.
      arma::vec condProbAlias = condProb.unsafe_col(i);
      phi(observations, means[i], covariances[i], condProbAlias);
      condProbAlias *= weights[i];
    }

    // Normalize row-wise.
    for (size_t i = 0; i < condProb.n_rows; i++)
      condProb.row(i) /= accu(condProb.row(i));

    // This will store the sum of probabilities of each state over all the
    // observations.
    arma::vec probRowSums(means.size());

    // Calculate the new value of the means using the updated conditional
    // probabilities.
    for (size_t i = 0; i < means.size(); i++)
    {
      // Calculate the sum of probabilities of points, which is the
      // conditional probability of each point being from Gaussian i
      // multiplied by the probability of the point being from this mixture
      // model.
      probRowSums[i] = accu(condProb.col(i) % probabilities);

      means[i] = (observations * (condProb.col(i) % probabilities)) /
        probRowSums[i];

      // Calculate the new value of the covariances using the updated
      // conditional probabilities and the updated means.
      arma::mat tmp = observations - (means[i] *
          arma::ones<arma::rowvec>(observations.n_cols));
      arma::mat tmpB = tmp % (arma::ones<arma::vec>(observations.n_rows) *
          trans(condProb.col(i) % probabilities));

      covariances[i] = (tmp * trans(tmpB)) / probRowSums[i];

      for (size_t d = 0; d < covariances[i].n_rows; ++d)
      {
        if (covariances[i](d, d) == 0.0)
        {
          Log::Debug << "Covariance " << i << " has zero in diagonal element "
            << d << "!  Adding perturbation." << std::endl;
          covariances[i](d, d) += 1e-50;
        }
      }
    }

    // Calculate the new values for omega using the updated conditional
    // probabilities.
    weights = probRowSums / accu(probabilities);

    // Update values of l; calculate new log-likelihood.
    lOld = l;
    l = LogLikelihood(observations, means, covariances, weights);

    iteration++;
  }
}

template<typename InitialClusteringType>
void EMFit<InitialClusteringType>::InitialClustering(
    const arma::mat& observations,
    std::vector<arma::vec>& means,
    std::vector<arma::mat>& covariances,
    arma::vec& weights)
{
  // Assignments from clustering.
  arma::Col<size_t> assignments;

  // Run clustering algorithm.
  clusterer.Cluster(observations, means.size(), assignments);

  // Now calculate the means, covariances, and weights.
  weights.zeros();
  for (size_t i = 0; i < means.size(); ++i)
  {
    means[i].zeros();
    covariances[i].zeros();
    covariances[i].diag().fill(1e-50);
  }

  // From the assignments, generate our means, covariances, and weights.
  for (size_t i = 0; i < observations.n_cols; ++i)
  {
    size_t cluster = assignments[i];

    // Add this to the relevant mean.
    means[cluster] += observations.col(i);

    // Add this to the relevant covariance.
    covariances[cluster] += observations.col(i) * trans(observations.col(i));

    // Now add one to the weights (we will normalize).
    weights[cluster]++;
  }

  // Now normalize the mean and covariance.
  for (size_t i = 0; i < means.size(); ++i)
  {
    covariances[i] -= means[i] * trans(means[i]) / weights[i];

    means[i] /= weights[i];
    covariances[i] /= (weights[i] > 1) ? weights[i] : 1;

    for (size_t d = 0; d < covariances[i].n_rows; ++d)
    {
      if (covariances[i](d, d) == 0.0)
      {
        Log::Debug << "Covariance " << i << " has zero in diagonal element "
          << d << "!  Adding perturbation." << std::endl;
        covariances[i](d, d) += 1e-50;
      }
    }
  }

  // Finally, normalize weights.
  weights /= accu(weights);
}

template<typename InitialClusteringType>
double EMFit<InitialClusteringType>::LogLikelihood(
    const arma::mat& observations,
    const std::vector<arma::vec>& means,
    const std::vector<arma::mat>& covariances,
    const arma::vec& weights) const
{
  double logLikelihood = 0;

  arma::vec phis;
  arma::mat likelihoods(means.size(), observations.n_cols);
  for (size_t i = 0; i < means.size(); ++i)
  {
    phi(observations, means[i], covariances[i], phis);
    likelihoods.row(i) = weights(i) * trans(phis);
  }

  // Now sum over every point.
  for (size_t j = 0; j < observations.n_cols; ++j)
    logLikelihood += log(accu(likelihoods.col(j)));

  return logLikelihood;
}

}; // namespace gmm
}; // namespace mlpack

#endif
<|endoftext|>


<commit_before>#include "stdafx.h"

#include "GraphHandler.h"
#include "Options.h"

#include <cinder/app/AppNative.h>
#include <cinder/params/Params.h>
#include <cinder/qtime/MovieWriter.h>

using namespace ci;
using namespace ci::app;

class GraphStudioApp : public AppNative {
public:
    void prepareSettings(Settings *settings) override;
    void setup() override;
    void mouseDown(MouseEvent event) override;
    void keyDown(KeyEvent event) override;
    void update() override;
    void draw() override;
    void resize() override;
    void shutdown() override;

    const ColorScheme &getCurrentColorScheme();
private:
    ci::params::InterfaceGlRef	params;
    qtime::MovieWriterRef	mMovieWriter;
    std::map<std::string, ColorScheme> colorSchemes;
    std::vector<std::string> colorSchemeNames;
    GraphHandler gh;
    int prevColorSchemeIndex;
    void addNewColorScheme();
    void storeColorScheme();

    void loadSettings();
    void saveSettings();
};

void GraphStudioApp::prepareSettings(Settings *settings)
{
    settings->enableConsoleWindow();
    settings->setWindowSize(800, 600);
    settings->setFrameRate(60.0f);
}

const ColorScheme &GraphStudioApp::getCurrentColorScheme()
{
    return colorSchemes[colorSchemeNames[Options::instance().currentColorSchemeIdx]];
}

void GraphStudioApp::addNewColorScheme()
{
    auto &cs = Options::instance().currentColorScheme;
    cs = ColorScheme();
    bool freeNameFound = false;
    int freeNameIdx = 0;
    std::string newName;
    do
    {
        newName = "ColorScheme #" + std::to_string(++freeNameIdx);
        if (find(begin(colorSchemeNames), end(colorSchemeNames), newName) == colorSchemeNames.end())
            freeNameFound = true;
    } while (!freeNameFound);
    cs.name = newName;
    colorSchemeNames.push_back(cs.name);
    colorSchemes[cs.name] = cs;
    Options::instance().currentColorSchemeIdx = colorSchemes.size() - 1;
    params->addParam("ColorScheme", colorSchemeNames, &Options::instance().currentColorSchemeIdx);
}

void GraphStudioApp::storeColorScheme()
{
    auto &cs = Options::instance().currentColorScheme;
    colorSchemes[cs.name] = cs;
}

void GraphStudioApp::saveSettings()
{
    ci::XmlTree configXml("graphStudioSettings", "");
    configXml.push_back(ci::XmlTree("nodeSize", std::to_string(Options::instance().nodeSize)));
    configXml.push_back(ci::XmlTree("edgeWidth", std::to_string(Options::instance().edgeWidth)));
    configXml.push_back(ci::XmlTree("highlightedEdgeWidth", std::to_string(Options::instance().highlighedEdgeWidth)));
    configXml.push_back(ci::XmlTree("arrowLength", std::to_string(Options::instance().arrowLength)));
    configXml.push_back(ci::XmlTree("arrowAngle", std::to_string(Options::instance().arrowAngle)));
    configXml.push_back(ci::XmlTree("showEdgeWeights", std::to_string(Options::instance().showEdgeWeights)));
    configXml.push_back(ci::XmlTree("showNodeWeights", std::to_string(Options::instance().showNodeWeights)));
    configXml.push_back(ci::XmlTree("force", std::to_string(Options::instance().force)));
    configXml.push_back(ci::XmlTree("speed", std::to_string(Options::instance().speed)));
    configXml.push_back(ci::XmlTree("edgeWeightScale", std::to_string(Options::instance().edgeWeightScale)));
    ci::XmlTree csList("colorSchemes", "");
    for (const auto &cs : colorSchemes)
    {
        csList.push_back(cs.second.toXml());
    }
    configXml.push_back(csList);

    configXml.write(ci::writeFile("config.xml"));
}

void GraphStudioApp::loadSettings()
{
    ci::XmlTree configXml(ci::loadFile("config.xml"));
    ci::XmlTree settings = configXml.getChild("graphStudioSettings");
    Options::instance().nodeSize = settings.getChild("nodeSize").getValue<float>();
    Options::instance().edgeWidth = settings.getChild("edgeWidth").getValue<float>();
    Options::instance().highlighedEdgeWidth = settings.getChild("highlightedEdgeWidth").getValue<float>();
    Options::instance().arrowLength = settings.getChild("arrowLength").getValue<float>();
    Options::instance().arrowAngle = settings.getChild("arrowAngle").getValue<float>();
    Options::instance().showEdgeWeights = settings.getChild("showEdgeWeights").getValue<bool>();
    Options::instance().showNodeWeights = settings.getChild("showNodeWeights").getValue<bool>();

    Options::instance().force = settings.getChild("force").getValue<float>();
    Options::instance().speed = settings.getChild("speed").getValue<int>();
    Options::instance().edgeWeightScale = settings.getChild("edgeWeightScale").getValue<int>();

    ci::XmlTree csList = settings.getChild("colorSchemes");
    for (auto csIt = csList.begin(); csIt != csList.end(); ++csIt)
    {
        ColorScheme cs = ColorScheme::fromXml(*csIt);
        colorSchemes[cs.name] = cs;
        colorSchemeNames.push_back(cs.name);
    }
}

void GraphStudioApp::setup()
{
    loadSettings();

    params = params::InterfaceGl::create("Graph Studio", Vec2i(200, 310));
    params->addParam("Node Size", &Options::instance().nodeSize, "min=1.0 max=50.0 step=1.0");
    params->addParam("Edge Width", &Options::instance().edgeWidth, "min=0.0 max=10.0 step=0.1");
    params->addParam("Highlighted Edge Width", &Options::instance().highlighedEdgeWidth, "min=0.0 max=10.0 step=0.1");
    params->addParam("Arrow Length", &Options::instance().arrowLength, "min=1.0 max=50.0 step=1.0");
    params->addParam("Arrow Angle", &Options::instance().arrowAngle, "min=0.0 max=90.0 step=1.0");
    params->addParam("Show Edge Weights", &Options::instance().showEdgeWeights);
    params->addParam("Show Node Weights", &Options::instance().showNodeWeights);
    params->addSeparator();
    params->addParam("Algorithm", AlgorithmNames, &Options::instance().algorithm);
    params->addParam("Starting Node",  &Options::instance().startNode, "min=1 step=1");
    params->addSeparator();
    params->addParam("Force", &Options::instance().force, "min=1.0 max=300.0 step=1.0");
    params->addParam("Speed", &Options::instance().speed, "min=1.0 max=300.0 step=1.0");
    params->addParam("Edge Weight Scale", &Options::instance().edgeWeightScale, "min=1.0 max=1000.0 step=1.0");
    params->addSeparator();
    params->addText("Colors");
    params->addParam("ColorScheme", colorSchemeNames, &Options::instance().currentColorSchemeIdx);
    params->addParam("Background", &Options::instance().currentColorScheme.backgroundColor);

    params->addParam("Node ", &Options::instance().currentColorScheme.nodeColor);
    params->addParam("Highlighted Node 1", &Options::instance().currentColorScheme.highlightedNodeColor1);
    params->addParam("Highlighted Node 2", &Options::instance().currentColorScheme.highlightedNodeColor2);
    params->addParam("Highlighted Node 3", &Options::instance().currentColorScheme.highlightedNodeColor3);

    params->addParam("Edge ", &Options::instance().currentColorScheme.edgeColor);
    params->addParam("Highlighted Edge 1", &Options::instance().currentColorScheme.highlightedEdgeColor1);
    params->addParam("Highlighted Edge 2", &Options::instance().currentColorScheme.highlightedEdgeColor2);
    params->addParam("Highlighted Edge 3", &Options::instance().currentColorScheme.highlightedEdgeColor3);

    params->addParam("Node Text", &Options::instance().currentColorScheme.nodeTextColor);
    params->addParam("highlightednodeText", &Options::instance().currentColorScheme.highlightednodeTextColor);
    params->addParam("Edge Text", &Options::instance().currentColorScheme.edgeTextColor);
    params->addParam("Highlighted Edge Text", &Options::instance().currentColorScheme.highlightedEdgeTextColor);

    params->addButton("New", std::bind(&GraphStudioApp::addNewColorScheme, this));
    params->addSeparator();
    params->addText("Random Edge Weights");
    params->addParam("Min", &Options::instance().minRandomEdgeWeight, "min=1, max=1000, step=1");
    params->addParam("Max", &Options::instance().maxRandomEdgeWeight, "min=1, max=1000, step=1");
    params->addButton("Generate Weights", std::bind(&GraphHandler::setRandomEdgeWeights, &gh));
    params->addSeparator();
    params->addText("Generate Grid");
    params->addParam("Columns", &GraphParamsGrid::instance().columns, "min=1 step=1");
    params->addParam("Rows", &GraphParamsGrid::instance().rows, "min=1 step=1");
    params->addParam("Directed", &GraphParamsGrid::instance().directed);
    params->addParam("Horizontal Edges", &GraphParamsGrid::instance().horizontal);
    params->addParam("Vertical Edges", &GraphParamsGrid::instance().vertical);
    params->addParam("Diagonal /", &GraphParamsGrid::instance().upDiagonal);
    params->addParam("Diagonal \\", &GraphParamsGrid::instance().downDiagonal);
    params->addButton("Generate grid", std::bind(&GraphHandler::generateSpecialGraph, &gh, GraphHandler::GraphType::grid));
    params->addText("Generate Triangle Mesh");
    params->addParam("Triangles", &GraphParamsTriangleMesh::instance().triangles, "min=1 step=1");
    params->addParam("Randomness", &GraphParamsTriangleMesh::instance().randomness, "min=0.0 step=0.1");
    params->addButton("Generate tri", std::bind(&GraphHandler::generateSpecialGraph, &gh, GraphHandler::GraphType::triangleMesh));

    gh.setup(getWindow());
    /*
    fs::path path = getSaveFilePath();
    if (path.empty())
        return; // user cancelled save
    qtime::MovieWriter::Format format;
    if (qtime::MovieWriter::getUserCompressionSettings(&format)) {
        mMovieWriter = qtime::MovieWriter::create(path, getWindowWidth(), getWindowHeight(), format);
    }
    */
}

void GraphStudioApp::shutdown()
{
    saveSettings();
}

void GraphStudioApp::keyDown(KeyEvent event)
{
    std::string nameBase = "graph_small2";
    if (event.getCode() == KeyEvent::KEY_SPACE)
    {
        // stop - play - pause - play - pause - play - until the last state is reached
        if (!Options::instance().animationPlaying)
        {
            Options::instance().animationPlaying = true;
            Options::instance().animationPaused = false;
            gh.animationPrepare();
        }
        else
        {
            Options::instance().animationPaused = !Options::instance().animationPaused;
            if (Options::instance().animationPaused)
            {
                gh.animationPause();
            }
            else
            {
                gh.animationResume();
            }
        }

        return;
    }
    else  if (event.getCode() == KeyEvent::KEY_RIGHT)
    {
        gh.animationNext();
        return;
    }
    else  if (event.getCode() == KeyEvent::KEY_LEFT)
    {
        gh.animationPrevious();
        return;
    }
    if (event.getChar() == 'm')
    {
        Options::instance().randomMovement = !Options::instance().randomMovement;
        if (Options::instance().randomMovement)
            Options::instance().animationPlaying = false;
    }
    if (event.getChar() == 's')
    {
        std::cout << "Saving graph..." << std::endl;
        gh.saveGraph(nameBase + ".txt");
        gh.saveGraphPositions(nameBase + ".pos");
        std::cout << "Done" << std::endl;
    }
    if (event.getChar() == 'l')
    {
        std::cout << "Loading graph..." << std::endl;

        gh.loadGraph(nameBase + ".txt");
        gh.loadGraphPositions(nameBase + ".pos");
        Options::instance().startNode = 1;
        gh.fitToWindow();
        std::cout << "Done" << std::endl;
    }
    if (event.getChar() == 'u')
    {
        gh.toggleAutomaticEdgeWeightUpdate();
        std::cout << "automaticEdgeWeightUpdate = " << gh.getAutomaticEdgeWeightUpdate() << std::endl;
    }
    if (event.getChar() == 'f')
    {
        gh.fitToWindow();
    }
    if (event.getChar() == 'r')
    {
        gh.reorderNodesSquare();
    }

    if (event.getChar() == 'q')
    {
        saveSettings();
        quit();
    }

}

void GraphStudioApp::mouseDown( MouseEvent event )
{
    //std::cout << "GraphStudioApp::mouseDown" << std::endl;
}

void GraphStudioApp::update()
{
    gh.update();
    if (prevColorSchemeIndex != Options::instance().currentColorSchemeIdx)
    {
        prevColorSchemeIndex = Options::instance().currentColorSchemeIdx;
        Options::instance().currentColorScheme = colorSchemes[colorSchemeNames[Options::instance().currentColorSchemeIdx]];
    }
    else
    {
        storeColorScheme();
    }
}

void GraphStudioApp::draw()
{
    // clear out the window with black
    gl::clear(Color(0, 0, 0));
    gh.draw();
    params->draw();
    /*
    if (mMovieWriter)
        mMovieWriter->addFrame(copyWindowSurface());
    */
}

void GraphStudioApp::resize()
{
    gh.resize(getWindowBounds());
}

CINDER_APP_NATIVE( GraphStudioApp, RendererGl )
<commit_msg>Fixed wierd leaks caused by line width set to 0.0<commit_after>#include "stdafx.h"

#include "GraphHandler.h"
#include "Options.h"

#include <cinder/app/AppNative.h>
#include <cinder/params/Params.h>
#include <cinder/qtime/MovieWriter.h>

using namespace ci;
using namespace ci::app;

class GraphStudioApp : public AppNative {
public:
    void prepareSettings(Settings *settings) override;
    void setup() override;
    void mouseDown(MouseEvent event) override;
    void keyDown(KeyEvent event) override;
    void update() override;
    void draw() override;
    void resize() override;
    void shutdown() override;

    const ColorScheme &getCurrentColorScheme();
private:
    ci::params::InterfaceGlRef	params;
    qtime::MovieWriterRef	mMovieWriter;
    std::map<std::string, ColorScheme> colorSchemes;
    std::vector<std::string> colorSchemeNames;
    GraphHandler gh;
    int prevColorSchemeIndex;
    void addNewColorScheme();
    void storeColorScheme();

    void loadSettings();
    void saveSettings();
};

void GraphStudioApp::prepareSettings(Settings *settings)
{
    settings->enableConsoleWindow();
    settings->setWindowSize(800, 600);
    settings->setFrameRate(60.0f);
}

const ColorScheme &GraphStudioApp::getCurrentColorScheme()
{
    return colorSchemes[colorSchemeNames[Options::instance().currentColorSchemeIdx]];
}

void GraphStudioApp::addNewColorScheme()
{
    auto &cs = Options::instance().currentColorScheme;
    cs = ColorScheme();
    bool freeNameFound = false;
    int freeNameIdx = 0;
    std::string newName;
    do
    {
        newName = "ColorScheme #" + std::to_string(++freeNameIdx);
        if (find(begin(colorSchemeNames), end(colorSchemeNames), newName) == colorSchemeNames.end())
            freeNameFound = true;
    } while (!freeNameFound);
    cs.name = newName;
    colorSchemeNames.push_back(cs.name);
    colorSchemes[cs.name] = cs;
    Options::instance().currentColorSchemeIdx = colorSchemes.size() - 1;
    params->addParam("ColorScheme", colorSchemeNames, &Options::instance().currentColorSchemeIdx);
}

void GraphStudioApp::storeColorScheme()
{
    auto &cs = Options::instance().currentColorScheme;
    colorSchemes[cs.name] = cs;
}

void GraphStudioApp::saveSettings()
{
    ci::XmlTree configXml("graphStudioSettings", "");
    configXml.push_back(ci::XmlTree("nodeSize", std::to_string(Options::instance().nodeSize)));
    configXml.push_back(ci::XmlTree("edgeWidth", std::to_string(Options::instance().edgeWidth)));
    configXml.push_back(ci::XmlTree("highlightedEdgeWidth", std::to_string(Options::instance().highlighedEdgeWidth)));
    configXml.push_back(ci::XmlTree("arrowLength", std::to_string(Options::instance().arrowLength)));
    configXml.push_back(ci::XmlTree("arrowAngle", std::to_string(Options::instance().arrowAngle)));
    configXml.push_back(ci::XmlTree("showEdgeWeights", std::to_string(Options::instance().showEdgeWeights)));
    configXml.push_back(ci::XmlTree("showNodeWeights", std::to_string(Options::instance().showNodeWeights)));
    configXml.push_back(ci::XmlTree("force", std::to_string(Options::instance().force)));
    configXml.push_back(ci::XmlTree("speed", std::to_string(Options::instance().speed)));
    configXml.push_back(ci::XmlTree("edgeWeightScale", std::to_string(Options::instance().edgeWeightScale)));
    ci::XmlTree csList("colorSchemes", "");
    for (const auto &cs : colorSchemes)
    {
        csList.push_back(cs.second.toXml());
    }
    configXml.push_back(csList);

    configXml.write(ci::writeFile("config.xml"));
}

void GraphStudioApp::loadSettings()
{
    ci::XmlTree configXml(ci::loadFile("config.xml"));
    ci::XmlTree settings = configXml.getChild("graphStudioSettings");
    Options::instance().nodeSize = settings.getChild("nodeSize").getValue<float>();
    Options::instance().edgeWidth = settings.getChild("edgeWidth").getValue<float>();
    Options::instance().highlighedEdgeWidth = settings.getChild("highlightedEdgeWidth").getValue<float>();
    Options::instance().arrowLength = settings.getChild("arrowLength").getValue<float>();
    Options::instance().arrowAngle = settings.getChild("arrowAngle").getValue<float>();
    Options::instance().showEdgeWeights = settings.getChild("showEdgeWeights").getValue<bool>();
    Options::instance().showNodeWeights = settings.getChild("showNodeWeights").getValue<bool>();

    Options::instance().force = settings.getChild("force").getValue<float>();
    Options::instance().speed = settings.getChild("speed").getValue<int>();
    Options::instance().edgeWeightScale = settings.getChild("edgeWeightScale").getValue<int>();

    ci::XmlTree csList = settings.getChild("colorSchemes");
    for (auto csIt = csList.begin(); csIt != csList.end(); ++csIt)
    {
        ColorScheme cs = ColorScheme::fromXml(*csIt);
        colorSchemes[cs.name] = cs;
        colorSchemeNames.push_back(cs.name);
    }
}

void GraphStudioApp::setup()
{
    loadSettings();

    params = params::InterfaceGl::create("Graph Studio", Vec2i(200, 310));
    params->addParam("Node Size", &Options::instance().nodeSize, "min=1.0 max=50.0 step=1.0");
    params->addParam("Edge Width", &Options::instance().edgeWidth, "min=0.1 max=10.0 step=0.1");
    params->addParam("Highlighted Edge Width", &Options::instance().highlighedEdgeWidth, "min=0.0 max=10.0 step=0.1");
    params->addParam("Arrow Length", &Options::instance().arrowLength, "min=1.0 max=50.0 step=1.0");
    params->addParam("Arrow Angle", &Options::instance().arrowAngle, "min=0.0 max=90.0 step=1.0");
    params->addParam("Show Edge Weights", &Options::instance().showEdgeWeights);
    params->addParam("Show Node Weights", &Options::instance().showNodeWeights);
    params->addSeparator();
    params->addParam("Algorithm", AlgorithmNames, &Options::instance().algorithm);
    params->addParam("Starting Node",  &Options::instance().startNode, "min=1 step=1");
    params->addSeparator();
    params->addParam("Force", &Options::instance().force, "min=1.0 max=300.0 step=1.0");
    params->addParam("Speed", &Options::instance().speed, "min=1.0 max=300.0 step=1.0");
    params->addParam("Edge Weight Scale", &Options::instance().edgeWeightScale, "min=1.0 max=1000.0 step=1.0");
    params->addSeparator();
    params->addText("Colors");
    params->addParam("ColorScheme", colorSchemeNames, &Options::instance().currentColorSchemeIdx);
    params->addParam("Background", &Options::instance().currentColorScheme.backgroundColor);

    params->addParam("Node ", &Options::instance().currentColorScheme.nodeColor);
    params->addParam("Highlighted Node 1", &Options::instance().currentColorScheme.highlightedNodeColor1);
    params->addParam("Highlighted Node 2", &Options::instance().currentColorScheme.highlightedNodeColor2);
    params->addParam("Highlighted Node 3", &Options::instance().currentColorScheme.highlightedNodeColor3);

    params->addParam("Edge ", &Options::instance().currentColorScheme.edgeColor);
    params->addParam("Highlighted Edge 1", &Options::instance().currentColorScheme.highlightedEdgeColor1);
    params->addParam("Highlighted Edge 2", &Options::instance().currentColorScheme.highlightedEdgeColor2);
    params->addParam("Highlighted Edge 3", &Options::instance().currentColorScheme.highlightedEdgeColor3);

    params->addParam("Node Text", &Options::instance().currentColorScheme.nodeTextColor);
    params->addParam("highlightednodeText", &Options::instance().currentColorScheme.highlightednodeTextColor);
    params->addParam("Edge Text", &Options::instance().currentColorScheme.edgeTextColor);
    params->addParam("Highlighted Edge Text", &Options::instance().currentColorScheme.highlightedEdgeTextColor);

    params->addButton("New", std::bind(&GraphStudioApp::addNewColorScheme, this));
    params->addSeparator();
    params->addText("Random Edge Weights");
    params->addParam("Min", &Options::instance().minRandomEdgeWeight, "min=1, max=1000, step=1");
    params->addParam("Max", &Options::instance().maxRandomEdgeWeight, "min=1, max=1000, step=1");
    params->addButton("Generate Weights", std::bind(&GraphHandler::setRandomEdgeWeights, &gh));
    params->addSeparator();
    params->addText("Generate Grid");
    params->addParam("Columns", &GraphParamsGrid::instance().columns, "min=1 step=1");
    params->addParam("Rows", &GraphParamsGrid::instance().rows, "min=1 step=1");
    params->addParam("Directed", &GraphParamsGrid::instance().directed);
    params->addParam("Horizontal Edges", &GraphParamsGrid::instance().horizontal);
    params->addParam("Vertical Edges", &GraphParamsGrid::instance().vertical);
    params->addParam("Diagonal /", &GraphParamsGrid::instance().upDiagonal);
    params->addParam("Diagonal \\", &GraphParamsGrid::instance().downDiagonal);
    params->addButton("Generate grid", std::bind(&GraphHandler::generateSpecialGraph, &gh, GraphHandler::GraphType::grid));
    params->addText("Generate Triangle Mesh");
    params->addParam("Triangles", &GraphParamsTriangleMesh::instance().triangles, "min=1 step=1");
    params->addParam("Randomness", &GraphParamsTriangleMesh::instance().randomness, "min=0.0 step=0.1");
    params->addButton("Generate tri", std::bind(&GraphHandler::generateSpecialGraph, &gh, GraphHandler::GraphType::triangleMesh));

    gh.setup(getWindow());
    /*
    fs::path path = getSaveFilePath();
    if (path.empty())
        return; // user cancelled save
    qtime::MovieWriter::Format format;
    if (qtime::MovieWriter::getUserCompressionSettings(&format)) {
        mMovieWriter = qtime::MovieWriter::create(path, getWindowWidth(), getWindowHeight(), format);
    }
    */
}

void GraphStudioApp::shutdown()
{
    saveSettings();
}

void GraphStudioApp::keyDown(KeyEvent event)
{
    std::string nameBase = "graph_small2";
    if (event.getCode() == KeyEvent::KEY_SPACE)
    {
        // stop - play - pause - play - pause - play - until the last state is reached
        if (!Options::instance().animationPlaying)
        {
            Options::instance().animationPlaying = true;
            Options::instance().animationPaused = false;
            gh.animationPrepare();
        }
        else
        {
            Options::instance().animationPaused = !Options::instance().animationPaused;
            if (Options::instance().animationPaused)
            {
                gh.animationPause();
            }
            else
            {
                gh.animationResume();
            }
        }

        return;
    }
    else  if (event.getCode() == KeyEvent::KEY_RIGHT)
    {
        gh.animationNext();
        return;
    }
    else  if (event.getCode() == KeyEvent::KEY_LEFT)
    {
        gh.animationPrevious();
        return;
    }
    if (event.getChar() == 'm')
    {
        Options::instance().randomMovement = !Options::instance().randomMovement;
        if (Options::instance().randomMovement)
            Options::instance().animationPlaying = false;
    }
    if (event.getChar() == 's')
    {
        std::cout << "Saving graph..." << std::endl;
        gh.saveGraph(nameBase + ".txt");
        gh.saveGraphPositions(nameBase + ".pos");
        std::cout << "Done" << std::endl;
    }
    if (event.getChar() == 'l')
    {
        std::cout << "Loading graph..." << std::endl;

        gh.loadGraph(nameBase + ".txt");
        gh.loadGraphPositions(nameBase + ".pos");
        Options::instance().startNode = 1;
        gh.fitToWindow();
        std::cout << "Done" << std::endl;
    }
    if (event.getChar() == 'u')
    {
        gh.toggleAutomaticEdgeWeightUpdate();
        std::cout << "automaticEdgeWeightUpdate = " << gh.getAutomaticEdgeWeightUpdate() << std::endl;
    }
    if (event.getChar() == 'f')
    {
        gh.fitToWindow();
    }
    if (event.getChar() == 'r')
    {
        gh.reorderNodesSquare();
    }

    if (event.getChar() == 'q')
    {
        saveSettings();
        quit();
    }

}

void GraphStudioApp::mouseDown( MouseEvent event )
{
    //std::cout << "GraphStudioApp::mouseDown" << std::endl;
}

void GraphStudioApp::update()
{
    gh.update();
    if (prevColorSchemeIndex != Options::instance().currentColorSchemeIdx)
    {
        prevColorSchemeIndex = Options::instance().currentColorSchemeIdx;
        Options::instance().currentColorScheme = colorSchemes[colorSchemeNames[Options::instance().currentColorSchemeIdx]];
    }
    else
    {
        storeColorScheme();
    }
}

void GraphStudioApp::draw()
{
    // clear out the window with black
    gl::clear(Color(0, 0, 0));
    gh.draw();
    params->draw();
    /*
    if (mMovieWriter)
        mMovieWriter->addFrame(copyWindowSurface());
    */
}

void GraphStudioApp::resize()
{
    gh.resize(getWindowBounds());
}

CINDER_APP_NATIVE( GraphStudioApp, RendererGl )
<|endoftext|>


<commit_before>/*
The MIT License (MIT)

Copyright (c) 2016 CStanKonrad

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.
*/

#include <cstdio>
#include <vector>

const int MAX_NUM_OF_LEFT_V = 50000;
const int MAX_NUM_OF_RIGHT_V = 50000;

struct SLeftVerticle
{
	std::vector<int> adj;	//Adjacent
	bool isMatched = false;
	bool isVisited = false;
} left[MAX_NUM_OF_LEFT_V + 7];

int rightVertMatch[MAX_NUM_OF_RIGHT_V + 7];	//0 means unmatched else id of matched left verticle

int n, m, p;	//number of left, right verticles and number of edges

bool dfs(int _leftId)
{
	left[_leftId].isVisited = true;
	for (unsigned i = 0, r; i < left[_leftId].adj.size(); ++i)
	{
		r = left[_leftId].adj[i];
		if (rightVertMatch[r] == false || (!left[rightVertMatch[r]].isVisited && dfs(rightVertMatch[r])))
		{
			rightVertMatch[r] = _leftId;
			left[_leftId].isMatched = true;
			return true;
		}
	}
	return false;
}

int turboMatching()
{
	bool find;
	int maximumMatching = 0;
	do
	{
		find = false;
		for (int i = 1; i <= n; ++i)
		{
			if (!left[i].isVisited && !left[i].isMatched && dfs(i))
			{
				++maximumMatching;
				find = true;
			}
		}

		for (int i = 1; i <= n; ++i)
			left[i].isVisited = false;

	} while(find == true);	//while I can extend matching
	return maximumMatching;
}

int main()
{
	scanf("%d%d%d", &n, &m, &p);
	for (int i = 1, l, r; i <= p; ++i)
	{
		scanf("%d%d", &l, &r);
		left[l].adj.push_back(r);
	}
	int maximumMatching = turboMatching();	//maximumNumberOfMatches
	printf("%d\n", maximumMatching);
	return 0;
}<commit_msg>turbomatching description update<commit_after>/*
The MIT License (MIT)

Copyright (c) 2016 CStanKonrad

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.

Based on ILOCAMP lecture
*/

#include <cstdio>
#include <vector>

const int MAX_NUM_OF_LEFT_V = 50000;
const int MAX_NUM_OF_RIGHT_V = 50000;

struct SLeftVerticle
{
	std::vector<int> adj;	//Adjacent
	bool isMatched = false;
	bool isVisited = false;
} left[MAX_NUM_OF_LEFT_V + 7];

int rightVertMatch[MAX_NUM_OF_RIGHT_V + 7];	//0 means unmatched else id of matched left verticle

int n, m, p;	//number of left, right verticles and number of edges

bool dfs(int _leftId)
{
	left[_leftId].isVisited = true;
	for (unsigned i = 0, r; i < left[_leftId].adj.size(); ++i)
	{
		r = left[_leftId].adj[i];
		if (rightVertMatch[r] == false || (!left[rightVertMatch[r]].isVisited && dfs(rightVertMatch[r])))
		{
			rightVertMatch[r] = _leftId;
			left[_leftId].isMatched = true;
			return true;
		}
	}
	return false;
}

int turboMatching()
{
	bool find;
	int maximumMatching = 0;
	do
	{
		find = false;
		for (int i = 1; i <= n; ++i)
		{
			if (!left[i].isVisited && !left[i].isMatched && dfs(i))
			{
				++maximumMatching;
				find = true;
			}
		}

		for (int i = 1; i <= n; ++i)
			left[i].isVisited = false;

	} while(find == true);	//while I can extend matching
	return maximumMatching;
}

int main()
{
	scanf("%d%d%d", &n, &m, &p);
	for (int i = 1, l, r; i <= p; ++i)
	{
		scanf("%d%d", &l, &r);
		left[l].adj.push_back(r);
	}
	int maximumMatching = turboMatching();	//maximumNumberOfMatches
	printf("%d\n", maximumMatching);
	return 0;
}<|endoftext|>


<commit_before>// $Id$

//**************************************************************************
//* This file is property of and copyright by the ALICE HLT Project        *
//* ALICE Experiment at CERN, All rights reserved.                         *
//*                                                                        *
//* Primary Authors: Matthias Richter <Matthias.Richter@ift.uib.no>        *
//*                  for The ALICE HLT Project.                            *
//*                                                                        *
//* Permission to use, copy, modify and distribute this software and its   *
//* documentation strictly for non-commercial purposes is hereby granted   *
//* without fee, provided that the above copyright notice appears in all   *
//* copies and that both the copyright notice and this permission notice   *
//* appear in the supporting documentation. The authors make no claims     *
//* about the suitability of this software for any purpose. It is          *
//* provided "as is" without express or implied warranty.                  *
//**************************************************************************

/// @file   AliHLTDataInflaterHuffman.cxx
/// @author Matthias Richter
/// @date   2011-09-01
/// @brief  Data inflater implementation for huffman encoded data
/// @note

#include "AliHLTDataInflaterHuffman.h"
#include "AliHLTHuffman.h"
#include "TList.h"

/** ROOT macro for the implementation of ROOT specific class methods */
ClassImp(AliHLTDataInflaterHuffman)

AliHLTDataInflaterHuffman::AliHLTDataInflaterHuffman()
  : AliHLTDataInflater()
  , fHuffmanCoders()
  , fHuffmanCoderList(NULL)
  , fCurrentParameter(-1)
  , fLegacyMode(-1)
{
  // see header file for class documentation
  // or
  // refer to README to build package
  // or
  // visit http://web.ift.uib.no/~kjeks/doc/alice-hlt
}

AliHLTDataInflaterHuffman::~AliHLTDataInflaterHuffman()
{
  // destructor
}

int AliHLTDataInflaterHuffman::AddParameterDefinition(const char* name, unsigned bitLength)
{
  /// search a parameter definition in the decoder configuration, and set the index
  /// array, return reference id
  /// TODO: this code is a copy of AliHLTDataDeflaterHuffman::AddParameterDefinition
  /// make a common base class
  if (!name) return -EINVAL;
  if (!fHuffmanCoderList) return -ENODEV;
  TObject* pObj=fHuffmanCoderList->FindObject(name);
  if (!pObj) {
    HLTError("can not find decoder of id '%s'", name);
    return -ENOENT;
  }
  AliHLTHuffman* pHuffman=dynamic_cast<AliHLTHuffman*>(pObj);
  if (!pHuffman) {
    HLTError("object %s has wrong type, expected AliHLTHuffman", name);
    return -EBADF;
  }
  if (pHuffman->GetMaxBits()!=bitLength) {
    HLTError("mismatch in bitlengt: can not use decoder %s of length %d for encoding of %d bits", pHuffman->GetName(), pHuffman->GetMaxBits(), bitLength);
    return -EPERM;
  }

  fHuffmanCoders.push_back(pHuffman);
  return fHuffmanCoders.size()-1;
}

int AliHLTDataInflaterHuffman::InitDecoders(TList* decoderlist)
{
  /// init list of decoders
  /// expects to be an external pointer, valid throughout the livetime of
  /// the instance
  /// TODO: this code is a copy of AliHLTDataDeflaterHuffman::InitDecoders
  /// make a common base class
  if (!decoderlist) return -EINVAL;
  if (!fHuffmanCoderList) {
    fHuffmanCoderList=new TList;
  } else {
    if (fHuffmanCoderList->GetEntries()>0 && fHuffmanCoderList->IsOwner()) {
      HLTWarning("list of decoders owns already %d object(s), but disabling ownership now because of new external pointers");
    }
  }
  if (!fHuffmanCoderList) return -ENOMEM;
  fHuffmanCoderList->SetOwner(kFALSE);
  TIter next(decoderlist);
  TObject* pObj=NULL;
  while ((pObj=next())!=NULL) {
    if (dynamic_cast<AliHLTHuffman*>(pObj)==NULL) continue;
    if (fHuffmanCoderList->FindObject(pObj->GetName())) {
      HLTError("duplicate entry of name '%s'", pObj->GetName());
      return -EEXIST;
    }
    fHuffmanCoderList->Add(pObj);
  }

  return fHuffmanCoderList->GetEntries();
}

bool AliHLTDataInflaterHuffman::NextValue(AliHLTUInt64_t& value, AliHLTUInt32_t& length)
{
  /// overloaded from AliHLTDataInflater
  /// functions reads the sequence of parameters as defined by the decoder
  /// list, than it starts at the first parameter again
  value=0;
  length=0;
  AliHLTUInt64_t input=0;
  AliHLTUInt32_t inputLength=64;
  if (GetRemainingBitDataSizeBytes()<=sizeof(AliHLTUInt64_t)) {
    inputLength=8*GetRemainingBitDataSizeBytes();
    inputLength-=(7-GetCurrentBitInputPosition());
  }
  if (!InputBits(input, inputLength)) return false;
  if (fLegacyMode!=0) {
  if ((++fCurrentParameter)>=(int)fHuffmanCoders.size()) fCurrentParameter=0;
  fLegacyMode=1;
  }
  if (fHuffmanCoders.size()==0 || fCurrentParameter<0) return false;
  // the huffman code is decoded from bit 0 corresponding to the top node and then to
  // the left. The bitstream stores the reversed huffman code from MSB to LSB to ensure
  // a continous bit stream, that's why then input word needs to be reversed before
  // decoding.
  // TODO: introducing DecodeReverse into AliHLTHuffman can speed up the reading
  std::bitset<64> bits;
  for (unsigned bit=0; bit<inputLength; bit++) {bits[inputLength-1-bit]=input&0x1;input>>=1;}
  AliHLTUInt32_t codeLength=0;
  if (!fHuffmanCoders[fCurrentParameter]->Decode(bits, value, length, codeLength)) return false;
  if (inputLength<codeLength) {
    HLTError("huffman decoder '%s' pretends to have %d bit(s) decoded, but only %d available",
	     fHuffmanCoders[fCurrentParameter]->GetName(), codeLength, inputLength);
    return false;
  }
  inputLength-=codeLength;
  RewindBitPosition(inputLength);

  return true;
}
<commit_msg>implementing cleanup functionality to use the same instance in multiple calls<commit_after>// $Id$

//**************************************************************************
//* This file is property of and copyright by the ALICE HLT Project        *
//* ALICE Experiment at CERN, All rights reserved.                         *
//*                                                                        *
//* Primary Authors: Matthias Richter <Matthias.Richter@ift.uib.no>        *
//*                  for The ALICE HLT Project.                            *
//*                                                                        *
//* Permission to use, copy, modify and distribute this software and its   *
//* documentation strictly for non-commercial purposes is hereby granted   *
//* without fee, provided that the above copyright notice appears in all   *
//* copies and that both the copyright notice and this permission notice   *
//* appear in the supporting documentation. The authors make no claims     *
//* about the suitability of this software for any purpose. It is          *
//* provided "as is" without express or implied warranty.                  *
//**************************************************************************

/// @file   AliHLTDataInflaterHuffman.cxx
/// @author Matthias Richter
/// @date   2011-09-01
/// @brief  Data inflater implementation for huffman encoded data
/// @note

#include "AliHLTDataInflaterHuffman.h"
#include "AliHLTHuffman.h"
#include "TList.h"

/** ROOT macro for the implementation of ROOT specific class methods */
ClassImp(AliHLTDataInflaterHuffman)

AliHLTDataInflaterHuffman::AliHLTDataInflaterHuffman()
  : AliHLTDataInflater()
  , fHuffmanCoders()
  , fHuffmanCoderList(NULL)
  , fCurrentParameter(-1)
  , fLegacyMode(-1)
{
  // see header file for class documentation
  // or
  // refer to README to build package
  // or
  // visit http://web.ift.uib.no/~kjeks/doc/alice-hlt
}

AliHLTDataInflaterHuffman::~AliHLTDataInflaterHuffman()
{
  // destructor
  if (fHuffmanCoderList) delete fHuffmanCoderList;
  fHuffmanCoderList=NULL;
}

int AliHLTDataInflaterHuffman::AddParameterDefinition(const char* name, unsigned bitLength)
{
  /// search a parameter definition in the decoder configuration, and set the index
  /// array, return reference id
  /// TODO: this code is a copy of AliHLTDataDeflaterHuffman::AddParameterDefinition
  /// make a common base class
  if (!name) return -EINVAL;
  if (!fHuffmanCoderList) return -ENODEV;
  TObject* pObj=fHuffmanCoderList->FindObject(name);
  if (!pObj) {
    HLTError("can not find decoder of id '%s'", name);
    return -ENOENT;
  }
  AliHLTHuffman* pHuffman=dynamic_cast<AliHLTHuffman*>(pObj);
  if (!pHuffman) {
    HLTError("object %s has wrong type, expected AliHLTHuffman", name);
    return -EBADF;
  }
  if (pHuffman->GetMaxBits()!=bitLength) {
    HLTError("mismatch in bitlengt: can not use decoder %s of length %d for encoding of %d bits", pHuffman->GetName(), pHuffman->GetMaxBits(), bitLength);
    return -EPERM;
  }

  fHuffmanCoders.push_back(pHuffman);
  return fHuffmanCoders.size()-1;
}

int AliHLTDataInflaterHuffman::InitDecoders(TList* decoderlist)
{
  /// init list of decoders
  /// expects to be an external pointer, valid throughout the livetime of
  /// the instance
  /// TODO: this code is a copy of AliHLTDataDeflaterHuffman::InitDecoders
  /// make a common base class
  if (!decoderlist) return -EINVAL;
  if (!fHuffmanCoderList) {
    fHuffmanCoderList=new TList;
  } else {
    if (fHuffmanCoderList->GetEntries()>0 && fHuffmanCoderList->IsOwner()) {
      HLTWarning("list of decoders owns already %d object(s), but disabling ownership now because of new external pointers");
    }
  }
  if (!fHuffmanCoderList) return -ENOMEM;
  fHuffmanCoderList->SetOwner(kFALSE);
  TIter next(decoderlist);
  TObject* pObj=NULL;
  while ((pObj=next())!=NULL) {
    if (dynamic_cast<AliHLTHuffman*>(pObj)==NULL) continue;
    if (fHuffmanCoderList->FindObject(pObj->GetName())) {
      HLTError("duplicate entry of name '%s'", pObj->GetName());
      return -EEXIST;
    }
    fHuffmanCoderList->Add(pObj);
  }

  return fHuffmanCoderList->GetEntries();
}

bool AliHLTDataInflaterHuffman::NextValue(AliHLTUInt64_t& value, AliHLTUInt32_t& length)
{
  /// overloaded from AliHLTDataInflater
  /// functions reads the sequence of parameters as defined by the decoder
  /// list, than it starts at the first parameter again
  value=0;
  length=0;
  AliHLTUInt64_t input=0;
  AliHLTUInt32_t inputLength=64;
  if (GetRemainingBitDataSizeBytes()<=sizeof(AliHLTUInt64_t)) {
    inputLength=8*GetRemainingBitDataSizeBytes();
    inputLength-=(7-GetCurrentBitInputPosition());
  }
  if (!InputBits(input, inputLength)) return false;
  if (fLegacyMode!=0) {
  if ((++fCurrentParameter)>=(int)fHuffmanCoders.size()) fCurrentParameter=0;
  fLegacyMode=1;
  }
  if (fHuffmanCoders.size()==0 || fCurrentParameter<0) return false;
  // the huffman code is decoded from bit 0 corresponding to the top node and then to
  // the left. The bitstream stores the reversed huffman code from MSB to LSB to ensure
  // a continous bit stream, that's why then input word needs to be reversed before
  // decoding.
  // TODO: introducing DecodeReverse into AliHLTHuffman can speed up the reading
  std::bitset<64> bits;
  for (unsigned bit=0; bit<inputLength; bit++) {bits[inputLength-1-bit]=input&0x1;input>>=1;}
  AliHLTUInt32_t codeLength=0;
  if (!fHuffmanCoders[fCurrentParameter]->Decode(bits, value, length, codeLength)) return false;
  if (inputLength<codeLength) {
    HLTError("huffman decoder '%s' pretends to have %d bit(s) decoded, but only %d available",
	     fHuffmanCoders[fCurrentParameter]->GetName(), codeLength, inputLength);
    return false;
  }
  inputLength-=codeLength;
  RewindBitPosition(inputLength);

  return true;
}

void AliHLTDataInflaterHuffman::Clear(Option_t * option)
{
  /// clear the object
  fCurrentParameter=-1;

  if (strcmp(option, "all")==0) {
    fHuffmanCoders.clear();
    if (fHuffmanCoderList) delete fHuffmanCoderList;
    fHuffmanCoderList=NULL;
  }

  AliHLTDataInflater::Clear(option);
}
<|endoftext|>


<commit_before>// Copyright (c) 2011 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/login/webui_login_view.h"

#include "base/bind.h"
#include "base/callback.h"
#include "base/i18n/rtl.h"
#include "base/utf_string_conversions.h"
#include "base/values.h"
#include "chrome/browser/chromeos/accessibility/accessibility_util.h"
#include "chrome/browser/chromeos/cros/cros_library.h"
#include "chrome/browser/chromeos/dbus/dbus_thread_manager.h"
#include "chrome/browser/chromeos/dbus/session_manager_client.h"
#include "chrome/browser/chromeos/login/proxy_settings_dialog.h"
#include "chrome/browser/chromeos/login/webui_login_display.h"
#include "chrome/browser/chromeos/status/status_area_view.h"
#include "chrome/browser/chromeos/status/status_area_view_chromeos.h"
#include "chrome/browser/profiles/profile_manager.h"
#include "chrome/browser/ui/views/dom_view.h"
#include "chrome/browser/ui/webui/chromeos/login/oobe_ui.h"
#include "chrome/common/render_messages.h"
#include "content/browser/tab_contents/tab_contents.h"
#include "content/public/browser/render_view_host_observer.h"
#include "ui/gfx/rect.h"
#include "ui/gfx/size.h"
#include "ui/views/widget/widget.h"

#if defined(TOOLKIT_USES_GTK)
#include "chrome/browser/chromeos/legacy_window_manager/wm_ipc.h"
#include "ui/views/widget/native_widget_gtk.h"
#endif

#if defined(USE_VIRTUAL_KEYBOARD)
#include "chrome/browser/ui/virtual_keyboard/virtual_keyboard_manager.h"
#endif

#if defined(USE_AURA)
#include "chrome/browser/ui/views/aura/chrome_shell_delegate.h"
#endif

namespace {

const char kViewClassName[] = "browser/chromeos/login/WebUILoginView";

// These strings must be kept in sync with handleAccelerator() in oobe.js.
const char kAccelNameAccessibility[] = "accessibility";
const char kAccelNameCancel[] = "cancel";
const char kAccelNameEnrollment[] = "enrollment";

// Observes IPC messages from the FrameSniffer and notifies JS if error
// appears.
class SnifferObserver : public content::RenderViewHostObserver {
 public:
  SnifferObserver(RenderViewHost* host, WebUI* webui)
      : content::RenderViewHostObserver(host), webui_(webui) {
    DCHECK(webui_);
    Send(new ChromeViewMsg_StartFrameSniffer(routing_id(),
                                             UTF8ToUTF16("gaia-frame")));
  }

  virtual ~SnifferObserver() {}

  // IPC::Channel::Listener implementation.
  virtual bool OnMessageReceived(const IPC::Message& message) {
    bool handled = true;
    IPC_BEGIN_MESSAGE_MAP(SnifferObserver, message)
      IPC_MESSAGE_HANDLER(ChromeViewHostMsg_FrameLoadingError, OnError)
      IPC_MESSAGE_UNHANDLED(handled = false)
    IPC_END_MESSAGE_MAP()
    return handled;
  }

 private:
  void OnError(int error) {
    base::FundamentalValue error_value(error);
    webui_->CallJavascriptFunction("login.ErrorMessageScreen.onFrameError",
                                   error_value);
  }

  WebUI* webui_;
};

// A View class which places its first child at the right most position.
class RightAlignedView : public views::View {
 public:
  virtual void Layout() OVERRIDE;
  virtual void ChildPreferredSizeChanged(View* child) OVERRIDE;
};

void RightAlignedView::Layout() {
  if (has_children()) {
    views::View* child = child_at(0);
    gfx::Size preferred_size = child->GetPreferredSize();
    child->SetBounds(width() - preferred_size.width(),
                     0, preferred_size.width(), preferred_size.height());
  }
}

void RightAlignedView::ChildPreferredSizeChanged(View* child) {
  Layout();
}

}  // namespace

namespace chromeos {

// static
const int WebUILoginView::kStatusAreaCornerPadding = 5;

// WebUILoginView public: ------------------------------------------------------

WebUILoginView::WebUILoginView()
    : status_area_(NULL),
      webui_login_(NULL),
      login_window_(NULL),
      status_window_(NULL),
      host_window_frozen_(false),
      status_area_visibility_on_init_(true) {
#if defined(USE_VIRTUAL_KEYBOARD)
  // Make sure the singleton VirtualKeyboardManager object is created.
  VirtualKeyboardManager::GetInstance();
#endif
  accel_map_[ui::Accelerator(ui::VKEY_Z, false, true, true)] =
      kAccelNameAccessibility;
  accel_map_[ui::Accelerator(ui::VKEY_ESCAPE, false, false, false)] =
      kAccelNameCancel;
  accel_map_[ui::Accelerator(ui::VKEY_E, false, true, true)] =
      kAccelNameEnrollment;

  for (AccelMap::iterator i(accel_map_.begin()); i != accel_map_.end(); ++i)
    AddAccelerator(i->first);
}

WebUILoginView::~WebUILoginView() {
  if (status_window_)
    status_window_->CloseNow();
  status_window_ = NULL;
}

void WebUILoginView::Init(views::Widget* login_window) {
  login_window_ = login_window;
  webui_login_ = new DOMView();
  AddChildView(webui_login_);
  webui_login_->Init(ProfileManager::GetDefaultProfile(), NULL);
  webui_login_->SetVisible(true);

  TabContents* tab_contents = webui_login_->dom_contents()->tab_contents();
  tab_contents->set_delegate(this);

  tab_watcher_.reset(new TabFirstRenderWatcher(tab_contents, this));
}

std::string WebUILoginView::GetClassName() const {
  return kViewClassName;
}

bool WebUILoginView::AcceleratorPressed(
    const ui::Accelerator& accelerator) {
  AccelMap::const_iterator entry = accel_map_.find(accelerator);
  if (entry == accel_map_.end())
    return false;

  if (!webui_login_)
    return true;

  WebUI* web_ui = GetWebUI();
  if (web_ui) {
    base::StringValue accel_name(entry->second);
    web_ui->CallJavascriptFunction("cr.ui.Oobe.handleAccelerator",
                                   accel_name);
  }

  return true;
}

gfx::NativeWindow WebUILoginView::GetNativeWindow() const {
  return GetWidget()->GetNativeWindow();
}

void WebUILoginView::OnWindowCreated() {
#if defined(TOOLKIT_USES_GTK)
  // Freezes host window update until the tab is rendered.
  host_window_frozen_ = static_cast<views::NativeWidgetGtk*>(
      GetWidget()->native_widget())->SuppressFreezeUpdates();
#else
  // TODO(saintlou): Unclear if we need this for the !gtk case.
  // According to nkostylev it prevents the renderer from flashing with a
  // white solid background until the content is fully rendered.
#endif
}

void WebUILoginView::UpdateWindowType() {
#if defined(TOOLKIT_USES_GTK)
  std::vector<int> params;
  WmIpc::instance()->SetWindowType(
      GTK_WIDGET(GetNativeWindow()),
      WM_IPC_WINDOW_LOGIN_WEBUI,
      &params);
#endif
}

void WebUILoginView::LoadURL(const GURL & url) {
  webui_login_->LoadURL(url);
  webui_login_->RequestFocus();
}

WebUI* WebUILoginView::GetWebUI() {
  return webui_login_->dom_contents()->tab_contents()->web_ui();
}

void WebUILoginView::SetStatusAreaEnabled(bool enable) {
  if (status_area_)
    status_area_->MakeButtonsActive(enable);
}

void WebUILoginView::SetStatusAreaVisible(bool visible) {
  if (status_area_)
    status_area_->SetVisible(visible);
  else
    status_area_visibility_on_init_ = visible;
}

// WebUILoginView protected: ---------------------------------------------------

void WebUILoginView::Layout() {
  DCHECK(webui_login_);
  webui_login_->SetBoundsRect(bounds());
}

void WebUILoginView::OnLocaleChanged() {
  // Proxy settings dialog contains localized strings.
  proxy_settings_dialog_.reset();
  SchedulePaint();
}

void WebUILoginView::ChildPreferredSizeChanged(View* child) {
  Layout();
  SchedulePaint();
}

// Overridden from StatusAreaButton::Delegate:

bool WebUILoginView::ShouldExecuteStatusAreaCommand(
    const views::View* button_view, int command_id) const {
  if (command_id == StatusAreaButton::Delegate::SHOW_NETWORK_OPTIONS)
    return true;
  return false;
}

void WebUILoginView::ExecuteStatusAreaCommand(
    const views::View* button_view, int command_id) {
  if (command_id == StatusAreaButton::Delegate::SHOW_NETWORK_OPTIONS) {
    if (proxy_settings_dialog_.get() == NULL) {
      proxy_settings_dialog_.reset(new ProxySettingsDialog(NULL,
                                                           GetNativeWindow()));
    }
    proxy_settings_dialog_->Show();
  }
}

gfx::Font WebUILoginView::GetStatusAreaFont(const gfx::Font& font) const {
  return font;
}

StatusAreaButton::TextStyle WebUILoginView::GetStatusAreaTextStyle() const {
  return StatusAreaButton::GRAY_PLAIN;
}

void WebUILoginView::ButtonVisibilityChanged(views::View* button_view) {
  status_area_->UpdateButtonVisibility();
}

void WebUILoginView::OnRenderHostCreated(RenderViewHost* host) {
  new SnifferObserver(host, GetWebUI());
}

void WebUILoginView::OnTabMainFrameLoaded() {
  VLOG(1) << "WebUI login main frame loaded.";
}

void WebUILoginView::OnTabMainFrameFirstRender() {
  VLOG(1) << "WebUI login main frame rendered.";
  StatusAreaViewChromeos::SetScreenMode(
      StatusAreaViewChromeos::LOGIN_MODE_WEBUI);
  // In aura there's a global status area shown already.
#if defined(USE_AURA)
  status_area_ = ChromeShellDelegate::instance()->GetStatusArea();
  status_area_->SetVisible(status_area_visibility_on_init_);
#else
  InitStatusArea();
#endif

#if defined(TOOLKIT_USES_GTK)
  if (host_window_frozen_) {
    host_window_frozen_ = false;

    // Unfreezes the host window since tab is rendered now.
    views::NativeWidgetGtk::UpdateFreezeUpdatesProperty(
        GetNativeWindow(), false);
  }
#endif

  bool emit_login_visible = false;

  // In aura, there will be no window-manager. So chrome needs to emit the
  // 'login-prompt-visible' signal. This needs to happen here, after the page
  // has completed rendering itself.
#if defined(USE_AURA)
  emit_login_visible = true;
#endif
  if (emit_login_visible)
    chromeos::DBusThreadManager::Get()->GetSessionManagerClient()
        ->EmitLoginPromptVisible();

  OobeUI* oobe_ui = static_cast<OobeUI*>(GetWebUI());
  // Notify OOBE that the login frame has been rendered. Currently
  // this is used to start camera presence check.
  oobe_ui->OnLoginPromptVisible();
}

void WebUILoginView::InitStatusArea() {
  DCHECK(status_area_ == NULL);
  DCHECK(status_window_ == NULL);
  StatusAreaViewChromeos* status_area_chromeos = new StatusAreaViewChromeos();
  status_area_chromeos->Init(this);
  status_area_ = status_area_chromeos;
  status_area_->SetVisible(status_area_visibility_on_init_);

  // Width of |status_window| is meant to be large enough.
  // The current value of status_area_->GetPreferredSize().width()
  // will be too small when button status is changed.
  // (e.g. when CapsLock indicator appears)
  gfx::Size widget_size(width()/2,
                        status_area_->GetPreferredSize().height());
  const int widget_x = base::i18n::IsRTL() ?
      kStatusAreaCornerPadding :
      width() - widget_size.width() - kStatusAreaCornerPadding;
  gfx::Rect widget_bounds(widget_x, kStatusAreaCornerPadding,
                          widget_size.width(), widget_size.height());
  // TODO(nkostylev|oshima): Make status area in the same window as
  // |webui_login_| once RenderWidgetHostViewViews and compositor are
  // ready.
  views::Widget::InitParams widget_params(
      views::Widget::InitParams::TYPE_WINDOW_FRAMELESS);
  widget_params.bounds = widget_bounds;
  widget_params.transparent = true;
  widget_params.parent_widget = login_window_;
  status_window_ = new views::Widget;
  status_window_->Init(widget_params);

#if defined(TOOLKIT_USES_GTK)
  chromeos::WmIpc::instance()->SetWindowType(
      status_window_->GetNativeView(),
      chromeos::WM_IPC_WINDOW_CHROME_INFO_BUBBLE,
      NULL);
#endif

  views::View* contents_view = new RightAlignedView;
  contents_view->AddChildView(status_area_);
  status_window_->SetContentsView(contents_view);
  status_window_->Show();
}

// WebUILoginView private: -----------------------------------------------------

bool WebUILoginView::HandleContextMenu(const ContextMenuParams& params) {
  // Do not show the context menu.
#ifndef NDEBUG
  return false;
#else
  return true;
#endif
}

bool WebUILoginView::IsPopupOrPanel(const TabContents* source) const {
  return true;
}

bool WebUILoginView::TakeFocus(bool reverse) {
  if (status_area_ && status_area_->IsVisible()) {
    // Forward the focus to the status area.
    base::Callback<void(bool)> return_focus_cb =
        base::Bind(&WebUILoginView::ReturnFocus, base::Unretained(this));
    status_area_->TakeFocus(reverse, return_focus_cb);
    status_area_->GetWidget()->Activate();
  }
  return true;
}

void WebUILoginView::ReturnFocus(bool reverse) {
  // Return the focus to the web contents.
  webui_login_->dom_contents()->tab_contents()->
      FocusThroughTabTraversal(reverse);
  GetWidget()->Activate();
}

void WebUILoginView::HandleKeyboardEvent(const NativeWebKeyboardEvent& event) {
  unhandled_keyboard_event_handler_.HandleKeyboardEvent(event,
                                                        GetFocusManager());

  // Make sure error bubble is cleared on keyboard event. This is needed
  // when the focus is inside an iframe. Only clear on KeyDown to prevent hiding
  // an immediate authentication error (See crbug.com/103643).
  if (event.type == WebKit::WebInputEvent::KeyDown) {
    WebUI* web_ui = GetWebUI();
    if (web_ui)
      web_ui->CallJavascriptFunction("cr.ui.Oobe.clearErrors");
  }
}

}  // namespace chromeos
<commit_msg>Protect status_area_ access<commit_after>// Copyright (c) 2011 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/login/webui_login_view.h"

#include "base/bind.h"
#include "base/callback.h"
#include "base/i18n/rtl.h"
#include "base/utf_string_conversions.h"
#include "base/values.h"
#include "chrome/browser/chromeos/accessibility/accessibility_util.h"
#include "chrome/browser/chromeos/cros/cros_library.h"
#include "chrome/browser/chromeos/dbus/dbus_thread_manager.h"
#include "chrome/browser/chromeos/dbus/session_manager_client.h"
#include "chrome/browser/chromeos/login/proxy_settings_dialog.h"
#include "chrome/browser/chromeos/login/webui_login_display.h"
#include "chrome/browser/chromeos/status/status_area_view.h"
#include "chrome/browser/chromeos/status/status_area_view_chromeos.h"
#include "chrome/browser/profiles/profile_manager.h"
#include "chrome/browser/ui/views/dom_view.h"
#include "chrome/browser/ui/webui/chromeos/login/oobe_ui.h"
#include "chrome/common/render_messages.h"
#include "content/browser/tab_contents/tab_contents.h"
#include "content/public/browser/render_view_host_observer.h"
#include "ui/gfx/rect.h"
#include "ui/gfx/size.h"
#include "ui/views/widget/widget.h"

#if defined(TOOLKIT_USES_GTK)
#include "chrome/browser/chromeos/legacy_window_manager/wm_ipc.h"
#include "ui/views/widget/native_widget_gtk.h"
#endif

#if defined(USE_VIRTUAL_KEYBOARD)
#include "chrome/browser/ui/virtual_keyboard/virtual_keyboard_manager.h"
#endif

#if defined(USE_AURA)
#include "chrome/browser/ui/views/aura/chrome_shell_delegate.h"
#endif

namespace {

const char kViewClassName[] = "browser/chromeos/login/WebUILoginView";

// These strings must be kept in sync with handleAccelerator() in oobe.js.
const char kAccelNameAccessibility[] = "accessibility";
const char kAccelNameCancel[] = "cancel";
const char kAccelNameEnrollment[] = "enrollment";

// Observes IPC messages from the FrameSniffer and notifies JS if error
// appears.
class SnifferObserver : public content::RenderViewHostObserver {
 public:
  SnifferObserver(RenderViewHost* host, WebUI* webui)
      : content::RenderViewHostObserver(host), webui_(webui) {
    DCHECK(webui_);
    Send(new ChromeViewMsg_StartFrameSniffer(routing_id(),
                                             UTF8ToUTF16("gaia-frame")));
  }

  virtual ~SnifferObserver() {}

  // IPC::Channel::Listener implementation.
  virtual bool OnMessageReceived(const IPC::Message& message) {
    bool handled = true;
    IPC_BEGIN_MESSAGE_MAP(SnifferObserver, message)
      IPC_MESSAGE_HANDLER(ChromeViewHostMsg_FrameLoadingError, OnError)
      IPC_MESSAGE_UNHANDLED(handled = false)
    IPC_END_MESSAGE_MAP()
    return handled;
  }

 private:
  void OnError(int error) {
    base::FundamentalValue error_value(error);
    webui_->CallJavascriptFunction("login.ErrorMessageScreen.onFrameError",
                                   error_value);
  }

  WebUI* webui_;
};

// A View class which places its first child at the right most position.
class RightAlignedView : public views::View {
 public:
  virtual void Layout() OVERRIDE;
  virtual void ChildPreferredSizeChanged(View* child) OVERRIDE;
};

void RightAlignedView::Layout() {
  if (has_children()) {
    views::View* child = child_at(0);
    gfx::Size preferred_size = child->GetPreferredSize();
    child->SetBounds(width() - preferred_size.width(),
                     0, preferred_size.width(), preferred_size.height());
  }
}

void RightAlignedView::ChildPreferredSizeChanged(View* child) {
  Layout();
}

}  // namespace

namespace chromeos {

// static
const int WebUILoginView::kStatusAreaCornerPadding = 5;

// WebUILoginView public: ------------------------------------------------------

WebUILoginView::WebUILoginView()
    : status_area_(NULL),
      webui_login_(NULL),
      login_window_(NULL),
      status_window_(NULL),
      host_window_frozen_(false),
      status_area_visibility_on_init_(true) {
#if defined(USE_VIRTUAL_KEYBOARD)
  // Make sure the singleton VirtualKeyboardManager object is created.
  VirtualKeyboardManager::GetInstance();
#endif
  accel_map_[ui::Accelerator(ui::VKEY_Z, false, true, true)] =
      kAccelNameAccessibility;
  accel_map_[ui::Accelerator(ui::VKEY_ESCAPE, false, false, false)] =
      kAccelNameCancel;
  accel_map_[ui::Accelerator(ui::VKEY_E, false, true, true)] =
      kAccelNameEnrollment;

  for (AccelMap::iterator i(accel_map_.begin()); i != accel_map_.end(); ++i)
    AddAccelerator(i->first);
}

WebUILoginView::~WebUILoginView() {
  if (status_window_)
    status_window_->CloseNow();
  status_window_ = NULL;
}

void WebUILoginView::Init(views::Widget* login_window) {
  login_window_ = login_window;
  webui_login_ = new DOMView();
  AddChildView(webui_login_);
  webui_login_->Init(ProfileManager::GetDefaultProfile(), NULL);
  webui_login_->SetVisible(true);

  TabContents* tab_contents = webui_login_->dom_contents()->tab_contents();
  tab_contents->set_delegate(this);

  tab_watcher_.reset(new TabFirstRenderWatcher(tab_contents, this));
}

std::string WebUILoginView::GetClassName() const {
  return kViewClassName;
}

bool WebUILoginView::AcceleratorPressed(
    const ui::Accelerator& accelerator) {
  AccelMap::const_iterator entry = accel_map_.find(accelerator);
  if (entry == accel_map_.end())
    return false;

  if (!webui_login_)
    return true;

  WebUI* web_ui = GetWebUI();
  if (web_ui) {
    base::StringValue accel_name(entry->second);
    web_ui->CallJavascriptFunction("cr.ui.Oobe.handleAccelerator",
                                   accel_name);
  }

  return true;
}

gfx::NativeWindow WebUILoginView::GetNativeWindow() const {
  return GetWidget()->GetNativeWindow();
}

void WebUILoginView::OnWindowCreated() {
#if defined(TOOLKIT_USES_GTK)
  // Freezes host window update until the tab is rendered.
  host_window_frozen_ = static_cast<views::NativeWidgetGtk*>(
      GetWidget()->native_widget())->SuppressFreezeUpdates();
#else
  // TODO(saintlou): Unclear if we need this for the !gtk case.
  // According to nkostylev it prevents the renderer from flashing with a
  // white solid background until the content is fully rendered.
#endif
}

void WebUILoginView::UpdateWindowType() {
#if defined(TOOLKIT_USES_GTK)
  std::vector<int> params;
  WmIpc::instance()->SetWindowType(
      GTK_WIDGET(GetNativeWindow()),
      WM_IPC_WINDOW_LOGIN_WEBUI,
      &params);
#endif
}

void WebUILoginView::LoadURL(const GURL & url) {
  webui_login_->LoadURL(url);
  webui_login_->RequestFocus();
}

WebUI* WebUILoginView::GetWebUI() {
  return webui_login_->dom_contents()->tab_contents()->web_ui();
}

void WebUILoginView::SetStatusAreaEnabled(bool enable) {
  if (status_area_)
    status_area_->MakeButtonsActive(enable);
}

void WebUILoginView::SetStatusAreaVisible(bool visible) {
  if (status_area_)
    status_area_->SetVisible(visible);
  else
    status_area_visibility_on_init_ = visible;
}

// WebUILoginView protected: ---------------------------------------------------

void WebUILoginView::Layout() {
  DCHECK(webui_login_);
  webui_login_->SetBoundsRect(bounds());
}

void WebUILoginView::OnLocaleChanged() {
  // Proxy settings dialog contains localized strings.
  proxy_settings_dialog_.reset();
  SchedulePaint();
}

void WebUILoginView::ChildPreferredSizeChanged(View* child) {
  Layout();
  SchedulePaint();
}

// Overridden from StatusAreaButton::Delegate:

bool WebUILoginView::ShouldExecuteStatusAreaCommand(
    const views::View* button_view, int command_id) const {
  if (command_id == StatusAreaButton::Delegate::SHOW_NETWORK_OPTIONS)
    return true;
  return false;
}

void WebUILoginView::ExecuteStatusAreaCommand(
    const views::View* button_view, int command_id) {
  if (command_id == StatusAreaButton::Delegate::SHOW_NETWORK_OPTIONS) {
    if (proxy_settings_dialog_.get() == NULL) {
      proxy_settings_dialog_.reset(new ProxySettingsDialog(NULL,
                                                           GetNativeWindow()));
    }
    proxy_settings_dialog_->Show();
  }
}

gfx::Font WebUILoginView::GetStatusAreaFont(const gfx::Font& font) const {
  return font;
}

StatusAreaButton::TextStyle WebUILoginView::GetStatusAreaTextStyle() const {
  return StatusAreaButton::GRAY_PLAIN;
}

void WebUILoginView::ButtonVisibilityChanged(views::View* button_view) {
  if (status_area_)
    status_area_->UpdateButtonVisibility();
}

void WebUILoginView::OnRenderHostCreated(RenderViewHost* host) {
  new SnifferObserver(host, GetWebUI());
}

void WebUILoginView::OnTabMainFrameLoaded() {
  VLOG(1) << "WebUI login main frame loaded.";
}

void WebUILoginView::OnTabMainFrameFirstRender() {
  VLOG(1) << "WebUI login main frame rendered.";
  StatusAreaViewChromeos::SetScreenMode(
      StatusAreaViewChromeos::LOGIN_MODE_WEBUI);
  // In aura there's a global status area shown already.
#if defined(USE_AURA)
  status_area_ = ChromeShellDelegate::instance()->GetStatusArea();
  status_area_->SetVisible(status_area_visibility_on_init_);
#else
  InitStatusArea();
#endif

#if defined(TOOLKIT_USES_GTK)
  if (host_window_frozen_) {
    host_window_frozen_ = false;

    // Unfreezes the host window since tab is rendered now.
    views::NativeWidgetGtk::UpdateFreezeUpdatesProperty(
        GetNativeWindow(), false);
  }
#endif

  bool emit_login_visible = false;

  // In aura, there will be no window-manager. So chrome needs to emit the
  // 'login-prompt-visible' signal. This needs to happen here, after the page
  // has completed rendering itself.
#if defined(USE_AURA)
  emit_login_visible = true;
#endif
  if (emit_login_visible)
    chromeos::DBusThreadManager::Get()->GetSessionManagerClient()
        ->EmitLoginPromptVisible();

  OobeUI* oobe_ui = static_cast<OobeUI*>(GetWebUI());
  // Notify OOBE that the login frame has been rendered. Currently
  // this is used to start camera presence check.
  oobe_ui->OnLoginPromptVisible();
}

void WebUILoginView::InitStatusArea() {
  DCHECK(status_area_ == NULL);
  DCHECK(status_window_ == NULL);
  StatusAreaViewChromeos* status_area_chromeos = new StatusAreaViewChromeos();
  status_area_chromeos->Init(this);
  status_area_ = status_area_chromeos;
  status_area_->SetVisible(status_area_visibility_on_init_);

  // Width of |status_window| is meant to be large enough.
  // The current value of status_area_->GetPreferredSize().width()
  // will be too small when button status is changed.
  // (e.g. when CapsLock indicator appears)
  gfx::Size widget_size(width()/2,
                        status_area_->GetPreferredSize().height());
  const int widget_x = base::i18n::IsRTL() ?
      kStatusAreaCornerPadding :
      width() - widget_size.width() - kStatusAreaCornerPadding;
  gfx::Rect widget_bounds(widget_x, kStatusAreaCornerPadding,
                          widget_size.width(), widget_size.height());
  // TODO(nkostylev|oshima): Make status area in the same window as
  // |webui_login_| once RenderWidgetHostViewViews and compositor are
  // ready.
  views::Widget::InitParams widget_params(
      views::Widget::InitParams::TYPE_WINDOW_FRAMELESS);
  widget_params.bounds = widget_bounds;
  widget_params.transparent = true;
  widget_params.parent_widget = login_window_;
  status_window_ = new views::Widget;
  status_window_->Init(widget_params);

#if defined(TOOLKIT_USES_GTK)
  chromeos::WmIpc::instance()->SetWindowType(
      status_window_->GetNativeView(),
      chromeos::WM_IPC_WINDOW_CHROME_INFO_BUBBLE,
      NULL);
#endif

  views::View* contents_view = new RightAlignedView;
  contents_view->AddChildView(status_area_);
  status_window_->SetContentsView(contents_view);
  status_window_->Show();
}

// WebUILoginView private: -----------------------------------------------------

bool WebUILoginView::HandleContextMenu(const ContextMenuParams& params) {
  // Do not show the context menu.
#ifndef NDEBUG
  return false;
#else
  return true;
#endif
}

bool WebUILoginView::IsPopupOrPanel(const TabContents* source) const {
  return true;
}

bool WebUILoginView::TakeFocus(bool reverse) {
  if (status_area_ && status_area_->IsVisible()) {
    // Forward the focus to the status area.
    base::Callback<void(bool)> return_focus_cb =
        base::Bind(&WebUILoginView::ReturnFocus, base::Unretained(this));
    status_area_->TakeFocus(reverse, return_focus_cb);
    status_area_->GetWidget()->Activate();
  }
  return true;
}

void WebUILoginView::ReturnFocus(bool reverse) {
  // Return the focus to the web contents.
  webui_login_->dom_contents()->tab_contents()->
      FocusThroughTabTraversal(reverse);
  GetWidget()->Activate();
}

void WebUILoginView::HandleKeyboardEvent(const NativeWebKeyboardEvent& event) {
  unhandled_keyboard_event_handler_.HandleKeyboardEvent(event,
                                                        GetFocusManager());

  // Make sure error bubble is cleared on keyboard event. This is needed
  // when the focus is inside an iframe. Only clear on KeyDown to prevent hiding
  // an immediate authentication error (See crbug.com/103643).
  if (event.type == WebKit::WebInputEvent::KeyDown) {
    WebUI* web_ui = GetWebUI();
    if (web_ui)
      web_ui->CallJavascriptFunction("cr.ui.Oobe.clearErrors");
  }
}

}  // namespace chromeos
<|endoftext|>