20 #include "../kig/kig_part.h"
21 #include "../kig/kig_document.h"
22 #include "../objects/bogus_imp.h"
23 #include "../objects/object_type.h"
24 #include "../objects/object_imp.h"
25 #include "../objects/object_calcer.h"
26 #include "../objects/object_drawer.h"
27 #include "../objects/object_holder.h"
28 #include "../objects/object_type_factory.h"
29 #include "../objects/object_imp_factory.h"
30 #include "../misc/calcpaths.h"
31 #include "../misc/coordinate_system.h"
33 #include <config-kig.h>
35 #include <qbytearray.h>
40 #include <qtextstream.h>
45 #include <kstandarddirs.h>
57 std::vector<int> parents;
63 if ( size > vect.size() )
65 int osize = vect.size();
67 for (
uint i = osize; i < size; ++i )
73 const std::vector<HierElem>& elems,
74 std::vector<bool>& seen,
79 for (
uint j = 0; j < elems[i].parents.size(); ++j )
80 visitElem( ret, elems, seen, elems[i].parents[j] - 1);
81 ret.push_back( elems[i] );
86 static std::vector<HierElem>
sortElems(
const std::vector<HierElem> elems )
88 std::vector<HierElem> ret;
89 std::vector<bool> seenElems( elems.size(), false );
90 for (
uint i = 0; i < elems.size(); ++i )
95 KigFilterNative::KigFilterNative()
99 KigFilterNative::~KigFilterNative()
105 return mime ==
"application/x-kig";
111 if ( ! ffile.open( QIODevice::ReadOnly ) )
117 QFile kigdoc( file );
118 bool iscompressed =
false;
119 if ( !file.endsWith(
".kig", Qt::CaseInsensitive ) )
125 QString tempdir = KGlobal::dirs()->saveLocation(
"tmp" );
126 if ( tempdir.isEmpty() )
129 QString tempname = file.section(
'/', -1 );
130 if ( file.endsWith(
".kigz", Qt::CaseInsensitive ) )
132 tempname.remove( QRegExp(
"\\.[Kk][Ii][Gg][Zz]$" ) );
137 KTar ark( file,
"application/x-gzip" );
138 ark.open( QIODevice::ReadOnly );
139 const KArchiveDirectory* dir = ark.directory();
141 QStringList entries = dir->entries();
142 QStringList kigfiles = entries.filter( QRegExp(
"\\.kig$" ) );
143 if ( kigfiles.count() != 1 )
148 const KArchiveEntry* kigz = dir->entry( kigfiles.at( 0 ) );
149 if ( !kigz->isFile() )
151 dynamic_cast<const KArchiveFile*
>( kigz )->copyTo( tempdir );
152 kDebug() <<
"extracted file: " << tempdir + kigz->name()
153 <<
"exists: " << QFile::exists( tempdir + kigz->name() ) << endl;
155 kigdoc.setFileName( tempdir + kigz->name() );
158 if ( !kigdoc.open( QIODevice::ReadOnly ) )
161 QDomDocument doc(
"KigDocument" );
162 if ( !doc.setContent( &kigdoc ) )
170 QDomElement
main = doc.documentElement();
172 QString version = main.attribute(
"CompatibilityVersion" );
173 if ( version.isEmpty() ) version = main.attribute(
"Version" );
174 if ( version.isEmpty() ) version = main.attribute(
"version" );
175 if ( version.isEmpty() )
179 QRegExp versionre(
"(\\d+)\\.(\\d+)(\\.(\\d+))?" );
180 if ( ! versionre.exactMatch( version ) )
183 int major = versionre.cap( 1 ).toInt( &ok );
185 int minor = versionre.cap( 2 ).toInt( &ok2 );
192 if ( major > 0 || minor > 9 )
194 notSupported( file, i18n(
"This file was created by Kig version \"%1\", "
195 "which this version cannot open.", version ) );
198 else if ( major == 0 && minor <= 3 )
200 notSupported( file, i18n(
"This file was created by Kig version \"%1\".\n"
201 "Support for older Kig formats (pre-0.4) has been "
202 "removed from Kig.\n"
203 "You can try to open this file with an older Kig "
204 "version (0.4 to 0.6),\n"
205 "and then save it again, which will save it in the "
206 "new format.", version ) );
209 else if ( major == 0 && minor <= 6 )
210 return load04( file, main );
212 return load07( file, main );
215 KigDocument* KigFilterNative::load04(
const QString& file,
const QDomElement& docelem )
221 for ( QDomNode n = docelem.firstChild(); ! n.isNull(); n = n.nextSibling() )
223 QDomElement e = n.toElement();
224 if ( e.isNull() )
continue;
225 if ( e.tagName() ==
"CoordinateSystem" )
227 const QByteArray type = e.text().toLatin1();
231 warning( i18n(
"This Kig file has a coordinate system "
232 "that this Kig version does not support.\n"
233 "A standard coordinate system will be used "
238 else if ( e.tagName() ==
"Objects" )
240 std::vector<ObjectCalcer*> retcalcers;
241 std::vector<ObjectHolder*> retholders;
245 std::vector<HierElem> elems;
246 QDomElement objectselem = e;
247 for ( QDomNode o = objectselem.firstChild(); ! o.isNull(); o = o.nextSibling() )
250 if ( e.isNull() )
continue;
252 if ( e.tagName() ==
"Data" || e.tagName() ==
"Property" || e.tagName() ==
"Object" )
255 QString tmp = e.attribute(
"id");
264 for ( QDomNode p = e.firstChild(); !p.isNull(); p = p.nextSibling() )
266 QDomElement f = p.toElement();
267 if ( f.isNull() )
continue;
268 if ( f.tagName() ==
"Parent" )
270 QString tmp = f.attribute(
"id" );
271 uint pid = tmp.toInt( &ok );
275 elems[
id-1].parents.push_back( pid );
280 for (
uint i = 0; i < elems.size(); ++i )
281 if ( elems[i].el.isNull() )
285 retcalcers.resize( elems.size(), 0 );
287 for ( std::vector<HierElem>::iterator i = elems.begin();
288 i != elems.end(); ++i )
290 QDomElement e = i->el;
291 bool internal = e.attribute(
"internal" ) ==
"true" ?
true :
false;
293 if ( e.tagName() ==
"Data" )
295 QString tmp = e.attribute(
"type" );
300 if ( ( !imp ) && !error.isEmpty() )
307 else if ( e.tagName() ==
"Property" )
310 for ( QDomElement ec = e.firstChild().toElement(); !ec.isNull();
311 ec = ec.nextSibling().toElement() )
313 if ( ec.tagName() ==
"Property" )
314 propname = ec.text().toLatin1();
320 int propid = propnames.indexOf( propname );
326 else if ( e.tagName() ==
"Object" )
328 QString tmp = e.attribute(
"type" );
336 notSupported( file, i18n(
"This Kig file uses an object of type \"%1\", "
337 "which this Kig version does not support."
338 "Perhaps you have compiled Kig without support "
339 "for this object type,"
340 "or perhaps you are using an older Kig version.", tmp ) );
344 std::vector<ObjectCalcer*> parents;
345 for ( std::vector<int>::iterator j = i->parents.begin();
346 j != i->parents.end(); ++j )
347 parents.push_back( retcalcers[*j - 1] );
354 retcalcers[i->id - 1] = o;
358 QString tmp = e.attribute(
"color" );
360 if ( !color.isValid() )
363 tmp = e.attribute(
"shown" );
364 bool shown = !( tmp ==
"false" || tmp ==
"no" );
366 tmp = e.attribute(
"width" );
367 int width = tmp.toInt( &ok );
368 if ( ! ok ) width = -1;
389 "This Kig file uses an object of type \"%1\", "
390 "which is obsolete, you should save the construction with "
391 "a different name and check that it works as expected." );
393 KigDocument* KigFilterNative::load07(
const QString& file,
const QDomElement& docelem )
398 std::vector<ObjectCalcer::shared_ptr> calcers;
399 std::vector<ObjectHolder*> holders;
401 QString t = docelem.attribute(
"grid" );
402 bool tmphide = ( t ==
"false" ) || ( t ==
"no" ) || ( t ==
"0" );
404 t = docelem.attribute(
"axes" );
405 tmphide = ( t ==
"false" ) || ( t ==
"no" ) || ( t ==
"0" );
408 for ( QDomElement subsectionelement = docelem.firstChild().toElement(); ! subsectionelement.isNull();
409 subsectionelement = subsectionelement.nextSibling().toElement() )
411 if ( subsectionelement.tagName() ==
"CoordinateSystem" )
413 QString tmptype = subsectionelement.text();
415 if ( tmptype ==
"Invisible" )
417 tmptype =
"Euclidean";
421 const QByteArray type = tmptype.toLatin1();
425 warning( i18n(
"This Kig file has a coordinate system "
426 "that this Kig version does not support.\n"
427 "A standard coordinate system will be used "
432 else if ( subsectionelement.tagName() ==
"Hierarchy" )
434 for ( QDomElement e = subsectionelement.firstChild().toElement(); ! e.isNull();
435 e = e.nextSibling().toElement() )
437 QString tmp = e.attribute(
"id" );
438 uint id = tmp.toInt( &ok );
441 std::vector<ObjectCalcer*> parents;
442 for ( QDomElement parentel = e.firstChild().toElement(); ! parentel.isNull();
443 parentel = parentel.nextSibling().toElement() )
445 if ( parentel.tagName() !=
"Parent" )
continue;
446 QString tmp = parentel.attribute(
"id" );
447 uint parentid = tmp.toInt( &ok );
452 parents.push_back( parent );
457 if ( e.tagName() ==
"Data" )
460 QString tmp = e.attribute(
"type" );
463 if ( ( !imp ) && !error.isEmpty() )
470 else if ( e.tagName() ==
"Property" )
473 QByteArray propname = e.attribute(
"which" ).toLatin1();
481 else if ( e.tagName() ==
"Object" )
483 QString tmp = e.attribute(
"type" );
488 if ( tmp ==
"MeasureTransport" && parents.size() == 3 )
490 warning( i18n( obsoletemessage, tmp ) );
495 parents[0] = segment;
498 }
else if ( tmp ==
"InvertLine" )
500 warning( i18n( obsoletemessage, tmp ) );
502 }
else if ( tmp ==
"InvertSegment" )
504 warning( i18n( obsoletemessage, tmp ) );
506 }
else if ( tmp ==
"InvertCircle" )
508 warning( i18n( obsoletemessage, tmp ) );
510 }
else if ( tmp ==
"InvertArc" )
512 warning( i18n( obsoletemessage, tmp ) );
514 }
else if ( tmp ==
"ConicArcBTPC" )
516 warning( i18n( obsoletemessage, tmp ) );
524 parents[3] = parents[2];
525 parents[2] = parents[1];
526 parents[1] = parents[0];
529 notSupported( file, i18n(
"This Kig file uses an object of type \"%1\", "
530 "which this Kig version does not support."
531 "Perhaps you have compiled Kig without support "
532 "for this object type,"
533 "or perhaps you are using an older Kig version.", tmp ) );
554 calcers.resize(
id, 0 );
558 else if ( subsectionelement.tagName() ==
"View" )
560 for ( QDomElement e = subsectionelement.firstChild().toElement(); ! e.isNull();
561 e = e.nextSibling().toElement() )
565 QString tmp = e.attribute(
"object" );
566 uint id = tmp.toInt( &ok );
568 if ( id <= 0 || id > calcers.size() )
572 tmp = e.attribute(
"color" );
574 if ( !color.isValid() )
577 tmp = e.attribute(
"shown" );
578 bool shown = !( tmp ==
"false" || tmp ==
"no" );
580 tmp = e.attribute(
"width" );
581 int width = tmp.toInt( &ok );
582 if ( ! ok ) width = -1;
584 tmp = e.attribute(
"style" );
587 tmp = e.attribute(
"point-style" );
590 tmp = e.attribute(
"font" );
592 if ( !tmp.isEmpty() )
596 tmp = e.attribute(
"namecalcer" );
597 if ( tmp !=
"none" && !tmp.isEmpty() )
599 int ncid = tmp.toInt( &ok );
601 if ( ncid <= 0 || ncid > static_cast<int>( calcers.size() ) )
603 if ( ! dynamic_cast<ObjectConstCalcer*>( calcers[ncid-1].
get() ) )
609 holders.push_back(
new ObjectHolder( calcer, drawer, namecalcer ) );
618 bool KigFilterNative::save07(
const KigDocument& kdoc, QTextStream& stream )
620 QDomDocument doc(
"KigDocument" );
622 QDomProcessingInstruction xmlpi = doc.createProcessingInstruction(
623 QString::fromLatin1(
"xml" ), QString::fromLatin1(
"version=\"1.0\" encoding=\"utf-8\"" ) );
624 doc.appendChild( xmlpi );
626 QDomElement docelem = doc.createElement(
"KigDocument" );
627 docelem.setAttribute(
"Version", KIGVERSION );
628 docelem.setAttribute(
"CompatibilityVersion",
"0.7.0" );
629 docelem.setAttribute(
"grid", kdoc.
grid() );
630 docelem.setAttribute(
"axes", kdoc.
axes() );
632 QDomElement cselem = doc.createElement(
"CoordinateSystem" );
634 docelem.appendChild( cselem );
636 std::vector<ObjectHolder*> holders = kdoc.
objects();
640 QDomElement hierelem = doc.createElement(
"Hierarchy" );
641 std::map<const ObjectCalcer*, int> idmap;
642 for ( std::vector<ObjectCalcer*>::const_iterator i = calcers.begin();
643 i != calcers.end(); ++i )
644 idmap[*i] = ( i - calcers.begin() ) + 1;
647 for ( std::vector<ObjectCalcer*>::const_iterator i = calcers.begin(); i != calcers.end(); ++i )
649 QDomElement objectelem;
650 if ( dynamic_cast<ObjectConstCalcer*>( *i ) )
652 objectelem = doc.createElement(
"Data" );
655 objectelem.setAttribute(
"type", ser );
657 else if ( dynamic_cast<const ObjectPropertyCalcer*>( *i ) )
660 objectelem = doc.createElement(
"Property" );
663 objectelem.setAttribute(
"which", QString( propname ) );
665 else if ( dynamic_cast<const ObjectTypeCalcer*>( *i ) )
668 objectelem = doc.createElement(
"Object" );
669 objectelem.setAttribute(
"type", o->
type()->
fullName() );
671 else assert(
false );
673 const std::vector<ObjectCalcer*> parents = ( *i )->parents();
674 for ( std::vector<ObjectCalcer*>::const_iterator i = parents.begin(); i != parents.end(); ++i )
676 std::map<const ObjectCalcer*,int>::const_iterator idp = idmap.find( *i );
677 assert( idp != idmap.end() );
678 int pid = idp->second;
679 QDomElement pel = doc.createElement(
"Parent" );
680 pel.setAttribute(
"id", pid );
681 objectelem.appendChild( pel );
684 objectelem.setAttribute(
"id",
id++ );
685 hierelem.appendChild( objectelem );
687 docelem.appendChild( hierelem );
689 QDomElement windowelem = doc.createElement(
"View" );
690 for ( std::vector<ObjectHolder*>::iterator i = holders.begin(); i != holders.end(); ++i )
692 std::map<const ObjectCalcer*,int>::const_iterator idp = idmap.find( ( *i )->calcer() );
693 assert( idp != idmap.end() );
694 int id = idp->second;
697 QDomElement drawelem = doc.createElement(
"Draw" );
698 drawelem.setAttribute(
"object",
id );
699 drawelem.setAttribute(
"color", d->
color().name() );
700 drawelem.setAttribute(
"shown", QLatin1String( d->
shown() ?
"true" :
"false" ) );
701 drawelem.setAttribute(
"width", QString::number( d->
width() ) );
704 drawelem.setAttribute(
"font", d->
font().toString() );
709 std::map<const ObjectCalcer*,int>::const_iterator ncp = idmap.find( namecalcer );
710 assert( ncp != idmap.end() );
711 int ncid = ncp->second;
712 drawelem.setAttribute(
"namecalcer", ncid );
716 drawelem.setAttribute(
"namecalcer",
"none" );
719 windowelem.appendChild( drawelem );
721 docelem.appendChild( windowelem );
723 doc.appendChild( docelem );
724 stream << doc.toString();
730 return save07( data, file );
733 bool KigFilterNative::save07(
const KigDocument& data,
const QString& outfile )
736 if ( outfile.isEmpty() )
738 QTextStream stdoutstream( stdout, QIODevice::WriteOnly );
739 stdoutstream.setCodec(
"UTF-8" );
740 return save07( data, stdoutstream );
742 if ( !outfile.endsWith(
".kig", Qt::CaseInsensitive ) )
747 QString tempdir = KGlobal::dirs()->saveLocation(
"tmp" );
748 if ( tempdir.isEmpty() )
751 QString tempname = outfile.section(
'/', -1 );
752 if ( outfile.endsWith(
".kigz", Qt::CaseInsensitive ) )
753 tempname.remove( QRegExp(
"\\.[Kk][Ii][Gg][Zz]$" ) );
757 QString tmpfile = tempdir + tempname +
".kig";
758 QFile ftmpfile( tmpfile );
759 if ( !ftmpfile.open( QIODevice::WriteOnly ) )
761 QTextStream stream( &ftmpfile );
762 stream.setCodec(
"UTF-8" );
763 if ( !save07( data, stream ) )
767 kDebug() <<
"tmp saved file: " << tmpfile;
770 KTar ark( outfile,
"application/x-gzip" );
771 ark.open( QIODevice::WriteOnly );
772 ark.addLocalFile( tmpfile, tempname +
".kig" );
776 QFile::remove( tmpfile );
782 QFile file( outfile );
783 if ( ! file.open( QIODevice::WriteOnly ) )
788 QTextStream stream( &file );
789 stream.setCodec(
"UTF-8" );
790 return save07( data, stream );
static const ObjectImpFactory * instance()
static CoordinateSystem * build(int which)
a CoordinateSystem is what the user sees: it is kept by KigPart to show the user a grid...
bool supportMime(const QString &mime)
can the filter handle the mimetype mime ?
bool save(const KigDocument &data, const QString &file)
QString pointStyleToString() const
return pointStyle transformed in a string
This is an ObjectCalcer that keeps an ObjectImp, and never calculates a new one.
static std::vector< HierElem > sortElems(const std::vector< HierElem > elems)
bool shown() const
returns whether the object this ObjectDrawer is responsible for will be drawn or not.
QFont font() const
return the font
int main(int argc, char **argv)
static void visitElem(std::vector< HierElem > &ret, const std::vector< HierElem > &elems, std::vector< bool > &seen, int i)
std::vector< ObjectCalcer * > getAllCalcers(const std::vector< ObjectHolder * > &os)
get the calcers that the holders represent and their namecalcers
void addObjects(const std::vector< ObjectHolder * > &os)
Add the objects os to the document.
virtual const QByteArrayList propertiesInternalNames() const
This is an ObjectCalcer that uses one of the various ObjectType's to calculate its ObjectImp...
void setCoordinateSystem(CoordinateSystem *s)
sets the coordinate system to s , and deletes the old one.
void setGrid(bool showgrid)
set to show/hide the grid.
static const char * obsoletemessage
static void extendVect(std::vector< HierElem > &vect, uint size)
std::vector< ObjectCalcer * > getAllParents(const std::vector< ObjectCalcer * > &objs)
This function returns all objects above the given in the dependency graph.
std::vector< ObjectCalcer * > calcPath(const std::vector< ObjectCalcer * > &os)
This function sorts os such that they're in the right order for calc()-ing.
void parseError(const QString &file, const QString &explanation=QString()) const
An ObjectHolder represents an object as it is known to the document.
ObjectImp * deserialize(const QString &type, const QDomElement &parent, QString &error) const
loads data from parent , and returns a new ObjectImp from the type string type .
An ObjectCalcer is an object that represents an algorithm for calculating an ObjectImp from other Obj...
static ObjectTypeFactory * instance()
void notSupported(const QString &file, const QString &explanation) const
virtual void calc(const KigDocument &)=0
Makes the ObjectCalcer recalculate its ObjectImp from its parents.
This is an ObjectCalcer that has a single parent, and gets a certain property from it in its calc() m...
const std::vector< ObjectHolder * > objects() const
Get a hold of the objects of this KigDocument.
static KigFilterNative * instance()
int width() const
return the width of the object
The ObjectType class is a thing that represents the "behaviour" for a certain type.
const ObjectType * type() const
static int pointStyleFromString(const QString &style)
Note that this returns a valid point style in every case, even if the given style string is unknown...
QString serialize(const ObjectImp &d, QDomElement &parent, QDomDocument &doc) const
adds data to parent , and returns a type string.
KigDocument * load(const QString &file)
load file fromfile and build a KigDocument from it.
const char * getPropName(int propgid) const
QString styleToString() const
return style transformed in a string
A class holding some information about how a certain object is drawn on the window.
void setAxes(bool showaxes)
set to show/hide the grid.
static Qt::PenStyle styleFromString(const QString &style)
Note that this returns a valid style in every case, even if the given style string is unknown...
KigDocument is the class holding the real data in a Kig document.
virtual const ObjectImp * imp() const =0
Returns the ObjectImp of this ObjectCalcer.
QColor color() const
returns the color that the object will be drawn in
QList< QByteArray > QByteArrayList
const char * fullName() const
The ObjectImp class represents the behaviour of an object after it is calculated. ...
#define KIG_FILTER_PARSE_ERROR
const CoordinateSystem & coordinateSystem() const
void warning(const QString &explanation) const
void fileNotFound(const QString &file) const
virtual const char * type() const =0
ObjectCalcer * parent() const
const ObjectType * find(const char *name) const