00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024 #include "TerminalDisplay.h"
00025
00026
00027 #include <QtGui/QApplication>
00028 #include <QtGui/QBoxLayout>
00029 #include <QtGui/QClipboard>
00030 #include <QtGui/QKeyEvent>
00031 #include <QtCore/QEvent>
00032 #include <QtCore/QTime>
00033 #include <QtCore/QFile>
00034 #include <QtGui/QGridLayout>
00035 #include <QtGui/QLabel>
00036 #include <QtGui/QLayout>
00037 #include <QtGui/QPainter>
00038 #include <QtGui/QPixmap>
00039 #include <QtGui/QScrollBar>
00040 #include <QtGui/QStyle>
00041 #include <QtCore/QTimer>
00042 #include <QtGui/QToolTip>
00043
00044
00045 #include <kshell.h>
00046 #include <KColorScheme>
00047 #include <KCursor>
00048 #include <kdebug.h>
00049 #include <KLocale>
00050 #include <KMenu>
00051 #include <KNotification>
00052 #include <KGlobalSettings>
00053 #include <KShortcut>
00054 #include <KIO/NetAccess>
00055
00056
00057 #include <config-apps.h>
00058 #include "Filter.h"
00059 #include "konsole_wcwidth.h"
00060 #include "ScreenWindow.h"
00061 #include "TerminalCharacterDecoder.h"
00062
00063 using namespace Konsole;
00064
00065 #ifndef loc
00066 #define loc(X,Y) ((Y)*_columns+(X))
00067 #endif
00068
00069 #define yMouseScroll 1
00070
00071 #define REPCHAR "ABCDEFGHIJKLMNOPQRSTUVWXYZ" \
00072 "abcdefgjijklmnopqrstuvwxyz" \
00073 "0123456789./+@"
const ColorEntry Konsole::base_color_table[TABLE_COLORS] =
// The following are almost IBM standard color codes, with some slight
// gamma correction for the dim colors to compensate for bright X screens.
// It contains the 8 ansiterm/xterm colors in 2 intensities.
{
// Fixme: could add faint colors here, also.
// normal
ColorEntry(QColor(0x00,0x00,0x00), 0, 0 ), ColorEntry( QColor(0xB2,0xB2,0xB2), 1, 0 ), // Dfore, Dback
ColorEntry(QColor(0x00,0x00,0x00), 0, 0 ), ColorEntry( QColor(0xB2,0x18,0x18), 0, 0 ), // Black, Red
ColorEntry(QColor(0x18,0xB2,0x18), 0, 0 ), ColorEntry( QColor(0xB2,0x68,0x18), 0, 0 ), // Green, Yellow
ColorEntry(QColor(0x18,0x18,0xB2), 0, 0 ), ColorEntry( QColor(0xB2,0x18,0xB2), 0, 0 ), // Blue, Magenta
ColorEntry(QColor(0x18,0xB2,0xB2), 0, 0 ), ColorEntry( QColor(0xB2,0xB2,0xB2), 0, 0 ), // Cyan, White
// intensiv
ColorEntry(QColor(0x00,0x00,0x00), 0, 1 ), ColorEntry( QColor(0xFF,0xFF,0xFF), 1, 0 ),
ColorEntry(QColor(0x68,0x68,0x68), 0, 0 ), ColorEntry( QColor(0xFF,0x54,0x54), 0, 0 ),
ColorEntry(QColor(0x54,0xFF,0x54), 0, 0 ), ColorEntry( QColor(0xFF,0xFF,0x54), 0, 0 ),
ColorEntry(QColor(0x54,0x54,0xFF), 0, 0 ), ColorEntry( QColor(0xFF,0x54,0xFF), 0, 0 ),
ColorEntry(QColor(0x54,0xFF,0xFF), 0, 0 ), ColorEntry( QColor(0xFF,0xFF,0xFF), 0, 0 )
};
// scroll increment used when dragging selection at top/bottom of window.
// static
bool TerminalDisplay::_antialiasText = true;
bool TerminalDisplay::HAVE_TRANSPARENCY = false;
// we use this to force QPainter to display text in LTR mode
// more information can be found in: http://unicode.org/reports/tr9/
const QChar LTR_OVERRIDE_CHAR( 0x202D );
/* ------------------------------------------------------------------------- */
/* */
/* Colors */
/* */
/* ------------------------------------------------------------------------- */
/* Note that we use ANSI color order (bgr), while IBMPC color order is (rgb)
Code 0 1 2 3 4 5 6 7
----------- ------- ------- ------- ------- ------- ------- ------- -------
ANSI (bgr) Black Red Green Yellow Blue Magenta Cyan White
IBMPC (rgb) Black Blue Green Cyan Red Magenta Yellow White
*/
ScreenWindow* TerminalDisplay::screenWindow() const
{
return _screenWindow;
}
void TerminalDisplay::setScreenWindow(ScreenWindow* window)
{
// disconnect existing screen window if any
if ( _screenWindow )
{
disconnect( _screenWindow , 0 , this , 0 );
}
_screenWindow = window;
if ( window )
{
#warning "The order here is not specified - does it matter whether updateImage or updateLineProperties comes first?"
00074 connect( _screenWindow , SIGNAL(outputChanged()) , this , SLOT(updateLineProperties()) );
00075 connect( _screenWindow , SIGNAL(outputChanged()) , this , SLOT(updateImage()) );
00076 window->setWindowLines(_lines);
00077 }
00078 }
00079
00080 const ColorEntry* TerminalDisplay::colorTable() const
00081 {
00082 return _colorTable;
00083 }
00084 void TerminalDisplay::setBackgroundColor(const QColor& color)
00085 {
00086 _colorTable[DEFAULT_BACK_COLOR].color = color;
00087 QPalette p = palette();
00088 p.setColor( backgroundRole(), color );
00089 setPalette( p );
00090
00091
00092 _scrollBar->setPalette( QApplication::palette() );
00093
00094 update();
00095 }
00096 void TerminalDisplay::setForegroundColor(const QColor& color)
00097 {
00098 _colorTable[DEFAULT_FORE_COLOR].color = color;
00099
00100 update();
00101 }
00102 void TerminalDisplay::setColorTable(const ColorEntry table[])
00103 {
00104 for (int i = 0; i < TABLE_COLORS; i++)
00105 _colorTable[i] = table[i];
00106
00107 setBackgroundColor(_colorTable[DEFAULT_BACK_COLOR].color);
00108 }
00109
00110
00111
00112
00113
00114
00115
00116
00117
00118
00119
00120
00121
00122
00123
00124
00125
00126
00127
00128 static inline bool isLineChar(quint16 c) { return ((c & 0xFF80) == 0x2500);}
00129 static inline bool isLineCharString(const QString& string)
00130 {
00131 return (string.length() > 0) && (isLineChar(string.at(0).unicode()));
00132 }
00133
00134
00135
00136
00137 unsigned short Konsole::vt100_graphics[32] =
00138 {
00139 0x0020, 0x25C6, 0x2592, 0x2409, 0x240c, 0x240d, 0x240a, 0x00b0,
00140 0x00b1, 0x2424, 0x240b, 0x2518, 0x2510, 0x250c, 0x2514, 0x253c,
00141 0xF800, 0xF801, 0x2500, 0xF803, 0xF804, 0x251c, 0x2524, 0x2534,
00142 0x252c, 0x2502, 0x2264, 0x2265, 0x03C0, 0x2260, 0x00A3, 0x00b7
00143 };
00144
00145 void TerminalDisplay::fontChange(const QFont&)
00146 {
00147 QFontMetrics fm(font());
00148 _fontHeight = fm.height() + _lineSpacing;
00149
00150
00151
00152
00153
00154 _fontWidth = qRound((double)fm.width(REPCHAR)/(double)strlen(REPCHAR));
00155
00156 _fixedFont = true;
00157
00158 int fw = fm.width(REPCHAR[0]);
00159 for(unsigned int i=1; i< strlen(REPCHAR); i++)
00160 {
00161 if (fw != fm.width(REPCHAR[i]))
00162 {
00163 _fixedFont = false;
00164 break;
00165 }
00166 }
00167
00168 if (_fontWidth < 1)
00169 _fontWidth=1;
00170
00171 _fontAscent = fm.ascent();
00172
00173 emit changedFontMetricSignal( _fontHeight, _fontWidth );
00174 propagateSize();
00175 update();
00176 }
00177
00178 void TerminalDisplay::setVTFont(const QFont& f)
00179 {
00180 QFont font = f;
00181
00182 QFontMetrics metrics(font);
00183
00184 if ( !QFontInfo(font).fixedPitch() )
00185 {
00186 kWarning() << "Using an unsupported variable-width font in the terminal. This may produce display errors.";
00187 }
00188
00189 if ( metrics.height() < height() && metrics.maxWidth() < width() )
00190 {
00191
00192
00193 if (!_antialiasText)
00194 font.setStyleStrategy( QFont::NoAntialias );
00195
00196
00197
00198
00199 font.setKerning(false);
00200
00201 QWidget::setFont(font);
00202 fontChange(font);
00203 }
00204 }
00205
00206 void TerminalDisplay::setFont(const QFont &)
00207 {
00208
00209 }
00210
00211
00212
00213
00214
00215
00216
00217 TerminalDisplay::TerminalDisplay(QWidget *parent)
00218 :QWidget(parent)
00219 ,_screenWindow(0)
00220 ,_allowBell(true)
00221 ,_gridLayout(0)
00222 ,_fontHeight(1)
00223 ,_fontWidth(1)
00224 ,_fontAscent(1)
00225 ,_lines(1)
00226 ,_columns(1)
00227 ,_usedLines(1)
00228 ,_usedColumns(1)
00229 ,_contentHeight(1)
00230 ,_contentWidth(1)
00231 ,_image(0)
00232 ,_randomSeed(0)
00233 ,_resizing(false)
00234 ,_terminalSizeHint(false)
00235 ,_terminalSizeStartup(true)
00236 ,_bidiEnabled(false)
00237 ,_actSel(0)
00238 ,_wordSelectionMode(false)
00239 ,_lineSelectionMode(false)
00240 ,_preserveLineBreaks(false)
00241 ,_columnSelectionMode(false)
00242 ,_scrollbarLocation(NoScrollBar)
00243 ,_wordCharacters(":@-./_~")
00244 ,_bellMode(SystemBeepBell)
00245 ,_blinking(false)
00246 ,_hasBlinker(false)
00247 ,_cursorBlinking(false)
00248 ,_hasBlinkingCursor(false)
00249 ,_ctrlDrag(false)
00250 ,_tripleClickMode(SelectWholeLine)
00251 ,_isFixedSize(false)
00252 ,_possibleTripleClick(false)
00253 ,_resizeWidget(0)
00254 ,_resizeTimer(0)
00255 ,_flowControlWarningEnabled(false)
00256 ,_outputSuspendedLabel(0)
00257 ,_lineSpacing(0)
00258 ,_colorsInverted(false)
00259 ,_blendColor(qRgba(0,0,0,0xff))
00260 ,_filterChain(new TerminalImageFilterChain())
00261 ,_cursorShape(BlockCursor)
00262 {
00263
00264
00265 setLayoutDirection(Qt::LeftToRight);
00266
00267
00268
00269
00270 _topMargin = DEFAULT_TOP_MARGIN;
00271 _leftMargin = DEFAULT_LEFT_MARGIN;
00272
00273
00274
00275 _scrollBar = new QScrollBar(this);
00276 setScroll(0,0);
00277 _scrollBar->setCursor( Qt::ArrowCursor );
00278 connect(_scrollBar, SIGNAL(valueChanged(int)), this,
00279 SLOT(scrollBarPositionChanged(int)));
00280
00281
00282 _blinkTimer = new QTimer(this);
00283 connect(_blinkTimer, SIGNAL(timeout()), this, SLOT(blinkEvent()));
00284 _blinkCursorTimer = new QTimer(this);
00285 connect(_blinkCursorTimer, SIGNAL(timeout()), this, SLOT(blinkCursorEvent()));
00286
00287 KCursor::setAutoHideCursor( this, true );
00288
00289 setUsesMouse(true);
00290 setColorTable(base_color_table);
00291 setMouseTracking(true);
00292
00293
00294 setAcceptDrops(true);
00295 dragInfo.state = diNone;
00296
00297 setFocusPolicy( Qt::WheelFocus );
00298
00299
00300 setAttribute(Qt::WA_InputMethodEnabled, true);
00301
00302
00303
00304 setAttribute(Qt::WA_OpaquePaintEvent);
00305
00306 _gridLayout = new QGridLayout(this);
00307 _gridLayout->setMargin(0);
00308
00309 setLayout( _gridLayout );
00310
00311 new AutoScrollHandler(this);
00312 }
00313
00314 TerminalDisplay::~TerminalDisplay()
00315 {
00316 qApp->removeEventFilter( this );
00317
00318 delete[] _image;
00319
00320 delete _gridLayout;
00321 delete _outputSuspendedLabel;
00322 delete _filterChain;
00323 }
00324
00325
00326
00327
00328
00329
00330
00350 enum LineEncode
00351 {
00352 TopL = (1<<1),
00353 TopC = (1<<2),
00354 TopR = (1<<3),
00355
00356 LeftT = (1<<5),
00357 Int11 = (1<<6),
00358 Int12 = (1<<7),
00359 Int13 = (1<<8),
00360 RightT = (1<<9),
00361
00362 LeftC = (1<<10),
00363 Int21 = (1<<11),
00364 Int22 = (1<<12),
00365 Int23 = (1<<13),
00366 RightC = (1<<14),
00367
00368 LeftB = (1<<15),
00369 Int31 = (1<<16),
00370 Int32 = (1<<17),
00371 Int33 = (1<<18),
00372 RightB = (1<<19),
00373
00374 BotL = (1<<21),
00375 BotC = (1<<22),
00376 BotR = (1<<23)
00377 };
00378
00379 #include "LineFont.h"
00380
00381 static void drawLineChar(QPainter& paint, int x, int y, int w, int h, uchar code)
00382 {
00383
00384 int cx = x + w/2;
00385 int cy = y + h/2;
00386 int ex = x + w - 1;
00387 int ey = y + h - 1;
00388
00389 quint32 toDraw = LineChars[code];
00390
00391
00392 if (toDraw & TopL)
00393 paint.drawLine(cx-1, y, cx-1, cy-2);
00394 if (toDraw & TopC)
00395 paint.drawLine(cx, y, cx, cy-2);
00396 if (toDraw & TopR)
00397 paint.drawLine(cx+1, y, cx+1, cy-2);
00398
00399
00400 if (toDraw & BotL)
00401 paint.drawLine(cx-1, cy+2, cx-1, ey);
00402 if (toDraw & BotC)
00403 paint.drawLine(cx, cy+2, cx, ey);
00404 if (toDraw & BotR)
00405 paint.drawLine(cx+1, cy+2, cx+1, ey);
00406
00407
00408 if (toDraw & LeftT)
00409 paint.drawLine(x, cy-1, cx-2, cy-1);
00410 if (toDraw & LeftC)
00411 paint.drawLine(x, cy, cx-2, cy);
00412 if (toDraw & LeftB)
00413 paint.drawLine(x, cy+1, cx-2, cy+1);
00414
00415
00416 if (toDraw & RightT)
00417 paint.drawLine(cx+2, cy-1, ex, cy-1);
00418 if (toDraw & RightC)
00419 paint.drawLine(cx+2, cy, ex, cy);
00420 if (toDraw & RightB)
00421 paint.drawLine(cx+2, cy+1, ex, cy+1);
00422
00423
00424 if (toDraw & Int11)
00425 paint.drawPoint(cx-1, cy-1);
00426 if (toDraw & Int12)
00427 paint.drawPoint(cx, cy-1);
00428 if (toDraw & Int13)
00429 paint.drawPoint(cx+1, cy-1);
00430
00431 if (toDraw & Int21)
00432 paint.drawPoint(cx-1, cy);
00433 if (toDraw & Int22)
00434 paint.drawPoint(cx, cy);
00435 if (toDraw & Int23)
00436 paint.drawPoint(cx+1, cy);
00437
00438 if (toDraw & Int31)
00439 paint.drawPoint(cx-1, cy+1);
00440 if (toDraw & Int32)
00441 paint.drawPoint(cx, cy+1);
00442 if (toDraw & Int33)
00443 paint.drawPoint(cx+1, cy+1);
00444
00445 }
00446
00447 void TerminalDisplay::drawLineCharString( QPainter& painter, int x, int y, const QString& str,
00448 const Character* attributes)
00449 {
00450 const QPen& currentPen = painter.pen();
00451
00452 if ( attributes->rendition & RE_BOLD )
00453 {
00454 QPen boldPen(currentPen);
00455 boldPen.setWidth(3);
00456 painter.setPen( boldPen );
00457 }
00458
00459 for (int i=0 ; i < str.length(); i++)
00460 {
00461 uchar code = str[i].cell();
00462 if (LineChars[code])
00463 drawLineChar(painter, x + (_fontWidth*i), y, _fontWidth, _fontHeight, code);
00464 }
00465
00466 painter.setPen( currentPen );
00467 }
00468
00469 void TerminalDisplay::setKeyboardCursorShape(KeyboardCursorShape shape)
00470 {
00471 _cursorShape = shape;
00472 }
00473 TerminalDisplay::KeyboardCursorShape TerminalDisplay::keyboardCursorShape() const
00474 {
00475 return _cursorShape;
00476 }
00477 void TerminalDisplay::setKeyboardCursorColor(bool useForegroundColor, const QColor& color)
00478 {
00479 if (useForegroundColor)
00480 _cursorColor = QColor();
00481
00482
00483
00484
00485 else
00486 _cursorColor = color;
00487 }
00488 QColor TerminalDisplay::keyboardCursorColor() const
00489 {
00490 return _cursorColor;
00491 }
00492
00493 void TerminalDisplay::setOpacity(qreal opacity)
00494 {
00495 QColor color(_blendColor);
00496 color.setAlphaF(opacity);
00497
00498
00499
00500
00501
00502
00503
00504
00505
00506
00507
00508
00509 _blendColor = color.rgba();
00510 }
00511
00512 void TerminalDisplay::drawBackground(QPainter& painter, const QRect& rect, const QColor& backgroundColor, bool useOpacitySetting )
00513 {
00514
00515
00516
00517
00518
00519
00520
00521
00522 QRect scrollBarArea = _scrollBar->isVisible() ?
00523 rect.intersected(_scrollBar->geometry()) :
00524 QRect();
00525 QRegion contentsRegion = QRegion(rect).subtracted(scrollBarArea);
00526 QRect contentsRect = contentsRegion.boundingRect();
00527
00528 if ( HAVE_TRANSPARENCY && qAlpha(_blendColor) < 0xff && useOpacitySetting )
00529 {
00530 QColor color(backgroundColor);
00531 color.setAlpha(qAlpha(_blendColor));
00532
00533 painter.save();
00534 painter.setCompositionMode(QPainter::CompositionMode_Source);
00535 painter.fillRect(contentsRect, color);
00536 painter.restore();
00537 }
00538 else
00539 painter.fillRect(contentsRect, backgroundColor);
00540
00541 painter.fillRect(scrollBarArea,_scrollBar->palette().background());
00542 }
00543
00544 void TerminalDisplay::drawCursor(QPainter& painter,
00545 const QRect& rect,
00546 const QColor& foregroundColor,
00547 const QColor& ,
00548 bool& invertCharacterColor)
00549 {
00550 QRect cursorRect = rect;
00551 cursorRect.setHeight(_fontHeight - _lineSpacing - 1);
00552
00553 if (!_cursorBlinking)
00554 {
00555 if ( _cursorColor.isValid() )
00556 painter.setPen(_cursorColor);
00557 else
00558 painter.setPen(foregroundColor);
00559
00560 if ( _cursorShape == BlockCursor )
00561 {
00562
00563
00564 int penWidth = qMax(1,painter.pen().width());
00565
00566 painter.drawRect(cursorRect.adjusted(penWidth/2,
00567 penWidth/2,
00568 - penWidth/2 - penWidth%2,
00569 - penWidth/2 - penWidth%2));
00570 if ( hasFocus() )
00571 {
00572 painter.fillRect(cursorRect, _cursorColor.isValid() ? _cursorColor : foregroundColor);
00573
00574 if ( !_cursorColor.isValid() )
00575 {
00576
00577
00578 invertCharacterColor = true;
00579 }
00580 }
00581 }
00582 else if ( _cursorShape == UnderlineCursor )
00583 painter.drawLine(cursorRect.left(),
00584 cursorRect.bottom(),
00585 cursorRect.right(),
00586 cursorRect.bottom());
00587 else if ( _cursorShape == IBeamCursor )
00588 painter.drawLine(cursorRect.left(),
00589 cursorRect.top(),
00590 cursorRect.left(),
00591 cursorRect.bottom());
00592
00593 }
00594 }
00595
00596 void TerminalDisplay::drawCharacters(QPainter& painter,
00597 const QRect& rect,
00598 const QString& text,
00599 const Character* style,
00600 bool invertCharacterColor)
00601 {
00602
00603 if ( _blinking && (style->rendition & RE_BLINK) )
00604 return;
00605
00606
00607 bool useBold = style->rendition & RE_BOLD || style->isBold(_colorTable) || font().bold();
00608 bool useUnderline = style->rendition & RE_UNDERLINE || font().underline();
00609
00610 QFont font = painter.font();
00611 if ( font.bold() != useBold
00612 || font.underline() != useUnderline )
00613 {
00614 font.setBold(useBold);
00615 font.setUnderline(useUnderline);
00616 painter.setFont(font);
00617 }
00618
00619
00620 const CharacterColor& textColor = ( invertCharacterColor ? style->backgroundColor : style->foregroundColor );
00621 const QColor color = textColor.color(_colorTable);
00622 QPen pen = painter.pen();
00623 if ( pen.color() != color )
00624 {
00625 pen.setColor(color);
00626 painter.setPen(color);
00627 }
00628
00629
00630 if ( isLineCharString(text) )
00631 drawLineCharString(painter,rect.x(),rect.y(),text,style);
00632 else
00633 {
00634
00635
00636
00637
00638
00639
00640 if (_bidiEnabled)
00641 painter.drawText(rect,0,text);
00642 else
00643 painter.drawText(rect,0,LTR_OVERRIDE_CHAR+text);
00644 }
00645 }
00646
00647 void TerminalDisplay::drawTextFragment(QPainter& painter ,
00648 const QRect& rect,
00649 const QString& text,
00650 const Character* style)
00651 {
00652 painter.save();
00653
00654
00655 const QColor foregroundColor = style->foregroundColor.color(_colorTable);
00656 const QColor backgroundColor = style->backgroundColor.color(_colorTable);
00657
00658
00659 if ( backgroundColor != palette().background().color() )
00660 drawBackground(painter,rect,backgroundColor,
00661 false );
00662
00663
00664
00665 bool invertCharacterColor = false;
00666 if ( style->rendition & RE_CURSOR )
00667 drawCursor(painter,rect,foregroundColor,backgroundColor,invertCharacterColor);
00668
00669
00670 drawCharacters(painter,rect,text,style,invertCharacterColor);
00671
00672 painter.restore();
00673 }
00674
00675 void TerminalDisplay::setRandomSeed(uint randomSeed) { _randomSeed = randomSeed; }
00676 uint TerminalDisplay::randomSeed() const { return _randomSeed; }
00677
00678 #if 0
00679
00682 void TerminalDisplay::setCursorPos(const int curx, const int cury)
00683 {
00684 QPoint tL = contentsRect().topLeft();
00685 int tLx = tL.x();
00686 int tLy = tL.y();
00687
00688 int xpos, ypos;
00689 ypos = _topMargin + tLy + _fontHeight*(cury-1) + _fontAscent;
00690 xpos = _leftMargin + tLx + _fontWidth*curx;
00691
00692
00693 _cursorLine = cury;
00694 _cursorCol = curx;
00695 }
00696 #endif
00697
00698
00699
00700
00701
00702
00703
00704
00705
00706 void TerminalDisplay::scrollImage(int lines , const QRect& screenWindowRegion)
00707 {
00708
00709
00710
00711 if ( _outputSuspendedLabel && _outputSuspendedLabel->isVisible() )
00712 return;
00713
00714
00715
00716
00717
00718 QRect region = screenWindowRegion;
00719 region.setBottom( qMin(region.bottom(),this->_lines-2) );
00720
00721
00722 if ( lines == 0
00723 || _image == 0
00724 || !region.isValid()
00725 || (region.top() + abs(lines)) >= region.bottom()
00726 || this->_lines <= region.height() ) return;
00727
00728
00729 if (_resizeWidget && _resizeWidget->isVisible())
00730 _resizeWidget->hide();
00731
00732
00733
00734
00735
00736
00737
00738
00739
00740
00741
00742 int scrollBarWidth = _scrollBar->isHidden() ? 0 : _scrollBar->width();
00743 const int SCROLLBAR_CONTENT_GAP = 1;
00744 QRect scrollRect;
00745 if ( _scrollbarLocation == ScrollBarLeft )
00746 {
00747 scrollRect.setLeft(scrollBarWidth+SCROLLBAR_CONTENT_GAP);
00748 scrollRect.setRight(width());
00749 }
00750 else
00751 {
00752 scrollRect.setLeft(0);
00753 scrollRect.setRight(width() - scrollBarWidth - SCROLLBAR_CONTENT_GAP);
00754 }
00755 void* firstCharPos = &_image[ region.top() * this->_columns ];
00756 void* lastCharPos = &_image[ (region.top() + abs(lines)) * this->_columns ];
00757
00758 int top = _topMargin + (region.top() * _fontHeight);
00759 int linesToMove = region.height() - abs(lines);
00760 int bytesToMove = linesToMove *
00761 this->_columns *
00762 sizeof(Character);
00763
00764 Q_ASSERT( linesToMove > 0 );
00765 Q_ASSERT( bytesToMove > 0 );
00766
00767
00768 if ( lines > 0 )
00769 {
00770
00771 Q_ASSERT( (char*)lastCharPos + bytesToMove <
00772 (char*)(_image + (this->_lines * this->_columns)) );
00773
00774 Q_ASSERT( (lines*this->_columns) < _imageSize );
00775
00776
00777 memmove( firstCharPos , lastCharPos , bytesToMove );
00778
00779
00780 scrollRect.setTop(top);
00781 }
00782 else
00783 {
00784
00785 Q_ASSERT( (char*)firstCharPos + bytesToMove <
00786 (char*)(_image + (this->_lines * this->_columns)) );
00787
00788
00789 memmove( lastCharPos , firstCharPos , bytesToMove );
00790
00791
00792 scrollRect.setTop(top + abs(lines) * _fontHeight);
00793 }
00794 scrollRect.setHeight(linesToMove * _fontHeight );
00795
00796 Q_ASSERT(scrollRect.isValid() && !scrollRect.isEmpty());
00797
00798
00799 scroll( 0 , _fontHeight * (-lines) , scrollRect );
00800 }
00801
00802 QRegion TerminalDisplay::hotSpotRegion() const
00803 {
00804 QRegion region;
00805 foreach( Filter::HotSpot* hotSpot , _filterChain->hotSpots() )
00806 {
00807 QRect rect;
00808 rect.setLeft(hotSpot->startColumn());
00809 rect.setTop(hotSpot->startLine());
00810 rect.setRight(hotSpot->endColumn());
00811 rect.setBottom(hotSpot->endLine());
00812
00813 region |= imageToWidget(rect);
00814 }
00815 return region;
00816 }
00817
00818 void TerminalDisplay::processFilters()
00819 {
00820 if (!_screenWindow)
00821 return;
00822
00823 QRegion preUpdateHotSpots = hotSpotRegion();
00824
00825
00826
00827
00828
00829
00830 _filterChain->setImage( _screenWindow->getImage(),
00831 _screenWindow->windowLines(),
00832 _screenWindow->windowColumns(),
00833 _screenWindow->getLineProperties() );
00834 _filterChain->process();
00835
00836 QRegion postUpdateHotSpots = hotSpotRegion();
00837
00838 update( preUpdateHotSpots | postUpdateHotSpots );
00839 }
00840
00841 void TerminalDisplay::updateImage()
00842 {
00843 if ( !_screenWindow )
00844 return;
00845
00846
00847
00848
00849 scrollImage( _screenWindow->scrollCount() ,
00850 _screenWindow->scrollRegion() );
00851 _screenWindow->resetScrollCount();
00852
00853 Character* const newimg = _screenWindow->getImage();
00854 int lines = _screenWindow->windowLines();
00855 int columns = _screenWindow->windowColumns();
00856
00857 setScroll( _screenWindow->currentLine() , _screenWindow->lineCount() );
00858
00859 if (!_image)
00860 updateImageSize();
00861
00862 Q_ASSERT( this->_usedLines <= this->_lines );
00863 Q_ASSERT( this->_usedColumns <= this->_columns );
00864
00865 int y,x,len;
00866
00867 QPoint tL = contentsRect().topLeft();
00868 int tLx = tL.x();
00869 int tLy = tL.y();
00870 _hasBlinker = false;
00871
00872 CharacterColor cf;
00873 CharacterColor _clipboard;
00874 int cr = -1;
00875
00876 const int linesToUpdate = qMin(this->_lines, qMax(0,lines ));
00877 const int columnsToUpdate = qMin(this->_columns,qMax(0,columns));
00878
00879 QChar *disstrU = new QChar[columnsToUpdate];
00880 char *dirtyMask = new char[columnsToUpdate+2];
00881 QRegion dirtyRegion;
00882
00883
00884
00885
00886 int dirtyLineCount = 0;
00887
00888 for (y = 0; y < linesToUpdate; y++)
00889 {
00890 const Character* currentLine = &_image[y*this->_columns];
00891 const Character* const newLine = &newimg[y*columns];
00892
00893 bool updateLine = false;
00894
00895
00896
00897
00898 memset(dirtyMask, 0, columnsToUpdate+2);
00899
00900 for( x = 0 ; x < columnsToUpdate ; x++)
00901 {
00902 if ( newLine[x] != currentLine[x] )
00903 {
00904 dirtyMask[x] = true;
00905 }
00906 }
00907
00908 if (!_resizing)
00909 for (x = 0; x < columnsToUpdate; x++)
00910 {
00911 _hasBlinker |= (newLine[x].rendition & RE_BLINK);
00912
00913
00914
00915
00916 if (dirtyMask[x])
00917 {
00918 quint16 c = newLine[x+0].character;
00919 if ( !c )
00920 continue;
00921 int p = 0;
00922 disstrU[p++] = c;
00923 bool lineDraw = isLineChar(c);
00924 bool doubleWidth = (x+1 == columnsToUpdate) ? false : (newLine[x+1].character == 0);
00925 cr = newLine[x].rendition;
00926 _clipboard = newLine[x].backgroundColor;
00927 if (newLine[x].foregroundColor != cf) cf = newLine[x].foregroundColor;
00928 int lln = columnsToUpdate - x;
00929 for (len = 1; len < lln; len++)
00930 {
00931 const Character& ch = newLine[x+len];
00932
00933 if (!ch.character)
00934 continue;
00935
00936 bool nextIsDoubleWidth = (x+len+1 == columnsToUpdate) ? false : (newLine[x+len+1].character == 0);
00937
00938 if ( ch.foregroundColor != cf ||
00939 ch.backgroundColor != _clipboard ||
00940 ch.rendition != cr ||
00941 !dirtyMask[x+len] ||
00942 isLineChar(c) != lineDraw ||
00943 nextIsDoubleWidth != doubleWidth )
00944 break;
00945
00946 disstrU[p++] = c;
00947 }
00948
00949 QString unistr(disstrU, p);
00950
00951 bool saveFixedFont = _fixedFont;
00952 if (lineDraw)
00953 _fixedFont = false;
00954 if (doubleWidth)
00955 _fixedFont = false;
00956
00957 updateLine = true;
00958
00959 _fixedFont = saveFixedFont;
00960 x += len - 1;
00961 }
00962
00963 }
00964
00965
00966
00967
00968
00969 if (_lineProperties.count() > y)
00970 updateLine |= (_lineProperties[y] & LINE_DOUBLEHEIGHT);
00971
00972
00973
00974 if (updateLine)
00975 {
00976 dirtyLineCount++;
00977
00978
00979
00980 QRect dirtyRect = QRect( _leftMargin+tLx ,
00981 _topMargin+tLy+_fontHeight*y ,
00982 _fontWidth * columnsToUpdate ,
00983 _fontHeight );
00984
00985 dirtyRegion |= dirtyRect;
00986 }
00987
00988
00989
00990 memcpy((void*)currentLine,(const void*)newLine,columnsToUpdate*sizeof(Character));
00991 }
00992
00993
00994
00995 if ( linesToUpdate < _usedLines )
00996 {
00997 dirtyRegion |= QRect( _leftMargin+tLx ,
00998 _topMargin+tLy+_fontHeight*linesToUpdate ,
00999 _fontWidth * this->_columns ,
01000 _fontHeight * (_usedLines-linesToUpdate) );
01001 }
01002 _usedLines = linesToUpdate;
01003
01004 if ( columnsToUpdate < _usedColumns )
01005 {
01006 dirtyRegion |= QRect( _leftMargin+tLx+columnsToUpdate*_fontWidth ,
01007 _topMargin+tLy ,
01008 _fontWidth * (_usedColumns-columnsToUpdate) ,
01009 _fontHeight * this->_lines );
01010 }
01011 _usedColumns = columnsToUpdate;
01012
01013 dirtyRegion |= _inputMethodData.previousPreeditRect;
01014
01015
01016 update(dirtyRegion);
01017
01018 if ( _hasBlinker && !_blinkTimer->isActive()) _blinkTimer->start( BLINK_DELAY );
01019 if (!_hasBlinker && _blinkTimer->isActive()) { _blinkTimer->stop(); _blinking = false; }
01020 delete[] dirtyMask;
01021 delete[] disstrU;
01022
01023 }
01024
01025 void TerminalDisplay::showResizeNotification()
01026 {
01027 if (_terminalSizeHint && isVisible())
01028 {
01029 if (_terminalSizeStartup) {
01030 _terminalSizeStartup=false;
01031 return;
01032 }
01033 if (!_resizeWidget)
01034 {
01035 _resizeWidget = new QLabel(i18n("Size: XXX x XXX"), this);
01036 _resizeWidget->setMinimumWidth(_resizeWidget->fontMetrics().width(i18n("Size: XXX x XXX")));
01037 _resizeWidget->setMinimumHeight(_resizeWidget->sizeHint().height());
01038 _resizeWidget->setAlignment(Qt::AlignCenter);
01039
01040 _resizeWidget->setStyleSheet("background-color:palette(window);border-style:solid;border-width:1px;border-color:palette(dark)");
01041
01042 _resizeTimer = new QTimer(this);
01043 _resizeTimer->setSingleShot(true);
01044 connect(_resizeTimer, SIGNAL(timeout()), _resizeWidget, SLOT(hide()));
01045 }
01046 QString sizeStr = i18n("Size: %1 x %2", _columns, _lines);
01047 _resizeWidget->setText(sizeStr);
01048 _resizeWidget->move((width()-_resizeWidget->width())/2,
01049 (height()-_resizeWidget->height())/2+20);
01050 _resizeWidget->show();
01051 _resizeTimer->start(1000);
01052 }
01053 }
01054
01055 void TerminalDisplay::setBlinkingCursor(bool blink)
01056 {
01057 _hasBlinkingCursor=blink;
01058
01059 if (blink && !_blinkCursorTimer->isActive())
01060 _blinkCursorTimer->start(BLINK_DELAY);
01061
01062 if (!blink && _blinkCursorTimer->isActive())
01063 {
01064 _blinkCursorTimer->stop();
01065 if (_cursorBlinking)
01066 blinkCursorEvent();
01067 else
01068 _cursorBlinking = false;
01069 }
01070 }
01071
01072 void TerminalDisplay::focusOutEvent(QFocusEvent*)
01073 {
01074
01075
01076
01077 _cursorBlinking = false;
01078 updateCursor();
01079
01080 _blinkCursorTimer->stop();
01081 if (_blinking)
01082 blinkEvent();
01083
01084 _blinkTimer->stop();
01085 }
01086 void TerminalDisplay::focusInEvent(QFocusEvent*)
01087 {
01088 if (_hasBlinkingCursor)
01089 {
01090 _blinkCursorTimer->start();
01091 }
01092 updateCursor();
01093
01094 if (_hasBlinker)
01095 _blinkTimer->start();
01096 }
01097
01098 void TerminalDisplay::paintEvent( QPaintEvent* pe )
01099 {
01100 QPainter paint(this);
01101
01102 foreach (QRect rect, (pe->region() & contentsRect()).rects())
01103 {
01104 drawBackground(paint,rect,palette().background().color(),
01105 true );
01106 drawContents(paint, rect);
01107 }
01108 drawInputMethodPreeditString(paint,preeditRect());
01109 paintFilters(paint);
01110 }
01111
01112 QPoint TerminalDisplay::cursorPosition() const
01113 {
01114 if (_screenWindow)
01115 return _screenWindow->cursorPosition();
01116 else
01117 return QPoint(0,0);
01118 }
01119
01120 QRect TerminalDisplay::preeditRect() const
01121 {
01122 const int preeditLength = string_width(_inputMethodData.preeditString);
01123
01124 if ( preeditLength == 0 )
01125 return QRect();
01126
01127 return QRect(_leftMargin + _fontWidth*cursorPosition().x(),
01128 _topMargin + _fontHeight*cursorPosition().y(),
01129 _fontWidth*preeditLength,
01130 _fontHeight);
01131 }
01132
01133 void TerminalDisplay::drawInputMethodPreeditString(QPainter& painter , const QRect& rect)
01134 {
01135 if ( _inputMethodData.preeditString.isEmpty() )
01136 return;
01137
01138 const QPoint cursorPos = cursorPosition();
01139
01140 bool invertColors = false;
01141 const QColor background = _colorTable[DEFAULT_BACK_COLOR].color;
01142 const QColor foreground = _colorTable[DEFAULT_FORE_COLOR].color;
01143 const Character* style = &_image[loc(cursorPos.x(),cursorPos.y())];
01144
01145 drawBackground(painter,rect,background,true);
01146 drawCursor(painter,rect,foreground,background,invertColors);
01147 drawCharacters(painter,rect,_inputMethodData.preeditString,style,invertColors);
01148
01149 _inputMethodData.previousPreeditRect = rect;
01150 }
01151
01152 FilterChain* TerminalDisplay::filterChain() const
01153 {
01154 return _filterChain;
01155 }
01156
01157 void TerminalDisplay::paintFilters(QPainter& painter)
01158 {
01159
01160
01161 QPoint cursorPos = mapFromGlobal(QCursor::pos());
01162 int cursorLine;
01163 int cursorColumn;
01164 getCharacterPosition( cursorPos , cursorLine , cursorColumn );
01165 Character cursorCharacter = _image[loc(cursorColumn,cursorLine)];
01166
01167 painter.setPen( QPen(cursorCharacter.foregroundColor.color(colorTable())) );
01168
01169
01170
01171
01172 QList<Filter::HotSpot*> spots = _filterChain->hotSpots();
01173 QListIterator<Filter::HotSpot*> iter(spots);
01174 while (iter.hasNext())
01175 {
01176 Filter::HotSpot* spot = iter.next();
01177
01178 for ( int line = spot->startLine() ; line <= spot->endLine() ; line++ )
01179 {
01180 int startColumn = 0;
01181 int endColumn = _columns-1;
01182
01183
01184
01185
01186 while ( QChar(_image[loc(endColumn,line)].character).isSpace() && endColumn > 0 )
01187 endColumn--;
01188
01189
01190
01191 endColumn++;
01192
01193 if ( line == spot->startLine() )
01194 startColumn = spot->startColumn();
01195 if ( line == spot->endLine() )
01196 endColumn = spot->endColumn();
01197
01198
01199
01200
01201
01202
01203
01204
01205
01206
01207 QRect r;
01208 r.setCoords( startColumn*_fontWidth + 1, line*_fontHeight + 1,
01209 endColumn*_fontWidth - 1, (line+1)*_fontHeight - 1 );
01210
01211
01212 if ( spot->type() == Filter::HotSpot::Link )
01213 {
01214 QFontMetrics metrics(font());
01215
01216
01217
01218 int baseline = r.bottom() - metrics.descent();
01219
01220 int underlinePos = baseline + metrics.underlinePos();
01221
01222 if ( r.contains( mapFromGlobal(QCursor::pos()) ) )
01223 painter.drawLine( r.left() , underlinePos ,
01224 r.right() , underlinePos );
01225 }
01226
01227
01228 else if ( spot->type() == Filter::HotSpot::Marker )
01229 {
01230
01231 painter.fillRect(r,QBrush(QColor(255,0,0,120)));
01232 }
01233 }
01234 }
01235 }
01236 void TerminalDisplay::drawContents(QPainter &paint, const QRect &rect)
01237 {
01238 QPoint tL = contentsRect().topLeft();
01239 int tLx = tL.x();
01240 int tLy = tL.y();
01241
01242 int lux = qMin(_usedColumns-1, qMax(0,(rect.left() - tLx - _leftMargin ) / _fontWidth));
01243 int luy = qMin(_usedLines-1, qMax(0,(rect.top() - tLy - _topMargin ) / _fontHeight));
01244 int rlx = qMin(_usedColumns-1, qMax(0,(rect.right() - tLx - _leftMargin ) / _fontWidth));
01245 int rly = qMin(_usedLines-1, qMax(0,(rect.bottom() - tLy - _topMargin ) / _fontHeight));
01246
01247 const int bufferSize = _usedColumns;
01248 QChar *disstrU = new QChar[bufferSize];
01249 for (int y = luy; y <= rly; y++)
01250 {
01251 quint16 c = _image[loc(lux,y)].character;
01252 int x = lux;
01253 if(!c && x)
01254 x--;
01255 for (; x <= rlx; x++)
01256 {
01257 int len = 1;
01258 int p = 0;
01259
01260
01261 if ( _image[loc(x,y)].rendition & RE_EXTENDED_CHAR )
01262 {
01263
01264 ushort extendedCharLength = 0;
01265 ushort* chars = ExtendedCharTable::instance
01266 .lookupExtendedChar(_image[loc(x,y)].charSequence,extendedCharLength);
01267 for ( int index = 0 ; index < extendedCharLength ; index++ )
01268 {
01269 Q_ASSERT( p < bufferSize );
01270 disstrU[p++] = chars[index];
01271 }
01272 }
01273 else
01274 {
01275
01276 c = _image[loc(x,y)].character;
01277 if (c)
01278 {
01279 Q_ASSERT( p < bufferSize );
01280 disstrU[p++] = c;
01281 }
01282 }
01283
01284 bool lineDraw = isLineChar(c);
01285 bool doubleWidth = (_image[ qMin(loc(x,y)+1,_imageSize) ].character == 0);
01286 CharacterColor currentForeground = _image[loc(x,y)].foregroundColor;
01287 CharacterColor currentBackground = _image[loc(x,y)].backgroundColor;
01288 quint8 currentRendition = _image[loc(x,y)].rendition;
01289
01290 while (x+len <= rlx &&
01291 _image[loc(x+len,y)].foregroundColor == currentForeground &&
01292 _image[loc(x+len,y)].backgroundColor == currentBackground &&
01293 _image[loc(x+len,y)].rendition == currentRendition &&
01294 (_image[ qMin(loc(x+len,y)+1,_imageSize) ].character == 0) == doubleWidth &&
01295 isLineChar( c = _image[loc(x+len,y)].character) == lineDraw)
01296 {
01297 if (c)
01298 disstrU[p++] = c;
01299 if (doubleWidth)
01300 len++;
01301 len++;
01302 }
01303 if ((x+len < _usedColumns) && (!_image[loc(x+len,y)].character))
01304 len++;
01305
01306 bool save__fixedFont = _fixedFont;
01307 if (lineDraw)
01308 _fixedFont = false;
01309 if (doubleWidth)
01310 _fixedFont = false;
01311 QString unistr(disstrU,p);
01312
01313 if (y < _lineProperties.size())
01314 {
01315 if (_lineProperties[y] & LINE_DOUBLEWIDTH)
01316 paint.scale(2,1);
01317
01318 if (_lineProperties[y] & LINE_DOUBLEHEIGHT)
01319 paint.scale(1,2);
01320 }
01321
01322
01323 QRect textArea = QRect( _leftMargin+tLx+_fontWidth*x , _topMargin+tLy+_fontHeight*y , _fontWidth*len , _fontHeight);
01324
01325
01326
01327
01328
01329
01330
01331 QTransform inverted = paint.worldTransform().inverted();
01332 textArea.moveTopLeft( inverted.map(textArea.topLeft()) );
01333
01334
01335 drawTextFragment( paint,
01336 textArea,
01337 unistr,
01338 &_image[loc(x,y)] );
01339
01341
01342 _fixedFont = save__fixedFont;
01343
01344
01345 paint.resetMatrix();
01346
01347 if (y < _lineProperties.size()-1)
01348 {
01349
01350
01351
01352
01353
01354 if (_lineProperties[y] & LINE_DOUBLEHEIGHT)
01355 y++;
01356 }
01357
01358 x += len - 1;
01359 }
01360 }
01361 delete [] disstrU;
01362 }
01363
01364 void TerminalDisplay::blinkEvent()
01365 {
01366 _blinking = !_blinking;
01367
01368
01369
01370
01371 update();
01372 }
01373
01374 QRect TerminalDisplay::imageToWidget(const QRect& imageArea) const
01375 {
01376 QRect result;
01377 result.setLeft( _leftMargin + _fontWidth * imageArea.left() );
01378 result.setTop( _topMargin + _fontHeight * imageArea.top() );
01379 result.setWidth( _fontWidth * imageArea.width() );
01380 result.setHeight( _fontHeight * imageArea.height() );
01381
01382 return result;
01383 }
01384
01385 void TerminalDisplay::updateCursor()
01386 {
01387 QRect cursorRect = imageToWidget( QRect(cursorPosition(),QSize(1,1)) );
01388 update(cursorRect);
01389 }
01390
01391 void TerminalDisplay::blinkCursorEvent()
01392 {
01393 _cursorBlinking = !_cursorBlinking;
01394 updateCursor();
01395 }
01396
01397
01398
01399
01400
01401
01402
01403 void TerminalDisplay::resizeEvent(QResizeEvent*)
01404 {
01405 updateImageSize();
01406 }
01407
01408 void TerminalDisplay::propagateSize()
01409 {
01410 if (_isFixedSize)
01411 {
01412 setSize(_columns, _lines);
01413 QWidget::setFixedSize(sizeHint());
01414 parentWidget()->adjustSize();
01415 parentWidget()->setFixedSize(parentWidget()->sizeHint());
01416 return;
01417 }
01418 if (_image)
01419 updateImageSize();
01420 }
01421
01422 void TerminalDisplay::updateImageSize()
01423 {
01424 Character* oldimg = _image;
01425 int oldlin = _lines;
01426 int oldcol = _columns;
01427
01428 makeImage();
01429
01430
01431 int lines = qMin(oldlin,_lines);
01432 int columns = qMin(oldcol,_columns);
01433
01434 if (oldimg)
01435 {
01436 for (int line = 0; line < lines; line++)
01437 {
01438 memcpy((void*)&_image[_columns*line],
01439 (void*)&oldimg[oldcol*line],columns*sizeof(Character));
01440 }
01441 delete[] oldimg;
01442 }
01443
01444 if (_screenWindow)
01445 _screenWindow->setWindowLines(_lines);
01446
01447 _resizing = (oldlin!=_lines) || (oldcol!=_columns);
01448
01449 if ( _resizing )
01450 {
01451 showResizeNotification();
01452 emit changedContentSizeSignal(_contentHeight, _contentWidth);
01453 }
01454
01455 _resizing = false;
01456 }
01457
01458
01459
01460
01461
01462
01463
01464 void TerminalDisplay::showEvent(QShowEvent*)
01465 {
01466 emit changedContentSizeSignal(_contentHeight,_contentWidth);
01467 }
01468 void TerminalDisplay::hideEvent(QHideEvent*)
01469 {
01470 emit changedContentSizeSignal(_contentHeight,_contentWidth);
01471 }
01472
01473
01474
01475
01476
01477
01478
01479 void TerminalDisplay::scrollBarPositionChanged(int)
01480 {
01481 if ( !_screenWindow )
01482 return;
01483
01484 _screenWindow->scrollTo( _scrollBar->value() );
01485
01486
01487
01488
01489
01490 const bool atEndOfOutput = (_scrollBar->value() == _scrollBar->maximum());
01491 _screenWindow->setTrackOutput( atEndOfOutput );
01492
01493 updateImage();
01494 }
01495
01496 void TerminalDisplay::setScroll(int cursor, int slines)
01497 {
01498
01499
01500
01501
01502
01503 if ( _scrollBar->minimum() == 0 &&
01504 _scrollBar->maximum() == (slines - _lines) &&
01505 _scrollBar->value() == cursor )
01506 {
01507 return;
01508 }
01509
01510 disconnect(_scrollBar, SIGNAL(valueChanged(int)), this, SLOT(scrollBarPositionChanged(int)));
01511 _scrollBar->setRange(0,slines - _lines);
01512 _scrollBar->setSingleStep(1);
01513 _scrollBar->setPageStep(_lines);
01514 _scrollBar->setValue(cursor);
01515 connect(_scrollBar, SIGNAL(valueChanged(int)), this, SLOT(scrollBarPositionChanged(int)));
01516 }
01517
01518 void TerminalDisplay::setScrollBarPosition(ScrollBarPosition position)
01519 {
01520 if (_scrollbarLocation == position)
01521 return;
01522
01523 if ( position == NoScrollBar )
01524 _scrollBar->hide();
01525 else
01526 _scrollBar->show();
01527
01528 _topMargin = _leftMargin = 1;
01529 _scrollbarLocation = position;
01530
01531 propagateSize();
01532 update();
01533 }
01534
01535 void TerminalDisplay::mousePressEvent(QMouseEvent* ev)
01536 {
01537 if ( _possibleTripleClick && (ev->button()==Qt::LeftButton) ) {
01538 mouseTripleClickEvent(ev);
01539 return;
01540 }
01541
01542 if ( !contentsRect().contains(ev->pos()) ) return;
01543
01544 if ( !_screenWindow ) return;
01545
01546 int charLine;
01547 int charColumn;
01548 getCharacterPosition(ev->pos(),charLine,charColumn);
01549 QPoint pos = QPoint(charColumn,charLine);
01550
01551 if ( ev->button() == Qt::LeftButton)
01552 {
01553 _lineSelectionMode = false;
01554 _wordSelectionMode = false;
01555
01556 emit isBusySelecting(true);
01557
01558 bool selected = false;
01559
01560
01561
01562
01563
01564 selected = _screenWindow->isSelected(pos.x(),pos.y());
01565
01566 if ((!_ctrlDrag || ev->modifiers() & Qt::ControlModifier) && selected ) {
01567
01568 dragInfo.state = diPending;
01569 dragInfo.start = ev->pos();
01570 }
01571 else {
01572
01573 dragInfo.state = diNone;
01574
01575 _preserveLineBreaks = !( ( ev->modifiers() & Qt::ControlModifier ) && !(ev->modifiers() & Qt::AltModifier) );
01576 _columnSelectionMode = (ev->modifiers() & Qt::AltModifier) && (ev->modifiers() & Qt::ControlModifier);
01577
01578 if (_mouseMarks || (ev->modifiers() & Qt::ShiftModifier))
01579 {
01580 _screenWindow->clearSelection();
01581
01582
01583 pos.ry() += _scrollBar->value();
01584 _iPntSel = _pntSel = pos;
01585 _actSel = 1;
01586
01587 }
01588 else
01589 {
01590 emit mouseSignal( 0, charColumn + 1, charLine + 1 +_scrollBar->value() -_scrollBar->maximum() , 0);
01591 }
01592 }
01593 }
01594 else if ( ev->button() == Qt::MidButton )
01595 {
01596 if ( _mouseMarks || (!_mouseMarks && (ev->modifiers() & Qt::ShiftModifier)) )
01597 emitSelection(true,ev->modifiers() & Qt::ControlModifier);
01598 else
01599 emit mouseSignal( 1, charColumn +1, charLine +1 +_scrollBar->value() -_scrollBar->maximum() , 0);
01600 }
01601 else if ( ev->button() == Qt::RightButton )
01602 {
01603 if (_mouseMarks || (ev->modifiers() & Qt::ShiftModifier))
01604 {
01605 emit configureRequest( this,
01606 ev->modifiers() & (Qt::ShiftModifier|Qt::ControlModifier),
01607 ev->pos()
01608 );
01609 }
01610 else
01611 emit mouseSignal( 2, charColumn +1, charLine +1 +_scrollBar->value() -_scrollBar->maximum() , 0);
01612 }
01613 }
01614
01615 QList<QAction*> TerminalDisplay::filterActions(const QPoint& position)
01616 {
01617 int charLine, charColumn;
01618 getCharacterPosition(position,charLine,charColumn);
01619
01620 Filter::HotSpot* spot = _filterChain->hotSpotAt(charLine,charColumn);
01621
01622 return spot ? spot->actions() : QList<QAction*>();
01623 }
01624
01625 void TerminalDisplay::mouseMoveEvent(QMouseEvent* ev)
01626 {
01627 int charLine = 0;
01628 int charColumn = 0;
01629
01630 getCharacterPosition(ev->pos(),charLine,charColumn);
01631
01632
01633
01634 Filter::HotSpot* spot = _filterChain->hotSpotAt(charLine,charColumn);
01635 if ( spot && spot->type() == Filter::HotSpot::Link)
01636 {
01637 QRect previousHotspotArea = _mouseOverHotspotArea;
01638 _mouseOverHotspotArea.setCoords( qMin(spot->startColumn() , spot->endColumn()) * _fontWidth,
01639 spot->startLine() * _fontHeight,
01640 qMax(spot->startColumn() , spot->endColumn()) * _fontHeight,
01641 (spot->endLine()+1) * _fontHeight );
01642
01643
01644
01645 const QString& tooltip = spot->tooltip();
01646 if ( !tooltip.isEmpty() )
01647 {
01648 QToolTip::showText( mapToGlobal(ev->pos()) , tooltip , this , _mouseOverHotspotArea );
01649 }
01650
01651 update( _mouseOverHotspotArea | previousHotspotArea );
01652 }
01653 else if ( _mouseOverHotspotArea.isValid() )
01654 {
01655 update( _mouseOverHotspotArea );
01656
01657 _mouseOverHotspotArea = QRect();
01658 }
01659
01660
01661 if (ev->buttons() == Qt::NoButton ) return;
01662
01663
01664
01665
01666 if (!_mouseMarks && !(ev->modifiers() & Qt::ShiftModifier))
01667 {
01668 int button = 3;
01669 if (ev->buttons() & Qt::LeftButton)
01670 button = 0;
01671 if (ev->buttons() & Qt::MidButton)
01672 button = 1;
01673 if (ev->buttons() & Qt::RightButton)
01674 button = 2;
01675
01676
01677 emit mouseSignal( button,
01678 charColumn + 1,
01679 charLine + 1 +_scrollBar->value() -_scrollBar->maximum(),
01680 1 );
01681
01682 return;
01683 }
01684
01685 if (dragInfo.state == diPending)
01686 {
01687
01688
01689
01690 int distance = KGlobalSettings::dndEventDelay();
01691 if ( ev->x() > dragInfo.start.x() + distance || ev->x() < dragInfo.start.x() - distance ||
01692 ev->y() > dragInfo.start.y() + distance || ev->y() < dragInfo.start.y() - distance)
01693 {
01694
01695 emit isBusySelecting(false);
01696
01697 _screenWindow->clearSelection();
01698 doDrag();
01699 }
01700 return;
01701 }
01702 else if (dragInfo.state == diDragging)
01703 {
01704
01705
01706 return;
01707 }
01708
01709 if (_actSel == 0) return;
01710
01711
01712 if (ev->buttons() & Qt::MidButton) return;
01713
01714 extendSelection( ev->pos() );
01715 }
01716
01717 void TerminalDisplay::extendSelection( const QPoint& position )
01718 {
01719 QPoint pos = position;
01720
01721 if ( !_screenWindow )
01722 return;
01723
01724
01725 QPoint tL = contentsRect().topLeft();
01726 int tLx = tL.x();
01727 int tLy = tL.y();
01728 int scroll = _scrollBar->value();
01729
01730
01731
01732
01733
01734 int linesBeyondWidget = 0;
01735
01736 QRect textBounds(tLx + _leftMargin,
01737 tLy + _topMargin,
01738 _usedColumns*_fontWidth-1,
01739 _usedLines*_fontHeight-1);
01740
01741
01742 QPoint oldpos = pos;
01743
01744 pos.setX( qBound(textBounds.left(),pos.x(),textBounds.right()) );
01745 pos.setY( qBound(textBounds.top(),pos.y(),textBounds.bottom()) );
01746
01747 if ( oldpos.y() > textBounds.bottom() )
01748 {
01749 linesBeyondWidget = (oldpos.y()-textBounds.bottom()) / _fontHeight;
01750 _scrollBar->setValue(_scrollBar->value()+linesBeyondWidget+1);
01751 }
01752 if ( oldpos.y() < textBounds.top() )
01753 {
01754 linesBeyondWidget = (textBounds.top()-oldpos.y()) / _fontHeight;
01755 _scrollBar->setValue(_scrollBar->value()-linesBeyondWidget-1);
01756 }
01757
01758 int charColumn = 0;
01759 int charLine = 0;
01760 getCharacterPosition(pos,charLine,charColumn);
01761
01762 QPoint here = QPoint(charColumn,charLine);
01763 QPoint ohere;
01764 QPoint _iPntSelCorr = _iPntSel;
01765 _iPntSelCorr.ry() -= _scrollBar->value();
01766 QPoint _pntSelCorr = _pntSel;
01767 _pntSelCorr.ry() -= _scrollBar->value();
01768 bool swapping = false;
01769
01770 if ( _wordSelectionMode )
01771 {
01772
01773 int i;
01774 QChar selClass;
01775
01776 bool left_not_right = ( here.y() < _iPntSelCorr.y() ||
01777 ( here.y() == _iPntSelCorr.y() && here.x() < _iPntSelCorr.x() ) );
01778 bool old_left_not_right = ( _pntSelCorr.y() < _iPntSelCorr.y() ||
01779 ( _pntSelCorr.y() == _iPntSelCorr.y() && _pntSelCorr.x() < _iPntSelCorr.x() ) );
01780 swapping = left_not_right != old_left_not_right;
01781
01782
01783 QPoint left = left_not_right ? here : _iPntSelCorr;
01784 i = loc(left.x(),left.y());
01785 if (i>=0 && i<=_imageSize) {
01786 selClass = charClass(_image[i].character);
01787 while ( ((left.x()>0) || (left.y()>0 && (_lineProperties[left.y()-1] & LINE_WRAPPED) ))
01788 && charClass(_image[i-1].character) == selClass )
01789 { i--; if (left.x()>0) left.rx()--; else {left.rx()=_usedColumns-1; left.ry()--;} }
01790 }
01791
01792
01793 QPoint right = left_not_right ? _iPntSelCorr : here;
01794 i = loc(right.x(),right.y());
01795 if (i>=0 && i<=_imageSize) {
01796 selClass = charClass(_image[i].character);
01797 while( ((right.x()<_usedColumns-1) || (right.y()<_usedLines-1 && (_lineProperties[right.y()] & LINE_WRAPPED) ))
01798 && charClass(_image[i+1].character) == selClass )
01799 { i++; if (right.x()<_usedColumns-1) right.rx()++; else {right.rx()=0; right.ry()++; } }
01800 }
01801
01802
01803 if ( left_not_right )
01804 {
01805 here = left; ohere = right;
01806 }
01807 else
01808 {
01809 here = right; ohere = left;
01810 }
01811 ohere.rx()++;
01812 }
01813
01814 if ( _lineSelectionMode )
01815 {
01816
01817 bool above_not_below = ( here.y() < _iPntSelCorr.y() );
01818
01819 QPoint above = above_not_below ? here : _iPntSelCorr;
01820 QPoint below = above_not_below ? _iPntSelCorr : here;
01821
01822 while (above.y()>0 && (_lineProperties[above.y()-1] & LINE_WRAPPED) )
01823 above.ry()--;
01824 while (below.y()<_usedLines-1 && (_lineProperties[below.y()] & LINE_WRAPPED) )
01825 below.ry()++;
01826
01827 above.setX(0);
01828 below.setX(_usedColumns-1);
01829
01830
01831 if ( above_not_below )
01832 {
01833 here = above; ohere = below;
01834 }
01835 else
01836 {
01837 here = below; ohere = above;
01838 }
01839
01840 QPoint newSelBegin = QPoint( ohere.x(), ohere.y() );
01841 swapping = !(_tripleSelBegin==newSelBegin);
01842 _tripleSelBegin = newSelBegin;
01843
01844 ohere.rx()++;
01845 }
01846
01847 int offset = 0;
01848 if ( !_wordSelectionMode && !_lineSelectionMode )
01849 {
01850 int i;
01851 QChar selClass;
01852
01853 bool left_not_right = ( here.y() < _iPntSelCorr.y() ||
01854 ( here.y() == _iPntSelCorr.y() && here.x() < _iPntSelCorr.x() ) );
01855 bool old_left_not_right = ( _pntSelCorr.y() < _iPntSelCorr.y() ||
01856 ( _pntSelCorr.y() == _iPntSelCorr.y() && _pntSelCorr.x() < _iPntSelCorr.x() ) );
01857 swapping = left_not_right != old_left_not_right;
01858
01859
01860 QPoint left = left_not_right ? here : _iPntSelCorr;
01861
01862
01863 QPoint right = left_not_right ? _iPntSelCorr : here;
01864 if ( right.x() > 0 && !_columnSelectionMode )
01865 {
01866 i = loc(right.x(),right.y());
01867 if (i>=0 && i<=_imageSize) {
01868 selClass = charClass(_image[i-1].character);
01869
01870
01871
01872
01873
01874
01875
01876
01877
01878
01879 }
01880 }
01881
01882
01883 if ( left_not_right )
01884 {
01885 here = left; ohere = right; offset = 0;
01886 }
01887 else
01888 {
01889 here = right; ohere = left; offset = -1;
01890 }
01891 }
01892
01893 if ((here == _pntSelCorr) && (scroll == _scrollBar->value())) return;
01894
01895 if (here == ohere) return;
01896
01897 if ( _actSel < 2 || swapping )
01898 {
01899 if ( _columnSelectionMode && !_lineSelectionMode && !_wordSelectionMode )
01900 {
01901 _screenWindow->setSelectionStart( ohere.x() , ohere.y() , true );
01902 }
01903 else
01904 {
01905 _screenWindow->setSelectionStart( ohere.x()-1-offset , ohere.y() , false );
01906 }
01907
01908 }
01909
01910 _actSel = 2;
01911 _pntSel = here;
01912 _pntSel.ry() += _scrollBar->value();
01913
01914 if ( _columnSelectionMode && !_lineSelectionMode && !_wordSelectionMode )
01915 {
01916 _screenWindow->setSelectionEnd( here.x() , here.y() );
01917 }
01918 else
01919 {
01920 _screenWindow->setSelectionEnd( here.x()+offset , here.y() );
01921 }
01922
01923 }
01924
01925 void TerminalDisplay::mouseReleaseEvent(QMouseEvent* ev)
01926 {
01927 if ( !_screenWindow )
01928 return;
01929
01930 int charLine;
01931 int charColumn;
01932 getCharacterPosition(ev->pos(),charLine,charColumn);
01933
01934 if ( ev->button() == Qt::LeftButton)
01935 {
01936 emit isBusySelecting(false);
01937 if(dragInfo.state == diPending)
01938 {
01939
01940 _screenWindow->clearSelection();
01941
01942 }
01943 else
01944 {
01945 if ( _actSel > 1 )
01946 {
01947 setSelection( _screenWindow->selectedText(_preserveLineBreaks) );
01948 }
01949
01950 _actSel = 0;
01951
01952
01953
01954
01955
01956 if (!_mouseMarks && !(ev->modifiers() & Qt::ShiftModifier))
01957 emit mouseSignal( 3,
01958 charColumn + 1,
01959 charLine + 1 +_scrollBar->value() -_scrollBar->maximum() , 0);
01960 }
01961 dragInfo.state = diNone;
01962 }
01963
01964
01965 if ( !_mouseMarks &&
01966 ((ev->button() == Qt::RightButton && !(ev->modifiers() & Qt::ShiftModifier))
01967 || ev->button() == Qt::MidButton) )
01968 {
01969 emit mouseSignal( 3,
01970 charColumn + 1,
01971 charLine + 1 +_scrollBar->value() -_scrollBar->maximum() ,
01972 0);
01973 }
01974 }
01975
01976 void TerminalDisplay::getCharacterPosition(const QPoint& widgetPoint,int& line,int& column) const
01977 {
01978 column = (widgetPoint.x() + _fontWidth/2 -contentsRect().left()-_leftMargin) / _fontWidth;
01979 line = (widgetPoint.y()-contentsRect().top()-_topMargin) / _fontHeight;
01980
01981 if ( line < 0 )
01982 line = 0;
01983 if ( column < 0 )
01984 column = 0;
01985
01986 if ( line >= _usedLines )
01987 line = _usedLines-1;
01988
01989
01990
01991
01992
01993
01994 if ( column > _usedColumns )
01995 column = _usedColumns;
01996 }
01997
01998 void TerminalDisplay::updateLineProperties()
01999 {
02000 if ( !_screenWindow )
02001 return;
02002
02003 _lineProperties = _screenWindow->getLineProperties();
02004 }
02005
02006 void TerminalDisplay::mouseDoubleClickEvent(QMouseEvent* ev)
02007 {
02008 if ( ev->button() != Qt::LeftButton) return;
02009 if ( !_screenWindow ) return;
02010
02011 int charLine = 0;
02012 int charColumn = 0;
02013
02014 getCharacterPosition(ev->pos(),charLine,charColumn);
02015
02016 QPoint pos(charColumn,charLine);
02017
02018
02019 if (!_mouseMarks && !(ev->modifiers() & Qt::ShiftModifier))
02020 {
02021
02022
02023 emit mouseSignal( 0,
02024 pos.x()+1,
02025 pos.y()+1 +_scrollBar->value() -_scrollBar->maximum(),
02026 0 );
02027 return;
02028 }
02029
02030 _screenWindow->clearSelection();
02031 QPoint bgnSel = pos;
02032 QPoint endSel = pos;
02033 int i = loc(bgnSel.x(),bgnSel.y());
02034 _iPntSel = bgnSel;
02035 _iPntSel.ry() += _scrollBar->value();
02036
02037 _wordSelectionMode = true;
02038
02039
02040 QChar selClass = charClass(_image[i].character);
02041 {
02042
02043 int x = bgnSel.x();
02044 while ( ((x>0) || (bgnSel.y()>0 && (_lineProperties[bgnSel.y()-1] & LINE_WRAPPED) ))
02045 && charClass(_image[i-1].character) == selClass )
02046 {
02047 i--;
02048 if (x>0)
02049 x--;
02050 else
02051 {
02052 x=_usedColumns-1;
02053 bgnSel.ry()--;
02054 }
02055 }
02056
02057 bgnSel.setX(x);
02058 _screenWindow->setSelectionStart( bgnSel.x() , bgnSel.y() , false );
02059
02060
02061 i = loc( endSel.x(), endSel.y() );
02062 x = endSel.x();
02063 while( ((x<_usedColumns-1) || (endSel.y()<_usedLines-1 && (_lineProperties[endSel.y()] & LINE_WRAPPED) ))
02064 && charClass(_image[i+1].character) == selClass )
02065 {
02066 i++;
02067 if (x<_usedColumns-1)
02068 x++;
02069 else
02070 {
02071 x=0;
02072 endSel.ry()++;
02073 }
02074 }
02075
02076 endSel.setX(x);
02077
02078
02079 if ( ( QChar( _image[i].character ) == '@' ) && ( ( endSel.x() - bgnSel.x() ) > 0 ) )
02080 endSel.setX( x - 1 );
02081
02082
02083 _actSel = 2;
02084
02085 _screenWindow->setSelectionEnd( endSel.x() , endSel.y() );
02086
02087 setSelection( _screenWindow->selectedText(_preserveLineBreaks) );
02088 }
02089
02090 _possibleTripleClick=true;
02091
02092 QTimer::singleShot(QApplication::doubleClickInterval(),this,
02093 SLOT(tripleClickTimeout()));
02094 }
02095
02096 void TerminalDisplay::wheelEvent( QWheelEvent* ev )
02097 {
02098 if (ev->orientation() != Qt::Vertical)
02099 return;
02100
02101
02102
02103
02104
02105 if ( _mouseMarks )
02106 {
02107 bool canScroll = _scrollBar->maximum() > 0;
02108 if (canScroll)
02109 _scrollBar->event(ev);
02110 else
02111 {
02112
02113
02114
02115
02116
02117
02118 int key = ev->delta() > 0 ? Qt::Key_Up : Qt::Key_Down;
02119
02120
02121 int wheelDegrees = ev->delta() / 8;
02122 int linesToScroll = abs(wheelDegrees) / 5;
02123
02124 QKeyEvent keyScrollEvent(QEvent::KeyPress,key,Qt::NoModifier);
02125
02126 for (int i=0;i<linesToScroll;i++)
02127 emit keyPressedSignal(&keyScrollEvent);
02128 }
02129 }
02130 else
02131 {
02132
02133
02134 int charLine;
02135 int charColumn;
02136 getCharacterPosition( ev->pos() , charLine , charColumn );
02137
02138 emit mouseSignal( ev->delta() > 0 ? 4 : 5,
02139 charColumn + 1,
02140 charLine + 1 +_scrollBar->value() -_scrollBar->maximum() ,
02141 0);
02142 }
02143 }
02144
02145 void TerminalDisplay::tripleClickTimeout()
02146 {
02147 _possibleTripleClick=false;
02148 }
02149
02150 void TerminalDisplay::mouseTripleClickEvent(QMouseEvent* ev)
02151 {
02152 if ( !_screenWindow ) return;
02153
02154 int charLine;
02155 int charColumn;
02156 getCharacterPosition(ev->pos(),charLine,charColumn);
02157 _iPntSel = QPoint(charColumn,charLine);
02158
02159 _screenWindow->clearSelection();
02160
02161 _lineSelectionMode = true;
02162 _wordSelectionMode = false;
02163
02164 _actSel = 2;
02165 emit isBusySelecting(true);
02166
02167 while (_iPntSel.y()>0 && (_lineProperties[_iPntSel.y()-1] & LINE_WRAPPED) )
02168 _iPntSel.ry()--;
02169
02170 if (_tripleClickMode == SelectForwardsFromCursor) {
02171
02172 int i = loc(_iPntSel.x(),_iPntSel.y());
02173 QChar selClass = charClass(_image[i].character);
02174 int x = _iPntSel.x();
02175
02176 while ( ((x>0) ||
02177 (_iPntSel.y()>0 && (_lineProperties[_iPntSel.y()-1] & LINE_WRAPPED) )
02178 )
02179 && charClass(_image[i-1].character) == selClass )
02180 {
02181 i--;
02182 if (x>0)
02183 x--;
02184 else
02185 {
02186 x=_columns-1;
02187 _iPntSel.ry()--;
02188 }
02189 }
02190
02191 _screenWindow->setSelectionStart( x , _iPntSel.y() , false );
02192 _tripleSelBegin = QPoint( x, _iPntSel.y() );
02193 }
02194 else if (_tripleClickMode == SelectWholeLine) {
02195 _screenWindow->setSelectionStart( 0 , _iPntSel.y() , false );
02196 _tripleSelBegin = QPoint( 0, _iPntSel.y() );
02197 }
02198
02199 while (_iPntSel.y()<_lines-1 && (_lineProperties[_iPntSel.y()] & LINE_WRAPPED) )
02200 _iPntSel.ry()++;
02201
02202 _screenWindow->setSelectionEnd( _columns - 1 , _iPntSel.y() );
02203
02204 setSelection(_screenWindow->selectedText(_preserveLineBreaks));
02205
02206 _iPntSel.ry() += _scrollBar->value();
02207 }
02208
02209
02210 bool TerminalDisplay::focusNextPrevChild( bool next )
02211 {
02212 if (next)
02213 return false;
02214
02215 return QWidget::focusNextPrevChild( next );
02216 }
02217
02218
02219 QChar TerminalDisplay::charClass(QChar qch) const
02220 {
02221 if ( qch.isSpace() ) return ' ';
02222
02223 if ( qch.isLetterOrNumber() || _wordCharacters.contains(qch, Qt::CaseInsensitive ) )
02224 return 'a';
02225
02226 return qch;
02227 }
02228
02229 void TerminalDisplay::setWordCharacters(const QString& wc)
02230 {
02231 _wordCharacters = wc;
02232 }
02233
02234 void TerminalDisplay::setUsesMouse(bool on)
02235 {
02236 _mouseMarks = on;
02237 setCursor( _mouseMarks ? Qt::IBeamCursor : Qt::ArrowCursor );
02238 }
02239 bool TerminalDisplay::usesMouse() const
02240 {
02241 return _mouseMarks;
02242 }
02243
02244
02245
02246
02247
02248
02249
02250 #undef KeyPress
02251
02252 void TerminalDisplay::emitSelection(bool useXselection,bool appendReturn)
02253 {
02254 if ( !_screenWindow )
02255 return;
02256
02257
02258 QString text = QApplication::clipboard()->text(useXselection ? QClipboard::Selection :
02259 QClipboard::Clipboard);
02260 if(appendReturn)
02261 text.append("\r");
02262 if ( ! text.isEmpty() )
02263 {
02264 text.replace("\n", "\r");
02265 QKeyEvent e(QEvent::KeyPress, 0, Qt::NoModifier, text);
02266 emit keyPressedSignal(&e);
02267
02268 _screenWindow->clearSelection();
02269 }
02270 }
02271
02272 void TerminalDisplay::setSelection(const QString& t)
02273 {
02274 QApplication::clipboard()->setText(t, QClipboard::Selection);
02275 }
02276
02277 void TerminalDisplay::copyClipboard()
02278 {
02279 if ( !_screenWindow )
02280 return;
02281
02282 QString text = _screenWindow->selectedText(_preserveLineBreaks);
02283 QApplication::clipboard()->setText(text);
02284 }
02285
02286 void TerminalDisplay::pasteClipboard()
02287 {
02288 emitSelection(false,false);
02289 }
02290
02291 void TerminalDisplay::pasteSelection()
02292 {
02293 emitSelection(true,false);
02294 }
02295
02296
02297
02298
02299
02300
02301
02302 void TerminalDisplay::setFlowControlWarningEnabled( bool enable )
02303 {
02304 _flowControlWarningEnabled = enable;
02305
02306
02307
02308 if (!enable)
02309 outputSuspended(false);
02310 }
02311
02312 void TerminalDisplay::keyPressEvent( QKeyEvent* event )
02313 {
02314 bool emitKeyPressSignal = true;
02315
02316
02317 if ( event->modifiers() == Qt::ShiftModifier )
02318 {
02319 bool update = true;
02320
02321 if ( event->key() == Qt::Key_PageUp )
02322 {
02323 _screenWindow->scrollBy( ScreenWindow::ScrollPages , -1 );
02324 }
02325 else if ( event->key() == Qt::Key_PageDown )
02326 {
02327 _screenWindow->scrollBy( ScreenWindow::ScrollPages , 1 );
02328 }
02329 else if ( event->key() == Qt::Key_Up )
02330 {
02331 _screenWindow->scrollBy( ScreenWindow::ScrollLines , -1 );
02332 }
02333 else if ( event->key() == Qt::Key_Down )
02334 {
02335 _screenWindow->scrollBy( ScreenWindow::ScrollLines , 1 );
02336 }
02337 else
02338 update = false;
02339
02340 if ( update )
02341 {
02342 _screenWindow->setTrackOutput( _screenWindow->atEndOfOutput() );
02343
02344 updateLineProperties();
02345 updateImage();
02346
02347
02348 emitKeyPressSignal = false;
02349 }
02350 }
02351
02352 _actSel=0;
02353
02354
02355 if (_hasBlinkingCursor)
02356 {
02357 _blinkCursorTimer->start(BLINK_DELAY);
02358 if (_cursorBlinking)
02359 blinkCursorEvent();
02360 else
02361 _cursorBlinking = false;
02362 }
02363
02364 if ( emitKeyPressSignal )
02365 emit keyPressedSignal(event);
02366
02367 event->accept();
02368 }
02369
02370 void TerminalDisplay::inputMethodEvent( QInputMethodEvent* event )
02371 {
02372 QKeyEvent keyEvent(QEvent::KeyPress,0,Qt::NoModifier,event->commitString());
02373 emit keyPressedSignal(&keyEvent);
02374
02375 _inputMethodData.preeditString = event->preeditString();
02376 update(preeditRect() | _inputMethodData.previousPreeditRect);
02377
02378 event->accept();
02379 }
02380 QVariant TerminalDisplay::inputMethodQuery( Qt::InputMethodQuery query ) const
02381 {
02382 const QPoint cursorPos = _screenWindow ? _screenWindow->cursorPosition() : QPoint(0,0);
02383 switch ( query )
02384 {
02385 case Qt::ImMicroFocus:
02386 return imageToWidget(QRect(cursorPos.x(),cursorPos.y(),1,1));
02387 break;
02388 case Qt::ImFont:
02389 return font();
02390 break;
02391 case Qt::ImCursorPosition:
02392
02393 return cursorPos.x();
02394 break;
02395 case Qt::ImSurroundingText:
02396 {
02397
02398 QString lineText;
02399 QTextStream stream(&lineText);
02400 PlainTextDecoder decoder;
02401 decoder.begin(&stream);
02402 decoder.decodeLine(&_image[loc(0,cursorPos.y())],_usedColumns,_lineProperties[cursorPos.y()]);
02403 decoder.end();
02404 return lineText;
02405 }
02406 break;
02407 case Qt::ImCurrentSelection:
02408 return QString();
02409 break;
02410 }
02411
02412 return QVariant();
02413 }
02414
02415 bool TerminalDisplay::event( QEvent *e )
02416 {
02417 if ( e->type() == QEvent::ShortcutOverride )
02418 {
02419 QKeyEvent* keyEvent = static_cast<QKeyEvent *>( e );
02420 int modifiers = keyEvent->modifiers();
02421
02422
02423
02424
02425 if (modifiers != Qt::NoModifier)
02426 {
02427 int modifierCount = 0;
02428 unsigned int currentModifier = Qt::ShiftModifier;
02429
02430 while (currentModifier <= Qt::KeypadModifier)
02431 {
02432 if (modifiers & currentModifier)
02433 modifierCount++;
02434 currentModifier <<= 1;
02435 }
02436 if (modifierCount < 2)
02437 {
02438 bool override = false;
02439 emit overrideShortcutCheck(keyEvent,override);
02440 if (override)
02441 {
02442 keyEvent->accept();
02443 return true;
02444 }
02445 }
02446 }
02447
02448
02449
02450 int keyCode = keyEvent->key() | modifiers;
02451 switch ( keyCode )
02452 {
02453
02454 case Qt::Key_Tab:
02455 case Qt::Key_Delete:
02456 case Qt::Key_Home:
02457 case Qt::Key_End:
02458 case Qt::Key_Backspace:
02459 case Qt::Key_Left:
02460 case Qt::Key_Right:
02461 keyEvent->accept();
02462 return true;
02463 }
02464 }
02465 return QWidget::event( e );
02466 }
02467
02468 void TerminalDisplay::setBellMode(int mode)
02469 {
02470 _bellMode=mode;
02471 }
02472
02473 void TerminalDisplay::enableBell()
02474 {
02475 _allowBell = true;
02476 }
02477
02478 void TerminalDisplay::bell(const QString& message)
02479 {
02480 if (_bellMode==NoBell) return;
02481
02482
02483
02484
02485 if ( _allowBell )
02486 {
02487 _allowBell = false;
02488 QTimer::singleShot(500,this,SLOT(enableBell()));
02489
02490 if (_bellMode==SystemBeepBell)
02491 {
02492 KNotification::beep();
02493 }
02494 else if (_bellMode==NotifyBell)
02495 {
02496 KNotification::event("BellVisible", message,QPixmap(),this);
02497 }
02498 else if (_bellMode==VisualBell)
02499 {
02500 swapColorTable();
02501 QTimer::singleShot(200,this,SLOT(swapColorTable()));
02502 }
02503 }
02504 }
02505
02506 void TerminalDisplay::swapColorTable()
02507 {
02508 ColorEntry color = _colorTable[1];
02509 _colorTable[1]=_colorTable[0];
02510 _colorTable[0]= color;
02511 _colorsInverted = !_colorsInverted;
02512 update();
02513 }
02514
02515 void TerminalDisplay::clearImage()
02516 {
02517
02518 for (int i = 0; i <= _imageSize; i++)
02519 {
02520 _image[i].character = ' ';
02521 _image[i].foregroundColor = CharacterColor(COLOR_SPACE_DEFAULT,
02522 DEFAULT_FORE_COLOR);
02523 _image[i].backgroundColor = CharacterColor(COLOR_SPACE_DEFAULT,
02524 DEFAULT_BACK_COLOR);
02525 _image[i].rendition = DEFAULT_RENDITION;
02526 }
02527 }
02528
02529 void TerminalDisplay::calcGeometry()
02530 {
02531 _scrollBar->resize(QApplication::style()->pixelMetric(QStyle::PM_ScrollBarExtent),
02532 contentsRect().height());
02533 switch(_scrollbarLocation)
02534 {
02535 case NoScrollBar :
02536 _leftMargin = DEFAULT_LEFT_MARGIN;
02537 _contentWidth = contentsRect().width() - 2 * DEFAULT_LEFT_MARGIN;
02538 break;
02539 case ScrollBarLeft :
02540 _leftMargin = DEFAULT_LEFT_MARGIN + _scrollBar->width();
02541 _contentWidth = contentsRect().width() - 2 * DEFAULT_LEFT_MARGIN - _scrollBar->width();
02542 _scrollBar->move(contentsRect().topLeft());
02543 break;
02544 case ScrollBarRight:
02545 _leftMargin = DEFAULT_LEFT_MARGIN;
02546 _contentWidth = contentsRect().width() - 2 * DEFAULT_LEFT_MARGIN - _scrollBar->width();
02547 _scrollBar->move(contentsRect().topRight() - QPoint(_scrollBar->width()-1,0));
02548 break;
02549 }
02550
02551 _topMargin = DEFAULT_TOP_MARGIN;
02552 _contentHeight = contentsRect().height() - 2 * DEFAULT_TOP_MARGIN + 1;
02553
02554 if (!_isFixedSize)
02555 {
02556
02557 _columns = qMax(1,_contentWidth / _fontWidth);
02558 _usedColumns = qMin(_usedColumns,_columns);
02559
02560
02561 _lines = qMax(1,_contentHeight / _fontHeight);
02562 _usedLines = qMin(_usedLines,_lines);
02563 }
02564 }
02565
02566 void TerminalDisplay::makeImage()
02567 {
02568 calcGeometry();
02569
02570
02571
02572 Q_ASSERT( _lines > 0 && _columns > 0 );
02573 Q_ASSERT( _usedLines <= _lines && _usedColumns <= _columns );
02574
02575 _imageSize=_lines*_columns;
02576
02577
02578
02579 _image = new Character[_imageSize+1];
02580
02581 clearImage();
02582 }
02583
02584
02585 void TerminalDisplay::setSize(int columns, int lines)
02586 {
02587 int scrollBarWidth = _scrollBar->isHidden() ? 0 :
02588 style()->pixelMetric(QStyle::PM_ScrollBarExtent);
02589 int horizontalMargin = 2 * DEFAULT_LEFT_MARGIN;
02590 int verticalMargin = 2 * DEFAULT_TOP_MARGIN;
02591
02592 QSize newSize = QSize( horizontalMargin + scrollBarWidth + (columns * _fontWidth) ,
02593 verticalMargin + (lines * _fontHeight) );
02594
02595 if ( newSize != size() )
02596 {
02597 _size = newSize;
02598 updateGeometry();
02599 }
02600 }
02601
02602 void TerminalDisplay::setFixedSize(int cols, int lins)
02603 {
02604 _isFixedSize = true;
02605
02606
02607 _columns = qMax(1,cols);
02608 _lines = qMax(1,lins);
02609 _usedColumns = qMin(_usedColumns,_columns);
02610 _usedLines = qMin(_usedLines,_lines);
02611
02612 if (_image)
02613 {
02614 delete[] _image;
02615 makeImage();
02616 }
02617 setSize(cols, lins);
02618 QWidget::setFixedSize(_size);
02619 }
02620
02621 QSize TerminalDisplay::sizeHint() const
02622 {
02623 return _size;
02624 }
02625
02626
02627
02628
02629
02630
02631
02632
02633 void TerminalDisplay::dragEnterEvent(QDragEnterEvent* event)
02634 {
02635 if (event->mimeData()->hasFormat("text/plain"))
02636 event->acceptProposedAction();
02637 }
02638
02639 void TerminalDisplay::dropEvent(QDropEvent* event)
02640 {
02641 KUrl::List urls = KUrl::List::fromMimeData(event->mimeData());
02642
02643 QString dropText;
02644 if (!urls.isEmpty())
02645 {
02646 for ( int i = 0 ; i < urls.count() ; i++ )
02647 {
02648 KUrl url = KIO::NetAccess::mostLocalUrl( urls[i] , 0 );
02649 QString urlText;
02650
02651 if (url.isLocalFile())
02652 urlText = url.path();
02653 else
02654 urlText = url.url();
02655
02656
02657
02658 urlText = KShell::quoteArg(urlText);
02659
02660 dropText += urlText;
02661
02662 if ( i != urls.count()-1 )
02663 dropText += ' ';
02664 }
02665 }
02666 else
02667 {
02668 dropText = event->mimeData()->text();
02669 }
02670
02671 if(event->mimeData()->hasFormat("text/plain"))
02672 {
02673 emit sendStringToEmu(dropText.toLocal8Bit());
02674 }
02675 }
02676
02677 void TerminalDisplay::doDrag()
02678 {
02679 dragInfo.state = diDragging;
02680 dragInfo.dragObject = new QDrag(this);
02681 QMimeData *mimeData = new QMimeData;
02682 mimeData->setText(QApplication::clipboard()->text(QClipboard::Selection));
02683 dragInfo.dragObject->setMimeData(mimeData);
02684 dragInfo.dragObject->start(Qt::CopyAction);
02685
02686 }
02687
02688 void TerminalDisplay::outputSuspended(bool suspended)
02689 {
02690
02691 if (!_outputSuspendedLabel)
02692 {
02693
02694
02695
02696
02697
02698 _outputSuspendedLabel = new QLabel( i18n("<qt>Output has been "
02699 "<a href=\"http://en.wikipedia.org/wiki/Flow_control\">suspended</a>"
02700 " by pressing Ctrl+S."
02701 " Press <b>Ctrl+Q</b> to resume.</qt>"),
02702 this );
02703
02704 QPalette palette(_outputSuspendedLabel->palette());
02705 KColorScheme::adjustBackground(palette,KColorScheme::NeutralBackground);
02706 _outputSuspendedLabel->setPalette(palette);
02707 _outputSuspendedLabel->setAutoFillBackground(true);
02708 _outputSuspendedLabel->setBackgroundRole(QPalette::Base);
02709 _outputSuspendedLabel->setFont(QApplication::font());
02710 _outputSuspendedLabel->setMargin(5);
02711
02712
02713 _outputSuspendedLabel->setTextInteractionFlags(Qt::LinksAccessibleByMouse |
02714 Qt::LinksAccessibleByKeyboard);
02715 _outputSuspendedLabel->setOpenExternalLinks(true);
02716 _outputSuspendedLabel->setVisible(false);
02717
02718 _gridLayout->addWidget(_outputSuspendedLabel);
02719 _gridLayout->addItem( new QSpacerItem(0,0,QSizePolicy::Expanding,
02720 QSizePolicy::Expanding),
02721 1,0);
02722
02723 }
02724
02725 _outputSuspendedLabel->setVisible(suspended);
02726 }
02727
02728 uint TerminalDisplay::lineSpacing() const
02729 {
02730 return _lineSpacing;
02731 }
02732
02733 void TerminalDisplay::setLineSpacing(uint i)
02734 {
02735 _lineSpacing = i;
02736 setVTFont(font());
02737 }
02738
02739 AutoScrollHandler::AutoScrollHandler(QWidget* parent)
02740 : QObject(parent)
02741 , _timerId(0)
02742 {
02743 parent->installEventFilter(this);
02744 }
02745 void AutoScrollHandler::timerEvent(QTimerEvent* event)
02746 {
02747 if (event->timerId() != _timerId)
02748 return;
02749
02750 QMouseEvent mouseEvent( QEvent::MouseMove,
02751 widget()->mapFromGlobal(QCursor::pos()),
02752 Qt::NoButton,
02753 Qt::LeftButton,
02754 Qt::NoModifier);
02755
02756 QApplication::sendEvent(widget(),&mouseEvent);
02757 }
02758 bool AutoScrollHandler::eventFilter(QObject* watched,QEvent* event)
02759 {
02760 Q_ASSERT( watched == parent() );
02761
02762 QMouseEvent* mouseEvent = (QMouseEvent*)event;
02763 switch (event->type())
02764 {
02765 case QEvent::MouseMove:
02766 {
02767 bool mouseInWidget = widget()->rect().contains(mouseEvent->pos());
02768
02769 if (mouseInWidget)
02770 {
02771 if (_timerId)
02772 killTimer(_timerId);
02773 _timerId = 0;
02774 }
02775 else
02776 {
02777 if (!_timerId && (mouseEvent->buttons() & Qt::LeftButton))
02778 _timerId = startTimer(100);
02779 }
02780 break;
02781 }
02782 case QEvent::MouseButtonRelease:
02783 if (_timerId && (mouseEvent->buttons() & ~Qt::LeftButton))
02784 {
02785 killTimer(_timerId);
02786 _timerId = 0;
02787 }
02788 break;
02789 default:
02790 break;
02791 };
02792
02793 return false;
02794 }
02795
02796 #include "TerminalDisplay.moc"
02797