kformula/flake

FormulaCursor.cpp

Go to the documentation of this file.
00001 /* This file is part of the KDE project
00002    Copyright (C) 2001 Andrea Rizzi <rizzi@kde.org>
00003                       Ulrich Kuettler <ulrich.kuettler@mailbox.tu-dresden.de>
00004                  2006 Martin Pfeiffer <hubipete@gmx.net>
00005                  2009 Jeremias Epperlein <jeeree@web.de>
00006 
00007    This library is free software; you can redistribute it and/or
00008    modify it under the terms of the GNU Library General Public
00009    License as published by the Free Software Foundation; either
00010    version 2 of the License, or (at your option) any later version.
00011 
00012    This library is distributed in the hope that it will be useful,
00013    but WITHOUT ANY WARRANTY; without even the implied warranty of
00014    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00015    Library General Public License for more details.
00016 
00017    You should have received a copy of the GNU Library General Public License
00018    along with this library; see the file COPYING.LIB.  If not, write to
00019    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00020    Boston, MA 02110-1301, USA.
00021 */
00022 
00023 #include "FormulaCursor.h"
00024 #include "BasicElement.h"
00025 #include "RowElement.h"
00026 #include "FixedElement.h"
00027 #include "NumberElement.h"
00028 #include "ElementFactory.h"
00029 #include "OperatorElement.h"
00030 #include "IdentifierElement.h"
00031 #include "ElementFactory.h"
00032 #include "FormulaCommand.h"
00033 #include <QPainter>
00034 #include <QPen>
00035 #include <algorithm>
00036 
00037 #include <kdebug.h>
00038 #include <QUndoCommand>
00039 #include <KoOdfLoadingContext.h>
00040 #include <KoOdfStylesReader.h>
00041 
00042 FormulaCursor::FormulaCursor(BasicElement* element, bool selecting, int position, int mark) {
00043     m_currentElement=element;
00044     m_selecting=selecting;
00045     m_position=position;
00046     m_mark=mark;
00047 }
00048 
00049 FormulaCursor::FormulaCursor ( BasicElement* element, int position )
00050 {
00051     m_currentElement=element;
00052     m_position=position;
00053     m_mark=0;
00054     m_selecting=false;
00055 }
00056 
00057 
00058 FormulaCursor::FormulaCursor()
00059 {
00060     FormulaCursor(0,0);
00061 }
00062 
00063 FormulaCursor::FormulaCursor (const FormulaCursor& other )
00064 {
00065     m_currentElement=other.currentElement();
00066     m_position=other.position();
00067     m_mark=other.mark();
00068     m_selecting=other.isSelecting();
00069 }
00070 
00071 
00072 void FormulaCursor::paint( QPainter& painter ) const
00073 {
00074     kDebug() << "Drawing cursor with selecting: "<< isSelecting() << " from "
00075     << mark()<<" to " << position() << " in "<<ElementFactory::elementName(m_currentElement->elementType());
00076     if( !m_currentElement )
00077         return;
00078     painter.save();
00079     QPointF origin=m_currentElement->absoluteBoundingRect().topLeft();
00080     double baseline=m_currentElement->baseLine();
00081     QPen pen;
00082     pen.setWidthF( 0.5 );
00083     pen.setColor(Qt::black);
00084     painter.setPen( pen );
00085     painter.drawLine(m_currentElement->cursorLine( m_position ));
00086     pen.setWidth( 0.1);
00087     pen.setColor(Qt::blue);
00088     pen.setStyle(Qt::DashLine);
00089     painter.setPen( pen );
00090     painter.drawLine( origin+QPointF(0.0,baseline),origin+QPointF(m_currentElement->width(), baseline) );
00091     pen.setStyle(Qt::DotLine);
00092     //Only here for debug purpose for now
00093     switch(m_currentElement->elementType()) {
00094     case Number:
00095         pen.setColor(Qt::red);
00096         break;
00097     case Identifier:
00098         pen.setColor(Qt::darkRed);
00099         break;
00100     case Row:
00101         pen.setColor(Qt::yellow);
00102         break;
00103     case Fraction:
00104         pen.setColor(Qt::blue);
00105         break;
00106     case Table:
00107         pen.setColor(Qt::darkGreen);
00108         break;
00109     case TableRow:
00110         pen.setColor(Qt::green);
00111         break;
00112     default:
00113         pen.setColor(Qt::darkGray);
00114         break;
00115     }
00116     painter.setPen(pen);
00117     painter.drawRect( m_currentElement->absoluteBoundingRect() );
00118     //draw the selection rectangle
00119     if ( m_selecting ) {
00120         QBrush brush;
00121         QColor color(Qt::blue);
00122         color.setAlpha(128);
00123         brush.setColor(color);
00124         brush.setStyle(Qt::SolidPattern);
00125         painter.setBrush(brush);
00126         painter.setPen(Qt::NoPen);
00127         int p1=position()<mark()? position() : mark();
00128         int p2=position()<mark()? mark() : position() ;
00129         painter.drawPath(m_currentElement->selectionRegion(p1,p2));
00130     }
00131     painter.restore();
00132 }
00133 
00134 void FormulaCursor::selectElement(BasicElement* element)
00135 {
00136     m_selecting=true;
00137     m_currentElement=element;
00138     m_mark=0;
00139     m_position=m_currentElement->endPosition();
00140 }
00141 
00142 void FormulaCursor::move( CursorDirection direction )
00143 {
00144     FormulaCursor oldcursor(*this);
00145     m_direction = direction;
00146     if (performMovement(oldcursor)==false) {
00147         (*this)=oldcursor;
00148     }
00149     m_direction=NoDirection;
00150 }
00151 
00152 bool FormulaCursor::moveCloseTo(BasicElement* element, FormulaCursor& cursor)
00153 {
00154     if (element->setCursorTo(*this,cursor.getCursorPosition()-element->absoluteBoundingRect().topLeft())) {
00155         return true;
00156     } else {
00157         return false;
00158     }
00159 }
00160 
00161 QPointF FormulaCursor::getCursorPosition() 
00162 {
00163     return ( m_currentElement->cursorLine(m_position).p1()
00164            + m_currentElement->cursorLine(m_position).p2())/2.;
00165 }
00166 
00167 void FormulaCursor::moveTo ( const FormulaCursor& pos )
00168 {
00169     m_currentElement=pos.currentElement();
00170     m_position=pos.position();
00171     m_selecting=pos.isSelecting();
00172     m_mark=pos.mark();
00173 }
00174 
00175 
00176 void FormulaCursor::moveTo ( BasicElement* element )
00177 {
00178     moveTo(element,0);
00179     if (direction()==MoveLeft) {
00180         moveEnd();
00181     }
00182 }
00183 
00184 
00185 void FormulaCursor::moveTo ( BasicElement* element, int position )
00186 {
00187     moveTo(FormulaCursor(element,position));
00188 }
00189 
00190 
00191 void FormulaCursor::setCursorTo( const QPointF& point )
00192 {
00193     if (m_selecting) {
00194         while (!m_currentElement->absoluteBoundingRect().contains(point)) {
00195             if ( m_currentElement->parentElement() ) {
00196                 m_position=0;
00197                 if (point.x()<m_currentElement->cursorLine(m_mark).p1().x()) {
00198                     //the point is left of the old selection start, so we move the selection 
00199                     //start after the old current element
00200                     m_mark=m_currentElement->parentElement()->positionOfChild(m_currentElement)+1;
00201                 } else {
00202                     m_mark=m_currentElement->parentElement()->positionOfChild(m_currentElement);
00203                 }
00204                 m_currentElement=m_currentElement->parentElement();
00205             } else {
00206                 return;
00207             }
00208         }
00209         while (!m_currentElement->setCursorTo(*this,point-m_currentElement->absoluteBoundingRect().topLeft())) {
00210             if ( m_currentElement->parentElement() ) {
00211                 m_mark=m_currentElement->parentElement()->positionOfChild(m_currentElement);
00212                 m_position=0;
00213                 if (point.x()<m_currentElement->cursorLine(m_mark).p1().x()) {
00214                     //the point is left of the old selection start, so we move the selection 
00215                     //start after the old current element
00216                     m_mark++;
00217                 }
00218                 m_currentElement=m_currentElement->parentElement();
00219             } else {
00220                     return;
00221             }
00222         }
00223     } else {
00224         BasicElement* formulaElement = m_currentElement;
00225         while( formulaElement->parentElement() != 0 ) {
00226             formulaElement = formulaElement->parentElement();
00227         }
00228         formulaElement->setCursorTo(*this,point);
00229     }
00230 }
00231 
00232 int FormulaCursor::mark() const 
00233 {
00234     return m_mark;
00235 }
00236 
00237 void FormulaCursor::moveHome()
00238 {
00239     m_position = 0;
00240 }
00241 
00242 void FormulaCursor::moveEnd()
00243 {
00244     m_position=m_currentElement->endPosition();
00245 }
00246 
00247 bool FormulaCursor::isHome() const
00248 {
00249     return m_position == 0;
00250 }
00251 
00252 bool FormulaCursor::isEnd() const
00253 {
00254     return m_position == m_currentElement->endPosition();
00255 }
00256 
00257 bool FormulaCursor::insideToken() const
00258 {
00259     if( m_currentElement->elementType() == Number ||
00260         m_currentElement->elementType() == Operator ||
00261         m_currentElement->elementType() == Identifier ) {
00262         return true;
00263     }
00264     return false;
00265 }
00266 
00267 bool FormulaCursor::insideInferredRow() const
00268 {
00269     return m_currentElement->isInferredRow();
00270 }
00271 
00272 bool FormulaCursor::insideFixedElement() const
00273 {
00274     if (m_currentElement->elementType() == Fraction ||
00275         m_currentElement->elementType() == Root ||
00276         m_currentElement->elementType() == SubScript ||
00277         m_currentElement->elementType() == SupScript ||
00278         m_currentElement->elementType() == SubScript ||
00279         m_currentElement->elementType() == SubSupScript ) {
00280         return true;
00281     }
00282     return false;
00283 }
00284  
00285 
00286 
00287 BasicElement* FormulaCursor::currentElement() const
00288 {
00289     return m_currentElement;
00290 }
00291 
00292 int FormulaCursor::position() const
00293 {
00294     return m_position;
00295 }
00296 
00297 void FormulaCursor::setCurrentElement(BasicElement* element) {
00298     m_currentElement=element;
00299 }
00300 
00301 void FormulaCursor::setPosition(int position) {
00302     m_position=position;
00303 }
00304 
00305 CursorDirection FormulaCursor::direction() const
00306 {
00307     return m_direction;
00308 }
00309 
00310 bool FormulaCursor::isSelecting() const
00311 {
00312     return m_selecting;
00313 }
00314 
00315 void FormulaCursor::setSelecting( bool selecting )
00316 {
00317     if (selecting) {
00318         if (!m_selecting) {
00319             //we start a new selection
00320             m_selecting = selecting;
00321             m_mark=m_position;
00322         }
00323     } else {
00324         m_selecting = selecting;
00325         m_mark=0;
00326     }
00327 }
00328 
00329 void FormulaCursor::setMark(int position) {
00330     m_mark=position;
00331 }
00332 
00333 QPair< int,int > FormulaCursor::selection() const
00334 {
00335     if (m_mark<m_position) {
00336         return QPair<int,int>(m_mark,m_position);
00337     } else {
00338         return QPair<int,int>(m_position,m_mark);
00339     }
00340 }
00341 
00342 
00343 bool FormulaCursor::hasSelection() const
00344 {
00345     return (m_selecting && m_mark!=m_position);
00346 }
00347 
00348 
00349 bool FormulaCursor::isAccepted() const
00350 {
00351     if (mark()<0 || mark()>m_currentElement->endPosition() ||
00352         position()<0 || position()>m_currentElement->endPosition()) {
00353         return false;
00354     }
00355     return m_currentElement->acceptCursor(*this);
00356 }
00357 
00358 bool FormulaCursor::performMovement ( FormulaCursor& oldcursor )
00359 {
00360     //handle selecting and not selecting case separately, which makes more clear
00361     if (isSelecting()) {
00362         while ( m_currentElement ) {
00363             if ( m_currentElement->moveCursor( *this, oldcursor ) ) {
00364                 if (isAccepted()) {
00365                     return true;
00366                 }
00367             } else {
00368                 if ( m_currentElement->parentElement() ) {
00369                     bool ltr=m_mark<=m_position;
00370                     //update the starting point of the selection
00371                     m_mark=m_currentElement->parentElement()->positionOfChild(m_currentElement);
00372                     //move the cursor to the parent and place it before the old element
00373                     m_position=m_currentElement->parentElement()->positionOfChild(m_currentElement);
00374                     m_currentElement=m_currentElement->parentElement();
00375                     if (ltr) {
00376                         m_position++; //place the cursor behind
00377                     } else {
00378                         m_mark++; //place the selection beginning behind 
00379                     }
00380                     if (isAccepted()) {
00381                         return true;
00382                     }
00383                 } else {
00384                     //we arrived at the toplevel element
00385                     return false;
00386                 }
00387             }
00388         }
00389     } else {
00390         while ( m_currentElement ) {
00391             if ( m_currentElement->moveCursor( *this, oldcursor ) ) {
00392                 if (isAccepted()) {
00393                     return true;
00394                 }
00395             } else {
00396                 if ( m_currentElement->parentElement() ) {
00397                     //move the cursor to the parent and place it before the old element
00398                     m_position=m_currentElement->parentElement()->positionOfChild(m_currentElement);
00399                     m_currentElement=m_currentElement->parentElement();
00400                     if (m_direction==MoveRight || m_direction==MoveDown) {
00401                         m_position++; //place the cursor behin
00402                     }
00403                     if (m_direction==MoveRight || m_direction==MoveLeft) {
00404                         if (isAccepted()) {
00405                             return true;
00406                         }
00407                     }   
00408                 } else {
00409                     //We arrived at the top level element
00410                     return false;
00411                 }
00412             }
00413         }
00414     }
00415     return false;
00416 }
00417 
00418 FormulaCursor& FormulaCursor::operator+= ( int step )
00419 {
00420     m_position+=step;
00421     return *this;
00422 }
00423 
00424 int FormulaCursor::offset ( )
00425 {
00426     if (m_direction==MoveDown || m_direction==MoveRight) {
00427         return -1;
00428     } else if (m_direction==MoveUp || m_direction==MoveLeft) {
00429         return 1;
00430     }
00431     return 0;
00432 }
00433