knotes Library API Documentation

knote.cpp

00001 /*******************************************************************
00002  KNotes -- Notes for the KDE project
00003 
00004  Copyright (c) 1997-2004, 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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
00019 *******************************************************************/
00020 
00021 #include <qlabel.h>
00022 #include <qsize.h>
00023 #include <qsizegrip.h>
00024 #include <qbitmap.h>
00025 #include <qcursor.h>
00026 #include <qpainter.h>
00027 #include <qpaintdevicemetrics.h>
00028 #include <qsimplerichtext.h>
00029 #include <qobjectlist.h>
00030 
00031 #include <kapplication.h>
00032 #include <kdebug.h>
00033 #include <kaction.h>
00034 #include <kcombobox.h>
00035 #include <ktoolbar.h>
00036 #include <kpopupmenu.h>
00037 #include <kxmlguifactory.h>
00038 #include <kprinter.h>
00039 #include <klocale.h>
00040 #include <kstandarddirs.h>
00041 #include <ksimpleconfig.h>
00042 #include <kiconloader.h>
00043 #include <kmessagebox.h>
00044 #include <kprocess.h>
00045 #include <kinputdialog.h>
00046 #include <kmdcodec.h>
00047 #include <kglobalsettings.h>
00048 #include <kio/netaccess.h>
00049 
00050 #include <libkcal/journal.h>
00051 
00052 #include "knote.h"
00053 #include "knotebutton.h"
00054 #include "knoteedit.h"
00055 #include "knoteconfig.h"
00056 #include "knoteconfigdlg.h"
00057 #include "version.h"
00058 
00059 #include <kwin.h>
00060 #include <netwm.h>
00061 
00062 #include <fixx11h.h>
00063 
00064 using namespace KCal;
00065 
00066 
00067 KNote::KNote( KXMLGUIBuilder* builder, QDomDocument buildDoc, Journal *j,
00068               QWidget* parent, const char* name )
00069   : QFrame( parent, name, WStyle_Customize | WStyle_NoBorder | WDestructiveClose ),
00070     m_label( 0 ), m_button( 0 ), m_tool( 0 ), m_editor( 0 ),
00071     m_config( 0 ), m_journal( j )
00072 {
00073     //actionCollection()->setWidget( this );
00074 
00075     // if there is no title yet, use the start date if valid
00076     // (KOrganizer's journals don't have titles but a valid start date)
00077     if ( m_journal->summary().isNull() && m_journal->dtStart().isValid() )
00078     {
00079         QString s = KGlobal::locale()->formatDateTime( m_journal->dtStart() );
00080         m_journal->setSummary( s );
00081     }
00082 
00083     // create the menu items for the note - not the editor...
00084     // rename, mail, print, insert date, close, delete, new note
00085     new KAction( i18n("New"), "filenew", 0,
00086         this, SIGNAL(sigRequestNewNote()), actionCollection(), "new_note" );
00087     new KAction( i18n("Rename..."), "text", 0,
00088         this, SLOT(slotRename()), actionCollection(), "rename_note" );
00089     new KAction( i18n("Hide"), "fileclose" , 0,
00090         this, SLOT(slotClose()), actionCollection(), "hide_note" );
00091     new KAction( i18n("Delete"), "knotes_delete", 0,
00092         this, SLOT(slotKill()), actionCollection(), "delete_note" );
00093 
00094     new KAction( i18n("Insert Date"), "knotes_date", 0 ,
00095         this, SLOT(slotInsDate()), actionCollection(), "insert_date" );
00096     new KAction( i18n("Mail..."), "mail_send", 0,
00097         this, SLOT(slotMail()), actionCollection(), "mail_note" );
00098     new KAction( i18n("Print..."), "fileprint", 0,
00099         this, SLOT(slotPrint()), actionCollection(), "print_note" );
00100     new KAction( i18n("Preferences..."), "configure", 0,
00101         this, SLOT(slotPreferences()), actionCollection(), "configure_note" );
00102 
00103     m_keepAbove = new KToggleAction( i18n("Always on Top"), "up", 0,
00104         this, SLOT(slotUpdateKeepAboveBelow()), actionCollection(), "keep_above" );
00105     m_keepAbove->setExclusiveGroup( "keepAB" );
00106 
00107     // string freeze
00108     m_keepBelow = new KToggleAction( /*i18n("Keep Below Others")*/"", "down", 0,
00109         this, SLOT(slotUpdateKeepAboveBelow()), actionCollection(), "keep_below" );
00110     m_keepBelow->setExclusiveGroup( "keepAB" );
00111 
00112     m_toDesktop = new KListAction( i18n("To Desktop"), 0,
00113         this, SLOT(slotPopupActionToDesktop(int)), actionCollection(), "to_desktop" );
00114     connect( m_toDesktop->popupMenu(), SIGNAL(aboutToShow()), this, SLOT(slotUpdateDesktopActions()) );
00115 
00116     // create the note header, button and label...
00117     m_button = new KNoteButton( "knotes_close", this );
00118     connect( m_button, SIGNAL(clicked()), this, SLOT(slotClose()) );
00119 
00120     m_label = new QLabel( this );
00121     m_label->installEventFilter( this );  // receive events (for dragging & action menu)
00122     setName( m_journal->summary() );      // don't worry, no signals are connected at this stage yet
00123 
00124     // create the note editor
00125     m_editor = new KNoteEdit( this );
00126     m_editor->installEventFilter( this ); // receive events (for modified)
00127     m_editor->viewport()->installEventFilter( this );
00128 
00129     setDOMDocument( buildDoc );
00130     KXMLGUIFactory factory( builder, this, "guifactory" );
00131     factory.addClient( this );
00132 
00133     m_menu = static_cast<KPopupMenu*>(factory.container( "note_context", this ));
00134     m_edit_menu = static_cast<KPopupMenu*>(factory.container( "note_edit", this ));
00135     m_tool = static_cast<KToolBar*>(factory.container( "note_tool", this ));
00136     m_tool->reparent( this, QPoint( 0, 0 ) );
00137     m_tool->hide();
00138 
00139     setFocusProxy( m_editor );
00140 
00141     // create the resize handle
00142     m_editor->setCornerWidget( new QSizeGrip( this ) );
00143     uint width = m_editor->cornerWidget()->width();
00144     uint height = m_editor->cornerWidget()->height();
00145     QBitmap mask;
00146     mask.resize( width, height );
00147     mask.fill( color0 );
00148     QPointArray array;
00149     array.setPoints( 3, 0, height, width, height, width, 0 );
00150     QPainter p;
00151     p.begin( &mask );
00152     p.setBrush( color1 );
00153     p.drawPolygon( array );
00154     p.end();
00155     m_editor->cornerWidget()->setMask( mask );
00156 
00157     // set up the look&feel of the note
00158     setMinimumSize( 20, 20 );
00159     setFrameStyle( WinPanel | Raised );
00160     setLineWidth( 1 );
00161 
00162     m_editor->setMargin( 5 );
00163     m_editor->setFrameStyle( NoFrame );
00164     m_editor->setBackgroundMode( PaletteBase );
00165 
00166     // the config file location
00167     QString configFile = KGlobal::dirs()->saveLocation( "appdata", "notes/" );
00168     configFile += m_journal->uid();
00169     KURL dst( configFile );
00170 
00171     // no config file yet? -> use the default display config if available
00172     // we want to write to configFile, so use "false"
00173     if ( !KIO::NetAccess::exists( dst, false, 0 ) )
00174     {
00175         // use saveLocation since it's the user's default and not the
00176         // system's default (i.e., KNotes has to have write permission)
00177         KURL src( KGlobal::dirs()->saveLocation( "config" ) + "knotesrc" );
00178 
00179         // "fill" the config file with the default config
00180         if ( KIO::NetAccess::exists( src, true, 0 ) )
00181             KIO::NetAccess::file_copy( src, dst, -1, true, false, 0 );
00182     }
00183 
00184     m_config = new KNoteConfig( KSharedConfig::openConfig( configFile, false, false ) );
00185     m_config->readConfig();
00186     m_config->setVersion( KNOTES_VERSION );
00187 
00188     // load the display configuration of the note
00189     width = m_config->width();
00190     height = m_config->height();
00191     resize( width, height );
00192 
00193     if ( m_config->keepAbove() )
00194         m_keepAbove->setChecked( true );
00195     else if ( m_config->keepBelow() )
00196         m_keepBelow->setChecked( true );
00197     else
00198     {
00199         m_keepAbove->setChecked( false );
00200         m_keepBelow->setChecked( false );
00201     }
00202 
00203     // let KWin do the placement if the position is illegal
00204     const QPoint& position = m_config->position();
00205     if ( kapp->desktop()->rect().intersects( QRect( position, QSize( width, height ) ) ) )
00206         move( position );           // do before calling show() to avoid flicker
00207 
00208     // read configuration settings...
00209     slotApplyConfig();
00210 
00211     // if this is a new note put on current desktop - we can't use defaults
00212     // in KConfig XT since only _changes_ will be stored in the config file
00213     int desktop = m_config->desktop();
00214     if ( desktop < 0 && desktop != NETWinInfo::OnAllDesktops )
00215         desktop = KWin::currentDesktop();
00216 
00217     // show the note if desired
00218     if ( desktop != 0 && !isVisible() )
00219     {
00220         // HACK HACK
00221         if ( desktop != NETWinInfo::OnAllDesktops )
00222         {
00223             // to avoid flicker, call this before show()
00224             toDesktop( desktop );
00225             show();
00226         }
00227         else
00228         {
00229             show();
00230             // if this is called before show(),
00231             // it won't work for sticky notes!!!
00232             toDesktop( desktop );
00233         }
00234     }
00235 
00236     m_editor->setText( m_journal->description() );
00237     m_editor->setModified( false );
00238 }
00239 
00240 KNote::~KNote()
00241 {
00242     delete m_config;
00243 }
00244 
00245 
00246 // -------------------- public slots -------------------- //
00247 
00248 void KNote::slotKill( bool force )
00249 {
00250     if ( !force &&
00251          KMessageBox::warningYesNo( this,
00252             i18n("<qt>Do you really want to delete note <b>%1</b>?</qt>")
00253                 .arg( m_label->text() ),
00254             i18n("Confirm Delete") )
00255          != KMessageBox::Yes )
00256     {
00257         return;
00258     }
00259 
00260     // delete the configuration first, then the corresponding file
00261     delete m_config;
00262     m_config = 0;
00263 
00264     QString configFile = KGlobal::dirs()->saveLocation( "appdata", "notes/" );
00265     configFile += m_journal->uid();
00266 
00267     if ( !KIO::NetAccess::del( KURL(configFile), this ) )
00268         kdError(5500) << "Can't remove the note config: " << configFile << endl;
00269 
00270     emit sigKillNote( m_journal );
00271 }
00272 
00273 
00274 // -------------------- public member functions -------------------- //
00275 
00276 void KNote::saveData()
00277 {
00278     m_journal->setSummary( m_label->text() );
00279     m_journal->setDescription( m_editor->text() );
00280 
00281     emit sigDataChanged();
00282     m_editor->setModified( false );
00283 }
00284 
00285 void KNote::saveConfig() const
00286 {
00287     m_config->setWidth( width() );
00288     m_config->setHeight( height() - (m_tool->isHidden() ? 0 : m_tool->height()) );
00289     m_config->setPosition( pos() );
00290 
00291     NETWinInfo wm_client( qt_xdisplay(), winId(), qt_xrootwin(), NET::WMDesktop | NET::WMState );
00292     m_config->setDesktop( wm_client.desktop() );
00293 
00294     // actually store the config on disk
00295     m_config->writeConfig();
00296 }
00297 
00298 QString KNote::noteId() const
00299 {
00300     return m_journal->uid();
00301 }
00302 
00303 QString KNote::name() const
00304 {
00305     return m_label->text();
00306 }
00307 
00308 QString KNote::text() const
00309 {
00310     return m_editor->text();
00311 }
00312 
00313 void KNote::setName( const QString& name )
00314 {
00315     m_label->setText( name );
00316     updateLabelAlignment();
00317 
00318     if ( m_editor )    // not called from CTOR?
00319         saveData();
00320 
00321     // set the window's name for the taskbar entry to be more helpful (#58338)
00322     NETWinInfo note_win( qt_xdisplay(), winId(), qt_xrootwin(), NET::WMDesktop );
00323     note_win.setName( name.utf8() );
00324 
00325     emit sigNameChanged();
00326 }
00327 
00328 void KNote::setText( const QString& text )
00329 {
00330     m_editor->setText( text );
00331     saveData();
00332 }
00333 
00334 // FIXME KDE 4.0: remove sync(), isNew() and isModified()
00335 void KNote::sync( const QString& app )
00336 {
00337     QByteArray sep( 1 );
00338     sep[0] = '\0';
00339 
00340     KMD5 hash;
00341     QCString result;
00342 
00343     hash.update( m_label->text().utf8() );
00344     hash.update( sep );
00345     hash.update( m_editor->text().utf8() );
00346     hash.hexDigest( result );
00347 
00348     // hacky... not possible with KConfig XT
00349     KConfig *config = m_config->config();
00350     config->setGroup( "Synchronisation" );
00351     config->writeEntry( app, result.data() );
00352 }
00353 
00354 bool KNote::isNew( const QString& app ) const
00355 {
00356     KConfig *config = m_config->config();
00357     config->setGroup( "Synchronisation" );
00358     QString hash = config->readEntry( app );
00359     return hash.isEmpty();
00360 }
00361 
00362 bool KNote::isModified( const QString& app ) const
00363 {
00364     QByteArray sep( 1 );
00365     sep[0] = '\0';
00366 
00367     KMD5 hash;
00368     hash.update( m_label->text().utf8() );
00369     hash.update( sep );
00370     hash.update( m_editor->text().utf8() );
00371     hash.hexDigest();
00372 
00373     KConfig *config = m_config->config();
00374     config->setGroup( "Synchronisation" );
00375     QString orig = config->readEntry( app );
00376 
00377     if ( hash.verify( orig.utf8() ) )   // returns false on error!
00378         return false;
00379     else
00380         return true;
00381 }
00382 
00383 void KNote::toDesktop( int desktop )
00384 {
00385     if ( desktop == 0 || desktop == NETWinInfo::OnAllDesktops )
00386         KWin::setOnAllDesktops( winId(), true );
00387     else
00388         KWin::setOnDesktop( winId(), desktop );
00389 }
00390 
00391 
00392 // ------------------ private slots (menu actions) ------------------ //
00393 
00394 void KNote::slotRename()
00395 {
00396     // pop up dialog to get the new name
00397     bool ok;
00398     QString newName = KInputDialog::getText( QString::null,
00399         i18n("Please enter the new name:"), m_label->text(), &ok, this );
00400     if ( !ok ) // handle cancel
00401         return;
00402 
00403     setName( newName );
00404 }
00405 
00406 void KNote::slotClose()
00407 {
00408     m_editor->clearFocus();
00409     hide(); //just hide the note so it's still available from the dock window
00410 }
00411 
00412 void KNote::slotInsDate()
00413 {
00414     m_editor->insert( KGlobal::locale()->formatDateTime(QDateTime::currentDateTime()) );
00415 }
00416 
00417 void KNote::slotPreferences()
00418 {
00419     // reuse if possible
00420     if ( KNoteConfigDlg::showDialog( noteId().utf8() ) )
00421         return;
00422 
00423     // create a new preferences dialog...
00424     KNoteConfigDlg *dialog = new KNoteConfigDlg( m_config, name(), false, this,
00425                                                  noteId().utf8() );
00426     connect( dialog, SIGNAL(settingsChanged()), this, SLOT(slotApplyConfig()) );
00427     connect( this, SIGNAL(sigNameChanged()), dialog, SLOT(slotUpdateCaption()) );
00428     dialog->show();
00429 }
00430 
00431 void KNote::slotMail()
00432 {
00433     saveData();
00434 
00435     QString msg_body = m_editor->text();
00436 
00437     // convert rich text to plain text first
00438     if ( m_editor->textFormat() == RichText )
00439     {
00440         QTextEdit conv;
00441         conv.setTextFormat( RichText );
00442         conv.setText( msg_body );
00443         conv.setTextFormat( PlainText );
00444         msg_body = conv.text();
00445     }
00446 
00447     // get the mail action command
00448     QStringList cmd_list = QStringList::split( QChar(' '), m_config->mailAction() );
00449 
00450     KProcess mail;
00451     for ( QStringList::Iterator it = cmd_list.begin();
00452         it != cmd_list.end(); ++it )
00453     {
00454         if ( *it == "%f" )
00455             mail << msg_body.local8Bit();
00456         else if ( *it == "%t" )
00457             mail << m_label->text().local8Bit();
00458         else
00459             mail << (*it).local8Bit();
00460     }
00461 
00462     if ( !mail.start( KProcess::DontCare ) )
00463         KMessageBox::sorry( this, i18n("Unable to start the mail process.") );
00464 }
00465 
00466 void KNote::slotPrint()
00467 {
00468     saveData();
00469 
00470     KPrinter printer;
00471     printer.setFullPage( true );
00472 
00473     if ( printer.setup(0L, i18n("Print %1").arg(name())) )
00474     {
00475         QPainter painter;
00476         painter.begin( &printer );
00477 
00478         const int margin = 40;  // pt
00479 
00480         QPaintDeviceMetrics metrics( painter.device() );
00481         int marginX = margin * metrics.logicalDpiX() / 72;
00482         int marginY = margin * metrics.logicalDpiY() / 72;
00483 
00484         QRect body( marginX, marginY,
00485                     metrics.width() - marginX * 2,
00486                     metrics.height() - marginY * 2 );
00487 
00488         QString content;
00489         if ( m_editor->textFormat() == PlainText )
00490             content = QStyleSheet::convertFromPlainText( m_editor->text() );
00491         else
00492             content = m_editor->text();
00493 
00494         QSimpleRichText text( content, m_config->font(), m_editor->context(),
00495                               m_editor->styleSheet(), m_editor->mimeSourceFactory(),
00496                               body.height() /*, linkColor, linkUnderline? */ );
00497 
00498         text.setWidth( &painter, body.width() );
00499         QRect view( body );
00500 
00501         int page = 1;
00502 
00503         for (;;)
00504         {
00505             text.draw( &painter, body.left(), body.top(), view, colorGroup() );
00506             view.moveBy( 0, body.height() );
00507             painter.translate( 0, -body.height() );
00508 
00509             // page numbers
00510             painter.setFont( m_config->font() );
00511             painter.drawText(
00512                 view.right() - painter.fontMetrics().width( QString::number( page ) ),
00513                 view.bottom() + painter.fontMetrics().ascent() + 5, QString::number( page )
00514             );
00515 
00516             if ( view.top() >= text.height() )
00517                 break;
00518 
00519             printer.newPage();
00520             page++;
00521         }
00522 
00523         painter.end();
00524     }
00525 }
00526 
00527 void KNote::slotPopupActionToDesktop( int id )
00528 {
00529     if( id > 1 )
00530       --id;      // compensate for the menu separator
00531     toDesktop( id );
00532 }
00533 
00534 
00535 // ------------------ private slots (configuration) ------------------ //
00536 
00537 void KNote::slotApplyConfig()
00538 {
00539     if ( m_config->richText() )
00540         m_editor->setTextFormat( RichText );
00541     else
00542         m_editor->setTextFormat( PlainText );
00543 
00544     m_label->setFont( m_config->titleFont() );
00545     m_editor->setTextFont( m_config->font() );
00546     m_editor->setTabStop( m_config->tabSize() );
00547     m_editor->setAutoIndentMode( m_config->autoIndent() );
00548 
00549     // if called as a slot, save the text, we might have changed the
00550     // text format - otherwise the journal will not be updated
00551     if ( sender() )
00552         saveData();
00553 
00554     setColor( m_config->fgColor(), m_config->bgColor() );
00555 
00556     updateLabelAlignment();
00557     slotUpdateShowInTaskbar();
00558 }
00559 
00560 void KNote::slotUpdateKeepAboveBelow()
00561 {
00562     KWin::WindowInfo info( KWin::windowInfo( winId() ) );
00563 
00564     if ( m_keepAbove->isChecked() )
00565     {
00566         m_config->setKeepAbove( true );
00567         m_config->setKeepBelow( false );
00568         KWin::setState( winId(), info.state() | NET::KeepAbove );
00569     }
00570     else if ( m_keepBelow->isChecked() )
00571     {
00572         m_config->setKeepAbove( false );
00573         m_config->setKeepBelow( true );
00574         KWin::setState( winId(), info.state() | NET::KeepBelow );
00575     }
00576     else
00577     {
00578         m_config->setKeepAbove( false );
00579         KWin::clearState( winId(), NET::KeepAbove );
00580 
00581         m_config->setKeepBelow( false );
00582         KWin::clearState( winId(), NET::KeepBelow );
00583     }
00584 }
00585 
00586 void KNote::slotUpdateShowInTaskbar()
00587 {
00588     if ( !m_config->showInTaskbar() )
00589         KWin::setState( winId(), KWin::windowInfo(winId()).state() | NET::SkipTaskbar );
00590     else
00591         KWin::clearState( winId(), NET::SkipTaskbar );
00592 }
00593 
00594 void KNote::slotUpdateDesktopActions()
00595 {
00596     NETRootInfo wm_root( qt_xdisplay(), NET::NumberOfDesktops | NET::DesktopNames );
00597     NETWinInfo wm_client( qt_xdisplay(), winId(), qt_xrootwin(), NET::WMDesktop );
00598 
00599     QStringList desktops;
00600     desktops.append( i18n("&All Desktops") );
00601     desktops.append( QString::null );           // Separator
00602 
00603     int count = wm_root.numberOfDesktops();
00604     for ( int n = 1; n <= count; n++ )
00605         desktops.append( QString("&%1 %2").arg( n ).arg( QString::fromUtf8(wm_root.desktopName( n )) ) );
00606 
00607     m_toDesktop->setItems( desktops );
00608 
00609     if ( wm_client.desktop() == NETWinInfo::OnAllDesktops )
00610         m_toDesktop->setCurrentItem( 0 );
00611     else
00612         m_toDesktop->setCurrentItem( wm_client.desktop() + 1 ); // compensate for separator (+1)
00613 }
00614 
00615 
00616 // -------------------- private methods -------------------- //
00617 
00618 void KNote::setColor( const QColor &fg, const QColor &bg )
00619 {
00620     QPalette newpalette = palette();
00621     newpalette.setColor( QColorGroup::Background, bg );
00622     newpalette.setColor( QColorGroup::Foreground, fg );
00623     newpalette.setColor( QColorGroup::Base,       bg ); // text background
00624     newpalette.setColor( QColorGroup::Text,       fg ); // text color
00625     newpalette.setColor( QColorGroup::Button,     bg );
00626 
00627     // the shadow
00628     newpalette.setColor( QColorGroup::Midlight, bg.light(110) );
00629     newpalette.setColor( QColorGroup::Shadow, bg.dark(116) );  // 132 ?
00630     newpalette.setColor( QColorGroup::Light, bg.light(180) );
00631     newpalette.setColor( QColorGroup::Dark, bg.dark(108) );
00632     setPalette( newpalette );
00633 
00634     // set the text color
00635     m_editor->setTextColor( fg );
00636 
00637     // set darker value for the hide button...
00638     QPalette darker = palette();
00639     darker.setColor( QColorGroup::Button, bg.dark(116) );
00640     m_button->setPalette( darker );
00641 
00642     // to set the color of the title
00643     updateFocus();
00644     emit sigColorChanged();
00645 }
00646 
00647 void KNote::updateLabelAlignment()
00648 {
00649     // if the name is too long to fit, left-align it, otherwise center it (#59028)
00650     QString labelText = m_label->text();
00651     if ( m_label->fontMetrics().boundingRect( labelText ).width() > m_label->width() )
00652         m_label->setAlignment( AlignLeft );
00653     else
00654         m_label->setAlignment( AlignHCenter );
00655 }
00656 
00657 void KNote::updateFocus()
00658 {
00659     if ( hasFocus() )
00660     {
00661         m_label->setBackgroundColor( palette().active().shadow() );
00662         m_button->show();
00663         m_editor->cornerWidget()->show();
00664 
00665         if ( m_tool->isHidden() && m_editor->textFormat() == QTextEdit::RichText )
00666         {
00667             m_tool->show();
00668             setGeometry( x(), y(), width(), height() + m_tool->height() );
00669         }
00670     }
00671     else
00672     {
00673         m_label->setBackgroundColor( palette().active().background() );
00674         m_button->hide();
00675         m_editor->cornerWidget()->hide();
00676 
00677         if ( !m_tool->isHidden() )
00678         {
00679             m_tool->hide();
00680             setGeometry( x(), y(), width(), height() - m_tool->height() );
00681             updateLayout();     // to update the minimum height
00682         }
00683     }
00684 }
00685 
00686 void KNote::updateLayout()
00687 {
00688     // DAMN, Qt still has no support for widgets with a fixed aspect ratio :-(
00689     // So we have to write our own layout manager...
00690 
00691     const int headerHeight = m_label->sizeHint().height();
00692     const int toolHeight = m_tool->isHidden() ? 0 : 16;
00693     const int margin = m_editor->margin();
00694     static const int border = 2;
00695     bool closeLeft = false;
00696 
00697     m_button->setGeometry(
00698         closeLeft ? frameRect().x() + border
00699                   : frameRect().width() - headerHeight - border,
00700         frameRect().y() + border,
00701         headerHeight,
00702         headerHeight
00703     );
00704 
00705     m_label->setGeometry(
00706         frameRect().x() + border + (closeLeft && !m_button->isHidden() ? headerHeight : 0),
00707         frameRect().y() + border,
00708         frameRect().width() - (m_button->isHidden() ? 0 : headerHeight) - border*2,
00709         headerHeight
00710     );
00711 
00712     m_editor->setGeometry(
00713         contentsRect().x(),
00714         contentsRect().y() + headerHeight + border,
00715         contentsRect().width(),
00716         contentsRect().height() - headerHeight - toolHeight - border*2
00717     );
00718 
00719     m_tool->setGeometry(
00720         contentsRect().x(),
00721         contentsRect().height() - 16,
00722         contentsRect().width(),
00723         16
00724     );
00725     m_tool->setIconSize( 10 );
00726 
00727     // if there was just a way of making KComboBox adhere the toolbar height...
00728     QObjectList *list = m_tool->queryList( "KComboBox" );
00729     QObjectListIt it( *list );
00730     while ( it.current() != 0 && toolHeight )
00731     {
00732         KComboBox *combo = (KComboBox *)it.current();
00733         QFont font = combo->font();
00734         font.setPointSize( 7 );
00735         combo->setFont( font );
00736         combo->setFixedHeight( m_tool->height() - 2 );
00737         ++it;
00738     }
00739     delete list;
00740 
00741     setMinimumSize(
00742         m_editor->cornerWidget()->width() + margin*2 + border*2,
00743         headerHeight + toolHeight +
00744                 m_editor->cornerWidget()->height() + margin*2 + border*2
00745     );
00746 
00747     updateLabelAlignment();
00748 }
00749 
00750 // -------------------- protected methods -------------------- //
00751 
00752 void KNote::showEvent( QShowEvent * )
00753 {
00754     // KWin does not preserve these properties for hidden windows
00755     slotUpdateKeepAboveBelow();
00756     slotUpdateShowInTaskbar();
00757 }
00758 
00759 void KNote::resizeEvent( QResizeEvent *qre )
00760 {
00761     QFrame::resizeEvent( qre );
00762     updateLayout();
00763 }
00764 
00765 void KNote::closeEvent( QCloseEvent * )
00766 {
00767     slotClose();
00768 }
00769 
00770 void KNote::keyPressEvent( QKeyEvent *e )
00771 {
00772     if ( e->key() == Key_Escape )
00773         slotClose();
00774     else
00775         e->ignore();
00776 }
00777 
00778 bool KNote::focusNextPrevChild( bool )
00779 {
00780     return true;
00781 }
00782 
00783 bool KNote::event( QEvent *ev )
00784 {
00785     if ( ev->type() == QEvent::LayoutHint )
00786     {
00787         updateLayout();
00788         return true;
00789     }
00790     else
00791         return QFrame::event( ev );
00792 }
00793 
00794 bool KNote::eventFilter( QObject *o, QEvent *ev )
00795 {
00796     if ( o == m_label )
00797     {
00798         QMouseEvent *e = (QMouseEvent *)ev;
00799 
00800         if ( ev->type() == QEvent::MouseButtonDblClick )
00801             slotRename();
00802 
00803         if ( ev->type() == QEvent::MouseButtonRelease &&
00804              (e->button() == LeftButton || e->button() == MidButton) )
00805         {
00806             m_dragging = false;
00807             m_label->releaseMouse();
00808             return true;
00809         }
00810 
00811         if ( ev->type() == QEvent::MouseButtonPress &&
00812              (e->button() == LeftButton || e->button() == MidButton))
00813         {
00814             m_pointerOffset = e->pos();
00815             m_label->grabMouse( sizeAllCursor );
00816 
00817             e->button() == LeftButton ? KWin::raiseWindow( winId() )
00818                                       : KWin::lowerWindow( winId() );
00819 
00820             return true;
00821         }
00822 
00823         if ( ev->type() == QEvent::MouseMove && m_label == mouseGrabber() )
00824         {
00825             if ( m_dragging )
00826                 move( QCursor::pos() - m_pointerOffset );
00827             else
00828             {
00829                 m_dragging = (
00830                     (e->pos().x() - m_pointerOffset.x()) *
00831                     (e->pos().x() - m_pointerOffset.x())
00832                     +
00833                     (e->pos().y() - m_pointerOffset.y()) *
00834                     (e->pos().y() - m_pointerOffset.y())   >= 9
00835                 );
00836             }
00837             return true;
00838         }
00839 
00840         if ( m_menu && ( ev->type() == QEvent::MouseButtonPress )
00841             && ( e->button() == RightButton ) )
00842         {
00843             m_menu->popup( QCursor::pos() );
00844             return true;
00845         }
00846 
00847         return false;
00848     }
00849 
00850     if ( o == m_editor )
00851     {
00852         if ( ev->type() == QEvent::FocusOut )
00853         {
00854             QFocusEvent *fe = static_cast<QFocusEvent *>(ev);
00855             if ( fe->reason() != QFocusEvent::Popup && fe->reason() != QFocusEvent::Mouse )
00856             {
00857                 updateFocus();
00858                 if ( m_editor->isModified() )
00859                     saveData();
00860             }
00861         }
00862         else if ( ev->type() == QEvent::FocusIn )
00863             updateFocus();
00864 
00865         return false;
00866     }
00867 
00868     if ( o == m_editor->viewport() )
00869     {
00870         if ( m_edit_menu &&
00871              ev->type() == QEvent::MouseButtonPress &&
00872              ((QMouseEvent *)ev)->button() == RightButton )
00873         {
00874             m_edit_menu->popup( QCursor::pos() );
00875             return true;
00876         }
00877     }
00878 
00879     return false;
00880 }
00881 
00882 #include "knote.moc"
00883 #include "knotebutton.moc"
KDE Logo
This file is part of the documentation for knotes Library Version 3.2.2.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Sat May 1 11:36:55 2004 by doxygen 1.2.15 written by Dimitri van Heesch, © 1997-2003