<commit_before>// This file is part of OpenMVG, an Open Multiple View Geometry C++ library.

// Copyright (c) 2015 Pierre Moulon.

// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

#include "openMVG/sfm/sfm_data_triangulation.hpp"

#include <deque>
#include <functional>

#include "openMVG/geometry/pose3.hpp"
#include "openMVG/multiview/triangulation_nview.hpp"
#include "openMVG/robust_estimation/rand_sampling.hpp"
#include "openMVG/sfm/sfm_data.hpp"
#include "openMVG/sfm/sfm_landmark.hpp"

#include "third_party/progress/progress_display.hpp"

namespace openMVG {
namespace sfm {

using namespace openMVG::geometry;
using namespace openMVG::cameras;

SfM_Data_Structure_Computation_Basis::SfM_Data_Structure_Computation_Basis
(
  bool bConsoleVerbose
)
  :bConsole_verbose_(bConsoleVerbose)
{
}

SfM_Data_Structure_Computation_Blind::SfM_Data_Structure_Computation_Blind
(
  bool bConsoleVerbose
)
  :SfM_Data_Structure_Computation_Basis(bConsoleVerbose)
{
}

/// Triangulate a given set of observations
bool track_triangulation
(
  const SfM_Data & sfm_data,
  const Observations & obs,
  Vec3 & X
)
{
  if (obs.size() >= 2)
  {
    std::vector<Vec3> bearing;
    std::vector<Mat34> poses;
    bearing.reserve(obs.size());
    poses.reserve(obs.size());
    for (const auto& observation : obs)
    {
      const View * view = sfm_data.views.at(observation.first).get();
      if (!sfm_data.IsPoseAndIntrinsicDefined(view))
        continue;
      const IntrinsicBase * cam = sfm_data.GetIntrinsics().at(view->id_intrinsic).get();
      const Pose3 pose = sfm_data.GetPoseOrDie(view);
      bearing.emplace_back((*cam)(cam->get_ud_pixel(observation.second.x)));
      poses.emplace_back(pose.asMatrix());
    }
    if (bearing.size() >= 2)
    {
      const Eigen::Map<const Mat3X> bearing_matrix(bearing[0].data(), 3, bearing.size());
      Vec4 Xhomogeneous;
      if (TriangulateNViewAlgebraic
      (
        bearing_matrix,
        poses,
        &Xhomogeneous))
      {
        X = Xhomogeneous.hnormalized();
        return true;
      }
    }
  }
  return false;
}

// Test if a predicate is true for each observation
// i.e: predicate could be:
// - cheirality test (depth test): cheirality_predicate
// - cheirality and residual error: ResidualAndCheiralityPredicate::predicate
bool track_check_predicate
(
  const Observations & obs,
  const SfM_Data & sfm_data,
  const Vec3 & X,
  std::function<bool(
    const IntrinsicBase&,
    const Pose3&,
    const Vec2&,
    const Vec3&)> predicate
)
{
  bool visibility = false; // assume that no observation has been looked yet
  for (const auto & obs_it : obs)
  {
    const View * view = sfm_data.views.at(obs_it.first).get();
    if (!sfm_data.IsPoseAndIntrinsicDefined(view))
      continue;
    visibility = true; // at least an observation is evaluated
    const IntrinsicBase * cam = sfm_data.intrinsics.at(view->id_intrinsic).get();
    const Pose3 pose = sfm_data.GetPoseOrDie(view);
    if (!predicate(*cam, pose, obs_it.second.x, X))
      return false;
  }
  return visibility;
}

bool cheirality_predicate
(
  const IntrinsicBase& cam,
  const Pose3& pose,
  const Vec2& x,
  const Vec3& X
)
{
  return CheiralityTest(cam(x), pose, X);
}

struct ResidualAndCheiralityPredicate
{
  const double squared_pixel_threshold_;

  ResidualAndCheiralityPredicate(const double squared_pixel_threshold)
    :squared_pixel_threshold_(squared_pixel_threshold){}

  bool predicate
  (
    const IntrinsicBase& cam,
    const Pose3& pose,
    const Vec2& x,
    const Vec3& X
  )
  {
    const Vec2 residual = cam.residual(pose(X), x);
    return CheiralityTest(cam(x), pose, X) &&
           residual.squaredNorm() < squared_pixel_threshold_;
  }
};

void SfM_Data_Structure_Computation_Blind::triangulate
(
  SfM_Data & sfm_data
)
const
{
  std::deque<IndexT> rejectedId;
  std::unique_ptr<C_Progress> my_progress_bar;
  if (bConsole_verbose_)
    my_progress_bar.reset(
      new C_Progress_display(
        sfm_data.structure.size(),
        std::cout,
        "Blind triangulation progress:\n" ));
#ifdef OPENMVG_USE_OPENMP
  #pragma omp parallel
#endif
  for (auto& tracks_it :sfm_data.structure)
  {
#ifdef OPENMVG_USE_OPENMP
  #pragma omp single nowait
#endif
    {
      if (bConsole_verbose_)
      {
        ++(*my_progress_bar);
      }

      const Observations & obs = tracks_it.second.obs;
      bool bKeep = false;
      {
        // Generate the track 3D hypothesis
        Vec3 X;
        if (track_triangulation(sfm_data, obs, X))
        {
          // Keep the point only if it has a positive depth for all obs
          if (track_check_predicate(obs, sfm_data, X, cheirality_predicate))
          {
            tracks_it.second.X = X;
            bKeep = true;
          }
        }
      }
      if (!bKeep)
      {
#ifdef OPENMVG_USE_OPENMP
        #pragma omp critical
#endif
        rejectedId.push_front(tracks_it.first);
      }
    }
  }
  // Erase the unsuccessful triangulated tracks
  for (auto& it : rejectedId)
  {
    sfm_data.structure.erase(it);
  }
}

SfM_Data_Structure_Computation_Robust::SfM_Data_Structure_Computation_Robust
(
  const double max_reprojection_error,
  const IndexT min_required_inliers,
  const IndexT min_sample_index,
  bool bConsoleVerbose
):
  SfM_Data_Structure_Computation_Basis(bConsoleVerbose),
  max_reprojection_error_(max_reprojection_error),
  min_required_inliers_(min_required_inliers),
  min_sample_index_(min_sample_index)
{
}

void SfM_Data_Structure_Computation_Robust::triangulate
(
  SfM_Data & sfm_data
)
const
{
  robust_triangulation(sfm_data);
}

/// Robust triangulation of track data contained in the structure
/// All observations must have View with valid Intrinsic and Pose data
/// Invalid landmark are removed.
void SfM_Data_Structure_Computation_Robust::robust_triangulation
(
  SfM_Data & sfm_data
)
const
{
  std::deque<IndexT> rejectedId;
  std::unique_ptr<C_Progress_display> my_progress_bar;
  if (bConsole_verbose_)
    my_progress_bar.reset(
      new C_Progress_display(
        sfm_data.structure.size(),
        std::cout,
        "Robust triangulation progress:\n" ));
#ifdef OPENMVG_USE_OPENMP
  #pragma omp parallel
#endif
  for (auto& tracks_it :sfm_data.structure)
  {
#ifdef OPENMVG_USE_OPENMP
  #pragma omp single nowait
#endif
    {
      if (bConsole_verbose_)
      {
        ++(*my_progress_bar);
      }
      Landmark landmark;
      if (robust_triangulation(sfm_data, tracks_it.second.obs, landmark))
      {
        tracks_it.second = landmark;
      }
      else
      {
        // Track must be deleted
#ifdef OPENMVG_USE_OPENMP
        #pragma omp critical
#endif
        rejectedId.push_front(tracks_it.first);
      }
    }
  }
  // Erase the unsuccessful triangulated tracks
  for (auto& it : rejectedId)
  {
    sfm_data.structure.erase(it);
  }
}

Observations ObservationsSampler
(
  const Observations & obs,
  const std::vector<std::uint32_t> & samples
)
{
  Observations sampled_obs;
  for (const auto& idx : samples)
  {
    Observations::const_iterator obs_it = obs.cbegin();
    std::advance(obs_it, idx);
    sampled_obs.insert(*obs_it);
  }
  return sampled_obs;
}

/// Robustly try to estimate the best 3D point using a ransac scheme
/// A point must be seen in at least min_required_inliers views
/// Return true for a successful triangulation
bool SfM_Data_Structure_Computation_Robust::robust_triangulation
(
  const SfM_Data & sfm_data,
  const Observations & obs,
  Landmark & landmark // X & valid observations
)
const
{
  if (obs.size() < min_required_inliers_ || obs.size() < min_sample_index_)
  {
    return false;
  }

  const double dSquared_pixel_threshold = Square(max_reprojection_error_);

  // Predicate to validate a sample (cheirality and residual error)
  ResidualAndCheiralityPredicate predicate(dSquared_pixel_threshold);
  auto predicate_binding = std::bind(&ResidualAndCheiralityPredicate::predicate,
                                     predicate,
                                     std::placeholders::_1,
                                     std::placeholders::_2,
                                     std::placeholders::_3,
                                     std::placeholders::_4);

  // Handle the case where all observations must be used
  if (min_required_inliers_ == min_sample_index_ &&
      obs.size() == min_required_inliers_)
  {
    // Generate the 3D point hypothesis by triangulating all the observations
    Vec3 X;
    if (track_triangulation(sfm_data, obs, X) &&
        track_check_predicate(obs, sfm_data, X, predicate_binding))
    {
      landmark.X = X;
      landmark.obs = obs;
      return true;
    }
    return false;
  }

  // else we perform a robust estimation since
  //  there is more observations than the minimal number of required sample.

  const IndexT nbIter = obs.size(); // TODO: automatic computation of the number of iterations?

  // - Ransac variables
  Vec3 best_model = Vec3::Zero();
  std::deque<IndexT> best_inlier_set;
  double best_error = std::numeric_limits<double>::max();

  //--
  // Random number generation
  std::mt19937 random_generator(std::mt19937::default_seed);

  // - Ransac loop
  for (IndexT i = 0; i < nbIter; ++i)
  {
    std::vector<uint32_t> samples;
    robust::UniformSample(min_sample_index_, obs.size(), random_generator, &samples);

    // Hypothesis generation
    Vec3 X;
    if (!track_triangulation(sfm_data, ObservationsSampler(obs, samples), X))
      continue;

    // Test validity of the hypothesis
    if (!track_check_predicate(obs, sfm_data, X, predicate_binding))
      continue;

    std::deque<IndexT> inlier_set;
    double current_error = 0.0;
    // inlier/outlier classification according pixel residual errors.
    for (const auto & obs_it : obs)
    {
      const View * view = sfm_data.views.at(obs_it.first).get();
      if (!sfm_data.IsPoseAndIntrinsicDefined(view))
        continue;
      const IntrinsicBase & cam =  *sfm_data.GetIntrinsics().at(view->id_intrinsic).get();
      const Pose3 pose = sfm_data.GetPoseOrDie(view);
      if (!CheiralityTest(cam(obs_it.second.x), pose, X))
        continue;
      const double residual_sq = cam.residual(pose(X), obs_it.second.x).squaredNorm();
      if (residual_sq < dSquared_pixel_threshold)
      {
        inlier_set.push_front(obs_it.first);
        current_error += residual_sq;
      }
      else
      {
        current_error += dSquared_pixel_threshold;
      }
    }
    // Does the hypothesis:
    // - is the best one we have seen so far.
    // - has sufficient inliers.
    if (current_error < best_error &&
      inlier_set.size() >= min_required_inliers_)
    {
      best_model = X;
      best_inlier_set = inlier_set;
      best_error = current_error;
    }
  }
  if (!best_inlier_set.empty() && best_inlier_set.size() >= min_required_inliers_)
  {
    // Update information (3D landmark position & valid observations)
    landmark.X = best_model;
    for (const IndexT & val : best_inlier_set)
    {
      landmark.obs[val] = obs.at(val);
    }
  }
  return !best_inlier_set.empty();
}

} // namespace sfm
} // namespace openMVG
<commit_msg>[SfM/triangulation] Predicate was checked against the whole track and not the hypothesis #1520<commit_after>// This file is part of OpenMVG, an Open Multiple View Geometry C++ library.

// Copyright (c) 2015 Pierre Moulon.

// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

#include "openMVG/sfm/sfm_data_triangulation.hpp"

#include <deque>
#include <functional>

#include "openMVG/geometry/pose3.hpp"
#include "openMVG/multiview/triangulation_nview.hpp"
#include "openMVG/robust_estimation/rand_sampling.hpp"
#include "openMVG/sfm/sfm_data.hpp"
#include "openMVG/sfm/sfm_landmark.hpp"

#include "third_party/progress/progress_display.hpp"

namespace openMVG {
namespace sfm {

using namespace openMVG::geometry;
using namespace openMVG::cameras;

SfM_Data_Structure_Computation_Basis::SfM_Data_Structure_Computation_Basis
(
  bool bConsoleVerbose
)
  :bConsole_verbose_(bConsoleVerbose)
{
}

SfM_Data_Structure_Computation_Blind::SfM_Data_Structure_Computation_Blind
(
  bool bConsoleVerbose
)
  :SfM_Data_Structure_Computation_Basis(bConsoleVerbose)
{
}

/// Triangulate a given set of observations
bool track_triangulation
(
  const SfM_Data & sfm_data,
  const Observations & obs,
  Vec3 & X
)
{
  if (obs.size() >= 2)
  {
    std::vector<Vec3> bearing;
    std::vector<Mat34> poses;
    bearing.reserve(obs.size());
    poses.reserve(obs.size());
    for (const auto& observation : obs)
    {
      const View * view = sfm_data.views.at(observation.first).get();
      if (!sfm_data.IsPoseAndIntrinsicDefined(view))
        continue;
      const IntrinsicBase * cam = sfm_data.GetIntrinsics().at(view->id_intrinsic).get();
      const Pose3 pose = sfm_data.GetPoseOrDie(view);
      bearing.emplace_back((*cam)(cam->get_ud_pixel(observation.second.x)));
      poses.emplace_back(pose.asMatrix());
    }
    if (bearing.size() >= 2)
    {
      const Eigen::Map<const Mat3X> bearing_matrix(bearing[0].data(), 3, bearing.size());
      Vec4 Xhomogeneous;
      if (TriangulateNViewAlgebraic
      (
        bearing_matrix,
        poses,
        &Xhomogeneous))
      {
        X = Xhomogeneous.hnormalized();
        return true;
      }
    }
  }
  return false;
}

// Test if a predicate is true for each observation
// i.e: predicate could be:
// - cheirality test (depth test): cheirality_predicate
// - cheirality and residual error: ResidualAndCheiralityPredicate::predicate
bool track_check_predicate
(
  const Observations & obs,
  const SfM_Data & sfm_data,
  const Vec3 & X,
  std::function<bool(
    const IntrinsicBase&,
    const Pose3&,
    const Vec2&,
    const Vec3&)> predicate
)
{
  bool visibility = false; // assume that no observation has been looked yet
  for (const auto & obs_it : obs)
  {
    const View * view = sfm_data.views.at(obs_it.first).get();
    if (!sfm_data.IsPoseAndIntrinsicDefined(view))
      continue;
    visibility = true; // at least an observation is evaluated
    const IntrinsicBase * cam = sfm_data.intrinsics.at(view->id_intrinsic).get();
    const Pose3 pose = sfm_data.GetPoseOrDie(view);
    if (!predicate(*cam, pose, obs_it.second.x, X))
      return false;
  }
  return visibility;
}

bool cheirality_predicate
(
  const IntrinsicBase& cam,
  const Pose3& pose,
  const Vec2& x,
  const Vec3& X
)
{
  return CheiralityTest(cam(x), pose, X);
}

struct ResidualAndCheiralityPredicate
{
  const double squared_pixel_threshold_;

  ResidualAndCheiralityPredicate(const double squared_pixel_threshold)
    :squared_pixel_threshold_(squared_pixel_threshold){}

  bool predicate
  (
    const IntrinsicBase& cam,
    const Pose3& pose,
    const Vec2& x,
    const Vec3& X
  )
  {
    const Vec2 residual = cam.residual(pose(X), x);
    return CheiralityTest(cam(x), pose, X) &&
           residual.squaredNorm() < squared_pixel_threshold_;
  }
};

void SfM_Data_Structure_Computation_Blind::triangulate
(
  SfM_Data & sfm_data
)
const
{
  std::deque<IndexT> rejectedId;
  std::unique_ptr<C_Progress> my_progress_bar;
  if (bConsole_verbose_)
    my_progress_bar.reset(
      new C_Progress_display(
        sfm_data.structure.size(),
        std::cout,
        "Blind triangulation progress:\n" ));
#ifdef OPENMVG_USE_OPENMP
  #pragma omp parallel
#endif
  for (auto& tracks_it :sfm_data.structure)
  {
#ifdef OPENMVG_USE_OPENMP
  #pragma omp single nowait
#endif
    {
      if (bConsole_verbose_)
      {
        ++(*my_progress_bar);
      }

      const Observations & obs = tracks_it.second.obs;
      bool bKeep = false;
      {
        // Generate the track 3D hypothesis
        Vec3 X;
        if (track_triangulation(sfm_data, obs, X))
        {
          // Keep the point only if it has a positive depth for all obs
          if (track_check_predicate(obs, sfm_data, X, cheirality_predicate))
          {
            tracks_it.second.X = X;
            bKeep = true;
          }
        }
      }
      if (!bKeep)
      {
#ifdef OPENMVG_USE_OPENMP
        #pragma omp critical
#endif
        rejectedId.push_front(tracks_it.first);
      }
    }
  }
  // Erase the unsuccessful triangulated tracks
  for (auto& it : rejectedId)
  {
    sfm_data.structure.erase(it);
  }
}

SfM_Data_Structure_Computation_Robust::SfM_Data_Structure_Computation_Robust
(
  const double max_reprojection_error,
  const IndexT min_required_inliers,
  const IndexT min_sample_index,
  bool bConsoleVerbose
):
  SfM_Data_Structure_Computation_Basis(bConsoleVerbose),
  max_reprojection_error_(max_reprojection_error),
  min_required_inliers_(min_required_inliers),
  min_sample_index_(min_sample_index)
{
}

void SfM_Data_Structure_Computation_Robust::triangulate
(
  SfM_Data & sfm_data
)
const
{
  robust_triangulation(sfm_data);
}

/// Robust triangulation of track data contained in the structure
/// All observations must have View with valid Intrinsic and Pose data
/// Invalid landmark are removed.
void SfM_Data_Structure_Computation_Robust::robust_triangulation
(
  SfM_Data & sfm_data
)
const
{
  std::deque<IndexT> rejectedId;
  std::unique_ptr<C_Progress_display> my_progress_bar;
  if (bConsole_verbose_)
    my_progress_bar.reset(
      new C_Progress_display(
        sfm_data.structure.size(),
        std::cout,
        "Robust triangulation progress:\n" ));
#ifdef OPENMVG_USE_OPENMP
  #pragma omp parallel
#endif
  for (auto& tracks_it :sfm_data.structure)
  {
#ifdef OPENMVG_USE_OPENMP
  #pragma omp single nowait
#endif
    {
      if (bConsole_verbose_)
      {
        ++(*my_progress_bar);
      }
      Landmark landmark;
      if (robust_triangulation(sfm_data, tracks_it.second.obs, landmark))
      {
        tracks_it.second = landmark;
      }
      else
      {
        // Track must be deleted
#ifdef OPENMVG_USE_OPENMP
        #pragma omp critical
#endif
        rejectedId.push_front(tracks_it.first);
      }
    }
  }
  // Erase the unsuccessful triangulated tracks
  for (auto& it : rejectedId)
  {
    sfm_data.structure.erase(it);
  }
}

Observations ObservationsSampler
(
  const Observations & obs,
  const std::vector<std::uint32_t> & samples
)
{
  Observations sampled_obs;
  for (const auto& idx : samples)
  {
    Observations::const_iterator obs_it = obs.cbegin();
    std::advance(obs_it, idx);
    sampled_obs.insert(*obs_it);
  }
  return sampled_obs;
}

/// Robustly try to estimate the best 3D point using a ransac scheme
/// A point must be seen in at least min_required_inliers views
/// Return true for a successful triangulation
bool SfM_Data_Structure_Computation_Robust::robust_triangulation
(
  const SfM_Data & sfm_data,
  const Observations & obs,
  Landmark & landmark // X & valid observations
)
const
{
  if (obs.size() < min_required_inliers_ || obs.size() < min_sample_index_)
  {
    return false;
  }

  const double dSquared_pixel_threshold = Square(max_reprojection_error_);

  // Predicate to validate a sample (cheirality and residual error)
  ResidualAndCheiralityPredicate predicate(dSquared_pixel_threshold);
  auto predicate_binding = std::bind(&ResidualAndCheiralityPredicate::predicate,
                                     predicate,
                                     std::placeholders::_1,
                                     std::placeholders::_2,
                                     std::placeholders::_3,
                                     std::placeholders::_4);

  // Handle the case where all observations must be used
  if (min_required_inliers_ == min_sample_index_ &&
      obs.size() == min_required_inliers_)
  {
    // Generate the 3D point hypothesis by triangulating all the observations
    Vec3 X;
    if (track_triangulation(sfm_data, obs, X) &&
        track_check_predicate(obs, sfm_data, X, predicate_binding))
    {
      landmark.X = X;
      landmark.obs = obs;
      return true;
    }
    return false;
  }

  // else we perform a robust estimation since
  //  there is more observations than the minimal number of required sample.

  const IndexT nbIter = obs.size(); // TODO: automatic computation of the number of iterations?

  // - Ransac variables
  Vec3 best_model = Vec3::Zero();
  std::deque<IndexT> best_inlier_set;
  double best_error = std::numeric_limits<double>::max();

  //--
  // Random number generation
  std::mt19937 random_generator(std::mt19937::default_seed);

  // - Ransac loop
  for (IndexT i = 0; i < nbIter; ++i)
  {
    std::vector<uint32_t> samples;
    robust::UniformSample(min_sample_index_, obs.size(), random_generator, &samples);

    Vec3 X;
    // Hypothesis generation
    const auto minimal_sample = ObservationsSampler(obs, samples);

    if (!track_triangulation(sfm_data, minimal_sample, X))
      continue;

    // Test validity of the hypothesis
    if (!track_check_predicate(minimal_sample, sfm_data, X, predicate_binding))
      continue;

    std::deque<IndexT> inlier_set;
    double current_error = 0.0;
    // inlier/outlier classification according pixel residual errors.
    for (const auto & obs_it : obs)
    {
      const View * view = sfm_data.views.at(obs_it.first).get();
      if (!sfm_data.IsPoseAndIntrinsicDefined(view))
        continue;
      const IntrinsicBase & cam =  *sfm_data.GetIntrinsics().at(view->id_intrinsic).get();
      const Pose3 pose = sfm_data.GetPoseOrDie(view);
      if (!CheiralityTest(cam(obs_it.second.x), pose, X))
        continue;
      const double residual_sq = cam.residual(pose(X), obs_it.second.x).squaredNorm();
      if (residual_sq < dSquared_pixel_threshold)
      {
        inlier_set.push_front(obs_it.first);
        current_error += residual_sq;
      }
      else
      {
        current_error += dSquared_pixel_threshold;
      }
    }
    // Does the hypothesis:
    // - is the best one we have seen so far.
    // - has sufficient inliers.
    if (current_error < best_error &&
      inlier_set.size() >= min_required_inliers_)
    {
      best_model = X;
      best_inlier_set = inlier_set;
      best_error = current_error;
    }
  }
  if (!best_inlier_set.empty() && best_inlier_set.size() >= min_required_inliers_)
  {
    // Update information (3D landmark position & valid observations)
    landmark.X = best_model;
    for (const IndexT & val : best_inlier_set)
    {
      landmark.obs[val] = obs.at(val);
    }
  }
  return !best_inlier_set.empty();
}

} // namespace sfm
} // namespace openMVG
<|endoftext|>


<commit_before>/**
@file debug.hpp
@brief Debug utilities.

@author Tim Howard
@copyright 2010-2013 Tim Howard under the MIT license;
see @ref index or the accompanying LICENSE file for full text.
*/

#ifndef DUCT_DEBUG_HPP_
#define DUCT_DEBUG_HPP_

#include "./config.hpp"

#include <cstdlib>
#include <cstdarg>
#include <cassert>
#include <cstdio>

namespace duct {

/**
	@addtogroup debug
	@{
*/

#ifdef DOXYGEN_CONSISTS_SOLELY_OF_UNICORNS_AND_CONFETTI
	/**
		@ingroup config
		When defined, force all #DUCT_DEBUG and #DUCT_DEBUG_ASSERT
		macros to be defined (regardless of @c NDEBUG presence).
	*/
	#define DUCT_CONFIG_FORCE_DEBUG_MACROS
#endif

/**
	@name Non-debug assertion
	@note These macros mimic @c assert(), and will @c std::abort()
	the program if @a expr evaluates to @c false.
	@note These macros are always defined.
	@sa DUCT_DEBUG_ASSERT(),
		DUCT_DEBUG_ASSERTE(),
		DUCT_DEBUG_ASSERTF(),
		DUCT_DEBUG_ASSERTP(),
		DUCT_DEBUG_ASSERTPF()
*/ /// @{
/**
	Assertion with message.
	@param expr Expression to evaluate.
	@param mesg Message.
*/
#define DUCT_ASSERT(expr, mesg) ( \
	(expr) ? void(0) : ( \
		std::fprintf( \
			stderr, "assertion failure: " mesg \
			"\n in %s:%d: %s: Assertion: `" #expr "`\n", \
			__FILE__, __LINE__, DUCT_FUNC_SIG \
		), \
		std::abort() \
	) \
)

/**
	Assertion with expression.
	@param expr Expression to evaluate.
*/
#define DUCT_ASSERTE(expr) ( \
	(expr) ? void(0) : ( \
		std::fprintf( \
			stderr, \
			"\n in %s:%d: %s: Assertion: `" #expr "`\n", \
			__FILE__, __LINE__, DUCT_FUNC_SIG \
		), \
		std::abort() \
	) \
)

/**
	Assertion with formatted message.
	@param expr Expression to evaluate.
	@param format Format string.
	@param ... Format arguments.
*/
#define DUCT_ASSERTF(expr, format, ...) ( \
	(expr) ? void(0) : ( \
		std::fprintf( \
			stderr, "assertion failure: " format \
			"\n in %s:%d: %s: Assertion: `" #expr "`\n", \
			__VA_ARGS__, __FILE__, __LINE__, DUCT_FUNC_SIG \
		), \
		std::abort() \
	) \
)

/**
	Assertion with pointer and message.
	@param expr Expression to evaluate.
	@param p Pointer.
	@param mesg Message.
*/
#define DUCT_ASSERTP(expr, p, mesg) \
	DUCT_ASSERTF(expr, "[%p] " mesg, (void const* const)p)

/**
	Assertion with pointer and formatted message.
	@param expr Expression to evaluate.
	@param p Pointer.
	@param format Format string.
	@param ... Format arguments.
*/
#define DUCT_ASSERTPF(expr, p, format, ...) \
	DUCT_ASSERTF(expr, "[%p] " format, (void const* const)p, __VA_ARGS__)
/// @}

#if (defined(NDEBUG) && !defined(DUCT_CONFIG_FORCE_DEBUG_MACROS)) \
	|| defined(DOXYGEN_CONSISTS_SOLELY_OF_UNICORNS_AND_CONFETTI)
/** @name Message */ /// @{
	/**
		Print debug message.
		@param mesg Debug message.
	*/
	#define DUCT_DEBUG(mesg)
	/**
		Print formatted debug message.
		@param format Format string.
		@param ... Format arguments.
	*/
	#define DUCT_DEBUGF(format, ...)
	/**
		Print debug message with no newline.
		@param mesg Debug message.
	*/
	#define DUCT_DEBUGN(mesg)
	/**
		Print formatted debug message with no newline.
		@param format Format string.
		@param ... Format arguments.
	*/
	#define DUCT_DEBUGNF(format, ...)
/// @}

/** @name Message with function signature */ /// @{
	/**
		Print debug message with function signature.
		@param mesg Debug message.
	*/
	#define DUCT_DEBUGC(mesg)
	/**
		Print formatted debug message with function signature.
		@param format Format string.
		@param ... Format arguments.
	*/
	#define DUCT_DEBUGCF(format, ...)
	/**
		Print debug message with no newline and function signature.
		@param mesg Debug message.
	*/
	#define DUCT_DEBUGNC(mesg)
	/**
		Print formatted debug message with no newline and function signature.
		@param format Format string.
		@param ... Format arguments.
	*/
	#define DUCT_DEBUGNCF(format, ...)
/// @}

/** @name Message with function signature and pointer */ /// @{
	/**
		Print debug message with function signature and pointer.
		@param mesg Debug message.
		@param p Pointer.
	*/
	#define DUCT_DEBUGCP(p, mesg)
	/**
		Print formatted debug message with function signature and pointer.
		@param p Pointer.
		@param format Format string.
		@param ... Format arguments.
	*/
	#define DUCT_DEBUGCPF(p, format, ...)
	/**
		Print debug message with no newline, function signature, and pointer.
		@param p Pointer.
		@param mesg Debug message.
	*/
	#define DUCT_DEBUGNCP(p, mesg)
	/**
		Print formatted debug message with no newline, function signature,
		and pointer.
		@param p Pointer.
		@param format Format string.
		@param ... Format arguments.
	*/
	#define DUCT_DEBUGNCPF(p, format, ...)
/// @}

/** @name Print function signature */ /// @{
	/**
		Print function signature.
	*/
	#define DUCT_DEBUG_CALLED()
	/**
		Print function signature with pointer.
		@param p Pointer.
	*/
	#define DUCT_DEBUG_CALLEDP(p)
/// @}

/**
	@name Debug assertion
	@note These route to the non-debug assertion macros.
	@sa DUCT_ASSERT(),
		DUCT_ASSERTE(),
		DUCT_ASSERTF(),
		DUCT_ASSERTP(),
		DUCT_ASSERTPF()
*/ /// @{
	/** @copydoc DUCT_ASSERT() */
	#define DUCT_DEBUG_ASSERT(expr, mesg)
	/** @copydoc DUCT_ASSERTE() */
	#define DUCT_DEBUG_ASSERTE(expr)
	/** @copydoc DUCT_ASSERTF() */
	#define DUCT_DEBUG_ASSERTF(expr, format, ...)
	/** @copydoc DUCT_ASSERTP() */
	#define DUCT_DEBUG_ASSERTP(expr, p, mesg)
	/** @copydoc DUCT_ASSERTPF() */
	#define DUCT_DEBUG_ASSERTPF(expr, p, format, ...)
/// @}

#else
	#define DUCT_DEBUG_PREFIX__ "debug: "

	// Debug
	#define DUCT_DEBUG(mesg) \
		std::printf(DUCT_DEBUG_PREFIX__ mesg "\n")

	#define DUCT_DEBUGF(format, ...) \
		std::printf(DUCT_DEBUG_PREFIX__ format "\n", __VA_ARGS__)

	// - no newline
	#define DUCT_DEBUGN(mesg) \
		std::printf(DUCT_DEBUG_PREFIX__ mesg)

	#define DUCT_DEBUGNF(format, ...) \
		std::printf(DUCT_DEBUG_PREFIX__ format, __VA_ARGS__)

	// - signature
	#define DUCT_DEBUGC(mesg) \
		DUCT_DEBUGF("in %s: " mesg, DUCT_FUNC_SIG)

	#define DUCT_DEBUGCF(format, ...) \
		DUCT_DEBUGF("in %s: " format, DUCT_FUNC_SIG, __VA_ARGS__)

	// - signature and no newline
	#define DUCT_DEBUGNC(mesg) \
		DUCT_DEBUGNF("in %s: " mesg, DUCT_FUNC_SIG)

	#define DUCT_DEBUGNCF(format, ...) \
		DUCT_DEBUGNF("in %s: " format, DUCT_FUNC_SIG, __VA_ARGS__)

	// - signature and pointer
	#define DUCT_DEBUGCP(p, mesg) \
		DUCT_DEBUGF("[%p] in %s: " mesg, (void const* const)p, DUCT_FUNC_SIG)

	#define DUCT_DEBUGCPF(p, format, ...) \
		DUCT_DEBUGF("[%p] in %s: " format, \
			(void const* const)p, DUCT_FUNC_SIG, __VA_ARGS__)

	// - signature and pointer and no newline
	#define DUCT_DEBUGNCP(p, mesg) \
		DUCT_DEBUGNF("[%p] in %s: " mesg, (void const* const)p, DUCT_FUNC_SIG)

	#define DUCT_DEBUGNCPF(p, format, ...) \
		DUCT_DEBUGNF("[%p] in %s: " format, \
			(void const* const)p, DUCT_FUNC_SIG, __VA_ARGS__)

	// Call
	#define DUCT_DEBUG_CALLED() \
		DUCT_DEBUGF("called: %s", DUCT_FUNC_SIG)

	#define DUCT_DEBUG_CALLEDP(p) \
		DUCT_DEBUGF("called: [%p] %s", (void const* const)p, DUCT_FUNC_SIG)

	// Assert
	#define DUCT_DEBUG_ASSERT(expr, mesg) \
		DUCT_ASSERT(expr, mesg)

	// Assert
	#define DUCT_DEBUG_ASSERTE(expr) \
		DUCT_ASSERTE(expr)

	#define DUCT_DEBUG_ASSERTF(expr, format, ...) \
		DUCT_ASSERTF(expr, format, __VA_ARGS__)

	// - pointer
	#define DUCT_DEBUG_ASSERTP(expr, p, mesg) \
		DUCT_ASSERTP(expr, p, mesg)

	#define DUCT_DEBUG_ASSERTPF(expr, p, format, ...) \
		DUCT_ASSERTPF(expr, p, format, __VA_ARGS__)

#endif

/** @} */ // end doc-group debug

} // namespace duct

#endif // DUCT_DEBUG_HPP_
<commit_msg>debug: corrected DUCT_ASSERTE() message prefix.<commit_after>/**
@file debug.hpp
@brief Debug utilities.

@author Tim Howard
@copyright 2010-2013 Tim Howard under the MIT license;
see @ref index or the accompanying LICENSE file for full text.
*/

#ifndef DUCT_DEBUG_HPP_
#define DUCT_DEBUG_HPP_

#include "./config.hpp"

#include <cstdlib>
#include <cstdarg>
#include <cassert>
#include <cstdio>

namespace duct {

/**
	@addtogroup debug
	@{
*/

#ifdef DOXYGEN_CONSISTS_SOLELY_OF_UNICORNS_AND_CONFETTI
	/**
		@ingroup config
		When defined, force all #DUCT_DEBUG and #DUCT_DEBUG_ASSERT
		macros to be defined (regardless of @c NDEBUG presence).
	*/
	#define DUCT_CONFIG_FORCE_DEBUG_MACROS
#endif

/**
	@name Non-debug assertion
	@note These macros mimic @c assert(), and will @c std::abort()
	the program if @a expr evaluates to @c false.
	@note These macros are always defined.
	@sa DUCT_DEBUG_ASSERT(),
		DUCT_DEBUG_ASSERTE(),
		DUCT_DEBUG_ASSERTF(),
		DUCT_DEBUG_ASSERTP(),
		DUCT_DEBUG_ASSERTPF()
*/ /// @{
/**
	Assertion with message.
	@param expr Expression to evaluate.
	@param mesg Message.
*/
#define DUCT_ASSERT(expr, mesg) ( \
	(expr) ? void(0) : ( \
		std::fprintf( \
			stderr, "assertion failure: " mesg \
			"\n in %s:%d: %s: Assertion: `" #expr "`\n", \
			__FILE__, __LINE__, DUCT_FUNC_SIG \
		), \
		std::abort() \
	) \
)

/**
	Assertion with expression.
	@param expr Expression to evaluate.
*/
#define DUCT_ASSERTE(expr) ( \
	(expr) ? void(0) : ( \
		std::fprintf( \
			stderr, "assertion failure "\
			"in %s:%d: %s: `" #expr "`\n", \
			__FILE__, __LINE__, DUCT_FUNC_SIG \
		), \
		std::abort() \
	) \
)

/**
	Assertion with formatted message.
	@param expr Expression to evaluate.
	@param format Format string.
	@param ... Format arguments.
*/
#define DUCT_ASSERTF(expr, format, ...) ( \
	(expr) ? void(0) : ( \
		std::fprintf( \
			stderr, "assertion failure: " format \
			"\n in %s:%d: %s: Assertion: `" #expr "`\n", \
			__VA_ARGS__, __FILE__, __LINE__, DUCT_FUNC_SIG \
		), \
		std::abort() \
	) \
)

/**
	Assertion with pointer and message.
	@param expr Expression to evaluate.
	@param p Pointer.
	@param mesg Message.
*/
#define DUCT_ASSERTP(expr, p, mesg) \
	DUCT_ASSERTF(expr, "[%p] " mesg, (void const* const)p)

/**
	Assertion with pointer and formatted message.
	@param expr Expression to evaluate.
	@param p Pointer.
	@param format Format string.
	@param ... Format arguments.
*/
#define DUCT_ASSERTPF(expr, p, format, ...) \
	DUCT_ASSERTF(expr, "[%p] " format, (void const* const)p, __VA_ARGS__)
/// @}

#if (defined(NDEBUG) && !defined(DUCT_CONFIG_FORCE_DEBUG_MACROS)) \
	|| defined(DOXYGEN_CONSISTS_SOLELY_OF_UNICORNS_AND_CONFETTI)
/** @name Message */ /// @{
	/**
		Print debug message.
		@param mesg Debug message.
	*/
	#define DUCT_DEBUG(mesg)
	/**
		Print formatted debug message.
		@param format Format string.
		@param ... Format arguments.
	*/
	#define DUCT_DEBUGF(format, ...)
	/**
		Print debug message with no newline.
		@param mesg Debug message.
	*/
	#define DUCT_DEBUGN(mesg)
	/**
		Print formatted debug message with no newline.
		@param format Format string.
		@param ... Format arguments.
	*/
	#define DUCT_DEBUGNF(format, ...)
/// @}

/** @name Message with function signature */ /// @{
	/**
		Print debug message with function signature.
		@param mesg Debug message.
	*/
	#define DUCT_DEBUGC(mesg)
	/**
		Print formatted debug message with function signature.
		@param format Format string.
		@param ... Format arguments.
	*/
	#define DUCT_DEBUGCF(format, ...)
	/**
		Print debug message with no newline and function signature.
		@param mesg Debug message.
	*/
	#define DUCT_DEBUGNC(mesg)
	/**
		Print formatted debug message with no newline and function signature.
		@param format Format string.
		@param ... Format arguments.
	*/
	#define DUCT_DEBUGNCF(format, ...)
/// @}

/** @name Message with function signature and pointer */ /// @{
	/**
		Print debug message with function signature and pointer.
		@param mesg Debug message.
		@param p Pointer.
	*/
	#define DUCT_DEBUGCP(p, mesg)
	/**
		Print formatted debug message with function signature and pointer.
		@param p Pointer.
		@param format Format string.
		@param ... Format arguments.
	*/
	#define DUCT_DEBUGCPF(p, format, ...)
	/**
		Print debug message with no newline, function signature, and pointer.
		@param p Pointer.
		@param mesg Debug message.
	*/
	#define DUCT_DEBUGNCP(p, mesg)
	/**
		Print formatted debug message with no newline, function signature,
		and pointer.
		@param p Pointer.
		@param format Format string.
		@param ... Format arguments.
	*/
	#define DUCT_DEBUGNCPF(p, format, ...)
/// @}

/** @name Print function signature */ /// @{
	/**
		Print function signature.
	*/
	#define DUCT_DEBUG_CALLED()
	/**
		Print function signature with pointer.
		@param p Pointer.
	*/
	#define DUCT_DEBUG_CALLEDP(p)
/// @}

/**
	@name Debug assertion
	@note These route to the non-debug assertion macros.
	@sa DUCT_ASSERT(),
		DUCT_ASSERTE(),
		DUCT_ASSERTF(),
		DUCT_ASSERTP(),
		DUCT_ASSERTPF()
*/ /// @{
	/** @copydoc DUCT_ASSERT() */
	#define DUCT_DEBUG_ASSERT(expr, mesg)
	/** @copydoc DUCT_ASSERTE() */
	#define DUCT_DEBUG_ASSERTE(expr)
	/** @copydoc DUCT_ASSERTF() */
	#define DUCT_DEBUG_ASSERTF(expr, format, ...)
	/** @copydoc DUCT_ASSERTP() */
	#define DUCT_DEBUG_ASSERTP(expr, p, mesg)
	/** @copydoc DUCT_ASSERTPF() */
	#define DUCT_DEBUG_ASSERTPF(expr, p, format, ...)
/// @}

#else
	#define DUCT_DEBUG_PREFIX__ "debug: "

	// Debug
	#define DUCT_DEBUG(mesg) \
		std::printf(DUCT_DEBUG_PREFIX__ mesg "\n")

	#define DUCT_DEBUGF(format, ...) \
		std::printf(DUCT_DEBUG_PREFIX__ format "\n", __VA_ARGS__)

	// - no newline
	#define DUCT_DEBUGN(mesg) \
		std::printf(DUCT_DEBUG_PREFIX__ mesg)

	#define DUCT_DEBUGNF(format, ...) \
		std::printf(DUCT_DEBUG_PREFIX__ format, __VA_ARGS__)

	// - signature
	#define DUCT_DEBUGC(mesg) \
		DUCT_DEBUGF("in %s: " mesg, DUCT_FUNC_SIG)

	#define DUCT_DEBUGCF(format, ...) \
		DUCT_DEBUGF("in %s: " format, DUCT_FUNC_SIG, __VA_ARGS__)

	// - signature and no newline
	#define DUCT_DEBUGNC(mesg) \
		DUCT_DEBUGNF("in %s: " mesg, DUCT_FUNC_SIG)

	#define DUCT_DEBUGNCF(format, ...) \
		DUCT_DEBUGNF("in %s: " format, DUCT_FUNC_SIG, __VA_ARGS__)

	// - signature and pointer
	#define DUCT_DEBUGCP(p, mesg) \
		DUCT_DEBUGF("[%p] in %s: " mesg, (void const* const)p, DUCT_FUNC_SIG)

	#define DUCT_DEBUGCPF(p, format, ...) \
		DUCT_DEBUGF("[%p] in %s: " format, \
			(void const* const)p, DUCT_FUNC_SIG, __VA_ARGS__)

	// - signature and pointer and no newline
	#define DUCT_DEBUGNCP(p, mesg) \
		DUCT_DEBUGNF("[%p] in %s: " mesg, (void const* const)p, DUCT_FUNC_SIG)

	#define DUCT_DEBUGNCPF(p, format, ...) \
		DUCT_DEBUGNF("[%p] in %s: " format, \
			(void const* const)p, DUCT_FUNC_SIG, __VA_ARGS__)

	// Call
	#define DUCT_DEBUG_CALLED() \
		DUCT_DEBUGF("called: %s", DUCT_FUNC_SIG)

	#define DUCT_DEBUG_CALLEDP(p) \
		DUCT_DEBUGF("called: [%p] %s", (void const* const)p, DUCT_FUNC_SIG)

	// Assert
	#define DUCT_DEBUG_ASSERT(expr, mesg) \
		DUCT_ASSERT(expr, mesg)

	// Assert
	#define DUCT_DEBUG_ASSERTE(expr) \
		DUCT_ASSERTE(expr)

	#define DUCT_DEBUG_ASSERTF(expr, format, ...) \
		DUCT_ASSERTF(expr, format, __VA_ARGS__)

	// - pointer
	#define DUCT_DEBUG_ASSERTP(expr, p, mesg) \
		DUCT_ASSERTP(expr, p, mesg)

	#define DUCT_DEBUG_ASSERTPF(expr, p, format, ...) \
		DUCT_ASSERTPF(expr, p, format, __VA_ARGS__)

#endif

/** @} */ // end doc-group debug

} // namespace duct

#endif // DUCT_DEBUG_HPP_
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2007-2008 Mauro Iazzi
 *
 * 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.
 *
 */

#ifndef __LQT_COMMON_HPP
#define __LQT_COMMON_HPP

#ifdef _WIN32
#define LQT_EXPORT  __declspec(dllexport)
#else
#define LQT_EXPORT
#endif

extern "C" {
#include <lua.h>
#include <lualib.h>
#include <lauxlib.h>
}

//#include <iostream>

//#define lqtL_register(L, p, n) ( (void)L, (void)p, (void)n )
//#define lqtL_unregister(L, p) ( (void)L, (void)p )

#define LQT_POINTERS "Registry Pointers"
#define LQT_REFS "Registry References"
#define LQT_ENUMS "Registry Enumerations"
#define LQT_PCALL "Registry PCall Pointer"

// Qt-specific fields
#define LQT_METACALLER "Registry MetaCaller"
#define LQT_OBJMETASTRING "Lqt MetaStringData"
#define LQT_OBJMETADATA "Lqt MetaData"
#define LQT_OBJSLOTS "Lqt Slots"
#define LQT_OBJSIGS "Lqt Signatures"

// macro to ge positive indexes
#define LQT_TOPOSITIVE(L, i) (((i)<0)?(lua_gettop(L)+1+(i)):(i))

// use standard pcall by default
#ifndef LQT_DEBUG
#define lqtL_pcall(L, n, r, e) lua_pcall(L, n, r, e)
#else  // LQT_DEBUG
#define lqtL_pcall(L, n, r, e) lqtL_pcall_debug(L, n, r, e)
#endif // LQT_DEBUG

typedef int (*lqt_PCallPtr) (lua_State *L, int nargs, int nresults, int errfunc);

void lqtL_register(lua_State *, const void *);
void lqtL_unregister(lua_State *, const void *);

//int& lqtL_tointref (lua_State *, int);

//void lqtL_pusharguments (lua_State *, char**);
//char** lqtL_toarguments (lua_State *, int);
//bool lqtL_testarguments (lua_State *, int);

//void lqtL_manageudata (lua_State *, int);
//void lqtL_unmanageudata (lua_State *, int);
void lqtL_pushudata (lua_State *, const void *, const char *);
void lqtL_passudata (lua_State *, const void *, const char *);
void lqtL_copyudata (lua_State *, const void *, const char *);
void * lqtL_toudata (lua_State *, int, const char *);
bool lqtL_testudata (lua_State *, int, const char *);
//#define lqtL_checkudata(a...) luaL_checkudata(a)
void * lqtL_checkudata (lua_State *, int, const char *);
void lqtL_eraseudata (lua_State *, int, const char *);
#define lqtL_isudata lqtL_testudata

void lqtL_pushenum (lua_State *, int, const char *);
bool lqtL_isenum (lua_State *, int, const char *);
int lqtL_toenum (lua_State *, int, const char *);

bool lqtL_isinteger (lua_State *, int);
bool lqtL_isnumber (lua_State *, int);
bool lqtL_isstring (lua_State *, int);
bool lqtL_isboolean (lua_State *, int);

bool lqtL_missarg (lua_State *, int, int);
//int lqtL_baseindex (lua_State *, int, int);

//int lqtL_gc (lua_State *);
//int lqtL_index (lua_State *);
//int lqtL_newindex (lua_State *);

typedef struct {
	const char *name;
	int value;
} lqt_Enum;

typedef struct {
	lqt_Enum *enums;
	const char *name;
} lqt_Enumlist;

int lqtL_createenumlist (lua_State *, lqt_Enumlist[]);

typedef struct {
	const char *basename;
	ptrdiff_t offset;
} lqt_Base;

typedef struct {
	luaL_Reg *mt;
	lqt_Base *bases;
	const char * name;
} lqt_Class;

int lqtL_createclass (lua_State *, const char *, luaL_Reg *, lqt_Base *);

/* functions to get/push special types */

bool * lqtL_toboolref (lua_State *, int);
void * lqtL_getref (lua_State *, size_t, bool);
int * lqtL_tointref (lua_State *, int);
char ** lqtL_toarguments (lua_State *, int);
void lqtL_pusharguments (lua_State *, char **);

int lqtL_getflags (lua_State *, int, const char *);
void lqtL_pushflags (lua_State *, int, const char *);
#define lqtL_isflags(L, i) (lua_istable((L), (i)) || lqtL_isinteger((L), (i)))

int lqtL_touintarray (lua_State *);

int lqtL_pcall_debug (lua_State *L, int narg, int nres, int err);

#endif // __LQT_COMMON_HPP

<commit_msg>add prototype for lqtL_getoverload<commit_after>/*
 * Copyright (c) 2007-2008 Mauro Iazzi
 *
 * 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.
 *
 */

#ifndef __LQT_COMMON_HPP
#define __LQT_COMMON_HPP

#ifdef _WIN32
#define LQT_EXPORT  __declspec(dllexport)
#else
#define LQT_EXPORT
#endif

extern "C" {
#include <lua.h>
#include <lualib.h>
#include <lauxlib.h>
}

//#include <iostream>

//#define lqtL_register(L, p, n) ( (void)L, (void)p, (void)n )
//#define lqtL_unregister(L, p) ( (void)L, (void)p )

#define LQT_POINTERS "Registry Pointers"
#define LQT_REFS "Registry References"
#define LQT_ENUMS "Registry Enumerations"
#define LQT_PCALL "Registry PCall Pointer"

// Qt-specific fields
#define LQT_METACALLER "Registry MetaCaller"
#define LQT_OBJMETASTRING "Lqt MetaStringData"
#define LQT_OBJMETADATA "Lqt MetaData"
#define LQT_OBJSLOTS "Lqt Slots"
#define LQT_OBJSIGS "Lqt Signatures"

// macro to ge positive indexes
#define LQT_TOPOSITIVE(L, i) (((i)<0)?(lua_gettop(L)+1+(i)):(i))

// use standard pcall by default
#ifndef LQT_DEBUG
#define lqtL_pcall(L, n, r, e) lua_pcall(L, n, r, e)
#else  // LQT_DEBUG
#define lqtL_pcall(L, n, r, e) lqtL_pcall_debug(L, n, r, e)
#endif // LQT_DEBUG

typedef int (*lqt_PCallPtr) (lua_State *L, int nargs, int nresults, int errfunc);

void lqtL_register(lua_State *, const void *);
void lqtL_unregister(lua_State *, const void *);

//int& lqtL_tointref (lua_State *, int);

//void lqtL_pusharguments (lua_State *, char**);
//char** lqtL_toarguments (lua_State *, int);
//bool lqtL_testarguments (lua_State *, int);

//void lqtL_manageudata (lua_State *, int);
//void lqtL_unmanageudata (lua_State *, int);
void lqtL_pushudata (lua_State *, const void *, const char *);
void lqtL_passudata (lua_State *, const void *, const char *);
void lqtL_copyudata (lua_State *, const void *, const char *);
void * lqtL_toudata (lua_State *, int, const char *);
bool lqtL_testudata (lua_State *, int, const char *);
//#define lqtL_checkudata(a...) luaL_checkudata(a)
void * lqtL_checkudata (lua_State *, int, const char *);
void lqtL_eraseudata (lua_State *, int, const char *);
#define lqtL_isudata lqtL_testudata

void lqtL_pushenum (lua_State *, int, const char *);
bool lqtL_isenum (lua_State *, int, const char *);
int lqtL_toenum (lua_State *, int, const char *);

bool lqtL_isinteger (lua_State *, int);
bool lqtL_isnumber (lua_State *, int);
bool lqtL_isstring (lua_State *, int);
bool lqtL_isboolean (lua_State *, int);

bool lqtL_missarg (lua_State *, int, int);
//int lqtL_baseindex (lua_State *, int, int);

//int lqtL_gc (lua_State *);
//int lqtL_index (lua_State *);
//int lqtL_newindex (lua_State *);

typedef struct {
	const char *name;
	int value;
} lqt_Enum;

typedef struct {
	lqt_Enum *enums;
	const char *name;
} lqt_Enumlist;

int lqtL_createenumlist (lua_State *, lqt_Enumlist[]);

typedef struct {
	const char *basename;
	ptrdiff_t offset;
} lqt_Base;

typedef struct {
	luaL_Reg *mt;
	lqt_Base *bases;
	const char * name;
} lqt_Class;

int lqtL_createclass (lua_State *, const char *, luaL_Reg *, lqt_Base *);

/* functions to get/push special types */

bool * lqtL_toboolref (lua_State *, int);
void * lqtL_getref (lua_State *, size_t, bool);
int * lqtL_tointref (lua_State *, int);
char ** lqtL_toarguments (lua_State *, int);
void lqtL_pusharguments (lua_State *, char **);

int lqtL_getflags (lua_State *, int, const char *);
void lqtL_pushflags (lua_State *, int, const char *);
#define lqtL_isflags(L, i) (lua_istable((L), (i)) || lqtL_isinteger((L), (i)))

int lqtL_touintarray (lua_State *);

int lqtL_pcall_debug (lua_State *L, int narg, int nres, int err);

int lqtL_getoverload (lua_State *L, int index, const char *name);

#endif // __LQT_COMMON_HPP

<|endoftext|>


<commit_before>/*********************************************************************************
 *
 * Inviwo - Interactive Visualization Workshop
 *
 * Copyright (c) 2012-2022 Inviwo Foundation
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice, this
 * list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright notice,
 * this list of conditions and the following disclaimer in the documentation
 * and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 *********************************************************************************/

#include <modules/qtwidgets/inviwodockwidgettitlebar.h>

#include <inviwo/core/util/raiiutils.h>       // for KeepTrueWhileInScope
#include <modules/qtwidgets/inviwoqtutils.h>  // for emToPx, windowTitleHelper

#include <QDockWidget>   // for QDockWidget
#include <QEvent>        // for QEvent, QEvent::ModifiedChange, QEvent::Win...
#include <QHBoxLayout>   // for QHBoxLayout
#include <QIcon>         // for QIcon, QIcon::Normal, QIcon::Off, QIcon::On
#include <QLabel>        // for QLabel
#include <QLayout>       // for QLayout
#include <QList>         // for QList, QList<>::iterator
#include <QPainter>      // for QPainter
#include <QSizeF>        // for QSizeF
#include <QStyle>        // for QStyle, QStyle::PE_Widget
#include <QStyleOption>  // for QStyleOption
#include <QToolButton>   // for QToolButton

class QHBoxLayout;
class QShowEvent;

namespace inviwo {

InviwoDockWidgetTitleBar::InviwoDockWidgetTitleBar(QWidget* parent)
    : QWidget(parent)
    , parent_(dynamic_cast<QDockWidget*>(parent))
    , allowedDockAreas_(parent_->allowedAreas())
    , internalStickyFlagUpdate_(false) {
    label_ = new QLabel(parent->windowTitle());
    label_->setObjectName("InviwoDockWidgetTitleBarLabel");

    const auto iconsize = utilqt::emToPx(this, QSizeF(iconSize_, iconSize_));

    {
        stickyBtn_ = new QToolButton();
        QIcon icon;
        icon.addFile(":/svgicons/dock-unsticky.svg", iconsize, QIcon::Normal, QIcon::Off);
        icon.addFile(":/svgicons/dock-sticky.svg", iconsize, QIcon::Normal, QIcon::On);
        stickyBtn_->setIcon(icon);
        stickyBtn_->setCheckable(true);
        stickyBtn_->setChecked(true);
        stickyBtn_->setIconSize(iconsize);
    }
    {
        floatBtn_ = new QToolButton();
        QIcon icon;
        icon.addFile(":/svgicons/dock-docked.svg", iconsize, QIcon::Normal, QIcon::Off);
        icon.addFile(":/svgicons/dock-floating.svg", iconsize, QIcon::Normal, QIcon::On);
        floatBtn_->setIcon(icon);
        floatBtn_->setCheckable(true);
        floatBtn_->setChecked(parent_->isFloating());
        floatBtn_->setIconSize(iconsize);
    }

    {
        closeBtn_ = new QToolButton();
        QIcon icon;
        icon.addFile(":/svgicons/close.svg", iconsize);
        closeBtn_->setIcon(icon);
        closeBtn_->setIconSize(iconsize);
    }

    QHBoxLayout* layout = new QHBoxLayout(this);
    layout->addWidget(label_, 1);
    layout->addWidget(stickyBtn_);
    layout->addWidget(floatBtn_);
    layout->addWidget(closeBtn_);
    layout->setSpacing(0);
    auto margin = utilqt::emToPx(this, 0.2);
    layout->setContentsMargins(margin, margin, margin, margin);

    setLayout(layout);

    QObject::connect(parent_, &QDockWidget::topLevelChanged, this,
                     &InviwoDockWidgetTitleBar::floating);
    QObject::connect(stickyBtn_, &QToolButton::toggled, this,
                     &InviwoDockWidgetTitleBar::stickyBtnToggled);
    QObject::connect(floatBtn_, &QToolButton::clicked, this,
                     [&]() { parent_->setFloating(!parent_->isFloating()); });
    QObject::connect(closeBtn_, &QToolButton::clicked, parent_, &QDockWidget::close);

    parent_->installEventFilter(this);
}

InviwoDockWidgetTitleBar::~InviwoDockWidgetTitleBar() = default;

void InviwoDockWidgetTitleBar::paintEvent(QPaintEvent*) {
    QStyleOption opt;
    opt.initFrom(this);
    QPainter p(this);
    // style()->drawControl(QStyle::CE_DockWidgetTitle, &opt, &p, this);
    style()->drawPrimitive(QStyle::PE_Widget, &opt, &p, this);
}

void InviwoDockWidgetTitleBar::stickyBtnToggled(bool toggle) {
    util::KeepTrueWhileInScope guard(&internalStickyFlagUpdate_);
    if (toggle) {
        // docking allowed, restore docking areas
        parent_->setAllowedAreas(allowedDockAreas_);
    } else {
        // no docking, disable all areas
        parent_->setAllowedAreas(Qt::NoDockWidgetArea);
    }
    emit stickyFlagChanged(toggle);
}

void InviwoDockWidgetTitleBar::showEvent(QShowEvent*) {
    if (isSticky()) {
        // docking allowed, restore docking areas
        parent_->setAllowedAreas(allowedDockAreas_);
    } else {
        // no docking, disable all areas
        parent_->setAllowedAreas(Qt::NoDockWidgetArea);
    }
}

bool InviwoDockWidgetTitleBar::eventFilter(QObject* obj, QEvent* event) {
    if ((event->type() == QEvent::ModifiedChange) || (event->type() == QEvent::WindowTitleChange)) {
        label_->setText(utilqt::windowTitleHelper(parent_->windowTitle(), parent_));
    }
    return QObject::eventFilter(obj, event);
}

void InviwoDockWidgetTitleBar::floating(bool floating) { floatBtn_->setChecked(floating); }

void InviwoDockWidgetTitleBar::setIconSize(double size) {
    iconSize_ = size;
    const auto iconsize = utilqt::emToPx(this, QSizeF(iconSize_, iconSize_));

    if (auto theLayout = layout()) {
        for (auto tb : theLayout->findChildren<QToolButton*>()) {
            tb->setIconSize(iconsize);
        }
    }
}

void InviwoDockWidgetTitleBar::setSticky(bool toggle) { stickyBtn_->setChecked(toggle); }

bool InviwoDockWidgetTitleBar::isSticky() const { return stickyBtn_->isChecked(); }

void InviwoDockWidgetTitleBar::allowedAreasChanged(Qt::DockWidgetAreas areas) {
    if (!internalStickyFlagUpdate_) {
        // save currently set docking areas
        allowedDockAreas_ = areas;
        if (!isSticky()) {
            // dockwidget is non-sticky, reset allowed areas to none
            util::KeepTrueWhileInScope guard(&internalStickyFlagUpdate_);
            parent_->setAllowedAreas(Qt::NoDockWidgetArea);
        }
    }
}

}  // namespace inviwo
<commit_msg>QtWidgets: fixed InviwoDockWidget min width<commit_after>/*********************************************************************************
 *
 * Inviwo - Interactive Visualization Workshop
 *
 * Copyright (c) 2012-2022 Inviwo Foundation
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice, this
 * list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright notice,
 * this list of conditions and the following disclaimer in the documentation
 * and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 *********************************************************************************/

#include <modules/qtwidgets/inviwodockwidgettitlebar.h>

#include <inviwo/core/util/raiiutils.h>       // for KeepTrueWhileInScope
#include <modules/qtwidgets/inviwoqtutils.h>  // for emToPx, windowTitleHelper

#include <QDockWidget>   // for QDockWidget
#include <QEvent>        // for QEvent, QEvent::ModifiedChange, QEvent::Win...
#include <QHBoxLayout>   // for QHBoxLayout
#include <QIcon>         // for QIcon, QIcon::Normal, QIcon::Off, QIcon::On
#include <QLabel>        // for QLabel
#include <QLayout>       // for QLayout
#include <QList>         // for QList, QList<>::iterator
#include <QPainter>      // for QPainter
#include <QSizeF>        // for QSizeF
#include <QStyle>        // for QStyle, QStyle::PE_Widget
#include <QStyleOption>  // for QStyleOption
#include <QToolButton>   // for QToolButton

class QHBoxLayout;
class QShowEvent;

namespace inviwo {

InviwoDockWidgetTitleBar::InviwoDockWidgetTitleBar(QWidget* parent)
    : QWidget(parent)
    , parent_(dynamic_cast<QDockWidget*>(parent))
    , allowedDockAreas_(parent_->allowedAreas())
    , internalStickyFlagUpdate_(false) {
    label_ = new QLabel(parent->windowTitle());
    label_->setObjectName("InviwoDockWidgetTitleBarLabel");
    label_->setMinimumWidth(50);
    auto policy = label_->sizePolicy();
    policy.setHorizontalPolicy(QSizePolicy::Expanding);
    label_->setSizePolicy(policy);

    const auto iconsize = utilqt::emToPx(this, QSizeF(iconSize_, iconSize_));

    {
        stickyBtn_ = new QToolButton();
        QIcon icon;
        icon.addFile(":/svgicons/dock-unsticky.svg", iconsize, QIcon::Normal, QIcon::Off);
        icon.addFile(":/svgicons/dock-sticky.svg", iconsize, QIcon::Normal, QIcon::On);
        stickyBtn_->setIcon(icon);
        stickyBtn_->setCheckable(true);
        stickyBtn_->setChecked(true);
        stickyBtn_->setIconSize(iconsize);
    }
    {
        floatBtn_ = new QToolButton();
        QIcon icon;
        icon.addFile(":/svgicons/dock-docked.svg", iconsize, QIcon::Normal, QIcon::Off);
        icon.addFile(":/svgicons/dock-floating.svg", iconsize, QIcon::Normal, QIcon::On);
        floatBtn_->setIcon(icon);
        floatBtn_->setCheckable(true);
        floatBtn_->setChecked(parent_->isFloating());
        floatBtn_->setIconSize(iconsize);
    }

    {
        closeBtn_ = new QToolButton();
        QIcon icon;
        icon.addFile(":/svgicons/close.svg", iconsize);
        closeBtn_->setIcon(icon);
        closeBtn_->setIconSize(iconsize);
    }

    QHBoxLayout* layout = new QHBoxLayout(this);
    layout->addWidget(label_, 1);
    layout->addWidget(stickyBtn_);
    layout->addWidget(floatBtn_);
    layout->addWidget(closeBtn_);
    layout->setSpacing(0);
    auto margin = utilqt::emToPx(this, 0.2);
    layout->setContentsMargins(margin, margin, margin, margin);

    setLayout(layout);

    QObject::connect(parent_, &QDockWidget::topLevelChanged, this,
                     &InviwoDockWidgetTitleBar::floating);
    QObject::connect(stickyBtn_, &QToolButton::toggled, this,
                     &InviwoDockWidgetTitleBar::stickyBtnToggled);
    QObject::connect(floatBtn_, &QToolButton::clicked, this,
                     [&]() { parent_->setFloating(!parent_->isFloating()); });
    QObject::connect(closeBtn_, &QToolButton::clicked, parent_, &QDockWidget::close);

    parent_->installEventFilter(this);
}

InviwoDockWidgetTitleBar::~InviwoDockWidgetTitleBar() = default;

void InviwoDockWidgetTitleBar::paintEvent(QPaintEvent*) {
    QStyleOption opt;
    opt.initFrom(this);
    QPainter p(this);
    // style()->drawControl(QStyle::CE_DockWidgetTitle, &opt, &p, this);
    style()->drawPrimitive(QStyle::PE_Widget, &opt, &p, this);
}

void InviwoDockWidgetTitleBar::stickyBtnToggled(bool toggle) {
    util::KeepTrueWhileInScope guard(&internalStickyFlagUpdate_);
    if (toggle) {
        // docking allowed, restore docking areas
        parent_->setAllowedAreas(allowedDockAreas_);
    } else {
        // no docking, disable all areas
        parent_->setAllowedAreas(Qt::NoDockWidgetArea);
    }
    emit stickyFlagChanged(toggle);
}

void InviwoDockWidgetTitleBar::showEvent(QShowEvent*) {
    if (isSticky()) {
        // docking allowed, restore docking areas
        parent_->setAllowedAreas(allowedDockAreas_);
    } else {
        // no docking, disable all areas
        parent_->setAllowedAreas(Qt::NoDockWidgetArea);
    }
}

bool InviwoDockWidgetTitleBar::eventFilter(QObject* obj, QEvent* event) {
    if ((event->type() == QEvent::ModifiedChange) || (event->type() == QEvent::WindowTitleChange) ||
        (event->type() == QEvent::Resize)) {
        QString windowTitle = utilqt::windowTitleHelper(parent_->windowTitle(), parent_);
        // elide window title in case it is too long to fit the label
        QFontMetrics fontMetrics(label_->font());
        label_->setText(fontMetrics.elidedText(windowTitle, Qt::ElideMiddle, label_->width() - 4));
    }
    return QObject::eventFilter(obj, event);
}

void InviwoDockWidgetTitleBar::floating(bool floating) { floatBtn_->setChecked(floating); }

void InviwoDockWidgetTitleBar::setIconSize(double size) {
    iconSize_ = size;
    const auto iconsize = utilqt::emToPx(this, QSizeF(iconSize_, iconSize_));

    if (auto theLayout = layout()) {
        for (auto tb : theLayout->findChildren<QToolButton*>()) {
            tb->setIconSize(iconsize);
        }
    }
}

void InviwoDockWidgetTitleBar::setSticky(bool toggle) { stickyBtn_->setChecked(toggle); }

bool InviwoDockWidgetTitleBar::isSticky() const { return stickyBtn_->isChecked(); }

void InviwoDockWidgetTitleBar::allowedAreasChanged(Qt::DockWidgetAreas areas) {
    if (!internalStickyFlagUpdate_) {
        // save currently set docking areas
        allowedDockAreas_ = areas;
        if (!isSticky()) {
            // dockwidget is non-sticky, reset allowed areas to none
            util::KeepTrueWhileInScope guard(&internalStickyFlagUpdate_);
            parent_->setAllowedAreas(Qt::NoDockWidgetArea);
        }
    }
}

}  // namespace inviwo
<|endoftext|>


<commit_before>#include "KVMainWindow.h"
#include <QMenuBar>
#include <QMenu>
#include <QWebFrame>
#include <QInputDialog>
#include <QFile>
#include <QUrl>
#include <QUrlQuery>
#include <QApplication>
#include <QNetworkProxy>
#include <QNetworkReply>
#include <QHostAddress>
#include <QSettings>
#include <QStandardPaths>
#include <QDebug>
#include <QTimer>
#include "KVNetworkAccessManager.h"
#include "KVTranslator.h"

KVMainWindow::KVMainWindow(QWidget *parent, Qt::WindowFlags flags):
	QMainWindow(parent, flags)
{
	// Load settings from the settings file
	this->loadSettings();

	this->setWindowTitle("KanColleTool Viewer");

	// Set up the window and menus and stuff
	QMenuBar *menuBar = new QMenuBar(this);

	QMenu *viewerMenu = menuBar->addMenu("Viewer");
	viewerMenu->addAction("Change API Link", this, SLOT(askForAPILink()), Qt::CTRL + Qt::Key_L);
	QAction *translationAction = viewerMenu->addAction("Enable Translation", this, SLOT(toggleTranslation(bool)));
	translationAction->setCheckable(true);
	translationAction->setChecked(KVTranslator::instance()->enabled);
	viewerMenu->addAction("Clear Cache", this, SLOT(clearCache()));
	viewerMenu->addSeparator();
	viewerMenu->addAction("Refresh", this, SLOT(loadBundledIndex));
	viewerMenu->addAction("Quit", qApp, SLOT(quit()), Qt::CTRL + Qt::Key_Q);

	QMenu *helpMenu = menuBar->addMenu("Help");
	helpMenu->addAction("About", this, SLOT(showAbout()));
	// Updates on Linux are handled by the package manager
#if !defined(Q_OS_LINUX)
	helpMenu->addAction("Check for Updates", this, SLOT(checkForUpdates()));
#endif

	this->setMenuBar(menuBar);

	// Set a custom network access manager to let us set up a cache and proxy.
	// Without a cache, the game takes ages to load.
	// Without a proxy, we can't do cool things like translating the game.
	wvManager = new KVNetworkAccessManager(this);

	// Set up a cache; a larger-than-normal disk cache is quite enough for our purposes
	cache = new QNetworkDiskCache(this);
	cache->setCacheDirectory(QStandardPaths::writableLocation(QStandardPaths::CacheLocation));
	wvManager->setCache(cache);

	// Set up the web view, using our custom Network Access Manager
	webView = new QWebView(this);
	webView->page()->setNetworkAccessManager(wvManager);

	// The context menu only contains "Reload" anyways
	webView->setContextMenuPolicy(Qt::PreventContextMenu);
	// These are so large that they create a need for themselves >_>
	webView->page()->mainFrame()->setScrollBarPolicy(Qt::Horizontal, Qt::ScrollBarAlwaysOff);
	webView->page()->mainFrame()->setScrollBarPolicy(Qt::Vertical, Qt::ScrollBarAlwaysOff);

	connect(webView, SIGNAL(loadStarted()), this, SLOT(onLoadStarted()));
	connect(webView, SIGNAL(loadFinished(bool)), this, SLOT(onLoadFinished(bool)));

	// To set the window size right, we have to first set the central widget (which we set to
	// the web view)'s size to a fixed size, ask the window to auto-adjust to that, and then
	// fix its size to what it adjusted itself to. A bit clumsy, but it works, and won't stop
	// us from adding any additional elements to the window, as this will account for ANYTHING.
	this->setCentralWidget(webView);
	this->centralWidget()->setFixedSize(800, 480);
	this->adjustSize();
	this->setFixedSize(this->width(), this->height());

	// Check for updates
	// Updates on Linux are handled by the package manager
#if !defined(Q_OS_LINUX)
	this->checkForUpdates();
#endif

	// Load the translation data before doing anything, otherwise we might end
	// up with partially translated data on spotty connections.
	if(KVTranslator::instance()->enabled)
		this->loadTranslation();

	this->loadBundledIndex();
}

void KVMainWindow::checkForUpdates()
{
	QNetworkReply *reply = manager.get(QNetworkRequest(QUrl("http://kancolletool.github.io/VERSION")));
	connect(reply, SIGNAL(finished()), this, SLOT(onVersionCheckFinished()));
}

void KVMainWindow::loadTranslation(QString language)
{
	KVTranslator *translator = KVTranslator::instance();
	if(translator->loaded()) return;

	connect(translator, SIGNAL(loadFailed(QString)), this, SLOT(onTranslationLoadFailed(QString)));
	translator->loadTranslation(language);
}

void KVMainWindow::loadBundledIndex()
{
	QFile file(":/index.html");
	if(file.open(QIODevice::ReadOnly))
	{
		webView->setHtml(file.readAll(), apiLink);
	}
	else
	{
		QMessageBox::critical(this, "Can't load resource", "Couldn't load the local resources needed to start the client.

I have no idea how you even managed to make this happen, since the resources are supposed to be inside the executable, but it probably involved a recompilation that went wrong.

index.html needs to be in the root of resources.qrc.");
		exit(1);
	}
}

void KVMainWindow::loadSettings()
{
	QSettings settings;

	server = settings.value("server").toString();
	apiToken = settings.value("apiToken").toString();

	if(server.isEmpty() || apiToken.isEmpty())
	{
		this->askForAPILink(false);
		if(server.isEmpty() || apiToken.isEmpty())
			exit(0);
	}
	else this->generateAPILinkURL();

	KVTranslator *translator = KVTranslator::instance();
	translator->enabled = settings.value("translation").toBool();

	qDebug() << "Server:" << server;
	qDebug() << "API Token:" << apiToken;
	qDebug() << "API Link:" << apiLink.toString();
	qDebug() << "Translation:" << (translator->enabled ? "enabled" : "disabled");
}

void KVMainWindow::generateAPILinkURL()
{
	apiLink = QUrl(QString("http://%1/kcs/mainD2.swf?api_token=%2").arg(server, apiToken));
}

void KVMainWindow::askForAPILink(bool reload)
{
	// Get the link from the user
	QString link = QInputDialog::getText(this, "Enter API Link", "Please enter your API Link.

It should look something like:
http://125.6.XXX.XXX/kcs/mainD2.swf?api_token=xxxxxxxxxx...");

	// If the link is empty, the user pressed cancel, for whatever reason
	if(link.isEmpty())
		return;

	// Make an URL and a Query from it
	QUrl url(link);
	QUrlQuery query(url);

	// Extract the important bits, and generate a well-formed URL from that
	// (It's important that nothing we're doing is noticeable to the staff!)
	server = url.host();
	apiToken = query.queryItemValue("api_token");
	this->generateAPILinkURL();

	// Put it in the settings and force a sync
	QSettings settings;
	settings.setValue("server", server);
	settings.setValue("apiToken", apiToken);
	settings.sync();

	// If we're in-game and expected to reload the page, do so.
	// This is NOT true when called from loadAPILink(), and should
	// be true when called from the menu item.
	if(reload)
		this->loadBundledIndex();
}

void KVMainWindow::toggleTranslation(bool checked)
{
	KVTranslator::instance()->enabled = checked;

	QSettings settings;
	settings.setValue("translation", checked);
	settings.sync();

	if(checked)
		this->loadTranslation();

	this->loadBundledIndex();
}

void KVMainWindow::clearCache()
{
	cache->clear();
	this->loadBundledIndex();
}

void KVMainWindow::showAbout()
{
	QMessageBox::about(this, "About KCTViewer",
		QString(
			"
KCTViewer %1
"
		).arg(
			QCoreApplication::applicationVersion()
		)
	);
}

void KVMainWindow::onVersionCheckFinished()
{
	QNetworkReply *reply = qobject_cast<QNetworkReply*>(QObject::sender());

	// If the check failed, do nothing
	if(reply->error() != QNetworkReply::NoError)
		return;

	// Parse the version numbers
	QString newVersion = QString::fromUtf8(reply->readAll()).trimmed();
	QList<int> newVersionComponents;
	foreach(QString part, newVersion.split("."))
		newVersionComponents.append(part.toInt());

	QString appVersion = qApp->applicationVersion();
	QList<int> appVersionComponents;
	foreach(QString part, appVersion.split("."))
		appVersionComponents.append(part.toInt());

	// Compare component-per-component to see if we're outdated
	bool outdated = false;
	for(int i = 0; i < qMin(newVersionComponents.length(), appVersionComponents.length()); i++)
	{
		if(newVersionComponents[i] != appVersionComponents[i])
		{
			outdated = (newVersionComponents[i] > appVersionComponents[i]);
			break;
		}
	}

	// Display a message if we are
	if(outdated)
		QMessageBox::information(this, "New Version Available", "Version " + newVersion + " has been released, and is available at:
http://kancolletool.github.io/downloads/");
}

void KVMainWindow::onLoadStarted()
{
	qDebug() << "Loading Started...";
}

void KVMainWindow::onLoadFinished(bool ok)
{
	qDebug() << "Finished Loading!" << ok;
	if(ok) this->setHTMLAPILink();
}

void KVMainWindow::onTranslationLoadFailed(QString error)
{
	qDebug() << "Translation failed to load:" << error;
	loadingMessageBox->reject();
	delete loadingMessageBox;

	QMessageBox::StandardButton button;
	if(KVTranslator::instance()->loaded()) {
		button = QMessageBox::warning(this, "Couldn't load network translation", "This might mean that your connection is bad. However, a cached translation has been loaded. Would you like to retry loading the translation from the network?", QMessageBox::Retry|QMessageBox::Ok, QMessageBox::Ok);
	} else {
		button = QMessageBox::warning(this, "Couldn't load translation", "This might mean that your connection is bad. You can continue without translation, but the game will be in Japanese.", QMessageBox::Retry|QMessageBox::Ok, QMessageBox::Ok);

		// Disable translation if they want it
		if(button != QMessageBox::Retry)
			KVTranslator::instance()->enabled = false;
	}

	// To retry, just send the request again.
	if(button == QMessageBox::Retry)
		this->loadTranslation();
}

void KVMainWindow::setHTMLAPILink()
{
	qDebug() << "Updating web view credentials to" << server << "-" << apiToken;
	webView->page()->mainFrame()->evaluateJavaScript(QString("setCredentials(\"%1\", \"%2\"); null").arg(server, apiToken));
}

/*void KVMainWindow::onAPIError(KVProxyServer::APIStatus error)
{
	qDebug() << error;

	QString readableError;

	switch(error)
	{
		case KVProxyServer::OK:
			readableError = "No Error, you shouldn't be seeing this.";
			break;
		case KVProxyServer::Unauthorized:
			readableError = "Either your API Link is invalid, or it has expired. That happens sometimes.";
			break;
		case KVProxyServer::InvalidAPIVersion:
		case KVProxyServer::MissingParameters:
			readableError = "The game was updated, but you have an old client.";
			break;
		default:
			readableError = "An unknown error occurred. Please tell the developers that this happened ALONG WITH THE ERROR CODE, and what you think caused it.";
	}

	QMessageBox::critical(this, QString("Errorcat (Code %1)").arg((int)error), readableError);
}*/
<commit_msg>stop qt from complaining about the refresh SLOT<commit_after>#include "KVMainWindow.h"
#include <QMenuBar>
#include <QMenu>
#include <QWebFrame>
#include <QInputDialog>
#include <QFile>
#include <QUrl>
#include <QUrlQuery>
#include <QApplication>
#include <QNetworkProxy>
#include <QNetworkReply>
#include <QHostAddress>
#include <QSettings>
#include <QStandardPaths>
#include <QDebug>
#include <QTimer>
#include "KVNetworkAccessManager.h"
#include "KVTranslator.h"

KVMainWindow::KVMainWindow(QWidget *parent, Qt::WindowFlags flags):
	QMainWindow(parent, flags)
{
	// Load settings from the settings file
	this->loadSettings();

	this->setWindowTitle("KanColleTool Viewer");

	// Set up the window and menus and stuff
	QMenuBar *menuBar = new QMenuBar(this);

	QMenu *viewerMenu = menuBar->addMenu("Viewer");
	viewerMenu->addAction("Change API Link", this, SLOT(askForAPILink()), Qt::CTRL + Qt::Key_L);
	QAction *translationAction = viewerMenu->addAction("Enable Translation", this, SLOT(toggleTranslation(bool)));
	translationAction->setCheckable(true);
	translationAction->setChecked(KVTranslator::instance()->enabled);
	viewerMenu->addAction("Clear Cache", this, SLOT(clearCache()));
	viewerMenu->addSeparator();
	viewerMenu->addAction("Refresh", this, SLOT(loadBundledIndex()));
	viewerMenu->addAction("Quit", qApp, SLOT(quit()), Qt::CTRL + Qt::Key_Q);

	QMenu *helpMenu = menuBar->addMenu("Help");
	helpMenu->addAction("About", this, SLOT(showAbout()));
	// Updates on Linux are handled by the package manager
#if !defined(Q_OS_LINUX)
	helpMenu->addAction("Check for Updates", this, SLOT(checkForUpdates()));
#endif

	this->setMenuBar(menuBar);

	// Set a custom network access manager to let us set up a cache and proxy.
	// Without a cache, the game takes ages to load.
	// Without a proxy, we can't do cool things like translating the game.
	wvManager = new KVNetworkAccessManager(this);

	// Set up a cache; a larger-than-normal disk cache is quite enough for our purposes
	cache = new QNetworkDiskCache(this);
	cache->setCacheDirectory(QStandardPaths::writableLocation(QStandardPaths::CacheLocation));
	wvManager->setCache(cache);

	// Set up the web view, using our custom Network Access Manager
	webView = new QWebView(this);
	webView->page()->setNetworkAccessManager(wvManager);

	// The context menu only contains "Reload" anyways
	webView->setContextMenuPolicy(Qt::PreventContextMenu);
	// These are so large that they create a need for themselves >_>
	webView->page()->mainFrame()->setScrollBarPolicy(Qt::Horizontal, Qt::ScrollBarAlwaysOff);
	webView->page()->mainFrame()->setScrollBarPolicy(Qt::Vertical, Qt::ScrollBarAlwaysOff);

	connect(webView, SIGNAL(loadStarted()), this, SLOT(onLoadStarted()));
	connect(webView, SIGNAL(loadFinished(bool)), this, SLOT(onLoadFinished(bool)));

	// To set the window size right, we have to first set the central widget (which we set to
	// the web view)'s size to a fixed size, ask the window to auto-adjust to that, and then
	// fix its size to what it adjusted itself to. A bit clumsy, but it works, and won't stop
	// us from adding any additional elements to the window, as this will account for ANYTHING.
	this->setCentralWidget(webView);
	this->centralWidget()->setFixedSize(800, 480);
	this->adjustSize();
	this->setFixedSize(this->width(), this->height());

	// Check for updates
	// Updates on Linux are handled by the package manager
#if !defined(Q_OS_LINUX)
	this->checkForUpdates();
#endif

	// Load the translation data before doing anything, otherwise we might end
	// up with partially translated data on spotty connections.
	if(KVTranslator::instance()->enabled)
		this->loadTranslation();

	this->loadBundledIndex();
}

void KVMainWindow::checkForUpdates()
{
	QNetworkReply *reply = manager.get(QNetworkRequest(QUrl("http://kancolletool.github.io/VERSION")));
	connect(reply, SIGNAL(finished()), this, SLOT(onVersionCheckFinished()));
}

void KVMainWindow::loadTranslation(QString language)
{
	KVTranslator *translator = KVTranslator::instance();
	if(translator->loaded()) return;

	connect(translator, SIGNAL(loadFailed(QString)), this, SLOT(onTranslationLoadFailed(QString)));
	translator->loadTranslation(language);
}

void KVMainWindow::loadBundledIndex()
{
	QFile file(":/index.html");
	if(file.open(QIODevice::ReadOnly))
	{
		webView->setHtml(file.readAll(), apiLink);
	}
	else
	{
		QMessageBox::critical(this, "Can't load resource", "Couldn't load the local resources needed to start the client.

I have no idea how you even managed to make this happen, since the resources are supposed to be inside the executable, but it probably involved a recompilation that went wrong.

index.html needs to be in the root of resources.qrc.");
		exit(1);
	}
}

void KVMainWindow::loadSettings()
{
	QSettings settings;

	server = settings.value("server").toString();
	apiToken = settings.value("apiToken").toString();

	if(server.isEmpty() || apiToken.isEmpty())
	{
		this->askForAPILink(false);
		if(server.isEmpty() || apiToken.isEmpty())
			exit(0);
	}
	else this->generateAPILinkURL();

	KVTranslator *translator = KVTranslator::instance();
	translator->enabled = settings.value("translation").toBool();

	qDebug() << "Server:" << server;
	qDebug() << "API Token:" << apiToken;
	qDebug() << "API Link:" << apiLink.toString();
	qDebug() << "Translation:" << (translator->enabled ? "enabled" : "disabled");
}

void KVMainWindow::generateAPILinkURL()
{
	apiLink = QUrl(QString("http://%1/kcs/mainD2.swf?api_token=%2").arg(server, apiToken));
}

void KVMainWindow::askForAPILink(bool reload)
{
	// Get the link from the user
	QString link = QInputDialog::getText(this, "Enter API Link", "Please enter your API Link.

It should look something like:
http://125.6.XXX.XXX/kcs/mainD2.swf?api_token=xxxxxxxxxx...");

	// If the link is empty, the user pressed cancel, for whatever reason
	if(link.isEmpty())
		return;

	// Make an URL and a Query from it
	QUrl url(link);
	QUrlQuery query(url);

	// Extract the important bits, and generate a well-formed URL from that
	// (It's important that nothing we're doing is noticeable to the staff!)
	server = url.host();
	apiToken = query.queryItemValue("api_token");
	this->generateAPILinkURL();

	// Put it in the settings and force a sync
	QSettings settings;
	settings.setValue("server", server);
	settings.setValue("apiToken", apiToken);
	settings.sync();

	// If we're in-game and expected to reload the page, do so.
	// This is NOT true when called from loadAPILink(), and should
	// be true when called from the menu item.
	if(reload)
		this->loadBundledIndex();
}

void KVMainWindow::toggleTranslation(bool checked)
{
	KVTranslator::instance()->enabled = checked;

	QSettings settings;
	settings.setValue("translation", checked);
	settings.sync();

	if(checked)
		this->loadTranslation();

	this->loadBundledIndex();
}

void KVMainWindow::clearCache()
{
	cache->clear();
	this->loadBundledIndex();
}

void KVMainWindow::showAbout()
{
	QMessageBox::about(this, "About KCTViewer",
		QString(
			"
KCTViewer %1
"
		).arg(
			QCoreApplication::applicationVersion()
		)
	);
}

void KVMainWindow::onVersionCheckFinished()
{
	QNetworkReply *reply = qobject_cast<QNetworkReply*>(QObject::sender());

	// If the check failed, do nothing
	if(reply->error() != QNetworkReply::NoError)
		return;

	// Parse the version numbers
	QString newVersion = QString::fromUtf8(reply->readAll()).trimmed();
	QList<int> newVersionComponents;
	foreach(QString part, newVersion.split("."))
		newVersionComponents.append(part.toInt());

	QString appVersion = qApp->applicationVersion();
	QList<int> appVersionComponents;
	foreach(QString part, appVersion.split("."))
		appVersionComponents.append(part.toInt());

	// Compare component-per-component to see if we're outdated
	bool outdated = false;
	for(int i = 0; i < qMin(newVersionComponents.length(), appVersionComponents.length()); i++)
	{
		if(newVersionComponents[i] != appVersionComponents[i])
		{
			outdated = (newVersionComponents[i] > appVersionComponents[i]);
			break;
		}
	}

	// Display a message if we are
	if(outdated)
		QMessageBox::information(this, "New Version Available", "Version " + newVersion + " has been released, and is available at:
http://kancolletool.github.io/downloads/");
}

void KVMainWindow::onLoadStarted()
{
	qDebug() << "Loading Started...";
}

void KVMainWindow::onLoadFinished(bool ok)
{
	qDebug() << "Finished Loading!" << ok;
	if(ok) this->setHTMLAPILink();
}

void KVMainWindow::onTranslationLoadFailed(QString error)
{
	qDebug() << "Translation failed to load:" << error;
	loadingMessageBox->reject();
	delete loadingMessageBox;

	QMessageBox::StandardButton button;
	if(KVTranslator::instance()->loaded()) {
		button = QMessageBox::warning(this, "Couldn't load network translation", "This might mean that your connection is bad. However, a cached translation has been loaded. Would you like to retry loading the translation from the network?", QMessageBox::Retry|QMessageBox::Ok, QMessageBox::Ok);
	} else {
		button = QMessageBox::warning(this, "Couldn't load translation", "This might mean that your connection is bad. You can continue without translation, but the game will be in Japanese.", QMessageBox::Retry|QMessageBox::Ok, QMessageBox::Ok);

		// Disable translation if they want it
		if(button != QMessageBox::Retry)
			KVTranslator::instance()->enabled = false;
	}

	// To retry, just send the request again.
	if(button == QMessageBox::Retry)
		this->loadTranslation();
}

void KVMainWindow::setHTMLAPILink()
{
	qDebug() << "Updating web view credentials to" << server << "-" << apiToken;
	webView->page()->mainFrame()->evaluateJavaScript(QString("setCredentials(\"%1\", \"%2\"); null").arg(server, apiToken));
}

/*void KVMainWindow::onAPIError(KVProxyServer::APIStatus error)
{
	qDebug() << error;

	QString readableError;

	switch(error)
	{
		case KVProxyServer::OK:
			readableError = "No Error, you shouldn't be seeing this.";
			break;
		case KVProxyServer::Unauthorized:
			readableError = "Either your API Link is invalid, or it has expired. That happens sometimes.";
			break;
		case KVProxyServer::InvalidAPIVersion:
		case KVProxyServer::MissingParameters:
			readableError = "The game was updated, but you have an old client.";
			break;
		default:
			readableError = "An unknown error occurred. Please tell the developers that this happened ALONG WITH THE ERROR CODE, and what you think caused it.";
	}

	QMessageBox::critical(this, QString("Errorcat (Code %1)").arg((int)error), readableError);
}*/
<|endoftext|>