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

#include "PreCompiled.h"

#ifndef _PreComp_
# include <sstream>
# include <iostream>
# include <iterator>
#include <Precision.hxx>
#include <cmath>
#endif

#include <Base/Exception.h>
#include <Base/Console.h>
#include <Base/FileInfo.h>
#include <Base/Parameter.h>
#include <Base/UnitsApi.h>

#include <App/Application.h>
#include <App/Document.h>
#include <boost/regex.hpp>

#include "DrawPage.h"
#include "DrawView.h"
#include "DrawProjGroup.h"
#include "DrawViewClip.h"
#include "DrawTemplate.h"
#include "DrawViewCollection.h"
#include "DrawViewPart.h"
#include "DrawViewDimension.h"

#include <Mod/TechDraw/App/DrawPagePy.h>  // generated from DrawPagePy.xml

using namespace TechDraw;
using namespace std;

//===========================================================================
// DrawPage
//===========================================================================

App::PropertyFloatConstraint::Constraints DrawPage::scaleRange = {Precision::Confusion(),
                                                                  std::numeric_limits<double>::max(),
                                                                  pow(10,- Base::UnitsApi::getDecimals())};

PROPERTY_SOURCE(TechDraw::DrawPage, App::DocumentObject)

const char* DrawPage::ProjectionTypeEnums[] = { "First Angle",
                                                "Third Angle",
                                                NULL };

DrawPage::DrawPage(void)
{
    static const char *group = "Page";
    nowDeleting = false;

    ADD_PROPERTY_TYPE(Template, (0), group, (App::PropertyType)(App::Prop_None), "Attached Template");
    ADD_PROPERTY_TYPE(Views, (0), group, (App::PropertyType)(App::Prop_None), "Attached Views");

    // Projection Properties
    ProjectionType.setEnums(ProjectionTypeEnums);

    Base::Reference<ParameterGrp> hGrp =
                        App::GetApplication().GetUserParameter().GetGroup("BaseApp")->GetGroup("Preferences")->GetGroup("Mod/TechDraw/General");

    // In preferences, 0 -> First Angle 1 -> Third Angle
    int projType = hGrp->GetInt("ProjectionAngle", -1);

    if (projType == -1) {
        ADD_PROPERTY(ProjectionType, ((long)0)); // Default to first angle
    } else {
        ADD_PROPERTY(ProjectionType, ((long)projType));
    }

    ADD_PROPERTY_TYPE(Scale, (1.0), group, App::Prop_None, "Scale factor for this Page");
    Scale.setConstraints(&scaleRange);
}

DrawPage::~DrawPage()
{
}

void DrawPage::onBeforeChange(const App::Property* prop)
{
    App::DocumentObject::onBeforeChange(prop);
}

void DrawPage::onChanged(const App::Property* prop)
{
    if (prop == &Template) {
        if (!isRestoring() &&
            !isDeleting()) {
        //TODO: reload if Template prop changes (ie different Template)
        }
    } else if (prop == &Views) {
        if (!isRestoring() &&
            !isDeleting() ) {
            //TODO: reload if Views prop changes (ie adds/deletes)
        }
    } else if(prop == &Scale) {
        // touch all views in the Page as they may be dependent on this scale
      const std::vector<App::DocumentObject*> &vals = Views.getValues();
      for(std::vector<App::DocumentObject *>::const_iterator it = vals.begin(); it < vals.end(); ++it) {
          TechDraw::DrawView *view = dynamic_cast<TechDraw::DrawView *>(*it);
          if (view != NULL && view->ScaleType.isValue("Page")) {
              view->Scale.touch();
          }
      }
    } else if (prop == &ProjectionType) {
      // touch all ortho views in the Page as they may be dependent on Projection Type
      const std::vector<App::DocumentObject*> &vals = Views.getValues();
      for(std::vector<App::DocumentObject *>::const_iterator it = vals.begin(); it < vals.end(); ++it) {
          TechDraw::DrawProjGroup *view = dynamic_cast<TechDraw::DrawProjGroup *>(*it);
          if (view != NULL && view->ProjectionType.isValue("Default")) {
              view->ProjectionType.touch();
          }
      }

      // TODO: Also update Template graphic.

    }
    App::DocumentObject::onChanged(prop);  //<<<<
}

App::DocumentObjectExecReturn *DrawPage::execute(void)
{
    //Page is just a property storage area? no real logic involved?
    //all this does is trigger onChanged in this and ViewProviderPage
    Template.touch();
    Views.touch();
    return App::DocumentObject::StdReturn;
}

short DrawPage::mustExecute() const
{
    if(Scale.isTouched())
        return 1;

    // Check the value of template if this has been modified
    App::DocumentObject* tmpl = Template.getValue();
    if(tmpl && tmpl->isTouched())
        return 1;

    // Check if within this Page, any Views have been touched
    // Why does Page have to execute if a View changes?
    const std::vector<App::DocumentObject*> &vals = Views.getValues();
    for(std::vector<App::DocumentObject *>::const_iterator it = vals.begin(); it < vals.end(); ++it) {
       if((*it)->isTouched()) {
            return 1;
        }
    }

    return App::DocumentObject::mustExecute();
}

PyObject *DrawPage::getPyObject(void)
{
    if (PythonObject.is(Py::_None())){
        // ref counter is set to 1
        PythonObject = Py::Object(new DrawPagePy(this),true);
    }

    return Py::new_reference_to(PythonObject);
}

bool DrawPage::hasValidTemplate() const
{
    App::DocumentObject *obj = 0;
    obj = Template.getValue();

    if(obj && obj->isDerivedFrom(TechDraw::DrawTemplate::getClassTypeId())) {
        TechDraw::DrawTemplate *templ = static_cast<TechDraw::DrawTemplate *>(obj);
        if (templ->getWidth() > 0. &&
            templ->getHeight() > 0.) {
            return true;
        }
    }

    return false;
}

double DrawPage::getPageWidth() const
{
    App::DocumentObject *obj = 0;
    obj = Template.getValue();

    if( obj && obj->isDerivedFrom(TechDraw::DrawTemplate::getClassTypeId()) ) {
        TechDraw::DrawTemplate *templ = static_cast<TechDraw::DrawTemplate *>(obj);
        return templ->getWidth();
    }

    throw Base::Exception("Template not set for Page");
}

double DrawPage::getPageHeight() const
{
    App::DocumentObject *obj = 0;
    obj = Template.getValue();

    if(obj) {
        if(obj->isDerivedFrom(TechDraw::DrawTemplate::getClassTypeId())) {
            TechDraw::DrawTemplate *templ = static_cast<TechDraw::DrawTemplate *>(obj);
            return templ->getHeight();
        }
    }

    throw Base::Exception("Template not set for Page");
}

const char * DrawPage::getPageOrientation() const
{
    App::DocumentObject *obj;
    obj = Template.getValue();

    if(obj) {
        if(obj->isDerivedFrom(TechDraw::DrawTemplate::getClassTypeId())) {
          TechDraw::DrawTemplate *templ = static_cast<TechDraw::DrawTemplate *>(obj);

          return templ->Orientation.getValueAsString();
        }
    }
    throw Base::Exception("Template not set for Page");
}

int DrawPage::addView(App::DocumentObject *docObj)
{
    if(!docObj->isDerivedFrom(TechDraw::DrawView::getClassTypeId()))
        return -1;
    DrawView* view = static_cast<DrawView*>(docObj);

    //position all new views in center of Page (exceptDVDimension)
    if (!docObj->isDerivedFrom(TechDraw::DrawViewDimension::getClassTypeId())) {
        view->X.setValue(getPageWidth()/2.0);
        view->Y.setValue(getPageHeight()/2.0);
    }

    //add view to list
    const std::vector<App::DocumentObject *> currViews = Views.getValues();
    std::vector<App::DocumentObject *> newViews(currViews);
    newViews.push_back(docObj);
    Views.setValues(newViews);

    //check if View fits on Page
    if ( !view->checkFit(this) ) {
        Base::Console().Warning("%s is larger than page. Will be scaled.\n",view->getNameInDocument());
        view->ScaleType.setValue("Automatic");
    }

    return Views.getSize();
}

int DrawPage::removeView(App::DocumentObject *docObj)
{
    if(!docObj->isDerivedFrom(TechDraw::DrawView::getClassTypeId()))
        return -1;

    const std::vector<App::DocumentObject*> currViews = Views.getValues();
    std::vector<App::DocumentObject*> newViews;
    std::vector<App::DocumentObject*>::const_iterator it = currViews.begin();
    for (; it != currViews.end(); it++) {
        std::string viewName = docObj->getNameInDocument();
        if (viewName.compare((*it)->getNameInDocument()) != 0) {
            newViews.push_back((*it));
        }
    }
    Views.setValues(newViews);

    return Views.getSize();
}

void DrawPage::onDocumentRestored()
{
    std::vector<App::DocumentObject*> featViews = Views.getValues();
    std::vector<App::DocumentObject*>::const_iterator it = featViews.begin();
    //first, make sure all the Parts have been executed so GeometryObjects exist
    for(; it != featViews.end(); ++it) {
        TechDraw::DrawViewPart *part = dynamic_cast<TechDraw::DrawViewPart *>(*it);
        if (part != nullptr &&
            !part->hasGeometry()) {
            part->execute();
//            std::vector<App::DocumentObject*> parent = part->getInList();
//            for (auto& p: parent) {
//                p->touch();
//            }
        }
    }
    //second, make sure all the Dimensions have been executed so Measurements have References
    for(it = featViews.begin(); it != featViews.end(); ++it) {
        TechDraw::DrawViewDimension *dim = dynamic_cast<TechDraw::DrawViewDimension *>(*it);
        if (dim != nullptr &&
            !dim->has2DReferences()) {
            dim->execute();
        }
    }
    recompute();
    App::DocumentObject::onDocumentRestored();
}

void DrawPage::unsetupObject()
{
    nowDeleting = true;

    // Remove the Page's views & template from document
    App::Document* doc = getDocument();
    std::string docName = doc->getName();

    const std::vector<App::DocumentObject*> currViews = Views.getValues();
    std::vector<App::DocumentObject*> emptyViews;
    std::vector<App::DocumentObject*>::const_iterator it = currViews.begin();
    for (; it != currViews.end(); it++) {
        std::string viewName = (*it)->getNameInDocument();
        Base::Interpreter().runStringArg("App.getDocument(\"%s\").removeObject(\"%s\")",
                                          docName.c_str(), viewName.c_str());
    }
    Views.setValues(emptyViews);

    //no template crash here?? if Template.getValue is null or invalid, this will fail.
    std::string templateName = Template.getValue()->getNameInDocument();
    Base::Interpreter().runStringArg("App.getDocument(\"%s\").removeObject(\"%s\")",
                                          docName.c_str(), templateName.c_str());
    Template.setValue(nullptr);
}

void DrawPage::Restore(Base::XMLReader &reader)
{
    reader.readElement("Properties");
    int Cnt = reader.getAttributeAsInteger("Count");

    for (int i=0 ;i<Cnt ;i++) {
        reader.readElement("Property");
        const char* PropName = reader.getAttribute("name");
        const char* TypeName = reader.getAttribute("type");
        App::Property* schemaProp = getPropertyByName(PropName);
        try {
            if(schemaProp){
                if (strcmp(schemaProp->getTypeId().getName(), TypeName) == 0){        //if the property type in obj == type in schema
                    schemaProp->Restore(reader);                                      //nothing special to do
                } else  {
                    if (strcmp(PropName, "Scale") == 0) {
                        if (schemaProp->isDerivedFrom(App::PropertyFloatConstraint::getClassTypeId())){  //right property type
                            schemaProp->Restore(reader);                                                  //nothing special to do
                        } else {                                                                //Scale, but not PropertyFloatConstraint
                            App::PropertyFloat tmp;
                            if (strcmp(tmp.getTypeId().getName(),TypeName)) {                   //property in file is Float
                                tmp.setContainer(this);
                                tmp.Restore(reader);
                                double tmpValue = tmp.getValue();
                                if (tmpValue > 0.0) {
                                    static_cast<App::PropertyFloatConstraint*>(schemaProp)->setValue(tmpValue);
                                } else {
                                    static_cast<App::PropertyFloatConstraint*>(schemaProp)->setValue(1.0);
                                }
                            } else {
                                // has Scale prop that isn't Float!
                                Base::Console().Log("DrawPage::Restore - old Document Scale is Not Float!\n");
                                // no idea
                            }
                        }
                    } else {
                        Base::Console().Log("DrawPage::Restore - old Document has unknown Property\n");
                    }
                }
            }
        }
        catch (const Base::XMLParseException&) {
            throw; // re-throw
        }
        catch (const Base::Exception &e) {
            Base::Console().Error("%s\n", e.what());
        }
        catch (const std::exception &e) {
            Base::Console().Error("%s\n", e.what());
        }
        catch (const char* e) {
            Base::Console().Error("%s\n", e);
        }
#ifndef FC_DEBUG
        catch (...) {
            Base::Console().Error("PropertyContainer::Restore: Unknown C++ exception thrown");
        }
#endif

        reader.readEndElement("Property");
    }
    reader.readEndElement("Properties");
}

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

#include "PreCompiled.h"

#ifndef _PreComp_
# include <sstream>
# include <iostream>
# include <iterator>
#include <Precision.hxx>
#include <cmath>
#endif

#include <Base/Exception.h>
#include <Base/Console.h>
#include <Base/FileInfo.h>
#include <Base/Parameter.h>
#include <Base/UnitsApi.h>

#include <App/Application.h>
#include <App/Document.h>
#include <boost/regex.hpp>

#include "DrawPage.h"
#include "DrawView.h"
#include "DrawProjGroup.h"
#include "DrawViewClip.h"
#include "DrawTemplate.h"
#include "DrawViewCollection.h"
#include "DrawViewPart.h"
#include "DrawViewDimension.h"

#include <Mod/TechDraw/App/DrawPagePy.h>  // generated from DrawPagePy.xml

using namespace TechDraw;
using namespace std;

//===========================================================================
// DrawPage
//===========================================================================

App::PropertyFloatConstraint::Constraints DrawPage::scaleRange = {Precision::Confusion(),
                                                                  std::numeric_limits<double>::max(),
                                                                  pow(10,- Base::UnitsApi::getDecimals())};

PROPERTY_SOURCE(TechDraw::DrawPage, App::DocumentObject)

const char* DrawPage::ProjectionTypeEnums[] = { "First Angle",
                                                "Third Angle",
                                                NULL };

DrawPage::DrawPage(void)
{
    static const char *group = "Page";
    nowDeleting = false;

    ADD_PROPERTY_TYPE(Template, (0), group, (App::PropertyType)(App::Prop_None), "Attached Template");
    ADD_PROPERTY_TYPE(Views, (0), group, (App::PropertyType)(App::Prop_None), "Attached Views");

    // Projection Properties
    ProjectionType.setEnums(ProjectionTypeEnums);

    Base::Reference<ParameterGrp> hGrp =
                        App::GetApplication().GetUserParameter().GetGroup("BaseApp")->GetGroup("Preferences")->GetGroup("Mod/TechDraw/General");

    // In preferences, 0 -> First Angle 1 -> Third Angle
    int projType = hGrp->GetInt("ProjectionAngle", -1);

    if (projType == -1) {
        ADD_PROPERTY(ProjectionType, ((long)0)); // Default to first angle
    } else {
        ADD_PROPERTY(ProjectionType, ((long)projType));
    }

    ADD_PROPERTY_TYPE(Scale, (1.0), group, App::Prop_None, "Scale factor for this Page");
    Scale.setConstraints(&scaleRange);
}

DrawPage::~DrawPage()
{
}

void DrawPage::onBeforeChange(const App::Property* prop)
{
    App::DocumentObject::onBeforeChange(prop);
}

void DrawPage::onChanged(const App::Property* prop)
{
    if (prop == &Template) {
        if (!isRestoring() &&
            !isDeleting()) {
        //TODO: reload if Template prop changes (ie different Template)
        }
    } else if (prop == &Views) {
        if (!isRestoring() &&
            !isDeleting() ) {
            //TODO: reload if Views prop changes (ie adds/deletes)
        }
    } else if(prop == &Scale) {
        // touch all views in the Page as they may be dependent on this scale
      const std::vector<App::DocumentObject*> &vals = Views.getValues();
      for(std::vector<App::DocumentObject *>::const_iterator it = vals.begin(); it < vals.end(); ++it) {
          TechDraw::DrawView *view = dynamic_cast<TechDraw::DrawView *>(*it);
          if (view != NULL && view->ScaleType.isValue("Page")) {
              view->Scale.touch();
          }
      }
    } else if (prop == &ProjectionType) {
      // touch all ortho views in the Page as they may be dependent on Projection Type
      const std::vector<App::DocumentObject*> &vals = Views.getValues();
      for(std::vector<App::DocumentObject *>::const_iterator it = vals.begin(); it < vals.end(); ++it) {
          TechDraw::DrawProjGroup *view = dynamic_cast<TechDraw::DrawProjGroup *>(*it);
          if (view != NULL && view->ProjectionType.isValue("Default")) {
              view->ProjectionType.touch();
          }
      }

      // TODO: Also update Template graphic.

    }
    App::DocumentObject::onChanged(prop);  //<<<<
}

App::DocumentObjectExecReturn *DrawPage::execute(void)
{
    //Page is just a property storage area? no real logic involved?
    //all this does is trigger onChanged in this and ViewProviderPage
    Template.touch();
    Views.touch();
    return App::DocumentObject::StdReturn;
}

short DrawPage::mustExecute() const
{
    if(Scale.isTouched())
        return 1;

    // Check the value of template if this has been modified
    App::DocumentObject* tmpl = Template.getValue();
    if(tmpl && tmpl->isTouched())
        return 1;

    // Check if within this Page, any Views have been touched
    // Why does Page have to execute if a View changes?
    const std::vector<App::DocumentObject*> &vals = Views.getValues();
    for(std::vector<App::DocumentObject *>::const_iterator it = vals.begin(); it < vals.end(); ++it) {
       if((*it)->isTouched()) {
            return 1;
        }
    }

    return App::DocumentObject::mustExecute();
}

PyObject *DrawPage::getPyObject(void)
{
    if (PythonObject.is(Py::_None())){
        // ref counter is set to 1
        PythonObject = Py::Object(new DrawPagePy(this),true);
    }

    return Py::new_reference_to(PythonObject);
}

bool DrawPage::hasValidTemplate() const
{
    App::DocumentObject *obj = 0;
    obj = Template.getValue();

    if(obj && obj->isDerivedFrom(TechDraw::DrawTemplate::getClassTypeId())) {
        TechDraw::DrawTemplate *templ = static_cast<TechDraw::DrawTemplate *>(obj);
        if (templ->getWidth() > 0. &&
            templ->getHeight() > 0.) {
            return true;
        }
    }

    return false;
}

double DrawPage::getPageWidth() const
{
    App::DocumentObject *obj = 0;
    obj = Template.getValue();

    if( obj && obj->isDerivedFrom(TechDraw::DrawTemplate::getClassTypeId()) ) {
        TechDraw::DrawTemplate *templ = static_cast<TechDraw::DrawTemplate *>(obj);
        return templ->getWidth();
    }

    throw Base::Exception("Template not set for Page");
}

double DrawPage::getPageHeight() const
{
    App::DocumentObject *obj = 0;
    obj = Template.getValue();

    if(obj) {
        if(obj->isDerivedFrom(TechDraw::DrawTemplate::getClassTypeId())) {
            TechDraw::DrawTemplate *templ = static_cast<TechDraw::DrawTemplate *>(obj);
            return templ->getHeight();
        }
    }

    throw Base::Exception("Template not set for Page");
}

const char * DrawPage::getPageOrientation() const
{
    App::DocumentObject *obj;
    obj = Template.getValue();

    if(obj) {
        if(obj->isDerivedFrom(TechDraw::DrawTemplate::getClassTypeId())) {
          TechDraw::DrawTemplate *templ = static_cast<TechDraw::DrawTemplate *>(obj);

          return templ->Orientation.getValueAsString();
        }
    }
    throw Base::Exception("Template not set for Page");
}

int DrawPage::addView(App::DocumentObject *docObj)
{
    if(!docObj->isDerivedFrom(TechDraw::DrawView::getClassTypeId()))
        return -1;
    DrawView* view = static_cast<DrawView*>(docObj);

    //position all new views in center of Page (exceptDVDimension)
    if (!docObj->isDerivedFrom(TechDraw::DrawViewDimension::getClassTypeId())) {
        view->X.setValue(getPageWidth()/2.0);
        view->Y.setValue(getPageHeight()/2.0);
    }

    //add view to list
    const std::vector<App::DocumentObject *> currViews = Views.getValues();
    std::vector<App::DocumentObject *> newViews(currViews);
    newViews.push_back(docObj);
    Views.setValues(newViews);

    //check if View fits on Page
    if ( !view->checkFit(this) ) {
        Base::Console().Warning("%s is larger than page. Will be scaled.\n",view->getNameInDocument());
        view->ScaleType.setValue("Automatic");
    }

    return Views.getSize();
}

int DrawPage::removeView(App::DocumentObject *docObj)
{
    if(!docObj->isDerivedFrom(TechDraw::DrawView::getClassTypeId()))
        return -1;

    const std::vector<App::DocumentObject*> currViews = Views.getValues();
    std::vector<App::DocumentObject*> newViews;
    std::vector<App::DocumentObject*>::const_iterator it = currViews.begin();
    for (; it != currViews.end(); it++) {
        std::string viewName = docObj->getNameInDocument();
        if (viewName.compare((*it)->getNameInDocument()) != 0) {
            newViews.push_back((*it));
        }
    }
    Views.setValues(newViews);

    return Views.getSize();
}

void DrawPage::onDocumentRestored()
{
    std::vector<App::DocumentObject*> featViews = Views.getValues();
    std::vector<App::DocumentObject*>::const_iterator it = featViews.begin();
    //first, make sure all the Parts have been executed so GeometryObjects exist
    for(; it != featViews.end(); ++it) {
        TechDraw::DrawViewPart *part = dynamic_cast<TechDraw::DrawViewPart *>(*it);
        if (part != nullptr &&
            !part->hasGeometry()) {
            part->execute();
//            std::vector<App::DocumentObject*> parent = part->getInList();
//            for (auto& p: parent) {
//                p->touch();
//            }
        }
    }
    //second, make sure all the Dimensions have been executed so Measurements have References
    for(it = featViews.begin(); it != featViews.end(); ++it) {
        TechDraw::DrawViewDimension *dim = dynamic_cast<TechDraw::DrawViewDimension *>(*it);
        if (dim != nullptr &&
            !dim->has2DReferences()) {
            dim->execute();
        }
    }
    recompute();
    App::DocumentObject::onDocumentRestored();
}

void DrawPage::unsetupObject()
{
    nowDeleting = true;

    // Remove the Page's views & template from document
    App::Document* doc = getDocument();
    std::string docName = doc->getName();

    const std::vector<App::DocumentObject*> currViews = Views.getValues();
    std::vector<App::DocumentObject*> emptyViews;
    std::vector<App::DocumentObject*>::const_iterator it = currViews.begin();
    for (; it != currViews.end(); it++) {
        std::string viewName = (*it)->getNameInDocument();
        Base::Interpreter().runStringArg("App.getDocument(\"%s\").removeObject(\"%s\")",
                                          docName.c_str(), viewName.c_str());
    }
    Views.setValues(emptyViews);

    App::DocumentObject* tmp = Template.getValue();
    if (tmp != nullptr) {
        std::string templateName = Template.getValue()->getNameInDocument();
        Base::Interpreter().runStringArg("App.getDocument(\"%s\").removeObject(\"%s\")",
                                              docName.c_str(), templateName.c_str());
    }
    Template.setValue(nullptr);
}

void DrawPage::Restore(Base::XMLReader &reader)
{
    reader.readElement("Properties");
    int Cnt = reader.getAttributeAsInteger("Count");

    for (int i=0 ;i<Cnt ;i++) {
        reader.readElement("Property");
        const char* PropName = reader.getAttribute("name");
        const char* TypeName = reader.getAttribute("type");
        App::Property* schemaProp = getPropertyByName(PropName);
        try {
            if(schemaProp){
                if (strcmp(schemaProp->getTypeId().getName(), TypeName) == 0){        //if the property type in obj == type in schema
                    schemaProp->Restore(reader);                                      //nothing special to do
                } else  {
                    if (strcmp(PropName, "Scale") == 0) {
                        if (schemaProp->isDerivedFrom(App::PropertyFloatConstraint::getClassTypeId())){  //right property type
                            schemaProp->Restore(reader);                                                  //nothing special to do
                        } else {                                                                //Scale, but not PropertyFloatConstraint
                            App::PropertyFloat tmp;
                            if (strcmp(tmp.getTypeId().getName(),TypeName)) {                   //property in file is Float
                                tmp.setContainer(this);
                                tmp.Restore(reader);
                                double tmpValue = tmp.getValue();
                                if (tmpValue > 0.0) {
                                    static_cast<App::PropertyFloatConstraint*>(schemaProp)->setValue(tmpValue);
                                } else {
                                    static_cast<App::PropertyFloatConstraint*>(schemaProp)->setValue(1.0);
                                }
                            } else {
                                // has Scale prop that isn't Float!
                                Base::Console().Log("DrawPage::Restore - old Document Scale is Not Float!\n");
                                // no idea
                            }
                        }
                    } else {
                        Base::Console().Log("DrawPage::Restore - old Document has unknown Property\n");
                    }
                }
            }
        }
        catch (const Base::XMLParseException&) {
            throw; // re-throw
        }
        catch (const Base::Exception &e) {
            Base::Console().Error("%s\n", e.what());
        }
        catch (const std::exception &e) {
            Base::Console().Error("%s\n", e.what());
        }
        catch (const char* e) {
            Base::Console().Error("%s\n", e);
        }
#ifndef FC_DEBUG
        catch (...) {
            Base::Console().Error("PropertyContainer::Restore: Unknown C++ exception thrown");
        }
#endif

        reader.readEndElement("Property");
    }
    reader.readEndElement("Properties");
}

<|endoftext|>


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

#include "PreCompiled.h"

#ifndef _PreComp_
# include <sstream>
# include <cstring>
# include <cstdlib>
# include <exception>
# include <boost/regex.hpp>
# include <QString>
# include <QStringList>
# include <QRegExp>
#include <QChar>

#include <BRep_Tool.hxx>
#include <gp_Pnt.hxx>
#include <Precision.hxx>
#include <BRepLProp_CLProps.hxx>
#include <TopExp_Explorer.hxx>
#include <BRepAdaptor_Curve.hxx>
#include <BRepLProp_CurveTool.hxx>
#include <TopTools_IndexedMapOfShape.hxx>
#include <TopExp.hxx>
#include <TopExp_Explorer.hxx>
#include <BRepGProp.hxx>
#include <GProp_GProps.hxx>

#endif

#include <App/Application.h>
#include <Base/Console.h>
#include <Base/Exception.h>
#include <Base/Parameter.h>

#include "DrawUtil.h"

using namespace TechDraw;

/*static*/ int DrawUtil::getIndexFromName(std::string geomName)
{
   boost::regex re("\\d+$"); // one of more digits at end of string
   boost::match_results<std::string::const_iterator> what;
   boost::match_flag_type flags = boost::match_default;
   char* endChar;
   std::string::const_iterator begin = geomName.begin();
   std::string::const_iterator end = geomName.end();
   std::stringstream ErrorMsg;

   if (!geomName.empty()) {
      if (boost::regex_search(begin, end, what, re, flags)) {
         return int (std::strtol(what.str().c_str(), &endChar, 10));         //TODO: use std::stoi() in c++11
      } else {
         ErrorMsg << "getIndexFromName: malformed geometry name - " << geomName;
         throw Base::Exception(ErrorMsg.str());
      }
   } else {
         throw Base::Exception("getIndexFromName - empty geometry name");
   }
}

std::string DrawUtil::getGeomTypeFromName(std::string geomName)
{
   boost::regex re("^[a-zA-Z]*");                                           //one or more letters at start of string
   boost::match_results<std::string::const_iterator> what;
   boost::match_flag_type flags = boost::match_default;
   std::string::const_iterator begin = geomName.begin();
   std::string::const_iterator end = geomName.end();
   std::stringstream ErrorMsg;

   if (!geomName.empty()) {
      if (boost::regex_search(begin, end, what, re, flags)) {
         return what.str();         //TODO: use std::stoi() in c++11
      } else {
         ErrorMsg << "In getGeomTypeFromName: malformed geometry name - " << geomName;
         throw Base::Exception(ErrorMsg.str());
      }
   } else {
         throw Base::Exception("getGeomTypeFromName - empty geometry name");
   }
}

std::string DrawUtil::makeGeomName(std::string geomType, int index)
{
    std::stringstream newName;
    newName << geomType << index;
    return newName.str();
}

bool DrawUtil::isSamePoint(TopoDS_Vertex v1, TopoDS_Vertex v2)
{
    bool result = false;
    gp_Pnt p1 = BRep_Tool::Pnt(v1);
    gp_Pnt p2 = BRep_Tool::Pnt(v2);
    if (p1.IsEqual(p2,Precision::Confusion())) {
        result = true;
    }
    return result;
}

bool DrawUtil::isZeroEdge(TopoDS_Edge e)
{
    TopoDS_Vertex vStart = TopExp::FirstVertex(e);
    TopoDS_Vertex vEnd = TopExp::LastVertex(e);
    bool result = isSamePoint(vStart,vEnd);
    if (result) {
        //closed edge will have same V's but non-zero length
        GProp_GProps props;
        BRepGProp::LinearProperties(e, props);
        double len = props.Mass();
        if (len > Precision::Confusion()) {
            result = false;
        }
    }
    return result;
}

//based on Function provided by Joe Dowsett, 2014
double DrawUtil::sensibleScale(double working_scale)
{
    double result = 1.0;
    //which gives the largest scale for which the min_space requirements can be met, but we want a 'sensible' scale, rather than 0.28457239...
    //eg if working_scale = 0.115, then we want to use 0.1, similarly 7.65 -> 5, and 76.5 -> 50

    float exponent = std::floor(std::log10(working_scale));                  //if working_scale = a * 10^b, what is b?
    working_scale *= std::pow(10, -exponent);                                //now find what 'a' is.

    //int choices = 10;
    float valid_scales[2][10] =
                          {{1.0, 1.25, 2.0, 2.5, 3.75, 5.0, 7.5, 10.0, 50.0, 100.0},   //equate to 1:10, 1:8, 1:5, 1:4, 3:8, 1:2, 3:4, 1:1
                                                                                //          .1   .125            .375      .75
                           {1.0, 1.5 , 2.0, 3.0, 4.0 , 5.0, 8.0, 10.0, 50.0, 100.0}};  //equate to 1:1, 3:2, 2:1, 3:1, 4:1, 5:1, 8:1, 10:1
                                                                                //              1.5:1
    //int i = choices - 1;
    int i = 9;
    while (valid_scales[(exponent >= 0)][i] > working_scale)                 //choose closest value smaller than 'a' from list.
        i -= 1;                                                              //choosing top list if exponent -ve, bottom list for +ve exponent

    //now have the appropriate scale, reapply the *10^b
    result = valid_scales[(exponent >= 0)][i] * pow(10, exponent);
    return result;
}

//============================
// various debugging routines.
void DrawUtil::dumpVertexes(const char* text, const TopoDS_Shape& s)
{
    Base::Console().Message("DUMP - %s\n",text);
    TopExp_Explorer expl(s, TopAbs_VERTEX);
    int i;
    for (i = 1 ; expl.More(); expl.Next(),i++) {
        const TopoDS_Vertex& v = TopoDS::Vertex(expl.Current());
        gp_Pnt pnt = BRep_Tool::Pnt(v);
        Base::Console().Message("v%d: (%.3f,%.3f,%.3f)\n",i,pnt.X(),pnt.Y(),pnt.Z());
    }
}

void DrawUtil::countFaces(const char* text, const TopoDS_Shape& s)
{
    TopTools_IndexedMapOfShape mapOfFaces;
    TopExp::MapShapes(s, TopAbs_FACE, mapOfFaces);
    int num = mapOfFaces.Extent();
    Base::Console().Message("COUNT - %s has %d Faces\n",text,num);
}

//count # of unique Wires in shape.
void DrawUtil::countWires(const char* text, const TopoDS_Shape& s)
{
    TopTools_IndexedMapOfShape mapOfWires;
    TopExp::MapShapes(s, TopAbs_WIRE, mapOfWires);
    int num = mapOfWires.Extent();
    Base::Console().Message("COUNT - %s has %d wires\n",text,num);
}

void DrawUtil::countEdges(const char* text, const TopoDS_Shape& s)
{
    TopTools_IndexedMapOfShape mapOfEdges;
    TopExp::MapShapes(s, TopAbs_EDGE, mapOfEdges);
    int num = mapOfEdges.Extent();
    Base::Console().Message("COUNT - %s has %d edges\n",text,num);
}

void DrawUtil::dump1Vertex(const char* text, const TopoDS_Vertex& v)
{
    Base::Console().Message("DUMP - dump1Vertex - %s\n",text);
    gp_Pnt pnt = BRep_Tool::Pnt(v);
    Base::Console().Message("%s: (%.3f,%.3f,%.3f)\n",text,pnt.X(),pnt.Y(),pnt.Z());
}

void DrawUtil::dumpEdge(char* label, int i, TopoDS_Edge e)
{
    BRepAdaptor_Curve adapt(e);
    double start = BRepLProp_CurveTool::FirstParameter(adapt);
    double end = BRepLProp_CurveTool::LastParameter(adapt);
    BRepLProp_CLProps propStart(adapt,start,0,Precision::Confusion());
    const gp_Pnt& vStart = propStart.Value();
    BRepLProp_CLProps propEnd(adapt,end,0,Precision::Confusion());
    const gp_Pnt& vEnd = propEnd.Value();
    //Base::Console().Message("%s edge:%d start:(%.3f,%.3f,%.3f)/%0.3f end:(%.2f,%.3f,%.3f)/%.3f\n",label,i,
    //                        vStart.X(),vStart.Y(),vStart.Z(),start,vEnd.X(),vEnd.Y(),vEnd.Z(),end);
    Base::Console().Message("%s edge:%d start:(%.3f,%.3f,%.3f)  end:(%.2f,%.3f,%.3f)\n",label,i,
                            vStart.X(),vStart.Y(),vStart.Z(),vEnd.X(),vEnd.Y(),vEnd.Z());
}
const char* DrawUtil::printBool(bool b)
{
    return (b ? "True" : "False");
}

QString DrawUtil::qbaToDebug(const QByteArray & line)
{
    QString s;
    uchar c;

    for ( int i=0 ; i < line.size() ; i++ ){
        c = line[i];
        if ( c >= 0x20 and c <= 126 ) {
            s.append(QChar::fromLatin1(c));
        } else {
            s.append(QString::fromUtf8("<%1>").arg(c, 2, 16, QChar::fromLatin1('0')));
        }
    }
    return s;
}

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

#include "PreCompiled.h"

#ifndef _PreComp_
# include <sstream>
# include <cstring>
# include <cstdlib>
# include <exception>
# include <boost/regex.hpp>
# include <QString>
# include <QStringList>
# include <QRegExp>
#include <QChar>

#include <BRep_Tool.hxx>
#include <gp_Pnt.hxx>
#include <Precision.hxx>
#include <BRepLProp_CLProps.hxx>
#include <TopExp_Explorer.hxx>
#include <BRepAdaptor_Curve.hxx>
#include <BRepLProp_CurveTool.hxx>
#include <TopTools_IndexedMapOfShape.hxx>
#include <TopExp.hxx>
#include <TopExp_Explorer.hxx>
#include <BRepGProp.hxx>
#include <GProp_GProps.hxx>

#endif

#include <App/Application.h>
#include <Base/Console.h>
#include <Base/Exception.h>
#include <Base/Parameter.h>

#include "DrawUtil.h"

using namespace TechDraw;

/*static*/ int DrawUtil::getIndexFromName(std::string geomName)
{
   boost::regex re("\\d+$"); // one of more digits at end of string
   boost::match_results<std::string::const_iterator> what;
   boost::match_flag_type flags = boost::match_default;
   char* endChar;
   std::string::const_iterator begin = geomName.begin();
   std::string::const_iterator end = geomName.end();
   std::stringstream ErrorMsg;

   if (!geomName.empty()) {
      if (boost::regex_search(begin, end, what, re, flags)) {
         return int (std::strtol(what.str().c_str(), &endChar, 10));         //TODO: use std::stoi() in c++11
      } else {
         ErrorMsg << "getIndexFromName: malformed geometry name - " << geomName;
         throw Base::Exception(ErrorMsg.str());
      }
   } else {
         throw Base::Exception("getIndexFromName - empty geometry name");
   }
}

std::string DrawUtil::getGeomTypeFromName(std::string geomName)
{
   boost::regex re("^[a-zA-Z]*");                                           //one or more letters at start of string
   boost::match_results<std::string::const_iterator> what;
   boost::match_flag_type flags = boost::match_default;
   std::string::const_iterator begin = geomName.begin();
   std::string::const_iterator end = geomName.end();
   std::stringstream ErrorMsg;

   if (!geomName.empty()) {
      if (boost::regex_search(begin, end, what, re, flags)) {
         return what.str();         //TODO: use std::stoi() in c++11
      } else {
         ErrorMsg << "In getGeomTypeFromName: malformed geometry name - " << geomName;
         throw Base::Exception(ErrorMsg.str());
      }
   } else {
         throw Base::Exception("getGeomTypeFromName - empty geometry name");
   }
}

std::string DrawUtil::makeGeomName(std::string geomType, int index)
{
    std::stringstream newName;
    newName << geomType << index;
    return newName.str();
}

bool DrawUtil::isSamePoint(TopoDS_Vertex v1, TopoDS_Vertex v2)
{
    bool result = false;
    gp_Pnt p1 = BRep_Tool::Pnt(v1);
    gp_Pnt p2 = BRep_Tool::Pnt(v2);
    if (p1.IsEqual(p2,Precision::Confusion())) {
        result = true;
    }
    return result;
}

bool DrawUtil::isZeroEdge(TopoDS_Edge e)
{
    TopoDS_Vertex vStart = TopExp::FirstVertex(e);
    TopoDS_Vertex vEnd = TopExp::LastVertex(e);
    bool result = isSamePoint(vStart,vEnd);
    if (result) {
        //closed edge will have same V's but non-zero length
        GProp_GProps props;
        BRepGProp::LinearProperties(e, props);
        double len = props.Mass();
        if (len > Precision::Confusion()) {
            result = false;
        }
    }
    return result;
}

//based on Function provided by Joe Dowsett, 2014
double DrawUtil::sensibleScale(double working_scale)
{
    double result = 1.0;
    //which gives the largest scale for which the min_space requirements can be met, but we want a 'sensible' scale, rather than 0.28457239...
    //eg if working_scale = 0.115, then we want to use 0.1, similarly 7.65 -> 5, and 76.5 -> 50

    float exponent = std::floor(std::log10(working_scale));                  //if working_scale = a * 10^b, what is b?
    working_scale *= std::pow(10, -exponent);                                //now find what 'a' is.

    //int choices = 10;
    float valid_scales[2][10] =
                          {{1.0, 1.25, 2.0, 2.5, 3.75, 5.0, 7.5, 10.0, 50.0, 100.0},   //equate to 1:10, 1:8, 1:5, 1:4, 3:8, 1:2, 3:4, 1:1
                                                                                //          .1   .125            .375      .75
                           {1.0, 1.5 , 2.0, 3.0, 4.0 , 5.0, 8.0, 10.0, 50.0, 100.0}};  //equate to 1:1, 3:2, 2:1, 3:1, 4:1, 5:1, 8:1, 10:1
                                                                                //              1.5:1
    //int i = choices - 1;
    int i = 9;
    while (valid_scales[(exponent >= 0)][i] > working_scale)                 //choose closest value smaller than 'a' from list.
        i -= 1;                                                              //choosing top list if exponent -ve, bottom list for +ve exponent

    //now have the appropriate scale, reapply the *10^b
    result = valid_scales[(exponent >= 0)][i] * pow(10, exponent);
    return result;
}

//============================
// various debugging routines.
void DrawUtil::dumpVertexes(const char* text, const TopoDS_Shape& s)
{
    Base::Console().Message("DUMP - %s\n",text);
    TopExp_Explorer expl(s, TopAbs_VERTEX);
    int i;
    for (i = 1 ; expl.More(); expl.Next(),i++) {
        const TopoDS_Vertex& v = TopoDS::Vertex(expl.Current());
        gp_Pnt pnt = BRep_Tool::Pnt(v);
        Base::Console().Message("v%d: (%.3f,%.3f,%.3f)\n",i,pnt.X(),pnt.Y(),pnt.Z());
    }
}

void DrawUtil::countFaces(const char* text, const TopoDS_Shape& s)
{
    TopTools_IndexedMapOfShape mapOfFaces;
    TopExp::MapShapes(s, TopAbs_FACE, mapOfFaces);
    int num = mapOfFaces.Extent();
    Base::Console().Message("COUNT - %s has %d Faces\n",text,num);
}

//count # of unique Wires in shape.
void DrawUtil::countWires(const char* text, const TopoDS_Shape& s)
{
    TopTools_IndexedMapOfShape mapOfWires;
    TopExp::MapShapes(s, TopAbs_WIRE, mapOfWires);
    int num = mapOfWires.Extent();
    Base::Console().Message("COUNT - %s has %d wires\n",text,num);
}

void DrawUtil::countEdges(const char* text, const TopoDS_Shape& s)
{
    TopTools_IndexedMapOfShape mapOfEdges;
    TopExp::MapShapes(s, TopAbs_EDGE, mapOfEdges);
    int num = mapOfEdges.Extent();
    Base::Console().Message("COUNT - %s has %d edges\n",text,num);
}

void DrawUtil::dump1Vertex(const char* text, const TopoDS_Vertex& v)
{
    Base::Console().Message("DUMP - dump1Vertex - %s\n",text);
    gp_Pnt pnt = BRep_Tool::Pnt(v);
    Base::Console().Message("%s: (%.3f,%.3f,%.3f)\n",text,pnt.X(),pnt.Y(),pnt.Z());
}

void DrawUtil::dumpEdge(char* label, int i, TopoDS_Edge e)
{
    BRepAdaptor_Curve adapt(e);
    double start = BRepLProp_CurveTool::FirstParameter(adapt);
    double end = BRepLProp_CurveTool::LastParameter(adapt);
    BRepLProp_CLProps propStart(adapt,start,0,Precision::Confusion());
    const gp_Pnt& vStart = propStart.Value();
    BRepLProp_CLProps propEnd(adapt,end,0,Precision::Confusion());
    const gp_Pnt& vEnd = propEnd.Value();
    //Base::Console().Message("%s edge:%d start:(%.3f,%.3f,%.3f)/%0.3f end:(%.2f,%.3f,%.3f)/%.3f\n",label,i,
    //                        vStart.X(),vStart.Y(),vStart.Z(),start,vEnd.X(),vEnd.Y(),vEnd.Z(),end);
    Base::Console().Message("%s edge:%d start:(%.3f,%.3f,%.3f)  end:(%.2f,%.3f,%.3f)\n",label,i,
                            vStart.X(),vStart.Y(),vStart.Z(),vEnd.X(),vEnd.Y(),vEnd.Z());
}
const char* DrawUtil::printBool(bool b)
{
    return (b ? "True" : "False");
}

QString DrawUtil::qbaToDebug(const QByteArray & line)
{
    QString s;
    uchar c;

    for ( int i=0 ; i < line.size() ; i++ ){
        c = line[i];
        if (( c >= 0x20) && (c <= 126) ) {
            s.append(QChar::fromLatin1(c));
        } else {
            s.append(QString::fromUtf8("<%1>").arg(c, 2, 16, QChar::fromLatin1('0')));
        }
    }
    return s;
}

//==================================
<|endoftext|>


<commit_before>#include "ProtocolSimpleNisse.h"
#include "NisseService.h"

using namespace ThorsAnvil::Nisse::ProtocolSimple;

ReadMessageHandler::ReadMessageHandler(NisseService& parent, LibEventBase* base, ThorsAnvil::Socket::DataSocket&& so)
    : NisseHandler(parent, base, so.getSocketId(), EV_READ)
    , socket(std::move(so))
    , readSizeObject(0)
    , readBuffer(0)
{}

void ReadMessageHandler::eventActivate(LibSocketId /*sockId*/, short /*eventType*/)
{
    bool more;
    if (readSizeObject != sizeof(readSizeObject))
    {
        std::tie(more, readSizeObject) = socket.getMessageData(reinterpret_cast<char*>(&bufferSize), sizeof(bufferSize), readSizeObject);
        if (!more)
        {
            dropHandler();
            return;
        }
        if (readSizeObject != sizeof(readSizeObject))
        {
            return;
        }
        buffer.resize(bufferSize);
    }
    std::tie(more, readBuffer) = socket.getMessageData(&buffer[0], bufferSize, readBuffer);
    if (!more)
    {
        dropHandler();
        return;
    }
    if (readBuffer != bufferSize)
    {
        return;
    }
    moveHandler<WriteMessageHandler>(std::move(socket), buffer);
}

WriteMessageHandler::WriteMessageHandler(NisseService& parent, LibEventBase* base, ThorsAnvil::Socket::DataSocket&& so, std::string const& m)
    : NisseHandler(parent, base, so.getSocketId(), EV_WRITE)
    , socket(std::move(so))
    , writeSizeObject(0)
    , writeBuffer(0)
    , message(m)
{
    message += " -> OK";
}

void WriteMessageHandler::eventActivate(LibSocketId /*sockId*/, short /*eventType*/)
{
    bool        more;
    if (writeSizeObject != sizeof(writeSizeObject))
    {
        std::size_t bufferSize = message.size();
        std::tie(more, writeSizeObject) = socket.putMessageData(reinterpret_cast<char*>(&bufferSize), sizeof(bufferSize), writeSizeObject);
        if (!more)
        {
            dropHandler();
            return;
        }
        if (writeSizeObject != sizeof(writeSizeObject))
        {
            return;
        }
    }
    std::tie(more, writeBuffer) = socket.putMessageData(message.c_str(), message.size(), writeBuffer);
    if (!more)
    {
        dropHandler();
        return;
    }
    if (writeBuffer != message.size())
    {
        return;
    }
    dropHandler();
}
<commit_msg>Fix simple bug<commit_after>#include "ProtocolSimpleNisse.h"
#include "NisseService.h"

using namespace ThorsAnvil::Nisse::ProtocolSimple;

ReadMessageHandler::ReadMessageHandler(NisseService& parent, LibEventBase* base, ThorsAnvil::Socket::DataSocket&& so)
    : NisseHandler(parent, base, so.getSocketId(), EV_READ)
    , socket(std::move(so))
    , readSizeObject(0)
    , readBuffer(0)
{}

void ReadMessageHandler::eventActivate(LibSocketId /*sockId*/, short /*eventType*/)
{
    bool more;
    if (readSizeObject != sizeof(readSizeObject))
    {
        std::tie(more, readSizeObject) = socket.getMessageData(reinterpret_cast<char*>(&bufferSize), sizeof(bufferSize), readSizeObject);
        if (!more)
        {
            dropHandler();
            return;
        }
        if (readSizeObject != sizeof(readSizeObject))
        {
            return;
        }
        buffer.resize(bufferSize);
    }
    std::tie(more, readBuffer) = socket.getMessageData(&buffer[0], bufferSize, readBuffer);
    if (!more)
    {
        dropHandler();
        return;
    }
    if (readBuffer != bufferSize)
    {
        return;
    }
    moveHandler<WriteMessageHandler>(std::move(socket), std::move(buffer));
}

WriteMessageHandler::WriteMessageHandler(NisseService& parent, LibEventBase* base, ThorsAnvil::Socket::DataSocket&& so, std::string const& m)
    : NisseHandler(parent, base, so.getSocketId(), EV_WRITE)
    , socket(std::move(so))
    , writeSizeObject(0)
    , writeBuffer(0)
    , message(m)
{
    message += " -> OK";
}

void WriteMessageHandler::eventActivate(LibSocketId /*sockId*/, short /*eventType*/)
{
    bool        more;
    if (writeSizeObject != sizeof(writeSizeObject))
    {
        std::size_t bufferSize = message.size();
        std::tie(more, writeSizeObject) = socket.putMessageData(reinterpret_cast<char*>(&bufferSize), sizeof(bufferSize), writeSizeObject);
        if (!more)
        {
            dropHandler();
            return;
        }
        if (writeSizeObject != sizeof(writeSizeObject))
        {
            return;
        }
    }
    std::tie(more, writeBuffer) = socket.putMessageData(message.c_str(), message.size(), writeBuffer);
    if (!more)
    {
        dropHandler();
        return;
    }
    if (writeBuffer != message.size())
    {
        return;
    }
    dropHandler();
}
<|endoftext|>


<commit_before>//#define RemCorReaPri_DEBUG

#include <stdexcept>

#include <boost/algorithm/string.hpp>
#include <boost/algorithm/string/split.hpp>
#include <boost/algorithm/string/classification.hpp>

#include <config.hh>

#ifdef USE_DBXML
#include <dbxml/DbXml.hpp>
#endif // USE_DBXML

#include <AlpinoCorpus/Error.hh>
#include <AlpinoCorpus/IterImpl.hh>
#include "RemoteCorpusReaderPrivate.hh"
#include "util/GetUrl.hh"
#include "util/parseString.hh"
#include "util/url.hh"

#ifdef RemCorReaPri_DEBUG
#include <iostream>
#endif

namespace alpinocorpus {

    // done
    RemoteCorpusReaderPrivate::RemoteCorpusReaderPrivate(std::string const &url)
        : d_validSize(true)
    {
        if (url.substr(0, 7) != "http://" && url.substr(0, 8) != "https://")
            throw OpenError(url, "Not a valid URL");

        size_t i = url.find_last_of('/');
        if (i == std::string::npos)
            throw std::invalid_argument("Invalid argument, must be http://host/name");
        d_name = url.substr(i + 1);
        d_url = url;

        bool OK = false;
        util::GetUrl p1(url.substr(0, i) + "/corpora");
        std::vector<std::string> lines;
        std::vector<std::string> words;
        boost::algorithm::split(lines, p1.body(), boost::algorithm::is_any_of("\n"), boost::algorithm::token_compress_on);
        for (std::vector<std::string>::const_iterator iter = lines.begin();
            iter != lines.end(); ++iter)
        {
            boost::algorithm::split(words, *iter, boost::algorithm::is_any_of("\t"));
            if (words.size() == 4 && words[0] == d_name) {
                OK = true;
                try {
                    d_size = util::parseString<size_t>(words[1]);
                } catch (std::invalid_argument &) {
                    d_size = 0;
                    d_validSize = false;
                }
            }
        }
        if (!OK)
            throw std::invalid_argument("URL is not a valid corpus: " + d_url);

        // why a reset here?
        d_geturl.reset(new util::GetUrl(d_url + "/entries"));
    }

    RemoteCorpusReaderPrivate::~RemoteCorpusReaderPrivate()
    {
    }

    // done
    CorpusReader::EntryIterator RemoteCorpusReaderPrivate::getBegin() const
    {
        if (d_geturl->interrupted() && ! d_geturl->completed())
            const_cast<RemoteCorpusReaderPrivate *>(this)->d_geturl->resume();

        return EntryIterator(new RemoteIter(d_geturl, 0, false));
    }

    // done
    CorpusReader::EntryIterator RemoteCorpusReaderPrivate::getEnd() const
    {
        return EntryIterator(new RemoteIter(d_geturl, 0, true));
    }

    // done? TODO: alleen naam van corpus of complete url? (nu: complete url)
    std::string RemoteCorpusReaderPrivate::getName() const
    {
        // return d_name;
        return d_url;
    }

    // done
    size_t RemoteCorpusReaderPrivate::getSize() const
    {
        if (d_validSize)
            return d_size;
        else
            throw std::runtime_error("RemoteCorpusReader: size is unknown");
    }

    bool RemoteCorpusReaderPrivate::validQuery(QueryDialect d, bool variables,
        std::string const &query) const
    {
#ifdef USE_DBXML
        try {
            DbXml::XmlQueryContext ctx = mgr.createQueryContext();
            mgr.prepare(query, ctx);
        } catch (DbXml::XmlException const &e) {
            return false;
        }
        return true;
#else
        util::GetUrl p(d_url + "/validQuery?query=" + util::toPercentEncoding(query));
        std::string result = p.body();
        boost::to_lower(result);
        boost::trim(result);
        return (result == "true" || result == "yes" || result == "1");
#endif
    }

    // done
    std::string RemoteCorpusReaderPrivate::readEntry(std::string const &filename) const
    {
        // util::GetUrl p(d_url + "/entry/" + escape(filename));
        util::GetUrl p(d_url + "/entry/" + filename);
        return p.body();
    }

    // TODO: multiple queries (now: only the first is used)
    std::string RemoteCorpusReaderPrivate::readEntryMarkQueries(std::string const &entry,
        std::list<MarkerQuery> const &queries) const
    {
        std::list<MarkerQuery>::const_iterator iter = queries.begin();

        if (iter == queries.end())
            return readEntry(entry);

        util::GetUrl p(d_url + "/entry/" + entry +   // escape(entry) +
                       "?markerQuery=" + util::toPercentEncoding(iter->query) +
                       "&markerAttr=" + util::toPercentEncoding(iter->attr) +
                       "&markerValue=" + util::toPercentEncoding(iter->value));

        ++iter;
        if (iter != queries.end())
            throw Error("RemoteCorpusReaderPrivate: Multiple queries not implemented");

        return p.body();
    }

    // TODO: multiple queries (now: only the first is used)
    CorpusReader::EntryIterator RemoteCorpusReaderPrivate::runQueryWithStylesheet(
        QueryDialect d, std::string const &q, std::string const &stylesheet,
        std::list<MarkerQuery> const &markerQueries) const
    {
        std::list<MarkerQuery>::const_iterator iter = markerQueries.begin();

        if (iter == markerQueries.end())
            throw Error("RemoteCorpusReaderPrivate: Missing query");

        std::tr1::shared_ptr<util::GetUrl> p(new util::GetUrl(d_url + "/entries?query=" +
                                                              util::toPercentEncoding(q) +
                                                              "&markerQuery=" + util::toPercentEncoding(iter->query) +
                                                              "&markerAttr=" + util::toPercentEncoding(iter->attr) +
                                                              "&markerValue=" + util::toPercentEncoding(iter->value) +
                                                              "&contents=1", stylesheet));

        ++iter;
        if (iter != markerQueries.end())
            throw Error("RemoteCorpusReaderPrivate: Multiple queries not implemented");

        return EntryIterator(new RemoteIter(p, 0, false, true));
    }

    // TODO: multiple queries (now: only the first is used)
    CorpusReader::EntryIterator RemoteCorpusReaderPrivate::beginWithStylesheet(
        std::string const &stylesheet,
        std::list<MarkerQuery> const &markerQueries) const
    {
        std::list<MarkerQuery>::const_iterator iter = markerQueries.begin();

        if (iter == markerQueries.end())
            throw Error("RemoteCorpusReaderPrivate: Missing query");

        std::tr1::shared_ptr<util::GetUrl> p(new util::GetUrl(d_url + "/entries" +
                                                              "?markerQuery=" + util::toPercentEncoding(iter->query) +
                                                              "&markerAttr=" + util::toPercentEncoding(iter->attr) +
                                                              "&markerValue=" + util::toPercentEncoding(iter->value) +
                                                              "&contents=1", stylesheet));

        ++iter;
        if (iter != markerQueries.end())
            throw Error("RemoteCorpusReaderPrivate: Multiple queries not implemented");

        return EntryIterator(new RemoteIter(p, 0, false, true));

    }

    // done
    CorpusReader::EntryIterator RemoteCorpusReaderPrivate::runXPath(
        std::string const &query) const
    {
        std::tr1::shared_ptr<util::GetUrl> p(new util::GetUrl(d_url +
            "/entries?query=" + util::toPercentEncoding(query) +
            "&contents=1"));
        return EntryIterator(new RemoteIter(p, 0, false, true));
    }

    // done? TODO: klopt dit? (blijkbaar wel)
    CorpusReader::EntryIterator RemoteCorpusReaderPrivate::runXQuery(
        std::string const &query) const
    {
        return runXPath(query);
    }

    // done
    RemoteCorpusReaderPrivate::RemoteIter::RemoteIter(std::tr1::shared_ptr<util::GetUrl> geturl,
                                                      size_t n,
                                                      bool end,
                                                      bool isquery)
        : d_geturl(geturl), d_idx(n), d_end(end), d_isquery(isquery), d_active(false)
    {
        d_interrupted = std::tr1::shared_ptr<bool>(new bool(false));
    }

    // done
    RemoteCorpusReaderPrivate::RemoteIter::~RemoteIter()
    {
    }

    void RemoteCorpusReaderPrivate::RemoteIter::activate() const
    {
        if (d_active)
            return;
        if (d_end) {
            d_active = true;
            return;
        }

        d_geturl->line(d_idx);
        if (d_geturl->eof())
            d_end = true;

        d_active = true;
    }

    // done
    std::string RemoteCorpusReaderPrivate::RemoteIter::current() const
    {
        activate();

        if (!d_end) {
            std::string s = d_geturl->line(d_idx);
            if (d_isquery) {
                size_t i = s.find('\t');
                if (i == std::string::npos)
                    return s;
                else
                    return s.substr(0, i);
            } else
                return s;
        } else
            return std::string();
    }

    // done
    void RemoteCorpusReaderPrivate::RemoteIter::next()
    {
        activate();

        if (*d_interrupted) {
#ifdef RemCorReaPri_DEBUG
            std::cerr << "[RemoteCorpusReaderPrivate] Calling next on interrupted RemoteIter" << std::endl;
#endif
            throw alpinocorpus::IterationInterrupted();
        }

        if (!d_end) {
            ++d_idx;
            d_geturl->line(d_idx);
            if (d_geturl->eof())
                d_end = true;
        }
    }

    // done
    bool RemoteCorpusReaderPrivate::RemoteIter::equals(IterImpl const &other) const
    {
        RemoteIter const &that = (RemoteIter const &)other;
        activate();
        that.activate();
        if (d_end && that.d_end)
          return true;
        else
          return (d_end == that.d_end && d_idx == that.d_idx);
    }

    // done
    IterImpl *RemoteCorpusReaderPrivate::RemoteIter::copy() const
    {
        RemoteIter *other = new RemoteIter(d_geturl, d_idx, d_end, d_isquery);

        other->d_interrupted = d_interrupted;

        return other;
    }

    // done
    void RemoteCorpusReaderPrivate::RemoteIter::interrupt()
    {
#ifdef RemCorReaPri_DEBUG
        std::cerr << "[RemoteCorpusReaderPrivate] interrupting..." << std::endl;
#endif
        d_geturl->interrupt();
        *d_interrupted = true;
    }

    // TODO ????? parameter rdr not used, what is this for?
    std::string RemoteCorpusReaderPrivate::RemoteIter::contents(
        CorpusReader const &rdr) const
    {
        activate();

        if (d_end)
            return std::string();

        if (!d_isquery)
            return std::string();

        std::string s = d_geturl->line(d_idx);
        size_t i = s.find('\t');
        s = s.substr(i + 1);

        std::string result;
        size_t e;
        for (;;) {
            e = s.find('\\');
            if (e > s.size() - 2) {
                result += s;
                break;
            }
            result += s.substr(0, e);
            switch (s[e + 1]) {
                case 'f':
                    result += '\f';
                    break;
                case 'n':
                    result += '\n';
                    break;
                case 'r':
                    result += '\r';
                    break;
                case 't':
                    result += '\t';
                    break;
                default:
                    result += s[e + 1];
            }
            s = s.substr(e + 2);
        }

        return result;
    }

}   // namespace alpinocorpus
<commit_msg>[RemoteCorpusReader] minor edit<commit_after>//#define RemCorReaPri_DEBUG

#include <stdexcept>

#include <boost/algorithm/string.hpp>
#include <boost/algorithm/string/split.hpp>
#include <boost/algorithm/string/classification.hpp>

#include <config.hh>

#ifdef USE_DBXML
#include <dbxml/DbXml.hpp>
#endif // USE_DBXML

#include <AlpinoCorpus/Error.hh>
#include <AlpinoCorpus/IterImpl.hh>
#include "RemoteCorpusReaderPrivate.hh"
#include "util/GetUrl.hh"
#include "util/parseString.hh"
#include "util/url.hh"

#ifdef RemCorReaPri_DEBUG
#include <iostream>
#endif

namespace alpinocorpus {

    // done
    RemoteCorpusReaderPrivate::RemoteCorpusReaderPrivate(std::string const &url)
        : d_validSize(true)
    {
        if (url.substr(0, 7) != "http://" && url.substr(0, 8) != "https://")
            throw OpenError(url, "Not a valid URL");

        size_t i = url.find_last_of('/');
        if (i == std::string::npos)
            throw std::invalid_argument("Invalid argument, must be http://host/name");
        d_name = url.substr(i + 1);
        d_url = url;

        bool OK = false;
        util::GetUrl p1(url.substr(0, i) + "/corpora");
        std::vector<std::string> lines;
        std::vector<std::string> words;
        boost::algorithm::split(lines, p1.body(), boost::algorithm::is_any_of("\n"), boost::algorithm::token_compress_on);
        for (std::vector<std::string>::const_iterator iter = lines.begin();
            iter != lines.end(); ++iter)
        {
            boost::algorithm::split(words, *iter, boost::algorithm::is_any_of("\t"));
            if (words.size() == 4 && words[0] == d_name) {
                OK = true;
                try {
                    d_size = util::parseString<size_t>(words[1]);
                } catch (std::invalid_argument &) {
                    d_size = 0;
                    d_validSize = false;
                }
            }
        }
        if (!OK)
            throw std::invalid_argument("URL is not a valid corpus: " + d_url);

        // why a reset here?
        d_geturl.reset(new util::GetUrl(d_url + "/entries"));
    }

    RemoteCorpusReaderPrivate::~RemoteCorpusReaderPrivate()
    {
    }

    // done
    CorpusReader::EntryIterator RemoteCorpusReaderPrivate::getBegin() const
    {
        if (d_geturl->interrupted() && ! d_geturl->completed())
            const_cast<RemoteCorpusReaderPrivate *>(this)->d_geturl->resume();

        return EntryIterator(new RemoteIter(d_geturl, 0));
    }

    // done
    CorpusReader::EntryIterator RemoteCorpusReaderPrivate::getEnd() const
    {
        return EntryIterator(new RemoteIter(d_geturl, 0, true));
    }

    // done? TODO: alleen naam van corpus of complete url? (nu: complete url)
    std::string RemoteCorpusReaderPrivate::getName() const
    {
        // return d_name;
        return d_url;
    }

    // done
    size_t RemoteCorpusReaderPrivate::getSize() const
    {
        if (d_validSize)
            return d_size;
        else
            throw std::runtime_error("RemoteCorpusReader: size is unknown");
    }

    bool RemoteCorpusReaderPrivate::validQuery(QueryDialect d, bool variables,
        std::string const &query) const
    {
#ifdef USE_DBXML
        try {
            DbXml::XmlQueryContext ctx = mgr.createQueryContext();
            mgr.prepare(query, ctx);
        } catch (DbXml::XmlException const &e) {
            return false;
        }
        return true;
#else
        util::GetUrl p(d_url + "/validQuery?query=" + util::toPercentEncoding(query));
        std::string result = p.body();
        boost::to_lower(result);
        boost::trim(result);
        return (result == "true" || result == "yes" || result == "1");
#endif
    }

    // done
    std::string RemoteCorpusReaderPrivate::readEntry(std::string const &filename) const
    {
        // util::GetUrl p(d_url + "/entry/" + escape(filename));
        util::GetUrl p(d_url + "/entry/" + filename);
        return p.body();
    }

    // TODO: multiple queries (now: only the first is used)
    std::string RemoteCorpusReaderPrivate::readEntryMarkQueries(std::string const &entry,
        std::list<MarkerQuery> const &queries) const
    {
        std::list<MarkerQuery>::const_iterator iter = queries.begin();

        if (iter == queries.end())
            return readEntry(entry);

        util::GetUrl p(d_url + "/entry/" + entry +   // escape(entry) +
                       "?markerQuery=" + util::toPercentEncoding(iter->query) +
                       "&markerAttr=" + util::toPercentEncoding(iter->attr) +
                       "&markerValue=" + util::toPercentEncoding(iter->value));

        ++iter;
        if (iter != queries.end())
            throw Error("RemoteCorpusReaderPrivate: Multiple queries not implemented");

        return p.body();
    }

    // TODO: multiple queries (now: only the first is used)
    CorpusReader::EntryIterator RemoteCorpusReaderPrivate::runQueryWithStylesheet(
        QueryDialect d, std::string const &q, std::string const &stylesheet,
        std::list<MarkerQuery> const &markerQueries) const
    {
        std::list<MarkerQuery>::const_iterator iter = markerQueries.begin();

        if (iter == markerQueries.end())
            throw Error("RemoteCorpusReaderPrivate: Missing query");

        std::tr1::shared_ptr<util::GetUrl> p(new util::GetUrl(d_url + "/entries?query=" +
                                                              util::toPercentEncoding(q) +
                                                              "&markerQuery=" + util::toPercentEncoding(iter->query) +
                                                              "&markerAttr=" + util::toPercentEncoding(iter->attr) +
                                                              "&markerValue=" + util::toPercentEncoding(iter->value) +
                                                              "&contents=1", stylesheet));

        ++iter;
        if (iter != markerQueries.end())
            throw Error("RemoteCorpusReaderPrivate: Multiple queries not implemented");

        return EntryIterator(new RemoteIter(p, 0, false, true));
    }

    // TODO: multiple queries (now: only the first is used)
    CorpusReader::EntryIterator RemoteCorpusReaderPrivate::beginWithStylesheet(
        std::string const &stylesheet,
        std::list<MarkerQuery> const &markerQueries) const
    {
        std::list<MarkerQuery>::const_iterator iter = markerQueries.begin();

        if (iter == markerQueries.end())
            throw Error("RemoteCorpusReaderPrivate: Missing query");

        std::tr1::shared_ptr<util::GetUrl> p(new util::GetUrl(d_url + "/entries" +
                                                              "?markerQuery=" + util::toPercentEncoding(iter->query) +
                                                              "&markerAttr=" + util::toPercentEncoding(iter->attr) +
                                                              "&markerValue=" + util::toPercentEncoding(iter->value) +
                                                              "&contents=1", stylesheet));

        ++iter;
        if (iter != markerQueries.end())
            throw Error("RemoteCorpusReaderPrivate: Multiple queries not implemented");

        return EntryIterator(new RemoteIter(p, 0, false, true));

    }

    // done
    CorpusReader::EntryIterator RemoteCorpusReaderPrivate::runXPath(
        std::string const &query) const
    {
        std::tr1::shared_ptr<util::GetUrl> p(new util::GetUrl(d_url +
            "/entries?query=" + util::toPercentEncoding(query) +
            "&contents=1"));
        return EntryIterator(new RemoteIter(p, 0, false, true));
    }

    // done? TODO: klopt dit? (blijkbaar wel)
    CorpusReader::EntryIterator RemoteCorpusReaderPrivate::runXQuery(
        std::string const &query) const
    {
        return runXPath(query);
    }

    // done
    RemoteCorpusReaderPrivate::RemoteIter::RemoteIter(std::tr1::shared_ptr<util::GetUrl> geturl,
                                                      size_t n,
                                                      bool end,
                                                      bool isquery)
        : d_geturl(geturl), d_idx(n), d_end(end), d_isquery(isquery), d_active(false)
    {
        d_interrupted = std::tr1::shared_ptr<bool>(new bool(false));
    }

    // done
    RemoteCorpusReaderPrivate::RemoteIter::~RemoteIter()
    {
    }

    void RemoteCorpusReaderPrivate::RemoteIter::activate() const
    {
        if (d_active)
            return;
        if (d_end) {
            d_active = true;
            return;
        }

        d_geturl->line(d_idx);
        if (d_geturl->eof())
            d_end = true;

        d_active = true;
    }

    // done
    std::string RemoteCorpusReaderPrivate::RemoteIter::current() const
    {
        activate();

        if (!d_end) {
            std::string s = d_geturl->line(d_idx);
            if (d_isquery) {
                size_t i = s.find('\t');
                if (i == std::string::npos)
                    return s;
                else
                    return s.substr(0, i);
            } else
                return s;
        } else
            return std::string();
    }

    // done
    void RemoteCorpusReaderPrivate::RemoteIter::next()
    {
        activate();

        if (*d_interrupted) {
#ifdef RemCorReaPri_DEBUG
            std::cerr << "[RemoteCorpusReaderPrivate] Calling next on interrupted RemoteIter" << std::endl;
#endif
            throw alpinocorpus::IterationInterrupted();
        }

        if (!d_end) {
            ++d_idx;
            d_geturl->line(d_idx);
            if (d_geturl->eof())
                d_end = true;
        }
    }

    // done
    bool RemoteCorpusReaderPrivate::RemoteIter::equals(IterImpl const &other) const
    {
        RemoteIter const &that = (RemoteIter const &)other;
        activate();
        that.activate();
        if (d_end && that.d_end)
          return true;
        else
          return (d_end == that.d_end && d_idx == that.d_idx);
    }

    // done
    IterImpl *RemoteCorpusReaderPrivate::RemoteIter::copy() const
    {
        RemoteIter *other = new RemoteIter(d_geturl, d_idx, d_end, d_isquery);

        other->d_interrupted = d_interrupted;

        return other;
    }

    // done
    void RemoteCorpusReaderPrivate::RemoteIter::interrupt()
    {
#ifdef RemCorReaPri_DEBUG
        std::cerr << "[RemoteCorpusReaderPrivate] interrupting..." << std::endl;
#endif
        d_geturl->interrupt();
        *d_interrupted = true;
    }

    // TODO ????? parameter rdr not used, what is this for?
    std::string RemoteCorpusReaderPrivate::RemoteIter::contents(
        CorpusReader const &rdr) const
    {
        activate();

        if (d_end)
            return std::string();

        if (!d_isquery)
            return std::string();

        std::string s = d_geturl->line(d_idx);
        size_t i = s.find('\t');
        s = s.substr(i + 1);

        std::string result;
        size_t e;
        for (;;) {
            e = s.find('\\');
            if (e > s.size() - 2) {
                result += s;
                break;
            }
            result += s.substr(0, e);
            switch (s[e + 1]) {
                case 'f':
                    result += '\f';
                    break;
                case 'n':
                    result += '\n';
                    break;
                case 'r':
                    result += '\r';
                    break;
                case 't':
                    result += '\t';
                    break;
                default:
                    result += s[e + 1];
            }
            s = s.substr(e + 2);
        }

        return result;
    }

}   // namespace alpinocorpus
<|endoftext|>


<commit_before>// License: Apache 2.0. See LICENSE file in root directory.
// Copyright(c) 2019 Intel Corporation. All Rights Reserved.
#include "usb_pipe.h"

#include <cstdlib>
#include <cstring>
#include <zconf.h>
#include "usbhost.h"
#include "usb_endpoint.h"
#include <linux/usbdevice_fs.h>
#include "android_uvc.h"
#include <chrono>
#include "../../types.h"

#define INTERRUPT_BUFFER_SIZE 1024
#define CLEAR_FEATURE 0x01
#define UVC_FEATURE 0x02
#define INTERRUPT_PACKET_SIZE 5
#define INTERRUPT_NOTIFICATION_INDEX 5
#define DEPTH_SENSOR_OVERFLOW_NOTIFICATION 11
#define COLOR_SENSOR_OVERFLOW_NOTIFICATION 13

using namespace librealsense::usb_host;

usb_pipe::usb_pipe(usb_device *usb_device, usb_endpoint endpoint) :
        _endpoint(endpoint),
        _device(usb_device)
{
    _request = std::shared_ptr<usb_request>(usb_request_new(_device, _endpoint.get_descriptor()), [](usb_request* req) {usb_request_free(req);});
}

usb_pipe::~usb_pipe()
{
    usb_request_cancel(_request.get());
}

bool usb_pipe::reset()
{
    int requestType = UVC_FEATURE;
    int request = CLEAR_FEATURE;
    int value = 0;
    int index = _endpoint.get_endpoint_address();
    void* buffer = NULL;
    int length = 0;
    unsigned int timeout = 10;
    bool rv = usb_device_control_transfer(_device, requestType, request, value,
            index, buffer, length, timeout) == UVC_SUCCESS;
    if(rv)
        LOG_DEBUG("USB pipe " << (int)_endpoint.get_endpoint_address() << " reset successfully");
    else
        LOG_DEBUG("Failed to reset the USB pipe " << (int)_endpoint.get_endpoint_address());
    return rv;
}

size_t usb_pipe::read_pipe(uint8_t *buffer, size_t buffer_len, unsigned int timeout_ms) {
    return usb_device_bulk_transfer(_device, _endpoint.get_endpoint_address(), buffer, buffer_len, timeout_ms);
}

void usb_pipe::queue_finished_request(usb_request* response) {
    assert (response->endpoint == _endpoint.get_endpoint_address());

    std::unique_lock<std::mutex> lk(_mutex);
    _received = true;
    lk.unlock();
    _cv.notify_all();
    if(_interrupt_buffer.size() > 0) {
        //Log fatal notifications, this is currently handles only D4xx devices.
        //TODO push HW notifications to librealsense
        if(response->actual_length > 0){
            std::string buff = "";
            for(int i = 0; i < response->actual_length; i++)
                buff += std::to_string(((uint8_t*)response->buffer)[i]) + ", ";
            LOG_DEBUG("interrupt_request: " << buff.c_str());
            if(response->actual_length == INTERRUPT_PACKET_SIZE){
                auto sts = ((uint8_t*)response->buffer)[INTERRUPT_NOTIFICATION_INDEX];
                if(sts == DEPTH_SENSOR_OVERFLOW_NOTIFICATION || sts == COLOR_SENSOR_OVERFLOW_NOTIFICATION)
                    LOG_ERROR("overflow status sent from the device");
            }
        }
        queue_interrupt_request();
    }
}

void usb_pipe::submit_request(uint8_t *buffer, size_t buffer_len) {
    _request->buffer = buffer;
    _request->buffer_length = buffer_len;
    int res = usb_request_queue(_request.get());
    if(res < 0) {
        LOG_ERROR("Cannot queue request: " << strerror(errno));
    }
}

void usb_pipe::queue_interrupt_request()
{
    std::lock_guard<std::mutex> lock(_mutex);
    submit_request(_interrupt_buffer.data(), _interrupt_buffer.size());
}

void usb_pipe::listen_to_interrupts()
{
    auto attr = _endpoint.get_descriptor()->bmAttributes;
    if(attr == USB_ENDPOINT_XFER_INT)
    {
        _interrupt_buffer = std::vector<uint8_t>(INTERRUPT_BUFFER_SIZE);
        queue_interrupt_request();
    }
}<commit_msg>Update usb_pipe.cpp<commit_after>// License: Apache 2.0. See LICENSE file in root directory.
// Copyright(c) 2019 Intel Corporation. All Rights Reserved.
#include "usb_pipe.h"

#include <cstdlib>
#include <cstring>
#include <zconf.h>
#include "usbhost.h"
#include "usb_endpoint.h"
#include <linux/usbdevice_fs.h>
#include "android_uvc.h"
#include <chrono>
#include "../../types.h"

#define INTERRUPT_BUFFER_SIZE 1024
#define CLEAR_FEATURE 0x01
#define UVC_FEATURE 0x02
#define INTERRUPT_PACKET_SIZE 6
#define INTERRUPT_NOTIFICATION_INDEX 5
#define DEPTH_SENSOR_OVERFLOW_NOTIFICATION 11
#define COLOR_SENSOR_OVERFLOW_NOTIFICATION 13

using namespace librealsense::usb_host;

usb_pipe::usb_pipe(usb_device *usb_device, usb_endpoint endpoint) :
        _endpoint(endpoint),
        _device(usb_device)
{
    _request = std::shared_ptr<usb_request>(usb_request_new(_device, _endpoint.get_descriptor()), [](usb_request* req) {usb_request_free(req);});
}

usb_pipe::~usb_pipe()
{
    usb_request_cancel(_request.get());
}

bool usb_pipe::reset()
{
    int requestType = UVC_FEATURE;
    int request = CLEAR_FEATURE;
    int value = 0;
    int index = _endpoint.get_endpoint_address();
    void* buffer = NULL;
    int length = 0;
    unsigned int timeout = 10;
    bool rv = usb_device_control_transfer(_device, requestType, request, value,
            index, buffer, length, timeout) == UVC_SUCCESS;
    if(rv)
        LOG_DEBUG("USB pipe " << (int)_endpoint.get_endpoint_address() << " reset successfully");
    else
        LOG_DEBUG("Failed to reset the USB pipe " << (int)_endpoint.get_endpoint_address());
    return rv;
}

size_t usb_pipe::read_pipe(uint8_t *buffer, size_t buffer_len, unsigned int timeout_ms) {
    return usb_device_bulk_transfer(_device, _endpoint.get_endpoint_address(), buffer, buffer_len, timeout_ms);
}

void usb_pipe::queue_finished_request(usb_request* response) {
    assert (response->endpoint == _endpoint.get_endpoint_address());

    std::unique_lock<std::mutex> lk(_mutex);
    _received = true;
    lk.unlock();
    _cv.notify_all();
    if(_interrupt_buffer.size() > 0) {
        //Log fatal notifications, this is currently handles only D4xx devices.
        //TODO push HW notifications to librealsense
        if(response->actual_length > 0){
            std::string buff = "";
            for(int i = 0; i < response->actual_length; i++)
                buff += std::to_string(((uint8_t*)response->buffer)[i]) + ", ";
            LOG_DEBUG("interrupt_request: " << buff.c_str());
            if(response->actual_length == INTERRUPT_PACKET_SIZE){
                auto sts = ((uint8_t*)response->buffer)[INTERRUPT_NOTIFICATION_INDEX];
                if(sts == DEPTH_SENSOR_OVERFLOW_NOTIFICATION || sts == COLOR_SENSOR_OVERFLOW_NOTIFICATION)
                    LOG_ERROR("overflow status sent from the device");
            }
        }
        queue_interrupt_request();
    }
}

void usb_pipe::submit_request(uint8_t *buffer, size_t buffer_len) {
    _request->buffer = buffer;
    _request->buffer_length = buffer_len;
    int res = usb_request_queue(_request.get());
    if(res < 0) {
        LOG_ERROR("Cannot queue request: " << strerror(errno));
    }
}

void usb_pipe::queue_interrupt_request()
{
    std::lock_guard<std::mutex> lock(_mutex);
    submit_request(_interrupt_buffer.data(), _interrupt_buffer.size());
}

void usb_pipe::listen_to_interrupts()
{
    auto attr = _endpoint.get_descriptor()->bmAttributes;
    if(attr == USB_ENDPOINT_XFER_INT)
    {
        _interrupt_buffer = std::vector<uint8_t>(INTERRUPT_BUFFER_SIZE);
        queue_interrupt_request();
    }
}
<|endoftext|>


<commit_before>// OpenLieroX

// Input box
// Created 30/3/03
// Jason Boettcher

// code under LGPL

#include "LieroX.h"

#include "MathLib.h"
#include "DeprecatedGUI/Menu.h"
#include "GfxPrimitives.h"
#include "StringUtils.h"
#include "DeprecatedGUI/CBox.h"

namespace DeprecatedGUI {

///////////////////
// Draw the frame into a buffer
void CBox::PreDraw()
{
	// TODO: clean up this function (eg, to much different usage of same var, too much most-upper-level vars, ...)

	// If the width or height of the box has changed, create new buffer
	if (bmpBuffer.get())  {
		if (iWidth != bmpBuffer.get()->w || iHeight != bmpBuffer.get()->h)  {
			bmpBuffer = NULL;
		}
	}

	// Create the buffer, if needed
	if (!bmpBuffer.get())  {
		SDL_PixelFormat *fmt = getMainPixelFormat();
		if (fmt)
			bmpBuffer = gfxCreateSurface(iWidth, iHeight);
		else
			bmpBuffer = NULL;

		if (!bmpBuffer.get())
			return;
	}

	// Set the whole buffer transparent
	SetColorKey(bmpBuffer.get());
	FillSurfaceTransparent(bmpBuffer.get());

	// Clip the border and radius
	if (iRound < 0 || iBorder < 0)
		return;

	iRound = MIN(MIN(iWidth,iHeight)/2,iRound);
	iBorder = MIN(MIN(iWidth,iHeight)/2,iBorder);

	//
	// 1. Draw the lines
	//
	int line_left,line_right,line_top,line_bottom;

	// Line positions
	line_left = MAX(iRound,iBorder);
	line_right = iWidth - MAX(iRound,iBorder);
	line_top = MAX(iRound,iBorder);
	line_bottom = iHeight - MAX(iRound,iBorder);

	// Color handling
	Color cur_col = iDarkColour;

	// Create gradient
	int rstep=0,gstep=0,bstep=0;
	if (iBorder)  {
		rstep = (iLightColour.r-iDarkColour.r)/iBorder;
		rstep = (iLightColour.g-iDarkColour.g)/iBorder;
		rstep = (iLightColour.b-iDarkColour.b)/iBorder;
	}

	// Top line
	int j;
	for (j=0; j<iBorder; j++)  {
		DrawHLine(bmpBuffer.get(),line_left,line_right,j,cur_col);
		cur_col = Color(iDarkColour.r+rstep*(j+1),iDarkColour.g+gstep*(j+1),iDarkColour.b+bstep*(j+1));
	}

	cur_col = iDarkColour;

	// Bottom line
	for (j=0; j<iBorder; j++)  {
		DrawHLine(bmpBuffer.get(),line_left,line_right,iHeight-j-1,cur_col);
		cur_col = Color(iDarkColour.r+rstep*(j+1),iDarkColour.g+gstep*(j+1),iDarkColour.b+bstep*(j+1));
	}

	cur_col = iDarkColour;

	// Left line
	for (j=0; j<iBorder; j++)  {
		DrawVLine(bmpBuffer.get(),line_top,line_bottom,j,cur_col);
		cur_col = Color(iDarkColour.r+rstep*(j+1),iDarkColour.g+gstep*(j+1),iDarkColour.b+bstep*(j+1));
	}

	cur_col = iDarkColour;

	// Right line
	for (j=0; j<iBorder; j++)  {
		DrawVLine(bmpBuffer.get(),line_top,line_bottom,iWidth-j-1,cur_col);
		cur_col = Color(iDarkColour.r+rstep*(j+1),iDarkColour.g+gstep*(j+1),iDarkColour.b+bstep*(j+1));
	}

	//
	// 2. Draw the round borders
	//

	int x,y;

	// Radius has to be bigger than or equal to border
	iRound = MAX(iBorder,iRound);

	// Step for circle drawing
	float step = (float)(1/(PI*(iRound+0.00000001)*(iBorder+0.000000001)));

	LOCK_OR_QUIT(bmpBuffer);

	// Top left
	// (PI,3/2*PI)
	float i;
	for (i=1.00f;i<1.5f;i+=step)  {
		cur_col = iDarkColour;
		for (j=0; j<iBorder; j++)  {
			x = CLAMP( (int)((iRound-j)*sin(PI*i))-1+iRound, 0, iWidth-1);
			y = CLAMP( (int)((iRound-j)*cos(PI*i))-1+iRound, 0, iHeight-1);

			PutPixel(bmpBuffer.get(),x,y,cur_col.get(bmpBuffer->format));
			cur_col = Color(iDarkColour.r+rstep*(j+1),iDarkColour.g+gstep*(j+1),iDarkColour.b+bstep*(j+1));
		}
	}

	// Top right
	// (PI/2,PI)
	for (i=0.50f;i<1.0f;i+=step)  {
		cur_col = iDarkColour;
		for (j=0; j<iBorder; j++)  {
			x = CLAMP( (int)((iRound-j)*sin(PI*i))+iWidth-iRound, 0, iWidth-1);
			y = CLAMP( (int)((iRound-j)*cos(PI*i))-1+iRound, 0, iHeight-1);
			PutPixel(bmpBuffer.get(),x,y,cur_col.get(bmpBuffer->format));
			cur_col = Color(iDarkColour.r+rstep*(j+1),iDarkColour.g+gstep*(j+1),iDarkColour.b+bstep*(j+1));
		}
	}

	// Bottom left
	// (3/2*PI,2PI)
	for (i=1.50f;i<2.0f;i+=step)  {
		cur_col = iDarkColour;
		for (j=0; j<iBorder; j++)  {
			x = CLAMP( (int)((iRound-j)*sin(PI*i))-1+iRound, 0, iWidth-1);
			y = CLAMP( (int)((iRound-j)*cos(PI*i))+iHeight-iRound, 0, iHeight-1);
			PutPixel(bmpBuffer.get(),x,y,cur_col.get(bmpBuffer->format));
			cur_col = Color(iDarkColour.r+rstep*(j+1),iDarkColour.g+gstep*(j+1),iDarkColour.b+bstep*(j+1));
		}
	}

	// Bottom right
	// (0,PI)
	for (i=-0.01f;i<0.5f;i+=step)  {
		cur_col = iDarkColour;
		for (j=0; j<iBorder; j++)  {
			x = CLAMP( (int)((iRound-j)*sin(PI*i))+iWidth-iRound, 0, iWidth-1);
			y = CLAMP( (int)((iRound-j)*cos(PI*i))+iHeight-iRound, 0, iHeight-1);
			PutPixel(bmpBuffer.get(),x,y,cur_col.get(bmpBuffer->format));
			cur_col = Color(iDarkColour.r+rstep*(j+1),iDarkColour.g+gstep*(j+1),iDarkColour.b+bstep*(j+1));
		}
	}

	//
	//	Draw the background
	//
	if (iBgColour == tLX->clPink)
		return;

	// Draw the center rectangle
	DrawRectFill(bmpBuffer.get(),line_left,iBorder,line_right,iHeight-iBorder,iBgColour);

	// No need to draw more
	if (iRound <= iBorder)
		return;

	DrawRectFill(bmpBuffer.get(),iBorder,line_top,line_left,line_bottom,iBgColour);
	DrawRectFill(bmpBuffer.get(),line_right,line_top,iWidth-iBorder,line_bottom,iBgColour);

	// Top left
	// (1,3/2*PI)
	for (i=1.01f;i<1.49;i+=step)  {
		for (j=iBorder; j<iRound-iBorder+2; j++)  {
			x = CLAMP( (int)((iRound-j)*sin(PI*i))-1+iRound, 0, iWidth-1);
			y = CLAMP( (int)((iRound-j)*cos(PI*i))-1+iRound, 0, iHeight-1);
			PutPixel(bmpBuffer.get(),x,y,iBgColour.get(bmpBuffer->format));
		}
	}

	// Top right
	// (PI/2,PI)
	for (i=0.51f;i<0.99;i+=step)  {
		for (j=iBorder; j<iRound-iBorder+2; j++)  {
			x = CLAMP( (int)((iRound-j)*sin(PI*i))+iWidth-iRound, 0, iWidth-1);
			y = CLAMP( (int)((iRound-j)*cos(PI*i))-1+iRound, 0, iHeight-1);
			PutPixel(bmpBuffer.get(),x,y,iBgColour.get(bmpBuffer->format));
		}
	}

	// Bottom left
	// (3/2*PI,2PI)
	for (i=1.51f;i<1.99;i+=step)  {
		for (j=iBorder; j<iRound-iBorder+2; j++)  {
			x = CLAMP( (int)((iRound-j)*sin(PI*i))-1+iRound, 0, iWidth-1);
			y = CLAMP( (int)((iRound-j)*cos(PI*i))+iHeight-iRound, 0, iHeight-1);
			PutPixel(bmpBuffer.get(),x,y,iBgColour.get(bmpBuffer->format));
		}
	}

	// Bottom right
	// (0,PI)
	for (i=0.01f;i<0.499;i+=step)  {
		for (j=iBorder; j<=iRound-iBorder+2; j++)  {
			x = CLAMP( (int)((iRound-j)*sin(PI*i))+iWidth-iRound, 0, iWidth-1);
			y = CLAMP( (int)((iRound-j)*cos(PI*i))+iHeight-iRound, 0, iHeight-1);
			PutPixel(bmpBuffer.get(),x,y,iBgColour.get(bmpBuffer->format));
		}
	}

	UnlockSurface(bmpBuffer);

}

/////////////////
// Draw the frame
void CBox::Draw(SDL_Surface * bmpDest)
{
	if (bmpBuffer.get())
		DrawImage(bmpDest,bmpBuffer,iX,iY);
}

/////////////////
// Free the widget
void CBox::Destroy()
{
	bmpBuffer = NULL;
}

//////////////////
// Checks if any mouse event happened
int	CBox::CheckEvent()
{
	// If the mouse is over transparent area, don't fire any event
	// CGuiLayout will then continue processing events for other widgets

	// Get the mouse pos
	mouse_t *Mouse = GetMouse();
	if (!Mouse)
		return BOX_NONE;
	int x = Mouse->X - iX;
	int y = Mouse->Y - iY;

	// Mouse in the buffer
	if (x < iWidth && y < iHeight)  {
		// Mouse over transparent pixel? No event
		if (!LockSurface(bmpBuffer))
			return BOX_NONE;
		if(Color(bmpBuffer.get()->format, GetPixel(bmpBuffer.get(),x,y)) == tLX->clPink)  {
			UnlockSurface(bmpBuffer);
			return BOX_NOEVENT;
		}
		UnlockSurface(bmpBuffer);
		return BOX_MOUSEOVER;
	} else
		return BOX_NONE;

}

}; // namespace DeprecatedGUI
<commit_msg>fixed possible crash<commit_after>// OpenLieroX

// Input box
// Created 30/3/03
// Jason Boettcher

// code under LGPL

#include "LieroX.h"

#include "MathLib.h"
#include "DeprecatedGUI/Menu.h"
#include "GfxPrimitives.h"
#include "StringUtils.h"
#include "DeprecatedGUI/CBox.h"

namespace DeprecatedGUI {

///////////////////
// Draw the frame into a buffer
void CBox::PreDraw()
{
	// TODO: clean up this function (eg, to much different usage of same var, too much most-upper-level vars, ...)

	// If the width or height of the box has changed, create new buffer
	if (bmpBuffer.get())  {
		if (iWidth != bmpBuffer.get()->w || iHeight != bmpBuffer.get()->h)  {
			bmpBuffer = NULL;
		}
	}

	// Create the buffer, if needed
	if (!bmpBuffer.get())  {
		SDL_PixelFormat *fmt = getMainPixelFormat();
		if (fmt)
			bmpBuffer = gfxCreateSurface(iWidth, iHeight);
		else
			bmpBuffer = NULL;

		if (!bmpBuffer.get())
			return;
	}

	// Set the whole buffer transparent
	SetColorKey(bmpBuffer.get());
	FillSurfaceTransparent(bmpBuffer.get());

	// Clip the border and radius
	if (iRound < 0 || iBorder < 0)
		return;

	iRound = MIN(MIN(iWidth,iHeight)/2,iRound);
	iBorder = MIN(MIN(iWidth,iHeight)/2,iBorder);

	//
	// 1. Draw the lines
	//
	int line_left,line_right,line_top,line_bottom;

	// Line positions
	line_left = MAX(iRound,iBorder);
	line_right = iWidth - MAX(iRound,iBorder);
	line_top = MAX(iRound,iBorder);
	line_bottom = iHeight - MAX(iRound,iBorder);

	// Color handling
	Color cur_col = iDarkColour;

	// Create gradient
	int rstep=0,gstep=0,bstep=0;
	if (iBorder)  {
		rstep = (iLightColour.r-iDarkColour.r)/iBorder;
		rstep = (iLightColour.g-iDarkColour.g)/iBorder;
		rstep = (iLightColour.b-iDarkColour.b)/iBorder;
	}

	// Top line
	int j;
	for (j=0; j<iBorder; j++)  {
		DrawHLine(bmpBuffer.get(),line_left,line_right,j,cur_col);
		cur_col = Color(iDarkColour.r+rstep*(j+1),iDarkColour.g+gstep*(j+1),iDarkColour.b+bstep*(j+1));
	}

	cur_col = iDarkColour;

	// Bottom line
	for (j=0; j<iBorder; j++)  {
		DrawHLine(bmpBuffer.get(),line_left,line_right,iHeight-j-1,cur_col);
		cur_col = Color(iDarkColour.r+rstep*(j+1),iDarkColour.g+gstep*(j+1),iDarkColour.b+bstep*(j+1));
	}

	cur_col = iDarkColour;

	// Left line
	for (j=0; j<iBorder; j++)  {
		DrawVLine(bmpBuffer.get(),line_top,line_bottom,j,cur_col);
		cur_col = Color(iDarkColour.r+rstep*(j+1),iDarkColour.g+gstep*(j+1),iDarkColour.b+bstep*(j+1));
	}

	cur_col = iDarkColour;

	// Right line
	for (j=0; j<iBorder; j++)  {
		DrawVLine(bmpBuffer.get(),line_top,line_bottom,iWidth-j-1,cur_col);
		cur_col = Color(iDarkColour.r+rstep*(j+1),iDarkColour.g+gstep*(j+1),iDarkColour.b+bstep*(j+1));
	}

	//
	// 2. Draw the round borders
	//

	int x,y;

	// Radius has to be bigger than or equal to border
	iRound = MAX(iBorder,iRound);

	// Step for circle drawing
	float step = (float)(1/(PI*(iRound+0.00000001)*(iBorder+0.000000001)));

	LOCK_OR_QUIT(bmpBuffer);

	// Top left
	// (PI,3/2*PI)
	float i;
	for (i=1.00f;i<1.5f;i+=step)  {
		cur_col = iDarkColour;
		for (j=0; j<iBorder; j++)  {
			x = CLAMP( (int)((iRound-j)*sin(PI*i))-1+iRound, 0, iWidth-1);
			y = CLAMP( (int)((iRound-j)*cos(PI*i))-1+iRound, 0, iHeight-1);

			PutPixel(bmpBuffer.get(),x,y,cur_col.get(bmpBuffer->format));
			cur_col = Color(iDarkColour.r+rstep*(j+1),iDarkColour.g+gstep*(j+1),iDarkColour.b+bstep*(j+1));
		}
	}

	// Top right
	// (PI/2,PI)
	for (i=0.50f;i<1.0f;i+=step)  {
		cur_col = iDarkColour;
		for (j=0; j<iBorder; j++)  {
			x = CLAMP( (int)((iRound-j)*sin(PI*i))+iWidth-iRound, 0, iWidth-1);
			y = CLAMP( (int)((iRound-j)*cos(PI*i))-1+iRound, 0, iHeight-1);
			PutPixel(bmpBuffer.get(),x,y,cur_col.get(bmpBuffer->format));
			cur_col = Color(iDarkColour.r+rstep*(j+1),iDarkColour.g+gstep*(j+1),iDarkColour.b+bstep*(j+1));
		}
	}

	// Bottom left
	// (3/2*PI,2PI)
	for (i=1.50f;i<2.0f;i+=step)  {
		cur_col = iDarkColour;
		for (j=0; j<iBorder; j++)  {
			x = CLAMP( (int)((iRound-j)*sin(PI*i))-1+iRound, 0, iWidth-1);
			y = CLAMP( (int)((iRound-j)*cos(PI*i))+iHeight-iRound, 0, iHeight-1);
			PutPixel(bmpBuffer.get(),x,y,cur_col.get(bmpBuffer->format));
			cur_col = Color(iDarkColour.r+rstep*(j+1),iDarkColour.g+gstep*(j+1),iDarkColour.b+bstep*(j+1));
		}
	}

	// Bottom right
	// (0,PI)
	for (i=-0.01f;i<0.5f;i+=step)  {
		cur_col = iDarkColour;
		for (j=0; j<iBorder; j++)  {
			x = CLAMP( (int)((iRound-j)*sin(PI*i))+iWidth-iRound, 0, iWidth-1);
			y = CLAMP( (int)((iRound-j)*cos(PI*i))+iHeight-iRound, 0, iHeight-1);
			PutPixel(bmpBuffer.get(),x,y,cur_col.get(bmpBuffer->format));
			cur_col = Color(iDarkColour.r+rstep*(j+1),iDarkColour.g+gstep*(j+1),iDarkColour.b+bstep*(j+1));
		}
	}

	//
	//	Draw the background
	//
	if (iBgColour == tLX->clPink)
		return;

	// Draw the center rectangle
	DrawRectFill(bmpBuffer.get(),line_left,iBorder,line_right,iHeight-iBorder,iBgColour);

	// No need to draw more
	if (iRound <= iBorder)
		return;

	DrawRectFill(bmpBuffer.get(),iBorder,line_top,line_left,line_bottom,iBgColour);
	DrawRectFill(bmpBuffer.get(),line_right,line_top,iWidth-iBorder,line_bottom,iBgColour);

	// Top left
	// (1,3/2*PI)
	for (i=1.01f;i<1.49;i+=step)  {
		for (j=iBorder; j<iRound-iBorder+2; j++)  {
			x = CLAMP( (int)((iRound-j)*sin(PI*i))-1+iRound, 0, iWidth-1);
			y = CLAMP( (int)((iRound-j)*cos(PI*i))-1+iRound, 0, iHeight-1);
			PutPixel(bmpBuffer.get(),x,y,iBgColour.get(bmpBuffer->format));
		}
	}

	// Top right
	// (PI/2,PI)
	for (i=0.51f;i<0.99;i+=step)  {
		for (j=iBorder; j<iRound-iBorder+2; j++)  {
			x = CLAMP( (int)((iRound-j)*sin(PI*i))+iWidth-iRound, 0, iWidth-1);
			y = CLAMP( (int)((iRound-j)*cos(PI*i))-1+iRound, 0, iHeight-1);
			PutPixel(bmpBuffer.get(),x,y,iBgColour.get(bmpBuffer->format));
		}
	}

	// Bottom left
	// (3/2*PI,2PI)
	for (i=1.51f;i<1.99;i+=step)  {
		for (j=iBorder; j<iRound-iBorder+2; j++)  {
			x = CLAMP( (int)((iRound-j)*sin(PI*i))-1+iRound, 0, iWidth-1);
			y = CLAMP( (int)((iRound-j)*cos(PI*i))+iHeight-iRound, 0, iHeight-1);
			PutPixel(bmpBuffer.get(),x,y,iBgColour.get(bmpBuffer->format));
		}
	}

	// Bottom right
	// (0,PI)
	for (i=0.01f;i<0.499;i+=step)  {
		for (j=iBorder; j<=iRound-iBorder+2; j++)  {
			x = CLAMP( (int)((iRound-j)*sin(PI*i))+iWidth-iRound, 0, iWidth-1);
			y = CLAMP( (int)((iRound-j)*cos(PI*i))+iHeight-iRound, 0, iHeight-1);
			PutPixel(bmpBuffer.get(),x,y,iBgColour.get(bmpBuffer->format));
		}
	}

	UnlockSurface(bmpBuffer);

}

/////////////////
// Draw the frame
void CBox::Draw(SDL_Surface * bmpDest)
{
	if (bmpBuffer.get())
		DrawImage(bmpDest,bmpBuffer,iX,iY);
}

/////////////////
// Free the widget
void CBox::Destroy()
{
	bmpBuffer = NULL;
}

//////////////////
// Checks if any mouse event happened
int	CBox::CheckEvent()
{
	// If the mouse is over transparent area, don't fire any event
	// CGuiLayout will then continue processing events for other widgets

	if(bmpBuffer.get() == NULL) {
		errors << "CBox::CheckEvent: bmpBuffer == NULL" << endl;
		return BOX_NONE;
	}

	// Get the mouse pos
	mouse_t *Mouse = GetMouse();
	if (!Mouse)
		return BOX_NONE;
	int x = Mouse->X - iX;
	int y = Mouse->Y - iY;

	// Mouse in the buffer
	if (x < iWidth && y < iHeight)  {
		// Mouse over transparent pixel? No event
		if (!LockSurface(bmpBuffer))
			return BOX_NONE;
		if(Color(bmpBuffer.get()->format, GetPixel(bmpBuffer.get(),x,y)) == tLX->clPink)  {
			UnlockSurface(bmpBuffer);
			return BOX_NOEVENT;
		}
		UnlockSurface(bmpBuffer);
		return BOX_MOUSEOVER;
	} else
		return BOX_NONE;

}

}; // namespace DeprecatedGUI
<|endoftext|>