diff options
Diffstat (limited to 'kig/filters/exporter.cpp')
-rw-r--r-- | kig/filters/exporter.cpp | 624 |
1 files changed, 624 insertions, 0 deletions
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 <devriese@kde.org> + +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +// 02110-1301, USA. + +#include "exporter.h" + +#include "imageexporteroptions.h" +#include "latexexporter.h" +#include "svgexporter.h" + +#include "../kig/kig_document.h" +#include "../kig/kig_part.h" +#include "../kig/kig_view.h" +#include "../misc/common.h" +#include "../misc/kigfiledialog.h" +#include "../misc/kigpainter.h" +#include "../objects/circle_imp.h" +#include "../objects/line_imp.h" +#include "../objects/object_drawer.h" +#include "../objects/object_holder.h" +#include "../objects/object_imp.h" +#include "../objects/other_imp.h" +#include "../objects/point_imp.h" +#include "../objects/text_imp.h" + +#include <tqcheckbox.h> +#include <tqcolor.h> +#include <tqfile.h> +#include <tqiconset.h> +#include <tqtextstream.h> + +#include <tdeaction.h> +#include <kiconloader.h> +#include <kimageio.h> +#include <tdelocale.h> +#include <tdemessagebox.h> +#include <knuminput.h> + +#include <map> + +// 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<TQColor, int> 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<ObjectHolder*> os = doc.document().objects(); + XFigExportImpVisitor visitor( stream, w ); + + for ( std::vector<ObjectHolder*>::const_iterator i = os.begin(); + i != os.end(); ++i ) + { + visitor.mapColor( ( *i )->drawer() ); + }; + + for ( std::vector<ObjectHolder*>::const_iterator i = os.begin(); + i != os.end(); ++i ) + { + visitor.visit( *i ); + }; +} |