From 65a9f54e1051ee8ab936975e78dcb7117b265ef5 Mon Sep 17 00:00:00 2001 From: Michele Calgaro Date: Fri, 11 Dec 2020 21:51:45 +0900 Subject: Renaming of files in preparation for code style tools. Signed-off-by: Michele Calgaro --- kig/filters/CMakeLists.txt | 24 +- kig/filters/Makefile.am | 24 +- kig/filters/cabri-filter.cc | 577 ------------------------- kig/filters/cabri-filter.cpp | 577 +++++++++++++++++++++++++ kig/filters/drgeo-filter-chooser.cc | 65 --- kig/filters/drgeo-filter-chooser.cpp | 65 +++ kig/filters/drgeo-filter.cc | 809 ----------------------------------- kig/filters/drgeo-filter.cpp | 809 +++++++++++++++++++++++++++++++++++ kig/filters/exporter.cc | 624 --------------------------- kig/filters/exporter.cpp | 624 +++++++++++++++++++++++++++ kig/filters/filter.cc | 114 ----- kig/filters/filter.cpp | 114 +++++ kig/filters/filters-common.cc | 39 -- kig/filters/filters-common.cpp | 39 ++ kig/filters/imageexporteroptions.cc | 57 --- kig/filters/imageexporteroptions.cpp | 57 +++ kig/filters/kgeo-filter.cc | 374 ---------------- kig/filters/kgeo-filter.cpp | 374 ++++++++++++++++ kig/filters/kseg-filter.cc | 679 ----------------------------- kig/filters/kseg-filter.cpp | 679 +++++++++++++++++++++++++++++ kig/filters/latexexporter.cc | 608 -------------------------- kig/filters/latexexporter.cpp | 608 ++++++++++++++++++++++++++ kig/filters/native-filter.cc | 747 -------------------------------- kig/filters/native-filter.cpp | 747 ++++++++++++++++++++++++++++++++ kig/filters/svgexporter.cc | 111 ----- kig/filters/svgexporter.cpp | 111 +++++ 26 files changed, 4828 insertions(+), 4828 deletions(-) delete mode 100644 kig/filters/cabri-filter.cc create mode 100644 kig/filters/cabri-filter.cpp delete mode 100644 kig/filters/drgeo-filter-chooser.cc create mode 100644 kig/filters/drgeo-filter-chooser.cpp delete mode 100644 kig/filters/drgeo-filter.cc create mode 100644 kig/filters/drgeo-filter.cpp delete mode 100644 kig/filters/exporter.cc create mode 100644 kig/filters/exporter.cpp delete mode 100644 kig/filters/filter.cc create mode 100644 kig/filters/filter.cpp delete mode 100644 kig/filters/filters-common.cc create mode 100644 kig/filters/filters-common.cpp delete mode 100644 kig/filters/imageexporteroptions.cc create mode 100644 kig/filters/imageexporteroptions.cpp delete mode 100644 kig/filters/kgeo-filter.cc create mode 100644 kig/filters/kgeo-filter.cpp delete mode 100644 kig/filters/kseg-filter.cc create mode 100644 kig/filters/kseg-filter.cpp delete mode 100644 kig/filters/latexexporter.cc create mode 100644 kig/filters/latexexporter.cpp delete mode 100644 kig/filters/native-filter.cc create mode 100644 kig/filters/native-filter.cpp delete mode 100644 kig/filters/svgexporter.cc create mode 100644 kig/filters/svgexporter.cpp (limited to 'kig/filters') diff --git a/kig/filters/CMakeLists.txt b/kig/filters/CMakeLists.txt index 35ded394..1685098e 100644 --- a/kig/filters/CMakeLists.txt +++ b/kig/filters/CMakeLists.txt @@ -23,18 +23,18 @@ tde_add_library( kigfilters STATIC_PIC AUTOMOC latexexporteroptions.ui svgexporteroptions.ui drgeo-filter-chooserbase.ui - cabri-filter.cc - exporter.cc - filter.cc - filters-common.cc - imageexporteroptions.cc - kgeo-filter.cc - kseg-filter.cc - latexexporter.cc - native-filter.cc - svgexporter.cc - drgeo-filter.cc - drgeo-filter-chooser.cc + cabri-filter.cpp + exporter.cpp + filter.cpp + filters-common.cpp + imageexporteroptions.cpp + kgeo-filter.cpp + kseg-filter.cpp + latexexporter.cpp + native-filter.cpp + svgexporter.cpp + drgeo-filter.cpp + drgeo-filter-chooser.cpp LINK kigmisc-static diff --git a/kig/filters/Makefile.am b/kig/filters/Makefile.am index bb827b5a..c7e82bb8 100644 --- a/kig/filters/Makefile.am +++ b/kig/filters/Makefile.am @@ -19,20 +19,20 @@ noinst_HEADERS= \ drgeo-filter.h \ drgeo-filter-chooser.h libfilters_la_SOURCES= \ - cabri-filter.cc \ - exporter.cc \ - filter.cc \ - filters-common.cc \ - imageexporteroptions.cc \ + cabri-filter.cpp \ + exporter.cpp \ + filter.cpp \ + filters-common.cpp \ + imageexporteroptions.cpp \ imageexporteroptionsbase.ui \ - kgeo-filter.cc \ - kseg-filter.cc \ - latexexporter.cc \ + kgeo-filter.cpp \ + kseg-filter.cpp \ + latexexporter.cpp \ latexexporteroptions.ui \ - native-filter.cc \ - svgexporter.cc \ + native-filter.cpp \ + svgexporter.cpp \ svgexporteroptions.ui \ - drgeo-filter.cc \ - drgeo-filter-chooser.cc \ + drgeo-filter.cpp \ + drgeo-filter-chooser.cpp \ drgeo-filter-chooserbase.ui diff --git a/kig/filters/cabri-filter.cc b/kig/filters/cabri-filter.cc deleted file mode 100644 index 0a94f140..00000000 --- a/kig/filters/cabri-filter.cc +++ /dev/null @@ -1,577 +0,0 @@ -/** - This file is part of Kig, a KDE program for Interactive Geometry... - Copyright (C) 2002 Dominique Devriese - - 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 -#include -#include - -#include -#include - -/** - * 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; - TQCString type; - uint numberOfParents; - TQColor color; - TQColor fillColor; - int thick; - int lineSegLength; - int lineSegSplit; - int specialAppearanceSwitch; - bool visible; - bool fixed; - std::vector parents; - std::vector data; -}; - -KigFilterCabri::KigFilterCabri() -{ -} - -KigFilterCabri::~KigFilterCabri() -{ -} - -bool KigFilterCabri::supportMime( const TQString& 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 TQString readLine( TQFile& file ) -{ - TQString 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 TQColor translatecolor( const TQString& s ) -{ - if ( s == "R" ) return TQt::red; - if ( s == "O" ) return TQt::magenta; - if ( s == "Y" ) return TQt::yellow; - if ( s == "P" ) return TQt::darkMagenta; - if ( s == "V" ) return TQt::darkBlue; - if ( s == "Bl" ) return TQt::blue; - if ( s == "lBl" ) return TQt::cyan; // TODO: bright blue - if ( s == "G" ) return TQt::green; - if ( s == "dG" ) return TQt::darkGreen; - if ( s == "Br" ) return TQColor( 165, 42, 42 ); - if ( s == "dBr" ) return TQColor( 128, 128, 0 ); - if ( s == "lGr" ) return TQt::lightGray; - if ( s == "Gr" ) return TQt::gray; - if ( s == "dGr" ) return TQt::darkGray; - if ( s == "B" ) return TQt::black; - if ( s == "W" ) return TQt::white; - - kdDebug() << k_funcinfo << "unknown color: " << s << endl; - return TQt::black; -} - -bool KigFilterCabri::readObject( TQFile& f, CabriObject& myobj ) -{ - // there are 4 lines per object in the file, so we read them all - // four now. - TQString line1, line2, line3, s; - TQString file = f.name(); - line1 = readLine( f ); - line2 = readLine( f ); - line3 = readLine( f ); - // ignore line 4, it is empty.. - s = readLine( f ); - - TQRegExp firstlinere( "^([^:]+): ([^,]+), ([^,]+), CN:([^,]*), VN:(.*)$" ); - if ( ! firstlinere.exactMatch( line1 ) ) - KIG_FILTER_PARSE_ERROR; - - bool ok; - TQString 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.. - - TQRegExp 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"; - - TQRegExp thirdlinere( "^(Const: ([^,]*),? ?)?(Val: (.*))?$" ); - if ( ! thirdlinere.exactMatch( line3 ) ) - KIG_FILTER_PARSE_ERROR; - - tmp = thirdlinere.cap( 2 ); - TQStringList parentsids = TQStringList::split( ' ', tmp ); - for ( TQStringList::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 ); - TQStringList valIds = TQStringList::split( ' ', tmp ); - for ( TQStringList::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::iterator i = myobj.parents.begin(); i != myobj.parents.end(); ++i ) -// kdDebug() << " " << *i << endl; -// kdDebug() << "vals = " << endl; -// for ( std::vector::iterator i = myobj.data.begin(); i != myobj.data.end(); ++i ) -// kdDebug() << " " << *i << endl; - - return true; -} - -KigDocument* KigFilterCabri::load( const TQString& file ) -{ - TQFile f( file ); - if ( ! f.open( IO_ReadOnly ) ) - { - fileNotFound( file ); - return 0; - } - - KigDocument* ret = new KigDocument(); - - TQString s = readLine( f ); - TQString a = s.left( 21 ); - TQString 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 holders; - std::vector calcers; - - const ObjectFactory* fact = ObjectFactory::instance(); - - std::vector 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::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( 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( TQString(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.cpp b/kig/filters/cabri-filter.cpp new file mode 100644 index 00000000..0a94f140 --- /dev/null +++ b/kig/filters/cabri-filter.cpp @@ -0,0 +1,577 @@ +/** + This file is part of Kig, a KDE program for Interactive Geometry... + Copyright (C) 2002 Dominique Devriese + + 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 +#include +#include + +#include +#include + +/** + * 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; + TQCString type; + uint numberOfParents; + TQColor color; + TQColor fillColor; + int thick; + int lineSegLength; + int lineSegSplit; + int specialAppearanceSwitch; + bool visible; + bool fixed; + std::vector parents; + std::vector data; +}; + +KigFilterCabri::KigFilterCabri() +{ +} + +KigFilterCabri::~KigFilterCabri() +{ +} + +bool KigFilterCabri::supportMime( const TQString& 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 TQString readLine( TQFile& file ) +{ + TQString 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 TQColor translatecolor( const TQString& s ) +{ + if ( s == "R" ) return TQt::red; + if ( s == "O" ) return TQt::magenta; + if ( s == "Y" ) return TQt::yellow; + if ( s == "P" ) return TQt::darkMagenta; + if ( s == "V" ) return TQt::darkBlue; + if ( s == "Bl" ) return TQt::blue; + if ( s == "lBl" ) return TQt::cyan; // TODO: bright blue + if ( s == "G" ) return TQt::green; + if ( s == "dG" ) return TQt::darkGreen; + if ( s == "Br" ) return TQColor( 165, 42, 42 ); + if ( s == "dBr" ) return TQColor( 128, 128, 0 ); + if ( s == "lGr" ) return TQt::lightGray; + if ( s == "Gr" ) return TQt::gray; + if ( s == "dGr" ) return TQt::darkGray; + if ( s == "B" ) return TQt::black; + if ( s == "W" ) return TQt::white; + + kdDebug() << k_funcinfo << "unknown color: " << s << endl; + return TQt::black; +} + +bool KigFilterCabri::readObject( TQFile& f, CabriObject& myobj ) +{ + // there are 4 lines per object in the file, so we read them all + // four now. + TQString line1, line2, line3, s; + TQString file = f.name(); + line1 = readLine( f ); + line2 = readLine( f ); + line3 = readLine( f ); + // ignore line 4, it is empty.. + s = readLine( f ); + + TQRegExp firstlinere( "^([^:]+): ([^,]+), ([^,]+), CN:([^,]*), VN:(.*)$" ); + if ( ! firstlinere.exactMatch( line1 ) ) + KIG_FILTER_PARSE_ERROR; + + bool ok; + TQString 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.. + + TQRegExp 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"; + + TQRegExp thirdlinere( "^(Const: ([^,]*),? ?)?(Val: (.*))?$" ); + if ( ! thirdlinere.exactMatch( line3 ) ) + KIG_FILTER_PARSE_ERROR; + + tmp = thirdlinere.cap( 2 ); + TQStringList parentsids = TQStringList::split( ' ', tmp ); + for ( TQStringList::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 ); + TQStringList valIds = TQStringList::split( ' ', tmp ); + for ( TQStringList::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::iterator i = myobj.parents.begin(); i != myobj.parents.end(); ++i ) +// kdDebug() << " " << *i << endl; +// kdDebug() << "vals = " << endl; +// for ( std::vector::iterator i = myobj.data.begin(); i != myobj.data.end(); ++i ) +// kdDebug() << " " << *i << endl; + + return true; +} + +KigDocument* KigFilterCabri::load( const TQString& file ) +{ + TQFile f( file ); + if ( ! f.open( IO_ReadOnly ) ) + { + fileNotFound( file ); + return 0; + } + + KigDocument* ret = new KigDocument(); + + TQString s = readLine( f ); + TQString a = s.left( 21 ); + TQString 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 holders; + std::vector calcers; + + const ObjectFactory* fact = ObjectFactory::instance(); + + std::vector 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::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( 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( TQString(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/drgeo-filter-chooser.cc b/kig/filters/drgeo-filter-chooser.cc deleted file mode 100644 index 89250235..00000000 --- a/kig/filters/drgeo-filter-chooser.cc +++ /dev/null @@ -1,65 +0,0 @@ -// Copyright (C) 2004 Pino Toscano -// Copyright (C) 2004 Dominique Devriese - -// 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 -#include -#include -#include -#include - -KigFilterDrgeoChooser::KigFilterDrgeoChooser( const TQStringList& l ) - : KigFilterDrgeoChooserBase( 0, "drgeo_filter", true ) -{ - OKButton->setGuiItem( KStdGuiItem::ok() ); - CancelButton->setGuiItem( KStdGuiItem::cancel() ); - - FigureListBox->insertStringList( l ); - - connect( OKButton, TQT_SIGNAL( clicked() ), TQT_SLOT( slotOKPressed() ) ); - connect( CancelButton, TQT_SIGNAL( clicked() ), TQT_SLOT( slotCancelPressed() ) ); - connect( FigureListBox, TQT_SIGNAL( executed( TQListBoxItem* ) ), TQT_SLOT( slotExecuted( TQListBoxItem* ) ) ); -} - -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( TQListBoxItem* i ) -{ - done( FigureListBox->index( i ) ); -} diff --git a/kig/filters/drgeo-filter-chooser.cpp b/kig/filters/drgeo-filter-chooser.cpp new file mode 100644 index 00000000..89250235 --- /dev/null +++ b/kig/filters/drgeo-filter-chooser.cpp @@ -0,0 +1,65 @@ +// Copyright (C) 2004 Pino Toscano +// Copyright (C) 2004 Dominique Devriese + +// 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 +#include +#include +#include +#include + +KigFilterDrgeoChooser::KigFilterDrgeoChooser( const TQStringList& l ) + : KigFilterDrgeoChooserBase( 0, "drgeo_filter", true ) +{ + OKButton->setGuiItem( KStdGuiItem::ok() ); + CancelButton->setGuiItem( KStdGuiItem::cancel() ); + + FigureListBox->insertStringList( l ); + + connect( OKButton, TQT_SIGNAL( clicked() ), TQT_SLOT( slotOKPressed() ) ); + connect( CancelButton, TQT_SIGNAL( clicked() ), TQT_SLOT( slotCancelPressed() ) ); + connect( FigureListBox, TQT_SIGNAL( executed( TQListBoxItem* ) ), TQT_SLOT( slotExecuted( TQListBoxItem* ) ) ); +} + +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( TQListBoxItem* i ) +{ + done( FigureListBox->index( i ) ); +} diff --git a/kig/filters/drgeo-filter.cc b/kig/filters/drgeo-filter.cc deleted file mode 100644 index 9742fcf5..00000000 --- a/kig/filters/drgeo-filter.cc +++ /dev/null @@ -1,809 +0,0 @@ -// Copyright (C) 2004 Pino Toscano -// Copyright (C) 2004 Dominique Devriese - -// 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 - -#include -#include - -#include - -#undef DRGEO_DEBUG -//#define DRGEO_DEBUG - -struct DrGeoHierarchyElement -{ - TQString id; - std::vector parents; -}; - -KigFilterDrgeo::KigFilterDrgeo() -{ -} - -KigFilterDrgeo::~KigFilterDrgeo() -{ -} - -bool KigFilterDrgeo::supportMime( const TQString& mime ) -{ - return mime == "application/x-drgeo"; -} - -KigDocument* KigFilterDrgeo::load( const TQString& file ) -{ - TQFile f( file ); - if ( ! f.open( IO_ReadOnly ) ) - { - fileNotFound( file ); - return 0; - } - - TQStringList figures; - TQDomDocument doc( "drgenius" ); - if ( !doc.setContent( &f ) ) - KIG_FILTER_PARSE_ERROR; - TQDomElement main = doc.documentElement(); - int nmacros = 0; - // reading figures... - for ( TQDomNode n = main.firstChild(); ! n.isNull(); n = n.nextSibling() ) - { - TQDomElement 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 0; - } - - 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 ( TQDomNode n = main.firstChild(); ! n.isNull(); n = n.nextSibling() ) - { - TQDomElement 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 es, const TQString 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( TQDomNode f, const TQString& file, const bool grid ) -{ - KigDocument* ret = new KigDocument(); - - using namespace std; - std::vector elems; - int withoutid = 0; - - // 1st: fetch relationships and build an appropriate structure - for (TQDomNode a = f; ! a.isNull(); a = a.nextSibling() ) - { - TQDomElement domelem = a.toElement(); - if ( domelem.isNull() ) continue; - else - { - DrGeoHierarchyElement elem; -#ifdef DRGEO_DEBUG - kdDebug() << " * " << domelem.tagName() << "(" << domelem.attribute("type") << ")" << endl; -#endif - for ( TQDomNode c = domelem.firstChild(); ! c.isNull(); c = c.nextSibling() ) - { - TQDomElement ce = c.toElement(); - if ( ce.isNull() ) continue; - else if ( ce.tagName() == "parent" ) - elem.parents.push_back( ce.attribute( "ref" ) ); - } - TQString curid = domelem.attribute( "id" ); - elem.id = !curid.isNull() ? curid : TQString::number( withoutid++ ) ; - elems.push_back( elem ); - } - } - -#ifdef DRGEO_DEBUG - TQString 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 holders; - std::vector 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 (TQDomNode a = f; ! a.isNull(); a = a.nextSibling() ) - { -#ifdef DRGEO_DEBUG - kdDebug() << "+++ id: " << curid << endl; -#endif - const DrGeoHierarchyElement& el = elems[curid]; - std::vector 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() ); - }; - TQDomElement 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" ) - { - TQString xs; - TQString ys; - TQString values; - for ( TQDomNode c = domelem.firstChild(); ! c.isNull(); c = c.nextSibling() ) - { - TQDomElement 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 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( 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( 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 0; - } - } - 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 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 0; - } - 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 0; - } -#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 0; - } - 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 0; - } - 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 0; - } - 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 0; - } - 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 0; - } -#ifdef DRGEO_DEBUG - kdDebug() << "+++++++++ oc:" << oc << endl; -#endif - } - else if( ( domelem.tagName() == "numeric" ) || - ( domelem.tagName() == "equation" ) ) - { - TQString xs; - TQString ys; - TQString value; - for ( TQDomNode c = domelem.firstChild(); ! c.isNull(); c = c.nextSibling() ) - { - TQDomElement 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 = TQString( "%1" ).arg( dvalue, 0, 'g', 3 ); - oc = fact->labelCalcer( value, m, false, std::vector(), *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 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 0; - } -#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 0; - } -#ifdef DRGEO_DEBUG - kdDebug() << "+++++++++ oc:" << oc << endl; -#endif - } - else if ( domelem.tagName() == "script" ) - { - TQString xs; - TQString ys; - TQString text; - for ( TQDomNode c = domelem.firstChild(); ! c.isNull(); c = c.nextSibling() ) - { - TQDomElement 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(), *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 0; - } - } - 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 0; - } -#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 0; - } - curid++; - if ( oc == 0 ) - continue; - -// reading color - TQColor co( domelem.attribute( "color" ) ); - if ( ! co.isValid() ) - if ( domelem.attribute( "color" ) == "Bordeaux" ) - co.setRgb( 145, 0, 0 ); - else - co = TQt::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; - } - TQString 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 - TQString 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 args2; - args2.push_back( o->nameCalcer() ); - oc2 = fact->attachedLabelCalcer( TQString::fromLatin1( "%1" ), oc, - static_cast( oc->imp() )->coordinate(), - false, args2, *ret ); - co = TQt::black; - } - } - else if ( domelem.tagName() == "angle" ) - { - oc2 = filtersConstructTextObject( - static_cast( 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.cpp b/kig/filters/drgeo-filter.cpp new file mode 100644 index 00000000..9742fcf5 --- /dev/null +++ b/kig/filters/drgeo-filter.cpp @@ -0,0 +1,809 @@ +// Copyright (C) 2004 Pino Toscano +// Copyright (C) 2004 Dominique Devriese + +// 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 + +#include +#include + +#include + +#undef DRGEO_DEBUG +//#define DRGEO_DEBUG + +struct DrGeoHierarchyElement +{ + TQString id; + std::vector parents; +}; + +KigFilterDrgeo::KigFilterDrgeo() +{ +} + +KigFilterDrgeo::~KigFilterDrgeo() +{ +} + +bool KigFilterDrgeo::supportMime( const TQString& mime ) +{ + return mime == "application/x-drgeo"; +} + +KigDocument* KigFilterDrgeo::load( const TQString& file ) +{ + TQFile f( file ); + if ( ! f.open( IO_ReadOnly ) ) + { + fileNotFound( file ); + return 0; + } + + TQStringList figures; + TQDomDocument doc( "drgenius" ); + if ( !doc.setContent( &f ) ) + KIG_FILTER_PARSE_ERROR; + TQDomElement main = doc.documentElement(); + int nmacros = 0; + // reading figures... + for ( TQDomNode n = main.firstChild(); ! n.isNull(); n = n.nextSibling() ) + { + TQDomElement 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 0; + } + + 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 ( TQDomNode n = main.firstChild(); ! n.isNull(); n = n.nextSibling() ) + { + TQDomElement 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 es, const TQString 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( TQDomNode f, const TQString& file, const bool grid ) +{ + KigDocument* ret = new KigDocument(); + + using namespace std; + std::vector elems; + int withoutid = 0; + + // 1st: fetch relationships and build an appropriate structure + for (TQDomNode a = f; ! a.isNull(); a = a.nextSibling() ) + { + TQDomElement domelem = a.toElement(); + if ( domelem.isNull() ) continue; + else + { + DrGeoHierarchyElement elem; +#ifdef DRGEO_DEBUG + kdDebug() << " * " << domelem.tagName() << "(" << domelem.attribute("type") << ")" << endl; +#endif + for ( TQDomNode c = domelem.firstChild(); ! c.isNull(); c = c.nextSibling() ) + { + TQDomElement ce = c.toElement(); + if ( ce.isNull() ) continue; + else if ( ce.tagName() == "parent" ) + elem.parents.push_back( ce.attribute( "ref" ) ); + } + TQString curid = domelem.attribute( "id" ); + elem.id = !curid.isNull() ? curid : TQString::number( withoutid++ ) ; + elems.push_back( elem ); + } + } + +#ifdef DRGEO_DEBUG + TQString 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 holders; + std::vector 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 (TQDomNode a = f; ! a.isNull(); a = a.nextSibling() ) + { +#ifdef DRGEO_DEBUG + kdDebug() << "+++ id: " << curid << endl; +#endif + const DrGeoHierarchyElement& el = elems[curid]; + std::vector 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() ); + }; + TQDomElement 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" ) + { + TQString xs; + TQString ys; + TQString values; + for ( TQDomNode c = domelem.firstChild(); ! c.isNull(); c = c.nextSibling() ) + { + TQDomElement 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 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( 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( 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 0; + } + } + 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 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 0; + } + 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 0; + } +#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 0; + } + 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 0; + } + 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 0; + } + 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 0; + } + 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 0; + } +#ifdef DRGEO_DEBUG + kdDebug() << "+++++++++ oc:" << oc << endl; +#endif + } + else if( ( domelem.tagName() == "numeric" ) || + ( domelem.tagName() == "equation" ) ) + { + TQString xs; + TQString ys; + TQString value; + for ( TQDomNode c = domelem.firstChild(); ! c.isNull(); c = c.nextSibling() ) + { + TQDomElement 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 = TQString( "%1" ).arg( dvalue, 0, 'g', 3 ); + oc = fact->labelCalcer( value, m, false, std::vector(), *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 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 0; + } +#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 0; + } +#ifdef DRGEO_DEBUG + kdDebug() << "+++++++++ oc:" << oc << endl; +#endif + } + else if ( domelem.tagName() == "script" ) + { + TQString xs; + TQString ys; + TQString text; + for ( TQDomNode c = domelem.firstChild(); ! c.isNull(); c = c.nextSibling() ) + { + TQDomElement 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(), *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 0; + } + } + 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 0; + } +#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 0; + } + curid++; + if ( oc == 0 ) + continue; + +// reading color + TQColor co( domelem.attribute( "color" ) ); + if ( ! co.isValid() ) + if ( domelem.attribute( "color" ) == "Bordeaux" ) + co.setRgb( 145, 0, 0 ); + else + co = TQt::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; + } + TQString 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 + TQString 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 args2; + args2.push_back( o->nameCalcer() ); + oc2 = fact->attachedLabelCalcer( TQString::fromLatin1( "%1" ), oc, + static_cast( oc->imp() )->coordinate(), + false, args2, *ret ); + co = TQt::black; + } + } + else if ( domelem.tagName() == "angle" ) + { + oc2 = filtersConstructTextObject( + static_cast( 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/exporter.cc b/kig/filters/exporter.cc deleted file mode 100644 index 32b25f01..00000000 --- a/kig/filters/exporter.cc +++ /dev/null @@ -1,624 +0,0 @@ -// Copyright (C) 2003 Dominique Devriese - -// 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 -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -#include - -// we need this for storing colors in a std::map.. -static bool operator<( const TQColor& a, const TQColor& b ) -{ - return a.rgb() < b.rgb(); -} - -class ExporterAction - : public TDEAction -{ - KigExporter* mexp; - const KigPart* mdoc; - KigWidget* mw; -public: - ExporterAction( const KigPart* doc, KigWidget* w, - TDEActionCollection* parent, KigExporter* exp ); - void slotActivated(); -}; - -ExporterAction::ExporterAction( const KigPart* doc, KigWidget* w, - TDEActionCollection* parent, KigExporter* exp ) - : TDEAction( exp->menuEntryName(), TDEShortcut(), 0, 0, parent ), - mexp( exp ), mdoc( doc ), mw( w ) -{ - TQString iconstr = exp->menuIcon(); - if ( iconstr.isEmpty() ) - return; - TDEIconLoader* l = doc->instance()->iconLoader(); - TQPixmap icon = l->loadIcon( iconstr, TDEIcon::Small, 16, TDEIcon::DefaultState, 0L, true ); - if ( !icon.isNull() ) - setIconSet( TQIconSet( icon ) ); -} - -void ExporterAction::slotActivated() -{ - mexp->run( *mdoc, *mw ); -} - -KigExporter::~KigExporter() -{ -} - -ImageExporter::~ImageExporter() -{ -} - -TQString ImageExporter::exportToStatement() const -{ - return i18n( "&Export to image" ); -} - -TQString ImageExporter::menuEntryName() const -{ - return i18n( "&Image..." ); -} - -TQString ImageExporter::menuIcon() const -{ - return "image-x-generic"; -} - -void ImageExporter::run( const KigPart& doc, KigWidget& w ) -{ - static bool kimageioRegistered = false; - if ( ! kimageioRegistered ) - { - KImageIO::registerFormats(); - kimageioRegistered = true; - } - - KigFileDialog* kfd = new KigFileDialog( - TQString(), 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; - - TQString 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; - - TQString type = KImageIO::type( filename ); - if ( type.isNull() ) - { - KMessageBox::sorry( &w, i18n( "Sorry, this file format is not supported." ) ); - return; - }; - - kdDebug() << k_funcinfo << type << endl; - - TQFile 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; - }; - - TQPixmap img( TQSize( width, height ) ); - img.fill( TQt::white ); - KigPainter p( ScreenInfo( w.screenInfo().shownRect(), img.rect() ), TQT_TQPAINTDEVICE(&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, - TDEActionCollection* coll ) -{ - TDEActionMenu* m = - new TDEActionMenu( 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() -{ -} - -TQString XFigExporter::exportToStatement() const -{ - return i18n( "Export to &XFig file" ); -} - - -TQString XFigExporter::menuEntryName() const -{ - return i18n( "&XFig File..." ); -} - -TQString XFigExporter::menuIcon() const -{ - return "kig_xfig"; -} - -class XFigExportImpVisitor - : public ObjectImpVisitor -{ - TQTextStream& mstream; - ObjectHolder* mcurobj; - const KigWidget& mw; - Rect msr; - std::map mcolormap; - int mnextcolorid; - int mcurcolorid; - - TQPoint 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.toTQPoint(); - } - - void emitLine( const Coordinate& a, const Coordinate& b, int width, bool vector = false ); -public: - void visit( ObjectHolder* obj ); - void mapColor( const ObjectDrawer* obj ); - - XFigExportImpVisitor( TQTextStream& s, const KigWidget& w ) - : mstream( s ), mw( w ), msr( mw.showingRect() ), - mnextcolorid( 32 ) - { - // predefined colors in XFig.. - mcolormap[TQt::black] = 0; - mcolormap[TQt::blue] = 1; - mcolormap[TQt::green] = 2; - mcolormap[TQt::cyan] = 3; - mcolormap[TQt::red] = 4; - mcolormap[TQt::magenta] = 5; - mcolormap[TQt::yellow] = 6; - mcolormap[TQt::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; - TQColor 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"; - } - TQPoint ca = convertCoord( a ); - TQPoint cb = convertCoord( b ); - - mstream << ca.x() << " " << ca.y() << " " << cb.x() << " " << cb.y() << "\n"; -} - -void XFigExportImpVisitor::visit( const PointImp* imp ) -{ - const TQPoint 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 ) -{ - TQString text = imp->text(); - TQPoint 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 TQPoint 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 TQPoint 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 TQPoint 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 TQPoint a = convertCoord( center + ad ); - const TQPoint b = convertCoord( center + bd ); - const TQPoint c = convertCoord( center + cd ); - const TQPoint 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; - - TQString file_name = kfd->selectedFile(); - - delete kfd; - - TQFile 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; - }; - TQTextStream 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 os = doc.document().objects(); - XFigExportImpVisitor visitor( stream, w ); - - for ( std::vector::const_iterator i = os.begin(); - i != os.end(); ++i ) - { - visitor.mapColor( ( *i )->drawer() ); - }; - - for ( std::vector::const_iterator i = os.begin(); - i != os.end(); ++i ) - { - visitor.visit( *i ); - }; -} diff --git a/kig/filters/exporter.cpp b/kig/filters/exporter.cpp new file mode 100644 index 00000000..32b25f01 --- /dev/null +++ b/kig/filters/exporter.cpp @@ -0,0 +1,624 @@ +// Copyright (C) 2003 Dominique Devriese + +// 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 +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include + +// we need this for storing colors in a std::map.. +static bool operator<( const TQColor& a, const TQColor& b ) +{ + return a.rgb() < b.rgb(); +} + +class ExporterAction + : public TDEAction +{ + KigExporter* mexp; + const KigPart* mdoc; + KigWidget* mw; +public: + ExporterAction( const KigPart* doc, KigWidget* w, + TDEActionCollection* parent, KigExporter* exp ); + void slotActivated(); +}; + +ExporterAction::ExporterAction( const KigPart* doc, KigWidget* w, + TDEActionCollection* parent, KigExporter* exp ) + : TDEAction( exp->menuEntryName(), TDEShortcut(), 0, 0, parent ), + mexp( exp ), mdoc( doc ), mw( w ) +{ + TQString iconstr = exp->menuIcon(); + if ( iconstr.isEmpty() ) + return; + TDEIconLoader* l = doc->instance()->iconLoader(); + TQPixmap icon = l->loadIcon( iconstr, TDEIcon::Small, 16, TDEIcon::DefaultState, 0L, true ); + if ( !icon.isNull() ) + setIconSet( TQIconSet( icon ) ); +} + +void ExporterAction::slotActivated() +{ + mexp->run( *mdoc, *mw ); +} + +KigExporter::~KigExporter() +{ +} + +ImageExporter::~ImageExporter() +{ +} + +TQString ImageExporter::exportToStatement() const +{ + return i18n( "&Export to image" ); +} + +TQString ImageExporter::menuEntryName() const +{ + return i18n( "&Image..." ); +} + +TQString ImageExporter::menuIcon() const +{ + return "image-x-generic"; +} + +void ImageExporter::run( const KigPart& doc, KigWidget& w ) +{ + static bool kimageioRegistered = false; + if ( ! kimageioRegistered ) + { + KImageIO::registerFormats(); + kimageioRegistered = true; + } + + KigFileDialog* kfd = new KigFileDialog( + TQString(), 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; + + TQString 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; + + TQString type = KImageIO::type( filename ); + if ( type.isNull() ) + { + KMessageBox::sorry( &w, i18n( "Sorry, this file format is not supported." ) ); + return; + }; + + kdDebug() << k_funcinfo << type << endl; + + TQFile 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; + }; + + TQPixmap img( TQSize( width, height ) ); + img.fill( TQt::white ); + KigPainter p( ScreenInfo( w.screenInfo().shownRect(), img.rect() ), TQT_TQPAINTDEVICE(&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, + TDEActionCollection* coll ) +{ + TDEActionMenu* m = + new TDEActionMenu( 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() +{ +} + +TQString XFigExporter::exportToStatement() const +{ + return i18n( "Export to &XFig file" ); +} + + +TQString XFigExporter::menuEntryName() const +{ + return i18n( "&XFig File..." ); +} + +TQString XFigExporter::menuIcon() const +{ + return "kig_xfig"; +} + +class XFigExportImpVisitor + : public ObjectImpVisitor +{ + TQTextStream& mstream; + ObjectHolder* mcurobj; + const KigWidget& mw; + Rect msr; + std::map mcolormap; + int mnextcolorid; + int mcurcolorid; + + TQPoint 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.toTQPoint(); + } + + void emitLine( const Coordinate& a, const Coordinate& b, int width, bool vector = false ); +public: + void visit( ObjectHolder* obj ); + void mapColor( const ObjectDrawer* obj ); + + XFigExportImpVisitor( TQTextStream& s, const KigWidget& w ) + : mstream( s ), mw( w ), msr( mw.showingRect() ), + mnextcolorid( 32 ) + { + // predefined colors in XFig.. + mcolormap[TQt::black] = 0; + mcolormap[TQt::blue] = 1; + mcolormap[TQt::green] = 2; + mcolormap[TQt::cyan] = 3; + mcolormap[TQt::red] = 4; + mcolormap[TQt::magenta] = 5; + mcolormap[TQt::yellow] = 6; + mcolormap[TQt::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; + TQColor 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"; + } + TQPoint ca = convertCoord( a ); + TQPoint cb = convertCoord( b ); + + mstream << ca.x() << " " << ca.y() << " " << cb.x() << " " << cb.y() << "\n"; +} + +void XFigExportImpVisitor::visit( const PointImp* imp ) +{ + const TQPoint 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 ) +{ + TQString text = imp->text(); + TQPoint 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 TQPoint 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 TQPoint 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 TQPoint 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 TQPoint a = convertCoord( center + ad ); + const TQPoint b = convertCoord( center + bd ); + const TQPoint c = convertCoord( center + cd ); + const TQPoint 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; + + TQString file_name = kfd->selectedFile(); + + delete kfd; + + TQFile 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; + }; + TQTextStream 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 os = doc.document().objects(); + XFigExportImpVisitor visitor( stream, w ); + + for ( std::vector::const_iterator i = os.begin(); + i != os.end(); ++i ) + { + visitor.mapColor( ( *i )->drawer() ); + }; + + for ( std::vector::const_iterator i = os.begin(); + i != os.end(); ++i ) + { + visitor.visit( *i ); + }; +} diff --git a/kig/filters/filter.cc b/kig/filters/filter.cc deleted file mode 100644 index 6a543430..00000000 --- a/kig/filters/filter.cc +++ /dev/null @@ -1,114 +0,0 @@ -/** - This file is part of Kig, a KDE program for Interactive Geometry... - Copyright (C) 2002 Dominique Devriese - - 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 -#include - -KigFilters* KigFilters::sThis; - -KigFilter* KigFilters::find(const TQString& 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 TQString& ) -{ - return false; -} - -void KigFilter::fileNotFound( const TQString& 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 TQString& file, const TQString& explanation ) const -{ - const TQString text = - i18n( "An error was encountered while parsing the file \"%1\". It " - "cannot be opened." ).arg( file ); - const TQString title = i18n( "Parse Error" ); - - if ( explanation.isNull() ) - KMessageBox::sorry( 0, text, title ); - else - KMessageBox::detailedSorry( 0, text, explanation, title ); -} - -void KigFilter::notSupported( const TQString& file, const TQString& explanation ) const -{ - KMessageBox::detailedSorry( 0, - i18n( "Kig cannot open the file \"%1\"." ).arg( file ), - explanation, i18n( "Not Supported" ) ); -} - -void KigFilter::warning( const TQString& explanation ) const -{ - KMessageBox::information( 0, explanation ); -} - -bool KigFilters::save( const KigDocument& data, const TQString& tofile ) -{ - return KigFilterNative::instance()->save( data, tofile ); -} - -/* -bool KigFilters::save( const KigDocument& data, TQTextStream& stream ) -{ - return KigFilterNative::instance()->save( data, stream ); -} -*/ diff --git a/kig/filters/filter.cpp b/kig/filters/filter.cpp new file mode 100644 index 00000000..6a543430 --- /dev/null +++ b/kig/filters/filter.cpp @@ -0,0 +1,114 @@ +/** + This file is part of Kig, a KDE program for Interactive Geometry... + Copyright (C) 2002 Dominique Devriese + + 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 +#include + +KigFilters* KigFilters::sThis; + +KigFilter* KigFilters::find(const TQString& 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 TQString& ) +{ + return false; +} + +void KigFilter::fileNotFound( const TQString& 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 TQString& file, const TQString& explanation ) const +{ + const TQString text = + i18n( "An error was encountered while parsing the file \"%1\". It " + "cannot be opened." ).arg( file ); + const TQString title = i18n( "Parse Error" ); + + if ( explanation.isNull() ) + KMessageBox::sorry( 0, text, title ); + else + KMessageBox::detailedSorry( 0, text, explanation, title ); +} + +void KigFilter::notSupported( const TQString& file, const TQString& explanation ) const +{ + KMessageBox::detailedSorry( 0, + i18n( "Kig cannot open the file \"%1\"." ).arg( file ), + explanation, i18n( "Not Supported" ) ); +} + +void KigFilter::warning( const TQString& explanation ) const +{ + KMessageBox::information( 0, explanation ); +} + +bool KigFilters::save( const KigDocument& data, const TQString& tofile ) +{ + return KigFilterNative::instance()->save( data, tofile ); +} + +/* +bool KigFilters::save( const KigDocument& data, TQTextStream& stream ) +{ + return KigFilterNative::instance()->save( data, stream ); +} +*/ diff --git a/kig/filters/filters-common.cc b/kig/filters/filters-common.cc deleted file mode 100644 index 4ba24e9f..00000000 --- a/kig/filters/filters-common.cc +++ /dev/null @@ -1,39 +0,0 @@ -// Copyright (C) 2004 Dominique Devriese - -// 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 - -#include -#include - -#include "../objects/object_calcer.h" -#include "../objects/object_factory.h" - -ObjectTypeCalcer* filtersConstructTextObject( - const Coordinate& c, ObjectCalcer* o, - const TQCString& arg, const KigDocument& doc, bool needframe ) -{ - const ObjectFactory* fact = ObjectFactory::instance(); - ObjectCalcer* propo = fact->propertyObjectCalcer( o, arg ); - propo->calc( doc ); - std::vector args; - args.push_back( propo ); - return fact->labelCalcer( TQString::fromLatin1( "%1" ), c, needframe, - args, doc ); -} diff --git a/kig/filters/filters-common.cpp b/kig/filters/filters-common.cpp new file mode 100644 index 00000000..4ba24e9f --- /dev/null +++ b/kig/filters/filters-common.cpp @@ -0,0 +1,39 @@ +// Copyright (C) 2004 Dominique Devriese + +// 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 + +#include +#include + +#include "../objects/object_calcer.h" +#include "../objects/object_factory.h" + +ObjectTypeCalcer* filtersConstructTextObject( + const Coordinate& c, ObjectCalcer* o, + const TQCString& arg, const KigDocument& doc, bool needframe ) +{ + const ObjectFactory* fact = ObjectFactory::instance(); + ObjectCalcer* propo = fact->propertyObjectCalcer( o, arg ); + propo->calc( doc ); + std::vector args; + args.push_back( propo ); + return fact->labelCalcer( TQString::fromLatin1( "%1" ), c, needframe, + args, doc ); +} diff --git a/kig/filters/imageexporteroptions.cc b/kig/filters/imageexporteroptions.cc deleted file mode 100644 index cd68a0af..00000000 --- a/kig/filters/imageexporteroptions.cc +++ /dev/null @@ -1,57 +0,0 @@ -// Copyright (C) 2002 Dominique Devriese - -// 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 -#include - -#include - -ImageExporterOptions::ImageExporterOptions( TQWidget* parent, const TQSize& s ) - : ImageExporterOptionsBase( parent, "imageexporteroptions" ), msize( s ), - minternallysettingstuff( false ) -{ - keepAspectRatio->setChecked( true ); - connect( WidthInput, TQT_SIGNAL( valueChanged( int ) ), this, TQT_SLOT( slotWidthChanged( int ) ) ); - connect( HeightInput, TQT_SIGNAL( valueChanged( int ) ), this, TQT_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.cpp b/kig/filters/imageexporteroptions.cpp new file mode 100644 index 00000000..cd68a0af --- /dev/null +++ b/kig/filters/imageexporteroptions.cpp @@ -0,0 +1,57 @@ +// Copyright (C) 2002 Dominique Devriese + +// 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 +#include + +#include + +ImageExporterOptions::ImageExporterOptions( TQWidget* parent, const TQSize& s ) + : ImageExporterOptionsBase( parent, "imageexporteroptions" ), msize( s ), + minternallysettingstuff( false ) +{ + keepAspectRatio->setChecked( true ); + connect( WidthInput, TQT_SIGNAL( valueChanged( int ) ), this, TQT_SLOT( slotWidthChanged( int ) ) ); + connect( HeightInput, TQT_SIGNAL( valueChanged( int ) ), this, TQT_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/kgeo-filter.cc b/kig/filters/kgeo-filter.cc deleted file mode 100644 index 8849256b..00000000 --- a/kig/filters/kgeo-filter.cc +++ /dev/null @@ -1,374 +0,0 @@ -/** - This file is part of Kig, a KDE program for Interactive Geometry... - Copyright (C) 2002 Dominique Devriese - - 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 - -#include -#include - -bool KigFilterKGeo::supportMime( const TQString& mime ) -{ - return mime == "application/x-kgeo"; -} - -KigDocument* KigFilterKGeo::load( const TQString& 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 parents; -}; - -static void visitElem( std::vector& ret, - const std::vector& elems, - std::vector& 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 sortElems( const std::vector elems ) -{ - std::vector ret; - std::vector seenElems( elems.size(), false ); - for ( uint i = 0; i < elems.size(); ++i ) - visitElem( ret, elems, seenElems, i ); - return ret; -} - -KigDocument* KigFilterKGeo::loadObjects( const TQString& file, KSimpleConfig* c ) -{ - KigDocument* ret = new KigDocument(); - - using namespace std; - - TQString 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 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 ); - TQStrList parents; - c->readListEntry( "Parents", parents ); - elems.push_back( elem ); - for ( const char* parent = parents.first(); parent; parent = parents.next() ) - { - int parentIndex = TQString::fromLatin1( parent ).toInt( &ok ); - if ( ! ok ) KIG_FILTER_PARSE_ERROR; - if ( parentIndex != 0 ) - elems[i].parents.push_back( parentIndex - 1 ); - }; - }; - - std::vector sortedElems = sortElems( elems ); - std::vector 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 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... - TQString strX = c->readEntry("TQPointX"); - TQString strY = c->readEntry("TQPointY"); - 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" ); - TQString 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(), *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( 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( parents[0]->imp() )->coordinate() + - static_cast( 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( 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( parents[0]->imp() )->coordinate() + - static_cast( 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( 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... - TQColor co = c->readColorEntry( "Color" ); - if( !co.isValid() ) - co = TQt::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.cpp b/kig/filters/kgeo-filter.cpp new file mode 100644 index 00000000..8849256b --- /dev/null +++ b/kig/filters/kgeo-filter.cpp @@ -0,0 +1,374 @@ +/** + This file is part of Kig, a KDE program for Interactive Geometry... + Copyright (C) 2002 Dominique Devriese + + 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 + +#include +#include + +bool KigFilterKGeo::supportMime( const TQString& mime ) +{ + return mime == "application/x-kgeo"; +} + +KigDocument* KigFilterKGeo::load( const TQString& 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 parents; +}; + +static void visitElem( std::vector& ret, + const std::vector& elems, + std::vector& 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 sortElems( const std::vector elems ) +{ + std::vector ret; + std::vector seenElems( elems.size(), false ); + for ( uint i = 0; i < elems.size(); ++i ) + visitElem( ret, elems, seenElems, i ); + return ret; +} + +KigDocument* KigFilterKGeo::loadObjects( const TQString& file, KSimpleConfig* c ) +{ + KigDocument* ret = new KigDocument(); + + using namespace std; + + TQString 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 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 ); + TQStrList parents; + c->readListEntry( "Parents", parents ); + elems.push_back( elem ); + for ( const char* parent = parents.first(); parent; parent = parents.next() ) + { + int parentIndex = TQString::fromLatin1( parent ).toInt( &ok ); + if ( ! ok ) KIG_FILTER_PARSE_ERROR; + if ( parentIndex != 0 ) + elems[i].parents.push_back( parentIndex - 1 ); + }; + }; + + std::vector sortedElems = sortElems( elems ); + std::vector 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 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... + TQString strX = c->readEntry("TQPointX"); + TQString strY = c->readEntry("TQPointY"); + 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" ); + TQString 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(), *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( 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( parents[0]->imp() )->coordinate() + + static_cast( 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( 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( parents[0]->imp() )->coordinate() + + static_cast( 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( 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... + TQColor co = c->readColorEntry( "Color" ); + if( !co.isValid() ) + co = TQt::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/kseg-filter.cc b/kig/filters/kseg-filter.cc deleted file mode 100644 index 1567ed37..00000000 --- a/kig/filters/kseg-filter.cc +++ /dev/null @@ -1,679 +0,0 @@ -// Copyright (C) 2003 Dominique Devriese - -// 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 -#include -#include -#include -#include -#include - -#include - -KigFilterKSeg::KigFilterKSeg() -{ -} - -KigFilterKSeg::~KigFilterKSeg() -{ -} - -bool KigFilterKSeg::supportMime( const TQString& mime ) -{ - return mime == "application/x-kseg"; -} - -struct drawstyle -{ - TQ_INT8 pointstyle; - TQFont font; - TQPen pen; - TQBrush brush; -}; - -static Coordinate readKSegCoordinate( TQDataStream& 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& 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 intparents( parents ); - intparents.push_back( new ObjectConstCalcer( new IntImp( which ) ) ); - return new ObjectTypeCalcer( ConicLineIntersectionType::instance(), intparents ); - } - else if ( nlines == 0 && nconics == 2 ) - { - std::vector 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 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 intparents( parents ); - intparents.push_back( new ObjectConstCalcer( new IntImp( which ) ) ); - return new ObjectTypeCalcer( ArcLineIntersectionType::instance(), intparents ); - } - else return 0; -} - -ObjectCalcer* KigFilterKSeg::transformObject( const TQString& file, KigDocument& kigdoc, - std::vector& parents, - int subtype, bool& ok ) -{ - ok = true; - ObjectCalcer* retobj = 0; - switch( subtype ) - { - case G_TRANSLATED: - { - std::vector vectorparents( parents.begin() + 1, parents.end() ); - ObjectTypeCalcer* vector = new ObjectTypeCalcer( VectorType::instance(), vectorparents ); - vector->calc( kigdoc ); - - std::vector transparents; - transparents.push_back( parents[0] ); - transparents.push_back( vector ); - retobj = new ObjectTypeCalcer( TranslatedType::instance(), transparents ); - break; - } - case G_ROTATED: - { - std::vector angleparents( parents.begin() + 2, parents.end() ); - ObjectTypeCalcer* angle = new ObjectTypeCalcer( AngleType::instance(), angleparents ); - angle->calc( kigdoc ); - - std::vector 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 mirparents( parents.begin(), parents.end() ); - retobj = new ObjectTypeCalcer( LineReflectionType::instance(), mirparents ); - break; - } - } - - return retobj; -} - -KigDocument* KigFilterKSeg::load( const TQString& file ) -{ - TQFile ffile( file ); - if ( ! ffile.open( IO_ReadOnly ) ) - { - fileNotFound( file ); - return 0; - }; - - KigDocument* retdoc = new KigDocument(); - - TQDataStream fstream( &ffile ); - - TQString versionstring; - fstream >> versionstring; - if ( !versionstring.startsWith( "KSeg Document Version " ) ) - KIG_FILTER_PARSE_ERROR; - - TQByteArray array; - fstream >> array; - TQBuffer buf( array ); - buf.open( IO_ReadOnly ); - TQDataStream stream( &buf ); - - stream.setVersion( 3 ); - - // G_drawstyles: - short numstyles; - stream >> numstyles; - std::vector 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 ret; - std::vector 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 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.. - TQString 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; - - TQColor 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 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 0; - }; - case G_ARCSECTOR: - { - notSupported( file, i18n( "This KSeg file contains an arc sector, " - "which Kig does not currently support." ) ); - return 0; - }; - case G_ARCSEGMENT: - { - notSupported( file, i18n( "This KSeg file contains an arc segment, " - "which Kig does not currently support." ) ); - return 0; - }; - 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 args2; - args2.push_back( object->nameCalcer() ); - ObjectCalcer* oc2 = fact->attachedLabelCalcer( - TQString::fromLatin1( "%1" ), object->calcer(), - static_cast( 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 ) - { - TQString 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.cpp b/kig/filters/kseg-filter.cpp new file mode 100644 index 00000000..1567ed37 --- /dev/null +++ b/kig/filters/kseg-filter.cpp @@ -0,0 +1,679 @@ +// Copyright (C) 2003 Dominique Devriese + +// 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 +#include +#include +#include +#include +#include + +#include + +KigFilterKSeg::KigFilterKSeg() +{ +} + +KigFilterKSeg::~KigFilterKSeg() +{ +} + +bool KigFilterKSeg::supportMime( const TQString& mime ) +{ + return mime == "application/x-kseg"; +} + +struct drawstyle +{ + TQ_INT8 pointstyle; + TQFont font; + TQPen pen; + TQBrush brush; +}; + +static Coordinate readKSegCoordinate( TQDataStream& 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& 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 intparents( parents ); + intparents.push_back( new ObjectConstCalcer( new IntImp( which ) ) ); + return new ObjectTypeCalcer( ConicLineIntersectionType::instance(), intparents ); + } + else if ( nlines == 0 && nconics == 2 ) + { + std::vector 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 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 intparents( parents ); + intparents.push_back( new ObjectConstCalcer( new IntImp( which ) ) ); + return new ObjectTypeCalcer( ArcLineIntersectionType::instance(), intparents ); + } + else return 0; +} + +ObjectCalcer* KigFilterKSeg::transformObject( const TQString& file, KigDocument& kigdoc, + std::vector& parents, + int subtype, bool& ok ) +{ + ok = true; + ObjectCalcer* retobj = 0; + switch( subtype ) + { + case G_TRANSLATED: + { + std::vector vectorparents( parents.begin() + 1, parents.end() ); + ObjectTypeCalcer* vector = new ObjectTypeCalcer( VectorType::instance(), vectorparents ); + vector->calc( kigdoc ); + + std::vector transparents; + transparents.push_back( parents[0] ); + transparents.push_back( vector ); + retobj = new ObjectTypeCalcer( TranslatedType::instance(), transparents ); + break; + } + case G_ROTATED: + { + std::vector angleparents( parents.begin() + 2, parents.end() ); + ObjectTypeCalcer* angle = new ObjectTypeCalcer( AngleType::instance(), angleparents ); + angle->calc( kigdoc ); + + std::vector 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 mirparents( parents.begin(), parents.end() ); + retobj = new ObjectTypeCalcer( LineReflectionType::instance(), mirparents ); + break; + } + } + + return retobj; +} + +KigDocument* KigFilterKSeg::load( const TQString& file ) +{ + TQFile ffile( file ); + if ( ! ffile.open( IO_ReadOnly ) ) + { + fileNotFound( file ); + return 0; + }; + + KigDocument* retdoc = new KigDocument(); + + TQDataStream fstream( &ffile ); + + TQString versionstring; + fstream >> versionstring; + if ( !versionstring.startsWith( "KSeg Document Version " ) ) + KIG_FILTER_PARSE_ERROR; + + TQByteArray array; + fstream >> array; + TQBuffer buf( array ); + buf.open( IO_ReadOnly ); + TQDataStream stream( &buf ); + + stream.setVersion( 3 ); + + // G_drawstyles: + short numstyles; + stream >> numstyles; + std::vector 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 ret; + std::vector 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 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.. + TQString 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; + + TQColor 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 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 0; + }; + case G_ARCSECTOR: + { + notSupported( file, i18n( "This KSeg file contains an arc sector, " + "which Kig does not currently support." ) ); + return 0; + }; + case G_ARCSEGMENT: + { + notSupported( file, i18n( "This KSeg file contains an arc segment, " + "which Kig does not currently support." ) ); + return 0; + }; + 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 args2; + args2.push_back( object->nameCalcer() ); + ObjectCalcer* oc2 = fact->attachedLabelCalcer( + TQString::fromLatin1( "%1" ), object->calcer(), + static_cast( 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 ) + { + TQString 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/latexexporter.cc b/kig/filters/latexexporter.cc deleted file mode 100644 index 622a1a49..00000000 --- a/kig/filters/latexexporter.cc +++ /dev/null @@ -1,608 +0,0 @@ -// Copyright (C) 2004 Pino Toscano - -// 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 - -#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 -#include - -#include -#include -#include -#include - -#include -#include - -#ifdef HAVE_TRUNC -#define KDE_TRUNC(a) trunc(a) -#else -#define KDE_TRUNC(a) rint(a) -#endif - -struct ColorMap { - TQColor color; - TQString name; -}; - -LatexExporter::~LatexExporter() -{ -} - -TQString LatexExporter::exportToStatement() const -{ - return i18n( "Export to &Latex..." ); -} - -TQString LatexExporter::menuEntryName() const -{ - return i18n( "&Latex..." ); -} - -TQString LatexExporter::menuIcon() const -{ - // TODO - return "text-x-tex"; -} - -class LatexExportImpVisitor - : public ObjectImpVisitor -{ - TQTextStream& mstream; - ObjectHolder* mcurobj; - const KigWidget& mw; - Rect msr; - std::vector mcolors; - TQString mcurcolorid; -public: - void visit( ObjectHolder* obj ); - void mapColor( TQColor color ); - - LatexExportImpVisitor( TQTextStream& 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( TQColor 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. - */ - TQString 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( TQColor c ) -{ - for ( uint i = 0; i < mcolors.size(); ++i ) - { - if ( c == mcolors[i].color ) - return i; - } - return -1; -} - -void LatexExportImpVisitor::mapColor( TQColor color ) -{ - if ( findColor( color ) == -1 ) - { - ColorMap newcolor; - newcolor.color = color; - TQString 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 ) -{ - TQRect qr( 0, 0, dim, dim ); - Rect r = mw.screenInfo().fromScreen( qr ); - return fabs( r.width() ); -} - -TQString LatexExportImpVisitor::writeStyle( Qt::PenStyle style ) -{ - TQString ret( "linestyle=" ); - if ( style == TQt::DashLine ) - ret += "dashed"; - else if ( style == TQt::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; - - TQString prefix = TQString( "\\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(); - TQString 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 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( - TQString(), 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; - - TQString file_name = kfd->selectedFile(); - bool showgrid = opts->showGridCheckBox->isOn(); - bool showaxes = opts->showAxesCheckBox->isOn(); - bool showframe = opts->showExtraFrameCheckBox->isOn(); - - delete opts; - delete kfd; - - TQFile 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; - }; - - TQTextStream 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 os = doc.document().objects(); - LatexExportImpVisitor visitor( stream, w ); - visitor.unit = xunit; - - for ( std::vector::const_iterator i = os.begin(); - i != os.end(); ++i ) - { - if ( ! ( *i )->shown() ) continue; - visitor.mapColor( ( *i )->drawer()->color() ); - }; - visitor.mapColor( TQColor( 255, 255, 222 ) ); // ffffde - text label background - visitor.mapColor( TQColor( 197, 194, 197 ) ); // c5c2c5 - text label border line - visitor.mapColor( TQColor( 160, 160, 164 ) ); // a0a0a4 - axes color - visitor.mapColor( TQColor( 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( 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( 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::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.cpp b/kig/filters/latexexporter.cpp new file mode 100644 index 00000000..622a1a49 --- /dev/null +++ b/kig/filters/latexexporter.cpp @@ -0,0 +1,608 @@ +// Copyright (C) 2004 Pino Toscano + +// 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 + +#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 +#include + +#include +#include +#include +#include + +#include +#include + +#ifdef HAVE_TRUNC +#define KDE_TRUNC(a) trunc(a) +#else +#define KDE_TRUNC(a) rint(a) +#endif + +struct ColorMap { + TQColor color; + TQString name; +}; + +LatexExporter::~LatexExporter() +{ +} + +TQString LatexExporter::exportToStatement() const +{ + return i18n( "Export to &Latex..." ); +} + +TQString LatexExporter::menuEntryName() const +{ + return i18n( "&Latex..." ); +} + +TQString LatexExporter::menuIcon() const +{ + // TODO + return "text-x-tex"; +} + +class LatexExportImpVisitor + : public ObjectImpVisitor +{ + TQTextStream& mstream; + ObjectHolder* mcurobj; + const KigWidget& mw; + Rect msr; + std::vector mcolors; + TQString mcurcolorid; +public: + void visit( ObjectHolder* obj ); + void mapColor( TQColor color ); + + LatexExportImpVisitor( TQTextStream& 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( TQColor 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. + */ + TQString 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( TQColor c ) +{ + for ( uint i = 0; i < mcolors.size(); ++i ) + { + if ( c == mcolors[i].color ) + return i; + } + return -1; +} + +void LatexExportImpVisitor::mapColor( TQColor color ) +{ + if ( findColor( color ) == -1 ) + { + ColorMap newcolor; + newcolor.color = color; + TQString 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 ) +{ + TQRect qr( 0, 0, dim, dim ); + Rect r = mw.screenInfo().fromScreen( qr ); + return fabs( r.width() ); +} + +TQString LatexExportImpVisitor::writeStyle( Qt::PenStyle style ) +{ + TQString ret( "linestyle=" ); + if ( style == TQt::DashLine ) + ret += "dashed"; + else if ( style == TQt::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; + + TQString prefix = TQString( "\\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(); + TQString 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 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( + TQString(), 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; + + TQString file_name = kfd->selectedFile(); + bool showgrid = opts->showGridCheckBox->isOn(); + bool showaxes = opts->showAxesCheckBox->isOn(); + bool showframe = opts->showExtraFrameCheckBox->isOn(); + + delete opts; + delete kfd; + + TQFile 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; + }; + + TQTextStream 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 os = doc.document().objects(); + LatexExportImpVisitor visitor( stream, w ); + visitor.unit = xunit; + + for ( std::vector::const_iterator i = os.begin(); + i != os.end(); ++i ) + { + if ( ! ( *i )->shown() ) continue; + visitor.mapColor( ( *i )->drawer()->color() ); + }; + visitor.mapColor( TQColor( 255, 255, 222 ) ); // ffffde - text label background + visitor.mapColor( TQColor( 197, 194, 197 ) ); // c5c2c5 - text label border line + visitor.mapColor( TQColor( 160, 160, 164 ) ); // a0a0a4 - axes color + visitor.mapColor( TQColor( 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( 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( 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::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/native-filter.cc b/kig/filters/native-filter.cc deleted file mode 100644 index cf6521b2..00000000 --- a/kig/filters/native-filter.cc +++ /dev/null @@ -1,747 +0,0 @@ -// Copyright (C) 2003 Dominique Devriese - -// 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 -#include -#include - -#include -#include -#include -#include -#include - -#include - -#include -#include -#include - -struct HierElem -{ - int id; - std::vector parents; - TQDomElement el; -}; - -static void extendVect( std::vector& 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& ret, - const std::vector& elems, - std::vector& 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 sortElems( const std::vector elems ) -{ - std::vector ret; - std::vector 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 TQString& mime ) -{ - return mime == "application/x-kig"; -} - -KigDocument* KigFilterNative::load( const TQString& file ) -{ - TQFile ffile( file ); - if ( ! ffile.open( IO_ReadOnly ) ) - { - fileNotFound( file ); - return 0; - }; - - TQFile 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; - - TQString tempdir = TDEGlobal::dirs()->saveLocation( "tmp" ); - if ( tempdir.isEmpty() ) - KIG_FILTER_PARSE_ERROR; - - TQString tempname = file.section( '/', -1 ); - if ( file.endsWith( ".kigz", false ) ) - { - tempname.remove( TQRegExp( "\\.[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 ); - TQStringList entries = dir->entries(); - TQStringList kigfiles = entries.grep( TQRegExp( "\\.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( kigz )->copyTo( tempdir ); - kdDebug() << "extracted file: " << tempdir + kigz->name() << endl - << "exists: " << TQFile::exists( tempdir + kigz->name() ) << endl; - - kigdoc.setName( tempdir + kigz->name() ); - } -#endif - - if ( !kigdoc.open( IO_ReadOnly ) ) - KIG_FILTER_PARSE_ERROR; - - TQDomDocument 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 - - TQDomElement main = doc.documentElement(); - - TQString 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. - TQRegExp 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 0; - } - 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 0; - } - else if ( major == 0 && minor <= 6 ) - return load04( file, main ); - else - return load07( file, main ); -} - -KigDocument* KigFilterNative::load04( const TQString& file, const TQDomElement& docelem ) -{ - bool ok = true; - - KigDocument* ret = new KigDocument(); - - for ( TQDomNode n = docelem.firstChild(); ! n.isNull(); n = n.nextSibling() ) - { - TQDomElement e = n.toElement(); - if ( e.isNull() ) continue; - if ( e.tagName() == "CoordinateSystem" ) - { - const TQCString type = e.text().latin1(); - CoordinateSystem* s = CoordinateSystemFactory::build( type.data() ); - 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 retcalcers; - std::vector retholders; - - // first pass: do a topological sort of the objects, to support - // randomly ordered files... - std::vector elems; - TQDomElement objectselem = e; - for ( TQDomNode 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 - TQString 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 ( TQDomNode p = e.firstChild(); !p.isNull(); p = p.nextSibling() ) - { - TQDomElement f = p.toElement(); - if ( f.isNull() ) continue; - if ( f.tagName() == "Parent" ) - { - TQString 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::iterator i = elems.begin(); - i != elems.end(); ++i ) - { - TQDomElement e = i->el; - bool internal = e.attribute( "internal" ) == "true" ? true : false; - ObjectCalcer* o = 0; - if ( e.tagName() == "Data" ) - { - TQString tmp = e.attribute( "type" ); - if ( tmp.isNull() ) - KIG_FILTER_PARSE_ERROR; - TQString error; - ObjectImp* imp = ObjectImpFactory::instance()->deserialize( tmp, e, error ); - if ( ( !imp ) && !error.isEmpty() ) - { - parseError( file, error ); - return 0; - } - o = new ObjectConstCalcer( imp ); - } - else if ( e.tagName() == "Property" ) - { - TQCString propname; - for ( TQDomElement 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" ) - { - TQString 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 0; - }; - - std::vector parents; - for ( std::vector::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 ) - { - TQString tmp = e.attribute( "color" ); - TQColor 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 TQString& file, const TQDomElement& docelem ) -{ - KigDocument* ret = new KigDocument(); - - bool ok = true; - std::vector calcers; - std::vector holders; - - TQString 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 ( TQDomElement subsectionelement = docelem.firstChild().toElement(); ! subsectionelement.isNull(); - subsectionelement = subsectionelement.nextSibling().toElement() ) - { - if ( subsectionelement.tagName() == "CoordinateSystem" ) - { - TQString tmptype = subsectionelement.text(); - // compatibility code - to support Invisible coord system... - if ( tmptype == "Invisible" ) - { - tmptype = "Euclidean"; - ret->setGrid( false ); - ret->setAxes( false ); - } - const TQCString type = tmptype.latin1(); - CoordinateSystem* s = CoordinateSystemFactory::build( type.data() ); - 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 ( TQDomElement e = subsectionelement.firstChild().toElement(); ! e.isNull(); - e = e.nextSibling().toElement() ) - { - TQString tmp = e.attribute( "id" ); - uint id = tmp.toInt( &ok ); - if ( id <= 0 ) KIG_FILTER_PARSE_ERROR; - - std::vector parents; - for ( TQDomElement parentel = e.firstChild().toElement(); ! parentel.isNull(); - parentel = parentel.nextSibling().toElement() ) - { - if ( parentel.tagName() != "Parent" ) continue; - TQString 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; - TQString tmp = e.attribute( "type" ); - TQString error; - ObjectImp* imp = ObjectImpFactory::instance()->deserialize( tmp, e, error ); - if ( ( !imp ) && !error.isEmpty() ) - { - parseError( file, error ); - return 0; - } - o = new ObjectConstCalcer( imp ); - } - else if ( e.tagName() == "Property" ) - { - if ( parents.size() != 1 ) KIG_FILTER_PARSE_ERROR; - TQCString 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" ) - { - TQString 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 0; - } - - // 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 ( TQDomElement e = subsectionelement.firstChild().toElement(); ! e.isNull(); - e = e.nextSibling().toElement() ) - { - if ( e.tagName() != "Draw" ) KIG_FILTER_PARSE_ERROR; - - TQString 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" ); - TQColor 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( calcers[ncid-1].get() ) ) - KIG_FILTER_PARSE_ERROR; - namecalcer = static_cast( 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, TQTextStream& stream ) -{ - TQDomDocument doc( "KigDocument" ); - - TQDomElement docelem = doc.createElement( "KigDocument" ); - docelem.setAttribute( "Version", KIGVERSION ); - docelem.setAttribute( "CompatibilityVersion", "0.7.0" ); - docelem.setAttribute( "grid", kdoc.grid() ); - docelem.setAttribute( "axes", kdoc.axes() ); - - TQDomElement cselem = doc.createElement( "CoordinateSystem" ); - cselem.appendChild( doc.createTextNode( kdoc.coordinateSystem().type() ) ); - docelem.appendChild( cselem ); - - std::vector holders = kdoc.objects(); - std::vector calcers = getAllParents( getAllCalcers( holders ) ); - calcers = calcPath( calcers ); - - TQDomElement hierelem = doc.createElement( "Hierarchy" ); - std::map idmap; - for ( std::vector::const_iterator i = calcers.begin(); - i != calcers.end(); ++i ) - idmap[*i] = ( i - calcers.begin() ) + 1; - int id = 1; - - for ( std::vector::const_iterator i = calcers.begin(); i != calcers.end(); ++i ) - { - TQDomElement objectelem; - if ( dynamic_cast( *i ) ) - { - objectelem = doc.createElement( "Data" ); - TQString ser = - ObjectImpFactory::instance()->serialize( *(*i)->imp(), objectelem, doc ); - objectelem.setAttribute( "type", ser ); - } - else if ( dynamic_cast( *i ) ) - { - const ObjectPropertyCalcer* o = static_cast( *i ); - objectelem = doc.createElement( "Property" ); - - TQCString propname = o->parent()->imp()->propertiesInternalNames()[o->propId()]; - objectelem.setAttribute( TQString("which"), TQString(propname) ); - } - else if ( dynamic_cast( *i ) ) - { - const ObjectTypeCalcer* o = static_cast( *i ); - objectelem = doc.createElement( "Object" ); - objectelem.setAttribute( "type", o->type()->fullName() ); - } - else assert( false ); - - const std::vector parents = ( *i )->parents(); - for ( std::vector::const_iterator i = parents.begin(); i != parents.end(); ++i ) - { - std::map::const_iterator idp = idmap.find( *i ); - assert( idp != idmap.end() ); - int pid = idp->second; - TQDomElement pel = doc.createElement( "Parent" ); - pel.setAttribute( "id", pid ); - objectelem.appendChild( pel ); - } - - objectelem.setAttribute( "id", id++ ); - hierelem.appendChild( objectelem ); - } - docelem.appendChild( hierelem ); - - TQDomElement windowelem = doc.createElement( "View" ); - for ( std::vector::iterator i = holders.begin(); i != holders.end(); ++i ) - { - std::map::const_iterator idp = idmap.find( ( *i )->calcer() ); - assert( idp != idmap.end() ); - int id = idp->second; - - const ObjectDrawer* d = ( *i )->drawer(); - TQDomElement drawelem = doc.createElement( "Draw" ); - drawelem.setAttribute( "object", id ); - drawelem.setAttribute( "color", d->color().name() ); - drawelem.setAttribute( "shown", TQString::fromLatin1( d->shown() ? "true" : "false" ) ); - drawelem.setAttribute( "width", TQString::number( d->width() ) ); - drawelem.setAttribute( "style", d->styleToString() ); - drawelem.setAttribute( "point-style", d->pointStyleToString() ); - - ObjectCalcer* namecalcer = ( *i )->nameCalcer(); - if ( namecalcer ) - { - std::map::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 TQString& file ) -{ - return save07( data, file ); -} - -bool KigFilterNative::save07( const KigDocument& data, const TQString& outfile ) -{ - // we have an empty outfile, so we have to print all to stdout - if ( outfile.isEmpty() ) - { - TQTextStream 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... - - TQString tempdir = TDEGlobal::dirs()->saveLocation( "tmp" ); - if ( tempdir.isEmpty() ) - return false; - - TQString tempname = outfile.section( '/', -1 ); - if ( outfile.endsWith( ".kigz", false ) ) - tempname.remove( TQRegExp( "\\.[Kk][Ii][Gg][Zz]$" ) ); - else - return false; - - TQString tmpfile = tempdir + tempname + ".kig"; - TQFile ftmpfile( tmpfile ); - if ( !ftmpfile.open( IO_WriteOnly ) ) - return false; - TQTextStream 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 - TQFile::remove( tmpfile ); - - return true; - } - else - { -#endif - TQFile file( outfile ); - if ( ! file.open( IO_WriteOnly ) ) - { - fileNotFound( outfile ); - return false; - } - TQTextStream 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, TQTextStream& stream ) -{ - return save07( data, stream ); -} -*/ diff --git a/kig/filters/native-filter.cpp b/kig/filters/native-filter.cpp new file mode 100644 index 00000000..cf6521b2 --- /dev/null +++ b/kig/filters/native-filter.cpp @@ -0,0 +1,747 @@ +// Copyright (C) 2003 Dominique Devriese + +// 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 +#include +#include + +#include +#include +#include +#include +#include + +#include + +#include +#include +#include + +struct HierElem +{ + int id; + std::vector parents; + TQDomElement el; +}; + +static void extendVect( std::vector& 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& ret, + const std::vector& elems, + std::vector& 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 sortElems( const std::vector elems ) +{ + std::vector ret; + std::vector 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 TQString& mime ) +{ + return mime == "application/x-kig"; +} + +KigDocument* KigFilterNative::load( const TQString& file ) +{ + TQFile ffile( file ); + if ( ! ffile.open( IO_ReadOnly ) ) + { + fileNotFound( file ); + return 0; + }; + + TQFile 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; + + TQString tempdir = TDEGlobal::dirs()->saveLocation( "tmp" ); + if ( tempdir.isEmpty() ) + KIG_FILTER_PARSE_ERROR; + + TQString tempname = file.section( '/', -1 ); + if ( file.endsWith( ".kigz", false ) ) + { + tempname.remove( TQRegExp( "\\.[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 ); + TQStringList entries = dir->entries(); + TQStringList kigfiles = entries.grep( TQRegExp( "\\.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( kigz )->copyTo( tempdir ); + kdDebug() << "extracted file: " << tempdir + kigz->name() << endl + << "exists: " << TQFile::exists( tempdir + kigz->name() ) << endl; + + kigdoc.setName( tempdir + kigz->name() ); + } +#endif + + if ( !kigdoc.open( IO_ReadOnly ) ) + KIG_FILTER_PARSE_ERROR; + + TQDomDocument 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 + + TQDomElement main = doc.documentElement(); + + TQString 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. + TQRegExp 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 0; + } + 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 0; + } + else if ( major == 0 && minor <= 6 ) + return load04( file, main ); + else + return load07( file, main ); +} + +KigDocument* KigFilterNative::load04( const TQString& file, const TQDomElement& docelem ) +{ + bool ok = true; + + KigDocument* ret = new KigDocument(); + + for ( TQDomNode n = docelem.firstChild(); ! n.isNull(); n = n.nextSibling() ) + { + TQDomElement e = n.toElement(); + if ( e.isNull() ) continue; + if ( e.tagName() == "CoordinateSystem" ) + { + const TQCString type = e.text().latin1(); + CoordinateSystem* s = CoordinateSystemFactory::build( type.data() ); + 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 retcalcers; + std::vector retholders; + + // first pass: do a topological sort of the objects, to support + // randomly ordered files... + std::vector elems; + TQDomElement objectselem = e; + for ( TQDomNode 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 + TQString 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 ( TQDomNode p = e.firstChild(); !p.isNull(); p = p.nextSibling() ) + { + TQDomElement f = p.toElement(); + if ( f.isNull() ) continue; + if ( f.tagName() == "Parent" ) + { + TQString 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::iterator i = elems.begin(); + i != elems.end(); ++i ) + { + TQDomElement e = i->el; + bool internal = e.attribute( "internal" ) == "true" ? true : false; + ObjectCalcer* o = 0; + if ( e.tagName() == "Data" ) + { + TQString tmp = e.attribute( "type" ); + if ( tmp.isNull() ) + KIG_FILTER_PARSE_ERROR; + TQString error; + ObjectImp* imp = ObjectImpFactory::instance()->deserialize( tmp, e, error ); + if ( ( !imp ) && !error.isEmpty() ) + { + parseError( file, error ); + return 0; + } + o = new ObjectConstCalcer( imp ); + } + else if ( e.tagName() == "Property" ) + { + TQCString propname; + for ( TQDomElement 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" ) + { + TQString 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 0; + }; + + std::vector parents; + for ( std::vector::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 ) + { + TQString tmp = e.attribute( "color" ); + TQColor 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 TQString& file, const TQDomElement& docelem ) +{ + KigDocument* ret = new KigDocument(); + + bool ok = true; + std::vector calcers; + std::vector holders; + + TQString 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 ( TQDomElement subsectionelement = docelem.firstChild().toElement(); ! subsectionelement.isNull(); + subsectionelement = subsectionelement.nextSibling().toElement() ) + { + if ( subsectionelement.tagName() == "CoordinateSystem" ) + { + TQString tmptype = subsectionelement.text(); + // compatibility code - to support Invisible coord system... + if ( tmptype == "Invisible" ) + { + tmptype = "Euclidean"; + ret->setGrid( false ); + ret->setAxes( false ); + } + const TQCString type = tmptype.latin1(); + CoordinateSystem* s = CoordinateSystemFactory::build( type.data() ); + 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 ( TQDomElement e = subsectionelement.firstChild().toElement(); ! e.isNull(); + e = e.nextSibling().toElement() ) + { + TQString tmp = e.attribute( "id" ); + uint id = tmp.toInt( &ok ); + if ( id <= 0 ) KIG_FILTER_PARSE_ERROR; + + std::vector parents; + for ( TQDomElement parentel = e.firstChild().toElement(); ! parentel.isNull(); + parentel = parentel.nextSibling().toElement() ) + { + if ( parentel.tagName() != "Parent" ) continue; + TQString 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; + TQString tmp = e.attribute( "type" ); + TQString error; + ObjectImp* imp = ObjectImpFactory::instance()->deserialize( tmp, e, error ); + if ( ( !imp ) && !error.isEmpty() ) + { + parseError( file, error ); + return 0; + } + o = new ObjectConstCalcer( imp ); + } + else if ( e.tagName() == "Property" ) + { + if ( parents.size() != 1 ) KIG_FILTER_PARSE_ERROR; + TQCString 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" ) + { + TQString 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 0; + } + + // 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 ( TQDomElement e = subsectionelement.firstChild().toElement(); ! e.isNull(); + e = e.nextSibling().toElement() ) + { + if ( e.tagName() != "Draw" ) KIG_FILTER_PARSE_ERROR; + + TQString 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" ); + TQColor 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( calcers[ncid-1].get() ) ) + KIG_FILTER_PARSE_ERROR; + namecalcer = static_cast( 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, TQTextStream& stream ) +{ + TQDomDocument doc( "KigDocument" ); + + TQDomElement docelem = doc.createElement( "KigDocument" ); + docelem.setAttribute( "Version", KIGVERSION ); + docelem.setAttribute( "CompatibilityVersion", "0.7.0" ); + docelem.setAttribute( "grid", kdoc.grid() ); + docelem.setAttribute( "axes", kdoc.axes() ); + + TQDomElement cselem = doc.createElement( "CoordinateSystem" ); + cselem.appendChild( doc.createTextNode( kdoc.coordinateSystem().type() ) ); + docelem.appendChild( cselem ); + + std::vector holders = kdoc.objects(); + std::vector calcers = getAllParents( getAllCalcers( holders ) ); + calcers = calcPath( calcers ); + + TQDomElement hierelem = doc.createElement( "Hierarchy" ); + std::map idmap; + for ( std::vector::const_iterator i = calcers.begin(); + i != calcers.end(); ++i ) + idmap[*i] = ( i - calcers.begin() ) + 1; + int id = 1; + + for ( std::vector::const_iterator i = calcers.begin(); i != calcers.end(); ++i ) + { + TQDomElement objectelem; + if ( dynamic_cast( *i ) ) + { + objectelem = doc.createElement( "Data" ); + TQString ser = + ObjectImpFactory::instance()->serialize( *(*i)->imp(), objectelem, doc ); + objectelem.setAttribute( "type", ser ); + } + else if ( dynamic_cast( *i ) ) + { + const ObjectPropertyCalcer* o = static_cast( *i ); + objectelem = doc.createElement( "Property" ); + + TQCString propname = o->parent()->imp()->propertiesInternalNames()[o->propId()]; + objectelem.setAttribute( TQString("which"), TQString(propname) ); + } + else if ( dynamic_cast( *i ) ) + { + const ObjectTypeCalcer* o = static_cast( *i ); + objectelem = doc.createElement( "Object" ); + objectelem.setAttribute( "type", o->type()->fullName() ); + } + else assert( false ); + + const std::vector parents = ( *i )->parents(); + for ( std::vector::const_iterator i = parents.begin(); i != parents.end(); ++i ) + { + std::map::const_iterator idp = idmap.find( *i ); + assert( idp != idmap.end() ); + int pid = idp->second; + TQDomElement pel = doc.createElement( "Parent" ); + pel.setAttribute( "id", pid ); + objectelem.appendChild( pel ); + } + + objectelem.setAttribute( "id", id++ ); + hierelem.appendChild( objectelem ); + } + docelem.appendChild( hierelem ); + + TQDomElement windowelem = doc.createElement( "View" ); + for ( std::vector::iterator i = holders.begin(); i != holders.end(); ++i ) + { + std::map::const_iterator idp = idmap.find( ( *i )->calcer() ); + assert( idp != idmap.end() ); + int id = idp->second; + + const ObjectDrawer* d = ( *i )->drawer(); + TQDomElement drawelem = doc.createElement( "Draw" ); + drawelem.setAttribute( "object", id ); + drawelem.setAttribute( "color", d->color().name() ); + drawelem.setAttribute( "shown", TQString::fromLatin1( d->shown() ? "true" : "false" ) ); + drawelem.setAttribute( "width", TQString::number( d->width() ) ); + drawelem.setAttribute( "style", d->styleToString() ); + drawelem.setAttribute( "point-style", d->pointStyleToString() ); + + ObjectCalcer* namecalcer = ( *i )->nameCalcer(); + if ( namecalcer ) + { + std::map::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 TQString& file ) +{ + return save07( data, file ); +} + +bool KigFilterNative::save07( const KigDocument& data, const TQString& outfile ) +{ + // we have an empty outfile, so we have to print all to stdout + if ( outfile.isEmpty() ) + { + TQTextStream 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... + + TQString tempdir = TDEGlobal::dirs()->saveLocation( "tmp" ); + if ( tempdir.isEmpty() ) + return false; + + TQString tempname = outfile.section( '/', -1 ); + if ( outfile.endsWith( ".kigz", false ) ) + tempname.remove( TQRegExp( "\\.[Kk][Ii][Gg][Zz]$" ) ); + else + return false; + + TQString tmpfile = tempdir + tempname + ".kig"; + TQFile ftmpfile( tmpfile ); + if ( !ftmpfile.open( IO_WriteOnly ) ) + return false; + TQTextStream 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 + TQFile::remove( tmpfile ); + + return true; + } + else + { +#endif + TQFile file( outfile ); + if ( ! file.open( IO_WriteOnly ) ) + { + fileNotFound( outfile ); + return false; + } + TQTextStream 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, TQTextStream& stream ) +{ + return save07( data, stream ); +} +*/ diff --git a/kig/filters/svgexporter.cc b/kig/filters/svgexporter.cc deleted file mode 100644 index 2fd53756..00000000 --- a/kig/filters/svgexporter.cc +++ /dev/null @@ -1,111 +0,0 @@ -// Copyright (C) 2004 Pino Toscano - -// 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 -#include -#include -#include - -#include -#include - -#include - -SVGExporter::~SVGExporter() -{ -} - -TQString SVGExporter::exportToStatement() const -{ - return i18n( "&Export to SVG..." ); -} - -TQString SVGExporter::menuEntryName() const -{ - return i18n( "&SVG..." ); -} - -TQString SVGExporter::menuIcon() const -{ - // TODO - return "image-svg+xml"; -} - -void SVGExporter::run( const KigPart& part, KigWidget& w ) -{ - KigFileDialog* kfd = new KigFileDialog( - TQString(), 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; - - TQString file_name = kfd->selectedFile(); - bool showgrid = opts->showGridCheckBox->isOn(); - bool showaxes = opts->showAxesCheckBox->isOn(); - - delete opts; - delete kfd; - - TQFile 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; - }; - - TQRect viewrect( w.screenInfo().viewRect() ); - TQRect r( 0, 0, viewrect.width(), viewrect.height() ); - - TQPicture pic; - pic.setBoundingRect( r ); - KigPainter* p = new KigPainter( ScreenInfo( w.screenInfo().shownRect(), viewrect ), - TQT_TQPAINTDEVICE(&pic), part.document() ); -// p->setWholeWinOverlay(); -// p->setBrushColor( TQt::white ); -// p->setBrushStyle( TQt::SolidPattern ); -// p->drawRect( r ); -// p->setBrushStyle( TQt::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.cpp b/kig/filters/svgexporter.cpp new file mode 100644 index 00000000..2fd53756 --- /dev/null +++ b/kig/filters/svgexporter.cpp @@ -0,0 +1,111 @@ +// Copyright (C) 2004 Pino Toscano + +// 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 +#include +#include +#include + +#include +#include + +#include + +SVGExporter::~SVGExporter() +{ +} + +TQString SVGExporter::exportToStatement() const +{ + return i18n( "&Export to SVG..." ); +} + +TQString SVGExporter::menuEntryName() const +{ + return i18n( "&SVG..." ); +} + +TQString SVGExporter::menuIcon() const +{ + // TODO + return "image-svg+xml"; +} + +void SVGExporter::run( const KigPart& part, KigWidget& w ) +{ + KigFileDialog* kfd = new KigFileDialog( + TQString(), 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; + + TQString file_name = kfd->selectedFile(); + bool showgrid = opts->showGridCheckBox->isOn(); + bool showaxes = opts->showAxesCheckBox->isOn(); + + delete opts; + delete kfd; + + TQFile 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; + }; + + TQRect viewrect( w.screenInfo().viewRect() ); + TQRect r( 0, 0, viewrect.width(), viewrect.height() ); + + TQPicture pic; + pic.setBoundingRect( r ); + KigPainter* p = new KigPainter( ScreenInfo( w.screenInfo().shownRect(), viewrect ), + TQT_TQPAINTDEVICE(&pic), part.document() ); +// p->setWholeWinOverlay(); +// p->setBrushColor( TQt::white ); +// p->setBrushStyle( TQt::SolidPattern ); +// p->drawRect( r ); +// p->setBrushStyle( TQt::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 ) ); + } + +} -- cgit v1.2.1