You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
188 lines
7.8 KiB
188 lines
7.8 KiB
// 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
|
|
* tqparents 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& tqparents ) 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 tqparents..
|
|
* \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 tqparents .
|
|
*/
|
|
const ObjectImpType* impRequirement( const ObjectImp* o, const Args& tqparents ) const;
|
|
|
|
/**
|
|
* Supposing that \p tqparents would be given as tqparents, 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& tqparents ) 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
|