/* This file is part of the KDE project Copyright (C) 1998, 1999 Reginald Stadlbauer Copyright (C) 2005-2006 Thorsten Zachmann This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library 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 Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include "KPrAutoformObject.h" #include "KPrAutoFormObjectIface.h" #include "KPrUtils.h" #include "KPrGradient.h" #include #include #include #include #include #include #include #include #include #include #include using namespace std; KPrAutoformObject::KPrAutoformObject() : KPr2DObject() , KPrStartEndLine( L_NORMAL, L_NORMAL ) , atfInterp() { } KPrAutoformObject::KPrAutoformObject( const KoPen & _pen, const TQBrush &_brush, const TQString & _filename, LineEnd _lineBegin, LineEnd _lineEnd, FillType _fillType, const TQColor &_gColor1, const TQColor &_gColor2, BCType _gType, bool _unbalanced, int _xfactor, int _yfactor) : KPr2DObject( _pen, _brush, _fillType, _gColor1, _gColor2, _gType, _unbalanced, _xfactor, _yfactor ) , KPrStartEndLine( _lineBegin, _lineEnd ) , filename( _filename ), atfInterp() { atfInterp.load( filename ); } KPrAutoformObject &KPrAutoformObject::operator=( const KPrAutoformObject & ) { return *this; } DCOPObject* KPrAutoformObject::dcopObject() { if ( !dcop ) dcop = new KPrAutoFormObjectIface( this ); return dcop; } void KPrAutoformObject::setFileName( const TQString & _filename ) { filename = _filename; atfInterp.load( filename ); } bool KPrAutoformObject::saveOasisObjectAttributes( KPOasisSaveContext &sc ) const { kdDebug(33001) << "bool KPrAutoformObject::saveOasisObjectAttributes()" << endl; TQSize size( int( ext.width() * 100 ), int( ext.height() * 100 ) ); sc.xmlWriter.addAttribute( "svg:viewBox", TQString( "0 0 %1 %2" ).arg( size.width() ) .arg( size.height() ) ); TQPointArray points = const_cast( atfInterp ).getPointArray( size.width(), size.height() ); unsigned int pointCount = points.size(); unsigned int pos = 0; bool closed = points.at( 0 ) == points.at( pointCount - 1 ); if ( closed ) --pointCount; TQString d; d += TQString( "M%1 %2" ).arg( points.at(pos).x() ) .arg( points.at(pos).y() ); ++pos; while ( pos < pointCount ) { d += TQString( "L%1 %2" ).arg( points.at( pos ).x() ) .arg( points.at( pos ).y() ); ++pos; } if ( closed ) d += "Z"; sc.xmlWriter.addAttribute( "svg:d", d ); return true; } void KPrAutoformObject::fillStyle( KoGenStyle& styleObjectAuto, KoGenStyles& mainStyles ) const { kdDebug(33001) << "KPr2DObject::fillStyle" << endl; KPrShadowObject::fillStyle( styleObjectAuto, mainStyles ); TQPointArray points = const_cast( atfInterp ).getPointArray( int( ext.width() * 100 ), int( ext.height() * 100 ) ); // if it is a closed object save the background if ( points.at( 0 ) == points.at( points.size() - 1 ) ) { m_brush.saveOasisFillStyle( styleObjectAuto, mainStyles ); } else { saveOasisMarkerElement( mainStyles, styleObjectAuto ); } } const char * KPrAutoformObject::getOasisElementName() const { return "draw:path"; } TQDomDocumentFragment KPrAutoformObject::save( TQDomDocument& doc, double offset ) { TQDomDocumentFragment fragment=KPr2DObject::save(doc, offset); KPrStartEndLine::save( fragment, doc ); // The filename contains the absolute path to the autoform. This is // bad, so we simply remove everything but the last dir and the name. // e.g. /my/local/path/to/kpresenter/Arrow/.source/Arrow1.atf -> Arrow/.source/Arrow1.atf TQStringList afDirs = KPrFactory::global()->dirs()->resourceDirs("autoforms"); TQValueList::ConstIterator it=afDirs.begin(); TQString str; for( ; it!=afDirs.end(); ++it) { if(filename.startsWith(*it)) { str=filename.mid((*it).length()); break; } } TQDomElement elem=doc.createElement("FILENAME"); elem.setAttribute("value", str); fragment.appendChild(elem); return fragment; } double KPrAutoformObject::load(const TQDomElement &element) { double offset=KPr2DObject::load(element); KPrStartEndLine::load( element ); TQDomElement e=element.namedItem("FILENAME").toElement(); if(!e.isNull()) { if(e.hasAttribute("value")) filename=e.attribute("value"); // don't crash on invalid files, better insert something if(filename.isEmpty()) filename="Connections/.source/Connection1.atf"; // workaround for a bug in the (very) old file format if(filename[0]=='/') { kdDebug(33001) << "rubbish ahead! cleaning up..." << endl; // remove the leading absolute path (i.e. to create Arrow/Arrow1.atf) filename=filename.mid(filename.findRev('/', filename.findRev('/')-1)+1); } // okay... we changed the file format again and now the autoforms // are stored in .../kpresenter/autoforms/.source/foo.atf (note: we didn't have .source // before. Therefore we have to add this dir if it's not already there to make it // work with old files if(filename.find(".source")==-1) { // okay, old file -- add the .source dir filename=filename.insert(filename.find('/'), "/.source"); } filename = locate("autoforms", filename, KPrFactory::global()); atfInterp.load( filename ); } return offset; } void KPrAutoformObject::paint( TQPainter* _painter, KoTextZoomHandler *_zoomHandler, int /* pageNum */, bool drawingShadow, bool drawContour ) { unsigned int pw = 0, pwOrig = 0, px, py; TQPen pen2; TQSize size( _zoomHandler->zoomSize( ext ) ); if ( drawContour ) pen2 = TQPen( TQt::black, 1, TQt::DotLine ); else { pen2 = pen.zoomedPen( _zoomHandler ); } _painter->setPen( pen2 ); pwOrig = ( pen2.style() == TQt::NoPen ) ? 1 : pen2.width(); if ( !drawContour ) _painter->setBrush( getBrush() ); TQPointArray pntArray = atfInterp.getPointArray( _zoomHandler->zoomItX( ext.width()), _zoomHandler->zoomItY( ext.height() ) ); TQPtrList atrLs = atfInterp.getAttribList(); TQPointArray pntArray2( pntArray.size() ); int ex = _zoomHandler->zoomItX(ext.width()); int ey = _zoomHandler->zoomItY(ext.height()); for ( unsigned int i = 0; i < pntArray.size(); i++ ) { px = pntArray.at( i ).x(); py = pntArray.at( i ).y(); if ( atrLs.at( i )->pwDiv > 0 ) { pw = pwOrig / atrLs.at( i )->pwDiv; px = (int)((double)(ex - pw) / (double)ex * px + pw / 2); py = (int)((double)(ey - pw) / (double)ey * py + pw / 2); } pntArray2.setPoint( i, px, py ); } if ( pntArray2.size() > 0 ) { if ( pntArray2.at( 0 ) == pntArray2.at( pntArray2.size() - 1 ) ) { if ( drawContour || (drawingShadow || getFillType() == FT_BRUSH || !gradient) ) _painter->drawPolygon( pntArray2 ); else { if ( angle == 0 || angle==360 ) { //int ox = _painter->viewport().x() + static_cast( _painter->worldMatrix().dx() ); //int oy = _painter->viewport().y() + static_cast( _painter->worldMatrix().dy() ); TQPointArray pntArray3 = pntArray2.copy(); _painter->save(); TQRegion clipregion( pntArray3 ); // Intersect with current clipregion (whereas setupClipRegion unites) if ( _painter->hasClipping() ) clipregion = _painter->clipRegion(TQPainter::CoordPainter).intersect( clipregion ); _painter->setClipRegion( clipregion, TQPainter::CoordPainter ); gradient->setSize( size ); _painter->drawPixmap( 0, 0, gradient->pixmap() ); _painter->restore(); } else { if ( m_redrawGradientPix || gradient->size() != size ) { kdDebug(33001) << "KPrAutoformObject::draw redrawPix" << endl; gradient->setSize( size ); m_redrawGradientPix = false; TQRegion clipregion( pntArray2 ); m_gradientPix.resize ( _zoomHandler->zoomItX(ext.width()),_zoomHandler->zoomItY(ext.height()) ); m_gradientPix.fill( TQt::white ); TQPainter p; p.begin( &m_gradientPix ); p.setClipRegion( clipregion , TQPainter::CoordPainter); p.drawPixmap( 0, 0, gradient->pixmap() ); p.end(); m_gradientPix.setMask( m_gradientPix.createHeuristicMask() ); } _painter->drawPixmap( 0, 0, m_gradientPix ); } _painter->setPen( pen2 ); _painter->setBrush( TQt::NoBrush ); _painter->drawPolygon( pntArray2 ); } } else { KoSize diff1( 0, 0 ), diff2( 0, 0 ); int _w = int( pen.pointWidth() ); if ( lineBegin != L_NORMAL ) diff1 = getBoundingSize( lineBegin, _w, _zoomHandler ); if ( lineEnd != L_NORMAL ) diff2 = getBoundingSize( lineEnd, _w, _zoomHandler ); if ( pntArray.size() > 1 ) { if ( lineBegin != L_NORMAL && !drawContour ) { TQPoint pnt1( pntArray2.at( 0 ) ), pnt2( pntArray2.at( 1 ) ); TQPoint pnt3, pnt4( pntArray.at( 0 ) ); float _angle = KoPoint::getAngle( KoPoint( pnt1 ), KoPoint( pnt2 ) ); switch ( static_cast( _angle ) ) { case 0: { pnt3.setX( pnt4.x() - (int)diff1.width() / 2 ); pnt3.setY( pnt1.y() ); } break; case 180: { pnt3.setX( pnt4.x() + (int)diff1.width() / 2 ); pnt3.setY( pnt1.y() ); } break; case 90: { pnt3.setX( pnt1.x() ); pnt3.setY( pnt4.y() - (int)diff1.width() / 2 ); } break; case 270: { pnt3.setX( pnt1.x() ); pnt3.setY( pnt4.y() + (int)diff1.width() / 2 ); } break; default: pnt3 = pnt1; break; } drawFigure( lineBegin, _painter, _zoomHandler->unzoomPoint( pnt3 ), pen2.color(), _w, _angle, _zoomHandler ); } if ( lineEnd != L_NORMAL && !drawContour ) { TQPoint pnt1( pntArray2.at( pntArray2.size() - 1 ) ), pnt2( pntArray2.at( pntArray2.size() - 2 ) ); TQPoint pnt3, pnt4( pntArray.at( pntArray.size() - 1 ) ); float _angle = KoPoint::getAngle( KoPoint( pnt1 ), KoPoint( pnt2 ) ); switch ( ( int )_angle ) { case 0: { pnt3.setX( pnt4.x() - (int)diff2.width() / 2 ); pnt3.setY( pnt1.y() ); } break; case 180: { pnt3.setX( pnt4.x() + (int)diff2.width() / 2 ); pnt3.setY( pnt1.y() ); } break; case 90: { pnt3.setX( pnt1.x() ); pnt3.setY( pnt4.y() - (int)diff2.width() / 2 ); } break; case 270: { pnt3.setX( pnt1.x() ); pnt3.setY( pnt4.y() + (int)diff2.width() / 2 ); } break; default: pnt3 = pnt1; break; } drawFigure( lineEnd, _painter, _zoomHandler->unzoomPoint( pnt3 ), pen2.color(), _w, _angle,_zoomHandler ); } } _painter->setPen( pen2 ); _painter->drawPolyline( pntArray2 ); } } }