00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020 #include "KoContextHelp.h"
00021
00022 #include <QPainter>
00023 #include <QRegion>
00024 #include <QFont>
00025 #include <QLabel>
00026 #include <QLayout>
00027 #include <q3simplerichtext.h>
00028 #include <QPixmap>
00029 #include <QPaintEvent>
00030 #include <QPolygon>
00031 #include <QEvent>
00032 #include <QKeyEvent>
00033 #include <QHBoxLayout>
00034 #include <QTimerEvent>
00035 #include <QResizeEvent>
00036 #include <QMouseEvent>
00037 #include <kicon.h>
00038 #include <klocale.h>
00039 #include <kdebug.h>
00040 #include <kiconloader.h>
00041 #include <kcursor.h>
00042 #include <kapplication.h>
00043 #include <QString>
00044 #include <ktoolinvocation.h>
00045 #include <ktoggleaction.h>
00046 #include <QAbstractEventDispatcher>
00047
00048 KoVerticalLabel::KoVerticalLabel( QWidget* parent, const char* )
00049 : QWidget( parent, Qt::WNoAutoErase )
00050 {
00051 QFont f( font() );
00052 f.setPointSize( f.pointSize() + 2 );
00053 f.setBold( true );
00054 setFont( f );
00055 setBackgroundRole( QPalette::Light );
00056 }
00057
00058 KoVerticalLabel::~KoVerticalLabel()
00059 {
00060 }
00061
00062 void KoVerticalLabel::setText( const QString& text )
00063 {
00064 m_text = text;
00065 QFontMetrics fm( font() );
00066 setMinimumSize( fm.height() + 2, fm.width( m_text ) + 4 );
00067 update();
00068 }
00069
00070 void KoVerticalLabel::paintEvent( QPaintEvent* )
00071 {
00072 QPixmap pm( height(), width() );
00073 QPainter p( &pm );
00074 p.fillRect( 0, 0, height(), width(), palette().window() );
00075 p.setFont( font() );
00076 p.drawText( 0, 0, height(), width(), Qt::AlignCenter, m_text );
00077 p.end();
00078 QPainter ap( this );
00079 ap.rotate( 270. );
00080 ap.translate( -height(), 0 );
00081 ap.drawPixmap( 0, 0, pm );
00082 }
00083
00084 static unsigned char upbits[] = { 0xc, 0x1e, 0x3f, 0x3f };
00085 static unsigned char downbits[] = { 0x3f, 0x3f, 0x1e, 0xc };
00086
00087 KoHelpNavButton::KoHelpNavButton( NavDirection d, QWidget* parent )
00088 : QWidget( parent )
00089 {
00090 m_pressed = false;
00091 m_bitmap = QBitmap::fromData( QSize(8, 4), ( d == Up ? upbits : downbits ) );
00092 m_bitmap.setMask( m_bitmap );
00093 setFixedSize( 8, 6 );
00094 setBackgroundRole( QPalette::Light );
00095 }
00096
00097 void KoHelpNavButton::paintEvent( QPaintEvent* )
00098 {
00099 QPainter p( this );
00100 if ( isEnabled() )
00101 {
00102 if ( m_pressed )
00103 p.setPen( palette().color( QPalette::Highlight ) );
00104 else
00105 p.setPen( palette().color( QPalette::Text ));
00106 p.drawPixmap( 1, 1, m_bitmap );
00107 }
00108 }
00109
00110 void KoHelpNavButton::enterEvent( QEvent* )
00111 {
00112 if ( isEnabled() )
00113 emit pressed();
00114 m_pressed = true;
00115 update();
00116 }
00117
00118 void KoHelpNavButton::leaveEvent( QEvent* )
00119 {
00120 if ( isEnabled() )
00121 emit released();
00122 m_pressed = false;
00123 update();
00124 }
00125
00126 static unsigned char notstickybits[] = { 0x8, 0x1e, 0xc, 0xa, 0x1 };
00127 static unsigned char stickybits[] = { 0xe, 0x11, 0x15, 0x11, 0xe };
00128 static unsigned char closebits[] = { 0x11, 0xa, 0x4, 0xa, 0x11 };
00129
00130 KoTinyButton::KoTinyButton( Action a, QWidget* parent )
00131 : QWidget( parent ), m_action( a )
00132 {
00133 m_pressed = false;
00134 m_toggled = false;
00135 switch ( a )
00136 {
00137 case Sticky:
00138 m_bitmap = QBitmap::fromData( QSize( 5, 5 ), notstickybits );
00139 break;
00140
00141 default:
00142 m_bitmap = QBitmap::fromData( QSize(5, 5), closebits );
00143 }
00144 m_bitmap.setMask( m_bitmap );
00145 setMinimumSize( 7, 7 );
00146 setBackgroundRole( QPalette::Window );
00147 }
00148
00149 void KoTinyButton::paintEvent( QPaintEvent* )
00150 {
00151 QPainter p( this );
00152 if ( isEnabled() )
00153 {
00154 if ( m_pressed )
00155 p.setPen( palette().color( QPalette::Highlight ) );
00156 else
00157 p.setPen( palette().color( QPalette::Text ) );
00158 p.drawPixmap( width() / 2 - 2, 1, m_bitmap );
00159 }
00160 }
00161
00162 void KoTinyButton::mousePressEvent( QMouseEvent* )
00163 {
00164 if ( isEnabled() )
00165 {
00166 m_pressed = true;
00167 update();
00168 }
00169 }
00170
00171 void KoTinyButton::mouseReleaseEvent( QMouseEvent* )
00172 {
00173 if ( isEnabled() && m_pressed )
00174 {
00175 m_pressed = false;
00176 emit( clicked() );
00177 if ( ( m_action == Sticky ) )
00178 {
00179 m_toggled = !m_toggled;
00180 emit( toggled( m_toggled ) );
00181
00182
00183
00184 m_bitmap = QBitmap::fromData( QSize( 5, 5), ( m_toggled ? stickybits : notstickybits ) );
00185
00186 m_bitmap.setMask( m_bitmap );
00187 }
00188 update();
00189 }
00190 }
00191
00192 KoHelpView::KoHelpView( QWidget* parent )
00193 : QWidget( parent )
00194 {
00195 currentText = 0L;
00196 setBackgroundRole( QPalette::Light );
00197 parent->installEventFilter( this );
00198 setMouseTracking( true );
00199 }
00200
00201 KoHelpView::~KoHelpView()
00202 {
00203 if ( currentText )
00204 delete currentText;
00205 }
00206
00207 void KoHelpView::setText( const QString& text )
00208 {
00209 if ( currentText )
00210 delete currentText;
00211 currentText = new Q3SimpleRichText( text, font() );
00212 currentText->setWidth( width() );
00213 setFixedHeight( currentText->height() );
00214 }
00215
00216 void KoHelpView::mousePressEvent( QMouseEvent* e )
00217 {
00218 currentAnchor = currentText->anchorAt( e->pos() );
00219 if ( !currentAnchor.isEmpty() )
00220 e->accept();
00221 else
00222 e->ignore();
00223 }
00224
00225 void KoHelpView::mouseReleaseEvent( QMouseEvent* e )
00226 {
00227 if ( ( !currentAnchor.isEmpty() ) && ( currentAnchor == currentText->anchorAt( e->pos() ) ) )
00228 {
00229 e->accept();
00230 if (currentAnchor.startsWith("help://#")) {
00231
00232 KToolInvocation::invokeHelp(currentAnchor.right(currentAnchor.length()-8));
00233 }
00234 else
00235 if (currentAnchor.startsWith("help://")) {
00236
00237 QString helpapp=currentAnchor.right(currentAnchor.length()-7);
00238 QString helpanchor;
00239 int pos;
00240 if ((pos=helpapp.indexOf("#"))!=-1) {
00241 helpanchor=helpapp.right(helpapp.length()-pos-1);
00242 helpapp=helpapp.left(pos);
00243 }
00244 KToolInvocation::invokeHelp(helpanchor,helpapp);
00245 }
00246 else
00247 emit linkClicked( currentAnchor );
00248 currentAnchor = "";
00249 }
00250 else
00251 e->ignore();
00252 }
00253
00254 void KoHelpView::mouseMoveEvent( QMouseEvent* e )
00255 {
00256 if ( !currentText->anchorAt( e->pos() ).isEmpty() )
00257 setCursor( KCursor::handCursor() );
00258 else
00259 setCursor( KCursor::arrowCursor() );
00260 }
00261
00262 bool KoHelpView::eventFilter( QObject*, QEvent* e )
00263 {
00264 if ( ( currentText ) && ( e->type() == QEvent::Resize ) )
00265 {
00266 setFixedWidth( ( (QResizeEvent*)e )->size().width() );
00267 currentText->setWidth( width() );
00268 setFixedHeight( currentText->height() );
00269
00270 return true;
00271 }
00272 return false;
00273 }
00274
00275 void KoHelpView::paintEvent( QPaintEvent* )
00276 {
00277 QPainter p( this );
00278 currentText->draw( &p, 0, 0, QRect(), palette() );
00279 }
00280
00281 KoHelpWidget::KoHelpWidget( const QString & help, QWidget* parent )
00282 : QWidget( parent )
00283 {
00284 QGridLayout* layout = new QGridLayout( this );
00285 layout->setMargin( 2 );
00286 layout->addWidget( m_upButton = new KoHelpNavButton( KoHelpNavButton::Up, this ), 0, 1, Qt::AlignHCenter );
00287 layout->addWidget( m_helpViewport = new QWidget( this ), 1, 1 );
00288 layout->addWidget( m_downButton = new KoHelpNavButton( KoHelpNavButton::Down, this ), 2, 1, Qt::AlignHCenter );
00289 layout->setSpacing( 5 );
00290 layout->setColumnStretch( 1, 1 );
00291
00292 m_helpView = new KoHelpView( m_helpViewport );
00293 m_helpViewport->setBackgroundRole( QPalette::Light );
00294 setText( help );
00295
00296 setBackgroundRole( QPalette::Light );
00297
00298 connect( m_upButton, SIGNAL( pressed() ), this, SLOT( startScrollingUp() ) );
00299 connect( m_downButton, SIGNAL( pressed() ), this, SLOT( startScrollingDown() ) );
00300 connect( m_upButton, SIGNAL( released() ), this, SLOT( stopScrolling() ) );
00301 connect( m_downButton, SIGNAL( released() ), this, SLOT( stopScrolling() ) );
00302 connect( m_helpView, SIGNAL( linkClicked( const QString& ) ), this, SIGNAL( linkClicked( const QString& ) ) );
00303 }
00304
00305 void KoHelpWidget::updateButtons()
00306 {
00307 m_upButton->setEnabled( m_ypos < 0 );
00308 m_downButton->setEnabled( m_helpViewport->height() - m_ypos < m_helpView->height() );
00309 }
00310
00311 void KoHelpWidget::setText( const QString & text )
00312 {
00313 m_helpView->setText( text );
00314 m_helpView->move( 0, 0 );
00315 m_ypos = 0;
00316 updateButtons();
00317 }
00318
00319 void KoHelpWidget::resizeEvent( QResizeEvent* )
00320 {
00321 updateButtons();
00322 }
00323
00324 void KoHelpWidget::startScrollingUp()
00325 {
00326 if ( !m_upButton->isEnabled() )
00327 return;
00328 m_scrollDown = false;
00329 startTimer( 80 );
00330 }
00331
00332 void KoHelpWidget::startScrollingDown()
00333 {
00334 if ( !m_downButton->isEnabled() )
00335 return;
00336 m_scrollDown = true;
00337 startTimer( 80 );
00338 }
00339
00340 void KoHelpWidget::scrollUp()
00341 {
00342 if ( m_ypos > 0 )
00343 stopScrolling();
00344 else
00345 {
00346 m_ypos += 2;
00347 m_helpViewport->scroll( 0, 2 );
00348 m_helpViewport->update();
00349 updateButtons();
00350 }
00351 }
00352
00353 void KoHelpWidget::scrollDown()
00354 {
00355 if ( m_helpViewport->height() - m_helpView->height() - m_ypos > 0 )
00356 stopScrolling();
00357 else
00358 {
00359 m_ypos -= 2;
00360 m_helpViewport->scroll( 0, -2 );
00361 m_helpViewport->update();
00362 updateButtons();
00363 }
00364 }
00365
00366 void KoHelpWidget::timerEvent( QTimerEvent* )
00367 {
00368 if ( m_scrollDown )
00369 scrollDown();
00370 else
00371 scrollUp();
00372 }
00373
00374 void KoHelpWidget::stopScrolling()
00375 {
00376 QAbstractEventDispatcher::instance()->unregisterTimers(this);
00377 }
00378
00379 KoContextHelpPopup::KoContextHelpPopup( QWidget* parent )
00380 : QWidget( parent, Qt::WType_Dialog | Qt::WStyle_Customize | Qt::WStyle_NoBorder )
00381 {
00382 QGridLayout* layout = new QGridLayout( this );
00383 QHBoxLayout* buttonLayout;
00384 layout->addWidget( m_helpIcon = new QLabel( this ), 0, 0 );
00385 layout->addWidget( m_helpTitle = new KoVerticalLabel( this ), 1, 0 );
00386 buttonLayout = new QHBoxLayout();
00387 layout->addLayout( buttonLayout, 2, 0 );
00388 layout->addWidget( m_helpViewer = new KoHelpWidget( "", this ), 0, 1, 3, 1 );
00389 buttonLayout->addWidget( m_close = new KoTinyButton( KoTinyButton::Close, this ) );
00390 buttonLayout->addWidget( m_sticky = new KoTinyButton( KoTinyButton::Sticky, this ) );
00391 layout->setMargin( 3 );
00392 layout->setSpacing( 1 );
00393 layout->setRowStretch( 1, 1 );
00394 buttonLayout->setSpacing( 1 );
00395 setMinimumSize( 180, 180 );
00396
00397 m_isSticky = false;
00398 setFocusPolicy( Qt::StrongFocus );
00399
00400 connect( m_close, SIGNAL( clicked() ), this, SIGNAL( wantsToBeClosed() ) );
00401 connect( m_sticky, SIGNAL( toggled( bool ) ), this, SLOT( setSticky( bool ) ) );
00402 connect( m_helpViewer, SIGNAL( linkClicked( const QString& ) ), this, SIGNAL( linkClicked( const QString& ) ) );
00403 }
00404
00405 KoContextHelpPopup::~KoContextHelpPopup()
00406 {
00407 }
00408
00409 void KoContextHelpPopup::setContextHelp( const QString& title, const QString& text, const QPixmap* icon )
00410 {
00411 m_helpIcon->setPixmap( icon ? *icon : BarIcon( "help" ) );
00412 m_helpTitle->setText( title );
00413 m_helpViewer->setText( text );
00414 }
00415
00416 void KoContextHelpPopup::mousePressEvent( QMouseEvent* e )
00417 {
00418 m_mousePos = e->globalPos() - pos();
00419 }
00420
00421 void KoContextHelpPopup::mouseMoveEvent( QMouseEvent* e )
00422 {
00423 move( e->globalPos() - m_mousePos );
00424 }
00425
00426 void KoContextHelpPopup::resizeEvent( QResizeEvent* )
00427 {
00428 QBitmap mask( width(), height() );
00429 QPolygon a;
00430 QPainter p( &mask );
00431 p.fillRect( 0, 0, width(), height(), Qt::color1 );
00432 p.setPen( Qt::color0 );
00433 p.setBrush( Qt::color0 );
00434 p.drawLine( 0, 0, 0, 3 );
00435 p.drawLine( 0, 0, 3, 0 );
00436 p.drawPoint( 1, 1 );
00437 a.setPoints( 3, 0, height() - 5, 4, height() - 1, 0, height() - 1 );
00438 p.drawPolygon( a );
00439 a.setPoints( 3, width() - 5, 0, width() - 1, 4, width() - 1, 0 );
00440 p.drawPolygon( a );
00441 p.drawLine( width() - 1, height() - 1, width() - 4, height() - 1 );
00442 p.drawLine( width() - 1, height() - 1, width() - 1, height() - 4 );
00443 p.drawPoint( width() - 2, height() - 2 );
00444 p.drawPoint( 0, height() - 6 );
00445 p.drawPoint( width() - 6, 0 );
00446 p.drawPoint( width() - 5, height() - 3 );
00447 p.drawPoint( width() - 3, height() - 5 );
00448 p.setPen( Qt::NoPen );
00449 p.setBrush( QBrush( Qt::color0, Qt::Dense4Pattern ) );
00450 p.drawRect( 0, height() - 2, width() - 1, height() - 1 );
00451 p.drawRect( width() - 2, 0, width() - 1, height() - 1 );
00452 p.drawRect( width() - 4, height() - 4, width() - 2, height() - 2 );
00453 p.end();
00454 setMask( QRegion( mask ) );
00455 }
00456
00457 void KoContextHelpPopup::paintEvent( QPaintEvent* )
00458 {
00459 QPainter p( this );
00460 p.fillRect( 0, 0, width(), height(), palette().light() );
00461 p.setPen( Qt::black );
00462 p.drawRect( 0, 0, width(), height() );
00463 p.fillRect( width() - 3, 0, width() - 1, height() - 1, Qt::black );
00464 p.fillRect( 0, height() - 3, width() - 1, height() - 1, Qt::black );
00465 p.drawLine( 1, 2, 1, 3 );
00466 p.drawLine( 2, 1, 3, 1 );
00467 p.drawLine( width() - 4, 2, width() - 4, 3 );
00468 p.drawLine( width() - 5, 1, width() - 6, 1 );
00469 p.drawLine( 1, height() - 5, 1, height() - 6 );
00470 p.drawLine( 2, height() - 4, 3, height() - 4 );
00471 p.drawLine( width() - 4, height() - 5, width() - 4, height() - 6 );
00472 p.drawLine( width() - 4, height() - 4, width() - 6, height() - 4 );
00473 }
00474
00475 void KoContextHelpPopup::windowActivationChange( bool )
00476 {
00477 if ( !isActiveWindow() && !m_isSticky )
00478 emit wantsToBeClosed();
00479 }
00480
00481 void KoContextHelpPopup::keyPressEvent( QKeyEvent* e )
00482 {
00483 switch ( e->key() )
00484 {
00485
00486
00487
00488
00489
00490
00491
00492 case Qt::Key_Up:
00493 m_helpViewer->scrollUp();
00494 break;
00495
00496 case Qt::Key_Down:
00497 m_helpViewer->scrollDown();
00498 break;
00499 }
00500 }
00501
00502 void KoContextHelpPopup::keyReleaseEvent( QKeyEvent* e )
00503 {
00504 switch ( e->key() )
00505 {
00506
00507
00508
00509
00510
00511 case Qt::Key_Escape:
00512 emit wantsToBeClosed();
00513 break;
00514 }
00515 }
00516
00517 KoContextHelpAction::KoContextHelpAction( KActionCollection* parent, QWidget* )
00518 : KToggleAction( KIcon(BarIcon("help")), i18n("Context Help"), parent, "help_context" )
00519 {
00520 setShortcut(KShortcut("CTRL+Qt::SHIFT+F1"));
00521
00522 m_popup = new KoContextHelpPopup( 0L );
00523 connect( m_popup, SIGNAL( wantsToBeClosed() ), this, SLOT( closePopup() ) );
00524 connect( this, SIGNAL( toggled( bool ) ), m_popup, SLOT( setShown( bool ) ) );
00525 connect( m_popup, SIGNAL( linkClicked( const QString& ) ), this, SIGNAL( linkClicked( const QString& ) ) );
00526 }
00527
00528 KoContextHelpAction::~KoContextHelpAction()
00529 {
00530 delete m_popup;
00531 }
00532
00533 void KoContextHelpAction::updateHelp( const QString& title, const QString& text, const QPixmap* icon )
00534 {
00535 m_popup->setContextHelp( title, text, icon );
00536 }
00537
00538 void KoContextHelpAction::closePopup()
00539 {
00540 activate(Trigger);
00541 setChecked( false );
00542 }
00543
00544
00545 KoContextHelpWidget::KoContextHelpWidget( QWidget* parent, const char* )
00546 : QWidget( parent )
00547 {
00548 setWindowTitle( i18n( "Context Help" ) );
00549 QGridLayout* layout = new QGridLayout( this );
00550 layout->addWidget( m_helpIcon = new QLabel( this ), 0, 0 );
00551 layout->addWidget( m_helpTitle = new KoVerticalLabel( this ), 1, 0 );
00552 layout->addWidget( m_helpViewer = new KoHelpWidget( "", this ), 0, 1, 2, 1 );
00553 layout->setMargin( 2 );
00554 layout->setSpacing( 1 );
00555 layout->setRowStretch( 1, 1 );
00556 this->setMinimumSize( 180, 120 );
00557 this->show();
00558 setContextHelp( i18n( "Context Help" ), i18n( "Here will be shown help according to your actions" ), 0 );
00559 connect( m_helpViewer, SIGNAL( linkClicked( const QString& ) ), this, SIGNAL( linkClicked( const QString& ) ) );
00560 }
00561
00562 KoContextHelpWidget::~KoContextHelpWidget()
00563 {
00564 }
00565
00566 void KoContextHelpWidget::setContextHelp( const QString& title, const QString& text, const QPixmap* icon )
00567 {
00568 m_helpIcon->setPixmap( icon ? *icon : BarIcon( "help" ) );
00569 m_helpTitle->setText( title );
00570 m_helpViewer->setText( text );
00571 }
00572
00573
00574 KoContextHelpDocker::KoContextHelpDocker( QWidget* parent, const char* name )
00575 : Q3DockWindow( parent, name )
00576 {
00577 setWindowTitle( i18n( "Context Help" ) );
00578 QWidget* mainWidget = new QWidget( this );
00579 QGridLayout* layout = new QGridLayout( mainWidget );
00580 layout->addWidget( m_helpIcon = new QLabel( mainWidget ), 0, 0 );
00581 layout->addWidget( m_helpTitle = new KoVerticalLabel( mainWidget ), 1, 0 );
00582 layout->addWidget( m_helpViewer = new KoHelpWidget( "", mainWidget ), 0, 1, 2, 1 );
00583 layout->setMargin( 2 );
00584 layout->setSpacing( 1 );
00585 layout->setRowStretch( 1, 1 );
00586 mainWidget->setMinimumSize( 180, 120 );
00587 mainWidget->show();
00588 setWidget( mainWidget );
00589 setContextHelp( i18n( "Context Help" ), i18n( "Here will be shown help according to your actions" ), 0 );
00590 connect( m_helpViewer, SIGNAL( linkClicked( const QString& ) ), this, SIGNAL( linkClicked( const QString& ) ) );
00591 }
00592
00593 KoContextHelpDocker::~KoContextHelpDocker()
00594 {
00595 }
00596
00597 void KoContextHelpDocker::setContextHelp( const QString& title, const QString& text, const QPixmap* icon )
00598 {
00599 m_helpIcon->setPixmap( icon ? *icon : BarIcon( "help" ) );
00600 m_helpTitle->setText( title );
00601 m_helpViewer->setText( text );
00602 }
00603
00604 #include "KoContextHelp.moc"