<commit_before>/******************************************************************************\
* EventHandler.cpp                                                             *
* An event handler providing GUI-like events                                   *
*                                                                              *
*                                                                              *
* Copyright (C) 2006 by Leandro Motta Barros.                                  *
*                                                                              *
* This program is distributed under the OpenSceneGraph Public License. You     *
* should have received a copy of it with the source distribution, in a file    *
* named 'COPYING.txt'.                                                         *
\******************************************************************************/

#include "OSGUIsh/EventHandler.hpp"
#include <boost/lexical_cast.hpp>

namespace OSGUIsh
{

   // - EventHandler::EventHandler ---------------------------------------------
   EventHandler::EventHandler(
      osgProducer::Viewer& viewer,
      const FocusPolicyFactory& kbdPolicyFactory,
      const FocusPolicyFactory& wheelPolicyFactory)
      : viewer_(viewer),
        kbdFocusPolicy_(kbdPolicyFactory.create (kbdFocus_)),
        wheelFocusPolicy_(wheelPolicyFactory.create (wheelFocus_))
   {
      addNode (NodePtr());

      for (int i = 0; i < MOUSE_BUTTON_COUNT; ++i)
      {
         nodeThatGotMouseDown_[i] = NodePtr();
         nodeThatGotClick_[i] = NodePtr();
         timeOfLastClick_[i] = -1.0;
      }
   }

   // - EventHandler::handle ---------------------------------------------------
   bool EventHandler::handle (const osgGA::GUIEventAdapter& ea,
                              osgGA::GUIActionAdapter&)
   {
      switch (ea.getEventType())
      {
         case osgGA::GUIEventAdapter::FRAME:
            handleFrameEvent (ea);
            break;

         case osgGA::GUIEventAdapter::PUSH:
            handlePushEvent (ea);
            break;

         case osgGA::GUIEventAdapter::RELEASE:
            handleReleaseEvent (ea);
            break;

         case osgGA::GUIEventAdapter::KEYDOWN:
            handleKeyDownEvent (ea);
            break;

         case osgGA::GUIEventAdapter::KEYUP:
            handleKeyUpEvent (ea);
            break;

         case osgGA::GUIEventAdapter::SCROLL:
            handleScrollEvent (ea);
            break;

         default:
            break;
      }

      kbdFocusPolicy_->updateFocus (ea, nodeUnderMouse_);
      wheelFocusPolicy_->updateFocus (ea, nodeUnderMouse_);

      return handleReturnValues_[ea.getEventType()];
   }

   // - EventHandler::addNode --------------------------------------------------
   void EventHandler::addNode (const osg::ref_ptr<osg::Node> node)
   {
#     define OSGUISH_EVENTHANDLER_ADD_EVENT(EVENT) \
         signals_[node][#EVENT] = SignalPtr (new EventHandler::Signal_t());

      OSGUISH_EVENTHANDLER_ADD_EVENT (MouseEnter);
      OSGUISH_EVENTHANDLER_ADD_EVENT (MouseLeave);
      OSGUISH_EVENTHANDLER_ADD_EVENT (MouseMove);
      OSGUISH_EVENTHANDLER_ADD_EVENT (MouseDown);
      OSGUISH_EVENTHANDLER_ADD_EVENT (MouseUp);
      OSGUISH_EVENTHANDLER_ADD_EVENT (Click);
      OSGUISH_EVENTHANDLER_ADD_EVENT (DoubleClick);
      OSGUISH_EVENTHANDLER_ADD_EVENT (MouseWheelUp);
      OSGUISH_EVENTHANDLER_ADD_EVENT (MouseWheelDown);
      OSGUISH_EVENTHANDLER_ADD_EVENT (KeyUp);
      OSGUISH_EVENTHANDLER_ADD_EVENT (KeyDown);

#     undef OSGUISH_EVENTHANDLER_ADD_EVENT
   }

   // - EventHandler::getSignal ------------------------------------------------
   EventHandler::SignalPtr EventHandler::getSignal(
      const NodePtr node, const std::string& signal)
   {
       SignalsMap_t::const_iterator signalsCollectionIter =
          signals_.find (node);

      if (signalsCollectionIter == signals_.end())
      {
         throw std::runtime_error(
            ("Trying to get a signal of an unknown node: '" + node->getName()
             + "' (" + boost::lexical_cast<std::string>(node.get())
             + ").").c_str());
      }

      SignalCollection_t::const_iterator signalIter =
         signalsCollectionIter->second.find (signal);

      if (signalIter == signalsCollectionIter->second.end())
      {
         throw std::runtime_error (("Trying to get an unknown signal: '"
                                    + signal + "'.").c_str());
      }

      return signalIter->second;
   }

   // - EventHandler::setKeyboardFocus -----------------------------------------
   void EventHandler::setKeyboardFocus (const NodePtr node)
   {
      kbdFocus_ = node;
   }

   // - EventHandler::setMouseWheelFocus ---------------------------------------
   void EventHandler::setMouseWheelFocus (const NodePtr node)
   {
      wheelFocus_ = node;
   }

   // - EventHandler::setKeyboardFocusPolicy -----------------------------------
   void EventHandler::setKeyboardFocusPolicy(
      const FocusPolicyFactory& policyFactory)
   {
      kbdFocusPolicy_ = policyFactory.create (kbdFocus_);
   }

   // - EventHandler::setMouseWheelFocusPolicy ---------------------------------
   void EventHandler::setMouseWheelFocusPolicy(
      const FocusPolicyFactory& policyFactory)
   {
      wheelFocusPolicy_ = policyFactory.create (wheelFocus_);
   }

   // - EventHandler::getObservedNode ------------------------------------------
   NodePtr EventHandler::getObservedNode (const osg::NodePath& nodePath)
   {
      typedef osg::NodePath::const_iterator iter_t;
      for (iter_t p = nodePath.begin(); p != nodePath.end(); ++p)
      {
         if (signals_.find (NodePtr(*p)) != signals_.end())
            return NodePtr(*p);
      }

      return NodePtr();
   }

   // - EventHandler::handleFrameEvent -----------------------------------------
   void EventHandler::handleFrameEvent (const osgGA::GUIEventAdapter& ea)
   {
      // Find out who is, and who was under the mouse pointer
      hitList_.clear();
      viewer_.computeIntersections (ea.getX(), ea.getY(), hitList_);

      NodePtr currentNodeUnderMouse;
      osg::Vec3 currentPositionUnderMouse;

      if (hitList_.size() > 0)
      {
         currentNodeUnderMouse = getObservedNode (hitList_[0].getNodePath());
         assert (signals_.find (currentNodeUnderMouse) != signals_.end()
                 && "'getObservedNode()' returned an invalid value!");

         currentPositionUnderMouse = hitList_[0].getLocalIntersectPoint();
      }

      NodePtr prevNodeUnderMouse = nodeUnderMouse_;
      osg::Vec3 prevPositionUnderMouse = positionUnderMouse_;

      nodeUnderMouse_ = currentNodeUnderMouse;
      positionUnderMouse_ = currentPositionUnderMouse;

      // Trigger the events
      if (currentNodeUnderMouse == prevNodeUnderMouse)
      {
         if (prevNodeUnderMouse.valid()
             && currentPositionUnderMouse != prevPositionUnderMouse)
         {
            signals_[currentNodeUnderMouse]["MouseMove"]->operator()(
               ea, currentNodeUnderMouse);
         }
      }
      else // currentNodeUnderMouse != prevNodeUnderMouse
      {
         if (!currentNodeUnderMouse.valid())
         {
            signals_[prevNodeUnderMouse]["MouseLeave"]->operator()(
               ea, prevNodeUnderMouse);
         }
         else if (!prevNodeUnderMouse.valid())
         {
            signals_[currentNodeUnderMouse]["MouseEnter"]->operator()(
               ea, currentNodeUnderMouse);
         }
         else // different and both are valid
         {
            signals_[prevNodeUnderMouse]["MouseLeave"]->operator()(
               ea, prevNodeUnderMouse);
            signals_[currentNodeUnderMouse]["MouseEnter"]->operator()(
               ea, currentNodeUnderMouse);
         }
      }
   }

   // - EventHandler::handlePushEvent ------------------------------------------
   void EventHandler::handlePushEvent (const osgGA::GUIEventAdapter& ea)
   {
      // Trigger a "MouseDown" signal.
      if (nodeUnderMouse_.valid())
      {
         signals_[nodeUnderMouse_]["MouseDown"]->operator()(
            ea, nodeUnderMouse_);
      }

      // Do the bookkeeping for "Click" and "DoubleClick"
      MouseButton button = getMouseButton (ea);
      nodeThatGotMouseDown_[button] = nodeUnderMouse_;
   }

   // - EventHandler::handleReleaseEvent ---------------------------------------
   void EventHandler::handleReleaseEvent (const osgGA::GUIEventAdapter& ea)
   {
      const double DOUBLE_CLICK_INTERVAL = 0.3;

      if (nodeUnderMouse_.valid())
      {
         MouseButton button = getMouseButton (ea);

         // First the trivial case: the "MouseUp" event
         signals_[nodeUnderMouse_]["MouseUp"]->operator()(
            ea, nodeUnderMouse_);

         // Now, the trickier ones: "Click" and "DoubleClick"
         if (nodeUnderMouse_ == nodeThatGotMouseDown_[button])
         {
            signals_[nodeUnderMouse_]["Click"]->operator()(
               ea, nodeUnderMouse_);

            const double now = ea.getTime();

            if (now - timeOfLastClick_[button] < DOUBLE_CLICK_INTERVAL
                && nodeUnderMouse_ == nodeThatGotClick_[button])
            {
               signals_[nodeUnderMouse_]["DoubleClick"]->operator()(
                  ea, nodeUnderMouse_);
            }

            nodeThatGotClick_[button] = nodeUnderMouse_;
            timeOfLastClick_[button] = now;
         }
      }
   }

   // - EventHandler::handleKeyDownEvent ---------------------------------------
   void EventHandler::handleKeyDownEvent (const osgGA::GUIEventAdapter& ea)
   {
      signals_[kbdFocus_]["KeyDown"]->operator()(ea, kbdFocus_);
   }

   // - EventHandler::handleKeyUpEvent -----------------------------------------
   void EventHandler::handleKeyUpEvent (const osgGA::GUIEventAdapter& ea)
   {
      signals_[kbdFocus_]["KeyUp"]->operator()(ea, kbdFocus_);
   }

   // - EventHandler::handleScrollEvent ----------------------------------------
   void EventHandler::handleScrollEvent (const osgGA::GUIEventAdapter& ea)
   {
      switch (ea.getScrollingMotion())
      {
         case osgGA::GUIEventAdapter::SCROLL_UP:
         {
            signals_[wheelFocus_]["MouseWheelUp"]->operator()(ea, wheelFocus_);
            break;
         }

         case osgGA::GUIEventAdapter::SCROLL_DOWN:
         {
            signals_[wheelFocus_]["MouseWheelDown"]->operator()(ea, wheelFocus_);
            break;
         }

         default:
            break; // ignore other events
      }
   }

   // - EventHandler::getMouseButton -------------------------------------------
   EventHandler::MouseButton EventHandler::getMouseButton(
      const osgGA::GUIEventAdapter& ea)
   {
      switch (ea.getButton())
      {
         case osgGA::GUIEventAdapter::LEFT_MOUSE_BUTTON:
            return LEFT_MOUSE_BUTTON;
         case osgGA::GUIEventAdapter::MIDDLE_MOUSE_BUTTON:
            return MIDDLE_MOUSE_BUTTON;
         case osgGA::GUIEventAdapter::RIGHT_MOUSE_BUTTON:
            return RIGHT_MOUSE_BUTTON;
         default:
         {
            assert (false && "Got an invalid mouse button code. Is 'ea' really "
                    "a mouse event?");
         }
      }
   }

} // namespace OSGUIsh
<commit_msg>Simplified the implementation of "MouseEnter" and "MouseLeave" events in 'EventHandler::handleFrameEvent()'.<commit_after>/******************************************************************************\
* EventHandler.cpp                                                             *
* An event handler providing GUI-like events                                   *
*                                                                              *
*                                                                              *
* Copyright (C) 2006 by Leandro Motta Barros.                                  *
*                                                                              *
* This program is distributed under the OpenSceneGraph Public License. You     *
* should have received a copy of it with the source distribution, in a file    *
* named 'COPYING.txt'.                                                         *
\******************************************************************************/

#include "OSGUIsh/EventHandler.hpp"
#include <boost/lexical_cast.hpp>

namespace OSGUIsh
{

   // - EventHandler::EventHandler ---------------------------------------------
   EventHandler::EventHandler(
      osgProducer::Viewer& viewer,
      const FocusPolicyFactory& kbdPolicyFactory,
      const FocusPolicyFactory& wheelPolicyFactory)
      : viewer_(viewer),
        kbdFocusPolicy_(kbdPolicyFactory.create (kbdFocus_)),
        wheelFocusPolicy_(wheelPolicyFactory.create (wheelFocus_))
   {
      addNode (NodePtr());

      for (int i = 0; i < MOUSE_BUTTON_COUNT; ++i)
      {
         nodeThatGotMouseDown_[i] = NodePtr();
         nodeThatGotClick_[i] = NodePtr();
         timeOfLastClick_[i] = -1.0;
      }
   }

   // - EventHandler::handle ---------------------------------------------------
   bool EventHandler::handle (const osgGA::GUIEventAdapter& ea,
                              osgGA::GUIActionAdapter&)
   {
      switch (ea.getEventType())
      {
         case osgGA::GUIEventAdapter::FRAME:
            handleFrameEvent (ea);
            break;

         case osgGA::GUIEventAdapter::PUSH:
            handlePushEvent (ea);
            break;

         case osgGA::GUIEventAdapter::RELEASE:
            handleReleaseEvent (ea);
            break;

         case osgGA::GUIEventAdapter::KEYDOWN:
            handleKeyDownEvent (ea);
            break;

         case osgGA::GUIEventAdapter::KEYUP:
            handleKeyUpEvent (ea);
            break;

         case osgGA::GUIEventAdapter::SCROLL:
            handleScrollEvent (ea);
            break;

         default:
            break;
      }

      kbdFocusPolicy_->updateFocus (ea, nodeUnderMouse_);
      wheelFocusPolicy_->updateFocus (ea, nodeUnderMouse_);

      return handleReturnValues_[ea.getEventType()];
   }

   // - EventHandler::addNode --------------------------------------------------
   void EventHandler::addNode (const osg::ref_ptr<osg::Node> node)
   {
#     define OSGUISH_EVENTHANDLER_ADD_EVENT(EVENT) \
         signals_[node][#EVENT] = SignalPtr (new EventHandler::Signal_t());

      OSGUISH_EVENTHANDLER_ADD_EVENT (MouseEnter);
      OSGUISH_EVENTHANDLER_ADD_EVENT (MouseLeave);
      OSGUISH_EVENTHANDLER_ADD_EVENT (MouseMove);
      OSGUISH_EVENTHANDLER_ADD_EVENT (MouseDown);
      OSGUISH_EVENTHANDLER_ADD_EVENT (MouseUp);
      OSGUISH_EVENTHANDLER_ADD_EVENT (Click);
      OSGUISH_EVENTHANDLER_ADD_EVENT (DoubleClick);
      OSGUISH_EVENTHANDLER_ADD_EVENT (MouseWheelUp);
      OSGUISH_EVENTHANDLER_ADD_EVENT (MouseWheelDown);
      OSGUISH_EVENTHANDLER_ADD_EVENT (KeyUp);
      OSGUISH_EVENTHANDLER_ADD_EVENT (KeyDown);

#     undef OSGUISH_EVENTHANDLER_ADD_EVENT
   }

   // - EventHandler::getSignal ------------------------------------------------
   EventHandler::SignalPtr EventHandler::getSignal(
      const NodePtr node, const std::string& signal)
   {
       SignalsMap_t::const_iterator signalsCollectionIter =
          signals_.find (node);

      if (signalsCollectionIter == signals_.end())
      {
         throw std::runtime_error(
            ("Trying to get a signal of an unknown node: '" + node->getName()
             + "' (" + boost::lexical_cast<std::string>(node.get())
             + ").").c_str());
      }

      SignalCollection_t::const_iterator signalIter =
         signalsCollectionIter->second.find (signal);

      if (signalIter == signalsCollectionIter->second.end())
      {
         throw std::runtime_error (("Trying to get an unknown signal: '"
                                    + signal + "'.").c_str());
      }

      return signalIter->second;
   }

   // - EventHandler::setKeyboardFocus -----------------------------------------
   void EventHandler::setKeyboardFocus (const NodePtr node)
   {
      kbdFocus_ = node;
   }

   // - EventHandler::setMouseWheelFocus ---------------------------------------
   void EventHandler::setMouseWheelFocus (const NodePtr node)
   {
      wheelFocus_ = node;
   }

   // - EventHandler::setKeyboardFocusPolicy -----------------------------------
   void EventHandler::setKeyboardFocusPolicy(
      const FocusPolicyFactory& policyFactory)
   {
      kbdFocusPolicy_ = policyFactory.create (kbdFocus_);
   }

   // - EventHandler::setMouseWheelFocusPolicy ---------------------------------
   void EventHandler::setMouseWheelFocusPolicy(
      const FocusPolicyFactory& policyFactory)
   {
      wheelFocusPolicy_ = policyFactory.create (wheelFocus_);
   }

   // - EventHandler::getObservedNode ------------------------------------------
   NodePtr EventHandler::getObservedNode (const osg::NodePath& nodePath)
   {
      typedef osg::NodePath::const_iterator iter_t;
      for (iter_t p = nodePath.begin(); p != nodePath.end(); ++p)
      {
         if (signals_.find (NodePtr(*p)) != signals_.end())
            return NodePtr(*p);
      }

      return NodePtr();
   }

   // - EventHandler::handleFrameEvent -----------------------------------------
   void EventHandler::handleFrameEvent (const osgGA::GUIEventAdapter& ea)
   {
      // Find out who is, and who was under the mouse pointer
      hitList_.clear();
      viewer_.computeIntersections (ea.getX(), ea.getY(), hitList_);

      NodePtr currentNodeUnderMouse;
      osg::Vec3 currentPositionUnderMouse;

      if (hitList_.size() > 0)
      {
         currentNodeUnderMouse = getObservedNode (hitList_[0].getNodePath());
         assert (signals_.find (currentNodeUnderMouse) != signals_.end()
                 && "'getObservedNode()' returned an invalid value!");

         currentPositionUnderMouse = hitList_[0].getLocalIntersectPoint();
      }

      NodePtr prevNodeUnderMouse = nodeUnderMouse_;
      osg::Vec3 prevPositionUnderMouse = positionUnderMouse_;

      nodeUnderMouse_ = currentNodeUnderMouse;
      positionUnderMouse_ = currentPositionUnderMouse;

      // Trigger the events
      if (currentNodeUnderMouse == prevNodeUnderMouse)
      {
         if (prevNodeUnderMouse.valid()
             && currentPositionUnderMouse != prevPositionUnderMouse)
         {
            signals_[currentNodeUnderMouse]["MouseMove"]->operator()(
               ea, currentNodeUnderMouse);
         }
      }
      else // currentNodeUnderMouse != prevNodeUnderMouse
      {
         if (prevNodeUnderMouse.valid())
         {
            signals_[prevNodeUnderMouse]["MouseLeave"]->operator()(
               ea, prevNodeUnderMouse);
         }

         if (currentNodeUnderMouse.valid())
         {
            signals_[currentNodeUnderMouse]["MouseEnter"]->operator()(
               ea, currentNodeUnderMouse);
         }
      }
   }

   // - EventHandler::handlePushEvent ------------------------------------------
   void EventHandler::handlePushEvent (const osgGA::GUIEventAdapter& ea)
   {
      // Trigger a "MouseDown" signal.
      if (nodeUnderMouse_.valid())
      {
         signals_[nodeUnderMouse_]["MouseDown"]->operator()(
            ea, nodeUnderMouse_);
      }

      // Do the bookkeeping for "Click" and "DoubleClick"
      MouseButton button = getMouseButton (ea);
      nodeThatGotMouseDown_[button] = nodeUnderMouse_;
   }

   // - EventHandler::handleReleaseEvent ---------------------------------------
   void EventHandler::handleReleaseEvent (const osgGA::GUIEventAdapter& ea)
   {
      const double DOUBLE_CLICK_INTERVAL = 0.3;

      if (nodeUnderMouse_.valid())
      {
         MouseButton button = getMouseButton (ea);

         // First the trivial case: the "MouseUp" event
         signals_[nodeUnderMouse_]["MouseUp"]->operator()(
            ea, nodeUnderMouse_);

         // Now, the trickier ones: "Click" and "DoubleClick"
         if (nodeUnderMouse_ == nodeThatGotMouseDown_[button])
         {
            signals_[nodeUnderMouse_]["Click"]->operator()(
               ea, nodeUnderMouse_);

            const double now = ea.getTime();

            if (now - timeOfLastClick_[button] < DOUBLE_CLICK_INTERVAL
                && nodeUnderMouse_ == nodeThatGotClick_[button])
            {
               signals_[nodeUnderMouse_]["DoubleClick"]->operator()(
                  ea, nodeUnderMouse_);
            }

            nodeThatGotClick_[button] = nodeUnderMouse_;
            timeOfLastClick_[button] = now;
         }
      }
   }

   // - EventHandler::handleKeyDownEvent ---------------------------------------
   void EventHandler::handleKeyDownEvent (const osgGA::GUIEventAdapter& ea)
   {
      signals_[kbdFocus_]["KeyDown"]->operator()(ea, kbdFocus_);
   }

   // - EventHandler::handleKeyUpEvent -----------------------------------------
   void EventHandler::handleKeyUpEvent (const osgGA::GUIEventAdapter& ea)
   {
      signals_[kbdFocus_]["KeyUp"]->operator()(ea, kbdFocus_);
   }

   // - EventHandler::handleScrollEvent ----------------------------------------
   void EventHandler::handleScrollEvent (const osgGA::GUIEventAdapter& ea)
   {
      switch (ea.getScrollingMotion())
      {
         case osgGA::GUIEventAdapter::SCROLL_UP:
         {
            signals_[wheelFocus_]["MouseWheelUp"]->operator()(ea, wheelFocus_);
            break;
         }

         case osgGA::GUIEventAdapter::SCROLL_DOWN:
         {
            signals_[wheelFocus_]["MouseWheelDown"]->operator()(ea, wheelFocus_);
            break;
         }

         default:
            break; // ignore other events
      }
   }

   // - EventHandler::getMouseButton -------------------------------------------
   EventHandler::MouseButton EventHandler::getMouseButton(
      const osgGA::GUIEventAdapter& ea)
   {
      switch (ea.getButton())
      {
         case osgGA::GUIEventAdapter::LEFT_MOUSE_BUTTON:
            return LEFT_MOUSE_BUTTON;
         case osgGA::GUIEventAdapter::MIDDLE_MOUSE_BUTTON:
            return MIDDLE_MOUSE_BUTTON;
         case osgGA::GUIEventAdapter::RIGHT_MOUSE_BUTTON:
            return RIGHT_MOUSE_BUTTON;
         default:
         {
            assert (false && "Got an invalid mouse button code. Is 'ea' really "
                    "a mouse event?");
         }
      }
   }

} // namespace OSGUIsh
<|endoftext|>


<commit_before>#include "combat.hpp"

Combat::Combat() {
    ia = false;
//    ia = true;
    state = CombatState::player_atk;
    player = new Player(0);
    //    enemy = new IaEnemy(1);
    enemy = new Player(1);
    scorePlayer = new Score(0);
    scoreEnemy = new Score(1);
    ASSERT(axisT.loadFromFile(WORK_DIR+"Resources/axis.png"));
    _axis.setTexture(axisT);
    _axis.setOrigin(axisT.getSize().x/2,axisT.getSize().y);
    _axis.setPosition(W_WIDTH/2,W_HEIGHT/2+18);
    initShader();
    SoundManager::load();
    SoundManager::playMusic("music");

}

Combat::~Combat(){
    for(std::vector<Wave*>::iterator w = waves.begin(); w != waves.end();){
        w=waves.erase(w);
    }
}

Combat::Combat(bool ia) {
    this->ia = ia;
    player = new Player(0);
    state = CombatState::player_atk;
    if (ia) enemy = new IaEnemy(1);
    else enemy = new Player(1);
    initShader();
}

bool Combat::isAttack() const {
    return state == CombatState::player_atk or state == CombatState::enemy_atk;
}

bool Combat::isPlayerOne() const {
    return state == CombatState::player_def or state == CombatState::player_atk;
}

void Combat::updateHalo() {
    switch(state) {
    case CombatState::player_def:
    case CombatState::enemy_def:
        _shaderHalo.setParameter("type", 0.0f);
        break;
    case CombatState::enemy_atk:
        _shaderHalo.setParameter("type", 1.0f);
        break;
    case CombatState::player_atk:
        _shaderHalo.setParameter("type", 2.0f);
        break;
    default:
        break;
    }

}

void Combat::initShader() {
    time = 0;
    _text.create(W_WIDTH, W_HEIGHT);
    _background.setTexture(_text);
    _shader.loadFromFile(WORK_DIR+"Resources/shader.frag", sf::Shader::Fragment);
    _shader.setParameter("resolution", sf::Vector2f(W_WIDTH, W_HEIGHT));
    _shader.setParameter("time", time);

    ASSERT(_haloT.loadFromFile(WORK_DIR+"Resources/platform-halo.png"));
    _halo.setTexture(_haloT);
    _halo.setPosition(W_WIDTH*0.05f, W_HEIGHT*0.5f);
    ASSERT(_plataformT.loadFromFile(WORK_DIR+"Resources/platforms-spreadsheet.png"));
    _plataform.setTexture(_plataformT);
    _plataform.setPosition(W_WIDTH*0.05f, W_HEIGHT*0.5f);

    sf::IntRect rect = sf::IntRect(0, 0, _plataformT.getSize().x/2, _plataformT.getSize().y);
    _plataform.setTextureRect(rect);
    _shaderHalo.loadFromFile(WORK_DIR+"Resources/halo.frag", sf::Shader::Fragment);
    _shaderHalo.setParameter("time", time);
    updateHalo();
}

void Combat::update(float deltaTime, sf::RenderWindow *window) {
    player->update(deltaTime, window);
    bool aux = enemy->update(deltaTime, window);
    if (ia) enemyManager(aux); //end of player two ia rythm

    time += deltaTime;
    _shader.setParameter("time", time);
    for(std::vector<Wave*>::iterator w = waves.begin(); w != waves.end();){
        if ((*w)->getDirection() && (*w)->getPosition().x >= 1024) w=waves.erase(w);
        else if (!(*w)->getDirection() && (*w)->getPosition().x <= 0) w=waves.erase(w);

        else{
            (*w)->update(deltaTime);
            ++w;
        }
    }
    _shaderHalo.setParameter("time", time);

    if (isPlayerOne()) {
        if(_halo.getPosition().x != W_WIDTH*0.05f)
            toEnemy = false;
    }
    else  {
        if(_halo.getPosition().x != W_WIDTH*0.65f)
            toEnemy = true;
    }
    animationTo(toEnemy, deltaTime);

    updateHalo();

    sf::IntRect rect;
    if (isPlayerOne())
        rect = sf::IntRect(0, 0, _plataformT.getSize().x/2, _plataformT.getSize().y);
    else
        rect = sf::IntRect(_plataformT.getSize().x/2, 0, _plataformT.getSize().x/2, _plataformT.getSize().y);
    _plataform.setTextureRect(rect);
}

void Combat::draw(sf::RenderWindow *window) {

    window->draw(_background, &_shader);
    window->draw(_plataform);
    player->draw(window);
    enemy->draw(window);
    window->draw(_halo, &_shaderHalo);
    scorePlayer->draw(window);
    scoreEnemy->draw(window);
    window->draw(_axis);
    for(std::vector<Wave*>::iterator w = waves.begin(); w != waves.end(); ++w){
        window->draw(*(*w));
    }
}

void Combat::updateEvents(sf::Event e) {
    if (isPlayerOne()) {
        if(e.type == sf::Event::KeyPressed && e.key.code == sf::Keyboard::C && !isAttack()) doMahWaves(!isPlayerOne());
        bool compasFinish = !player->event(e);
        enemyManager(compasFinish);
    }
    else if (!ia) {
        if(e.type == sf::Event::KeyPressed && e.key.code == sf::Keyboard::C && !isAttack()) doMahWaves(!isPlayerOne());
        bool compasFinish = !enemy->event(e);
        enemyManager(compasFinish);
    }
}

void Combat::enemyManager(bool compasFinish) {
    if(compasFinish) {
        Compas compas;
        if(isPlayerOne()) compas = enemy->getAttack();
        else compas = player->getAttack();

        if(!isAttack()) {
            if(!ia) {
                bool hit;
                if(isPlayerOne()) hit = !player->hitBy(compas);
                else hit = !enemy->hitBy(compas);
                if(hit) {
                    if(isPlayerOne())
                        scoreEnemy->incrisScore();
                    else
                        scorePlayer->incrisScore();
                }
            }
        }
        else if(compas.isFailed())
            state = (CombatState::combatState) ((((int) state)+1) % 4);
        state = (CombatState::combatState) ((((int) state)+1) % 4);
    }
}

void Combat::doMahWaves(bool p) {
    std::cout << "defensa jugador " << p << std::endl;
    std::vector<int> notes;
    if(p){
        notes = player->getAttack().getNotes();
    }
    else notes = enemy->getAttack().getNotes();
    if (notes.size() > 0){
        int anterior = notes[0];
        if(!p) anterior = 256+256*anterior;
        else anterior = 768-256*anterior;
        for(int i = 0; i < notes.size(); ++i){
            std::cout << notes[i] << std::endl;
            Wave* w = new Wave(p);
            //if(!p) w->setPosition(anterior,500);
            //else w->setPosition(512-512*anterior,500);
            w->setPosition(anterior,200);
            if(i<notes.size()) {
                if(!p) anterior += 176*notes[i+1];
                else anterior -= 176*notes[i+1];
            }
            waves.push_back(w);
        }

//        int anterior = 1;
//        if(!p) anterior = 512+256*anterior;
//        else anterior = 512-256*anterior;
//        for(int i = 0; i < 20; ++i){
//            //std::cout << 0 << std::endl;
//            Wave* w = new Wave(p);
//            //if(!p) w->setPosition(anterior,500);
//            //else w->setPosition(512-512*anterior,500);
//            w->setPosition(anterior,200);
//            if(i<20) {
//                if(!p) anterior += 128*4;
//                else anterior -= 128*4;
//            }
//            waves.push_back(w);
        }

}

void Combat::animationTo(bool toEnemy, float deltaTime) {
   if (toEnemy) {
        _halo.move(deltaTime*2000, 0.0f);
        _plataform.move(deltaTime*2000, 0.0f);
        if (_halo.getPosition().x > W_WIDTH*0.65f) {
            _halo.setPosition(W_WIDTH*0.65f, _halo.getPosition().y);
            _plataform.setPosition(W_WIDTH*0.65f, _plataform.getPosition().y);
        }
   }
   else {
       _halo.move(deltaTime*-2000, 0.0f);
       _plataform.move(deltaTime*-2000, 0.0f);
       if (_halo.getPosition().x < W_WIDTH*0.05f) {
           _halo.setPosition(W_WIDTH*0.05f, _halo.getPosition().y);
           _plataform.setPosition(W_WIDTH*0.05f, _plataform.getPosition().y);
       }
   }
}
<commit_msg>Parece que ahora funciona<commit_after>#include "combat.hpp"

Combat::Combat() {
    ia = false;
//    ia = true;
    state = CombatState::player_atk;
    player = new Player(0);
    //    enemy = new IaEnemy(1);
    enemy = new Player(1);
    scorePlayer = new Score(0);
    scoreEnemy = new Score(1);
    ASSERT(axisT.loadFromFile(WORK_DIR+"Resources/axis.png"));
    _axis.setTexture(axisT);
    _axis.setOrigin(axisT.getSize().x/2,axisT.getSize().y);
    _axis.setPosition(W_WIDTH/2,W_HEIGHT/2+18);
    initShader();
    SoundManager::load();
    SoundManager::playMusic("music");

}

Combat::~Combat(){
    for(std::vector<Wave*>::iterator w = waves.begin(); w != waves.end();){
        w=waves.erase(w);
    }
}

Combat::Combat(bool ia) {
    this->ia = ia;
    player = new Player(0);
    state = CombatState::player_atk;
    if (ia) enemy = new IaEnemy(1);
    else enemy = new Player(1);
    initShader();
}

bool Combat::isAttack() const {
    return state == CombatState::player_atk or state == CombatState::enemy_atk;
}

bool Combat::isPlayerOne() const {
    return state == CombatState::player_def or state == CombatState::player_atk;
}

void Combat::updateHalo() {
    switch(state) {
    case CombatState::player_def:
    case CombatState::enemy_def:
        _shaderHalo.setParameter("type", 0.0f);
        break;
    case CombatState::enemy_atk:
        _shaderHalo.setParameter("type", 1.0f);
        break;
    case CombatState::player_atk:
        _shaderHalo.setParameter("type", 2.0f);
        break;
    default:
        break;
    }

}

void Combat::initShader() {
    time = 0;
    _text.create(W_WIDTH, W_HEIGHT);
    _background.setTexture(_text);
    _shader.loadFromFile(WORK_DIR+"Resources/shader.frag", sf::Shader::Fragment);
    _shader.setParameter("resolution", sf::Vector2f(W_WIDTH, W_HEIGHT));
    _shader.setParameter("time", time);

    ASSERT(_haloT.loadFromFile(WORK_DIR+"Resources/platform-halo.png"));
    _halo.setTexture(_haloT);
    _halo.setPosition(W_WIDTH*0.05f, W_HEIGHT*0.5f);
    ASSERT(_plataformT.loadFromFile(WORK_DIR+"Resources/platforms-spreadsheet.png"));
    _plataform.setTexture(_plataformT);
    _plataform.setPosition(W_WIDTH*0.05f, W_HEIGHT*0.5f);

    sf::IntRect rect = sf::IntRect(0, 0, _plataformT.getSize().x/2, _plataformT.getSize().y);
    _plataform.setTextureRect(rect);
    _shaderHalo.loadFromFile(WORK_DIR+"Resources/halo.frag", sf::Shader::Fragment);
    _shaderHalo.setParameter("time", time);
    updateHalo();
}

void Combat::update(float deltaTime, sf::RenderWindow *window) {
    player->update(deltaTime, window);
    bool aux = enemy->update(deltaTime, window);
    if (ia) enemyManager(aux); //end of player two ia rythm

    time += deltaTime;
    _shader.setParameter("time", time);
    for(std::vector<Wave*>::iterator w = waves.begin(); w != waves.end();){
        if ((*w)->getDirection() && (*w)->getPosition().x >= 1024) w=waves.erase(w);
        else if (!(*w)->getDirection() && (*w)->getPosition().x <= 0) w=waves.erase(w);

        else{
            (*w)->update(deltaTime);
            ++w;
        }
    }
    _shaderHalo.setParameter("time", time);

    if (isPlayerOne()) {
        if(_halo.getPosition().x != W_WIDTH*0.05f)
            toEnemy = false;
    }
    else  {
        if(_halo.getPosition().x != W_WIDTH*0.65f)
            toEnemy = true;
    }
    animationTo(toEnemy, deltaTime);

    updateHalo();

    sf::IntRect rect;
    if (isPlayerOne())
        rect = sf::IntRect(0, 0, _plataformT.getSize().x/2, _plataformT.getSize().y);
    else
        rect = sf::IntRect(_plataformT.getSize().x/2, 0, _plataformT.getSize().x/2, _plataformT.getSize().y);
    _plataform.setTextureRect(rect);
}

void Combat::draw(sf::RenderWindow *window) {

    window->draw(_background, &_shader);
    window->draw(_plataform);
    player->draw(window);
    enemy->draw(window);
    window->draw(_halo, &_shaderHalo);
    scorePlayer->draw(window);
    scoreEnemy->draw(window);
    window->draw(_axis);
    for(std::vector<Wave*>::iterator w = waves.begin(); w != waves.end(); ++w){
        window->draw(*(*w));
    }
}

void Combat::updateEvents(sf::Event e) {
    if (isPlayerOne()) {
        if(e.type == sf::Event::KeyPressed && e.key.code == sf::Keyboard::C && !isAttack()) doMahWaves(!isPlayerOne());
        bool compasFinish = !player->event(e);
        enemyManager(compasFinish);
    }
    else if (!ia) {
        if(e.type == sf::Event::KeyPressed && e.key.code == sf::Keyboard::C && !isAttack()) doMahWaves(!isPlayerOne());
        bool compasFinish = !enemy->event(e);
        enemyManager(compasFinish);
    }
}

void Combat::enemyManager(bool compasFinish) {  //To do: considerar si hay ia
    if(compasFinish) {
        Compas compas;

        switch(state) {
            case CombatState::player_def:
                compas = enemy->getAttack();
                if(!player->hitBy(compas)) {
                    scoreEnemy->incrisScore();
                }
                state = CombatState::player_atk;
                break;
            case CombatState::player_atk:
                compas = player->getAttack();
                if(compas.isFailed()) {
                    state = CombatState::enemy_atk;
                }
                else state = CombatState::enemy_def;
                break;
            case CombatState::enemy_def:
                compas = player->getAttack();
                if(!enemy->hitBy(compas)) {
                    scorePlayer->incrisScore();
                }
                state = CombatState::enemy_atk;
                break;
            case CombatState::enemy_atk:
                compas = enemy->getAttack();
                if(compas.isFailed()) {
                    state = CombatState::player_atk;
                }
                else state = CombatState::player_def;
                break;
            default:
                break;
        }
    }
}

void Combat::doMahWaves(bool p) {
    std::cout << "defensa jugador " << p << std::endl;
    std::vector<int> notes;
    if(p){
        notes = player->getAttack().getNotes();
    }
    else notes = enemy->getAttack().getNotes();
    if (notes.size() > 0){
        int anterior = notes[0];
        if(!p) anterior = 256+256*anterior;
        else anterior = 768-256*anterior;
        for(int i = 0; i < notes.size(); ++i){
            std::cout << notes[i] << std::endl;
            Wave* w = new Wave(p);
            //if(!p) w->setPosition(anterior,500);
            //else w->setPosition(512-512*anterior,500);
            w->setPosition(anterior,200);
            if(i<notes.size()) {
                if(!p) anterior += 176*notes[i+1];
                else anterior -= 176*notes[i+1];
            }
            waves.push_back(w);
        }

//        int anterior = 1;
//        if(!p) anterior = 512+256*anterior;
//        else anterior = 512-256*anterior;
//        for(int i = 0; i < 20; ++i){
//            //std::cout << 0 << std::endl;
//            Wave* w = new Wave(p);
//            //if(!p) w->setPosition(anterior,500);
//            //else w->setPosition(512-512*anterior,500);
//            w->setPosition(anterior,200);
//            if(i<20) {
//                if(!p) anterior += 128*4;
//                else anterior -= 128*4;
//            }
//            waves.push_back(w);
        }

}

void Combat::animationTo(bool toEnemy, float deltaTime) {
   if (toEnemy) {
        _halo.move(deltaTime*2000, 0.0f);
        _plataform.move(deltaTime*2000, 0.0f);
        if (_halo.getPosition().x > W_WIDTH*0.65f) {
            _halo.setPosition(W_WIDTH*0.65f, _halo.getPosition().y);
            _plataform.setPosition(W_WIDTH*0.65f, _plataform.getPosition().y);
        }
   }
   else {
       _halo.move(deltaTime*-2000, 0.0f);
       _plataform.move(deltaTime*-2000, 0.0f);
       if (_halo.getPosition().x < W_WIDTH*0.05f) {
           _halo.setPosition(W_WIDTH*0.05f, _halo.getPosition().y);
           _plataform.setPosition(W_WIDTH*0.05f, _plataform.getPosition().y);
       }
   }
}
<|endoftext|>


<commit_before>// @(#)root/eve7:$Id$
// Authors: Matevz Tadel & Alja Mrak-Tadel, 2018

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

#include <ROOT/REveDataProxyBuilderBase.hxx>
#include <ROOT/REveProjectionManager.hxx>
#include <ROOT/REveViewContext.hxx>
#include <ROOT/REveCompound.hxx>

#include <cassert>

using namespace ROOT::Experimental;
namespace REX = ROOT::Experimental;

REveDataProxyBuilderBase::Product::Product(std::string iViewType, const REveViewContext* c) : m_viewType(iViewType), m_viewContext(c), m_elements(0)
{
   m_elements = new REveCompound("ProxyProduct", "", false);
   m_elements->IncDenyDestroy();
}

//______________________________________________________________________________

REveDataProxyBuilderBase::REveDataProxyBuilderBase(const std::string &type):
   m_type(type),
   m_collection(nullptr),
   //   m_interactionList(0),
   m_haveWindow(false)
{
}

REveDataProxyBuilderBase::Product::~Product()
{
   // remove product from projected scene (RhoPhi or RhoZ)
   for (auto i : m_elements->RefProjecteds())
   {
      REveElement *projected = i->GetProjectedAsElement();
      projected->GetMother()->RemoveElement(projected);
   }

   // XXXX This might break now ... m_elements will auto drestruct, no?
   // We don't set incdenydestroy or additional something, do we?

   // remove from 3D scenes
   if (m_elements->HasMother())
   {
      m_elements->GetMother()->RemoveElement(m_elements);
   }

   m_elements->Annihilate();
}

//______________________________________________________________________________
void REveDataProxyBuilderBase::SetCollection(REveDataCollection* c)
{
   m_collection = c;
}

//______________________________________________________________________________
/*
void
REveDataProxyBuilderBase::SetInteractionList(REveDataInteractionList* l, const std::string& purpose )
{
   // Called if willHandleInteraction() returns false. Purpose ignored by default.

   m_interactionList = l;
}
*/

//______________________________________________________________________________
void REveDataProxyBuilderBase::Build()
{
   if (m_collection)
   {
      printf("Base %p %s %s\n", m_collection, m_collection->GetCName(), m_type.c_str());
      try
      {
         size_t itemSize = (size_t)m_collection->GetNItems(); //cashed

         Clean();
         for (Product_it i = m_products.begin(); i != m_products.end(); ++i)
         {
            printf("build() %s \n", m_collection->GetCName());
            REveElement* elms = (*i)->m_elements;
            size_t oldSize = elms->NumChildren();

            if (HaveSingleProduct())
            {
               Build(m_collection, elms, (*i)->m_viewContext);
            }
            else
            {
               BuildViewType(m_collection, elms, (*i)->m_viewType, (*i)->m_viewContext);
            }

            // Project all children of current product.
            // If product is not registered into any projection-manager,
            // this does nothing.
            REveProjectable* pable = dynamic_cast<REveProjectable*>(elms);
            if (pable->HasProjecteds())
            {
               // loop projected holders
               for (REveProjectable::ProjList_i pi = pable->BeginProjecteds(); pi != pable->EndProjecteds(); ++pi)
               {
                  REveProjectionManager *pmgr = (*pi)->GetManager();
                  Float_t oldDepth = pmgr->GetCurrentDepth();
                  pmgr->SetCurrentDepth(m_layer);
                  size_t cnt = 0;

                  REveElement* projectedAsElement = (*pi)->GetProjectedAsElement();
                  REveElement::List_i parentIt = projectedAsElement->BeginChildren();
                  for (REveElement::List_i prodIt = elms->BeginChildren(); prodIt != elms->EndChildren(); ++prodIt, ++cnt)
                  {
                      // reused projected holder
                     if (cnt < oldSize)
                     {
                        if ((*parentIt)->NumChildren()) {
                            // update projected (mislleading name)
                           for ( REveElement::List_i pci = (*parentIt)->BeginChildren(); pci != (*parentIt)->EndChildren(); pci++)
                               pmgr->ProjectChildrenRecurse(*parentIt);
                        }
                        else {
                            // import projectable
                           pmgr->SubImportChildren(*prodIt, *parentIt);
                        }

                        ++parentIt;
                     }
                     else if (cnt < itemSize)
                     {
                        // new product holder
                        pmgr->SubImportElements(*prodIt, projectedAsElement);
                     }
                     else
                     {
                        break;
                     }
                  }
                  pmgr->SetCurrentDepth(oldDepth);
               }
            }

            /*
            if (m_interactionList && itemSize > oldSize)
            {
               REveElement::List_i elIt = elms->BeginChildren();
               for (size_t cnt = 0; cnt < itemSize; ++cnt, ++elIt)
               {
                  if (cnt >= oldSize )
                       m_interactionList->Added(*elIt, cnt);
               }
            }
            */
         }
      }
      catch (const std::runtime_error& iException)
      {
         std::cout << "Caught exception in build function for item " << m_collection->GetCName() << ":\n"
                              << iException.what() << std::endl;
         exit(1);
      }
   }
}

//______________________________________________________________________________
void
REveDataProxyBuilderBase::Build(const REveDataCollection*, REveElement*, const REveViewContext*)
{
   assert("virtual Build(const REveEventItem*, REveElement*, const REveViewContext*) not implemented by inherited class");
}

void
REveDataProxyBuilderBase::BuildViewType(const REveDataCollection*, REveElement*, std::string, const REveViewContext*)
{
   assert("virtual BuildViewType(const FWEventItem*, TEveElementList*, FWViewType::EType, const FWViewContext*) not implemented by inherited class");
}

//______________________________________________________________________________

REveElement*
REveDataProxyBuilderBase::CreateProduct( std::string viewType, const REveViewContext* viewContext)
{
   if ( m_products.empty() == false)
   {
      if (HaveSingleProduct()) {
         return m_products.back()->m_elements;
      }
      else {

         for (Product_it i = m_products.begin(); i!= m_products.end(); ++i)
         {
            if (viewType == (*i)->m_viewType)
               return (*i)->m_elements;
         }
      }
   }

   Product* product = new Product(viewType, viewContext);
   m_products.push_back(product);

   if (m_collection)
   {
      // debug info in eve browser
      product->m_elements->SetName(Form("product %s", m_collection->GetCName()));
   }
   return product->m_elements;
}

//______________________________________________________________________________

//namespace {
//   void applyVisAttrToChildren(REveElement* p) {
//      for (auto it = p->BeginChildren(); it != p->EndChildren(); ++it)
//      {
//         REveElement* c = *it;
//         if (c->GetMainColor() != p->GetMainColor())
//         {
//            c->SetMainColor(p->GetMainColor());
//            printf("apply color %d to %s\n", p->GetMainColor(), c->GetCName());
//         }
//         c->SetRnrSelf(p->GetRnrSelf());
//         applyVisAttrToChildren(c);
//      }
//   }
//}

void
REveDataProxyBuilderBase::ModelChanges(const REveDataCollection::Ids_t& iIds, Product* p)
{
   printf("REveDataProxyBuilderBase::ModelChanges  %s \n",  m_collection->GetCName());
   REveElement* elms = p->m_elements;
   assert(m_collection && static_cast<int>(m_collection->GetNItems()) <= elms->NumChildren() && "can not use default modelChanges implementation");

   for (REveDataCollection::Ids_t::const_iterator it = iIds.begin(); it != iIds.end(); ++it)
   {
      int itemIdx = *it;
      REveDataItem* item = m_collection->GetDataItem(itemIdx);

      // printf("Edit compound for item index %d \n", itemIdx);
      // imitate FWInteractionList::modelChanges
      REveElement::List_i itElement = elms->BeginChildren();
      std::advance(itElement, itemIdx);
      REveElement* comp = *itElement;
      comp->SetMainColor(item->GetMainColor());
      comp->SetRnrSelf(item->GetRnrSelf());

      // AMT temporary workaround for use of compunds
      // applyVisAttrToChildren(comp);

      if (VisibilityModelChanges(*it, *itElement, p->m_viewContext))
      {
         elms->ProjectChild(*itElement);
         printf("---REveDataProxyBuilderBase project child\n ");
      }
   }
}

//______________________________________________________________________________

void
REveDataProxyBuilderBase::ModelChanges(const REveDataCollection::Ids_t& iIds)
{
  if(m_haveWindow) {
    for (Product_it i = m_products.begin(); i!= m_products.end(); ++i)
    {
       ModelChanges(iIds, *i);
    }
    m_modelsChanged=false;
  } else {
    m_modelsChanged=true;
  }
}

//______________________________________________________________________________
void
REveDataProxyBuilderBase::CollectionChanged(const REveDataCollection* /*iItem*/)
{
   if(m_haveWindow) {
      Build();
   }
}

//------------------------------------------------------------------------------

void
REveDataProxyBuilderBase::SetupAddElement(REveElement* el, REveElement* parent, bool color) const
{
   SetupElement(el, color);
   // AMT -- this temprary to get right tooltip
   el->SetName(parent->GetName());
   parent->AddElement(el);
}

/** This method is invoked to setup the per element properties of the various
    objects being drawn.
  */
void
REveDataProxyBuilderBase::SetupElement(REveElement* el, bool color) const
{
   el->CSCTakeMotherAsMaster();
   el->SetPickable(true);
   el->SetMainColor(m_collection->GetMainColor());
   if (color)
   {
      el->CSCApplyMainColorToMatchingChildren();
      el->CSCApplyMainTransparencyToMatchingChildren();
      el->SetMainColor(m_collection->GetMainColor());
      el->SetMainTransparency(m_collection->GetMainTransparency());
   }
}

REveCompound*
REveDataProxyBuilderBase::CreateCompound(bool set_color, bool propagate_color_to_all_children) const
{
   REveCompound* c = new REveCompound();
   c->CSCTakeMotherAsMaster();
   c->CSCImplySelectAllChildren();
   c->SetPickable(true);
   if (set_color)
   {
      c->SetMainColor(m_collection->GetMainColor());
      c->SetMainTransparency(m_collection->GetMainTransparency());
   }
   if (propagate_color_to_all_children)
   {
      c->CSCApplyMainColorToAllChildren();
      c->CSCApplyMainTransparencyToAllChildren();
   }
   else
   {
      c->CSCApplyMainColorToMatchingChildren();
      c->CSCApplyMainTransparencyToMatchingChildren();
   }
   return c;
}

//______________________________________________________________________________

void
REveDataProxyBuilderBase::Clean()
{
   // Cleans local common element list.
   for (Product_it i = m_products.begin(); i != m_products.end(); ++i)
   {
      if ((*i)->m_elements)
         (*i)->m_elements->DestroyElements();
   }

   CleanLocal();
}

void
REveDataProxyBuilderBase::CleanLocal()
{
   // Cleans local common element list.
}

void
REveDataProxyBuilderBase::CollectionBeingDestroyed(const REveDataCollection* /*iItem*/)
{
   m_collection = 0;

   CleanLocal();

   for (Product_it i = m_products.begin(); i!= m_products.end(); i++)
   {

      // (*i)->m_scaleConnection.disconnect();
      delete (*i);
   }

   m_products.clear();
}

bool
REveDataProxyBuilderBase::VisibilityModelChanges(int, REveElement*, const REveViewContext*)
{
   return false;
}

void
REveDataProxyBuilderBase::SetHaveAWindow(bool iHaveAWindow)
{
   m_haveWindow = iHaveAWindow;
}
<commit_msg>eve7: fix failure in REveDataProxyBuilderBase, use c++11 loops<commit_after>// @(#)root/eve7:$Id$
// Authors: Matevz Tadel & Alja Mrak-Tadel, 2018

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

#include <ROOT/REveDataProxyBuilderBase.hxx>
#include <ROOT/REveProjectionManager.hxx>
#include <ROOT/REveViewContext.hxx>
#include <ROOT/REveCompound.hxx>

#include <cassert>

using namespace ROOT::Experimental;
namespace REX = ROOT::Experimental;

REveDataProxyBuilderBase::Product::Product(std::string iViewType, const REveViewContext* c) : m_viewType(iViewType), m_viewContext(c), m_elements(0)
{
   m_elements = new REveCompound("ProxyProduct", "", false);
   m_elements->IncDenyDestroy();
}

//______________________________________________________________________________

REveDataProxyBuilderBase::REveDataProxyBuilderBase(const std::string &type):
   m_type(type),
   m_collection(nullptr),
   //   m_interactionList(0),
   m_haveWindow(false)
{
}

REveDataProxyBuilderBase::Product::~Product()
{
   // remove product from projected scene (RhoPhi or RhoZ)
   for (auto i : m_elements->RefProjecteds())
   {
      REveElement *projected = i->GetProjectedAsElement();
      projected->GetMother()->RemoveElement(projected);
   }

   // XXXX This might break now ... m_elements will auto drestruct, no?
   // We don't set incdenydestroy or additional something, do we?

   // remove from 3D scenes
   if (m_elements->HasMother())
   {
      m_elements->GetMother()->RemoveElement(m_elements);
   }

   m_elements->Annihilate();
}

//______________________________________________________________________________
void REveDataProxyBuilderBase::SetCollection(REveDataCollection* c)
{
   m_collection = c;
}

//______________________________________________________________________________
/*
void
REveDataProxyBuilderBase::SetInteractionList(REveDataInteractionList* l, const std::string& purpose )
{
   // Called if willHandleInteraction() returns false. Purpose ignored by default.

   m_interactionList = l;
}
*/

//______________________________________________________________________________
void REveDataProxyBuilderBase::Build()
{
   if (m_collection)
   {
      printf("Base %p %s %s\n", m_collection, m_collection->GetCName(), m_type.c_str());
      try
      {
         auto itemSize = m_collection->GetNItems(); //cashed

         Clean();
         for (Product_it i = m_products.begin(); i != m_products.end(); ++i)
         {
            printf("build() %s \n", m_collection->GetCName());
            REveElement* elms = (*i)->m_elements;
            auto oldSize = elms->NumChildren();

            if (HaveSingleProduct())
            {
               Build(m_collection, elms, (*i)->m_viewContext);
            }
            else
            {
               BuildViewType(m_collection, elms, (*i)->m_viewType, (*i)->m_viewContext);
            }

            // Project all children of current product.
            // If product is not registered into any projection-manager,
            // this does nothing.
            REveProjectable* pable = dynamic_cast<REveProjectable*>(elms);
            if (pable->HasProjecteds())
            {
               // loop projected holders
               for (REveProjectable::ProjList_i pi = pable->BeginProjecteds(); pi != pable->EndProjecteds(); ++pi)
               {
                  REveProjectionManager *pmgr = (*pi)->GetManager();
                  Float_t oldDepth = pmgr->GetCurrentDepth();
                  pmgr->SetCurrentDepth(m_layer);
                  Int_t cnt = 0;

                  REveElement *projectedAsElement = (*pi)->GetProjectedAsElement();
                  auto parentIt = projectedAsElement->RefChildren().begin();
                  for (auto &prod: elms->RefChildren())
                  {
                      // reused projected holder
                     if (cnt < oldSize)
                     {
                        if ((*parentIt)->NumChildren()) {
                            // update projected (mislleading name)
                           for ( auto &pci: (*parentIt)->RefChildren())
                               pmgr->ProjectChildrenRecurse(pci /* *parentIt */);  // SL: was *parentIt here, seems to be wrong
                        }
                        else {
                            // import projectable
                           pmgr->SubImportChildren(prod, *parentIt);
                        }

                        ++parentIt;
                     }
                     else if (cnt < itemSize)
                     {
                        // new product holder
                        pmgr->SubImportElements(prod, projectedAsElement);
                     }
                     else
                     {
                        break;
                     }
                     ++cnt;
                  }
                  pmgr->SetCurrentDepth(oldDepth);
               }
            }

            /*
            if (m_interactionList && itemSize > oldSize)
            {
               auto elIt = elms->RefChildren().begin();
               for (size_t cnt = 0; cnt < itemSize; ++cnt, ++elIt)
               {
                  if (cnt >= oldSize )
                       m_interactionList->Added(*elIt, cnt);
               }
            }
            */
         }
      }
      catch (const std::runtime_error& iException)
      {
         std::cout << "Caught exception in build function for item " << m_collection->GetCName() << ":\n"
                              << iException.what() << std::endl;
         exit(1);
      }
   }
}

//______________________________________________________________________________
void
REveDataProxyBuilderBase::Build(const REveDataCollection*, REveElement*, const REveViewContext*)
{
   assert("virtual Build(const REveEventItem*, REveElement*, const REveViewContext*) not implemented by inherited class");
}

void
REveDataProxyBuilderBase::BuildViewType(const REveDataCollection*, REveElement*, std::string, const REveViewContext*)
{
   assert("virtual BuildViewType(const FWEventItem*, TEveElementList*, FWViewType::EType, const FWViewContext*) not implemented by inherited class");
}

//______________________________________________________________________________

REveElement*
REveDataProxyBuilderBase::CreateProduct( std::string viewType, const REveViewContext* viewContext)
{
   if ( m_products.empty() == false)
   {
      if (HaveSingleProduct()) {
         return m_products.back()->m_elements;
      }
      else {

         for (Product_it i = m_products.begin(); i!= m_products.end(); ++i)
         {
            if (viewType == (*i)->m_viewType)
               return (*i)->m_elements;
         }
      }
   }

   Product* product = new Product(viewType, viewContext);
   m_products.push_back(product);

   if (m_collection)
   {
      // debug info in eve browser
      product->m_elements->SetName(Form("product %s", m_collection->GetCName()));
   }
   return product->m_elements;
}

//______________________________________________________________________________

//namespace {
//   void applyVisAttrToChildren(REveElement* p) {
//      for (auto it = p->BeginChildren(); it != p->EndChildren(); ++it)
//      {
//         REveElement* c = *it;
//         if (c->GetMainColor() != p->GetMainColor())
//         {
//            c->SetMainColor(p->GetMainColor());
//            printf("apply color %d to %s\n", p->GetMainColor(), c->GetCName());
//         }
//         c->SetRnrSelf(p->GetRnrSelf());
//         applyVisAttrToChildren(c);
//      }
//   }
//}

void
REveDataProxyBuilderBase::ModelChanges(const REveDataCollection::Ids_t& iIds, Product* p)
{
   printf("REveDataProxyBuilderBase::ModelChanges  %s \n",  m_collection->GetCName());
   REveElement* elms = p->m_elements;
   assert(m_collection && static_cast<int>(m_collection->GetNItems()) <= elms->NumChildren() && "can not use default modelChanges implementation");

   for (auto itemIdx: iIds)
   {
      REveDataItem *item = m_collection->GetDataItem(itemIdx);

      // printf("Edit compound for item index %d \n", itemIdx);
      // imitate FWInteractionList::modelChanges
      auto itElement = elms->RefChildren().begin();
      std::advance(itElement, itemIdx);
      auto comp = *itElement;
      comp->SetMainColor(item->GetMainColor());
      comp->SetRnrSelf(item->GetRnrSelf());

      // AMT temporary workaround for use of compunds
      // applyVisAttrToChildren(comp);

      if (VisibilityModelChanges(itemIdx, comp, p->m_viewContext))
      {
         elms->ProjectChild(comp);
         printf("---REveDataProxyBuilderBase project child\n ");
      }
   }
}

//______________________________________________________________________________

void
REveDataProxyBuilderBase::ModelChanges(const REveDataCollection::Ids_t& iIds)
{
  if(m_haveWindow) {
    for (Product_it i = m_products.begin(); i!= m_products.end(); ++i)
    {
       ModelChanges(iIds, *i);
    }
    m_modelsChanged=false;
  } else {
    m_modelsChanged=true;
  }
}

//______________________________________________________________________________
void
REveDataProxyBuilderBase::CollectionChanged(const REveDataCollection* /*iItem*/)
{
   if(m_haveWindow) {
      Build();
   }
}

//------------------------------------------------------------------------------

void
REveDataProxyBuilderBase::SetupAddElement(REveElement* el, REveElement* parent, bool color) const
{
   SetupElement(el, color);
   // AMT -- this temprary to get right tooltip
   el->SetName(parent->GetName());
   parent->AddElement(el);
}

/** This method is invoked to setup the per element properties of the various
    objects being drawn.
  */
void
REveDataProxyBuilderBase::SetupElement(REveElement* el, bool color) const
{
   el->CSCTakeMotherAsMaster();
   el->SetPickable(true);
   el->SetMainColor(m_collection->GetMainColor());
   if (color)
   {
      el->CSCApplyMainColorToMatchingChildren();
      el->CSCApplyMainTransparencyToMatchingChildren();
      el->SetMainColor(m_collection->GetMainColor());
      el->SetMainTransparency(m_collection->GetMainTransparency());
   }
}

REveCompound*
REveDataProxyBuilderBase::CreateCompound(bool set_color, bool propagate_color_to_all_children) const
{
   REveCompound* c = new REveCompound();
   c->CSCTakeMotherAsMaster();
   c->CSCImplySelectAllChildren();
   c->SetPickable(true);
   if (set_color)
   {
      c->SetMainColor(m_collection->GetMainColor());
      c->SetMainTransparency(m_collection->GetMainTransparency());
   }
   if (propagate_color_to_all_children)
   {
      c->CSCApplyMainColorToAllChildren();
      c->CSCApplyMainTransparencyToAllChildren();
   }
   else
   {
      c->CSCApplyMainColorToMatchingChildren();
      c->CSCApplyMainTransparencyToMatchingChildren();
   }
   return c;
}

//______________________________________________________________________________

void
REveDataProxyBuilderBase::Clean()
{
   // Cleans local common element list.
   for (Product_it i = m_products.begin(); i != m_products.end(); ++i)
   {
      if ((*i)->m_elements)
         (*i)->m_elements->DestroyElements();
   }

   CleanLocal();
}

void
REveDataProxyBuilderBase::CleanLocal()
{
   // Cleans local common element list.
}

void
REveDataProxyBuilderBase::CollectionBeingDestroyed(const REveDataCollection* /*iItem*/)
{
   m_collection = 0;

   CleanLocal();

   for (Product_it i = m_products.begin(); i!= m_products.end(); i++)
   {

      // (*i)->m_scaleConnection.disconnect();
      delete (*i);
   }

   m_products.clear();
}

bool
REveDataProxyBuilderBase::VisibilityModelChanges(int, REveElement*, const REveViewContext*)
{
   return false;
}

void
REveDataProxyBuilderBase::SetHaveAWindow(bool iHaveAWindow)
{
   m_haveWindow = iHaveAWindow;
}
<|endoftext|>


<commit_before>//
// This file is part of the Marble Virtual Globe.
//
// This program is free software licensed under the GNU LGPL. You can
// find a copy of this license in LICENSE.txt in the top directory of
// the source code.
//
// Copyright 2009      Bastian Holst <bastianholst@gmx.de>
//

// Self
#include "AbstractDataPluginModel.h"

// Qt
#include <QtCore/QUrl>
#include <QtCore/QTimer>
#include <QtCore/QPointF>
#include <QtCore/QtAlgorithms>
#include <QtCore/QVariant>

// Marble
#include "MarbleDebug.h"
#include "AbstractDataPluginItem.h"
#include "CacheStoragePolicy.h"
#include "GeoDataCoordinates.h"
#include "GeoDataLatLonAltBox.h"
#include "HttpDownloadManager.h"
#include "MarbleModel.h"
#include "MarbleDirs.h"
#include "ViewportParams.h"

#include <cmath>

namespace Marble
{

const QString descriptionPrefix( "description_" );

// Time between two tried description file downloads (we decided not to download anything) in ms
const int timeBetweenTriedDownloads = 500;
// Time between two real description file downloads in ms
const int timeBetweenDownloads = 1500;

// The factor describing how much the box has to be changed to download a new description file.
// A higher factor means more downloads.
const qreal boxComparisonFactor = 16.0;

// Separator to separate the id of the item from the file type
const char fileIdSeparator = '_';

class AbstractDataPluginModelPrivate
{
 public:
    AbstractDataPluginModelPrivate( const QString& name,
                                    AbstractDataPluginModel * parent )
        : m_parent( parent ),
          m_name( name ),
          m_lastBox(),
          m_downloadedBox(),
          m_lastNumber( 0 ),
          m_downloadedNumber( 0 ),
          m_lastMarbleModel( 0 ),
          m_downloadTimer( new QTimer( m_parent ) ),
          m_descriptionFileNumber( 0 ),
          m_itemSettings(),
          m_downloadManager( 0 )
    {
    }

    ~AbstractDataPluginModelPrivate() {
        QList<AbstractDataPluginItem*>::iterator lIt = m_itemSet.begin();
        QList<AbstractDataPluginItem*>::iterator const lItEnd = m_itemSet.end();
        for (; lIt != lItEnd; ++lIt ) {
            (*lIt)->deleteLater();
        }

        QHash<QString,AbstractDataPluginItem*>::iterator hIt = m_downloadingItems.begin();
        QHash<QString,AbstractDataPluginItem*>::iterator const hItEnd = m_downloadingItems.end();
        for (; hIt != hItEnd; ++hIt ) {
            (*hIt)->deleteLater();
        }

        m_downloadManager->storagePolicy()->clearCache();
        delete m_downloadManager;
    }

    AbstractDataPluginModel *m_parent;
    QString m_name;
    GeoDataLatLonAltBox m_lastBox;
    GeoDataLatLonAltBox m_downloadedBox;
    qint32 m_lastNumber;
    qint32 m_downloadedNumber;
    const MarbleModel *m_lastMarbleModel;
    QString m_downloadedTarget;
    QList<AbstractDataPluginItem*> m_itemSet;
    QHash<QString, AbstractDataPluginItem*> m_downloadingItems;
    QList<AbstractDataPluginItem*> m_displayedItems;
    QTimer *m_downloadTimer;
    quint32 m_descriptionFileNumber;
    QHash<QString, QVariant> m_itemSettings;

    HttpDownloadManager *m_downloadManager;
};

AbstractDataPluginModel::AbstractDataPluginModel( const QString& name,
                                                  PluginManager *pluginManager,
                                                  QObject *parent )
    : QObject(  parent ),
      d( new AbstractDataPluginModelPrivate( name, this ) )
{
    // Initializing file and download System
    CacheStoragePolicy *storagePolicy = new CacheStoragePolicy( MarbleDirs::localPath()
                                                                + "/cache/" + d->m_name + '/' );
    d->m_downloadManager = new HttpDownloadManager( storagePolicy, pluginManager );
    connect( d->m_downloadManager, SIGNAL( downloadComplete( QString, QString ) ),
             this,                 SLOT( processFinishedJob( QString , QString ) ) );

    // We want to download a new description file every timeBetweenDownloads ms
    connect( d->m_downloadTimer, SIGNAL( timeout() ),
             this,               SLOT( handleChangedViewport() ),
             Qt::QueuedConnection );
    d->m_downloadTimer->start( timeBetweenDownloads );
}

AbstractDataPluginModel::~AbstractDataPluginModel()
{
    delete d;
}

QList<AbstractDataPluginItem*> AbstractDataPluginModel::items( ViewportParams *viewport,
                                                               const MarbleModel *model,
                                                               qint32 number )
{
    GeoDataLatLonAltBox currentBox = viewport->viewLatLonAltBox();
    QString target = model->planetId();
    QList<AbstractDataPluginItem*> list;

    d->m_displayedItems.removeAll( 0 );

    QList<AbstractDataPluginItem*>::iterator i = d->m_displayedItems.begin();
    QList<AbstractDataPluginItem*>::iterator end = d->m_displayedItems.end();

    // Items that are already shown have the highest priority
    for (; i != end && list.size() < number; ++i ) {
        // Don't try to access an object that doesn't exist
        if( !*i ) {
            continue;
        }

        // Only show items that are initialized
        if( !(*i)->initialized() ) {
            continue;
        }

        // Only show items that are on the current planet
        if( (*i)->target() != target ) {
            continue;
        }

        if( !currentBox.contains( (*i)->coordinate() ) ) {
            continue;
        }

        // If the item was added initially at a nearer position, they don't have priority,
        // because we zoomed out since then.
        if( (*i)->addedAngularResolution() >= viewport->angularResolution() ) {
            list.append( *i );
            (*i)->setSettings( d->m_itemSettings );
        }
    }

    d->m_itemSet.removeAll( 0 );

    for ( i = d->m_itemSet.begin(), end = d->m_itemSet.end();
          i != end && list.size() < number; ++i )
    {
        // Don't try to access an object that doesn't exist
        if( !*i ) {
            mDebug() << "Warning: Null pointer in m_itemSet";
            continue;
        }

        // Only show items that are initialized
        if( !(*i)->initialized() ) {
            continue;
        }

        // Only show items that are on the current planet
        if( (*i)->target() != target ) {
            continue;
        }

        // If the item is on the viewport, we want to return it
        if( currentBox.contains( (*i)->coordinate() )
            && !list.contains( *i ) )
        {
            list.append( *i );
            (*i)->setSettings( d->m_itemSettings );

            // We want to save the angular resolution of the first time the item got added.
            // If it is in the list of displayedItems, it was added before
            if( !d->m_displayedItems.contains( *i ) ) {
                (*i)->setAddedAngularResolution( viewport->angularResolution() );
            }
        }
        // FIXME: We have to do something if the item that is not on the viewport.
    }

    d->m_lastMarbleModel = model;

    if( (!(currentBox == d->m_lastBox)
          || number != d->m_lastNumber ) )
    {
        d->m_lastBox = currentBox;
        d->m_lastNumber = number;
        d->m_lastMarbleModel = model;
    }
    else {
    }

    d->m_displayedItems = list;
    return list;
}

QList<AbstractDataPluginItem *> AbstractDataPluginModel::whichItemAt( const QPoint& curpos )
{
    QList<AbstractDataPluginItem *> itemsAt;

    foreach( AbstractDataPluginItem* item, d->m_displayedItems ) {
        if( item && item->contains( QPointF( curpos ) ) )
            itemsAt.append( item );
    }

    return itemsAt;
}

void AbstractDataPluginModel::parseFile( const QByteArray& file )
{
    Q_UNUSED( file );
}

void AbstractDataPluginModel::downloadItemData( const QUrl& url,
                                                const QString& type,
                                                AbstractDataPluginItem *item )
{
    if( !item ) {
        return;
    }

    QString id = generateFilename( item->id(), type );

    d->m_downloadManager->addJob( url, id, id, DownloadBrowse );
    d->m_downloadingItems.insert( id, item );

    connect( item, SIGNAL( destroyed( QObject* ) ), this, SLOT( removeItem( QObject* ) ) );

    addItemToList( item );
}

void AbstractDataPluginModel::downloadDescriptionFile( const QUrl& url )
{
    if( !url.isEmpty() ) {
        QString name( descriptionPrefix );
        name += QString::number( d->m_descriptionFileNumber );

        d->m_downloadManager->addJob( url, name, name, DownloadBrowse );
        d->m_descriptionFileNumber++;
    }
}

static bool lessThanByPointer( const AbstractDataPluginItem *item1,
                               const AbstractDataPluginItem *item2 )
{
    if( item1 != 0 && item2 != 0 ) {
        return item1->operator<( item2 );
    }
    else {
        return false;
    }
}

void AbstractDataPluginModel::addItemToList( AbstractDataPluginItem *item )
{
    if( !item ) {
        return;
    }

    // If the item is already in our list, don't add it.
    if( AbstractDataPluginItem *oldItem = findItem( item->id() ) ) {
        if ( oldItem == item ) {
            return;
        }
        else {
            item->deleteLater();
            return;
        }
    }

    mDebug() << "New item " << item->id();

    // This find the right position in the sorted to insert the new item
    QList<AbstractDataPluginItem*>::iterator i = qLowerBound( d->m_itemSet.begin(),
                                                                d->m_itemSet.end(),
                                                                item,
                                                                lessThanByPointer );
    // Insert the item on the right position in the list
    d->m_itemSet.insert( i, item );

    connect( item, SIGNAL( destroyed( QObject* ) ), this, SLOT( removeItem( QObject* ) ) );
    connect( item, SIGNAL( updated() ), this, SIGNAL( itemsUpdated() ) );

    if ( item->initialized() ) {
        emit itemsUpdated();
    }
}

QString AbstractDataPluginModel::name() const
{
    return d->m_name;
}

void AbstractDataPluginModel::setName( const QString& name )
{
    d->m_name = name;
}

QString AbstractDataPluginModel::generateFilename( const QString& id, const QString& type ) const
{
    QString name;
    name += id;
    name += fileIdSeparator;
    name += type;

    return name;
}

QString AbstractDataPluginModel::generateFilepath( const QString& id, const QString& type ) const
{
    return MarbleDirs::localPath() + "/cache/" + d->m_name + '/' + generateFilename( id, type );
}

bool AbstractDataPluginModel::fileExists( const QString& fileName ) const
{
    return d->m_downloadManager->storagePolicy()->fileExists( fileName );
}

bool AbstractDataPluginModel::fileExists( const QString& id, const QString& type ) const
{
    return fileExists( generateFilename( id, type ) );
}

AbstractDataPluginItem *AbstractDataPluginModel::findItem( const QString& id ) const
{
    QList<AbstractDataPluginItem*>::iterator listIt = d->m_itemSet.begin();
    QList<AbstractDataPluginItem*>::iterator const end = d->m_itemSet.end();

    for (; listIt != end; ++listIt ) {
        if( (*listIt)->id() == id ) {
            return (*listIt);
        }
    }

    return 0;
}

bool AbstractDataPluginModel::itemExists( const QString& id ) const
{
    return findItem( id );
}

void AbstractDataPluginModel::setItemSettings( QHash<QString,QVariant> itemSettings )
{
    d->m_itemSettings = itemSettings;
}

void AbstractDataPluginModel::handleChangedViewport()
{
    if( !d->m_lastMarbleModel ) {
        return;
    }

    // All this is to prevent to often downloads
    if( d->m_lastNumber != 0
        // We don't need to download if nothing changed
        && ( !( d->m_downloadedBox == d->m_lastBox )
             || d->m_downloadedNumber != d->m_lastNumber
             || d->m_downloadedTarget != d->m_lastMarbleModel->planetId() )
        // We try to filter little changes of the bounding box
        && ( fabs( d->m_downloadedBox.east() - d->m_lastBox.east() ) * boxComparisonFactor
                                > d->m_lastBox.width()
             || fabs( d->m_downloadedBox.south() - d->m_lastBox.south() ) * boxComparisonFactor
                                > d->m_lastBox.height()
             || fabs( d->m_downloadedBox.north() - d->m_lastBox.north() ) * boxComparisonFactor
                                > d->m_lastBox.height()
             || fabs( d->m_downloadedBox.west() - d->m_lastBox.west() ) * boxComparisonFactor
                                > d->m_lastBox.width() ) )
    {
        // We will wait a little bit longer to start the the
        // next download as we will really download something now.
        d->m_downloadTimer->setInterval( timeBetweenDownloads );

        // Save the download parameter
        d->m_downloadedBox = d->m_lastBox;
        d->m_downloadedNumber = d->m_lastNumber;
        d->m_downloadedTarget = d->m_lastMarbleModel->planetId();

        // Get items
        getAdditionalItems( d->m_lastBox, d->m_lastMarbleModel, d->m_lastNumber );
    }
    else {
        // Don't wait to long to start the next download as we decided not to download anything.
        // This will enhance response.
        d->m_downloadTimer->setInterval( timeBetweenTriedDownloads );
    }
}

void AbstractDataPluginModel::processFinishedJob( const QString& relativeUrlString,
                                                  const QString& id )
{
    Q_UNUSED( relativeUrlString );

    if( id.startsWith( descriptionPrefix ) ) {
        CacheStoragePolicy *storagePolicy
                = qobject_cast<CacheStoragePolicy*>( d->m_downloadManager->storagePolicy() );
        if ( storagePolicy ) {
            parseFile( storagePolicy->data( id ) );
        }
    }
    else {
        // The downloaded file contains item data.

        // Splitting the id in itemId and fileType
        QStringList fileInformation = id.split( fileIdSeparator );

        if( fileInformation.size() < 2) {
            mDebug() << "Strange file information " << id;
            return;
        }
        QString itemId = fileInformation.at( 0 );
        fileInformation.removeAt( 0 );
        QString fileType = fileInformation.join( QString( fileIdSeparator ) );

        // Searching for the right item in m_downloadingItems
        QHash<QString, AbstractDataPluginItem *>::iterator i = d->m_downloadingItems.find( id );
        if( i != d->m_downloadingItems.end() ) {
            if( itemId != (*i)->id() ) {
                return;
            }

            (*i)->addDownloadedFile( generateFilepath( itemId, fileType ),
                                     fileType );

            d->m_downloadingItems.erase( i );
        }
    }
}

void AbstractDataPluginModel::removeItem( QObject *item )
{
    d->m_itemSet.removeAll( (AbstractDataPluginItem *) item );
    QHash<QString, AbstractDataPluginItem *>::iterator i;
    for( i = d->m_downloadingItems.begin(); i != d->m_downloadingItems.end(); ++i ) {
        if( (*i) == (AbstractDataPluginItem *) item ) {
            d->m_downloadingItems.erase( i );
        }
    }
}

} // namespace Marble

#include "AbstractDataPluginModel.moc"
<commit_msg>erase() invalidates the iterator.<commit_after>//
// This file is part of the Marble Virtual Globe.
//
// This program is free software licensed under the GNU LGPL. You can
// find a copy of this license in LICENSE.txt in the top directory of
// the source code.
//
// Copyright 2009      Bastian Holst <bastianholst@gmx.de>
//

// Self
#include "AbstractDataPluginModel.h"

// Qt
#include <QtCore/QUrl>
#include <QtCore/QTimer>
#include <QtCore/QPointF>
#include <QtCore/QtAlgorithms>
#include <QtCore/QVariant>

// Marble
#include "MarbleDebug.h"
#include "AbstractDataPluginItem.h"
#include "CacheStoragePolicy.h"
#include "GeoDataCoordinates.h"
#include "GeoDataLatLonAltBox.h"
#include "HttpDownloadManager.h"
#include "MarbleModel.h"
#include "MarbleDirs.h"
#include "ViewportParams.h"

#include <cmath>

namespace Marble
{

const QString descriptionPrefix( "description_" );

// Time between two tried description file downloads (we decided not to download anything) in ms
const int timeBetweenTriedDownloads = 500;
// Time between two real description file downloads in ms
const int timeBetweenDownloads = 1500;

// The factor describing how much the box has to be changed to download a new description file.
// A higher factor means more downloads.
const qreal boxComparisonFactor = 16.0;

// Separator to separate the id of the item from the file type
const char fileIdSeparator = '_';

class AbstractDataPluginModelPrivate
{
 public:
    AbstractDataPluginModelPrivate( const QString& name,
                                    AbstractDataPluginModel * parent )
        : m_parent( parent ),
          m_name( name ),
          m_lastBox(),
          m_downloadedBox(),
          m_lastNumber( 0 ),
          m_downloadedNumber( 0 ),
          m_lastMarbleModel( 0 ),
          m_downloadTimer( new QTimer( m_parent ) ),
          m_descriptionFileNumber( 0 ),
          m_itemSettings(),
          m_downloadManager( 0 )
    {
    }

    ~AbstractDataPluginModelPrivate() {
        QList<AbstractDataPluginItem*>::iterator lIt = m_itemSet.begin();
        QList<AbstractDataPluginItem*>::iterator const lItEnd = m_itemSet.end();
        for (; lIt != lItEnd; ++lIt ) {
            (*lIt)->deleteLater();
        }

        QHash<QString,AbstractDataPluginItem*>::iterator hIt = m_downloadingItems.begin();
        QHash<QString,AbstractDataPluginItem*>::iterator const hItEnd = m_downloadingItems.end();
        for (; hIt != hItEnd; ++hIt ) {
            (*hIt)->deleteLater();
        }

        m_downloadManager->storagePolicy()->clearCache();
        delete m_downloadManager;
    }

    AbstractDataPluginModel *m_parent;
    QString m_name;
    GeoDataLatLonAltBox m_lastBox;
    GeoDataLatLonAltBox m_downloadedBox;
    qint32 m_lastNumber;
    qint32 m_downloadedNumber;
    const MarbleModel *m_lastMarbleModel;
    QString m_downloadedTarget;
    QList<AbstractDataPluginItem*> m_itemSet;
    QHash<QString, AbstractDataPluginItem*> m_downloadingItems;
    QList<AbstractDataPluginItem*> m_displayedItems;
    QTimer *m_downloadTimer;
    quint32 m_descriptionFileNumber;
    QHash<QString, QVariant> m_itemSettings;

    HttpDownloadManager *m_downloadManager;
};

AbstractDataPluginModel::AbstractDataPluginModel( const QString& name,
                                                  PluginManager *pluginManager,
                                                  QObject *parent )
    : QObject(  parent ),
      d( new AbstractDataPluginModelPrivate( name, this ) )
{
    // Initializing file and download System
    CacheStoragePolicy *storagePolicy = new CacheStoragePolicy( MarbleDirs::localPath()
                                                                + "/cache/" + d->m_name + '/' );
    d->m_downloadManager = new HttpDownloadManager( storagePolicy, pluginManager );
    connect( d->m_downloadManager, SIGNAL( downloadComplete( QString, QString ) ),
             this,                 SLOT( processFinishedJob( QString , QString ) ) );

    // We want to download a new description file every timeBetweenDownloads ms
    connect( d->m_downloadTimer, SIGNAL( timeout() ),
             this,               SLOT( handleChangedViewport() ),
             Qt::QueuedConnection );
    d->m_downloadTimer->start( timeBetweenDownloads );
}

AbstractDataPluginModel::~AbstractDataPluginModel()
{
    delete d;
}

QList<AbstractDataPluginItem*> AbstractDataPluginModel::items( ViewportParams *viewport,
                                                               const MarbleModel *model,
                                                               qint32 number )
{
    GeoDataLatLonAltBox currentBox = viewport->viewLatLonAltBox();
    QString target = model->planetId();
    QList<AbstractDataPluginItem*> list;

    d->m_displayedItems.removeAll( 0 );

    QList<AbstractDataPluginItem*>::iterator i = d->m_displayedItems.begin();
    QList<AbstractDataPluginItem*>::iterator end = d->m_displayedItems.end();

    // Items that are already shown have the highest priority
    for (; i != end && list.size() < number; ++i ) {
        // Don't try to access an object that doesn't exist
        if( !*i ) {
            continue;
        }

        // Only show items that are initialized
        if( !(*i)->initialized() ) {
            continue;
        }

        // Only show items that are on the current planet
        if( (*i)->target() != target ) {
            continue;
        }

        if( !currentBox.contains( (*i)->coordinate() ) ) {
            continue;
        }

        // If the item was added initially at a nearer position, they don't have priority,
        // because we zoomed out since then.
        if( (*i)->addedAngularResolution() >= viewport->angularResolution() ) {
            list.append( *i );
            (*i)->setSettings( d->m_itemSettings );
        }
    }

    d->m_itemSet.removeAll( 0 );

    for ( i = d->m_itemSet.begin(), end = d->m_itemSet.end();
          i != end && list.size() < number; ++i )
    {
        // Don't try to access an object that doesn't exist
        if( !*i ) {
            mDebug() << "Warning: Null pointer in m_itemSet";
            continue;
        }

        // Only show items that are initialized
        if( !(*i)->initialized() ) {
            continue;
        }

        // Only show items that are on the current planet
        if( (*i)->target() != target ) {
            continue;
        }

        // If the item is on the viewport, we want to return it
        if( currentBox.contains( (*i)->coordinate() )
            && !list.contains( *i ) )
        {
            list.append( *i );
            (*i)->setSettings( d->m_itemSettings );

            // We want to save the angular resolution of the first time the item got added.
            // If it is in the list of displayedItems, it was added before
            if( !d->m_displayedItems.contains( *i ) ) {
                (*i)->setAddedAngularResolution( viewport->angularResolution() );
            }
        }
        // FIXME: We have to do something if the item that is not on the viewport.
    }

    d->m_lastMarbleModel = model;

    if( (!(currentBox == d->m_lastBox)
          || number != d->m_lastNumber ) )
    {
        d->m_lastBox = currentBox;
        d->m_lastNumber = number;
        d->m_lastMarbleModel = model;
    }
    else {
    }

    d->m_displayedItems = list;
    return list;
}

QList<AbstractDataPluginItem *> AbstractDataPluginModel::whichItemAt( const QPoint& curpos )
{
    QList<AbstractDataPluginItem *> itemsAt;

    foreach( AbstractDataPluginItem* item, d->m_displayedItems ) {
        if( item && item->contains( QPointF( curpos ) ) )
            itemsAt.append( item );
    }

    return itemsAt;
}

void AbstractDataPluginModel::parseFile( const QByteArray& file )
{
    Q_UNUSED( file );
}

void AbstractDataPluginModel::downloadItemData( const QUrl& url,
                                                const QString& type,
                                                AbstractDataPluginItem *item )
{
    if( !item ) {
        return;
    }

    QString id = generateFilename( item->id(), type );

    d->m_downloadManager->addJob( url, id, id, DownloadBrowse );
    d->m_downloadingItems.insert( id, item );

    connect( item, SIGNAL( destroyed( QObject* ) ), this, SLOT( removeItem( QObject* ) ) );

    addItemToList( item );
}

void AbstractDataPluginModel::downloadDescriptionFile( const QUrl& url )
{
    if( !url.isEmpty() ) {
        QString name( descriptionPrefix );
        name += QString::number( d->m_descriptionFileNumber );

        d->m_downloadManager->addJob( url, name, name, DownloadBrowse );
        d->m_descriptionFileNumber++;
    }
}

static bool lessThanByPointer( const AbstractDataPluginItem *item1,
                               const AbstractDataPluginItem *item2 )
{
    if( item1 != 0 && item2 != 0 ) {
        return item1->operator<( item2 );
    }
    else {
        return false;
    }
}

void AbstractDataPluginModel::addItemToList( AbstractDataPluginItem *item )
{
    if( !item ) {
        return;
    }

    // If the item is already in our list, don't add it.
    if( AbstractDataPluginItem *oldItem = findItem( item->id() ) ) {
        if ( oldItem == item ) {
            return;
        }
        else {
            item->deleteLater();
            return;
        }
    }

    mDebug() << "New item " << item->id();

    // This find the right position in the sorted to insert the new item
    QList<AbstractDataPluginItem*>::iterator i = qLowerBound( d->m_itemSet.begin(),
                                                                d->m_itemSet.end(),
                                                                item,
                                                                lessThanByPointer );
    // Insert the item on the right position in the list
    d->m_itemSet.insert( i, item );

    connect( item, SIGNAL( destroyed( QObject* ) ), this, SLOT( removeItem( QObject* ) ) );
    connect( item, SIGNAL( updated() ), this, SIGNAL( itemsUpdated() ) );

    if ( item->initialized() ) {
        emit itemsUpdated();
    }
}

QString AbstractDataPluginModel::name() const
{
    return d->m_name;
}

void AbstractDataPluginModel::setName( const QString& name )
{
    d->m_name = name;
}

QString AbstractDataPluginModel::generateFilename( const QString& id, const QString& type ) const
{
    QString name;
    name += id;
    name += fileIdSeparator;
    name += type;

    return name;
}

QString AbstractDataPluginModel::generateFilepath( const QString& id, const QString& type ) const
{
    return MarbleDirs::localPath() + "/cache/" + d->m_name + '/' + generateFilename( id, type );
}

bool AbstractDataPluginModel::fileExists( const QString& fileName ) const
{
    return d->m_downloadManager->storagePolicy()->fileExists( fileName );
}

bool AbstractDataPluginModel::fileExists( const QString& id, const QString& type ) const
{
    return fileExists( generateFilename( id, type ) );
}

AbstractDataPluginItem *AbstractDataPluginModel::findItem( const QString& id ) const
{
    QList<AbstractDataPluginItem*>::iterator listIt = d->m_itemSet.begin();
    QList<AbstractDataPluginItem*>::iterator const end = d->m_itemSet.end();

    for (; listIt != end; ++listIt ) {
        if( (*listIt)->id() == id ) {
            return (*listIt);
        }
    }

    return 0;
}

bool AbstractDataPluginModel::itemExists( const QString& id ) const
{
    return findItem( id );
}

void AbstractDataPluginModel::setItemSettings( QHash<QString,QVariant> itemSettings )
{
    d->m_itemSettings = itemSettings;
}

void AbstractDataPluginModel::handleChangedViewport()
{
    if( !d->m_lastMarbleModel ) {
        return;
    }

    // All this is to prevent to often downloads
    if( d->m_lastNumber != 0
        // We don't need to download if nothing changed
        && ( !( d->m_downloadedBox == d->m_lastBox )
             || d->m_downloadedNumber != d->m_lastNumber
             || d->m_downloadedTarget != d->m_lastMarbleModel->planetId() )
        // We try to filter little changes of the bounding box
        && ( fabs( d->m_downloadedBox.east() - d->m_lastBox.east() ) * boxComparisonFactor
                                > d->m_lastBox.width()
             || fabs( d->m_downloadedBox.south() - d->m_lastBox.south() ) * boxComparisonFactor
                                > d->m_lastBox.height()
             || fabs( d->m_downloadedBox.north() - d->m_lastBox.north() ) * boxComparisonFactor
                                > d->m_lastBox.height()
             || fabs( d->m_downloadedBox.west() - d->m_lastBox.west() ) * boxComparisonFactor
                                > d->m_lastBox.width() ) )
    {
        // We will wait a little bit longer to start the the
        // next download as we will really download something now.
        d->m_downloadTimer->setInterval( timeBetweenDownloads );

        // Save the download parameter
        d->m_downloadedBox = d->m_lastBox;
        d->m_downloadedNumber = d->m_lastNumber;
        d->m_downloadedTarget = d->m_lastMarbleModel->planetId();

        // Get items
        getAdditionalItems( d->m_lastBox, d->m_lastMarbleModel, d->m_lastNumber );
    }
    else {
        // Don't wait to long to start the next download as we decided not to download anything.
        // This will enhance response.
        d->m_downloadTimer->setInterval( timeBetweenTriedDownloads );
    }
}

void AbstractDataPluginModel::processFinishedJob( const QString& relativeUrlString,
                                                  const QString& id )
{
    Q_UNUSED( relativeUrlString );

    if( id.startsWith( descriptionPrefix ) ) {
        CacheStoragePolicy *storagePolicy
                = qobject_cast<CacheStoragePolicy*>( d->m_downloadManager->storagePolicy() );
        if ( storagePolicy ) {
            parseFile( storagePolicy->data( id ) );
        }
    }
    else {
        // The downloaded file contains item data.

        // Splitting the id in itemId and fileType
        QStringList fileInformation = id.split( fileIdSeparator );

        if( fileInformation.size() < 2) {
            mDebug() << "Strange file information " << id;
            return;
        }
        QString itemId = fileInformation.at( 0 );
        fileInformation.removeAt( 0 );
        QString fileType = fileInformation.join( QString( fileIdSeparator ) );

        // Searching for the right item in m_downloadingItems
        QHash<QString, AbstractDataPluginItem *>::iterator i = d->m_downloadingItems.find( id );
        if( i != d->m_downloadingItems.end() ) {
            if( itemId != (*i)->id() ) {
                return;
            }

            (*i)->addDownloadedFile( generateFilepath( itemId, fileType ),
                                     fileType );

            d->m_downloadingItems.erase( i );
        }
    }
}

void AbstractDataPluginModel::removeItem( QObject *item )
{
    d->m_itemSet.removeAll( (AbstractDataPluginItem *) item );
    QHash<QString, AbstractDataPluginItem *>::iterator i;
    for( i = d->m_downloadingItems.begin(); i != d->m_downloadingItems.end(); ++i ) {
        if( (*i) == (AbstractDataPluginItem *) item ) {
            i = d->m_downloadingItems.erase( i );
        }
    }
}

} // namespace Marble

#include "AbstractDataPluginModel.moc"
<|endoftext|>