summaryrefslogtreecommitdiffstats
path: root/kig/filters
diff options
context:
space:
mode:
Diffstat (limited to 'kig/filters')
-rw-r--r--kig/filters/Makefile.am38
-rw-r--r--kig/filters/cabri-filter.cc577
-rw-r--r--kig/filters/cabri-filter.h55
-rw-r--r--kig/filters/drgeo-filter-chooser.cc65
-rw-r--r--kig/filters/drgeo-filter-chooser.h41
-rw-r--r--kig/filters/drgeo-filter-chooserbase.ui140
-rw-r--r--kig/filters/drgeo-filter-status.txt50
-rw-r--r--kig/filters/drgeo-filter.cc809
-rw-r--r--kig/filters/drgeo-filter.h46
-rw-r--r--kig/filters/exporter.cc624
-rw-r--r--kig/filters/exporter.h102
-rw-r--r--kig/filters/filter.cc114
-rw-r--r--kig/filters/filter.h96
-rw-r--r--kig/filters/filters-common.cc39
-rw-r--r--kig/filters/filters-common.h30
-rw-r--r--kig/filters/imageexporteroptions.cc57
-rw-r--r--kig/filters/imageexporteroptions.h45
-rw-r--r--kig/filters/imageexporteroptionsbase.ui152
-rw-r--r--kig/filters/kgeo-filter.cc374
-rw-r--r--kig/filters/kgeo-filter.h55
-rw-r--r--kig/filters/kgeo-resource.h204
-rw-r--r--kig/filters/kseg-defs.h301
-rw-r--r--kig/filters/kseg-filter-status.txt41
-rw-r--r--kig/filters/kseg-filter.cc679
-rw-r--r--kig/filters/kseg-filter.h42
-rw-r--r--kig/filters/latexexporter.cc608
-rw-r--r--kig/filters/latexexporter.h41
-rw-r--r--kig/filters/latexexporteroptions.ui69
-rw-r--r--kig/filters/native-filter.cc747
-rw-r--r--kig/filters/native-filter.h66
-rw-r--r--kig/filters/svgexporter.cc111
-rw-r--r--kig/filters/svgexporter.h41
-rw-r--r--kig/filters/svgexporteroptions.ui61
-rw-r--r--kig/filters/tests/circleBCP.FIG24
-rw-r--r--kig/filters/tests/constrainedPoint.FIG24
-rw-r--r--kig/filters/tests/cubiclineintersect.kig105
-rw-r--r--kig/filters/tests/intersectandasymptotestest.kig111
-rw-r--r--kig/filters/tests/intersection-test.segbin0 -> 484 bytes
-rw-r--r--kig/filters/tests/invisibleLine.FIG32
-rw-r--r--kig/filters/tests/lineBTP.FIG24
-rw-r--r--kig/filters/tests/linebyonepoint.FIG20
-rw-r--r--kig/filters/tests/locus.fgeo2
-rw-r--r--kig/filters/tests/lotsOfObjects.FIG148
-rw-r--r--kig/filters/tests/python-script.kig29
-rw-r--r--kig/filters/tests/radicallinestest.kig85
-rw-r--r--kig/filters/tests/stylestest.kig27
-rw-r--r--kig/filters/tests/test.kgeo145
-rw-r--r--kig/filters/tests/test.segbin0 -> 576 bytes
-rw-r--r--kig/filters/tests/testalotofeverything.kig174
-rw-r--r--kig/filters/tests/testlocuswithinvalidpoints.kig177
-rw-r--r--kig/filters/tests/testnames.kig62
-rw-r--r--kig/filters/tests/testtest.kig66
-rw-r--r--kig/filters/tests/transform-test.segbin0 -> 672 bytes
-rw-r--r--kig/filters/tests/transformlocustest.kig82
54 files changed, 7857 insertions, 0 deletions
diff --git a/kig/filters/Makefile.am b/kig/filters/Makefile.am
new file mode 100644
index 00000000..bb827b5a
--- /dev/null
+++ b/kig/filters/Makefile.am
@@ -0,0 +1,38 @@
+INCLUDES=$(all_includes)
+
+METASOURCES = AUTO
+
+noinst_LTLIBRARIES=libfilters.la
+noinst_HEADERS= \
+ cabri-filter.h \
+ exporter.h \
+ filter.h \
+ filters-common.h \
+ imageexporteroptions.h \
+ kgeo-filter.h \
+ kgeo-resource.h \
+ kseg-defs.h \
+ kseg-filter.h \
+ latexexporter.h \
+ native-filter.h \
+ svgexporter.h \
+ drgeo-filter.h \
+ drgeo-filter-chooser.h
+libfilters_la_SOURCES= \
+ cabri-filter.cc \
+ exporter.cc \
+ filter.cc \
+ filters-common.cc \
+ imageexporteroptions.cc \
+ imageexporteroptionsbase.ui \
+ kgeo-filter.cc \
+ kseg-filter.cc \
+ latexexporter.cc \
+ latexexporteroptions.ui \
+ native-filter.cc \
+ svgexporter.cc \
+ svgexporteroptions.ui \
+ drgeo-filter.cc \
+ drgeo-filter-chooser.cc \
+ drgeo-filter-chooserbase.ui
+
diff --git a/kig/filters/cabri-filter.cc b/kig/filters/cabri-filter.cc
new file mode 100644
index 00000000..6d19027b
--- /dev/null
+++ b/kig/filters/cabri-filter.cc
@@ -0,0 +1,577 @@
+/**
+ This file is part of Kig, a KDE program for Interactive Geometry...
+ 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
+**/
+
+#include "cabri-filter.h"
+
+#include "../kig/kig_document.h"
+#include "../kig/kig_part.h"
+#include "../misc/coordinate.h"
+#include "../objects/arc_type.h"
+#include "../objects/bogus_imp.h"
+#include "../objects/circle_type.h"
+#include "../objects/conic_types.h"
+#include "../objects/curve_imp.h"
+#include "../objects/line_imp.h"
+#include "../objects/line_type.h"
+#include "../objects/object_calcer.h"
+#include "../objects/object_drawer.h"
+#include "../objects/object_factory.h"
+#include "../objects/object_holder.h"
+#include "../objects/other_imp.h"
+#include "../objects/other_type.h"
+#include "../objects/point_type.h"
+#include "../objects/polygon_type.h"
+#include "../objects/transform_types.h"
+#include "../objects/vector_type.h"
+
+#include <qcolor.h>
+#include <qfile.h>
+#include <qregexp.h>
+
+#include <kdebug.h>
+#include <klocale.h>
+
+/**
+ * a line:
+ * "Nr": Type, Unknown, "CN:"NumberOfParents, "VN:"Unknown
+ * Color, FillType, Thickness, "DS":Dots, "GT":SpecialAppearance, Visible, Fixed
+ * ["Const": Parents] ["Val": Constants]
+ *
+ * Nr: Simple sequential numbering of the objects in a file.
+ * Type: seen so far: Pt, Axes, Line, Cir
+ * NumberOfParents: The number of parents that will be specified in
+ * Parents
+ * Color:
+ * R -> red
+ * O -> purple
+ * Y -> yellow
+ * P -> dark purple
+ * V -> dark blue
+ * Bl -> blue
+ * lBl -> bright blue
+ * G -> bright green
+ * dG -> dark green
+ * Br -> brown
+ * dBr -> beige
+ * lGr -> light grey
+ * Gr -> grey
+ * dGr -> dark grey
+ * B -> black
+ * FillType:
+ * W -> not filled ( white ? )
+ * all values of the Color item are valid here too..
+ * Thickness:
+ * t -> thin
+ * tT -> medium
+ * T -> Thick
+ * Dots:
+ * a specification for how a line should be drawn ( with many
+ * dots, with short lines, it's a pretty generic format: the first
+ * number signifies the number of sequential dots to draw first, and
+ * the next is the sum of this first number with the number of
+ * spaces to leave before starting a new segment.
+ * SpecialAppearance:
+ * a number indicating some way of specially drawing an object. This
+ * can be modified using the "Modify Appearance" button in
+ * Cabri. For example, for a segment, the number indicates the
+ * amount of ticks to put on the segment, to indicate
+ * correspondances between segments..
+ * Visible:
+ * V means visible, I means invisible
+ * Fixed:
+ * St means fix this object ( if you move one of its parents, it
+ * won't move ), nSt ( the default ) means don't fix this object.
+ * Parents:
+ * The numbers of the objects this object depends on
+ * Constants:
+ * Constants whose meaning depends on the type of object. E.g. for
+ * a point, this means first x, then y component.
+ */
+
+struct CabriObject
+{
+ uint id;
+ QCString type;
+ uint numberOfParents;
+ QColor color;
+ QColor fillColor;
+ int thick;
+ int lineSegLength;
+ int lineSegSplit;
+ int specialAppearanceSwitch;
+ bool visible;
+ bool fixed;
+ std::vector<int> parents;
+ std::vector<double> data;
+};
+
+KigFilterCabri::KigFilterCabri()
+{
+}
+
+KigFilterCabri::~KigFilterCabri()
+{
+}
+
+bool KigFilterCabri::supportMime( const QString& mime )
+{
+ // ugly hack to avoid duplicate extension ( XFig and Cabri files
+ // have the same .fig extension ).
+ return ( mime == "image/x-xfig" ) ||
+ ( mime == "application/x-cabri" );
+}
+
+static QString readLine( QFile& file )
+{
+ QString ret;
+ file.readLine( ret, 10000L );
+ if ( ret[ret.length() - 1] == '\n' )
+ ret.truncate( ret.length() - 1 );
+ if ( ret[ret.length() - 1] == '\r' )
+ ret.truncate( ret.length() - 1 );
+ return ret;
+}
+
+static QColor translatecolor( const QString& s )
+{
+ if ( s == "R" ) return Qt::red;
+ if ( s == "O" ) return Qt::magenta;
+ if ( s == "Y" ) return Qt::yellow;
+ if ( s == "P" ) return Qt::darkMagenta;
+ if ( s == "V" ) return Qt::darkBlue;
+ if ( s == "Bl" ) return Qt::blue;
+ if ( s == "lBl" ) return Qt::cyan; // TODO: bright blue
+ if ( s == "G" ) return Qt::green;
+ if ( s == "dG" ) return Qt::darkGreen;
+ if ( s == "Br" ) return QColor( 165, 42, 42 );
+ if ( s == "dBr" ) return QColor( 128, 128, 0 );
+ if ( s == "lGr" ) return Qt::lightGray;
+ if ( s == "Gr" ) return Qt::gray;
+ if ( s == "dGr" ) return Qt::darkGray;
+ if ( s == "B" ) return Qt::black;
+ if ( s == "W" ) return Qt::white;
+
+ kdDebug() << k_funcinfo << "unknown color: " << s << endl;
+ return Qt::black;
+}
+
+bool KigFilterCabri::readObject( QFile& f, CabriObject& myobj )
+{
+ // there are 4 lines per object in the file, so we read them all
+ // four now.
+ QString line1, line2, line3, s;
+ QString file = f.name();
+ line1 = readLine( f );
+ line2 = readLine( f );
+ line3 = readLine( f );
+ // ignore line 4, it is empty..
+ s = readLine( f );
+
+ QRegExp firstlinere( "^([^:]+): ([^,]+), ([^,]+), CN:([^,]*), VN:(.*)$" );
+ if ( ! firstlinere.exactMatch( line1 ) )
+ KIG_FILTER_PARSE_ERROR;
+
+ bool ok;
+ QString tmp;
+
+ tmp = firstlinere.cap( 1 );
+ myobj.id = tmp.toInt( &ok );
+ if ( !ok ) KIG_FILTER_PARSE_ERROR;
+
+ tmp = firstlinere.cap( 2 );
+ myobj.type = tmp.latin1();
+
+ tmp = firstlinere.cap( 3 );
+ // i have no idea what this number means..
+
+ tmp = firstlinere.cap( 4 );
+ myobj.numberOfParents = tmp.toInt( &ok );
+ if ( ! ok ) KIG_FILTER_PARSE_ERROR;
+
+ tmp = firstlinere.cap( 5 );
+ // i have no idea what this number means..
+
+ QRegExp secondlinere( "^([^,]+), ([^,]+), ([^,]+), DS:([^ ]+) ([^,]+), GT:([^,]+), ([^,]+), (.*)$" );
+ if ( ! secondlinere.exactMatch( line2 ) )
+ KIG_FILTER_PARSE_ERROR;
+
+ tmp = secondlinere.cap( 1 );
+ myobj.color = translatecolor( tmp );
+// if ( ! color.isValid() ) KIG_FILTER_PARSE_ERROR;
+
+ tmp = secondlinere.cap( 2 );
+ myobj.fillColor = translatecolor( tmp );
+// if ( ! fillcolor.isValid() ) KIG_FILTER_PARSE_ERROR;
+
+ tmp = secondlinere.cap( 3 );
+ myobj.thick = tmp == "t" ? 1 : tmp == "tT" ? 2 : 3;
+
+ tmp = secondlinere.cap( 4 );
+ myobj.lineSegLength = tmp.toInt( &ok );
+ if ( ! ok ) KIG_FILTER_PARSE_ERROR;
+
+ tmp = secondlinere.cap( 5 );
+ myobj.lineSegSplit = tmp.toInt( &ok );
+ if ( ! ok ) KIG_FILTER_PARSE_ERROR;
+
+ tmp = secondlinere.cap( 6 );
+ myobj.specialAppearanceSwitch = tmp.toInt( &ok );
+ if ( ! ok ) KIG_FILTER_PARSE_ERROR;
+
+ tmp = secondlinere.cap( 7 );
+ myobj.visible = tmp == "V";
+
+ tmp = secondlinere.cap( 8 );
+ myobj.fixed = tmp == "St";
+
+ QRegExp thirdlinere( "^(Const: ([^,]*),? ?)?(Val: (.*))?$" );
+ if ( ! thirdlinere.exactMatch( line3 ) )
+ KIG_FILTER_PARSE_ERROR;
+
+ tmp = thirdlinere.cap( 2 );
+ QStringList parentsids = QStringList::split( ' ', tmp );
+ for ( QStringList::iterator i = parentsids.begin();
+ i != parentsids.end(); ++i )
+ {
+ myobj.parents.push_back( ( *i ).toInt( &ok ) );
+ if ( ! ok ) KIG_FILTER_PARSE_ERROR;
+ }
+ if ( myobj.parents.size() != myobj.numberOfParents )
+ KIG_FILTER_PARSE_ERROR;
+
+ tmp = thirdlinere.cap( 4 );
+ QStringList valIds = QStringList::split( ' ', tmp );
+ for ( QStringList::iterator i = valIds.begin();
+ i != valIds.end(); ++i )
+ {
+ myobj.data.push_back( ( *i ).toDouble( &ok ) );
+ if ( ! ok ) KIG_FILTER_PARSE_ERROR;
+ }
+// kdDebug()
+// << k_funcinfo << endl
+// << "id = " << myobj.id << endl
+// << "type = " << myobj.type << endl
+// << "numberOfParents = " << myobj.numberOfParents << endl
+// << "color = " << myobj.color.name() << endl
+// << "fillcolor = " << myobj.fillColor.name() << endl
+// << "thick = " << myobj.thick << endl
+// << "lineseglength = " << myobj.lineSegLength << endl
+// << "linesegsplit = " << myobj.lineSegSplit << endl
+// << "specialAppearanceSwitch = " << myobj.specialAppearanceSwitch << endl
+// << "visible = " << visible << endl
+// << "fixed = " << myobj.fixed << endl
+// << "parents =" << endl;
+// for ( std::vector<int>::iterator i = myobj.parents.begin(); i != myobj.parents.end(); ++i )
+// kdDebug() << " " << *i << endl;
+// kdDebug() << "vals = " << endl;
+// for ( std::vector<double>::iterator i = myobj.data.begin(); i != myobj.data.end(); ++i )
+// kdDebug() << " " << *i << endl;
+
+ return true;
+}
+
+KigDocument* KigFilterCabri::load( const QString& file )
+{
+ QFile f( file );
+ if ( ! f.open( IO_ReadOnly ) )
+ {
+ fileNotFound( file );
+ return 0;
+ }
+
+ KigDocument* ret = new KigDocument();
+
+ QString s = readLine( f );
+ QString a = s.left( 21 );
+ QString b = s.mid( 21 );
+ if( a != "FIGURE CabriII vers. " ||
+ ( b != "DOS 1.0" && b != "MS-Windows 1.0" ) )
+ {
+ if ( s.left( 5 ) == "#FIG " )
+ {
+ notSupported( file, i18n( "This is an XFig file, not a Cabri figure." ) );
+ return 0;
+ }
+ else
+ KIG_FILTER_PARSE_ERROR;
+ }
+
+ // next we have:
+ // line 2: empty line
+ // line 3: window dimensions -> we don't need/use that...
+ // line 4: empty line
+ // line 5 through 8: center point
+ // line 9 through 12: axes
+ // so we skip 11 lines...
+ for( int i = 0; i != 11; ++i)
+ s = readLine( f );
+
+ // all Cabri files seem to at least have these center and axes...
+ if ( f.atEnd() )
+ KIG_FILTER_PARSE_ERROR;
+
+ std::vector<ObjectHolder*> holders;
+ std::vector<ObjectCalcer*> calcers;
+
+ const ObjectFactory* fact = ObjectFactory::instance();
+
+ std::vector<ObjectCalcer*> args;
+ ObjectCalcer* oc = 0;
+
+ while ( ! f.atEnd() )
+ {
+ CabriObject obj;
+ // we do one object each iteration..
+ if ( !readObject( f, obj ) )
+ return 0;
+
+// reading linestyle
+ Qt::PenStyle ls = Qt::SolidLine;
+ if ( ( obj.lineSegLength > 1 ) && ( obj.lineSegLength < 6 ) &&
+ ( obj.lineSegSplit > 1 ) && ( obj.lineSegSplit <= 10 ) )
+ ls = Qt::DotLine;
+ else if ( ( obj.lineSegLength >= 6 ) && ( obj.lineSegSplit > 10 ) )
+ ls = Qt::DashLine;
+ int ps = 0;
+
+ args.clear();
+ for ( std::vector<int>::iterator i = obj.parents.begin();
+ i != obj.parents.end(); ++i )
+ args.push_back( calcers[*i-3] );
+
+ // two fake objects at the start ( origin and axes.. )
+ if ( obj.id != calcers.size() + 3 ) KIG_FILTER_PARSE_ERROR;
+ oc = 0;
+ if ( obj.type == "Pt" )
+ {
+ if ( ! args.empty() ) KIG_FILTER_PARSE_ERROR;
+ if ( obj.data.size() != 2 ) KIG_FILTER_PARSE_ERROR;
+
+ switch ( obj.specialAppearanceSwitch )
+ {
+ case 0:
+ {
+ obj.thick -= 1;
+ break;
+ }
+ case 2:
+ {
+ obj.thick += 1;
+ break;
+ }
+ case 3:
+ {
+ obj.thick += 1;
+ ps = 1;
+ break;
+ }
+ case 4:
+ {
+ obj.thick += 2;
+ ps = 4;
+ break;
+ }
+ }
+ // different sizes for points..
+ obj.thick *= 2;
+
+ oc = fact->fixedPointCalcer( Coordinate( obj.data[0], obj.data[1] ) );
+ }
+ else if ( obj.type == "Cir" )
+ {
+ if ( args.size() == 1 )
+ {
+ if ( obj.data.size() != 1 ) KIG_FILTER_PARSE_ERROR;
+ ObjectConstCalcer* radc =
+ new ObjectConstCalcer( new DoubleImp( obj.data[0] ) );
+ args.push_back( radc );
+ oc = new ObjectTypeCalcer( CircleBPRType::instance(), args );
+ }
+ else if ( args.size() == 2 )
+ {
+ if ( ! obj.data.empty() ) KIG_FILTER_PARSE_ERROR;
+ oc = new ObjectTypeCalcer( CircleBCPType::instance(), args );
+ }
+ else KIG_FILTER_PARSE_ERROR;
+ }
+ else if ( obj.type == "Line" || obj.type == "Ray" || obj.type == "Seg" ||
+ obj.type == "Vec" )
+ {
+ if ( args.size() == 1 )
+ {
+ if ( obj.data.size() != 2 ) KIG_FILTER_PARSE_ERROR;
+ Coordinate vect( obj.data[0], obj.data[1] );
+ ObjectConstCalcer* vectorcalcer =
+ new ObjectConstCalcer( new VectorImp( Coordinate( 0, 0 ), vect ) );
+ args.push_back( vectorcalcer );
+ ObjectTypeCalcer* secondpoint =
+ new ObjectTypeCalcer( TranslatedType::instance(), args );
+ secondpoint->calc( *ret );
+ args[1] = secondpoint;
+ }
+ if ( args.size() != 2 ) KIG_FILTER_PARSE_ERROR;
+ const ObjectType* t = 0;
+ if ( obj.type == "Line" ) t = LineABType::instance();
+ else if ( obj.type == "Ray" ) t = RayABType::instance();
+ else if ( obj.type == "Seg" ) t = SegmentABType::instance();
+ else if ( obj.type == "Vec" ) t = VectorType::instance();
+ else assert( t );
+ oc = new ObjectTypeCalcer( t, args );
+ }
+ else if ( obj.type == "Pt/" )
+ {
+ // different sizes for points..
+ obj.thick *= 2;
+ if ( args.size() != 1 || obj.data.size() != 2 )
+ KIG_FILTER_PARSE_ERROR;
+ ObjectCalcer* parent = args[0];
+ if ( !parent->imp()->inherits( CurveImp::stype() ) )
+ KIG_FILTER_PARSE_ERROR;
+ const CurveImp* curve = static_cast<const CurveImp*>( parent->imp() );
+ Coordinate pt = Coordinate( obj.data[0], obj.data[1] );
+ double param = curve->getParam( pt, *ret );
+ args.push_back( new ObjectConstCalcer( new DoubleImp( param ) ) );
+ oc = new ObjectTypeCalcer( ConstrainedPointType::instance(), args );
+ }
+ else if ( obj.type == "Perp" || obj.type == "Par" )
+ {
+ if ( args.size() != 2 || obj.data.size() != 0 )
+ KIG_FILTER_PARSE_ERROR;
+ const ObjectType* t = 0;
+ if ( obj.type == "Perp" ) t = LinePerpendLPType::instance();
+ else if ( obj.type == "Par" ) t = LineParallelLPType::instance();
+ else assert( false );
+ oc = new ObjectTypeCalcer( t, args );
+ }
+ else if ( obj.type == "Arc" )
+ {
+ if ( args.size() != 3 || ! obj.data.empty() )
+ KIG_FILTER_PARSE_ERROR;
+ oc = new ObjectTypeCalcer( ArcBTPType::instance(), args );
+ }
+ else if ( obj.type == "Con" )
+ {
+ if ( args.size() != 5 || !obj.data.empty() )
+ KIG_FILTER_PARSE_ERROR;
+ oc = new ObjectTypeCalcer( ConicB5PType::instance(), args );
+ }
+ else if ( obj.type == "Mid" )
+ {
+ if ( args.size() == 2 )
+ {
+ ObjectCalcer* c =
+ new ObjectTypeCalcer( SegmentABType::instance(), args );
+ c->calc( *ret );
+ args.clear();
+ args.push_back( c );
+ }
+ // midpoint -> this can be the midpoint of a segment, two
+ // points, or a vector...
+ if ( args.size() != 1 || !obj.data.empty() )
+ KIG_FILTER_PARSE_ERROR;
+ ObjectCalcer* parent = args[0];
+ if ( parent->imp()->inherits( SegmentImp::stype() ) )
+ oc = fact->propertyObjectCalcer( parent, "mid-point" ) ;
+ else if ( parent->imp()->inherits( VectorImp::stype() ) )
+ oc = fact->propertyObjectCalcer( parent, "vect-mid-point" );
+ else KIG_FILTER_PARSE_ERROR;
+ }
+ else if ( obj.type == "PBiss" )
+ {
+ if ( args.size() == 2 )
+ {
+ ObjectCalcer* c =
+ new ObjectTypeCalcer( SegmentABType::instance(), args );
+ c->calc( *ret );
+ args.clear();
+ args.push_back( c );
+ }
+ if ( args.size() != 1 || !obj.data.empty() )
+ KIG_FILTER_PARSE_ERROR;
+ ObjectCalcer* parent = args[0];
+ ObjectCalcer* midpoint = 0;
+ if ( parent->imp()->inherits( SegmentImp::stype() ) )
+ midpoint = fact->propertyObjectCalcer( parent, "mid-point" ) ;
+// else if ( parent->imp()->inherits( VectorImp::stype() ) )
+// midpoint = fact->propertyObjectCalcer( parent, "vect-mid-point" );
+ else KIG_FILTER_PARSE_ERROR;
+ midpoint->calc( *ret );
+ args.push_back( midpoint );
+ oc = new ObjectTypeCalcer( LinePerpendLPType::instance(), args );
+ }
+ else if ( obj.type == "Pol" )
+ {
+ if ( args.size() < 3 || !obj.data.empty() )
+ KIG_FILTER_PARSE_ERROR;
+ oc = new ObjectTypeCalcer( PolygonBNPType::instance(), args );
+ }
+ else if ( obj.type == "Locus" )
+ {
+ if ( args.size() != 2 || !obj.data.empty() )
+ KIG_FILTER_PARSE_ERROR;
+ oc = fact->locusCalcer( args[0], args[1] );
+ }
+ else if ( obj.type == "Refl" )
+ {
+ if ( args.size() != 2 || !obj.data.empty() )
+ KIG_FILTER_PARSE_ERROR;
+ oc = new ObjectTypeCalcer( LineReflectionType::instance(), args );
+ }
+ else if ( obj.type == "Sym" )
+ {
+ if ( args.size() != 2 || !obj.data.empty() )
+ KIG_FILTER_PARSE_ERROR;
+ oc = new ObjectTypeCalcer( PointReflectionType::instance(), args );
+ }
+ else if ( obj.type == "Tran" )
+ {
+ if ( args.size() != 2 || !obj.data.empty() )
+ KIG_FILTER_PARSE_ERROR;
+ oc = new ObjectTypeCalcer( TranslatedType::instance(), args );
+ }
+ else
+ {
+ notSupported( file, i18n( "This Cabri file contains a \"%1\" object, "
+ "which Kig does not currently support." ).arg( obj.type ) );
+ return 0;
+ }
+
+ if ( oc == 0 ) KIG_FILTER_PARSE_ERROR;
+
+ oc->calc( *ret );
+ calcers.push_back( oc );
+ ObjectDrawer* d = new ObjectDrawer( obj.color, obj.thick, obj.visible, ls, ps );
+ ObjectHolder* oh = new ObjectHolder( oc, d );
+ holders.push_back( oh );
+
+ oc = 0;
+ }
+
+ ret->addObjects( holders );
+ ret->setGrid( false );
+ ret->setAxes( false );
+ return ret;
+}
+
+KigFilterCabri* KigFilterCabri::instance()
+{
+ static KigFilterCabri t;
+ return &t;
+}
diff --git a/kig/filters/cabri-filter.h b/kig/filters/cabri-filter.h
new file mode 100644
index 00000000..5760040f
--- /dev/null
+++ b/kig/filters/cabri-filter.h
@@ -0,0 +1,55 @@
+// This file is part of Kig, a KDE program for Interactive Geometry...
+// 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_FILTERS_CABRI_FILTER_H
+#define KIG_FILTERS_CABRI_FILTER_H
+
+#include "filter.h"
+
+struct CabriObject;
+
+class QFile;
+
+/**
+ * This is an import filter for the output of the commercial program
+ * Cabri ("CAhier de BRouillon Interactif" or something like that),
+ * which is being pushed by Texas Instruments, but only exists for
+ * the Winblows(tm) platform and some TI scientific calculator...
+ *
+ * \note
+ * This is completely free code, i have not looked at any Cabri source
+ * code, and have implemented this implementation of the Cabri file
+ * format from zero, by just looking at the input and output from a
+ * (properly licensed) Cabri program...
+ */
+class KigFilterCabri
+ : public KigFilter
+{
+ KigFilterCabri();
+ ~KigFilterCabri();
+public:
+ static KigFilterCabri* instance();
+
+ bool supportMime ( const QString& mime );
+ KigDocument* load ( const QString& fromfile );
+private:
+ bool readObject( QFile& f, CabriObject& myobj );
+
+};
+
+#endif
diff --git a/kig/filters/drgeo-filter-chooser.cc b/kig/filters/drgeo-filter-chooser.cc
new file mode 100644
index 00000000..424a3462
--- /dev/null
+++ b/kig/filters/drgeo-filter-chooser.cc
@@ -0,0 +1,65 @@
+// Copyright (C) 2004 Pino Toscano <toscano.pino@tiscali.it>
+// Copyright (C) 2004 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.
+
+#include "drgeo-filter-chooser.h"
+#include "drgeo-filter-chooser.moc"
+
+#include <klistbox.h>
+#include <klocale.h>
+#include <kmessagebox.h>
+#include <kpushbutton.h>
+#include <kstdguiitem.h>
+
+KigFilterDrgeoChooser::KigFilterDrgeoChooser( const QStringList& l )
+ : KigFilterDrgeoChooserBase( 0, "drgeo_filter", true )
+{
+ OKButton->setGuiItem( KStdGuiItem::ok() );
+ CancelButton->setGuiItem( KStdGuiItem::cancel() );
+
+ FigureListBox->insertStringList( l );
+
+ connect( OKButton, SIGNAL( clicked() ), SLOT( slotOKPressed() ) );
+ connect( CancelButton, SIGNAL( clicked() ), SLOT( slotCancelPressed() ) );
+ connect( FigureListBox, SIGNAL( executed( QListBoxItem* ) ), SLOT( slotExecuted( QListBoxItem* ) ) );
+}
+
+void KigFilterDrgeoChooser::slotOKPressed()
+{
+ const int r = FigureListBox->currentItem();
+ if ( r == -1 )
+ {
+ KMessageBox::sorry( 0, i18n( "Please select a figure." ) );
+ return;
+ }
+ done( r );
+}
+
+void KigFilterDrgeoChooser::slotCancelPressed()
+{
+ done( -1 );
+}
+
+KigFilterDrgeoChooser::~KigFilterDrgeoChooser()
+{
+
+}
+
+void KigFilterDrgeoChooser::slotExecuted( QListBoxItem* i )
+{
+ done( FigureListBox->index( i ) );
+}
diff --git a/kig/filters/drgeo-filter-chooser.h b/kig/filters/drgeo-filter-chooser.h
new file mode 100644
index 00000000..fd4ce606
--- /dev/null
+++ b/kig/filters/drgeo-filter-chooser.h
@@ -0,0 +1,41 @@
+// Copyright (C) 2004 Pino Toscano <toscano.pino@tiscali.it>
+// 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 DRGEOFILTERCHOOSER_H
+#define DRGEOFILTERCHOOSER_H
+
+#include "drgeo-filter-chooserbase.h"
+
+class QListBoxItem;
+class QStringList;
+
+class KigFilterDrgeoChooser
+ : public KigFilterDrgeoChooserBase
+{
+ Q_OBJECT
+
+public:
+ KigFilterDrgeoChooser( const QStringList& l );
+ ~KigFilterDrgeoChooser();
+public slots:
+ void slotOKPressed();
+ void slotCancelPressed();
+ void slotExecuted( QListBoxItem* );
+};
+
+#endif
diff --git a/kig/filters/drgeo-filter-chooserbase.ui b/kig/filters/drgeo-filter-chooserbase.ui
new file mode 100644
index 00000000..829d84cc
--- /dev/null
+++ b/kig/filters/drgeo-filter-chooserbase.ui
@@ -0,0 +1,140 @@
+<!DOCTYPE UI><UI version="3.1" stdsetdef="1">
+<class>KigFilterDrgeoChooserBase</class>
+<widget class="QDialog">
+ <property name="name">
+ <cstring>KigFilterDrgeoChooserBase</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>300</width>
+ <height>202</height>
+ </rect>
+ </property>
+ <property name="caption">
+ <string>Dr. Geo Filter</string>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>11</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>ExplanationTextLabel</cstring>
+ </property>
+ <property name="text">
+ <string>The current Dr. Geo file contains more than one figure.
+Please select which to import:</string>
+ </property>
+ <property name="alignment">
+ <set>WordBreak|AlignVCenter</set>
+ </property>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>Layout1</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <widget class="KListBox">
+ <property name="name">
+ <cstring>FigureListBox</cstring>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ <widget class="Line">
+ <property name="name">
+ <cstring>Line1</cstring>
+ </property>
+ <property name="frameShape">
+ <enum>HLine</enum>
+ </property>
+ <property name="frameShadow">
+ <enum>Sunken</enum>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>Layout7</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <spacer>
+ <property name="name">
+ <cstring>spacer</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>20</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="KPushButton">
+ <property name="name">
+ <cstring>OKButton</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>1</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>&amp;OK</string>
+ </property>
+ </widget>
+ <widget class="KPushButton">
+ <property name="name">
+ <cstring>CancelButton</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Cancel</string>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ </vbox>
+</widget>
+<layoutdefaults spacing="6" margin="11"/>
+<includehints>
+ <includehint>klistbox.h</includehint>
+ <includehint>kpushbutton.h</includehint>
+ <includehint>kpushbutton.h</includehint>
+</includehints>
+</UI>
diff --git a/kig/filters/drgeo-filter-status.txt b/kig/filters/drgeo-filter-status.txt
new file mode 100644
index 00000000..db399eae
--- /dev/null
+++ b/kig/filters/drgeo-filter-status.txt
@@ -0,0 +1,50 @@
+Dr. Geo filter status
+=====================
+
+Objects imported
+----------------
+
+Points most, On_curve (most)
+Rays ok
+Vectors ok
+Lines most
+Circles most
+Numberics most (as a label)
+Angles 3pts
+Arcs ok
+Locuses ok
+Transformations most
+Intersections most
+Scripts as a label
+Equations ok
+Polygons ok
+
+Colors ok
+Visibility ok
+Styles ok
+Grid ok
+
+Objects not imported
+--------------------
+
+Points Coordinate(*)
+Lines pt_slope(*)
+Circle radius(*)
+Numberics distance_pt_circle
+Angles vectors
+Transformations scaling(*)
+Intersections arc-circle(**), locus-other object(**)
+
+(*) objects which depend on numerics
+(**) objects which currently are not implemented in Kig
+
+Objects ignored
+---------------
+
+boundingBox
+customUI
+
+Known problems
+--------------
+
+* Point(On_curve): does not work with locuses
diff --git a/kig/filters/drgeo-filter.cc b/kig/filters/drgeo-filter.cc
new file mode 100644
index 00000000..8fa306cc
--- /dev/null
+++ b/kig/filters/drgeo-filter.cc
@@ -0,0 +1,809 @@
+// Copyright (C) 2004 Pino Toscano <toscano.pino@tiscali.it>
+// Copyright (C) 2004 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.
+
+#include "drgeo-filter.h"
+
+#include "drgeo-filter-chooser.h"
+#include "filters-common.h"
+
+#include "../kig/kig_document.h"
+#include "../kig/kig_part.h"
+#include "../misc/common.h"
+#include "../misc/coordinate.h"
+#include "../objects/angle_type.h"
+#include "../objects/arc_type.h"
+#include "../objects/bogus_imp.h"
+#include "../objects/circle_imp.h"
+#include "../objects/circle_type.h"
+#include "../objects/conic_imp.h"
+#include "../objects/conic_types.h"
+#include "../objects/curve_imp.h"
+#include "../objects/intersection_types.h"
+#include "../objects/line_imp.h"
+#include "../objects/line_type.h"
+#include "../objects/object_calcer.h"
+#include "../objects/object_drawer.h"
+#include "../objects/object_factory.h"
+#include "../objects/object_holder.h"
+#include "../objects/object_type.h"
+#include "../objects/other_imp.h"
+#include "../objects/other_type.h"
+#include "../objects/point_imp.h"
+#include "../objects/point_type.h"
+#include "../objects/polygon_type.h"
+#include "../objects/transform_types.h"
+#include "../objects/vector_type.h"
+
+#include <math.h>
+
+#include <qfile.h>
+#include <qnamespace.h>
+
+#include <klocale.h>
+
+#undef DRGEO_DEBUG
+//#define DRGEO_DEBUG
+
+struct DrGeoHierarchyElement
+{
+ QString id;
+ std::vector<QString> parents;
+};
+
+KigFilterDrgeo::KigFilterDrgeo()
+{
+}
+
+KigFilterDrgeo::~KigFilterDrgeo()
+{
+}
+
+bool KigFilterDrgeo::supportMime( const QString& mime )
+{
+ return mime == "application/x-drgeo";
+}
+
+KigDocument* KigFilterDrgeo::load( const QString& file )
+{
+ QFile f( file );
+ if ( ! f.open( IO_ReadOnly ) )
+ {
+ fileNotFound( file );
+ return 0;
+ }
+
+ QStringList figures;
+ QDomDocument doc( "drgenius" );
+ if ( !doc.setContent( &f ) )
+ KIG_FILTER_PARSE_ERROR;
+ QDomElement main = doc.documentElement();
+ int nmacros = 0;
+ // reading figures...
+ for ( QDomNode n = main.firstChild(); ! n.isNull(); n = n.nextSibling() )
+ {
+ QDomElement e = n.toElement();
+ if ( e.isNull() ) continue;
+ else if ( e.tagName() == "drgeo" )
+ figures.append( e.attribute( "name" ) );
+ else if ( e.tagName() == "macro" )
+ nmacros++;
+ }
+ if ( figures.isEmpty() ) {
+ if( nmacros > 0 )
+ warning( i18n( "The Dr. Geo file \"%1\" is a macro file so it contains no "
+ "figures." ).arg( file ) );
+ else
+ warning( i18n( "There are no figures in Dr. Geo file \"%1\"." ).arg( file ) );
+ return false;
+ }
+
+ int nfig = figures.count();
+ // no figures, no party...
+ if ( nfig == 0 )
+ return 0;
+
+ int myfig = 0;
+
+ if ( nfig > 1 )
+ {
+ // Dr. Geo file has more than 1 figure, let the user choose one...
+ KigFilterDrgeoChooser* c = new KigFilterDrgeoChooser( figures );
+ myfig = c->exec();
+ delete c;
+ }
+
+#ifdef DRGEO_DEBUG
+ kdDebug() << "drgeo file " << file << endl;
+#endif
+ int curfig = -1;
+
+ for ( QDomNode n = main.firstChild(); ! n.isNull(); n = n.nextSibling() )
+ {
+ QDomElement e = n.toElement();
+ if ( e.isNull() ) continue;
+ else if ( e.tagName() == "drgeo" )
+ {
+ curfig += 1;
+ if ( curfig == myfig )
+ {
+#ifdef DRGEO_DEBUG
+ kdDebug() << "- Figure: '" << e.attribute("name") << "'" << endl;
+#endif
+ bool grid = !e.attribute( "grid" ).isEmpty() &&
+ ( e.attribute( "grid" ) != "False" );
+ return importFigure( e.firstChild(), file, grid );
+ }
+ }
+ }
+
+ return 0;
+}
+
+int convertDrgeoIndex( const std::vector<DrGeoHierarchyElement> es, const QString myid )
+{
+ for ( uint i = 0; i < es.size(); ++i )
+ if ( es[i].id == myid )
+ return i;
+ return -1;
+}
+
+const Coordinate convertDrgeoLineParam( const double param, const LineData& line )
+{
+ const double n = ( param - 0.5 ) * M_PI;
+ const Coordinate c = line.dir() / line.dir().length();
+ const Coordinate p = line.a + tan( n ) * c;
+ return p;
+}
+
+const Coordinate convertDrgeoHalflineParam( const double param, const LineData& line )
+{
+ const double n = param * M_PI * 0.5;
+ const Coordinate c = line.dir() / line.dir().length();
+ const Coordinate p = line.a + tan( n ) * c;
+ return p;
+}
+
+KigDocument* KigFilterDrgeo::importFigure( QDomNode f, const QString& file, const bool grid )
+{
+ KigDocument* ret = new KigDocument();
+
+ using namespace std;
+ std::vector<DrGeoHierarchyElement> elems;
+ int withoutid = 0;
+
+ // 1st: fetch relationships and build an appropriate structure
+ for (QDomNode a = f; ! a.isNull(); a = a.nextSibling() )
+ {
+ QDomElement domelem = a.toElement();
+ if ( domelem.isNull() ) continue;
+ else
+ {
+ DrGeoHierarchyElement elem;
+#ifdef DRGEO_DEBUG
+ kdDebug() << " * " << domelem.tagName() << "(" << domelem.attribute("type") << ")" << endl;
+#endif
+ for ( QDomNode c = domelem.firstChild(); ! c.isNull(); c = c.nextSibling() )
+ {
+ QDomElement ce = c.toElement();
+ if ( ce.isNull() ) continue;
+ else if ( ce.tagName() == "parent" )
+ elem.parents.push_back( ce.attribute( "ref" ) );
+ }
+ QString curid = domelem.attribute( "id" );
+ elem.id = !curid.isNull() ? curid : QString::number( withoutid++ ) ;
+ elems.push_back( elem );
+ }
+ }
+
+#ifdef DRGEO_DEBUG
+ QString x;
+ kdDebug() << "+++ elems" << endl;
+ for ( uint i = 0; i < elems.size(); ++i )
+ {
+ x = "";
+ for ( uint j = 0; j < elems[i].parents.size(); ++j )
+ {
+ x += elems[i].parents[j] + "_";
+ }
+ kdDebug() << " --> " << i << " - " << elems[i].id << " - " << x << endl;
+ }
+#endif
+
+ // 2nd: let's draw!
+ int curid = 0;
+ const ObjectFactory* fact = ObjectFactory::instance();
+ std::vector<ObjectHolder*> holders;
+ std::vector<ObjectHolder*> holders2;
+ ObjectTypeCalcer* oc = 0;
+ ObjectCalcer* oc2 = 0;
+ int nignored = 0;
+
+ // there's no need to sort the objects because it seems that DrGeo objects
+ // appear in the right order... so let's go!
+ for (QDomNode a = f; ! a.isNull(); a = a.nextSibling() )
+ {
+#ifdef DRGEO_DEBUG
+ kdDebug() << "+++ id: " << curid << endl;
+#endif
+ const DrGeoHierarchyElement& el = elems[curid];
+ std::vector<ObjectCalcer*> parents;
+ for ( uint j = 0; j < el.parents.size(); ++j )
+ {
+ int parentid = convertDrgeoIndex( elems, el.parents[j] );
+ if ( parentid == -1 )
+ KIG_FILTER_PARSE_ERROR;
+ parents.push_back( holders[parentid-nignored]->calcer() );
+ };
+ QDomElement domelem = a.toElement();
+
+#ifdef DRGEO_DEBUG
+ if ( parents.size() > 0 )
+ for ( uint j = 0; j < parents.size(); ++j )
+ {
+ kdDebug() << "+++++++++ parent[" << j << "]: " << parents[j] << " - "
+ << parents[j]->imp()->type()->internalName() << endl;
+ }
+ else
+ kdDebug() << "+++++++++ parents: NO" << endl;
+ kdDebug() << "+++++++++ " << domelem.tagName() << " - " << domelem.attribute("type") << endl;
+#endif
+
+ if ( domelem.isNull() ) continue;
+ else if ( domelem.tagName() == "point" )
+ {
+ QString xs;
+ QString ys;
+ QString values;
+ for ( QDomNode c = domelem.firstChild(); ! c.isNull(); c = c.nextSibling() )
+ {
+ QDomElement ce = c.toElement();
+ if ( ce.isNull() ) continue;
+ else if ( ce.tagName() == "x" )
+ xs = ce.text();
+ else if ( ce.tagName() == "y" )
+ ys = ce.text();
+ else if ( ce.tagName() == "value" )
+ values = ce.text();
+ }
+ if ( domelem.attribute( "type" ) == "Free" )
+ {
+ bool ok;
+ bool ok2;
+ double x = xs.toDouble( &ok );
+ double y = ys.toDouble( &ok2 );
+ if ( ! ( ok && ok2 ) )
+ KIG_FILTER_PARSE_ERROR;
+ oc = fact->fixedPointCalcer( Coordinate( x, y ) );
+ }
+ else if ( domelem.attribute( "type" ) == "Middle_2pts" )
+ oc = new ObjectTypeCalcer( MidPointType::instance(), parents );
+ else if ( domelem.attribute( "type" ) == "Middle_segment" )
+ {
+ if ( parents.size() != 1 ) KIG_FILTER_PARSE_ERROR;
+ if ( !parents[0]->imp()->inherits( SegmentImp::stype() ) )
+ KIG_FILTER_PARSE_ERROR;
+ ObjectPropertyCalcer* o1 = fact->propertyObjectCalcer( parents[0], "end-point-A" );
+ o1->calc( *ret );
+ ObjectPropertyCalcer* o2 = fact->propertyObjectCalcer( parents[0], "end-point-B" );
+ o2->calc( *ret );
+ std::vector<ObjectCalcer*> args;
+ args.push_back( o1 );
+ args.push_back( o2 );
+ oc = new ObjectTypeCalcer( MidPointType::instance(), args );
+ }
+ else if ( domelem.attribute( "type" ) == "On_curve" )
+ {
+ bool ok3;
+ double value = values.toDouble( &ok3 );
+ if ( ! ok3 )
+ KIG_FILTER_PARSE_ERROR;
+ if ( ( parents[0]->imp()->inherits( CircleImp::stype() ) ) ||
+ ( parents[0]->imp()->inherits( SegmentImp::stype() ) ) )
+ oc = fact->constrainedPointCalcer( parents[0], value );
+ else if ( parents[0]->imp()->inherits( LineImp::stype() ) )
+ {
+ const LineData l = static_cast<const LineImp*>( parents[0]->imp() )->data();
+ const Coordinate p = convertDrgeoLineParam( value, l );
+ oc = fact->constrainedPointCalcer( parents[0], p, *ret );
+ }
+ else if ( parents[0]->imp()->inherits( RayImp::stype() ) )
+ {
+ const LineData l = static_cast<const RayImp*>( parents[0]->imp() )->data();
+ const Coordinate p = convertDrgeoHalflineParam( value, l );
+ oc = fact->constrainedPointCalcer( parents[0], p, *ret );
+ }
+ else if ( parents[0]->imp()->inherits( ArcImp::stype() ) )
+ oc = fact->constrainedPointCalcer( parents[0], 1 - value );
+ else
+ {
+// oc = fact->constrainedPointCalcer( parents[0], value );
+ notSupported( file, i18n( "This Dr. Geo file contains a \"%1 %2\" object, "
+ "which Kig does not currently support." ).arg( domelem.tagName() ).arg(
+ domelem.attribute( "type" ) ) );
+ return false;
+ }
+ }
+ else if ( domelem.attribute( "type" ) == "Intersection" )
+ {
+ if ( ( parents[0]->imp()->inherits( AbstractLineImp::stype() ) ) &&
+ ( parents[1]->imp()->inherits( AbstractLineImp::stype() ) ) )
+ oc = new ObjectTypeCalcer( LineLineIntersectionType::instance(), parents );
+ else
+ {
+ bool ok;
+ int which = domelem.attribute( "extra" ).toInt( &ok );
+ if ( !ok ) KIG_FILTER_PARSE_ERROR;
+ if ( which == 1 ) which = -1;
+ else if ( which == 0 ) which = 1;
+ else KIG_FILTER_PARSE_ERROR;
+ std::vector<ObjectCalcer*> args = parents;
+ const ObjectType* type = 0;
+ args.push_back( new ObjectConstCalcer( new IntImp( which ) ) );
+ if ( ( parents[0]->imp()->inherits( CircleImp::stype() ) ) &&
+ ( parents[1]->imp()->inherits( CircleImp::stype() ) ) )
+ type = CircleCircleIntersectionType::instance();
+ else if ( ( parents[0]->imp()->inherits( CircleImp::stype() ) &&
+ parents[1]->imp()->inherits( AbstractLineImp::stype() ) ) ||
+ ( parents[1]->imp()->inherits( CircleImp::stype() ) &&
+ parents[0]->imp()->inherits( AbstractLineImp::stype() ) ) )
+ type = ConicLineIntersectionType::instance();
+ else if ( ( parents[0]->imp()->inherits( ArcImp::stype() ) &&
+ parents[1]->imp()->inherits( AbstractLineImp::stype() ) ) ||
+ ( parents[1]->imp()->inherits( ArcImp::stype() ) &&
+ parents[0]->imp()->inherits( AbstractLineImp::stype() ) ) )
+ type = ArcLineIntersectionType::instance();
+ else
+ {
+ notSupported( file, i18n( "This Dr. Geo file contains an intersection type, "
+ "which Kig does not currently support." ) );
+ return false;
+ }
+ oc = new ObjectTypeCalcer( type, args );
+ }
+ }
+ else if ( domelem.attribute( "type" ) == "Reflexion" )
+ oc = new ObjectTypeCalcer( LineReflectionType::instance(), parents );
+ else if ( domelem.attribute( "type" ) == "Symmetry" )
+ oc = new ObjectTypeCalcer( PointReflectionType::instance(), parents );
+ else if ( domelem.attribute( "type" ) == "Translation" )
+ oc = new ObjectTypeCalcer( TranslatedType::instance(), parents );
+ else if ( domelem.attribute( "type" ) == "Rotation" )
+ oc = new ObjectTypeCalcer( RotationType::instance(), parents );
+ else
+ {
+ notSupported( file, i18n( "This Dr. Geo file contains a \"%1 %2\" object, "
+ "which Kig does not currently support." ).arg( domelem.tagName() ).arg(
+ domelem.attribute( "type" ) ) );
+ return false;
+ }
+#ifdef DRGEO_DEBUG
+ kdDebug() << "+++++++++ oc:" << oc << endl;
+#endif
+ }
+ else if( ( domelem.tagName() == "line" ) ||
+ ( domelem.tagName() == "halfLine" ) ||
+ ( domelem.tagName() == "segment" ) ||
+ ( domelem.tagName() == "vector" ) ||
+ ( domelem.tagName() == "circle" ) ||
+ ( domelem.tagName() == "arcCircle" ) ||
+ ( domelem.tagName() == "polygon" ) )
+ {
+ const ObjectType* type = 0;
+ if ( domelem.attribute( "type" ) == "2pts" )
+ {
+ if( domelem.tagName() == "line" )
+ type = LineABType::instance();
+ else if( domelem.tagName() == "halfLine" )
+ type = RayABType::instance();
+ else if( domelem.tagName() == "segment" )
+ type = SegmentABType::instance();
+ else if( domelem.tagName() == "vector" )
+ type = VectorType::instance();
+ else if( domelem.tagName() == "circle" )
+ type = CircleBCPType::instance();
+ else
+ {
+ notSupported( file, i18n( "This Dr. Geo file contains a \"%1 %2\" object, "
+ "which Kig does not currently support." ).arg( domelem.tagName() ).arg(
+ domelem.attribute( "type" ) ) );
+ return false;
+ }
+ oc = new ObjectTypeCalcer( type, parents );
+ }
+ else if( domelem.attribute( "type" ) == "3pts" )
+ {
+ if( domelem.tagName() == "arcCircle" )
+ type = ArcBTPType::instance();
+ else
+ {
+ notSupported( file, i18n( "This Dr. Geo file contains a \"%1 %2\" object, "
+ "which Kig does not currently support." ).arg( domelem.tagName() ).arg(
+ domelem.attribute( "type" ) ) );
+ return false;
+ }
+ oc = new ObjectTypeCalcer( type, parents );
+ }
+ else if( domelem.attribute( "type" ) == "segment" )
+ {
+ if( domelem.tagName() == "circle" )
+ {
+ type = CircleBPRType::instance();
+ ObjectPropertyCalcer* o = fact->propertyObjectCalcer( parents[1], "length" );
+ o->calc( *ret );
+ ObjectCalcer* a = parents[0];
+ parents.clear();
+ parents.push_back( a );
+ parents.push_back( o );
+ }
+ else
+ {
+ notSupported( file, i18n( "This Dr. Geo file contains a \"%1 %2\" object, "
+ "which Kig does not currently support." ).arg( domelem.tagName() ).arg(
+ domelem.attribute( "type" ) ) );
+ return false;
+ }
+ oc = new ObjectTypeCalcer( type, parents );
+ }
+ else if( domelem.attribute( "type" ) == "npts" )
+ {
+ if( domelem.tagName() == "polygon" )
+ {
+ if ( parents.size() < 3 ) KIG_FILTER_PARSE_ERROR;
+ type = PolygonBNPType::instance();
+ }
+ else
+ {
+ notSupported( file, i18n( "This Dr. Geo file contains a \"%1 %2\" object, "
+ "which Kig does not currently support." ).arg( domelem.tagName() ).arg(
+ domelem.attribute( "type" ) ) );
+ return false;
+ }
+ oc = new ObjectTypeCalcer( type, parents );
+ }
+ else if ( domelem.attribute( "type" ) == "perpendicular" )
+ oc = new ObjectTypeCalcer( LinePerpendLPType::instance(), parents );
+ else if ( domelem.attribute( "type" ) == "parallel" )
+ oc = new ObjectTypeCalcer( LineParallelLPType::instance(), parents );
+ else if ( domelem.attribute( "type" ) == "Reflexion" )
+ oc = new ObjectTypeCalcer( LineReflectionType::instance(), parents );
+ else if ( domelem.attribute( "type" ) == "Symmetry" )
+ oc = new ObjectTypeCalcer( PointReflectionType::instance(), parents );
+ else if ( domelem.attribute( "type" ) == "Translation" )
+ oc = new ObjectTypeCalcer( TranslatedType::instance(), parents );
+ else if ( domelem.attribute( "type" ) == "Rotation" )
+ oc = new ObjectTypeCalcer( RotationType::instance(), parents );
+ else
+ {
+ notSupported( file, i18n( "This Dr. Geo file contains a \"%1 %2\" object, "
+ "which Kig does not currently support." ).arg( domelem.tagName() ).arg(
+ domelem.attribute( "type" ) ) );
+ return false;
+ }
+#ifdef DRGEO_DEBUG
+ kdDebug() << "+++++++++ oc:" << oc << endl;
+#endif
+ }
+ else if( ( domelem.tagName() == "numeric" ) ||
+ ( domelem.tagName() == "equation" ) )
+ {
+ QString xs;
+ QString ys;
+ QString value;
+ for ( QDomNode c = domelem.firstChild(); ! c.isNull(); c = c.nextSibling() )
+ {
+ QDomElement ce = c.toElement();
+ if ( ce.isNull() ) continue;
+ else if ( ce.tagName() == "x" )
+ xs = ce.text();
+ else if ( ce.tagName() == "y" )
+ ys = ce.text();
+ else if ( ce.tagName() == "value" )
+ value = ce.text();
+ }
+ bool ok;
+ bool ok2;
+ double x = xs.toDouble( &ok );
+ double y = ys.toDouble( &ok2 );
+ if ( ! ( ok && ok2 ) )
+ KIG_FILTER_PARSE_ERROR;
+ Coordinate m( x, y );
+ // types of 'numeric'
+ // ugly hack to show value numerics...
+ if ( domelem.attribute( "type" ) == "value" )
+ {
+ bool ok3;
+ double dvalue = value.toDouble( &ok3 );
+ if ( ok3 )
+ value = QString( "%1" ).arg( dvalue, 0, 'g', 3 );
+ oc = fact->labelCalcer( value, m, false, std::vector<ObjectCalcer*>(), *ret );
+ }
+ else if ( domelem.attribute( "type" ) == "pt_abscissa" )
+ {
+ if ( parents.size() != 1 ) KIG_FILTER_PARSE_ERROR;
+ oc = filtersConstructTextObject( m, parents[0], "coordinate-x", *ret, false );
+ }
+ else if ( domelem.attribute( "type" ) == "pt_ordinate" )
+ {
+ if ( parents.size() != 1 ) KIG_FILTER_PARSE_ERROR;
+ oc = filtersConstructTextObject( m, parents[0], "coordinate-y", *ret, false );
+ }
+ else if ( domelem.attribute( "type" ) == "segment_length" )
+ {
+ if ( parents.size() != 1 ) KIG_FILTER_PARSE_ERROR;
+ oc = filtersConstructTextObject( m, parents[0], "length", *ret, false );
+ }
+ else if ( domelem.attribute( "type" ) == "circle_perimeter" )
+ {
+ if ( parents.size() != 1 ) KIG_FILTER_PARSE_ERROR;
+ oc = filtersConstructTextObject( m, parents[0], "circumference", *ret, false );
+ }
+ else if ( domelem.attribute( "type" ) == "arc_length" )
+ {
+ if ( parents.size() != 1 ) KIG_FILTER_PARSE_ERROR;
+ oc = filtersConstructTextObject( m, parents[0], "arc-length", *ret, false );
+ }
+ else if ( domelem.attribute( "type" ) == "distance_2pts" )
+ {
+ if ( parents.size() != 2 ) KIG_FILTER_PARSE_ERROR;
+ ObjectTypeCalcer* so = new ObjectTypeCalcer( SegmentABType::instance(), parents );
+ so->calc( *ret );
+ oc = filtersConstructTextObject( m, so, "length", *ret, false );
+ }
+ else if ( domelem.attribute( "type" ) == "vector_norm" )
+ {
+ if ( parents.size() != 1 ) KIG_FILTER_PARSE_ERROR;
+ oc = filtersConstructTextObject( m, parents[0], "length", *ret, false );
+ }
+ else if ( domelem.attribute( "type" ) == "vector_abscissa" )
+ {
+ if ( parents.size() != 1 ) KIG_FILTER_PARSE_ERROR;
+ oc = filtersConstructTextObject( m, parents[0], "length-x", *ret, false );
+ }
+ else if ( domelem.attribute( "type" ) == "vector_ordinate" )
+ {
+ if ( parents.size() != 1 ) KIG_FILTER_PARSE_ERROR;
+ oc = filtersConstructTextObject( m, parents[0], "length-y", *ret, false );
+ }
+ else if ( domelem.attribute( "type" ) == "slope" )
+ {
+ if ( parents.size() != 1 ) KIG_FILTER_PARSE_ERROR;
+ oc = filtersConstructTextObject( m, parents[0], "slope", *ret, false );
+ }
+ else if ( domelem.attribute( "type" ) == "distance_pt_line" )
+ {
+ if ( parents.size() != 2 ) KIG_FILTER_PARSE_ERROR;
+ std::vector<ObjectCalcer*> args;
+ args.push_back( parents[1] );
+ args.push_back( parents[0] );
+ ObjectTypeCalcer* po = new ObjectTypeCalcer( LinePerpendLPType::instance(), args );
+ po->calc( *ret );
+ args.clear();
+ args.push_back( parents[1] );
+ args.push_back( po );
+ ObjectTypeCalcer* io = new ObjectTypeCalcer( LineLineIntersectionType::instance(), args );
+ io->calc( *ret );
+ args.clear();
+ args.push_back( parents[0] );
+ args.push_back( io );
+ ObjectTypeCalcer* so = new ObjectTypeCalcer( SegmentABType::instance(), args );
+ so->calc( *ret );
+ oc = filtersConstructTextObject( m, so, "length", *ret, false );
+ }
+ // types of 'equation'
+ else if ( domelem.attribute( "type" ) == "line" )
+ {
+ if ( parents.size() != 1 ) KIG_FILTER_PARSE_ERROR;
+ oc = filtersConstructTextObject( m, parents[0], "equation", *ret, false );
+ }
+ else if ( domelem.attribute( "type" ) == "circle" )
+ {
+ if ( parents.size() != 1 ) KIG_FILTER_PARSE_ERROR;
+ oc = filtersConstructTextObject( m, parents[0], "simply-cartesian-equation", *ret, false );
+ }
+ else
+ {
+ notSupported( file, i18n( "This Dr. Geo file contains a \"%1 %2\" object, "
+ "which Kig does not currently support." ).arg( domelem.tagName() ).arg(
+ domelem.attribute( "type" ) ) );
+ return false;
+ }
+#ifdef DRGEO_DEBUG
+ kdDebug() << "+++++++++ oc:" << oc << endl;
+#endif
+ }
+ else if ( domelem.tagName() == "angle" )
+ {
+ if ( domelem.attribute( "type" ) == "3pts" )
+ {
+ if ( parents.size() != 3 ) KIG_FILTER_PARSE_ERROR;
+ oc = new ObjectTypeCalcer( HalfAngleType::instance(), parents );
+ }
+ else
+ {
+ notSupported( file, i18n( "This Dr. Geo file contains a \"%1 %2\" object, "
+ "which Kig does not currently support." ).arg( domelem.tagName() ).arg(
+ domelem.attribute( "type" ) ) );
+ return false;
+ }
+#ifdef DRGEO_DEBUG
+ kdDebug() << "+++++++++ oc:" << oc << endl;
+#endif
+ }
+ else if ( domelem.tagName() == "script" )
+ {
+ QString xs;
+ QString ys;
+ QString text;
+ for ( QDomNode c = domelem.firstChild(); ! c.isNull(); c = c.nextSibling() )
+ {
+ QDomElement ce = c.toElement();
+ if ( ce.isNull() ) continue;
+ else if ( ce.tagName() == "x" )
+ xs = ce.text();
+ else if ( ce.tagName() == "y" )
+ ys = ce.text();
+ else if ( ce.tagName() == "code" )
+ text = ce.text();
+ }
+ bool ok;
+ bool ok2;
+ double x = xs.toDouble( &ok );
+ double y = ys.toDouble( &ok2 );
+ if ( ! ( ok && ok2 ) )
+ KIG_FILTER_PARSE_ERROR;
+ // since Kig doesn't support Guile scripts, it will write script's text
+ // in a label, so the user can freely see the code and make whatever
+ // he/she wants
+ // possible idea: construct a new script object with the parents of Guile
+ // one and the Guile code inserted commented... depends on a better
+ // handling of arguments in scripts?
+ if ( domelem.attribute( "type" ) == "nitems" )
+ oc = fact->labelCalcer( text, Coordinate( x, y ), false, std::vector<ObjectCalcer*>(), *ret );
+ else
+ {
+ notSupported( file, i18n( "This Dr. Geo file contains a \"%1 %2\" object, "
+ "which Kig does not currently support." ).arg( domelem.tagName() ).arg(
+ domelem.attribute( "type" ) ) );
+ return false;
+ }
+ }
+ else if ( domelem.tagName() == "locus" )
+ {
+ if ( domelem.attribute( "type" ) == "None" )
+ oc = fact->locusCalcer( parents[0], parents[1] );
+ else
+ {
+ notSupported( file, i18n( "This Dr. Geo file contains a \"%1 %2\" object, "
+ "which Kig does not currently support." ).arg( domelem.tagName() ).arg(
+ domelem.attribute( "type" ) ) );
+ return false;
+ }
+#ifdef DRGEO_DEBUG
+ kdDebug() << "+++++++++ oc:" << oc << endl;
+#endif
+ }
+ else if ( ( domelem.tagName() == "boundingBox" ) ||
+ ( domelem.tagName() == "customUI" ) )
+ {
+ // ignoring these elements, since they are not useful to us...
+ nignored++;
+ }
+ else
+ {
+#ifdef DRGEO_DEBUG
+ kdDebug() << ">>>>>>>>> UNKNOWN OBJECT" << endl;
+#endif
+ notSupported( file, i18n( "This Dr. Geo file contains a \"%1 %2\" object, "
+ "which Kig does not currently support." ).arg( domelem.tagName() ).arg(
+ domelem.attribute( "type" ) ) );
+ return false;
+ }
+ curid++;
+ if ( oc == 0 )
+ continue;
+
+// reading color
+ QColor co( domelem.attribute( "color" ) );
+ if ( ! co.isValid() )
+ if ( domelem.attribute( "color" ) == "Bordeaux" )
+ co.setRgb( 145, 0, 0 );
+ else
+ co = Qt::blue;
+// reading width and style
+// Dashed -> the little one
+// Normal -> the medium
+// Thick -> the biggest one
+ int w = -1;
+ Qt::PenStyle s = Qt::SolidLine;
+ if ( domelem.tagName() == "point" )
+ {
+ if ( domelem.attribute( "thickness" ) == "Normal" )
+ w = 7;
+ else if ( domelem.attribute( "thickness" ) == "Thick" )
+ w = 9;
+ }
+ else
+ {
+ if ( domelem.attribute( "thickness" ) == "Dashed" )
+ s = Qt::DotLine;
+ if ( domelem.attribute( "thickness" ) == "Thick" )
+ w = 2;
+ }
+ QString ps = domelem.attribute( "style" );
+ int pointstyle = ObjectDrawer::pointStyleFromString( ps );
+// show this object?
+ bool show = ( ( domelem.attribute( "masked" ) != "True" ) &&
+ ( domelem.attribute( "masked" ) != "Alway" ) );
+// costructing the ObjectDrawer*
+ ObjectDrawer* d = new ObjectDrawer( co, w, show, s, pointstyle );
+// reading object name
+ QString strname = domelem.attribute( "name" );
+ ObjectConstCalcer* name = new ObjectConstCalcer( new StringImp( strname ) );
+
+// creating the ObjectHolder*
+ ObjectHolder* o = new ObjectHolder( oc, d, name );
+ holders.push_back( o );
+// calc()
+#ifdef DRGEO_DEBUG
+ kdDebug() << ">>>>>>>>> calc" << endl;
+#endif
+ holders[curid-1-nignored]->calc( *ret );
+
+ if ( domelem.tagName() == "point" )
+ {
+ if ( !strname.isEmpty() )
+ {
+ std::vector<ObjectCalcer*> args2;
+ args2.push_back( o->nameCalcer() );
+ oc2 = fact->attachedLabelCalcer( QString::fromLatin1( "%1" ), oc,
+ static_cast<const PointImp*>( oc->imp() )->coordinate(),
+ false, args2, *ret );
+ co = Qt::black;
+ }
+ }
+ else if ( domelem.tagName() == "angle" )
+ {
+ oc2 = filtersConstructTextObject(
+ static_cast<const PointImp*>( holders[curid-1-nignored]->calcer()->parents()[1]->imp() )->coordinate(),
+ holders[curid-1-nignored]->calcer(), "angle-degrees", *ret, false );
+ }
+
+ oc = 0;
+
+ if ( oc2 != 0 )
+ {
+ oc2->calc( *ret );
+ ObjectDrawer* d2 = new ObjectDrawer( co );
+ ObjectHolder* o2 = new ObjectHolder( oc2, d2 );
+ holders2.push_back( o2 );
+ oc2 = 0;
+ }
+ }
+
+ ret->addObjects( holders );
+ ret->addObjects( holders2 );
+ ret->setGrid( grid );
+ ret->setAxes( grid );
+ return ret;
+}
+
+KigFilterDrgeo* KigFilterDrgeo::instance()
+{
+ static KigFilterDrgeo f;
+ return &f;
+}
diff --git a/kig/filters/drgeo-filter.h b/kig/filters/drgeo-filter.h
new file mode 100644
index 00000000..7485fd5b
--- /dev/null
+++ b/kig/filters/drgeo-filter.h
@@ -0,0 +1,46 @@
+// Copyright (C) 2004 Pino Toscano <toscano.pino@tiscali.it>
+// Copyright (C) 2004 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_FILTERS_DRGEO_FILTER_H
+#define KIG_FILTERS_DRGEO_FILTER_H
+
+#include "filter.h"
+
+class QDomNode;
+class KigDocument;
+class QString;
+
+/**
+ * This is an import filter for the GNOME geometry program DrGeo.
+ */
+class KigFilterDrgeo
+ : public KigFilter
+{
+protected:
+ KigFilterDrgeo();
+ ~KigFilterDrgeo();
+public:
+ static KigFilterDrgeo* instance();
+
+ bool supportMime( const QString& mime );
+ KigDocument* load( const QString& file );
+private:
+ KigDocument* importFigure( QDomNode f, const QString& file, const bool grid );
+};
+
+#endif
diff --git a/kig/filters/exporter.cc b/kig/filters/exporter.cc
new file mode 100644
index 00000000..c2ece44e
--- /dev/null
+++ b/kig/filters/exporter.cc
@@ -0,0 +1,624 @@
+// Copyright (C) 2003 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.
+
+#include "exporter.h"
+
+#include "imageexporteroptions.h"
+#include "latexexporter.h"
+#include "svgexporter.h"
+
+#include "../kig/kig_document.h"
+#include "../kig/kig_part.h"
+#include "../kig/kig_view.h"
+#include "../misc/common.h"
+#include "../misc/kigfiledialog.h"
+#include "../misc/kigpainter.h"
+#include "../objects/circle_imp.h"
+#include "../objects/line_imp.h"
+#include "../objects/object_drawer.h"
+#include "../objects/object_holder.h"
+#include "../objects/object_imp.h"
+#include "../objects/other_imp.h"
+#include "../objects/point_imp.h"
+#include "../objects/text_imp.h"
+
+#include <qcheckbox.h>
+#include <qcolor.h>
+#include <qfile.h>
+#include <qiconset.h>
+#include <qtextstream.h>
+
+#include <kaction.h>
+#include <kiconloader.h>
+#include <kimageio.h>
+#include <klocale.h>
+#include <kmessagebox.h>
+#include <knuminput.h>
+
+#include <map>
+
+// we need this for storing colors in a std::map..
+static bool operator<( const QColor& a, const QColor& b )
+{
+ return a.rgb() < b.rgb();
+}
+
+class ExporterAction
+ : public KAction
+{
+ KigExporter* mexp;
+ const KigPart* mdoc;
+ KigWidget* mw;
+public:
+ ExporterAction( const KigPart* doc, KigWidget* w,
+ KActionCollection* parent, KigExporter* exp );
+ void slotActivated();
+};
+
+ExporterAction::ExporterAction( const KigPart* doc, KigWidget* w,
+ KActionCollection* parent, KigExporter* exp )
+ : KAction( exp->menuEntryName(), KShortcut(), 0, 0, parent ),
+ mexp( exp ), mdoc( doc ), mw( w )
+{
+ QString iconstr = exp->menuIcon();
+ if ( iconstr.isEmpty() )
+ return;
+ KIconLoader* l = doc->instance()->iconLoader();
+ QPixmap icon = l->loadIcon( iconstr, KIcon::Small, 16, KIcon::DefaultState, 0L, true );
+ if ( !icon.isNull() )
+ setIconSet( QIconSet( icon ) );
+}
+
+void ExporterAction::slotActivated()
+{
+ mexp->run( *mdoc, *mw );
+}
+
+KigExporter::~KigExporter()
+{
+}
+
+ImageExporter::~ImageExporter()
+{
+}
+
+QString ImageExporter::exportToStatement() const
+{
+ return i18n( "&Export to image" );
+}
+
+QString ImageExporter::menuEntryName() const
+{
+ return i18n( "&Image..." );
+}
+
+QString ImageExporter::menuIcon() const
+{
+ return "image";
+}
+
+void ImageExporter::run( const KigPart& doc, KigWidget& w )
+{
+ static bool kimageioRegistered = false;
+ if ( ! kimageioRegistered )
+ {
+ KImageIO::registerFormats();
+ kimageioRegistered = true;
+ }
+
+ KigFileDialog* kfd = new KigFileDialog(
+ QString::null, KImageIO::pattern( KImageIO::Writing ),
+ i18n( "Export as Image" ), &w );
+ kfd->setOptionCaption( i18n( "Image Options" ) );
+ ImageExporterOptions* opts = new ImageExporterOptions( 0L, w.size() );
+ kfd->setOptionsWidget( opts );
+ opts->WidthInput->setValue( w.size().width() );
+ opts->HeightInput->setValue( w.size().height() );
+ opts->showGridCheckBox->setChecked( doc.document().grid() );
+ opts->showAxesCheckBox->setChecked( doc.document().axes() );
+ if ( !kfd->exec() )
+ return;
+
+ QString filename = kfd->selectedFile();
+ bool showgrid = opts->showGridCheckBox->isOn();
+ bool showaxes = opts->showAxesCheckBox->isOn();
+ int width = opts->WidthInput->value();
+ int height = opts->HeightInput->value();
+
+ delete opts;
+ delete kfd;
+
+ QString type = KImageIO::type( filename );
+ if ( type.isNull() )
+ {
+ KMessageBox::sorry( &w, i18n( "Sorry, this file format is not supported." ) );
+ return;
+ };
+
+ kdDebug() << k_funcinfo << type << endl;
+
+ QFile file( filename );
+ if ( ! file.open( IO_WriteOnly ) )
+ {
+ KMessageBox::sorry( &w,
+ i18n( "The file \"%1\" could not be opened. Please check if the file permissions are set correctly." )
+ .arg( filename ) );
+ return;
+ };
+
+ QPixmap img( QSize( width, height ) );
+ img.fill( Qt::white );
+ KigPainter p( ScreenInfo( w.screenInfo().shownRect(), img.rect() ), &img, doc.document() );
+ p.setWholeWinOverlay();
+ p.drawGrid( doc.document().coordinateSystem(), showgrid, showaxes );
+ // FIXME: show the selections ?
+ p.drawObjects( doc.document().objects(), false );
+ if ( ! img.save( filename, type.latin1() ) )
+ {
+ KMessageBox::error( &w, i18n( "Sorry, something went wrong while saving to image \"%1\"" ).arg( filename ) );
+ }
+
+}
+
+KigExportManager::KigExportManager()
+{
+ mexporters.push_back( new ImageExporter );
+ // working on this one ;)
+ mexporters.push_back( new XFigExporter );
+ mexporters.push_back( new LatexExporter );
+ mexporters.push_back( new SVGExporter );
+}
+
+KigExportManager::~KigExportManager()
+{
+ for ( uint i = 0; i < mexporters.size(); ++i )
+ delete mexporters[i];
+}
+
+void KigExportManager::addMenuAction( const KigPart* doc, KigWidget* w,
+ KActionCollection* coll )
+{
+ KActionMenu* m =
+ new KActionMenu( i18n( "&Export To" ), coll, "file_export" );
+ for ( uint i = 0; i < mexporters.size(); ++i )
+ m->insert( new ExporterAction( doc, w, coll, mexporters[i] ) );
+}
+
+KigExportManager* KigExportManager::instance()
+{
+ static KigExportManager m;
+ return &m;
+}
+
+XFigExporter::~XFigExporter()
+{
+}
+
+QString XFigExporter::exportToStatement() const
+{
+ return i18n( "Export to &XFig file" );
+}
+
+
+QString XFigExporter::menuEntryName() const
+{
+ return i18n( "&XFig File..." );
+}
+
+QString XFigExporter::menuIcon() const
+{
+ return "kig_xfig";
+}
+
+class XFigExportImpVisitor
+ : public ObjectImpVisitor
+{
+ QTextStream& mstream;
+ ObjectHolder* mcurobj;
+ const KigWidget& mw;
+ Rect msr;
+ std::map<QColor, int> mcolormap;
+ int mnextcolorid;
+ int mcurcolorid;
+
+ QPoint convertCoord( const Coordinate& c )
+ {
+ Coordinate ret = ( c - msr.bottomLeft() );
+ ret.y = msr.height() - ret.y;
+// kdDebug() << "msr: " << msr << endl
+// << "ret: " << ret << endl
+// << "c: " << c << endl;
+ ret *= 9450;
+ ret /= msr.width();
+ return ret.toQPoint();
+ }
+
+ void emitLine( const Coordinate& a, const Coordinate& b, int width, bool vector = false );
+public:
+ void visit( ObjectHolder* obj );
+ void mapColor( const ObjectDrawer* obj );
+
+ XFigExportImpVisitor( QTextStream& s, const KigWidget& w )
+ : mstream( s ), mw( w ), msr( mw.showingRect() ),
+ mnextcolorid( 32 )
+ {
+ // predefined colors in XFig..
+ mcolormap[Qt::black] = 0;
+ mcolormap[Qt::blue] = 1;
+ mcolormap[Qt::green] = 2;
+ mcolormap[Qt::cyan] = 3;
+ mcolormap[Qt::red] = 4;
+ mcolormap[Qt::magenta] = 5;
+ mcolormap[Qt::yellow] = 6;
+ mcolormap[Qt::white] = 7;
+ }
+ void visit( const LineImp* imp );
+ void visit( const PointImp* imp );
+ void visit( const TextImp* imp );
+ void visit( const AngleImp* imp );
+ void visit( const VectorImp* imp );
+ void visit( const LocusImp* imp );
+ void visit( const CircleImp* imp );
+ void visit( const ConicImp* imp );
+ void visit( const CubicImp* imp );
+ void visit( const SegmentImp* imp );
+ void visit( const RayImp* imp );
+ void visit( const ArcImp* imp );
+};
+
+void XFigExportImpVisitor::mapColor( const ObjectDrawer* obj )
+{
+ if ( ! obj->shown() ) return;
+ QColor color = obj->color();
+ if ( mcolormap.find( color ) == mcolormap.end() )
+ {
+ int newcolorid = mnextcolorid++;
+ mstream << "0 "
+ << newcolorid << " "
+ << color.name() << "\n";
+ mcolormap[color] = newcolorid;
+ }
+}
+
+void XFigExportImpVisitor::visit( ObjectHolder* obj )
+{
+ if ( ! obj->drawer()->shown() ) return;
+ assert( mcolormap.find( obj->drawer()->color() ) != mcolormap.end() );
+ mcurcolorid = mcolormap[ obj->drawer()->color() ];
+ mcurobj = obj;
+ obj->imp()->visit( this );
+}
+
+void XFigExportImpVisitor::visit( const LineImp* imp )
+{
+ Coordinate a = imp->data().a;
+ Coordinate b = imp->data().b;
+ calcBorderPoints( a, b, msr );
+ int width = mcurobj->drawer()->width();
+ if ( width == -1 ) width = 1;
+
+ if ( a != b )
+ emitLine( a, b, width );
+}
+
+void XFigExportImpVisitor::emitLine( const Coordinate& a, const Coordinate& b, int width, bool vector )
+{
+ mstream << "2 "; // polyline type;
+ mstream << "1 "; // polyline subtype;
+ mstream << "0 "; // line_style: Solid
+ mstream << width << " "; // thickness: *1/80 inch
+ mstream << mcurcolorid << " "; // pen_color: default
+ mstream << "7 "; // fill_color: white
+ mstream << "50 "; // depth: 50
+ mstream << "-1 "; // pen_style: unused by XFig
+ mstream << "-1 "; // area_fill: no fill
+ mstream << "0.000 "; // style_val: the distance between dots and
+ // dashes in case of dotted or dashed lines..
+ mstream << "0 "; // join_style: Miter
+ mstream << "0 "; // cap_style: Butt
+ mstream << "-1 "; // radius in case of an arc-box, but we're a
+ // polyline, so nothing here..
+ if ( ! vector )
+ mstream << "0 "; // forward arrow: no
+ else
+ mstream << "1 "; // forward arrow: yes
+ mstream << "0 "; // backward arrow: no
+ mstream << "2"; // a two points polyline..
+
+ mstream << "\n\t ";
+
+ if ( vector )
+ {
+ // first the arrow line in case of a vector..
+ mstream << "1 " // arrow_type: closed triangle
+ << "1 " // arrow_style: filled with pen color..
+ << "1.00 " // arrow_thickness: 1
+ << "195.00 " // arrow_width
+ << "165.00 " // arrow_height
+ << "\n\t";
+ }
+ QPoint ca = convertCoord( a );
+ QPoint cb = convertCoord( b );
+
+ mstream << ca.x() << " " << ca.y() << " " << cb.x() << " " << cb.y() << "\n";
+}
+
+void XFigExportImpVisitor::visit( const PointImp* imp )
+{
+ const QPoint center = convertCoord( imp->coordinate() );
+ int width = mcurobj->drawer()->width();
+ if ( width == -1 ) width = 5;
+ width *= 10;
+
+ mstream << "1 " // Ellipse type
+ << "3 " // circle defined by radius subtype
+ << "0 "; // line_style: Solid
+ mstream << "1 " << " " // thickness: *1/80 inch
+ << mcurcolorid << " " // pen_color: default
+ << mcurcolorid << " " // fill_color: black
+ << "50 " // depth: 50
+ << "-1 " // pen_style: unused by XFig
+ << "20 " // area_fill: full saturation of the fill color
+ << "0.000 " // style_val: the distance between dots and
+ // dashes in case of dotted or dashed lines..
+ << "1 " // direction: always 1
+ << "0.0000 " // angle: the radius of the x-axis: 0
+ << center.x() << " " << center.y() << " " // the center..
+ << width << " " << width << " " // radius_x and radius_y
+ << center.x() << " " // start_x and start_y, appear
+ << center.y() << " " // unused..
+ << center.x() + width << " " // end_x and end_y,
+ << center.y() << "\n"; // appear unused too...
+}
+
+void XFigExportImpVisitor::visit( const TextImp* imp )
+{
+ QString text = imp->text();
+ QPoint coord = convertCoord( imp->surroundingRect().bottomLeft() );
+
+ mstream << "4 " // text type
+ << "0 " // subtype: left justfied
+ << mcurcolorid << " " // color: black
+ << "50 " // depth: 50
+ << "-1 " // pen style: unused
+ << "0 " // font: default
+ << "11 " // font-size: 11
+ << "0 " // angle
+ << "0 " // font-flags: all the defaults..
+ << "500 500 " // height, width: large enough..
+ << coord.x() << " " // x, y
+ << coord.y() << " "
+ << text.ascii() << "\\001" // text, terminated by \001
+ << "\n";
+}
+
+void XFigExportImpVisitor::visit( const AngleImp* )
+{
+}
+
+void XFigExportImpVisitor::visit( const VectorImp* imp )
+{
+ int width = mcurobj->drawer()->width();
+ if ( width == -1 ) width = 1;
+ emitLine( imp->a(), imp->b(), width, true );
+}
+
+void XFigExportImpVisitor::visit( const LocusImp* )
+{
+
+}
+
+void XFigExportImpVisitor::visit( const CircleImp* imp )
+{
+ const QPoint center = convertCoord( imp->center() );
+ const int radius =
+ ( convertCoord( imp->center() + Coordinate( imp->radius(), 0 ) ) - center ).x();
+
+ mstream << "1 " // Ellipse type
+ << "3 " // circle defined by radius subtype
+ << "0 "; // line_style: Solid
+ int width = mcurobj->drawer()->width();
+ if ( width == -1 ) width = 1;
+ mstream << width << " " // thickness: *1/80 inch
+ << mcurcolorid << " " // pen_color: default
+ << "7 " // fill_color: white
+ << "50 " // depth: 50
+ << "-1 " // pen_style: unused by XFig
+ << "-1 " // area_fill: no fill
+ << "0.000 " // style_val: the distance between dots and
+ // dashes in case of dotted or dashed lines..
+ << "1 " // direction: always 1
+ << "0.0000 " // angle: the radius of the x-axis: 0
+ << center.x() << " " << center.y() << " " // the center..
+ << radius << " " << radius << " " // radius_x and radius_y
+ << center.x() << " " // start_x and start_y, appear
+ << center.y() << " " // unused..
+ << center.x() + radius << " " // end_x and end_y,
+ << center.y() << "\n"; // appear unused too...
+}
+
+void XFigExportImpVisitor::visit( const ConicImp* imp )
+{
+ int width = mcurobj->drawer()->width();
+ if ( width == -1 ) width = 1;
+ if ( imp->conicType() == 1 )
+ {
+ // an ellipse, this is good, cause this allows us to export to a
+ // real ellipse type..
+ const ConicPolarData data = imp->polarData();
+
+ // gather some necessary data..
+ // the angle of the x axis..
+ double anglex = atan2( data.esintheta0, data.ecostheta0 );
+ // the exentricity
+ double e = hypot( data.esintheta0, data.ecostheta0 );
+ // the x radius is easy to find..
+ double radiusx = data.pdimen / ( 1 - e * e );
+ // the y radius is a bit harder: we first find the distance from
+ // the focus point to the mid point of the two focuses, this is:
+ double d = -e * data.pdimen / ( 1 - e * e );
+ // the distance from the first focus to the intersection of the
+ // second axis with the conic equals radiusx:
+ double r = radiusx;
+ double radiusy = sqrt( r*r - d*d );
+
+ Coordinate center = data.focus1 - Coordinate( cos( anglex ), sin( anglex ) ).normalize( d );
+ const QPoint qcenter = convertCoord( center );
+ const int radius_x = ( convertCoord( center + Coordinate( radiusx, 0 ) ) -
+ convertCoord( center ) ).x();
+ const int radius_y = ( convertCoord( center + Coordinate( radiusy, 0 ) ) -
+ convertCoord( center ) ).x();
+ const QPoint qpoint2 = convertCoord( center + Coordinate( -sin( anglex ), cos( anglex ) ) * radiusy );
+
+ mstream << "1 " // ellipse type
+ << "1 " // subtype: ellipse defined by readii
+ << "0 " // line_style: Solid
+ << width << " " // thickness
+ << mcurcolorid << " " // pen_color: black
+ << "7 " // fill_color: white
+ << "50 " // depth: 50
+ << "-1 " // pan_style: not used
+ << "-1 " // area_fill: no fill
+ << "0.000 " // style_val: not used
+ << "1 " // direction: always 1
+ << anglex << " " // angle of the main axis
+ << qcenter.x() << " " // center
+ << qcenter.y() << " "
+ << radius_x << " " // radiuses
+ << radius_y << " "
+ << qcenter.x() << " " // start point
+ << qcenter.y() << " "
+ << qpoint2.x() << " " // end point
+ << qpoint2.y() << " ";
+ }
+ else return;
+}
+
+void XFigExportImpVisitor::visit( const CubicImp* )
+{
+}
+
+void XFigExportImpVisitor::visit( const SegmentImp* imp )
+{
+ Coordinate a = imp->data().a;
+ Coordinate b = imp->data().b;
+ int width = mcurobj->drawer()->width();
+ if ( width == -1 ) width = 1;
+
+ emitLine( a, b, width );
+}
+
+void XFigExportImpVisitor::visit( const RayImp* imp )
+{
+ Coordinate a = imp->data().a;
+ Coordinate b = imp->data().b;
+ calcRayBorderPoints( a, b, msr );
+
+ int width = mcurobj->drawer()->width();
+ if ( width == -1 ) width = 1;
+
+ emitLine( a, b, width );
+}
+
+void XFigExportImpVisitor::visit( const ArcImp* imp )
+{
+ const Coordinate center = imp->center();
+ const double radius = imp->radius();
+ const double startangle = imp->startAngle();
+ const double endangle = startangle + imp->angle();
+ const double middleangle = ( startangle + endangle ) / 2;
+ const Coordinate ad = Coordinate( cos( startangle ), sin( startangle ) ).normalize( radius );
+ const Coordinate bd = Coordinate( cos( middleangle ), sin( middleangle ) ).normalize( radius );
+ const Coordinate cd = Coordinate( cos( endangle ), sin( endangle ) ).normalize( radius );
+ const QPoint a = convertCoord( center + ad );
+ const QPoint b = convertCoord( center + bd );
+ const QPoint c = convertCoord( center + cd );
+ const QPoint cent = convertCoord( center );
+
+ mstream << "5 " // Ellipse type
+ << "1 " // subtype: open ended arc
+ << "0 "; // line_style: Solid
+ int width = mcurobj->drawer()->width();
+ if ( width == -1 ) width = 1;
+ mstream << width << " " // thickness: *1/80 inch
+ << mcurcolorid << " " // pen_color: default
+ << "7 " // fill_color: white
+ << "50 " // depth: 50
+ << "-1 " // pen_style: unused by XFig
+ << "-1 " // area_fill: no fill
+ << "0.000 " // style_val: the distance between dots and
+ // dashes in case of dotted or dashed lines..
+ << "0 "; // cap_style: Butt..
+ // 0 is clockwise, 1 is counterclockwise .
+ int direction = imp->angle() > 0 ? 1 : 0;
+ // direction next
+ mstream << direction << " " // direction..
+ << "0 " // forward_arrow: no
+ << "0 " // backward_arrow: no
+ << cent.x() << " " << cent.y() << " " // the center..
+ << a.x() << " " << a.y() << " " // x1, y1
+ << b.x() << " " << b.y() << " " // x2, y2
+ << c.x() << " " << c.y() << " " // x3, y3
+ << "\n";
+}
+
+void XFigExporter::run( const KigPart& doc, KigWidget& w )
+{
+ KigFileDialog* kfd = new KigFileDialog(
+ ":document", i18n( "*.fig|XFig Documents (*.fig)" ),
+ i18n( "Export as XFig File" ), &w );
+ if ( !kfd->exec() )
+ return;
+
+ QString file_name = kfd->selectedFile();
+
+ delete kfd;
+
+ QFile file( file_name );
+ if ( ! file.open( IO_WriteOnly ) )
+ {
+ KMessageBox::sorry( &w, i18n( "The file \"%1\" could not be opened. Please "
+ "check if the file permissions are set correctly." )
+ .arg( file_name ) );
+ return;
+ };
+ QTextStream stream( &file );
+ stream << "#FIG 3.2\n";
+ stream << "Landscape\n";
+ stream << "Center\n";
+ stream << "Metric\n";
+ stream << "A4\n";
+ stream << "100.00\n";
+ stream << "Single\n";
+ stream << "-2\n";
+ stream << "1200 2\n";
+
+ std::vector<ObjectHolder*> os = doc.document().objects();
+ XFigExportImpVisitor visitor( stream, w );
+
+ for ( std::vector<ObjectHolder*>::const_iterator i = os.begin();
+ i != os.end(); ++i )
+ {
+ visitor.mapColor( ( *i )->drawer() );
+ };
+
+ for ( std::vector<ObjectHolder*>::const_iterator i = os.begin();
+ i != os.end(); ++i )
+ {
+ visitor.visit( *i );
+ };
+}
diff --git a/kig/filters/exporter.h b/kig/filters/exporter.h
new file mode 100644
index 00000000..4fc74453
--- /dev/null
+++ b/kig/filters/exporter.h
@@ -0,0 +1,102 @@
+// Copyright (C) 2003 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_FILTERS_EXPORTER_H
+#define KIG_FILTERS_EXPORTER_H
+
+#include <vector>
+
+class QString;
+class KigDocument;
+class KigPart;
+class KigWidget;
+class KActionCollection;
+
+class KigExporter;
+
+class KigExportManager
+{
+ std::vector<KigExporter*> mexporters;
+ KigExportManager();
+ ~KigExportManager();
+public:
+ static KigExportManager* instance();
+ void addMenuAction( const KigPart* doc, KigWidget* w,
+ KActionCollection* coll );
+};
+
+/**
+ * Base class for a Kig exporter.
+ *
+ * Subclass it and implement its methods to have it working.
+ */
+class KigExporter
+{
+public:
+ virtual ~KigExporter();
+
+ /**
+ * Returns a statement like i18n( "Export to image" )
+ */
+ virtual QString exportToStatement() const = 0;
+ /**
+ * Returns a string like i18n( "Image..." )
+ */
+ virtual QString menuEntryName() const = 0;
+ /**
+ * Returns a string with the name of the icon
+ */
+ virtual QString menuIcon() const = 0;
+
+ /**
+ * Do what you need to do. It's up to the individual exporters to
+ * ask the user for which file to export to etc., because they can
+ * do a much better job at that..
+ */
+ virtual void run( const KigPart& doc, KigWidget& w ) = 0;
+};
+
+/**
+ * This exporter takes care of the "Export to Image" stuff..
+ */
+class ImageExporter
+ : public KigExporter
+{
+public:
+ ~ImageExporter();
+ QString exportToStatement() const;
+ QString menuEntryName() const;
+ QString menuIcon() const;
+ void run( const KigPart& doc, KigWidget& w );
+};
+
+/**
+ * Guess what this one does ;)
+ * It exports to the XFig file format, as documented in the file
+ * FORMAT3.2 in the XFig source distribution.
+ */
+class XFigExporter
+ : public KigExporter
+{
+public:
+ ~XFigExporter();
+ QString exportToStatement() const;
+ QString menuEntryName() const;
+ QString menuIcon() const;
+ void run( const KigPart& doc, KigWidget& w );
+};
+#endif
diff --git a/kig/filters/filter.cc b/kig/filters/filter.cc
new file mode 100644
index 00000000..70290e8a
--- /dev/null
+++ b/kig/filters/filter.cc
@@ -0,0 +1,114 @@
+/**
+ This file is part of Kig, a KDE program for Interactive Geometry...
+ 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
+**/
+
+#include "filter.h"
+
+#include "kgeo-filter.h"
+#include "cabri-filter.h"
+#include "native-filter.h"
+#include "kseg-filter.h"
+#include "drgeo-filter.h"
+
+#include <kmessagebox.h>
+#include <klocale.h>
+
+KigFilters* KigFilters::sThis;
+
+KigFilter* KigFilters::find(const QString& mime)
+{
+ for (vect::iterator i = mFilters.begin(); i != mFilters.end(); ++i)
+ {
+ if ((*i)->supportMime(mime)) return *i;
+ };
+ return 0;
+}
+
+KigFilters::KigFilters()
+{
+ mFilters.push_back( KigFilterKGeo::instance() );
+ mFilters.push_back( KigFilterKSeg::instance() );
+ mFilters.push_back( KigFilterCabri::instance() );
+ mFilters.push_back( KigFilterNative::instance() );
+ mFilters.push_back( KigFilterDrgeo::instance() );
+}
+
+KigFilters* KigFilters::instance()
+{
+ return sThis ? sThis : ( sThis = new KigFilters() );
+}
+
+KigFilter::KigFilter()
+{
+}
+
+KigFilter::~KigFilter()
+{
+}
+
+bool KigFilter::supportMime( const QString& )
+{
+ return false;
+}
+
+void KigFilter::fileNotFound( const QString& file ) const
+{
+ KMessageBox::sorry( 0,
+ i18n( "The file \"%1\" could not be opened. "
+ "This probably means that it does not "
+ "exist, or that it cannot be opened due to "
+ "its permissions" ).arg( file ) );
+}
+
+void KigFilter::parseError( const QString& file, const QString& explanation ) const
+{
+ const QString text =
+ i18n( "An error was encountered while parsing the file \"%1\". It "
+ "cannot be opened." ).arg( file );
+ const QString title = i18n( "Parse Error" );
+
+ if ( explanation.isNull() )
+ KMessageBox::sorry( 0, text, title );
+ else
+ KMessageBox::detailedSorry( 0, text, explanation, title );
+}
+
+void KigFilter::notSupported( const QString& file, const QString& explanation ) const
+{
+ KMessageBox::detailedSorry( 0,
+ i18n( "Kig cannot open the file \"%1\"." ).arg( file ),
+ explanation, i18n( "Not Supported" ) );
+}
+
+void KigFilter::warning( const QString& explanation ) const
+{
+ KMessageBox::information( 0, explanation );
+}
+
+bool KigFilters::save( const KigDocument& data, const QString& tofile )
+{
+ return KigFilterNative::instance()->save( data, tofile );
+}
+
+/*
+bool KigFilters::save( const KigDocument& data, QTextStream& stream )
+{
+ return KigFilterNative::instance()->save( data, stream );
+}
+*/
diff --git a/kig/filters/filter.h b/kig/filters/filter.h
new file mode 100644
index 00000000..f5d8b0f9
--- /dev/null
+++ b/kig/filters/filter.h
@@ -0,0 +1,96 @@
+// This file is part of Kig, a KDE program for Interactive Geometry...
+// 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 FILTER_H
+#define FILTER_H
+
+#include <qstring.h>
+
+#include <vector>
+
+class KigFilter;
+class ScreenInfo;
+class KigDocument;
+
+/**
+ * This singleton class handles all the input filters.
+ */
+class KigFilters
+{
+public:
+ static KigFilters* instance();
+ KigFilter* find (const QString& mime);
+
+// bool save ( const KigDocument& data, QTextStream& stream );
+ /**
+ * saving is always done with the native filter. We don't support
+ * output filters..
+ */
+ bool save ( const KigDocument& data, const QString& outfile );
+protected:
+ KigFilters();
+ static KigFilters* sThis;
+ typedef std::vector<KigFilter*> vect;
+ vect mFilters;
+};
+
+// KigFilter::load functions should use this macro to conveniently
+// return a very useful parse error in a filter's load function..
+#define KIG_FILTER_PARSE_ERROR \
+ { \
+ QString locs = i18n( "An error was encountered at " \
+ "line %1 in file %2." ) \
+ .arg( __LINE__ ).arg( __FILE__ ); \
+ parseError( file, locs ); \
+ return 0; \
+ }
+
+/**
+ * This is the base class for an input filter.
+ *
+ * All the needed work to add a new input filter to Kig is
+ * subclassing this class and implement supportMime() and load().
+ */
+class KigFilter
+{
+protected:
+ // shows errors to the user..
+ void fileNotFound( const QString& file ) const;
+ void parseError( const QString& file, const QString& explanation = QString::null ) const;
+ void notSupported( const QString& file, const QString& explanation ) const;
+ void warning( const QString& explanation ) const;
+public:
+ KigFilter();
+ virtual ~KigFilter();
+
+ /**
+ * can the filter handle the mimetype \p mime ?
+ */
+ virtual bool supportMime ( const QString& mime );
+
+ /**
+ * load file \p fromfile and build a KigDocument from it.. If this
+ * function returns 0, that means that an error occurred while
+ * loading ( implementations of this function are responsible for
+ * showing an error message themselves, using the above error
+ * functions ). If this functions returns non-0, the caller owns
+ * the returned KigDocument ( that was allocated with "new" ).
+ */
+ virtual KigDocument* load ( const QString& fromfile ) = 0;
+};
+#endif
diff --git a/kig/filters/filters-common.cc b/kig/filters/filters-common.cc
new file mode 100644
index 00000000..d25c2e14
--- /dev/null
+++ b/kig/filters/filters-common.cc
@@ -0,0 +1,39 @@
+// Copyright (C) 2004 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.
+
+#include "filters-common.h"
+
+#include <vector>
+
+#include <qcstring.h>
+#include <qstring.h>
+
+#include "../objects/object_calcer.h"
+#include "../objects/object_factory.h"
+
+ObjectTypeCalcer* filtersConstructTextObject(
+ const Coordinate& c, ObjectCalcer* o,
+ const QCString& arg, const KigDocument& doc, bool needframe )
+{
+ const ObjectFactory* fact = ObjectFactory::instance();
+ ObjectCalcer* propo = fact->propertyObjectCalcer( o, arg );
+ propo->calc( doc );
+ std::vector<ObjectCalcer*> args;
+ args.push_back( propo );
+ return fact->labelCalcer( QString::fromLatin1( "%1" ), c, needframe,
+ args, doc );
+}
diff --git a/kig/filters/filters-common.h b/kig/filters/filters-common.h
new file mode 100644
index 00000000..c46facc4
--- /dev/null
+++ b/kig/filters/filters-common.h
@@ -0,0 +1,30 @@
+// Copyright (C) 2004 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.
+
+class ObjectTypeCalcer;
+class Coordinate;
+class ObjectCalcer;
+class QCString;
+class KigDocument;
+
+/**
+ * constructs a text object with text "%1", location \p c, and variable
+ * parts given by the argument \p arg of obj \p o.
+ */
+ObjectTypeCalcer* filtersConstructTextObject(
+ const Coordinate& c, ObjectCalcer* o,
+ const QCString& arg, const KigDocument& doc, bool needframe );
diff --git a/kig/filters/imageexporteroptions.cc b/kig/filters/imageexporteroptions.cc
new file mode 100644
index 00000000..cb996926
--- /dev/null
+++ b/kig/filters/imageexporteroptions.cc
@@ -0,0 +1,57 @@
+// 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.
+
+#include "imageexporteroptions.h"
+#include "imageexporteroptions.moc"
+
+#include <qcheckbox.h>
+#include <qsize.h>
+
+#include <knuminput.h>
+
+ImageExporterOptions::ImageExporterOptions( QWidget* parent, const QSize& s )
+ : ImageExporterOptionsBase( parent, "imageexporteroptions" ), msize( s ),
+ minternallysettingstuff( false )
+{
+ keepAspectRatio->setChecked( true );
+ connect( WidthInput, SIGNAL( valueChanged( int ) ), this, SLOT( slotWidthChanged( int ) ) );
+ connect( HeightInput, SIGNAL( valueChanged( int ) ), this, SLOT( slotHeightChanged( int ) ) );
+}
+
+ImageExporterOptions::~ImageExporterOptions()
+{
+}
+
+void ImageExporterOptions::slotWidthChanged( int w )
+{
+ if ( ! minternallysettingstuff && keepAspectRatio->isOn() )
+ {
+ minternallysettingstuff = true;
+ HeightInput->setValue( w * msize.height() / msize.width() );
+ minternallysettingstuff = false;
+ };
+}
+
+void ImageExporterOptions::slotHeightChanged( int h )
+{
+ if ( ! minternallysettingstuff && keepAspectRatio->isOn() )
+ {
+ minternallysettingstuff = true;
+ WidthInput->setValue( h * msize.width() / msize.height() );
+ minternallysettingstuff = false;
+ };
+}
diff --git a/kig/filters/imageexporteroptions.h b/kig/filters/imageexporteroptions.h
new file mode 100644
index 00000000..1ef6a855
--- /dev/null
+++ b/kig/filters/imageexporteroptions.h
@@ -0,0 +1,45 @@
+// 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_FILTERS_IMAGEEXPORTEROPTIONS_H
+#define KIG_FILTERS_IMAGEEXPORTEROPTIONS_H
+
+#include "imageexporteroptionsbase.h"
+
+class QSize;
+
+class ImageExporterOptions
+ : public ImageExporterOptionsBase
+{
+ Q_OBJECT
+
+ QSize msize;
+
+ // this is set by slotWidthChanged() when they set the other input
+ // widget's value, to avoid reacting to internal changes to the
+ // value like to user changes...
+ bool minternallysettingstuff;
+public:
+ ImageExporterOptions( QWidget* parent, const QSize& s );
+ ~ImageExporterOptions();
+
+protected slots:
+ void slotWidthChanged( int );
+ void slotHeightChanged( int );
+};
+
+#endif
diff --git a/kig/filters/imageexporteroptionsbase.ui b/kig/filters/imageexporteroptionsbase.ui
new file mode 100644
index 00000000..03145dec
--- /dev/null
+++ b/kig/filters/imageexporteroptionsbase.ui
@@ -0,0 +1,152 @@
+<!DOCTYPE UI><UI version="3.1" stdsetdef="1">
+<class>ImageExporterOptionsBase</class>
+<widget class="QWidget">
+ <property name="name">
+ <cstring>ImageExporterOptionsBase</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>400</width>
+ <height>250</height>
+ </rect>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <widget class="QGroupBox">
+ <property name="name">
+ <cstring>groupBox1</cstring>
+ </property>
+ <property name="title">
+ <string>Resolution</string>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>Layout2_2</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>WidthLabel_2</cstring>
+ </property>
+ <property name="text">
+ <string>Width:</string>
+ </property>
+ </widget>
+ <widget class="KIntNumInput">
+ <property name="name">
+ <cstring>WidthInput</cstring>
+ </property>
+ <property name="minValue">
+ <number>1</number>
+ </property>
+ <property name="suffix">
+ <string> pixels</string>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>Layout3_2</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>HeightLabel_2</cstring>
+ </property>
+ <property name="text">
+ <string>Height:</string>
+ </property>
+ </widget>
+ <widget class="KIntNumInput">
+ <property name="name">
+ <cstring>HeightInput</cstring>
+ </property>
+ <property name="minValue">
+ <number>1</number>
+ </property>
+ <property name="suffix">
+ <string> pixels</string>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ <widget class="QCheckBox">
+ <property name="name">
+ <cstring>keepAspectRatio</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Keep aspect ratio</string>
+ </property>
+ </widget>
+ </vbox>
+ </widget>
+ <widget class="QGroupBox">
+ <property name="name">
+ <cstring>groupBox2</cstring>
+ </property>
+ <property name="title">
+ <string>Options</string>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QCheckBox" row="0" column="0">
+ <property name="name">
+ <cstring>showGridCheckBox</cstring>
+ </property>
+ <property name="text">
+ <string>Show grid</string>
+ </property>
+ </widget>
+ <widget class="QCheckBox" row="0" column="1">
+ <property name="name">
+ <cstring>showAxesCheckBox</cstring>
+ </property>
+ <property name="text">
+ <string>Show axes</string>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ </vbox>
+</widget>
+<layoutdefaults spacing="6" margin="11"/>
+<includehints>
+ <includehint>knuminput.h</includehint>
+ <includehint>knuminput.h</includehint>
+</includehints>
+</UI>
diff --git a/kig/filters/kgeo-filter.cc b/kig/filters/kgeo-filter.cc
new file mode 100644
index 00000000..da26457d
--- /dev/null
+++ b/kig/filters/kgeo-filter.cc
@@ -0,0 +1,374 @@
+/**
+ This file is part of Kig, a KDE program for Interactive Geometry...
+ 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
+**/
+
+#include "kgeo-filter.h"
+
+#include "kgeo-resource.h"
+#include "filters-common.h"
+
+#include "../kig/kig_part.h"
+#include "../kig/kig_document.h"
+#include "../objects/angle_type.h"
+#include "../objects/bogus_imp.h"
+#include "../objects/circle_imp.h"
+#include "../objects/circle_type.h"
+#include "../objects/intersection_types.h"
+#include "../objects/line_type.h"
+#include "../objects/object_calcer.h"
+#include "../objects/object_drawer.h"
+#include "../objects/object_factory.h"
+#include "../objects/object_holder.h"
+#include "../objects/other_type.h"
+#include "../objects/point_imp.h"
+#include "../objects/point_type.h"
+#include "../objects/text_type.h"
+#include "../objects/transform_types.h"
+#include "../objects/vector_type.h"
+
+#include <ksimpleconfig.h>
+
+#include <algorithm>
+#include <functional>
+
+bool KigFilterKGeo::supportMime( const QString& mime )
+{
+ return mime == "application/x-kgeo";
+}
+
+KigDocument* KigFilterKGeo::load( const QString& sFrom )
+{
+ // kgeo uses a KSimpleConfig to save its contents...
+ KSimpleConfig config ( sFrom );
+
+ loadMetrics ( &config );
+ return loadObjects ( sFrom, &config );
+}
+
+void KigFilterKGeo::loadMetrics(KSimpleConfig* c )
+{
+ c->setGroup("Main");
+ xMax = c->readNumEntry("XMax", 16);
+ yMax = c->readNumEntry("YMax", 11);
+ grid = c->readBoolEntry( "Grid", true );
+ axes = c->readBoolEntry( "Axes", true );
+ // the rest is not relevant to us (yet ?)...
+}
+
+struct KGeoHierarchyElement
+{
+ int id;
+ std::vector<int> parents;
+};
+
+static void visitElem( std::vector<KGeoHierarchyElement>& ret,
+ const std::vector<KGeoHierarchyElement>& elems,
+ std::vector<bool>& seen,
+ int i )
+{
+ if ( !seen[i] )
+ {
+ for ( uint j = 0; j < elems[i].parents.size(); ++j )
+ visitElem( ret, elems, seen, elems[i].parents[j] );
+ ret.push_back( elems[i] );
+ seen[i] = true;
+ };
+}
+
+static std::vector<KGeoHierarchyElement> sortElems( const std::vector<KGeoHierarchyElement> elems )
+{
+ std::vector<KGeoHierarchyElement> ret;
+ std::vector<bool> seenElems( elems.size(), false );
+ for ( uint i = 0; i < elems.size(); ++i )
+ visitElem( ret, elems, seenElems, i );
+ return ret;
+}
+
+KigDocument* KigFilterKGeo::loadObjects( const QString& file, KSimpleConfig* c )
+{
+ KigDocument* ret = new KigDocument();
+
+ using namespace std;
+
+ QString group;
+ bool ok = true;
+ c->setGroup("Main");
+ int number = c->readNumEntry ("Number");
+
+ // first we determine the parent relationships, and sort the
+ // elements in an order that we can be sure all of an object's
+ // parents will have been handled before it is handled itself..
+ // ( aka topological sort of the parent relations graph..
+ std::vector<KGeoHierarchyElement> elems;
+ elems.reserve( number );
+
+ for ( int i = 0; i < number; ++i )
+ {
+ KGeoHierarchyElement elem;
+ elem.id = i;
+ group.setNum( i + 1 );
+ group.prepend( "Object " );
+ c->setGroup( group );
+ QStrList parents;
+ c->readListEntry( "Parents", parents );
+ elems.push_back( elem );
+ for ( const char* parent = parents.first(); parent; parent = parents.next() )
+ {
+ int parentIndex = QString::fromLatin1( parent ).toInt( &ok );
+ if ( ! ok ) KIG_FILTER_PARSE_ERROR;
+ if ( parentIndex != 0 )
+ elems[i].parents.push_back( parentIndex - 1 );
+ };
+ };
+
+ std::vector<KGeoHierarchyElement> sortedElems = sortElems( elems );
+ std::vector<ObjectHolder*> os;
+ os.resize( number, 0 );
+ const ObjectFactory* factory = ObjectFactory::instance();
+
+ // now we iterate over the elems again in the newly determined
+ // order..
+ for ( uint i = 0; i < sortedElems.size(); ++i )
+ {
+ const KGeoHierarchyElement& e = sortedElems[i];
+ int id = e.id;
+ group.setNum( id + 1 );
+ group.prepend( "Object " );
+ c->setGroup( group );
+ int objID = c->readNumEntry( "Geo" );
+
+ std::vector<ObjectCalcer*> parents;
+ for ( uint j = 0; j < e.parents.size(); ++j )
+ {
+ int parentid = e.parents[j];
+ parents.push_back( os[parentid]->calcer() );
+ };
+
+ ObjectCalcer* o = 0;
+ switch (objID)
+ {
+ case ID_point:
+ {
+ // fetch the coordinates...
+ QString strX = c->readEntry("QPointX");
+ QString strY = c->readEntry("QPointY");
+ double x = strX.toDouble(&ok);
+ if (!ok) KIG_FILTER_PARSE_ERROR;
+ double y = strY.toDouble(&ok);
+ if (!ok) KIG_FILTER_PARSE_ERROR;
+ Coordinate m( x, y );
+ uint nparents = parents.size();
+ if ( nparents == 0 )
+ o = factory->fixedPointCalcer( m );
+ else if ( nparents == 1 )
+ o = factory->constrainedPointCalcer( parents[0], m, *ret );
+ else
+ KIG_FILTER_PARSE_ERROR;
+ break;
+ }
+ case ID_segment:
+ {
+ o = new ObjectTypeCalcer( SegmentABType::instance(), parents );
+ break;
+ }
+ case ID_circle:
+ {
+ o = new ObjectTypeCalcer( CircleBCPType::instance(), parents );
+ break;
+ }
+ case ID_line:
+ {
+ o = new ObjectTypeCalcer( LineABType::instance(), parents );
+ break;
+ }
+ case ID_bisection:
+ {
+ // if this is the bisection of two points, first build a segment
+ // between them..
+ if ( parents.size() == 2 )
+ {
+ ObjectTypeCalcer* seg = new ObjectTypeCalcer( SegmentABType::instance(), parents );
+ parents.clear();
+ parents.push_back( seg );
+ }
+ if ( parents.size() != 1 ) KIG_FILTER_PARSE_ERROR;
+ o = factory->propertyObjectCalcer( parents[0], "mid-point" );
+ break;
+ };
+ case ID_perpendicular:
+ {
+ o = new ObjectTypeCalcer( LinePerpendLPType::instance(), parents );
+ break;
+ }
+ case ID_parallel:
+ {
+ o = new ObjectTypeCalcer( LineParallelLPType::instance(), parents );
+ break;
+ }
+ case ID_vector:
+ {
+ o = new ObjectTypeCalcer( VectorType::instance(), parents );
+ break;
+ }
+ case ID_ray:
+ {
+ o = new ObjectTypeCalcer( RayABType::instance(), parents );
+ break;
+ }
+ case ID_move:
+ {
+ o = new ObjectTypeCalcer( TranslatedType::instance(), parents );
+ break;
+ }
+ case ID_mirrorPoint:
+ {
+ o = new ObjectTypeCalcer( PointReflectionType::instance(), parents );
+ break;
+ }
+ case ID_pointOfConc:
+ {
+ o = new ObjectTypeCalcer( LineLineIntersectionType::instance(), parents );
+ break;
+ }
+ case ID_text:
+ {
+ bool frame = c->readBoolEntry( "Frame" );
+ double x = c->readDoubleNumEntry( "TextRectCenterX" );
+ double y = c->readDoubleNumEntry( "TextRectCenterY" );
+ QString text = c->readEntry( "TextRectEntry" );
+ double height = c->readNumEntry( "TextRectHeight" );
+ double width = c->readNumEntry( "TextRectWidth" );
+ // we don't want the center, but the top left..
+ x -= width / 80;
+ y -= height / 80;
+ o = factory->labelCalcer(
+ text, Coordinate( x, y ), frame, std::vector<ObjectCalcer*>(), *ret );
+ break;
+ }
+ case ID_fixedCircle:
+ {
+ double r = c->readDoubleNumEntry( "Radius" );
+ parents.push_back( new ObjectConstCalcer( new DoubleImp( r ) ) );
+ o = new ObjectTypeCalcer( CircleBPRType::instance(), parents );
+ break;
+ }
+ case ID_angle:
+ {
+ if ( parents.size() == 3 )
+ {
+ ObjectTypeCalcer* ao = new ObjectTypeCalcer( AngleType::instance(), parents );
+ ao->calc( *ret );
+ parents.clear();
+ parents.push_back( ao );
+ };
+ if ( parents.size() != 1 ) KIG_FILTER_PARSE_ERROR;
+ ObjectCalcer* angle = parents[0];
+ parents.clear();
+ const Coordinate c =
+ static_cast<const PointImp*>( angle->parents()[1]->imp() )->coordinate();
+ o = filtersConstructTextObject( c, angle, "angle-degrees", *ret, true );
+ break;
+ }
+ case ID_distance:
+ {
+ if ( parents.size() != 2 ) KIG_FILTER_PARSE_ERROR;
+ ObjectTypeCalcer* segment = new ObjectTypeCalcer( SegmentABType::instance(), parents );
+ segment->calc( *ret );
+ Coordinate m = ( static_cast<const PointImp*>( parents[0]->imp() )->coordinate() +
+ static_cast<const PointImp*>( parents[1]->imp() )->coordinate() ) / 2;
+ o = filtersConstructTextObject( m, segment, "length", *ret, true );
+ break;
+ }
+ case ID_arc:
+ {
+ o = new ObjectTypeCalcer( AngleType::instance(), parents );
+ break;
+ }
+ case ID_area:
+ {
+ if ( parents.size() != 1 ) KIG_FILTER_PARSE_ERROR;
+ const CircleImp* circle = static_cast<const CircleImp*>( parents[0]->imp() );
+ const Coordinate c = circle->center() + Coordinate( circle->radius(), 0 );
+ o = filtersConstructTextObject( c, parents[0], "surface", *ret, true );
+ break;
+ }
+ case ID_slope:
+ {
+ // if parents contains a segment, line, vector or whatever, we
+ // take its parents cause we want points..
+ if ( parents.size() == 1 ) parents = parents[0]->parents();
+ if ( parents.size() != 2 ) KIG_FILTER_PARSE_ERROR;
+ const Coordinate c = (
+ static_cast<const PointImp*>( parents[0]->imp() )->coordinate() +
+ static_cast<const PointImp*>( parents[1]->imp() )->coordinate() ) / 2;
+ ObjectTypeCalcer* line = new ObjectTypeCalcer( LineABType::instance(), parents );
+ line->calc( *ret );
+ o = filtersConstructTextObject( c, line, "slope", *ret, true );
+ break;
+ }
+ case ID_circumference:
+ {
+ if ( parents.size() != 1 ) KIG_FILTER_PARSE_ERROR;
+ const CircleImp* c = static_cast<const CircleImp*>( parents[0]->imp() );
+ const Coordinate m = c->center() + Coordinate( c->radius(), 0 );
+ o = filtersConstructTextObject( m, parents[0], "circumference", *ret, true );
+ break;
+ }
+ case ID_rotation:
+ {
+ // in kig, the rotated object should be last..
+ ObjectCalcer* t = parents[2];
+ parents[2] = parents[0];
+ parents[0] = t;
+ o = new ObjectTypeCalcer( RotationType::instance(), parents );
+ break;
+ }
+ default:
+ KIG_FILTER_PARSE_ERROR;
+ };
+
+ // set the color...
+ QColor co = c->readColorEntry( "Color" );
+ if( !co.isValid() )
+ co = Qt::blue;
+ ObjectDrawer* d = new ObjectDrawer( co );
+
+ os[i] = new ObjectHolder( o, d );
+ os[i]->calc( *ret );
+ }; // for loop (creating KGeoHierarchyElements..
+
+ ret->addObjects( os );
+ ret->setGrid( grid );
+ ret->setAxes( axes );
+ return ret;
+}
+
+KigFilterKGeo::KigFilterKGeo()
+{
+}
+
+KigFilterKGeo::~KigFilterKGeo()
+{
+}
+
+KigFilterKGeo* KigFilterKGeo::instance()
+{
+ static KigFilterKGeo f;
+ return &f;
+}
diff --git a/kig/filters/kgeo-filter.h b/kig/filters/kgeo-filter.h
new file mode 100644
index 00000000..1a2ff83d
--- /dev/null
+++ b/kig/filters/kgeo-filter.h
@@ -0,0 +1,55 @@
+// This file is part of Kig, a KDE program for Interactive Geometry...
+// 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_FILTERS_KGEO_FILTER_H
+#define KIG_FILTERS_KGEO_FILTER_H
+
+#include "filter.h"
+
+class KSimpleConfig;
+
+/**
+ * This is an import filter for files generated by the program KGeo,
+ * which was an interactive geometry program in kdeedu. Kig is
+ * supposed to be its successor, and this import filter is part of my
+ * attempt to achieve that :)
+ *
+ * Status: a significant part of KGeo's format is supported, not all
+ * yet, though..
+ */
+class KigFilterKGeo
+ : public KigFilter
+{
+public:
+ static KigFilterKGeo* instance();
+ bool supportMime ( const QString& mime );
+ KigDocument* load ( const QString& from );
+protected:
+ KigFilterKGeo();
+ ~KigFilterKGeo();
+
+ void loadMetrics ( KSimpleConfig* );
+ KigDocument* loadObjects ( const QString& file, KSimpleConfig* );
+
+ int xMax;
+ int yMax;
+ bool grid;
+ bool axes;
+};
+
+#endif
diff --git a/kig/filters/kgeo-resource.h b/kig/filters/kgeo-resource.h
new file mode 100644
index 00000000..2a272ed0
--- /dev/null
+++ b/kig/filters/kgeo-resource.h
@@ -0,0 +1,204 @@
+/**
+ This file is part of Kig, a KDE program for Interactive Geometry...
+ 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
+**/
+
+
+/// note: this code comes from KGeo by Marc Bartsch..
+
+
+/***************************************************************************
+ resource.h - description
+ -------------------
+ begin : Die Okt 3 09:00:59 CEST 2000
+ copyright : (C) 2000 by Marc Bartsch
+ email : marc.bartsch@topmail.de
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * 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. *
+ * *
+ ***************************************************************************/
+
+#ifndef RESOURCE_H
+#define RESOURCE_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <iostream>
+#include <qstring.h>
+#include <klocale.h>
+
+///////////////////////////////////////////////////////////////////
+// resource.h -- contains macros used for commands
+
+
+///////////////////////////////////////////////////////////////////
+// COMMAND VALUES FOR MENUBAR AND TOOLBAR ENTRIES
+
+
+///////////////////////////////////////////////////////////////////
+// File-menu entries
+#define ID_FILE_NEW_WINDOW 10010
+#define ID_FILE_NEW 10020
+#define ID_FILE_OPEN 10030
+#define ID_FILE_OPEN_RECENT 10040
+#define ID_FILE_CLOSE 10050
+
+#define ID_FILE_SAVE 10060
+#define ID_FILE_SAVE_AS 10070
+
+#define ID_FILE_PRINT 10080
+
+#define ID_FILE_QUIT 10090
+
+///////////////////////////////////////////////////////////////////
+// Edit-menu entries
+#define ID_EDIT_COPY 11010
+#define ID_EDIT_CUT 11020
+#define ID_EDIT_PASTE 11030
+// domi: disabled, breaks --enable-final, and is not used anyway.
+//#define ID_EDIT_PREFERENCES 11040
+#define ID_EDIT_FULLSCREEN 11050
+
+///////////////////////////////////////////////////////////////////
+// View-menu entries
+#define ID_VIEW_TOOLBAR 12010
+#define ID_VIEW_STATUSBAR 12020
+#define ID_VIEW_FULLSCREEN 12030
+
+///////////////////////////////////////////////////////////////////
+// Help-menu entries
+#define ID_HELP_CONTENTS 1002
+
+///////////////////////////////////////////////////////////////////
+// General application values
+#define ID_STATUS_MSG 1001
+
+#define IDS_STATUS_DEFAULT "Ready."
+
+#define ID_infinite -1
+
+#define ID_point 1
+#define ID_pointxy 14
+#define ID_pointOnLine 15
+#define ID_pointOfConc 7
+#define ID_bisection 5
+#define ID_mirrorPoint 9
+
+#define ID_segment 2
+#define ID_circle 3
+#define ID_line 4
+#define ID_fixedCircle 6
+#define ID_arc 8
+#define ID_eraser 10
+#define ID_attacher 11
+#define ID_tracer 12
+#define ID_triangle 13
+#define ID_colorizer 16
+#define ID_thicker 17
+#define ID_geoPoint 18
+#define ID_geoTool 19
+#define ID_geoObject 20
+#define ID_geoMeasure 21
+#define ID_distance 22
+#define ID_angle 23
+#define ID_area 24
+#define ID_slope 25
+#define ID_circumference 26
+#define ID_vector 27
+#define ID_geoLine 28
+#define ID_ray 29
+#define ID_parallel 30
+#define ID_perpendicular 31
+#define ID_move 32
+#define ID_rotation 33
+#define ID_text 34
+
+#define ID_buttonFileNew 100
+#define ID_buttonKiosk 101
+
+#define ID_buttonPoint 110
+#define ID_buttonPointxy 111
+#define ID_buttonPointOnLine 112
+#define ID_buttonPointOfConc 113
+#define ID_buttonBisection 114
+#define ID_buttonMirrorPoint 115
+#define ID_buttonMove 116
+#define ID_buttonRotation 117
+
+#define ID_buttonSegment 120
+#define ID_buttonLine 121
+#define ID_buttonVector 122
+#define ID_buttonRay 123
+#define ID_buttonParallel 124
+#define ID_buttonPerpendicular 125
+#define ID_buttonTriangle 126
+
+#define ID_buttonBaseCircle 130
+#define ID_buttonCircle 131
+#define ID_buttonArc 132
+
+#define ID_buttonDistance 140
+#define ID_buttonAngle 141
+#define ID_buttonArea 142
+#define ID_buttonSlope 143
+#define ID_buttonCircumference 144
+
+#define ID_buttonBlack 150
+#define ID_buttonDarkGray 151
+#define ID_buttonLightGray 152
+#define ID_buttonWhite 153
+#define ID_buttonBlue 154
+#define ID_buttonRed 155
+#define ID_buttonGreen 156
+
+#define ID_buttonThinLine 160
+#define ID_buttonMiddleLine 161
+#define ID_buttonThickLine 162
+
+#define ID_buttonEraser 170
+#define ID_buttonAttacher 171
+#define ID_buttonTracer 172
+#define ID_buttonText 173
+#define ID_buttonMoveGrid 174
+#define ID_buttonPointer 175
+#define ID_buttonDrawColor 176
+#define ID_buttonSizer 177
+
+#define ID_drawingModeNoMode 0
+#define ID_drawingModeMovingGrid 1
+#define ID_drawingModeMovingObjects 2
+#define ID_drawingModeConstructing 3
+
+#define MinimumPointSize 3
+
+#define Str_AppName "KGeo"
+
+
+#define ID_overlayRectSize 24
+
+#define PI 3.1415926535
+
+#endif // RESOURCE_H
diff --git a/kig/filters/kseg-defs.h b/kig/filters/kseg-defs.h
new file mode 100644
index 00000000..ad90fa1a
--- /dev/null
+++ b/kig/filters/kseg-defs.h
@@ -0,0 +1,301 @@
+// Copyright (C) 2003 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.
+
+// this is a collection of definitions we need from KSeg. It includes
+// code from defs.H and G_drawstyle.H. Thanks to Ilya Baran for
+// making KSeg GPL, so there are no license probs or whatever..
+
+/*
+ * KSeg
+ * Copyright (C) 1999-2003 Ilya Baran
+ *
+ * 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, Cambridge, MA 02110-1301, USA.
+ *
+ * Send comments and/or bug reports to:
+ * ibaran@mit.edu
+ */
+
+
+#ifndef DEFS_H
+#define DEFS_H
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <qglobal.h>
+
+using namespace std;
+
+#define DRAW_MAX 5000 // maximum coordinate. assumes you have a screen resolution less than this.
+
+#define BIG (1e+37)
+#define SMALL (1e-10)
+
+inline int ROUND(double x) { return ((int)(x + 0.5)); }
+inline int SIGN(double x) { return (x < 0) ? -1 : 1; }
+inline int INTRAND(int a, int b) { return QMIN(a, b) + rand() % abs(a - b); }
+#define SQR(x) ((x) * (x))
+#define CUBE(x) ((x) * (x) * (x))
+#define QUAD(x) (((x) * (x)) * ((x) * (x)))
+
+enum G_Type
+{
+ G_POINT = 1,
+ G_SEGMENT = 2,
+ G_RAY = 4,
+ G_LINE = 8,
+ G_CIRCLE = 16,
+ G_ARC = 32,
+ G_POLYGON = 64,
+ G_CIRCLEINTERIOR = 128,
+ G_ARCSECTOR = 256,
+ G_ARCSEGMENT = 512,
+ //non-primitive geometric types now:
+ G_LOCUS = 1024,
+ G_MEASURE = 2048,
+ G_CALCULATE = 4096,
+ G_ANNOTATION = 8192,
+ //fake type for scripting:
+ G_LOOP = 16384,
+ //compound types now:
+ G_STRAIGHT = G_SEGMENT | G_LINE | G_RAY,
+ G_CURVE = G_STRAIGHT | G_ARC | G_CIRCLE,
+ G_FILLED = G_POLYGON | G_CIRCLEINTERIOR | G_ARCSECTOR | G_ARCSEGMENT,
+ G_GEOMETRIC = G_POINT | G_CURVE | G_FILLED | G_LOCUS,
+ G_VALUE = G_MEASURE | G_CALCULATE,
+ G_TEXT = G_VALUE | G_ANNOTATION,
+ G_ANY = G_GEOMETRIC | G_TEXT | G_LOOP
+};
+
+enum G_AnyType
+{
+ G_TRANSLATED,
+ G_ROTATED,
+ G_SCALED,
+ G_REFLECTED
+};
+
+#define IS_TRANSFORM(x) ((x) == G_TRANSLATED || (x) == G_ROTATED || (x) == G_SCALED || (x) == G_REFLECTED)
+
+enum G_PointType
+{
+ G_FREE_POINT = G_REFLECTED + 1,
+ G_CONSTRAINED_POINT,
+ G_INTERSECTION_POINT,
+ G_INTERSECTION2_POINT,
+ G_MID_POINT
+};
+
+enum G_SegmentType
+{
+ G_ENDPOINTS_SEGMENT = G_REFLECTED + 1
+};
+
+enum G_RayType
+{
+ G_TWOPOINTS_RAY = G_REFLECTED + 1,
+ G_BISECTOR_RAY
+};
+
+enum G_LineType
+{
+ G_TWOPOINTS_LINE = G_REFLECTED + 1,
+ G_PARALLEL_LINE,
+ G_PERPENDICULAR_LINE
+};
+
+enum G_CircleType
+{
+ G_CENTERPOINT_CIRCLE = G_REFLECTED + 1,
+ G_CENTERRADIUS_CIRCLE
+};
+
+enum G_ArcType
+{
+ G_THREEPOINTS_ARC = G_REFLECTED + 1
+};
+
+enum G_FilledType
+{
+ G_DEFAULT_FILLED = G_REFLECTED + 1
+};
+
+enum G_LocusType
+{
+ G_OBJECT_LOCUS = G_REFLECTED + 1
+};
+
+enum G_MeasureType
+{
+ G_DISTANCE_MEASURE,
+ G_LENGTH_MEASURE,
+ G_RADIUS_MEASURE,
+ G_ANGLE_MEASURE,
+ G_RATIO_MEASURE,
+ G_SLOPE_MEASURE,
+ G_AREA_MEASURE
+};
+
+enum G_CalculateType
+{
+ G_REGULAR_CALCULATE
+};
+
+
+enum MenuIDs
+{
+ ID_NEW_SEGMENT = 1,
+ ID_NEW_MIDPOINT,
+ ID_NEW_LINE,
+ ID_NEW_PERPENDICULAR,
+ ID_NEW_RAY,
+ ID_NEW_BISECTOR,
+ ID_NEW_CIRCLE,
+ ID_NEW_INTERSECTION,
+ ID_NEW_ARC,
+ ID_NEW_LOCUS,
+ ID_NEW_ARCSECTOR,
+ ID_NEW_ARCSEGMENT,
+ ID_NEW_CIRCLEINTERIOR,
+ ID_NEW_POLYGON,
+
+ ID_EDIT_UNDO,
+ ID_EDIT_REDO,
+ ID_EDIT_DELETE,
+ ID_EDIT_TOGGLELABELS,
+ ID_EDIT_SHOWLABELS,
+ ID_EDIT_HIDELABELS,
+ ID_EDIT_CHANGELABEL,
+ ID_EDIT_HIDE,
+ ID_EDIT_SHOWHIDDEN,
+ ID_EDIT_COLOR,
+ ID_EDIT_POINTSTYLE,
+ ID_EDIT_LINESTYLE,
+ ID_EDIT_FONT,
+ ID_EDIT_CHANGE_NUMBER_OF_SAMPLES,
+ ID_EDIT_PREFERENCES,
+
+ ID_EDIT_COLOR_BLACK,
+ ID_EDIT_COLOR_GRAY,
+ ID_EDIT_COLOR_RED,
+ ID_EDIT_COLOR_GREEN,
+ ID_EDIT_COLOR_BLUE,
+ ID_EDIT_COLOR_YELLOW,
+ ID_EDIT_COLOR_PURPLE,
+ ID_EDIT_COLOR_CYAN,
+ ID_EDIT_COLOR_OTHER,
+
+ ID_EDIT_POINTSTYLE_LARGECIRCLE,
+ ID_EDIT_POINTSTYLE_MEDIUMCIRCLE,
+ ID_EDIT_POINTSTYLE_SMALLCIRCLE,
+
+ ID_EDIT_LINESTYLE_SOLID,
+ ID_EDIT_LINESTYLE_DASHED,
+ ID_EDIT_LINESTYLE_DOTTED,
+ ID_EDIT_LINESTYLE_THIN,
+ ID_EDIT_LINESTYLE_NORMAL,
+ ID_EDIT_LINESTYLE_THICK,
+
+ ID_EDIT_FONT_10,
+ ID_EDIT_FONT_12,
+ ID_EDIT_FONT_14,
+ ID_EDIT_FONT_20,
+ ID_EDIT_FONT_30,
+ ID_EDIT_FONT_FONT,
+
+ ID_MEASURE_DISTANCE,
+ ID_MEASURE_LENGTH,
+ ID_MEASURE_RADIUS,
+ ID_MEASURE_ANGLE,
+ ID_MEASURE_RATIO,
+ ID_MEASURE_SLOPE,
+ ID_MEASURE_AREA,
+ ID_MEASURE_CALCULATE,
+
+ ID_TRANSFORM_CHOOSE_VECTOR,
+ ID_TRANSFORM_CHOOSE_MIRROR,
+ ID_TRANSFORM_CHOOSE_CENTER,
+ ID_TRANSFORM_CHOOSE_RATIO,
+ ID_TRANSFORM_CHOOSE_ANGLE,
+ ID_TRANSFORM_CLEAR_CHOSEN,
+ ID_TRANSFORM_TRANSLATE,
+ ID_TRANSFORM_ROTATE,
+ ID_TRANSFORM_REFLECT,
+ ID_TRANSFORM_SCALE,
+
+ ID_CONSTRUCTION_MAKE_NORMAL,
+ ID_CONSTRUCTION_MAKE_GIVEN,
+ ID_CONSTRUCTION_MAKE_FINAL,
+ ID_CONSTRUCTION_MAKE_INITIAL,
+ ID_CONSTRUCTION_RECURSE,
+
+ ID_PLAY_QUICKPLAY,
+
+ ID_QUICKPLAY_SET_DIRECTORY,
+
+ ID_FILE_RECENTLIST_START //should be the last entry
+};
+
+#endif //DEFS_H
+
+
+/*
+ * KSeg
+ * Copyright (C) 1999-2003 Ilya Baran
+ *
+ * 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, Cambridge, MA 02110-1301, USA.
+ *
+ * Send comments and/or bug reports to:
+ * ibaran@mit.edu
+ */
+
+
+#ifndef G_DRAWSTYLE_H
+#define G_DRAWSTYLE_H
+
+enum PointStyle
+{
+ ANY = 0,
+ SMALL_CIRCLE,
+ MEDIUM_CIRCLE,
+ LARGE_CIRCLE
+};
+
+#endif //G_DRAWSTYLE_H
diff --git a/kig/filters/kseg-filter-status.txt b/kig/filters/kseg-filter-status.txt
new file mode 100644
index 00000000..eb896726
--- /dev/null
+++ b/kig/filters/kseg-filter-status.txt
@@ -0,0 +1,41 @@
+KSeg filter status
+==================
+
+Objects imported
+----------------
+
+Points ok
+Rays ok
+Vectors ok
+Lines ok
+Circles ok
+Angles ok
+Arcs ok
+Locuses some
+Transformations most
+Intersections most
+Polygons ok
+Labels ok
+
+Colors ok
+Visibility ok
+Styles ok
+Grid ok
+
+Objects not imported
+--------------------
+
+Transformations scaling (with ratio as formula) (*)
+Intersections arc-circle(*)
+Filled circles (*)
+Arc sectors (*)
+Arc segments (*)
+Formulas (*)
+
+(*) objects which currently are not implemented in Kig
+
+Known problems
+--------------
+
+* Some locuses may crash the filter.
+* Label text should be correctly encoded.
diff --git a/kig/filters/kseg-filter.cc b/kig/filters/kseg-filter.cc
new file mode 100644
index 00000000..f2ba901b
--- /dev/null
+++ b/kig/filters/kseg-filter.cc
@@ -0,0 +1,679 @@
+// Copyright (C) 2003 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.
+
+#include "kseg-filter.h"
+
+#include "kseg-defs.h"
+
+#include "../kig/kig_document.h"
+#include "../kig/kig_part.h"
+#include "../misc/coordinate.h"
+#include "../objects/angle_type.h"
+#include "../objects/arc_type.h"
+#include "../objects/bogus_imp.h"
+#include "../objects/circle_type.h"
+#include "../objects/conic_imp.h"
+#include "../objects/conic_types.h"
+#include "../objects/intersection_types.h"
+#include "../objects/line_imp.h"
+#include "../objects/line_type.h"
+#include "../objects/object_calcer.h"
+#include "../objects/object_drawer.h"
+#include "../objects/object_factory.h"
+#include "../objects/object_holder.h"
+#include "../objects/other_imp.h"
+#include "../objects/other_type.h"
+#include "../objects/point_imp.h"
+#include "../objects/point_type.h"
+#include "../objects/polygon_type.h"
+#include "../objects/transform_types.h"
+#include "../objects/vector_type.h"
+
+#include <qfont.h>
+#include <qpen.h>
+#include <qbrush.h>
+#include <qfile.h>
+#include <qdatastream.h>
+#include <qbuffer.h>
+
+#include <klocale.h>
+
+KigFilterKSeg::KigFilterKSeg()
+{
+}
+
+KigFilterKSeg::~KigFilterKSeg()
+{
+}
+
+bool KigFilterKSeg::supportMime( const QString& mime )
+{
+ return mime == "application/x-kseg";
+}
+
+struct drawstyle
+{
+ Q_INT8 pointstyle;
+ QFont font;
+ QPen pen;
+ QBrush brush;
+};
+
+static Coordinate readKSegCoordinate( QDataStream& stream )
+{
+ // read the coord..
+ float inx, iny;
+ stream >> inx >> iny;
+ // KSeg uses a coordinate system, where the topleft is (0,0), and
+ // the bottom right is the widget coordinate in the window: if the
+ // KSeg window had a width of 600 pixels and a height of 600, then
+ // the bottom right will be at (600,600). We assume a window of
+ // such a height here, and transform it into Kig Coordinates. This
+ // function is quite similar to ScreenInfo::fromScreen, and it's
+ // basically a simple modification of that code to floats..
+
+ // invert the y-axis: 0 is at the bottom !
+ Coordinate t( inx, 600 - iny );
+ t *= 14;
+ t /= 600;
+ return t + Coordinate( -7, -7 );
+}
+
+static ObjectTypeCalcer* intersectionPoint( const std::vector<ObjectCalcer*>& parents, int which )
+{
+ if ( parents.size() != 2 ) return 0;
+ int nlines = 0;
+ int nconics = 0;
+ int narcs = 0;
+ for ( int i = 0; i < 2; ++i )
+ {
+ if ( parents[i]->imp()->inherits( AbstractLineImp::stype() ) ) ++nlines;
+ else if ( parents[i]->imp()->inherits( ConicImp::stype() ) ) ++nconics;
+ else if ( parents[i]->imp()->inherits( ArcImp::stype() ) ) ++narcs;
+ else return 0;
+ };
+ if ( nlines == 2 )
+ return which == -1 ? new ObjectTypeCalcer( LineLineIntersectionType::instance(), parents ) : 0;
+ else if ( nlines == 1 && nconics == 1 )
+ {
+ std::vector<ObjectCalcer*> intparents( parents );
+ intparents.push_back( new ObjectConstCalcer( new IntImp( which ) ) );
+ return new ObjectTypeCalcer( ConicLineIntersectionType::instance(), intparents );
+ }
+ else if ( nlines == 0 && nconics == 2 )
+ {
+ std::vector<ObjectCalcer*> rparents( parents );
+ rparents.push_back( new ObjectConstCalcer( new IntImp( 1 ) ) );
+ rparents.push_back( new ObjectConstCalcer( new IntImp( 1 ) ) );
+ rparents.push_back( new ObjectTypeCalcer( ConicRadicalType::instance(), rparents ) );
+ std::vector<ObjectCalcer*> iparents;
+ iparents.push_back( parents[0] );
+ iparents.push_back( rparents.back() );
+ iparents.push_back( new ObjectConstCalcer( new IntImp( which ) ) );
+ return new ObjectTypeCalcer( ConicLineIntersectionType::instance(), iparents );
+ }
+ else if ( nlines == 1 && narcs == 1 )
+ {
+ std::vector<ObjectCalcer*> intparents( parents );
+ intparents.push_back( new ObjectConstCalcer( new IntImp( which ) ) );
+ return new ObjectTypeCalcer( ArcLineIntersectionType::instance(), intparents );
+ }
+ else return 0;
+}
+
+ObjectCalcer* KigFilterKSeg::transformObject( const QString& file, KigDocument& kigdoc,
+ std::vector<ObjectCalcer*>& parents,
+ int subtype, bool& ok )
+{
+ ok = true;
+ ObjectCalcer* retobj = 0;
+ switch( subtype )
+ {
+ case G_TRANSLATED:
+ {
+ std::vector<ObjectCalcer*> vectorparents( parents.begin() + 1, parents.end() );
+ ObjectTypeCalcer* vector = new ObjectTypeCalcer( VectorType::instance(), vectorparents );
+ vector->calc( kigdoc );
+
+ std::vector<ObjectCalcer*> transparents;
+ transparents.push_back( parents[0] );
+ transparents.push_back( vector );
+ retobj = new ObjectTypeCalcer( TranslatedType::instance(), transparents );
+ break;
+ }
+ case G_ROTATED:
+ {
+ std::vector<ObjectCalcer*> angleparents( parents.begin() + 2, parents.end() );
+ ObjectTypeCalcer* angle = new ObjectTypeCalcer( AngleType::instance(), angleparents );
+ angle->calc( kigdoc );
+
+ std::vector<ObjectCalcer*> rotparents;
+ rotparents.push_back( parents[0] );
+ rotparents.push_back( parents[1] );
+ rotparents.push_back( angle );
+ retobj = new ObjectTypeCalcer( RotationType::instance(), rotparents );
+ break;
+ }
+ case G_SCALED:
+ {
+ if ( parents.size() == 4 )
+ {
+ retobj = new ObjectTypeCalcer( ScalingOverCenter2Type::instance(), parents );
+ }
+ else
+ {
+ // TODO
+ notSupported( file, i18n( "This KSeg document uses a scaling "
+ "transformation, which Kig currently "
+ "cannot import." ) );
+ ok = false;
+ return 0;
+ }
+ break;
+ }
+ case G_REFLECTED:
+ {
+ std::vector<ObjectCalcer*> mirparents( parents.begin(), parents.end() );
+ retobj = new ObjectTypeCalcer( LineReflectionType::instance(), mirparents );
+ break;
+ }
+ }
+
+ return retobj;
+}
+
+KigDocument* KigFilterKSeg::load( const QString& file )
+{
+ QFile ffile( file );
+ if ( ! ffile.open( IO_ReadOnly ) )
+ {
+ fileNotFound( file );
+ return false;
+ };
+
+ KigDocument* retdoc = new KigDocument();
+
+ QDataStream fstream( &ffile );
+
+ QString versionstring;
+ fstream >> versionstring;
+ if ( !versionstring.startsWith( "KSeg Document Version " ) )
+ KIG_FILTER_PARSE_ERROR;
+
+ QByteArray array;
+ fstream >> array;
+ QBuffer buf( array );
+ buf.open( IO_ReadOnly );
+ QDataStream stream( &buf );
+
+ stream.setVersion( 3 );
+
+ // G_drawstyles:
+ short numstyles;
+ stream >> numstyles;
+ std::vector<drawstyle> drawstyles( numstyles );
+ for ( short i = 0; i < numstyles; ++i )
+ {
+ stream >> drawstyles[i].pointstyle;
+ stream >> drawstyles[i].font;
+ stream >> drawstyles[i].pen;
+ stream >> drawstyles[i].brush;
+ };
+
+ std::vector<ObjectHolder*> ret;
+ std::vector<ObjectHolder*> ret2;
+
+ // G_refs
+ unsigned int count;
+ stream >> count;
+
+ ret.resize( count, 0 );
+ const ObjectFactory* fact = ObjectFactory::instance();
+
+ // KSeg topologically sorts the objects before saving, that means we
+ // can read the entire file in one iteration..
+ for ( uint i = 0; i < count; ++i )
+ {
+ short styleid;
+ stream >> styleid;
+ short nparents;
+ stream >> nparents;
+ std::vector<ObjectCalcer*> parents( nparents, 0 );
+ for ( short j = 0; j < nparents; ++j )
+ {
+ int parent;
+ stream >> parent;
+ parents[j] = ret[parent]->calcer();
+ };
+
+ // read the object..
+ short info;
+ stream >> info;
+ int type = 1 << (info & 31);
+ info >>= 5;
+ int descendtype = (info & 15);
+ info >>= 4;
+ bool visible = info & 1;
+ bool labelVisible = info & 2;
+ bool given = info & 4;
+ bool final = info & 8;
+
+ // avoid g++ warnings about unused vars..
+ // this doesn't really do anything..
+ (void) given;
+ (void) final;
+
+ drawstyle style = drawstyles[styleid];
+
+ if ( type == G_LOOP ) continue;
+ // read the label..
+ QString labeltext;
+ stream >> labeltext;
+ Coordinate relcoord = readKSegCoordinate( stream );
+ // shut up gcc
+ (void) relcoord;
+ if ( type & G_CURVE )
+ {
+ Coordinate relcurvecoord = readKSegCoordinate( stream );
+ // shut up gcc
+ (void) relcurvecoord;
+ };
+
+ // now load the object data..
+ ObjectHolder* object = 0;
+ ObjectCalcer* o = 0;
+ bool ok = true;
+
+ QColor color = style.pen.color();
+ int width = style.pen.width();
+
+/*
+ kdDebug() << "type: " << type << endl
+ << "descendtype: " << descendtype << endl
+ << "label: " << labeltext << endl;
+//*/
+
+ switch ( type )
+ {
+ case G_POINT:
+ {
+ switch( descendtype )
+ {
+ case G_TRANSLATED:
+ case G_ROTATED:
+ case G_SCALED:
+ case G_REFLECTED:
+ {
+ o = transformObject( file, *retdoc, parents, descendtype, ok );
+ break;
+ }
+ case G_FREE_POINT:
+ {
+ // fixed point
+ if ( nparents != 0 ) KIG_FILTER_PARSE_ERROR;
+ Coordinate c = readKSegCoordinate( stream );
+ o = fact->fixedPointCalcer( c );
+ break;
+ }
+ case G_CONSTRAINED_POINT:
+ {
+ // constrained point
+ double p;
+ stream >> p;
+ if ( nparents != 1 ) KIG_FILTER_PARSE_ERROR;
+ ObjectCalcer* parent = parents[0];
+ assert( parent );
+ o = fact->constrainedPointCalcer( parent, p );
+ break;
+ }
+ case G_INTERSECTION_POINT:
+ {
+ // KSeg has somewhat weird intersection objects..
+ // for all objects G_INTERSECTION_POINT gets the
+ // first intersection of its parents, G_INTERSECTION2_POINT
+ // represents the second, if present.
+ o = intersectionPoint( parents, -1 );
+ if ( ! o ) KIG_FILTER_PARSE_ERROR;
+ break;
+ }
+ case G_INTERSECTION2_POINT:
+ {
+ o = intersectionPoint( parents, 1 );
+ if ( ! o ) KIG_FILTER_PARSE_ERROR;
+ break;
+ }
+ case G_MID_POINT:
+ {
+ // midpoint of a segment..
+ if ( parents.size() != 1 ) KIG_FILTER_PARSE_ERROR;
+ if ( !parents[0]->imp()->inherits( SegmentImp::stype() ) )
+ KIG_FILTER_PARSE_ERROR;
+ int index = parents[0]->imp()->propertiesInternalNames().findIndex( "mid-point" );
+ assert( index != -1 );
+ o = new ObjectPropertyCalcer( parents[0], index );
+ break;
+ }
+ default:
+ KIG_FILTER_PARSE_ERROR;
+ };
+ width = style.pointstyle == SMALL_CIRCLE ? 2 : style.pointstyle == MEDIUM_CIRCLE ? 3 : 5;
+ color = style.brush.color();
+ break;
+ };
+ case G_SEGMENT:
+ {
+ switch( descendtype )
+ {
+ case G_TRANSLATED:
+ case G_ROTATED:
+ case G_SCALED:
+ case G_REFLECTED:
+ {
+ o = transformObject( file, *retdoc, parents, descendtype, ok );
+ break;
+ }
+ case G_ENDPOINTS_SEGMENT:
+ {
+ if ( nparents != 2 ) KIG_FILTER_PARSE_ERROR;
+ o = new ObjectTypeCalcer( SegmentABType::instance(), parents );
+ break;
+ }
+ default:
+ KIG_FILTER_PARSE_ERROR;
+ }
+ break;
+ };
+ case G_RAY:
+ {
+ switch( descendtype )
+ {
+ case G_TRANSLATED:
+ case G_ROTATED:
+ case G_SCALED:
+ case G_REFLECTED:
+ {
+ o = transformObject( file, *retdoc, parents, descendtype, ok );
+ break;
+ }
+ case G_TWOPOINTS_RAY:
+ {
+ if ( nparents != 2 ) KIG_FILTER_PARSE_ERROR;
+ o = new ObjectTypeCalcer( RayABType::instance(), parents );
+ break;
+ }
+ case G_BISECTOR_RAY:
+ {
+ ObjectTypeCalcer* angle = new ObjectTypeCalcer( HalfAngleType::instance(), parents );
+ angle->calc( *retdoc );
+ o = fact->propertyObjectCalcer( angle, "angle-bisector" );
+ break;
+ }
+ default:
+ KIG_FILTER_PARSE_ERROR;
+ };
+ break;
+ };
+ case G_LINE:
+ {
+ switch( descendtype )
+ {
+ case G_TRANSLATED:
+ case G_ROTATED:
+ case G_SCALED:
+ case G_REFLECTED:
+ {
+ o = transformObject( file, *retdoc, parents, descendtype, ok );
+ break;
+ }
+ case G_TWOPOINTS_LINE:
+ {
+ if ( nparents != 2 ) KIG_FILTER_PARSE_ERROR;
+ o = new ObjectTypeCalcer( LineABType::instance(), parents );
+ break;
+ }
+ case G_PARALLEL_LINE:
+ {
+ if ( nparents != 2 ) KIG_FILTER_PARSE_ERROR;
+ o = new ObjectTypeCalcer( LineParallelLPType::instance(), parents );
+ break;
+ }
+ case G_PERPENDICULAR_LINE:
+ {
+ if ( nparents != 2 ) KIG_FILTER_PARSE_ERROR;
+ o = new ObjectTypeCalcer( LinePerpendLPType::instance(), parents );
+ break;
+ }
+ default:
+ KIG_FILTER_PARSE_ERROR;
+ };
+ break;
+ };
+ case G_CIRCLE:
+ {
+ switch( descendtype )
+ {
+ case G_TRANSLATED:
+ case G_ROTATED:
+ case G_SCALED:
+ case G_REFLECTED:
+ {
+ o = transformObject( file, *retdoc, parents, descendtype, ok );
+ break;
+ }
+ case G_CENTERPOINT_CIRCLE:
+ {
+ if ( nparents != 2 ) KIG_FILTER_PARSE_ERROR;
+ o = new ObjectTypeCalcer( CircleBCPType::instance(), parents );
+ break;
+ }
+ case G_CENTERRADIUS_CIRCLE:
+ {
+ ObjectCalcer* point;
+ ObjectCalcer* segment;
+ if ( parents[0]->imp()->inherits( PointImp::stype() ) )
+ {
+ point = parents[0];
+ segment = parents[1];
+ }
+ else
+ {
+ point = parents[1];
+ segment = parents[0];
+ };
+ int index = segment->imp()->propertiesInternalNames().findIndex( "length" );
+ if ( index == -1 ) KIG_FILTER_PARSE_ERROR;
+ ObjectPropertyCalcer* length = new ObjectPropertyCalcer( segment, index );
+ length->calc( *retdoc );
+ std::vector<ObjectCalcer*> cparents;
+ cparents.push_back( point );
+ cparents.push_back( length );
+ o = new ObjectTypeCalcer( CircleBPRType::instance(), cparents );
+ break;
+ }
+ default:
+ KIG_FILTER_PARSE_ERROR;
+ };
+ break;
+ };
+ case G_ARC:
+ {
+ switch( descendtype )
+ {
+ case G_TRANSLATED:
+ case G_ROTATED:
+ case G_SCALED:
+ case G_REFLECTED:
+ {
+ o = transformObject( file, *retdoc, parents, descendtype, ok );
+ break;
+ }
+ case G_THREEPOINTS_ARC:
+ {
+ if ( nparents != 3 ) KIG_FILTER_PARSE_ERROR;
+ o = new ObjectTypeCalcer( ArcBTPType::instance(), parents );
+ break;
+ }
+ default:
+ KIG_FILTER_PARSE_ERROR;
+ }
+ break;
+ };
+ case G_POLYGON:
+ {
+ switch( descendtype )
+ {
+ case G_TRANSLATED:
+ case G_ROTATED:
+ case G_SCALED:
+ case G_REFLECTED:
+ {
+ o = transformObject( file, *retdoc, parents, descendtype, ok );
+ break;
+ }
+ default:
+ {
+ if ( nparents < 3 ) KIG_FILTER_PARSE_ERROR;
+ o = new ObjectTypeCalcer( PolygonBNPType::instance(), parents );
+ }
+ }
+// default:
+// KIG_FILTER_PARSE_ERROR;
+ break;
+ };
+ case G_CIRCLEINTERIOR:
+ {
+ notSupported( file, i18n( "This KSeg file contains a filled circle, "
+ "which Kig does not currently support." ) );
+ return false;
+ };
+ case G_ARCSECTOR:
+ {
+ notSupported( file, i18n( "This KSeg file contains an arc sector, "
+ "which Kig does not currently support." ) );
+ return false;
+ };
+ case G_ARCSEGMENT:
+ {
+ notSupported( file, i18n( "This KSeg file contains an arc segment, "
+ "which Kig does not currently support." ) );
+ return false;
+ };
+ case G_LOCUS:
+ {
+ switch( descendtype )
+ {
+ case G_TRANSLATED:
+ case G_ROTATED:
+ case G_SCALED:
+ case G_REFLECTED:
+ {
+ o = transformObject( file, *retdoc, parents, descendtype, ok );
+ break;
+ }
+ case G_OBJECT_LOCUS:
+ {
+ if ( nparents != 2 ) KIG_FILTER_PARSE_ERROR;
+ o = fact->locusCalcer( parents[0], parents[1] );
+ break;
+ }
+ default:
+ KIG_FILTER_PARSE_ERROR;
+ }
+ break;
+ };
+ case G_MEASURE:
+ KIG_FILTER_PARSE_ERROR;
+ case G_CALCULATE:
+ KIG_FILTER_PARSE_ERROR;
+ case G_ANNOTATION:
+ KIG_FILTER_PARSE_ERROR;
+ case G_LOOP:
+ KIG_FILTER_PARSE_ERROR;
+ default:
+ KIG_FILTER_PARSE_ERROR;
+
+ }
+
+ // checking if the object was correctly created
+ if ( ! o )
+ {
+ if ( ok )
+ KIG_FILTER_PARSE_ERROR
+ else
+ return 0;
+ }
+
+ ObjectDrawer* d = new ObjectDrawer( color, width, visible, style.pen.style() );
+ if ( !labeltext.isEmpty() )
+ {
+ ObjectConstCalcer* name = new ObjectConstCalcer( new StringImp( labeltext ) );
+ object = new ObjectHolder( o, d, name );
+ }
+ else
+ {
+ object = new ObjectHolder( o, d );
+ }
+
+ assert( object );
+ ret[i] = object;
+ object->calc( *retdoc );
+ if ( !labeltext.isEmpty() && labelVisible )
+ {
+ std::vector<ObjectCalcer*> args2;
+ args2.push_back( object->nameCalcer() );
+ ObjectCalcer* oc2 = fact->attachedLabelCalcer(
+ QString::fromLatin1( "%1" ), object->calcer(),
+ static_cast<const PointImp*>( object->imp() )->coordinate(),
+ false, args2, *retdoc );
+ oc2->calc( *retdoc );
+ ObjectDrawer* d2 = new ObjectDrawer( style.pen.color() );
+ ObjectHolder* o2 = new ObjectHolder( oc2, d2 );
+ ret2.push_back( o2 );
+ }
+ };
+
+ // selection groups ( we ignore them, but we pretend to read them
+ // out anyway, so we can find what comes after them.. )
+ int selgroupcount;
+ stream >> selgroupcount;
+ for ( int i = 0; i < selgroupcount; ++i )
+ {
+ QString name;
+ stream >> name;
+ int size;
+ stream >> size;
+ for ( int i = 0; i < size; ++i )
+ {
+ short object;
+ stream >> object;
+ (void) object;
+ };
+ };
+
+ // no more data in the file..
+ retdoc->addObjects( ret );
+ retdoc->addObjects( ret2 );
+ retdoc->setAxes( false );
+ retdoc->setGrid( false );
+ return retdoc;
+}
+
+KigFilterKSeg* KigFilterKSeg::instance()
+{
+ static KigFilterKSeg f;
+ return &f;
+}
diff --git a/kig/filters/kseg-filter.h b/kig/filters/kseg-filter.h
new file mode 100644
index 00000000..af475a7a
--- /dev/null
+++ b/kig/filters/kseg-filter.h
@@ -0,0 +1,42 @@
+// Copyright (C) 2003 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_FILTERS_KSEG_FILTER_H
+#define KIG_FILTERS_KSEG_FILTER_H
+
+#include "filter.h"
+
+class ObjectCalcer;
+
+class KigFilterKSeg
+ : public KigFilter
+{
+ KigFilterKSeg();
+ ~KigFilterKSeg();
+
+ ObjectCalcer* transformObject( const QString& file, KigDocument& kigdoc,
+ std::vector<ObjectCalcer*>& parents,
+ int subtype, bool& ok );
+
+public:
+ static KigFilterKSeg* instance();
+
+ bool supportMime ( const QString& mime );
+ KigDocument* load ( const QString& fromfile );
+};
+
+#endif
diff --git a/kig/filters/latexexporter.cc b/kig/filters/latexexporter.cc
new file mode 100644
index 00000000..955ac148
--- /dev/null
+++ b/kig/filters/latexexporter.cc
@@ -0,0 +1,608 @@
+// Copyright (C) 2004 Pino Toscano <toscano.pino@tiscali.it>
+
+// 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.
+
+#include <config.h>
+
+#include "latexexporter.h"
+
+#include "latexexporteroptions.h"
+
+#include "../kig/kig_document.h"
+#include "../kig/kig_part.h"
+#include "../kig/kig_view.h"
+#include "../misc/common.h"
+#include "../misc/goniometry.h"
+#include "../misc/kigfiledialog.h"
+#include "../misc/rect.h"
+#include "../objects/circle_imp.h"
+#include "../objects/cubic_imp.h"
+#include "../objects/curve_imp.h"
+#include "../objects/line_imp.h"
+#include "../objects/locus_imp.h"
+#include "../objects/object_drawer.h"
+#include "../objects/object_holder.h"
+#include "../objects/object_imp.h"
+#include "../objects/other_imp.h"
+#include "../objects/point_imp.h"
+#include "../objects/polygon_imp.h"
+#include "../objects/text_imp.h"
+
+#include <math.h>
+#include <algorithm>
+
+#include <qcheckbox.h>
+#include <qcolor.h>
+#include <qfile.h>
+#include <qtextstream.h>
+
+#include <klocale.h>
+#include <kmessagebox.h>
+
+#ifdef HAVE_TRUNC
+#define KDE_TRUNC(a) trunc(a)
+#else
+#define KDE_TRUNC(a) rint(a)
+#endif
+
+struct ColorMap {
+ QColor color;
+ QString name;
+};
+
+LatexExporter::~LatexExporter()
+{
+}
+
+QString LatexExporter::exportToStatement() const
+{
+ return i18n( "Export to &Latex..." );
+}
+
+QString LatexExporter::menuEntryName() const
+{
+ return i18n( "&Latex..." );
+}
+
+QString LatexExporter::menuIcon() const
+{
+ // TODO
+ return "tex";
+}
+
+class LatexExportImpVisitor
+ : public ObjectImpVisitor
+{
+ QTextStream& mstream;
+ ObjectHolder* mcurobj;
+ const KigWidget& mw;
+ Rect msr;
+ std::vector<ColorMap> mcolors;
+ QString mcurcolorid;
+public:
+ void visit( ObjectHolder* obj );
+ void mapColor( QColor color );
+
+ LatexExportImpVisitor( QTextStream& s, const KigWidget& w )
+ : mstream( s ), mw( w ), msr( mw.showingRect() )
+ {
+ }
+ void visit( const LineImp* imp );
+ void visit( const PointImp* imp );
+ void visit( const TextImp* imp );
+ void visit( const AngleImp* imp );
+ void visit( const VectorImp* imp );
+ void visit( const LocusImp* imp );
+ void visit( const CircleImp* imp );
+ void visit( const ConicImp* imp );
+ void visit( const CubicImp* imp );
+ void visit( const SegmentImp* imp );
+ void visit( const RayImp* imp );
+ void visit( const ArcImp* imp );
+ void visit( const PolygonImp* imp );
+
+ double unit;
+
+private:
+ /**
+ * Converts Kig coords to pstrick coord system and sends them to stream
+ * using the format: (xcoord,ycoord)
+ */
+ void emitCoord( const Coordinate& c );
+ /**
+ * Draws a line (segment) or a vector if vector is true.
+ */
+ void emitLine( const Coordinate& a, const Coordinate& b, const int width,
+ const Qt::PenStyle s, bool vector = false );
+ /**
+ * Sends a new line character ( \n ) to stream.
+ */
+ void newLine();
+ /**
+ * Searches if a color is already mapped into mcolors, and returns its
+ * index or -1 if not found.
+ */
+ int findColor( QColor c );
+ /**
+ * Use to convert a dimension "on the screen" to a dimension wrt.
+ * Kig coordinate system.
+ */
+ double dimRealToCoord( int dim );
+ /**
+ * Converts a pen style into latex style string.
+ */
+ QString writeStyle( Qt::PenStyle style );
+ /**
+ * Plots a generic curve though its points calc'ed with getPoint.
+ */
+ void plotGenericCurve( const CurveImp* imp );
+};
+
+void LatexExportImpVisitor::emitCoord( const Coordinate& c )
+{
+ mstream << "(" << c.x - msr.left() << "," << c.y - msr.bottom() << ")";
+}
+
+void LatexExportImpVisitor::emitLine( const Coordinate& a, const Coordinate& b,
+ const int width, const Qt::PenStyle s,
+ bool vector )
+{
+ mstream << "\\psline[linecolor=" << mcurcolorid << ",linewidth=" << width / 100.0
+ << "," << writeStyle( s );
+ if ( vector )
+ mstream << ",arrowscale=3,arrowinset=1.3";
+ mstream << "]";
+ if ( vector )
+ mstream << "{->}";
+ emitCoord( a );
+ emitCoord( b );
+ newLine();
+}
+
+void LatexExportImpVisitor::newLine()
+{
+ mstream << "\n";
+}
+
+int LatexExportImpVisitor::findColor( QColor c )
+{
+ for ( uint i = 0; i < mcolors.size(); ++i )
+ {
+ if ( c == mcolors[i].color )
+ return i;
+ }
+ return -1;
+}
+
+void LatexExportImpVisitor::mapColor( QColor color )
+{
+ if ( findColor( color ) == -1 )
+ {
+ ColorMap newcolor;
+ newcolor.color = color;
+ QString tmpname = color.name();
+ tmpname.replace( "#", "" );
+ newcolor.name = tmpname;
+ mcolors.push_back( newcolor );
+ mstream << "\\newrgbcolor{" << tmpname << "}{"
+ << color.red() / 255.0 << " " << color.green() / 255.0 << " "
+ << color.blue() / 255.0 << "}\n";
+ }
+}
+
+double LatexExportImpVisitor::dimRealToCoord( int dim )
+{
+ QRect qr( 0, 0, dim, dim );
+ Rect r = mw.screenInfo().fromScreen( qr );
+ return fabs( r.width() );
+}
+
+QString LatexExportImpVisitor::writeStyle( Qt::PenStyle style )
+{
+ QString ret( "linestyle=" );
+ if ( style == Qt::DashLine )
+ ret += "dashed";
+ else if ( style == Qt::DotLine )
+ ret += "dotted,dotsep=2pt";
+ else
+ ret += "solid";
+ return ret;
+}
+
+void LatexExportImpVisitor::plotGenericCurve( const CurveImp* imp )
+{
+ int width = mcurobj->drawer()->width();
+ if ( width == -1 ) width = 1;
+
+ QString prefix = QString( "\\pscurve[linecolor=%1,linewidth=%2,%3]" )
+ .arg( mcurcolorid )
+ .arg( width / 100.0 )
+ .arg( writeStyle( mcurobj->drawer()->style() ) );
+
+ std::vector< std::vector< Coordinate > > coordlist;
+ coordlist.push_back( std::vector< Coordinate >() );
+ uint curid = 0;
+
+ Coordinate c;
+ Coordinate prev = Coordinate::invalidCoord();
+ for ( double i = 0.0; i <= 1.0; i += 0.005 )
+ {
+ c = imp->getPoint( i, mw.document() );
+ if ( !c.valid() )
+ {
+ if ( coordlist[curid].size() > 0 )
+ {
+ coordlist.push_back( std::vector< Coordinate >() );
+ ++curid;
+ prev = Coordinate::invalidCoord();
+ }
+ continue;
+ }
+ if ( ! ( ( fabs( c.x ) <= 1000 ) && ( fabs( c.y ) <= 1000 ) ) )
+ continue;
+ // if there's too much distance between this coordinate and the previous
+ // one, then it's another piece of curve not joined with the rest
+ if ( prev.valid() && ( c.distance( prev ) > 4.0 ) )
+ {
+ coordlist.push_back( std::vector< Coordinate >() );
+ ++curid;
+ }
+ coordlist[curid].push_back( c );
+ prev = c;
+ }
+ // special case for ellipse
+ if ( const ConicImp* conic = dynamic_cast< const ConicImp* >( imp ) )
+ {
+ // if ellipse, close its path
+ if ( conic->conicType() == 1 && coordlist.size() == 1 && coordlist[0].size() > 1 )
+ {
+ coordlist[0].push_back( coordlist[0][0] );
+ }
+ }
+ for ( uint i = 0; i < coordlist.size(); ++i )
+ {
+ uint s = coordlist[i].size();
+ // there's no point in draw curves empty or with only one point
+ if ( s <= 1 )
+ continue;
+
+ mstream << prefix;
+ for ( uint j = 0; j < s; ++j )
+ emitCoord( coordlist[i][j] );
+ newLine();
+ }
+}
+
+void LatexExportImpVisitor::visit( ObjectHolder* obj )
+{
+ if ( ! obj->drawer()->shown() )
+ return;
+ const int id = findColor( obj->drawer()->color() );
+ if ( id == -1 )
+ return;
+ mcurcolorid = mcolors[id].name;
+ mcurobj = obj;
+ obj->imp()->visit( this );
+}
+
+void LatexExportImpVisitor::visit( const LineImp* imp )
+{
+ Coordinate a = imp->data().a;
+ Coordinate b = imp->data().b;
+ calcBorderPoints( a, b, msr );
+
+ int width = mcurobj->drawer()->width();
+ if ( width == -1 ) width = 1;
+
+ emitLine( a, b, width, mcurobj->drawer()->style() );
+}
+
+void LatexExportImpVisitor::visit( const PointImp* imp )
+{
+ int width = mcurobj->drawer()->width();
+ if ( width == -1 ) width = 5;
+ width /= 5;
+
+ mstream << "\\psdots[linecolor=" << mcurcolorid
+ << ",dotscale=" << width << ",dotstyle=";
+ const int ps = mcurobj->drawer()->pointStyle();
+ QString pss( "*,fillstyle=solid,fillcolor=" + mcurcolorid );
+ if ( ps == 1 )
+ pss = "o,fillstyle=none";
+ else if ( ps == 2 )
+ pss = "square*,fillstyle=solid,fillcolor=" + mcurcolorid;
+ else if ( ps == 3 )
+ pss = "square,fillstyle=none";
+ else if ( ps == 4 )
+ pss = "+,dotangle=45";
+ mstream << pss << "]";
+ emitCoord( imp->coordinate() );
+ newLine();
+}
+
+void LatexExportImpVisitor::visit( const TextImp* imp )
+{
+ // FIXME: support multiline texts...
+ mstream << "\\rput[tl]";
+ emitCoord( imp->coordinate() );
+ newLine();
+ mstream << "{";
+ newLine();
+ if ( imp->hasFrame() )
+ {
+ mstream << " \\psframebox[linecolor=c5c2c5,linewidth=0.01"
+ << ",fillstyle=solid,fillcolor=ffffde]"
+ << "{" << imp->text() << "}";
+ }
+ else
+ {
+ mstream << imp->text();
+ }
+ newLine();
+ mstream << "}";
+ newLine();
+}
+
+void LatexExportImpVisitor::visit( const AngleImp* imp )
+{
+ const Coordinate center = imp->point();
+ const double radius = dimRealToCoord( 50 ) * unit;
+ double startangle = imp->startAngle();
+ double endangle = startangle + imp->angle();
+// if ( startangle > M_PI )
+// startangle -= 2 * M_PI;
+ startangle = Goniometry::convert( startangle, Goniometry::Rad, Goniometry::Deg );
+// if ( endangle > 2 * M_PI )
+// endangle -= 2 * M_PI;
+ endangle = Goniometry::convert( endangle, Goniometry::Rad, Goniometry::Deg );
+ int width = mcurobj->drawer()->width();
+ if ( width == -1 ) width = 1;
+
+ mstream << "\\psarc[linecolor=" << mcurcolorid << ",linewidth=" << width / 100.0
+ << "," << writeStyle( mcurobj->drawer()->style() ) << ",arrowscale=3,arrowinset=0]{->}";
+ emitCoord( center );
+ mstream << "{" << radius << "}{" << startangle << "}{" << endangle << "}";
+ newLine();
+}
+
+void LatexExportImpVisitor::visit( const VectorImp* imp )
+{
+ Coordinate a = imp->data().a;
+ Coordinate b = imp->data().b;
+
+ int width = mcurobj->drawer()->width();
+ if ( width == -1 ) width = 1;
+
+ emitLine( a, b, width, mcurobj->drawer()->style(), true );
+}
+
+void LatexExportImpVisitor::visit( const LocusImp* imp )
+{
+ plotGenericCurve( imp );
+}
+
+void LatexExportImpVisitor::visit( const CircleImp* imp )
+{
+ int width = mcurobj->drawer()->width();
+ if ( width == -1 ) width = 1;
+
+ mstream << "\\pscircle[linecolor=" << mcurcolorid << ",linewidth=" << width / 100.0
+ << "," << writeStyle( mcurobj->drawer()->style() ) << "]";
+ emitCoord( imp->center() );
+ mstream << "{" << imp->radius() * unit << "}";
+ newLine();
+}
+
+void LatexExportImpVisitor::visit( const ConicImp* imp )
+{
+ plotGenericCurve( imp );
+}
+
+void LatexExportImpVisitor::visit( const CubicImp* )
+{
+ // FIXME: cubic are not drawn correctly with plotGenericCurve
+// plotGenericCurve( imp );
+}
+
+void LatexExportImpVisitor::visit( const SegmentImp* imp )
+{
+ Coordinate a = imp->data().a;
+ Coordinate b = imp->data().b;
+
+ int width = mcurobj->drawer()->width();
+ if ( width == -1 ) width = 1;
+
+ emitLine( a, b, width, mcurobj->drawer()->style() );
+}
+
+void LatexExportImpVisitor::visit( const RayImp* imp )
+{
+ Coordinate a = imp->data().a;
+ Coordinate b = imp->data().b;
+ calcRayBorderPoints( a, b, msr );
+
+ int width = mcurobj->drawer()->width();
+ if ( width == -1 ) width = 1;
+
+ emitLine( a, b, width, mcurobj->drawer()->style() );
+}
+
+void LatexExportImpVisitor::visit( const ArcImp* imp )
+{
+ const Coordinate center = imp->center();
+ const double radius = imp->radius() * unit;
+ double startangle = imp->startAngle();
+ double endangle = startangle + imp->angle();
+// if ( startangle > M_PI )
+// startangle -= 2 * M_PI;
+ startangle = Goniometry::convert( startangle, Goniometry::Rad, Goniometry::Deg );
+// if ( endangle > M_PI )
+// endangle -= 2 * M_PI;
+ endangle = Goniometry::convert( endangle, Goniometry::Rad, Goniometry::Deg );
+ int width = mcurobj->drawer()->width();
+ if ( width == -1 ) width = 1;
+
+ mstream << "\\psarc[linecolor=" << mcurcolorid << ",linewidth=" << width / 100.0
+ << "," << writeStyle( mcurobj->drawer()->style() ) << "]";
+ emitCoord( center );
+ mstream << "{" << radius << "}{" << startangle << "}{" << endangle << "}";
+ newLine();
+}
+
+void LatexExportImpVisitor::visit( const PolygonImp* imp )
+{
+ int width = mcurobj->drawer()->width();
+ if ( width == -1 ) width = 1;
+
+ mstream << "\\pspolygon[linecolor=" << mcurcolorid << ",linewidth=0"
+ << "," << writeStyle( mcurobj->drawer()->style() )
+ << ",hatchcolor=" << mcurcolorid << ",hatchwidth=0.5pt,hatchsep=0.5pt"
+ << ",fillcolor=" << mcurcolorid << ",fillstyle=crosshatch]";
+
+ std::vector<Coordinate> pts = imp->points();
+ for ( uint i = 0; i < pts.size(); i++ )
+ {
+ emitCoord( pts[i] );
+ }
+ newLine();
+}
+
+void LatexExporter::run( const KigPart& doc, KigWidget& w )
+{
+ KigFileDialog* kfd = new KigFileDialog(
+ QString::null, i18n( "*.tex|Latex Documents (*.tex)" ),
+ i18n( "Export as Latex" ), &w );
+ kfd->setOptionCaption( i18n( "Latex Options" ) );
+ LatexExporterOptions* opts = new LatexExporterOptions( 0L );
+ kfd->setOptionsWidget( opts );
+ opts->showGridCheckBox->setChecked( doc.document().grid() );
+ opts->showAxesCheckBox->setChecked( doc.document().axes() );
+ opts->showExtraFrameCheckBox->setChecked( false );
+ if ( !kfd->exec() )
+ return;
+
+ QString file_name = kfd->selectedFile();
+ bool showgrid = opts->showGridCheckBox->isOn();
+ bool showaxes = opts->showAxesCheckBox->isOn();
+ bool showframe = opts->showExtraFrameCheckBox->isOn();
+
+ delete opts;
+ delete kfd;
+
+ QFile file( file_name );
+ if ( ! file.open( IO_WriteOnly ) )
+ {
+ KMessageBox::sorry( &w, i18n( "The file \"%1\" could not be opened. Please "
+ "check if the file permissions are set correctly." )
+ .arg( file_name ) );
+ return;
+ };
+
+ QTextStream stream( &file );
+ stream << "\\documentclass[a4paper]{minimal}\n";
+// stream << "\\usepackage[latin1]{inputenc}\n";
+ stream << "\\usepackage{pstricks}\n";
+ stream << "\\usepackage{pst-plot}\n";
+ stream << "\\author{Kig " << KIGVERSION << "}\n";
+ stream << "\\begin{document}\n";
+
+ const double bottom = w.showingRect().bottom();
+ const double left = w.showingRect().left();
+ const double height = w.showingRect().height();
+ const double width = w.showingRect().width();
+
+/*
+ // TODO: calculating aspect ratio...
+ if ( 297 / 210 >= height / width )
+ {
+
+ }
+*/
+ const double tmpwidth = 15.0;
+ const double xunit = tmpwidth / width;
+ const double yunit = xunit;
+
+ stream << "\\begin{pspicture*}(0,0)(" << tmpwidth << "," << yunit * height << ")\n";
+ stream << "\\psset{xunit=" << xunit << "}\n";
+ stream << "\\psset{yunit=" << yunit << "}\n";
+
+ std::vector<ObjectHolder*> os = doc.document().objects();
+ LatexExportImpVisitor visitor( stream, w );
+ visitor.unit = xunit;
+
+ for ( std::vector<ObjectHolder*>::const_iterator i = os.begin();
+ i != os.end(); ++i )
+ {
+ if ( ! ( *i )->shown() ) continue;
+ visitor.mapColor( ( *i )->drawer()->color() );
+ };
+ visitor.mapColor( QColor( 255, 255, 222 ) ); // ffffde - text label background
+ visitor.mapColor( QColor( 197, 194, 197 ) ); // c5c2c5 - text label border line
+ visitor.mapColor( QColor( 160, 160, 164 ) ); // a0a0a4 - axes color
+ visitor.mapColor( QColor( 192, 192, 192 ) ); // c0c0c0 - grid color
+
+ // extra frame
+ if ( showframe )
+ {
+ stream << "\\psframe[linecolor=black,linewidth=0.02]"
+ << "(0,0)"
+ << "(" << width << "," << height << ")"
+ << "\n";
+ }
+
+ // grid
+ if ( showgrid )
+ {
+ // vertical lines...
+ double startingpoint = - left - 1 + static_cast<int>( KDE_TRUNC( left ) );
+ for ( double i = startingpoint; i < width; ++i )
+ {
+ stream << "\\psline[linecolor=c0c0c0,linewidth=0.01,linestyle=dashed]"
+ << "(" << i << ",0)"
+ << "(" << i << "," << height << ")"
+ << "\n";
+ }
+
+ // horizontal lines...
+ startingpoint = - bottom - 1 + static_cast<int>( KDE_TRUNC( bottom ) );
+ for ( double i = startingpoint; i < height; ++i )
+ {
+ stream << "\\psline[linecolor=c0c0c0,linewidth=0.01,linestyle=dashed]"
+ << "(0," << i << ")"
+ << "(" << width << "," << i << ")"
+ << "\n";
+ }
+ }
+
+ // axes
+ if ( showaxes )
+ {
+ stream << "\\psaxes[linecolor=a0a0a4,linewidth=0.03,ticks=none,arrowinset=0]{->}"
+ << "(" << -left << "," << -bottom << ")"
+ << "(0,0)"
+ << "(" << width << "," << height << ")"
+ << "\n";
+ }
+
+ for ( std::vector<ObjectHolder*>::const_iterator i = os.begin();
+ i != os.end(); ++i )
+ {
+ visitor.visit( *i );
+ };
+
+ stream << "\\end{pspicture*}\n";
+ stream << "\\end{document}\n";
+}
diff --git a/kig/filters/latexexporter.h b/kig/filters/latexexporter.h
new file mode 100644
index 00000000..32638de1
--- /dev/null
+++ b/kig/filters/latexexporter.h
@@ -0,0 +1,41 @@
+// Copyright (C) 2004 Pino Toscano <toscano.pino@tiscali.it>
+
+// 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_FILTERS_LATEXEXPORTER_H
+#define KIG_FILTERS_LATEXEXPORTER_H
+
+#include "exporter.h"
+
+class QString;
+class KigPart;
+class KigWidget;
+
+/**
+ * Export to LaTex.
+ */
+class LatexExporter
+ : public KigExporter
+{
+public:
+ ~LatexExporter();
+ QString exportToStatement() const;
+ QString menuEntryName() const;
+ QString menuIcon() const;
+ void run( const KigPart& doc, KigWidget& w );
+};
+
+#endif
diff --git a/kig/filters/latexexporteroptions.ui b/kig/filters/latexexporteroptions.ui
new file mode 100644
index 00000000..d2e60c5b
--- /dev/null
+++ b/kig/filters/latexexporteroptions.ui
@@ -0,0 +1,69 @@
+<!DOCTYPE UI><UI version="3.2" stdsetdef="1">
+<class>LatexExporterOptions</class>
+<widget class="QWidget">
+ <property name="name">
+ <cstring>LatexExporterOptions</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>450</width>
+ <height>150</height>
+ </rect>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <widget class="QGroupBox">
+ <property name="name">
+ <cstring>groupBox1</cstring>
+ </property>
+ <property name="title">
+ <string>Options</string>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QCheckBox" row="0" column="0">
+ <property name="name">
+ <cstring>showGridCheckBox</cstring>
+ </property>
+ <property name="text">
+ <string>Show grid</string>
+ </property>
+ </widget>
+ <widget class="QCheckBox" row="0" column="1">
+ <property name="name">
+ <cstring>showAxesCheckBox</cstring>
+ </property>
+ <property name="text">
+ <string>Show axes</string>
+ </property>
+ </widget>
+ <widget class="QCheckBox" row="1" column="0">
+ <property name="name">
+ <cstring>showExtraFrameCheckBox</cstring>
+ </property>
+ <property name="text">
+ <string>Show extra frame</string>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ </vbox>
+</widget>
+<customwidgets>
+</customwidgets>
+<layoutdefaults spacing="6" margin="11"/>
+<includehints>
+</includehints>
+</UI>
diff --git a/kig/filters/native-filter.cc b/kig/filters/native-filter.cc
new file mode 100644
index 00000000..6cecf09b
--- /dev/null
+++ b/kig/filters/native-filter.cc
@@ -0,0 +1,747 @@
+// Copyright (C) 2003 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.
+
+#include "native-filter.h"
+
+#include "../kig/kig_part.h"
+#include "../kig/kig_document.h"
+#include "../objects/bogus_imp.h"
+#include "../objects/object_type.h"
+#include "../objects/object_imp.h"
+#include "../objects/object_calcer.h"
+#include "../objects/object_drawer.h"
+#include "../objects/object_holder.h"
+#include "../objects/object_type_factory.h"
+#include "../objects/object_imp_factory.h"
+#include "../misc/calcpaths.h"
+#include "../misc/coordinate_system.h"
+
+#include "config.h"
+
+#include <qdom.h>
+#include <qfile.h>
+#include <qregexp.h>
+
+#include <karchive.h>
+#include <kdebug.h>
+#include <kglobal.h>
+#include <kstandarddirs.h>
+#include <ktar.h>
+
+#include <stdio.h>
+
+#include <vector>
+#include <algorithm>
+#include <map>
+
+struct HierElem
+{
+ int id;
+ std::vector<int> parents;
+ QDomElement el;
+};
+
+static void extendVect( std::vector<HierElem>& vect, uint size )
+{
+ if ( size > vect.size() )
+ {
+ int osize = vect.size();
+ vect.resize( size );
+ for ( uint i = osize; i < size; ++i )
+ vect[i].id = i+1;
+ };
+}
+
+static void visitElem( std::vector<HierElem>& ret,
+ const std::vector<HierElem>& elems,
+ std::vector<bool>& seen,
+ int i )
+{
+ if ( !seen[i] )
+ {
+ for ( uint j = 0; j < elems[i].parents.size(); ++j )
+ visitElem( ret, elems, seen, elems[i].parents[j] - 1);
+ ret.push_back( elems[i] );
+ seen[i] = true;
+ };
+}
+
+static std::vector<HierElem> sortElems( const std::vector<HierElem> elems )
+{
+ std::vector<HierElem> ret;
+ std::vector<bool> seenElems( elems.size(), false );
+ for ( uint i = 0; i < elems.size(); ++i )
+ visitElem( ret, elems, seenElems, i );
+ return ret;
+}
+
+KigFilterNative::KigFilterNative()
+{
+}
+
+KigFilterNative::~KigFilterNative()
+{
+}
+
+bool KigFilterNative::supportMime( const QString& mime )
+{
+ return mime == "application/x-kig";
+}
+
+KigDocument* KigFilterNative::load( const QString& file )
+{
+ QFile ffile( file );
+ if ( ! ffile.open( IO_ReadOnly ) )
+ {
+ fileNotFound( file );
+ return 0;
+ };
+
+ QFile kigdoc( file );
+#ifndef KIG_NO_COMPRESSED_FILES
+ bool iscompressed = false;
+ if ( !file.endsWith( ".kig", false ) )
+ {
+ // the file is compressed, so we have to decompress it and fetch the
+ // kig file inside it...
+ iscompressed = true;
+
+ QString tempdir = KGlobal::dirs()->saveLocation( "tmp" );
+ if ( tempdir.isEmpty() )
+ KIG_FILTER_PARSE_ERROR;
+
+ QString tempname = file.section( '/', -1 );
+ if ( file.endsWith( ".kigz", false ) )
+ {
+ tempname.remove( QRegExp( "\\.[Kk][Ii][Gg][Zz]$" ) );
+ }
+ else
+ KIG_FILTER_PARSE_ERROR;
+ // reading compressed file
+ KTar* ark = new KTar( file, "application/x-gzip" );
+ ark->open( IO_ReadOnly );
+ const KArchiveDirectory* dir = ark->directory();
+// assert( dir );
+ QStringList entries = dir->entries();
+ QStringList kigfiles = entries.grep( QRegExp( "\\.kig$" ) );
+ if ( kigfiles.count() != 1 )
+ // I throw a generic parse error here, but I should warn the user that
+ // this kig archive file doesn't contain one kig file (it contains no
+ // kig files or more than one).
+ KIG_FILTER_PARSE_ERROR;
+ const KArchiveEntry* kigz = dir->entry( kigfiles[0] );
+ if ( !kigz->isFile() )
+ KIG_FILTER_PARSE_ERROR;
+ dynamic_cast<const KArchiveFile*>( kigz )->copyTo( tempdir );
+ kdDebug() << "extracted file: " << tempdir + kigz->name() << endl
+ << "exists: " << QFile::exists( tempdir + kigz->name() ) << endl;
+
+ kigdoc.setName( tempdir + kigz->name() );
+ }
+#endif
+
+ if ( !kigdoc.open( IO_ReadOnly ) )
+ KIG_FILTER_PARSE_ERROR;
+
+ QDomDocument doc( "KigDocument" );
+ if ( !doc.setContent( &kigdoc ) )
+ KIG_FILTER_PARSE_ERROR;
+ kigdoc.close();
+
+#ifndef KIG_NO_COMPRESSED_FILES
+ // removing temp file
+ if ( iscompressed )
+ kigdoc.remove();
+#endif
+
+ QDomElement main = doc.documentElement();
+
+ QString version = main.attribute( "CompatibilityVersion" );
+ if ( version.isEmpty() ) version = main.attribute( "Version" );
+ if ( version.isEmpty() ) version = main.attribute( "version" );
+ if ( version.isEmpty() )
+ KIG_FILTER_PARSE_ERROR;
+
+ // matches 0.1, 0.2.0, 153.128.99 etc.
+ QRegExp versionre( "(\\d+)\\.(\\d+)(\\.(\\d+))?" );
+ if ( ! versionre.exactMatch( version ) )
+ KIG_FILTER_PARSE_ERROR;
+ bool ok = true;
+ int major = versionre.cap( 1 ).toInt( &ok );
+ bool ok2 = true;
+ int minor = versionre.cap( 2 ).toInt( &ok2 );
+ if ( ! ok || ! ok2 )
+ KIG_FILTER_PARSE_ERROR;
+
+ // int minorminor = versionre.cap( 4 ).toInt( &ok );
+
+ // we only support 0.[0-7] and 1.0.*
+ if ( major > 0 || minor > 9 )
+ {
+ notSupported( file, i18n( "This file was created by Kig version \"%1\", "
+ "which this version cannot open." ).arg( version ) );
+ return false;
+ }
+ else if ( major == 0 && minor <= 3 )
+ {
+ notSupported( file, i18n( "This file was created by Kig version \"%1\".\n"
+ "Support for older Kig formats (pre-0.4) has been "
+ "removed from Kig.\n"
+ "You can try to open this file with an older Kig "
+ "version (0.4 to 0.6),\n"
+ "and then save it again, which will save it in the "
+ "new format." ).arg( version ) );
+ return false;
+ }
+ else if ( major == 0 && minor <= 6 )
+ return load04( file, main );
+ else
+ return load07( file, main );
+}
+
+KigDocument* KigFilterNative::load04( const QString& file, const QDomElement& docelem )
+{
+ bool ok = true;
+
+ KigDocument* ret = new KigDocument();
+
+ for ( QDomNode n = docelem.firstChild(); ! n.isNull(); n = n.nextSibling() )
+ {
+ QDomElement e = n.toElement();
+ if ( e.isNull() ) continue;
+ if ( e.tagName() == "CoordinateSystem" )
+ {
+ const QCString type = e.text().latin1();
+ CoordinateSystem* s = CoordinateSystemFactory::build( type );
+ if ( ! s )
+ {
+ warning( i18n( "This Kig file has a coordinate system "
+ "that this Kig version does not support.\n"
+ "A standard coordinate system will be used "
+ "instead." ) );
+ }
+ else ret->setCoordinateSystem( s );
+ }
+ else if ( e.tagName() == "Objects" )
+ {
+ std::vector<ObjectCalcer*> retcalcers;
+ std::vector<ObjectHolder*> retholders;
+
+ // first pass: do a topological sort of the objects, to support
+ // randomly ordered files...
+ std::vector<HierElem> elems;
+ QDomElement objectselem = e;
+ for ( QDomNode o = objectselem.firstChild(); ! o.isNull(); o = o.nextSibling() )
+ {
+ e = o.toElement();
+ if ( e.isNull() ) continue;
+ uint id;
+ if ( e.tagName() == "Data" || e.tagName() == "Property" || e.tagName() == "Object" )
+ {
+ // fetch the id
+ QString tmp = e.attribute("id");
+ id = tmp.toInt(&ok);
+ if ( !ok ) KIG_FILTER_PARSE_ERROR;
+
+ extendVect( elems, id );
+ elems[id-1].el = e;
+ }
+ else continue;
+
+ for ( QDomNode p = e.firstChild(); !p.isNull(); p = p.nextSibling() )
+ {
+ QDomElement f = p.toElement();
+ if ( f.isNull() ) continue;
+ if ( f.tagName() == "Parent" )
+ {
+ QString tmp = f.attribute( "id" );
+ uint pid = tmp.toInt( &ok );
+ if ( ! ok ) KIG_FILTER_PARSE_ERROR;
+
+ extendVect( elems, id );
+ elems[id-1].parents.push_back( pid );
+ }
+ }
+ };
+
+ for ( uint i = 0; i < elems.size(); ++i )
+ if ( elems[i].el.isNull() )
+ KIG_FILTER_PARSE_ERROR;
+ elems = sortElems( elems );
+
+ retcalcers.resize( elems.size(), 0 );
+
+ for ( std::vector<HierElem>::iterator i = elems.begin();
+ i != elems.end(); ++i )
+ {
+ QDomElement e = i->el;
+ bool internal = e.attribute( "internal" ) == "true" ? true : false;
+ ObjectCalcer* o = 0;
+ if ( e.tagName() == "Data" )
+ {
+ QString tmp = e.attribute( "type" );
+ if ( tmp.isNull() )
+ KIG_FILTER_PARSE_ERROR;
+ QString error;
+ ObjectImp* imp = ObjectImpFactory::instance()->deserialize( tmp, e, error );
+ if ( ( !imp ) && !error.isEmpty() )
+ {
+ parseError( file, error );
+ return false;
+ }
+ o = new ObjectConstCalcer( imp );
+ }
+ else if ( e.tagName() == "Property" )
+ {
+ QCString propname;
+ for ( QDomElement ec = e.firstChild().toElement(); !ec.isNull();
+ ec = ec.nextSibling().toElement() )
+ {
+ if ( ec.tagName() == "Property" )
+ propname = ec.text().latin1();
+ };
+
+ if ( i->parents.size() != 1 ) KIG_FILTER_PARSE_ERROR;
+ ObjectCalcer* parent = retcalcers[i->parents[0] -1];
+ QCStringList propnames = parent->imp()->propertiesInternalNames();
+ int propid = propnames.findIndex( propname );
+ if ( propid == -1 )
+ KIG_FILTER_PARSE_ERROR;
+
+ o = new ObjectPropertyCalcer( parent, propid );
+ }
+ else if ( e.tagName() == "Object" )
+ {
+ QString tmp = e.attribute( "type" );
+ if ( tmp.isNull() )
+ KIG_FILTER_PARSE_ERROR;
+
+ const ObjectType* type =
+ ObjectTypeFactory::instance()->find( tmp.latin1() );
+ if ( !type )
+ {
+ notSupported( file, i18n( "This Kig file uses an object of type \"%1\", "
+ "which this Kig version does not support."
+ "Perhaps you have compiled Kig without support "
+ "for this object type,"
+ "or perhaps you are using an older Kig version." ).arg( tmp ) );
+ return false;
+ };
+
+ std::vector<ObjectCalcer*> parents;
+ for ( std::vector<int>::iterator j = i->parents.begin();
+ j != i->parents.end(); ++j )
+ parents.push_back( retcalcers[*j - 1] );
+
+ o = new ObjectTypeCalcer( type, parents );
+ }
+ else continue;
+
+ o->calc( *ret );
+ retcalcers[i->id - 1] = o;
+
+ if ( ! internal )
+ {
+ QString tmp = e.attribute( "color" );
+ QColor color( tmp );
+ if ( !color.isValid() )
+ KIG_FILTER_PARSE_ERROR;
+
+ tmp = e.attribute( "shown" );
+ bool shown = !( tmp == "false" || tmp == "no" );
+
+ tmp = e.attribute( "width" );
+ int width = tmp.toInt( &ok );
+ if ( ! ok ) width = -1;
+
+ ObjectDrawer* d = new ObjectDrawer( color, width, shown );
+ retholders.push_back( new ObjectHolder( o, d ) );
+ }
+ }
+ ret->addObjects( retholders );
+ }
+ else continue; // be forward-compatible..
+ };
+
+ return ret;
+}
+
+KigFilterNative* KigFilterNative::instance()
+{
+ static KigFilterNative f;
+ return &f;
+}
+
+KigDocument* KigFilterNative::load07( const QString& file, const QDomElement& docelem )
+{
+ KigDocument* ret = new KigDocument();
+
+ bool ok = true;
+ std::vector<ObjectCalcer::shared_ptr> calcers;
+ std::vector<ObjectHolder*> holders;
+
+ QString t = docelem.attribute( "grid" );
+ bool tmphide = ( t == "false" ) || ( t == "no" ) || ( t == "0" );
+ ret->setGrid( !tmphide );
+ t = docelem.attribute( "axes" );
+ tmphide = ( t == "false" ) || ( t == "no" ) || ( t == "0" );
+ ret->setAxes( !tmphide );
+
+ for ( QDomElement subsectionelement = docelem.firstChild().toElement(); ! subsectionelement.isNull();
+ subsectionelement = subsectionelement.nextSibling().toElement() )
+ {
+ if ( subsectionelement.tagName() == "CoordinateSystem" )
+ {
+ QString tmptype = subsectionelement.text();
+ // compatibility code - to support Invisible coord system...
+ if ( tmptype == "Invisible" )
+ {
+ tmptype = "Euclidean";
+ ret->setGrid( false );
+ ret->setAxes( false );
+ }
+ const QCString type = tmptype.latin1();
+ CoordinateSystem* s = CoordinateSystemFactory::build( type );
+ if ( ! s )
+ {
+ warning( i18n( "This Kig file has a coordinate system "
+ "that this Kig version does not support.\n"
+ "A standard coordinate system will be used "
+ "instead." ) );
+ }
+ else ret->setCoordinateSystem( s );
+ }
+ else if ( subsectionelement.tagName() == "Hierarchy" )
+ {
+ for ( QDomElement e = subsectionelement.firstChild().toElement(); ! e.isNull();
+ e = e.nextSibling().toElement() )
+ {
+ QString tmp = e.attribute( "id" );
+ uint id = tmp.toInt( &ok );
+ if ( id <= 0 ) KIG_FILTER_PARSE_ERROR;
+
+ std::vector<ObjectCalcer*> parents;
+ for ( QDomElement parentel = e.firstChild().toElement(); ! parentel.isNull();
+ parentel = parentel.nextSibling().toElement() )
+ {
+ if ( parentel.tagName() != "Parent" ) continue;
+ QString tmp = parentel.attribute( "id" );
+ uint parentid = tmp.toInt( &ok );
+ if ( ! ok ) KIG_FILTER_PARSE_ERROR;
+ if ( parentid == 0 || parentid > calcers.size() ) KIG_FILTER_PARSE_ERROR;
+ ObjectCalcer* parent = calcers[parentid - 1].get();
+ if ( ! parent ) KIG_FILTER_PARSE_ERROR;
+ parents.push_back( parent );
+ }
+
+ ObjectCalcer* o = 0;
+
+ if ( e.tagName() == "Data" )
+ {
+ if ( !parents.empty() ) KIG_FILTER_PARSE_ERROR;
+ QString tmp = e.attribute( "type" );
+ QString error;
+ ObjectImp* imp = ObjectImpFactory::instance()->deserialize( tmp, e, error );
+ if ( ( !imp ) && !error.isEmpty() )
+ {
+ parseError( file, error );
+ return false;
+ }
+ o = new ObjectConstCalcer( imp );
+ }
+ else if ( e.tagName() == "Property" )
+ {
+ if ( parents.size() != 1 ) KIG_FILTER_PARSE_ERROR;
+ QCString propname = e.attribute( "which" ).latin1();
+
+ ObjectCalcer* parent = parents[0];
+ int propid = parent->imp()->propertiesInternalNames().findIndex( propname );
+ if ( propid == -1 ) KIG_FILTER_PARSE_ERROR;
+
+ o = new ObjectPropertyCalcer( parent, propid );
+ }
+ else if ( e.tagName() == "Object" )
+ {
+ QString tmp = e.attribute( "type" );
+ const ObjectType* type =
+ ObjectTypeFactory::instance()->find( tmp.latin1() );
+ if ( ! type )
+ {
+ notSupported( file, i18n( "This Kig file uses an object of type \"%1\", "
+ "which this Kig version does not support."
+ "Perhaps you have compiled Kig without support "
+ "for this object type,"
+ "or perhaps you are using an older Kig version." ).arg( tmp ) );
+ return false;
+ }
+
+ // mp: (I take the responsibility for this!) explanation: the usual ObjectTypeCalcer
+ // constructor also "sortArgs" the parents. I believe that this *must not* be done
+ // when loading from a saved kig file for the following reasons:
+ // 1. the arguments should already be in their intended order, since the file was
+ // saved from a working hierarchy; furthermore we actually want to restore the original
+ // hierarchy, not really to also fix possible problems with the original hierarchy;
+ // 2. calling sortArgs could have undesirable side effects in particular situations,
+ // since kig actually allow an ObjectType to produce different type of ObjectImp's
+ // it may happen that the parents of an object do not satisfy the requirements
+ // enforced by sortArgs (while moving around the free objects) but still be
+ // perfectly valid
+ o = new ObjectTypeCalcer( type, parents, false );
+ }
+ else KIG_FILTER_PARSE_ERROR;
+
+ o->calc( *ret );
+ calcers.resize( id, 0 );
+ calcers[id-1] = o;
+ }
+ }
+ else if ( subsectionelement.tagName() == "View" )
+ {
+ for ( QDomElement e = subsectionelement.firstChild().toElement(); ! e.isNull();
+ e = e.nextSibling().toElement() )
+ {
+ if ( e.tagName() != "Draw" ) KIG_FILTER_PARSE_ERROR;
+
+ QString tmp = e.attribute( "object" );
+ uint id = tmp.toInt( &ok );
+ if ( !ok ) KIG_FILTER_PARSE_ERROR;
+ if ( id <= 0 || id > calcers.size() )
+ KIG_FILTER_PARSE_ERROR;
+ ObjectCalcer* calcer = calcers[id-1].get();
+
+ tmp = e.attribute( "color" );
+ QColor color( tmp );
+ if ( !color.isValid() )
+ KIG_FILTER_PARSE_ERROR;
+
+ tmp = e.attribute( "shown" );
+ bool shown = !( tmp == "false" || tmp == "no" );
+
+ tmp = e.attribute( "width" );
+ int width = tmp.toInt( &ok );
+ if ( ! ok ) width = -1;
+
+ tmp = e.attribute( "style" );
+ Qt::PenStyle style = ObjectDrawer::styleFromString( tmp );
+
+ tmp = e.attribute( "point-style" );
+ int pointstyle = ObjectDrawer::pointStyleFromString( tmp );
+
+ ObjectConstCalcer* namecalcer = 0;
+ tmp = e.attribute( "namecalcer" );
+ if ( tmp != "none" && !tmp.isEmpty() )
+ {
+ int ncid = tmp.toInt( &ok );
+ if ( !ok ) KIG_FILTER_PARSE_ERROR;
+ if ( ncid <= 0 || ncid > calcers.size() )
+ KIG_FILTER_PARSE_ERROR;
+ if ( ! dynamic_cast<ObjectConstCalcer*>( calcers[ncid-1].get() ) )
+ KIG_FILTER_PARSE_ERROR;
+ namecalcer = static_cast<ObjectConstCalcer*>( calcers[ncid-1].get() );
+ }
+
+ ObjectDrawer* drawer = new ObjectDrawer( color, width, shown, style, pointstyle );
+ holders.push_back( new ObjectHolder( calcer, drawer, namecalcer ) );
+ }
+ }
+ }
+
+ ret->addObjects( holders );
+ return ret;
+}
+
+bool KigFilterNative::save07( const KigDocument& kdoc, QTextStream& stream )
+{
+ QDomDocument doc( "KigDocument" );
+
+ QDomElement docelem = doc.createElement( "KigDocument" );
+ docelem.setAttribute( "Version", KIGVERSION );
+ docelem.setAttribute( "CompatibilityVersion", "0.7.0" );
+ docelem.setAttribute( "grid", kdoc.grid() );
+ docelem.setAttribute( "axes", kdoc.axes() );
+
+ QDomElement cselem = doc.createElement( "CoordinateSystem" );
+ cselem.appendChild( doc.createTextNode( kdoc.coordinateSystem().type() ) );
+ docelem.appendChild( cselem );
+
+ std::vector<ObjectHolder*> holders = kdoc.objects();
+ std::vector<ObjectCalcer*> calcers = getAllParents( getAllCalcers( holders ) );
+ calcers = calcPath( calcers );
+
+ QDomElement hierelem = doc.createElement( "Hierarchy" );
+ std::map<const ObjectCalcer*, int> idmap;
+ for ( std::vector<ObjectCalcer*>::const_iterator i = calcers.begin();
+ i != calcers.end(); ++i )
+ idmap[*i] = ( i - calcers.begin() ) + 1;
+ int id = 1;
+
+ for ( std::vector<ObjectCalcer*>::const_iterator i = calcers.begin(); i != calcers.end(); ++i )
+ {
+ QDomElement objectelem;
+ if ( dynamic_cast<ObjectConstCalcer*>( *i ) )
+ {
+ objectelem = doc.createElement( "Data" );
+ QString ser =
+ ObjectImpFactory::instance()->serialize( *(*i)->imp(), objectelem, doc );
+ objectelem.setAttribute( "type", ser );
+ }
+ else if ( dynamic_cast<const ObjectPropertyCalcer*>( *i ) )
+ {
+ const ObjectPropertyCalcer* o = static_cast<const ObjectPropertyCalcer*>( *i );
+ objectelem = doc.createElement( "Property" );
+
+ QCString propname = o->parent()->imp()->propertiesInternalNames()[o->propId()];
+ objectelem.setAttribute( "which", propname );
+ }
+ else if ( dynamic_cast<const ObjectTypeCalcer*>( *i ) )
+ {
+ const ObjectTypeCalcer* o = static_cast<const ObjectTypeCalcer*>( *i );
+ objectelem = doc.createElement( "Object" );
+ objectelem.setAttribute( "type", o->type()->fullName() );
+ }
+ else assert( false );
+
+ const std::vector<ObjectCalcer*> parents = ( *i )->parents();
+ for ( std::vector<ObjectCalcer*>::const_iterator i = parents.begin(); i != parents.end(); ++i )
+ {
+ std::map<const ObjectCalcer*,int>::const_iterator idp = idmap.find( *i );
+ assert( idp != idmap.end() );
+ int pid = idp->second;
+ QDomElement pel = doc.createElement( "Parent" );
+ pel.setAttribute( "id", pid );
+ objectelem.appendChild( pel );
+ }
+
+ objectelem.setAttribute( "id", id++ );
+ hierelem.appendChild( objectelem );
+ }
+ docelem.appendChild( hierelem );
+
+ QDomElement windowelem = doc.createElement( "View" );
+ for ( std::vector<ObjectHolder*>::iterator i = holders.begin(); i != holders.end(); ++i )
+ {
+ std::map<const ObjectCalcer*,int>::const_iterator idp = idmap.find( ( *i )->calcer() );
+ assert( idp != idmap.end() );
+ int id = idp->second;
+
+ const ObjectDrawer* d = ( *i )->drawer();
+ QDomElement drawelem = doc.createElement( "Draw" );
+ drawelem.setAttribute( "object", id );
+ drawelem.setAttribute( "color", d->color().name() );
+ drawelem.setAttribute( "shown", QString::fromLatin1( d->shown() ? "true" : "false" ) );
+ drawelem.setAttribute( "width", QString::number( d->width() ) );
+ drawelem.setAttribute( "style", d->styleToString() );
+ drawelem.setAttribute( "point-style", d->pointStyleToString() );
+
+ ObjectCalcer* namecalcer = ( *i )->nameCalcer();
+ if ( namecalcer )
+ {
+ std::map<const ObjectCalcer*,int>::const_iterator ncp = idmap.find( namecalcer );
+ assert( ncp != idmap.end() );
+ int ncid = ncp->second;
+ drawelem.setAttribute( "namecalcer", ncid );
+ }
+ else
+ {
+ drawelem.setAttribute( "namecalcer", "none" );
+ }
+
+ windowelem.appendChild( drawelem );
+ };
+ docelem.appendChild( windowelem );
+
+ doc.appendChild( docelem );
+ stream << doc.toString();
+ return true;
+}
+
+bool KigFilterNative::save( const KigDocument& data, const QString& file )
+{
+ return save07( data, file );
+}
+
+bool KigFilterNative::save07( const KigDocument& data, const QString& outfile )
+{
+ // we have an empty outfile, so we have to print all to stdout
+ if ( outfile.isEmpty() )
+ {
+ QTextStream stdoutstream( stdout, IO_WriteOnly );
+ return save07( data, stdoutstream );
+ }
+#ifndef KIG_NO_COMPRESSED_FILES
+ if ( !outfile.endsWith( ".kig", false ) )
+ {
+ // the user wants to save a compressed file, so we have to save our kig
+ // file to a temp file and then compress it...
+
+ QString tempdir = KGlobal::dirs()->saveLocation( "tmp" );
+ if ( tempdir.isEmpty() )
+ return false;
+
+ QString tempname = outfile.section( '/', -1 );
+ if ( outfile.endsWith( ".kigz", false ) )
+ tempname.remove( QRegExp( "\\.[Kk][Ii][Gg][Zz]$" ) );
+ else
+ return false;
+
+ QString tmpfile = tempdir + tempname + ".kig";
+ QFile ftmpfile( tmpfile );
+ if ( !ftmpfile.open( IO_WriteOnly ) )
+ return false;
+ QTextStream stream( &ftmpfile );
+ if ( !save07( data, stream ) )
+ return false;
+ ftmpfile.close();
+
+ kdDebug() << "tmp saved file: " << tmpfile << endl;
+
+ // creating the archive and adding our file
+ KTar* ark = new KTar( outfile, "application/x-gzip" );
+ ark->open( IO_WriteOnly );
+ ark->addLocalFile( tmpfile, tempname + ".kig" );
+ ark->close();
+
+ // finally, removing temp file
+ QFile::remove( tmpfile );
+
+ return true;
+ }
+ else
+ {
+#endif
+ QFile file( outfile );
+ if ( ! file.open( IO_WriteOnly ) )
+ {
+ fileNotFound( outfile );
+ return false;
+ }
+ QTextStream stream( &file );
+ return save07( data, stream );
+#ifndef KIG_NO_COMPRESSED_FILES
+ }
+
+ // we should never reach this point...
+ return false;
+#endif
+}
+
+/*
+bool KigFilterNative::save( const KigDocument& data, QTextStream& stream )
+{
+ return save07( data, stream );
+}
+*/
diff --git a/kig/filters/native-filter.h b/kig/filters/native-filter.h
new file mode 100644
index 00000000..12778f35
--- /dev/null
+++ b/kig/filters/native-filter.h
@@ -0,0 +1,66 @@
+// Copyright (C) 2003 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_FILTERS_NATIVE_FILTER_H
+#define KIG_FILTERS_NATIVE_FILTER_H
+
+#include "filter.h"
+
+class QDomElement;
+class KigDocument;
+class QTextStream;
+class QString;
+
+/**
+ * Kig's native format. Between versions 0.3.1 and 0.4, there was a
+ * change in the file format. This filter no longer supports pre-0.4
+ * formats, it did up until Kig 0.6.
+ */
+class KigFilterNative
+ : public KigFilter
+{
+private:
+ /**
+ * this is the load function for the Kig format that is used,
+ * starting at Kig 0.4
+ */
+ KigDocument* load04( const QString& file, const QDomElement& doc );
+ /**
+ * this is the load function for the Kig format that is used
+ * starting at Kig 0.7
+ */
+ KigDocument* load07( const QString& file, const QDomElement& doc );
+
+ /**
+ * save in the Kig format that is used starting at Kig 0.7
+ */
+ bool save07( const KigDocument& data, const QString& outfile );
+ bool save07( const KigDocument& data, QTextStream& file );
+
+ KigFilterNative();
+ ~KigFilterNative();
+public:
+ static KigFilterNative* instance();
+
+ bool supportMime( const QString& mime );
+ KigDocument* load( const QString& file );
+
+ bool save( const KigDocument& data, const QString& file );
+// bool save( const KigDocument& data, QTextStream& stream );
+};
+
+#endif
diff --git a/kig/filters/svgexporter.cc b/kig/filters/svgexporter.cc
new file mode 100644
index 00000000..6e945de2
--- /dev/null
+++ b/kig/filters/svgexporter.cc
@@ -0,0 +1,111 @@
+// Copyright (C) 2004 Pino Toscano <toscano.pino@tiscali.it>
+
+// 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.
+
+#include "svgexporter.h"
+
+#include "svgexporteroptions.h"
+
+#include "../kig/kig_document.h"
+#include "../kig/kig_part.h"
+#include "../kig/kig_view.h"
+#include "../misc/common.h"
+#include "../misc/kigfiledialog.h"
+#include "../misc/kigpainter.h"
+
+#include <qcheckbox.h>
+#include <qfile.h>
+#include <qpicture.h>
+#include <qrect.h>
+
+#include <klocale.h>
+#include <kmessagebox.h>
+
+#include <map>
+
+SVGExporter::~SVGExporter()
+{
+}
+
+QString SVGExporter::exportToStatement() const
+{
+ return i18n( "&Export to SVG..." );
+}
+
+QString SVGExporter::menuEntryName() const
+{
+ return i18n( "&SVG..." );
+}
+
+QString SVGExporter::menuIcon() const
+{
+ // TODO
+ return "vectorgfx";
+}
+
+void SVGExporter::run( const KigPart& part, KigWidget& w )
+{
+ KigFileDialog* kfd = new KigFileDialog(
+ QString::null, i18n( "*.svg|Scalable Vector Graphics (*.svg)" ),
+ i18n( "Export as SVG" ), &w );
+ kfd->setOptionCaption( i18n( "SVG Options" ) );
+ SVGExporterOptions* opts = new SVGExporterOptions( 0L );
+ kfd->setOptionsWidget( opts );
+ opts->showGridCheckBox->setChecked( part.document().grid() );
+ opts->showAxesCheckBox->setChecked( part.document().axes() );
+ if ( !kfd->exec() )
+ return;
+
+ QString file_name = kfd->selectedFile();
+ bool showgrid = opts->showGridCheckBox->isOn();
+ bool showaxes = opts->showAxesCheckBox->isOn();
+
+ delete opts;
+ delete kfd;
+
+ QFile file( file_name );
+ if ( ! file.open( IO_WriteOnly ) )
+ {
+ KMessageBox::sorry( &w, i18n( "The file \"%1\" could not be opened. Please "
+ "check if the file permissions are set correctly." )
+ .arg( file_name ) );
+ return;
+ };
+
+ QRect viewrect( w.screenInfo().viewRect() );
+ QRect r( 0, 0, viewrect.width(), viewrect.height() );
+
+ QPicture pic;
+ pic.setBoundingRect( r );
+ KigPainter* p = new KigPainter( ScreenInfo( w.screenInfo().shownRect(), viewrect ),
+ &pic, part.document() );
+// p->setWholeWinOverlay();
+// p->setBrushColor( Qt::white );
+// p->setBrushStyle( Qt::SolidPattern );
+// p->drawRect( r );
+// p->setBrushStyle( Qt::NoBrush );
+// p->setWholeWinOverlay();
+ p->drawGrid( part.document().coordinateSystem(), showgrid, showaxes );
+ p->drawObjects( part.document().objects(), false );
+
+ delete p;
+
+ if ( !pic.save( file_name, "SVG" ) )
+ {
+ KMessageBox::error( &w, i18n( "Sorry, something went wrong while saving to SVG file \"%1\"" ).arg( file_name ) );
+ }
+
+}
diff --git a/kig/filters/svgexporter.h b/kig/filters/svgexporter.h
new file mode 100644
index 00000000..17193673
--- /dev/null
+++ b/kig/filters/svgexporter.h
@@ -0,0 +1,41 @@
+// Copyright (C) 2004 Pino Toscano <toscano.pino@tiscali.it>
+
+// 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_FILTERS_SVGEXPORTER_H
+#define KIG_FILTERS_SVGEXPORTER_H
+
+#include "exporter.h"
+
+class QString;
+class KigPart;
+class KigWidget;
+
+/**
+ * Export to Scalable Vector Graphics (SVG)
+ */
+class SVGExporter
+ : public KigExporter
+{
+public:
+ ~SVGExporter();
+ QString exportToStatement() const;
+ QString menuEntryName() const;
+ QString menuIcon() const;
+ void run( const KigPart& part, KigWidget& w );
+};
+
+#endif
diff --git a/kig/filters/svgexporteroptions.ui b/kig/filters/svgexporteroptions.ui
new file mode 100644
index 00000000..2de679cb
--- /dev/null
+++ b/kig/filters/svgexporteroptions.ui
@@ -0,0 +1,61 @@
+<!DOCTYPE UI><UI version="3.2" stdsetdef="1">
+<class>SVGExporterOptions</class>
+<widget class="QWidget">
+ <property name="name">
+ <cstring>SVGExporterOptions</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>440</width>
+ <height>200</height>
+ </rect>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <widget class="QGroupBox">
+ <property name="name">
+ <cstring>groupBox1</cstring>
+ </property>
+ <property name="title">
+ <string>Options</string>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QCheckBox" row="0" column="0">
+ <property name="name">
+ <cstring>showGridCheckBox</cstring>
+ </property>
+ <property name="text">
+ <string>Show grid</string>
+ </property>
+ </widget>
+ <widget class="QCheckBox" row="0" column="1">
+ <property name="name">
+ <cstring>showAxesCheckBox</cstring>
+ </property>
+ <property name="text">
+ <string>Show axes</string>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ </vbox>
+</widget>
+<customwidgets>
+</customwidgets>
+<layoutdefaults spacing="6" margin="11"/>
+<includehints>
+</includehints>
+</UI>
diff --git a/kig/filters/tests/circleBCP.FIG b/kig/filters/tests/circleBCP.FIG
new file mode 100644
index 00000000..aeaa9689
--- /dev/null
+++ b/kig/filters/tests/circleBCP.FIG
@@ -0,0 +1,24 @@
+FIGURE CabriII vers. MS-Windows 1.0
+
+Window center x: 0 y: 0 Window size x: 16.2983333333333 y: 9.68375
+
+1: Pt, 0, CN:0, VN:1
+R, W, t, DS:1 1, GT:1, I, nSt
+Val: 0 0
+
+2: Axes, 1, CN:1, VN:3
+Gr, W, t, DS:1 1, GT:0, I, nSt
+Const: 1, Val: 1 0, 0 1
+
+3: Pt, 0, CN:0, VN:1
+R, W, t, DS:1 1, GT:1, V, nSt
+Val: -4.89479166666667 0.291041666666667
+
+4: Pt, 0, CN:0, VN:1
+R, W, t, DS:1 1, GT:1, V, nSt
+Val: -1.61395833333333 2.43416666666667
+
+5: Cir, 0, CN:2, VN:2
+Bl, W, t, DS:1 1, GT:0, V, nSt
+Const: 3 4
+
diff --git a/kig/filters/tests/constrainedPoint.FIG b/kig/filters/tests/constrainedPoint.FIG
new file mode 100644
index 00000000..ac086421
--- /dev/null
+++ b/kig/filters/tests/constrainedPoint.FIG
@@ -0,0 +1,24 @@
+FIGURE CabriII vers. MS-Windows 1.0
+
+Window center x: 0 y: 0 Window size x: 16.2983333333333 y: 9.68375
+
+1: Pt, 0, CN:0, VN:1
+R, W, t, DS:1 1, GT:1, I, nSt
+Val: 0 0
+
+2: Axes, 1, CN:1, VN:3
+Gr, W, t, DS:1 1, GT:0, I, nSt
+Const: 1, Val: 1 0, 0 1
+
+3: Pt, 0, CN:0, VN:1
+R, W, t, DS:1 1, GT:1, V, nSt
+Val: -5.18583333333333 1.11125
+
+4: Line, 0, CN:1, VN:2
+V, W, t, DS:1 1, GT:0, V, nSt
+Const: 3, Val: 0.958665525176453 0.284535429846892
+
+5: Pt/, 0, CN:1, VN:3
+R, W, t, DS:1 1, GT:1, V, nSt
+Const: 4, Val: -2.80458333333333 1.81801369863014
+
diff --git a/kig/filters/tests/cubiclineintersect.kig b/kig/filters/tests/cubiclineintersect.kig
new file mode 100644
index 00000000..a157f611
--- /dev/null
+++ b/kig/filters/tests/cubiclineintersect.kig
@@ -0,0 +1,105 @@
+<!DOCTYPE KigDocument>
+<KigDocument Version="0.6.0" >
+ <CoordinateSystem>Euclidean</CoordinateSystem>
+ <Objects>
+ <Data internal="true" type="double" id="1" >-5.63522</Data>
+ <Data internal="true" type="double" id="2" >1.0566</Data>
+ <Data internal="true" type="double" id="3" >-1.49686</Data>
+ <Data internal="true" type="double" id="4" >2.33333</Data>
+ <Data internal="true" type="double" id="5" >-1.14465</Data>
+ <Data internal="true" type="double" id="6" >-0.220126</Data>
+ <Data internal="true" type="double" id="7" >-4.66667</Data>
+ <Data internal="true" type="double" id="8" >-1.14465</Data>
+ <Data internal="true" type="double" id="9" >-8.1927</Data>
+ <Data internal="true" type="double" id="10" >-2.01515</Data>
+ <Data internal="true" type="double" id="11" >-8.36478</Data>
+ <Data internal="true" type="double" id="12" >1.36478</Data>
+ <Data internal="true" type="double" id="13" >-7.48428</Data>
+ <Data internal="true" type="double" id="14" >2.64151</Data>
+ <Data internal="true" type="double" id="15" >-4.88679</Data>
+ <Data internal="true" type="double" id="16" >3.12579</Data>
+ <Data internal="true" type="double" id="17" >-3.03774</Data>
+ <Data internal="true" type="double" id="18" >1.49686</Data>
+ <Data internal="true" type="double" id="19" >-6.25157</Data>
+ <Data internal="true" type="double" id="20" >3.91824</Data>
+ <Data internal="true" type="double" id="21" >-2.06918</Data>
+ <Data internal="true" type="double" id="22" >-3.47799</Data>
+ <Data internal="true" type="int" id="23" >1</Data>
+ <Data internal="true" type="int" id="24" >2</Data>
+ <Data internal="true" type="int" id="25" >3</Data>
+ <Object width="5" internal="false" shown="true" type="FixedPoint" id="26" color="#0000ff" >
+ <Parent id="1" />
+ <Parent id="2" />
+ </Object>
+ <Object width="5" internal="false" shown="true" type="FixedPoint" id="27" color="#0000ff" >
+ <Parent id="3" />
+ <Parent id="4" />
+ </Object>
+ <Object width="5" internal="false" shown="true" type="FixedPoint" id="28" color="#0000ff" >
+ <Parent id="5" />
+ <Parent id="6" />
+ </Object>
+ <Object width="5" internal="false" shown="true" type="FixedPoint" id="29" color="#0000ff" >
+ <Parent id="7" />
+ <Parent id="8" />
+ </Object>
+ <Object width="5" internal="false" shown="true" type="FixedPoint" id="30" color="#0000ff" >
+ <Parent id="9" />
+ <Parent id="10" />
+ </Object>
+ <Object width="5" internal="false" shown="true" type="FixedPoint" id="31" color="#0000ff" >
+ <Parent id="11" />
+ <Parent id="12" />
+ </Object>
+ <Object width="5" internal="false" shown="true" type="FixedPoint" id="32" color="#0000ff" >
+ <Parent id="13" />
+ <Parent id="14" />
+ </Object>
+ <Object width="5" internal="false" shown="true" type="FixedPoint" id="33" color="#0000ff" >
+ <Parent id="15" />
+ <Parent id="16" />
+ </Object>
+ <Object width="5" internal="false" shown="true" type="FixedPoint" id="34" color="#0000ff" >
+ <Parent id="17" />
+ <Parent id="18" />
+ </Object>
+ <Object width="5" internal="false" shown="true" type="FixedPoint" id="35" color="#0000ff" >
+ <Parent id="19" />
+ <Parent id="20" />
+ </Object>
+ <Object width="5" internal="false" shown="true" type="FixedPoint" id="36" color="#0000ff" >
+ <Parent id="21" />
+ <Parent id="22" />
+ </Object>
+ <Object width="-1" internal="false" shown="true" type="CubicB9P" id="37" color="#0000ff" >
+ <Parent id="26" />
+ <Parent id="27" />
+ <Parent id="28" />
+ <Parent id="29" />
+ <Parent id="30" />
+ <Parent id="31" />
+ <Parent id="32" />
+ <Parent id="33" />
+ <Parent id="34" />
+ </Object>
+ <Object width="-1" internal="false" shown="true" type="LineAB" id="38" color="#0000ff" >
+ <Parent id="35" />
+ <Parent id="36" />
+ </Object>
+ <Object width="-1" internal="false" shown="true" type="LineCubicIntersection" id="39" color="#0000ff" >
+ <Parent id="37" />
+ <Parent id="38" />
+ <Parent id="23" />
+ </Object>
+ <Object width="-1" internal="false" shown="true" type="LineCubicIntersection" id="40" color="#0000ff" >
+ <Parent id="37" />
+ <Parent id="38" />
+ <Parent id="24" />
+ </Object>
+ <Object width="-1" internal="false" shown="true" type="LineCubicIntersection" id="41" color="#0000ff" >
+ <Parent id="37" />
+ <Parent id="38" />
+ <Parent id="25" />
+ </Object>
+ </Objects>
+</KigDocument>
diff --git a/kig/filters/tests/intersectandasymptotestest.kig b/kig/filters/tests/intersectandasymptotestest.kig
new file mode 100644
index 00000000..d521e241
--- /dev/null
+++ b/kig/filters/tests/intersectandasymptotestest.kig
@@ -0,0 +1,111 @@
+<!DOCTYPE KigDocument>
+<KigDocument Version="0.6.0" >
+ <CoordinateSystem>Euclidean</CoordinateSystem>
+ <Objects>
+ <Data internal="true" type="double" id="1" >-6.73585</Data>
+ <Data internal="true" type="double" id="2" >-1.0566</Data>
+ <Data internal="true" type="double" id="3" >-2.92721</Data>
+ <Data internal="true" type="double" id="4" >2.22373</Data>
+ <Data internal="true" type="double" id="5" >-5.45912</Data>
+ <Data internal="true" type="double" id="6" >4.40252</Data>
+ <Data internal="true" type="double" id="7" >-6.16352</Data>
+ <Data internal="true" type="double" id="8" >2.11321</Data>
+ <Data internal="true" type="int" id="9" >-1</Data>
+ <Data internal="true" type="int" id="10" >1</Data>
+ <Data internal="true" type="double" id="11" >-12.1069</Data>
+ <Data internal="true" type="double" id="12" >1.0566</Data>
+ <Data internal="true" type="double" id="13" >2.50943</Data>
+ <Data internal="true" type="double" id="14" >-1.10063</Data>
+ <Data internal="true" type="int" id="15" >1</Data>
+ <Data internal="true" type="int" id="16" >-1</Data>
+ <Data internal="true" type="double" id="17" >1.84906</Data>
+ <Data internal="true" type="double" id="18" >1.45283</Data>
+ <Data internal="true" type="double" id="19" >7.04403</Data>
+ <Data internal="true" type="double" id="20" >1.49686</Data>
+ <Data internal="true" type="double" id="21" >6.42767</Data>
+ <Data internal="true" type="double" id="22" >-0.440252</Data>
+ <Data internal="true" type="int" id="23" >1</Data>
+ <Data internal="true" type="int" id="24" >-1</Data>
+ <Object width="5" internal="false" shown="true" type="FixedPoint" id="25" color="#0000ff" >
+ <Parent id="1" />
+ <Parent id="2" />
+ </Object>
+ <Object width="5" internal="false" shown="true" type="FixedPoint" id="26" color="#0000ff" >
+ <Parent id="3" />
+ <Parent id="4" />
+ </Object>
+ <Object width="5" internal="false" shown="true" type="FixedPoint" id="27" color="#0000ff" >
+ <Parent id="5" />
+ <Parent id="6" />
+ </Object>
+ <Object width="5" internal="false" shown="true" type="FixedPoint" id="28" color="#0000ff" >
+ <Parent id="7" />
+ <Parent id="8" />
+ </Object>
+ <Object width="5" internal="false" shown="true" type="FixedPoint" id="29" color="#0000ff" >
+ <Parent id="11" />
+ <Parent id="12" />
+ </Object>
+ <Object width="5" internal="false" shown="true" type="FixedPoint" id="30" color="#0000ff" >
+ <Parent id="13" />
+ <Parent id="14" />
+ </Object>
+ <Object width="5" internal="false" shown="true" type="FixedPoint" id="31" color="#0000ff" >
+ <Parent id="17" />
+ <Parent id="18" />
+ </Object>
+ <Object width="5" internal="false" shown="true" type="FixedPoint" id="32" color="#0000ff" >
+ <Parent id="19" />
+ <Parent id="20" />
+ </Object>
+ <Object width="5" internal="false" shown="true" type="FixedPoint" id="33" color="#0000ff" >
+ <Parent id="21" />
+ <Parent id="22" />
+ </Object>
+ <Object width="-1" internal="false" shown="true" type="CircleBCP" id="34" color="#0000ff" >
+ <Parent id="25" />
+ <Parent id="26" />
+ </Object>
+ <Object width="-1" internal="false" shown="true" type="SegmentAB" id="35" color="#0000ff" >
+ <Parent id="27" />
+ <Parent id="28" />
+ </Object>
+ <Object width="-1" internal="false" shown="true" type="LineAB" id="36" color="#0000ff" >
+ <Parent id="29" />
+ <Parent id="30" />
+ </Object>
+ <Object width="-1" internal="false" shown="true" type="HyperbolaBFFP" id="37" color="#0000ff" >
+ <Parent id="31" />
+ <Parent id="32" />
+ <Parent id="33" />
+ </Object>
+ <Object width="-1" internal="false" shown="true" type="ConicLineIntersection" id="38" color="#0000ff" >
+ <Parent id="34" />
+ <Parent id="35" />
+ <Parent id="9" />
+ </Object>
+ <Object width="-1" internal="false" shown="true" type="ConicLineIntersection" id="39" color="#0000ff" >
+ <Parent id="34" />
+ <Parent id="35" />
+ <Parent id="10" />
+ </Object>
+ <Object width="-1" internal="false" shown="true" type="ConicLineIntersection" id="40" color="#0000ff" >
+ <Parent id="34" />
+ <Parent id="36" />
+ <Parent id="15" />
+ </Object>
+ <Object width="-1" internal="false" shown="true" type="ConicLineIntersection" id="41" color="#0000ff" >
+ <Parent id="34" />
+ <Parent id="36" />
+ <Parent id="16" />
+ </Object>
+ <Object width="-1" internal="false" shown="true" type="ConicAsymptote" id="42" color="#0000ff" >
+ <Parent id="37" />
+ <Parent id="23" />
+ </Object>
+ <Object width="-1" internal="false" shown="true" type="ConicAsymptote" id="43" color="#0000ff" >
+ <Parent id="37" />
+ <Parent id="24" />
+ </Object>
+ </Objects>
+</KigDocument>
diff --git a/kig/filters/tests/intersection-test.seg b/kig/filters/tests/intersection-test.seg
new file mode 100644
index 00000000..44d69b70
--- /dev/null
+++ b/kig/filters/tests/intersection-test.seg
Binary files differ
diff --git a/kig/filters/tests/invisibleLine.FIG b/kig/filters/tests/invisibleLine.FIG
new file mode 100644
index 00000000..5eeb6ae3
--- /dev/null
+++ b/kig/filters/tests/invisibleLine.FIG
@@ -0,0 +1,32 @@
+FIGURE CabriII vers. MS-Windows 1.0
+
+Window center x: 0 y: 0 Window size x: 16.2983333333333 y: 9.68375
+
+1: Pt, 0, CN:0, VN:1
+R, W, t, DS:1 1, GT:1, I, nSt
+Val: 0 0
+
+2: Axes, 1, CN:1, VN:3
+Gr, W, t, DS:1 1, GT:0, I, nSt
+Const: 1, Val: 1 0, 0 1
+
+3: Pt, 0, CN:0, VN:1
+R, W, t, DS:1 1, GT:1, V, nSt
+Val: -5.159375 -0.608541666666667
+
+4: Pt, 0, CN:0, VN:1
+R, W, t, DS:1 1, GT:1, V, nSt
+Val: -2.91041666666667 3.54541666666667
+
+5: Pt, 0, CN:0, VN:1
+R, W, t, DS:1 1, GT:1, V, nSt
+Val: 2.19604166666667 0.79375
+
+6: Line, 0, CN:2, VN:2
+V, W, t, DS:1 1, GT:0, I, nSt
+Const: 5 3
+
+7: Perp, 0, CN:2, VN:2
+V, W, t, DS:1 1, GT:0, V, nSt
+Const: 4 6
+
diff --git a/kig/filters/tests/lineBTP.FIG b/kig/filters/tests/lineBTP.FIG
new file mode 100644
index 00000000..7926b787
--- /dev/null
+++ b/kig/filters/tests/lineBTP.FIG
@@ -0,0 +1,24 @@
+FIGURE CabriII vers. MS-Windows 1.0
+
+Window center x: 0 y: 0 Window size x: 16.2983333333333 y: 9.68375
+
+1: Pt, 0, CN:0, VN:1
+R, W, t, DS:1 1, GT:1, I, nSt
+Val: 0 0
+
+2: Axes, 1, CN:1, VN:3
+Gr, W, t, DS:1 1, GT:0, I, nSt
+Const: 1, Val: 1 0, 0 1
+
+3: Pt, 0, CN:0, VN:1
+R, W, t, DS:1 1, GT:1, V, nSt
+Val: -5.318125 2.16958333333333
+
+4: Pt, 0, CN:0, VN:1
+R, W, t, DS:1 1, GT:1, V, nSt
+Val: -1.29645833333333 3.01625
+
+5: Line, 0, CN:2, VN:2
+V, W, t, DS:1 1, GT:0, V, nSt
+Const: 3 4
+
diff --git a/kig/filters/tests/linebyonepoint.FIG b/kig/filters/tests/linebyonepoint.FIG
new file mode 100644
index 00000000..4cdac84e
--- /dev/null
+++ b/kig/filters/tests/linebyonepoint.FIG
@@ -0,0 +1,20 @@
+FIGURE CabriII vers. MS-Windows 1.0
+
+Window center x: 0 y: 0 Window size x: 16.2983333333333 y: 9.68375
+
+1: Pt, 0, CN:0, VN:1
+R, W, t, DS:1 1, GT:1, I, nSt
+Val: 0 0
+
+2: Axes, 1, CN:1, VN:3
+Gr, W, t, DS:1 1, GT:0, I, nSt
+Const: 1, Val: 1 0, 0 1
+
+3: Pt, 0, CN:0, VN:1
+R, W, t, DS:1 1, GT:1, V, nSt
+Val: -4.683125 1.93145833333333
+
+4: Line, 0, CN:1, VN:2
+V, W, t, DS:1 1, GT:0, V, nSt
+Const: 3, Val: 0.972745500001038 0.231875380814201
+
diff --git a/kig/filters/tests/locus.fgeo b/kig/filters/tests/locus.fgeo
new file mode 100644
index 00000000..a914068c
--- /dev/null
+++ b/kig/filters/tests/locus.fgeo
@@ -0,0 +1,2 @@
+<?xml version="1.0"?>
+<drgenius><drgeo name="Figuur 1" scale="30.000000" origin_x="0.000000" origin_y="0.000000" grid="False"><point id="8293DE0" type="Free" color="Red" thickness="Dashed" style="Cross" filled="False" masked="False" name=""><x>-1.666666</x><y>3.216667</y></point><point id="8306C70" type="Free" color="Red" thickness="Dashed" style="Cross" filled="False" masked="False" name=""><x>-2.766667</x><y>0.550000</y></point><circle id="8307268" type="2pts" color="Black" thickness="Normal" style="Cross" filled="False" masked="False" name=""><parent ref="8293DE0"/><parent ref="8306C70"/></circle><point id="8309098" type="On_curve" color="Red" thickness="Dashed" style="Cross" filled="False" masked="False" name=""><value>0.080691</value><parent ref="8307268"/></point><point id="830A920" type="Free" color="Red" thickness="Dashed" style="Cross" filled="False" masked="False" name=""><x>3.000000</x><y>3.016667</y></point><line id="8172970" type="2pts" color="Black" thickness="Normal" style="Cross" filled="False" masked="False" name=""><parent ref="8309098"/><parent ref="830A920"/></line><point id="8339730" type="Free" color="Red" thickness="Dashed" style="Cross" filled="False" masked="False" name=""><x>2.866667</x><y>-0.750000</y></point><line id="833AD18" type="2pts" color="Black" thickness="Normal" style="Cross" filled="False" masked="False" name=""><parent ref="8309098"/><parent ref="8339730"/></line><point id="8338A50" type="Free" color="Red" thickness="Dashed" style="Cross" filled="False" masked="False" name=""><x>2.600000</x><y>3.816667</y></point><line id="833BBB8" type="perpendicular" color="Black" thickness="Normal" style="Cross" filled="False" masked="False" name=""><parent ref="8338A50"/><parent ref="833AD18"/></line><point id="8342478" type="Intersection" color="Red" thickness="Dashed" style="Cross" filled="False" masked="False" name="" extra="0"><parent ref="8172970"/><parent ref="833BBB8"/></point><locus id="8345D60" type="None" color="Black" thickness="Dashed" style="Cross" filled="False" masked="False" name=""><parent ref="8309098"/><parent ref="8342478"/></locus></drgeo></drgenius>
diff --git a/kig/filters/tests/lotsOfObjects.FIG b/kig/filters/tests/lotsOfObjects.FIG
new file mode 100644
index 00000000..67b24164
--- /dev/null
+++ b/kig/filters/tests/lotsOfObjects.FIG
@@ -0,0 +1,148 @@
+FIGURE CabriII vers. MS-Windows 1.0
+
+Window center x: 0 y: 0 Window size x: 16.2983333333333 y: 9.68375
+
+1: Pt, 0, CN:0, VN:1
+R, W, t, DS:1 1, GT:1, I, nSt
+Val: 0 0
+
+2: Axes, 1, CN:1, VN:3
+Gr, W, t, DS:1 1, GT:0, I, nSt
+Const: 1, Val: 1 0, 0 1
+
+3: Pt, 0, CN:0, VN:1
+R, W, t, DS:1 1, GT:1, V, nSt
+Val: -6.72041666666667 3.94229166666667
+
+4: Line, 0, CN:1, VN:2
+V, W, t, DS:1 1, GT:0, V, nSt
+Const: 3, Val: -0.0202661071897195 -0.999794621359494
+
+5: Pt, 0, CN:0, VN:1
+R, W, t, DS:1 1, GT:1, V, nSt
+Val: 0.582083333333333 2.35479166666667
+
+6: Line, 0, CN:2, VN:2
+V, W, t, DS:1 1, GT:0, V, nSt
+Const: 5 3
+
+7: Pt, 0, CN:0, VN:1
+R, W, t, DS:1 1, GT:1, V, nSt
+Val: -4.78895833333333 -0.661458333333333
+
+8: Seg, 0, CN:2, VN:0
+V, W, t, DS:1 1, GT:0, V, nSt
+Const: 5 7
+
+9: Ray, 0, CN:1, VN:2
+V, W, t, DS:1 1, GT:0, V, nSt
+Const: 7, Val: 0.965226371919943 -0.261415475728318
+
+10: Pt, 0, CN:0, VN:1
+R, W, t, DS:1 1, GT:1, V, nSt
+Val: -2.19604166666667 -2.56645833333333
+
+11: Ray, 0, CN:2, VN:2
+V, W, t, DS:1 1, GT:0, V, nSt
+Const: 7 10
+
+12: Pt, 0, CN:0, VN:1
+R, W, t, DS:1 1, GT:0, V, nSt
+Val: -0.687916666666667 -0.820208333333333
+
+13: Vec, 0, CN:2, VN:0
+P, W, t, DS:1 1, GT:0, V, nSt
+Const: 10 12
+
+14: Pt, 0, CN:0, VN:1
+R, W, t, DS:1 1, GT:1, V, nSt
+Val: 3.75708333333333 -0.661458333333333
+
+15: Cir, 0, CN:1, VN:2
+Bl, W, t, DS:1 1, GT:0, V, nSt
+Const: 14, Val: 2.32351774734393
+
+16: Cir, 0, CN:2, VN:2
+Bl, W, t, DS:1 1, GT:0, V, nSt
+Const: 14 5
+
+17: Pt, 0, CN:0, VN:1
+R, W, t, DS:1 1, GT:1, V, nSt
+Val: -4.70958333333333 2.19604166666667
+
+18: Pt, 0, CN:0, VN:1
+R, W, t, DS:1 1, GT:1, V, nSt
+Val: -6.19125 1.00541666666667
+
+19: Arc, 0, CN:3, VN:4
+R, W, t, DS:1 1, GT:0, V, nSt
+Const: 7 17 18
+
+20: Pt, 0, CN:0, VN:1
+R, W, t, DS:1 1, GT:1, V, nSt
+Val: -2.96333333333333 3.78354166666667
+
+21: Pt, 0, CN:0, VN:1
+R, W, t, DS:1 1, GT:1, V, nSt
+Val: -0.0264583333333333 4.1275
+
+22: Pt, 0, CN:0, VN:1
+R, W, t, DS:1 1, GT:1, V, nSt
+Val: 1.95791666666667 2.69875
+
+23: Pt, 0, CN:0, VN:1
+R, W, t, DS:1 1, GT:1, V, nSt
+Val: 0.0264583333333333 0.582083333333333
+
+24: Pt, 0, CN:0, VN:1
+R, W, t, DS:1 1, GT:1, V, nSt
+Val: -4.25979166666667 1.08479166666667
+
+25: Con, 1, CN:5, VN:6
+Bl, W, t, DS:1 1, GT:0, V, nSt
+Const: 20 21 22 23 24
+
+26: Perp, 0, CN:2, VN:2
+V, W, t, DS:1 1, GT:0, V, nSt
+Const: 14 11
+
+27: Pt, 0, CN:0, VN:1
+R, W, t, DS:1 1, GT:1, V, nSt
+Val: -5.37104166666667 -2.56645833333333
+
+28: Par, 0, CN:2, VN:2
+V, W, t, DS:1 1, GT:0, V, nSt
+Const: 27 11
+
+29: Mid, 0, CN:1, VN:1
+R, W, t, DS:1 1, GT:1, V, nSt
+Const: 13
+
+30: Mid, 0, CN:1, VN:1
+R, W, t, DS:1 1, GT:1, V, nSt
+Const: 8
+
+31: Pt, 0, CN:0, VN:1
+R, W, t, DS:1 1, GT:1, V, nSt
+Val: -5.97958333333333 3.254375
+
+32: Mid, 0, CN:2, VN:1
+R, W, t, DS:1 1, GT:1, V, nSt
+Const: 31 18
+
+33: PBiss, 0, CN:1, VN:2
+V, W, t, DS:1 1, GT:0, V, nSt
+Const: 8
+
+34: Pt, 0, CN:0, VN:1
+R, W, t, DS:1 1, GT:1, V, nSt
+Val: -4.55083333333333 -2.460625
+
+35: Pt, 0, CN:0, VN:1
+R, W, t, DS:1 1, GT:1, V, nSt
+Val: -3.889375 -1.71979166666667
+
+36: PBiss, 0, CN:2, VN:2
+V, W, t, DS:1 1, GT:0, V, nSt
+Const: 34 35
+
diff --git a/kig/filters/tests/python-script.kig b/kig/filters/tests/python-script.kig
new file mode 100644
index 00000000..edac8b48
--- /dev/null
+++ b/kig/filters/tests/python-script.kig
@@ -0,0 +1,29 @@
+<!DOCTYPE KigDocument>
+<KigDocument Version="0.5.1" >
+ <CoordinateSystem>Euclidean</CoordinateSystem>
+ <Objects>
+ <Data internal="true" type="double" id="1" >-3.93514</Data>
+ <Data internal="true" type="double" id="2" >2.97568</Data>
+ <Data internal="true" type="double" id="3" >-2.03636</Data>
+ <Data internal="true" type="double" id="4" >1.57224</Data>
+ <Data internal="true" type="string" id="5" >def calc( arg1, arg2 ):
+ return Point( ( arg1.coordinate() + arg2.coordinate() ) / 2 )
+</Data>
+ <Object width="-1" internal="false" shown="true" type="FixedPoint" id="6" color="#0000ff" >
+ <Parent id="1" />
+ <Parent id="2" />
+ </Object>
+ <Object width="-1" internal="false" shown="true" type="FixedPoint" id="7" color="#0000ff" >
+ <Parent id="3" />
+ <Parent id="4" />
+ </Object>
+ <Object width="-1" internal="true" shown="true" type="PythonCompileType" id="8" color="#0000ff" >
+ <Parent id="5" />
+ </Object>
+ <Object width="-1" internal="false" shown="true" type="PythonExecuteType" id="9" color="#0000ff" >
+ <Parent id="8" />
+ <Parent id="6" />
+ <Parent id="7" />
+ </Object>
+ </Objects>
+</KigDocument>
diff --git a/kig/filters/tests/radicallinestest.kig b/kig/filters/tests/radicallinestest.kig
new file mode 100644
index 00000000..82b1e564
--- /dev/null
+++ b/kig/filters/tests/radicallinestest.kig
@@ -0,0 +1,85 @@
+<!DOCTYPE KigDocument>
+<KigDocument Version="0.6.0" >
+ <CoordinateSystem>Euclidean</CoordinateSystem>
+ <Objects>
+ <Data internal="true" type="double" id="1" >-3.43396</Data>
+ <Data internal="true" type="double" id="2" >1.54088</Data>
+ <Data internal="true" type="double" id="3" >-1.10063</Data>
+ <Data internal="true" type="double" id="4" >2.01216</Data>
+ <Data internal="true" type="double" id="5" >-0.0880503</Data>
+ <Data internal="true" type="double" id="6" >-0.748428</Data>
+ <Data internal="true" type="double" id="7" >-2.28931</Data>
+ <Data internal="true" type="double" id="8" >0.968553</Data>
+ <Data internal="true" type="double" id="9" >-0.836478</Data>
+ <Data internal="true" type="double" id="10" >4.35849</Data>
+ <Data internal="true" type="int" id="11" >1</Data>
+ <Data internal="true" type="int" id="12" >1</Data>
+ <Data internal="true" type="int" id="13" >-1</Data>
+ <Data internal="true" type="int" id="14" >1</Data>
+ <Data internal="true" type="double" id="15" >5.50314</Data>
+ <Data internal="true" type="double" id="16" >-0.0440252</Data>
+ <Data internal="true" type="double" id="17" >1.01258</Data>
+ <Data internal="true" type="double" id="18" >1.80503</Data>
+ <Data internal="true" type="int" id="19" >1</Data>
+ <Data internal="true" type="int" id="20" >1</Data>
+ <Object width="5" internal="false" shown="true" type="FixedPoint" id="21" color="#0000ff" >
+ <Parent id="1" />
+ <Parent id="2" />
+ </Object>
+ <Object width="5" internal="false" shown="true" type="FixedPoint" id="22" color="#0000ff" >
+ <Parent id="3" />
+ <Parent id="4" />
+ </Object>
+ <Object width="5" internal="false" shown="true" type="FixedPoint" id="23" color="#0000ff" >
+ <Parent id="5" />
+ <Parent id="6" />
+ </Object>
+ <Object width="5" internal="false" shown="true" type="FixedPoint" id="24" color="#0000ff" >
+ <Parent id="7" />
+ <Parent id="8" />
+ </Object>
+ <Object width="5" internal="false" shown="true" type="FixedPoint" id="25" color="#0000ff" >
+ <Parent id="9" />
+ <Parent id="10" />
+ </Object>
+ <Object width="5" internal="false" shown="true" type="FixedPoint" id="26" color="#0000ff" >
+ <Parent id="15" />
+ <Parent id="16" />
+ </Object>
+ <Object width="5" internal="false" shown="true" type="FixedPoint" id="27" color="#0000ff" >
+ <Parent id="17" />
+ <Parent id="18" />
+ </Object>
+ <Object width="-1" internal="false" shown="true" type="CircleBCP" id="28" color="#0000ff" >
+ <Parent id="21" />
+ <Parent id="22" />
+ </Object>
+ <Object width="-1" internal="false" shown="true" type="CircleBTP" id="29" color="#0000ff" >
+ <Parent id="23" />
+ <Parent id="24" />
+ <Parent id="25" />
+ </Object>
+ <Object width="-1" internal="false" shown="true" type="CircleBCP" id="30" color="#0000ff" >
+ <Parent id="26" />
+ <Parent id="27" />
+ </Object>
+ <Object width="-1" internal="false" shown="true" type="ConicRadical" id="31" color="#0000ff" >
+ <Parent id="28" />
+ <Parent id="29" />
+ <Parent id="11" />
+ <Parent id="12" />
+ </Object>
+ <Object width="-1" internal="false" shown="true" type="ConicRadical" id="32" color="#0000ff" >
+ <Parent id="28" />
+ <Parent id="29" />
+ <Parent id="13" />
+ <Parent id="14" />
+ </Object>
+ <Object width="-1" internal="false" shown="true" type="ConicRadical" id="33" color="#0000ff" >
+ <Parent id="29" />
+ <Parent id="30" />
+ <Parent id="19" />
+ <Parent id="20" />
+ </Object>
+ </Objects>
+</KigDocument>
diff --git a/kig/filters/tests/stylestest.kig b/kig/filters/tests/stylestest.kig
new file mode 100644
index 00000000..f9a91951
--- /dev/null
+++ b/kig/filters/tests/stylestest.kig
@@ -0,0 +1,27 @@
+<!DOCTYPE KigDocument>
+<KigDocument Version="0.7.1" >
+ <CoordinateSystem>Euclidean</CoordinateSystem>
+ <Hierarchy>
+ <Data type="double" id="1" >-3.41511</Data>
+ <Data type="double" id="2" >-0.798177</Data>
+ <Data type="double" id="3" >2.53813</Data>
+ <Data type="double" id="4" >3.67781</Data>
+ <Object type="FixedPoint" id="5" >
+ <Parent id="1" />
+ <Parent id="3" />
+ </Object>
+ <Object type="FixedPoint" id="6" >
+ <Parent id="4" />
+ <Parent id="2" />
+ </Object>
+ <Object type="LineAB" id="7" >
+ <Parent id="5" />
+ <Parent id="6" />
+ </Object>
+ </Hierarchy>
+ <View>
+ <Draw width="-1" point-style="Round" style="DashLine" shown="true" color="#0000ff" object="7" />
+ <Draw width="-1" point-style="Cross" style="SolidLine" shown="true" color="#0000ff" object="5" />
+ <Draw width="-1" point-style="RectangularEmpty" style="SolidLine" shown="true" color="#0000ff" object="6" />
+ </View>
+</KigDocument>
diff --git a/kig/filters/tests/test.kgeo b/kig/filters/tests/test.kgeo
new file mode 100644
index 00000000..e0edaa9d
--- /dev/null
+++ b/kig/filters/tests/test.kgeo
@@ -0,0 +1,145 @@
+[Colors]
+Background=255,255,255
+Draw=0,0,0
+
+[Main]
+Axes=true
+Grid=true
+Number=17
+Numbers=true
+Scaling=false
+Version=KGeo 1.0.2
+XMax=11
+YMax=7
+
+[Object 1]
+Color=0,0,0
+Geo=1
+Parents=
+Position=1
+QPointX=-3.4
+QPointY=1.3
+Size=3
+
+[Object 10]
+Color=0,0,0
+Geo=31
+Parents=8,9
+Size=1
+
+[Object 11]
+Color=0,0,0
+Geo=27
+Parents=5,7
+Size=1
+
+[Object 12]
+Color=0,0,0
+Geo=29
+Parents=9,5
+Size=1
+
+[Object 13]
+Color=0,0,0
+Geo=1
+Parents=
+Position=1
+QPointX=3.8
+QPointY=-1.7
+Size=3
+
+[Object 14]
+Color=0,0,0
+Geo=32
+Parents=13,11
+Position=1
+QPointX=-0.2
+QPointY=-0.3
+Size=3
+
+[Object 15]
+Color=0,0,0
+Geo=1
+Parents=
+Position=1
+QPointX=-7.4
+QPointY=7.8
+Size=3
+
+[Object 16]
+Color=0,0,0
+Geo=1
+Parents=
+Position=1
+QPointX=-7.4
+QPointY=6.4
+Size=3
+
+[Object 17]
+Color=0,0,0
+Geo=9
+Parents=15,16
+Position=1
+QPointX=-7.4
+QPointY=5
+Size=3
+
+[Object 2]
+Color=0,0,0
+Geo=1
+Parents=
+Position=1
+QPointX=-3.4
+QPointY=2.4
+Size=3
+
+[Object 3]
+Color=0,0,0
+Geo=3
+Parents=1,2
+Size=1
+
+[Object 4]
+Color=0,0,0
+Geo=4
+Parents=1,2
+Size=1
+
+[Object 5]
+Color=0,0,0
+Geo=1
+Parents=
+Position=1
+QPointX=1.5
+QPointY=3.6
+Size=3
+
+[Object 6]
+Color=0,0,0
+Geo=2
+Parents=1,5
+Size=1
+
+[Object 7]
+Color=0,0,0
+Geo=1
+Parents=
+Position=1
+QPointX=-2.5
+QPointY=5
+Size=3
+
+[Object 8]
+Color=0,0,0
+Geo=30
+Parents=6,7
+Size=1
+
+[Object 9]
+Color=0,0,0
+Geo=1
+Parents=
+Position=1
+QPointX=-5.1
+QPointY=-4.1
+Size=3
diff --git a/kig/filters/tests/test.seg b/kig/filters/tests/test.seg
new file mode 100644
index 00000000..d51c281d
--- /dev/null
+++ b/kig/filters/tests/test.seg
Binary files differ
diff --git a/kig/filters/tests/testalotofeverything.kig b/kig/filters/tests/testalotofeverything.kig
new file mode 100644
index 00000000..1e7a5fcb
--- /dev/null
+++ b/kig/filters/tests/testalotofeverything.kig
@@ -0,0 +1,174 @@
+<!DOCTYPE KigDocument>
+<KigDocument Version="0.7.1" >
+ <CoordinateSystem>Euclidean</CoordinateSystem>
+ <Hierarchy>
+ <Data type="double" id="1" >4.20683</Data>
+ <Data type="double" id="2" >-1.93144</Data>
+ <Data type="double" id="3" >0.661451</Data>
+ <Data type="double" id="4" >-2.91039</Data>
+ <Data type="double" id="5" >0.694042</Data>
+ <Data type="double" id="6" >-2.38123</Data>
+ <Data type="double" id="7" >-2.27539</Data>
+ <Data type="double" id="8" >3.2808</Data>
+ <Data type="double" id="9" >-0.8202</Data>
+ <Data type="double" id="10" >0.24161</Data>
+ <Data type="double" id="11" >2.0671</Data>
+ <Data type="double" id="12" >5.39744</Data>
+ <Data type="double" id="13" >2.17293</Data>
+ <Data type="double" id="14" >5.39744</Data>
+ <Data type="double" id="15" >-1.66686</Data>
+ <Data type="double" id="16" >-0.0760034</Data>
+ <Data type="double" id="17" >3.09559</Data>
+ <Data type="double" id="18" >0.434012</Data>
+ <Data type="int" id="19" >1</Data>
+ <Data type="double" id="20" >-3.91579</Data>
+ <Data type="double" id="21" >6.42931</Data>
+ <Data type="double" id="22" >4.73936</Data>
+ <Data type="string" id="23" >%1</Data>
+ <Data type="double" id="24" >-1.34936</Data>
+ <Data type="point" id="25" >
+ <x>4.55079</x>
+ <y>3.67767</y>
+ </Data>
+ <Data type="double" id="26" >-1.76794</Data>
+ <Data type="hierarchy" id="27" >
+ <input requirement="point" id="1" />
+ <input requirement="point" id="2" />
+ <input requirement="double" id="3" />
+ <intermediate action="calc" type="LineAB" id="4" >
+ <arg>1</arg>
+ <arg>2</arg>
+ </intermediate>
+ <result action="calc" type="ConstrainedPoint" id="5" >
+ <arg>3</arg>
+ <arg>4</arg>
+ </result>
+ </Data>
+ <Data type="double" id="28" >1.93481</Data>
+ <Data type="string" id="29" >def calc( arg1 ):
+ return Point( arg1.coordinate() + Coordinate( 1,.8))</Data>
+ <Object type="FixedPoint" id="30" >
+ <Parent id="3" />
+ <Parent id="2" />
+ </Object>
+ <Object type="FixedPoint" id="31" >
+ <Parent id="7" />
+ <Parent id="9" />
+ </Object>
+ <Object type="FixedPoint" id="32" >
+ <Parent id="15" />
+ <Parent id="6" />
+ </Object>
+ <Object type="FixedPoint" id="33" >
+ <Parent id="12" />
+ <Parent id="16" />
+ </Object>
+ <Object type="FixedPoint" id="34" >
+ <Parent id="17" />
+ <Parent id="8" />
+ </Object>
+ <Object type="FixedPoint" id="35" >
+ <Parent id="20" />
+ <Parent id="11" />
+ </Object>
+ <Object type="FixedPoint" id="36" >
+ <Parent id="1" />
+ <Parent id="21" />
+ </Object>
+ <Object type="FixedPoint" id="37" >
+ <Parent id="4" />
+ <Parent id="22" />
+ </Object>
+ <Object type="FixedPoint" id="38" >
+ <Parent id="24" />
+ <Parent id="13" />
+ </Object>
+ <Object type="FixedPoint" id="39" >
+ <Parent id="26" />
+ <Parent id="18" />
+ </Object>
+ <Object type="FixedPoint" id="40" >
+ <Parent id="14" />
+ <Parent id="28" />
+ </Object>
+ <Object type="PythonCompileType" id="41" >
+ <Parent id="29" />
+ </Object>
+ <Object type="Vector" id="42" >
+ <Parent id="36" />
+ <Parent id="34" />
+ </Object>
+ <Object type="Vector" id="43" >
+ <Parent id="35" />
+ <Parent id="38" />
+ </Object>
+ <Object type="CircleBCP" id="44" >
+ <Parent id="33" />
+ <Parent id="40" />
+ </Object>
+ <Object type="PythonExecuteType" id="45" >
+ <Parent id="41" />
+ <Parent id="37" />
+ </Object>
+ <Object type="LineByVector" id="46" >
+ <Parent id="43" />
+ <Parent id="37" />
+ </Object>
+ <Object type="VectorEquality" id="47" >
+ <Parent id="43" />
+ <Parent id="42" />
+ </Object>
+ <Object type="ConstrainedPoint" id="48" >
+ <Parent id="10" />
+ <Parent id="44" />
+ </Object>
+ <Object type="Locus" id="49" >
+ <Parent id="27" />
+ <Parent id="44" />
+ <Parent id="39" />
+ <Parent id="5" />
+ </Object>
+ <Property which="test-result" id="50" >
+ <Parent id="47" />
+ </Property>
+ <Object type="LineAB" id="51" >
+ <Parent id="48" />
+ <Parent id="39" />
+ </Object>
+ <Object type="Similitude" id="52" >
+ <Parent id="49" />
+ <Parent id="31" />
+ <Parent id="32" />
+ <Parent id="30" />
+ </Object>
+ <Object type="Label" id="53" >
+ <Parent id="19" />
+ <Parent id="25" />
+ <Parent id="23" />
+ <Parent id="50" />
+ </Object>
+ </Hierarchy>
+ <View>
+ <Draw width="-1" point-style="Round" style="SolidLine" shown="true" color="#0000ff" object="35" />
+ <Draw width="-1" point-style="Round" style="SolidLine" shown="true" color="#0000ff" object="39" />
+ <Draw width="-1" point-style="Round" style="SolidLine" shown="true" color="#0000ff" object="48" />
+ <Draw width="-1" point-style="Round" style="SolidLine" shown="true" color="#0000ff" object="51" />
+ <Draw width="-1" point-style="Round" style="SolidLine" shown="true" color="#0000ff" object="53" />
+ <Draw width="-1" point-style="Round" style="SolidLine" shown="true" color="#0000ff" object="30" />
+ <Draw width="-1" point-style="Round" style="SolidLine" shown="true" color="#0000ff" object="43" />
+ <Draw width="-1" point-style="Round" style="SolidLine" shown="true" color="#0000ff" object="31" />
+ <Draw width="-1" point-style="Round" style="SolidLine" shown="true" color="#0000ff" object="38" />
+ <Draw width="-1" point-style="Round" style="SolidLine" shown="true" color="#0000ff" object="40" />
+ <Draw width="5" point-style="Round" style="SolidLine" shown="true" color="#ffff00" object="52" />
+ <Draw width="-1" point-style="Round" style="SolidLine" shown="true" color="#0000ff" object="42" />
+ <Draw width="-1" point-style="Round" style="SolidLine" shown="true" color="#0000ff" object="34" />
+ <Draw width="-1" point-style="Round" style="SolidLine" shown="true" color="#0000ff" object="32" />
+ <Draw width="-1" point-style="Round" style="SolidLine" shown="true" color="#0000ff" object="33" />
+ <Draw width="7" point-style="Round" style="DotLine" shown="true" color="#a0a0a4" object="49" />
+ <Draw width="-1" point-style="Round" style="SolidLine" shown="true" color="#0000ff" object="36" />
+ <Draw width="7" point-style="Round" style="DashDotDotLine" shown="true" color="#00ff00" object="46" />
+ <Draw width="-1" point-style="Round" style="SolidLine" shown="true" color="#0000ff" object="44" />
+ <Draw width="-1" point-style="Round" style="SolidLine" shown="true" color="#0000ff" object="37" />
+ <Draw width="-1" point-style="Round" style="SolidLine" shown="true" color="#0000ff" object="45" />
+ </View>
+</KigDocument>
diff --git a/kig/filters/tests/testlocuswithinvalidpoints.kig b/kig/filters/tests/testlocuswithinvalidpoints.kig
new file mode 100644
index 00000000..6bb3f57d
--- /dev/null
+++ b/kig/filters/tests/testlocuswithinvalidpoints.kig
@@ -0,0 +1,177 @@
+<!DOCTYPE KigDocument>
+<KigDocument Version="0.7.1" >
+ <CoordinateSystem>Euclidean</CoordinateSystem>
+ <Hierarchy>
+ <Data type="int" id="1" >0</Data>
+ <Data type="hierarchy" id="2" >
+ <input requirement="point" id="1" />
+ <input requirement="double" id="2" />
+ <input requirement="circle" id="3" />
+ <input requirement="int" id="4" />
+ <intermediate action="calc" type="CircleBPR" id="5" >
+ <arg>1</arg>
+ <arg>2</arg>
+ </intermediate>
+ <intermediate action="calc" type="CircleCircleIntersection" id="6" >
+ <arg>3</arg>
+ <arg>5</arg>
+ <arg>4</arg>
+ </intermediate>
+ <intermediate action="calc" type="SegmentAB" id="7" >
+ <arg>6</arg>
+ <arg>1</arg>
+ </intermediate>
+ <result action="fetch-property" property="mid-point" id="8" >
+ <arg>7</arg>
+ </result>
+ </Data>
+ <Data type="double" id="3" >-1.40273</Data>
+ <Data type="double" id="4" >-0.608162</Data>
+ <Data type="int" id="5" >1</Data>
+ <Data type="int" id="6" >0</Data>
+ <Data type="double" id="7" >1.74813</Data>
+ <Data type="double" id="8" >-8.26962</Data>
+ <Data type="double" id="9" >-2.18736</Data>
+ <Data type="double" id="10" >-9.17811</Data>
+ <Data type="double" id="11" >-8.44019</Data>
+ <Data type="double" id="12" >-9.66304</Data>
+ <Data type="string" id="13" >Q</Data>
+ <Data type="double" id="14" >3.24779</Data>
+ <Data type="double" id="15" >-0.401053</Data>
+ <Data type="double" id="16" >3.41264</Data>
+ <Data type="double" id="17" >-0.327406</Data>
+ <Data type="double" id="18" >2.46458</Data>
+ <Data type="double" id="19" >-9.94648</Data>
+ <Data type="string" id="20" >P</Data>
+ <Data type="double" id="21" >-0.816147</Data>
+ <Data type="int" id="22" >-1</Data>
+ <Data type="double" id="23" >-5.54805</Data>
+ <Data type="double" id="24" >0.177996</Data>
+ <Object type="FixedPoint" id="25" >
+ <Parent id="8" />
+ <Parent id="7" />
+ </Object>
+ <Object type="FixedPoint" id="26" >
+ <Parent id="12" />
+ <Parent id="14" />
+ </Object>
+ <Object type="FixedPoint" id="27" >
+ <Parent id="10" />
+ <Parent id="15" />
+ </Object>
+ <Object type="FixedPoint" id="28" >
+ <Parent id="11" />
+ <Parent id="16" />
+ </Object>
+ <Object type="FixedPoint" id="29" >
+ <Parent id="4" />
+ <Parent id="18" />
+ </Object>
+ <Object type="FixedPoint" id="30" >
+ <Parent id="19" />
+ <Parent id="9" />
+ </Object>
+ <Object type="FixedPoint" id="31" >
+ <Parent id="17" />
+ <Parent id="21" />
+ </Object>
+ <Object type="FixedPoint" id="32" >
+ <Parent id="23" />
+ <Parent id="3" />
+ </Object>
+ <Object type="SegmentAB" id="33" >
+ <Parent id="27" />
+ <Parent id="25" />
+ </Object>
+ <Object type="SegmentAB" id="34" >
+ <Parent id="26" />
+ <Parent id="28" />
+ </Object>
+ <Object type="SegmentAB" id="35" >
+ <Parent id="30" />
+ <Parent id="32" />
+ </Object>
+ <Property which="length" id="36" >
+ <Parent id="33" />
+ </Property>
+ <Property which="length" id="37" >
+ <Parent id="34" />
+ </Property>
+ <Property which="length" id="38" >
+ <Parent id="35" />
+ </Property>
+ <Object type="CircleBPR" id="39" >
+ <Parent id="29" />
+ <Parent id="36" />
+ </Object>
+ <Object type="CircleBPR" id="40" >
+ <Parent id="31" />
+ <Parent id="37" />
+ </Object>
+ <Object type="ConstrainedPoint" id="41" >
+ <Parent id="24" />
+ <Parent id="40" />
+ </Object>
+ <Object type="Locus" id="42" >
+ <Parent id="2" />
+ <Parent id="40" />
+ <Parent id="38" />
+ <Parent id="39" />
+ <Parent id="5" />
+ </Object>
+ <Object type="CircleBPR" id="43" >
+ <Parent id="41" />
+ <Parent id="38" />
+ </Object>
+ <Object type="Label" id="44" >
+ <Parent id="1" />
+ <Parent id="41" />
+ <Parent id="20" />
+ </Object>
+ <Object type="CircleCircleIntersection" id="45" >
+ <Parent id="39" />
+ <Parent id="43" />
+ <Parent id="22" />
+ </Object>
+ <Object type="CircleCircleIntersection" id="46" >
+ <Parent id="39" />
+ <Parent id="43" />
+ <Parent id="5" />
+ </Object>
+ <Object type="SegmentAB" id="47" >
+ <Parent id="46" />
+ <Parent id="41" />
+ </Object>
+ <Property which="mid-point" id="48" >
+ <Parent id="47" />
+ </Property>
+ <Object type="Label" id="49" >
+ <Parent id="6" />
+ <Parent id="48" />
+ <Parent id="13" />
+ </Object>
+ </Hierarchy>
+ <View>
+ <Draw width="-1" point-style="Round" style="SolidLine" shown="true" color="#0000ff" object="44" />
+ <Draw width="-1" point-style="Round" style="SolidLine" shown="true" color="#0000ff" object="26" />
+ <Draw width="-1" point-style="Round" style="SolidLine" shown="true" color="#0000ff" object="42" />
+ <Draw width="-1" point-style="Round" style="SolidLine" shown="true" color="#0000ff" object="43" />
+ <Draw width="-1" point-style="Round" style="SolidLine" shown="true" color="#0000ff" object="33" />
+ <Draw width="-1" point-style="Round" style="SolidLine" shown="true" color="#0000ff" object="30" />
+ <Draw width="-1" point-style="Round" style="SolidLine" shown="true" color="#0000ff" object="46" />
+ <Draw width="-1" point-style="Round" style="SolidLine" shown="true" color="#0000ff" object="49" />
+ <Draw width="-1" point-style="Round" style="SolidLine" shown="true" color="#0000ff" object="41" />
+ <Draw width="-1" point-style="Round" style="SolidLine" shown="true" color="#0000ff" object="31" />
+ <Draw width="-1" point-style="Round" style="SolidLine" shown="true" color="#0000ff" object="27" />
+ <Draw width="-1" point-style="Round" style="SolidLine" shown="true" color="#0000ff" object="35" />
+ <Draw width="-1" point-style="Round" style="SolidLine" shown="true" color="#0000ff" object="28" />
+ <Draw width="-1" point-style="Round" style="SolidLine" shown="true" color="#0000ff" object="40" />
+ <Draw width="-1" point-style="Round" style="SolidLine" shown="true" color="#0000ff" object="32" />
+ <Draw width="-1" point-style="Round" style="SolidLine" shown="true" color="#0000ff" object="39" />
+ <Draw width="-1" point-style="Round" style="SolidLine" shown="true" color="#0000ff" object="45" />
+ <Draw width="-1" point-style="Round" style="SolidLine" shown="true" color="#0000ff" object="25" />
+ <Draw width="-1" point-style="Round" style="SolidLine" shown="true" color="#0000ff" object="29" />
+ <Draw width="-1" point-style="Round" style="SolidLine" shown="true" color="#0000ff" object="48" />
+ <Draw width="-1" point-style="Round" style="SolidLine" shown="true" color="#0000ff" object="34" />
+ </View>
+</KigDocument>
diff --git a/kig/filters/tests/testnames.kig b/kig/filters/tests/testnames.kig
new file mode 100644
index 00000000..3fd10730
--- /dev/null
+++ b/kig/filters/tests/testnames.kig
@@ -0,0 +1,62 @@
+<!DOCTYPE KigDocument>
+<KigDocument Version="0.7.1" >
+ <CoordinateSystem>Euclidean</CoordinateSystem>
+ <Hierarchy>
+ <Data type="int" id="1" >0</Data>
+ <Data type="double" id="2" >1.3131</Data>
+ <Data type="string" id="3" >%1</Data>
+ <Data type="double" id="4" >-4.04756</Data>
+ <Data type="double" id="5" >4.22311</Data>
+ <Data type="double" id="6" >0.661366</Data>
+ <Data type="int" id="7" >0</Data>
+ <Data type="double" id="8" >0.55381</Data>
+ <Data type="string" id="9" >%1</Data>
+ <Data type="string" id="10" >ab</Data>
+ <Data type="int" id="11" >0</Data>
+ <Data type="string" id="12" >%1</Data>
+ <Data type="string" id="13" >a</Data>
+ <Data type="string" id="14" >b</Data>
+ <Object type="FixedPoint" id="15" >
+ <Parent id="4" />
+ <Parent id="2" />
+ </Object>
+ <Object type="FixedPoint" id="16" >
+ <Parent id="6" />
+ <Parent id="5" />
+ </Object>
+ <Object type="Label" id="17" >
+ <Parent id="11" />
+ <Parent id="15" />
+ <Parent id="12" />
+ <Parent id="14" />
+ </Object>
+ <Object type="SegmentAB" id="18" >
+ <Parent id="15" />
+ <Parent id="16" />
+ </Object>
+ <Object type="Label" id="19" >
+ <Parent id="1" />
+ <Parent id="16" />
+ <Parent id="3" />
+ <Parent id="13" />
+ </Object>
+ <Object type="ConstrainedPoint" id="20" >
+ <Parent id="8" />
+ <Parent id="18" />
+ </Object>
+ <Object type="Label" id="21" >
+ <Parent id="7" />
+ <Parent id="20" />
+ <Parent id="9" />
+ <Parent id="10" />
+ </Object>
+ </Hierarchy>
+ <View>
+ <Draw width="-1" point-style="Round" namecalcer="none" style="SolidLine" shown="true" color="#0000ff" object="19" />
+ <Draw width="-1" point-style="Round" namecalcer="none" style="SolidLine" shown="true" color="#0000ff" object="21" />
+ <Draw width="-1" point-style="Round" namecalcer="10" style="SolidLine" shown="true" color="#0000ff" object="18" />
+ <Draw width="-1" point-style="Round" namecalcer="13" style="SolidLine" shown="true" color="#0000ff" object="16" />
+ <Draw width="-1" point-style="Round" namecalcer="14" style="SolidLine" shown="true" color="#0000ff" object="15" />
+ <Draw width="-1" point-style="Round" namecalcer="none" style="SolidLine" shown="true" color="#0000ff" object="17" />
+ </View>
+</KigDocument>
diff --git a/kig/filters/tests/testtest.kig b/kig/filters/tests/testtest.kig
new file mode 100644
index 00000000..b232d227
--- /dev/null
+++ b/kig/filters/tests/testtest.kig
@@ -0,0 +1,66 @@
+<!DOCTYPE KigDocument>
+<KigDocument Version="0.7.1" >
+ <CoordinateSystem>Euclidean</CoordinateSystem>
+ <Hierarchy>
+ <Data type="point" id="1" >
+ <x>0.446592</x>
+ <y>0.0161959</y>
+ </Data>
+ <Data type="double" id="2" >0.278897</Data>
+ <Data type="double" id="3" >-0.288971</Data>
+ <Data type="double" id="4" >0.278897</Data>
+ <Data type="double" id="5" >-2.2855</Data>
+ <Data type="double" id="6" >-2.92606</Data>
+ <Data type="double" id="7" >-3.91425</Data>
+ <Data type="double" id="8" >2.27542</Data>
+ <Data type="int" id="9" >1</Data>
+ <Data type="double" id="10" >0.157621</Data>
+ <Data type="string" id="11" >%1</Data>
+ <Object type="FixedPoint" id="12" >
+ <Parent id="3" />
+ <Parent id="4" />
+ </Object>
+ <Object type="FixedPoint" id="13" >
+ <Parent id="5" />
+ <Parent id="6" />
+ </Object>
+ <Object type="FixedPoint" id="14" >
+ <Parent id="7" />
+ <Parent id="2" />
+ </Object>
+ <Object type="FixedPoint" id="15" >
+ <Parent id="10" />
+ <Parent id="8" />
+ </Object>
+ <Object type="LineAB" id="16" >
+ <Parent id="12" />
+ <Parent id="13" />
+ </Object>
+ <Object type="SegmentAB" id="17" >
+ <Parent id="15" />
+ <Parent id="14" />
+ </Object>
+ <Object type="AreOrthogonal" id="18" >
+ <Parent id="16" />
+ <Parent id="17" />
+ </Object>
+ <Property which="test-result" id="19" >
+ <Parent id="18" />
+ </Property>
+ <Object type="Label" id="20" >
+ <Parent id="9" />
+ <Parent id="1" />
+ <Parent id="11" />
+ <Parent id="19" />
+ </Object>
+ </Hierarchy>
+ <View>
+ <Draw width="-1" point-style="Round" style="SolidLine" shown="true" color="#0000ff" object="14" />
+ <Draw width="-1" point-style="Round" style="SolidLine" shown="true" color="#0000ff" object="12" />
+ <Draw width="-1" point-style="Round" style="SolidLine" shown="true" color="#0000ff" object="16" />
+ <Draw width="-1" point-style="Round" style="SolidLine" shown="true" color="#0000ff" object="13" />
+ <Draw width="-1" point-style="Round" style="SolidLine" shown="true" color="#0000ff" object="20" />
+ <Draw width="-1" point-style="Round" style="SolidLine" shown="true" color="#0000ff" object="15" />
+ <Draw width="-1" point-style="Round" style="SolidLine" shown="true" color="#0000ff" object="17" />
+ </View>
+</KigDocument>
diff --git a/kig/filters/tests/transform-test.seg b/kig/filters/tests/transform-test.seg
new file mode 100644
index 00000000..e2dc7219
--- /dev/null
+++ b/kig/filters/tests/transform-test.seg
Binary files differ
diff --git a/kig/filters/tests/transformlocustest.kig b/kig/filters/tests/transformlocustest.kig
new file mode 100644
index 00000000..f9c8500c
--- /dev/null
+++ b/kig/filters/tests/transformlocustest.kig
@@ -0,0 +1,82 @@
+<!DOCTYPE KigDocument>
+<KigDocument Version="0.4.0" >
+ <CoordinateSystem>Euclidean</CoordinateSystem>
+ <Objects>
+ <Data type="double" id="1" >-4.86</Data>
+ <Data type="double" id="2" >0</Data>
+ <Data type="double" id="3" >-6.93</Data>
+ <Data type="double" id="4" >0.42</Data>
+ <Data type="double" id="5" >0.346818</Data>
+ <Data type="double" id="6" >0.12</Data>
+ <Data type="double" id="7" >4.14</Data>
+ <Data type="double" id="8" >0.698969</Data>
+ <Data type="hierarchy" id="9" >
+ <input requirement="point" id="1" />
+ <input requirement="point" id="2" />
+ <input requirement="double" id="3" />
+ <intermediate action="calc" type="LineAB" id="4" >
+ <arg>1</arg>
+ <arg>2</arg>
+ </intermediate>
+ <result action="calc" type="ConstrainedPoint" id="5" >
+ <arg>3</arg>
+ <arg>4</arg>
+ </result>
+ </Data>
+ <Data type="double" id="10" >0.15</Data>
+ <Data type="double" id="11" >0</Data>
+ <Data type="double" id="12" >3.63</Data>
+ <Data type="double" id="13" >-0.12</Data>
+ <Object width="-1" shown="true" type="FixedPoint" id="14" color="#0000ff" >
+ <Parent id="1" />
+ <Parent id="2" />
+ </Object>
+ <Object width="-1" shown="true" type="FixedPoint" id="15" color="#0000ff" >
+ <Parent id="3" />
+ <Parent id="4" />
+ </Object>
+ <Object width="-1" shown="true" type="FixedPoint" id="16" color="#0000ff" >
+ <Parent id="6" />
+ <Parent id="7" />
+ </Object>
+ <Object width="-1" shown="true" type="FixedPoint" id="17" color="#0000ff" >
+ <Parent id="10" />
+ <Parent id="11" />
+ </Object>
+ <Object width="-1" shown="true" type="FixedPoint" id="18" color="#0000ff" >
+ <Parent id="12" />
+ <Parent id="13" />
+ </Object>
+ <Object width="-1" shown="true" type="CircleBCP" id="19" color="#0000ff" >
+ <Parent id="14" />
+ <Parent id="15" />
+ </Object>
+ <Object width="-1" shown="true" type="SegmentAB" id="20" color="#0000ff" >
+ <Parent id="17" />
+ <Parent id="18" />
+ </Object>
+ <Object width="-1" shown="true" type="ConstrainedPoint" id="21" color="#0000ff" >
+ <Parent id="5" />
+ <Parent id="19" />
+ </Object>
+ <Object width="-1" shown="true" type="Locus" id="22" color="#0000ff" >
+ <Parent id="19" />
+ <Parent id="9" />
+ <Parent id="16" />
+ <Parent id="8" />
+ </Object>
+ <Object width="-1" shown="true" type="LineAB" id="23" color="#0000ff" >
+ <Parent id="21" />
+ <Parent id="16" />
+ </Object>
+ <Object width="-1" shown="true" type="ConstrainedPoint" id="24" color="#0000ff" >
+ <Parent id="8" />
+ <Parent id="23" />
+ </Object>
+ <Object width="-1" shown="true" type="ScalingOverLine" id="25" color="#0000ff" >
+ <Parent id="22" />
+ <Parent id="23" />
+ <Parent id="20" />
+ </Object>
+ </Objects>
+</KigDocument>