knotes

knoteedit.cpp

00001 /*******************************************************************
00002  KNotes -- Notes for the KDE project
00003 
00004  Copyright (c) 1997-2005, The KNotes Developers
00005 
00006  This program is free software; you can redistribute it and/or
00007  modify it under the terms of the GNU General Public License
00008  as published by the Free Software Foundation; either version 2
00009  of the License, or (at your option) any later version.
00010 
00011  This program is distributed in the hope that it will be useful,
00012  but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014  GNU General Public License for more details.
00015 
00016  You should have received a copy of the GNU General Public License
00017  along with this program; if not, write to the Free Software
00018  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00019 *******************************************************************/
00020 
00021 #include <tqdragobject.h>
00022 #include <tqfont.h>
00023 
00024 #include <kdebug.h>
00025 #include <klocale.h>
00026 #include <kaction.h>
00027 #include <kurldrag.h>
00028 #include <kstdaction.h>
00029 #include <kcolordialog.h>
00030 #include <tqpopupmenu.h>
00031 #include <kiconloader.h>
00032 #include "knoteedit.h"
00033 #include "knote.h"
00034 
00035 static const short SEP = 5;
00036 static const short ICON_SIZE = 10;
00037 
00038 
00039 KNoteEdit::KNoteEdit( KActionCollection *actions, TQWidget *parent, const char *name )
00040     : KTextEdit( parent, name ), m_note( 0 )
00041 {
00042     setAcceptDrops( true );
00043     setWordWrap( WidgetWidth );
00044     setWrapPolicy( AtWhiteSpace );
00045     setLinkUnderline( true );
00046     setCheckSpellingEnabled(false);
00047     // create the actions for the RMB menu
00048     undo = KStdAction::undo( this, TQT_SLOT(undo()), actions );
00049     redo = KStdAction::redo( this, TQT_SLOT(redo()), actions );
00050     undo->setEnabled( isUndoAvailable() );
00051     redo->setEnabled( isRedoAvailable() );
00052 
00053     m_cut = KStdAction::cut( this, TQT_SLOT(cut()), actions );
00054     m_copy = KStdAction::copy( this, TQT_SLOT(copy()), actions );
00055     m_paste = KStdAction::paste( this, TQT_SLOT(paste()), actions );
00056 
00057     m_cut->setEnabled( false );
00058     m_copy->setEnabled( false );
00059     m_paste->setEnabled( true );
00060 
00061     connect( this, TQT_SIGNAL(undoAvailable(bool)), this, TQT_SLOT(setEnabledUndo(bool)) );
00062     connect( this, TQT_SIGNAL(redoAvailable(bool)), this, TQT_SLOT(setEnabledRedo(bool)) );
00063 
00064     connect( this, TQT_SIGNAL(copyAvailable(bool)), this, TQT_SLOT( slotCutEnabled( bool ) ) );
00065     connect( this, TQT_SIGNAL(copyAvailable(bool)), m_copy, TQT_SLOT(setEnabled(bool)) );
00066 
00067     new KAction( KStdGuiItem::clear(), 0, this, TQT_SLOT(clear()), actions, "edit_clear" );
00068     KStdAction::selectAll( this, TQT_SLOT(selectAll()), actions );
00069 
00070     // create the actions modifying the text format
00071     m_textBold = new KToggleAction( i18n("Bold"), "text_bold", CTRL + Key_B, 0, 0,
00072                                     actions, "format_bold" );
00073     m_textItalic = new KToggleAction( i18n("Italic"), "text_italic", CTRL + Key_I, 0, 0,
00074                                       actions, "format_italic" );
00075     m_textUnderline = new KToggleAction( i18n("Underline"), "text_under", CTRL + Key_U, 0, 0,
00076                                          actions, "format_underline" );
00077     m_textStrikeOut = new KToggleAction( i18n("Strike Out"), "text_strike", CTRL + Key_S, 0, 0,
00078                                          actions, "format_strikeout" );
00079 
00080     connect( m_textBold, TQT_SIGNAL(toggled(bool)), TQT_SLOT(setBold(bool)) );
00081     connect( m_textItalic, TQT_SIGNAL(toggled(bool)), TQT_SLOT(setItalic(bool)) );
00082     connect( m_textUnderline, TQT_SIGNAL(toggled(bool)), TQT_SLOT(setUnderline(bool)) );
00083     connect( m_textStrikeOut, TQT_SIGNAL(toggled(bool)), TQT_SLOT(textStrikeOut(bool)) );
00084 
00085     m_textAlignLeft = new KToggleAction( i18n("Align Left"), "text_left", ALT + Key_L,
00086                                  this, TQT_SLOT(textAlignLeft()),
00087                                  actions, "format_alignleft" );
00088     m_textAlignLeft->setChecked( true ); // just a dummy, will be updated later
00089     m_textAlignCenter = new KToggleAction( i18n("Align Center"), "text_center", ALT + Key_C,
00090                                  this, TQT_SLOT(textAlignCenter()),
00091                                  actions, "format_aligncenter" );
00092     m_textAlignRight = new KToggleAction( i18n("Align Right"), "text_right", ALT + Key_R,
00093                                  this, TQT_SLOT(textAlignRight()),
00094                                  actions, "format_alignright" );
00095     m_textAlignBlock = new KToggleAction( i18n("Align Block"), "text_block", ALT + Key_B,
00096                                  this, TQT_SLOT(textAlignBlock()),
00097                                  actions, "format_alignblock" );
00098 
00099     m_textAlignLeft->setExclusiveGroup( "align" );
00100     m_textAlignCenter->setExclusiveGroup( "align" );
00101     m_textAlignRight->setExclusiveGroup( "align" );
00102     m_textAlignBlock->setExclusiveGroup( "align" );
00103 
00104     m_textList = new KToggleAction( i18n("List"), "enum_list", 0,
00105                                     this, TQT_SLOT(textList()),
00106                                     actions, "format_list" );
00107 
00108     m_textList->setExclusiveGroup( "style" );
00109 
00110     m_textSuper = new KToggleAction( i18n("Superscript"), "text_super", 0,
00111                                      this, TQT_SLOT(textSuperScript()),
00112                                      actions, "format_super" );
00113     m_textSub = new KToggleAction( i18n("Subscript"), "text_sub", 0,
00114                                    this, TQT_SLOT(textSubScript()),
00115                                    actions, "format_sub" );
00116 
00117     m_textSuper->setExclusiveGroup( "valign" );
00118     m_textSub->setExclusiveGroup( "valign" );
00119 
00120 // There is no easy possibility to implement text indenting with QTextEdit
00121 //
00122 //     m_textIncreaseIndent = new KAction( i18n("Increase Indent"), "format_increaseindent", 0,
00123 //                                         this, TQT_SLOT(textIncreaseIndent()),
00124 //                                         actions, "format_increaseindent" );
00125 //
00126 //     m_textDecreaseIndent = new KAction( i18n("Decrease Indent"), "format_decreaseindent", 0,
00127 //                                         this, TQT_SLOT(textDecreaseIndent()),
00128 //                                         actions, "format_decreaseindent" );
00129 
00130     TQPixmap pix( ICON_SIZE, ICON_SIZE );
00131     pix.fill( black );     // just a dummy, gets updated before widget is shown
00132     m_textColor = new KAction( i18n("Text Color..."), pix, 0, this,
00133                                   TQT_SLOT(textColor()), actions, "format_color" );
00134 
00135     m_textFont = new KFontAction( i18n("Text Font"), "text", KKey(),
00136                                   actions, "format_font" );
00137     connect( m_textFont, TQT_SIGNAL(activated( const TQString & )),
00138              this, TQT_SLOT(setFamily( const TQString & )) );
00139 
00140     m_textSize = new KFontSizeAction( i18n("Text Size"), KKey(),
00141                                       actions, "format_size" );
00142     connect( m_textSize, TQT_SIGNAL(fontSizeChanged( int )),
00143              this, TQT_SLOT(setPointSize( int )) );
00144 
00145     // TQTextEdit connections
00146     connect( this, TQT_SIGNAL(returnPressed()), TQT_SLOT(slotReturnPressed()) );
00147     connect( this, TQT_SIGNAL(currentFontChanged( const TQFont & )),
00148              this, TQT_SLOT(fontChanged( const TQFont & )) );
00149     connect( this, TQT_SIGNAL(currentColorChanged( const TQColor & )),
00150              this, TQT_SLOT(colorChanged( const TQColor & )) );
00151     connect( this, TQT_SIGNAL(currentAlignmentChanged( int )),
00152              this, TQT_SLOT(alignmentChanged( int )) );
00153     connect( this, TQT_SIGNAL(currentVerticalAlignmentChanged( VerticalAlignment )),
00154              this, TQT_SLOT(verticalAlignmentChanged( VerticalAlignment )) );
00155 }
00156 
00157 KNoteEdit::~KNoteEdit()
00158 {
00159 }
00160 
00161 void KNoteEdit::setEnabledRedo( bool b )
00162 {
00163     redo->setEnabled( b && !isReadOnly() );
00164 }
00165 
00166 void KNoteEdit::setEnabledUndo( bool b )
00167 {
00168     undo->setEnabled( b && !isReadOnly() );
00169 }
00170 
00171 void KNoteEdit::slotCutEnabled( bool b )
00172 {
00173     m_cut->setEnabled( b && !isReadOnly() );
00174 }
00175 
00176 void KNoteEdit::setText( const TQString& text )
00177 {
00178     // to update the font and font size combo box - TQTextEdit stopped
00179     // emitting the currentFontChanged signal with the new optimizations
00180     KTextEdit::setText( text );
00181     fontChanged( currentFont() );
00182 }
00183 
00184 void KNoteEdit::setTextFont( const TQFont& font )
00185 {
00186     if ( textFormat() == PlainText )
00187         setFont( font );
00188     else
00189         setCurrentFont( font );
00190 }
00191 
00192 void KNoteEdit::setTextColor( const TQColor& color )
00193 {
00194     setColor( color );
00195     colorChanged( color );
00196 }
00197 
00198 void KNoteEdit::setTabStop( int tabs )
00199 {
00200     TQFontMetrics fm( font() );
00201     setTabStopWidth( fm.width( 'x' ) * tabs );
00202 }
00203 
00204 void KNoteEdit::setAutoIndentMode( bool newmode )
00205 {
00206     m_autoIndentMode = newmode;
00207 }
00208 
00209 
00212 void KNoteEdit::setTextFormat( TextFormat f )
00213 {
00214     if ( f == textFormat() )
00215         return;
00216 
00217     if ( f == RichText )
00218     {
00219         TQString t = text();
00220         KTextEdit::setTextFormat( f );
00221 
00222         // if the note contains html/xml source try to display it, otherwise
00223         // get the modified text again and set it to preserve newlines
00224         if ( TQStyleSheet::mightBeRichText( t ) )
00225             setText( t );
00226         else
00227             setText( text() );
00228 
00229         enableRichTextActions();
00230     }
00231     else
00232     {
00233         KTextEdit::setTextFormat( f );
00234         TQString t = text();
00235         setText( t );
00236 
00237         disableRichTextActions();
00238     }
00239 }
00240 
00241 void KNoteEdit::textStrikeOut( bool s )
00242 {
00243     // TQTextEdit does not support stroke out text (no saving,
00244     // no changing of more than one selected character)
00245     TQFont font;
00246 
00247     if ( !hasSelectedText() )
00248     {
00249         font = currentFont();
00250         font.setStrikeOut( s );
00251         setCurrentFont( font );
00252     }
00253     else
00254     {
00255         int pFrom, pTo, iFrom, iTo, iF, iT;
00256         int cp, ci;
00257 
00258         getSelection( &pFrom, &iFrom, &pTo, &iTo );
00259         getCursorPosition( &cp, &ci );
00260 
00261         for ( int p = pFrom; p <= pTo; p++ )
00262         {
00263             iF = 0;
00264             iT = paragraphLength( p );
00265 
00266             if ( p == pFrom )
00267                 iF = iFrom;
00268 
00269             if ( p == pTo )
00270                 iT = iTo;
00271 
00272             for ( int i = iF; i < iT; i++ )
00273             {
00274                 setCursorPosition( p, i + 1 );
00275                 setSelection( p, i, p, i + 1 );
00276                 font = currentFont();
00277                 font.setStrikeOut( s );
00278                 setCurrentFont( font );
00279             }
00280         }
00281 
00282         setSelection( pFrom, iFrom, pTo, iTo );
00283         setCursorPosition( cp, ci );
00284     }
00285 }
00286 
00287 void KNoteEdit::textColor()
00288 {
00289     if ( m_note )
00290         m_note->blockEmitDataChanged( true );
00291     TQColor c = color();
00292     int ret = KColorDialog::getColor( c, this );
00293     if ( ret == TQDialog::Accepted )
00294         setTextColor( c );
00295     if ( m_note )
00296         m_note->blockEmitDataChanged( false );
00297 }
00298 
00299 void KNoteEdit::textAlignLeft()
00300 {
00301     setAlignment( AlignLeft );
00302     m_textAlignLeft->setChecked( true );
00303 }
00304 
00305 void KNoteEdit::textAlignCenter()
00306 {
00307     setAlignment( AlignCenter );
00308     m_textAlignCenter->setChecked( true );
00309 }
00310 
00311 void KNoteEdit::textAlignRight()
00312 {
00313     setAlignment( AlignRight );
00314     m_textAlignRight->setChecked( true );
00315 }
00316 
00317 void KNoteEdit::textAlignBlock()
00318 {
00319     setAlignment( AlignJustify );
00320     m_textAlignBlock->setChecked( true );
00321 }
00322 
00323 void KNoteEdit::textList()
00324 {
00325     if ( m_textList->isChecked() )
00326         setParagType( TQStyleSheetItem::DisplayListItem, TQStyleSheetItem::ListDisc );
00327     else
00328         setParagType( TQStyleSheetItem::DisplayBlock, TQStyleSheetItem::ListDisc );
00329 }
00330 
00331 void KNoteEdit::textSuperScript()
00332 {
00333     if ( m_textSuper->isChecked() )
00334         setVerticalAlignment( AlignSuperScript );
00335     else
00336         setVerticalAlignment( AlignNormal );
00337 }
00338 
00339 void KNoteEdit::textSubScript()
00340 {
00341     if ( m_textSub->isChecked() )
00342         setVerticalAlignment( AlignSubScript );
00343     else
00344         setVerticalAlignment( AlignNormal );
00345 }
00346 
00347 //void KNoteEdit::textIncreaseIndent()
00348 //{
00349 //}
00350 
00351 //void KNoteEdit::textDecreaseIndent()
00352 //{
00353 //}
00354 
00355 
00358 void KNoteEdit::contentsDragEnterEvent( TQDragEnterEvent *e )
00359 {
00360     if ( KURLDrag::canDecode( e ) )
00361         e->accept();
00362     else
00363         KTextEdit::contentsDragEnterEvent( e );
00364 }
00365 
00366 void KNoteEdit::contentsDropEvent( TQDropEvent *e )
00367 {
00368     KURL::List list;
00369 
00370     if ( KURLDrag::decode( e, list ) )
00371     {
00372     KURL::List::ConstIterator begin = list.constBegin();
00373     KURL::List::ConstIterator end = list.constEnd();
00374         for ( KURL::List::ConstIterator it = begin; it != end; ++it )
00375         {
00376             if ( it != begin )
00377                 insert( ", " );
00378 
00379             insert( (*it).prettyURL() );
00380         }
00381     }
00382     else
00383         KTextEdit::contentsDropEvent( e );
00384 }
00385 
00388 void KNoteEdit::slotReturnPressed()
00389 {
00390     if ( m_autoIndentMode )
00391         autoIndent();
00392 }
00393 
00394 void KNoteEdit::fontChanged( const TQFont &f )
00395 {
00396     m_textFont->setFont( f.family() );
00397     m_textSize->setFontSize( f.pointSize() );
00398 
00399     m_textBold->setChecked( f.bold() );
00400     m_textItalic->setChecked( f.italic() );
00401     m_textUnderline->setChecked( f.underline() );
00402     m_textStrikeOut->setChecked( f.strikeOut() );
00403 }
00404 
00405 void KNoteEdit::colorChanged( const TQColor &c )
00406 {
00407     TQPixmap pix( ICON_SIZE, ICON_SIZE );
00408     pix.fill( c );
00409     m_textColor->setIconSet( pix );
00410 }
00411 
00412 void KNoteEdit::alignmentChanged( int a )
00413 {
00414     // TODO: AlignAuto
00415     if ( ( a == AlignAuto ) || ( a & AlignLeft ) )
00416         m_textAlignLeft->setChecked( true );
00417     else if ( ( a & AlignHCenter ) )
00418         m_textAlignCenter->setChecked( true );
00419     else if ( ( a & AlignRight ) )
00420         m_textAlignRight->setChecked( true );
00421     else if ( ( a & AlignJustify ) )
00422         m_textAlignBlock->setChecked( true );
00423 }
00424 
00425 void KNoteEdit::verticalAlignmentChanged( VerticalAlignment a )
00426 {
00427     if ( a == AlignNormal )
00428     {
00429         m_textSuper->setChecked( false );
00430         m_textSub->setChecked( false );
00431     }
00432     else if ( a == AlignSuperScript )
00433         m_textSuper->setChecked( true );
00434     else if ( a == AlignSubScript )
00435         m_textSub->setChecked( true );
00436 }
00437 
00438 
00441 void KNoteEdit::autoIndent()
00442 {
00443     int para, index;
00444     TQString string;
00445     getCursorPosition( &para, &index );
00446     while ( para > 0 && string.stripWhiteSpace().isEmpty() )
00447         string = text( --para );
00448 
00449     if ( string.stripWhiteSpace().isEmpty() )
00450         return;
00451 
00452     // This routine returns the whitespace before the first non white space
00453     // character in string.
00454     // It is assumed that string contains at least one non whitespace character
00455     // ie \n \r \t \v \f and space
00456     TQString indentString;
00457 
00458     int len = string.length();
00459     int i = 0;
00460     while ( i < len && string.at(i).isSpace() )
00461         indentString += string.at( i++ );
00462 
00463     if ( !indentString.isEmpty() )
00464         insert( indentString );
00465 }
00466 
00467 void KNoteEdit::emitLinkClicked( const TQString &s )
00468 {
00469     kdDebug(5500) << k_funcinfo << s << endl;
00470 }
00471 
00472 void KNoteEdit::enableRichTextActions()
00473 {
00474     m_textColor->setEnabled( true );
00475     m_textFont->setEnabled( true );
00476     m_textSize->setEnabled( true );
00477 
00478     m_textBold->setEnabled( true );
00479     m_textItalic->setEnabled( true );
00480     m_textUnderline->setEnabled( true );
00481     m_textStrikeOut->setEnabled( true );
00482 
00483     m_textAlignLeft->setEnabled( true );
00484     m_textAlignCenter->setEnabled( true );
00485     m_textAlignRight->setEnabled( true );
00486     m_textAlignBlock->setEnabled( true );
00487 
00488     m_textList->setEnabled( true );
00489     m_textSuper->setEnabled( true );
00490     m_textSub->setEnabled( true );
00491 
00492 //    m_textIncreaseIndent->setEnabled( true );
00493 //    m_textDecreaseIndent->setEnabled( true );
00494 }
00495 
00496 void KNoteEdit::disableRichTextActions()
00497 {
00498     m_textColor->setEnabled( false );
00499     m_textFont->setEnabled( false );
00500     m_textSize->setEnabled( false );
00501 
00502     m_textBold->setEnabled( false );
00503     m_textItalic->setEnabled( false );
00504     m_textUnderline->setEnabled( false );
00505     m_textStrikeOut->setEnabled( false );
00506 
00507     m_textAlignLeft->setEnabled( false );
00508     m_textAlignCenter->setEnabled( false );
00509     m_textAlignRight->setEnabled( false );
00510     m_textAlignBlock->setEnabled( false );
00511 
00512     m_textList->setEnabled( false );
00513     m_textSuper->setEnabled( false );
00514     m_textSub->setEnabled( false );
00515 
00516 //    m_textIncreaseIndent->setEnabled( false );
00517 //    m_textDecreaseIndent->setEnabled( false );
00518 }
00519 
00520 void KNoteEdit::slotAllowTab()
00521 {
00522     setTabChangesFocus(!tabChangesFocus());
00523 }
00524 
00525 TQPopupMenu *KNoteEdit::createPopupMenu( const TQPoint &pos )
00526 {
00527     enum { IdUndo, IdRedo, IdSep1, IdCut, IdCopy, IdPaste, IdClear, IdSep2, IdSelectAll };
00528 
00529     TQPopupMenu *menu = TQTextEdit::createPopupMenu( pos );
00530 
00531     if ( isReadOnly() )
00532       menu->changeItem( menu->idAt(0), SmallIconSet("editcopy"), menu->text( menu->idAt(0) ) );
00533     else {
00534       int id = menu->idAt(0);
00535       menu->changeItem( id - IdUndo, SmallIconSet("undo"), menu->text( id - IdUndo) );
00536       menu->changeItem( id - IdRedo, SmallIconSet("redo"), menu->text( id - IdRedo) );
00537       menu->changeItem( id - IdCut, SmallIconSet("editcut"), menu->text( id - IdCut) );
00538       menu->changeItem( id - IdCopy, SmallIconSet("editcopy"), menu->text( id - IdCopy) );
00539       menu->changeItem( id - IdPaste, SmallIconSet("editpaste"), menu->text( id - IdPaste) );
00540       menu->changeItem( id - IdClear, SmallIconSet("editclear"), menu->text( id - IdClear) );
00541 
00542         menu->insertSeparator();
00543         id = menu->insertItem( SmallIconSet( "spellcheck" ), i18n( "Check Spelling..." ),
00544                                    this, TQT_SLOT( checkSpelling() ) );
00545 
00546         if( text().isEmpty() )
00547             menu->setItemEnabled( id, false );
00548 
00549     menu->insertSeparator();
00550     id=menu->insertItem(i18n("Allow Tabulations"),this,TQT_SLOT(slotAllowTab()));
00551     menu->setItemChecked(id, !tabChangesFocus());
00552     }
00553 
00554     return menu;
00555 }
00556 
00557 #include "knoteedit.moc"