knotes

knoteedit.cpp
1/*******************************************************************
2 KNotes -- Notes for the KDE project
3
4 Copyright (c) 1997-2005, The KNotes Developers
5
6 This program is free software; you can redistribute it and/or
7 modify it under the terms of the GNU General Public License
8 as published by the Free Software Foundation; either version 2
9 of the License, or (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19*******************************************************************/
20
21#include <tqdragobject.h>
22#include <tqfont.h>
23
24#include <kdebug.h>
25#include <tdelocale.h>
26#include <tdeaction.h>
27#include <kurldrag.h>
28#include <kstdaction.h>
29#include <kcolordialog.h>
30#include <tqpopupmenu.h>
31#include <kiconloader.h>
32#include "knoteedit.h"
33#include "knote.h"
34
35static const short SEP = 5;
36static const short ICON_SIZE = 10;
37
38
39KNoteEdit::KNoteEdit( TDEActionCollection *actions, TQWidget *parent, const char *name )
40 : KTextEdit( parent, name ), m_note( 0 )
41{
42 setAcceptDrops( true );
43 setWordWrap( WidgetWidth );
44 setWrapPolicy( AtWhiteSpace );
45 setLinkUnderline( true );
46 setCheckSpellingEnabled(false);
47 // create the actions for the RMB menu
48 undo = KStdAction::undo( this, TQ_SLOT(undo()), actions );
49 redo = KStdAction::redo( this, TQ_SLOT(redo()), actions );
50 undo->setEnabled( isUndoAvailable() );
51 redo->setEnabled( isRedoAvailable() );
52
53 m_cut = KStdAction::cut( this, TQ_SLOT(cut()), actions );
54 m_copy = KStdAction::copy( this, TQ_SLOT(copy()), actions );
55 m_paste = KStdAction::paste( this, TQ_SLOT(paste()), actions );
56
57 m_cut->setEnabled( false );
58 m_copy->setEnabled( false );
59 m_paste->setEnabled( true );
60
61 connect( this, TQ_SIGNAL(undoAvailable(bool)), this, TQ_SLOT(setEnabledUndo(bool)) );
62 connect( this, TQ_SIGNAL(redoAvailable(bool)), this, TQ_SLOT(setEnabledRedo(bool)) );
63
64 connect( this, TQ_SIGNAL(copyAvailable(bool)), this, TQ_SLOT( slotCutEnabled( bool ) ) );
65 connect( this, TQ_SIGNAL(copyAvailable(bool)), m_copy, TQ_SLOT(setEnabled(bool)) );
66
67 new TDEAction( KStdGuiItem::clear(), 0, this, TQ_SLOT(clear()), actions, "edit_clear" );
68 KStdAction::selectAll( this, TQ_SLOT(selectAll()), actions );
69
70 // create the actions modifying the text format
71 m_textBold = new TDEToggleAction( i18n("Bold"), "format-text-bold", CTRL + Key_B, 0, 0,
72 actions, "format_bold" );
73 m_textItalic = new TDEToggleAction( i18n("Italic"), "format-text-italic", CTRL + Key_I, 0, 0,
74 actions, "format_italic" );
75 m_textUnderline = new TDEToggleAction( i18n("Underline"), "format-text-underline", CTRL + Key_U, 0, 0,
76 actions, "format_underline" );
77 m_textStrikeOut = new TDEToggleAction( i18n("Strike Out"), "format-text-strikethrough", CTRL + Key_S, 0, 0,
78 actions, "format_strikeout" );
79
80 connect( m_textBold, TQ_SIGNAL(toggled(bool)), TQ_SLOT(setBold(bool)) );
81 connect( m_textItalic, TQ_SIGNAL(toggled(bool)), TQ_SLOT(setItalic(bool)) );
82 connect( m_textUnderline, TQ_SIGNAL(toggled(bool)), TQ_SLOT(setUnderline(bool)) );
83 connect( m_textStrikeOut, TQ_SIGNAL(toggled(bool)), TQ_SLOT(textStrikeOut(bool)) );
84
85 m_textAlignLeft = new TDEToggleAction( i18n("Align Left"), "format-text-direction-ltr", ALT + Key_L,
86 this, TQ_SLOT(textAlignLeft()),
87 actions, "format_alignleft" );
88 m_textAlignLeft->setChecked( true ); // just a dummy, will be updated later
89 m_textAlignCenter = new TDEToggleAction( i18n("Align Center"), "text_center", ALT + Key_C,
90 this, TQ_SLOT(textAlignCenter()),
91 actions, "format_aligncenter" );
92 m_textAlignRight = new TDEToggleAction( i18n("Align Right"), "format-text-direction-rtl", ALT + Key_R,
93 this, TQ_SLOT(textAlignRight()),
94 actions, "format_alignright" );
95 m_textAlignBlock = new TDEToggleAction( i18n("Align Block"), "text_block", ALT + Key_B,
96 this, TQ_SLOT(textAlignBlock()),
97 actions, "format_alignblock" );
98
99 m_textAlignLeft->setExclusiveGroup( "align" );
100 m_textAlignCenter->setExclusiveGroup( "align" );
101 m_textAlignRight->setExclusiveGroup( "align" );
102 m_textAlignBlock->setExclusiveGroup( "align" );
103
104 m_textList = new TDEToggleAction( i18n("List"), "enum_list", 0,
105 this, TQ_SLOT(textList()),
106 actions, "format_list" );
107
108 m_textList->setExclusiveGroup( "style" );
109
110 m_textSuper = new TDEToggleAction( i18n("Superscript"), "text_super", 0,
111 this, TQ_SLOT(textSuperScript()),
112 actions, "format_super" );
113 m_textSub = new TDEToggleAction( i18n("Subscript"), "text_sub", 0,
114 this, TQ_SLOT(textSubScript()),
115 actions, "format_sub" );
116
117 m_textSuper->setExclusiveGroup( "valign" );
118 m_textSub->setExclusiveGroup( "valign" );
119
120// There is no easy possibility to implement text indenting with TQTextEdit
121//
122// m_textIncreaseIndent = new TDEAction( i18n("Increase Indent"), "format_increaseindent", 0,
123// this, TQ_SLOT(textIncreaseIndent()),
124// actions, "format_increaseindent" );
125//
126// m_textDecreaseIndent = new TDEAction( i18n("Decrease Indent"), "format_decreaseindent", 0,
127// this, TQ_SLOT(textDecreaseIndent()),
128// actions, "format_decreaseindent" );
129
130 TQPixmap pix( ICON_SIZE, ICON_SIZE );
131 pix.fill( black ); // just a dummy, gets updated before widget is shown
132 m_textColor = new TDEAction( i18n("Text Color..."), pix, 0, this,
133 TQ_SLOT(textColor()), actions, "format_color" );
134
135 m_textFont = new TDEFontAction( i18n("Text Font"), "text", KKey(),
136 actions, "format_font" );
137 connect( m_textFont, TQ_SIGNAL(activated( const TQString & )),
138 this, TQ_SLOT(setFamily( const TQString & )) );
139
140 m_textSize = new TDEFontSizeAction( i18n("Text Size"), KKey(),
141 actions, "format_size" );
142 connect( m_textSize, TQ_SIGNAL(fontSizeChanged( int )),
143 this, TQ_SLOT(setPointSize( int )) );
144
145 // TQTextEdit connections
146 connect( this, TQ_SIGNAL(returnPressed()), TQ_SLOT(slotReturnPressed()) );
147 connect( this, TQ_SIGNAL(currentFontChanged( const TQFont & )),
148 this, TQ_SLOT(fontChanged( const TQFont & )) );
149 connect( this, TQ_SIGNAL(currentColorChanged( const TQColor & )),
150 this, TQ_SLOT(colorChanged( const TQColor & )) );
151 connect( this, TQ_SIGNAL(currentAlignmentChanged( int )),
152 this, TQ_SLOT(alignmentChanged( int )) );
153 connect( this, TQ_SIGNAL(currentVerticalAlignmentChanged( VerticalAlignment )),
154 this, TQ_SLOT(verticalAlignmentChanged( VerticalAlignment )) );
155}
156
157KNoteEdit::~KNoteEdit()
158{
159}
160
161void KNoteEdit::setEnabledRedo( bool b )
162{
163 redo->setEnabled( b && !isReadOnly() );
164}
165
166void KNoteEdit::setEnabledUndo( bool b )
167{
168 undo->setEnabled( b && !isReadOnly() );
169}
170
171void KNoteEdit::slotCutEnabled( bool b )
172{
173 m_cut->setEnabled( b && !isReadOnly() );
174}
175
176void KNoteEdit::setText( const TQString& text )
177{
178 // to update the font and font size combo box - TQTextEdit stopped
179 // emitting the currentFontChanged signal with the new optimizations
180 KTextEdit::setText( text );
181 fontChanged( currentFont() );
182}
183
184void KNoteEdit::setTextFont( const TQFont& font )
185{
186 if ( textFormat() == PlainText )
187 setFont( font );
188 else
189 setCurrentFont( font );
190}
191
192void KNoteEdit::setTextColor( const TQColor& color )
193{
194 setColor( color );
195 colorChanged( color );
196}
197
198void KNoteEdit::setTabStop( int tabs )
199{
200 TQFontMetrics fm( font() );
201 setTabStopWidth( fm.width( 'x' ) * tabs );
202}
203
204void KNoteEdit::setAutoIndentMode( bool newmode )
205{
206 m_autoIndentMode = newmode;
207}
208
209
212void KNoteEdit::setTextFormat( TextFormat f )
213{
214 if ( f == textFormat() )
215 return;
216
217 if ( f == RichText )
218 {
219 TQString t = text();
220 KTextEdit::setTextFormat( f );
221
222 // if the note contains html/xml source try to display it, otherwise
223 // get the modified text again and set it to preserve newlines
224 if ( TQStyleSheet::mightBeRichText( t ) )
225 setText( t );
226 else
227 setText( text() );
228
229 enableRichTextActions();
230 }
231 else
232 {
233 KTextEdit::setTextFormat( f );
234 TQString t = text();
235 setText( t );
236
237 disableRichTextActions();
238 }
239}
240
241void KNoteEdit::textStrikeOut( bool s )
242{
243 // TQTextEdit does not support stroke out text (no saving,
244 // no changing of more than one selected character)
245 TQFont font;
246
247 if ( !hasSelectedText() )
248 {
249 font = currentFont();
250 font.setStrikeOut( s );
251 setCurrentFont( font );
252 }
253 else
254 {
255 int pFrom, pTo, iFrom, iTo, iF, iT;
256 int cp, ci;
257
258 getSelection( &pFrom, &iFrom, &pTo, &iTo );
259 getCursorPosition( &cp, &ci );
260
261 for ( int p = pFrom; p <= pTo; p++ )
262 {
263 iF = 0;
264 iT = paragraphLength( p );
265
266 if ( p == pFrom )
267 iF = iFrom;
268
269 if ( p == pTo )
270 iT = iTo;
271
272 for ( int i = iF; i < iT; i++ )
273 {
274 setCursorPosition( p, i + 1 );
275 setSelection( p, i, p, i + 1 );
276 font = currentFont();
277 font.setStrikeOut( s );
278 setCurrentFont( font );
279 }
280 }
281
282 setSelection( pFrom, iFrom, pTo, iTo );
283 setCursorPosition( cp, ci );
284 }
285}
286
287void KNoteEdit::textColor()
288{
289 if ( m_note )
290 m_note->blockEmitDataChanged( true );
291 TQColor c = color();
292 int ret = KColorDialog::getColor( c, this );
293 if ( ret == TQDialog::Accepted )
294 setTextColor( c );
295 if ( m_note )
296 m_note->blockEmitDataChanged( false );
297}
298
299void KNoteEdit::textAlignLeft()
300{
301 setAlignment( AlignLeft );
302 m_textAlignLeft->setChecked( true );
303}
304
305void KNoteEdit::textAlignCenter()
306{
307 setAlignment( AlignCenter );
308 m_textAlignCenter->setChecked( true );
309}
310
311void KNoteEdit::textAlignRight()
312{
313 setAlignment( AlignRight );
314 m_textAlignRight->setChecked( true );
315}
316
317void KNoteEdit::textAlignBlock()
318{
319 setAlignment( AlignJustify );
320 m_textAlignBlock->setChecked( true );
321}
322
323void KNoteEdit::textList()
324{
325 if ( m_textList->isChecked() )
326 setParagType( TQStyleSheetItem::DisplayListItem, TQStyleSheetItem::ListDisc );
327 else
328 setParagType( TQStyleSheetItem::DisplayBlock, TQStyleSheetItem::ListDisc );
329}
330
331void KNoteEdit::textSuperScript()
332{
333 if ( m_textSuper->isChecked() )
334 setVerticalAlignment( AlignSuperScript );
335 else
336 setVerticalAlignment( AlignNormal );
337}
338
339void KNoteEdit::textSubScript()
340{
341 if ( m_textSub->isChecked() )
342 setVerticalAlignment( AlignSubScript );
343 else
344 setVerticalAlignment( AlignNormal );
345}
346
347//void KNoteEdit::textIncreaseIndent()
348//{
349//}
350
351//void KNoteEdit::textDecreaseIndent()
352//{
353//}
354
355
358void KNoteEdit::contentsDragEnterEvent( TQDragEnterEvent *e )
359{
360 if ( KURLDrag::canDecode( e ) )
361 e->accept();
362 else
363 KTextEdit::contentsDragEnterEvent( e );
364}
365
366void KNoteEdit::contentsDropEvent( TQDropEvent *e )
367{
368 KURL::List list;
369
370 if ( KURLDrag::decode( e, list ) )
371 {
372 KURL::List::ConstIterator begin = list.constBegin();
373 KURL::List::ConstIterator end = list.constEnd();
374 for ( KURL::List::ConstIterator it = begin; it != end; ++it )
375 {
376 if ( it != begin )
377 insert( ", " );
378
379 insert( (*it).prettyURL() );
380 }
381 }
382 else
383 KTextEdit::contentsDropEvent( e );
384}
385
388void KNoteEdit::slotReturnPressed()
389{
390 if ( m_autoIndentMode )
391 autoIndent();
392}
393
394void KNoteEdit::fontChanged( const TQFont &f )
395{
396 m_textFont->setFont( f.family() );
397 m_textSize->setFontSize( f.pointSize() );
398
399 m_textBold->setChecked( f.bold() );
400 m_textItalic->setChecked( f.italic() );
401 m_textUnderline->setChecked( f.underline() );
402 m_textStrikeOut->setChecked( f.strikeOut() );
403}
404
405void KNoteEdit::colorChanged( const TQColor &c )
406{
407 TQPixmap pix( ICON_SIZE, ICON_SIZE );
408 pix.fill( c );
409 m_textColor->setIconSet( pix );
410}
411
412void KNoteEdit::alignmentChanged( int a )
413{
414 // TODO: AlignAuto
415 if ( ( a == AlignAuto ) || ( a & AlignLeft ) )
416 m_textAlignLeft->setChecked( true );
417 else if ( ( a & AlignHCenter ) )
418 m_textAlignCenter->setChecked( true );
419 else if ( ( a & AlignRight ) )
420 m_textAlignRight->setChecked( true );
421 else if ( ( a & AlignJustify ) )
422 m_textAlignBlock->setChecked( true );
423}
424
425void KNoteEdit::verticalAlignmentChanged( VerticalAlignment a )
426{
427 if ( a == AlignNormal )
428 {
429 m_textSuper->setChecked( false );
430 m_textSub->setChecked( false );
431 }
432 else if ( a == AlignSuperScript )
433 m_textSuper->setChecked( true );
434 else if ( a == AlignSubScript )
435 m_textSub->setChecked( true );
436}
437
438
441void KNoteEdit::autoIndent()
442{
443 int para, index;
444 TQString string;
445 getCursorPosition( &para, &index );
446 while ( para > 0 && string.stripWhiteSpace().isEmpty() )
447 string = text( --para );
448
449 if ( string.stripWhiteSpace().isEmpty() )
450 return;
451
452 // This routine returns the whitespace before the first non white space
453 // character in string.
454 // It is assumed that string contains at least one non whitespace character
455 // ie \n \r \t \v \f and space
456 TQString indentString;
457
458 int len = string.length();
459 int i = 0;
460 while ( i < len && string.at(i).isSpace() )
461 indentString += string.at( i++ );
462
463 if ( !indentString.isEmpty() )
464 insert( indentString );
465}
466
467void KNoteEdit::emitLinkClicked( const TQString &s )
468{
469 kdDebug(5500) << k_funcinfo << s << endl;
470}
471
472void KNoteEdit::enableRichTextActions()
473{
474 m_textColor->setEnabled( true );
475 m_textFont->setEnabled( true );
476 m_textSize->setEnabled( true );
477
478 m_textBold->setEnabled( true );
479 m_textItalic->setEnabled( true );
480 m_textUnderline->setEnabled( true );
481 m_textStrikeOut->setEnabled( true );
482
483 m_textAlignLeft->setEnabled( true );
484 m_textAlignCenter->setEnabled( true );
485 m_textAlignRight->setEnabled( true );
486 m_textAlignBlock->setEnabled( true );
487
488 m_textList->setEnabled( true );
489 m_textSuper->setEnabled( true );
490 m_textSub->setEnabled( true );
491
492// m_textIncreaseIndent->setEnabled( true );
493// m_textDecreaseIndent->setEnabled( true );
494}
495
496void KNoteEdit::disableRichTextActions()
497{
498 m_textColor->setEnabled( false );
499 m_textFont->setEnabled( false );
500 m_textSize->setEnabled( false );
501
502 m_textBold->setEnabled( false );
503 m_textItalic->setEnabled( false );
504 m_textUnderline->setEnabled( false );
505 m_textStrikeOut->setEnabled( false );
506
507 m_textAlignLeft->setEnabled( false );
508 m_textAlignCenter->setEnabled( false );
509 m_textAlignRight->setEnabled( false );
510 m_textAlignBlock->setEnabled( false );
511
512 m_textList->setEnabled( false );
513 m_textSuper->setEnabled( false );
514 m_textSub->setEnabled( false );
515
516// m_textIncreaseIndent->setEnabled( false );
517// m_textDecreaseIndent->setEnabled( false );
518}
519
520void KNoteEdit::slotAllowTab()
521{
522 setTabChangesFocus(!tabChangesFocus());
523}
524
525TQPopupMenu *KNoteEdit::createPopupMenu( const TQPoint &pos )
526{
527 enum { IdUndo, IdRedo, IdSep1, IdCut, IdCopy, IdPaste, IdClear, IdSep2, IdSelectAll };
528
529 TQPopupMenu *menu = TQTextEdit::createPopupMenu( pos );
530
531 if ( isReadOnly() )
532 menu->changeItem( menu->idAt(0), SmallIconSet("edit-copy"), menu->text( menu->idAt(0) ) );
533 else {
534 int id = menu->idAt(0);
535 menu->changeItem( id - IdUndo, SmallIconSet("edit-undo"), menu->text( id - IdUndo) );
536 menu->changeItem( id - IdRedo, SmallIconSet("edit-redo"), menu->text( id - IdRedo) );
537 menu->changeItem( id - IdCut, SmallIconSet("edit-cut"), menu->text( id - IdCut) );
538 menu->changeItem( id - IdCopy, SmallIconSet("edit-copy"), menu->text( id - IdCopy) );
539 menu->changeItem( id - IdPaste, SmallIconSet("edit-paste"), menu->text( id - IdPaste) );
540 menu->changeItem( id - IdClear, SmallIconSet("edit-clear"), menu->text( id - IdClear) );
541
542 menu->insertSeparator();
543 id = menu->insertItem( SmallIconSet( "tools-check-spelling" ), i18n( "Check Spelling..." ),
544 this, TQ_SLOT( checkSpelling() ) );
545
546 if( text().isEmpty() )
547 menu->setItemEnabled( id, false );
548
549 menu->insertSeparator();
550 id=menu->insertItem(i18n("Allow Tabulations"),this,TQ_SLOT(slotAllowTab()));
551 menu->setItemChecked(id, !tabChangesFocus());
552 }
553
554 return menu;
555}
556
557#include "knoteedit.moc"