You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
koffice/lib/kotext/KoTextView.cpp

1550 lines
53 KiB

/* This file is part of the KDE project
Copyright (C) 2001-2006 David Faure <faure@kde.org>
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 "KoTextView.h"
#include "KoTextParag.h"
#include "KoParagCounter.h"
#include "KoTextObject.h"
#include "KoTextViewIface.h"
#include "KoStyleCollection.h"
#include "KoBgSpellCheck.h"
#include "KoVariable.h"
#include <klocale.h>
#include <kstandarddirs.h>
#include <tdestdaccel.h>
#include <kdebug.h>
#include <kinstance.h>
#include <kdatatool.h>
#include <krun.h>
#include <kmessagebox.h>
#include <kcommand.h>
#include <kbookmarkmanager.h>
#include <kbookmark.h>
#include <kurldrag.h>
#include <tqapplication.h>
#include <tqtimer.h>
#include <tqclipboard.h>
class KoTextView::KoTextViewPrivate
{
public:
KoTextViewPrivate()
{
m_currentUnicodeNumber = 0;
m_backSpeller = 0;
}
void appendDigit( int digit ) { m_currentUnicodeNumber = 10 * m_currentUnicodeNumber + digit; }
int currentUnicodeNumber() const { return m_currentUnicodeNumber; }
void clearCurrentUnicodeNumber() { m_currentUnicodeNumber = 0; }
KoBgSpellCheck* m_backSpeller;
private:
int m_currentUnicodeNumber; // For the alt+123 feature
};
KoTextView::KoTextView( KoTextObject *textobj )
{
d = new KoTextViewPrivate;
m_bReadWrite = true;
m_textobj = textobj;
dcop=0;
connect( m_textobj, TQT_SIGNAL( hideCursor() ), this, TQT_SLOT( hideCursor() ) );
connect( m_textobj, TQT_SIGNAL( showCursor() ), this, TQT_SLOT( showCursor() ) );
connect( m_textobj, TQT_SIGNAL( setCursor( KoTextCursor * ) ), this, TQT_SLOT( setCursor( KoTextCursor * ) ) );
connect( m_textobj, TQT_SIGNAL( updateUI(bool, bool) ), this, TQT_SLOT( updateUI(bool, bool) ) );
connect( m_textobj, TQT_SIGNAL( showCurrentFormat() ), this, TQT_SLOT( showCurrentFormat() ) );
connect( m_textobj, TQT_SIGNAL( ensureCursorVisible() ), this, TQT_SLOT( ensureCursorVisible() ) );
m_cursor = new KoTextCursor( m_textobj->textDocument() );
m_cursorVisible = false;
showCursor();
blinkTimer = new TQTimer( this );
connect( blinkTimer, TQT_SIGNAL( timeout() ),
this, TQT_SLOT( blinkCursor() ) );
if ( TQApplication::cursorFlashTime() > 0 )
blinkTimer->start( TQApplication::cursorFlashTime() / 2 );
dragStartTimer = new TQTimer( this );
connect( dragStartTimer, TQT_SIGNAL( timeout() ),
this, TQT_SLOT( startDrag() ) );
m_textobj->formatMore( 2 );
blinkCursorVisible = FALSE;
inDoubleClick = FALSE;
mightStartDrag = FALSE;
possibleTripleClick = FALSE;
afterTripleClick = FALSE;
m_currentFormat = 0;
m_variablePosition =-1;
m_overwriteMode = false;
//updateUI( true, true );
}
KoTextView::~KoTextView()
{
delete m_cursor;
delete d;
delete dcop;
delete blinkTimer;
delete dragStartTimer;
}
KoTextViewIface* KoTextView::dcopObject()
{
if ( !dcop )
dcop = new KoTextViewIface( this );
return dcop;
}
void KoTextView::terminate(bool removeselection)
{
textObject()->clearUndoRedoInfo();
if ( removeselection && textDocument()->removeSelection( KoTextDocument::Standard ) )
textObject()->selectionChangedNotify();
hideCursor();
}
void KoTextView::deleteWordRight()
{
if ( textObject()->hasSelection() ) {
textObject()->removeSelectedText( m_cursor );
return;
}
textDocument()->setSelectionStart( KoTextDocument::Standard, m_cursor );
do {
m_cursor->gotoRight();
} while ( !m_cursor->atParagEnd()
&& !m_cursor->parag()->at( m_cursor->index() )->c.isSpace() );
textDocument()->setSelectionEnd( KoTextDocument::Standard, m_cursor );
textObject()->removeSelectedText( m_cursor, KoTextDocument::Standard, i18n("Remove Word") );
}
void KoTextView::deleteWordLeft()
{
if ( textObject()->hasSelection() ) {
textObject()->removeSelectedText( m_cursor );
return;
}
textDocument()->setSelectionStart( KoTextDocument::Standard, m_cursor );
do {
m_cursor->gotoLeft();
} while ( !m_cursor->atParagStart()
&& !m_cursor->parag()->at( m_cursor->index()-1 )->c.isSpace() );
textDocument()->setSelectionEnd( KoTextDocument::Standard, m_cursor );
textObject()->removeSelectedText( m_cursor, KoTextDocument::Standard, i18n("Remove Word") );
}
// Compare with TQTextEdit::keyPressEvent
void KoTextView::handleKeyPressEvent( TQKeyEvent * e, TQWidget *widget, const TQPoint &pos)
{
textObject()->typingStarted();
/* bool selChanged = FALSE;
for ( int i = 1; i < textDocument()->numSelections(); ++i )
selChanged = textDocument()->removeSelection( i ) || selChanged;
if ( selChanged ) {
// m_cursor->parag()->document()->nextDoubleBuffered = TRUE; ######## we need that only if we have nested items/documents
textFrameSet()->selectionChangedNotify();
}*/
bool clearUndoRedoInfo = TRUE;
if ( TDEShortcut( KKey( e ) ) == TDEStdAccel::deleteWordBack() )
{
if ( m_cursor->parag()->string()->isRightToLeft() )
deleteWordRight();
else
deleteWordLeft();
clearUndoRedoInfo = TRUE;
} else if ( TDEShortcut( KKey( e ) ) == TDEStdAccel::deleteWordForward() )
{
if ( m_cursor->parag()->string()->isRightToLeft() )
deleteWordLeft();
else
deleteWordRight();
clearUndoRedoInfo = TRUE;
}
else
switch ( e->key() ) {
case Key_Left:
case Key_Right: {
if (!doToolTipCompletion(m_cursor, m_cursor->parag(), m_cursor->index() - 1, e->key()) )
{
// a bit hacky, but can't change this without introducing new enum values for move and keeping the
// correct semantics and movement for BiDi and non BiDi text.
CursorAction a;
if ( m_cursor->parag()->string()->isRightToLeft() == (e->key() == Key_Right) )
a = e->state() & ControlButton ? MoveWordBackward : MoveBackward;
else
a = e->state() & ControlButton ? MoveWordForward : MoveForward;
moveCursor( a, e->state() & ShiftButton );
}
break;
}
case Key_Up:
moveCursor( e->state() & ControlButton ? MoveParagUp : MoveUp, e->state() & ShiftButton );
break;
case Key_Down:
moveCursor( e->state() & ControlButton ? MoveParagDown : MoveDown, e->state() & ShiftButton );
break;
case Key_Home:
moveCursor( e->state() & ControlButton ? MoveHome : MoveLineStart, e->state() & ShiftButton );
break;
case Key_End:
if (!doToolTipCompletion(m_cursor, m_cursor->parag(), m_cursor->index() - 1, e->key()) )
moveCursor( e->state() & ControlButton ? MoveEnd : MoveLineEnd, e->state() & ShiftButton );
break;
case Key_Prior:
moveCursor( e->state() & ControlButton ? MovePgUp : MoveViewportUp, e->state() & ShiftButton );
break;
case Key_Next:
moveCursor( e->state() & ControlButton ? MovePgDown : MoveViewportDown, e->state() & ShiftButton );
break;
case Key_Return: case Key_Enter:
if (!doToolTipCompletion(m_cursor, m_cursor->parag(), m_cursor->index() - 1, e->key()) )
if ( (e->state() & (ShiftButton|ControlButton)) == 0 )
{
if ( textObject()->hasSelection() )
textObject()->removeSelectedText( m_cursor );
clearUndoRedoInfo = FALSE;
textObject()->doKeyboardAction( m_cursor, m_currentFormat, KoTextObject::ActionReturn );
Q_ASSERT( m_cursor->parag()->prev() );
if ( m_cursor->parag()->prev() )
doAutoFormat( m_cursor, m_cursor->parag()->prev(),
m_cursor->parag()->prev()->length() - 1, '\n' );
}
clearUndoRedoInfo = true;
break;
case Key_Delete:
if ( textObject()->hasSelection() ) {
textObject()->removeSelectedText( m_cursor );
break;
}
textObject()->doKeyboardAction( m_cursor, m_currentFormat, KoTextObject::ActionDelete );
clearUndoRedoInfo = FALSE;
break;
case Key_Backtab:
if (e->state() & ShiftButton && m_cursor->parag() && m_cursor->atParagStart() && m_cursor->parag()->counter() && textDecreaseIndent())
break;
break;
case Key_Backspace:
if ( textObject()->hasSelection() ) {
textObject()->removeSelectedText( m_cursor );
break;
}
textObject()->doKeyboardAction( m_cursor, m_currentFormat, KoTextObject::ActionBackspace );
clearUndoRedoInfo = FALSE;
break;
case Key_F16: // Copy key on Sun keyboards
emit copy();
break;
case Key_F18: // Paste key on Sun keyboards
emit paste();
break;
case Key_F20: // Cut key on Sun keyboards
emit cut();
break;
case Key_Direction_L: {
if ( m_cursor->parag() && m_cursor->parag()->direction() != TQChar::DirL )
{
KCommand* cmd = textObject()->setParagDirectionCommand( m_cursor, TQChar::DirL );
textObject()->emitNewCommand( cmd );
}
break;
}
case Key_Direction_R: {
if ( m_cursor->parag() && m_cursor->parag()->direction() != TQChar::DirR )
{
KCommand* cmd = textObject()->setParagDirectionCommand( m_cursor, TQChar::DirR );
textObject()->emitNewCommand( cmd );
}
break;
}
default: {
//kdDebug(32500) << "KoTextView::keyPressEvent ascii=" << e->ascii() << " text=" << e->text()[0].unicode() << " state=" << e->state() << endl;
if (e->key() == TQt::Key_Tab)
{
if (doToolTipCompletion(m_cursor, m_cursor->parag(), m_cursor->index() - 1, e->key()) )
break;
if ( m_cursor->parag() && m_cursor->atParagStart() && m_cursor->parag()->counter() )
{
textIncreaseIndent();
break;
}
}
if ( e->key() == TQt::Key_Space )
{
if (doToolTipCompletion(m_cursor, m_cursor->parag(), m_cursor->index() - 1, e->key()) )
break;
}
if ( e->text().length() &&
( !e->ascii() || e->ascii() >= 32 ) ||
( e->text() == "\t" && !( e->state() & ControlButton ) ) ) {
clearUndoRedoInfo = FALSE;
TQString text = e->text();
if ( d->m_backSpeller ) {
d->m_backSpeller->setIntraWordEditing( m_cursor->parag(), m_cursor->index() );
}
// Alt+123 feature
if ( ( e->state() & AltButton ) && text[0].isDigit() )
{
while ( text[0].isDigit() ) {
d->appendDigit( text[0].digitValue() );
text.remove( 0, 1 );
}
}
if ( !text.isEmpty() )
{
// Bidi support: need to reverse mirrored chars (e.g. parenthesis)
KoTextParag *p = m_cursor->parag();
if ( p && p->string() && p->string()->isRightToLeft() ) {
TQChar *c = (TQChar *)text.unicode();
int l = text.length();
while( l-- ) {
if ( c->mirrored() )
*c = c->mirroredChar();
c++;
}
}
if( !doIgnoreDoubleSpace( p, m_cursor->index()-1, text[ text.length() - 1 ] ) )
{
// ###### BUG: with the event compression, typing "kde" and then " k", might not apply
// autocorrection like it does for "kde" followed by " " followed by "k". We need to insert
// one character at a time, or better, to tell doAutoFormat how many chars to consider...
insertText( text );
// Don't use 'p' past this point. If we replaced a selection, p could have been deleted (#48999)
doAutoFormat( m_cursor, m_cursor->parag(), m_cursor->index() - 1, text[ text.length() - 1 ] );
}
showToolTipBox(m_cursor->parag(), m_cursor->index()-1, widget,pos);
}
else
removeToolTipCompletion();
}
// We should use TDEAccel instead, to make this configurable !
// Well, those are all alternate keys, for keys already configurable (KDE-wide)
// and a tdeaccel makes it hard to
else
{
if ( e->state() & ControlButton ) {
switch ( e->key() )
{
case Key_F16: // Copy key on Sun keyboards
copy();
break;
case Key_A:
moveCursor( MoveLineStart, e->state() & ShiftButton );
break;
case Key_E:
moveCursor( MoveLineEnd, e->state() & ShiftButton );
break;
case Key_K:
textObject()->doKeyboardAction( m_cursor, m_currentFormat, KoTextObject::ActionKill );
break;
case Key_Insert:
copy();
break;
case Key_Space:
insertNonbreakingSpace();
break;
default:
clearUndoRedoInfo = FALSE;
break;
}
}
else // e.g. just Key_Shift -> don't do anything (#129481)
{
clearUndoRedoInfo = FALSE;
}
}
break;
}
}
if ( clearUndoRedoInfo ) {
textObject()->clearUndoRedoInfo();
if ( d->m_backSpeller )
d->m_backSpeller->setIntraWordEditing( 0, 0 );
}
textObject()->typingDone();
}
void KoTextView::setOverwriteMode( bool overwriteMode )
{
m_overwriteMode = overwriteMode;
}
void KoTextView::insertText( const TQString &text )
{
int insertFlags = KoTextObject::DefaultInsertFlags;
if ( m_overwriteMode )
insertFlags |= KoTextObject::OverwriteMode;
textObject()->insert( m_cursor, m_currentFormat, text, i18n("Insert Text"), KoTextDocument::Standard, insertFlags );
}
void KoTextView::newParagraph()
{
textObject()->insert( m_cursor, m_currentFormat, "\n", i18n("Insert Text"), KoTextDocument::Standard, KoTextObject::CheckNewLine );
}
void KoTextView::handleKeyReleaseEvent( TQKeyEvent * e )
{
if ( e->key() == Key_Alt && d->currentUnicodeNumber() >= 32 )
{
TQString text = TQChar( d->currentUnicodeNumber() );
d->clearCurrentUnicodeNumber();
insertText( text );
doAutoFormat( m_cursor, m_cursor->parag(),
m_cursor->index() - 1, text[ text.length() - 1 ] );
}
}
void KoTextView::handleImStartEvent( TQIMEvent * )
{
// nothing to do
}
void KoTextView::handleImComposeEvent( TQIMEvent * e )
{
// remove old preedit
if ( textDocument()->hasSelection( KoTextDocument::Standard ) )
textDocument()->removeSelection( KoTextDocument::Standard );
if ( textDocument()->hasSelection( KoTextDocument::InputMethodPreedit ) )
textDocument()->removeSelectedText( KoTextDocument::InputMethodPreedit, m_cursor );
// insert preedit
int preeditStartIdx = m_cursor->index();
textDocument()->setSelectionStart( KoTextDocument::InputMethodPreedit, m_cursor );
textObject()->insert( m_cursor, m_currentFormat, e->text(), i18n("Insert Text"),
KoTextDocument::Standard,
KoTextObject::DoNotRepaint/* DO NOT REPAINT CURSOR! */ );
textDocument()->setSelectionEnd( KoTextDocument::InputMethodPreedit, m_cursor );
// selection
int preeditSelStart = preeditStartIdx + e->cursorPos();
int preeditSelEnd = preeditSelStart + e->selectionLength();
m_cursor->setIndex( preeditSelStart );
textDocument()->setSelectionStart( KoTextDocument::Standard, m_cursor );
m_cursor->setIndex( preeditSelEnd );
textDocument()->setSelectionEnd( KoTextDocument::Standard, m_cursor );
// set cursor pos
m_cursor->setIndex( preeditSelStart );
textObject()->emitUpdateUI( true );
textObject()->emitShowCursor();
textObject()->selectionChangedNotify();
}
void KoTextView::handleImEndEvent( TQIMEvent * e )
{
// remove old preedit
if ( textDocument()->hasSelection( KoTextDocument::Standard ) )
textDocument()->removeSelection( KoTextDocument::Standard );
if ( textDocument()->hasSelection( KoTextDocument::InputMethodPreedit ) )
textDocument()->removeSelectedText( KoTextDocument::InputMethodPreedit, m_cursor );
insertText( e->text() );
textObject()->emitUpdateUI( true );
textObject()->emitShowCursor();
textObject()->selectionChangedNotify();
}
void KoTextView::completion()
{
(void) doCompletion(m_cursor, m_cursor->parag(),
m_cursor->index() - 1);
}
void KoTextView::moveCursor( CursorAction action, bool select )
{
hideCursor();
bool cursorMoved = false;
if ( select ) {
if ( !textDocument()->hasSelection( KoTextDocument::Standard ) )
textDocument()->setSelectionStart( KoTextDocument::Standard, m_cursor );
cursorMoved = moveCursor( action );
if ( textDocument()->setSelectionEnd( KoTextDocument::Standard, m_cursor ) ) {
textObject()->selectionChangedNotify();
}
} else {
bool redraw = textDocument()->removeSelection( KoTextDocument::Standard );
cursorMoved = moveCursor( action );
if ( redraw ) {
textObject()->selectionChangedNotify();
}
}
if ( cursorMoved ) // e.g. not when pressing Ctrl/PgDown after the last parag
{
ensureCursorVisible();
// updateUI( true ); // done by moveCursor
}
showCursor();
}
bool KoTextView::moveCursor( CursorAction action )
{
bool cursorMoved = true;
switch ( action ) {
case MoveBackward:
m_cursor->gotoPreviousLetter();
break;
case MoveWordBackward:
m_cursor->gotoPreviousWord();
break;
case MoveForward:
m_cursor->gotoNextLetter();
break;
case MoveWordForward:
m_cursor->gotoNextWord();
break;
case MoveUp:
m_cursor->gotoUp();
break;
case MoveDown:
m_cursor->gotoDown();
break;
case MoveViewportUp:
cursorMoved = pgUpKeyPressed();
break;
case MoveViewportDown:
cursorMoved = pgDownKeyPressed();
break;
case MovePgUp:
ctrlPgUpKeyPressed();
break;
case MovePgDown:
ctrlPgDownKeyPressed();
break;
case MoveLineStart:
m_cursor->gotoLineStart();
break;
case MoveHome:
m_cursor->gotoHome();
break;
case MoveLineEnd:
m_cursor->gotoLineEnd();
break;
case MoveEnd:
textObject()->ensureFormatted( textDocument()->lastParag() );
m_cursor->gotoEnd();
break;
case MoveParagUp: {
KoTextParag * parag = m_cursor->parag()->prev();
if ( m_cursor->index()==0 && parag )
{
m_cursor->setParag( parag );
m_cursor->setIndex( 0 );
}
else m_cursor->setIndex( 0 );
} break;
case MoveParagDown: {
KoTextParag * parag = m_cursor->parag()->next();
if ( parag )
{
m_cursor->setParag( parag );
m_cursor->setIndex( 0 );
}
} break;
}
updateUI( true );
return cursorMoved;
}
KoTextCursor KoTextView::selectWordUnderCursor( const KoTextCursor& cursor, int selectionId )
{
KoTextCursor c1 = cursor;
KoTextCursor c2 = cursor;
if ( cursor.index() > 0 && !cursor.parag()->at( cursor.index()-1 )->c.isSpace() )
c1.gotoWordLeft();
if ( !cursor.parag()->at( cursor.index() )->c.isSpace() && !cursor.atParagEnd() )
c2.gotoWordRight();
// The above is almost correct, but gotoWordRight also skips the spaces/punctuations
// until the next word. So the 'word under cursor' contained e.g. that trailing space.
// To be on the safe side, we skip spaces/punctuations on both sides:
KoTextString *s = cursor.parag()->string();
bool beginFound = false;
for ( int i = c1.index(); i< c2.index(); i++)
{
const TQChar ch = s->at(i).c;
// This list comes from KoTextCursor::gotoPreviousWord.
// Can't use TQChar::isPunct since "'" and "-" are not word separators
const bool isWordDelimiter = ch.isSpace()
|| ch.category() == TQChar::Punctuation_Open // e.g. '('
|| ch.category() == TQChar::Punctuation_Close // e.g. ')'
|| ch.category() == TQChar::Punctuation_Other // see http://www.fileformat.info/info/unicode/category/Po/list.htm
;
if( !beginFound && !isWordDelimiter )
{
c1.setIndex(i);
beginFound = true;
}
else if ( beginFound && isWordDelimiter )
{
c2.setIndex(i);
break;
}
}
textDocument()->setSelectionStart( selectionId, &c1 );
textDocument()->setSelectionEnd( selectionId, &c2 );
return c2;
}
KoTextCursor KoTextView::selectParagUnderCursor( const KoTextCursor& cursor, int selectionId, bool copyAndNotify )
{
KoTextCursor c1 = cursor;
KoTextCursor c2 = cursor;
c1.setIndex(0);
c2.setIndex(c1.parag()->string()->length() - 1);
textDocument()->setSelectionStart( selectionId, &c1 );
textDocument()->setSelectionEnd( selectionId, &c2 );
if ( copyAndNotify )
{
textObject()->selectionChangedNotify();
// Copy the selection.
TQApplication::clipboard()->setSelectionMode( true );
emit copy();
TQApplication::clipboard()->setSelectionMode( false );
}
return c2;
}
void KoTextView::extendParagraphSelection( const TQPoint& iPoint )
{
hideCursor();
KoTextCursor oldCursor = *m_cursor;
placeCursor( iPoint );
bool redraw = FALSE;
if ( textDocument()->hasSelection( KoTextDocument::Standard ) )
{
redraw = textDocument()->setSelectionEnd( KoTextDocument::Standard, m_cursor );
if ( textDocument()->isSelectionSwapped( KoTextDocument::Standard ) )
m_cursor->setIndex( 0 );
else
m_cursor->setIndex( m_cursor->parag()->string()->length() - 1 );
textDocument()->setSelectionEnd( KoTextDocument::Standard, m_cursor );
}
//else // it may be that the initial click was out of the frame
// textDocument()->setSelectionStart( KoTextDocument::Standard, m_cursor );
if ( redraw )
textObject()->selectionChangedNotify( false );
showCursor();
}
TQString KoTextView::wordUnderCursor( const KoTextCursor& cursor )
{
selectWordUnderCursor( cursor, KoTextDocument::Temp );
TQString text = textObject()->selectedText( KoTextDocument::Temp );
bool hasCustomItems = textObject()->selectionHasCustomItems( KoTextDocument::Temp );
textDocument()->removeSelection( KoTextDocument::Temp );
if( !hasCustomItems )
return text;
return TQString();
}
bool KoTextView::handleMousePressEvent( TQMouseEvent *e, const TQPoint &iPoint, bool canStartDrag, bool insertDirectCursor )
{
bool addParag = false;
mightStartDrag = FALSE;
hideCursor();
if (possibleTripleClick)
{
handleMouseTripleClickEvent( e, iPoint );
return addParag;
}
KoTextCursor oldCursor = *m_cursor;
addParag = placeCursor( iPoint, insertDirectCursor&& isReadWrite() );
ensureCursorVisible();
if ( e->button() != Qt::LeftButton )
{
showCursor();
return addParag;
}
KoLinkVariable* lv = linkVariable();
if ( lv && openLink( lv ) )
{
return addParag;
}
KoTextDocument * textdoc = textDocument();
if ( canStartDrag && textdoc->inSelection( KoTextDocument::Standard, iPoint ) ) {
mightStartDrag = TRUE;
m_textobj->emitShowCursor();
dragStartTimer->start( TQApplication::startDragTime(), TRUE );
dragStartPos = e->pos();
return addParag;
}
bool redraw = FALSE;
if ( textdoc->hasSelection( KoTextDocument::Standard ) ) {
if ( !( e->state() & ShiftButton ) ) {
redraw = textdoc->removeSelection( KoTextDocument::Standard );
textdoc->setSelectionStart( KoTextDocument::Standard, m_cursor );
} else {
redraw = textdoc->setSelectionEnd( KoTextDocument::Standard, m_cursor ) || redraw;
}
} else {
if ( !( e->state() & ShiftButton ) ) {
textdoc->setSelectionStart( KoTextDocument::Standard, m_cursor );
} else {
textdoc->setSelectionStart( KoTextDocument::Standard, &oldCursor );
redraw = textdoc->setSelectionEnd( KoTextDocument::Standard, m_cursor ) || redraw;
}
}
//kdDebug(32500) << "KoTextView::mousePressEvent redraw=" << redraw << endl;
if ( !redraw ) {
showCursor();
} else {
textObject()->selectionChangedNotify();
}
return addParag;
}
void KoTextView::handleMouseMoveEvent( TQMouseEvent*, const TQPoint& iPoint )
{
hideCursor();
KoTextCursor oldCursor = *m_cursor;
placeCursor( iPoint );
// Double click + mouse still down + moving the mouse selects full words.
if ( inDoubleClick ) {
KoTextCursor cl = *m_cursor;
cl.gotoWordLeft();
KoTextCursor cr = *m_cursor;
cr.gotoWordRight();
int diff = TQABS( oldCursor.parag()->at( oldCursor.index() )->x - iPoint.x() );
int ldiff = TQABS( cl.parag()->at( cl.index() )->x - iPoint.x() );
int rdiff = TQABS( cr.parag()->at( cr.index() )->x - iPoint.x() );
if ( m_cursor->parag()->lineStartOfChar( m_cursor->index() ) !=
oldCursor.parag()->lineStartOfChar( oldCursor.index() ) )
diff = 0xFFFFFF;
if ( rdiff < diff && rdiff < ldiff )
*m_cursor = cr;
else if ( ldiff < diff && ldiff < rdiff )
*m_cursor = cl;
else
*m_cursor = oldCursor;
}
bool redraw = FALSE;
if ( textDocument()->hasSelection( KoTextDocument::Standard ) )
redraw = textDocument()->setSelectionEnd( KoTextDocument::Standard, m_cursor ) || redraw;
else // it may be that the initial click was out of the frame
textDocument()->setSelectionStart( KoTextDocument::Standard, m_cursor );
if ( redraw )
textObject()->selectionChangedNotify( false );
showCursor();
}
void KoTextView::handleMouseReleaseEvent()
{
if ( dragStartTimer->isActive() )
dragStartTimer->stop();
if ( mightStartDrag ) {
textObject()->selectAll( FALSE );
mightStartDrag = false;
}
else
{
if ( textDocument()->selectionStartCursor( KoTextDocument::Standard ) == textDocument()->selectionEndCursor( KoTextDocument::Standard ) )
{
textDocument()->removeSelection( KoTextDocument::Standard );
}
textObject()->selectionChangedNotify();
// Copy the selection.
TQApplication::clipboard()->setSelectionMode( true );
emit copy();
TQApplication::clipboard()->setSelectionMode( false );
}
inDoubleClick = FALSE;
m_textobj->emitShowCursor();
}
void KoTextView::handleMouseDoubleClickEvent( TQMouseEvent*ev, const TQPoint& i )
{
//after a triple click it's not a double click but a simple click
//but as triple click didn't exist it's necessary to do it.
if(afterTripleClick)
{
handleMousePressEvent( ev, i );
return;
}
inDoubleClick = TRUE;
*m_cursor = selectWordUnderCursor( *m_cursor );
textObject()->selectionChangedNotify();
// Copy the selection.
TQApplication::clipboard()->setSelectionMode( true );
emit copy();
TQApplication::clipboard()->setSelectionMode( false );
possibleTripleClick=true;
TQTimer::singleShot(TQApplication::doubleClickInterval(),this,TQT_SLOT(tripleClickTimeout()));
}
void KoTextView::tripleClickTimeout()
{
possibleTripleClick=false;
}
void KoTextView::handleMouseTripleClickEvent( TQMouseEvent*ev, const TQPoint& /* Currently unused */ )
{
if ( ev->button() != Qt::LeftButton)
{
showCursor();
return;
}
afterTripleClick= true;
inDoubleClick = FALSE;
*m_cursor = selectParagUnderCursor( *m_cursor );
TQTimer::singleShot(TQApplication::doubleClickInterval(),this,TQT_SLOT(afterTripleClickTimeout()));
}
void KoTextView::afterTripleClickTimeout()
{
afterTripleClick=false;
}
bool KoTextView::maybeStartDrag( TQMouseEvent* e )
{
if ( mightStartDrag ) {
dragStartTimer->stop();
if ( ( e->pos() - dragStartPos ).manhattanLength() > TQApplication::startDragDistance() )
startDrag();
return true;
}
return false;
}
bool KoTextView::insertParagraph(const TQPoint &pos)
{
KoTextParag *last = textDocument()->lastParag();
KoTextFormat *f = 0;
KoParagStyle *style = last->style();
KoParagCounter *counter = last->counter();
int diff = (pos.y()- textDocument()->height());
f = last->at( last->length()-1 )->format();
int height =f->height();
int nbParag = (diff / height);
TQFontMetrics fm = f->refFontMetrics();
for (int i = 0; i < nbParag ;i++)
{
KoTextParag *s=textDocument()->createParag( textDocument(), last );
s->setFormat( 0, 1, f, TRUE );
if ( style )
s->setStyle( style );
s->setCounter( counter );
last = s;
}
bool createParag = (nbParag > 0 );
if ( createParag )
{
if ( pos.x() + f->width(' ') >= textDocument()->width())
{
//FIXME me bidi.
//change parag alignment => right alignment
last->setAlignment( TQt::AlignRight );
}
else
{
int nbSpace = pos.x()/f->width(' ');
TQString tmp;
for (int i = 0; i< nbSpace; i++)
{
tmp+=' ';
}
last->insert( 0, tmp );
}
}
return createParag;
}
bool KoTextView::placeCursor( const TQPoint &pos, bool insertDirectCursor )
{
bool addParag = false;
if ( insertDirectCursor && (pos.y()>textDocument()->height()) )
addParag = insertParagraph(pos);
KoTextParag *s = 0L;
if ( addParag )
s = textDocument()->lastParag();
else
s = textDocument()->firstParag();
m_cursor->place( pos, s, false, &m_variablePosition );
if ( m_variablePosition != -1 )
kdDebug() << k_funcinfo << " m_variablePosition set to " << m_variablePosition << endl;
updateUI( true );
return addParag;
}
void KoTextView::blinkCursor()
{
//kdDebug(32500) << "KoTextView::blinkCursor m_cursorVisible=" << m_cursorVisible
// << " blinkCursorVisible=" << blinkCursorVisible << endl;
if ( !m_cursorVisible )
return;
bool cv = m_cursorVisible;
blinkCursorVisible = !blinkCursorVisible;
drawCursor( blinkCursorVisible );
m_cursorVisible = cv;
}
void KoTextView::drawCursor( bool visible )
{
m_cursorVisible = visible;
// The rest is up to the app ;)
}
void KoTextView::focusInEvent()
{
if ( TQApplication::cursorFlashTime() > 0 )
blinkTimer->start( TQApplication::cursorFlashTime() / 2 );
showCursor();
}
void KoTextView::focusOutEvent()
{
blinkTimer->stop();
hideCursor();
}
/*void KoTextView::setFormat( KoTextFormat * newFormat, int flags, bool zoomFont)
{
textObject()->setFormat( m_cursor, m_currentFormat, newFormat, flags, zoomFont );
}*/
KCommand* KoTextView::setFormatCommand( const KoTextFormat * newFormat, int flags, bool zoomFont)
{
return textObject()->setFormatCommand( m_cursor, &m_currentFormat, newFormat, flags, zoomFont );
}
void KoTextView::dragStarted()
{
mightStartDrag = FALSE;
inDoubleClick = FALSE;
}
void KoTextView::applyStyle( const KoParagStyle * style )
{
if ( style )
{
textObject()->applyStyle( m_cursor, style );
showCurrentFormat();
}
}
void KoTextView::updateUI( bool updateFormat, bool /*force*/ )
{
// Update UI - only for those items which have changed
if ( updateFormat )
{
int i = cursor()->index();
if ( i > 0 )
--i;
#ifdef DEBUG_FORMATS
if ( currentFormat() )
kdDebug(32500) << "KoTextView::updateUI old currentFormat=" << currentFormat()
<< " " << currentFormat()->key()
<< " parag format=" << cursor()->parag()->at( i )->format()->key() << endl;
else
kdDebug(32500) << "KoTextView::updateUI old currentFormat=0" << endl;
#endif
if ( !currentFormat() || currentFormat()->key() != cursor()->parag()->at( i )->format()->key() )
{
if ( currentFormat() )
currentFormat()->removeRef();
#ifdef DEBUG_FORMATS
kdDebug(32500) << "Setting currentFormat from format " << cursor()->parag()->at( i )->format()
<< " ( character " << i << " in paragraph " << cursor()->parag()->paragId() << " )" << endl;
#endif
setCurrentFormat( textDocument()->formatCollection()->format( cursor()->parag()->at( i )->format() ) );
if ( currentFormat()->isMisspelled() ) {
KoTextFormat fNoMisspelled( *currentFormat() );
fNoMisspelled.setMisspelled( false );
currentFormat()->removeRef();
setCurrentFormat( textDocument()->formatCollection()->format( &fNoMisspelled ) );
}
showCurrentFormat();
}
}
}
void KoTextView::showCurrentFormat()
{
//kdDebug(32500) << "KoTextView::showCurrentFormat currentFormat=" << currentFormat() << " " << currentFormat()->key() << endl;
KoTextFormat format = *currentFormat();
//format.setPointSize( textObject()->docFontSize( currentFormat() ) ); // "unzoom" the font size
showFormat( &format );
}
KCommand * KoTextView::setCounterCommand( const KoParagCounter & counter )
{
return textObject()->setCounterCommand( m_cursor, counter );
}
KCommand * KoTextView::setAlignCommand( int align )
{
return textObject()->setAlignCommand( m_cursor, align );
}
KCommand * KoTextView::setLineSpacingCommand( double spacing, KoParagLayout::SpacingType _type)
{
return textObject()->setLineSpacingCommand( m_cursor, spacing, _type);
}
KCommand * KoTextView::setBordersCommand( const KoBorder& leftBorder, const KoBorder& rightBorder, const KoBorder& bottomBorder, const KoBorder& topBorder )
{
return textObject()->setBordersCommand( m_cursor, leftBorder, rightBorder, bottomBorder, topBorder );
}
KCommand * KoTextView::setJoinBordersCommand( bool join )
{
return textObject()->setJoinBordersCommand( m_cursor, join );
}
KCommand * KoTextView::setMarginCommand( TQStyleSheetItem::Margin m, double margin )
{
return textObject()->setMarginCommand( m_cursor, m, margin );
}
KCommand * KoTextView::setTabListCommand( const KoTabulatorList & tabList )
{
return textObject()->setTabListCommand( m_cursor, tabList );
}
KCommand * KoTextView::setBackgroundColorCommand( const TQColor & color )
{
return textObject()->setBackgroundColorCommand( m_cursor, color );
}
KoTextDocument * KoTextView::textDocument() const
{
return textObject()->textDocument();
}
KoVariable *KoTextView::variable()
{
if ( m_variablePosition < 0 )
return 0;
// Can't use m_cursor here, it could be before or after the variable, depending on which half of it was clicked
return textObject()->variableAtPosition( m_cursor->parag(), m_variablePosition );
}
KoLinkVariable * KoTextView::linkVariable()
{
return dynamic_cast<KoLinkVariable *>(variable());
}
TQPtrList<TDEAction> KoTextView::dataToolActionList(TDEInstance * instance, const TQString& word, bool & _singleWord )
{
m_singleWord = false;
m_wordUnderCursor = TQString();
TQString text;
if ( textObject()->hasSelection() )
{
text = textObject()->selectedText();
if ( text.find(' ') == -1 && text.find('\t') == -1 && text.find(KoTextObject::customItemChar()) == -1 )
{
m_singleWord = true;
}
else
{
m_singleWord = false;
//laurent : don't try to search thesaurus when we have a customItemChar.
if( text.find(KoTextObject::customItemChar())!=-1)
text = TQString();
}
}
else // No selection -> use word under cursor
{
if ( !word.isEmpty() )
{
m_singleWord = true;
m_wordUnderCursor = word;
text = word;
}
}
if ( text.isEmpty() || textObject()->protectContent()) // Nothing to apply a tool to
return TQPtrList<TDEAction>();
// Any tool that works on plain text is relevant
TQValueList<KDataToolInfo> tools;
tools +=KDataToolInfo::query( TQSTRING_OBJECT_NAME_STRING, "text/plain", instance );
// Add tools that work on a single word if that is the case
if ( m_singleWord )
{
_singleWord = true;
tools += KDataToolInfo::query( TQSTRING_OBJECT_NAME_STRING, "application/x-singleword", instance );
}
// Maybe one day we'll have tools that use libkotext (or qt3's qrt), to act on formatted text
tools += KDataToolInfo::query( "KoTextString", "application/x-qrichtext", instance );
return KDataToolAction::dataToolActionList( tools, this, TQT_SLOT( slotToolActivated( const KDataToolInfo &, const TQString & ) ) );
}
TQString KoTextView::currentWordOrSelection() const
{
if ( textObject()->hasSelection() )
return textObject()->selectedText();
else
return m_wordUnderCursor;
}
void KoTextView::slotToolActivated( const KDataToolInfo & info, const TQString & command )
{
KDataTool* tool = info.createTool( );
if ( !tool )
{
kdWarning() << "Could not create Tool !" << endl;
return;
}
kdDebug(32500) << "KWTextFrameSetEdit::slotToolActivated command=" << command
<< " dataType=" << info.dataType() << endl;
TQString text;
if ( textObject()->hasSelection() )
text = textObject()->selectedText();
else
text = m_wordUnderCursor;
// Preferred type is richtext
TQString mimetype = "application/x-qrichtext";
TQString datatype = "KoTextString";
// If unsupported, try text/plain
if ( !info.mimeTypes().contains( mimetype ) )
{
mimetype = "text/plain";
datatype = TQSTRING_OBJECT_NAME_STRING;
}
// If unsupported (and if we have a single word indeed), try application/x-singleword
if ( !info.mimeTypes().contains( mimetype ) && m_singleWord )
mimetype = "application/x-singleword";
kdDebug(32500) << "Running tool with datatype=" << datatype << " mimetype=" << mimetype << endl;
TQString origText = text;
if ( tool->run( command, &text, datatype, mimetype) )
{
kdDebug(32500) << "Tool ran. Text is now " << text << endl;
if ( origText != text )
{
if ( !textObject()->hasSelection() )
{
// Warning: ok for now, but wrong cursor if RMB doesn't place cursor anymore
selectWordUnderCursor( *m_cursor );
}
// replace selection with 'text'
textObject()->emitNewCommand( textObject()->replaceSelectionCommand(
cursor(), text, i18n("Replace Word") ));
}
}
delete tool;
}
bool KoTextView::openLink( KoLinkVariable* variable )
{
kdDebug() << k_funcinfo << variable->url() << endl;
KURL url( variable->url() );
if( url.isValid() )
{
(void) new KRun( url );
return true;
}
else
{
KMessageBox::sorry( 0, i18n("%1 is not a valid link.").arg( variable->url() ) );
return false;
}
}
void KoTextView::insertSoftHyphen()
{
textObject()->insert( cursor(), currentFormat(), TQChar(0xad) /* see TQRichText */,
i18n("Insert Soft Hyphen") );
}
void KoTextView::insertLineBreak()
{
textObject()->insert( cursor(), currentFormat(), TQChar('\n'),
i18n("Insert Line Break") );
}
void KoTextView::insertNonbreakingSpace()
{
textObject()->insert( cursor(), currentFormat(), TQChar(0xa0) /* see TQRichText */,
i18n("Insert Non-Breaking Space") );
}
void KoTextView::insertNonbreakingHyphen()
{
textObject()->insert( cursor(), currentFormat(), TQChar(0x2013),
i18n("Insert Non-Breaking Hyphen") );
}
void KoTextView::insertSpecialChar(TQChar _c, const TQString& font)
{
KoTextFormat * newFormat = new KoTextFormat(*currentFormat());
newFormat->setFamily( font );
if ( textObject()->hasSelection() )
{
KoTextFormat * lastFormat = currentFormat();
KCommand *cmd = textObject()->setFormatCommand( cursor(), &lastFormat, newFormat, KoTextFormat::Family );
KMacroCommand* macroCmd = new KMacroCommand( i18n("Insert Special Char") );
macroCmd->addCommand( cmd );
macroCmd->addCommand( textObject()->replaceSelectionCommand(
cursor(), _c, TQString()) );
textObject()->emitNewCommand( macroCmd );
}
else
{
textObject()->insert( cursor(), newFormat, _c, i18n("Insert Special Char"));
delete newFormat;
}
}
const KoParagLayout * KoTextView::currentParagLayoutFormat() const
{
KoTextParag * parag = m_cursor->parag();
return &(parag->paragLayout());
}
bool KoTextView::rtl() const
{
return m_cursor->parag()->string()->isRightToLeft();
}
KCommand* KoTextView::setParagLayoutFormatCommand( KoParagLayout *newLayout, int flags, int marginIndex )
{
return textObject()->setParagLayoutCommand( m_cursor, *newLayout, KoTextDocument::Standard,
flags, marginIndex, true /*createUndoRedo*/ );
}
// Heading1 -> Heading2 -> Heading3 -> normal -> 1 -> 1.1 -> 1.1.1
void KoTextView::increaseNumberingLevel( const KoStyleCollection* styleCollection )
{
// TODO: do this for each paragraph in the selection
KoParagStyle* style = 0;
int level = 0;
KoParagCounter* counter = m_cursor->parag()->counter();
if ( counter )
level = counter->depth() + 1;
if ( m_cursor->parag()->style()->isOutline() )
{
TQValueVector<KoParagStyle *> outlineStyles = styleCollection->outlineStyles();
while ( level < 10 && !style ) {
style = outlineStyles[ level ];
++level;
}
if ( !style ) // no lower-level heading exists, use standard style
style = styleCollection->defaultStyle();
}
else // non-outline, just a numbered list
{
// Try to find a style with this depth, to know if the user wants display-levels etc.
style = styleCollection->numberedStyleForLevel( level );
if ( !style ) { // not found. Make the change though.
KoParagCounter c;
if (counter) {
c = *counter;
c.setDepth( level );
c.setDisplayLevels( c.displayLevels() + 1 );
} else {
// Start a simple numbered list.
c.setNumbering(KoParagCounter::NUM_LIST);
c.setStyle(KoParagCounter::STYLE_NUM);
}
KCommand* command = textObject()->setCounterCommand( m_cursor, c );
textObject()->emitNewCommand( command );
}
}
if ( style ) // can't be 0
textObject()->applyStyle( m_cursor, style );
}
// 1.1.1 -> 1.1 -> 1 -> normal -> Heading3 -> Heading2 -> Heading1
void KoTextView::decreaseNumberingLevel( const KoStyleCollection* styleCollection )
{
// TODO: do this for each paragraph in the selection
KoParagCounter* counter = m_cursor->parag()->counter();
int level = 9;
if ( counter )
level = counter->depth() - 1;
KoParagStyle* style = 0;
if ( m_cursor->parag()->style()->isOutline() || !counter ) // heading or normal
{
if ( level == -1 ) // nothing higher than Heading1
return;
TQValueVector<KoParagStyle *> outlineStyles = styleCollection->outlineStyles();
while ( level >= 0 && !style ) {
style = outlineStyles[ level ];
--level;
}
}
else // non-outline, numbered list
{
if ( level == -1 )
style = styleCollection->defaultStyle();
else
{
style = styleCollection->numberedStyleForLevel( level );
if ( !style ) { // not found. Make the change though.
KoParagCounter c( *counter );
c.setDepth( level );
if ( c.displayLevels() > 1 ) {
c.setDisplayLevels( c.displayLevels() - 1 );
}
KCommand* command = textObject()->setCounterCommand( m_cursor, c );
textObject()->emitNewCommand( command );
}
}
}
if ( style )
textObject()->applyStyle( m_cursor, style );
}
KCommand *KoTextView::setChangeCaseOfTextCommand(KoChangeCaseDia::TypeOfCase _type)
{
TQString text;
if ( textObject()->hasSelection() )
text = textObject()->selectedText();
if(!text.isEmpty())
return textObject()->changeCaseOfText(cursor(), _type);
else
return 0L;
}
KCommand *KoTextView::prepareDropMove( KoTextCursor dropCursor )
{
Q_ASSERT( textDocument()->hasSelection( KoTextDocument::Standard ) );
// Dropping into the selection itself ?
KoTextCursor startSel = textDocument()->selectionStartCursor( KoTextDocument::Standard );
KoTextCursor endSel = textDocument()->selectionEndCursor( KoTextDocument::Standard );
bool inSelection = false;
if ( startSel.parag() == endSel.parag() )
inSelection = dropCursor.parag() == startSel.parag()
&& dropCursor.index() >= startSel.index()
&& dropCursor.index() <= endSel.index();
else
{
// Looking at first line first:
inSelection = dropCursor.parag() == startSel.parag() && dropCursor.index() >= startSel.index();
if ( !inSelection )
{
// Look at all other paragraphs except last one
KoTextParag *p = startSel.parag()->next();
while ( !inSelection && p && p != endSel.parag() )
{
inSelection = ( p == dropCursor.parag() );
p = p->next();
}
// Look at last paragraph
if ( !inSelection )
inSelection = dropCursor.parag() == endSel.parag() && dropCursor.index() <= endSel.index();
}
}
if ( inSelection || m_textobj->protectContent() )
{
textDocument()->removeSelection( KoTextDocument::Standard );
textObject()->selectionChangedNotify();
hideCursor();
*cursor() = dropCursor;
showCursor();
ensureCursorVisible();
return 0L;
}
if ( textObject()->protectContent() )
{
textDocument()->removeSelection( KoTextDocument::Standard );
textObject()->selectionChangedNotify();
}
// Tricky. We don't want to do the placeCursor after removing the selection
// (the user pointed at some text with the old selection in place).
// However, something got deleted in our parag, dropCursor's index needs adjustment.
if ( endSel.parag() == dropCursor.parag() )
{
// Does the selection starts before (other parag or same parag) ?
if ( startSel.parag() != dropCursor.parag() || startSel.index() < dropCursor.index() )
{
// If other -> endSel.parag() will get deleted. The final position is in startSel.parag(),
// where the selection started + how much after the end we are. Make a drawing :)
// If same -> simply move back by how many chars we've deleted. Funny thing is, it's the same formula.
int dropIndex = dropCursor.index();
dropCursor.setParag( startSel.parag() );
// If dropCursor - endSel < 0, selection ends after, we're dropping into selection (no-op)
dropCursor.setIndex( dropIndex - TQMIN( endSel.index(), dropIndex ) + startSel.index() );
}
kdDebug(32500) << "dropCursor: parag=" << dropCursor.parag()->paragId() << " index=" << dropCursor.index() << endl;
}
KCommand* cmd = textObject()->removeSelectedTextCommand( cursor(), KoTextDocument::Standard );
hideCursor();
*cursor() = dropCursor;
showCursor();
return cmd;
}
void KoTextView::copyTextOfComment()
{
KoNoteVariable *var = dynamic_cast<KoNoteVariable *>( variable() );
if( var )
{
KURL::List lst;
lst.append( var->note() );
TQApplication::clipboard()->setSelectionMode(true);
TQApplication::clipboard()->setData( new KURLDrag(lst, 0, 0) );
TQApplication::clipboard()->setSelectionMode(false);
TQApplication::clipboard()->setData( new KURLDrag(lst, 0, 0) );
}
}
void KoTextView::removeComment()
{
KoNoteVariable *var = dynamic_cast<KoNoteVariable *>( variable() );
if( var )
{
m_cursor->setIndex( m_variablePosition );
textDocument()->setSelectionStart( KoTextDocument::Temp, m_cursor );
m_cursor->setIndex( m_variablePosition + 1 );
textDocument()->setSelectionEnd( KoTextDocument::Temp, m_cursor );
textObject()->removeSelectedText( m_cursor, KoTextDocument::Temp, i18n("Remove Comment") );
}
}
KoParagStyle * KoTextView::createStyleFromSelection(const TQString & name)
{
KoTextCursor cursor = *m_cursor;
if ( textDocument()->hasSelection( KoTextDocument::Standard ) )
cursor = textDocument()->selectionStartCursor( KoTextDocument::Standard );
KoParagStyle * style = new KoParagStyle (name);
KoParagLayout layout(cursor.parag()->paragLayout());
layout.style = style;
style->setFollowingStyle( style );
style->format() = *(cursor.parag()->at(cursor.index())->format());
style->paragLayout() = layout;
// Select this new style - hmm only the parag layout, we don't want to erase any text-formatting
cursor.parag()->setParagLayout( style->paragLayout() );
return style;
}
void KoTextView::updateStyleFromSelection( KoParagStyle* style )
{
KoTextCursor cursor = *m_cursor;
if ( textDocument()->hasSelection( KoTextDocument::Standard ) )
cursor = textDocument()->selectionStartCursor( KoTextDocument::Standard );
style->paragLayout() = cursor.parag()->paragLayout();
style->paragLayout().style = style;
style->format() = *(cursor.parag()->at(cursor.index())->format());
}
void KoTextView::addBookmarks(const TQString &url)
{
TQString filename = locateLocal( "data", TQString::fromLatin1("konqueror/bookmarks.xml") );
KBookmarkManager *bookManager = KBookmarkManager::managerForFile( filename,false );
KBookmarkGroup group = bookManager->root();
group.addBookmark( bookManager, url, KURL( url));
bookManager->save();
// delete bookManager;
}
void KoTextView::copyLink()
{
KoLinkVariable * var=linkVariable();
if(var)
{
KURL::List lst;
lst.append( var->url() );
TQApplication::clipboard()->setSelectionMode(true);
TQApplication::clipboard()->setData( new KURLDrag(lst, 0, 0) );
TQApplication::clipboard()->setSelectionMode(false);
TQApplication::clipboard()->setData( new KURLDrag(lst, 0, 0) );
}
}
void KoTextView::removeLink()
{
KoLinkVariable * var=linkVariable();
if(var)
{
KoTextCursor c1 = *m_cursor;
KoTextCursor c2 = *m_cursor;
c1.setIndex(var->index());
c2.setIndex(var->index()+1);
textDocument()->setSelectionStart( KoTextDocument::Temp, &c1 );
textDocument()->setSelectionEnd( KoTextDocument::Temp, &c2 );
KCommand *cmd=textObject()->replaceSelectionCommand( &c1, var->value(),
i18n("Remove Link"), KoTextDocument::Temp );
if ( cmd )
textObject()->emitNewCommand( cmd );
}
}
void KoTextView::setBackSpeller( KoBgSpellCheck* backSpeller )
{
d->m_backSpeller = backSpeller;
}
#include "KoTextView.moc"
class KoBgSpellCheck;