<commit_before>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: uicategorydescription.hxx,v $
 *
 *  $Revision: 1.4 $
 *
 *  last change: $Author: rt $ $Date: 2005-09-09 00:40:51 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

#ifndef __FRAMEWORK_UIELEMENT_UICOMMANDCATEGORY_HXX_
#define __FRAMEWORK_UIELEMENT_UICOMMANDCATEGORY_HXX_

/** Attention: stl headers must(!) be included at first. Otherwhise it can make trouble
               with solaris headers ...
*/
#include <vector>
#include <list>
#include <hash_map>

//_________________________________________________________________________________________________________________
//  my own includes
//_________________________________________________________________________________________________________________

#ifndef __FRAMEWORK_THREADHELP_THREADHELPBASE_HXX_
#include <threadhelp/threadhelpbase.hxx>
#endif

#ifndef __FRAMEWORK_MACROS_GENERIC_HXX_
#include <macros/generic.hxx>
#endif

#ifndef __FRAMEWORK_MACROS_XINTERFACE_HXX_
#include <macros/xinterface.hxx>
#endif

#ifndef __FRAMEWORK_MACROS_XTYPEPROVIDER_HXX_
#include <macros/xtypeprovider.hxx>
#endif

#ifndef __FRAMEWORK_MACROS_XSERVICEINFO_HXX_
#include <macros/xserviceinfo.hxx>
#endif

#ifndef __FRAMEWORK_STDTYPES_H_
#include <stdtypes.h>
#endif

//_________________________________________________________________________________________________________________
//  interface includes
//_________________________________________________________________________________________________________________

#ifndef _COM_SUN_STAR_LANG_XSERVICEINFO_HPP_
#include <com/sun/star/lang/XServiceInfo.hpp>
#endif

#ifndef _COM_SUN_STAR_LANG_XTYPEPROVIDER_HPP_
#include <com/sun/star/lang/XTypeProvider.hpp>
#endif

#ifndef _COM_SUN_STAR_CONTAINER_XNAMEACCESS_HPP_
#include <com/sun/star/container/XNameAccess.hpp>
#endif

#ifndef _COM_SUN_STAR_FRAME_XMODULEMANAGER_HPP_
#include <com/sun/star/frame/XModuleManager.hpp>
#endif

//_________________________________________________________________________________________________________________
//  other includes
//_________________________________________________________________________________________________________________

#ifndef _CPPUHELPER_WEAK_HXX_
#include <cppuhelper/weak.hxx>
#endif

#ifndef _RTL_USTRING_HXX_
#include <rtl/ustring.hxx>
#endif

namespace framework
{

class ConfigurationAccess_UICategory;
class UICategoryDescription :  public com::sun::star::lang::XTypeProvider    ,
                               public com::sun::star::lang::XServiceInfo     ,
                               public com::sun::star::container::XNameAccess ,
                               private ThreadHelpBase                        ,  // Struct for right initalization of mutex member! Must be first of baseclasses.
                               public ::cppu::OWeakObject
{
    public:
        UICategoryDescription( const ::com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory >& xServiceManager );
        virtual ~UICategoryDescription();

        //  XInterface, XTypeProvider, XServiceInfo
        DECLARE_XINTERFACE
        DECLARE_XTYPEPROVIDER
        DECLARE_XSERVICEINFO

        // XNameAccess
        virtual ::com::sun::star::uno::Any SAL_CALL getByName( const ::rtl::OUString& aName )
            throw ( ::com::sun::star::container::NoSuchElementException, ::com::sun::star::lang::WrappedTargetException, ::com::sun::star::uno::RuntimeException);

        virtual ::com::sun::star::uno::Sequence< ::rtl::OUString > SAL_CALL getElementNames()
            throw (::com::sun::star::uno::RuntimeException);

        virtual sal_Bool SAL_CALL hasByName( const ::rtl::OUString& aName )
            throw (::com::sun::star::uno::RuntimeException);

        // XElementAccess
        virtual ::com::sun::star::uno::Type SAL_CALL getElementType()
            throw (::com::sun::star::uno::RuntimeException);
        virtual sal_Bool SAL_CALL hasElements()
            throw (::com::sun::star::uno::RuntimeException);

        typedef ::std::hash_map< ::rtl::OUString,
                                 ::rtl::OUString,
                                 OUStringHashCode,
                                 ::std::equal_to< ::rtl::OUString > > ModuleToCategoryFileMap;

        typedef ::std::hash_map< ::rtl::OUString,
                                 ::com::sun::star::uno::Reference< ::com::sun::star::container::XNameAccess >,
                                 OUStringHashCode,
                                 ::std::equal_to< ::rtl::OUString > > CategoryHashMap;

    private:
        sal_Bool                                                                            m_bConfigRead;
        ::com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory >    m_xServiceManager;
        ModuleToCategoryFileMap                                                             m_aModuleToCategoryFileMap;
        CategoryHashMap                                                                     m_aCategoryHashMap;
        ::com::sun::star::uno::Reference< ::com::sun::star::container::XNameAccess >        m_xGenericCategories;
        ::com::sun::star::uno::Reference< ::com::sun::star::frame::XModuleManager > m_xModuleManager;
};

} // namespace framework

#endif // __FRAMEWORK_SERVICES_UICOMMANDCATEGORY_HXX_
<commit_msg>INTEGRATION: CWS warnings01 (1.4.32); FILE MERGED 2005/10/28 14:48:20 cd 1.4.32.1: #i55991# Warning free code changes for gcc<commit_after>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: uicategorydescription.hxx,v $
 *
 *  $Revision: 1.5 $
 *
 *  last change: $Author: hr $ $Date: 2006-06-19 11:03:32 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

#ifndef __FRAMEWORK_UIELEMENT_UICOMMANDCATEGORY_HXX_
#define __FRAMEWORK_UIELEMENT_UICOMMANDCATEGORY_HXX_

/** Attention: stl headers must(!) be included at first. Otherwhise it can make trouble
               with solaris headers ...
*/
#include <vector>
#include <list>
#include <hash_map>

//_________________________________________________________________________________________________________________
//  my own includes
//_________________________________________________________________________________________________________________

#ifndef __FRAMEWORK_THREADHELP_THREADHELPBASE_HXX_
#include <threadhelp/threadhelpbase.hxx>
#endif

#ifndef __FRAMEWORK_MACROS_GENERIC_HXX_
#include <macros/generic.hxx>
#endif

#ifndef __FRAMEWORK_MACROS_XINTERFACE_HXX_
#include <macros/xinterface.hxx>
#endif

#ifndef __FRAMEWORK_MACROS_XTYPEPROVIDER_HXX_
#include <macros/xtypeprovider.hxx>
#endif

#ifndef __FRAMEWORK_MACROS_XSERVICEINFO_HXX_
#include <macros/xserviceinfo.hxx>
#endif

#ifndef __FRAMEWORK_STDTYPES_H_
#include <stdtypes.h>
#endif

//_________________________________________________________________________________________________________________
//  interface includes
//_________________________________________________________________________________________________________________

#ifndef _COM_SUN_STAR_LANG_XSERVICEINFO_HPP_
#include <com/sun/star/lang/XServiceInfo.hpp>
#endif

#ifndef _COM_SUN_STAR_LANG_XTYPEPROVIDER_HPP_
#include <com/sun/star/lang/XTypeProvider.hpp>
#endif

#ifndef _COM_SUN_STAR_CONTAINER_XNAMEACCESS_HPP_
#include <com/sun/star/container/XNameAccess.hpp>
#endif

#ifndef _COM_SUN_STAR_FRAME_XMODULEMANAGER_HPP_
#include <com/sun/star/frame/XModuleManager.hpp>
#endif

//_________________________________________________________________________________________________________________
//  other includes
//_________________________________________________________________________________________________________________

#ifndef _CPPUHELPER_WEAK_HXX_
#include <cppuhelper/weak.hxx>
#endif

#ifndef _RTL_USTRING_HXX_
#include <rtl/ustring.hxx>
#endif

namespace framework
{

class ConfigurationAccess_UICategory;
class UICategoryDescription :  public com::sun::star::lang::XTypeProvider    ,
                               public com::sun::star::lang::XServiceInfo     ,
                               public com::sun::star::container::XNameAccess ,
                               private ThreadHelpBase                        ,  // Struct for right initalization of mutex member! Must be first of baseclasses.
                               public ::cppu::OWeakObject
{
    public:
        UICategoryDescription( const ::com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory >& xServiceManager );
        virtual ~UICategoryDescription();

        //  XInterface, XTypeProvider, XServiceInfo
        FWK_DECLARE_XINTERFACE
        FWK_DECLARE_XTYPEPROVIDER
        DECLARE_XSERVICEINFO

        // XNameAccess
        virtual ::com::sun::star::uno::Any SAL_CALL getByName( const ::rtl::OUString& aName )
            throw ( ::com::sun::star::container::NoSuchElementException, ::com::sun::star::lang::WrappedTargetException, ::com::sun::star::uno::RuntimeException);

        virtual ::com::sun::star::uno::Sequence< ::rtl::OUString > SAL_CALL getElementNames()
            throw (::com::sun::star::uno::RuntimeException);

        virtual sal_Bool SAL_CALL hasByName( const ::rtl::OUString& aName )
            throw (::com::sun::star::uno::RuntimeException);

        // XElementAccess
        virtual ::com::sun::star::uno::Type SAL_CALL getElementType()
            throw (::com::sun::star::uno::RuntimeException);
        virtual sal_Bool SAL_CALL hasElements()
            throw (::com::sun::star::uno::RuntimeException);

        typedef ::std::hash_map< ::rtl::OUString,
                                 ::rtl::OUString,
                                 OUStringHashCode,
                                 ::std::equal_to< ::rtl::OUString > > ModuleToCategoryFileMap;

        typedef ::std::hash_map< ::rtl::OUString,
                                 ::com::sun::star::uno::Reference< ::com::sun::star::container::XNameAccess >,
                                 OUStringHashCode,
                                 ::std::equal_to< ::rtl::OUString > > CategoryHashMap;

    private:
        sal_Bool                                                                            m_bConfigRead;
        ::com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory >    m_xServiceManager;
        ModuleToCategoryFileMap                                                             m_aModuleToCategoryFileMap;
        CategoryHashMap                                                                     m_aCategoryHashMap;
        ::com::sun::star::uno::Reference< ::com::sun::star::container::XNameAccess >        m_xGenericCategories;
        ::com::sun::star::uno::Reference< ::com::sun::star::frame::XModuleManager > m_xModuleManager;
};

} // namespace framework

#endif // __FRAMEWORK_SERVICES_UICOMMANDCATEGORY_HXX_
<|endoftext|>


<commit_before>
// Copyright (c) 2012, 2013 Lionel MOISAN.
// Copyright (c) 2012, 2013 Pascal MONASSE.
// Copyright (c) 2012, 2013 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/.

#ifndef OPENMVG_ROBUST_ESTIMATOR_ACRANSAC_H_
#define OPENMVG_ROBUST_ESTIMATOR_ACRANSAC_H_

//-------------------
// Generic implementation of ACRANSAC
//-------------------
// The A contrario parametrization have been first explained in [1] and
//  later extended to generic model estimation in [2] (with a demonstration for
//  the homography) and extended and use at large scale for Structure from
//  Motion in [3].
//
//--
//  [1] Lionel Moisan, Berenger Stival,
//  A probalistic criterion to detect rigid point matches between
//  two images and estimate the fundamental matrix.
//  IJCV 04.
//--
//  [2] Lionel Moisan, Pierre Moulon, Pascal Monasse.
//  Automatic Homographic Registration of a Pair of Images,
//    with A Contrario Elimination of Outliers
//  Image Processing On Line (IPOL), 2012.
//  http://dx.doi.org/10.5201/ipol.2012.mmm-oh
//--
//  [3] Pierre Moulon, Pascal Monasse and Renaud Marlet.
//  Adaptive Structure from Motion with a contrario mode estimation.
//  In 11th Asian Conference on Computer Vision (ACCV 2012)
//--

#include <algorithm>
#include <cmath>
#include <iostream>
#include <iterator>
#include <limits>
#include <numeric>
#include <vector>

#include "openMVG/robust_estimation/rand_sampling.hpp"

namespace openMVG {
namespace robust{

/// logarithm (base 10) of binomial coefficient
template <typename T>
static T logcombi
(
  size_t k,
  size_t n,
  const std::vector<T> & vec_log10 // lookuptable in [0,n+1]
)
{
  if (k>=n || k<=0) return(0.0f);
  if (n-k<k) k=n-k;
  T r = 0.0f;
  for (size_t i = 1; i <= k; ++i)
    r += vec_log10[n-i+1] - vec_log10[i];
  return r;
}

/// tabulate logcombi(.,n)
template<typename Type>
static void makelogcombi_n
(
  size_t n,
  std::vector<Type> & l,
  std::vector<Type> & vec_log10 // lookuptable [0,n+1]
)
{
  l.resize(n+1);
  for (size_t k = 0; k <= n; ++k)
    l[k] = logcombi<Type>(k, n, vec_log10);
}

/// tabulate logcombi(k,.)
template<typename Type>
static void makelogcombi_k
(
  size_t k,
  size_t nmax,
  std::vector<Type> & l,
  std::vector<Type> & vec_log10 // lookuptable [0,n+1]
)
{
  l.resize(nmax+1);
  for (size_t n = 0; n <= nmax; ++n)
    l[n] = logcombi<Type>(k, n, vec_log10);
}

template <typename Type>
static void makelogcombi
(
  size_t k,
  size_t n,
  std::vector<Type> & vec_logc_k,
  std::vector<Type> & vec_logc_n)
{
  // compute a lookuptable of log10 value for the range [0,n+1]
  std::vector<Type> vec_log10(n + 1);
  for (size_t k = 0; k <= n; ++k)
    vec_log10[k] = log10((Type)k);

  makelogcombi_n(n, vec_logc_n, vec_log10);
  makelogcombi_k(k, n, vec_logc_k, vec_log10);
}

/// NFA and associated index
typedef std::pair<double,size_t> ErrorIndex;

/// Find best NFA and its index wrt square error threshold in e.
static ErrorIndex bestNFA(
  int startIndex, //number of point required for estimation
  double logalpha0,
  const std::vector<ErrorIndex>& e,
  double loge0,
  double maxThreshold,
  const std::vector<float> &logc_n,
  const std::vector<float> &logc_k,
  double multError = 1.0)
{
  ErrorIndex bestIndex(std::numeric_limits<double>::infinity(), startIndex);
  const size_t n = e.size();
  for(size_t k = startIndex + 1; k <= n && e[k - 1].first <= maxThreshold; ++k)
  {
    const double logalpha = logalpha0 +
      multError * log10(e[k - 1].first + std::numeric_limits<float>::epsilon());
    ErrorIndex index(loge0 +
                     logalpha * (double) (k - startIndex) +
                     logc_n[k] +
                     logc_k[k], k);

    if(index.first < bestIndex.first)
      bestIndex = index;
  }
  return bestIndex;
}

/// Pick a random sample
/// \param sizeSample The size of the sample.
/// \param vec_index  The possible data indices.
/// \param sample The random sample of sizeSample indices (output).
static void UniformSample(int sizeSample,
  const std::vector<size_t> &vec_index,
  std::vector<size_t> *sample)
{
  sample->resize(sizeSample);
  random_sample(sizeSample, vec_index.size(), sample);
  for(int i = 0; i < sizeSample; ++i)
    (*sample)[i] = vec_index[ (*sample)[i] ];
}

/**
 * @brief ACRANSAC routine (ErrorThreshold, NFA)
 *
 * @param[in] kernel model and metric object
 * @param[out] vec_inliers points that fit the estimated model
 * @param[in] nIter maximum number of consecutive iterations
 * @param[out] model returned model if found
 * @param[in] precision upper bound of the precision (squared error)
 * @param[in] bVerbose display console log
 *
 * @return (errorMax, minNFA)
 */
template<typename Kernel>
std::pair<double, double> ACRANSAC(const Kernel &kernel,
  std::vector<size_t> & vec_inliers,
  size_t nIter = 1024,
  typename Kernel::Model * model = NULL,
  double precision = std::numeric_limits<double>::infinity(),
  bool bVerbose = false)
{
  vec_inliers.clear();

  const size_t sizeSample = Kernel::MINIMUM_SAMPLES;
  const size_t nData = kernel.NumSamples();
  if (nData <= (size_t)sizeSample)
    return std::make_pair(0.0,0.0);

  const double maxThreshold = (precision==std::numeric_limits<double>::infinity()) ?
    std::numeric_limits<double>::infinity() :
    precision * kernel.normalizer2()(0,0) * kernel.normalizer2()(0,0);

  std::vector<ErrorIndex> vec_residuals(nData); // [residual,index]
  std::vector<double> vec_residuals_(nData);
  std::vector<size_t> vec_sample(sizeSample); // Sample indices

  // Possible sampling indices [0,..,nData] (will change in the optimization phase)
  std::vector<size_t> vec_index(nData);
  std::iota(vec_index.begin(), vec_index.end(), 0);

  // Precompute log combi
  const double loge0 = log10((double)Kernel::MAX_MODELS * (nData-sizeSample));
  std::vector<float> vec_logc_n, vec_logc_k;
  makelogcombi(sizeSample, nData, vec_logc_k, vec_logc_n);

  // Output parameters
  double minNFA = std::numeric_limits<double>::infinity();
  double errorMax = std::numeric_limits<double>::infinity();

  // Reserve 10% of iterations for focused sampling
  size_t nIterReserve = nIter/10;
  nIter -= nIterReserve;

  bool bACRansacMode = (precision == std::numeric_limits<double>::infinity());

  // Main estimation loop.
  for (size_t iter=0; iter < nIter; ++iter)
  {
    if (bACRansacMode)
      UniformSample(sizeSample, vec_index, &vec_sample); // Get random sample
    else
      UniformSample(sizeSample, nData, &vec_sample); // Get random sample

    std::vector<typename Kernel::Model> vec_models; // Up to max_models solutions
    kernel.Fit(vec_sample, &vec_models);

    // Evaluate models
    bool better = false;
    for (size_t k = 0; k < vec_models.size(); ++k)
    {
      // Residuals computation and ordering
      kernel.Errors(vec_models[k], vec_residuals_);

      if (!bACRansacMode)
      {
        unsigned int nInlier = 0;
        for (size_t i = 0; i < nData; ++i)
        {
          if (vec_residuals_[i] <= maxThreshold)
            ++nInlier;
        }
        if (nInlier > 2.5 * sizeSample) // does the model is meaningful
          bACRansacMode = true;
        if (!bACRansacMode && nIter > nIterReserve)
          nIter = 0;
      }
      if (bACRansacMode)
      {
        for (size_t i = 0; i < nData; ++i)  {
          const double error = vec_residuals_[i];
          vec_residuals[i] = ErrorIndex(error, i);
        }
        std::sort(vec_residuals.begin(), vec_residuals.end());

        // Most meaningful discrimination inliers/outliers
        const ErrorIndex best = bestNFA(
          sizeSample,
          kernel.logalpha0(),
          vec_residuals,
          loge0,
          maxThreshold,
          vec_logc_n,
          vec_logc_k,
          kernel.multError());

        if (best.first < minNFA /*&& vec_residuals[best.second-1].first < errorMax*/)  {
          // A better model was found
          better = true;
          minNFA = best.first;
          vec_inliers.resize(best.second);
          for (size_t i=0; i<best.second; ++i)
            vec_inliers[i] = vec_residuals[i].second;
          errorMax = vec_residuals[best.second-1].first; // Error threshold
          if(model) *model = vec_models[k];

          if(bVerbose)  {
            std::cout << "  nfa=" << minNFA
              << " inliers=" << best.second << "/" << nData
              << " precisionNormalized=" << errorMax
              << " precision=" << kernel.unormalizeError(errorMax)
              << " (iter=" << iter;
            std::cout << ",sample=";
            std::copy(vec_sample.begin(), vec_sample.end(),
              std::ostream_iterator<size_t>(std::cout, ","));
            std::cout << ")" <<std::endl;
          }
        }
      }
    }

    // ACRANSAC optimization: draw samples among best set of inliers so far
    if (bACRansacMode && ((better && minNFA<0) || (iter+1==nIter && nIterReserve)))
    {
      if (vec_inliers.empty())
      {
        // No model found at all so far
        ++nIter; // Continue to look for any model, even not meaningful
        --nIterReserve;
      }
      else
      {
        // ACRANSAC optimization: draw samples among best set of inliers so far
        vec_index = vec_inliers;
        if(nIterReserve)
        {
            nIter = iter + 1 + nIterReserve;
            nIterReserve = 0;
        }
      }
    }
  }

  if(minNFA >= 0)
    vec_inliers.clear();

  if (!vec_inliers.empty())
  {
    if (model)
      kernel.Unnormalize(model);
    errorMax = kernel.unormalizeError(errorMax);
  }

  return std::make_pair(errorMax, minNFA);
}

} // namespace robust
} // namespace openMVG
#endif // OPENMVG_ROBUST_ESTIMATOR_ACRANSAC_H_
<commit_msg>[robust_estimation] bugfix for acransac<commit_after>
// Copyright (c) 2012, 2013 Lionel MOISAN.
// Copyright (c) 2012, 2013 Pascal MONASSE.
// Copyright (c) 2012, 2013 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/.

#ifndef OPENMVG_ROBUST_ESTIMATOR_ACRANSAC_H_
#define OPENMVG_ROBUST_ESTIMATOR_ACRANSAC_H_

//-------------------
// Generic implementation of ACRANSAC
//-------------------
// The A contrario parametrization have been first explained in [1] and
//  later extended to generic model estimation in [2] (with a demonstration for
//  the homography) and extended and use at large scale for Structure from
//  Motion in [3].
//
//--
//  [1] Lionel Moisan, Berenger Stival,
//  A probalistic criterion to detect rigid point matches between
//  two images and estimate the fundamental matrix.
//  IJCV 04.
//--
//  [2] Lionel Moisan, Pierre Moulon, Pascal Monasse.
//  Automatic Homographic Registration of a Pair of Images,
//    with A Contrario Elimination of Outliers
//  Image Processing On Line (IPOL), 2012.
//  http://dx.doi.org/10.5201/ipol.2012.mmm-oh
//--
//  [3] Pierre Moulon, Pascal Monasse and Renaud Marlet.
//  Adaptive Structure from Motion with a contrario mode estimation.
//  In 11th Asian Conference on Computer Vision (ACCV 2012)
//--

#include <algorithm>
#include <cmath>
#include <iostream>
#include <iterator>
#include <limits>
#include <numeric>
#include <vector>

#include "openMVG/robust_estimation/rand_sampling.hpp"

namespace openMVG {
namespace robust{

/// logarithm (base 10) of binomial coefficient
template <typename T>
static T logcombi
(
  size_t k,
  size_t n,
  const std::vector<T> & vec_log10 // lookuptable in [0,n+1]
)
{
  if (k>=n || k<=0) return(0.0f);
  if (n-k<k) k=n-k;
  T r = 0.0f;
  for (size_t i = 1; i <= k; ++i)
    r += vec_log10[n-i+1] - vec_log10[i];
  return r;
}

/// tabulate logcombi(.,n)
template<typename Type>
static void makelogcombi_n
(
  size_t n,
  std::vector<Type> & l,
  std::vector<Type> & vec_log10 // lookuptable [0,n+1]
)
{
  l.resize(n+1);
  for (size_t k = 0; k <= n; ++k)
    l[k] = logcombi<Type>(k, n, vec_log10);
}

/// tabulate logcombi(k,.)
template<typename Type>
static void makelogcombi_k
(
  size_t k,
  size_t nmax,
  std::vector<Type> & l,
  std::vector<Type> & vec_log10 // lookuptable [0,n+1]
)
{
  l.resize(nmax+1);
  for (size_t n = 0; n <= nmax; ++n)
    l[n] = logcombi<Type>(k, n, vec_log10);
}

template <typename Type>
static void makelogcombi
(
  size_t k,
  size_t n,
  std::vector<Type> & vec_logc_k,
  std::vector<Type> & vec_logc_n)
{
  // compute a lookuptable of log10 value for the range [0,n+1]
  std::vector<Type> vec_log10(n + 1);
  for (size_t k = 0; k <= n; ++k)
    vec_log10[k] = log10((Type)k);

  makelogcombi_n(n, vec_logc_n, vec_log10);
  makelogcombi_k(k, n, vec_logc_k, vec_log10);
}

/// NFA and associated index
typedef std::pair<double,size_t> ErrorIndex;

/// Find best NFA and its index wrt square error threshold in e.
static ErrorIndex bestNFA(
  int startIndex, //number of point required for estimation
  double logalpha0,
  const std::vector<ErrorIndex>& e,
  double loge0,
  double maxThreshold,
  const std::vector<float> &logc_n,
  const std::vector<float> &logc_k,
  double multError = 1.0)
{
  ErrorIndex bestIndex(std::numeric_limits<double>::infinity(), startIndex);
  const size_t n = e.size();
  for(size_t k = startIndex + 1; k <= n && e[k - 1].first <= maxThreshold; ++k)
  {
    const double logalpha = logalpha0 +
      multError * log10(e[k - 1].first + std::numeric_limits<float>::epsilon());
    ErrorIndex index(loge0 +
                     logalpha * (double) (k - startIndex) +
                     logc_n[k] +
                     logc_k[k], k);

    if(index.first < bestIndex.first)
      bestIndex = index;
  }
  return bestIndex;
}

/// Pick a random sample
/// \param sizeSample The size of the sample.
/// \param vec_index  The possible data indices.
/// \param sample The random sample of sizeSample indices (output).
static void UniformSample(int sizeSample,
  const std::vector<size_t> &vec_index,
  std::vector<size_t> *sample)
{
  sample->resize(sizeSample);
  random_sample(sizeSample, vec_index.size(), sample);
  for(int i = 0; i < sizeSample; ++i)
    (*sample)[i] = vec_index[ (*sample)[i] ];
}

/**
 * @brief ACRANSAC routine (ErrorThreshold, NFA)
 *
 * @param[in] kernel model and metric object
 * @param[out] vec_inliers points that fit the estimated model
 * @param[in] nIter maximum number of consecutive iterations
 * @param[out] model returned model if found
 * @param[in] precision upper bound of the precision (squared error)
 * @param[in] bVerbose display console log
 *
 * @return (errorMax, minNFA)
 */
template<typename Kernel>
std::pair<double, double> ACRANSAC(const Kernel &kernel,
  std::vector<size_t> & vec_inliers,
  size_t nIter = 1024,
  typename Kernel::Model * model = NULL,
  double precision = std::numeric_limits<double>::infinity(),
  bool bVerbose = false)
{
  vec_inliers.clear();

  const size_t sizeSample = Kernel::MINIMUM_SAMPLES;
  const size_t nData = kernel.NumSamples();
  if (nData <= (size_t)sizeSample)
    return std::make_pair(0.0,0.0);

  const double maxThreshold = (precision==std::numeric_limits<double>::infinity()) ?
    std::numeric_limits<double>::infinity() :
    precision * kernel.normalizer2()(0,0) * kernel.normalizer2()(0,0);

  std::vector<ErrorIndex> vec_residuals(nData); // [residual,index]
  std::vector<double> vec_residuals_(nData);
  std::vector<size_t> vec_sample(sizeSample); // Sample indices

  // Possible sampling indices [0,..,nData] (will change in the optimization phase)
  std::vector<size_t> vec_index(nData);
  std::iota(vec_index.begin(), vec_index.end(), 0);

  // Precompute log combi
  const double loge0 = log10((double)Kernel::MAX_MODELS * (nData-sizeSample));
  std::vector<float> vec_logc_n, vec_logc_k;
  makelogcombi(sizeSample, nData, vec_logc_k, vec_logc_n);

  // Output parameters
  double minNFA = std::numeric_limits<double>::infinity();
  double errorMax = std::numeric_limits<double>::infinity();

  // Reserve 10% of iterations for focused sampling
  size_t nIterReserve = nIter/10;
  nIter -= nIterReserve;

  bool bACRansacMode = (precision == std::numeric_limits<double>::infinity());

  // Main estimation loop.
  for (size_t iter=0; iter < nIter; ++iter)
  {
    if (bACRansacMode)
      UniformSample(sizeSample, vec_index, &vec_sample); // Get random sample
    else
      UniformSample(sizeSample, nData, &vec_sample); // Get random sample

    std::vector<typename Kernel::Model> vec_models; // Up to max_models solutions
    kernel.Fit(vec_sample, &vec_models);

    // Evaluate models
    bool better = false;
    for (size_t k = 0; k < vec_models.size(); ++k)
    {
      // Residuals computation and ordering
      kernel.Errors(vec_models[k], vec_residuals_);

      if (!bACRansacMode)
      {
        unsigned int nInlier = 0;
        for (size_t i = 0; i < nData; ++i)
        {
          if (vec_residuals_[i] <= maxThreshold)
            ++nInlier;
        }
        if (nInlier > 2.5 * sizeSample) // does the model is meaningful
          bACRansacMode = true;
      }
      if (bACRansacMode)
      {
        for (size_t i = 0; i < nData; ++i)  {
          const double error = vec_residuals_[i];
          vec_residuals[i] = ErrorIndex(error, i);
        }
        std::sort(vec_residuals.begin(), vec_residuals.end());

        // Most meaningful discrimination inliers/outliers
        const ErrorIndex best = bestNFA(
          sizeSample,
          kernel.logalpha0(),
          vec_residuals,
          loge0,
          maxThreshold,
          vec_logc_n,
          vec_logc_k,
          kernel.multError());

        if (best.first < minNFA /*&& vec_residuals[best.second-1].first < errorMax*/)  {
          // A better model was found
          better = true;
          minNFA = best.first;
          vec_inliers.resize(best.second);
          for (size_t i=0; i<best.second; ++i)
            vec_inliers[i] = vec_residuals[i].second;
          errorMax = vec_residuals[best.second-1].first; // Error threshold
          if(model) *model = vec_models[k];

          if(bVerbose)  {
            std::cout << "  nfa=" << minNFA
              << " inliers=" << best.second << "/" << nData
              << " precisionNormalized=" << errorMax
              << " precision=" << kernel.unormalizeError(errorMax)
              << " (iter=" << iter;
            std::cout << ",sample=";
            std::copy(vec_sample.begin(), vec_sample.end(),
              std::ostream_iterator<size_t>(std::cout, ","));
            std::cout << ")" <<std::endl;
          }
        }
      } //if(bACRansacMode)
    } //for(size_t k...

    // Early exit test -> no meaningful model found after nIterReserve*2 iterations
    if (!bACRansacMode && iter > nIterReserve*2)
      break;

    // ACRANSAC optimization: draw samples among best set of inliers so far
    if (bACRansacMode && ((better && minNFA<0) || (iter+1==nIter && nIterReserve)))
    {
      if (vec_inliers.empty())
      {
        // No model found at all so far
        ++nIter; // Continue to look for any model, even not meaningful
        --nIterReserve;
      }
      else
      {
        // ACRANSAC optimization: draw samples among best set of inliers so far
        vec_index = vec_inliers;
        if(nIterReserve)
        {
            nIter = iter + 1 + nIterReserve;
            nIterReserve = 0;
        }
      }
    }
  }

  if(minNFA >= 0)
    vec_inliers.clear();

  if (!vec_inliers.empty())
  {
    if (model)
      kernel.Unnormalize(model);
    errorMax = kernel.unormalizeError(errorMax);
  }

  return std::make_pair(errorMax, minNFA);
}

} // namespace robust
} // namespace openMVG
#endif // OPENMVG_ROBUST_ESTIMATOR_ACRANSAC_H_
<|endoftext|>


<commit_before>/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia.  For licensing terms and
** conditions see http://qt.digia.com/licensing.  For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights.  These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/

#include "pythonhighlighterfactory.h"
#include "pythoneditorconstants.h"
#include "tools/pythonhighlighter.h"

using namespace PythonEditor::Internal;

PythonHighlighterFactory::PythonHighlighterFactory()
{
    setId(Constants::C_PYTHONEDITOR_ID);
    addMimeType(QLatin1String(Constants::C_PY_MIMETYPE));
}

TextEditor::SyntaxHighlighter *PythonHighlighterFactory::createHighlighter() const
{
    return new PythonHighlighter;
}
<commit_msg>Compile fix<commit_after>/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia.  For licensing terms and
** conditions see http://qt.digia.com/licensing.  For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights.  These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/

#include "pythonhighlighterfactory.h"
#include "../pythoneditorconstants.h"
#include "pythonhighlighter.h"

using namespace PythonEditor::Internal;

PythonHighlighterFactory::PythonHighlighterFactory()
{
    setId(Constants::C_PYTHONEDITOR_ID);
    addMimeType(QLatin1String(Constants::C_PY_MIMETYPE));
}

TextEditor::SyntaxHighlighter *PythonHighlighterFactory::createHighlighter() const
{
    return new PythonHighlighter;
}
<|endoftext|>


<commit_before>/*
 * Originally written by Xinef - Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license: http://github.com/azerothcore/azerothcore-wotlk/LICENSE-AGPL
*/

#include "ScriptMgr.h"
#include "ScriptedCreature.h"
#include "ahnkahet.h"

enum Spells
{
    SPELL_BASH                              = 57094,
    SPELL_ENTANGLING_ROOTS                  = 57095,
    SPELL_MINI                              = 57055,
    SPELL_VENOM_BOLT_VOLLEY                 = 57088,
    SPELL_HEALTHY_MUSHROOM_POTENT_FUNGUS    = 56648,
    SPELL_POISONOUS_MUSHROOM_POISON_CLOUD   = 57061,
    SPELL_POISONOUS_MUSHROOM_VISUAL_AURA    = 56741,
    SPELL_HEALTHY_MUSHROOM_VISUAL_AURA      = 56740,
};

enum Creatures
{
    NPC_HEALTHY_MUSHROOM                    = 30391,
    NPC_POISONOUS_MUSHROOM                  = 30435
};

enum Events
{
    EVENT_AMANITAR_SPAWN                    = 1,
    EVENT_AMANITAR_ROOTS                    = 2,
    EVENT_AMANITAR_BASH                     = 3,
    EVENT_AMANITAR_BOLT                     = 4,
};

class boss_amanitar : public CreatureScript
{
public:
    boss_amanitar() : CreatureScript("boss_amanitar") { }

    struct boss_amanitarAI : public ScriptedAI
    {
        boss_amanitarAI(Creature *c) : ScriptedAI(c), summons(me)
        {
            pInstance = c->GetInstanceScript();
            me->ApplySpellImmune(0, IMMUNITY_SCHOOL, SPELL_SCHOOL_MASK_NATURE, true);
        }

        InstanceScript* pInstance;
        EventMap events;
        SummonList summons;

        void Reset()
        {
            events.Reset();
            summons.DespawnAll();
            me->SetMeleeDamageSchool(SPELL_SCHOOL_NATURE);

            if (pInstance)
            {
                pInstance->SetData(DATA_AMANITAR_EVENT, NOT_STARTED);
                pInstance->DoRemoveAurasDueToSpellOnPlayers(SPELL_MINI);
            }
        }

        void JustDied(Unit* /*Killer*/)
        {
            summons.DespawnAll();
            if (pInstance)
            {
                pInstance->SetData(DATA_AMANITAR_EVENT, DONE);
                pInstance->DoRemoveAurasDueToSpellOnPlayers(SPELL_MINI);
            }
        }

        void EnterCombat(Unit* /*who*/)
        {
            if (pInstance)
                pInstance->SetData(DATA_AMANITAR_EVENT, IN_PROGRESS);

            me->CastSpell(me, SPELL_MINI, false);

            events.ScheduleEvent(EVENT_AMANITAR_ROOTS, urand(5000, 9000));
            events.ScheduleEvent(EVENT_AMANITAR_BASH, urand(10000, 14000));
            events.ScheduleEvent(EVENT_AMANITAR_BOLT, urand(15000, 20000));
            events.ScheduleEvent(EVENT_AMANITAR_SPAWN, 0);
        }

        void JustSummoned(Creature *cr) { summons.Summon(cr); }

        void SpawnAdds()
        {
            summons.DespawnAll();
            Position center;
            center.Relocate(362.6f, -870, -75);

            for (uint8 i = 0; i < 25; ++i)
            {
                float orientation = 2*rand_norm()*M_PI;
                float x = center.GetPositionX() + i*2*cos(orientation);
                float y = center.GetPositionY() + i*2*sin(orientation);
                me->SummonCreature(NPC_POISONOUS_MUSHROOM, x, y, me->GetMap()->GetHeight(x, y, MAX_HEIGHT));
            }

            for (uint8 i = 0; i < 25; ++i)
            {
                float orientation = 2*rand_norm()*M_PI;
                float x = center.GetPositionX() + i*2*cos(orientation);
                float y = center.GetPositionY() + i*2*sin(orientation);
                me->SummonCreature(NPC_HEALTHY_MUSHROOM, x, y, me->GetMap()->GetHeight(x, y, MAX_HEIGHT));
            }
        }

        void UpdateAI(uint32 diff)
        {
            //Return since we have no target
            if (!UpdateVictim())
                return;

            events.Update(diff);
            if (me->HasUnitState(UNIT_STATE_CASTING))
                return;

            switch (events.GetEvent())
            {
                case EVENT_AMANITAR_SPAWN:
                {
                    SpawnAdds();
                    events.RepeatEvent(urand(35000, 40000));
                    break;
                }
                case EVENT_AMANITAR_ROOTS:
                {
                    if (Unit *pTarget = SelectTarget(SELECT_TARGET_RANDOM, 0, 100, true))
                        me->CastSpell(pTarget, SPELL_ENTANGLING_ROOTS, false);

                    events.RepeatEvent(urand(15000, 20000));
                    break;
                }
                case EVENT_AMANITAR_BASH:
                {
                    me->CastSpell(me->GetVictim(), SPELL_BASH, false);
                    events.RepeatEvent(urand(15000, 20000));
                    break;
                }
                case EVENT_AMANITAR_BOLT:
                {
                    if (Unit *pTarget = SelectTarget(SELECT_TARGET_RANDOM, 0, 100, true))
                        me->CastSpell(pTarget, SPELL_VENOM_BOLT_VOLLEY, false);

                    events.RepeatEvent(urand(15000, 20000));
                    break;
                }
            }

            DoMeleeAttackIfReady();
        }
    };

    CreatureAI *GetAI(Creature *creature) const
    {
        return new boss_amanitarAI(creature);
    }
};

class npc_amanitar_mushrooms : public CreatureScript
{
public:
    npc_amanitar_mushrooms() : CreatureScript("npc_amanitar_mushrooms") { }

    struct npc_amanitar_mushroomsAI : public ScriptedAI
    {
        npc_amanitar_mushroomsAI(Creature* c) : ScriptedAI(c)
        {
            SetCombatMovement(false);
        }

        uint32 Timer;
        void Reset()
        {
            me->CastSpell(me, 31690, true);

            Timer = 0;
            if (me->GetEntry() == NPC_POISONOUS_MUSHROOM)
            {
                me->CastSpell(me, SPELL_POISONOUS_MUSHROOM_VISUAL_AURA, true);
                me->CastSpell(me, SPELL_POISONOUS_MUSHROOM_POISON_CLOUD, false);
            }
            else
                me->CastSpell(me, SPELL_HEALTHY_MUSHROOM_VISUAL_AURA, true);
        }

        void JustDied(Unit* killer)
        {
            if (!killer)
                return;

            if (me->GetEntry() == NPC_HEALTHY_MUSHROOM)
                me->CastSpell(me, SPELL_HEALTHY_MUSHROOM_POTENT_FUNGUS, true);
        }

        void EnterCombat(Unit* /*who*/) {}
        void AttackStart(Unit* /*victim*/) {}

        void UpdateAI(uint32 diff)
        {
            if (me->GetEntry() == NPC_POISONOUS_MUSHROOM)
            {
                Timer += diff;
                if (Timer >= 7000)
                {
                    me->CastSpell(me, SPELL_POISONOUS_MUSHROOM_POISON_CLOUD, false);
                    Timer = 0;
                }
            }
        }
    };

    CreatureAI *GetAI(Creature *creature) const
    {
        return new npc_amanitar_mushroomsAI(creature);
    }
};

void AddSC_boss_amanitar()
{
    new boss_amanitar;
    new npc_amanitar_mushrooms;
}
<commit_msg>Update mushrooms<commit_after>/*
 * Originally written by Xinef - Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license: http://github.com/azerothcore/azerothcore-wotlk/LICENSE-AGPL
*/

#include "ScriptMgr.h"
#include "ScriptedCreature.h"
#include "ahnkahet.h"

enum Spells
{
    SPELL_BASH                              = 57094,
    SPELL_ENTANGLING_ROOTS                  = 57095,
    SPELL_MINI                              = 57055,
    SPELL_VENOM_BOLT_VOLLEY                 = 57088,
    SPELL_HEALTHY_MUSHROOM_POTENT_FUNGUS    = 56648,
    SPELL_POISONOUS_MUSHROOM_POISON_CLOUD   = 57061,
    SPELL_POISONOUS_MUSHROOM_VISUAL_AURA    = 56741,
    SPELL_HEALTHY_MUSHROOM_VISUAL_AURA      = 56740,
};

enum Creatures
{
    NPC_HEALTHY_MUSHROOM                    = 30391,
    NPC_POISONOUS_MUSHROOM                  = 30435
};

enum Events
{
    EVENT_AMANITAR_SPAWN                    = 1,
    EVENT_AMANITAR_ROOTS                    = 2,
    EVENT_AMANITAR_BASH                     = 3,
    EVENT_AMANITAR_BOLT                     = 4,
};

class boss_amanitar : public CreatureScript
{
public:
    boss_amanitar() : CreatureScript("boss_amanitar") { }

    struct boss_amanitarAI : public ScriptedAI
    {
        boss_amanitarAI(Creature *c) : ScriptedAI(c), summons(me)
        {
            pInstance = c->GetInstanceScript();
            me->ApplySpellImmune(0, IMMUNITY_SCHOOL, SPELL_SCHOOL_MASK_NATURE, true);
        }

        InstanceScript* pInstance;
        EventMap events;
        SummonList summons;

        void Reset()
        {
            events.Reset();
            summons.DespawnAll();
            me->SetMeleeDamageSchool(SPELL_SCHOOL_NATURE);

            if (pInstance)
            {
                pInstance->SetData(DATA_AMANITAR_EVENT, NOT_STARTED);
                pInstance->DoRemoveAurasDueToSpellOnPlayers(SPELL_MINI);
            }
        }

        void JustDied(Unit* /*Killer*/)
        {
            summons.DespawnAll();
            if (pInstance)
            {
                pInstance->SetData(DATA_AMANITAR_EVENT, DONE);
                pInstance->DoRemoveAurasDueToSpellOnPlayers(SPELL_MINI);
            }
        }

        void EnterCombat(Unit* /*who*/)
        {
            if (pInstance)
                pInstance->SetData(DATA_AMANITAR_EVENT, IN_PROGRESS);

            me->CastSpell(me, SPELL_MINI, false);

            events.ScheduleEvent(EVENT_AMANITAR_ROOTS, urand(5000, 9000));
            events.ScheduleEvent(EVENT_AMANITAR_BASH, urand(10000, 14000));
            events.ScheduleEvent(EVENT_AMANITAR_BOLT, urand(15000, 20000));
            events.ScheduleEvent(EVENT_AMANITAR_SPAWN, 0);
        }

        void JustSummoned(Creature *cr) { summons.Summon(cr); }

        void SpawnAdds()
        {
            summons.DespawnAll();
            Position center;
            center.Relocate(362.6f, -870, -75);

            for (uint8 i = 0; i < 25; ++i)
            {
                float orientation = 2*rand_norm()*M_PI;
                float x = center.GetPositionX() + i*2*cos(orientation);
                float y = center.GetPositionY() + i*2*sin(orientation);
                me->SummonCreature(NPC_POISONOUS_MUSHROOM, x, y, me->GetMap()->GetHeight(x, y, MAX_HEIGHT));
            }

            for (uint8 i = 0; i < 25; ++i)
            {
                float orientation = 2*rand_norm()*M_PI;
                float x = center.GetPositionX() + i*2*cos(orientation);
                float y = center.GetPositionY() + i*2*sin(orientation);
                me->SummonCreature(NPC_HEALTHY_MUSHROOM, x, y, me->GetMap()->GetHeight(x, y, MAX_HEIGHT));
            }
        }

        void UpdateAI(uint32 diff)
        {
            //Return since we have no target
            if (!UpdateVictim())
                return;

            events.Update(diff);
            if (me->HasUnitState(UNIT_STATE_CASTING))
                return;

            switch (events.GetEvent())
            {
                case EVENT_AMANITAR_SPAWN:
                {
                    SpawnAdds();
                    events.RepeatEvent(urand(35000, 40000));
                    break;
                }
                case EVENT_AMANITAR_ROOTS:
                {
                    if (Unit *pTarget = SelectTarget(SELECT_TARGET_RANDOM, 0, 100, true))
                        me->CastSpell(pTarget, SPELL_ENTANGLING_ROOTS, false);

                    events.RepeatEvent(urand(15000, 20000));
                    break;
                }
                case EVENT_AMANITAR_BASH:
                {
                    me->CastSpell(me->GetVictim(), SPELL_BASH, false);
                    events.RepeatEvent(urand(15000, 20000));
                    break;
                }
                case EVENT_AMANITAR_BOLT:
                {
                    if (Unit *pTarget = SelectTarget(SELECT_TARGET_RANDOM, 0, 100, true))
                        me->CastSpell(pTarget, SPELL_VENOM_BOLT_VOLLEY, false);

                    events.RepeatEvent(urand(15000, 20000));
                    break;
                }
            }

            DoMeleeAttackIfReady();
        }
    };

    CreatureAI *GetAI(Creature *creature) const
    {
        return new boss_amanitarAI(creature);
    }
};

class npc_amanitar_mushrooms : public CreatureScript
{
public:
    npc_amanitar_mushrooms() : CreatureScript("npc_amanitar_mushrooms") { }

    struct npc_amanitar_mushroomsAI : public ScriptedAI
    {
        npc_amanitar_mushroomsAI(Creature* c) : ScriptedAI(c)
        {
            SetCombatMovement(false);
            me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);
            me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE);
        }

        uint32 Timer;
        void Reset()
        {
            me->CastSpell(me, 31690, true);

            Timer = 0;
            if (me->GetEntry() == NPC_POISONOUS_MUSHROOM)
            {
                me->CastSpell(me, SPELL_POISONOUS_MUSHROOM_VISUAL_AURA, true);
                me->CastSpell(me, SPELL_POISONOUS_MUSHROOM_POISON_CLOUD, false);
            }
            else
                me->CastSpell(me, SPELL_HEALTHY_MUSHROOM_VISUAL_AURA, true);
        }

        void JustDied(Unit* killer)
        {
            if (!killer)
                return;

            if (me->GetEntry() == NPC_HEALTHY_MUSHROOM)
                me->CastSpell(me, SPELL_HEALTHY_MUSHROOM_POTENT_FUNGUS, true);
        }

        void EnterCombat(Unit* /*who*/) {}
        void AttackStart(Unit* /*victim*/) {}

        void UpdateAI(uint32 diff)
        {
            if (me->GetEntry() == NPC_POISONOUS_MUSHROOM)
            {
                Timer += diff;
                if (Timer >= 7000)
                {
                    me->CastSpell(me, SPELL_POISONOUS_MUSHROOM_POISON_CLOUD, false);
                    Timer = 0;
                }
            }
        }
    };

    CreatureAI *GetAI(Creature *creature) const
    {
        return new npc_amanitar_mushroomsAI(creature);
    }
};

void AddSC_boss_amanitar()
{
    new boss_amanitar;
    new npc_amanitar_mushrooms;
}
<|endoftext|>


<commit_before>// Copyright (c) 2014 GitHub, Inc.
// Use of this source code is governed by the MIT license that can be
// found in the LICENSE file.

#include <memory>
#include <string>

#include "base/callback.h"
#include "base/files/file_util.h"
#include "base/strings/string_util.h"
#include "base/threading/thread_restrictions.h"
#include "electron/electron_gtk_stubs.h"
#include "shell/browser/javascript_environment.h"
#include "shell/browser/native_window_views.h"
#include "shell/browser/ui/file_dialog.h"
#include "shell/browser/ui/gtk_util.h"
#include "shell/browser/unresponsive_suppressor.h"
#include "shell/common/gin_converters/file_path_converter.h"
#include "ui/base/glib/glib_signal.h"
#include "ui/gtk/gtk_ui.h"    // nogncheck
#include "ui/gtk/gtk_util.h"  // nogncheck

namespace file_dialog {

DialogSettings::DialogSettings() = default;
DialogSettings::DialogSettings(const DialogSettings&) = default;
DialogSettings::~DialogSettings() = default;

namespace {

static const int kPreviewWidth = 256;
static const int kPreviewHeight = 512;

std::string MakeCaseInsensitivePattern(const std::string& extension) {
  std::string pattern("*.");

  for (std::size_t i = 0, n = extension.size(); i < n; i++) {
    char ch = extension[i];
    if (!base::IsAsciiAlpha(ch)) {
      pattern.push_back(ch);
      continue;
    }

    pattern.push_back('[');
    pattern.push_back(base::ToLowerASCII(ch));
    pattern.push_back(base::ToUpperASCII(ch));
    pattern.push_back(']');
  }

  return pattern;
}

class FileChooserDialog {
 public:
  FileChooserDialog(GtkFileChooserAction action, const DialogSettings& settings)
      : parent_(
            static_cast<electron::NativeWindowViews*>(settings.parent_window)),
        filters_(settings.filters) {
    auto label = settings.button_label;

    if (electron::IsElectron_gtkInitialized()) {
      dialog_ = GTK_FILE_CHOOSER(gtk_file_chooser_native_new(
          settings.title.c_str(), NULL, action,
          label.empty() ? nullptr : label.c_str(), nullptr));
    } else {
      const char* confirm_text = gtk_util::GetOkLabel();
      if (!label.empty())
        confirm_text = label.c_str();
      else if (action == GTK_FILE_CHOOSER_ACTION_SAVE)
        confirm_text = gtk_util::GetSaveLabel();
      else if (action == GTK_FILE_CHOOSER_ACTION_OPEN)
        confirm_text = gtk_util::GetOpenLabel();

      dialog_ = GTK_FILE_CHOOSER(gtk_file_chooser_dialog_new(
          settings.title.c_str(), NULL, action, gtk_util::GetCancelLabel(),
          GTK_RESPONSE_CANCEL, confirm_text, GTK_RESPONSE_ACCEPT, NULL));
    }

    if (parent_) {
      parent_->SetEnabled(false);
      if (electron::IsElectron_gtkInitialized()) {
        gtk_native_dialog_set_modal(GTK_NATIVE_DIALOG(dialog_), TRUE);
      } else {
        gtk::SetGtkTransientForAura(GTK_WIDGET(dialog_),
                                    parent_->GetNativeWindow());
        gtk_window_set_modal(GTK_WINDOW(dialog_), TRUE);
      }
    }

    if (action == GTK_FILE_CHOOSER_ACTION_SAVE)
      gtk_file_chooser_set_do_overwrite_confirmation(dialog_, TRUE);
    if (action != GTK_FILE_CHOOSER_ACTION_OPEN)
      gtk_file_chooser_set_create_folders(dialog_, TRUE);

    if (!settings.default_path.empty()) {
      base::ThreadRestrictions::ScopedAllowIO allow_io;
      if (base::DirectoryExists(settings.default_path)) {
        gtk_file_chooser_set_current_folder(
            dialog_, settings.default_path.value().c_str());
      } else {
        if (settings.default_path.IsAbsolute()) {
          gtk_file_chooser_set_current_folder(
              dialog_, settings.default_path.DirName().value().c_str());
        }

        gtk_file_chooser_set_current_name(
            GTK_FILE_CHOOSER(dialog_),
            settings.default_path.BaseName().value().c_str());
      }
    }

    if (!settings.filters.empty())
      AddFilters(settings.filters);

    // GtkFileChooserNative does not support preview widgets through the
    // org.freedesktop.portal.FileChooser portal. In the case of running through
    // the org.freedesktop.portal.FileChooser portal, anything having to do with
    // the update-preview signal or the preview widget will just be ignored.
    if (!electron::IsElectron_gtkInitialized()) {
      preview_ = gtk_image_new();
      g_signal_connect(dialog_, "update-preview",
                       G_CALLBACK(OnUpdatePreviewThunk), this);
      gtk_file_chooser_set_preview_widget(dialog_, preview_);
    }
  }

  ~FileChooserDialog() {
    if (electron::IsElectron_gtkInitialized()) {
      gtk_native_dialog_destroy(GTK_NATIVE_DIALOG(dialog_));
    } else {
      gtk_widget_destroy(GTK_WIDGET(dialog_));
    }

    if (parent_)
      parent_->SetEnabled(true);
  }

  // disable copy
  FileChooserDialog(const FileChooserDialog&) = delete;
  FileChooserDialog& operator=(const FileChooserDialog&) = delete;

  void SetupOpenProperties(int properties) {
    const auto hasProp = [properties](OpenFileDialogProperty prop) {
      return gboolean((properties & prop) != 0);
    };
    auto* file_chooser = dialog();
    gtk_file_chooser_set_select_multiple(file_chooser,
                                         hasProp(OPEN_DIALOG_MULTI_SELECTIONS));
    gtk_file_chooser_set_show_hidden(file_chooser,
                                     hasProp(OPEN_DIALOG_SHOW_HIDDEN_FILES));
  }

  void SetupSaveProperties(int properties) {
    const auto hasProp = [properties](SaveFileDialogProperty prop) {
      return gboolean((properties & prop) != 0);
    };
    auto* file_chooser = dialog();
    gtk_file_chooser_set_show_hidden(file_chooser,
                                     hasProp(SAVE_DIALOG_SHOW_HIDDEN_FILES));
    gtk_file_chooser_set_do_overwrite_confirmation(
        file_chooser, hasProp(SAVE_DIALOG_SHOW_OVERWRITE_CONFIRMATION));
  }

  void RunAsynchronous() {
    g_signal_connect(dialog_, "response", G_CALLBACK(OnFileDialogResponseThunk),
                     this);
    if (electron::IsElectron_gtkInitialized()) {
      gtk_native_dialog_show(GTK_NATIVE_DIALOG(dialog_));
    } else {
      gtk_widget_show_all(GTK_WIDGET(dialog_));
      gtk::GtkUi::GetPlatform()->ShowGtkWindow(GTK_WINDOW(dialog_));
    }
  }

  void RunSaveAsynchronous(
      gin_helper::Promise<gin_helper::Dictionary> promise) {
    save_promise_ =
        std::make_unique<gin_helper::Promise<gin_helper::Dictionary>>(
            std::move(promise));
    RunAsynchronous();
  }

  void RunOpenAsynchronous(
      gin_helper::Promise<gin_helper::Dictionary> promise) {
    open_promise_ =
        std::make_unique<gin_helper::Promise<gin_helper::Dictionary>>(
            std::move(promise));
    RunAsynchronous();
  }

  base::FilePath GetFileName() const {
    gchar* filename = gtk_file_chooser_get_filename(dialog_);
    const base::FilePath path(filename);
    g_free(filename);
    return path;
  }

  std::vector<base::FilePath> GetFileNames() const {
    std::vector<base::FilePath> paths;
    auto* filenames = gtk_file_chooser_get_filenames(GTK_FILE_CHOOSER(dialog_));
    for (auto* iter = filenames; iter != nullptr; iter = iter->next) {
      auto* filename = static_cast<char*>(iter->data);
      paths.emplace_back(filename);
      g_free(filename);
    }
    g_slist_free(filenames);
    return paths;
  }

  CHROMEG_CALLBACK_1(FileChooserDialog,
                     void,
                     OnFileDialogResponse,
                     GtkWidget*,
                     int);

  GtkFileChooser* dialog() const { return dialog_; }

 private:
  void AddFilters(const Filters& filters);

  electron::NativeWindowViews* parent_;
  electron::UnresponsiveSuppressor unresponsive_suppressor_;

  GtkFileChooser* dialog_;
  GtkWidget* preview_;

  Filters filters_;
  std::unique_ptr<gin_helper::Promise<gin_helper::Dictionary>> save_promise_;
  std::unique_ptr<gin_helper::Promise<gin_helper::Dictionary>> open_promise_;

  // Callback for when we update the preview for the selection.
  CHROMEG_CALLBACK_0(FileChooserDialog, void, OnUpdatePreview, GtkFileChooser*);
};

void FileChooserDialog::OnFileDialogResponse(GtkWidget* widget, int response) {
  if (electron::IsElectron_gtkInitialized()) {
    gtk_native_dialog_hide(GTK_NATIVE_DIALOG(dialog_));
  } else {
    gtk_widget_hide(GTK_WIDGET(dialog_));
  }
  v8::Isolate* isolate = electron::JavascriptEnvironment::GetIsolate();
  v8::HandleScope scope(isolate);
  if (save_promise_) {
    gin_helper::Dictionary dict =
        gin::Dictionary::CreateEmpty(save_promise_->isolate());
    if (response == GTK_RESPONSE_ACCEPT) {
      dict.Set("canceled", false);
      dict.Set("filePath", GetFileName());
    } else {
      dict.Set("canceled", true);
      dict.Set("filePath", base::FilePath());
    }
    save_promise_->Resolve(dict);
  } else if (open_promise_) {
    gin_helper::Dictionary dict =
        gin::Dictionary::CreateEmpty(open_promise_->isolate());
    if (response == GTK_RESPONSE_ACCEPT) {
      dict.Set("canceled", false);
      dict.Set("filePaths", GetFileNames());
    } else {
      dict.Set("canceled", true);
      dict.Set("filePaths", std::vector<base::FilePath>());
    }
    open_promise_->Resolve(dict);
  }
  delete this;
}

void FileChooserDialog::AddFilters(const Filters& filters) {
  for (const auto& filter : filters) {
    GtkFileFilter* gtk_filter = gtk_file_filter_new();

    for (const auto& extension : filter.second) {
      std::string pattern = MakeCaseInsensitivePattern(extension);
      gtk_file_filter_add_pattern(gtk_filter, pattern.c_str());
    }

    gtk_file_filter_set_name(gtk_filter, filter.first.c_str());
    gtk_file_chooser_add_filter(dialog_, gtk_filter);
  }
}

bool CanPreview(const struct stat& st) {
  // Only preview regular files; pipes may hang.
  // See https://crbug.com/534754.
  if (!S_ISREG(st.st_mode)) {
    return false;
  }

  // Don't preview huge files; they may crash.
  // https://github.com/electron/electron/issues/31630
  // Setting an arbitrary filesize max t at 100 MB here.
  constexpr off_t ArbitraryMax = 100000000ULL;
  return st.st_size < ArbitraryMax;
}

void FileChooserDialog::OnUpdatePreview(GtkFileChooser* chooser) {
  CHECK(!electron::IsElectron_gtkInitialized());
  gchar* filename = gtk_file_chooser_get_preview_filename(chooser);
  if (!filename) {
    gtk_file_chooser_set_preview_widget_active(chooser, FALSE);
    return;
  }

  struct stat sb;
  if (stat(filename, &sb) != 0 || !CanPreview(sb)) {
    g_free(filename);
    gtk_file_chooser_set_preview_widget_active(chooser, FALSE);
    return;
  }

  // This will preserve the image's aspect ratio.
  GdkPixbuf* pixbuf = gdk_pixbuf_new_from_file_at_size(filename, kPreviewWidth,
                                                       kPreviewHeight, nullptr);
  g_free(filename);
  if (pixbuf) {
    gtk_image_set_from_pixbuf(GTK_IMAGE(preview_), pixbuf);
    g_object_unref(pixbuf);
  }
  gtk_file_chooser_set_preview_widget_active(chooser, pixbuf ? TRUE : FALSE);
}

}  // namespace

void ShowFileDialog(const FileChooserDialog& dialog) {
  // gtk_native_dialog_run() will call gtk_native_dialog_show() for us.
  if (!electron::IsElectron_gtkInitialized()) {
    gtk_widget_show_all(GTK_WIDGET(dialog.dialog()));
  }
}

int RunFileDialog(const FileChooserDialog& dialog) {
  int response = 0;
  if (electron::IsElectron_gtkInitialized()) {
    response = gtk_native_dialog_run(GTK_NATIVE_DIALOG(dialog.dialog()));
  } else {
    response = gtk_dialog_run(GTK_DIALOG(dialog.dialog()));
  }

  return response;
}

bool ShowOpenDialogSync(const DialogSettings& settings,
                        std::vector<base::FilePath>* paths) {
  GtkFileChooserAction action = GTK_FILE_CHOOSER_ACTION_OPEN;
  if (settings.properties & OPEN_DIALOG_OPEN_DIRECTORY)
    action = GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER;
  FileChooserDialog open_dialog(action, settings);
  open_dialog.SetupOpenProperties(settings.properties);

  ShowFileDialog(open_dialog);

  const int response = RunFileDialog(open_dialog);
  if (response == GTK_RESPONSE_ACCEPT) {
    *paths = open_dialog.GetFileNames();
    return true;
  }
  return false;
}

void ShowOpenDialog(const DialogSettings& settings,
                    gin_helper::Promise<gin_helper::Dictionary> promise) {
  GtkFileChooserAction action = GTK_FILE_CHOOSER_ACTION_OPEN;
  if (settings.properties & OPEN_DIALOG_OPEN_DIRECTORY)
    action = GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER;
  FileChooserDialog* open_dialog = new FileChooserDialog(action, settings);
  open_dialog->SetupOpenProperties(settings.properties);
  open_dialog->RunOpenAsynchronous(std::move(promise));
}

bool ShowSaveDialogSync(const DialogSettings& settings, base::FilePath* path) {
  FileChooserDialog save_dialog(GTK_FILE_CHOOSER_ACTION_SAVE, settings);
  save_dialog.SetupSaveProperties(settings.properties);

  ShowFileDialog(save_dialog);

  const int response = RunFileDialog(save_dialog);
  if (response == GTK_RESPONSE_ACCEPT) {
    *path = save_dialog.GetFileName();
    return true;
  }
  return false;
}

void ShowSaveDialog(const DialogSettings& settings,
                    gin_helper::Promise<gin_helper::Dictionary> promise) {
  FileChooserDialog* save_dialog =
      new FileChooserDialog(GTK_FILE_CHOOSER_ACTION_SAVE, settings);
  save_dialog->RunSaveAsynchronous(std::move(promise));
}

}  // namespace file_dialog
<commit_msg>fix: all files selection logic on linux (#34496)<commit_after>// Copyright (c) 2014 GitHub, Inc.
// Use of this source code is governed by the MIT license that can be
// found in the LICENSE file.

#include <memory>
#include <string>

#include "base/callback.h"
#include "base/files/file_util.h"
#include "base/strings/string_util.h"
#include "base/threading/thread_restrictions.h"
#include "electron/electron_gtk_stubs.h"
#include "shell/browser/javascript_environment.h"
#include "shell/browser/native_window_views.h"
#include "shell/browser/ui/file_dialog.h"
#include "shell/browser/ui/gtk_util.h"
#include "shell/browser/unresponsive_suppressor.h"
#include "shell/common/gin_converters/file_path_converter.h"
#include "ui/base/glib/glib_signal.h"
#include "ui/gtk/gtk_ui.h"    // nogncheck
#include "ui/gtk/gtk_util.h"  // nogncheck

namespace file_dialog {

DialogSettings::DialogSettings() = default;
DialogSettings::DialogSettings(const DialogSettings&) = default;
DialogSettings::~DialogSettings() = default;

namespace {

static const int kPreviewWidth = 256;
static const int kPreviewHeight = 512;

std::string MakeCaseInsensitivePattern(const std::string& extension) {
  // If the extension is the "all files" extension, no change needed.
  if (extension == "*")
    return extension;

  std::string pattern("*.");
  for (std::size_t i = 0, n = extension.size(); i < n; i++) {
    char ch = extension[i];
    if (!base::IsAsciiAlpha(ch)) {
      pattern.push_back(ch);
      continue;
    }

    pattern.push_back('[');
    pattern.push_back(base::ToLowerASCII(ch));
    pattern.push_back(base::ToUpperASCII(ch));
    pattern.push_back(']');
  }

  return pattern;
}

class FileChooserDialog {
 public:
  FileChooserDialog(GtkFileChooserAction action, const DialogSettings& settings)
      : parent_(
            static_cast<electron::NativeWindowViews*>(settings.parent_window)),
        filters_(settings.filters) {
    auto label = settings.button_label;

    if (electron::IsElectron_gtkInitialized()) {
      dialog_ = GTK_FILE_CHOOSER(gtk_file_chooser_native_new(
          settings.title.c_str(), NULL, action,
          label.empty() ? nullptr : label.c_str(), nullptr));
    } else {
      const char* confirm_text = gtk_util::GetOkLabel();
      if (!label.empty())
        confirm_text = label.c_str();
      else if (action == GTK_FILE_CHOOSER_ACTION_SAVE)
        confirm_text = gtk_util::GetSaveLabel();
      else if (action == GTK_FILE_CHOOSER_ACTION_OPEN)
        confirm_text = gtk_util::GetOpenLabel();

      dialog_ = GTK_FILE_CHOOSER(gtk_file_chooser_dialog_new(
          settings.title.c_str(), NULL, action, gtk_util::GetCancelLabel(),
          GTK_RESPONSE_CANCEL, confirm_text, GTK_RESPONSE_ACCEPT, NULL));
    }

    if (parent_) {
      parent_->SetEnabled(false);
      if (electron::IsElectron_gtkInitialized()) {
        gtk_native_dialog_set_modal(GTK_NATIVE_DIALOG(dialog_), TRUE);
      } else {
        gtk::SetGtkTransientForAura(GTK_WIDGET(dialog_),
                                    parent_->GetNativeWindow());
        gtk_window_set_modal(GTK_WINDOW(dialog_), TRUE);
      }
    }

    if (action == GTK_FILE_CHOOSER_ACTION_SAVE)
      gtk_file_chooser_set_do_overwrite_confirmation(dialog_, TRUE);
    if (action != GTK_FILE_CHOOSER_ACTION_OPEN)
      gtk_file_chooser_set_create_folders(dialog_, TRUE);

    if (!settings.default_path.empty()) {
      base::ThreadRestrictions::ScopedAllowIO allow_io;
      if (base::DirectoryExists(settings.default_path)) {
        gtk_file_chooser_set_current_folder(
            dialog_, settings.default_path.value().c_str());
      } else {
        if (settings.default_path.IsAbsolute()) {
          gtk_file_chooser_set_current_folder(
              dialog_, settings.default_path.DirName().value().c_str());
        }

        gtk_file_chooser_set_current_name(
            GTK_FILE_CHOOSER(dialog_),
            settings.default_path.BaseName().value().c_str());
      }
    }

    if (!settings.filters.empty())
      AddFilters(settings.filters);

    // GtkFileChooserNative does not support preview widgets through the
    // org.freedesktop.portal.FileChooser portal. In the case of running through
    // the org.freedesktop.portal.FileChooser portal, anything having to do with
    // the update-preview signal or the preview widget will just be ignored.
    if (!electron::IsElectron_gtkInitialized()) {
      preview_ = gtk_image_new();
      g_signal_connect(dialog_, "update-preview",
                       G_CALLBACK(OnUpdatePreviewThunk), this);
      gtk_file_chooser_set_preview_widget(dialog_, preview_);
    }
  }

  ~FileChooserDialog() {
    if (electron::IsElectron_gtkInitialized()) {
      gtk_native_dialog_destroy(GTK_NATIVE_DIALOG(dialog_));
    } else {
      gtk_widget_destroy(GTK_WIDGET(dialog_));
    }

    if (parent_)
      parent_->SetEnabled(true);
  }

  // disable copy
  FileChooserDialog(const FileChooserDialog&) = delete;
  FileChooserDialog& operator=(const FileChooserDialog&) = delete;

  void SetupOpenProperties(int properties) {
    const auto hasProp = [properties](OpenFileDialogProperty prop) {
      return gboolean((properties & prop) != 0);
    };
    auto* file_chooser = dialog();
    gtk_file_chooser_set_select_multiple(file_chooser,
                                         hasProp(OPEN_DIALOG_MULTI_SELECTIONS));
    gtk_file_chooser_set_show_hidden(file_chooser,
                                     hasProp(OPEN_DIALOG_SHOW_HIDDEN_FILES));
  }

  void SetupSaveProperties(int properties) {
    const auto hasProp = [properties](SaveFileDialogProperty prop) {
      return gboolean((properties & prop) != 0);
    };
    auto* file_chooser = dialog();
    gtk_file_chooser_set_show_hidden(file_chooser,
                                     hasProp(SAVE_DIALOG_SHOW_HIDDEN_FILES));
    gtk_file_chooser_set_do_overwrite_confirmation(
        file_chooser, hasProp(SAVE_DIALOG_SHOW_OVERWRITE_CONFIRMATION));
  }

  void RunAsynchronous() {
    g_signal_connect(dialog_, "response", G_CALLBACK(OnFileDialogResponseThunk),
                     this);
    if (electron::IsElectron_gtkInitialized()) {
      gtk_native_dialog_show(GTK_NATIVE_DIALOG(dialog_));
    } else {
      gtk_widget_show_all(GTK_WIDGET(dialog_));
      gtk::GtkUi::GetPlatform()->ShowGtkWindow(GTK_WINDOW(dialog_));
    }
  }

  void RunSaveAsynchronous(
      gin_helper::Promise<gin_helper::Dictionary> promise) {
    save_promise_ =
        std::make_unique<gin_helper::Promise<gin_helper::Dictionary>>(
            std::move(promise));
    RunAsynchronous();
  }

  void RunOpenAsynchronous(
      gin_helper::Promise<gin_helper::Dictionary> promise) {
    open_promise_ =
        std::make_unique<gin_helper::Promise<gin_helper::Dictionary>>(
            std::move(promise));
    RunAsynchronous();
  }

  base::FilePath GetFileName() const {
    gchar* filename = gtk_file_chooser_get_filename(dialog_);
    const base::FilePath path(filename);
    g_free(filename);
    return path;
  }

  std::vector<base::FilePath> GetFileNames() const {
    std::vector<base::FilePath> paths;
    auto* filenames = gtk_file_chooser_get_filenames(GTK_FILE_CHOOSER(dialog_));
    for (auto* iter = filenames; iter != nullptr; iter = iter->next) {
      auto* filename = static_cast<char*>(iter->data);
      paths.emplace_back(filename);
      g_free(filename);
    }
    g_slist_free(filenames);
    return paths;
  }

  CHROMEG_CALLBACK_1(FileChooserDialog,
                     void,
                     OnFileDialogResponse,
                     GtkWidget*,
                     int);

  GtkFileChooser* dialog() const { return dialog_; }

 private:
  void AddFilters(const Filters& filters);

  electron::NativeWindowViews* parent_;
  electron::UnresponsiveSuppressor unresponsive_suppressor_;

  GtkFileChooser* dialog_;
  GtkWidget* preview_;

  Filters filters_;
  std::unique_ptr<gin_helper::Promise<gin_helper::Dictionary>> save_promise_;
  std::unique_ptr<gin_helper::Promise<gin_helper::Dictionary>> open_promise_;

  // Callback for when we update the preview for the selection.
  CHROMEG_CALLBACK_0(FileChooserDialog, void, OnUpdatePreview, GtkFileChooser*);
};

void FileChooserDialog::OnFileDialogResponse(GtkWidget* widget, int response) {
  if (electron::IsElectron_gtkInitialized()) {
    gtk_native_dialog_hide(GTK_NATIVE_DIALOG(dialog_));
  } else {
    gtk_widget_hide(GTK_WIDGET(dialog_));
  }
  v8::Isolate* isolate = electron::JavascriptEnvironment::GetIsolate();
  v8::HandleScope scope(isolate);
  if (save_promise_) {
    gin_helper::Dictionary dict =
        gin::Dictionary::CreateEmpty(save_promise_->isolate());
    if (response == GTK_RESPONSE_ACCEPT) {
      dict.Set("canceled", false);
      dict.Set("filePath", GetFileName());
    } else {
      dict.Set("canceled", true);
      dict.Set("filePath", base::FilePath());
    }
    save_promise_->Resolve(dict);
  } else if (open_promise_) {
    gin_helper::Dictionary dict =
        gin::Dictionary::CreateEmpty(open_promise_->isolate());
    if (response == GTK_RESPONSE_ACCEPT) {
      dict.Set("canceled", false);
      dict.Set("filePaths", GetFileNames());
    } else {
      dict.Set("canceled", true);
      dict.Set("filePaths", std::vector<base::FilePath>());
    }
    open_promise_->Resolve(dict);
  }
  delete this;
}

void FileChooserDialog::AddFilters(const Filters& filters) {
  for (const auto& filter : filters) {
    GtkFileFilter* gtk_filter = gtk_file_filter_new();

    for (const auto& extension : filter.second) {
      std::string pattern = MakeCaseInsensitivePattern(extension);
      gtk_file_filter_add_pattern(gtk_filter, pattern.c_str());
    }

    gtk_file_filter_set_name(gtk_filter, filter.first.c_str());
    gtk_file_chooser_add_filter(dialog_, gtk_filter);
  }
}

bool CanPreview(const struct stat& st) {
  // Only preview regular files; pipes may hang.
  // See https://crbug.com/534754.
  if (!S_ISREG(st.st_mode)) {
    return false;
  }

  // Don't preview huge files; they may crash.
  // https://github.com/electron/electron/issues/31630
  // Setting an arbitrary filesize max t at 100 MB here.
  constexpr off_t ArbitraryMax = 100000000ULL;
  return st.st_size < ArbitraryMax;
}

void FileChooserDialog::OnUpdatePreview(GtkFileChooser* chooser) {
  CHECK(!electron::IsElectron_gtkInitialized());
  gchar* filename = gtk_file_chooser_get_preview_filename(chooser);
  if (!filename) {
    gtk_file_chooser_set_preview_widget_active(chooser, FALSE);
    return;
  }

  struct stat sb;
  if (stat(filename, &sb) != 0 || !CanPreview(sb)) {
    g_free(filename);
    gtk_file_chooser_set_preview_widget_active(chooser, FALSE);
    return;
  }

  // This will preserve the image's aspect ratio.
  GdkPixbuf* pixbuf = gdk_pixbuf_new_from_file_at_size(filename, kPreviewWidth,
                                                       kPreviewHeight, nullptr);
  g_free(filename);
  if (pixbuf) {
    gtk_image_set_from_pixbuf(GTK_IMAGE(preview_), pixbuf);
    g_object_unref(pixbuf);
  }
  gtk_file_chooser_set_preview_widget_active(chooser, pixbuf ? TRUE : FALSE);
}

}  // namespace

void ShowFileDialog(const FileChooserDialog& dialog) {
  // gtk_native_dialog_run() will call gtk_native_dialog_show() for us.
  if (!electron::IsElectron_gtkInitialized()) {
    gtk_widget_show_all(GTK_WIDGET(dialog.dialog()));
  }
}

int RunFileDialog(const FileChooserDialog& dialog) {
  int response = 0;
  if (electron::IsElectron_gtkInitialized()) {
    response = gtk_native_dialog_run(GTK_NATIVE_DIALOG(dialog.dialog()));
  } else {
    response = gtk_dialog_run(GTK_DIALOG(dialog.dialog()));
  }

  return response;
}

bool ShowOpenDialogSync(const DialogSettings& settings,
                        std::vector<base::FilePath>* paths) {
  GtkFileChooserAction action = GTK_FILE_CHOOSER_ACTION_OPEN;
  if (settings.properties & OPEN_DIALOG_OPEN_DIRECTORY)
    action = GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER;
  FileChooserDialog open_dialog(action, settings);
  open_dialog.SetupOpenProperties(settings.properties);

  ShowFileDialog(open_dialog);

  const int response = RunFileDialog(open_dialog);
  if (response == GTK_RESPONSE_ACCEPT) {
    *paths = open_dialog.GetFileNames();
    return true;
  }
  return false;
}

void ShowOpenDialog(const DialogSettings& settings,
                    gin_helper::Promise<gin_helper::Dictionary> promise) {
  GtkFileChooserAction action = GTK_FILE_CHOOSER_ACTION_OPEN;
  if (settings.properties & OPEN_DIALOG_OPEN_DIRECTORY)
    action = GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER;
  FileChooserDialog* open_dialog = new FileChooserDialog(action, settings);
  open_dialog->SetupOpenProperties(settings.properties);
  open_dialog->RunOpenAsynchronous(std::move(promise));
}

bool ShowSaveDialogSync(const DialogSettings& settings, base::FilePath* path) {
  FileChooserDialog save_dialog(GTK_FILE_CHOOSER_ACTION_SAVE, settings);
  save_dialog.SetupSaveProperties(settings.properties);

  ShowFileDialog(save_dialog);

  const int response = RunFileDialog(save_dialog);
  if (response == GTK_RESPONSE_ACCEPT) {
    *path = save_dialog.GetFileName();
    return true;
  }
  return false;
}

void ShowSaveDialog(const DialogSettings& settings,
                    gin_helper::Promise<gin_helper::Dictionary> promise) {
  FileChooserDialog* save_dialog =
      new FileChooserDialog(GTK_FILE_CHOOSER_ACTION_SAVE, settings);
  save_dialog->RunSaveAsynchronous(std::move(promise));
}

}  // namespace file_dialog
<|endoftext|>