knotes

knote.cpp

00001 /*******************************************************************
00002  KNotes -- Notes for the KDE project
00003 
00004  Copyright (c) 1997-2006, 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 <qlabel.h>
00022 #include <qdrawutil.h>
00023 #include <qsize.h>
00024 #include <qsizegrip.h>
00025 #include <qbitmap.h>
00026 #include <qcursor.h>
00027 #include <qpainter.h>
00028 #include <qpaintdevicemetrics.h>
00029 #include <qsimplerichtext.h>
00030 #include <qobjectlist.h>
00031 #include <qfile.h>
00032 #include <qcheckbox.h>
00033 #include <qtimer.h>
00034 
00035 #include <kapplication.h>
00036 #include <kdebug.h>
00037 #include <kaction.h>
00038 #include <kstdaction.h>
00039 #include <kcombobox.h>
00040 #include <ktoolbar.h>
00041 #include <kpopupmenu.h>
00042 #include <kxmlguibuilder.h>
00043 #include <kxmlguifactory.h>
00044 #include <kcolordrag.h>
00045 #include <kiconeffect.h>
00046 #include <klocale.h>
00047 #include <kstandarddirs.h>
00048 #include <kmessagebox.h>
00049 #include <kfind.h>
00050 #include <kprocess.h>
00051 #include <kinputdialog.h>
00052 #include <kmdcodec.h>
00053 #include <kglobalsettings.h>
00054 #include <kfiledialog.h>
00055 #include <kio/netaccess.h>
00056 
00057 #include <libkcal/journal.h>
00058 
00059 #include "knote.h"
00060 #include "knotebutton.h"
00061 #include "knoteedit.h"
00062 #include "knoteconfig.h"
00063 #include "knotesglobalconfig.h"
00064 #include "knoteconfigdlg.h"
00065 #include "knotealarmdlg.h"
00066 #include "knotehostdlg.h"
00067 #include "knotesnetsend.h"
00068 #include "knoteprinter.h"
00069 #include "version.h"
00070 
00071 #include "pushpin.xpm"
00072 
00073 #include <kwin.h>
00074 #include <netwm.h>
00075 
00076 #include <fixx11h.h>
00077 
00078 using namespace KCal;
00079 
00080 extern Time qt_x_time;
00081 
00082 int KNote::s_ppOffset = 0;
00083 
00084 KNote::KNote( QDomDocument buildDoc, Journal *j, QWidget *parent, const char *name )
00085   : QFrame( parent, name, WStyle_Customize | WStyle_NoBorder | WDestructiveClose ),
00086     m_label( 0 ), m_pushpin( 0 ), m_fold( 0 ), m_button( 0 ), m_tool( 0 ), m_editor( 0 ),
00087     m_config( 0 ), m_journal( j ), m_find( 0 ),
00088     m_kwinConf( KSharedConfig::openConfig( "kwinrc", true ) ),
00089     m_busy( 0 ), m_deleteWhenIdle( false ), m_blockEmitDataChanged( false )
00090 {
00091     setAcceptDrops( true );
00092     actionCollection()->setWidget( this );
00093 
00094     setDOMDocument( buildDoc );
00095 
00096     // just set the name of the file to save the actions to, do NOT reparse it
00097     setXMLFile( instance()->instanceName() + "ui.rc", false, false );
00098 
00099     // if there is no title yet, use the start date if valid
00100     // (KOrganizer's journals don't have titles but a valid start date)
00101     if ( m_journal->summary().isNull() && m_journal->dtStart().isValid() )
00102     {
00103         QString s = KGlobal::locale()->formatDateTime( m_journal->dtStart() );
00104         m_journal->setSummary( s );
00105     }
00106 
00107     // create the menu items for the note - not the editor...
00108     // rename, mail, print, save as, insert date, alarm, close, delete, new note
00109     new KAction( i18n("New"), "filenew", 0,
00110         this,SLOT(slotRequestNewNote()) , actionCollection(), "new_note" );
00111     new KAction( i18n("Rename..."), "text", 0,
00112         this, SLOT(slotRename()), actionCollection(), "rename_note" );
00113     m_readOnly = new KToggleAction( i18n("Lock"), "lock" , 0,
00114         this, SLOT(slotUpdateReadOnly()), actionCollection(), "lock_note" );
00115     m_readOnly->setCheckedState( KGuiItem( i18n("Unlock"), "unlock" ) );
00116     new KAction( i18n("Hide"), "fileclose" , Key_Escape,
00117         this, SLOT(slotClose()), actionCollection(), "hide_note" );
00118     new KAction( i18n("Delete"), "knotes_delete", 0,
00119         this, SLOT(slotKill()), actionCollection(), "delete_note" );
00120 
00121     new KAction( i18n("Insert Date"), "knotes_date", 0 ,
00122         this, SLOT(slotInsDate()), actionCollection(), "insert_date" );
00123     new KAction( i18n("Set Alarm..."), "knotes_alarm", 0 ,
00124         this, SLOT(slotSetAlarm()), actionCollection(), "set_alarm" );
00125 
00126     new KAction( i18n("Send..."), "network", 0,
00127         this, SLOT(slotSend()), actionCollection(), "send_note" );
00128     new KAction( i18n("Mail..."), "mail_send", 0,
00129         this, SLOT(slotMail()), actionCollection(), "mail_note" );
00130     new KAction( i18n("Save As..."), "filesaveas", 0,
00131         this, SLOT(slotSaveAs()), actionCollection(), "save_note" );
00132     KStdAction::print( this, SLOT(slotPrint()), actionCollection(), "print_note" );
00133     new KAction( i18n("Preferences..."), "configure", 0,
00134         this, SLOT(slotPreferences()), actionCollection(), "configure_note" );
00135 
00136     m_keepAbove = new KToggleAction( i18n("Keep Above Others"), "up", 0,
00137         this, SLOT(slotUpdateKeepAboveBelow()), actionCollection(), "keep_above" );
00138     m_keepAbove->setExclusiveGroup( "keepAB" );
00139 
00140     m_keepBelow = new KToggleAction( i18n("Keep Below Others"), "down", 0,
00141         this, SLOT(slotUpdateKeepAboveBelow()), actionCollection(), "keep_below" );
00142     m_keepBelow->setExclusiveGroup( "keepAB" );
00143 
00144     m_toDesktop = new KListAction( i18n("To Desktop"), 0,
00145         this, SLOT(slotPopupActionToDesktop(int)), actionCollection(), "to_desktop" );
00146     connect( m_toDesktop->popupMenu(), SIGNAL(aboutToShow()), this, SLOT(slotUpdateDesktopActions()) );
00147 
00148     // invisible action to walk through the notes to make this configurable
00149     new KAction( i18n("Walk Through Notes"), 0, SHIFT+Key_BackTab,
00150                  this, SIGNAL(sigShowNextNote()), actionCollection(), "walk_notes" );
00151 
00152     // create the note header, button and label...
00153     m_label = new QLabel( this );
00154     m_label->setFrameStyle( NoFrame );
00155     m_label->setLineWidth( 0 );
00156     m_label->installEventFilter( this );  // receive events (for dragging & action menu)
00157     setName( m_journal->summary() );      // don't worry, no signals are connected at this stage yet
00158 
00159     m_button = new KNoteButton( "knotes_close", this );
00160     connect( m_button, SIGNAL(clicked()), this, SLOT(slotClose()) );
00161 
00162     // create the note editor
00163     m_editor = new KNoteEdit( actionCollection(), this );
00164     m_editor->setNote( this );
00165     m_editor->installEventFilter( this ); // receive events (for modified)
00166     m_editor->viewport()->installEventFilter( this );
00167     connect( m_editor, SIGNAL(contentsMoving( int, int )), this, SLOT(slotUpdateViewport( int, int )));
00168 
00169     KXMLGUIBuilder builder( this );
00170     KXMLGUIFactory factory( &builder, this );
00171     factory.addClient( this );
00172 
00173     m_menu = dynamic_cast<KPopupMenu*>(factory.container( "note_context", this ));
00174     m_edit_menu = dynamic_cast<KPopupMenu*>(factory.container( "note_edit", this ));
00175     m_tool = dynamic_cast<KToolBar*>(factory.container( "note_tool", this ));
00176 
00177     if ( m_tool ) {
00178       m_tool->setIconSize( 10 );
00179       m_tool->setFixedHeight( 16 );
00180       m_tool->setIconText( KToolBar::IconOnly );
00181 
00182       // if there was just a way of making KComboBox adhere the toolbar height...
00183       QObjectList *list = m_tool->queryList( "KComboBox" );
00184       QObjectListIt it( *list );
00185       while ( it.current() != 0 )
00186       {
00187           KComboBox *combo = (KComboBox *)it.current();
00188           QFont font = combo->font();
00189           font.setPointSize( 7 );
00190           combo->setFont( font );
00191           combo->setFixedHeight( 14 );
00192           ++it;
00193       }
00194       delete list;
00195 
00196       m_tool->hide();
00197     }
00198 
00199     setFocusProxy( m_editor );
00200 
00201     // create the resize handle
00202     m_editor->setCornerWidget( new QSizeGrip( this ) );
00203     uint width = m_editor->cornerWidget()->width();
00204     uint height = m_editor->cornerWidget()->height();
00205     QBitmap mask;
00206     mask.resize( width, height );
00207     mask.fill( color0 );
00208     QPointArray array;
00209     array.setPoints( 3, 0, height, width, height, width, 0 );
00210     QPainter p;
00211     p.begin( &mask );
00212     p.setBrush( color1 );
00213     p.drawPolygon( array );
00214     p.end();
00215     m_editor->cornerWidget()->setMask( mask );
00216     m_editor->cornerWidget()->setBackgroundMode( PaletteBase );
00217 
00218     // the config file location
00219     QString configFile = KGlobal::dirs()->saveLocation( "appdata", "notes/" );
00220     configFile += m_journal->uid();
00221 
00222     // no config file yet? -> use the default display config if available
00223     // we want to write to configFile, so use "false"
00224     bool newNote = !KIO::NetAccess::exists( KURL::fromPathOrURL( configFile ), false, 0 );
00225 
00226     m_config = new KNoteConfig( KSharedConfig::openConfig( configFile, false, false ) );
00227     m_config->readConfig();
00228     m_config->setVersion( KNOTES_VERSION );
00229 
00230     if ( newNote )
00231     {
00232         // until kdelibs provides copying of KConfigSkeletons (KDE 3.4)
00233         KNotesGlobalConfig *globalConfig = KNotesGlobalConfig::self();
00234         m_config->setBgColor( globalConfig->bgColor() );
00235         m_config->setFgColor( globalConfig->fgColor() );
00236         m_config->setWidth( globalConfig->width() );
00237         m_config->setHeight( globalConfig->height() );
00238 
00239         m_config->setFont( globalConfig->font() );
00240         m_config->setTitleFont( globalConfig->titleFont() );
00241         m_config->setAutoIndent( globalConfig->autoIndent() );
00242         m_config->setRichText( globalConfig->richText() );
00243         m_config->setTabSize( globalConfig->tabSize() );
00244         m_config->setReadOnly( globalConfig->readOnly() );
00245 
00246         m_config->setDesktop( globalConfig->desktop() );
00247         m_config->setHideNote( globalConfig->hideNote() );
00248         m_config->setPosition( globalConfig->position() );
00249         m_config->setShowInTaskbar( globalConfig->showInTaskbar() );
00250         m_config->setKeepAbove( globalConfig->keepAbove() );
00251         m_config->setKeepBelow( globalConfig->keepBelow() );
00252 
00253         m_config->writeConfig();
00254     }
00255 
00256     // set up the look&feel of the note
00257     setMinimumSize( 20, 20 );
00258     setLineWidth( 1 );
00259     setMargin( 0 );
00260 
00261     m_editor->setMargin( 0 );
00262     m_editor->setFrameStyle( NoFrame );
00263     m_editor->setBackgroundOrigin( WindowOrigin );
00264 
00265     // can be done here since this doesn't pick up changes while KNotes is running anyway
00266     bool closeLeft = false;
00267     m_kwinConf->setGroup( "Style" );
00268     if ( m_kwinConf->readBoolEntry( "CustomButtonPositions" ) )
00269         closeLeft = m_kwinConf->readEntry( "ButtonsOnLeft" ).find( 'X' ) > -1;
00270 
00271     QPixmap pushpin_pix;
00272     if ( closeLeft )
00273         pushpin_pix = QPixmap( QPixmap( pushpin_xpm ).convertToImage().mirror( true, false ) );
00274     else
00275         pushpin_pix = QPixmap( pushpin_xpm );
00276 
00277     // the pushpin label at the top left or right corner
00278     m_pushpin = new QLabel( this );
00279     m_pushpin->setScaledContents( true );
00280     m_pushpin->setBackgroundMode( NoBackground );
00281     m_pushpin->setPixmap( pushpin_pix );
00282     m_pushpin->resize( pushpin_pix.size() );
00283 
00284     // fold label at bottom right corner
00285     m_fold = new QLabel( this );
00286     m_fold->setScaledContents( true );
00287     m_fold->setBackgroundMode( NoBackground );
00288 
00289     // load the display configuration of the note
00290     width = m_config->width();
00291     height = m_config->height();
00292     resize( width, height );
00293 
00294     // let KWin do the placement if the position is illegal--at least 10 pixels
00295     // of a note need to be visible
00296     const QPoint& position = m_config->position();
00297     QRect desk = kapp->desktop()->rect();
00298     desk.addCoords( 10, 10, -10, -10 );
00299     if ( desk.intersects( QRect( position, QSize( width, height ) ) ) )
00300         move( position );           // do before calling show() to avoid flicker
00301 
00302     // config items in the journal have priority
00303     QString property = m_journal->customProperty( "KNotes", "FgColor" );
00304     if ( !property.isNull() )
00305         m_config->setFgColor( QColor( property ) );
00306     else
00307         m_journal->setCustomProperty( "KNotes", "FgColor", m_config->fgColor().name() );
00308 
00309     property = m_journal->customProperty( "KNotes", "BgColor" );
00310     if ( !property.isNull() )
00311         m_config->setBgColor( QColor( property ) );
00312     else
00313         m_journal->setCustomProperty( "KNotes", "BgColor", m_config->bgColor().name() );
00314 
00315     property = m_journal->customProperty( "KNotes", "RichText" );
00316     if ( !property.isNull() )
00317         m_config->setRichText( property == "true" ? true : false );
00318     else
00319         m_journal->setCustomProperty( "KNotes", "RichText", m_config->richText() ? "true" : "false" );
00320 
00321     // read configuration settings...
00322     slotApplyConfig();
00323 
00324     // create the mask for the fold---to be done after slotApplyConfig(),
00325     // which calls createFold()
00326     m_fold->setMask( QRegion( m_fold->pixmap()->createHeuristicMask() ) );
00327 
00328     // if this is a new note put on current desktop - we can't use defaults
00329     // in KConfig XT since only _changes_ will be stored in the config file
00330     int desktop = m_config->desktop();
00331     if ( desktop < 0 && desktop != NETWinInfo::OnAllDesktops )
00332         desktop = KWin::currentDesktop();
00333 
00334     // show the note if desired
00335     if ( desktop != 0 && !m_config->hideNote() )
00336     {
00337         // to avoid flicker, call this before show()
00338         toDesktop( desktop );
00339         show();
00340 
00341         // because KWin forgets about that for hidden windows
00342         if ( desktop == NETWinInfo::OnAllDesktops )
00343             toDesktop( desktop );
00344     }
00345 
00346     m_editor->setText( m_journal->description() );
00347     m_editor->setModified( false );
00348 
00349     m_readOnly->setChecked( m_config->readOnly() );
00350     slotUpdateReadOnly();
00351 
00352     if ( m_config->keepAbove() )
00353         m_keepAbove->setChecked( true );
00354     else if ( m_config->keepBelow() )
00355         m_keepBelow->setChecked( true );
00356     else
00357     {
00358         m_keepAbove->setChecked( false );
00359         m_keepBelow->setChecked( false );
00360     }
00361     slotUpdateKeepAboveBelow();
00362 
00363     // HACK: update the icon color - again after showing the note, to make kicker aware of the new colors
00364     KIconEffect effect;
00365     QPixmap icon = effect.apply( kapp->icon(), KIconEffect::Colorize, 1, m_config->bgColor(), false );
00366     QPixmap miniIcon = effect.apply( kapp->miniIcon(), KIconEffect::Colorize, 1, m_config->bgColor(), false );
00367     KWin::setIcons( winId(), icon, miniIcon );
00368 }
00369 
00370 KNote::~KNote()
00371 {
00372     delete m_config;
00373 }
00374 
00375 void KNote::slotRequestNewNote()
00376 {
00377     emit sigRequestNewNote();
00378 }
00379 
00380 void KNote::slotEmitCreateNewNote()
00381 {
00382     emit sigRequestNewNote();
00383 }
00384 
00385 void KNote::changeJournal(KCal::Journal *journal)
00386 {
00387    m_journal = journal;
00388    m_editor->setText( m_journal->description() );
00389    m_label->setText( m_journal->summary() );
00390    updateLabelAlignment();
00391 }
00392 
00393 // -------------------- public slots -------------------- //
00394 
00395 void KNote::slotKill( bool force )
00396 {
00397     m_blockEmitDataChanged = true;
00398     if ( !force &&
00399          KMessageBox::warningContinueCancel( this,
00400              i18n("<qt>Do you really want to delete note <b>%1</b>?</qt>").arg( m_label->text() ),
00401              i18n("Confirm Delete"), KGuiItem( i18n("&Delete"), "editdelete" ),
00402              "ConfirmDeleteNote"
00403          )
00404          != KMessageBox::Continue )
00405     {
00406     m_blockEmitDataChanged = false;
00407         return;
00408     }
00409     aboutToEnterEventLoop();
00410     // delete the configuration first, then the corresponding file
00411     delete m_config;
00412     m_config = 0;
00413 
00414     QString configFile = KGlobal::dirs()->saveLocation( "appdata", "notes/" );
00415     configFile += m_journal->uid();
00416 
00417     if ( !KIO::NetAccess::del( KURL::fromPathOrURL( configFile ), this ) )
00418         kdError(5500) << "Can't remove the note config: " << configFile << endl;
00419 
00420     emit sigKillNote( m_journal );
00421     eventLoopLeft();
00422 
00423 }
00424 
00425 
00426 // -------------------- public member functions -------------------- //
00427 
00428 void KNote::saveData(bool update)
00429 {
00430     m_journal->setSummary( m_label->text() );
00431     m_journal->setDescription( m_editor->text() );
00432     m_journal->setCustomProperty( "KNotes", "FgColor", m_config->fgColor().name() );
00433     m_journal->setCustomProperty( "KNotes", "BgColor", m_config->bgColor().name() );
00434     m_journal->setCustomProperty( "KNotes", "RichText", m_config->richText() ? "true" : "false" );
00435     if(update) {
00436     emit sigDataChanged(m_journal->uid());
00437     m_editor->setModified( false );
00438     }
00439 }
00440 
00441 void KNote::saveConfig() const
00442 {
00443     m_config->setWidth( width() );
00444     if ( m_tool )
00445       m_config->setHeight( height() - (m_tool->isHidden() ? 0 : m_tool->height()) );
00446     else
00447       m_config->setHeight( 0 );
00448     m_config->setPosition( pos() );
00449 
00450     NETWinInfo wm_client( qt_xdisplay(), winId(), qt_xrootwin(), NET::WMDesktop );
00451     if ( wm_client.desktop() == NETWinInfo::OnAllDesktops || wm_client.desktop() > 0 )
00452         m_config->setDesktop( wm_client.desktop() );
00453 
00454     // actually store the config on disk
00455     m_config->writeConfig();
00456 }
00457 
00458 QString KNote::noteId() const
00459 {
00460     return m_journal->uid();
00461 }
00462 
00463 QString KNote::name() const
00464 {
00465     return m_label->text();
00466 }
00467 
00468 QString KNote::text() const
00469 {
00470     return m_editor->text();
00471 }
00472 
00473 QString KNote::plainText() const
00474 {
00475     if ( m_editor->textFormat() == RichText )
00476     {
00477         QTextEdit conv;
00478         conv.setTextFormat( RichText );
00479         conv.setText( m_editor->text() );
00480         conv.setTextFormat( PlainText );
00481         return conv.text();
00482     }
00483     else
00484         return m_editor->text();
00485 }
00486 
00487 void KNote::setName( const QString& name )
00488 {
00489     m_label->setText( name );
00490     updateLabelAlignment();
00491 
00492     if ( m_editor )    // not called from CTOR?
00493         saveData();
00494 
00495     // set the window's name for the taskbar entry to be more helpful (#58338)
00496     NETWinInfo note_win( qt_xdisplay(), winId(), qt_xrootwin(), NET::WMDesktop );
00497     note_win.setName( name.utf8() );
00498 
00499     emit sigNameChanged();
00500 }
00501 
00502 void KNote::setText( const QString& text )
00503 {
00504     m_editor->setText( text );
00505     saveData();
00506 }
00507 
00508 QColor KNote::fgColor() const
00509 {
00510     return m_config->fgColor();
00511 }
00512 
00513 QColor KNote::bgColor() const
00514 {
00515     return m_config->bgColor();
00516 }
00517 
00518 void KNote::setColor( const QColor& fg, const QColor& bg )
00519 {
00520     m_journal->setCustomProperty( "KNotes", "FgColor", fg.name() );
00521     m_journal->setCustomProperty( "KNotes", "BgColor", bg.name() );
00522     m_config->setFgColor( fg );
00523     m_config->setBgColor( bg );
00524 
00525     m_journal->updated();  // because setCustomProperty() doesn't call it!!
00526     emit sigDataChanged(noteId());
00527     m_config->writeConfig();
00528 
00529     QPalette newpalette = palette();
00530     newpalette.setColor( QColorGroup::Background, bg );
00531     newpalette.setColor( QColorGroup::Foreground, fg );
00532     newpalette.setColor( QColorGroup::Base,       bg ); // text background
00533     newpalette.setColor( QColorGroup::Text,       fg ); // text color
00534     newpalette.setColor( QColorGroup::Button,     bg );
00535     newpalette.setColor( QColorGroup::ButtonText, fg );
00536 
00537 //    newpalette.setColor( QColorGroup::Highlight,  bg );
00538 //    newpalette.setColor( QColorGroup::HighlightedText, fg );
00539 
00540     // the shadow
00541     newpalette.setColor( QColorGroup::Midlight, bg.light(150) );
00542     newpalette.setColor( QColorGroup::Shadow, bg.dark(116) );
00543     newpalette.setColor( QColorGroup::Light, bg.light(180) );
00544     if ( s_ppOffset )
00545         newpalette.setColor( QColorGroup::Dark, bg.dark(200) );
00546     else
00547         newpalette.setColor( QColorGroup::Dark, bg.dark(108) );
00548     setPalette( newpalette );
00549 
00550     // set the text color
00551     m_editor->setTextColor( fg );
00552 
00553     // set the background color or gradient
00554     updateBackground();
00555 
00556     // set darker value for the hide button...
00557     QPalette darker = palette();
00558     darker.setColor( QColorGroup::Button, bg.dark(116) );
00559     m_button->setPalette( darker );
00560 
00561     // update the icon color
00562     KIconEffect effect;
00563     QPixmap icon = effect.apply( kapp->icon(), KIconEffect::Colorize, 1, bg, false );
00564     QPixmap miniIcon = effect.apply( kapp->miniIcon(), KIconEffect::Colorize, 1, bg, false );
00565     KWin::setIcons( winId(), icon, miniIcon );
00566 
00567     // set the color for the selection used to highlight the find stuff
00568     QColor sel = palette().color( QPalette::Active, QColorGroup::Base ).dark();
00569     if ( sel == Qt::black )
00570         sel = palette().color( QPalette::Active, QColorGroup::Base ).light();
00571 
00572     m_editor->setSelectionAttributes( 1, sel, true );
00573 
00574     // update the color of the fold
00575     createFold();
00576 
00577     // update the color of the title
00578     updateFocus();
00579     emit sigColorChanged();
00580 }
00581 
00582 void KNote::find( const QString& pattern, long options )
00583 {
00584     delete m_find;
00585     m_find = new KFind( pattern, options, this );
00586 
00587     connect( m_find, SIGNAL(highlight( const QString &, int, int )),
00588              this, SLOT(slotHighlight( const QString &, int, int )) );
00589     connect( m_find, SIGNAL(findNext()), this, SLOT(slotFindNext()) );
00590 
00591     m_find->setData( plainText() );
00592     slotFindNext();
00593 }
00594 
00595 void KNote::slotFindNext()
00596 {
00597     // TODO: honor FindBackwards
00598     // TODO: dialogClosed() -> delete m_find
00599 
00600     // Let KFind inspect the text fragment, and display a dialog if a match is found
00601     KFind::Result res = m_find->find();
00602 
00603     if ( res == KFind::NoMatch ) // i.e. at end-pos
00604     {
00605         m_editor->removeSelection( 1 );
00606         emit sigFindFinished();
00607         delete m_find;
00608         m_find = 0;
00609     }
00610     else
00611     {
00612         show();
00613         KWin::setCurrentDesktop( KWin::windowInfo( winId() ).desktop() );
00614     }
00615 }
00616 
00617 void KNote::slotHighlight( const QString& str, int idx, int len )
00618 {
00619     int paraFrom = 0, idxFrom = 0, p = 0;
00620     for ( ; p < idx; ++p )
00621         if ( str[p] == '\n' )
00622         {
00623             ++paraFrom;
00624             idxFrom = 0;
00625         }
00626         else
00627             ++idxFrom;
00628 
00629     int paraTo = paraFrom, idxTo = idxFrom;
00630 
00631     for ( ; p < idx + len; ++p )
00632     {
00633         if ( str[p] == '\n' )
00634         {
00635             ++paraTo;
00636             idxTo = 0;
00637         }
00638         else
00639             ++idxTo;
00640     }
00641 
00642     m_editor->setSelection( paraFrom, idxFrom, paraTo, idxTo, 1 );
00643 }
00644 
00645 bool KNote::isModified() const
00646 {
00647     return m_editor->isModified();
00648 }
00649 
00650 // FIXME KDE 4.0: remove sync(), isNew() and isModified()
00651 void KNote::sync( const QString& app )
00652 {
00653     QByteArray sep( 1 );
00654     sep[0] = '\0';
00655 
00656     KMD5 hash;
00657     QCString result;
00658 
00659     hash.update( m_label->text().utf8() );
00660     hash.update( sep );
00661     hash.update( m_editor->text().utf8() );
00662     hash.hexDigest( result );
00663 
00664     // hacky... not possible with KConfig XT
00665     KConfig *config = m_config->config();
00666     config->setGroup( "Synchronisation" );
00667     config->writeEntry( app, result.data() );
00668 }
00669 
00670 bool KNote::isNew( const QString& app ) const
00671 {
00672     KConfig *config = m_config->config();
00673     config->setGroup( "Synchronisation" );
00674     QString hash = config->readEntry( app );
00675     return hash.isEmpty();
00676 }
00677 
00678 bool KNote::isModified( const QString& app ) const
00679 {
00680     QByteArray sep( 1 );
00681     sep[0] = '\0';
00682 
00683     KMD5 hash;
00684     hash.update( m_label->text().utf8() );
00685     hash.update( sep );
00686     hash.update( m_editor->text().utf8() );
00687     hash.hexDigest();
00688 
00689     KConfig *config = m_config->config();
00690     config->setGroup( "Synchronisation" );
00691     QString orig = config->readEntry( app );
00692 
00693     if ( hash.verify( orig.utf8() ) )   // returns false on error!
00694         return false;
00695     else
00696         return true;
00697 }
00698 
00699 void KNote::setStyle( int style )
00700 {
00701     if ( style == KNotesGlobalConfig::EnumStyle::Plain )
00702         s_ppOffset = 0;
00703     else
00704         s_ppOffset = 12;
00705 }
00706 
00707 
00708 // ------------------ private slots (menu actions) ------------------ //
00709 
00710 void KNote::slotRename()
00711 {
00712     m_blockEmitDataChanged = true;
00713     // pop up dialog to get the new name
00714     bool ok;
00715     aboutToEnterEventLoop();
00716     QString oldName = m_label->text();
00717     QString newName = KInputDialog::getText( QString::null,
00718         i18n("Please enter the new name:"), m_label->text(), &ok, this );
00719     eventLoopLeft();
00720     m_blockEmitDataChanged = false;
00721     if ( !ok || ( oldName == newName) ) // handle cancel
00722         return;
00723 
00724     setName( newName );
00725 }
00726 
00727 void KNote::slotUpdateReadOnly()
00728 {
00729     const bool readOnly = m_readOnly->isChecked();
00730 
00731     m_editor->setReadOnly( readOnly );
00732     m_config->setReadOnly( readOnly );
00733 
00734     // Enable/disable actions accordingly
00735     actionCollection()->action( "configure_note" )->setEnabled( !readOnly );
00736     actionCollection()->action( "insert_date" )->setEnabled( !readOnly );
00737     actionCollection()->action( "delete_note" )->setEnabled( !readOnly );
00738 
00739     actionCollection()->action( "edit_undo" )->setEnabled( !readOnly && m_editor->isUndoAvailable() );
00740     actionCollection()->action( "edit_redo" )->setEnabled( !readOnly && m_editor->isRedoAvailable() );
00741     actionCollection()->action( "edit_cut" )->setEnabled( !readOnly && m_editor->hasSelectedText() );
00742     actionCollection()->action( "edit_paste" )->setEnabled( !readOnly );
00743     actionCollection()->action( "edit_clear" )->setEnabled( !readOnly );
00744     actionCollection()->action( "rename_note" )->setEnabled( !readOnly );
00745 
00746     actionCollection()->action( "format_bold" )->setEnabled( !readOnly );
00747     actionCollection()->action( "format_italic" )->setEnabled( !readOnly );
00748     actionCollection()->action( "format_underline" )->setEnabled( !readOnly );
00749     actionCollection()->action( "format_strikeout" )->setEnabled( !readOnly );
00750     actionCollection()->action( "format_alignleft" )->setEnabled( !readOnly );
00751     actionCollection()->action( "format_aligncenter" )->setEnabled( !readOnly );
00752     actionCollection()->action( "format_alignright" )->setEnabled( !readOnly );
00753     actionCollection()->action( "format_alignblock" )->setEnabled( !readOnly );
00754     actionCollection()->action( "format_list" )->setEnabled( !readOnly );
00755     actionCollection()->action( "format_super" )->setEnabled( !readOnly );
00756     actionCollection()->action( "format_sub" )->setEnabled( !readOnly );
00757     actionCollection()->action( "format_size" )->setEnabled( !readOnly );
00758     actionCollection()->action( "format_color" )->setEnabled( !readOnly );
00759 
00760     updateFocus();
00761 }
00762 
00763 void KNote::slotClose()
00764 {
00765     NETWinInfo wm_client( qt_xdisplay(), winId(), qt_xrootwin(), NET::WMDesktop );
00766     if ( wm_client.desktop() == NETWinInfo::OnAllDesktops || wm_client.desktop() > 0 )
00767         m_config->setDesktop( wm_client.desktop() );
00768 
00769     m_editor->clearFocus();
00770     m_config->setHideNote( true );
00771     m_config->setPosition( pos() );
00772     m_config->writeConfig();
00773     // just hide the note so it's still available from the dock window
00774     hide();
00775 }
00776 
00777 void KNote::slotInsDate()
00778 {
00779     m_editor->insert( KGlobal::locale()->formatDateTime(QDateTime::currentDateTime()) );
00780 }
00781 
00782 void KNote::slotSetAlarm()
00783 {
00784     m_blockEmitDataChanged = true;
00785     KNoteAlarmDlg dlg( name(), this );
00786     dlg.setIncidence( m_journal );
00787 
00788     aboutToEnterEventLoop();
00789     if ( dlg.exec() == QDialog::Accepted )
00790         emit sigDataChanged(noteId());
00791     eventLoopLeft();
00792     m_blockEmitDataChanged = false;
00793 }
00794 
00795 void KNote::slotPreferences()
00796 {
00797     // reuse if possible
00798     if ( KNoteConfigDlg::showDialog( noteId().utf8() ) )
00799         return;
00800 
00801     // create a new preferences dialog...
00802     KNoteConfigDlg *dialog = new KNoteConfigDlg( m_config, name(), this, noteId().utf8() );
00803     connect( dialog, SIGNAL(settingsChanged()), this, SLOT(slotApplyConfig()) );
00804     connect( this, SIGNAL(sigNameChanged()), dialog, SLOT(slotUpdateCaption()) );
00805     dialog->show();
00806 }
00807 
00808 void KNote::slotSend()
00809 {
00810     // pop up dialog to get the IP
00811     KNoteHostDlg hostDlg( i18n("Send \"%1\"").arg( name() ), this );
00812     aboutToEnterEventLoop();
00813     bool ok = (hostDlg.exec() == QDialog::Accepted);
00814     eventLoopLeft();
00815     if ( !ok ) // handle cancel
00816         return;
00817     QString host = hostDlg.host();
00818 
00819     if ( host.isEmpty() )
00820     {
00821         KMessageBox::sorry( this, i18n("The host cannot be empty.") );
00822         return;
00823     }
00824 
00825     // Send the note
00826     KNotesNetworkSender *sender = new KNotesNetworkSender( host, KNotesGlobalConfig::port() );
00827     sender->setSenderId( KNotesGlobalConfig::senderID() );
00828     sender->setNote( name(), text() );
00829     sender->connect();
00830 }
00831 
00832 void KNote::slotMail()
00833 {
00834     // get the mail action command
00835     const QStringList cmd_list = QStringList::split( QChar(' '), KNotesGlobalConfig::mailAction() );
00836 
00837     KProcess mail;
00838     for ( QStringList::ConstIterator it = cmd_list.constBegin();
00839         it != cmd_list.constEnd(); ++it )
00840     {
00841         if ( *it == "%f" )
00842             mail << plainText().local8Bit();  // convert rich text to plain text
00843         else if ( *it == "%t" )
00844             mail << m_label->text().local8Bit();
00845         else
00846             mail << (*it).local8Bit();
00847     }
00848 
00849     if ( !mail.start( KProcess::DontCare ) )
00850         KMessageBox::sorry( this, i18n("Unable to start the mail process.") );
00851 }
00852 
00853 void KNote::slotPrint()
00854 {
00855     QString content;
00856     if ( m_editor->textFormat() == PlainText )
00857         content = QStyleSheet::convertFromPlainText( m_editor->text() );
00858     else
00859         content = m_editor->text();
00860 
00861     KNotePrinter printer;
00862     printer.setMimeSourceFactory( m_editor->mimeSourceFactory() );
00863     printer.setFont( m_config->font() );
00864     printer.setContext( m_editor->context() );
00865     printer.setStyleSheet( m_editor->styleSheet() );
00866     printer.setColorGroup( colorGroup() );
00867     printer.printNote( QString(), content );
00868 }
00869 
00870 void KNote::slotSaveAs()
00871 {
00872     m_blockEmitDataChanged = true;
00873     QCheckBox *convert = 0;
00874 
00875     if ( m_editor->textFormat() == RichText )
00876     {
00877         convert = new QCheckBox( 0 );
00878         convert->setText( i18n("Save note as plain text") );
00879     }
00880 
00881     KFileDialog dlg( QString::null, QString::null, this, "filedialog", true, convert );
00882     dlg.setOperationMode( KFileDialog::Saving );
00883     dlg.setCaption( i18n("Save As") );
00884     aboutToEnterEventLoop();
00885     dlg.exec();
00886     eventLoopLeft();
00887 
00888     QString fileName = dlg.selectedFile();
00889     if ( fileName.isEmpty() )
00890     {
00891     m_blockEmitDataChanged = false;
00892         return;
00893     }
00894     QFile file( fileName );
00895 
00896     if ( file.exists() &&
00897          KMessageBox::warningContinueCancel( this, i18n("<qt>A file named <b>%1</b> already exists.<br>"
00898                            "Are you sure you want to overwrite it?</qt>").arg( QFileInfo(file).fileName() ) )
00899          != KMessageBox::Continue )
00900     {
00901     m_blockEmitDataChanged = false;
00902         return;
00903     }
00904 
00905     if ( file.open( IO_WriteOnly ) )
00906     {
00907         QTextStream stream( &file );
00908         // convert rich text to plain text first
00909         if ( convert && convert->isChecked() )
00910             stream << plainText();
00911         else
00912             stream << text();
00913     }
00914     m_blockEmitDataChanged = false;
00915 }
00916 
00917 void KNote::slotPopupActionToDesktop( int id )
00918 {
00919     toDesktop( id - 1 ); // compensate for the menu separator, -1 == all desktops
00920 }
00921 
00922 
00923 // ------------------ private slots (configuration) ------------------ //
00924 
00925 void KNote::slotApplyConfig()
00926 {
00927     if ( m_config->richText() )
00928         m_editor->setTextFormat( RichText );
00929     else
00930         m_editor->setTextFormat( PlainText );
00931 
00932     m_label->setFont( m_config->titleFont() );
00933     m_editor->setTextFont( m_config->font() );
00934     m_editor->setTabStop( m_config->tabSize() );
00935     m_editor->setAutoIndentMode( m_config->autoIndent() );
00936 
00937     // if called as a slot, save the text, we might have changed the
00938     // text format - otherwise the journal will not be updated
00939     if ( sender() )
00940         saveData();
00941 
00942     setColor( m_config->fgColor(), m_config->bgColor() );
00943 
00944     updateLabelAlignment();
00945     slotUpdateShowInTaskbar();
00946 }
00947 
00948 void KNote::slotUpdateKeepAboveBelow()
00949 {
00950     KWin::WindowInfo info( KWin::windowInfo( winId() ) );
00951 
00952     if ( m_keepAbove->isChecked() )
00953     {
00954         m_config->setKeepAbove( true );
00955         m_config->setKeepBelow( false );
00956         KWin::setState( winId(), info.state() | NET::KeepAbove );
00957     }
00958     else if ( m_keepBelow->isChecked() )
00959     {
00960         m_config->setKeepAbove( false );
00961         m_config->setKeepBelow( true );
00962         KWin::setState( winId(), info.state() | NET::KeepBelow );
00963     }
00964     else
00965     {
00966         m_config->setKeepAbove( false );
00967         KWin::clearState( winId(), NET::KeepAbove );
00968 
00969         m_config->setKeepBelow( false );
00970         KWin::clearState( winId(), NET::KeepBelow );
00971     }
00972 }
00973 
00974 void KNote::slotUpdateShowInTaskbar()
00975 {
00976     if ( !m_config->showInTaskbar() )
00977         KWin::setState( winId(), KWin::windowInfo(winId()).state() | NET::SkipTaskbar );
00978     else
00979         KWin::clearState( winId(), NET::SkipTaskbar );
00980 }
00981 
00982 void KNote::slotUpdateDesktopActions()
00983 {
00984     NETRootInfo wm_root( qt_xdisplay(), NET::NumberOfDesktops | NET::DesktopNames );
00985     NETWinInfo wm_client( qt_xdisplay(), winId(), qt_xrootwin(), NET::WMDesktop );
00986 
00987     QStringList desktops;
00988     desktops.append( i18n("&All Desktops") );
00989     desktops.append( QString::null );           // Separator
00990 
00991     int count = wm_root.numberOfDesktops();
00992     for ( int n = 1; n <= count; n++ )
00993         desktops.append( QString("&%1 %2").arg( n ).arg( QString::fromUtf8(wm_root.desktopName( n )) ) );
00994 
00995     m_toDesktop->setItems( desktops );
00996 
00997     if ( wm_client.desktop() == NETWinInfo::OnAllDesktops )
00998         m_toDesktop->setCurrentItem( 0 );
00999     else
01000         m_toDesktop->setCurrentItem( wm_client.desktop() + 1 ); // compensate for separator (+1)
01001 }
01002 
01003 void KNote::slotUpdateViewport( int /*x*/, int y )
01004 {
01005     if ( s_ppOffset )
01006         updateBackground( y );
01007 }
01008 
01009 // -------------------- private methods -------------------- //
01010 
01011 void KNote::toDesktop( int desktop )
01012 {
01013     if ( desktop == 0 )
01014         return;
01015 
01016     if ( desktop == NETWinInfo::OnAllDesktops )
01017         KWin::setOnAllDesktops( winId(), true );
01018     else
01019         KWin::setOnDesktop( winId(), desktop );
01020 }
01021 
01022 void KNote::createFold()
01023 {
01024     QPixmap fold( 15, 15 );
01025     QPainter foldp( &fold );
01026     foldp.setPen( Qt::NoPen );
01027     foldp.setBrush( palette().active().dark() );
01028     QPointArray foldpoints( 3 );
01029     foldpoints.putPoints( 0, 3, 0, 0, 14, 0, 0, 14 );
01030     foldp.drawPolygon( foldpoints );
01031     foldp.end();
01032     m_fold->setPixmap( fold );
01033 }
01034 
01035 void KNote::updateLabelAlignment()
01036 {
01037     // if the name is too long to fit, left-align it, otherwise center it (#59028)
01038     QString labelText = m_label->text();
01039     if ( m_label->fontMetrics().boundingRect( labelText ).width() > m_label->width() )
01040         m_label->setAlignment( AlignLeft );
01041     else
01042         m_label->setAlignment( AlignHCenter );
01043 }
01044 
01045 void KNote::updateFocus()
01046 {
01047     if ( hasFocus() )
01048     {
01049         m_label->setBackgroundColor( palette().active().shadow() );
01050         m_button->show();
01051 
01052         if ( !m_editor->isReadOnly() )
01053         {
01054             if ( m_tool && m_tool->isHidden() && m_editor->textFormat() == QTextEdit::RichText )
01055             {
01056                 m_tool->show();
01057         m_editor->cornerWidget()->show();
01058                 setGeometry( x(), y(), width(), height() + m_tool->height() );
01059             }
01060         }
01061         else if ( m_tool && !m_tool->isHidden() )
01062         {
01063             m_tool->hide();
01064         m_editor->cornerWidget()->hide();
01065             setGeometry( x(), y(), width(), height() - m_tool->height() );
01066             updateLayout();     // to update the minimum height
01067         }
01068 
01069         m_fold->hide();
01070     }
01071     else
01072     {
01073         m_button->hide();
01074         m_editor->cornerWidget()->hide();
01075 
01076         if ( m_tool && !m_tool->isHidden() )
01077         {
01078             m_tool->hide();
01079             setGeometry( x(), y(), width(), height() - m_tool->height() );
01080             updateLayout();     // to update the minimum height
01081         }
01082 
01083         if ( s_ppOffset )
01084         {
01085             m_label->setBackgroundColor( palette().active().midlight() );
01086             m_fold->show();
01087         }
01088         else
01089             m_label->setBackgroundColor( palette().active().background() );
01090     }
01091 }
01092 
01093 void KNote::updateMask()
01094 {
01095     if ( !s_ppOffset )
01096     {
01097         clearMask();
01098         return;
01099     }
01100 
01101     int w = width();
01102     int h = height();
01103     QRegion reg( 0, s_ppOffset, w, h - s_ppOffset );
01104 
01105     const QBitmap *pushpin_bitmap = m_pushpin->pixmap()->mask();
01106     QRegion pushpin_reg( *pushpin_bitmap );
01107     m_pushpin->setMask( pushpin_reg );
01108     pushpin_reg.translate( m_pushpin->x(), m_pushpin->y() );
01109 
01110     if ( !hasFocus() )
01111     {
01112         QPointArray foldpoints( 3 );
01113         foldpoints.putPoints( 0, 3, w-15, h, w, h-15, w, h );
01114         QRegion fold( foldpoints, false );
01115         setMask( reg.unite( pushpin_reg ).subtract( fold ) );
01116     }
01117     else
01118         setMask( reg.unite( pushpin_reg ) );
01119 }
01120 
01121 void KNote::updateBackground( int y_offset )
01122 {
01123     if ( !s_ppOffset )
01124     {
01125         m_editor->setPaper( QBrush( colorGroup().background() ) );
01126         return;
01127     }
01128 
01129     int w = m_editor->visibleWidth();
01130     int h = m_editor->visibleHeight();
01131 
01132     // in case y_offset is not set, calculate y_offset as the content
01133     // y-coordinate of the top-left point of the viewport - which is essentially
01134     // the vertical scroll amount
01135     if ( y_offset == -1 )
01136         y_offset = m_editor->contentsY();
01137 
01138     y_offset = y_offset % h;
01139 
01140     QImage grad_img( w, h, 32 );
01141     QRgb rgbcol;
01142     QColor bg = palette().active().background();
01143 
01144     for ( int i = 0; i < h; ++i )
01145     {
01146         // if the scrollbar has moved, then adjust the gradient by the amount the
01147         // scrollbar moved -- so that the background gradient looks ok when tiled
01148 
01149         // the lightness is calculated as follows:
01150         // if i >= y, then lightness = 150 - (i-y)*75/h;
01151         // if i < y, then lightness = 150 - (i+h-y)*75/h
01152 
01153         int i_1 = 150 - 75 * ((i - y_offset + h) % h) / h;
01154         rgbcol = bg.light( i_1 ).rgb();
01155         for ( int j = 0; j < w; ++j )
01156             grad_img.setPixel( j, i, rgbcol );
01157     }
01158 
01159     // setPaletteBackgroundPixmap makes QTextEdit::color() stop working!!
01160     m_editor->setPaper( QBrush( Qt::black, QPixmap( grad_img ) ) );
01161 }
01162 
01163 void KNote::updateLayout()
01164 {
01165     const int headerHeight = m_label->sizeHint().height();
01166     const int margin = m_editor->margin();
01167     bool closeLeft = false;
01168 
01169     m_kwinConf->setGroup( "Style" );
01170     if ( m_kwinConf->readBoolEntry( "CustomButtonPositions" ) )
01171         closeLeft = m_kwinConf->readEntry( "ButtonsOnLeft" ).find( 'X' ) > -1;
01172 
01173     if ( s_ppOffset )
01174     {
01175         if ( !m_editor->paper().pixmap() )  // just changed the style
01176             setColor( palette().active().foreground(), palette().active().background() );
01177 
01178         m_pushpin->show();
01179         setFrameStyle( Panel | Raised );
01180 
01181         if ( closeLeft )
01182             m_pushpin->move( width() - m_pushpin->width(), 0 );
01183         else
01184             m_pushpin->move( 0, 0 );
01185     }
01186     else
01187     {
01188         if ( m_editor->paper().pixmap() )  // just changed the style
01189             setColor( palette().active().foreground(), palette().active().background() );
01190 
01191         setFrameStyle( WinPanel | Raised );
01192         m_pushpin->hide();
01193         m_fold->hide();
01194     }
01195 
01196     m_button->setGeometry(
01197         closeLeft ? contentsRect().x() : contentsRect().width() - headerHeight,
01198         contentsRect().y() + s_ppOffset,
01199         headerHeight,
01200         headerHeight
01201     );
01202 
01203     m_label->setGeometry(
01204         contentsRect().x(), contentsRect().y() + s_ppOffset,
01205         contentsRect().width(), headerHeight
01206     );
01207 
01208     m_editor->setGeometry( QRect(
01209         QPoint( contentsRect().x(),
01210                 contentsRect().y() + headerHeight + s_ppOffset ),
01211         QPoint( contentsRect().right(),
01212                 contentsRect().bottom() - ( m_tool ? (m_tool->isHidden() ? 0 : m_tool->height()) : 0 ) )
01213     ) );
01214 
01215     if( m_tool ) {
01216       m_tool->setGeometry(
01217           contentsRect().x(),
01218           contentsRect().bottom() - m_tool->height() + 1,
01219           contentsRect().width(),
01220           m_tool->height()
01221       );
01222     }
01223 
01224     if ( s_ppOffset )
01225         m_fold->move( width() - 15, height() - 15 );
01226 
01227     setMinimumSize(
01228         m_editor->cornerWidget()->width() + margin*2,
01229         headerHeight + s_ppOffset + ( m_tool ? (m_tool->isHidden() ? 0 : m_tool->height() ) : 0 ) +
01230                 m_editor->cornerWidget()->height() + margin*2
01231     );
01232 
01233     updateLabelAlignment();
01234     updateMask();
01235     updateBackground();
01236 }
01237 
01238 // -------------------- protected methods -------------------- //
01239 
01240 void KNote::drawFrame( QPainter *p )
01241 {
01242     QRect r = frameRect();
01243     r.setTop( s_ppOffset );
01244     if ( s_ppOffset )
01245         qDrawShadePanel( p, r, colorGroup(), false, lineWidth() );
01246     else
01247         qDrawWinPanel( p, r, colorGroup(), false );
01248 }
01249 
01250 void KNote::showEvent( QShowEvent * )
01251 {
01252     if ( m_config->hideNote() )
01253     {
01254         // KWin does not preserve these properties for hidden windows
01255         slotUpdateKeepAboveBelow();
01256         slotUpdateShowInTaskbar();
01257         toDesktop( m_config->desktop() );
01258         move( m_config->position() );
01259         m_config->setHideNote( false );
01260     }
01261 }
01262 
01263 void KNote::resizeEvent( QResizeEvent *qre )
01264 {
01265     QFrame::resizeEvent( qre );
01266     updateLayout();
01267 }
01268 
01269 void KNote::closeEvent( QCloseEvent * )
01270 {
01271     slotClose();
01272 }
01273 
01274 void KNote::dragEnterEvent( QDragEnterEvent *e )
01275 {
01276     if ( !m_config->readOnly() )
01277         e->accept( KColorDrag::canDecode( e ) );
01278 }
01279 
01280 void KNote::dropEvent( QDropEvent *e )
01281 {
01282     if ( m_config->readOnly() )
01283         return;
01284 
01285     QColor bg;
01286     if ( KColorDrag::decode( e, bg ) )
01287         setColor( paletteForegroundColor(), bg );
01288 }
01289 
01290 bool KNote::focusNextPrevChild( bool )
01291 {
01292     return true;
01293 }
01294 
01295 bool KNote::event( QEvent *ev )
01296 {
01297     if ( ev->type() == QEvent::LayoutHint )
01298     {
01299         updateLayout();
01300         return true;
01301     }
01302     else
01303         return QFrame::event( ev );
01304 }
01305 
01306 bool KNote::eventFilter( QObject *o, QEvent *ev )
01307 {
01308     if ( ev->type() == QEvent::DragEnter &&
01309          KColorDrag::canDecode( static_cast<QDragEnterEvent *>(ev) ) )
01310     {
01311         dragEnterEvent( static_cast<QDragEnterEvent *>(ev) );
01312         return true;
01313     }
01314 
01315     if ( ev->type() == QEvent::Drop &&
01316          KColorDrag::canDecode( static_cast<QDropEvent *>(ev) ) )
01317     {
01318         dropEvent( static_cast<QDropEvent *>(ev) );
01319         return true;
01320     }
01321 
01322     if ( o == m_label )
01323     {
01324         QMouseEvent *e = (QMouseEvent *)ev;
01325 
01326         if ( ev->type() == QEvent::MouseButtonDblClick )
01327     {
01328         if( !m_editor->isReadOnly())
01329                slotRename();
01330         }
01331         if ( ev->type() == QEvent::MouseButtonPress &&
01332              (e->button() == LeftButton || e->button() == MidButton))
01333         {
01334             e->button() == LeftButton ? KWin::raiseWindow( winId() )
01335                                       : KWin::lowerWindow( winId() );
01336 
01337             XUngrabPointer( qt_xdisplay(), qt_x_time );
01338             NETRootInfo wm_root( qt_xdisplay(), NET::WMMoveResize );
01339             wm_root.moveResizeRequest( winId(), e->globalX(), e->globalY(), NET::Move );
01340             return true;
01341         }
01342 
01343 #if KDE_IS_VERSION( 3, 5, 1 )
01344         if ( ev->type() == QEvent::MouseButtonRelease )
01345         {
01346             NETRootInfo wm_root( qt_xdisplay(), NET::WMMoveResize );
01347             wm_root.moveResizeRequest( winId(), e->globalX(), e->globalY(), NET::MoveResizeCancel );
01348             return false;
01349         }
01350 #endif
01351 
01352         if ( m_menu && ( ev->type() == QEvent::MouseButtonPress )
01353             && ( e->button() == RightButton ) )
01354         {
01355             m_menu->popup( QCursor::pos() );
01356             return true;
01357         }
01358 
01359         return false;
01360     }
01361 
01362     if ( o == m_editor )
01363     {
01364         if ( ev->type() == QEvent::FocusOut )
01365         {
01366             QFocusEvent *fe = static_cast<QFocusEvent *>(ev);
01367             if ( fe->reason() != QFocusEvent::Popup &&
01368                  fe->reason() != QFocusEvent::Mouse )
01369             {
01370                 updateFocus();
01371                 if ( m_editor->isModified() ) {
01372             saveConfig();
01373                         if ( !m_blockEmitDataChanged )
01374                         {
01375                             QTimer::singleShot ( 100, this,SLOT(slotSaveData())  );
01376                         }
01377         }
01378             }
01379         }
01380         else if ( ev->type() == QEvent::FocusIn )
01381             updateFocus();
01382 
01383         return false;
01384     }
01385 
01386     if ( o == m_editor->viewport() )
01387     {
01388         if ( m_edit_menu &&
01389              ev->type() == QEvent::MouseButtonPress &&
01390              ((QMouseEvent *)ev)->button() == RightButton )
01391         {
01392             m_edit_menu->popup( QCursor::pos() );
01393             return true;
01394         }
01395     }
01396 
01397     return false;
01398 }
01399 
01400 void KNote::slotSaveData()
01401 {
01402     saveData();
01403 }
01404 
01405 void KNote::deleteWhenIdle()
01406 {
01407   if ( m_busy <= 0 )
01408     deleteLater();
01409   else
01410     m_deleteWhenIdle = true;
01411 }
01412 
01413 void KNote::aboutToEnterEventLoop()
01414 {
01415   ++m_busy;
01416 }
01417 
01418 void KNote::eventLoopLeft()
01419 {
01420   --m_busy;
01421   if ( m_busy <= 0 && m_deleteWhenIdle )
01422     deleteLater();
01423 }
01424 
01425 
01426 #include "knote.moc"
01427 #include "knotebutton.moc"