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