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( TQT_TQOBJECT(this), TQT_SLOT(undo()), actions ); 00049 redo = KStdAction::redo( TQT_TQOBJECT(this), TQT_SLOT(redo()), actions ); 00050 undo->setEnabled( isUndoAvailable() ); 00051 redo->setEnabled( isRedoAvailable() ); 00052 00053 m_cut = KStdAction::cut( TQT_TQOBJECT(this), TQT_SLOT(cut()), actions ); 00054 m_copy = KStdAction::copy( TQT_TQOBJECT(this), TQT_SLOT(copy()), actions ); 00055 m_paste = KStdAction::paste( TQT_TQOBJECT(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)), TQT_TQOBJECT(this), TQT_SLOT(setEnabledUndo(bool)) ); 00062 connect( this, TQT_SIGNAL(redoAvailable(bool)), TQT_TQOBJECT(this), TQT_SLOT(setEnabledRedo(bool)) ); 00063 00064 connect( this, TQT_SIGNAL(copyAvailable(bool)), TQT_TQOBJECT(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, TQT_TQOBJECT(this), TQT_SLOT(clear()), actions, "edit_clear" ); 00068 KStdAction::selectAll( TQT_TQOBJECT(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 TQT_TQOBJECT(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 TQT_TQOBJECT(this), TQT_SLOT(textAlignCenter()), 00091 actions, "format_aligncenter" ); 00092 m_textAlignRight = new KToggleAction( i18n("Align Right"), "text_right", ALT + Key_R, 00093 TQT_TQOBJECT(this), TQT_SLOT(textAlignRight()), 00094 actions, "format_alignright" ); 00095 m_textAlignBlock = new KToggleAction( i18n("Align Block"), "text_block", ALT + Key_B, 00096 TQT_TQOBJECT(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 TQT_TQOBJECT(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 TQT_TQOBJECT(this), TQT_SLOT(textSuperScript()), 00112 actions, "format_super" ); 00113 m_textSub = new KToggleAction( i18n("Subscript"), "text_sub", 0, 00114 TQT_TQOBJECT(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 TQTextEdit 00121 // 00122 // m_textIncreaseIndent = new KAction( i18n("Increase Indent"), "format_increaseindent", 0, 00123 // TQT_TQOBJECT(this), TQT_SLOT(textIncreaseIndent()), 00124 // actions, "format_increaseindent" ); 00125 // 00126 // m_textDecreaseIndent = new KAction( i18n("Decrease Indent"), "format_decreaseindent", 0, 00127 // TQT_TQOBJECT(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, TQT_TQOBJECT(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 TQT_TQOBJECT(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 TQT_TQOBJECT(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 TQT_TQOBJECT(this), TQT_SLOT(fontChanged( const TQFont & )) ); 00149 connect( this, TQT_SIGNAL(currentColorChanged( const TQColor & )), 00150 TQT_TQOBJECT(this), TQT_SLOT(colorChanged( const TQColor & )) ); 00151 connect( this, TQT_SIGNAL(currentAlignmentChanged( int )), 00152 TQT_TQOBJECT(this), TQT_SLOT(alignmentChanged( int )) ); 00153 connect( this, TQT_SIGNAL(currentVerticalAlignmentChanged( VerticalAlignment )), 00154 TQT_TQOBJECT(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( ¶, &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 TQT_TQOBJECT(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"