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