<commit_before>/*
 * Copyright (c) 2018 Abit More, and contributors.
 *
 * The MIT License
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */

#include <graphene/grouped_orders/grouped_orders_plugin.hpp>

#include <graphene/chain/market_object.hpp>

namespace graphene { namespace grouped_orders {

namespace detail
{

class grouped_orders_plugin_impl
{
   public:
      grouped_orders_plugin_impl(grouped_orders_plugin& _plugin)
      :_self( _plugin ) {}
      virtual ~grouped_orders_plugin_impl();

      graphene::chain::database& database()
      {
         return _self.database();
      }

      grouped_orders_plugin&     _self;
      flat_set<uint16_t>         _tracked_groups;
};

/**
 *  @brief This secondary index is used to track changes on limit order objects.
 */
class limit_order_group_index : public secondary_index
{
   public:
      limit_order_group_index( const flat_set<uint16_t>& groups ) : _tracked_groups( groups ) {};

      virtual void object_inserted( const object& obj ) override;
      virtual void object_removed( const object& obj ) override;
      virtual void about_to_modify( const object& before ) override;
      virtual void object_modified( const object& after  ) override;

      const flat_set<uint16_t>& get_tracked_groups() const
      { return _tracked_groups; }

      const map< limit_order_group_key, limit_order_group_data >& get_order_groups() const
      { return _og_data; }

   private:
      void remove_order( const limit_order_object& obj, bool remove_empty = true );

      /** tracked groups */
      flat_set<uint16_t> _tracked_groups;

      /** maps the group key to group data */
      map< limit_order_group_key, limit_order_group_data > _og_data;
};

void limit_order_group_index::object_inserted( const object& objct )
{ try {
   const limit_order_object& o = static_cast<const limit_order_object&>( objct );

   auto& idx = _og_data;

   for( uint16_t group : get_tracked_groups() )
   {
      auto create_ogo = [&]() {
         idx[ limit_order_group_key( group, o.sell_price ) ] = limit_order_group_data( o.sell_price, o.for_sale );
      };
      // if idx is empty, insert this order
      // Note: not capped
      if( idx.empty() )
      {
         create_ogo();
         continue;
      }

      // cap the price
      price capped_price = o.sell_price;
      price max = o.sell_price.max();
      price min = o.sell_price.min();
      bool capped_max = false;
      bool capped_min = false;
      if( o.sell_price > max )
      {
         capped_price = max;
         capped_max = true;
      }
      else if( o.sell_price < min )
      {
         capped_price = min;
         capped_min = true;
      }
      // if idx is not empty, find the group that is next to this order
      auto itr = idx.lower_bound( limit_order_group_key( group, capped_price ) );
      bool check_previous = false;
      if( itr == idx.end() || itr->first.group != group
            || itr->first.min_price.base.asset_id != o.sell_price.base.asset_id
            || itr->first.min_price.quote.asset_id != o.sell_price.quote.asset_id )
         // not same market or group type
         check_previous = true;
      else // same market and group type
      {
         bool update_max = false;
         if( capped_price > itr->second.max_price ) // implies itr->min_price <= itr->max_price < max
         {
            update_max = true;
            price max_price = itr->first.min_price * ratio_type( GRAPHENE_100_PERCENT + group, GRAPHENE_100_PERCENT );
            // max_price should have been capped here
            if( capped_price > max_price ) // new order is out of range
               check_previous = true;
         }
         if( !check_previous ) // new order is within the range
         {
            if( capped_min && o.sell_price < itr->first.min_price )
            {  // need to update itr->min_price here, if itr is below min, and new order is even lower
               // TODO improve performance
               limit_order_group_data data( itr->second.max_price, o.for_sale + itr->second.total_for_sale );
               idx.erase( itr );
               idx[ limit_order_group_key( group, o.sell_price ) ] = data;
            }
            else
            {
               if( update_max || ( capped_max && o.sell_price > itr->second.max_price ) )
                  itr->second.max_price = o.sell_price; // store real price here, not capped
               itr->second.total_for_sale += o.for_sale;
            }
         }
      }

      if( check_previous )
      {
         if( itr == idx.begin() ) // no previous
            create_ogo();
         else
         {
            --itr; // should be valid
            if( itr->first.group != group || itr->first.min_price.base.asset_id != o.sell_price.base.asset_id
                                          || itr->first.min_price.quote.asset_id != o.sell_price.quote.asset_id )
               // not same market or group type
               create_ogo();
            else // same market and group type
            {
               // due to lower_bound, always true: capped_price < itr->first.min_price, so no need to check again,
               // if new order is in range of itr group, always need to update itr->first.min_price, unless
               //   o.sell_price is higher than max
               price min_price = itr->second.max_price / ratio_type( GRAPHENE_100_PERCENT + group, GRAPHENE_100_PERCENT );
               // min_price should have been capped here
               if( capped_price < min_price ) // new order is out of range
                  create_ogo();
               else if( capped_max && o.sell_price >= itr->first.min_price )
               {  // itr is above max, and price of new order is even higher
                  if( o.sell_price > itr->second.max_price )
                     itr->second.max_price = o.sell_price;
                  itr->second.total_for_sale += o.for_sale;
               }
               else
               {  // new order is within the range
                  // TODO improve performance
                  limit_order_group_data data( itr->second.max_price, o.for_sale + itr->second.total_for_sale );
                  idx.erase( itr );
                  idx[ limit_order_group_key( group, o.sell_price ) ] = data;
               }
            }
         }
      }
   }
} FC_CAPTURE_AND_RETHROW( (objct) ); }

void limit_order_group_index::object_removed( const object& objct )
{ try {
   const limit_order_object& o = static_cast<const limit_order_object&>( objct );
   remove_order( o );
} FC_CAPTURE_AND_RETHROW( (objct) ); }

void limit_order_group_index::about_to_modify( const object& objct )
{ try {
   const limit_order_object& o = static_cast<const limit_order_object&>( objct );
   remove_order( o, false );
} FC_CAPTURE_AND_RETHROW( (objct) ); }

void limit_order_group_index::object_modified( const object& objct )
{ try {
   object_inserted( objct );
} FC_CAPTURE_AND_RETHROW( (objct) ); }

void limit_order_group_index::remove_order( const limit_order_object& o, bool remove_empty )
{
   auto& idx = _og_data;

   for( uint16_t group : get_tracked_groups() )
   {
      // find the group that should contain this order
      auto itr = idx.lower_bound( limit_order_group_key( group, o.sell_price ) );
      if( itr == idx.end() || itr->first.group != group
            || itr->first.min_price.base.asset_id != o.sell_price.base.asset_id
            || itr->first.min_price.quote.asset_id != o.sell_price.quote.asset_id
            || itr->second.max_price < o.sell_price )
      {
         // can not find corresponding group, should not happen
         wlog( "can not find the order group containing order for removing: ${o}", ("o",o) );
         continue;
      }
      else // found
      {
         if( itr->second.total_for_sale < o.for_sale )
            // should not happen
            wlog( "can not find the order group containing order for removing: ${o}", ("o",o) );
         else if( itr->second.total_for_sale > o.for_sale || !remove_empty )
            itr->second.total_for_sale -= o.for_sale;
         else
            // it's the only order in the group and need to be removed
            idx.erase( itr );
      }
   }
}

grouped_orders_plugin_impl::~grouped_orders_plugin_impl()
{}

} // end namespace detail

grouped_orders_plugin::grouped_orders_plugin() :
   my( new detail::grouped_orders_plugin_impl(*this) )
{
}

grouped_orders_plugin::~grouped_orders_plugin()
{
}

std::string grouped_orders_plugin::plugin_name()const
{
   return "grouped_orders";
}

void grouped_orders_plugin::plugin_set_program_options(
   boost::program_options::options_description& cli,
   boost::program_options::options_description& cfg
   )
{
   cli.add_options()
         ("tracked-groups", boost::program_options::value<string>()->default_value("[10,100]"), // 0.1% and 1%
          "Group orders by percentage increase on price. Specify a JSON array of numbers here, each number is a group, number 1 means 0.01%. ")
         ;
   cfg.add(cli);
}

void grouped_orders_plugin::plugin_initialize(const boost::program_options::variables_map& options)
{ try {

   if( options.count( "tracked-groups" ) )
   {
      const std::string& groups = options["tracked-groups"].as<string>();
      my->_tracked_groups = fc::json::from_string(groups).as<flat_set<uint16_t>>();
      my->_tracked_groups.erase( 0 );
   }
   else
      my->_tracked_groups = fc::json::from_string("[10,100]").as<flat_set<uint16_t>>();

   database().add_secondary_index< primary_index<limit_order_index>, detail::limit_order_group_index >( my->_tracked_groups );

} FC_CAPTURE_AND_RETHROW() }

void grouped_orders_plugin::plugin_startup()
{
}

const flat_set<uint16_t>& grouped_orders_plugin::tracked_groups() const
{
   return my->_tracked_groups;
}

const map< limit_order_group_key, limit_order_group_data >& grouped_orders_plugin::limit_order_groups()
{
   const auto& idx = database().get_index_type< limit_order_index >();
   const auto& pidx = dynamic_cast<const primary_index< limit_order_index >&>(idx);
   const auto& logidx = pidx.get_secondary_index< detail::limit_order_group_index >();
   return logidx.get_order_groups();
}

} }
<commit_msg>More detailed warning messages when fail to remove<commit_after>/*
 * Copyright (c) 2018 Abit More, and contributors.
 *
 * The MIT License
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */

#include <graphene/grouped_orders/grouped_orders_plugin.hpp>

#include <graphene/chain/market_object.hpp>

namespace graphene { namespace grouped_orders {

namespace detail
{

class grouped_orders_plugin_impl
{
   public:
      grouped_orders_plugin_impl(grouped_orders_plugin& _plugin)
      :_self( _plugin ) {}
      virtual ~grouped_orders_plugin_impl();

      graphene::chain::database& database()
      {
         return _self.database();
      }

      grouped_orders_plugin&     _self;
      flat_set<uint16_t>         _tracked_groups;
};

/**
 *  @brief This secondary index is used to track changes on limit order objects.
 */
class limit_order_group_index : public secondary_index
{
   public:
      limit_order_group_index( const flat_set<uint16_t>& groups ) : _tracked_groups( groups ) {};

      virtual void object_inserted( const object& obj ) override;
      virtual void object_removed( const object& obj ) override;
      virtual void about_to_modify( const object& before ) override;
      virtual void object_modified( const object& after  ) override;

      const flat_set<uint16_t>& get_tracked_groups() const
      { return _tracked_groups; }

      const map< limit_order_group_key, limit_order_group_data >& get_order_groups() const
      { return _og_data; }

   private:
      void remove_order( const limit_order_object& obj, bool remove_empty = true );

      /** tracked groups */
      flat_set<uint16_t> _tracked_groups;

      /** maps the group key to group data */
      map< limit_order_group_key, limit_order_group_data > _og_data;
};

void limit_order_group_index::object_inserted( const object& objct )
{ try {
   const limit_order_object& o = static_cast<const limit_order_object&>( objct );

   auto& idx = _og_data;

   for( uint16_t group : get_tracked_groups() )
   {
      auto create_ogo = [&]() {
         idx[ limit_order_group_key( group, o.sell_price ) ] = limit_order_group_data( o.sell_price, o.for_sale );
      };
      // if idx is empty, insert this order
      // Note: not capped
      if( idx.empty() )
      {
         create_ogo();
         continue;
      }

      // cap the price
      price capped_price = o.sell_price;
      price max = o.sell_price.max();
      price min = o.sell_price.min();
      bool capped_max = false;
      bool capped_min = false;
      if( o.sell_price > max )
      {
         capped_price = max;
         capped_max = true;
      }
      else if( o.sell_price < min )
      {
         capped_price = min;
         capped_min = true;
      }
      // if idx is not empty, find the group that is next to this order
      auto itr = idx.lower_bound( limit_order_group_key( group, capped_price ) );
      bool check_previous = false;
      if( itr == idx.end() || itr->first.group != group
            || itr->first.min_price.base.asset_id != o.sell_price.base.asset_id
            || itr->first.min_price.quote.asset_id != o.sell_price.quote.asset_id )
         // not same market or group type
         check_previous = true;
      else // same market and group type
      {
         bool update_max = false;
         if( capped_price > itr->second.max_price ) // implies itr->min_price <= itr->max_price < max
         {
            update_max = true;
            price max_price = itr->first.min_price * ratio_type( GRAPHENE_100_PERCENT + group, GRAPHENE_100_PERCENT );
            // max_price should have been capped here
            if( capped_price > max_price ) // new order is out of range
               check_previous = true;
         }
         if( !check_previous ) // new order is within the range
         {
            if( capped_min && o.sell_price < itr->first.min_price )
            {  // need to update itr->min_price here, if itr is below min, and new order is even lower
               // TODO improve performance
               limit_order_group_data data( itr->second.max_price, o.for_sale + itr->second.total_for_sale );
               idx.erase( itr );
               idx[ limit_order_group_key( group, o.sell_price ) ] = data;
            }
            else
            {
               if( update_max || ( capped_max && o.sell_price > itr->second.max_price ) )
                  itr->second.max_price = o.sell_price; // store real price here, not capped
               itr->second.total_for_sale += o.for_sale;
            }
         }
      }

      if( check_previous )
      {
         if( itr == idx.begin() ) // no previous
            create_ogo();
         else
         {
            --itr; // should be valid
            if( itr->first.group != group || itr->first.min_price.base.asset_id != o.sell_price.base.asset_id
                                          || itr->first.min_price.quote.asset_id != o.sell_price.quote.asset_id )
               // not same market or group type
               create_ogo();
            else // same market and group type
            {
               // due to lower_bound, always true: capped_price < itr->first.min_price, so no need to check again,
               // if new order is in range of itr group, always need to update itr->first.min_price, unless
               //   o.sell_price is higher than max
               price min_price = itr->second.max_price / ratio_type( GRAPHENE_100_PERCENT + group, GRAPHENE_100_PERCENT );
               // min_price should have been capped here
               if( capped_price < min_price ) // new order is out of range
                  create_ogo();
               else if( capped_max && o.sell_price >= itr->first.min_price )
               {  // itr is above max, and price of new order is even higher
                  if( o.sell_price > itr->second.max_price )
                     itr->second.max_price = o.sell_price;
                  itr->second.total_for_sale += o.for_sale;
               }
               else
               {  // new order is within the range
                  // TODO improve performance
                  limit_order_group_data data( itr->second.max_price, o.for_sale + itr->second.total_for_sale );
                  idx.erase( itr );
                  idx[ limit_order_group_key( group, o.sell_price ) ] = data;
               }
            }
         }
      }
   }
} FC_CAPTURE_AND_RETHROW( (objct) ); }

void limit_order_group_index::object_removed( const object& objct )
{ try {
   const limit_order_object& o = static_cast<const limit_order_object&>( objct );
   remove_order( o );
} FC_CAPTURE_AND_RETHROW( (objct) ); }

void limit_order_group_index::about_to_modify( const object& objct )
{ try {
   const limit_order_object& o = static_cast<const limit_order_object&>( objct );
   remove_order( o, false );
} FC_CAPTURE_AND_RETHROW( (objct) ); }

void limit_order_group_index::object_modified( const object& objct )
{ try {
   object_inserted( objct );
} FC_CAPTURE_AND_RETHROW( (objct) ); }

void limit_order_group_index::remove_order( const limit_order_object& o, bool remove_empty )
{
   auto& idx = _og_data;

   for( uint16_t group : get_tracked_groups() )
   {
      // find the group that should contain this order
      auto itr = idx.lower_bound( limit_order_group_key( group, o.sell_price ) );
      if( itr == idx.end() || itr->first.group != group
            || itr->first.min_price.base.asset_id != o.sell_price.base.asset_id
            || itr->first.min_price.quote.asset_id != o.sell_price.quote.asset_id
            || itr->second.max_price < o.sell_price )
      {
         // can not find corresponding group, should not happen
         wlog( "can not find the order group containing order for removing (price dismatch): ${o}", ("o",o) );
         continue;
      }
      else // found
      {
         if( itr->second.total_for_sale < o.for_sale )
            // should not happen
            wlog( "can not find the order group containing order for removing (amount dismatch): ${o}", ("o",o) );
         else if( !remove_empty || itr->second.total_for_sale > o.for_sale )
            itr->second.total_for_sale -= o.for_sale;
         else
            // it's the only order in the group and need to be removed
            idx.erase( itr );
      }
   }
}

grouped_orders_plugin_impl::~grouped_orders_plugin_impl()
{}

} // end namespace detail

grouped_orders_plugin::grouped_orders_plugin() :
   my( new detail::grouped_orders_plugin_impl(*this) )
{
}

grouped_orders_plugin::~grouped_orders_plugin()
{
}

std::string grouped_orders_plugin::plugin_name()const
{
   return "grouped_orders";
}

void grouped_orders_plugin::plugin_set_program_options(
   boost::program_options::options_description& cli,
   boost::program_options::options_description& cfg
   )
{
   cli.add_options()
         ("tracked-groups", boost::program_options::value<string>()->default_value("[10,100]"), // 0.1% and 1%
          "Group orders by percentage increase on price. Specify a JSON array of numbers here, each number is a group, number 1 means 0.01%. ")
         ;
   cfg.add(cli);
}

void grouped_orders_plugin::plugin_initialize(const boost::program_options::variables_map& options)
{ try {

   if( options.count( "tracked-groups" ) )
   {
      const std::string& groups = options["tracked-groups"].as<string>();
      my->_tracked_groups = fc::json::from_string(groups).as<flat_set<uint16_t>>();
      my->_tracked_groups.erase( 0 );
   }
   else
      my->_tracked_groups = fc::json::from_string("[10,100]").as<flat_set<uint16_t>>();

   database().add_secondary_index< primary_index<limit_order_index>, detail::limit_order_group_index >( my->_tracked_groups );

} FC_CAPTURE_AND_RETHROW() }

void grouped_orders_plugin::plugin_startup()
{
}

const flat_set<uint16_t>& grouped_orders_plugin::tracked_groups() const
{
   return my->_tracked_groups;
}

const map< limit_order_group_key, limit_order_group_data >& grouped_orders_plugin::limit_order_groups()
{
   const auto& idx = database().get_index_type< limit_order_index >();
   const auto& pidx = dynamic_cast<const primary_index< limit_order_index >&>(idx);
   const auto& logidx = pidx.get_secondary_index< detail::limit_order_group_index >();
   return logidx.get_order_groups();
}

} }
<|endoftext|>


<commit_before>// @(#)root/gui:$Id$
// Author: Reiner Rohlfs   24/03/2002

/*************************************************************************
 * Copyright (C) 1995-2001, Rene Brun, Fons Rademakers and Reiner Rohlfs *
 * All rights reserved.                                                  *
 *                                                                       *
 * For the licensing terms see $ROOTSYS/LICENSE.                         *
 * For the list of contributors see $ROOTSYS/README/CREDITS.             *
 *************************************************************************/

//////////////////////////////////////////////////////////////////////////
//                                                                      //
// TGXYLayout                                                           //
//                                                                      //
// Is a layout manager where the position and the size of each widget   //
// in the frame are defined by X / Y - coordinates. The coordinates     //
// for each widget are defined by the TGXYLayoutHints. Therefore it     //
// is not possible to share a layout hint for several widgets.          //
//                                                                      //
// The coordinates (X, Y) and the size (W, H) are defined in units      //
// of the size of a typical character. Also the size of the             //
// TGCompositeFrame for which a TGXYLayout manager is used has to be    //
// defined in its constructor in units of the size of a character!      //
//                                                                      //
// It is not possible to use any other layout hint than the             //
// TGXYLayoutHints for this layout manager!                             //
//                                                                      //
// The rubberFlag in the constructor of the TGLXYLayoutHins defines     //
// how the position and the size of a widget is recalculated if the     //
// size of the frame is increased:                                      //
// - kLRubberX: The X - position (left edge) is increased by the same   //
//              factor as the width of the frame increases.             //
// - kLRubberY: The Y - position (upper edge) is increased by the same  //
//              factor as the height of the frame increases.            //
// - kLRubberW: The width of the widget is increased by the same        //
//              factor as the width of the frame increases.             //
// - kLRubberH: The height of the widget is increased by the same       //
//              factor as the height of the frame increases.            //
// But the size never becomes smaller than defined by the               //
// TGXYLayoutHints and the X and Y coordinates becomes never smaller    //
// than defined by the layout hints.                                    //
//                                                                      //
// TGXYLayoutHints                                                      //
//                                                                      //
// This layout hint must be used for the TGXYLouyout manager!           //
//                                                                      //
//                                                                      //
// Example how to use this layout manager:                              //
//                                                                      //
// TGMyFrame::TGMyFrame()                                               //
//    : TGMainFrame(gClient->GetRoot(), 30, 12)                         //
//    // frame is 30 character long and 12 character heigh              //
// {                                                                    //
//    SetLayoutManager(new TGXYLayout(this));                           //
//                                                                      //
//    // create a button of size 8 X 1.8 at position 20 / 1             //
//    TGTextButton * button;                                            //
//    button = new TGTextButton(this, "&Apply", 1);                     //
//    AddFrame(button, new TGXYLayoutHints(20, 1, 8, 1.8));             //
//                                                                      //
//    // create a listbox of size 18 X 10 at position 1 / 1.            //
//    // The height will increase if the frame height increases         //
//    TGListBox * listBox;                                              //
//    listBox = new TGListBox(this, 2);                                 //
//    AddFrame(listBox, new TGXYLayoutHints(1, 1, 18, 10,               //
//             TGXYLayoutHints::kLRubberX |                             //
//             TGXYLayoutHints::kLRubberY |                             //
//             TGXYLayoutHints::kLRubberH ));                           //
//    .                                                                 //
//    .                                                                 //
//    .                                                                 //
// }                                                                    //
//                                                                      //
// Normaly there is one layout hint per widget. Therefore these         //
// can be deleted like in the following example in the desctuctor       //
// of the frame:                                                        //
//                                                                      //
// TGMyFrame::~TGMyFrame()                                              //
// {                                                                    //
//    // Destructor, deletes all frames and their layout hints.         //
//                                                                      //
//    TGFrameElement *ptr;                                              //
//                                                                      //
//    // delete all frames and layout hints                             //
//    if (fList) {                                                      //
//       TIter next(fList);                                             //
//       while ((ptr = (TGFrameElement *) next())) {                    //
//          if (ptr->fLayout)                                           //
//             delete ptr->fLayout;                                     //
//          if (ptr->fFrame)                                            //
//             delete ptr->fFrame;                                      //
//       }                                                              //
//    }                                                                 //
// }                                                                    //
//                                                                      //
//////////////////////////////////////////////////////////////////////////

#include "TGXYLayout.h"
#include "TGFrame.h"
#include "TGLabel.h"
#include "Riostream.h"

ClassImp(TGXYLayout)
ClassImp(TGXYLayoutHints)

////////////////////////////////////////////////////////////////////////////////
/// Constructor. The x, y, w and h define the position of the widget in
/// its frame and the size of the widget. The unit is the size of a
/// character. The rubberFlag defines how to move and to resize the
/// widget when the frame is resized. Default is moving the X and Y
/// position but keep the size of the widget.

TGXYLayoutHints::TGXYLayoutHints(Double_t x, Double_t y, Double_t w, Double_t h,
                                 UInt_t rubberFlag)
   : TGLayoutHints(kLHintsNormal, 0,0,0,0)
{
   fX    = x;
   fY    = y;
   fW    = w;
   fH    = h;
   fFlag = rubberFlag;
}

////////////////////////////////////////////////////////////////////////////////
/// Save XY layout hints as a C++ statement(s) on output stream.

void TGXYLayoutHints::SavePrimitive(std::ostream &out, Option_t * /*option = ""*/)
{
   TString flag = "";
   if (fFlag & kLRubberX) {
      if (flag.Length() == 0)  flag  = "TGXYLayoutHints::kLRubberX";
      else                     flag += " | TGXYLayoutHints::kLRubberX";
   }
   if (fFlag & kLRubberY) {
      if  (flag.Length() == 0) flag  = "TGXYLayoutHints::kLRubberY";
      else                      flag += " | TGXYLayoutHints::kLRubberY";
   }
   if (fFlag & kLRubberW) {
      if (flag.Length() == 0) flag  = "TGXYLayoutHints::kLRubberW";
      else                     flag += " | TGXYLayoutHints::kLRubberW";
   }
   if (fFlag & kLRubberH) {
      if (flag.Length() == 0) flag  = "TGXYLayoutHints::kLRubberH";
      else                     flag += " | TGXYLayoutHints::kLRubberH";
   }

   out << ", new TGXYLayoutHints(" << GetX() << ", " << GetY() << ", "
       << GetW() << ", " << GetH();

   if (!flag.Length())
      out << ")";
   else
      out << ", " << flag << ")";

}

////////////////////////////////////////////////////////////////////////////////
/// Constructor. The main is the frame for which this layout manager works.

TGXYLayout::TGXYLayout(TGCompositeFrame *main)
{
   UInt_t  width, height;
   Int_t   dummy;

   fMain = main;
   fList = main->GetList();
   fFirst = kTRUE;
   fFirstWidth = fFirstHeight = 0;

   FontStruct_t fs = TGLabel::GetDefaultFontStruct();

   // get standard width an height of a character
   fTWidth = gVirtualX->TextWidth(fs, "1234567890", 10) / 10;
   gVirtualX->GetFontProperties(fs, fTHeight, dummy);

   // the size of the main window are defined in units of a character
   // but the system does not understand this. We have to recalculate
   // the size into pixels.
   width  = main->GetWidth() * fTWidth;
   height = main->GetHeight() * fTHeight;

   main->Resize(width, height);
}

////////////////////////////////////////////////////////////////////////////////
///copy constructor

TGXYLayout::TGXYLayout(const TGXYLayout& xyl) :
  TGLayoutManager(xyl),
  fList(xyl.fList),
  fMain(xyl.fMain),
  fFirst(xyl.fFirst),
  fFirstWidth(xyl.fFirstWidth),
  fFirstHeight(xyl.fFirstHeight),
  fTWidth(xyl.fTWidth),
  fTHeight(xyl.fTHeight)
{
}

////////////////////////////////////////////////////////////////////////////////
///assignment operator

TGXYLayout& TGXYLayout::operator=(const TGXYLayout& xyl)
{
   if(this!=&xyl) {
      TGLayoutManager::operator=(xyl);
      fList=xyl.fList;
      fMain=xyl.fMain;
      fFirst=xyl.fFirst;
      fFirstWidth=xyl.fFirstWidth;
      fFirstHeight=xyl.fFirstHeight;
      fTWidth=xyl.fTWidth;
      fTHeight=xyl.fTHeight;
   }
   return *this;
}

////////////////////////////////////////////////////////////////////////////////
/// Recalculates the postion and the size of all widgets.

void TGXYLayout::Layout()
{
   TGFrameElement   *ptr;
   TGXYLayoutHints  *layout;
   Double_t          xFactor;
   Double_t          yFactor;
   Int_t             newX, newY;
   UInt_t            newW, newH;
   Double_t          temp;

   if (!fList) return;

   if (fFirst) {
      // save the original size of the frame. It is used to determin
      // if the user has changed the window
      fFirstWidth   = fMain->GetWidth();
      fFirstHeight  = fMain->GetHeight();
      fFirst        = kFALSE;
   }

   // get the factor of the increacement of the window
   xFactor = (Double_t)fMain->GetWidth() / (Double_t)fFirstWidth;
   if (xFactor < 1.0) xFactor = 1.0;
   yFactor = (Double_t)fMain->GetHeight() / (Double_t)fFirstHeight;
   if (yFactor < 1.0) yFactor = 1.0;

   // set the position an size for each widget and call the layout
   // function for each widget
   TIter next(fList);
   while ((ptr = (TGFrameElement *) next()))  {
      if (ptr->fState & kIsVisible) {
         layout = (TGXYLayoutHints*)ptr->fLayout;
         if (layout == 0)
            continue;

         temp = layout->GetX() * fTWidth ;
         if (layout->GetFlag() & TGXYLayoutHints::kLRubberX)
            temp *= xFactor;
         newX = (Int_t)(temp + 0.5);

         temp = layout->GetY() * fTHeight;
         if (layout->GetFlag() & TGXYLayoutHints::kLRubberY)
            temp *= yFactor;
         newY = (Int_t)(temp + 0.5);

         temp = layout->GetW() * fTWidth;
         if (layout->GetFlag() & TGXYLayoutHints::kLRubberW)
            temp *= xFactor;
         newW = (UInt_t)(temp + 0.5);

         temp = layout->GetH() * fTHeight;
         if (layout->GetFlag() & TGXYLayoutHints::kLRubberH)
            temp *= yFactor;
         newH = (UInt_t)(temp + 0.5);
         ptr->fFrame->MoveResize(newX, newY, newW, newH);
         ptr->fFrame->Layout();
      }
   }
}

////////////////////////////////////////////////////////////////////////////////
/// Returns the original size of the frame.

TGDimension TGXYLayout::GetDefaultSize() const
{
   TGDimension size(fFirstWidth, fFirstHeight);

   return size;
}

////////////////////////////////////////////////////////////////////////////////
/// Save XY layout manager as a C++ statement(s) on output stream.

void TGXYLayout::SavePrimitive(std::ostream &out, Option_t * /*option = ""*/)
{
   out << "new TGXYLayout(" << fMain->GetName() << ")";

}
<commit_msg>Speling.<commit_after>// @(#)root/gui:$Id$
// Author: Reiner Rohlfs   24/03/2002

/*************************************************************************
 * Copyright (C) 1995-2001, Rene Brun, Fons Rademakers and Reiner Rohlfs *
 * All rights reserved.                                                  *
 *                                                                       *
 * For the licensing terms see $ROOTSYS/LICENSE.                         *
 * For the list of contributors see $ROOTSYS/README/CREDITS.             *
 *************************************************************************/

//////////////////////////////////////////////////////////////////////////
//                                                                      //
// TGXYLayout                                                           //
//                                                                      //
// Is a layout manager where the position and the size of each widget   //
// in the frame are defined by X / Y - coordinates. The coordinates     //
// for each widget are defined by the TGXYLayoutHints. Therefore it     //
// is not possible to share a layout hint for several widgets.          //
//                                                                      //
// The coordinates (X, Y) and the size (W, H) are defined in units      //
// of the size of a typical character. Also the size of the             //
// TGCompositeFrame for which a TGXYLayout manager is used has to be    //
// defined in its constructor in units of the size of a character!      //
//                                                                      //
// It is not possible to use any other layout hint than the             //
// TGXYLayoutHints for this layout manager!                             //
//                                                                      //
// The rubberFlag in the constructor of the TGLXYLayoutHins defines     //
// how the position and the size of a widget is recalculated if the     //
// size of the frame is increased:                                      //
// - kLRubberX: The X - position (left edge) is increased by the same   //
//              factor as the width of the frame increases.             //
// - kLRubberY: The Y - position (upper edge) is increased by the same  //
//              factor as the height of the frame increases.            //
// - kLRubberW: The width of the widget is increased by the same        //
//              factor as the width of the frame increases.             //
// - kLRubberH: The height of the widget is increased by the same       //
//              factor as the height of the frame increases.            //
// But the size never becomes smaller than defined by the               //
// TGXYLayoutHints and the X and Y coordinates becomes never smaller    //
// than defined by the layout hints.                                    //
//                                                                      //
// TGXYLayoutHints                                                      //
//                                                                      //
// This layout hint must be used for the TGXYLouyout manager!           //
//                                                                      //
//                                                                      //
// Example how to use this layout manager:                              //
//                                                                      //
// TGMyFrame::TGMyFrame()                                               //
//    : TGMainFrame(gClient->GetRoot(), 30, 12)                         //
//    // frame is 30 character long and 12 character heigh              //
// {                                                                    //
//    SetLayoutManager(new TGXYLayout(this));                           //
//                                                                      //
//    // create a button of size 8 X 1.8 at position 20 / 1             //
//    TGTextButton * button;                                            //
//    button = new TGTextButton(this, "&Apply", 1);                     //
//    AddFrame(button, new TGXYLayoutHints(20, 1, 8, 1.8));             //
//                                                                      //
//    // create a listbox of size 18 X 10 at position 1 / 1.            //
//    // The height will increase if the frame height increases         //
//    TGListBox * listBox;                                              //
//    listBox = new TGListBox(this, 2);                                 //
//    AddFrame(listBox, new TGXYLayoutHints(1, 1, 18, 10,               //
//             TGXYLayoutHints::kLRubberX |                             //
//             TGXYLayoutHints::kLRubberY |                             //
//             TGXYLayoutHints::kLRubberH ));                           //
//    .                                                                 //
//    .                                                                 //
//    .                                                                 //
// }                                                                    //
//                                                                      //
// Normally there is one layout hint per widget. Therefore these        //
// can be deleted like in the following example in the desctuctor       //
// of the frame:                                                        //
//                                                                      //
// TGMyFrame::~TGMyFrame()                                              //
// {                                                                    //
//    // Destructor, deletes all frames and their layout hints.         //
//                                                                      //
//    TGFrameElement *ptr;                                              //
//                                                                      //
//    // delete all frames and layout hints                             //
//    if (fList) {                                                      //
//       TIter next(fList);                                             //
//       while ((ptr = (TGFrameElement *) next())) {                    //
//          if (ptr->fLayout)                                           //
//             delete ptr->fLayout;                                     //
//          if (ptr->fFrame)                                            //
//             delete ptr->fFrame;                                      //
//       }                                                              //
//    }                                                                 //
// }                                                                    //
//                                                                      //
//////////////////////////////////////////////////////////////////////////

#include "TGXYLayout.h"
#include "TGFrame.h"
#include "TGLabel.h"
#include "Riostream.h"

ClassImp(TGXYLayout)
ClassImp(TGXYLayoutHints)

////////////////////////////////////////////////////////////////////////////////
/// Constructor. The x, y, w and h define the position of the widget in
/// its frame and the size of the widget. The unit is the size of a
/// character. The rubberFlag defines how to move and to resize the
/// widget when the frame is resized. Default is moving the X and Y
/// position but keep the size of the widget.

TGXYLayoutHints::TGXYLayoutHints(Double_t x, Double_t y, Double_t w, Double_t h,
                                 UInt_t rubberFlag)
   : TGLayoutHints(kLHintsNormal, 0,0,0,0)
{
   fX    = x;
   fY    = y;
   fW    = w;
   fH    = h;
   fFlag = rubberFlag;
}

////////////////////////////////////////////////////////////////////////////////
/// Save XY layout hints as a C++ statement(s) on output stream.

void TGXYLayoutHints::SavePrimitive(std::ostream &out, Option_t * /*option = ""*/)
{
   TString flag = "";
   if (fFlag & kLRubberX) {
      if (flag.Length() == 0)  flag  = "TGXYLayoutHints::kLRubberX";
      else                     flag += " | TGXYLayoutHints::kLRubberX";
   }
   if (fFlag & kLRubberY) {
      if  (flag.Length() == 0) flag  = "TGXYLayoutHints::kLRubberY";
      else                      flag += " | TGXYLayoutHints::kLRubberY";
   }
   if (fFlag & kLRubberW) {
      if (flag.Length() == 0) flag  = "TGXYLayoutHints::kLRubberW";
      else                     flag += " | TGXYLayoutHints::kLRubberW";
   }
   if (fFlag & kLRubberH) {
      if (flag.Length() == 0) flag  = "TGXYLayoutHints::kLRubberH";
      else                     flag += " | TGXYLayoutHints::kLRubberH";
   }

   out << ", new TGXYLayoutHints(" << GetX() << ", " << GetY() << ", "
       << GetW() << ", " << GetH();

   if (!flag.Length())
      out << ")";
   else
      out << ", " << flag << ")";

}

////////////////////////////////////////////////////////////////////////////////
/// Constructor. The main is the frame for which this layout manager works.

TGXYLayout::TGXYLayout(TGCompositeFrame *main)
{
   UInt_t  width, height;
   Int_t   dummy;

   fMain = main;
   fList = main->GetList();
   fFirst = kTRUE;
   fFirstWidth = fFirstHeight = 0;

   FontStruct_t fs = TGLabel::GetDefaultFontStruct();

   // get standard width an height of a character
   fTWidth = gVirtualX->TextWidth(fs, "1234567890", 10) / 10;
   gVirtualX->GetFontProperties(fs, fTHeight, dummy);

   // the size of the main window are defined in units of a character
   // but the system does not understand this. We have to recalculate
   // the size into pixels.
   width  = main->GetWidth() * fTWidth;
   height = main->GetHeight() * fTHeight;

   main->Resize(width, height);
}

////////////////////////////////////////////////////////////////////////////////
///copy constructor

TGXYLayout::TGXYLayout(const TGXYLayout& xyl) :
  TGLayoutManager(xyl),
  fList(xyl.fList),
  fMain(xyl.fMain),
  fFirst(xyl.fFirst),
  fFirstWidth(xyl.fFirstWidth),
  fFirstHeight(xyl.fFirstHeight),
  fTWidth(xyl.fTWidth),
  fTHeight(xyl.fTHeight)
{
}

////////////////////////////////////////////////////////////////////////////////
///assignment operator

TGXYLayout& TGXYLayout::operator=(const TGXYLayout& xyl)
{
   if(this!=&xyl) {
      TGLayoutManager::operator=(xyl);
      fList=xyl.fList;
      fMain=xyl.fMain;
      fFirst=xyl.fFirst;
      fFirstWidth=xyl.fFirstWidth;
      fFirstHeight=xyl.fFirstHeight;
      fTWidth=xyl.fTWidth;
      fTHeight=xyl.fTHeight;
   }
   return *this;
}

////////////////////////////////////////////////////////////////////////////////
/// Recalculates the postion and the size of all widgets.

void TGXYLayout::Layout()
{
   TGFrameElement   *ptr;
   TGXYLayoutHints  *layout;
   Double_t          xFactor;
   Double_t          yFactor;
   Int_t             newX, newY;
   UInt_t            newW, newH;
   Double_t          temp;

   if (!fList) return;

   if (fFirst) {
      // save the original size of the frame. It is used to determin
      // if the user has changed the window
      fFirstWidth   = fMain->GetWidth();
      fFirstHeight  = fMain->GetHeight();
      fFirst        = kFALSE;
   }

   // get the factor of the increacement of the window
   xFactor = (Double_t)fMain->GetWidth() / (Double_t)fFirstWidth;
   if (xFactor < 1.0) xFactor = 1.0;
   yFactor = (Double_t)fMain->GetHeight() / (Double_t)fFirstHeight;
   if (yFactor < 1.0) yFactor = 1.0;

   // set the position an size for each widget and call the layout
   // function for each widget
   TIter next(fList);
   while ((ptr = (TGFrameElement *) next()))  {
      if (ptr->fState & kIsVisible) {
         layout = (TGXYLayoutHints*)ptr->fLayout;
         if (layout == 0)
            continue;

         temp = layout->GetX() * fTWidth ;
         if (layout->GetFlag() & TGXYLayoutHints::kLRubberX)
            temp *= xFactor;
         newX = (Int_t)(temp + 0.5);

         temp = layout->GetY() * fTHeight;
         if (layout->GetFlag() & TGXYLayoutHints::kLRubberY)
            temp *= yFactor;
         newY = (Int_t)(temp + 0.5);

         temp = layout->GetW() * fTWidth;
         if (layout->GetFlag() & TGXYLayoutHints::kLRubberW)
            temp *= xFactor;
         newW = (UInt_t)(temp + 0.5);

         temp = layout->GetH() * fTHeight;
         if (layout->GetFlag() & TGXYLayoutHints::kLRubberH)
            temp *= yFactor;
         newH = (UInt_t)(temp + 0.5);
         ptr->fFrame->MoveResize(newX, newY, newW, newH);
         ptr->fFrame->Layout();
      }
   }
}

////////////////////////////////////////////////////////////////////////////////
/// Returns the original size of the frame.

TGDimension TGXYLayout::GetDefaultSize() const
{
   TGDimension size(fFirstWidth, fFirstHeight);

   return size;
}

////////////////////////////////////////////////////////////////////////////////
/// Save XY layout manager as a C++ statement(s) on output stream.

void TGXYLayout::SavePrimitive(std::ostream &out, Option_t * /*option = ""*/)
{
   out << "new TGXYLayout(" << fMain->GetName() << ")";

}
<|endoftext|>


<commit_before>/*******************************************************************************
 * Copyright (c) 2009-2014, MAV'RIC Development Team
 * 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.
 *
 * 3. Neither the name of the copyright holder nor the names of its contributors
 * may be used to endorse or promote products derived from this software without
 * specific prior written permission.
 *
 * 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 HOLDER 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.
 ******************************************************************************/

/*******************************************************************************
 * \file 	serial_avr32.cpp
 *
 * \author 	MAV'RIC Team
 *
 * \brief 	Implementation of serial peripheral for avr32
 *
 ******************************************************************************/

#include <libopencm3/stm32/rcc.h>
#include <libopencm3/cm3/nvic.h>

#include "serial_stm32.hpp"

///< Array of 'this' pointers used for interrupt handling
static Serial_stm32* handlers_[SERIAL_STM32_MAX_NUMBER] = {0};

//------------------------------------------------------------------------------
// PUBLIC FUNCTIONS IMPLEMENTATION
//------------------------------------------------------------------------------

Serial_stm32::Serial_stm32(serial_stm32_conf_t config)
{
	config_			= config;
	irq_callback 	= 0;
}

bool Serial_stm32::init(void)
{
	// Enable the USART interrupt
	switch( config_.device )
	{
		case SERIAL_STM32_1:
			rcc_periph_clock_enable(RCC_USART1);
			nvic_enable_irq(NVIC_USART1_IRQ);
			handlers_[0] = this;
		break;

		case SERIAL_STM32_2:
			rcc_periph_clock_enable(RCC_USART2);
			nvic_enable_irq(NVIC_USART2_IRQ);
			handlers_[1] = this;
		break;

		case SERIAL_STM32_3:
			rcc_periph_clock_enable(RCC_USART3);
			nvic_enable_irq(NVIC_USART3_IRQ);
			handlers_[2] = this;
		break;

		case SERIAL_STM32_4:
			rcc_periph_clock_enable(RCC_UART4);
			nvic_enable_irq(NVIC_UART4_IRQ);
			handlers_[3] = this;
		break;

		case SERIAL_STM32_5:
			rcc_periph_clock_enable(RCC_UART5);
			nvic_enable_irq(NVIC_UART5_IRQ);
			handlers_[4] = this;
		break;

		case SERIAL_STM32_6:
			rcc_periph_clock_enable(RCC_USART6);
			nvic_enable_irq(NVIC_USART6_IRQ);
			handlers_[5] = this;
		break;

		case SERIAL_STM32_7:
			rcc_periph_clock_enable(RCC_UART7);
			nvic_enable_irq(NVIC_UART7_IRQ);
			handlers_[6] = this;
		break;

		case SERIAL_STM32_8:
			rcc_periph_clock_enable(RCC_UART8);
			nvic_enable_irq(NVIC_UART8_IRQ);
			handlers_[7] = this;
		break;

		default:
		break;
	}

	// Setup GPIO pins for TX
	gpio_mode_setup(config_.tx_port,
					GPIO_MODE_AF,
					GPIO_PUPD_NONE,
					config_.tx_pin);

	// Setup GPIO pins for RX
	gpio_mode_setup(config_.rx_port,
					GPIO_MODE_AF,
					GPIO_PUPD_NONE,
					config_.rx_pin);

	// Setup TX and RX pin as alternate function
	gpio_set_af(config_.tx_port, config_.tx_af, config_.tx_pin);
	gpio_set_af(config_.rx_port, config_.rx_af, config_.tx_pin);

	// Setup USART parameters
	usart_set_baudrate(config_.device, config_.baudrate);
	usart_set_databits(config_.device, config_.databits);
	usart_set_stopbits(config_.device, config_.stopbits);
	usart_set_mode(config_.device, config_.mode);
	usart_set_parity(config_.device, config_.parity);
	usart_set_flow_control(config_.device, config_.flow_control);

	// Enable RX interrupt
	usart_enable_rx_interrupt(config_.device);

	// Finally enable the USART
	usart_enable(config_.device);

	return true;
}

uint32_t Serial_stm32::readable(void)
{
	return rx_buffer_.readable();
}

uint32_t Serial_stm32::writeable(void)
{
	return tx_buffer_.writeable();
}

void Serial_stm32::flush(void)
{
	usart_enable_tx_interrupt(config_.device);

	// Wait until the transmit buffer is empty
	while( !tx_buffer_.empty() )
	{
		;
	}
}

bool Serial_stm32::attach(serial_interrupt_callback_t func)
{
	irq_callback = func;
	return true;
}

bool Serial_stm32::write(const uint8_t* bytes, const uint32_t size)
{
	bool ret = false;

	//  Queue byte
	if (writeable() >= size)
	{
		for (uint32_t i = 0; i < size; ++i)
		{
			tx_buffer_.put(bytes[i]);
		}
		ret = true;
	}

	// Start transmission
	if( tx_buffer_.readable() >= 1 )
	{
		usart_enable_tx_interrupt(config_.device);
	}

	return ret;
}

bool Serial_stm32::read(uint8_t* bytes, const uint32_t size)
{
	bool ret = false;

	if (readable() >= size)
	{
		ret = true;
		for( uint32_t i = 0; i < size; ++i )
		{
			ret &= rx_buffer_.get(bytes[i]);
		}
	}

	return ret;
}

//------------------------------------------------------------------------------
// PRIVATE FUNCTIONS IMPLEMENTATION
//------------------------------------------------------------------------------

/**
 * \brief 		Main irq function
 *
 * \details 	This function has to be static in order to be registerable
 * 				as interrupt handler. It does internally the dispatch to
 * 				call the 'irq_handler' function on the right object instance
 */
__attribute__((interrupt))
void usart1_isr(void)
{
	handlers_[0]->irq_handler();
}

__attribute__((interrupt))
void usart2_isr(void)
{
	handlers_[1]->irq_handler();
}

__attribute__((interrupt))
void usart3_isr(void)
{
	handlers_[2]->irq_handler();
}

__attribute__((interrupt))
void uart4_isr(void)
{
	handlers_[3]->irq_handler();
}

__attribute__((interrupt))
void uart5_isr(void)
{
	handlers_[4]->irq_handler();
}

__attribute__((interrupt))
void usart6_isr(void)
{
	handlers_[5]->irq_handler();
}

__attribute__((interrupt))
void uart7_isr(void)
{
	handlers_[6]->irq_handler();
}

__attribute__((interrupt))
void uart8_isr(void)
{
	handlers_[7]->irq_handler();
}

void Serial_stm32::irq_handler(void)
{
	uint8_t data = 0;

	// Check if we were called because of RXNE
	if( ((USART_CR1(config_.device) & USART_CR1_RXNEIE) != 0) &&
	    ((USART_SR(config_.device)  & USART_SR_RXNE)    != 0) )
	{

		// Retrieve the data from the peripheral
		data = usart_recv(config_.device);
		rx_buffer_.put_lossy(data);

		// Enable transmit interrupt so it sends back the data
		usart_enable_tx_interrupt(config_.device);
	}

	// Check if we were called because of TXE
	if( ((USART_CR1(config_.device) & USART_CR1_TXEIE) != 0) &&
	    ((USART_SR(config_.device)  & USART_SR_TXE)    != 0) )
	{
		if( tx_buffer_.readable() > 0 )
		{
			// Get data from output buffer
			tx_buffer_.get(data);

			// Put data into the transmit register
			usart_send(config_.device, data);
		}
		else
		{
			// Disable the TXE interrupt as we don't need it anymore
			usart_disable_tx_interrupt(config_.device);
		}
	}

	// Call callback function if attached
	if( irq_callback != 0 )
	{
		irq_callback(this);
	}
}<commit_msg>Fix typo<commit_after>/*******************************************************************************
 * Copyright (c) 2009-2014, MAV'RIC Development Team
 * 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.
 *
 * 3. Neither the name of the copyright holder nor the names of its contributors
 * may be used to endorse or promote products derived from this software without
 * specific prior written permission.
 *
 * 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 HOLDER 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.
 ******************************************************************************/

/*******************************************************************************
 * \file 	serial_avr32.cpp
 *
 * \author 	MAV'RIC Team
 *
 * \brief 	Implementation of serial peripheral for avr32
 *
 ******************************************************************************/

#include <libopencm3/stm32/rcc.h>
#include <libopencm3/cm3/nvic.h>

#include "serial_stm32.hpp"

///< Array of 'this' pointers used for interrupt handling
static Serial_stm32* handlers_[SERIAL_STM32_MAX_NUMBER] = {0};

//------------------------------------------------------------------------------
// PUBLIC FUNCTIONS IMPLEMENTATION
//------------------------------------------------------------------------------

Serial_stm32::Serial_stm32(serial_stm32_conf_t config)
{
	config_			= config;
	irq_callback 	= 0;
}

bool Serial_stm32::init(void)
{
	// Enable the USART interrupt
	switch( config_.device )
	{
		case SERIAL_STM32_1:
			rcc_periph_clock_enable(RCC_USART1);
			nvic_enable_irq(NVIC_USART1_IRQ);
			handlers_[0] = this;
		break;

		case SERIAL_STM32_2:
			rcc_periph_clock_enable(RCC_USART2);
			nvic_enable_irq(NVIC_USART2_IRQ);
			handlers_[1] = this;
		break;

		case SERIAL_STM32_3:
			rcc_periph_clock_enable(RCC_USART3);
			nvic_enable_irq(NVIC_USART3_IRQ);
			handlers_[2] = this;
		break;

		case SERIAL_STM32_4:
			rcc_periph_clock_enable(RCC_UART4);
			nvic_enable_irq(NVIC_UART4_IRQ);
			handlers_[3] = this;
		break;

		case SERIAL_STM32_5:
			rcc_periph_clock_enable(RCC_UART5);
			nvic_enable_irq(NVIC_UART5_IRQ);
			handlers_[4] = this;
		break;

		case SERIAL_STM32_6:
			rcc_periph_clock_enable(RCC_USART6);
			nvic_enable_irq(NVIC_USART6_IRQ);
			handlers_[5] = this;
		break;

		case SERIAL_STM32_7:
			rcc_periph_clock_enable(RCC_UART7);
			nvic_enable_irq(NVIC_UART7_IRQ);
			handlers_[6] = this;
		break;

		case SERIAL_STM32_8:
			rcc_periph_clock_enable(RCC_UART8);
			nvic_enable_irq(NVIC_UART8_IRQ);
			handlers_[7] = this;
		break;

		default:
		break;
	}

	// Setup GPIO pins for TX
	gpio_mode_setup(config_.tx_port,
					GPIO_MODE_AF,
					GPIO_PUPD_NONE,
					config_.tx_pin);

	// Setup GPIO pins for RX
	gpio_mode_setup(config_.rx_port,
					GPIO_MODE_AF,
					GPIO_PUPD_NONE,
					config_.rx_pin);

	// Setup TX and RX pins alternate function
	gpio_set_af(config_.tx_port, config_.tx_af, config_.tx_pin);
	gpio_set_af(config_.rx_port, config_.rx_af, config_.rx_pin);

	// Setup USART parameters
	usart_set_baudrate(config_.device, config_.baudrate);
	usart_set_databits(config_.device, config_.databits);
	usart_set_stopbits(config_.device, config_.stopbits);
	usart_set_mode(config_.device, config_.mode);
	usart_set_parity(config_.device, config_.parity);
	usart_set_flow_control(config_.device, config_.flow_control);

	// Enable RX interrupt
	usart_enable_rx_interrupt(config_.device);

	// Finally enable the USART
	usart_enable(config_.device);

	return true;
}

uint32_t Serial_stm32::readable(void)
{
	return rx_buffer_.readable();
}

uint32_t Serial_stm32::writeable(void)
{
	return tx_buffer_.writeable();
}

void Serial_stm32::flush(void)
{
	usart_enable_tx_interrupt(config_.device);

	// Wait until the transmit buffer is empty
	while( !tx_buffer_.empty() )
	{
		;
	}
}

bool Serial_stm32::attach(serial_interrupt_callback_t func)
{
	irq_callback = func;
	return true;
}

bool Serial_stm32::write(const uint8_t* bytes, const uint32_t size)
{
	bool ret = false;

	//  Queue byte
	if (writeable() >= size)
	{
		for (uint32_t i = 0; i < size; ++i)
		{
			tx_buffer_.put(bytes[i]);
		}
		ret = true;
	}

	// Start transmission
	if( tx_buffer_.readable() >= 1 )
	{
		usart_enable_tx_interrupt(config_.device);
	}

	return ret;
}

bool Serial_stm32::read(uint8_t* bytes, const uint32_t size)
{
	bool ret = false;

	if (readable() >= size)
	{
		ret = true;
		for( uint32_t i = 0; i < size; ++i )
		{
			ret &= rx_buffer_.get(bytes[i]);
		}
	}

	return ret;
}

//------------------------------------------------------------------------------
// PRIVATE FUNCTIONS IMPLEMENTATION
//------------------------------------------------------------------------------

/**
 * \brief 		Main irq function
 *
 * \details 	This function has to be static in order to be registerable
 * 				as interrupt handler. It does internally the dispatch to
 * 				call the 'irq_handler' function on the right object instance
 */
__attribute__((interrupt))
void usart1_isr(void)
{
	handlers_[0]->irq_handler();
}

__attribute__((interrupt))
void usart2_isr(void)
{
	handlers_[1]->irq_handler();
}

__attribute__((interrupt))
void usart3_isr(void)
{
	handlers_[2]->irq_handler();
}

__attribute__((interrupt))
void uart4_isr(void)
{
	handlers_[3]->irq_handler();
}

__attribute__((interrupt))
void uart5_isr(void)
{
	handlers_[4]->irq_handler();
}

__attribute__((interrupt))
void usart6_isr(void)
{
	handlers_[5]->irq_handler();
}

__attribute__((interrupt))
void uart7_isr(void)
{
	handlers_[6]->irq_handler();
}

__attribute__((interrupt))
void uart8_isr(void)
{
	handlers_[7]->irq_handler();
}

void Serial_stm32::irq_handler(void)
{
	uint8_t data = 0;

	// Check if we were called because of RXNE
	if( ((USART_CR1(config_.device) & USART_CR1_RXNEIE) != 0) &&
	    ((USART_SR(config_.device)  & USART_SR_RXNE)    != 0) )
	{

		// Retrieve the data from the peripheral
		data = usart_recv(config_.device);
		rx_buffer_.put_lossy(data);

		// Enable transmit interrupt so it sends back the data
		usart_enable_tx_interrupt(config_.device);
	}

	// Check if we were called because of TXE
	if( ((USART_CR1(config_.device) & USART_CR1_TXEIE) != 0) &&
	    ((USART_SR(config_.device)  & USART_SR_TXE)    != 0) )
	{
		if( tx_buffer_.readable() > 0 )
		{
			// Get data from output buffer
			tx_buffer_.get(data);

			// Put data into the transmit register
			usart_send(config_.device, data);
		}
		else
		{
			// Disable the TXE interrupt as we don't need it anymore
			usart_disable_tx_interrupt(config_.device);
		}
	}

	// Call callback function if attached
	if( irq_callback != 0 )
	{
		irq_callback(this);
	}
}<|endoftext|>


<commit_before>/*****************************************************************************
 * Media Library
 *****************************************************************************
 * Copyright (C) 2015 Hugo Beauzée-Luyssen, Videolabs
 *
 * Authors: Hugo Beauzée-Luyssen<hugo@beauzee.fr>
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation; either version 2.1 of the License, or
 * (at your option) any later version.
 *
 * This program 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 program; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
 *****************************************************************************/

#include "Parser.h"

#include <algorithm>

#include "IMedia.h"

Parser::Parser(DBConnection dbConnection , IMediaLibraryCb* cb)
    : m_stopParser( false )
    , m_dbConnection( dbConnection )
    , m_callback( cb )
    , m_nbParsed( 0 )
    , m_nbToParse( 0 )
    , m_paused( false )
{
}

Parser::~Parser()
{
    if ( m_thread.joinable() )
    {
        {
            std::lock_guard<std::mutex> lock( m_lock );
            if ( m_tasks.empty() == true )
                m_cond.notify_all();
            m_stopParser = true;
        }
        m_thread.join();
    }
    while ( m_tasks.empty() == false )
    {
        delete m_tasks.front();
        m_tasks.pop();
    }
}

void Parser::addService(std::unique_ptr<IMetadataService> service)
{
    m_services.emplace_back( std::move( service ) );
    std::push_heap( m_services.begin(), m_services.end(), []( const ServicePtr& a, const ServicePtr& b )
    {
        // We want higher priority first
        return a->priority() < b->priority();
    });
}

void Parser::parse( std::shared_ptr<Media> file )
{
    std::lock_guard<std::mutex> lock( m_lock );

    if ( m_services.size() == 0 )
        return;
    m_tasks.push( new Task( file, m_services, m_callback ) );
    updateStats( false, true );
    if ( m_paused == false )
        m_cond.notify_all();
}

void Parser::start()
{
    // Ensure we don't start multiple times.
    assert( m_thread.joinable() == false );

    m_thread = std::thread{ &Parser::run, this };
}

void Parser::pause()
{
    std::lock_guard<std::mutex> lock( m_lock );
    m_paused = true;
}

void Parser::resume()
{
    std::lock_guard<std::mutex> lock( m_lock );
    m_paused = false;
    m_cond.notify_all();
}

void Parser::run()
{
    LOG_INFO("Starting Parser thread");
    restore();

    while ( m_stopParser == false )
    {
        Task* task = nullptr;
        {
            std::unique_lock<std::mutex> lock( m_lock );
            if ( m_tasks.empty() == true || m_paused == true )
            {
                m_cond.wait( lock, [this]() {
                    return ( m_tasks.empty() == false && m_paused == false )
                            || m_stopParser == true;
                });
                // We might have been woken up because the parser is being destroyed
                if ( m_stopParser  == true )
                    break;
            }
            // Otherwise it's safe to assume we have at least one element.
            task = m_tasks.front();
            m_tasks.pop();
        }
        (*task->it)->run( task->file, task );
    }
    LOG_INFO("Exiting Parser thread");
}

void Parser::restore()
{
    static const std::string req = "SELECT * FROM " + policy::MediaTable::Name
            + " WHERE parsed = 0";
    auto media = Media::fetchAll( m_dbConnection, req );

    std::lock_guard<std::mutex> lock( m_lock );
    for ( auto& it : media )
    {
        auto m = std::static_pointer_cast<Media>( it );
        m_tasks.push( new Task( m, m_services, m_callback ) );
    }
}

void Parser::updateStats( bool newMediaParsed, bool newMediaQueued )
{
    if ( m_callback == nullptr )
        return;

    if ( newMediaParsed == true )
        m_nbParsed++;
    else if ( newMediaQueued == true )
        m_nbToParse++;
    else
        assert(false);

    if ( m_nbParsed == m_nbToParse )
    {
        m_callback->onParsingStatsUpdated( m_nbParsed, m_nbToParse );
        m_nbParsed = 0;
        m_nbToParse = 0;
        return;
    }
    // Only send an update every X new elem
    const uint32_t NbElems = 3;
    if ( ( newMediaParsed == true && m_nbParsed % NbElems == 0 ) ||
         ( newMediaQueued == true && m_nbToParse % NbElems == 0 ) )
    {
        m_callback->onParsingStatsUpdated( m_nbParsed, m_nbToParse );
    }
}

Parser::Task::Task(std::shared_ptr<Media> file, Parser::ServiceList& serviceList, IMediaLibraryCb* metadataCb )
    : file(file)
    , it( serviceList.begin() )
    , end( serviceList.end() )
    , cb( metadataCb )
{
}

void Parser::done(std::shared_ptr<Media> file, IMetadataService::Status status, void* data )
{
    Task *t = reinterpret_cast<Task*>( data );
    if ( status == IMetadataService::Status::TemporaryUnavailable ||
         status == IMetadataService::Status::Fatal )
    {
        updateStats( true, false );
        delete t;
        return;
    }
    else if ( status == IMetadataService::Status::Success )
    {
        t->cb->onFileUpdated( file );
    }

    ++t->it;
    if (t->it == t->end)
    {
        updateStats( true, false );
        file->markParsed();
        delete t;
        return;
    }
    std::lock_guard<std::mutex> lock( m_lock );
    m_tasks.push( t );
    m_cond.notify_all();
}
<commit_msg>Parser: Don't try to parse unparsed file when no services are available<commit_after>/*****************************************************************************
 * Media Library
 *****************************************************************************
 * Copyright (C) 2015 Hugo Beauzée-Luyssen, Videolabs
 *
 * Authors: Hugo Beauzée-Luyssen<hugo@beauzee.fr>
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation; either version 2.1 of the License, or
 * (at your option) any later version.
 *
 * This program 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 program; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
 *****************************************************************************/

#include "Parser.h"

#include <algorithm>

#include "IMedia.h"

Parser::Parser(DBConnection dbConnection , IMediaLibraryCb* cb)
    : m_stopParser( false )
    , m_dbConnection( dbConnection )
    , m_callback( cb )
    , m_nbParsed( 0 )
    , m_nbToParse( 0 )
    , m_paused( false )
{
}

Parser::~Parser()
{
    if ( m_thread.joinable() )
    {
        {
            std::lock_guard<std::mutex> lock( m_lock );
            if ( m_tasks.empty() == true )
                m_cond.notify_all();
            m_stopParser = true;
        }
        m_thread.join();
    }
    while ( m_tasks.empty() == false )
    {
        delete m_tasks.front();
        m_tasks.pop();
    }
}

void Parser::addService(std::unique_ptr<IMetadataService> service)
{
    m_services.emplace_back( std::move( service ) );
    std::push_heap( m_services.begin(), m_services.end(), []( const ServicePtr& a, const ServicePtr& b )
    {
        // We want higher priority first
        return a->priority() < b->priority();
    });
}

void Parser::parse( std::shared_ptr<Media> file )
{
    std::lock_guard<std::mutex> lock( m_lock );

    if ( m_services.size() == 0 )
        return;
    m_tasks.push( new Task( file, m_services, m_callback ) );
    updateStats( false, true );
    if ( m_paused == false )
        m_cond.notify_all();
}

void Parser::start()
{
    // Ensure we don't start multiple times.
    assert( m_thread.joinable() == false );

    m_thread = std::thread{ &Parser::run, this };
}

void Parser::pause()
{
    std::lock_guard<std::mutex> lock( m_lock );
    m_paused = true;
}

void Parser::resume()
{
    std::lock_guard<std::mutex> lock( m_lock );
    m_paused = false;
    m_cond.notify_all();
}

void Parser::run()
{
    LOG_INFO("Starting Parser thread");
    restore();

    while ( m_stopParser == false )
    {
        Task* task = nullptr;
        {
            std::unique_lock<std::mutex> lock( m_lock );
            if ( m_tasks.empty() == true || m_paused == true )
            {
                m_cond.wait( lock, [this]() {
                    return ( m_tasks.empty() == false && m_paused == false )
                            || m_stopParser == true;
                });
                // We might have been woken up because the parser is being destroyed
                if ( m_stopParser  == true )
                    break;
            }
            // Otherwise it's safe to assume we have at least one element.
            task = m_tasks.front();
            m_tasks.pop();
        }
        (*task->it)->run( task->file, task );
    }
    LOG_INFO("Exiting Parser thread");
}

void Parser::restore()
{
    if ( m_services.empty() == true )
        return;

    static const std::string req = "SELECT * FROM " + policy::MediaTable::Name
            + " WHERE parsed = 0";
    auto media = Media::fetchAll( m_dbConnection, req );

    std::lock_guard<std::mutex> lock( m_lock );
    for ( auto& it : media )
    {
        auto m = std::static_pointer_cast<Media>( it );
        m_tasks.push( new Task( m, m_services, m_callback ) );
    }
}

void Parser::updateStats( bool newMediaParsed, bool newMediaQueued )
{
    if ( m_callback == nullptr )
        return;

    if ( newMediaParsed == true )
        m_nbParsed++;
    else if ( newMediaQueued == true )
        m_nbToParse++;
    else
        assert(false);

    if ( m_nbParsed == m_nbToParse )
    {
        m_callback->onParsingStatsUpdated( m_nbParsed, m_nbToParse );
        m_nbParsed = 0;
        m_nbToParse = 0;
        return;
    }
    // Only send an update every X new elem
    const uint32_t NbElems = 3;
    if ( ( newMediaParsed == true && m_nbParsed % NbElems == 0 ) ||
         ( newMediaQueued == true && m_nbToParse % NbElems == 0 ) )
    {
        m_callback->onParsingStatsUpdated( m_nbParsed, m_nbToParse );
    }
}

Parser::Task::Task(std::shared_ptr<Media> file, Parser::ServiceList& serviceList, IMediaLibraryCb* metadataCb )
    : file(file)
    , it( serviceList.begin() )
    , end( serviceList.end() )
    , cb( metadataCb )
{
}

void Parser::done(std::shared_ptr<Media> file, IMetadataService::Status status, void* data )
{
    Task *t = reinterpret_cast<Task*>( data );
    if ( status == IMetadataService::Status::TemporaryUnavailable ||
         status == IMetadataService::Status::Fatal )
    {
        updateStats( true, false );
        delete t;
        return;
    }
    else if ( status == IMetadataService::Status::Success )
    {
        t->cb->onFileUpdated( file );
    }

    ++t->it;
    if (t->it == t->end)
    {
        updateStats( true, false );
        file->markParsed();
        delete t;
        return;
    }
    std::lock_guard<std::mutex> lock( m_lock );
    m_tasks.push( t );
    m_cond.notify_all();
}
<|endoftext|>


<commit_before>/***************************************************************************
 *   Copyright (c) 2011 Jrgen Riegel (juergen.riegel@web.de)               *
 *   Copyright (c) 2015 Eivind Kvedalen (eivind@kvedalen.name)             *
 *                                                                         *
 *   This file is part of the FreeCAD CAx development system.              *
 *                                                                         *
 *   This library is free software; you can redistribute it and/or         *
 *   modify it under the terms of the GNU Library General Public           *
 *   License as published by the Free Software Foundation; either          *
 *   version 2 of the License, or (at your option) any later version.      *
 *                                                                         *
 *   This library  is distributed in the hope that it will be useful,      *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU Library General Public License for more details.                  *
 *                                                                         *
 *   You should have received a copy of the GNU Library General Public     *
 *   License along with this library; see the file COPYING.LIB. If not,    *
 *   write to the Free Software Foundation, Inc., 59 Temple Place,         *
 *   Suite 330, Boston, MA  02111-1307, USA                                *
 *                                                                         *
 ***************************************************************************/

#include "PreCompiled.h"

#ifndef _PreComp_
# include <QFile>
# include <QFileInfo>
# include <QImage>
# include <QString>
# include <QMenu>
#endif

#include "ViewProviderSpreadsheet.h"
#include "SpreadsheetView.h"

#include <Mod/Spreadsheet/App/Sheet.h>
#include <App/Document.h>
#include <Gui/BitmapFactory.h>
#include <Gui/Application.h>
#include <Gui/MainWindow.h>
#include <Gui/Command.h>
#include <Base/FileInfo.h>
#include <Base/Stream.h>
#include <Base/Console.h>
#include <sstream>

using namespace Gui;
using namespace SpreadsheetGui;
using namespace Spreadsheet;

PROPERTY_SOURCE(SpreadsheetGui::ViewProviderSheet, Gui::ViewProviderDocumentObject)

ViewProviderSheet::ViewProviderSheet()
    : Gui::ViewProviderDocumentObject()
{
}

ViewProviderSheet::~ViewProviderSheet()
{
    if (!view.isNull()) {
        Gui::getMainWindow()->removeWindow(view);
//        delete view;
    }
}

void ViewProviderSheet::setDisplayMode(const char* ModeName)
{
    ViewProviderDocumentObject::setDisplayMode(ModeName);
}

std::vector<std::string> ViewProviderSheet::getDisplayModes(void) const
{
    std::vector<std::string> StrList;
    StrList.push_back("Spreadsheet");
    return StrList;
}

QIcon ViewProviderSheet::getIcon() const
{
    static const char * const Points_Feature_xpm[] = {
        "16 16 3 1",
        "       c None",
        ".      c #000000",
        "+      c #FFFFFF",
        "                ",
        "                ",
        "................",
        ".++++.++++.++++.",
        ".++++.++++.++++.",
        "................",
        ".++++.++++.++++.",
        ".++++.++++.++++.",
        "................",
        ".++++.++++.++++.",
        ".++++.++++.++++.",
        "................",
        ".++++.++++.++++.",
        ".++++.++++.++++.",
        "................",
        "                "};
    QPixmap px(Points_Feature_xpm);
    return px;
}

bool ViewProviderSheet::setEdit(int ModNum)
{
    if (ModNum == ViewProvider::Default) {
        if (!this->view) {
            showSpreadsheetView();
            view->viewAll();
        }
        Gui::getMainWindow()->setActiveWindow(this->view);
        return false;
    }
    return false;
}

bool ViewProviderSheet::doubleClicked()
{
    if (!this->view) {
        showSpreadsheetView();
        view->viewAll();
    }
    Gui::getMainWindow()->setActiveWindow(this->view);
    return true;
}

void ViewProviderSheet::setupContextMenu(QMenu * menu, QObject *receiver, const char *member)
{
    QAction* act;
    act = menu->addAction(QObject::tr("Show spreadsheet"), receiver, member);
    act->setData(QVariant((int)ViewProvider::Default));
}

Sheet *ViewProviderSheet::getSpreadsheetObject() const
{
    return freecad_dynamic_cast<Sheet>(pcObject);
}

bool ViewProviderSheet::onDelete(const std::vector<std::string> &)
{
    // If view is closed, delete the object
    if (view.isNull())
        return true;

    // View is not closed, delete cell contents instead if it is active
    if (Gui::Application::Instance->activeDocument()) {
        Gui::MDIView* activeWindow = Gui::getMainWindow()->activeWindow();
        SpreadsheetGui::SheetView * sheetView = freecad_dynamic_cast<SpreadsheetGui::SheetView>(activeWindow);

        if (sheetView) {
            Sheet * sheet = sheetView->getSheet();
            QModelIndexList selection = sheetView->selectedIndexes();

            if (selection.size() > 0) {
                Gui::Command::openCommand("Clear cell(s)");
                for (QModelIndexList::const_iterator it = selection.begin(); it != selection.end(); ++it) {
                    std::string address = CellAddress((*it).row(), (*it).column()).toString();
                    Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.clear('%s')", sheet->getNameInDocument(),
                                            address.c_str());
                }
                Gui::Command::commitCommand();
                Gui::Command::doCommand(Gui::Command::Doc, "App.ActiveDocument.recompute()");
            }
        }
    }

    return false;
}

SheetView *ViewProviderSheet::showSpreadsheetView()
{
    if (!view){
        Gui::Document* doc = Gui::Application::Instance->getDocument
            (this->pcObject->getDocument());
        view = new SheetView(doc, this->pcObject, Gui::getMainWindow());
        view->setWindowIcon(Gui::BitmapFactory().pixmap(":icons/Spreadsheet.svg"));
        view->setWindowTitle(QString::fromUtf8(pcObject->Label.getValue()) + QString::fromAscii("[*]"));
        Gui::getMainWindow()->addWindow(view);
        startEditing();
    }

    return view;
}

void ViewProviderSheet::updateData(const App::Property* prop)
{
    if (view)
        view->updateCell(prop);
}
<commit_msg>Spreadsheet: Fixed bug in setEdit method for Spreadsheet module (#2144)<commit_after>/***************************************************************************
 *   Copyright (c) 2011 Jrgen Riegel (juergen.riegel@web.de)               *
 *   Copyright (c) 2015 Eivind Kvedalen (eivind@kvedalen.name)             *
 *                                                                         *
 *   This file is part of the FreeCAD CAx development system.              *
 *                                                                         *
 *   This library is free software; you can redistribute it and/or         *
 *   modify it under the terms of the GNU Library General Public           *
 *   License as published by the Free Software Foundation; either          *
 *   version 2 of the License, or (at your option) any later version.      *
 *                                                                         *
 *   This library  is distributed in the hope that it will be useful,      *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU Library General Public License for more details.                  *
 *                                                                         *
 *   You should have received a copy of the GNU Library General Public     *
 *   License along with this library; see the file COPYING.LIB. If not,    *
 *   write to the Free Software Foundation, Inc., 59 Temple Place,         *
 *   Suite 330, Boston, MA  02111-1307, USA                                *
 *                                                                         *
 ***************************************************************************/

#include "PreCompiled.h"

#ifndef _PreComp_
# include <QFile>
# include <QFileInfo>
# include <QImage>
# include <QString>
# include <QMenu>
#endif

#include "ViewProviderSpreadsheet.h"
#include "SpreadsheetView.h"

#include <Mod/Spreadsheet/App/Sheet.h>
#include <App/Document.h>
#include <Gui/BitmapFactory.h>
#include <Gui/Application.h>
#include <Gui/MainWindow.h>
#include <Gui/Command.h>
#include <Base/FileInfo.h>
#include <Base/Stream.h>
#include <Base/Console.h>
#include <sstream>

using namespace Gui;
using namespace SpreadsheetGui;
using namespace Spreadsheet;

PROPERTY_SOURCE(SpreadsheetGui::ViewProviderSheet, Gui::ViewProviderDocumentObject)

ViewProviderSheet::ViewProviderSheet()
    : Gui::ViewProviderDocumentObject()
{
}

ViewProviderSheet::~ViewProviderSheet()
{
    if (!view.isNull()) {
        Gui::getMainWindow()->removeWindow(view);
//        delete view;
    }
}

void ViewProviderSheet::setDisplayMode(const char* ModeName)
{
    ViewProviderDocumentObject::setDisplayMode(ModeName);
}

std::vector<std::string> ViewProviderSheet::getDisplayModes(void) const
{
    std::vector<std::string> StrList;
    StrList.push_back("Spreadsheet");
    return StrList;
}

QIcon ViewProviderSheet::getIcon() const
{
    static const char * const Points_Feature_xpm[] = {
        "16 16 3 1",
        "       c None",
        ".      c #000000",
        "+      c #FFFFFF",
        "                ",
        "                ",
        "................",
        ".++++.++++.++++.",
        ".++++.++++.++++.",
        "................",
        ".++++.++++.++++.",
        ".++++.++++.++++.",
        "................",
        ".++++.++++.++++.",
        ".++++.++++.++++.",
        "................",
        ".++++.++++.++++.",
        ".++++.++++.++++.",
        "................",
        "                "};
    QPixmap px(Points_Feature_xpm);
    return px;
}

bool ViewProviderSheet::setEdit(int ModNum)
{
    if (ModNum == ViewProvider::Default) {
        if (!this->view) {
            showSpreadsheetView();
            view->viewAll();
        }
        Gui::getMainWindow()->setActiveWindow(this->view);
        return true;
    }
    return false;
}

bool ViewProviderSheet::doubleClicked()
{
    if (!this->view) {
        showSpreadsheetView();
        view->viewAll();
    }
    Gui::getMainWindow()->setActiveWindow(this->view);
    return true;
}

void ViewProviderSheet::setupContextMenu(QMenu * menu, QObject *receiver, const char *member)
{
    QAction* act;
    act = menu->addAction(QObject::tr("Show spreadsheet"), receiver, member);
    act->setData(QVariant((int)ViewProvider::Default));
}

Sheet *ViewProviderSheet::getSpreadsheetObject() const
{
    return freecad_dynamic_cast<Sheet>(pcObject);
}

bool ViewProviderSheet::onDelete(const std::vector<std::string> &)
{
    // If view is closed, delete the object
    if (view.isNull())
        return true;

    // View is not closed, delete cell contents instead if it is active
    if (Gui::Application::Instance->activeDocument()) {
        Gui::MDIView* activeWindow = Gui::getMainWindow()->activeWindow();
        SpreadsheetGui::SheetView * sheetView = freecad_dynamic_cast<SpreadsheetGui::SheetView>(activeWindow);

        if (sheetView) {
            Sheet * sheet = sheetView->getSheet();
            QModelIndexList selection = sheetView->selectedIndexes();

            if (selection.size() > 0) {
                Gui::Command::openCommand("Clear cell(s)");
                for (QModelIndexList::const_iterator it = selection.begin(); it != selection.end(); ++it) {
                    std::string address = CellAddress((*it).row(), (*it).column()).toString();
                    Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.clear('%s')", sheet->getNameInDocument(),
                                            address.c_str());
                }
                Gui::Command::commitCommand();
                Gui::Command::doCommand(Gui::Command::Doc, "App.ActiveDocument.recompute()");
            }
        }
    }

    return false;
}

SheetView *ViewProviderSheet::showSpreadsheetView()
{
    if (!view){
        Gui::Document* doc = Gui::Application::Instance->getDocument
            (this->pcObject->getDocument());
        view = new SheetView(doc, this->pcObject, Gui::getMainWindow());
        view->setWindowIcon(Gui::BitmapFactory().pixmap(":icons/Spreadsheet.svg"));
        view->setWindowTitle(QString::fromUtf8(pcObject->Label.getValue()) + QString::fromAscii("[*]"));
        Gui::getMainWindow()->addWindow(view);
        startEditing();
    }

    return view;
}

void ViewProviderSheet::updateData(const App::Property* prop)
{
    if (view)
        view->updateCell(prop);
}
<|endoftext|>


<commit_before>/*
   For more information, please see: http://software.sci.utah.edu

   The MIT License

   Copyright (c) 2009 Scientific Computing and Imaging Institute,
   University of Utah.

   Permission is hereby granted, free of charge, to any person obtaining a
   copy of this software and associated documentation files (the "Software"),
   to deal in the Software without restriction, including without limitation
   the rights to use, copy, modify, merge, publish, distribute, sublicense,
   and/or sell copies of the Software, and to permit persons to whom the
   Software is furnished to do so, subject to the following conditions:

   The above copyright notice and this permission notice shall be included
   in all copies or substantial portions of the Software.

   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
   OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
   THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
   LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
   FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
   DEALINGS IN THE SOFTWARE.
*/

#include <Modules/Legacy/Fields/AlignMeshBoundingBoxes.h>

namespace SCIRun {

using namespace SCIRun;

class AlignMeshBoundingBoxes : public Module {
  public:
    AlignMeshBoundingBoxes(GuiContext*);
    virtual ~AlignMeshBoundingBoxes() {}
    virtual void execute();

  private:
    SCIRunAlgo::AlignMeshBoundingBoxesAlgo algo_;
};

DECLARE_MAKER(AlignMeshBoundingBoxes)

AlignMeshBoundingBoxes::AlignMeshBoundingBoxes(GuiContext* ctx) :
  Module("AlignMeshBoundingBoxes", ctx, Source, "ChangeMesh", "SCIRun")
{
  algo_.set_progress_reporter(this);
}

void
AlignMeshBoundingBoxes::execute()
{
  // Get input field.
  FieldHandle ifield, ofield,objfield;
  MatrixHandle omatrix;

  get_input_handle("Input", ifield,true);
  get_input_handle("AlignmentField", objfield,true);

  if (inputs_changed_ || !oport_cached("Output") || !oport_cached("Transform"))
  {
    // Inform module that execution started
    update_state(Executing);

    // Core algorithm of the module
    if(!(algo_.run(ifield,objfield,ofield,omatrix))) return;

    // Send output to output ports
    send_output_handle("Output", ofield);
    send_output_handle("Transform", omatrix);
  }
}

} // End namespace SCIRun

<commit_msg>Delete class decl and maker<commit_after>/*
   For more information, please see: http://software.sci.utah.edu

   The MIT License

   Copyright (c) 2009 Scientific Computing and Imaging Institute,
   University of Utah.

   Permission is hereby granted, free of charge, to any person obtaining a
   copy of this software and associated documentation files (the "Software"),
   to deal in the Software without restriction, including without limitation
   the rights to use, copy, modify, merge, publish, distribute, sublicense,
   and/or sell copies of the Software, and to permit persons to whom the
   Software is furnished to do so, subject to the following conditions:

   The above copyright notice and this permission notice shall be included
   in all copies or substantial portions of the Software.

   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
   OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
   THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
   LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
   FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
   DEALINGS IN THE SOFTWARE.
*/

#include <Modules/Legacy/Fields/AlignMeshBoundingBoxes.h>

namespace SCIRun {

using namespace SCIRun;

AlignMeshBoundingBoxes::AlignMeshBoundingBoxes(GuiContext* ctx) :
  Module("AlignMeshBoundingBoxes", ctx, Source, "ChangeMesh", "SCIRun")
{
  algo_.set_progress_reporter(this);
}

void
AlignMeshBoundingBoxes::execute()
{
  // Get input field.
  FieldHandle ifield, ofield,objfield;
  MatrixHandle omatrix;

  get_input_handle("Input", ifield,true);
  get_input_handle("AlignmentField", objfield,true);

  if (inputs_changed_ || !oport_cached("Output") || !oport_cached("Transform"))
  {
    // Inform module that execution started
    update_state(Executing);

    // Core algorithm of the module
    if(!(algo_.run(ifield,objfield,ofield,omatrix))) return;

    // Send output to output ports
    send_output_handle("Output", ofield);
    send_output_handle("Transform", omatrix);
  }
}

} // End namespace SCIRun

<|endoftext|>