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