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