/* This file is part of the KDE project
   Copyright (C) 2001 Andrea Rizzi <rizzi@kde.org>
	              Ulrich Kuettler <ulrich.kuettler@mailbox.tu-dresden.de>

   This library is free software; you can redistribute it and/or
   modify it under the terms of the GNU Library General Public
   License as published by the Free Software Foundation; either
   version 2 of the License, or (at your option) any later version.

   This library is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   Library General Public License for more details.

   You should have received a copy of the GNU Library General Public License
   along with this library; see the file COPYING.LIB.  If not, write to
   the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 * Boston, MA 02110-1301, USA.
*/

#include <tqptrlist.h>
#include <tqstringlist.h>

#include <kdebug.h>
#include <tdeglobal.h>
#include <kiconloader.h>
#include <tdelocale.h>
#include <ksimpleconfig.h>
#include <kstandarddirs.h>

#include <KoDocument.h>

#include "contextstyle.h"
#include "creationstrategy.h"
#include "oasiscreationstrategy.h"
#include "kformulacontainer.h"
#include "kformuladocument.h"
#include "sequenceelement.h"
#include "symboltable.h"
#include "symbolaction.h"

KFORMULA_NAMESPACE_BEGIN

static const int CURRENT_SYNTAX_VERSION = 1;
// Make sure an appropriate DTD is available in www/koffice/DTD if changing this value
static const char * CURRENT_DTD_VERSION = "1.3";

int FormulaList::compareItems( TQPtrCollection::Item a, TQPtrCollection::Item b )
{
    double ya = static_cast<Container*>( a )->getDocumentY();
    double yb = static_cast<Container*>( b )->getDocumentY();
    if ( fabs( ya-yb ) < 1e-4 ) {
        double xa = static_cast<Container*>( a )->getDocumentX();
        double xb = static_cast<Container*>( b )->getDocumentX();
        if ( xa < xb ) return -1;
        if ( xa > xb ) return 1;
        return 0;
    }
    if ( ya < yb ) return -1;
    return 1;
}


Document::Document( TQObject *parent, const char *name,
                    const TQStringList &/*args*/ )
    : TQObject( parent, name ), m_wrapper( 0 ), m_formula( 0 ), creationStrategy( 0 )
{
    m_contextStyle = new ContextStyle;
    setCreationStrategy( "Oasis" );
    formulae.setAutoDelete( false );
}


Document::~Document()
{
    // Destroy remaining formulae. We do it backward because
    // the formulae remove themselves from this document upon
    // destruction.
    int count = formulae.count();
    for ( int i=count-1; i>=0; --i ) {
        delete formulae.at( i );
    }
    delete m_contextStyle;
}


bool Document::hasFormula()
{
    return ( m_formula != 0 ) && ( m_formula->activeCursor() != 0 );
}


Container* Document::createFormula( int pos, bool registerMe )
{
    Container* formula = new Container( this, pos, registerMe );
    formula->initialize();
    return formula;
}


TQPtrListIterator<Container> Document::formulas()
{
    return TQPtrListIterator<Container>( formulae );
}


int Document::formulaPos( Container* formula )
{
    return formulae.find( formula );
}


Container* Document::formulaAt( uint pos )
{
    return formulae.at( pos );
}


int Document::formulaCount()
{
    return formulae.count();
}


bool Document::loadXML( const TQDomDocument& doc )
{
    setCreationStrategy( "Ordinary" );
        
    //clear();
    TQDomElement root = doc.documentElement();

    // backward compatibility
    if ( root.tagName() == "FORMULA" ) {
        Container* formula = newFormula( 0 );
        return formula->load( root );
    }

    TQDomNode node = root.firstChild();
    if ( node.isElement() ) {
        TQDomElement element = node.toElement();
        if ( element.tagName() == "FORMULASETTINGS" ) {
            if ( !loadDocumentPart( element ) ) {
                return false;
            }
        }
        node = node.nextSibling();
    }
    uint number = 0;
    while ( !node.isNull() ) {
        if ( node.isElement() ) {
            TQDomElement element = node.toElement();
            Container* formula = newFormula( number );
            if ( !formula->load( element ) ) {
                return false;
            }
            number += 1;
        }
        node = node.nextSibling();
    }
    return formulae.count() > 0;
}

bool Document::loadOasis( const TQDomDocument& doc )
{
    // ### TODO: not finished!
    setCreationStrategy( "Oasis" );
    KFormula::Container* formula = newFormula( 0 );
    return formula->loadMathML( doc, true );
}

bool Document::loadDocumentPart( TQDomElement /*node*/ )
{
    return true;
}

TQDomDocument Document::saveXML()
{
    TQDomDocument doc = createDomDocument();
    TQDomElement root = doc.documentElement();
    root.appendChild( saveDocumentPart( doc ) );
    uint count = formulae.count();
    for ( uint i=0; i<count; ++i ) {
        formulae.at( i )->save( root );
    }
    return doc;
}


TQDomElement Document::saveDocumentPart( TQDomDocument& doc )
{
    TQDomElement settings = doc.createElement( "FORMULASETTINGS" );
    return settings;
}


TQDomDocument Document::createDomDocument()
{
    return KoDocument::createDomDocument( "kformula", "KFORMULA",
                                          CURRENT_DTD_VERSION );
}

/**
 * Create a MathML Dom Document, deprecates KFO Dom Document for internal layout
 * TODO: Shouldn't this go to KoDocument ?
 */
TQDomDocument Document::createMathMLDomDocument()
{
    TQDomDocumentType dt = 
        TQDomImplementation().createDocumentType( "math",
                                                 "-//W3C//DTD MathML 2.0//EN",
                                                 "http://www.w3.org/TR/MathML2/dtd/mathml2.dtd");
    TQDomDocument doc( dt );
    doc.insertBefore( doc.createProcessingInstruction( "xml", 
                                                       "version=\"1.0\" encoding=\"UTF-8\"" ),
                      doc.documentElement() );
    return doc;
}

/**
 * Set formula creation strategy: old KFormula or MathML/ODF.
 * This tells which tags are valid during formula constructions
 *
 * @param strategy -- "Ordinary" for old Kformula, "Oasis" for MathML/ODF
 */
void Document::setCreationStrategy( TQString strategy )
{
    if ( !creationStrategy || creationStrategy->type() != strategy ) {
        delete creationStrategy;
        if ( strategy == "Ordinary" )
            creationStrategy = new OrdinaryCreationStrategy;
        else
            creationStrategy = new OasisCreationStrategy;
        SequenceElement::setCreationStrategy( creationStrategy );
    }
}

void Document::registerFormula( Container* f, int pos )
{
    if ( ( pos > -1 ) &&
         ( static_cast<uint>( pos ) < formulae.count() ) ) {
        formulae.insert( pos, f );
        //emit sigInsertFormula( f, pos );
    }
    else {
        formulae.append( f );
        //emit sigInsertFormula( f, formulae.count()-1 );
    }
}

void Document::unregisterFormula( Container* f )
{
    if ( m_formula == f ) {
        m_formula = 0;
    }
    formulae.removeRef( f );
}

void Document::activate(Container* f)
{
    m_formula = f;
}


void Document::sortFormulaList()
{
    formulae.sort();
}


Container* Document::newFormula( uint number )
{
    if ( number < formulae.count() ) {
        return formulae.at( number );
    }
    return createFormula();
}


double Document::getXResolution() const
{
    return m_contextStyle->zoomedResolutionX();
}
double Document::getYResolution() const
{
    return m_contextStyle->zoomedResolutionY();
}

const SymbolTable& Document::getSymbolTable() const
{
    return m_contextStyle->symbolTable();
}

ContextStyle& Document::getContextStyle( bool edit )
{
    m_contextStyle->setEdit( edit );
    return *m_contextStyle;
}

void Document::setZoomAndResolution( int zoom, int dpiX, int dpiY )
{
    m_contextStyle->setZoomAndResolution( zoom, dpiX, dpiY );
}

void Document::newZoomAndResolution( bool updateViews, bool /*forPrint*/ )
{
    if ( updateViews ) {
        recalc();
    }
}

void Document::setZoomAndResolution( int zoom,
                                     double zoomX, double zoomY,
                                     bool updateViews, bool forPrint )
{
    if ( getContextStyle( !forPrint ).setZoomAndResolution( zoom, zoomX, zoomY, updateViews, forPrint ) && updateViews ) {
        recalc();
    }
}


SymbolType Document::leftBracketChar()
{
    return m_wrapper->leftBracketChar();
}

SymbolType Document::rightBracketChar()
{
    return m_wrapper->rightBracketChar();
}


void Document::setEnabled( bool enabled )
{
    m_wrapper->setEnabled( enabled );
}


KoCommandHistory* Document::getHistory() const
{
    return m_wrapper->getHistory();
}


void Document::recalc()
{
    for ( Container* f = formulae.first();
          f != 0;
          f=formulae.next() ) {
        f->recalc();
    }
}


void Document::updateConfig()
{
    m_wrapper->updateConfig();
    recalc();
}


void Document::introduceWrapper( DocumentWrapper* wrapper, bool init )
{
    m_wrapper = wrapper;
    m_contextStyle->readConfig( wrapper->config(), init );
    m_contextStyle->init( init );
}


//////////////////////////////////////////////////////////////////////////////

DocumentWrapper::DocumentWrapper( TDEConfig* config,
                                  TDEActionCollection* collection,
                                  KoCommandHistory* history )
    : m_document( 0 ),
      m_leftBracketChar( LeftRoundBracket ),
      m_rightBracketChar( RightRoundBracket ),
      m_config( config ),
      m_hasActions( collection != 0 )
{
    if ( m_hasActions ) {
        createActions( collection );
        enableMatrixActions( false );
    }
    setCommandStack( history );
}


DocumentWrapper::~DocumentWrapper()
{
    delete m_document;
    if ( m_ownHistory ) {
        delete m_history;
    }

    if ( m_hasActions )
    {
        m_config->setGroup("General");
        m_config->writeEntry("syntaxHighlighting", m_syntaxHighlightingAction->isChecked() );
    }
}


void DocumentWrapper::document( Document* document, bool init )
{
    m_document = document;
    m_document->introduceWrapper( this, init );
    initSymbolNamesAction();
    m_config->setGroup("General");
    if ( m_hasActions )
    {
        m_syntaxHighlightingAction->setChecked( m_config->readBoolEntry("syntaxHighlighting", true ) );
        if ( !m_syntaxHighlightingAction->isChecked() )
            toggleSyntaxHighlighting();
    }
    else if ( m_config->readBoolEntry("syntaxHighlighting", true ) )
    {
        m_document->m_contextStyle->setSyntaxHighlighting( true );
        // Only to notify all views. We don't expect to get new values.
        m_document->recalc();
    }
}


void DocumentWrapper::setCommandStack( KoCommandHistory* history )
{
    if ( history == 0 ) {
        m_history = new KoCommandHistory;
        m_ownHistory = true;
    }
    else {
        m_history = history;
        m_ownHistory = false;
    }
}


void DocumentWrapper::createActions( TDEActionCollection* collection )
{
    TDEGlobal::dirs()->addResourceType( "toolbar",
                                      TDEStandardDirs::kde_default("data") +
                                      "kformula/pics/" );

    m_addNegThinSpaceAction = new TDEAction( i18n( "Add Negative Thin Space" ),
                                    0,
                                    this, TQ_SLOT( addNegThinSpace() ),
                                    collection, "formula_addnegthinspace") ;
    m_addThinSpaceAction = new TDEAction( i18n( "Add Thin Space" ),
                                    0,
                                    this, TQ_SLOT( addThinSpace() ),
                                    collection, "formula_addthinspace") ;
    m_addMediumSpaceAction = new TDEAction( i18n( "Add Medium Space" ),
                                    0,
                                    this, TQ_SLOT( addMediumSpace() ),
                                    collection, "formula_addmediumspace" );
    m_addThickSpaceAction = new TDEAction( i18n( "Add Thick Space" ),
                                    0,
                                    this, TQ_SLOT( addThickSpace() ),
                                    collection, "formula_addthickspace" );
    m_addQuadSpaceAction = new TDEAction( i18n( "Add Quad Space" ),
                                    0,
                                    this, TQ_SLOT( addQuadSpace() ),
                                    collection, "formula_addquadspace" );

    m_addIntegralAction = new TDEAction(i18n("Add Integral"),
                                    "int",
                                    0,
                                    this, TQ_SLOT(addIntegral()),
                                    collection, "formula_addintegral");
    m_addSumAction      = new TDEAction(i18n("Add Sum"),
                                    "sum",
                                    0,
                                    this, TQ_SLOT(addSum()),
                                    collection, "formula_addsum");
    m_addProductAction  = new TDEAction(i18n("Add Product"),
                                    "prod",
                                    0,
                                    this, TQ_SLOT(addProduct()),
                                    collection, "formula_addproduct");
    m_addRootAction     = new TDEAction(i18n("Add Root"),
                                    "sqrt",
                                    0,
                                    this, TQ_SLOT(addRoot()),
                                    collection, "formula_addroot");
    m_addFractionAction = new TDEAction(i18n("Add Fraction"),
                                    "frac",
                                    0,
                                    this, TQ_SLOT(addFraction()),
                                    collection, "formula_addfrac");
    m_addBracketAction  = new TDEAction(i18n("Add Bracket"),
                                    "paren",
                                    0,
                                    this, TQ_SLOT(addDefaultBracket()),
                                    collection,"formula_addbra");
    m_addSBracketAction = new TDEAction(i18n("Add Square Bracket"),
                                    "brackets",
                                    0,
                                    this, TQ_SLOT(addSquareBracket()),
                                    collection,"formula_addsqrbra");
    m_addCBracketAction = new TDEAction(i18n("Add Curly Bracket"),
                                    "math_brace",
                                    0,
                                    this, TQ_SLOT(addCurlyBracket()),
                                    collection,"formula_addcurbra");
    m_addAbsAction      = new TDEAction(i18n("Add Abs"),
                                    "abs",
                                    0,
                                    this, TQ_SLOT(addLineBracket()),
                                    collection,"formula_addabsbra");

    m_addMatrixAction   = new TDEAction(i18n("Add Matrix..."),
                                    "matrix",
                                    0,
                                    this, TQ_SLOT(addMatrix()),
                                    collection, "formula_addmatrix");

    m_addOneByTwoMatrixAction   = new TDEAction(i18n("Add 1x2 Matrix"),
                                    "onetwomatrix",
                                    0,
                                    this, TQ_SLOT(addOneByTwoMatrix()),
                                    collection, "formula_add_one_by_two_matrix");


    m_addUpperLeftAction  = new TDEAction(i18n("Add Upper Left Index"),
                                      "lsup",
                                      0,
                                      this, TQ_SLOT(addUpperLeftIndex()),
                                      collection, "formula_addupperleft");
    m_addLowerLeftAction  = new TDEAction(i18n("Add Lower Left Index"),
                                      "lsub",
                                      0,
                                      this, TQ_SLOT(addLowerLeftIndex()),
                                      collection, "formula_addlowerleft");
    m_addUpperRightAction = new TDEAction(i18n("Add Upper Right Index"),
                                      "rsup",
                                      0,
                                      this, TQ_SLOT(addUpperRightIndex()),
                                      collection, "formula_addupperright");
    m_addLowerRightAction = new TDEAction(i18n("Add Lower Right Index"),
                                      "rsub",
                                      0,
                                      this, TQ_SLOT(addLowerRightIndex()),
                                      collection, "formula_addlowerright");

    m_addGenericUpperAction = new TDEAction(i18n("Add Upper Index"),
                                      "gsup",
                                              /*CTRL + Key_U*/0,
                                      this, TQ_SLOT(addGenericUpperIndex()),
                                      collection, "formula_addupperindex");
    m_addGenericLowerAction = new TDEAction(i18n("Add Lower Index"),
                                      "gsub",
                                      0,
                                      this, TQ_SLOT(addGenericLowerIndex()),
                                      collection, "formula_addlowerindex");

    m_addOverlineAction = new TDEAction(i18n("Add Overline"),
                                          "over",
                                          0,
                                          this, TQ_SLOT(addOverline()),
                                          collection, "formula_addoverline");
    m_addUnderlineAction = new TDEAction(i18n("Add Underline"),
                                           "under",
                                           0,
                                           this, TQ_SLOT(addUnderline()),
                                           collection, "formula_addunderline");

    m_addMultilineAction = new TDEAction(i18n("Add Multiline"),
                                           "multiline",
                                           0,
                                           this, TQ_SLOT(addMultiline()),
                                           collection, "formula_addmultiline");

    m_removeEnclosingAction = new TDEAction(i18n("Remove Enclosing Element"),
                                        0,
                                        this, TQ_SLOT(removeEnclosing()),
                                        collection, "formula_removeenclosing");

    m_makeGreekAction = new TDEAction(i18n("Convert to Greek"),
                                  0,
                                  this, TQ_SLOT(makeGreek()),
                                  collection, "formula_makegreek");

    m_appendColumnAction = new TDEAction( i18n( "Append Column" ),
                                            "inscol",
                                            0,
                                            this, TQ_SLOT( appendColumn() ),
                                            collection, "formula_appendcolumn" );
    m_insertColumnAction = new TDEAction( i18n( "Insert Column" ),
                                            "inscol",
                                            0,
                                            this, TQ_SLOT( insertColumn() ),
                                            collection, "formula_insertcolumn" );
    m_removeColumnAction = new TDEAction( i18n( "Remove Column" ),
                                            "remcol",
                                            0,
                                            this, TQ_SLOT( removeColumn() ),
                                            collection, "formula_removecolumn" );
    m_appendRowAction = new TDEAction( i18n( "Append Row" ),
                                         "insrow",
                                         0,
                                         this, TQ_SLOT( appendRow() ),
                                         collection, "formula_appendrow" );
    m_insertRowAction = new TDEAction( i18n( "Insert Row" ),
                                         "insrow",
                                         0,
                                         this, TQ_SLOT( insertRow() ),
                                         collection, "formula_insertrow" );
    m_removeRowAction = new TDEAction( i18n( "Remove Row" ),
                                         "remrow",
                                         0,
                                         this, TQ_SLOT( removeRow() ),
                                         collection, "formula_removerow" );

    m_syntaxHighlightingAction = new TDEToggleAction(i18n("Syntax Highlighting"),
                                                 0,
                                                 this, TQ_SLOT(toggleSyntaxHighlighting()),
                                                 collection, "formula_syntaxhighlighting");
    //m_syntaxHighlightingAction->setChecked( m_contextStyle->syntaxHighlighting() );

    m_formatBoldAction = new TDEToggleAction( i18n( "&Bold" ), "format-text-bold",
                                                0, //CTRL + Key_B,
                                                this, TQ_SLOT( textBold() ),
                                                collection, "formula_format_bold" );
    m_formatItalicAction = new TDEToggleAction( i18n( "&Italic" ), "format-text-italic",
                                                  0, //CTRL + Key_I,
                                                  this, TQ_SLOT( textItalic() ),
                                                  collection, "formula_format_italic" );
    m_formatBoldAction->setEnabled( false );
    m_formatItalicAction->setEnabled( false );

    TQStringList delimiter;
    delimiter.append(TQString("("));
    delimiter.append(TQString("["));
    delimiter.append(TQString("{"));
    delimiter.append(TQString("<"));
    delimiter.append(TQString("/"));
    delimiter.append(TQString("\\"));
    delimiter.append(TQString("|"));
    delimiter.append(TQString(" "));
    delimiter.append(TQString(")"));
    delimiter.append(TQString("]"));
    delimiter.append(TQString("}"));
    delimiter.append(TQString(">"));
    m_leftBracket = new TDESelectAction(i18n("Left Delimiter"),
                                    0, this, TQ_SLOT(delimiterLeft()),
                                    collection, "formula_typeleft");
    m_leftBracket->setItems(delimiter);
    //leftBracket->setCurrentItem(0);

    delimiter.clear();
    delimiter.append(TQString(")"));
    delimiter.append(TQString("]"));
    delimiter.append(TQString("}"));
    delimiter.append(TQString(">"));
    delimiter.append(TQString("/"));
    delimiter.append(TQString("\\"));
    delimiter.append(TQString("|"));
    delimiter.append(TQString(" "));
    delimiter.append(TQString("("));
    delimiter.append(TQString("["));
    delimiter.append(TQString("{"));
    delimiter.append(TQString("<"));
    m_rightBracket = new TDESelectAction(i18n("Right Delimiter"),
                                     0, this, TQ_SLOT(delimiterRight()),
                                     collection, "formula_typeright");
    m_rightBracket->setItems(delimiter);
    //rightBracket->setCurrentItem(0);

    m_insertSymbolAction = new TDEAction(i18n("Insert Symbol"),
                                           "key_enter",
                                           /*CTRL + Key_I*/0,
                                           this, TQ_SLOT(insertSymbol()),
                                           collection, "formula_insertsymbol");
    m_symbolNamesAction = new SymbolAction(i18n("Symbol Names"),
                                               0, this, TQ_SLOT(symbolNames()),
                                               collection, "formula_symbolnames");

    TQStringList ff;
    ff.append( i18n( "Normal" ) );
    ff.append( i18n( "Script" ) );
    ff.append( i18n( "Fraktur" ) );
    ff.append( i18n( "Double Struck" ) );
    m_fontFamily = new TDESelectAction(i18n("Font Family"),
                                         0, this, TQ_SLOT(fontFamily()),
                                         collection, "formula_fontfamily");
    m_fontFamily->setItems( ff );
    m_fontFamily->setEnabled( false );

    TQStringList et;
    et.append( i18n( "Identifier" ) );
    et.append( i18n( "Operator" ) );
    et.append( i18n( "Number" ) );
    et.append( i18n( "Text" ) );
    m_tokenElement = new TDESelectAction( i18n( "Token Type" ),
                                     0, this, TQ_SLOT( tokenElement() ),
                                     collection, "formula_tokenelement" );
    m_tokenElement->setItems( et );
//    m_tokenElements->setEnabled( true );
}


void DocumentWrapper::paste()
{
    if (hasFormula()) {
        formula()->paste();
    }
}

void DocumentWrapper::copy()
{
    if (hasFormula()) {
        formula()->copy();
    }
}

void DocumentWrapper::cut()
{
    if (hasFormula()) {
        formula()->cut();
    }
}

void DocumentWrapper::undo()
{
    m_history->undo();
}

void DocumentWrapper::redo()
{
    m_history->redo();
}

void DocumentWrapper::addNegThinSpace()
{
    if (hasFormula()) {
        SpaceRequest r( NEGTHIN );
        formula()->performRequest( &r );
    }
}
void DocumentWrapper::addThinSpace()
{
    if (hasFormula()) {
        SpaceRequest r( THIN );
        formula()->performRequest( &r );
    }
}
void DocumentWrapper::addMediumSpace()
{
    if (hasFormula()) {
        SpaceRequest r( MEDIUM );
        formula()->performRequest( &r );
    }
}
void DocumentWrapper::addThickSpace()
{
    if (hasFormula()) {
        SpaceRequest r( THICK );
        formula()->performRequest( &r );
    }
}
void DocumentWrapper::addQuadSpace()
{
    if (hasFormula()) {
        SpaceRequest r( QUAD );
        formula()->performRequest( &r );
    }
}

void DocumentWrapper::addDefaultBracket()
{
    if (hasFormula()) {
        BracketRequest r( m_leftBracketChar, m_rightBracketChar );
        formula()->performRequest( &r );
    }
}

void DocumentWrapper::addBracket( SymbolType left, SymbolType right )
{
    if (hasFormula()) {
        BracketRequest r( left, right );
        formula()->performRequest( &r );
    }
}

void DocumentWrapper::addParenthesis()
{
    if (hasFormula()) {
        BracketRequest r( LeftRoundBracket, RightRoundBracket );
        formula()->performRequest( &r );
    }
}

void DocumentWrapper::addSquareBracket()
{
    if (hasFormula()) {
        BracketRequest r( LeftSquareBracket, RightSquareBracket );
        formula()->performRequest( &r );
    }
}

void DocumentWrapper::addCurlyBracket()
{
    if (hasFormula()) {
        BracketRequest r( LeftCurlyBracket, RightCurlyBracket );
        formula()->performRequest( &r );
    }
}

void DocumentWrapper::addLineBracket()
{
    if (hasFormula()) {
        BracketRequest r( LeftLineBracket, RightLineBracket );
        formula()->performRequest( &r );
    }
}

void DocumentWrapper::addFraction()
{
    if (hasFormula()) {
        Request r( req_addFraction );
        formula()->performRequest( &r );
    }
}

void DocumentWrapper::addRoot()
{
    if (hasFormula()) {
        Request r( req_addRoot );
        formula()->performRequest( &r );
    }
}

void DocumentWrapper::addIntegral()
{
    if (hasFormula()) {
        SymbolRequest r( Integral );
        formula()->performRequest( &r );
    }
}

void DocumentWrapper::addProduct()
{
    if (hasFormula()) {
        SymbolRequest r( Product );
        formula()->performRequest( &r );
    }
}

void DocumentWrapper::addSum()
{
    if (hasFormula()) {
        SymbolRequest r( Sum );
        formula()->performRequest( &r );
    }
}

void DocumentWrapper::addMatrix( uint rows, uint columns )
{
    if (hasFormula()) {
        MatrixRequest r( rows, columns );
        formula()->performRequest( &r );
    }
}

void DocumentWrapper::addOneByTwoMatrix()
{
    if (hasFormula()) {
        Request r( req_addOneByTwoMatrix );
        formula()->performRequest( &r );
    }
}

void DocumentWrapper::addNameSequence()
{
    if (hasFormula()) {
        Request r( req_addNameSequence );
        formula()->performRequest( &r );
    }
}

void DocumentWrapper::addLowerLeftIndex()
{
    if (hasFormula()) {
        IndexRequest r( lowerLeftPos );
        formula()->performRequest( &r );
    }
}

void DocumentWrapper::addUpperLeftIndex()
{
    if (hasFormula()) {
        IndexRequest r( upperLeftPos );
        formula()->performRequest( &r );
    }
}

void DocumentWrapper::addLowerRightIndex()
{
    if (hasFormula()) {
        IndexRequest r( lowerRightPos );
        formula()->performRequest( &r );
    }
}

void DocumentWrapper::addUpperRightIndex()
{
    if (hasFormula()) {
        IndexRequest r( upperRightPos );
        formula()->performRequest( &r );
    }
}

void DocumentWrapper::addGenericLowerIndex()
{
    if (hasFormula()) {
        IndexRequest r( lowerMiddlePos );
        formula()->performRequest( &r );
    }
}

void DocumentWrapper::addGenericUpperIndex()
{
    if (hasFormula()) {
        IndexRequest r( upperMiddlePos );
        formula()->performRequest( &r );
    }
}

void DocumentWrapper::addOverline()
{
    if (hasFormula()) {
        Request r( req_addOverline );
        formula()->performRequest( &r );
    }
}

void DocumentWrapper::addUnderline()
{
    if (hasFormula()) {
        Request r( req_addUnderline );
        formula()->performRequest( &r );
    }
}

void DocumentWrapper::addMultiline()
{
    if (hasFormula()) {
        Request r( req_addMultiline );
        formula()->performRequest( &r );
    }
}

void DocumentWrapper::removeEnclosing()
{
    if (hasFormula()) {
        DirectedRemove r( req_removeEnclosing, beforeCursor );
        formula()->performRequest( &r );
    }
}

void DocumentWrapper::makeGreek()
{
    if (hasFormula()) {
        Request r( req_makeGreek );
        formula()->performRequest( &r );
    }
}

void DocumentWrapper::insertSymbol()
{
    if ( hasFormula() &&
         m_document->m_contextStyle->symbolTable().contains( m_selectedName ) ) {
        TQChar ch = m_document->m_contextStyle->symbolTable().unicode( m_selectedName );
        if ( ch != TQChar::null ) {
            TextCharRequest r( ch, true );
            formula()->performRequest( &r );
        }
        else {
            TextRequest r( m_selectedName );
            formula()->performRequest( &r );
        }
    }
}

void DocumentWrapper::insertSymbol( TQString name )
{
    if ( hasFormula() ) {
        if ( m_document->m_contextStyle->symbolTable().contains( name ) ) {
            TQChar ch = m_document->m_contextStyle->symbolTable().unicode( name );
            if ( ch != TQChar::null ) {
                TextCharRequest r( ch, true );
                formula()->performRequest( &r );
                return;
            }
        }
        TextRequest r( name );
        formula()->performRequest( &r );
    }
}

void DocumentWrapper::appendColumn()
{
    if ( hasFormula() ) {
        Request r( req_appendColumn );
        formula()->performRequest( &r );
    }
}

void DocumentWrapper::insertColumn()
{
    if ( hasFormula() ) {
        Request r( req_insertColumn );
        formula()->performRequest( &r );
    }
}

void DocumentWrapper::removeColumn()
{
    if ( hasFormula() ) {
        Request r( req_removeColumn );
        formula()->performRequest( &r );
    }
}

void DocumentWrapper::appendRow()
{
    if ( hasFormula() ) {
        Request r( req_appendRow );
        formula()->performRequest( &r );
    }
}

void DocumentWrapper::insertRow()
{
    if ( hasFormula() ) {
        Request r( req_insertRow );
        formula()->performRequest( &r );
    }
}

void DocumentWrapper::removeRow()
{
    if ( hasFormula() ) {
        Request r( req_removeRow );
        formula()->performRequest( &r );
    }
}

void DocumentWrapper::toggleSyntaxHighlighting()
{
    m_document->m_contextStyle->setSyntaxHighlighting( m_syntaxHighlightingAction->isChecked() );
    // Only to notify all views. We don't expect to get new values.
    m_document->recalc();
}

void DocumentWrapper::textBold()
{
    if ( hasFormula() ) {
        CharStyleRequest r( req_formatBold,
                            getFormatBoldAction()->isChecked(),
                            getFormatItalicAction()->isChecked() );
        formula()->performRequest( &r );
    }
}

void DocumentWrapper::textItalic()
{
    if ( hasFormula() ) {
        CharStyleRequest r( req_formatItalic,
                            getFormatBoldAction()->isChecked(),
                            getFormatItalicAction()->isChecked() );
        formula()->performRequest( &r );
    }
}

void DocumentWrapper::delimiterLeft()
{
    TQString left = m_leftBracket->currentText();
    switch ( left.at(0).latin1() ) {
    case '[':
    case ']':
    case '{':
    case '}':
    case '<':
    case '>':
    case '(':
    case ')':
    case '/':
    case '\\':
        m_leftBracketChar = static_cast<SymbolType>( left.at(0).latin1() );
        break;
    case '|':
        m_leftBracketChar = LeftLineBracket;
        break;
    case ' ':
        m_leftBracketChar = EmptyBracket;
        break;
    }
}

void DocumentWrapper::delimiterRight()
{
    TQString right = m_rightBracket->currentText();
    switch ( right.at(0).latin1() ) {
    case '[':
    case ']':
    case '{':
    case '}':
    case '<':
    case '>':
    case '(':
    case ')':
    case '/':
    case '\\':
        m_rightBracketChar = static_cast<SymbolType>( right.at(0).latin1() );
        break;
    case '|':
        m_rightBracketChar = RightLineBracket;
        break;
    case ' ':
        m_rightBracketChar = EmptyBracket;
        break;
    }
}

void DocumentWrapper::symbolNames()
{
    m_selectedName = m_symbolNamesAction->currentText();
}


void DocumentWrapper::fontFamily()
{
    if ( hasFormula() ) {
        int i = m_fontFamily->currentItem();
        CharFamily cf = anyFamily;
        switch( i ) {
        case 0: cf = normalFamily; break;
        case 1: cf = scriptFamily; break;
        case 2: cf = frakturFamily; break;
        case 3: cf = doubleStruckFamily; break;
        }
        CharFamilyRequest r( cf );
        formula()->performRequest( &r );
    }
}


void DocumentWrapper::tokenElement()
{
    if ( hasFormula() ) {
        int i = m_tokenElement->currentItem();
        TokenElementType te = anyElement;
        switch( i ) {
        case 0: te = identifierElement; break;
        case 1: te = operatorElement; break;
        case 2: te = numberElement; break;
        case 3: te = textElement; break;
        }
        TokenElementRequest r( te );
        formula()->performRequest( &r );
    }
}


void DocumentWrapper::initSymbolNamesAction()
{
    if ( m_hasActions ) {
        const SymbolTable& st = m_document->m_contextStyle->symbolTable();
        TQStringList names = st.allNames();
        TQFont font( m_document->m_contextStyle->getFontStyle() );
        TQMemArray<TQChar> chars( names.count() );

        uint i = 0;
        for ( TQStringList::Iterator it = names.begin();
              it != names.end();
              ++it, ++i ) {
            chars[ i ] = st.unicode( *it );
        }
        m_symbolNamesAction->setSymbols( names, m_document->m_contextStyle->getMathFont(), chars );
        m_selectedName = names[0];
    }
}


void DocumentWrapper::setEnabled( bool enabled )
{
    kdDebug( DEBUGID ) << "DocumentWrapper::setEnabled " << enabled << endl;
    getAddNegThinSpaceAction()->setEnabled( enabled );
    getMakeGreekAction()->setEnabled( enabled );
    getAddGenericUpperAction()->setEnabled( enabled );
    getAddGenericLowerAction()->setEnabled( enabled );
    getAddOverlineAction()->setEnabled( enabled );
    getAddUnderlineAction()->setEnabled( enabled );
    getRemoveEnclosingAction()->setEnabled( enabled );
    getInsertSymbolAction()->setEnabled( enabled );
    getAddThinSpaceAction()->setEnabled( enabled );
    getAddMediumSpaceAction()->setEnabled( enabled );
    getAddThickSpaceAction()->setEnabled( enabled );
    getAddQuadSpaceAction()->setEnabled( enabled );
    getAddBracketAction()->setEnabled( enabled );
    getAddSBracketAction()->setEnabled( enabled );
    getAddCBracketAction()->setEnabled( enabled );
    getAddAbsAction()->setEnabled(enabled);
    getAddFractionAction()->setEnabled( enabled );
    getAddRootAction()->setEnabled( enabled );
    getAddSumAction()->setEnabled( enabled );
    getAddProductAction()->setEnabled( enabled );
    getAddIntegralAction()->setEnabled( enabled );
    getAddMatrixAction()->setEnabled( enabled );
    getAddOneByTwoMatrixAction()->setEnabled( enabled );
    getAddUpperLeftAction()->setEnabled( enabled );
    getAddLowerLeftAction()->setEnabled( enabled );
    getAddUpperRightAction()->setEnabled( enabled );
    getAddLowerRightAction()->setEnabled( enabled );
    
    getAddGenericUpperAction()->setEnabled( enabled );
    getAddGenericLowerAction()->setEnabled( enabled );
    

    if ( enabled ) {
        getAddGenericUpperAction()->
            setShortcut( TDEShortcut( CTRL + Key_U ) );
        getAddGenericLowerAction()->
            setShortcut( TDEShortcut( CTRL + Key_L ) );
        getRemoveEnclosingAction()->
            setShortcut( TDEShortcut( CTRL + Key_R ) );
        getMakeGreekAction()->
            setShortcut( TDEShortcut( CTRL + Key_G ) );
        getInsertSymbolAction()->
            setShortcut( TDEShortcut( CTRL + Key_I ) );
        getAddOverlineAction()->
            setShortcut( TDEShortcut( CTRL + SHIFT + Key_O ) );
        getAddUnderlineAction()->
            setShortcut( TDEShortcut( CTRL + SHIFT + Key_U ) );
        getAddBracketAction()->
            setShortcut( TDEShortcut( CTRL + SHIFT + Key_B ) );
        getAddSBracketAction()->
            setShortcut( TDEShortcut( CTRL + SHIFT + Key_D ) );
        getAddCBracketAction()->
            setShortcut( TDEShortcut( CTRL + SHIFT + Key_C ) );
        getAddAbsAction()->
            setShortcut( TDEShortcut( CTRL + SHIFT + Key_A ) );
        getAddFractionAction()->
            setShortcut( TDEShortcut( CTRL + SHIFT + Key_F ) );
        getAddRootAction()->
            setShortcut( TDEShortcut( CTRL + SHIFT + Key_R ) );
        getAddSumAction()->
            setShortcut( TDEShortcut( CTRL + SHIFT + Key_S ) );
        getAddProductAction()->
            setShortcut( TDEShortcut( CTRL + SHIFT + Key_P ) );
        getAddIntegralAction()->
            setShortcut( TDEShortcut( CTRL + SHIFT + Key_I ) );
        getAddMatrixAction()->
            setShortcut( TDEShortcut( CTRL + SHIFT + Key_M ) );

    }
    else {
        getAddGenericUpperAction()->setShortcut( TDEShortcut() );
        getAddGenericLowerAction()->setShortcut( TDEShortcut() );
        getRemoveEnclosingAction()->setShortcut( TDEShortcut() );
        getMakeGreekAction()->setShortcut( TDEShortcut() );
        getInsertSymbolAction()->setShortcut( TDEShortcut() );
        getAddOverlineAction()->setShortcut( TDEShortcut() );
        getAddUnderlineAction()->setShortcut( TDEShortcut() );
        getAddBracketAction()->setShortcut( TDEShortcut() );
        getAddSBracketAction()->setShortcut( TDEShortcut() );
        getAddCBracketAction()->setShortcut( TDEShortcut() );
        getAddAbsAction()->setShortcut( TDEShortcut() );
        getAddFractionAction()->setShortcut( TDEShortcut() );
        getAddRootAction()->setShortcut( TDEShortcut() );
        getAddSumAction()->setShortcut( TDEShortcut() );
        getAddProductAction()->setShortcut( TDEShortcut() );
        getAddIntegralAction()->setShortcut( TDEShortcut() );
        getAddMatrixAction()->setShortcut( TDEShortcut() );
    }
}

void DocumentWrapper::enableMatrixActions( bool b)
{
    getAppendColumnAction()->setEnabled( b );
    getInsertColumnAction()->setEnabled( b );
    getRemoveColumnAction()->setEnabled( b );
    getAppendRowAction()->setEnabled( b );
    getInsertRowAction()->setEnabled( b );
    getRemoveRowAction()->setEnabled( b );
}

void DocumentWrapper::updateConfig()
{
    m_syntaxHighlightingAction->
        setChecked( m_document->m_contextStyle->syntaxHighlighting() );
    initSymbolNamesAction();
}


KFORMULA_NAMESPACE_END

using namespace KFormula;
#include "kformuladocument.moc"
