1 /*******************************************************************
2 KNotes -- Notes for the KDE project
4 Copyright (c) 1997-2007, The KNotes Developers
6 This program is free software; you can redistribute it and/or
7 modify it under the terms of the GNU General Public License
8 as published by the Free Software Foundation; either version 2
9 of the License, or (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19 *******************************************************************/
22 #include "knotealarmdlg.h"
23 #include "knotebutton.h"
24 #include "knoteconfig.h"
25 #include "knoteconfigdlg.h"
26 #include "knoteedit.h"
27 #include "knotehostdlg.h"
28 #include "knoteprinter.h"
29 #include "knotesglobalconfig.h"
30 #include "knotesnetsend.h"
31 #include "kdepim-version.h"
34 #include <kactioncollection.h>
35 #include <kapplication.h>
36 #include <kcal/journal.h>
38 #include <kcombobox.h>
40 #include <kfiledialog.h>
42 #include <kglobalsettings.h>
44 #include <kiconeffect.h>
45 #include <kiconloader.h>
46 #include <kinputdialog.h>
47 #include <kio/netaccess.h>
50 #include <kmessagebox.h>
52 #include <kselectaction.h>
53 #include <ksocketfactory.h>
54 #include <kstandardaction.h>
55 #include <kstandarddirs.h>
56 #include <ktoggleaction.h>
58 #include <kwindowsystem.h>
59 #include <kxmlguibuilder.h>
60 #include <kxmlguifactory.h>
66 #include <QHBoxLayout>
72 #include <QTextStream>
73 #include <QVBoxLayout>
74 #include <QDesktopWidget>
84 KNote::KNote( const QDomDocument
& buildDoc
, Journal
*j
, QWidget
*parent
)
85 : QFrame( parent
, Qt::FramelessWindowHint
), m_label( 0 ), m_grip( 0 ),
86 m_button( 0 ), m_tool( 0 ), m_editor( 0 ), m_config( 0 ), m_journal( j
),
87 m_find( 0 ), m_kwinConf( KSharedConfig::openConfig( "kwinrc" ) ), m_blockEmitDataChanged( false ),mBlockWriteConfigDuringCommitData( false )
89 setAcceptDrops( true );
90 setAttribute( Qt::WA_DeleteOnClose
);
91 setDOMDocument( buildDoc
);
92 setObjectName( m_journal
->uid() );
93 setXMLFile( componentData().componentName() + "ui.rc", false, false );
95 // create the main layout
96 m_noteLayout
= new QVBoxLayout( this );
97 m_noteLayout
->setMargin( 0 );
99 // if there is no title yet, use the start date if valid
100 // (KOrganizer's journals don't have titles but a valid start date)
101 if ( m_journal
->summary().isNull() && m_journal
->dtStart().isValid() ) {
102 const QString s
= KGlobal::locale()->formatDateTime( m_journal
->dtStart() );
103 m_journal
->setSummary( s
);
118 void KNote::changeJournal(KCal::Journal
*journal
)
121 m_editor
->setText( m_journal
->description() );
122 m_editor
->document()->setModified( false );
123 m_label
->setText( m_journal
->summary() );
124 updateLabelAlignment();
128 // -------------------- public slots -------------------- //
130 void KNote::slotKill( bool force
)
132 m_blockEmitDataChanged
= true;
134 ( KMessageBox::warningContinueCancel( this,
135 i18n( "<qt>Do you really want to delete note <b>%1</b>?</qt>",
137 i18n( "Confirm Delete" ),
138 KGuiItem( i18n( "&Delete" ), "edit-delete" ),
139 KStandardGuiItem::cancel(),
140 "ConfirmDeleteNote" ) != KMessageBox::Continue
) ) {
141 m_blockEmitDataChanged
= false;
144 // delete the configuration first, then the corresponding file
147 QString configFile
= KGlobal::dirs()->saveLocation( "appdata", "notes/" );
148 configFile
+= m_journal
->uid();
149 if ( !KIO::NetAccess::del( KUrl( configFile
), this ) ) {
150 kError( 5500 ) <<"Can't remove the note config:" << configFile
;
153 emit
sigKillNote( m_journal
);
157 // -------------------- public member functions -------------------- //
159 void KNote::saveData(bool update
)
161 m_journal
->setSummary( m_label
->text() );
162 m_journal
->setDescription( m_editor
->text() );
163 m_journal
->setCustomProperty( "KNotes", "FgColor",
164 m_config
->fgColor().name() );
165 m_journal
->setCustomProperty( "KNotes", "BgColor",
166 m_config
->bgColor().name() );
167 m_journal
->setCustomProperty( "KNotes", "RichText",
168 m_config
->richText() ? "true" : "false" );
172 emit
sigDataChanged(noteId());
173 m_editor
->document()->setModified( false );
177 void KNote::saveConfig() const
179 m_config
->setWidth( width() );
182 height() - ( m_tool
->isHidden() ? 0 : m_tool
->height() ) );
184 m_config
->setHeight( 0 );
186 m_config
->setPosition( pos() );
189 NETWinInfo
wm_client( QX11Info::display(), winId(),
190 QX11Info::appRootWindow(), NET::WMDesktop
);
191 if ( ( wm_client
.desktop() == NETWinInfo::OnAllDesktops
) ||
192 ( wm_client
.desktop() > 0 ) ) {
193 m_config
->setDesktop( wm_client
.desktop() );
197 // actually store the config on disk
198 m_config
->writeConfig();
201 QString
KNote::noteId() const
203 return m_journal
->uid();
206 QString
KNote::name() const
208 return m_label
->text();
211 QString
KNote::text() const
213 return m_editor
->text();
216 void KNote::setName( const QString
& name
)
218 m_label
->setText( name
);
219 updateLabelAlignment();
221 if ( m_editor
) { // not called from CTOR?
225 // set the window's name for the taskbar entry to be more helpful (#58338)
226 NETWinInfo
note_win( QX11Info::display(), winId(), QX11Info::appRootWindow(),
228 note_win
.setName( name
.toUtf8() );
231 emit
sigNameChanged(name
);
234 void KNote::setText( const QString
& text
)
236 m_editor
->setText( text
);
241 void KNote::find( KFind
* kfind
)
244 disconnect( m_find
);
245 connect( m_find
, SIGNAL(highlight(QString
,int,int)),
246 this, SLOT(slotHighlight(QString
,int,int)) );
247 connect( m_find
, SIGNAL(findNext()), this, SLOT(slotFindNext()) );
249 m_find
->setData( m_editor
->toPlainText() );
253 void KNote::slotFindNext()
255 // TODO: honor FindBackwards
257 // Let KFind inspect the text fragment, and display a dialog if a match is
259 KFind::Result res
= m_find
->find();
261 if ( res
== KFind::NoMatch
) { // i.e. at end-pos
263 QTextCursor c
= m_editor
->textCursor(); //doesn't return by reference, so we use setTextCursor
265 m_editor
->setTextCursor( c
);
267 disconnect( m_find
, 0, this, 0 );
268 emit
sigFindFinished();
273 KWindowSystem::setCurrentDesktop( KWindowSystem::windowInfo( winId(),
274 NET::WMDesktop
).desktop() );
279 void KNote::slotHighlight( const QString
& /*str*/, int idx
, int len
)
281 m_editor
->textCursor().clearSelection();
282 m_editor
->highlightWord( len
, idx
);
284 // TODO: modify the selection color, use a different QTextCursor?
287 bool KNote::isModified() const
289 return m_editor
->document()->isModified();
292 // ------------------ private slots (menu actions) ------------------ //
294 void KNote::slotRename()
296 m_blockEmitDataChanged
= true;
297 // pop up dialog to get the new name
299 const QString oldName
= m_label
->text();
300 const QString newName
= KInputDialog::getText( QString::null
, //krazy:exclude=nullstrassign for old broken gcc
301 i18n( "Please enter the new name:" ), m_label
->text(), &ok
, this );
302 m_blockEmitDataChanged
= false;
303 if ( !ok
|| (oldName
== newName
) ) { // handle cancel
310 void KNote::slotUpdateReadOnly()
312 const bool readOnly
= m_readOnly
->isChecked();
314 m_editor
->setReadOnly( readOnly
);
315 m_config
->setReadOnly( readOnly
);
317 // enable/disable actions accordingly
318 actionCollection()->action( "configure_note" )->setEnabled( !readOnly
);
319 actionCollection()->action( "insert_date" )->setEnabled( !readOnly
);
320 actionCollection()->action( "delete_note" )->setEnabled( !readOnly
);
321 actionCollection()->action( "format_bold" )->setEnabled( !readOnly
);
322 actionCollection()->action( "format_italic" )->setEnabled( !readOnly
);
323 actionCollection()->action( "format_underline" )->setEnabled( !readOnly
);
324 actionCollection()->action( "format_strikeout" )->setEnabled( !readOnly
);
325 actionCollection()->action( "format_alignleft" )->setEnabled( !readOnly
);
326 actionCollection()->action( "format_aligncenter" )->setEnabled( !readOnly
);
327 actionCollection()->action( "format_alignright" )->setEnabled( !readOnly
);
328 actionCollection()->action( "format_alignblock" )->setEnabled( !readOnly
);
329 actionCollection()->action( "format_list" )->setEnabled( !readOnly
);
330 actionCollection()->action( "format_super" )->setEnabled( !readOnly
);
331 actionCollection()->action( "format_sub" )->setEnabled( !readOnly
);
332 actionCollection()->action( "format_increaseindent" )->setEnabled( !readOnly
);
333 actionCollection()->action( "format_decreaseindent" )->setEnabled( !readOnly
);
334 actionCollection()->action( "text_background_color" )->setEnabled( !readOnly
);
335 actionCollection()->action( "format_size" )->setEnabled( !readOnly
);
336 actionCollection()->action( "format_color" )->setEnabled( !readOnly
);
337 actionCollection()->action( "rename_note" )->setEnabled( !readOnly
);
343 void KNote::commitData()
345 mBlockWriteConfigDuringCommitData
= true;
348 void KNote::slotClose()
351 NETWinInfo
wm_client( QX11Info::display(), winId(),
352 QX11Info::appRootWindow(), NET::WMDesktop
);
353 if ( ( wm_client
.desktop() == NETWinInfo::OnAllDesktops
) ||
354 ( wm_client
.desktop() > 0 ) ) {
355 m_config
->setDesktop( wm_client
.desktop() );
359 m_editor
->clearFocus();
360 if( !mBlockWriteConfigDuringCommitData
)
362 m_config
->setHideNote( true );
363 m_config
->setPosition( pos() );
364 m_config
->writeConfig();
366 // just hide the note so it's still available from the dock window
370 void KNote::slotInsDate()
372 m_editor
->insertPlainText(
373 KGlobal::locale()->formatDateTime( QDateTime::currentDateTime() ) );
376 void KNote::slotSetAlarm()
378 m_blockEmitDataChanged
= true;
379 KNoteAlarmDlg
dlg( name(), this );
380 dlg
.setIncidence( m_journal
);
382 if ( dlg
.exec() == QDialog::Accepted
) {
383 emit
sigDataChanged(noteId());
385 m_blockEmitDataChanged
= false;
388 void KNote::slotPreferences()
390 m_blockEmitDataChanged
= true;
392 // create a new preferences dialog...
393 KNoteSimpleConfigDlg
*dialog
= new KNoteSimpleConfigDlg( m_config
, name(), this, noteId() );
394 connect( dialog
, SIGNAL(settingsChanged(QString
)) , this,
395 SLOT(slotApplyConfig()) );
396 connect( this, SIGNAL(sigNameChanged(QString
)), dialog
,
397 SLOT(slotUpdateCaption(QString
)) );
400 m_blockEmitDataChanged
= false;
404 void KNote::slotSend()
406 // pop up dialog to get the IP
407 KNoteHostDlg
hostDlg( i18n( "Send \"%1\"", name() ), this );
408 const bool ok
= ( hostDlg
.exec() == QDialog::Accepted
);
410 if ( !ok
) { // handle cancel
413 const QString host
= hostDlg
.host();
414 quint16 port
= hostDlg
.port();
416 if ( !port
) { // not specified, use default
417 port
= KNotesGlobalConfig::port();
420 if ( host
.isEmpty() ) {
421 KMessageBox::sorry( this, i18n( "The host cannot be empty." ) );
427 KNotesNetworkSender
*sender
= new KNotesNetworkSender(
428 KSocketFactory::connectToHost( "knotes", host
, port
) );
429 sender
->setSenderId( KNotesGlobalConfig::senderID() );
430 sender
->setNote( name(), text() ); // FIXME: plainText ??
433 void KNote::slotMail()
435 // get the mail action command
436 const QStringList cmd_list
= KNotesGlobalConfig::mailAction().split( QChar(' '),
437 QString::SkipEmptyParts
);
440 foreach ( const QString
&cmd
, cmd_list
) {
442 mail
<< m_editor
->toPlainText();
443 } else if ( cmd
== "%t" ) {
444 mail
<< m_label
->text();
450 if ( !mail
.startDetached() ) {
451 KMessageBox::sorry( this, i18n( "Unable to start the mail process." ) );
455 void KNote::slotPrint()
458 if ( !Qt::mightBeRichText( m_editor
->text() ) ) {
459 content
= Qt::convertFromPlainText( m_editor
->text() );
461 content
= m_editor
->text();
463 KNotePrinter printer
;
464 printer
.setDefaultFont( m_config
->font() );
465 printer
.printNote( name(), content
);
468 void KNote::slotSaveAs()
470 // TODO: where to put pdf file support? In the printer??!??!
471 m_blockEmitDataChanged
= true;
472 QCheckBox
*convert
= 0;
474 if ( m_editor
->acceptRichText() ) {
475 convert
= new QCheckBox( 0 );
476 convert
->setText( i18n( "Save note as plain text" ) );
478 m_blockEmitDataChanged
= true;
480 KFileDialog
dlg( url
, QString(), this, convert
);
481 dlg
.setOperationMode( KFileDialog::Saving
);
482 dlg
.setCaption( i18n( "Save As" ) );
485 QString fileName
= dlg
.selectedFile();
486 if ( fileName
.isEmpty() ) {
487 m_blockEmitDataChanged
= false;
491 QFile
file( fileName
);
493 if ( file
.exists() &&
494 KMessageBox::warningContinueCancel( this,
495 i18n( "<qt>A file named <b>%1</b> already exists.<br />"
496 "Are you sure you want to overwrite it?</qt>",
497 QFileInfo( file
).fileName() ) ) != KMessageBox::Continue
) {
498 m_blockEmitDataChanged
= false;
502 if ( file
.open( QIODevice::WriteOnly
) ) {
503 QTextStream
stream( &file
);
504 if ( convert
&& !convert
->isChecked() ) {
505 stream
<< m_editor
->toHtml();
507 stream
<< m_editor
->toPlainText();
510 m_blockEmitDataChanged
= false;
513 void KNote::slotPopupActionToDesktop( int id
)
515 toDesktop( id
- 1 ); // compensate for the menu separator, -1 == all desktops
519 // ------------------ private slots (configuration) ------------------ //
521 void KNote::slotApplyConfig()
523 m_label
->setFont( m_config
->titleFont() );
524 m_editor
->setRichText( m_config
->richText() );
525 m_editor
->setTextFont( m_config
->font() );
526 m_editor
->setTabStop( m_config
->tabSize() );
527 m_editor
->setAutoIndentMode( m_config
->autoIndent() );
529 setColor( m_config
->fgColor(), m_config
->bgColor() );
532 slotUpdateShowInTaskbar();
535 void KNote::slotKeepAbove()
537 if ( m_keepBelow
->isChecked() )
539 m_keepBelow
->setChecked( false );
541 slotUpdateKeepAboveBelow();
544 void KNote::slotKeepBelow()
546 if ( m_keepAbove
->isChecked() )
548 m_keepAbove
->setChecked( false );
550 slotUpdateKeepAboveBelow();
553 void KNote::slotUpdateKeepAboveBelow()
556 unsigned long state
= KWindowInfo( KWindowSystem::windowInfo( winId(), NET::WMState
) ).state();
558 unsigned long state
= 0; // neutral state, TODO
560 if ( m_keepAbove
->isChecked() ) {
561 m_config
->setKeepAbove( true );
562 m_config
->setKeepBelow( false );
563 KWindowSystem::setState( winId(), state
| NET::KeepAbove
);
564 } else if ( m_keepBelow
->isChecked() ) {
565 m_config
->setKeepAbove( false );
566 m_config
->setKeepBelow( true );
567 KWindowSystem::setState( winId(), state
| NET::KeepBelow
);
569 m_config
->setKeepAbove( false );
570 KWindowSystem::clearState( winId(), NET::KeepAbove
);
571 m_config
->setKeepBelow( false );
572 KWindowSystem::clearState( winId(), NET::KeepBelow
);
576 void KNote::slotUpdateShowInTaskbar()
579 if ( !m_config
->showInTaskbar() ) {
580 KWindowSystem::setState( winId(), KWindowSystem::windowInfo( winId(),
581 NET::WMState
).state() | NET::SkipTaskbar
);
583 KWindowSystem::clearState( winId(), NET::SkipTaskbar
);
588 void KNote::slotUpdateDesktopActions()
591 NETRootInfo
wm_root( QX11Info::display(), NET::NumberOfDesktops
|
593 NETWinInfo
wm_client( QX11Info::display(), winId(),
594 QX11Info::appRootWindow(), NET::WMDesktop
);
596 QStringList desktops
;
597 desktops
.append( i18n( "&All Desktops" ) );
598 desktops
.append( QString::null
); // Separator
599 // krazy:exclude=nullstrassign
600 // for old broken gcc
602 const int count
= wm_root
.numberOfDesktops();
603 for ( int n
= 1; n
<= count
; n
++ ) {
604 desktops
.append( QString( "&%1 %2" ).arg( n
).arg(
605 QString::fromUtf8( wm_root
.desktopName( n
) ) ) );
607 m_toDesktop
->setItems( desktops
);
609 if ( wm_client
.desktop() == NETWinInfo::OnAllDesktops
) {
610 m_toDesktop
->setCurrentItem( 0 );
612 m_toDesktop
->setCurrentItem( wm_client
.desktop() + 1 ); // compensate for
619 // -------------------- private methods -------------------- //
621 void KNote::buildGui()
626 KXMLGUIBuilder
builder( this );
627 KXMLGUIFactory
factory( &builder
, this );
628 factory
.addClient( this );
630 m_menu
= dynamic_cast<KMenu
*>( factory
.container( "note_context", this ) );
631 m_tool
= dynamic_cast<KToolBar
*>( factory
.container( "note_tool", this ) );
636 void KNote::createActions()
638 // create the menu items for the note - not the editor...
639 // rename, mail, print, save as, insert date, alarm, close, delete, new note
642 action
= new KAction( KIcon( "document-new" ), i18n( "New" ), this );
643 actionCollection()->addAction( "new_note", action
);
644 connect( action
, SIGNAL(triggered(bool)), SLOT(slotRequestNewNote()) );
646 action
= new KAction( KIcon( "edit-rename" ), i18n( "Rename..." ), this );
647 actionCollection()->addAction( "rename_note", action
);
648 connect( action
, SIGNAL(triggered(bool)), SLOT(slotRename()) );
650 m_readOnly
= new KToggleAction( KIcon( "object-locked" ),
651 i18n( "Lock" ), this );
652 actionCollection()->addAction( "lock_note", m_readOnly
);
653 connect( m_readOnly
, SIGNAL(triggered(bool)),
654 SLOT(slotUpdateReadOnly()) );
655 m_readOnly
->setCheckedState( KGuiItem( i18n( "Unlock" ), "object-unlocked" ) );
657 action
= new KAction( KIcon( "window-close" ), i18n( "Hide" ), this );
658 actionCollection()->addAction( "hide_note", action
);
659 connect( action
, SIGNAL(triggered(bool)), SLOT(slotClose()) );
660 action
->setShortcut( QKeySequence( Qt::Key_Escape
) );
662 action
= new KAction( KIcon( "edit-delete" ), i18n( "Delete" ), this );
663 actionCollection()->addAction( "delete_note", action
);
664 connect( action
, SIGNAL(triggered(bool)), SLOT(slotKill()),Qt::QueuedConnection
);
666 action
= new KAction( KIcon( "knotes_date" ), i18n( "Insert Date" ), this );
667 actionCollection()->addAction( "insert_date", action
);
668 connect( action
, SIGNAL(triggered(bool)), SLOT(slotInsDate()) );
670 action
= new KAction( KIcon( "knotes_alarm" ), i18n( "Set Alarm..." ),
672 actionCollection()->addAction( "set_alarm", action
);
673 connect( action
, SIGNAL(triggered(bool)), SLOT(slotSetAlarm()) );
675 action
= new KAction( KIcon( "network-wired" ), i18n( "Send..." ), this );
676 actionCollection()->addAction( "send_note", action
);
677 connect( action
, SIGNAL(triggered(bool)), SLOT(slotSend()) );
679 action
= new KAction( KIcon( "mail-send" ), i18n( "Mail..." ), this );
680 actionCollection()->addAction( "mail_note", action
);
681 connect( action
, SIGNAL(triggered(bool)), SLOT(slotMail()) );
683 action
= new KAction( KIcon( "document-save-as" ), i18n( "Save As..." ),
685 actionCollection()->addAction( "save_note", action
);
686 connect( action
, SIGNAL(triggered(bool)), SLOT(slotSaveAs()) );
687 actionCollection()->addAction( KStandardAction::Print
, "print_note", this,
690 action
= new KAction( KIcon( "configure" ), i18n( "Preferences..." ), this );
691 actionCollection()->addAction( "configure_note", action
);
692 connect( action
, SIGNAL(triggered(bool)), SLOT(slotPreferences()) );
695 m_keepAbove
= new KToggleAction( KIcon( "go-up" ),
696 i18n( "Keep Above Others" ), this );
697 actionCollection()->addAction( "keep_above", m_keepAbove
);
698 connect( m_keepAbove
, SIGNAL(triggered(bool)),
699 SLOT(slotKeepAbove()) );
701 m_keepBelow
= new KToggleAction( KIcon( "go-down" ),
702 i18n( "Keep Below Others" ), this );
703 actionCollection()->addAction( "keep_below", m_keepBelow
);
704 connect( m_keepBelow
, SIGNAL(triggered(bool)),
705 SLOT(slotKeepBelow()) );
708 m_toDesktop
= new KSelectAction( i18n( "To Desktop" ), this );
709 actionCollection()->addAction( "to_desktop", m_toDesktop
);
710 connect( m_toDesktop
, SIGNAL(triggered(int)),
711 SLOT(slotPopupActionToDesktop(int)) );
712 connect( m_toDesktop
->menu(), SIGNAL(aboutToShow()),
713 SLOT(slotUpdateDesktopActions()) );
716 // invisible action to walk through the notes to make this configurable
717 action
= new KAction( i18n( "Walk Through Notes" ), this );
718 actionCollection()->addAction( "walk_notes", action
);
719 connect( action
, SIGNAL(triggered(bool)), SIGNAL(sigShowNextNote()) );
720 action
->setShortcut( QKeySequence( Qt::SHIFT
+ Qt::Key_Backtab
) );
722 actionCollection()->addAssociatedWidget( this );
723 foreach (QAction
* action
, actionCollection()->actions())
724 action
->setShortcutContext(Qt::WidgetWithChildrenShortcut
);
727 void KNote::createNoteHeader()
729 // load style configuration
730 KConfigGroup
styleGroup( m_kwinConf
, "Style" );
732 QBoxLayout::Direction headerLayoutDirection
= QBoxLayout::LeftToRight
;
734 if ( styleGroup
.readEntry( "CustomButtonPositions", false ) ) {
735 if ( styleGroup
.readEntry( "ButtonsOnLeft" ).contains( 'X' ) ) {
736 headerLayoutDirection
= QBoxLayout::RightToLeft
;
740 QBoxLayout
*headerLayout
= new QBoxLayout( headerLayoutDirection
);
743 // create header label
744 m_label
= new QLabel( this );
745 headerLayout
->addWidget( m_label
);
746 m_label
->setFrameStyle( NoFrame
);
747 m_label
->setBackgroundRole( QPalette::Base
);
748 m_label
->setLineWidth( 0 );
749 m_label
->setAutoFillBackground( true );
750 m_label
->installEventFilter( this ); // receive events ( for dragging &
752 setName( m_journal
->summary() ); // don't worry, no signals are
753 // connected at this stage yet
754 m_button
= new KNoteButton( "knotes_close", this );
755 headerLayout
->addWidget( m_button
);
757 connect( m_button
, SIGNAL(clicked()), this, SLOT(slotClose()) );
759 m_noteLayout
->addItem( headerLayout
);
762 void KNote::createNoteEditor()
764 m_editor
= new KNoteEdit( actionCollection(), this );
765 m_noteLayout
->addWidget( m_editor
);
766 m_editor
->setNote( this );
767 m_editor
->installEventFilter( this ); // receive focus events for modified
768 setFocusProxy( m_editor
);
771 void KNote::slotRequestNewNote()
773 //Be sure to save before to request a new note
776 emit
sigRequestNewNote();
779 void KNote::createNoteFooter()
782 m_tool
->setIconSize( QSize( 10, 10 ) );
783 m_tool
->setFixedHeight( 24 );
784 m_tool
->setToolButtonStyle( Qt::ToolButtonIconOnly
);
788 QHBoxLayout
*gripLayout
= new QHBoxLayout
;
789 m_grip
= new QSizeGrip( this );
790 m_grip
->setFixedSize( m_grip
->sizeHint() );
793 gripLayout
->addWidget( m_tool
);
794 gripLayout
->setAlignment( m_tool
, Qt::AlignBottom
| Qt::AlignLeft
);
798 gripLayout
->addWidget( m_grip
);
799 gripLayout
->setAlignment( m_grip
, Qt::AlignBottom
| Qt::AlignRight
);
800 m_noteLayout
->addItem( gripLayout
);
802 // if there was just a way of making KComboBox adhere the toolbar height...
804 foreach ( KComboBox
*combo
, m_tool
->findChildren
<KComboBox
*>() ) {
805 QFont font
= combo
->font();
806 font
.setPointSize( 7 );
807 combo
->setFont( font
);
808 combo
->setFixedHeight( 14 );
813 void KNote::prepare()
815 // the config file location
816 const QString configFile
= KGlobal::dirs()->saveLocation( "appdata", "notes/" ) + m_journal
->uid();
818 // no config file yet? -> use the default display config if available
819 // we want to write to configFile, so use "false"
820 const bool newNote
= !KIO::NetAccess::exists( KUrl( configFile
),
821 KIO::NetAccess::DestinationSide
, 0 );
823 m_config
= new KNoteConfig( KSharedConfig::openConfig( configFile
,
824 KConfig::NoGlobals
) );
825 m_config
->readConfig();
826 m_config
->setVersion( KDEPIM_VERSION
);
829 // until kdelibs provides copying of KConfigSkeletons (KDE 3.4)
830 KNotesGlobalConfig
*globalConfig
= KNotesGlobalConfig::self();
831 m_config
->setBgColor( globalConfig
->bgColor() );
832 m_config
->setFgColor( globalConfig
->fgColor() );
833 m_config
->setWidth( globalConfig
->width() );
834 m_config
->setHeight( globalConfig
->height() );
836 m_config
->setFont( globalConfig
->font() );
837 m_config
->setTitleFont( globalConfig
->titleFont() );
838 m_config
->setAutoIndent( globalConfig
->autoIndent() );
839 m_config
->setRichText( globalConfig
->richText() );
840 m_config
->setTabSize( globalConfig
->tabSize() );
841 m_config
->setReadOnly( globalConfig
->readOnly() );
843 m_config
->setDesktop( globalConfig
->desktop() );
844 m_config
->setHideNote( globalConfig
->hideNote() );
845 m_config
->setPosition( globalConfig
->position() );
846 m_config
->setShowInTaskbar( globalConfig
->showInTaskbar() );
847 m_config
->setRememberDesktop( globalConfig
->rememberDesktop() );
848 m_config
->setKeepAbove( globalConfig
->keepAbove() );
849 m_config
->setKeepBelow( globalConfig
->keepBelow() );
851 m_config
->writeConfig();
854 // set up the look&feel of the note
855 setFrameStyle( Panel
| Raised
);
856 setMinimumSize( 20, 20 );
857 setBackgroundRole( QPalette::Base
);
859 m_editor
->setContentsMargins( 0, 0, 0, 0 );
860 m_editor
->setBackgroundRole( QPalette::Base
);
861 m_editor
->setFrameStyle( NoFrame
);
862 m_editor
->setText( m_journal
->description() );
864 // load the display configuration of the note
865 uint width
= m_config
->width();
866 uint height
= m_config
->height();
867 resize( width
, height
);
869 // let KWin do the placement if the position is illegal--at least 10 pixels
870 // of a note need to be visible
871 const QPoint
& position
= m_config
->position();
872 QRect desk
= kapp
->desktop()->rect();
873 desk
.adjust( 10, 10, -10, -10 );
874 if ( desk
.intersects( QRect( position
, QSize( width
, height
) ) ) ) {
875 move( position
); // do before calling show() to avoid flicker
878 // config items in the journal have priority
879 QString property
= m_journal
->customProperty( "KNotes", "FgColor" );
880 if ( !property
.isNull() ) {
881 m_config
->setFgColor( QColor( property
) );
883 m_journal
->setCustomProperty( "KNotes", "FgColor",
884 m_config
->fgColor().name() );
887 property
= m_journal
->customProperty( "KNotes", "BgColor" );
888 if ( !property
.isNull() ) {
889 m_config
->setBgColor( QColor( property
) );
891 m_journal
->setCustomProperty( "KNotes", "BgColor",
892 m_config
->bgColor().name() );
894 property
= m_journal
->customProperty( "KNotes", "RichText" );
895 if ( !property
.isNull() ) {
896 m_config
->setRichText( property
== "true" ? true : false );
898 m_journal
->setCustomProperty( "KNotes", "RichText",
899 m_config
->richText() ? "true" : "false" );
902 // read configuration settings...
905 // if this is a new note put on current desktop - we can't use defaults
906 // in KConfig XT since only _changes_ will be stored in the config file
907 int desktop
= m_config
->desktop();
910 if ( ( desktop
< 0 && desktop
!= NETWinInfo::OnAllDesktops
) ||
911 !m_config
->rememberDesktop() )
912 desktop
= KWindowSystem::currentDesktop();
915 // show the note if desired
916 if ( desktop
!= 0 && !m_config
->hideNote() ) {
917 // to avoid flicker, call this before show()
918 toDesktop( desktop
);
921 // because KWin forgets about that for hidden windows
923 if ( desktop
== NETWinInfo::OnAllDesktops
) {
924 toDesktop( desktop
);
929 m_readOnly
->setChecked( m_config
->readOnly() );
930 slotUpdateReadOnly();
932 if ( m_config
->keepAbove() ) {
933 m_keepAbove
->setChecked( true );
934 } else if ( m_config
->keepBelow() ) {
935 m_keepBelow
->setChecked( true );
937 m_keepAbove
->setChecked( false );
938 m_keepBelow
->setChecked( false );
940 slotUpdateKeepAboveBelow();
942 // HACK: update the icon color - again after showing the note, to make kicker
943 // aware of the new colors
945 QPixmap icon
= effect
.apply( qApp
->windowIcon().pixmap(
946 IconSize( KIconLoader::Desktop
),
947 IconSize( KIconLoader::Desktop
) ),
948 KIconEffect::Colorize
,
949 1, m_config
->bgColor(), false );
950 QPixmap miniIcon
= effect
.apply( qApp
->windowIcon().pixmap(
951 IconSize( KIconLoader::Small
),
952 IconSize( KIconLoader::Small
) ),
953 KIconEffect::Colorize
,
954 1, m_config
->bgColor(), false );
956 KWindowSystem::setIcons( winId(), icon
, miniIcon
);
958 m_editor
->document()->setModified( false );
961 void KNote::toDesktop( int desktop
)
963 if ( desktop
== 0 ) {
968 if ( desktop
== NETWinInfo::OnAllDesktops
) {
969 KWindowSystem::setOnAllDesktops( winId(), true );
971 KWindowSystem::setOnDesktop( winId(), desktop
);
976 void KNote::setColor( const QColor
&fg
, const QColor
&bg
)
978 QPalette p
= palette();
980 // better: from light(150) to light(100) to light(75)
981 // QLinearGradient g( width()/2, 0, width()/2, height() );
982 // g.setColorAt( 0, bg );
983 // g.setColorAt( 1, bg.dark(150) );
985 p
.setColor( QPalette::Window
, bg
);
986 // p.setBrush( QPalette::Window, g );
987 p
.setColor( QPalette::Base
, bg
);
988 // p.setBrush( QPalette::Base, g );
990 p
.setColor( QPalette::WindowText
, fg
);
991 p
.setColor( QPalette::Text
, fg
);
993 p
.setColor( QPalette::Button
, bg
.dark( 116 ) );
994 p
.setColor( QPalette::ButtonText
, fg
);
996 //p.setColor( QPalette::Highlight, bg );
997 //p.setColor( QPalette::HighlightedText, fg );
999 // order: Light, Midlight, Button, Mid, Dark, Shadow
1002 p
.setColor( QPalette::Light
, bg
.light( 180 ) );
1003 p
.setColor( QPalette::Midlight
, bg
.light( 150 ) );
1004 p
.setColor( QPalette::Mid
, bg
.light( 150 ) );
1005 p
.setColor( QPalette::Dark
, bg
.dark( 108 ) );
1006 p
.setColor( QPalette::Shadow
, bg
.dark( 116 ) );
1010 // darker values for the active label
1011 p
.setColor( QPalette::Active
, QPalette::Base
, bg
.dark( 116 ) );
1013 m_label
->setPalette( p
);
1015 // set the text color
1016 m_editor
->setTextColor( fg
);
1018 // update the icon color
1020 QPixmap icon
= effect
.apply( qApp
->windowIcon().pixmap(
1021 IconSize( KIconLoader::Desktop
),
1022 IconSize( KIconLoader::Desktop
) ),
1023 KIconEffect::Colorize
, 1, bg
, false );
1024 QPixmap miniIcon
= effect
.apply( qApp
->windowIcon().pixmap(
1025 IconSize( KIconLoader::Small
),
1026 IconSize( KIconLoader::Small
) ),
1027 KIconEffect::Colorize
, 1, bg
, false );
1029 KWindowSystem::setIcons( winId(), icon
, miniIcon
);
1031 // update the color of the title
1033 emit
sigColorChanged();
1036 void KNote::updateLabelAlignment()
1038 // if the name is too long to fit, left-align it, otherwise center it (#59028)
1039 const QString labelText
= m_label
->text();
1040 if ( m_label
->fontMetrics().boundingRect( labelText
).width() >
1041 m_label
->width() ) {
1042 m_label
->setAlignment( Qt::AlignLeft
);
1044 m_label
->setAlignment( Qt::AlignHCenter
);
1048 void KNote::updateFocus()
1053 if ( !m_editor
->isReadOnly() )
1055 if ( m_tool
&& m_tool
->isHidden() && m_editor
->acceptRichText() )
1058 setGeometry( x(), y(), width(), height() + m_tool
->height() );
1064 if ( m_tool
&& !m_tool
->isHidden() ) {
1066 setGeometry( x(), y(), width(), height() - m_tool
->height() );
1067 updateLayout(); // to update the minimum height
1076 if ( m_tool
&& !m_tool
->isHidden() )
1079 setGeometry( x(), y(), width(), height() - m_tool
->height() );
1080 updateLayout(); // to update the minimum height
1085 void KNote::updateLayout()
1087 // TODO: remove later if no longer needed.
1088 updateLabelAlignment();
1091 // -------------------- protected methods -------------------- //
1093 void KNote::contextMenuEvent( QContextMenuEvent
*e
)
1096 m_menu
->popup( e
->globalPos() );
1100 void KNote::showEvent( QShowEvent
* )
1102 if ( m_config
->hideNote() ) {
1103 // KWin does not preserve these properties for hidden windows
1104 slotUpdateKeepAboveBelow();
1105 slotUpdateShowInTaskbar();
1106 toDesktop( m_config
->desktop() );
1107 move( m_config
->position() );
1108 m_config
->setHideNote( false );
1112 void KNote::resizeEvent( QResizeEvent
*qre
)
1114 QFrame::resizeEvent( qre
);
1118 void KNote::closeEvent( QCloseEvent
* event
)
1120 event
->ignore(); //We don't want to close (and delete the widget). Just hide it
1124 void KNote::dragEnterEvent( QDragEnterEvent
*e
)
1126 if ( !m_config
->readOnly() ) {
1127 e
->setAccepted( e
->mimeData()->hasColor() );
1131 void KNote::dropEvent( QDropEvent
*e
)
1133 if ( m_config
->readOnly() ) {
1137 const QMimeData
*md
= e
->mimeData();
1138 if ( md
->hasColor() ) {
1139 QColor bg
= qvariant_cast
<QColor
>( md
->colorData() );
1140 setColor( palette().color( foregroundRole() ), bg
);
1141 m_journal
->setCustomProperty( "KNotes", "BgColor", bg
.name() );
1142 m_config
->setBgColor( bg
);
1146 bool KNote::event( QEvent
*ev
)
1148 if ( ev
->type() == QEvent::LayoutRequest
) {
1152 return QFrame::event( ev
);
1156 bool KNote::eventFilter( QObject
*o
, QEvent
*ev
)
1158 if ( ev
->type() == QEvent::DragEnter
&&
1159 static_cast<QDragEnterEvent
*>( ev
)->mimeData()->hasColor() ) {
1160 dragEnterEvent( static_cast<QDragEnterEvent
*>( ev
) );
1164 if ( ev
->type() == QEvent::Drop
&&
1165 static_cast<QDropEvent
*>( ev
)->mimeData()->hasColor() ) {
1166 dropEvent( static_cast<QDropEvent
*>( ev
) );
1170 if ( o
== m_label
) {
1171 QMouseEvent
*e
= ( QMouseEvent
* )ev
;
1173 if ( ev
->type() == QEvent::MouseButtonDblClick
) {
1174 if(!m_editor
->isReadOnly())
1178 if ( ev
->type() == QEvent::MouseButtonPress
&&
1179 ( e
->button() == Qt::LeftButton
|| e
->button() == Qt::MidButton
) ) {
1181 e
->button() == Qt::LeftButton
? KWindowSystem::raiseWindow( winId() )
1182 : KWindowSystem::lowerWindow( winId() );
1184 XUngrabPointer( QX11Info::display(), QX11Info::appTime() );
1185 NETRootInfo
wm_root( QX11Info::display(), NET::WMMoveResize
);
1186 wm_root
.moveResizeRequest( winId(), e
->globalX(), e
->globalY(),
1192 if ( ev
->type() == QEvent::MouseButtonRelease
) {
1194 NETRootInfo
wm_root( QX11Info::display(), NET::WMMoveResize
);
1195 wm_root
.moveResizeRequest( winId(), e
->globalX(), e
->globalY(),
1196 NET::MoveResizeCancel
);
1204 if ( o
== m_editor
) {
1205 if ( ev
->type() == QEvent::FocusOut
) {
1206 QFocusEvent
*fe
= static_cast<QFocusEvent
*>( ev
);
1207 if ( fe
->reason() != Qt::PopupFocusReason
&&
1208 fe
->reason() != Qt::MouseFocusReason
) {
1210 if ( isModified() ) {
1212 if ( !m_blockEmitDataChanged
)
1216 } else if ( ev
->type() == QEvent::FocusIn
) {
1227 #include "knote.moc"