kpresenter

KPrTextObject.cpp

00001 // -*- Mode: c++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 4; -*-
00002 /* This file is part of the KDE project
00003    Copyright (C) 1998, 1999 Reginald Stadlbauer <reggie@kde.org>
00004    Copyright (C) 2005-2006 Thorsten Zachmann <zachmann@kde.org>
00005 
00006    This library is free software; you can redistribute it and/or
00007    modify it under the terms of the GNU Library General Public
00008    License as published by the Free Software Foundation; either
00009    version 2 of the License, or (at your option) any later version.
00010 
00011    This library is distributed in the hope that it will be useful,
00012    but WITHOUT ANY WARRANTY; without even the implied warranty of
00013    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00014    Library General Public License for more details.
00015 
00016    You should have received a copy of the GNU Library General Public License
00017    along with this library; see the file COPYING.LIB.  If not, write to
00018    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00019  * Boston, MA 02110-1301, USA.
00020 */
00021 #ifdef HAVE_CONFIG_H
00022 #include <config.h>
00023 #endif
00024 #include "KPrTextObject.h"
00025 #include "KPrTextObject.moc"
00026 #include "KPrGradient.h"
00027 #include "KPrCommand.h"
00028 #include "KPrCanvas.h"
00029 #include "KPrPage.h"
00030 #include "KPrView.h"
00031 #include "KPrDocument.h"
00032 #include "KPrBgSpellCheck.h"
00033 #include "KPrVariableCollection.h"
00034 
00035 #include <KoAutoFormat.h>
00036 #include <KoTextParag.h>
00037 #include <KoTextObject.h>
00038 #include <KoStyleCollection.h>
00039 #include <KoTextFormatter.h>
00040 #include <KoTextZoomHandler.h>
00041 #include "KPrTextViewIface.h"
00042 #include "KPrTextObjectIface.h"
00043 #include <KoOasisContext.h>
00044 #include <KoStyleStack.h>
00045 #include <ktempfile.h>
00046 #include <klocale.h>
00047 #include <kdebug.h>
00048 #include <kdeversion.h>
00049 #include <kmultipledrag.h>
00050 
00051 #include <qfont.h>
00052 #include <qfile.h>
00053 #include <qwidget.h>
00054 #include <qpicture.h>
00055 #include <qpainter.h>
00056 #include <qwmatrix.h>
00057 #include <qdom.h>
00058 #include <qapplication.h>
00059 #include <qfontdatabase.h>
00060 #include <qpopupmenu.h>
00061 #include <qclipboard.h>
00062 
00063 #include <KoParagCounter.h>
00064 #include <kaction.h>
00065 #include <KoVariable.h>
00066 #include <KoCustomVariablesDia.h>
00067 #include <KoRuler.h>
00068 #include <KoSize.h>
00069 #include <KoXmlNS.h>
00070 #include <KoDom.h>
00071 #include <KoStore.h>
00072 #include <KoStoreDrag.h>
00073 #include <KoOasisStore.h>
00074 
00075 #include <float.h>
00076 using namespace std;
00077 
00078 #undef S_NONE // Solaris defines it in sys/signal.h
00079 
00080 const QString &KPrTextObject::tagTEXTOBJ=KGlobal::staticQString("TEXTOBJ");
00081 const QString &KPrTextObject::attrLineSpacing=KGlobal::staticQString("lineSpacing");
00082 const QString &KPrTextObject::attrParagSpacing=KGlobal::staticQString("paragSpacing");
00083 const QString &KPrTextObject::attrMargin=KGlobal::staticQString("margin");
00084 const QString &KPrTextObject::attrBulletType1=KGlobal::staticQString("bulletType1");
00085 const QString &KPrTextObject::attrBulletType2=KGlobal::staticQString("bulletType2");
00086 const QString &KPrTextObject::attrBulletType3=KGlobal::staticQString("bulletType3");
00087 const QString &KPrTextObject::attrBulletType4=KGlobal::staticQString("bulletType4");
00088 const QString &KPrTextObject::attrBulletColor1=KGlobal::staticQString("bulletColor1");
00089 const QString &KPrTextObject::attrBulletColor2=KGlobal::staticQString("bulletColor2");
00090 const QString &KPrTextObject::attrBulletColor3=KGlobal::staticQString("bulletColor3");
00091 const QString &KPrTextObject::attrBulletColor4=KGlobal::staticQString("bulletColor4");
00092 const QString &KPrTextObject::tagP=KGlobal::staticQString("P");
00093 const QString &KPrTextObject::attrAlign=KGlobal::staticQString("align");
00094 const QString &KPrTextObject::attrType=KGlobal::staticQString("type");
00095 const QString &KPrTextObject::attrDepth=KGlobal::staticQString("depth");
00096 const QString &KPrTextObject::tagTEXT=KGlobal::staticQString("TEXT");
00097 const QString &KPrTextObject::attrFamily=KGlobal::staticQString("family");
00098 const QString &KPrTextObject::attrPointSize=KGlobal::staticQString("pointSize");
00099 const QString &KPrTextObject::attrBold=KGlobal::staticQString("bold");
00100 const QString &KPrTextObject::attrItalic=KGlobal::staticQString("italic");
00101 const QString &KPrTextObject::attrUnderline=KGlobal::staticQString("underline");
00102 const QString &KPrTextObject::attrStrikeOut=KGlobal::staticQString("strikeOut");
00103 const QString &KPrTextObject::attrColor=KGlobal::staticQString("color");
00104 const QString &KPrTextObject::attrWhitespace=KGlobal::staticQString("whitespace");
00105 const QString &KPrTextObject::attrTextBackColor=KGlobal::staticQString("textbackcolor");
00106 const QString &KPrTextObject::attrVertAlign=KGlobal::staticQString("VERTALIGN");
00107 
00108 
00109 KPrTextObject::KPrTextObject(  KPrDocument *doc )
00110     : KPr2DObject()
00111 {
00112     m_doc=doc;
00113     m_textVertAlign = KP_TOP;
00114     // Default color should be QColor() ... but kpresenter isn't fully color-scheme-aware yet
00115     KoTextFormatCollection* fc = new KoTextFormatCollection( doc->defaultFont(), Qt::black, doc->globalLanguage(), doc->globalHyphenation() );
00116     KPrTextDocument * textdoc = new KPrTextDocument( this, fc );
00117     if ( m_doc->tabStopValue() != -1 )
00118         textdoc->setTabStops( m_doc->zoomHandler()->ptToLayoutUnitPixX( m_doc->tabStopValue() ));
00119 
00120     m_textobj = new KoTextObject( textdoc, m_doc->styleCollection()->findStyle( "Standard" ), this );
00121     textdoc->setFlow( this );
00122 
00123     m_doc->backSpeller()->registerNewTextObject( m_textobj );
00124     pen = defaultPen();
00125     drawEditRect = true;
00126     drawEmpty = true;
00127     editingTextObj = false;
00128 
00129     bleft = 0.0;
00130     btop = 0.0;
00131     bright = 0.0;
00132     bbottom = 0.0;
00133     alignVertical = 0.0;
00134 
00135     connect( m_textobj, SIGNAL( newCommand( KCommand * ) ),
00136              SLOT( slotNewCommand( KCommand * ) ) );
00137     connect( m_textobj, SIGNAL( availableHeightNeeded() ),
00138              SLOT( slotAvailableHeightNeeded() ) );
00139     connect( m_textobj, SIGNAL( repaintChanged( KoTextObject* ) ),
00140              SLOT( slotRepaintChanged() ) );
00141 
00142     // Send our "repaintChanged" signals to the document.
00143     connect( this, SIGNAL( repaintChanged( KPrTextObject * ) ),
00144              m_doc, SLOT( slotRepaintChanged( KPrTextObject * ) ) );
00145     connect(m_textobj, SIGNAL( showFormatObject(const KoTextFormat &) ),
00146             SLOT( slotFormatChanged(const KoTextFormat &)) );
00147     connect( m_textobj, SIGNAL( afterFormatting( int, KoTextParag*, bool* ) ),
00148              SLOT( slotAfterFormatting( int, KoTextParag*, bool* ) ) );
00149     connect( m_textobj, SIGNAL( paragraphDeleted( KoTextParag*) ),
00150              SLOT( slotParagraphDeleted(KoTextParag*) ));
00151 
00152 }
00153 
00154 KPrTextObject::~KPrTextObject()
00155 {
00156     textDocument()->takeFlow();
00157     m_doc = 0L;
00158 }
00159 
00160 DCOPObject* KPrTextObject::dcopObject()
00161 {
00162     if ( !dcop )
00163         dcop = new KPrTextObjectIface( this );
00164     return dcop;
00165 }
00166 
00167 void KPrTextObject::slotParagraphDeleted(KoTextParag*_parag)
00168 {
00169     m_doc->spellCheckParagraphDeleted( _parag,  this);
00170 }
00171 
00172 QBrush KPrTextObject::getBrush() const
00173 {
00174     QBrush tmpBrush( m_brush.getBrush() );
00175     if(!tmpBrush.color().isValid())
00176         tmpBrush.setColor(QApplication::palette().color( QPalette::Active, QColorGroup::Base ));
00177     return tmpBrush;
00178 }
00179 
00180 void KPrTextObject::resizeTextDocument( bool widthChanged, bool heightChanged )
00181 {
00182     if ( heightChanged )
00183     {
00184         // Recalc available height
00185         slotAvailableHeightNeeded();
00186         // Recalc the vertical centering, if enabled
00187         recalcVerticalAlignment();
00188     }
00189     if ( widthChanged )
00190     {
00191         // not when simply changing the height, otherwise the auto-resize code
00192         // prevents making a textobject less high than it currently is.
00193         textDocument()->setWidth( m_doc->zoomHandler()->ptToLayoutUnitPixX( innerWidth() ) );
00194         m_textobj->setLastFormattedParag( textDocument()->firstParag() );
00195         m_textobj->formatMore( 2 );
00196     }
00197 }
00198 
00199 void KPrTextObject::setSize( double _width, double _height )
00200 {
00201     bool widthModified = KABS( _width - ext.width() ) > DBL_EPSILON ; // floating-point equality test
00202     bool heightModified = KABS( _height - ext.height() ) > DBL_EPSILON;
00203     if ( widthModified || heightModified )
00204     {
00205         KPrObject::setSize( _width, _height );
00206         resizeTextDocument( widthModified, heightModified ); // will call formatMore() if widthModified
00207     }
00208 }
00209 
00210 QDomDocumentFragment KPrTextObject::save( QDomDocument& doc, double offset )
00211 {
00212     QDomDocumentFragment fragment=KPr2DObject::save(doc, offset);
00213     fragment.appendChild(saveKTextObject( doc ));
00214     return fragment;
00215 }
00216 
00217 bool KPrTextObject::saveOasisObjectAttributes( KPOasisSaveContext &sc ) const
00218 {
00219     sc.xmlWriter.startElement( "draw:text-box" );
00220     m_textobj->saveOasisContent( sc.xmlWriter, sc.context );
00221     sc.xmlWriter.endElement();
00222     return true;
00223 }
00224 
00225 const char * KPrTextObject::getOasisElementName() const
00226 {
00227     return "draw:frame";
00228 }
00229 
00230 void KPrTextObject::saveOasisMarginElement( KoGenStyle &styleobjectauto ) const
00231 {
00232     kdDebug()<<"void KPrTextObject::saveOasisMarginElement( KoGenStyle &styleobjectauto )\n";
00233     if ( btop != 0.0 )
00234         styleobjectauto.addPropertyPt("fo:padding-top", btop );
00235     if ( bbottom != 0.0 )
00236         styleobjectauto.addPropertyPt("fo:padding-bottom", bbottom );
00237     if ( bleft != 0.0 )
00238         styleobjectauto.addPropertyPt("fo:padding-left", bleft );
00239     if ( bright != 0.0 )
00240         styleobjectauto.addPropertyPt("fo:padding-right", bright );
00241 
00242     //add vertical alignment
00243     switch( m_textVertAlign )
00244     {
00245     case KP_TOP:
00246         styleobjectauto.addProperty("draw:textarea-vertical-align", "top" );
00247         break;
00248     case KP_CENTER:
00249         styleobjectauto.addProperty("draw:textarea-vertical-align", "middle" );
00250         break;
00251     case KP_BOTTOM:
00252         styleobjectauto.addProperty("draw:textarea-vertical-align", "bottom" );
00253         break;
00254     }
00255 
00256     // fo:padding-top="1.372cm" fo:padding-bottom="0.711cm" fo:padding-left="1.118cm" fo:padding-right="1.27cm"
00257 }
00258 
00259 void KPrTextObject::loadOasis(const QDomElement &element, KoOasisContext& context,
00260                              KPrLoadingInfo *info )
00261 {
00262     KPr2DObject::loadOasis(element, context, info);
00263     //todo other attribute
00264     KoStyleStack &styleStack = context.styleStack();
00265     styleStack.setTypeProperties( "graphic" );
00266     if( styleStack.hasAttributeNS( KoXmlNS::fo, "padding-top" ) )
00267         btop = KoUnit::parseValue( styleStack.attributeNS( KoXmlNS::fo, "padding-top" ) );
00268     if( styleStack.hasAttributeNS( KoXmlNS::fo, "padding-bottom" ) )
00269         bbottom = KoUnit::parseValue( styleStack.attributeNS( KoXmlNS::fo, "padding-bottom" ) );
00270     if( styleStack.hasAttributeNS( KoXmlNS::fo, "padding-left") )
00271         bleft = KoUnit::parseValue( styleStack.attributeNS( KoXmlNS::fo, "padding-left" ) );
00272     if( styleStack.hasAttributeNS( KoXmlNS::fo, "padding-right" ) )
00273         bright = KoUnit::parseValue( styleStack.attributeNS( KoXmlNS::fo, "padding-right" ) );
00274     kdDebug()<<" KPrTextObject::loadOasis : btp :"<<btop<<" bbottom :"<<bbottom<<" bleft :"<<bleft<<" bright :"<<bright<<endl;
00275     // vertical alignment
00276     if ( styleStack.hasAttributeNS( KoXmlNS::draw, "textarea-vertical-align" ) )
00277     {
00278         QString alignment = styleStack.attributeNS( KoXmlNS::draw, "textarea-vertical-align" );
00279         if ( alignment == "top" )
00280             m_textVertAlign= KP_TOP;
00281         else if ( alignment == "middle" )
00282             m_textVertAlign= KP_CENTER;
00283         else if ( alignment == "bottom" )
00284             m_textVertAlign= KP_BOTTOM;
00285     }
00286     kdDebug()<<" vertical Alignment :"<< ( ( m_textVertAlign== KP_TOP ) ? "top" : ( m_textVertAlign==  KP_CENTER ) ? "center": "bottom" )<<endl;
00287     QDomElement tmp = KoDom::namedItemNS( element, KoXmlNS::draw, "text-box");
00288     m_textobj->loadOasisContent( tmp, context, m_doc->styleCollection() );
00289     resizeTextDocument(); // this will to formatMore()
00290 }
00291 
00292 
00293 double KPrTextObject::load(const QDomElement &element)
00294 {
00295     double offset=KPr2DObject::load(element);
00296     QDomElement e=element.namedItem(tagTEXTOBJ).toElement();
00297     if(!e.isNull()) {
00298         if ( e.hasAttribute( "protectcontent"))
00299             setProtectContent((bool)e.attribute( "protectcontent" ).toInt());
00300         if (e.hasAttribute( "bleftpt"))
00301             bleft = e.attribute( "bleftpt").toDouble();
00302         if (e.hasAttribute( "brightpt"))
00303             bright = e.attribute( "brightpt").toDouble();
00304         if (e.hasAttribute( "btoppt"))
00305             btop = e.attribute( "btoppt").toDouble();
00306         if (e.hasAttribute( "bbottompt"))
00307             bbottom = e.attribute( "bbottompt").toDouble();
00308         if ( e.hasAttribute("verticalAlign"))
00309         {
00310             QString str =e.attribute("verticalAlign");
00311             if ( str == "bottom" )
00312                 m_textVertAlign= KP_BOTTOM;
00313             else if ( str == "center" )
00314                 m_textVertAlign= KP_CENTER;
00315             else if ( str == "top" )//never
00316                 m_textVertAlign= KP_TOP;
00317         }
00318         if ( e.hasAttribute( "verticalValue" ))
00319             alignVertical = e.attribute( "verticalValue" ).toDouble();
00320 
00321         loadKTextObject( e );
00322     }
00323 
00324     shadowCompatibility();
00325 
00326     resizeTextDocument(); // this will to formatMore()
00327     return offset;
00328 }
00329 
00330 void KPrTextObject::shadowCompatibility()
00331 {
00332     if ( shadowDistance != 0)
00333     {
00334         int sx = 0;
00335         int sy = 0;
00336         switch ( shadowDirection )
00337         {
00338         case SD_LEFT_BOTTOM:
00339         case SD_LEFT:
00340         case SD_LEFT_UP:
00341             sx = - shadowDistance;
00342         case SD_RIGHT_UP:
00343         case SD_RIGHT:
00344         case SD_RIGHT_BOTTOM:
00345             sx = shadowDistance;
00346         default:
00347             break;
00348         }
00349         switch ( shadowDirection )
00350         {
00351         case SD_LEFT_UP:
00352         case SD_UP:
00353         case SD_RIGHT_UP:
00354             sy = - shadowDistance;
00355         case SD_LEFT_BOTTOM:
00356         case SD_BOTTOM:
00357         case SD_RIGHT_BOTTOM:
00358             sy = shadowDistance;
00359         default:
00360             break;
00361         }
00362         KoTextFormat tmpFormat;
00363         tmpFormat.setShadow( sx, sy, shadowColor );
00364         KCommand* cmd = m_textobj->setFormatCommand( &tmpFormat, KoTextFormat::ShadowText );
00365         delete cmd;
00366     }
00367     //force to reset shadow compatibility between koffice 1.1 and 1.2
00368     shadowDirection = SD_RIGHT_BOTTOM;
00369     shadowDistance = 0;
00370     shadowColor = Qt::gray;
00371 }
00372 
00373 
00374 // Standard paint method for KP2DObjects.
00375 void KPrTextObject::paint( QPainter *_painter, KoTextZoomHandler*_zoomHandler,
00376                           int pageNum, bool drawingShadow, bool drawContour )
00377 {
00378     // Never draw shadow (in text objects, it's a character property, not an object property)
00379     KPrPage *p = m_doc->pageList().at( pageNum );
00380     // neccessary when on masterpage
00381     if ( p )
00382         recalcPageNum( p );
00383     if ( drawingShadow ) return;
00384     paint( _painter, _zoomHandler, false, 0L, true, drawContour );
00385 }
00386 
00387 // Special method for drawing a text object that is being edited
00388 void KPrTextObject::paintEdited( QPainter *_painter, KoTextZoomHandler*_zoomHandler,
00389                                 bool onlyChanged, KoTextCursor* cursor, bool resetChanged )
00390 {
00391     _painter->save();
00392     _painter->translate( _zoomHandler->zoomItX(orig.x()), _zoomHandler->zoomItY(orig.y()) );
00393 
00394     if ( angle != 0 )
00395         rotateObject(_painter,_zoomHandler);
00396     paint( _painter, _zoomHandler, onlyChanged, cursor, resetChanged, false /*not drawContour*/ );
00397     _painter->restore();
00398 }
00399 
00400 // Common functionality for the above 2 methods
00401 void KPrTextObject::paint( QPainter *_painter, KoTextZoomHandler*_zoomHandler,
00402                           bool onlyChanged, KoTextCursor* cursor, bool resetChanged,
00403                           bool drawContour )
00404 {
00405     double ow = ext.width();
00406     double oh = ext.height();
00407     double pw = pen.pointWidth() / 2;
00408     if ( drawContour ) {
00409         QPen pen3( Qt::black, 1, Qt::DotLine );
00410         _painter->setPen( pen3 );
00411         _painter->setRasterOp( Qt::NotXorROP );
00412         _painter->drawRect( _zoomHandler->zoomItX(pw), _zoomHandler->zoomItY(pw),
00413                             _zoomHandler->zoomItX(ow), _zoomHandler->zoomItY( oh) );
00414 
00415         return;
00416     }
00417 
00418     _painter->save();
00419     QPen pen2 = pen.zoomedPen(_zoomHandler);
00420     //QRect clip=QRect(_zoomHandler->zoomItX(pw), _zoomHandler->zoomItY(pw), _zoomHandler->zoomItX( ow - 2 * pw),_zoomHandler->zoomItY( oh - 2 * pw));
00421     //setupClipRegion( _painter, clip );
00422     //for debug
00423     //_painter->fillRect( clip, Qt::blue );
00424     _painter->setPen( pen2 );
00425 
00426     if ( editingTextObj && _painter->device() && _painter->device()->devType() != QInternal::Printer)  // editing text object
00427         _painter->setBrush( QBrush( m_doc->txtBackCol(), Qt::SolidPattern ) );
00428     else {
00429         // Handle the rotation, draw the background/border, then call drawText()
00430         if ( getFillType() == FT_BRUSH || !gradient ) {
00431             _painter->setBrush( getBrush() );
00432         }
00433         else {
00434             QSize size( _zoomHandler->zoomSize( ext ) );
00435             gradient->setSize( size );
00436             _painter->drawPixmap( _zoomHandler->zoomItX(pw), _zoomHandler->zoomItX(pw), gradient->pixmap(), 0, 0,
00437                                   _zoomHandler->zoomItX( ow - 2 * pw ),
00438                                   _zoomHandler->zoomItY( oh - 2 * pw ) );
00439         }
00440     }
00441     if ( !editingTextObj || !onlyChanged )
00442     {
00444         // (so that the border gets drawn OUTSIDE of the object area)
00445         _painter->drawRect( _zoomHandler->zoomItX(pw), _zoomHandler->zoomItX(pw), _zoomHandler->zoomItX( ow - 2 * pw),
00446                             _zoomHandler->zoomItY( oh - 2 * pw) );
00447     }
00448 
00449     drawText( _painter, _zoomHandler, onlyChanged, cursor, resetChanged );
00450     _painter->restore();
00451 
00452 
00453     // And now draw the border for text objects.
00454     // When they are drawn outside of the object, this can be moved to the standard paint() method,
00455     // so that we don't have to do it while editing the object, maybe.
00456     if ( m_doc->firstView() && m_doc->firstView()->getCanvas()->getEditMode() &&
00457          getDrawEditRect() && getPen().style() == Qt::NoPen )
00458     {
00459         _painter->save();
00460 
00461         _painter->setPen( QPen( Qt::gray, 1, Qt::DotLine ) );
00462         _painter->setBrush( Qt::NoBrush );
00463         _painter->setRasterOp( Qt::NotXorROP );
00464         _painter->drawRect( 0, 0, _zoomHandler->zoomItX(ow), _zoomHandler->zoomItY( oh) );
00465 
00466         _painter->restore();
00467     }
00468 }
00469 
00470 // This method simply draws the paragraphs in the given painter
00471 // Assumes the painter is already set up correctly.
00472 void KPrTextObject::drawText( QPainter* _painter, KoTextZoomHandler *zoomHandler, bool onlyChanged, KoTextCursor* cursor, bool resetChanged )
00473 {
00474     //kdDebug(33001) << "KPrTextObject::drawText onlyChanged=" << onlyChanged << " cursor=" << cursor << " resetChanged=" << resetChanged << endl;
00475     recalcVerticalAlignment();
00476     QColorGroup cg = QApplication::palette().active();
00477     _painter->save();
00478     _painter->translate( m_doc->zoomHandler()->zoomItX( bLeft()), m_doc->zoomHandler()->zoomItY( bTop()+alignVertical));
00479     if ( !editingTextObj || (_painter->device() && _painter->device()->devType() == QInternal::Printer))
00480         cg.setBrush( QColorGroup::Base, NoBrush );
00481     else
00482         cg.setColor( QColorGroup::Base, m_doc->txtBackCol() );
00483 
00484     QRect r = zoomHandler->zoomRect( KoRect( 0, 0, innerWidth(), innerHeight() ) );
00485     bool editMode = false;
00486     if( m_doc->firstView() && m_doc->firstView()->getCanvas())
00487         editMode = m_doc->firstView()->getCanvas()->getEditMode();
00488 
00489     uint drawingFlags = 0;
00490     if ( _painter->device() && _painter->device()->devType() != QInternal::Printer )
00491         drawingFlags |= KoTextDocument::DrawSelections;
00492     if ( m_doc->backgroundSpellCheckEnabled() && editMode )
00493         drawingFlags |= KoTextDocument::DrawMisspelledLine;
00494     if ( !editMode )
00495         drawingFlags |= KoTextDocument::DontDrawNoteVariable;
00496     if ( m_doc->viewFormattingChars() && editMode )
00497         drawingFlags |= KoTextDocument::DrawFormattingChars;
00498 
00499     if ( specEffects )
00500     {
00501         switch ( effect2 )
00502         {
00503         case EF2T_PARA:
00504             //kdDebug(33001) << "KPrTextObject::draw onlyCurrStep=" << onlyCurrStep << " subPresStep=" << subPresStep << endl;
00505             drawParags( _painter, zoomHandler, cg, ( onlyCurrStep ? subPresStep : 0 ), subPresStep );
00506             break;
00507         default:
00508             /*KoTextParag * lastFormatted =*/ textDocument()->drawWYSIWYG(
00509                 _painter, r.x(), r.y(), r.width(), r.height(),
00510                 cg, zoomHandler,
00511                 onlyChanged, cursor != 0, cursor, resetChanged, drawingFlags );
00512         }
00513     }
00514     else
00515     {
00516 
00517         //kdDebug(33001) << "KPrTextObject::drawText r=" << DEBUGRECT(r) << endl;
00518         /*KoTextParag * lastFormatted = */ textDocument()->drawWYSIWYG(
00519             _painter, r.x(), r.y(), r.width(), r.height(),
00520             cg, zoomHandler,
00521             onlyChanged, cursor != 0, cursor, resetChanged, drawingFlags );
00522     }
00523     _painter->restore();
00524 }
00525 
00526 int KPrTextObject::getSubPresSteps() const
00527 {
00528     int paragraphs = 0;
00529     KoTextParag * parag = textDocument()->firstParag();
00530     for ( ; parag ; parag = parag->next() )
00531         paragraphs++;
00532     return paragraphs;
00533 }
00534 
00535 
00536 QDomElement KPrTextObject::saveKTextObject( QDomDocument& doc )
00537 {
00538 #if 0
00539     KTextEditParag *parag = ktextobject.document()->firstParag();
00540     KTextEditDocument::TextSettings textSettings = ktextobject.document()->textSettings();
00541 #endif
00542 
00543     QDomElement textobj=doc.createElement(tagTEXTOBJ);
00544     if ( isProtectContent() )
00545         textobj.setAttribute( "protectcontent", (int)isProtectContent());
00546     if (bleft !=0.0)
00547         textobj.setAttribute( "bleftpt", bleft );
00548     if (bright !=0.0)
00549         textobj.setAttribute( "brightpt", bright );
00550     if (btop !=0.0)
00551         textobj.setAttribute( "btoppt", btop );
00552     if (bbottom !=0.0)
00553         textobj.setAttribute( "bbottompt", bbottom );
00554     if ( m_textVertAlign != KP_TOP )
00555     {
00556         if ( m_textVertAlign == KP_BOTTOM )
00557             textobj.setAttribute( "verticalAlign", "bottom" );
00558         else if ( m_textVertAlign == KP_CENTER )
00559             textobj.setAttribute( "verticalAlign", "center" );
00560         else if ( m_textVertAlign == KP_TOP )//never
00561             textobj.setAttribute( "verticalAlign", "top" );
00562         textobj.setAttribute( "verticalValue",alignVertical );
00563     }
00564 #if 0
00565     textobj.setAttribute(attrLineSpacing, ktextobject.document()->lineSpacing());
00566     textobj.setAttribute(attrParagSpacing, ktextobject.document()->paragSpacing());
00567     textobj.setAttribute(attrMargin, ktextobject.document()->margin());
00568     textobj.setAttribute(attrBulletType1, (int)textSettings.bulletType[0]);
00569     textobj.setAttribute(attrBulletType2, (int)textSettings.bulletType[1]);
00570     textobj.setAttribute(attrBulletType3, (int)textSettings.bulletType[2]);
00571     textobj.setAttribute(attrBulletType4, (int)textSettings.bulletType[3]);
00572     textobj.setAttribute(attrBulletColor1, textSettings.bulletColor[0].name());
00573     textobj.setAttribute(attrBulletColor2, textSettings.bulletColor[1].name());
00574     textobj.setAttribute(attrBulletColor3, textSettings.bulletColor[2].name());
00575     textobj.setAttribute(attrBulletColor4, textSettings.bulletColor[3].name());
00576 #endif
00577     KoTextParag *parag = static_cast<KoTextParag*> (textDocument()->firstParag());
00578     // ### fix this loop (Werner)
00579     while ( parag ) {
00580         saveParagraph( doc, parag, textobj, 0, parag->length()-2 );
00581         parag = static_cast<KoTextParag*>( parag->next());
00582     }
00583     return textobj;
00584 }
00585 
00586 void KPrTextObject::saveFormat( QDomElement & element, KoTextFormat*lastFormat )
00587 {
00588     QString tmpFamily, tmpColor, tmpTextBackColor;
00589     unsigned int tmpBold=false, tmpItalic=false, tmpUnderline=false,tmpStrikeOut=false;
00590     int tmpVerticalAlign=-1;
00591 
00592     tmpFamily=lastFormat->font().family();
00593     tmpBold=static_cast<unsigned int>(lastFormat->font().bold());
00594     tmpItalic=static_cast<unsigned int>(lastFormat->font().italic());
00595     tmpUnderline=static_cast<unsigned int>(lastFormat->underline());
00596     tmpStrikeOut=static_cast<unsigned int>(lastFormat->strikeOut());
00597     tmpColor=lastFormat->color().name();
00598     tmpVerticalAlign=static_cast<unsigned int>(lastFormat->vAlign());
00599     if(lastFormat->textBackgroundColor().isValid())
00600         tmpTextBackColor=lastFormat->textBackgroundColor().name();
00601 
00602     element.setAttribute(attrFamily, tmpFamily);
00603     element.setAttribute(attrPointSize, lastFormat->pointSize());
00604 
00605     if(tmpBold)
00606         element.setAttribute(attrBold, tmpBold);
00607     if(tmpItalic)
00608         element.setAttribute(attrItalic, tmpItalic);
00609     if ( lastFormat->underlineType()!= KoTextFormat::U_NONE )
00610     {
00611         if(lastFormat->doubleUnderline())
00612             element.setAttribute(attrUnderline, "double");
00613         if(lastFormat->underlineType()==KoTextFormat::U_SIMPLE_BOLD)
00614             element.setAttribute(attrUnderline, "single-bold");
00615         else if( lastFormat->underlineType()==KoTextFormat::U_WAVE)
00616             element.setAttribute(attrUnderline, "wave");
00617         else if(tmpUnderline)
00618             element.setAttribute(attrUnderline, tmpUnderline);
00619         QString strLineType=KoTextFormat::underlineStyleToString( lastFormat->underlineStyle() );
00620         element.setAttribute( "underlinestyleline", strLineType );
00621         if ( lastFormat->textUnderlineColor().isValid() )
00622             element.setAttribute( "underlinecolor", lastFormat->textUnderlineColor().name() );
00623     }
00624     if ( lastFormat->strikeOutType()!= KoTextFormat::S_NONE )
00625     {
00626         if ( lastFormat->doubleStrikeOut() )
00627             element.setAttribute(attrStrikeOut, "double");
00628         else if ( lastFormat->strikeOutType()== KoTextFormat::S_SIMPLE_BOLD)
00629             element.setAttribute(attrStrikeOut, "single-bold");
00630         else if(tmpStrikeOut)
00631             element.setAttribute(attrStrikeOut, tmpStrikeOut);
00632         QString strLineType=KoTextFormat::strikeOutStyleToString( lastFormat->strikeOutStyle() );
00633         element.setAttribute( "strikeoutstyleline", strLineType );
00634 
00635     }
00636     element.setAttribute(attrColor, tmpColor);
00637 
00638     if(!tmpTextBackColor.isEmpty())
00639         element.setAttribute(attrTextBackColor, tmpTextBackColor);
00640     if(tmpVerticalAlign!=-1)
00641     {
00642         element.setAttribute(attrVertAlign,tmpVerticalAlign);
00643         if(lastFormat->relativeTextSize()!=0.66)
00644             element.setAttribute("relativetextsize",lastFormat->relativeTextSize());
00645     }
00646 
00647     if ( lastFormat->shadowDistanceX() != 0
00648         || lastFormat->shadowDistanceY() != 0)
00649         element.setAttribute("text-shadow", lastFormat->shadowAsCss());
00650     if ( lastFormat->offsetFromBaseLine()!=0 )
00651         element.setAttribute( "offsetfrombaseline" , lastFormat->offsetFromBaseLine());
00652     if ( lastFormat->wordByWord() )
00653         element.setAttribute("wordbyword", true);
00654     if ( lastFormat->attributeFont()!= KoTextFormat::ATT_NONE )
00655         element.setAttribute("fontattribute", KoTextFormat::attributeFontToString(lastFormat->attributeFont() ));
00656     if ( !lastFormat->language().isEmpty())
00657         element.setAttribute("language", lastFormat->language());
00658 }
00659 
00660 QDomElement KPrTextObject::saveHelper(const QString &tmpText,KoTextFormat*lastFormat , QDomDocument &doc)
00661 {
00662     QDomElement element=doc.createElement(tagTEXT);
00663 
00664     saveFormat ( element, lastFormat );
00665 
00666     if(tmpText.stripWhiteSpace().isEmpty())
00667         // working around a bug in QDom
00668         element.setAttribute(attrWhitespace, tmpText.length());
00669     element.appendChild(doc.createTextNode(tmpText));
00670     return element;
00671 }
00672 
00673 void KPrTextObject::fillStyle( KoGenStyle& styleObjectAuto, KoGenStyles& mainStyles ) const
00674 {
00675     KPr2DObject::fillStyle( styleObjectAuto, mainStyles );
00676     saveOasisMarginElement( styleObjectAuto );
00677 }
00678 
00679 void KPrTextObject::loadKTextObject( const QDomElement &elem )
00680 {
00681     QDomElement e = elem.firstChild().toElement();
00682     KoTextParag *lastParag = static_cast<KoTextParag *>(textDocument()->firstParag());
00683     int i = 0;
00684     int listNum = 0;
00685     // Initialize lineSpacing and paragSpacing with the values of the object-level attributes
00686     // (KOffice-1.1 file format)
00687     int lineSpacing = elem.attribute( attrLineSpacing ).toInt();
00688     int bottomBorder = elem.attribute( attrParagSpacing ).toInt();
00689     int topBorder = 0;
00690 
00691     while ( !e.isNull() ) {
00692         QValueList<QDomElement> listVariable;
00693         listVariable.clear();
00694 
00695         if ( e.tagName() == tagP ) {
00696             QDomElement n = e.firstChild().toElement();
00697 
00698             //skip the whitespace if it's a bullet/number
00699             if( e.hasAttribute( attrType ) && n.hasAttribute( attrWhitespace ) )
00700                 if ( e.attribute( attrType )!="0" && n.attribute( attrWhitespace )=="1" ) {
00701                     e = e.nextSibling().toElement();
00702                     continue;
00703                 }
00704 
00705             KoParagLayout paragLayout = loadParagLayout(e, m_doc, true);
00706 
00707             // compatibility (bullet/numbering depth); only a simulation thru the margins, this is how it _looked_ before
00708             double depth = 0.0;
00709             if( e.hasAttribute(attrDepth) ) {
00710                 depth = e.attribute( attrDepth ).toDouble();
00711                 paragLayout.margins[QStyleSheetItem::MarginLeft] = depth * MM_TO_POINT(10.0);
00712             }
00713 
00714             //kdDebug(33001) << k_funcinfo << "old bullet depth is: " << depth  << endl;
00715 
00716             // 1.1 compatibility (bullets)
00717             QString type;
00718             if( e.hasAttribute(attrType) )
00719                 type = e.attribute( attrType );
00720 
00721             //kdDebug(33001) << k_funcinfo << "old PARAG type is: " << type  << endl;
00722 
00723             // Do not import type="2" (enum list). The enum was there in 1.1, but not the code!
00724             if(type == "1")
00725             {
00726                 if(!paragLayout.counter)
00727                     paragLayout.counter = new KoParagCounter;
00728                 paragLayout.counter->setStyle(KoParagCounter::STYLE_DISCBULLET);
00729                 paragLayout.counter->setNumbering(KoParagCounter::NUM_LIST);
00730                 paragLayout.counter->setPrefix(QString::null);
00731                 paragLayout.counter->setSuffix(QString::null);
00732             }
00733 
00734             // This is for very old (KOffice-1.0) documents.
00735             if ( e.hasAttribute( attrLineSpacing ) )
00736                 lineSpacing = e.attribute( attrLineSpacing ).toInt();
00737             if ( e.hasAttribute( "distBefore" ) )
00738                 topBorder = e.attribute( "distBefore" ).toInt();
00739             if ( e.hasAttribute( "distAfter" ) )
00740                 bottomBorder = e.attribute( "distAfter" ).toInt();
00741 
00742             // Apply values coming from 1.0 or 1.1 documents
00743             if ( paragLayout.lineSpacingValue() == 0 )
00744                 paragLayout.setLineSpacingValue(lineSpacing);
00745             if ( paragLayout.margins[ QStyleSheetItem::MarginTop ] == 0 )
00746                 paragLayout.margins[ QStyleSheetItem::MarginTop ] = topBorder;
00747             if ( paragLayout.margins[ QStyleSheetItem::MarginBottom ] == 0 )
00748                 paragLayout.margins[ QStyleSheetItem::MarginBottom ] = bottomBorder;
00749             lastParag->setParagLayout( paragLayout );
00750             //lastParag->setAlign(Qt::AlignAuto);
00751 
00752             if(e.hasAttribute(attrAlign))
00753             {
00754                 int tmpAlign=e.attribute( attrAlign ).toInt();
00755                 if(tmpAlign==1 || tmpAlign==0 /* a kpresenter version I think a cvs version saved leftAlign = 0 for header/footer */)
00756                     lastParag->setAlign(Qt::AlignLeft);
00757                 else if(tmpAlign==2)
00758                     lastParag->setAlign(Qt::AlignRight);
00759                 else if(tmpAlign==4)
00760                     lastParag->setAlign(Qt::AlignHCenter);
00761                 else if(tmpAlign==8)
00762                     lastParag->setAlign(Qt::AlignJustify);
00763                 else
00764                     kdDebug(33001) << "Error in e.attribute( attrAlign ).toInt()" << endl;
00765             }
00766             // ######## TODO  paragraph direction (LTR or RTL)
00767 
00768             // TODO check/convert values
00769             bool firstTextTag = true;
00770             while ( !n.isNull() ) {
00771                 if ( n.tagName() == tagTEXT ) {
00772 
00773                     if ( firstTextTag ) {
00774                         lastParag->remove( 0, 1 ); // Remove current trailing space
00775                         firstTextTag = false;
00776                     }
00777                     KoTextFormat fm = loadFormat( n, lastParag->paragraphFormat(), m_doc->defaultFont(), m_doc->globalLanguage(),
00778                                                   m_doc->globalHyphenation() );
00779 
00780                     QString txt = n.firstChild().toText().data();
00781 
00782                     if(n.hasAttribute(attrWhitespace)) {
00783                         int ws=n.attribute(attrWhitespace).toInt();
00784                         txt.fill(' ', ws);
00785                     }
00786                     n=n.nextSibling().toElement();
00787                     if ( n.isNull() )
00788                         txt += ' '; // trailing space at end of paragraph
00789                     lastParag->append( txt, true );
00790                     lastParag->setFormat( i, txt.length(), textDocument()->formatCollection()->format( &fm ) );
00791                     //kdDebug(33001)<<"setFormat :"<<txt<<" i :"<<i<<" txt.length() "<<txt.length()<<endl;
00792                     i += txt.length();
00793                 }
00794                 else if ( n.tagName() == "CUSTOM" )
00795                 {
00796                     listVariable.append( n );
00797                     n = n.nextSibling().toElement();
00798                 }
00799                 else
00800                     n = n.nextSibling().toElement();
00801             }
00802         } else if ( e.tagName() == "UNSORTEDLISTTYPE" ) {
00803             if ( listNum < 4 ) {
00804                 //QColor c( e.attribute( "red" ).toInt(), e.attribute( "green" ).toInt(), e.attribute( "blue" ).toInt() );
00805                 // ## settings.bulletColor[ listNum++ ] = c;
00806             }
00807         }
00808         e = e.nextSibling().toElement();
00809         loadVariable( listVariable,lastParag );
00810         if ( e.isNull() )
00811             break;
00812         i = 0;
00813         if ( !lastParag->length() == 0 )
00814             lastParag = new KoTextParag( textDocument(), lastParag, 0 );
00815     }
00816 }
00817 
00818 void KPrTextObject::loadVariable( QValueList<QDomElement> & listVariable,KoTextParag *lastParag, int offset )
00819 {
00820     QValueList<QDomElement>::Iterator it = listVariable.begin();
00821     QValueList<QDomElement>::Iterator end = listVariable.end();
00822     for ( ; it != end ; ++it )
00823     {
00824         QDomElement elem = *it;
00825         if ( !elem.hasAttribute("pos"))
00826             continue;
00827         int index = elem.attribute("pos").toInt();
00828         index+=offset;
00829         QDomElement varElem = elem.namedItem( "VARIABLE" ).toElement();
00830         if ( !varElem.isNull() )
00831         {
00832             QDomElement typeElem = varElem.namedItem( "TYPE" ).toElement();
00833             int type = typeElem.attribute( "type" ).toInt();
00834             QString key = typeElem.attribute( "key" );
00835             int correct = 0;
00836             if (typeElem.hasAttribute( "correct" ))
00837                 correct = typeElem.attribute("correct").toInt();
00838             kdDebug(33001) << "loadKTextObject variable type=" << type << " key=" << key << endl;
00839             KoVariableFormat * varFormat = key.isEmpty() ? 0 : m_doc->variableFormatCollection()->format( key.latin1() );
00840             // If varFormat is 0 (no key specified), the default format will be used.
00841             KoVariable * var =m_doc->getVariableCollection()->createVariable( type, -1, m_doc->variableFormatCollection(),
00842                                                                               varFormat, lastParag->textDocument(),
00843                                                                               m_doc, correct, true/* force default format for date/time*/ );
00844             if ( var )
00845             {
00846                 var->load( varElem );
00847                 KoTextFormat format = loadFormat( *it, lastParag->paragraphFormat(), m_doc->defaultFont(), m_doc->globalLanguage(),
00848                                                   m_doc->globalHyphenation() );
00849                 lastParag->setCustomItem( index, var, lastParag->document()->formatCollection()->format( &format ));
00850                 var->recalc();
00851             }
00852         }
00853     }
00854 }
00855 
00856 KoTextFormat KPrTextObject::loadFormat( QDomElement &n, KoTextFormat * refFormat, const QFont & defaultFont,
00857                                        const QString & defaultLanguage, bool hyphen )
00858 {
00859     KoTextFormat format;
00860     format.setHyphenation( hyphen );
00861     QFont fn;
00862     if ( refFormat )
00863     {
00864         format = *refFormat;
00865         format.setCollection( 0 ); // Out of collection copy
00866         fn = format.font();
00867     }
00868     else
00869         fn = defaultFont;
00870 
00871     if ( !n.isNull() )
00872     {
00873         QFontDatabase fdb;
00874         QStringList families = fdb.families();
00875         if ( families.findIndex( n.attribute( attrFamily ) ) != -1 )
00876             fn.setFamily( n.attribute( attrFamily ) );
00877         else
00878             fn = defaultFont;
00879     }
00880     else if ( !refFormat )
00881     {   // No reference format and no FONT tag -> use default font
00882         fn = defaultFont;
00883     }
00884 
00885 
00886     int size = n.attribute( attrPointSize ).toInt();
00887     bool bold=false;
00888     if(n.hasAttribute(attrBold))
00889         bold = (bool)n.attribute( attrBold ).toInt();
00890     bool italic = false;
00891     if(n.hasAttribute(attrItalic))
00892         italic=(bool)n.attribute( attrItalic ).toInt();
00893 
00894     if(n.hasAttribute( attrUnderline ))
00895     {
00896         QString value = n.attribute( attrUnderline );
00897         if ( value == "double" )
00898             format.setUnderlineType ( KoTextFormat::U_DOUBLE);
00899         else if ( value == "single" )
00900             format.setUnderlineType ( KoTextFormat::U_SIMPLE);
00901         else if ( value == "single-bold" )
00902             format.setUnderlineType ( KoTextFormat::U_SIMPLE_BOLD);
00903         else if( value =="wave" )
00904             format.setUnderlineType( KoTextFormat::U_WAVE);
00905         else
00906             format.setUnderlineType ( (bool)value.toInt() ? KoTextFormat::U_SIMPLE :KoTextFormat::U_NONE);
00907     }
00908     if (n.hasAttribute("underlinestyleline") )
00909         format.setUnderlineStyle( KoTextFormat::stringToUnderlineStyle( n.attribute("underlinestyleline") ));
00910 
00911     if (n.hasAttribute("underlinecolor"))
00912         format.setTextUnderlineColor(QColor(n.attribute("underlinecolor")));
00913 
00914     if(n.hasAttribute(attrStrikeOut))
00915     {
00916         QString value = n.attribute( attrStrikeOut );
00917         if ( value == "double" )
00918             format.setStrikeOutType ( KoTextFormat::S_DOUBLE);
00919         else if ( value == "single" )
00920             format.setStrikeOutType ( KoTextFormat::S_SIMPLE);
00921         else if ( value == "single-bold" )
00922             format.setStrikeOutType ( KoTextFormat::S_SIMPLE_BOLD);
00923         else
00924             format.setStrikeOutType ( (bool)value.toInt() ? KoTextFormat::S_SIMPLE :KoTextFormat::S_NONE);
00925     }
00926 
00927     if (n.hasAttribute("strikeoutstyleline"))
00928     {
00929         QString strLineType = n.attribute("strikeoutstyleline");
00930         format.setStrikeOutStyle( KoTextFormat::stringToStrikeOutStyle( strLineType ));
00931     }
00932 
00933     QString color = n.attribute( attrColor );
00934     fn.setPointSize( size );
00935     fn.setBold( bold );
00936     fn.setItalic( italic );
00937     //kdDebug(33001) << "KPrTextObject::loadFormat: family=" << fn.family() << " size=" << fn.pointSize() << endl;
00938     QColor col( color );
00939 
00940     format.setFont( fn );
00941     format.setColor( col );
00942     QString textBackColor=n.attribute(attrTextBackColor);
00943     if(!textBackColor.isEmpty())
00944     {
00945         QColor tmpCol(textBackColor);
00946         tmpCol=tmpCol.isValid() ? tmpCol : QApplication::palette().color( QPalette::Active, QColorGroup::Base );
00947         format.setTextBackgroundColor(tmpCol);
00948     }
00949     if(n.hasAttribute(attrVertAlign))
00950         format.setVAlign( static_cast<KoTextFormat::VerticalAlignment>(n.attribute(attrVertAlign).toInt() ) );
00951     if ( n.hasAttribute("text-shadow") )
00952         format.parseShadowFromCss( n.attribute("text-shadow") );
00953     if ( n.hasAttribute("relativetextsize") )
00954         format.setRelativeTextSize( n.attribute("relativetextsize").toDouble() ) ;
00955     if ( n.hasAttribute("offsetfrombaseline") )
00956         format.setOffsetFromBaseLine( static_cast<int>(n.attribute("offsetfrombaseline").toInt() ) );
00957     if ( n.hasAttribute("wordbyword") )
00958         format.setWordByWord( static_cast<int>(n.attribute("wordbyword").toInt() ) );
00959 
00960     if ( n.hasAttribute("fontattribute") )
00961         format.setAttributeFont( KoTextFormat::stringToAttributeFont(n.attribute("fontattribute") )  );
00962     if ( n.hasAttribute("language"))
00963         format.setLanguage( n.attribute("language"));
00964     else
00965     {   // No reference format and no language tag -> use default font
00966         format.setLanguage( defaultLanguage);
00967     }
00968 
00969     //kdDebug(33001)<<"loadFormat :"<<format.key()<<endl;
00970     return format;
00971 }
00972 
00973 KoParagLayout KPrTextObject::loadParagLayout( QDomElement & parentElem, KPrDocument *doc, bool findStyle)
00974 {
00975     KoParagLayout layout;
00976 
00977     // Only when loading paragraphs, not when loading styles
00978     if ( findStyle )
00979     {
00980         KoParagStyle *style;
00981         // Name of the style. If there is no style, then we do not supply
00982         // any default!
00983         QDomElement element = parentElem.namedItem( "NAME" ).toElement();
00984         if ( !element.isNull() )
00985         {
00986             QString styleName = element.attribute( "value" );
00987             style = doc->styleCollection()->findStyle( styleName );
00988             if (!style)
00989             {
00990                 kdError(33001) << "Cannot find style \"" << styleName << "\" specified in paragraph LAYOUT - using Standard" << endl;
00991                 style = doc->styleCollection()->findStyle( "Standard" );
00992             }
00993             //else kdDebug(33001) << "KoParagLayout::KoParagLayout setting style to " << style << " " << style->name() << endl;
00994         }
00995         else
00996         {
00997             kdError(33001) << "Missing NAME tag in paragraph LAYOUT - using Standard" << endl;
00998             style = doc->styleCollection()->findStyle( "Standard" );
00999         }
01000         Q_ASSERT(style);
01001         layout.style = style;
01002     }
01003 
01004     QDomElement element = parentElem.namedItem( "INDENTS" ).toElement();
01005     if ( !element.isNull() )
01006     {
01007         double val=0.0;
01008         if(element.hasAttribute("first"))
01009             val=element.attribute("first").toDouble();
01010         layout.margins[QStyleSheetItem::MarginFirstLine] = val;
01011         val=0.0;
01012         if(element.hasAttribute( "left"))
01013             // The GUI prevents a negative indent, so let's fixup broken docs too
01014             val=QMAX(0, element.attribute( "left").toDouble());
01015         layout.margins[QStyleSheetItem::MarginLeft] = val;
01016         val=0.0;
01017         if(element.hasAttribute("right"))
01018             // The GUI prevents a negative indent, so let's fixup broken docs too
01019             val=QMAX(0, element.attribute("right").toDouble());
01020         layout.margins[QStyleSheetItem::MarginRight] = val;
01021     }
01022     element = parentElem.namedItem( "LINESPACING" ).toElement();
01023     if ( !element.isNull() )
01024     {
01025         //compatibility with koffice 1.1
01026         if ( element.hasAttribute( "value" ))
01027         {
01028             QString value = element.attribute( "value" );
01029             if ( value == "oneandhalf" )
01030             {
01031                 layout.lineSpacingType = KoParagLayout::LS_ONEANDHALF;
01032                 layout.setLineSpacingValue(0);
01033             }
01034             else if ( value == "double" )
01035             {
01036                 layout.lineSpacingType = KoParagLayout::LS_DOUBLE;
01037                 layout.setLineSpacingValue(0);
01038             }
01039             else
01040             {
01041                 layout.lineSpacingType = KoParagLayout::LS_CUSTOM;
01042                 layout.setLineSpacingValue(value.toDouble());
01043             }
01044         }
01045         else
01046         {
01047             QString type = element.attribute( "type" );
01048             if ( type == "oneandhalf" )
01049             {
01050                 layout.lineSpacingType = KoParagLayout::LS_ONEANDHALF;
01051                 layout.setLineSpacingValue(0);
01052             }
01053             else if ( type == "double" )
01054             {
01055                 layout.lineSpacingType = KoParagLayout::LS_DOUBLE;
01056                 layout.setLineSpacingValue(0);
01057             }
01058             else if ( type == "custom" )
01059             {
01060                 layout.lineSpacingType = KoParagLayout::LS_CUSTOM;
01061                 layout.setLineSpacingValue(element.attribute( "spacingvalue" ).toDouble());
01062             }
01063             else if ( type == "atleast" )
01064             {
01065                 layout.lineSpacingType = KoParagLayout::LS_AT_LEAST;
01066                 layout.setLineSpacingValue(element.attribute( "spacingvalue" ).toDouble());
01067             }
01068             else if ( type == "multiple" )
01069             {
01070                 layout.lineSpacingType = KoParagLayout::LS_MULTIPLE;
01071                 layout.setLineSpacingValue(element.attribute( "spacingvalue" ).toDouble());
01072             }
01073         }
01074     }
01075 
01076     element = parentElem.namedItem( "OFFSETS" ).toElement();
01077     if ( !element.isNull() )
01078     {
01079         double val =0.0;
01080         if(element.hasAttribute("before"))
01081             val=QMAX(0, element.attribute("before").toDouble());
01082         layout.margins[QStyleSheetItem::MarginTop] = val;
01083         val = 0.0;
01084         if(element.hasAttribute("after"))
01085             val=QMAX(0, element.attribute("after").toDouble());
01086         layout.margins[QStyleSheetItem::MarginBottom] = val;
01087     }
01088 
01089 
01090     element = parentElem.namedItem( "LEFTBORDER" ).toElement();
01091     if ( !element.isNull() )
01092         layout.leftBorder = KoBorder::loadBorder( element );
01093     else
01094         layout.leftBorder.setPenWidth( 0);
01095 
01096     element = parentElem.namedItem( "RIGHTBORDER" ).toElement();
01097     if ( !element.isNull() )
01098         layout.rightBorder = KoBorder::loadBorder( element );
01099     else
01100         layout.rightBorder.setPenWidth( 0);
01101 
01102     element = parentElem.namedItem( "TOPBORDER" ).toElement();
01103     if ( !element.isNull() )
01104         layout.topBorder = KoBorder::loadBorder( element );
01105     else
01106         layout.topBorder.setPenWidth(0);
01107 
01108     element = parentElem.namedItem( "BOTTOMBORDER" ).toElement();
01109     if ( !element.isNull() )
01110         layout.bottomBorder = KoBorder::loadBorder( element );
01111     else
01112         layout.bottomBorder.setPenWidth(0);
01113 
01114     element = parentElem.namedItem( "COUNTER" ).toElement();
01115     if ( !element.isNull() )
01116     {
01117         layout.counter = new KoParagCounter;
01118         layout.counter->load( element );
01119     }
01120 
01121     KoTabulatorList tabList;
01122     element = parentElem.firstChild().toElement();
01123     for ( ; !element.isNull() ; element = element.nextSibling().toElement() )
01124     {
01125         if ( element.tagName() == "TABULATOR" )
01126         {
01127             KoTabulator tab;
01128             tab.type=T_LEFT;
01129             if(element.hasAttribute("type"))
01130                 tab.type = static_cast<KoTabulators>( element.attribute("type").toInt());
01131             tab.ptPos=0.0;
01132             if(element.hasAttribute("ptpos"))
01133                 tab.ptPos=element.attribute("ptpos").toDouble();
01134             tab.filling=TF_BLANK;
01135             if(element.hasAttribute("filling"))
01136                 tab.filling = static_cast<KoTabulatorFilling>( element.attribute("filling").toInt());
01137             tab.ptWidth=0.5;
01138             if(element.hasAttribute("width"))
01139                 tab.ptWidth=element.attribute("width").toDouble();
01140             tabList.append( tab );
01141         }
01142     }
01143     layout.setTabList( tabList );
01144 
01145 
01146     return layout;
01147 }
01148 
01149 void KPrTextObject::saveParagLayout( const KoParagLayout& layout, QDomElement & parentElem )
01150 {
01151     QDomDocument doc = parentElem.ownerDocument();
01152     QDomElement element = doc.createElement( "NAME" );
01153     parentElem.appendChild( element );
01154     if ( layout.style )
01155         element.setAttribute( "value", layout.style->name() );
01156     else
01157         kdWarning() << "KWTextParag::saveParagLayout: style==0L!" << endl;
01158 
01159 
01160     if ( layout.margins[QStyleSheetItem::MarginFirstLine] != 0 ||
01161          layout.margins[QStyleSheetItem::MarginLeft] != 0 ||
01162          layout.margins[QStyleSheetItem::MarginRight] != 0 )
01163     {
01164         element = doc.createElement( "INDENTS" );
01165         parentElem.appendChild( element );
01166         if ( layout.margins[QStyleSheetItem::MarginFirstLine] != 0 )
01167             element.setAttribute( "first", layout.margins[QStyleSheetItem::MarginFirstLine] );
01168         if ( layout.margins[QStyleSheetItem::MarginLeft] != 0 )
01169             element.setAttribute( "left", layout.margins[QStyleSheetItem::MarginLeft] );
01170         if ( layout.margins[QStyleSheetItem::MarginRight] != 0 )
01171             element.setAttribute( "right", layout.margins[QStyleSheetItem::MarginRight] );
01172     }
01173 
01174 
01175     if ( layout.margins[QStyleSheetItem::MarginTop] != 0 ||
01176          layout.margins[QStyleSheetItem::MarginBottom] != 0 )
01177     {
01178         element = doc.createElement( "OFFSETS" );
01179         parentElem.appendChild( element );
01180         if ( layout.margins[QStyleSheetItem::MarginTop] != 0 )
01181             element.setAttribute( "before", layout.margins[QStyleSheetItem::MarginTop] );
01182         if ( layout.margins[QStyleSheetItem::MarginBottom] != 0 )
01183             element.setAttribute( "after", layout.margins[QStyleSheetItem::MarginBottom] );
01184     }
01185 
01186     if ( layout.lineSpacingType != KoParagLayout::LS_SINGLE )
01187     {
01188         element = doc.createElement( "LINESPACING" );
01189         parentElem.appendChild( element );
01190         if ( layout.lineSpacingType == KoParagLayout::LS_ONEANDHALF )
01191             element.setAttribute( "type", "oneandhalf" );
01192         else if ( layout.lineSpacingType == KoParagLayout::LS_DOUBLE )
01193             element.setAttribute( "type", "double" );
01194         else if ( layout.lineSpacingType == KoParagLayout::LS_CUSTOM )
01195         {
01196             element.setAttribute( "type", "custom" );
01197             element.setAttribute( "spacingvalue", layout.lineSpacingValue());
01198         }
01199         else if ( layout.lineSpacingType == KoParagLayout::LS_AT_LEAST )
01200         {
01201             element.setAttribute( "type", "atleast" );
01202             element.setAttribute( "spacingvalue", layout.lineSpacingValue());
01203         }
01204         else if ( layout.lineSpacingType == KoParagLayout::LS_MULTIPLE )
01205         {
01206             element.setAttribute( "type", "multiple" );
01207             element.setAttribute( "spacingvalue", layout.lineSpacingValue());
01208         }
01209         else
01210             kdDebug(33001) << " error in lineSpacing Type" << endl;
01211     }
01212 
01213     if ( layout.leftBorder.penWidth() > 0 )
01214     {
01215         element = doc.createElement( "LEFTBORDER" );
01216         parentElem.appendChild( element );
01217         layout.leftBorder.save( element );
01218     }
01219     if ( layout.rightBorder.penWidth() > 0 )
01220     {
01221         element = doc.createElement( "RIGHTBORDER" );
01222         parentElem.appendChild( element );
01223         layout.rightBorder.save( element );
01224     }
01225     if ( layout.topBorder.penWidth() > 0 )
01226     {
01227         element = doc.createElement( "TOPBORDER" );
01228         parentElem.appendChild( element );
01229         layout.topBorder.save( element );
01230     }
01231     if ( layout.bottomBorder.penWidth() > 0 )
01232     {
01233         element = doc.createElement( "BOTTOMBORDER" );
01234         parentElem.appendChild( element );
01235         layout.bottomBorder.save( element );
01236     }
01237 
01238     if ( layout.counter && layout.counter->numbering() != KoParagCounter::NUM_NONE )
01239     {
01240         element = doc.createElement( "COUNTER" );
01241         parentElem.appendChild( element );
01242         if (layout.counter )
01243             layout.counter->save( element );
01244     }
01245 
01246     KoTabulatorList tabList = layout.tabList();
01247     KoTabulatorList::ConstIterator it = tabList.begin();
01248     for ( ; it != tabList.end() ; it++ )
01249     {
01250         element = doc.createElement( "TABULATOR" );
01251         parentElem.appendChild( element );
01252         element.setAttribute( "type", (*it).type );
01253         element.setAttribute( "ptpos", (*it).ptPos );
01254         element.setAttribute( "filling", (*it).filling );
01255         element.setAttribute( "width", (*it).ptWidth );
01256     }
01257 }
01258 
01259 void KPrTextObject::recalcPageNum( KPrPage *page )
01260 {
01261     int pgnum=m_doc->pageList().findRef(page);
01262 
01263     pgnum+=1;
01264     QPtrListIterator<KoTextCustomItem> cit( textDocument()->allCustomItems() );
01265     for ( ; cit.current() ; ++cit )
01266     {
01267         KPrPgNumVariable * var = dynamic_cast<KPrPgNumVariable *>( cit.current() );
01268         if ( var && !var->isDeleted()  )
01269         {
01270             switch ( var->subType() ) {
01271             case KPrPgNumVariable::VST_PGNUM_CURRENT:
01272                 var->setPgNum( pgnum + kPresenterDocument()->getVariableCollection()->variableSetting()->startingPageNumber()-1);
01273                 break;
01274             case KPrPgNumVariable::VST_CURRENT_SECTION:
01275                 var->setSectionTitle( page->pageTitle() );
01276                 break;
01277             case KPrPgNumVariable::VST_PGNUM_PREVIOUS:
01278                 var->setPgNum( QMAX( pgnum -1 , 0) +
01279                                kPresenterDocument()->getVariableCollection()->variableSetting()->startingPageNumber());
01280                 break;
01281             case KPrPgNumVariable::VST_PGNUM_NEXT:
01282                 var->setPgNum( QMIN( (int)m_doc->getPageNums(), pgnum+1 ) +
01283                                kPresenterDocument()->getVariableCollection()->variableSetting()->startingPageNumber());
01284                 break;
01285             default:
01286                 break;
01287             }
01288 
01289             var->resize();
01290             var->paragraph()->invalidate( 0 ); // size may have changed -> need reformatting !
01291             var->paragraph()->setChanged( true );
01292         }
01293     }
01294 }
01295 
01296 void KPrTextObject::layout()
01297 {
01298     invalidate();
01299     // Get the thing going though, repainting doesn't call formatMore
01300     m_textobj->formatMore( 2 );
01301 }
01302 
01303 void KPrTextObject::invalidate()
01304 {
01305     //kdDebug(33001) << "KWTextFrameSet::invalidate " << getName() << endl;
01306     m_textobj->setLastFormattedParag( textDocument()->firstParag() );
01307     textDocument()->formatter()->setViewFormattingChars( m_doc->viewFormattingChars() );
01308     textDocument()->invalidate(); // lazy layout, real update follows upon next repaint
01309 }
01310 
01311 // For the "paragraph after paragraph" effect
01312 void KPrTextObject::drawParags( QPainter *painter, KoTextZoomHandler* zoomHandler, const QColorGroup& cg, int from, int to )
01313 {
01314     // The fast and difficult way would be to call drawParagWYSIWYG
01315     // only on the paragraphs to be drawn. Then we have duplicate quite some code
01316     // (or lose double-buffering).
01317     // Easy (and not so slow) way:
01318     // we call KoTextDocument::drawWYSIWYG with a cliprect.
01319     Q_ASSERT( from <= to );
01320     int i = 0;
01321     bool editMode=false;
01322     if( m_doc->firstView() && m_doc->firstView()->getCanvas())
01323         editMode = m_doc->firstView()->getCanvas()->getEditMode();
01324 
01325     QRect r = zoomHandler->zoomRect( KoRect( 0, 0, innerWidth(), innerHeight() ) );
01326     KoTextParag *parag = textDocument()->firstParag();
01327     while ( parag ) {
01328         if ( !parag->isValid() )
01329             parag->format();
01330         if ( i == from )
01331             r.setTop( m_doc->zoomHandler()->layoutUnitToPixelY( parag->rect().top() ) );
01332         if ( i == to ) {
01333             r.setBottom( m_doc->zoomHandler()->layoutUnitToPixelY( parag->rect().bottom() ) );
01334             break;
01335         }
01336         ++i;
01337         parag = parag->next();
01338     }
01339 
01340     uint drawingFlags = 0; // don't draw selections
01341     if ( m_doc->backgroundSpellCheckEnabled() && editMode )
01342         drawingFlags |= KoTextDocument::DrawMisspelledLine;
01343     textDocument()->drawWYSIWYG(
01344         painter, r.x(), r.y(), r.width(), r.height(),
01345         cg, m_doc->zoomHandler(), // TODO (long term) the view's zoomHandler
01346         false /*onlyChanged*/, false /*cursor != 0*/, 0 /*cursor*/,
01347         true /*resetChanged*/, drawingFlags );
01348 }
01349 
01350 void KPrTextObject::drawCursor( QPainter *p, KoTextCursor *cursor, bool cursorVisible, KPrCanvas* canvas )
01351 {
01352     // The implementation is very related to KWord's KWTextFrameSet::drawCursor
01353     KoTextZoomHandler *zh = m_doc->zoomHandler();
01354     QPoint origPix = zh->zoomPoint( orig+KoPoint(bLeft(), bTop()+alignVertical) );
01355     // Painter is already translated for diffx/diffy, but not for the object yet
01356     p->translate( origPix.x(), origPix.y() );
01357     if ( angle != 0 )
01358         rotateObject( p, zh );
01359 
01360     KoTextParag* parag = cursor->parag();
01361     QPoint topLeft = parag->rect().topLeft();         // in QRT coords
01362     int lineY;
01363     // Cursor height, in pixels
01364     int cursorHeight = zh->layoutUnitToPixelY( topLeft.y(), parag->lineHeightOfChar( cursor->index(), 0, &lineY ) );
01365     QPoint iPoint( topLeft.x() + cursor->x(),
01366                    topLeft.y() + lineY );
01367     // from now on, iPoint will be in pixels
01368     iPoint = zh->layoutUnitToPixel( iPoint );
01369 
01370     QPoint vPoint = iPoint; // vPoint and iPoint are the same currently
01371                             // do not simplify this, will be useful with viewmodes.
01372     //int xadj = parag->at( cursor->index() )->pixelxadj;
01373     //iPoint.rx() += xadj;
01374     //vPoint.rx() += xadj;
01375     // very small clipping around the cursor
01376     QRect clip( vPoint.x() - 5, vPoint.y() , 10, cursorHeight );
01377     setupClipRegion( p, clip );
01378 
01379     // for debug only!
01380     //p->fillRect( clip, Qt::blue );
01381 
01382     QPixmap *pix = 0;
01383     QColorGroup cg = QApplication::palette().active();
01384     cg.setColor( QColorGroup::Base, m_doc->txtBackCol() );
01385 
01386     uint drawingFlags = KoTextDocument::DrawSelections;
01387     if ( m_doc->backgroundSpellCheckEnabled() )
01388         drawingFlags |= KoTextDocument::DrawMisspelledLine;
01389     if ( m_doc->viewFormattingChars() )
01390         drawingFlags |= KoTextDocument::DrawFormattingChars;
01391 
01392     // To force the drawing to happen:
01393     bool wasChanged = parag->hasChanged();
01394     int oldLineChanged = parag->lineChanged();
01395     int line; // line number
01396     parag->lineStartOfChar( cursor->index(), 0, &line );
01397     parag->setChanged( false ); // not all changed, only from a given line
01398     parag->setLineChanged( line );
01399     //kdDebug(33001) << "KPrTextObject::drawCursor cursorVisible=" << cursorVisible << " line=" << line << endl;
01400 
01401     textDocument()->drawParagWYSIWYG(
01402         p, parag,
01403         QMAX(0, iPoint.x() - 5), // negative values create problems
01404         iPoint.y(), clip.width(), clip.height(),
01405         pix, cg, m_doc->zoomHandler(),
01406         cursorVisible, cursor, FALSE /*resetChanged*/, drawingFlags );
01407 
01408     if ( wasChanged )      // Maybe we have more changes to draw, than those in the small cliprect
01409         cursor->parag()->setLineChanged( oldLineChanged ); // -1 = all
01410     else
01411         cursor->parag()->setChanged( false );
01412 
01413     // XIM Position
01414     QPoint ximPoint = vPoint;
01415     QFont f = parag->at( cursor->index() )->format()->font();
01416     canvas->setXimPosition( ximPoint.x() + origPix.x(), ximPoint.y() + origPix.y(),
01417                             0, cursorHeight - parag->lineSpacing( line ), &f );
01418 }
01419 
01420 KPrTextDocument * KPrTextObject::textDocument() const
01421 {
01422     return static_cast<KPrTextDocument*>(m_textobj->textDocument());
01423 }
01424 
01425 void KPrTextObject::slotNewCommand( KCommand * cmd)
01426 {
01427     m_doc->addCommand(cmd);
01428 }
01429 
01430 int KPrTextObject::availableHeight() const
01431 {
01432     return m_textobj->availableHeight();
01433 }
01434 
01435 void KPrTextObject::slotAvailableHeightNeeded()
01436 {
01437     int ah = m_doc->zoomHandler()->ptToLayoutUnitPixY( innerHeight() );
01438     m_textobj->setAvailableHeight( ah );
01439     //kdDebug(33001)<<"slotAvailableHeightNeeded: height=:"<<ah<<endl;
01440 }
01441 
01442 void KPrTextObject::slotRepaintChanged()
01443 {
01444     emit repaintChanged( this );
01445 }
01446 
01447 KPrTextView * KPrTextObject::createKPTextView( KPrCanvas * _canvas, bool temp )
01448 {
01449     return new KPrTextView( this, _canvas, temp );
01450 }
01451 
01452 void KPrTextObject::removeHighlight ()
01453 {
01454     m_textobj->removeHighlight( true /*repaint*/ );
01455 }
01456 
01457 void KPrTextObject::highlightPortion( KoTextParag * parag, int index, int length, KPrCanvas* canvas, bool repaint, KDialogBase* dialog )
01458 {
01459     m_textobj->highlightPortion( parag, index, length, repaint );
01460     if ( repaint )
01461     {
01462         KPrDocument* doc = canvas->getView()->kPresenterDoc();
01463 
01464         // Is this object in the current active page?
01465         if ( canvas->activePage()->findTextObject( this ) )
01466         {
01467             kdDebug(33001) << k_funcinfo << "object in current page" << endl;
01468         }
01469         else
01470         {
01471             // No -> find the right page and activate it
01472             // ** slow method **
01473             KPrPage* page = doc->findPage( this );
01474             if ( page ) {
01475                 int pageNum = doc->pageList().findRef( page );
01476                 // if the pageNum is -1 the object is located on the master slide
01477                 if ( pageNum > -1 )
01478                 {
01479                     canvas->getView()->skipToPage( pageNum );
01480                 }
01481             } else
01482                 kdWarning(33001) << "object " << this << " not found in any page!?" << endl;
01483         }
01484         // Now ensure text is fully visible
01485         QRect rect = m_doc->zoomHandler()->zoomRect( getRect() );
01486         QRect expose = m_doc->zoomHandler()->layoutUnitToPixel( parag->rect() );
01487         expose.moveBy( rect.x(), rect.y() );
01488         canvas->ensureVisible( (expose.left()+expose.right()) / 2,  // point = center of the rect
01489                                (expose.top()+expose.bottom()) / 2,
01490                                (expose.right()-expose.left()) / 2,  // margin = half-width of the rect
01491                                (expose.bottom()-expose.top()) / 2);
01492 #if KDE_IS_VERSION(3,1,90)
01493         if ( dialog ) {
01494             QRect globalRect( expose );
01495             globalRect.moveTopLeft( canvas->mapToGlobal( globalRect.topLeft() ) );
01496             KDialog::avoidArea( dialog, globalRect );
01497         }
01498 #endif
01499     }
01500 }
01501 
01502 KCommand * KPrTextObject::pasteOasis( KoTextCursor * cursor, const QByteArray & data, bool removeSelected )
01503 {
01504     //kdDebug(33001) << "KPrTextObject::pasteOasis" << endl;
01505     KMacroCommand * macroCmd = new KMacroCommand( i18n("Paste Text") );
01506     if ( removeSelected && textDocument()->hasSelection( KoTextDocument::Standard ) )
01507         macroCmd->addCommand( m_textobj->removeSelectedTextCommand( cursor, KoTextDocument::Standard ) );
01508     m_textobj->emitHideCursor();
01509     m_textobj->setLastFormattedParag( cursor->parag()->prev() ?
01510                                       cursor->parag()->prev() : cursor->parag() );
01511 
01512     // We have our own command for this.
01513     // Using insert() wouldn't help storing the parag stuff for redo
01514     KPrOasisPasteTextCommand * cmd = new KPrOasisPasteTextCommand( textDocument(), cursor->parag()->paragId(), cursor->index(), data );
01515     textDocument()->addCommand( cmd );
01516 
01517     macroCmd->addCommand( new KoTextCommand( m_textobj, /*cmd, */QString::null ) );
01518     *cursor = *( cmd->execute( cursor ) );
01519 
01520     m_textobj->formatMore( 2 );
01521     emit repaintChanged( this );
01522     m_textobj->emitEnsureCursorVisible();
01523     m_textobj->emitUpdateUI( true );
01524     m_textobj->emitShowCursor();
01525     m_textobj->selectionChangedNotify();
01526     return macroCmd;
01527 }
01528 
01529 
01530 void KPrTextObject::setShadowParameter(int _distance,ShadowDirection _direction,const QColor &_color)
01531 {
01532     int sx = 0;
01533     int sy = 0;
01534     switch ( _direction )
01535     {
01536     case SD_LEFT_BOTTOM:
01537     case SD_LEFT:
01538     case SD_LEFT_UP:
01539         sx = - _distance;
01540     case SD_RIGHT_UP:
01541     case SD_RIGHT:
01542     case SD_RIGHT_BOTTOM:
01543         sx = _distance;
01544     default:
01545         break;
01546     }
01547     switch ( _direction )
01548     {
01549     case SD_LEFT_UP:
01550     case SD_UP:
01551     case SD_RIGHT_UP:
01552         sy = - _distance;
01553     case SD_LEFT_BOTTOM:
01554     case SD_BOTTOM:
01555     case SD_RIGHT_BOTTOM:
01556         sy = _distance;
01557     default:
01558         break;
01559     }
01560     KoTextFormat tmpFormat;
01561     tmpFormat.setShadow( sx, sy, _color );
01562     KCommand* cmd = m_textobj->setFormatCommand( &tmpFormat, KoTextFormat::ShadowText );
01563     if ( cmd )
01564         m_doc->addCommand(cmd);
01565 }
01566 
01567 void KPrTextObject::slotFormatChanged(const KoTextFormat &_format)
01568 {
01569     if(m_doc && m_doc->firstView())
01570         m_doc->firstView()->showFormat( _format );
01571 }
01572 
01573 void KPrTextObject::applyStyleChange( KoStyleChangeDefMap changed )
01574 {
01575     m_textobj->applyStyleChange( changed );
01576 }
01577 
01578 void KPrTextObject::slotAfterFormatting( int bottom, KoTextParag* lastFormatted, bool* abort)
01579 {
01580     recalcVerticalAlignment();
01581     int availHeight = availableHeight() - m_doc->zoomHandler()->ptToLayoutUnitPixY(alignmentValue());
01582     if ( ( bottom > availHeight ) ||   // this parag is already below the avail height
01583          ( lastFormatted && (bottom + lastFormatted->rect().height() > availHeight) ) ) // or next parag will be below it
01584     {
01585         int difference = ( bottom + 2 ) - availHeight; // in layout unit pixels
01586         if( lastFormatted && bottom + lastFormatted->rect().height() > availHeight )
01587         {
01588             difference += lastFormatted->rect().height();
01589         }
01590 #if 0
01591         if(lastFormatted)
01592             kdDebug(33001) << "slotAfterFormatting We need more space in " << this
01593                            << " bottom=" << bottom + lastFormatted->rect().height()
01594                            << " availHeight=" << availHeight
01595                            << " ->difference=" << difference << endl;
01596         else
01597             kdDebug(33001) << "slotAfterFormatting We need more space in " << this
01598                            << " bottom2=" << bottom << " availHeight=" << availHeight
01599                            << " ->difference=" << difference << endl;
01600 #endif
01601         // We only auto-grow. We don't auto-shrink.
01602         if(difference > 0 && !isProtect())
01603         {
01604             double wantedPosition = m_doc->zoomHandler()->layoutUnitPtToPt( m_doc->zoomHandler()->pixelYToPt( difference ) )
01605                                     + getRect().bottom();
01606             const KoPageLayout& p = m_doc->pageLayout();
01607             double pageBottom = p.ptHeight - p.ptBottom;
01608             double newBottom = QMIN( wantedPosition, pageBottom ); // don't grow bigger than the page
01609             newBottom = QMAX( newBottom, getOrig().y() ); // avoid negative heights
01610             //kdDebug(33001) << k_funcinfo << " current bottom=" << getRect().bottom() << " newBottom=" << newBottom << endl;
01611             if ( getRect().bottom() != newBottom )
01612             {
01613                 // We resize the text object, but skipping the KPrTextObject::setSize code
01614                 // (which invalidates everything etc.)
01615                 KPrObject::setSize( getSize().width(), newBottom - getOrig().y() );
01616                 // Do recalculate the new available height though
01617                 slotAvailableHeightNeeded();
01618                 m_doc->updateRuler();
01619                 m_doc->repaint( true );
01620                 *abort = false;
01621             }
01622         }
01623         else if ( isProtect() )
01624             m_textobj->setLastFormattedParag( 0 );
01625     }
01626 }
01627 
01628 // "Extend Contents to Object Height"
01629 KCommand * KPrTextObject::textContentsToHeight()
01630 {
01631     if (isProtect() )
01632         return 0L;
01633 
01634     // Count total number of lines and sum up their height (linespacing excluded)
01635     KoTextParag * parag = textDocument()->firstParag();
01636     int numLines = 0;
01637     int textHeightLU = 0;
01638     bool lineSpacingEqual = false;
01639     int oldLineSpacing = 0;
01640     for ( ; parag ; parag = parag->next() )
01641     {
01642         int lines = parag->lines();
01643         numLines += lines;
01644         for ( int line = 0 ; line < lines ; ++line )
01645         {
01646             int y, h, baseLine;
01647             parag->lineInfo( line, y, h, baseLine );
01648             int ls = parag->lineSpacing( line );
01649             lineSpacingEqual = (oldLineSpacing == ls);
01650             oldLineSpacing = ls;
01651             textHeightLU += h - ls;
01652         }
01653     }
01654 
01655     double textHeight = m_doc->zoomHandler()->layoutUnitPtToPt( textHeightLU );
01656     double lineSpacing = ( innerHeight() - textHeight ) /  numLines; // this gives the linespacing diff to apply, in pt
01657     //kdDebug(33001) << k_funcinfo << "lineSpacing=" << lineSpacing << endl;
01658 
01659     if ( KABS( innerHeight() - textHeight ) < DBL_EPSILON ) // floating-point equality test
01660         return 0L; // nothing to do
01661     bool oneLine =(textDocument()->firstParag() == textDocument()->lastParag() && numLines == 1);
01662     if ( lineSpacing < 0  || oneLine) // text object is too small
01663         lineSpacing = 0; // we can't do smaller linespacing than that, but we do need to apply it
01664                          // (in case there's some bigger linespacing in use)
01665     if ( (oneLine || lineSpacingEqual) && (textDocument()->firstParag()->kwLineSpacing() == lineSpacing))
01666         return 0L;
01667     // Apply the new linespacing to the whole object
01668     textDocument()->selectAll( KoTextDocument::Temp );
01669     KCommand* cmd = m_textobj->setLineSpacingCommand( 0L, lineSpacing, KoParagLayout::LS_CUSTOM, KoTextDocument::Temp );
01670     textDocument()->removeSelection( KoTextDocument::Temp );
01671     return cmd;
01672 }
01673 
01674 // "Resize Object to fit Contents"
01675 KCommand * KPrTextObject::textObjectToContents()
01676 {
01677     if ( isProtect() )
01678         return 0L;
01679     // Calculate max parag width (in case all parags are short, otherwise - with wrapping -
01680     // the width is more or less the current object's width anyway).
01681     KoTextParag * parag = textDocument()->firstParag();
01682     double txtWidth = 10;
01683     for ( ; parag ; parag = parag->next() )
01684         txtWidth = QMAX( txtWidth, m_doc->zoomHandler()->layoutUnitPtToPt( parag->widthUsed() ));
01685 
01686     // Calculate text height
01687     int heightLU = textDocument()->height();
01688     double txtHeight = m_doc->zoomHandler()->layoutUnitPtToPt( heightLU );
01689 
01690     // Compare with current object's size
01691     KoSize sizeDiff = KoSize( txtWidth, txtHeight ) - innerRect().size();
01692     if( !sizeDiff.isNull() )
01693     {
01694         // The command isn't named since it's always put into a macro command.
01695         return new KPrResizeCmd( QString::null, KoPoint( 0, 0 ), sizeDiff, this, m_doc);
01696     }
01697     return 0L;
01698 }
01699 
01700 void KPrTextObject::setTextMargins( double _left, double _top, double _right, double _bottom)
01701 {
01702     bleft = _left;
01703     btop = _top;
01704     bright = _right;
01705     bbottom = _bottom;
01706 }
01707 
01708 KoRect KPrTextObject::innerRect() const
01709 {
01710     KoRect inner( getRect());
01711     inner.moveBy( bLeft(), bTop());
01712     inner.setWidth( inner.width() - bLeft() - bRight() );
01713     inner.setHeight( inner.height() - bTop() - bBottom() );
01714     return inner;
01715 }
01716 
01717 double KPrTextObject::innerWidth() const
01718 {
01719     return getSize().width() - bLeft() - bRight();
01720 }
01721 
01722 double KPrTextObject::innerHeight() const
01723 {
01724     return getSize().height() - bTop() - bBottom();
01725 }
01726 
01727 void KPrTextObject::setVerticalAligment( VerticalAlignmentType _type)
01728 {
01729     m_textVertAlign = _type;
01730     recalcVerticalAlignment();
01731 }
01732 
01733 void KPrTextObject::recalcVerticalAlignment()
01734 {
01735     double txtHeight = m_doc->zoomHandler()->layoutUnitPtToPt( m_doc->zoomHandler()->pixelYToPt( textDocument()->height() ) ) + btop + bbottom;
01736     double diffy = getSize().height() - txtHeight;
01737 
01738     //kdDebug(33001) << k_funcinfo << "txtHeight: " << txtHeight << " rectHeight:" << getSize().height() << " -> diffy=" << diffy << endl;
01739 
01740     if ( diffy <= 0.0 ) {
01741         alignVertical = 0.0;
01742         return;
01743     }
01744     switch( m_textVertAlign )
01745     {
01746     case KP_CENTER:
01747         alignVertical = diffy/2.0;
01748         break;
01749     case KP_TOP:
01750         alignVertical = 0.0;
01751         break;
01752     case KP_BOTTOM:
01753         alignVertical = diffy;
01754         break;
01755     }
01756 }
01757 
01758 QPoint KPrTextObject::cursorPos(KPrCanvas *canvas, KoTextCursor *cursor) const
01759 {
01760   KoTextZoomHandler *zh = m_doc->zoomHandler();
01761   QPoint origPix = zh->zoomPoint( orig+KoPoint(bLeft(), bTop()+alignVertical) );
01762   KoTextParag* parag = cursor->parag();
01763   QPoint topLeft = parag->rect().topLeft();         // in QRT coords
01764   int lineY = 0;
01765     // Cursor height, in pixels
01766   //int cursorHeight = zh->layoutUnitToPixelY( topLeft.y(), parag->lineHeightOfChar( cursor->index(), 0, &lineY ) );
01767   QPoint iPoint( topLeft.x() + cursor->x(), topLeft.y() + lineY );
01768   iPoint = zh->layoutUnitToPixel( iPoint );
01769   iPoint.rx() -= canvas->diffx();
01770   iPoint.ry() -= canvas->diffy();
01771   return origPix+iPoint;
01772 }
01773 
01774 KPrTextView::KPrTextView( KPrTextObject * txtObj, KPrCanvas *_canvas, bool temp )
01775     : KoTextView( txtObj->textObject() )
01776 {
01777     setBackSpeller( txtObj->kPresenterDocument()->backSpeller() );
01778     m_canvas=_canvas;
01779     m_kptextobj=txtObj;
01780     if (temp)
01781       return;
01782     connect( txtObj->textObject(), SIGNAL( selectionChanged(bool) ),
01783              m_canvas, SIGNAL( selectionChanged(bool) ) );
01784     KoTextView::setReadWrite( txtObj->kPresenterDocument()->isReadWrite() );
01785     connect( textView(), SIGNAL( cut() ), SLOT( cut() ) );
01786     connect( textView(), SIGNAL( copy() ), SLOT( copy() ) );
01787     connect( textView(), SIGNAL( paste() ), SLOT( paste() ) );
01788     updateUI( true, true );
01789 
01790     txtObj->setEditingTextObj( true );
01791 }
01792 
01793 KPrTextView::~KPrTextView()
01794 {
01795 }
01796 
01797 KoTextViewIface* KPrTextView::dcopObject()
01798 {
01799     if ( !dcop )
01800         dcop = new KPrTextViewIface( this );
01801 
01802     return dcop;
01803 }
01804 
01805 void KPrTextView::terminate(bool removeSelection)
01806 {
01807     disconnect( textView()->textObject(), SIGNAL( selectionChanged(bool) ),
01808                 m_canvas, SIGNAL( selectionChanged(bool) ) );
01809     textView()->terminate(removeSelection);
01810 }
01811 
01812 void KPrTextView::cut()
01813 {
01814     if ( textDocument()->hasSelection( KoTextDocument::Standard ) ) {
01815         copy();
01816         textObject()->removeSelectedText( cursor() );
01817     }
01818 }
01819 
01820 void KPrTextView::copy()
01821 {
01822     //kdDebug(33001)<<"void KPrTextView::copy() "<<endl;
01823     if ( textDocument()->hasSelection( KoTextDocument::Standard ) ) {
01824         QDragObject *drag = newDrag( 0 );
01825         QApplication::clipboard()->setData( drag );
01826     }
01827 }
01828 
01829 void KPrTextView::paste()
01830 {
01831     //kdDebug(33001) << "KPrTextView::paste()" << endl;
01832 
01833     QMimeSource *data = QApplication::clipboard()->data();
01834     QCString returnedMimeType = KoTextObject::providesOasis( data );
01835     if ( !returnedMimeType.isEmpty() )
01836     {
01837         QByteArray arr = data->encodedData( returnedMimeType );
01838         if ( arr.size() )
01839         {
01840 #if 0
01841             QFile paste( "/tmp/oasis.tmp" );
01842             paste.open( IO_WriteOnly );
01843             paste.writeBlock( arr );
01844             paste.close();
01845 #endif
01846             KCommand *cmd = kpTextObject()->pasteOasis( cursor(), arr, true );
01847             if ( cmd )
01848                 kpTextObject()->kPresenterDocument()->addCommand(cmd);
01849         }
01850     }
01851     else
01852     {
01853         // Note: QClipboard::text() seems to do a better job than encodedData( "text/plain" )
01854         // In particular it handles charsets (in the mimetype).
01855         QString text = QApplication::clipboard()->text();
01856         if ( !text.isEmpty() )
01857             textObject()->pasteText( cursor(), text, currentFormat(), true /*removeSelected*/ );
01858     }
01859     kpTextObject()->layout();
01860 }
01861 
01862 void KPrTextView::updateUI( bool updateFormat, bool force  )
01863 {
01864     KoTextView::updateUI( updateFormat, force  );
01865     // Paragraph settings
01866     KoTextParag * parag = static_cast<KoTextParag*>( cursor()->parag());
01867     if ( m_paragLayout.alignment != parag->resolveAlignment() || force ) {
01868         m_paragLayout.alignment = parag->resolveAlignment();
01869         m_canvas->getView()->alignChanged(  m_paragLayout.alignment );
01870     }
01871 
01872     // Counter
01873     if ( !m_paragLayout.counter )
01874         m_paragLayout.counter = new KoParagCounter; // we can afford to always have one here
01875     KoParagCounter::Style cstyle = m_paragLayout.counter->style();
01876     if ( parag->counter() )
01877         *m_paragLayout.counter = *parag->counter();
01878     else
01879     {
01880         m_paragLayout.counter->setNumbering( KoParagCounter::NUM_NONE );
01881         m_paragLayout.counter->setStyle( KoParagCounter::STYLE_NONE );
01882     }
01883 
01884     if ( m_paragLayout.counter->style() != cstyle || force )
01885         m_canvas->getView()->showCounter( * m_paragLayout.counter );
01886 
01887     if(m_paragLayout.leftBorder!=parag->leftBorder() ||
01888        m_paragLayout.rightBorder!=parag->rightBorder() ||
01889        m_paragLayout.topBorder!=parag->topBorder() ||
01890        m_paragLayout.bottomBorder!=parag->bottomBorder() || force )
01891     {
01892         m_paragLayout.leftBorder = parag->leftBorder();
01893         m_paragLayout.rightBorder = parag->rightBorder();
01894         m_paragLayout.topBorder = parag->topBorder();
01895         m_paragLayout.bottomBorder = parag->bottomBorder();
01896         //todo
01897         //m_canvas->gui()->getView()->showParagBorders( m_paragLayout.leftBorder, m_paragLayout.rightBorder, m_paragLayout.topBorder, m_paragLayout.bottomBorder );
01898     }
01899 
01900     if ( !parag->style() )
01901         kdWarning(33001) << "Paragraph " << parag->paragId() << " has no style" << endl;
01902     else if ( m_paragLayout.style != parag->style() || force )
01903     {
01904         m_paragLayout.style = parag->style();
01905         m_canvas->getView()->showStyle( m_paragLayout.style->name() );
01906     }
01907 
01908     if( m_paragLayout.margins[QStyleSheetItem::MarginLeft] != parag->margin(QStyleSheetItem::MarginLeft)
01909         || m_paragLayout.margins[QStyleSheetItem::MarginFirstLine] != parag->margin(QStyleSheetItem::MarginFirstLine)
01910         || m_paragLayout.margins[QStyleSheetItem::MarginRight] != parag->margin(QStyleSheetItem::MarginRight)
01911         || force )
01912     {
01913         m_paragLayout.margins[QStyleSheetItem::MarginFirstLine] = parag->margin(QStyleSheetItem::MarginFirstLine);
01914         m_paragLayout.margins[QStyleSheetItem::MarginLeft] = parag->margin(QStyleSheetItem::MarginLeft);
01915         m_paragLayout.margins[QStyleSheetItem::MarginRight] = parag->margin(QStyleSheetItem::MarginRight);
01916         m_canvas->getView()->showRulerIndent( m_paragLayout.margins[QStyleSheetItem::MarginLeft],
01917                                               m_paragLayout.margins[QStyleSheetItem::MarginFirstLine],
01918                                               m_paragLayout.margins[QStyleSheetItem::MarginRight],
01919                                               parag->string()->isRightToLeft() );
01920     }
01921 
01922     if( m_paragLayout.tabList() != parag->tabList() || force )
01923     {
01924         m_paragLayout.setTabList( parag->tabList() );
01925         KoRuler * hr = m_canvas->getView()->getHRuler();
01926         if ( hr )
01927             hr->setTabList( parag->tabList() );
01928     }
01929 }
01930 
01931 void KPrTextView::ensureCursorVisible()
01932 {
01933     //kdDebug(33001) << "KWTextFrameSetEdit::ensureCursorVisible paragId=" << cursor()->parag()->paragId() << endl;
01934     KoTextParag * parag = cursor()->parag();
01935     kpTextObject()->textObject()->ensureFormatted( parag );
01936     KoTextStringChar *chr = parag->at( cursor()->index() );
01937     int h = parag->lineHeightOfChar( cursor()->index() );
01938     int x = parag->rect().x() + chr->x;
01939     int y = 0; int dummy;
01940 
01941     parag->lineHeightOfChar( cursor()->index(), &dummy, &y );
01942     y += parag->rect().y();
01943     int w = 1;
01944     KPrDocument *doc= m_kptextobj->kPresenterDocument();
01945     KoPoint pt= kpTextObject()->getOrig();
01946     pt.setX( doc->zoomHandler()->layoutUnitPtToPt( doc->zoomHandler()->pixelXToPt( x) ) +pt.x());
01947     pt.setY( doc->zoomHandler()->layoutUnitPtToPt( doc->zoomHandler()->pixelYToPt( y ))+pt.y() );
01948 
01949     QPoint p = m_kptextobj->kPresenterDocument()->zoomHandler()->zoomPoint( pt );
01950     w = m_kptextobj->kPresenterDocument()->zoomHandler()->layoutUnitToPixelX( w );
01951     h = m_kptextobj->kPresenterDocument()->zoomHandler()->layoutUnitToPixelY( h );
01952     m_canvas->ensureVisible( p.x(), p.y() + h / 2, w, h / 2 + 2 );
01953 }
01954 
01955 bool KPrTextView::doCompletion( KoTextCursor* cursor, KoTextParag *parag, int index )
01956 {
01957     if( m_kptextobj->kPresenterDocument()->allowAutoFormat() )
01958     {
01959         KoAutoFormat * autoFormat = m_kptextobj->kPresenterDocument()->getAutoFormat();
01960         if( autoFormat )
01961             return autoFormat->doCompletion(  cursor, parag, index, textObject());
01962     }
01963     return false;
01964 }
01965 
01966 bool KPrTextView::doToolTipCompletion( KoTextCursor* cursor, KoTextParag *parag, int index,int keyPress )
01967 {
01968     if( m_kptextobj->kPresenterDocument()->allowAutoFormat() )
01969     {
01970         KoAutoFormat * autoFormat = m_kptextobj->kPresenterDocument()->getAutoFormat();
01971         if( autoFormat )
01972             return autoFormat->doToolTipCompletion(  cursor, parag, index, textObject(), keyPress);
01973     }
01974     return false;
01975 }
01976 void KPrTextView::showToolTipBox(KoTextParag *parag, int index, QWidget *widget, const QPoint &pos)
01977 {
01978     if( m_kptextobj->kPresenterDocument()->allowAutoFormat() )
01979     {
01980         KoAutoFormat * autoFormat = m_kptextobj->kPresenterDocument()->getAutoFormat();
01981         if( autoFormat )
01982             autoFormat->showToolTipBox(parag, index, widget, pos);
01983     }
01984 }
01985 
01986 void KPrTextView::removeToolTipCompletion()
01987 {
01988     if( m_kptextobj->kPresenterDocument()->allowAutoFormat() )
01989     {
01990         KoAutoFormat * autoFormat = m_kptextobj->kPresenterDocument()->getAutoFormat();
01991         if( autoFormat )
01992             autoFormat->removeToolTipCompletion();
01993     }
01994 }
01995 void KPrTextView::textIncreaseIndent()
01996 {
01997   m_canvas->setTextDepthPlus();
01998 }
01999 
02000 bool KPrTextView::textDecreaseIndent()
02001 {
02002   if (m_paragLayout.margins[QStyleSheetItem::MarginLeft]>0)
02003   {
02004     m_canvas->setTextDepthMinus();
02005     return true;
02006   }
02007   else
02008     return false;
02009 }
02010 
02011 void KPrTextView::doAutoFormat( KoTextCursor* cursor, KoTextParag *parag, int index, QChar ch )
02012 {
02013     if( m_kptextobj->kPresenterDocument()->allowAutoFormat())
02014     {
02015         KoAutoFormat * autoFormat = m_kptextobj->kPresenterDocument()->getAutoFormat();
02016         if ( autoFormat )
02017             autoFormat->doAutoFormat( cursor, parag, index, ch, textObject());
02018     }
02019 }
02020 
02021 bool KPrTextView::doIgnoreDoubleSpace(KoTextParag * parag, int index,QChar ch )
02022 {
02023     if( m_kptextobj->kPresenterDocument()->allowAutoFormat())
02024     {
02025 
02026         KoAutoFormat * autoFormat = m_kptextobj->kPresenterDocument()->getAutoFormat();
02027         if( autoFormat )
02028             return autoFormat->doIgnoreDoubleSpace( parag, index,ch );
02029     }
02030     return false;
02031 }
02032 
02033 void KPrTextView::startDrag()
02034 {
02035     textView()->dragStarted();
02036     m_canvas->dragStarted();
02037     QDragObject *drag = newDrag( m_canvas );
02038     if ( !kpTextObject()->kPresenterDocument()->isReadWrite() )
02039         drag->dragCopy();
02040     else
02041     {
02042         if ( drag->drag() && QDragObject::target() != m_canvas  )
02043             textObject()->removeSelectedText( cursor() );
02044     }
02045 }
02046 
02047 void KPrTextView::showFormat( KoTextFormat *format )
02048 {
02049     m_canvas->getView()->showFormat( *format );
02050 }
02051 
02052 bool KPrTextView::pgUpKeyPressed()
02053 {
02054     KoTextCursor *cursor = textView()->cursor();
02055     KoTextParag *s = cursor->parag();
02056     s = textDocument()->firstParag();
02057 
02058     textView()->cursor()->setParag( s );
02059     textView()->cursor()->setIndex( 0 );
02060     return true;
02061 }
02062 
02063 bool KPrTextView::pgDownKeyPressed()
02064 {
02065     KoTextCursor *cursor = textView()->cursor();
02066     KoTextParag *s = cursor->parag();
02067     s = textDocument()->lastParag();
02068     cursor->setParag( s );
02069     cursor->setIndex( s->length() - 1 );
02070     return true;
02071 }
02072 
02073 void KPrTextView::keyPressEvent( QKeyEvent *e )
02074 {
02075   //Calculate position of tooltip for autocompletion
02076   const QPoint pos = kpTextObject()->cursorPos(m_canvas, cursor());
02077   textView()->handleKeyPressEvent( e, m_canvas, pos );
02078 }
02079 
02080 void KPrTextView::keyReleaseEvent( QKeyEvent *e )
02081 {
02082     handleKeyReleaseEvent(e);
02083 }
02084 
02085 void KPrTextView::imStartEvent( QIMEvent *e )
02086 {
02087     handleImStartEvent(e);
02088 }
02089 
02090 void KPrTextView::imComposeEvent( QIMEvent *e )
02091 {
02092     handleImComposeEvent(e);
02093 }
02094 
02095 void KPrTextView::imEndEvent( QIMEvent *e )
02096 {
02097     handleImEndEvent(e);
02098 }
02099 
02100 void KPrTextView::clearSelection()
02101 {
02102     if ( textDocument()->hasSelection( KoTextDocument::Standard ) )
02103         textDocument()->removeSelection(KoTextDocument::Standard );
02104 }
02105 
02106 void KPrTextView::selectAll(bool select)
02107 {
02108     textObject()->selectAll( select );
02109 }
02110 
02111 void KPrTextView::drawCursor( bool b )
02112 {
02113     KoTextView::drawCursor( b );
02114     if ( !cursor()->parag() )
02115         return;
02116     if ( !kpTextObject()->kPresenterDocument()->isReadWrite() )
02117         return;
02118 
02119     QPainter painter( m_canvas );
02120     painter.translate( -m_canvas->diffx(), -m_canvas->diffy() );
02121     painter.setBrushOrigin( -m_canvas->diffx(), -m_canvas->diffy() );
02122 
02123     kpTextObject()->drawCursor( &painter, cursor(), b, m_canvas );
02124 }
02125 
02126 // Convert a mouse position into a QRT document position
02127 QPoint KPrTextView::viewToInternal( const QPoint & pos ) const
02128 {
02129 #if 0
02130     KoTextZoomHandler* zh = kpTextObject()->kPresenterDocument()->zoomHandler();
02131     QPoint tmp(pos);
02132     QWMatrix m;
02133     m.translate( zh->zoomItX(kpTextObject()->getSize().width() / 2.0),
02134                  zh->zoomItY(kpTextObject()->getSize().height() /  2.0) );
02135     m.rotate( kpTextObject()->getAngle() );
02136 
02137 
02138 
02139     m.translate( zh->zoomItX(kpTextObject()->getOrig().x()),
02140                  zh->zoomItY(kpTextObject()->getOrig().y()) );
02141     //m = m.invert();
02142     tmp = m * pos;
02143 
02144     kdDebug(33001)<<" tmp.x() :"<<tmp.x()<<" tmp.y() "<<tmp.y()<<endl;
02145 
02146     KoRect br = KoRect( 0, 0, kpTextObject()->getSize().width(), kpTextObject()->getSize().height() );
02147     double pw = br.width();
02148     double ph = br.height();
02149     KoRect rr = br;
02150     double yPos = -rr.y();
02151     double xPos = -rr.x();
02152     rr.moveTopLeft( KoPoint( -rr.width() / 2.0, -rr.height() / 2.0 ) );
02153 
02154     m.translate( zh->zoomItX(pw / 2.0),
02155                  zh->zoomItY(ph / 2.0 ));
02156     m.rotate( kpTextObject()->getAngle() );
02157     m.translate( zh->zoomItX(rr.left() + xPos),
02158                  zh->zoomItY(rr.top() + yPos) );
02159 
02160     m = m.invert();
02161 
02162     tmp = m * pos;
02163 
02164     kdDebug(33001)<<" tmp.x() :"<<tmp.x()<<" tmp.y() "<<tmp.y()<<endl;
02165 #endif
02166 
02167     return kpTextObject()->viewToInternal( pos, m_canvas );
02168 }
02169 
02170 void KPrTextView::mousePressEvent( QMouseEvent *e, const QPoint &/*_pos*/)
02171 {
02172     bool addParag = handleMousePressEvent( e, viewToInternal( e->pos() ),true /*bool canStartDrag*/,
02173                                            kpTextObject()->kPresenterDocument()->insertDirectCursor() );
02174 
02175     if ( addParag )
02176         kpTextObject()->kPresenterDocument()->setModified( true );
02177 }
02178 
02179 void KPrTextView::mouseDoubleClickEvent( QMouseEvent *e, const QPoint &pos)
02180 {
02181     handleMouseDoubleClickEvent( e, pos  );
02182 }
02183 
02184 void KPrTextView::mouseMoveEvent( QMouseEvent *e, const QPoint &_pos )
02185 {
02186     if ( textView()->maybeStartDrag( e ) )
02187         return;
02188     if ( _pos.y() > 0  )
02189         textView()->handleMouseMoveEvent( e,viewToInternal( e->pos() ) );
02190 }
02191 
02192 bool KPrTextView::isLinkVariable( const QPoint & pos )
02193 {
02194     const QPoint iPoint = viewToInternal( pos );
02195     KoLinkVariable* linkVariable = dynamic_cast<KoLinkVariable *>( textObject()->variableAtPoint( iPoint ) );
02196     return linkVariable != 0;
02197 }
02198 
02199 void KPrTextView::openLink()
02200 {
02201     KPrDocument * doc = kpTextObject()->kPresenterDocument();
02202     if ( doc->getVariableCollection()->variableSetting()->displayLink() ) {
02203         KoLinkVariable* v = linkVariable();
02204         if ( v )
02205             KoTextView::openLink( v );
02206     }
02207 }
02208 
02209 void KPrTextView::mouseReleaseEvent( QMouseEvent *, const QPoint & )
02210 {
02211     handleMouseReleaseEvent();
02212 }
02213 
02214 void KPrTextView::showPopup( KPrView *view, const QPoint &point, QPtrList<KAction>& actionList )
02215 {
02216     QString word = wordUnderCursor( *cursor() );
02217     view->unplugActionList( "datatools" );
02218     view->unplugActionList( "datatools_link" );
02219     view->unplugActionList( "spell_result_action" );
02220     view->unplugActionList( "variable_action" );
02221     QPtrList<KAction> &variableList = view->variableActionList();
02222     variableList.clear();
02223     actionList.clear();
02224 
02225     view->kPresenterDoc()->getVariableCollection()->setVariableSelected(variable());
02226     KoVariable* var = variable();
02227     if ( var )
02228     {
02229         variableList = view->kPresenterDoc()->getVariableCollection()->popupActionList();
02230     }
02231 
02232     if( variableList.count()>0)
02233     {
02234         view->plugActionList( "variable_action", variableList );
02235         QPopupMenu * popup = view->popupMenu("variable_popup");
02236         Q_ASSERT(popup);
02237         if (popup)
02238             popup->popup( point ); // using exec() here breaks the spellcheck tool (event loop pb)
02239 
02240     }
02241     else
02242     {
02243         bool singleWord= false;
02244         actionList = dataToolActionList(view->kPresenterDoc()->instance(), word, singleWord);
02245         //kdDebug(33001) << "KWView::openPopupMenuInsideFrame plugging actionlist with " << actionList.count() << " actions" << endl;
02246         KoLinkVariable* linkVar = dynamic_cast<KoLinkVariable *>( var );
02247         QPopupMenu * popup;
02248         if ( !linkVar )
02249         {
02250             view->plugActionList( "datatools", actionList );
02251 
02252             KoNoteVariable * noteVar = dynamic_cast<KoNoteVariable *>( var );
02253             KoCustomVariable * customVar = dynamic_cast<KoCustomVariable *>( var );
02254             if( noteVar )
02255                 popup = view->popupMenu("note_popup");
02256             else if( customVar )
02257                 popup = view->popupMenu("custom_var_popup");
02258             else
02259             {
02260                 if ( singleWord )
02261                 {
02262                     QPtrList<KAction> actionCheckSpellList =view->listOfResultOfCheckWord( word );
02263                     if ( actionCheckSpellList.count()>0)
02264                     {
02265                         view->plugActionList( "spell_result_action", actionCheckSpellList );
02266                         popup = view->popupMenu("text_popup_spell_with_result");
02267                     }
02268                     else
02269                         popup = view->popupMenu("text_popup_spell");
02270                 }
02271                 else
02272                     popup = view->popupMenu("text_popup");
02273             }
02274         }
02275         else
02276         {
02277             view->plugActionList( "datatools_link", actionList );
02278             popup = view->popupMenu("text_popup_link");
02279         }
02280         Q_ASSERT(popup);
02281         if (popup)
02282             popup->popup( point ); // using exec() here breaks the spellcheck tool (event loop pb)
02283     }
02284 }
02285 
02286 void KPrTextView::insertCustomVariable( const QString &name)
02287 {
02288     KPrDocument * doc = kpTextObject()->kPresenterDocument();
02289     KoVariable * var = new KoCustomVariable( textDocument(), name, doc->variableFormatCollection()->format( "STRING" ),
02290                                 doc->getVariableCollection());
02291     insertVariable( var );
02292 }
02293 
02294 void KPrTextView::insertLink(const QString &_linkName, const QString & hrefName)
02295 {
02296     KPrDocument * doc = kpTextObject()->kPresenterDocument();
02297     KoVariable * var = new KoLinkVariable( textDocument(), _linkName, hrefName,
02298                                            doc->variableFormatCollection()->format( "STRING" ),
02299                                            doc->getVariableCollection());
02300     insertVariable( var );
02301 }
02302 
02303 void KPrTextView::insertComment(const QString &_comment)
02304 {
02305     KPrDocument * doc = kpTextObject()->kPresenterDocument();
02306 
02307     KoVariable * var = new KoNoteVariable( textDocument(), _comment,
02308                                            doc->variableFormatCollection()->format( "STRING" ),
02309                                            doc->getVariableCollection());
02310     insertVariable( var );
02311 }
02312 
02313 void KPrTextView::insertVariable( int type, int subtype )
02314 {
02315     KPrDocument * doc = kpTextObject()->kPresenterDocument();
02316     bool refreshCustomMenu = false;
02317     KoVariable * var = 0L;
02318     if ( type == VT_CUSTOM )
02319     {
02320         KoCustomVarDialog dia( m_canvas );
02321         if ( dia.exec() == QDialog::Accepted )
02322         {
02323             KoCustomVariable *v = new KoCustomVariable( textDocument(), dia.name(),
02324                                                         doc->variableFormatCollection()->format( "STRING" ),
02325                                                         doc->getVariableCollection() );
02326             v->setValue( dia.value() );
02327             var = v;
02328             refreshCustomMenu = true;
02329         }
02330     }
02331     else
02332         var = doc->getVariableCollection()->createVariable( type, subtype,  doc->variableFormatCollection(), 0L, textDocument(),doc, 0);
02333     if ( var )
02334     {
02335         insertVariable( var, 0, refreshCustomMenu);
02336         doc->recalcPageNum();
02337     }
02338 }
02339 
02340 void KPrTextView::insertVariable( KoVariable *var, KoTextFormat *format, bool refreshCustomMenu )
02341 {
02342     if ( var )
02343     {
02344         CustomItemsMap customItemsMap;
02345         customItemsMap.insert( 0, var );
02346         if (!format)
02347             format = currentFormat();
02348         //kdDebug(33001) << "KPrTextView::insertVariable inserting into paragraph" << endl;
02349 #ifdef DEBUG_FORMATS
02350         kdDebug(33001) << "KPrTextView::insertVariable currentFormat=" << currentFormat() << endl;
02351 #endif
02352         textObject()->insert( cursor(), format, KoTextObject::customItemChar(),
02353                               i18n("Insert Variable"),
02354                               KoTextDocument::Standard,
02355                               KoTextObject::DoNotRemoveSelected,
02356                               customItemsMap );
02357         if ( refreshCustomMenu && var->type() == VT_CUSTOM )
02358             kpTextObject()->kPresenterDocument()->refreshMenuCustomVariable();
02359         kpTextObject()->kPresenterDocument()->repaint( kpTextObject() );
02360     }
02361 }
02362 
02363 bool KPrTextView::canDecode( QMimeSource *e )
02364 {
02365     return kpTextObject()->kPresenterDocument()->isReadWrite() && ( KoTextObject::providesOasis( e ) || QTextDrag::canDecode( e ) );
02366 }
02367 
02368 QDragObject * KPrTextView::newDrag( QWidget * parent )
02369 {
02370     QBuffer buffer;
02371     const QCString mimeType = "application/vnd.oasis.opendocument.text";
02372     KoStore * store = KoStore::createStore( &buffer, KoStore::Write, mimeType );
02373     Q_ASSERT( store );
02374     Q_ASSERT( !store->bad() );
02375 
02376     KoOasisStore oasisStore( store );
02377 
02378     //KoXmlWriter* manifestWriter = oasisStore.manifestWriter( mimeType );
02379     
02380     KPrDocument * doc = kpTextObject()->kPresenterDocument();
02381     
02382     doc->getVariableCollection()->variableSetting()->setModificationDate( QDateTime::currentDateTime() );
02383     doc->recalcVariables( VT_DATE );
02384     doc->recalcVariables( VT_TIME );
02385     doc->recalcVariables( VT_STATISTIC );
02386 
02387     KoGenStyles mainStyles;
02388     KoSavingContext savingContext( mainStyles, 0, false, KoSavingContext::Store );
02389 
02390     doc->styleCollection()->saveOasis( mainStyles, KoGenStyle::STYLE_USER, savingContext );
02391 
02392     KoXmlWriter* bodyWriter = oasisStore.bodyWriter();
02393     bodyWriter->startElement( "office:body" );
02394     bodyWriter->startElement( "office:text" );
02395 
02396     const QString plainText = textDocument()->copySelection( *bodyWriter, savingContext, KoTextDocument::Standard );
02397 
02398     bodyWriter->endElement(); // office:text
02399     bodyWriter->endElement(); // office:body
02400 
02401     KoXmlWriter* contentWriter = oasisStore.contentWriter();
02402     Q_ASSERT( contentWriter );
02403 
02404     //KPrDocument * doc = kpTextObject()->kPresenterDocument();
02405     doc->writeAutomaticStyles( *contentWriter, mainStyles, savingContext, false );
02406 
02407     oasisStore.closeContentWriter();
02408 
02409     if ( !store->open( "styles.xml" ) )
02410         return false;
02411     //manifestWriter->addManifestEntry( "styles.xml", "text/xml" );
02412     doc->saveOasisDocumentStyles( store, mainStyles, 0, savingContext, KPrDocument::SaveSelected /* simply means not SaveAll */ );
02413     if ( !store->close() ) // done with styles.xml
02414         return false;
02415 
02416     delete store;
02417 
02418     KMultipleDrag* multiDrag = new KMultipleDrag( parent );
02419     if (  !plainText.isEmpty() )
02420         multiDrag->addDragObject( new QTextDrag( plainText, 0 ) );
02421     KoStoreDrag* storeDrag = new KoStoreDrag( mimeType, 0 );
02422     kdDebug() << k_funcinfo << "setting zip data: " << buffer.buffer().size() << " bytes." << endl;
02423     storeDrag->setEncodedData( buffer.buffer() );
02424     multiDrag->addDragObject( storeDrag );
02425     return multiDrag;
02426 }
02427 
02428 void KPrTextView::dragEnterEvent( QDragEnterEvent *e )
02429 {
02430     if ( !canDecode( e ) )
02431     {
02432         e->ignore();
02433         return;
02434     }
02435     e->acceptAction();
02436 }
02437 
02438 void KPrTextView::dragMoveEvent( QDragMoveEvent *e, const QPoint & )
02439 {
02440     if ( !canDecode( e ) )
02441     {
02442         e->ignore();
02443         return;
02444     }
02445     QPoint iPoint = viewToInternal( e->pos() );
02446 
02447     textObject()->emitHideCursor();
02448     placeCursor( iPoint );
02449     textObject()->emitShowCursor();
02450     e->acceptAction(); // here or out of the if ?
02451 }
02452 
02453 void KPrTextView::dropEvent( QDropEvent * e )
02454 {
02455     if ( canDecode( e ) )
02456     {
02457         KPrDocument *doc = kpTextObject()->kPresenterDocument();
02458         e->acceptAction();
02459         KoTextCursor dropCursor( textDocument() );
02460         QPoint dropPoint = viewToInternal( e->pos() );
02461         KMacroCommand *macroCmd=new KMacroCommand(i18n("Paste Text"));
02462         bool addMacroCmd = false;
02463         dropCursor.place( dropPoint, textDocument()->firstParag() );
02464         kdDebug(33001) << "KPrTextView::dropEvent dropCursor at parag=" << dropCursor.parag()->paragId() << " index=" << dropCursor.index() << endl;
02465 
02466         if ( ( e->source() == m_canvas ) &&
02467              e->action() == QDropEvent::Move &&
02468              // this is the indicator that the source and dest text objects are the same
02469              textDocument()->hasSelection( KoTextDocument::Standard )
02470             ) {
02471             //kdDebug(33001)<<"decodeFrameSetNumber( QMimeSource *e ) :"<<numberFrameSet<<endl;
02472             KCommand *cmd = textView()->prepareDropMove( dropCursor );
02473             if(cmd)
02474             {
02475                 kpTextObject()->layout();
02476                 macroCmd->addCommand(cmd);
02477                 addMacroCmd = true;
02478             }
02479             else
02480             {
02481                 delete macroCmd;
02482                 return;
02483             }
02484         }
02485         else
02486         {   // drop coming from outside -> forget about current selection
02487             textDocument()->removeSelection( KoTextDocument::Standard );
02488             textObject()->selectionChangedNotify();
02489         }
02490         QCString returnedTypeMime = KoTextObject::providesOasis( e );
02491         if ( !returnedTypeMime.isEmpty() )
02492         {
02493             QByteArray arr = e->encodedData( returnedTypeMime );
02494             if ( arr.size() )
02495             {
02496                 KCommand *cmd = kpTextObject()->pasteOasis( cursor(), arr, false );
02497                 if ( cmd )
02498                 {
02499                     macroCmd->addCommand(cmd);
02500                     addMacroCmd = true;
02501                 }
02502             }
02503         }
02504         else
02505         {
02506             QString text;
02507             if ( QTextDrag::decode( e, text ) )
02508                 textObject()->pasteText( cursor(), text, currentFormat(),
02509                                          false /*do not remove selected text*/ );
02510         }
02511         if ( addMacroCmd )
02512             doc->addCommand(macroCmd);
02513         else
02514             delete macroCmd;
02515     }
02516 }
02517 
02518 void KPrTextObject::saveParagraph( QDomDocument& doc,KoTextParag * parag,QDomElement &parentElem,
02519                                   int from /* default 0 */,
02520                                   int to /* default length()-2 */ )
02521 {
02522     if(!parag)
02523         return;
02524     QDomElement paragraph=doc.createElement(tagP);
02525     int tmpAlign=0;
02526     switch(parag->resolveAlignment())
02527     {
02528     case Qt::AlignLeft:
02529         tmpAlign=1;
02530         break;
02531     case Qt::AlignRight:
02532         tmpAlign=2;
02533         break;
02534     case Qt::AlignHCenter:
02535         tmpAlign=4;
02536         break;
02537     case Qt::AlignJustify:
02538         tmpAlign=8;
02539     }
02540     if(tmpAlign!=1)
02541         paragraph.setAttribute(attrAlign, tmpAlign);
02542 
02543     saveParagLayout( parag->paragLayout(), paragraph );
02544     KoTextFormat *lastFormat = 0;
02545     QString tmpText;
02546     for ( int i = from; i <= to; ++i ) {
02547         KoTextStringChar &c = parag->string()->at(i);
02548         if ( c.isCustom() )
02549         {
02550             QDomElement variable = doc.createElement("CUSTOM");
02551             variable.setAttribute("pos", (i-from));
02552             saveFormat( variable, c.format() );
02553             paragraph.appendChild( variable );
02554             static_cast<KoTextCustomItem *>( c.customItem() )->save(variable );
02555         }
02556         if ( !lastFormat || c.format()->key() != lastFormat->key() ) {
02557             if ( lastFormat )
02558                 paragraph.appendChild(saveHelper(tmpText, lastFormat, doc));
02559             lastFormat = static_cast<KoTextFormat*> (c.format());
02560             tmpText=QString::null;
02561         }
02562         tmpText+=QString(c.c);
02563     }
02564     if ( lastFormat )
02565         paragraph.appendChild(saveHelper(tmpText, lastFormat, doc));
02566     else
02567         paragraph.appendChild(saveHelper(tmpText, parag->string()->at(0).format(), doc));
02568 
02569     parentElem.appendChild(paragraph);
02570 }
02571 
02572 KoPen KPrTextObject::defaultPen() const
02573 {
02574     return KoPen( Qt::black, 1.0, Qt::NoPen );
02575 }
02576 
02577 QPoint KPrTextObject::viewToInternal( const QPoint & pos, KPrCanvas* canvas ) const
02578 {
02579     KoTextZoomHandler* zh = kPresenterDocument()->zoomHandler();
02580     QPoint iPoint = pos - zh->zoomPoint(
02581         getOrig() + KoPoint( bLeft(),
02582                              bTop() + alignmentValue()) );
02583     iPoint = zh->pixelToLayoutUnit(
02584         QPoint( iPoint.x() + canvas->diffx(), iPoint.y() + canvas->diffy() ) );
02585     return iPoint;
02586 }
KDE Home | KDE Accessibility Home | Description of Access Keys