knotes

knote.cpp
1 /*******************************************************************
2  KNotes -- Notes for the KDE project
3 
4  Copyright (c) 1997-2006, 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 <tqlabel.h>
22 #include <tqdrawutil.h>
23 #include <tqsize.h>
24 #include <tqsizegrip.h>
25 #include <tqbitmap.h>
26 #include <tqcursor.h>
27 #include <tqpainter.h>
28 #include <tqpaintdevicemetrics.h>
29 #include <tqsimplerichtext.h>
30 #include <tqobjectlist.h>
31 #include <tqfile.h>
32 #include <tqcheckbox.h>
33 #include <tqtimer.h>
34 
35 #include <tdeapplication.h>
36 #include <kdebug.h>
37 #include <tdeaction.h>
38 #include <kstdaction.h>
39 #include <kcombobox.h>
40 #include <tdetoolbar.h>
41 #include <tdepopupmenu.h>
42 #include <kxmlguibuilder.h>
43 #include <kxmlguifactory.h>
44 #include <kcolordrag.h>
45 #include <kiconeffect.h>
46 #include <tdelocale.h>
47 #include <kstandarddirs.h>
48 #include <tdemessagebox.h>
49 #include <kfind.h>
50 #include <kprocess.h>
51 #include <kinputdialog.h>
52 #include <kmdcodec.h>
53 #include <tdeglobalsettings.h>
54 #include <tdefiledialog.h>
55 #include <tdeio/netaccess.h>
56 
57 #include <libkcal/journal.h>
58 
59 #include "knote.h"
60 #include "knotebutton.h"
61 #include "knoteedit.h"
62 #include "knoteconfig.h"
63 #include "knotesglobalconfig.h"
64 #include "knoteconfigdlg.h"
65 #include "knotealarmdlg.h"
66 #include "knotehostdlg.h"
67 #include "knotesnetsend.h"
68 #include "knoteprinter.h"
69 #include "version.h"
70 
71 #include "pushpin.xpm"
72 
73 #include <twin.h>
74 #include <netwm.h>
75 
76 #include <fixx11h.h>
77 
78 using namespace KCal;
79 
80 int KNote::s_ppOffset = 0;
81 
82 KNote::KNote( TQDomDocument buildDoc, Journal *j, TQWidget *parent, const char *name )
83  : TQFrame( parent, name, WStyle_Customize | WStyle_NoBorder | WDestructiveClose ),
84  m_label( 0 ), m_pushpin( 0 ), m_fold( 0 ), m_button( 0 ), m_tool( 0 ), m_editor( 0 ),
85  m_config( 0 ), m_journal( j ), m_find( 0 ),
86  m_twinConf( TDESharedConfig::openConfig( "twinrc", true ) ),
87  m_busy( 0 ), m_deleteWhenIdle( false ), m_blockEmitDataChanged( false )
88 {
89  setAcceptDrops( true );
90  actionCollection()->setWidget( this );
91 
92  setDOMDocument( buildDoc );
93 
94  // just set the name of the file to save the actions to, do NOT reparse it
95  setXMLFile( instance()->instanceName() + "ui.rc", false, false );
96 
97  // if there is no title yet, use the start date if valid
98  // (KOrganizer's journals don't have titles but a valid start date)
99  if ( m_journal->summary().isNull() && m_journal->dtStart().isValid() )
100  {
101  TQString s = TDEGlobal::locale()->formatDateTime( m_journal->dtStart() );
102  m_journal->setSummary( s );
103  }
104 
105  // create the menu items for the note - not the editor...
106  // rename, mail, print, save as, insert date, alarm, close, delete, new note
107  new TDEAction( i18n("New"), "document-new", 0,
108  TQT_TQOBJECT(this),TQT_SLOT(slotRequestNewNote()) , actionCollection(), "new_note" );
109  new TDEAction( i18n("Rename..."), "text", 0,
110  TQT_TQOBJECT(this), TQT_SLOT(slotRename()), actionCollection(), "rename_note" );
111  m_readOnly = new TDEToggleAction( i18n("Lock"), "system-lock-screen" , 0,
112  TQT_TQOBJECT(this), TQT_SLOT(slotUpdateReadOnly()), actionCollection(), "lock_note" );
113  m_readOnly->setCheckedState( KGuiItem( i18n("Unlock"), "unlock" ) );
114  new TDEAction( i18n("Hide"), "window-close" , Key_Escape,
115  TQT_TQOBJECT(this), TQT_SLOT(slotClose()), actionCollection(), "hide_note" );
116  new TDEAction( i18n("Delete"), "knotes_delete", 0,
117  TQT_TQOBJECT(this), TQT_SLOT(slotKill()), actionCollection(), "delete_note" );
118 
119  new TDEAction( i18n("Insert Date"), "knotes_date", 0 ,
120  TQT_TQOBJECT(this), TQT_SLOT(slotInsDate()), actionCollection(), "insert_date" );
121  new TDEAction( i18n("Set Alarm..."), "knotes_alarm", 0 ,
122  TQT_TQOBJECT(this), TQT_SLOT(slotSetAlarm()), actionCollection(), "set_alarm" );
123 
124  new TDEAction( i18n("Send..."), "network", 0,
125  TQT_TQOBJECT(this), TQT_SLOT(slotSend()), actionCollection(), "send_note" );
126  new TDEAction( i18n("Mail..."), "mail-send", 0,
127  TQT_TQOBJECT(this), TQT_SLOT(slotMail()), actionCollection(), "mail_note" );
128  new TDEAction( i18n("Save As..."), "document-save-as", 0,
129  TQT_TQOBJECT(this), TQT_SLOT(slotSaveAs()), actionCollection(), "save_note" );
130  KStdAction::print( TQT_TQOBJECT(this), TQT_SLOT(slotPrint()), actionCollection(), "print_note" );
131  new TDEAction( i18n("Preferences..."), "configure", 0,
132  TQT_TQOBJECT(this), TQT_SLOT(slotPreferences()), actionCollection(), "configure_note" );
133 
134  m_keepAbove = new TDEToggleAction( i18n("Keep Above Others"), "go-up", 0,
135  TQT_TQOBJECT(this), TQT_SLOT(slotUpdateKeepAboveBelow()), actionCollection(), "keep_above" );
136  m_keepAbove->setExclusiveGroup( "keepAB" );
137 
138  m_keepBelow = new TDEToggleAction( i18n("Keep Below Others"), "go-down", 0,
139  TQT_TQOBJECT(this), TQT_SLOT(slotUpdateKeepAboveBelow()), actionCollection(), "keep_below" );
140  m_keepBelow->setExclusiveGroup( "keepAB" );
141 
142  m_toDesktop = new TDEListAction( i18n("To Desktop"), 0,
143  TQT_TQOBJECT(this), TQT_SLOT(slotPopupActionToDesktop(int)), actionCollection(), "to_desktop" );
144  connect( m_toDesktop->popupMenu(), TQT_SIGNAL(aboutToShow()), TQT_TQOBJECT(this), TQT_SLOT(slotUpdateDesktopActions()) );
145 
146  // invisible action to walk through the notes to make this configurable
147  new TDEAction( i18n("Walk Through Notes"), 0, SHIFT+Key_BackTab,
148  TQT_TQOBJECT(this), TQT_SIGNAL(sigShowNextNote()), actionCollection(), "walk_notes" );
149 
150  // create the note header, button and label...
151  m_label = new TQLabel( this );
152  m_label->setFrameStyle( NoFrame );
153  m_label->setLineWidth( 0 );
154  m_label->installEventFilter( this ); // receive events (for dragging & action menu)
155  setName( m_journal->summary() ); // don't worry, no signals are connected at this stage yet
156 
157  m_button = new KNoteButton( "knotes_close", this );
158  connect( m_button, TQT_SIGNAL(clicked()), TQT_TQOBJECT(this), TQT_SLOT(slotClose()) );
159 
160  // create the note editor
161  m_editor = new KNoteEdit( actionCollection(), this );
162  m_editor->setNote( this );
163  m_editor->installEventFilter( this ); // receive events (for modified)
164  m_editor->viewport()->installEventFilter( this );
165  connect( m_editor, TQT_SIGNAL(contentsMoving( int, int )), TQT_TQOBJECT(this), TQT_SLOT(slotUpdateViewport( int, int )));
166 
167  KXMLGUIBuilder builder( this );
168  KXMLGUIFactory factory( &builder, TQT_TQOBJECT(this) );
169  factory.addClient( this );
170 
171  m_menu = dynamic_cast<TDEPopupMenu*>(factory.container( "note_context", this ));
172  m_edit_menu = dynamic_cast<TDEPopupMenu*>(factory.container( "note_edit", this ));
173  m_tool = dynamic_cast<TDEToolBar*>(factory.container( "note_tool", this ));
174 
175  if ( m_tool ) {
176  m_tool->setIconSize( 10 );
177  m_tool->setFixedHeight( 16 );
178  m_tool->setIconText( TDEToolBar::IconOnly );
179 
180  // if there was just a way of making KComboBox adhere the toolbar height...
181  TQObjectList *list = m_tool->queryList( "KComboBox" );
182  TQObjectListIt it( *list );
183  while ( it.current() != 0 )
184  {
185  KComboBox *combo = (KComboBox *)it.current();
186  TQFont font = combo->font();
187  font.setPointSize( 7 );
188  combo->setFont( font );
189  combo->setFixedHeight( 14 );
190  ++it;
191  }
192  delete list;
193 
194  m_tool->hide();
195  }
196 
197  setFocusProxy( m_editor );
198 
199  // create the resize handle
200  m_editor->setCornerWidget( new TQSizeGrip( this ) );
201  uint width = m_editor->cornerWidget()->width();
202  uint height = m_editor->cornerWidget()->height();
203  TQBitmap mask;
204  mask.resize( width, height );
205  mask.fill( color0 );
206  TQPointArray array;
207  array.setPoints( 3, 0, height, width, height, width, 0 );
208  TQPainter p;
209  p.begin( &mask );
210  p.setBrush( color1 );
211  p.drawPolygon( array );
212  p.end();
213  m_editor->cornerWidget()->setMask( mask );
214  m_editor->cornerWidget()->setBackgroundMode( PaletteBase );
215 
216  // the config file location
217  TQString configFile = TDEGlobal::dirs()->saveLocation( "appdata", "notes/" );
218  configFile += m_journal->uid();
219 
220  // no config file yet? -> use the default display config if available
221  // we want to write to configFile, so use "false"
222  bool newNote = !TDEIO::NetAccess::exists( KURL::fromPathOrURL( configFile ), false, 0 );
223 
224  m_config = new KNoteConfig( TDESharedConfig::openConfig( configFile, false, false ) );
225  m_config->readConfig();
226  m_config->setVersion( KNOTES_VERSION );
227 
228  if ( newNote )
229  {
230  // until tdelibs provides copying of TDEConfigSkeletons (KDE 3.4)
231  KNotesGlobalConfig *globalConfig = KNotesGlobalConfig::self();
232  m_config->setBgColor( globalConfig->bgColor() );
233  m_config->setFgColor( globalConfig->fgColor() );
234  m_config->setWidth( globalConfig->width() );
235  m_config->setHeight( globalConfig->height() );
236 
237  m_config->setFont( globalConfig->font() );
238  m_config->setTitleFont( globalConfig->titleFont() );
239  m_config->setAutoIndent( globalConfig->autoIndent() );
240  m_config->setRichText( globalConfig->richText() );
241  m_config->setTabSize( globalConfig->tabSize() );
242  m_config->setReadOnly( globalConfig->readOnly() );
243 
244  m_config->setDesktop( globalConfig->desktop() );
245  m_config->setHideNote( globalConfig->hideNote() );
246  m_config->setPosition( globalConfig->position() );
247  m_config->setShowInTaskbar( globalConfig->showInTaskbar() );
248  m_config->setKeepAbove( globalConfig->keepAbove() );
249  m_config->setKeepBelow( globalConfig->keepBelow() );
250 
251  m_config->writeConfig();
252  }
253 
254  // set up the look&feel of the note
255  setMinimumSize( 20, 20 );
256  setLineWidth( 1 );
257  setMargin( 0 );
258 
259  m_editor->setMargin( 0 );
260  m_editor->setFrameStyle( NoFrame );
261  m_editor->setBackgroundOrigin( WindowOrigin );
262 
263  // can be done here since this doesn't pick up changes while KNotes is running anyway
264  bool closeLeft = false;
265  m_twinConf->setGroup( "Style" );
266  if ( m_twinConf->readBoolEntry( "CustomButtonPositions" ) )
267  closeLeft = m_twinConf->readEntry( "ButtonsOnLeft" ).find( 'X' ) > -1;
268 
269  TQPixmap pushpin_pix;
270  if ( closeLeft )
271  pushpin_pix = TQPixmap( TQPixmap( pushpin_xpm ).convertToImage().mirror( true, false ) );
272  else
273  pushpin_pix = TQPixmap( pushpin_xpm );
274 
275  // the pushpin label at the top left or right corner
276  m_pushpin = new TQLabel( this );
277  m_pushpin->setScaledContents( true );
278  m_pushpin->setBackgroundMode( NoBackground );
279  m_pushpin->setPixmap( pushpin_pix );
280  m_pushpin->resize( pushpin_pix.size() );
281 
282  // fold label at bottom right corner
283  m_fold = new TQLabel( this );
284  m_fold->setScaledContents( true );
285  m_fold->setBackgroundMode( NoBackground );
286 
287  // load the display configuration of the note
288  width = m_config->width();
289  height = m_config->height();
290  resize( width, height );
291 
292  // let KWin do the placement if the position is illegal--at least 10 pixels
293  // of a note need to be visible
294  const TQPoint& position = m_config->position();
295  TQRect desk = kapp->desktop()->rect();
296  desk.addCoords( 10, 10, -10, -10 );
297  if ( desk.intersects( TQRect( position, TQSize( width, height ) ) ) )
298  move( position ); // do before calling show() to avoid flicker
299 
300  // config items in the journal have priority
301  TQString property = m_journal->customProperty( "KNotes", "FgColor" );
302  if ( !property.isNull() )
303  m_config->setFgColor( TQColor( property ) );
304  else
305  m_journal->setCustomProperty( "KNotes", "FgColor", m_config->fgColor().name() );
306 
307  property = m_journal->customProperty( "KNotes", "BgColor" );
308  if ( !property.isNull() )
309  m_config->setBgColor( TQColor( property ) );
310  else
311  m_journal->setCustomProperty( "KNotes", "BgColor", m_config->bgColor().name() );
312 
313  property = m_journal->customProperty( "KNotes", "RichText" );
314  if ( !property.isNull() )
315  m_config->setRichText( property == "true" ? true : false );
316  else
317  m_journal->setCustomProperty( "KNotes", "RichText", m_config->richText() ? "true" : "false" );
318 
319  // read configuration settings...
320  slotApplyConfig();
321 
322  // create the mask for the fold---to be done after slotApplyConfig(),
323  // which calls createFold()
324  m_fold->setMask( TQRegion( m_fold->pixmap()->createHeuristicMask() ) );
325 
326  // if this is a new note put on current desktop - we can't use defaults
327  // in TDEConfig XT since only _changes_ will be stored in the config file
328  int desktop = m_config->desktop();
329  if ( desktop < 0 && desktop != NETWinInfo::OnAllDesktops )
330  desktop = KWin::currentDesktop();
331 
332  // show the note if desired
333  if ( desktop != 0 && !m_config->hideNote() )
334  {
335  // to avoid flicker, call this before show()
336  toDesktop( desktop );
337  show();
338 
339  // because KWin forgets about that for hidden windows
340  if ( desktop == NETWinInfo::OnAllDesktops )
341  toDesktop( desktop );
342  }
343 
344  m_editor->setText( m_journal->description() );
345  m_editor->setModified( false );
346 
347  m_readOnly->setChecked( m_config->readOnly() );
348  slotUpdateReadOnly();
349 
350  if ( m_config->keepAbove() )
351  m_keepAbove->setChecked( true );
352  else if ( m_config->keepBelow() )
353  m_keepBelow->setChecked( true );
354  else
355  {
356  m_keepAbove->setChecked( false );
357  m_keepBelow->setChecked( false );
358  }
359  slotUpdateKeepAboveBelow();
360 
361  // HACK: update the icon color - again after showing the note, to make kicker aware of the new colors
362  TDEIconEffect effect;
363  TQPixmap icon = effect.apply( kapp->icon(), TDEIconEffect::Colorize, 1, m_config->bgColor(), false );
364  TQPixmap miniIcon = effect.apply( kapp->miniIcon(), TDEIconEffect::Colorize, 1, m_config->bgColor(), false );
365  KWin::setIcons( winId(), icon, miniIcon );
366 }
367 
368 KNote::~KNote()
369 {
370  delete m_config;
371 }
372 
373 void KNote::slotRequestNewNote()
374 {
375  //Be sure to save before to request a new note
376  saveConfig();
377  saveData();
378  emit sigRequestNewNote();
379 }
380 
381 void KNote::changeJournal(KCal::Journal *journal)
382 {
383  m_journal = journal;
384  m_editor->setText( m_journal->description() );
385  m_label->setText( m_journal->summary() );
386  updateLabelAlignment();
387 }
388 
389 // -------------------- public slots -------------------- //
390 
391 void KNote::slotKill( bool force )
392 {
393  m_blockEmitDataChanged = true;
394  if ( !force &&
395  KMessageBox::warningContinueCancel( this,
396  i18n("<qt>Do you really want to delete note <b>%1</b>?</qt>").arg( m_label->text() ),
397  i18n("Confirm Delete"), KGuiItem( i18n("&Delete"), "edit-delete" ),
398  "ConfirmDeleteNote"
399  )
400  != KMessageBox::Continue )
401  {
402  m_blockEmitDataChanged = false;
403  return;
404  }
405  aboutToEnterEventLoop();
406  // delete the configuration first, then the corresponding file
407  delete m_config;
408  m_config = 0;
409 
410  TQString configFile = TDEGlobal::dirs()->saveLocation( "appdata", "notes/" );
411  configFile += m_journal->uid();
412 
413  if ( !TDEIO::NetAccess::del( KURL::fromPathOrURL( configFile ), this ) )
414  kdError(5500) << "Can't remove the note config: " << configFile << endl;
415 
416  emit sigKillNote( m_journal );
417  eventLoopLeft();
418 
419 }
420 
421 
422 // -------------------- public member functions -------------------- //
423 
424 void KNote::saveData(bool update)
425 {
426  m_journal->setSummary( m_label->text() );
427  m_journal->setDescription( m_editor->text() );
428  m_journal->setCustomProperty( "KNotes", "FgColor", m_config->fgColor().name() );
429  m_journal->setCustomProperty( "KNotes", "BgColor", m_config->bgColor().name() );
430  m_journal->setCustomProperty( "KNotes", "RichText", m_config->richText() ? "true" : "false" );
431  if(update) {
432  emit sigDataChanged( noteId() );
433  m_editor->setModified( false );
434  }
435 }
436 
437 void KNote::saveConfig() const
438 {
439  m_config->setWidth( width() );
440  m_config->setHeight( height() );
441  m_config->setPosition( pos() );
442 
443  NETWinInfo wm_client( tqt_xdisplay(), winId(), tqt_xrootwin(), NET::WMDesktop );
444  if ( wm_client.desktop() == NETWinInfo::OnAllDesktops || wm_client.desktop() > 0 )
445  m_config->setDesktop( wm_client.desktop() );
446 
447  // actually store the config on disk
448  m_config->writeConfig();
449 }
450 
451 TQString KNote::noteId() const
452 {
453  return m_journal->uid();
454 }
455 
456 TQString KNote::name() const
457 {
458  return m_label->text();
459 }
460 
461 TQString KNote::text() const
462 {
463  return m_editor->text();
464 }
465 
466 TQString KNote::plainText() const
467 {
468  if ( m_editor->textFormat() == RichText )
469  {
470  TQTextEdit conv;
471  conv.setTextFormat( RichText );
472  conv.setText( m_editor->text() );
473  conv.setTextFormat( PlainText );
474  return conv.text();
475  }
476  else
477  return m_editor->text();
478 }
479 
480 void KNote::setName( const TQString& name )
481 {
482  m_label->setText( name );
483  updateLabelAlignment();
484 
485  if ( m_editor ) // not called from CTOR?
486  saveData();
487 
488  // set the window's name for the taskbar entry to be more helpful (#58338)
489  NETWinInfo note_win( tqt_xdisplay(), winId(), tqt_xrootwin(), NET::WMDesktop );
490  note_win.setName( name.utf8() );
491 
492  emit sigNameChanged();
493 }
494 
495 void KNote::setText( const TQString& text )
496 {
497  m_editor->setText( text );
498  saveData();
499 }
500 
501 TQColor KNote::fgColor() const
502 {
503  return m_config->fgColor();
504 }
505 
506 TQColor KNote::bgColor() const
507 {
508  return m_config->bgColor();
509 }
510 
511 void KNote::setColor( const TQColor& fg, const TQColor& bg )
512 {
513  bool updateJournal = false;
514  TQString journalFg = m_journal->customProperty( "KNotes", "FgColor" );
515  if ( journalFg.isEmpty() || journalFg != fg.name() )
516  {
517  m_journal->setCustomProperty( "KNotes", "FgColor", fg.name() );
518  updateJournal = true;
519  }
520  TQString journalbg = m_journal->customProperty( "KNotes", "BgColor" );
521  if ( journalbg.isEmpty() || journalbg != bg.name() )
522  {
523  m_journal->setCustomProperty( "KNotes", "BgColor", bg.name() );
524  updateJournal = true;
525  }
526 
527  m_config->setFgColor( fg );
528  m_config->setBgColor( bg );
529 
530  if (updateJournal)
531  {
532  // Only update the journal if new configuration was really used.
533  // This is necessary because setColor() is called also when loading a note from an .ics
534  // file and we do not want to inadvertantly update the last modified field each time.
535  m_journal->updated(); // because setCustomProperty() doesn't call it!!
536  emit sigDataChanged(noteId());
537  }
538  m_config->writeConfig();
539 
540  TQPalette newpalette = palette();
541  newpalette.setColor( TQColorGroup::Background, bg );
542  newpalette.setColor( TQColorGroup::Foreground, fg );
543  newpalette.setColor( TQColorGroup::Base, bg ); // text background
544  newpalette.setColor( TQColorGroup::Text, fg ); // text color
545  newpalette.setColor( TQColorGroup::Button, bg );
546  newpalette.setColor( TQColorGroup::ButtonText, fg );
547 
548 // newpalette.setColor( TQColorGroup::Highlight, bg );
549 // newpalette.setColor( TQColorGroup::HighlightedText, fg );
550 
551  // the shadow
552  newpalette.setColor( TQColorGroup::Midlight, bg.light(150) );
553  newpalette.setColor( TQColorGroup::Shadow, bg.dark(116) );
554  newpalette.setColor( TQColorGroup::Light, bg.light(180) );
555  if ( s_ppOffset )
556  newpalette.setColor( TQColorGroup::Dark, bg.dark(200) );
557  else
558  newpalette.setColor( TQColorGroup::Dark, bg.dark(108) );
559  setPalette( newpalette );
560 
561  // set the text color
562  m_editor->setTextColor( fg );
563 
564  // set the background color or gradient
565  updateBackground();
566 
567  // set darker value for the hide button...
568  TQPalette darker = palette();
569  darker.setColor( TQColorGroup::Button, bg.dark(116) );
570  m_button->setPalette( darker );
571 
572  // update the icon color
573  TDEIconEffect effect;
574  TQPixmap icon = effect.apply( kapp->icon(), TDEIconEffect::Colorize, 1, bg, false );
575  TQPixmap miniIcon = effect.apply( kapp->miniIcon(), TDEIconEffect::Colorize, 1, bg, false );
576  KWin::setIcons( winId(), icon, miniIcon );
577 
578  // set the color for the selection used to highlight the find stuff
579  TQColor sel = palette().color( TQPalette::Active, TQColorGroup::Base ).dark();
580  if ( sel == TQt::black )
581  sel = palette().color( TQPalette::Active, TQColorGroup::Base ).light();
582 
583  m_editor->setSelectionAttributes( 1, sel, true );
584 
585  // update the color of the fold
586  createFold();
587 
588  // update the color of the title
589  updateFocus();
590  emit sigColorChanged();
591 }
592 
593 void KNote::find( const TQString& pattern, long options )
594 {
595  delete m_find;
596  m_find = new KFind( pattern, options, this );
597 
598  connect( m_find, TQT_SIGNAL(highlight( const TQString &, int, int )),
599  TQT_TQOBJECT(this), TQT_SLOT(slotHighlight( const TQString &, int, int )) );
600  connect( m_find, TQT_SIGNAL(findNext()), TQT_TQOBJECT(this), TQT_SLOT(slotFindNext()) );
601 
602  m_find->setData( plainText() );
603  slotFindNext();
604 }
605 
606 void KNote::slotFindNext()
607 {
608  // TODO: honor FindBackwards
609  // TODO: dialogClosed() -> delete m_find
610 
611  // Let KFind inspect the text fragment, and display a dialog if a match is found
612  KFind::Result res = m_find->find();
613 
614  if ( res == KFind::NoMatch ) // i.e. at end-pos
615  {
616  m_editor->removeSelection( 1 );
617  emit sigFindFinished();
618  delete m_find;
619  m_find = 0;
620  }
621  else
622  {
623  show();
624  KWin::setCurrentDesktop( KWin::windowInfo( winId() ).desktop() );
625  }
626 }
627 
628 void KNote::slotHighlight( const TQString& str, int idx, int len )
629 {
630  int paraFrom = 0, idxFrom = 0, p = 0;
631  for ( ; p < idx; ++p )
632  if ( str[p] == '\n' )
633  {
634  ++paraFrom;
635  idxFrom = 0;
636  }
637  else
638  ++idxFrom;
639 
640  int paraTo = paraFrom, idxTo = idxFrom;
641 
642  for ( ; p < idx + len; ++p )
643  {
644  if ( str[p] == '\n' )
645  {
646  ++paraTo;
647  idxTo = 0;
648  }
649  else
650  ++idxTo;
651  }
652 
653  m_editor->setSelection( paraFrom, idxFrom, paraTo, idxTo, 1 );
654 }
655 
656 bool KNote::isModified() const
657 {
658  return m_editor->isModified();
659 }
660 
661 // FIXME KDE 4.0: remove sync(), isNew() and isModified()
662 void KNote::sync( const TQString& app )
663 {
664  TQByteArray sep( 1 );
665  sep[0] = '\0';
666 
667  KMD5 hash;
668  TQCString result;
669 
670  hash.update( m_label->text().utf8() );
671  hash.update( sep );
672  hash.update( m_editor->text().utf8() );
673  hash.hexDigest( result );
674 
675  // hacky... not possible with TDEConfig XT
676  TDEConfig *config = m_config->config();
677  config->setGroup( "Synchronisation" );
678  config->writeEntry( app, result.data() );
679 }
680 
681 bool KNote::isNew( const TQString& app ) const
682 {
683  TDEConfig *config = m_config->config();
684  config->setGroup( "Synchronisation" );
685  TQString hash = config->readEntry( app );
686  return hash.isEmpty();
687 }
688 
689 bool KNote::isModified( const TQString& app ) const
690 {
691  TQByteArray sep( 1 );
692  sep[0] = '\0';
693 
694  KMD5 hash;
695  hash.update( m_label->text().utf8() );
696  hash.update( sep );
697  hash.update( m_editor->text().utf8() );
698  hash.hexDigest();
699 
700  TDEConfig *config = m_config->config();
701  config->setGroup( "Synchronisation" );
702  TQString orig = config->readEntry( app );
703 
704  if ( hash.verify( orig.utf8() ) ) // returns false on error!
705  return false;
706  else
707  return true;
708 }
709 
710 void KNote::setStyle( int style )
711 {
712  if ( style == KNotesGlobalConfig::EnumStyle::Plain )
713  s_ppOffset = 0;
714  else
715  s_ppOffset = 12;
716 }
717 
718 
719 // ------------------ private slots (menu actions) ------------------ //
720 
721 void KNote::slotRename()
722 {
723  m_blockEmitDataChanged = true;
724  // pop up dialog to get the new name
725  bool ok;
726  aboutToEnterEventLoop();
727  TQString oldName = m_label->text();
728  TQString newName = KInputDialog::getText( TQString(),
729  i18n("Please enter the new name:"), m_label->text(), &ok, this );
730  eventLoopLeft();
731  m_blockEmitDataChanged = false;
732  if ( !ok || ( oldName == newName) ) // handle cancel
733  return;
734 
735  setName( newName );
736 }
737 
738 void KNote::slotUpdateReadOnly()
739 {
740  const bool readOnly = m_readOnly->isChecked();
741 
742  m_editor->setReadOnly( readOnly );
743  m_config->setReadOnly( readOnly );
744 
745  // Enable/disable actions accordingly
746  actionCollection()->action( "configure_note" )->setEnabled( !readOnly );
747  actionCollection()->action( "insert_date" )->setEnabled( !readOnly );
748  actionCollection()->action( "delete_note" )->setEnabled( !readOnly );
749 
750  actionCollection()->action( "edit_undo" )->setEnabled( !readOnly && m_editor->isUndoAvailable() );
751  actionCollection()->action( "edit_redo" )->setEnabled( !readOnly && m_editor->isRedoAvailable() );
752  actionCollection()->action( "edit_cut" )->setEnabled( !readOnly && m_editor->hasSelectedText() );
753  actionCollection()->action( "edit_paste" )->setEnabled( !readOnly );
754  actionCollection()->action( "edit_clear" )->setEnabled( !readOnly );
755  actionCollection()->action( "rename_note" )->setEnabled( !readOnly );
756 
757  actionCollection()->action( "format_bold" )->setEnabled( !readOnly );
758  actionCollection()->action( "format_italic" )->setEnabled( !readOnly );
759  actionCollection()->action( "format_underline" )->setEnabled( !readOnly );
760  actionCollection()->action( "format_strikeout" )->setEnabled( !readOnly );
761  actionCollection()->action( "format_alignleft" )->setEnabled( !readOnly );
762  actionCollection()->action( "format_aligncenter" )->setEnabled( !readOnly );
763  actionCollection()->action( "format_alignright" )->setEnabled( !readOnly );
764  actionCollection()->action( "format_alignblock" )->setEnabled( !readOnly );
765  actionCollection()->action( "format_list" )->setEnabled( !readOnly );
766  actionCollection()->action( "format_super" )->setEnabled( !readOnly );
767  actionCollection()->action( "format_sub" )->setEnabled( !readOnly );
768  actionCollection()->action( "format_size" )->setEnabled( !readOnly );
769  actionCollection()->action( "format_color" )->setEnabled( !readOnly );
770 
771  updateFocus();
772 }
773 
774 void KNote::slotClose()
775 {
776  NETWinInfo wm_client( tqt_xdisplay(), winId(), tqt_xrootwin(), NET::WMDesktop );
777  if ( wm_client.desktop() == NETWinInfo::OnAllDesktops || wm_client.desktop() > 0 )
778  m_config->setDesktop( wm_client.desktop() );
779 
780  m_editor->clearFocus();
781  m_config->setHideNote( true );
782  m_config->setPosition( pos() );
783 
784  // just hide the note so it's still available from the dock window
785  hide();
786 }
787 
788 void KNote::slotInsDate()
789 {
790  m_editor->insert( TDEGlobal::locale()->formatDateTime(TQDateTime::currentDateTime()) );
791 }
792 
793 void KNote::slotSetAlarm()
794 {
795  m_blockEmitDataChanged = true;
796  KNoteAlarmDlg dlg( name(), this );
797  dlg.setIncidence( m_journal );
798 
799  aboutToEnterEventLoop();
800  if ( dlg.exec() == TQDialog::Accepted )
801  emit sigDataChanged(noteId());
802  eventLoopLeft();
803  m_blockEmitDataChanged = false;
804 }
805 
806 void KNote::slotPreferences()
807 {
808  // reuse if possible
809  if ( KNoteConfigDlg::showDialog( noteId().utf8() ) )
810  return;
811 
812  // create a new preferences dialog...
813  KNoteConfigDlg *dialog = new KNoteConfigDlg( m_config, name(), this, noteId().utf8() );
814  connect( dialog, TQT_SIGNAL(settingsChanged()), TQT_TQOBJECT(this), TQT_SLOT(slotApplyConfig()) );
815  connect( this, TQT_SIGNAL(sigNameChanged()), dialog, TQT_SLOT(slotUpdateCaption()) );
816  dialog->show();
817 }
818 
819 void KNote::slotSend()
820 {
821  // pop up dialog to get the IP
822  KNoteHostDlg hostDlg( i18n("Send \"%1\"").arg( name() ), this );
823  aboutToEnterEventLoop();
824  bool ok = (hostDlg.exec() == TQDialog::Accepted);
825  eventLoopLeft();
826  if ( !ok ) // handle cancel
827  return;
828  TQString host = hostDlg.host();
829 
830  if ( host.isEmpty() )
831  {
832  KMessageBox::sorry( this, i18n("The host cannot be empty.") );
833  return;
834  }
835 
836  // Send the note
837  KNotesNetworkSender *sender = new KNotesNetworkSender( host, KNotesGlobalConfig::port() );
838  sender->setSenderId( KNotesGlobalConfig::senderID() );
839  sender->setNote( name(), text() );
840  sender->connect();
841 }
842 
843 void KNote::slotMail()
844 {
845  // get the mail action command
846  const TQStringList cmd_list = TQStringList::split( TQChar(' '), KNotesGlobalConfig::mailAction() );
847 
848  TDEProcess mail;
849  for ( TQStringList::ConstIterator it = cmd_list.constBegin();
850  it != cmd_list.constEnd(); ++it )
851  {
852  if ( *it == "%f" )
853  mail << plainText().local8Bit(); // convert rich text to plain text
854  else if ( *it == "%t" )
855  mail << m_label->text().local8Bit();
856  else
857  mail << (*it).local8Bit();
858  }
859 
860  if ( !mail.start( TDEProcess::DontCare ) )
861  KMessageBox::sorry( this, i18n("Unable to start the mail process.") );
862 }
863 
864 void KNote::slotPrint()
865 {
866  TQString content;
867  if ( m_editor->textFormat() == PlainText )
868  content = TQStyleSheet::convertFromPlainText( m_editor->text() );
869  else
870  content = m_editor->text();
871 
872  KNotePrinter printer;
873  printer.setMimeSourceFactory( m_editor->mimeSourceFactory() );
874  printer.setFont( m_config->font() );
875  printer.setContext( m_editor->context() );
876  printer.setStyleSheet( m_editor->styleSheet() );
877  printer.setColorGroup( colorGroup() );
878  printer.printNote( TQString(), content );
879 }
880 
881 void KNote::slotSaveAs()
882 {
883  m_blockEmitDataChanged = true;
884  TQCheckBox *convert = 0;
885 
886  if ( m_editor->textFormat() == RichText )
887  {
888  convert = new TQCheckBox( 0 );
889  convert->setText( i18n("Save note as plain text") );
890  }
891 
892  KFileDialog dlg( TQString(), TQString(), this, "filedialog", true, convert );
893  dlg.setOperationMode( KFileDialog::Saving );
894  dlg.setCaption( i18n("Save As") );
895  aboutToEnterEventLoop();
896  dlg.exec();
897  eventLoopLeft();
898 
899  TQString fileName = dlg.selectedFile();
900  if ( fileName.isEmpty() )
901  {
902  m_blockEmitDataChanged = false;
903  return;
904  }
905  TQFile file( fileName );
906 
907  if ( file.exists() &&
908  KMessageBox::warningContinueCancel( this, i18n("<qt>A file named <b>%1</b> already exists.<br>"
909  "Are you sure you want to overwrite it?</qt>").arg( TQFileInfo(file).fileName() ) )
910  != KMessageBox::Continue )
911  {
912  m_blockEmitDataChanged = false;
913  return;
914  }
915 
916  if ( file.open( IO_WriteOnly ) )
917  {
918  TQTextStream stream( &file );
919  // convert rich text to plain text first
920  if ( convert && convert->isChecked() )
921  stream << plainText();
922  else
923  stream << text();
924  }
925  m_blockEmitDataChanged = false;
926 }
927 
928 void KNote::slotPopupActionToDesktop( int id )
929 {
930  toDesktop( id - 1 ); // compensate for the menu separator, -1 == all desktops
931 }
932 
933 
934 // ------------------ private slots (configuration) ------------------ //
935 
936 void KNote::slotApplyConfig()
937 {
938  if ( m_config->richText() )
939  m_editor->setTextFormat( RichText );
940  else
941  m_editor->setTextFormat( PlainText );
942 
943  m_label->setFont( m_config->titleFont() );
944  m_editor->setTextFont( m_config->font() );
945  m_editor->setTabStop( m_config->tabSize() );
946  m_editor->setAutoIndentMode( m_config->autoIndent() );
947 
948  // if called as a slot, save the text, we might have changed the
949  // text format - otherwise the journal will not be updated
950  if ( sender() )
951  saveData();
952 
953  setColor( m_config->fgColor(), m_config->bgColor() );
954 
955  updateLabelAlignment();
956  slotUpdateShowInTaskbar();
957 }
958 
959 void KNote::slotUpdateKeepAboveBelow()
960 {
961  KWin::WindowInfo info( KWin::windowInfo( winId() ) );
962 
963  if ( m_keepAbove->isChecked() )
964  {
965  m_config->setKeepAbove( true );
966  m_config->setKeepBelow( false );
967  KWin::setState( winId(), info.state() | NET::KeepAbove );
968  }
969  else if ( m_keepBelow->isChecked() )
970  {
971  m_config->setKeepAbove( false );
972  m_config->setKeepBelow( true );
973  KWin::setState( winId(), info.state() | NET::KeepBelow );
974  }
975  else
976  {
977  m_config->setKeepAbove( false );
978  KWin::clearState( winId(), NET::KeepAbove );
979 
980  m_config->setKeepBelow( false );
981  KWin::clearState( winId(), NET::KeepBelow );
982  }
983 }
984 
985 void KNote::slotUpdateShowInTaskbar()
986 {
987  if ( !m_config->showInTaskbar() )
988  KWin::setState( winId(), KWin::windowInfo(winId()).state() | NET::SkipTaskbar );
989  else
990  KWin::clearState( winId(), NET::SkipTaskbar );
991 }
992 
993 void KNote::slotUpdateDesktopActions()
994 {
995  NETRootInfo wm_root( tqt_xdisplay(), NET::NumberOfDesktops | NET::DesktopNames );
996  NETWinInfo wm_client( tqt_xdisplay(), winId(), tqt_xrootwin(), NET::WMDesktop );
997 
998  TQStringList desktops;
999  desktops.append( i18n("&All Desktops") );
1000  desktops.append( TQString() ); // Separator
1001 
1002  int count = wm_root.numberOfDesktops();
1003  for ( int n = 1; n <= count; n++ )
1004  desktops.append( TQString("&%1 %2").arg( n ).arg( TQString::fromUtf8(wm_root.desktopName( n )) ) );
1005 
1006  m_toDesktop->setItems( desktops );
1007 
1008  if ( wm_client.desktop() == NETWinInfo::OnAllDesktops )
1009  m_toDesktop->setCurrentItem( 0 );
1010  else
1011  m_toDesktop->setCurrentItem( wm_client.desktop() + 1 ); // compensate for separator (+1)
1012 }
1013 
1014 void KNote::slotUpdateViewport( int /*x*/, int y )
1015 {
1016  if ( s_ppOffset )
1017  updateBackground( y );
1018 }
1019 
1020 // -------------------- private methods -------------------- //
1021 
1022 void KNote::toDesktop( int desktop )
1023 {
1024  if ( desktop == 0 )
1025  return;
1026 
1027  if ( desktop == NETWinInfo::OnAllDesktops )
1028  KWin::setOnAllDesktops( winId(), true );
1029  else
1030  KWin::setOnDesktop( winId(), desktop );
1031 }
1032 
1033 void KNote::createFold()
1034 {
1035  TQPixmap fold( 15, 15 );
1036  TQPainter foldp( &fold );
1037  foldp.setPen( TQt::NoPen );
1038  foldp.setBrush( palette().active().dark() );
1039  TQPointArray foldpoints( 3 );
1040  foldpoints.putPoints( 0, 3, 0, 0, 14, 0, 0, 14 );
1041  foldp.drawPolygon( foldpoints );
1042  foldp.end();
1043  m_fold->setPixmap( fold );
1044 }
1045 
1046 void KNote::updateLabelAlignment()
1047 {
1048  // if the name is too long to fit, left-align it, otherwise center it (#59028)
1049  TQString labelText = m_label->text();
1050  if ( m_label->fontMetrics().boundingRect( labelText ).width() > m_label->width() )
1051  m_label->setAlignment( AlignLeft );
1052  else
1053  m_label->setAlignment( AlignHCenter );
1054 }
1055 
1056 void KNote::updateFocus()
1057 {
1058  if ( hasFocus() )
1059  {
1060  m_label->setBackgroundColor( palette().active().shadow() );
1061  m_button->show();
1062 
1063  if ( !m_editor->isReadOnly() )
1064  {
1065  if ( m_tool && m_tool->isHidden() && m_editor->textFormat() == TQTextEdit::RichText )
1066  {
1067  m_tool->show();
1068  updateLayout(); // to update the editor height
1069  }
1070  m_editor->cornerWidget()->show();
1071  }
1072  else
1073  {
1074  if ( m_tool && !m_tool->isHidden() )
1075  {
1076  m_tool->hide();
1077  updateLayout(); // to update the minimum height
1078  }
1079  m_editor->cornerWidget()->hide();
1080  }
1081 
1082  m_fold->hide();
1083  }
1084  else
1085  {
1086  m_button->hide();
1087  m_editor->cornerWidget()->hide();
1088 
1089  if ( m_tool && !m_tool->isHidden() )
1090  {
1091  m_tool->hide();
1092  updateLayout(); // to update the minimum height
1093  }
1094 
1095  if ( s_ppOffset )
1096  {
1097  m_label->setBackgroundColor( palette().active().midlight() );
1098  m_fold->show();
1099  }
1100  else
1101  m_label->setBackgroundColor( palette().active().background() );
1102  }
1103 }
1104 
1105 void KNote::updateMask()
1106 {
1107  if ( !s_ppOffset )
1108  {
1109  clearMask();
1110  return;
1111  }
1112 
1113  int w = width();
1114  int h = height();
1115  TQRegion reg( 0, s_ppOffset, w, h - s_ppOffset );
1116 
1117  const TQBitmap *pushpin_bitmap = m_pushpin->pixmap()->mask();
1118  TQRegion pushpin_reg( *pushpin_bitmap );
1119  m_pushpin->setMask( pushpin_reg );
1120  pushpin_reg.translate( m_pushpin->x(), m_pushpin->y() );
1121 
1122  if ( !hasFocus() )
1123  {
1124  TQPointArray foldpoints( 3 );
1125  foldpoints.putPoints( 0, 3, w-15, h, w, h-15, w, h );
1126  TQRegion fold( foldpoints, false );
1127  setMask( reg.unite( pushpin_reg ).subtract( fold ) );
1128  }
1129  else
1130  setMask( reg.unite( pushpin_reg ) );
1131 }
1132 
1133 void KNote::updateBackground( int y_offset )
1134 {
1135  if ( !s_ppOffset )
1136  {
1137  m_editor->setPaper( TQBrush( colorGroup().background() ) );
1138  return;
1139  }
1140 
1141  int w = m_editor->visibleWidth();
1142  int h = m_editor->visibleHeight();
1143 
1144  // in case y_offset is not set, calculate y_offset as the content
1145  // y-coordinate of the top-left point of the viewport - which is essentially
1146  // the vertical scroll amount
1147  if ( y_offset == -1 )
1148  y_offset = m_editor->contentsY();
1149 
1150  y_offset = y_offset % h;
1151 
1152  TQImage grad_img( w, h, 32 );
1153  TQRgb rgbcol;
1154  TQColor bg = palette().active().background();
1155 
1156  for ( int i = 0; i < h; ++i )
1157  {
1158  // if the scrollbar has moved, then adjust the gradient by the amount the
1159  // scrollbar moved -- so that the background gradient looks ok when tiled
1160 
1161  // the lightness is calculated as follows:
1162  // if i >= y, then lightness = 150 - (i-y)*75/h;
1163  // if i < y, then lightness = 150 - (i+h-y)*75/h
1164 
1165  int i_1 = 150 - 75 * ((i - y_offset + h) % h) / h;
1166  rgbcol = bg.light( i_1 ).rgb();
1167  for ( int j = 0; j < w; ++j )
1168  grad_img.setPixel( j, i, rgbcol );
1169  }
1170 
1171  // setPaletteBackgroundPixmap makes TQTextEdit::color() stop working!!
1172  m_editor->setPaper( TQBrush( TQt::black, TQPixmap( grad_img ) ) );
1173 }
1174 
1175 void KNote::updateLayout()
1176 {
1177  const int headerHeight = m_label->sizeHint().height();
1178  const int margin = m_editor->margin();
1179  bool closeLeft = false;
1180 
1181  m_twinConf->setGroup( "Style" );
1182  if ( m_twinConf->readBoolEntry( "CustomButtonPositions" ) )
1183  closeLeft = m_twinConf->readEntry( "ButtonsOnLeft" ).find( 'X' ) > -1;
1184 
1185  if ( s_ppOffset )
1186  {
1187  if ( !m_editor->paper().pixmap() ) // just changed the style
1188  setColor( palette().active().foreground(), palette().active().background() );
1189 
1190  m_pushpin->show();
1191  setFrameStyle( Panel | Raised );
1192 
1193  if ( closeLeft )
1194  m_pushpin->move( width() - m_pushpin->width(), 0 );
1195  else
1196  m_pushpin->move( 0, 0 );
1197  }
1198  else
1199  {
1200  if ( m_editor->paper().pixmap() ) // just changed the style
1201  setColor( palette().active().foreground(), palette().active().background() );
1202 
1203  setFrameStyle( WinPanel | Raised );
1204  m_pushpin->hide();
1205  m_fold->hide();
1206  }
1207 
1208  m_button->setGeometry(
1209  closeLeft ? contentsRect().x() : contentsRect().width() - headerHeight,
1210  contentsRect().y() + s_ppOffset,
1211  headerHeight,
1212  headerHeight
1213  );
1214 
1215  m_label->setGeometry(
1216  contentsRect().x(), contentsRect().y() + s_ppOffset,
1217  contentsRect().width(), headerHeight
1218  );
1219 
1220  m_editor->setGeometry( TQRect(
1221  TQPoint( contentsRect().x(),
1222  contentsRect().y() + headerHeight + s_ppOffset ),
1223  TQPoint( contentsRect().right(),
1224  contentsRect().bottom() - ( m_tool ? (m_tool->isHidden() ? 0 : m_tool->height()) : 0 ) )
1225  ) );
1226 
1227  if( m_tool ) {
1228  m_tool->setGeometry(
1229  contentsRect().x(),
1230  contentsRect().bottom() - m_tool->height() + 1,
1231  contentsRect().width(),
1232  m_tool->height()
1233  );
1234  }
1235 
1236  if ( s_ppOffset )
1237  m_fold->move( width() - 15, height() - 15 );
1238 
1239  setMinimumSize(
1240  m_editor->cornerWidget()->width() + margin*2,
1241  headerHeight + s_ppOffset + ( m_tool ? m_tool->height() : 0 ) +
1242  m_editor->cornerWidget()->height() + margin*2
1243  );
1244 
1245  updateLabelAlignment();
1246  updateMask();
1247  updateBackground();
1248 }
1249 
1250 // -------------------- protected methods -------------------- //
1251 
1252 void KNote::drawFrame( TQPainter *p )
1253 {
1254  TQRect r = frameRect();
1255  r.setTop( s_ppOffset );
1256  if ( s_ppOffset )
1257  qDrawShadePanel( p, r, colorGroup(), false, lineWidth() );
1258  else
1259  qDrawWinPanel( p, r, colorGroup(), false );
1260 }
1261 
1262 void KNote::showEvent( TQShowEvent * )
1263 {
1264  if ( m_config->hideNote() )
1265  {
1266  // KWin does not preserve these properties for hidden windows
1267  slotUpdateKeepAboveBelow();
1268  slotUpdateShowInTaskbar();
1269  toDesktop( m_config->desktop() );
1270  move( m_config->position() );
1271  m_config->setHideNote( false );
1272  }
1273 }
1274 
1275 void KNote::resizeEvent( TQResizeEvent *qre )
1276 {
1277  TQFrame::resizeEvent( qre );
1278  updateLayout();
1279 }
1280 
1281 void KNote::closeEvent( TQCloseEvent *event )
1282 {
1283  if(kapp->sessionSaving())
1284  return;
1285  event->ignore(); //We don't want to close (and delete the widget). Just hide it
1286  slotClose();
1287 }
1288 
1289 void KNote::dragEnterEvent( TQDragEnterEvent *e )
1290 {
1291  if ( !m_config->readOnly() )
1292  e->accept( KColorDrag::canDecode( e ) );
1293 }
1294 
1295 void KNote::dropEvent( TQDropEvent *e )
1296 {
1297  if ( m_config->readOnly() )
1298  return;
1299 
1300  TQColor bg;
1301  if ( KColorDrag::decode( e, bg ) )
1302  setColor( paletteForegroundColor(), bg );
1303 }
1304 
1305 bool KNote::focusNextPrevChild( bool )
1306 {
1307  return true;
1308 }
1309 
1310 bool KNote::event( TQEvent *ev )
1311 {
1312  if ( ev->type() == TQEvent::LayoutHint )
1313  {
1314  updateLayout();
1315  return true;
1316  }
1317  else
1318  return TQFrame::event( ev );
1319 }
1320 
1321 bool KNote::eventFilter( TQObject *o, TQEvent *ev )
1322 {
1323  if ( ev->type() == TQEvent::DragEnter &&
1324  KColorDrag::canDecode( static_cast<TQDragEnterEvent *>(ev) ) )
1325  {
1326  dragEnterEvent( static_cast<TQDragEnterEvent *>(ev) );
1327  return true;
1328  }
1329 
1330  if ( ev->type() == TQEvent::Drop &&
1331  KColorDrag::canDecode( static_cast<TQDropEvent *>(ev) ) )
1332  {
1333  dropEvent( static_cast<TQDropEvent *>(ev) );
1334  return true;
1335  }
1336 
1337  if ( TQT_BASE_OBJECT(o) == TQT_BASE_OBJECT(m_label) )
1338  {
1339  TQMouseEvent *e = (TQMouseEvent *)ev;
1340 
1341  if ( ev->type() == TQEvent::MouseButtonDblClick )
1342  {
1343  if( !m_editor->isReadOnly())
1344  slotRename();
1345  }
1346  if ( ev->type() == TQEvent::MouseButtonPress &&
1347  (e->button() == Qt::LeftButton || e->button() == Qt::MidButton))
1348  {
1349  e->button() == Qt::LeftButton ? KWin::raiseWindow( winId() )
1350  : KWin::lowerWindow( winId() );
1351 
1352  XUngrabPointer( tqt_xdisplay(), GET_QT_X_TIME() );
1353  NETRootInfo wm_root( tqt_xdisplay(), NET::WMMoveResize );
1354  wm_root.moveResizeRequest( winId(), e->globalX(), e->globalY(), NET::Move );
1355  return true;
1356  }
1357 
1358 #if KDE_IS_VERSION( 3, 5, 1 )
1359  if ( ev->type() == TQEvent::MouseButtonRelease )
1360  {
1361  NETRootInfo wm_root( tqt_xdisplay(), NET::WMMoveResize );
1362  wm_root.moveResizeRequest( winId(), e->globalX(), e->globalY(), NET::MoveResizeCancel );
1363  return false;
1364  }
1365 #endif
1366 
1367  if ( m_menu && ( ev->type() == TQEvent::MouseButtonPress )
1368  && ( e->button() == Qt::RightButton ) )
1369  {
1370  m_menu->popup( TQCursor::pos() );
1371  return true;
1372  }
1373 
1374  return false;
1375  }
1376 
1377  if ( TQT_BASE_OBJECT(o) == TQT_BASE_OBJECT(m_editor) ) {
1378  if ( ev->type() == TQEvent::FocusOut ) {
1379  TQFocusEvent *fe = TQT_TQFOCUSEVENT(ev);
1380  if ( fe->reason() != TQFocusEvent::Popup &&
1381  fe->reason() != TQFocusEvent::Mouse ) {
1382  updateFocus();
1383  if ( isModified() ) {
1384  saveConfig();
1385  if ( !m_blockEmitDataChanged )
1386  saveData();
1387  }
1388  }
1389  } else if ( ev->type() == TQEvent::FocusIn ) {
1390  updateFocus();
1391  }
1392 
1393  return false;
1394  }
1395 
1396  if ( TQT_BASE_OBJECT(o) == TQT_BASE_OBJECT(m_editor->viewport()) )
1397  {
1398  if ( m_edit_menu &&
1399  ev->type() == TQEvent::MouseButtonPress &&
1400  ((TQMouseEvent *)ev)->button() == Qt::RightButton )
1401  {
1402  m_edit_menu->popup( TQCursor::pos() );
1403  return true;
1404  }
1405  }
1406 
1407  return false;
1408 }
1409 
1410 void KNote::slotSaveData()
1411 {
1412  saveData();
1413 }
1414 
1415 void KNote::deleteWhenIdle()
1416 {
1417  if ( m_busy <= 0 )
1418  deleteLater();
1419  else
1420  m_deleteWhenIdle = true;
1421 }
1422 
1423 void KNote::aboutToEnterEventLoop()
1424 {
1425  ++m_busy;
1426 }
1427 
1428 void KNote::eventLoopLeft()
1429 {
1430  --m_busy;
1431  if ( m_busy <= 0 && m_deleteWhenIdle )
1432  deleteLater();
1433 }
1434 
1435 
1436 #include "knote.moc"
1437 #include "knotebutton.moc"