diff options
Diffstat (limited to 'kig/misc/argsparser.h')
-rw-r--r-- | kig/misc/argsparser.h | 187 |
1 files changed, 187 insertions, 0 deletions
diff --git a/kig/misc/argsparser.h b/kig/misc/argsparser.h new file mode 100644 index 00000000..001d9359 --- /dev/null +++ b/kig/misc/argsparser.h @@ -0,0 +1,187 @@ +// Copyright (C) 2002 Dominique Devriese <devriese@kde.org> + +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +// 02110-1301, USA. + +#ifndef KIG_MISC_ARGSPARSER_H +#define KIG_MISC_ARGSPARSER_H + +#include "../objects/common.h" + +#include <string> + +class ObjectImpType; + +/** + * This class is meant to take care of checking the types of the + * parents to ObjectCalcer's, and to put them in the correct order. + * An ObjectType should construct an ArgsParser with a specification + * of the arguments it wants. This specification is given as an array + * of ArgsParser::spec structs. This struct contains a pointer to an + * ObjectImpType ( which is the type you want the argument to have ), + * a string ( which is an I18N_NOOP'd string describing what you will + * be using the argument for ) and a boolean ( which says whether the + * constructed object is by construction on the curve argument ( if + * the constructed object is a point ), or whether the constructed + * object is by construction through the point argument ( if the + * constructed object is a curve ) ). + * + * An ObjectType using an ArgsParser to take care of the various + * things that it can handle ( impRequirement, the sortArgs functions + * and the isDefinedOnOrThrough stuff ), should inherit from + * ArgsParserObjectType, which takes care of calling the ArgsParser + * for these things... It also allows you to use a convenient + * ObjectConstructor for your type. + * + * E.g., let's see what CircleBCPType has for its arguments spec: + * here's some code: + * \code + * static const ArgsParser::spec argsspecTranslation[] = + * { + * { ObjectImp::stype(), I18N_NOOP("Translate this object"), false }, + * { VectorImp::stype(), I18N_NOOP("Translate by this vector"), false } + * }; + * + * TranslatedType::TranslatedType() + * : ArgsParserObjectType( "Translation", argsspecTranslation, 2 ) + * { + * } + * + * ObjectImp* TranslatedType::calc( const Args& args, const KigDocument& ) const + * { + * if ( ! margsparser.checkArgs( args ) ) return new InvalidImp; + * + * Coordinate dir = static_cast<const VectorImp*>( args[1] )->dir(); + * Transformation t = Transformation::translation( dir ); + * + * return args[0]->transform( t ); + * } + * \endcode + * + * As you can see above, the argsspec can be declared right in the + * cpp-file. The usetexts explain to the user what the argument in + * question will be used for. The boolean says that in this case, the + * constructed object is not by construction on or through one of its + * arguments. In the constructor, you simply call the + * ArgsParserObjectType with the argsspec struct you defined, and the + * number of arguments in the argsspec ( in this case 2 ). + * + * In the calc function, you can rely on the arguments already being + * in the correct order ( the same order as you put them in in the + * arguments spec. You should use the checkArgs function to check if + * all the arguments are valid, and if they aren't return a + * InvalidImp. All objects can always become invalid ( e.g. an + * intersection point of two non-intersecting conics can become valid + * again when the conics move ), and you should always check for this. + * + * An interesting to note here is that the first argument is of a more + * general type than the second. A VectorImp is *also* an ObjectImp. + * In general, when this happens, you should put the more general type + * first, as in general this produces the results that the user + * expects. I have no formal proof for this, just talking from + * experience. It might be that you experience different things, but + * unless you're sure of the results, put the more general type first. + * + * This class uses a pretty basic algorithm for doing the parsing ( + * e.g. if a match fails in one order, it does not try a different + * order, which could perhaps be necessary in the case of having more + * general argument types in the same argument spec ). However, the + * current algorithm works in all the situation where I've tested it, + * and I don't feel the need to change it. Feel free to do so if you + * like, but even if you do, I'm not sure if I will include it in + * mainline Kig. + */ +class ArgsParser +{ +public: + /** + * this are some enum values that we return from some functions. + */ + enum { Invalid = 0, Valid = 1, Complete = 2 }; + struct spec { const ObjectImpType* type; std::string usetext; std::string selectstat; bool onOrThrough;}; +private: + /** + * the args spec.. + */ + std::vector<spec> margs; + + spec findSpec( const ObjectImp* o, const Args& parents ) const; +public: + ArgsParser( const struct spec* args, int n ); + ArgsParser( const std::vector<spec>& args ); + ArgsParser(); + ~ArgsParser(); + + void initialize( const std::vector<spec>& args ); + void initialize( const struct spec* args, int n ); + + /** + * returns a new ArgsParser that wants the same args, except for the + * ones of the given type.. + */ + ArgsParser without( const ObjectImpType* type ) const; + // checks if os matches the argument list this parser should parse.. + int check( const Args& os ) const; + int check( const std::vector<ObjectCalcer*>& os ) const; + /** + * returns the usetext for the argument that o would be used for, + * if sel were used as parents.. + * \p o should be in \p sel ... + */ + std::string usetext( const ObjectImp* o, const Args& sel ) const; + + /** + * returns the select statement for the next selectable argument + * when the given args are selected. + */ + std::string selectStatement( const Args& sel ) const; + + // this reorders the objects or args so that they are in the same + // order as the requested arguments.. + Args parse( const Args& os ) const; + std::vector<ObjectCalcer*> parse( const std::vector<ObjectCalcer*>& os ) const; + + /** + * returns the minimal ObjectImp ID that \p o needs to inherit in order + * to be useful.. \p o should be part of \p parents . + */ + const ObjectImpType* impRequirement( const ObjectImp* o, const Args& parents ) const; + + /** + * Supposing that \p parents would be given as parents, this function + * returns whether the returned ObjectImp will be, by construction, + * on \p o ( if \p o is a curve ), or through \p o ( if \p o is a point ). + */ + bool isDefinedOnOrThrough( const ObjectImp* o, const Args& parents ) const; + + // Checks the args according to this args specification. If the + // objects should never have occurred, then an assertion failure + // will happen, if one of the args is invalid, then false will be + // returned, if all is fine, then true is returned.. + // assert that the objects are of the right types, and in the right + // order as what would be returned by parse( os ).. If minobjects + // is provided, then not all objects are needed, and it is enough if + // at least minobjects are available.. Use this for object types + // that can calc a temporary example object using less than the + // required args. These args need to be at the end of argsspec + + // anyobjsspec. If minobjects is not provided, then it is assumed + // that all args are necessary. + bool checkArgs( const std::vector<ObjectCalcer*>& os ) const; + bool checkArgs( const std::vector<ObjectCalcer*>& os, uint minobjects ) const; + bool checkArgs( const Args& os ) const; + bool checkArgs( const Args& os, uint minobjects ) const; +}; + +#endif |