Subversion Repositories Scribus

Rev

Rev 24665 | Blame | Compare with Previous | Last modification | View Log | RSS feed

/*
 *  actions.h
 *  
 *
 *  Created by Andreas Vox on 02.06.06.
 *  Copyright 2006 under GPL2. All rights reserved.
 *
 */



#ifndef ACTIONS_H
#define ACTIONS_H

#include <map>
#include <string>
#include "digester.h"

namespace desaxe {

/**
 *   Action / Action_body follow the handle/body pattern. This allows to omit the
 *   new operator when creating Action expressions and make dynamic memory handling
 *   more secure.
 *   Base class for the body of all actions. Usually Digester calls these methods,
 *   but subclasses are also allowed to call those methods if they know what they are
 *   doing...
 */

class Action_body
{
protected:
        Action_body() {}
        virtual ~Action_body() {}
        virtual void begin(const Xml_string&, Xml_attr) {}                      
        virtual void end(const Xml_string&) {}
        virtual void chars(const Xml_string&) {}
        virtual void reset() {}

        Digester* dig {nullptr};
private:
        int refs { 0 };
        friend class Action;
};



/**
 *   Actions do all the real work when digesting XML files: creating new objects,
 *   setting attributes, calling methods. Each Action gets control two or more times
 *   for each time the corresponding rule triggers: 1 x begin(), 0- x chars(), 1 x end().
 *   They come in two basic flavors: Generators create a new object in their begin()
 *   method and put it on the object stack. Other Actions use objects on the stack,
 *   XML attributes or XML text to store this data in other objects. This is usually
 *   done in the end() method.
 *   Warning: end() methods are called in reverse order. This is to ensure that they
 *   see exactly the same stack content as their corresponding begin() method.
 *   This is the handle class which delegates to the body
 */

class Action
{
public:
        inline Digester* digester()                { return body->dig; }
        inline void setDigester(Digester* dig)     { body->dig = dig; }
       
        inline void begin(const Xml_string& tag, Xml_attr attr)
                                                   { body->begin(tag, attr); }
        inline void end(const Xml_string& tag)     { body->end(tag); }
        inline void chars(const Xml_string& data)  { body->chars(data); }

        // Handle stuff:
        Action(const Action& other)
        {
                body = other.body;
                body->refs++;
        }
        virtual ~Action()                          
        {
                if (--body->refs == 0)
                        delete body;
        }
        Action& operator=(const Action& other)
        {
                if (body != other.body) {
                        if (--body->refs == 0)
                                delete body;
                        body = other.body;
                        ++body->refs;
                }
                return *this;
        }

        virtual void reset()
        {
                body->reset();
        }

protected:
        Action(Action_body* body_)
        {
                body = body_;
                body->refs = 1;
        }

        Action_body* body { nullptr };

private:
        Action();  // not defined
};


class Dummy {};

/**
 * This class implements typed constructors. They are in a subclass since
 * we don't want the type arguments in Action itself.
 * Use "class MyAction : public MakeAction<MyAction_body> {} " to define
 * your own Actions. You have to implement MyAction constructors if you
 * want constructors with arguments.
 */

template <class Body, class Arg1=Dummy, class Arg2=Dummy, class Arg3=Dummy, class Arg4=Dummy, class Arg5=Dummy>
struct MakeAction : public Action
{
        MakeAction() : Action(new Body()) {}
        MakeAction(Arg1 a1) : Action(new Body(a1)) {}
        MakeAction(Arg1 a1, Arg2 a2) : Action(new Body(a1, a2)) {}
        MakeAction(Arg1 a1, Arg2 a2, Arg3 a3) : Action(new Body(a1, a2, a3)) {}
        MakeAction(Arg1 a1, Arg2 a2, Arg3 a3, Arg4 a4) : Action(new Body(a1, a2, a3, a4)) {}
        MakeAction(Arg1 a1, Arg2 a2, Arg3 a3, Arg4 a4, Arg5 a5) : Action(new Body(a1, a2, a3, a4, a5)) {}
};



/**
 *   Abstract class for actions which leave a new object on the stack
 *   The begin() method is defined in subclasses and puts the object on stack,
 *   the generic end() method removes this object from stack.
 */

template<class Type>
class Generator_body : public Action_body
{
public:
        virtual Type* eval(Digester* dig_, const Xml_string& tag, Xml_attr attr)
        {
                dig = dig_;
                begin(tag, attr);
                Type* res;
                res = dig->template top<Type>();
                end(tag);
                return res;
        }
protected:
        virtual void end(const Xml_string& ) { dig->pop(); }
};



/**
 * Generators have their own handle class, which is a subclass of Action
 */

template<class Type>
class Generator : public Action
{
public:
        Type* eval(Digester* dig, const Xml_string& tag, Xml_attr attr)
        {
                return static_cast<Generator_body<Type>*>(body)->eval(dig, tag, attr);
        }

protected:
        Generator(Generator_body<Type>* body_) : Action(body_) {}
};


/**
 * This class implements typed constructors. They are in a subclass since
 * we don't want the type arguments in Generator itself.
 * Use "class MyGenerator : public MakeGenerator<MyGenarator_body, MyType> {} " to
 * define your own generators. You have to implement MyGenerator constructors if you
 * want constructors with arguments.
 */

template <class Body, class Obj_Type, class Arg1=Dummy, class Arg2=Dummy, class Arg3=Dummy>
struct MakeGenerator : public Generator<Obj_Type>
{
        MakeGenerator() : Generator<Obj_Type>(new Body()) {}
        MakeGenerator(Arg1 a) : Generator<Obj_Type>(new Body(a)) {}
        MakeGenerator(Arg1 a1, Arg2 a2) : Generator<Obj_Type>(new Body(a1, a2)) {}
        MakeGenerator(Arg1 a1, Arg2 a2, Arg3 a3) : Generator<Obj_Type>(new Body(a1, a2, a3)) {}
};

} // namespace

#endif