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