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