00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021 #include "kateviewhelpers.h"
00022 #include "kateviewhelpers.moc"
00023
00024 #include "kateview.h"
00025 #include "kateviewinternal.h"
00026 #include "katedocument.h"
00027 #include "katecodefoldinghelpers.h"
00028 #include "katerenderer.h"
00029 #include "kateattribute.h"
00030 #include "kateconfig.h"
00031
00032 #include <kglobalsettings.h>
00033 #include <klocale.h>
00034
00035 #include <qpainter.h>
00036 #include <qpopupmenu.h>
00037 #include <qcursor.h>
00038 #include <qstyle.h>
00039 #include <qtimer.h>
00040
00041 #include <math.h>
00042
00043 #include "kateview.h"
00044 #include "katefactory.h"
00045
00046 #include "../interfaces/katecmd.h"
00047 #include "../interfaces/document.h"
00048
00049 #include <klocale.h>
00050
00051 #include <qtimer.h>
00052
00053 #include <kdebug.h>
00054
00055 KateCmdLine::KateCmdLine (KateView *view)
00056 : KLineEdit (view)
00057 , m_view (view)
00058 , m_msgMode (false)
00059 {
00060 connect (this, SIGNAL(returnPressed(const QString &)),
00061 this, SLOT(slotReturnPressed(const QString &)));
00062
00063 completionObject()->insertItems (KateCmd::self()->cmds());
00064 }
00065
00066 void KateCmdLine::slotReturnPressed ( const QString& cmd )
00067 {
00068 if (cmd.length () > 0)
00069 {
00070 Kate::Command *p = KateCmd::self()->queryCommand (cmd);
00071
00072 m_oldText = cmd;
00073 m_msgMode = true;
00074
00075 if (p)
00076 {
00077 QString msg;
00078
00079 if (p->exec (m_view, cmd, msg))
00080 {
00081 completionObject()->addItem (cmd);
00082 m_oldText = QString ();
00083
00084 if (msg.length() > 0)
00085 setText (i18n ("Success: ") + msg);
00086 else
00087 setText (i18n ("Success"));
00088 }
00089 else
00090 {
00091 if (msg.length() > 0)
00092 setText (i18n ("Error: ") + msg);
00093 else
00094 setText (i18n ("Command \"%1\" failed.").arg (cmd));
00095 }
00096 }
00097 else
00098 setText (i18n ("No such command: \"%1\"").arg (cmd));
00099 }
00100
00101 m_view->setFocus ();
00102 QTimer::singleShot( 4000, this, SLOT(hideMe()) );
00103 }
00104
00105 void KateCmdLine::hideMe ()
00106 {
00107 if (isVisibleTo(parentWidget())) {
00108 m_view->toggleCmdLine ();
00109 }
00110
00111 }
00112
00113 void KateCmdLine::focusInEvent ( QFocusEvent *ev )
00114 {
00115 if (m_msgMode)
00116 {
00117 m_msgMode = false;
00118 setText (m_oldText);
00119 }
00120
00121 KLineEdit::focusInEvent (ev);
00122 }
00123
00124 void KateCmdLine::keyPressEvent( QKeyEvent *ev )
00125 {
00126 if (ev->key() == Key_Escape)
00127 {
00128 m_view->setFocus ();
00129 hideMe();
00130
00131 }
00132
00133 return KLineEdit::keyPressEvent (ev);
00134 }
00135
00136 using namespace KTextEditor;
00137
00138 static const char* const plus_xpm[] = {
00139 "11 11 3 1",
00140 " c None",
00141 ". c #000000",
00142 "+ c #FFFFFF",
00143 "...........",
00144 ".+++++++++.",
00145 ".+++++++++.",
00146 ".++++.++++.",
00147 ".++++.++++.",
00148 ".++.....++.",
00149 ".++++.++++.",
00150 ".++++.++++.",
00151 ".+++++++++.",
00152 ".+++++++++.",
00153 "..........."};
00154
00155 static const char* const minus_xpm[] = {
00156 "11 11 3 1",
00157 " c None",
00158 ". c #000000",
00159 "+ c #FFFFFF",
00160 "...........",
00161 ".+++++++++.",
00162 ".+++++++++.",
00163 ".+++++++++.",
00164 ".+++++++++.",
00165 ".++.....++.",
00166 ".+++++++++.",
00167 ".+++++++++.",
00168 ".+++++++++.",
00169 ".+++++++++.",
00170 "..........."};
00171
00172
00173 static const char* const bookmark_xpm[]={
00174 "12 12 4 1",
00175 "b c #808080",
00176 "a c #000080",
00177 "# c #0000ff",
00178 ". c None",
00179 "........###.",
00180 ".......#...a",
00181 "......#.##.a",
00182 ".....#.#..aa",
00183 "....#.#...a.",
00184 "...#.#.a.a..",
00185 "..#.#.a.a...",
00186 ".#.#.a.a....",
00187 "#.#.a.a.....",
00188 "#.#a.a...bbb",
00189 "#...a..bbb..",
00190 ".aaa.bbb...."};
00191
00192 const int iconPaneWidth = 16;
00193 const int halfIPW = 8;
00194
00195 static QPixmap minus_px ((const char**)minus_xpm);
00196 static QPixmap plus_px ((const char**)plus_xpm);
00197
00198 KateIconBorder::KateIconBorder ( KateViewInternal* internalView, QWidget *parent )
00199 : QWidget(parent, "", Qt::WStaticContents | Qt::WRepaintNoErase | Qt::WResizeNoErase )
00200 , m_view( internalView->m_view )
00201 , m_doc( internalView->m_doc )
00202 , m_viewInternal( internalView )
00203 , m_iconBorderOn( false )
00204 , m_lineNumbersOn( false )
00205 , m_foldingMarkersOn( false )
00206 , m_dynWrapIndicatorsOn( false )
00207 , m_dynWrapIndicators( 0 )
00208 , m_cachedLNWidth( 0 )
00209 , m_maxCharWidth( 0 )
00210 {
00211 setSizePolicy( QSizePolicy( QSizePolicy::Fixed, QSizePolicy::Minimum ) );
00212
00213 setBackgroundMode( NoBackground );
00214
00215 m_doc->setDescription( MarkInterface::markType01, i18n("Bookmark") );
00216 m_doc->setPixmap( MarkInterface::markType01, QPixmap((const char**)bookmark_xpm) );
00217
00218 updateFont();
00219 }
00220
00221 void KateIconBorder::setIconBorderOn( bool enable )
00222 {
00223 if( enable == m_iconBorderOn )
00224 return;
00225
00226 m_iconBorderOn = enable;
00227
00228 updateGeometry();
00229
00230 QTimer::singleShot( 0, this, SLOT(update()) );
00231 }
00232
00233 void KateIconBorder::setLineNumbersOn( bool enable )
00234 {
00235 if( enable == m_lineNumbersOn )
00236 return;
00237
00238 m_lineNumbersOn = enable;
00239 m_dynWrapIndicatorsOn = (m_dynWrapIndicators == 1) ? enable : m_dynWrapIndicators;
00240
00241 updateGeometry();
00242
00243 QTimer::singleShot( 0, this, SLOT(update()) );
00244 }
00245
00246 void KateIconBorder::setDynWrapIndicators( int state )
00247 {
00248 if (state == m_dynWrapIndicators )
00249 return;
00250
00251 m_dynWrapIndicators = state;
00252 m_dynWrapIndicatorsOn = (state == 1) ? m_lineNumbersOn : state;
00253
00254 updateGeometry ();
00255
00256 QTimer::singleShot( 0, this, SLOT(update()) );
00257 }
00258
00259 void KateIconBorder::setFoldingMarkersOn( bool enable )
00260 {
00261 if( enable == m_foldingMarkersOn )
00262 return;
00263
00264 m_foldingMarkersOn = enable;
00265
00266 updateGeometry();
00267
00268 QTimer::singleShot( 0, this, SLOT(update()) );
00269 }
00270
00271 QSize KateIconBorder::sizeHint() const
00272 {
00273 int w = 0;
00274
00275 if (m_iconBorderOn)
00276 w += iconPaneWidth + 1;
00277
00278 if (m_lineNumbersOn || (m_view->dynWordWrap() && m_dynWrapIndicatorsOn)) {
00279 w += lineNumberWidth();
00280 }
00281
00282 if (m_foldingMarkersOn)
00283 w += iconPaneWidth;
00284
00285 w += 4;
00286
00287 return QSize( w, 0 );
00288 }
00289
00290
00291
00292 void KateIconBorder::updateFont()
00293 {
00294 const QFontMetrics *fm = m_view->renderer()->config()->fontMetrics();
00295 m_maxCharWidth = 0;
00296
00297
00298 for (int i = 48; i < 58; i++) {
00299 int charWidth = fm->width( QChar(i) );
00300 m_maxCharWidth = QMAX(m_maxCharWidth, charWidth);
00301 }
00302 }
00303
00304 int KateIconBorder::lineNumberWidth() const
00305 {
00306 int width = m_lineNumbersOn ? ((int)log10((double)(m_view->doc()->numLines())) + 1) * m_maxCharWidth + 4 : 0;
00307
00308 if (m_view->dynWordWrap() && m_dynWrapIndicatorsOn) {
00309 width = QMAX(style().scrollBarExtent().width() + 4, width);
00310
00311 if (m_cachedLNWidth != width || m_oldBackgroundColor != m_view->renderer()->config()->iconBarColor()) {
00312 int w = style().scrollBarExtent().width();
00313 int h = m_view->renderer()->config()->fontMetrics()->height();
00314
00315 QSize newSize(w, h);
00316 if ((m_arrow.size() != newSize || m_oldBackgroundColor != m_view->renderer()->config()->iconBarColor()) && !newSize.isEmpty()) {
00317 m_arrow.resize(newSize);
00318
00319 QPainter p(&m_arrow);
00320 p.fillRect( 0, 0, w, h, m_view->renderer()->config()->iconBarColor() );
00321
00322 h = m_view->renderer()->config()->fontMetrics()->ascent();
00323
00324 p.setPen(m_view->renderer()->attribute(0)->textColor());
00325 p.drawLine(w/2, h/2, w/2, 0);
00326 #if 1
00327 p.lineTo(w/4, h/4);
00328 p.lineTo(0, 0);
00329 p.lineTo(0, h/2);
00330 p.lineTo(w/2, h-1);
00331 p.lineTo(w*3/4, h-1);
00332 p.lineTo(w-1, h*3/4);
00333 p.lineTo(w*3/4, h/2);
00334 p.lineTo(0, h/2);
00335 #else
00336 p.lineTo(w*3/4, h/4);
00337 p.lineTo(w-1,0);
00338 p.lineTo(w-1, h/2);
00339 p.lineTo(w/2, h-1);
00340 p.lineTo(w/4,h-1);
00341 p.lineTo(0, h*3/4);
00342 p.lineTo(w/4, h/2);
00343 p.lineTo(w-1, h/2);
00344 #endif
00345 }
00346 }
00347 }
00348
00349 return width;
00350 }
00351
00352 void KateIconBorder::paintEvent(QPaintEvent* e)
00353 {
00354 paintBorder(e->rect().x(), e->rect().y(), e->rect().width(), e->rect().height());
00355 }
00356
00357 void KateIconBorder::paintBorder (int , int y, int , int height)
00358 {
00359 uint h = m_view->renderer()->config()->fontStruct()->fontHeight;
00360 uint startz = (y / h);
00361 uint endz = startz + 1 + (height / h);
00362 uint lineRangesSize = m_viewInternal->lineRanges.size();
00363
00364
00365 int m_px = (h - 11) / 2;
00366 if (m_px < 0)
00367 m_px = 0;
00368
00369 int lnWidth( 0 );
00370 if ( m_lineNumbersOn || (m_view->dynWordWrap() && m_dynWrapIndicatorsOn) )
00371 {
00372 lnWidth = lineNumberWidth();
00373 if ( lnWidth != m_cachedLNWidth || m_oldBackgroundColor != m_view->renderer()->config()->iconBarColor() )
00374 {
00375
00376
00377
00378
00379 m_cachedLNWidth = lnWidth;
00380 m_oldBackgroundColor = m_view->renderer()->config()->iconBarColor();
00381 updateGeometry();
00382 update ();
00383 return;
00384 }
00385 }
00386
00387 int w( this->width() );
00388
00389 QPainter p ( this );
00390 p.setFont ( *m_view->renderer()->config()->font() );
00391
00392
00393 p.setPen ( m_view->renderer()->config()->lineNumberColor() );
00394
00395 KateLineInfo oldInfo;
00396 if (startz < lineRangesSize)
00397 {
00398 if ((m_viewInternal->lineRanges[startz].line-1) < 0)
00399 oldInfo.topLevel = true;
00400 else
00401 m_doc->lineInfo(&oldInfo,m_viewInternal->lineRanges[startz].line-1);
00402 }
00403
00404 for (uint z=startz; z <= endz; z++)
00405 {
00406 int y = h * z;
00407 int realLine = -1;
00408
00409 if (z < lineRangesSize)
00410 realLine = m_viewInternal->lineRanges[z].line;
00411
00412 int lnX ( 0 );
00413
00414 p.fillRect( 0, y, w-4, h, m_view->renderer()->config()->iconBarColor() );
00415 p.fillRect( w-4, y, 4, h, m_view->renderer()->config()->backgroundColor() );
00416
00417
00418 if( m_iconBorderOn )
00419 {
00420 p.drawLine(lnX+iconPaneWidth, y, lnX+iconPaneWidth, y+h);
00421
00422 if( (realLine > -1) && (m_viewInternal->lineRanges[z].startCol == 0) )
00423 {
00424 uint mrk ( m_doc->mark( realLine ) );
00425
00426 if ( mrk )
00427 {
00428 for( uint bit = 0; bit < 32; bit++ )
00429 {
00430 MarkInterface::MarkTypes markType = (MarkInterface::MarkTypes)(1<<bit);
00431 if( mrk & markType )
00432 {
00433 QPixmap *px_mark (m_doc->markPixmap( markType ));
00434
00435 if (px_mark)
00436 {
00437
00438 int x_px = (iconPaneWidth - px_mark->width()) / 2;
00439 if (x_px < 0)
00440 x_px = 0;
00441
00442 int y_px = (h - px_mark->height()) / 2;
00443 if (y_px < 0)
00444 y_px = 0;
00445
00446 p.drawPixmap( lnX+x_px, y+y_px, *px_mark);
00447 }
00448 }
00449 }
00450 }
00451 }
00452
00453 lnX += iconPaneWidth + 1;
00454 }
00455
00456
00457 if( m_lineNumbersOn || (m_view->dynWordWrap() && m_dynWrapIndicatorsOn) )
00458 {
00459 lnX +=2;
00460
00461 if (realLine > -1)
00462 if (m_viewInternal->lineRanges[z].startCol == 0) {
00463 if (m_lineNumbersOn)
00464 p.drawText( lnX + 1, y, lnWidth-4, h, Qt::AlignRight|Qt::AlignVCenter, QString("%1").arg( realLine + 1 ) );
00465 } else if (m_view->dynWordWrap() && m_dynWrapIndicatorsOn) {
00466 p.drawPixmap(lnX + lnWidth - m_arrow.width() - 4, y, m_arrow);
00467 }
00468
00469 lnX += lnWidth;
00470 }
00471
00472
00473 if( m_foldingMarkersOn )
00474 {
00475 if( realLine > -1 )
00476 {
00477 KateLineInfo info;
00478 m_doc->lineInfo(&info,realLine);
00479
00480 if (!info.topLevel)
00481 {
00482 if (info.startsVisibleBlock && (m_viewInternal->lineRanges[z].startCol == 0))
00483 {
00484 if (oldInfo.topLevel)
00485 p.drawLine(lnX+halfIPW,y+m_px,lnX+halfIPW,y+h-1);
00486 else
00487 p.drawLine(lnX+halfIPW,y,lnX+halfIPW,y+h-1);
00488
00489 p.drawPixmap(lnX+3,y+m_px,minus_px);
00490 }
00491 else if (info.startsInVisibleBlock)
00492 {
00493 if (m_viewInternal->lineRanges[z].startCol == 0)
00494 {
00495 if (oldInfo.topLevel)
00496 p.drawLine(lnX+halfIPW,y+m_px,lnX+halfIPW,y+h-1);
00497 else
00498 p.drawLine(lnX+halfIPW,y,lnX+halfIPW,y+h-1);
00499
00500 p.drawPixmap(lnX+3,y+m_px,plus_px);
00501 }
00502 else
00503 {
00504 p.drawLine(lnX+halfIPW,y,lnX+halfIPW,y+h-1);
00505 }
00506
00507 if (!m_viewInternal->lineRanges[z].wrap)
00508 p.drawLine(lnX+halfIPW,y+h-1,lnX+iconPaneWidth-2,y+h-1);
00509 }
00510 else
00511 {
00512 p.drawLine(lnX+halfIPW,y,lnX+halfIPW,y+h-1);
00513
00514 if (info.endsBlock && !m_viewInternal->lineRanges[z].wrap)
00515 p.drawLine(lnX+halfIPW,y+h-1,lnX+iconPaneWidth-2,y+h-1);
00516 }
00517 }
00518
00519 oldInfo = info;
00520 }
00521
00522 lnX += iconPaneWidth;
00523 }
00524 }
00525 }
00526
00527 KateIconBorder::BorderArea KateIconBorder::positionToArea( const QPoint& p ) const
00528 {
00529 int x = 0;
00530 if( m_iconBorderOn ) {
00531 x += iconPaneWidth;
00532 if( p.x() <= x )
00533 return IconBorder;
00534 }
00535 if( m_lineNumbersOn || m_dynWrapIndicators ) {
00536 x += lineNumberWidth();
00537 if( p.x() <= x )
00538 return LineNumbers;
00539 }
00540 if( m_foldingMarkersOn ) {
00541 x += iconPaneWidth;
00542 if( p.x() <= x )
00543 return FoldingMarkers;
00544 }
00545 return None;
00546 }
00547
00548 void KateIconBorder::mousePressEvent( QMouseEvent* e )
00549 {
00550 m_lastClickedLine = m_viewInternal->yToKateLineRange(e->y()).line;
00551
00552 if ( positionToArea( e->pos() ) != IconBorder )
00553 {
00554 QMouseEvent forward( QEvent::MouseButtonPress,
00555 QPoint( 0, e->y() ), e->button(), e->state() );
00556 m_viewInternal->mousePressEvent( &forward );
00557 }
00558 e->accept();
00559 }
00560
00561 void KateIconBorder::mouseMoveEvent( QMouseEvent* e )
00562 {
00563 if ( positionToArea( e->pos() ) != IconBorder )
00564 {
00565 QMouseEvent forward( QEvent::MouseMove,
00566 QPoint( 0, e->y() ), e->button(), e->state() );
00567 m_viewInternal->mouseMoveEvent( &forward );
00568 }
00569 }
00570
00571 void KateIconBorder::mouseReleaseEvent( QMouseEvent* e )
00572 {
00573 uint cursorOnLine = m_viewInternal->yToKateLineRange(e->y()).line;
00574
00575 if (cursorOnLine == m_lastClickedLine &&
00576 cursorOnLine <= m_doc->lastLine() )
00577 {
00578 BorderArea area = positionToArea( e->pos() );
00579 if( area == IconBorder) {
00580 if (e->button() == LeftButton) {
00581 if( m_doc->editableMarks() & KateViewConfig::global()->defaultMarkType() ) {
00582 if( m_doc->mark( cursorOnLine ) & KateViewConfig::global()->defaultMarkType() )
00583 m_doc->removeMark( cursorOnLine, KateViewConfig::global()->defaultMarkType() );
00584 else
00585 m_doc->addMark( cursorOnLine, KateViewConfig::global()->defaultMarkType() );
00586 } else {
00587 showMarkMenu( cursorOnLine, QCursor::pos() );
00588 }
00589 }
00590 else
00591 if (e->button() == RightButton) {
00592 showMarkMenu( cursorOnLine, QCursor::pos() );
00593 }
00594 }
00595
00596 if ( area == FoldingMarkers) {
00597 KateLineInfo info;
00598 m_doc->lineInfo(&info,cursorOnLine);
00599 if ((info.startsVisibleBlock) || (info.startsInVisibleBlock)) {
00600 emit toggleRegionVisibility(cursorOnLine);
00601 }
00602 }
00603 }
00604
00605 QMouseEvent forward( QEvent::MouseButtonRelease,
00606 QPoint( 0, e->y() ), e->button(), e->state() );
00607 m_viewInternal->mouseReleaseEvent( &forward );
00608 }
00609
00610 void KateIconBorder::mouseDoubleClickEvent( QMouseEvent* e )
00611 {
00612 QMouseEvent forward( QEvent::MouseButtonDblClick,
00613 QPoint( 0, e->y() ), e->button(), e->state() );
00614 m_viewInternal->mouseDoubleClickEvent( &forward );
00615 }
00616
00617 void KateIconBorder::showMarkMenu( uint line, const QPoint& pos )
00618 {
00619 QPopupMenu markMenu;
00620 QPopupMenu selectDefaultMark;
00621
00622 typedef QValueVector<int> MarkTypeVector;
00623 MarkTypeVector vec( 33 );
00624 int i=1;
00625
00626 for( uint bit = 0; bit < 32; bit++ ) {
00627 MarkInterface::MarkTypes markType = (MarkInterface::MarkTypes)(1<<bit);
00628 if( !(m_doc->editableMarks() & markType) )
00629 continue;
00630
00631 if( !m_doc->markDescription( markType ).isEmpty() ) {
00632 markMenu.insertItem( m_doc->markDescription( markType ), i );
00633 selectDefaultMark.insertItem( m_doc->markDescription( markType ), i+100);
00634 } else {
00635 markMenu.insertItem( i18n("Mark Type %1").arg( bit + 1 ), i );
00636 selectDefaultMark.insertItem( i18n("Mark Type %1").arg( bit + 1 ), i+100);
00637 }
00638
00639 if( m_doc->mark( line ) & markType )
00640 markMenu.setItemChecked( i, true );
00641
00642 if( markType & KateViewConfig::global()->defaultMarkType() )
00643 selectDefaultMark.setItemChecked( i+100, true );
00644
00645 vec[i++] = markType;
00646 }
00647
00648 if( markMenu.count() == 0 )
00649 return;
00650
00651 if( markMenu.count() > 1 )
00652 markMenu.insertItem( i18n("Set Default Mark Type" ), &selectDefaultMark);
00653
00654 int result = markMenu.exec( pos );
00655 if( result <= 0 )
00656 return;
00657
00658 if ( result > 100)
00659 KateViewConfig::global()->setDefaultMarkType (vec[result-100]);
00660 else
00661 {
00662 MarkInterface::MarkTypes markType = (MarkInterface::MarkTypes) vec[result];
00663 if( m_doc->mark( line ) & markType ) {
00664 m_doc->removeMark( line, markType );
00665 } else {
00666 m_doc->addMark( line, markType );
00667 }
00668 }
00669 }
00670
00671