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