27 #include <config-konsole.h>
30 #include <QApplication>
31 #include <QtGui/QClipboard>
32 #include <QtGui/QKeyEvent>
33 #include <QtCore/QEvent>
34 #include <QtCore/QFileInfo>
35 #include <QGridLayout>
38 #include <QtGui/QPainter>
39 #include <QtGui/QPixmap>
42 #include <QtCore/QTimer>
44 #include <QtGui/QAccessible>
48 #include <KColorScheme>
51 #include <KLocalizedString>
52 #include <KNotification>
53 #include <KGlobalSettings>
54 #include <KIO/NetAccess>
55 #if defined(HAVE_LIBKONQ)
56 #include <konq_operations.h>
60 #include <KMessageBox>
75 using namespace Konsole;
78 #define loc(X,Y) ((Y)*_columns+(X))
81 #define REPCHAR "ABCDEFGHIJKLMNOPQRSTUVWXYZ" \
82 "abcdefgjijklmnopqrstuvwxyz" \
105 return _screenWindow;
111 disconnect(_screenWindow , 0 ,
this , 0);
114 _screenWindow = window;
118 connect(_screenWindow , SIGNAL(outputChanged()) ,
this , SLOT(
updateImage()));
119 connect(_screenWindow , SIGNAL(currentResultLineChanged()) ,
this , SLOT(
updateImage()));
120 _screenWindow->setWindowLines(_lines);
132 QPalette p = palette();
133 p.setColor(backgroundRole(), color);
137 _scrollBar->setPalette(QApplication::palette());
143 QPalette p = palette();
144 return p.color(backgroundRole());
155 _colorTable[i] = table[i];
168 if (
string.length() == 0)
176 QFontMetrics fm(font());
177 _fontHeight = fm.height() + _lineSpacing;
183 _fontWidth = qRound((static_cast<double>(fm.width(
REPCHAR)) / static_cast<double>(qstrlen(
REPCHAR))));
187 const int fw = fm.width(
REPCHAR[0]);
188 for (
unsigned int i = 1; i < qstrlen(
REPCHAR); i++) {
189 if (fw != fm.width(
REPCHAR[i])) {
198 _fontAscent = fm.ascent();
209 QFontMetrics metrics(font);
211 if (!QFontInfo(font).fixedPitch()) {
212 kWarning() <<
"Using an unsupported variable-width font in the terminal. This may produce display errors.";
215 if (metrics.height() < height() && metrics.maxWidth() < width()) {
219 font.setStyleStrategy(QFont::NoAntialias);
224 font.setKerning(
false);
227 font.setStyleStrategy(QFont::StyleStrategy(font.styleStrategy() | QFont::ForceIntegerMetrics));
229 QWidget::setFont(font);
242 font.setPointSizeF(font.pointSizeF() + 1);
248 const qreal MinimumFontSize = 6;
251 font.setPointSizeF(qMax(font.pointSizeF() - 1, MinimumFontSize));
310 , _showTerminalSizeHint(true)
311 , _bidiEnabled(false)
313 , _wordSelectionMode(false)
314 , _lineSelectionMode(false)
315 , _preserveLineBreaks(false)
316 , _columnSelectionMode(false)
317 , _autoCopySelectedText(false)
318 , _middleClickPasteMode(
Enum::PasteFromX11Selection)
319 , _scrollbarLocation(
Enum::ScrollBarRight)
320 , _scrollFullPage(false)
321 , _wordCharacters(
":@-./_~")
322 , _bellMode(
Enum::NotifyBell)
323 , _allowBlinkingText(true)
324 , _allowBlinkingCursor(false)
325 , _textBlinking(false)
326 , _cursorBlinking(false)
327 , _hasTextBlinker(false)
328 , _underlineLinks(true)
329 , _openLinksByDirectClick(false)
330 , _isFixedSize(false)
331 , _ctrlRequiredForDrag(true)
332 , _tripleClickMode(
Enum::SelectWholeLine)
333 , _possibleTripleClick(false)
336 , _flowControlWarningEnabled(false)
337 , _outputSuspendedLabel(0)
339 , _blendColor(qRgba(0, 0, 0, 0xff))
341 , _cursorShape(
Enum::BlockCursor)
342 , _antialiasText(true)
343 , _printerFriendly(false)
344 , _sessionController(0)
345 , _trimTrailingSpaces(false)
347 , _centerContents(false)
351 setLayoutDirection(Qt::LeftToRight);
353 _contentRect = QRect(_margin, _margin, 1, 1);
356 _scrollBar =
new QScrollBar(
this);
359 _scrollBar->setCursor(Qt::ArrowCursor);
360 connect(_scrollBar, SIGNAL(valueChanged(
int)),
362 connect(_scrollBar, SIGNAL(sliderMoved(
int)),
363 this, SLOT(viewScrolledByUser()));
366 _blinkTextTimer =
new QTimer(
this);
367 _blinkTextTimer->setInterval(TEXT_BLINK_DELAY);
368 connect(_blinkTextTimer, SIGNAL(timeout()),
this, SLOT(
blinkTextEvent()));
371 _blinkCursorTimer =
new QTimer(
this);
372 _blinkCursorTimer->setInterval(QApplication::cursorFlashTime() / 2);
373 connect(_blinkCursorTimer, SIGNAL(timeout()),
this, SLOT(
blinkCursorEvent()));
376 KCursor::setAutoHideCursor(
this,
true);
377 setMouseTracking(
true);
384 setAcceptDrops(
true);
387 setFocusPolicy(Qt::WheelFocus);
390 setAttribute(Qt::WA_InputMethodEnabled,
true);
394 setAttribute(Qt::WA_OpaquePaintEvent);
396 _gridLayout =
new QGridLayout(
this);
397 _gridLayout->setContentsMargins(0, 0, 0, 0);
399 setLayout(_gridLayout);
404 #ifndef QT_NO_ACCESSIBILITY
411 disconnect(_blinkTextTimer);
412 disconnect(_blinkCursorTimer);
417 delete _outputSuspendedLabel;
473 static void drawLineChar(QPainter& paint,
int x,
int y,
int w,
int h, uchar code)
476 const int cx = x + w / 2;
477 const int cy = y + h / 2;
478 const int ex = x + w - 1;
479 const int ey = y + h - 1;
485 paint.drawLine(cx - 1, y, cx - 1, cy - 2);
487 paint.drawLine(cx, y, cx, cy - 2);
489 paint.drawLine(cx + 1, y, cx + 1, cy - 2);
493 paint.drawLine(cx - 1, cy + 2, cx - 1, ey);
495 paint.drawLine(cx, cy + 2, cx, ey);
497 paint.drawLine(cx + 1, cy + 2, cx + 1, ey);
501 paint.drawLine(x, cy - 1, cx - 2, cy - 1);
503 paint.drawLine(x, cy, cx - 2, cy);
505 paint.drawLine(x, cy + 1, cx - 2, cy + 1);
509 paint.drawLine(cx + 2, cy - 1, ex, cy - 1);
511 paint.drawLine(cx + 2, cy, ex, cy);
513 paint.drawLine(cx + 2, cy + 1, ex, cy + 1);
517 paint.drawPoint(cx - 1, cy - 1);
519 paint.drawPoint(cx, cy - 1);
521 paint.drawPoint(cx + 1, cy - 1);
524 paint.drawPoint(cx - 1, cy);
526 paint.drawPoint(cx, cy);
528 paint.drawPoint(cx + 1, cy);
531 paint.drawPoint(cx - 1, cy + 1);
533 paint.drawPoint(cx, cy + 1);
535 paint.drawPoint(cx + 1, cy + 1);
538 void TerminalDisplay::drawLineCharString(QPainter& painter,
int x,
int y,
const QString& str,
541 const QPen& originalPen = painter.pen();
544 QPen boldPen(originalPen);
546 painter.setPen(boldPen);
549 for (
int i = 0 ; i < str.length(); i++) {
550 const uchar code = str[i].cell();
552 drawLineChar(painter, x + (_fontWidth * i), y, _fontWidth, _fontHeight, code);
555 painter.setPen(originalPen);
560 _cursorShape = shape;
568 _cursorColor = color;
577 QColor color(_blendColor);
578 color.setAlphaF(opacity);
591 _blendColor = color.rgba();
599 void TerminalDisplay::drawBackground(QPainter& painter,
const QRect& rect,
const QColor& backgroundColor,
bool useOpacitySetting)
609 QRect scrollBarArea = _scrollBar->isVisible() ?
610 rect.intersected(_scrollBar->geometry()) :
612 QRegion contentsRegion = QRegion(rect).subtracted(scrollBarArea);
613 QRect contentsRect = contentsRegion.boundingRect();
615 if (useOpacitySetting && !_wallpaper->isNull() &&
616 _wallpaper->draw(painter, contentsRect)) {
617 }
else if (qAlpha(_blendColor) < 0xff && useOpacitySetting) {
621 QColor color(backgroundColor);
622 color.setAlpha(qAlpha(_blendColor));
625 painter.setCompositionMode(QPainter::CompositionMode_Source);
626 painter.fillRect(contentsRect, color);
629 painter.fillRect(contentsRect, backgroundColor);
632 painter.fillRect(scrollBarArea, _scrollBar->palette().background());
635 void TerminalDisplay::drawCursor(QPainter& painter,
637 const QColor& foregroundColor,
639 bool& invertCharacterColor)
645 QRect cursorRect = rect;
646 cursorRect.setHeight(_fontHeight - _lineSpacing - 1);
648 QColor cursorColor = _cursorColor.isValid() ? _cursorColor : foregroundColor;
649 painter.setPen(cursorColor);
654 int penWidth = qMax(1, painter.pen().width());
655 painter.drawRect(cursorRect.adjusted(penWidth / 2,
657 - penWidth / 2 - penWidth % 2,
658 - penWidth / 2 - penWidth % 2));
662 painter.fillRect(cursorRect, cursorColor);
664 if (!_cursorColor.isValid()) {
667 invertCharacterColor =
true;
671 painter.drawLine(cursorRect.left(),
674 cursorRect.bottom());
677 painter.drawLine(cursorRect.left(),
680 cursorRect.bottom());
684 void TerminalDisplay::drawCharacters(QPainter& painter,
688 bool invertCharacterColor)
704 QFont font = painter.font();
705 if (font.bold() != useBold
706 || font.underline() != useUnderline
707 || font.italic() != useItalic) {
708 font.setBold(useBold);
709 font.setUnderline(useUnderline);
710 font.setItalic(useItalic);
711 painter.setFont(font);
716 const QColor color = textColor.
color(_colorTable);
717 QPen pen = painter.pen();
718 if (pen.color() != color) {
720 painter.setPen(color);
725 drawLineCharString(painter, rect.x(), rect.y(), text, style);
731 painter.setLayoutDirection(Qt::LeftToRight);
741 painter.drawText(rect, 0, text);
744 #if QT_VERSION >= 0x040800
753 void TerminalDisplay::drawTextFragment(QPainter& painter ,
765 if (backgroundColor != palette().background().color())
766 drawBackground(painter, rect, backgroundColor,
771 bool invertCharacterColor =
false;
773 drawCursor(painter, rect, foregroundColor, backgroundColor, invertCharacterColor);
776 drawCharacters(painter, rect, text, style, invertCharacterColor);
781 void TerminalDisplay::drawPrinterFriendlyTextFragment(QPainter& painter,
795 drawCharacters(painter, rect, text, &print_style,
false);
817 void TerminalDisplay::scrollImage(
int lines ,
const QRect& screenWindowRegion)
822 if (_outputSuspendedLabel && _outputSuspendedLabel->isVisible())
829 QRect region = screenWindowRegion;
830 region.setBottom(qMin(region.bottom(), this->_lines - 2));
836 || (region.top() + abs(lines)) >= region.bottom()
837 || this->_lines <= region.height())
return;
840 if (_resizeWidget && _resizeWidget->isVisible())
841 _resizeWidget->hide();
853 const int scrollBarWidth = _scrollBar->isHidden() ? 0 : _scrollBar->width();
854 const int SCROLLBAR_CONTENT_GAP = 1;
857 scrollRect.setLeft(scrollBarWidth + SCROLLBAR_CONTENT_GAP);
858 scrollRect.setRight(width());
860 scrollRect.setLeft(0);
861 scrollRect.setRight(width() - scrollBarWidth - SCROLLBAR_CONTENT_GAP);
863 void* firstCharPos = &_image[ region.top() * this->_columns ];
864 void* lastCharPos = &_image[(region.top() + abs(lines)) * this->_columns ];
866 const int top = _contentRect.top() + (region.top() * _fontHeight);
867 const int linesToMove = region.height() - abs(lines);
868 const int bytesToMove = linesToMove * this->_columns *
sizeof(
Character);
870 Q_ASSERT(linesToMove > 0);
871 Q_ASSERT(bytesToMove > 0);
876 Q_ASSERT((
char*)lastCharPos + bytesToMove <
877 (
char*)(_image + (this->_lines * this->_columns)));
879 Q_ASSERT((lines * this->_columns) < _imageSize);
882 memmove(firstCharPos , lastCharPos , bytesToMove);
885 scrollRect.setTop(top);
888 Q_ASSERT((
char*)firstCharPos + bytesToMove <
889 (
char*)(_image + (this->_lines * this->_columns)));
892 memmove(lastCharPos , firstCharPos , bytesToMove);
895 scrollRect.setTop(top + abs(lines) * _fontHeight);
897 scrollRect.setHeight(linesToMove * _fontHeight);
899 Q_ASSERT(scrollRect.isValid() && !scrollRect.isEmpty());
902 scroll(0 , _fontHeight * (-lines) , scrollRect);
905 QRegion TerminalDisplay::hotSpotRegion()
const
914 r.setBottom(hotSpot->
endLine());
915 region |= imageToWidget(r);
919 r.setRight(_columns);
921 region |= imageToWidget(r);
922 for (
int line = hotSpot->
startLine() + 1 ; line < hotSpot->
endLine() ; line++) {
925 r.setRight(_columns);
927 region |= imageToWidget(r);
932 r.setBottom(hotSpot->
endLine());
933 region |= imageToWidget(r);
944 QRegion preUpdateHotSpots = hotSpotRegion();
951 _filterChain->
setImage(_screenWindow->getImage(),
952 _screenWindow->windowLines(),
953 _screenWindow->windowColumns(),
954 _screenWindow->getLineProperties());
957 QRegion postUpdateHotSpots = hotSpotRegion();
959 update(preUpdateHotSpots | postUpdateHotSpots);
970 if (_wallpaper->isNull()) {
971 scrollImage(_screenWindow->scrollCount() ,
972 _screenWindow->scrollRegion());
973 _screenWindow->resetScrollCount();
982 Character*
const newimg = _screenWindow->getImage();
983 const int lines = _screenWindow->windowLines();
984 const int columns = _screenWindow->windowColumns();
986 setScroll(_screenWindow->currentLine() , _screenWindow->lineCount());
988 Q_ASSERT(this->_usedLines <= this->_lines);
989 Q_ASSERT(this->_usedColumns <= this->_columns);
993 const QPoint tL = contentsRect().topLeft();
994 const int tLx = tL.x();
995 const int tLy = tL.y();
996 _hasTextBlinker =
false;
1000 const int linesToUpdate = qMin(this->_lines, qMax(0, lines));
1001 const int columnsToUpdate = qMin(this->_columns, qMax(0, columns));
1003 char* dirtyMask =
new char[columnsToUpdate + 2];
1004 QRegion dirtyRegion;
1009 int dirtyLineCount = 0;
1011 for (y = 0; y < linesToUpdate; ++y) {
1012 const Character* currentLine = &_image[y * this->_columns];
1015 bool updateLine =
false;
1020 memset(dirtyMask, 0, columnsToUpdate + 2);
1022 for (x = 0 ; x < columnsToUpdate ; ++x) {
1023 if (newLine[x] != currentLine[x]) {
1024 dirtyMask[x] =
true;
1029 for (x = 0; x < columnsToUpdate; ++x) {
1036 if (!newLine[x + 0].character)
1038 const bool lineDraw = newLine[x + 0].
isLineChar();
1039 const bool doubleWidth = (x + 1 == columnsToUpdate) ?
false : (newLine[x + 1].character == 0);
1042 if (newLine[x].foregroundColor != cf) cf = newLine[x].
foregroundColor;
1043 const int lln = columnsToUpdate - x;
1044 for (len = 1; len < lln; ++len) {
1050 const bool nextIsDoubleWidth = (x + len + 1 == columnsToUpdate) ?
false : (newLine[x + len + 1].character == 0);
1055 !dirtyMask[x + len] ||
1057 nextIsDoubleWidth != doubleWidth)
1061 const bool saveFixedFont = _fixedFont;
1069 _fixedFont = saveFixedFont;
1078 if (_lineProperties.count() > y)
1088 QRect dirtyRect = QRect(_contentRect.left() + tLx ,
1089 _contentRect.top() + tLy + _fontHeight * y ,
1090 _fontWidth * columnsToUpdate ,
1093 dirtyRegion |= dirtyRect;
1098 memcpy((
void*)currentLine, (
const void*)newLine, columnsToUpdate *
sizeof(
Character));
1103 if (linesToUpdate < _usedLines) {
1104 dirtyRegion |= QRect(_contentRect.left() + tLx ,
1105 _contentRect.top() + tLy + _fontHeight * linesToUpdate ,
1106 _fontWidth * this->_columns ,
1107 _fontHeight * (_usedLines - linesToUpdate));
1109 _usedLines = linesToUpdate;
1111 if (columnsToUpdate < _usedColumns) {
1112 dirtyRegion |= QRect(_contentRect.left() + tLx + columnsToUpdate * _fontWidth ,
1113 _contentRect.top() + tLy ,
1114 _fontWidth * (_usedColumns - columnsToUpdate) ,
1115 _fontHeight * this->_lines);
1117 _usedColumns = columnsToUpdate;
1119 dirtyRegion |= _inputMethodData.previousPreeditRect;
1122 update(dirtyRegion);
1124 if (_allowBlinkingText && _hasTextBlinker && !_blinkTextTimer->isActive()) {
1125 _blinkTextTimer->start();
1127 if (!_hasTextBlinker && _blinkTextTimer->isActive()) {
1128 _blinkTextTimer->stop();
1129 _textBlinking =
false;
1133 #if QT_VERSION >= 0x040800 // added in Qt 4.8.0
1134 #ifndef QT_NO_ACCESSIBILITY
1135 QAccessible::updateAccessibility(
this, 0, QAccessible::TextUpdated);
1136 QAccessible::updateAccessibility(
this, 0, QAccessible::TextCaretMoved);
1141 void TerminalDisplay::showResizeNotification()
1143 if (_showTerminalSizeHint && isVisible()) {
1144 if (!_resizeWidget) {
1145 _resizeWidget =
new QLabel(i18n(
"Size: XXX x XXX"),
this);
1146 _resizeWidget->setMinimumWidth(_resizeWidget->fontMetrics().width(i18n(
"Size: XXX x XXX")));
1147 _resizeWidget->setMinimumHeight(_resizeWidget->sizeHint().height());
1148 _resizeWidget->setAlignment(Qt::AlignCenter);
1150 _resizeWidget->setStyleSheet(
"background-color:palette(window);border-style:solid;border-width:1px;border-color:palette(dark)");
1152 _resizeTimer =
new QTimer(
this);
1153 _resizeTimer->setInterval(SIZE_HINT_DURATION);
1154 _resizeTimer->setSingleShot(
true);
1155 connect(_resizeTimer, SIGNAL(timeout()), _resizeWidget, SLOT(hide()));
1157 QString sizeStr = i18n(
"Size: %1 x %2", _columns, _lines);
1158 _resizeWidget->setText(sizeStr);
1159 _resizeWidget->move((width() - _resizeWidget->width()) / 2,
1160 (height() - _resizeWidget->height()) / 2 + 20);
1161 _resizeWidget->show();
1162 _resizeTimer->start();
1168 QPainter paint(
this);
1170 foreach(
const QRect & rect, (pe->region() & contentsRect()).rects()) {
1171 drawBackground(paint, rect, palette().background().color(),
1173 drawContents(paint, rect);
1175 drawCurrentResultRect(paint);
1176 drawInputMethodPreeditString(paint, preeditRect());
1177 paintFilters(paint);
1185 QFont font(savedFont, painter.device());
1186 painter.setFont(font);
1189 QRect rect(0, 0, size().width(), size().height());
1191 _printerFriendly = friendly;
1196 drawContents(painter, rect);
1197 _printerFriendly =
false;
1201 QPoint TerminalDisplay::cursorPosition()
const
1204 return _screenWindow->cursorPosition();
1206 return QPoint(0, 0);
1211 return _filterChain;
1214 void TerminalDisplay::paintFilters(QPainter& painter)
1218 QPoint cursorPos = mapFromGlobal(QCursor::pos());
1222 getCharacterPosition(cursorPos , cursorLine , cursorColumn);
1223 Character cursorCharacter = _image[
loc(cursorColumn, cursorLine)];
1236 r.setCoords(spot->
startColumn()*_fontWidth + _contentRect.left(),
1237 spot->
startLine()*_fontHeight + _contentRect.top(),
1238 (spot->
endColumn())*_fontWidth + _contentRect.left() - 1,
1239 (spot->
endLine() + 1)*_fontHeight + _contentRect.top() - 1);
1242 r.setCoords(spot->
startColumn()*_fontWidth + _contentRect.left(),
1243 spot->
startLine()*_fontHeight + _contentRect.top(),
1244 (_columns)*_fontWidth + _contentRect.left() - 1,
1245 (spot->
startLine() + 1)*_fontHeight + _contentRect.top() - 1);
1248 r.setCoords(0 * _fontWidth + _contentRect.left(),
1249 line * _fontHeight + _contentRect.top(),
1250 (_columns)*_fontWidth + _contentRect.left() - 1,
1251 (line + 1)*_fontHeight + _contentRect.top() - 1);
1254 r.setCoords(0 * _fontWidth + _contentRect.left(),
1255 spot->
endLine()*_fontHeight + _contentRect.top(),
1256 (spot->
endColumn())*_fontWidth + _contentRect.left() - 1,
1257 (spot->
endLine() + 1)*_fontHeight + _contentRect.top() - 1);
1263 int startColumn = 0;
1264 int endColumn = _columns - 1;
1269 if (
loc(endColumn, line) > _imageSize)
1273 while (_image[
loc(endColumn, line)].isSpace() && endColumn > 0)
1296 r.setCoords(startColumn * _fontWidth + _contentRect.left(),
1297 line * _fontHeight + _contentRect.top(),
1298 endColumn * _fontWidth + _contentRect.left() - 1,
1299 (line + 1)*_fontHeight + _contentRect.top() - 1);
1302 QFontMetrics metrics(font());
1306 const int baseline = r.bottom() - metrics.descent();
1308 const int underlinePos = baseline + metrics.underlinePos();
1309 if (region.contains(mapFromGlobal(QCursor::pos()))) {
1310 painter.drawLine(r.left() , underlinePos ,
1311 r.right() , underlinePos);
1317 const bool isCurrentResultLine = (_screenWindow->currentResultLine() == (spot->
startLine() + _screenWindow->currentLine()));
1318 QColor color = isCurrentResultLine ? QColor(255, 255, 0, 120) : QColor(255, 0, 0, 120);
1319 painter.fillRect(r, color);
1324 void TerminalDisplay::drawContents(QPainter& paint,
const QRect& rect)
1326 const QPoint tL = contentsRect().topLeft();
1327 const int tLx = tL.x();
1328 const int tLy = tL.y();
1330 const int lux = qMin(_usedColumns - 1, qMax(0, (rect.left() - tLx - _contentRect.left()) / _fontWidth));
1331 const int luy = qMin(_usedLines - 1, qMax(0, (rect.top() - tLy - _contentRect.top()) / _fontHeight));
1332 const int rlx = qMin(_usedColumns - 1, qMax(0, (rect.right() - tLx - _contentRect.left()) / _fontWidth));
1333 const int rly = qMin(_usedLines - 1, qMax(0, (rect.bottom() - tLy - _contentRect.top()) / _fontHeight));
1335 const int numberOfColumns = _usedColumns;
1337 unistr.reserve(numberOfColumns);
1338 for (
int y = luy; y <= rly; y++) {
1340 if (!_image[
loc(lux, y)].character && x)
1342 for (; x <= rlx; x++) {
1347 int bufferSize = numberOfColumns;
1348 unistr.resize(bufferSize);
1349 QChar *disstrU = unistr.data();
1354 ushort extendedCharLength = 0;
1357 Q_ASSERT(extendedCharLength > 1);
1358 bufferSize += extendedCharLength - 1;
1359 unistr.resize(bufferSize);
1360 disstrU = unistr.data();
1361 for (
int index = 0 ; index < extendedCharLength ; index++) {
1362 Q_ASSERT(p < bufferSize);
1363 disstrU[p++] = chars[index];
1370 Q_ASSERT(p < bufferSize);
1376 const bool doubleWidth = (_image[ qMin(
loc(x, y) + 1, _imageSize) ].
character == 0);
1379 const quint8 currentRendition = _image[
loc(x, y)].
rendition;
1381 while (x + len <= rlx &&
1382 _image[
loc(x + len, y)].foregroundColor == currentForeground &&
1383 _image[
loc(x + len, y)].backgroundColor == currentBackground &&
1384 (_image[
loc(x + len, y)].rendition & ~RE_EXTENDED_CHAR) == (currentRendition & ~RE_EXTENDED_CHAR) &&
1385 (_image[ qMin(
loc(x + len, y) + 1, _imageSize) ].character == 0) == doubleWidth &&
1386 _image[
loc(x + len, y)].isLineChar() == lineDraw) {
1388 if (_image[
loc(x + len, y)].rendition & RE_EXTENDED_CHAR) {
1390 ushort extendedCharLength = 0;
1393 Q_ASSERT(extendedCharLength > 1);
1394 bufferSize += extendedCharLength - 1;
1395 unistr.resize(bufferSize);
1396 disstrU = unistr.data();
1397 for (
int index = 0 ; index < extendedCharLength ; index++) {
1398 Q_ASSERT(p < bufferSize);
1399 disstrU[p++] = chars[index];
1405 Q_ASSERT(p < bufferSize);
1414 if ((x + len < _usedColumns) && (!_image[
loc(x + len, y)].character))
1417 const bool save__fixedFont = _fixedFont;
1427 if (y < _lineProperties.size()) {
1429 textScale.scale(2, 1);
1432 textScale.scale(1, 2);
1436 paint.setWorldMatrix(textScale,
true);
1439 QRect textArea = QRect(_contentRect.left() + tLx + _fontWidth * x , _contentRect.top() + tLy + _fontHeight * y , _fontWidth * len , _fontHeight);
1447 textArea.moveTopLeft(textScale.inverted().map(textArea.topLeft()));
1450 if (_printerFriendly) {
1451 drawPrinterFriendlyTextFragment(paint,
1454 &_image[
loc(x, y)]);
1456 drawTextFragment(paint,
1459 &_image[
loc(x, y)]);
1462 _fixedFont = save__fixedFont;
1465 paint.setWorldMatrix(textScale.inverted(),
true);
1467 if (y < _lineProperties.size() - 1) {
1473 if (_lineProperties[y] & LINE_DOUBLEHEIGHT)
1482 void TerminalDisplay::drawCurrentResultRect(QPainter& painter)
1484 if(_screenWindow->currentResultLine() == -1) {
1488 QRect r(0, (_screenWindow->currentResultLine() - _screenWindow->currentLine())*_fontHeight,
1489 contentsRect().width(), _fontHeight);
1490 painter.fillRect(r, QColor(0, 0, 255, 80));
1493 QRect TerminalDisplay::imageToWidget(
const QRect& imageArea)
const
1496 result.setLeft(_contentRect.left() + _fontWidth * imageArea.left());
1497 result.setTop(_contentRect.top() + _fontHeight * imageArea.top());
1498 result.setWidth(_fontWidth * imageArea.width());
1499 result.setHeight(_fontHeight * imageArea.height());
1512 _allowBlinkingCursor = blink;
1514 if (blink && !_blinkCursorTimer->isActive())
1515 _blinkCursorTimer->start();
1517 if (!blink && _blinkCursorTimer->isActive()) {
1518 _blinkCursorTimer->stop();
1519 if (_cursorBlinking) {
1523 Q_ASSERT(_cursorBlinking ==
false);
1529 _allowBlinkingText = blink;
1531 if (blink && !_blinkTextTimer->isActive())
1532 _blinkTextTimer->start();
1534 if (!blink && _blinkTextTimer->isActive()) {
1535 _blinkTextTimer->stop();
1536 _textBlinking =
false;
1546 _cursorBlinking =
false;
1550 _blinkCursorTimer->stop();
1551 Q_ASSERT(_cursorBlinking ==
false);
1558 _blinkTextTimer->stop();
1559 Q_ASSERT(_textBlinking ==
false);
1564 if (_allowBlinkingCursor)
1565 _blinkCursorTimer->start();
1569 if (_allowBlinkingText && _hasTextBlinker)
1570 _blinkTextTimer->start();
1575 Q_ASSERT(_allowBlinkingText);
1577 _textBlinking = !_textBlinking;
1586 Q_ASSERT(_allowBlinkingCursor);
1588 _cursorBlinking = !_cursorBlinking;
1592 void TerminalDisplay::updateCursor()
1594 QRect cursorRect = imageToWidget(QRect(cursorPosition(), QSize(1, 1)));
1609 void TerminalDisplay::propagateSize()
1614 parentWidget()->adjustSize();
1615 parentWidget()->setFixedSize(parentWidget()->
sizeHint());
1622 void TerminalDisplay::updateImageSize()
1625 const int oldLines = _lines;
1626 const int oldColumns = _columns;
1632 int lines = qMin(oldLines, _lines);
1633 int columns = qMin(oldColumns, _columns);
1634 for (
int line = 0; line <
lines; line++) {
1635 memcpy((
void*)&_image[_columns * line],
1636 (
void*)&oldImage[oldColumns * line],
1643 _screenWindow->setWindowLines(_lines);
1645 _resizing = (oldLines != _lines) || (oldColumns != _columns);
1648 showResizeNotification();
1655 void TerminalDisplay::makeImage()
1663 Q_ASSERT(_lines > 0 && _columns > 0);
1664 Q_ASSERT(_usedLines <= _lines && _usedColumns <= _columns);
1666 _imageSize = _lines * _columns;
1677 for (
int i = 0; i <= _imageSize; ++i)
1681 void TerminalDisplay::calcGeometry()
1683 _scrollBar->resize(_scrollBar->sizeHint().width(), contentsRect().height());
1684 _contentRect = contentsRect().adjusted(_margin, _margin, -_margin, -_margin);
1686 switch (_scrollbarLocation) {
1690 _contentRect.setLeft(_contentRect.left() + _scrollBar->width());
1691 _scrollBar->move(contentsRect().topLeft());
1694 _contentRect.setRight(_contentRect.right() - _scrollBar->width());
1695 _scrollBar->move(contentsRect().topRight() - QPoint(_scrollBar->width() - 1, 0));
1699 if (!_isFixedSize) {
1701 _columns = qMax(1, _contentRect.width() / _fontWidth);
1702 _usedColumns = qMin(_usedColumns, _columns);
1705 _lines = qMax(1, _contentRect.height() / _fontHeight);
1706 _usedLines = qMin(_usedLines, _lines);
1708 if(_centerContents) {
1709 QSize unusedPixels = _contentRect.size() - QSize(_columns * _fontWidth, _lines * _fontHeight);
1710 _contentRect.adjust(unusedPixels.width() / 2, unusedPixels.height() / 2, 0, 0);
1718 const int scrollBarWidth = _scrollBar->isHidden() ? 0 : _scrollBar->sizeHint().width();
1719 const int horizontalMargin = _margin * 2;
1720 const int verticalMargin = _margin * 2;
1722 QSize newSize = QSize(horizontalMargin + scrollBarWidth + (columns * _fontWidth) ,
1723 verticalMargin + (lines * _fontHeight));
1725 if (newSize != size()) {
1733 _isFixedSize =
true;
1736 _columns = qMax(1, cols);
1737 _lines = qMax(1, lins);
1738 _usedColumns = qMin(_usedColumns, _columns);
1739 _usedLines = qMin(_usedLines, _lines);
1746 QWidget::setFixedSize(_size);
1776 _centerContents = enable;
1789 if (_scrollbarLocation == position)
1797 _scrollbarLocation = position;
1808 _screenWindow->scrollTo(_scrollBar->value());
1814 const bool atEndOfOutput = (_scrollBar->value() == _scrollBar->maximum());
1815 _screenWindow->setTrackOutput(atEndOfOutput);
1827 if (_scrollBar->minimum() == 0 &&
1828 _scrollBar->maximum() == (slines - _lines) &&
1829 _scrollBar->value() == cursor) {
1834 _scrollBar->setRange(0, slines - _lines);
1835 _scrollBar->setSingleStep(1);
1836 _scrollBar->setPageStep(_lines);
1837 _scrollBar->setValue(cursor);
1843 _scrollFullPage = fullPage;
1848 return _scrollFullPage;
1858 if (_possibleTripleClick && (ev->button() == Qt::LeftButton)) {
1863 if (!contentsRect().contains(ev->pos()))
return;
1865 if (!_screenWindow)
return;
1869 getCharacterPosition(ev->pos(), charLine, charColumn);
1870 QPoint pos = QPoint(charColumn, charLine);
1872 if (ev->button() == Qt::LeftButton) {
1874 if (qApp->autoSipEnabled()) {
1875 QStyle::RequestSoftwareInputPanel behavior = QStyle::RequestSoftwareInputPanel(
1876 style()->styleHint(QStyle::SH_RequestSoftwareInputPanel));
1877 if (hasFocus() || behavior == QStyle::RSIP_OnMouseClick) {
1878 QEvent
event(QEvent::RequestSoftwareInputPanel);
1879 QApplication::sendEvent(
this, &event);
1883 _lineSelectionMode =
false;
1884 _wordSelectionMode =
false;
1887 bool selected = _screenWindow->isSelected(pos.x(), pos.y());
1890 if ((!_ctrlRequiredForDrag || ev->modifiers() & Qt::ControlModifier) && selected) {
1897 _preserveLineBreaks = !((ev->modifiers() & Qt::ControlModifier) && !(ev->modifiers() & Qt::AltModifier));
1898 _columnSelectionMode = (ev->modifiers() & Qt::AltModifier) && (ev->modifiers() & Qt::ControlModifier);
1900 if (_mouseMarks || (ev->modifiers() == Qt::ShiftModifier)) {
1902 if (_mouseMarks && (ev->modifiers() == Qt::ShiftModifier)) {
1905 _screenWindow->clearSelection();
1907 pos.ry() += _scrollBar->value();
1908 _iPntSel = _pntSel = pos;
1912 emit
mouseSignal(0, charColumn + 1, charLine + 1 + _scrollBar->value() - _scrollBar->maximum() , 0);
1915 if (_underlineLinks && (_openLinksByDirectClick || (ev->modifiers() & Qt::ControlModifier))) {
1919 action.setObjectName(
"open-action");
1924 }
else if (ev->button() == Qt::MidButton) {
1925 processMidButtonClick(ev);
1926 }
else if (ev->button() == Qt::RightButton) {
1927 if (_mouseMarks || (ev->modifiers() & Qt::ShiftModifier))
1930 emit
mouseSignal(2, charColumn + 1, charLine + 1 + _scrollBar->value() - _scrollBar->maximum() , 0);
1936 int charLine, charColumn;
1937 getCharacterPosition(position, charLine, charColumn);
1948 getCharacterPosition(ev->pos(), charLine, charColumn);
1954 if (_underlineLinks) {
1955 QRegion previousHotspotArea = _mouseOverHotspotArea;
1956 _mouseOverHotspotArea = QRegion();
1958 if (spot->startLine() == spot->endLine()) {
1959 r.setCoords(spot->startColumn()*_fontWidth + _contentRect.left(),
1960 spot->startLine()*_fontHeight + _contentRect.top(),
1961 (spot->endColumn())*_fontWidth + _contentRect.left() - 1,
1962 (spot->endLine() + 1)*_fontHeight + _contentRect.top() - 1);
1963 _mouseOverHotspotArea |= r;
1965 r.setCoords(spot->startColumn()*_fontWidth + _contentRect.left(),
1966 spot->startLine()*_fontHeight + _contentRect.top(),
1967 (_columns)*_fontWidth + _contentRect.left() - 1,
1968 (spot->startLine() + 1)*_fontHeight + _contentRect.top() - 1);
1969 _mouseOverHotspotArea |= r;
1970 for (
int line = spot->startLine() + 1 ; line < spot->endLine() ; line++) {
1971 r.setCoords(0 * _fontWidth + _contentRect.left(),
1972 line * _fontHeight + _contentRect.top(),
1973 (_columns)*_fontWidth + _contentRect.left() - 1,
1974 (line + 1)*_fontHeight + _contentRect.top() - 1);
1975 _mouseOverHotspotArea |= r;
1977 r.setCoords(0 * _fontWidth + _contentRect.left(),
1978 spot->endLine()*_fontHeight + _contentRect.top(),
1979 (spot->endColumn())*_fontWidth + _contentRect.left() - 1,
1980 (spot->endLine() + 1)*_fontHeight + _contentRect.top() - 1);
1981 _mouseOverHotspotArea |= r;
1984 if ((_openLinksByDirectClick || (ev->modifiers() & Qt::ControlModifier)) && (cursor().shape() != Qt::PointingHandCursor))
1985 setCursor(Qt::PointingHandCursor);
1987 update(_mouseOverHotspotArea | previousHotspotArea);
1989 }
else if (!_mouseOverHotspotArea.isEmpty()) {
1990 if ((_underlineLinks && (_openLinksByDirectClick || (ev->modifiers() & Qt::ControlModifier))) || (cursor().shape() == Qt::PointingHandCursor))
1991 setCursor(_mouseMarks ? Qt::IBeamCursor : Qt::ArrowCursor);
1993 update(_mouseOverHotspotArea);
1995 _mouseOverHotspotArea = QRegion();
1999 if (ev->buttons() == Qt::NoButton)
return;
2004 if (!_mouseMarks && !(ev->modifiers() & Qt::ShiftModifier)) {
2006 if (ev->buttons() & Qt::LeftButton)
2008 if (ev->buttons() & Qt::MidButton)
2010 if (ev->buttons() & Qt::RightButton)
2015 charLine + 1 + _scrollBar->value() - _scrollBar->maximum(),
2025 const int distance = KGlobalSettings::dndEventDelay();
2030 _screenWindow->clearSelection();
2040 if (_actSel == 0)
return;
2043 if (ev->buttons() & Qt::MidButton)
return;
2051 if(!_mouseOverHotspotArea.isEmpty()) {
2052 update(_mouseOverHotspotArea);
2053 _mouseOverHotspotArea = QRegion();
2063 const QPoint tL = contentsRect().topLeft();
2064 const int tLx = tL.x();
2065 const int tLy = tL.y();
2066 const int scroll = _scrollBar->value();
2072 int linesBeyondWidget = 0;
2074 QRect textBounds(tLx + _contentRect.left(),
2075 tLy + _contentRect.top(),
2076 _usedColumns * _fontWidth - 1,
2077 _usedLines * _fontHeight - 1);
2079 QPoint pos = position;
2082 const QPoint oldpos = pos;
2084 pos.setX(qBound(textBounds.left(), pos.x(), textBounds.right()));
2085 pos.setY(qBound(textBounds.top(), pos.y(), textBounds.bottom()));
2087 if (oldpos.y() > textBounds.bottom()) {
2088 linesBeyondWidget = (oldpos.y() - textBounds.bottom()) / _fontHeight;
2089 _scrollBar->setValue(_scrollBar->value() + linesBeyondWidget + 1);
2091 if (oldpos.y() < textBounds.top()) {
2092 linesBeyondWidget = (textBounds.top() - oldpos.y()) / _fontHeight;
2093 _scrollBar->setValue(_scrollBar->value() - linesBeyondWidget - 1);
2098 getCharacterPosition(pos, charLine, charColumn);
2100 QPoint here = QPoint(charColumn, charLine);
2102 QPoint _iPntSelCorr = _iPntSel;
2103 _iPntSelCorr.ry() -= _scrollBar->value();
2104 QPoint _pntSelCorr = _pntSel;
2105 _pntSelCorr.ry() -= _scrollBar->value();
2106 bool swapping =
false;
2108 if (_wordSelectionMode) {
2113 const bool left_not_right = (here.y() < _iPntSelCorr.y() ||
2114 (here.y() == _iPntSelCorr.y() && here.x() < _iPntSelCorr.x()));
2115 const bool old_left_not_right = (_pntSelCorr.y() < _iPntSelCorr.y() ||
2116 (_pntSelCorr.y() == _iPntSelCorr.y() && _pntSelCorr.x() < _iPntSelCorr.x()));
2117 swapping = left_not_right != old_left_not_right;
2120 QPoint left = left_not_right ? here : _iPntSelCorr;
2121 i =
loc(left.x(), left.y());
2122 if (i >= 0 && i <= _imageSize) {
2124 while (((left.x() > 0) || (left.y() > 0 && (_lineProperties[left.y() - 1] &
LINE_WRAPPED)))
2125 &&
charClass(_image[i - 1]) == selClass) {
2130 left.rx() = _usedColumns - 1;
2137 QPoint right = left_not_right ? _iPntSelCorr : here;
2138 i =
loc(right.x(), right.y());
2139 if (i >= 0 && i <= _imageSize) {
2141 while (((right.x() < _usedColumns - 1) || (right.y() < _usedLines - 1 && (_lineProperties[right.y()] &
LINE_WRAPPED)))
2142 &&
charClass(_image[i + 1]) == selClass) {
2144 if (right.x() < _usedColumns - 1) {
2154 if (left_not_right) {
2164 if (_lineSelectionMode) {
2166 const bool above_not_below = (here.y() < _iPntSelCorr.y());
2167 if (above_not_below) {
2168 ohere = findLineEnd(_iPntSelCorr);
2169 here = findLineStart(here);
2171 ohere = findLineStart(_iPntSelCorr);
2172 here = findLineEnd(here);
2175 swapping = !(_tripleSelBegin == ohere);
2176 _tripleSelBegin = ohere;
2182 if (!_wordSelectionMode && !_lineSelectionMode) {
2185 const bool left_not_right = (here.y() < _iPntSelCorr.y() ||
2186 (here.y() == _iPntSelCorr.y() && here.x() < _iPntSelCorr.x()));
2187 const bool old_left_not_right = (_pntSelCorr.y() < _iPntSelCorr.y() ||
2188 (_pntSelCorr.y() == _iPntSelCorr.y() && _pntSelCorr.x() < _iPntSelCorr.x()));
2189 swapping = left_not_right != old_left_not_right;
2192 const QPoint left = left_not_right ? here : _iPntSelCorr;
2195 QPoint right = left_not_right ? _iPntSelCorr : here;
2196 if (right.x() > 0 && !_columnSelectionMode) {
2197 int i =
loc(right.x(), right.y());
2198 if (i >= 0 && i <= _imageSize) {
2214 if (left_not_right) {
2225 if ((here == _pntSelCorr) && (scroll == _scrollBar->value()))
return;
2227 if (here == ohere)
return;
2229 if (_actSel < 2 || swapping) {
2230 if (_columnSelectionMode && !_lineSelectionMode && !_wordSelectionMode) {
2231 _screenWindow->setSelectionStart(ohere.x() , ohere.y() ,
true);
2233 _screenWindow->setSelectionStart(ohere.x() - 1 - offset , ohere.y() ,
false);
2239 _pntSel.ry() += _scrollBar->value();
2241 if (_columnSelectionMode && !_lineSelectionMode && !_wordSelectionMode) {
2242 _screenWindow->setSelectionEnd(here.x() , here.y());
2244 _screenWindow->setSelectionEnd(here.x() + offset , here.y());
2255 getCharacterPosition(ev->pos(), charLine, charColumn);
2257 if (ev->button() == Qt::LeftButton) {
2260 _screenWindow->clearSelection();
2272 if (!_mouseMarks && !(ev->modifiers() & Qt::ShiftModifier))
2275 charLine + 1 + _scrollBar->value() - _scrollBar->maximum() , 2);
2281 (ev->button() == Qt::RightButton || ev->button() == Qt::MidButton) &&
2282 !(ev->modifiers() & Qt::ShiftModifier)) {
2283 emit
mouseSignal(ev->button() == Qt::MidButton ? 1 : 2,
2285 charLine + 1 + _scrollBar->value() - _scrollBar->maximum() ,
2290 void TerminalDisplay::getCharacterPosition(
const QPoint& widgetPoint,
int& line,
int& column)
const
2292 column = (widgetPoint.x() + _fontWidth / 2 - contentsRect().left() - _contentRect.left()) / _fontWidth;
2293 line = (widgetPoint.y() - contentsRect().top() - _contentRect.top()) / _fontHeight;
2300 if (line >= _usedLines)
2301 line = _usedLines - 1;
2308 if (column > _usedColumns)
2309 column = _usedColumns;
2317 _lineProperties = _screenWindow->getLineProperties();
2320 void TerminalDisplay::processMidButtonClick(QMouseEvent* ev)
2322 if (_mouseMarks || (ev->modifiers() & Qt::ShiftModifier)) {
2323 const bool appendEnter = ev->modifiers() & Qt::ControlModifier;
2335 getCharacterPosition(ev->pos(), charLine, charColumn);
2337 emit
mouseSignal(1, charColumn + 1, charLine + 1 + _scrollBar->value() - _scrollBar->maximum() , 0);
2344 if (ev->button() == Qt::MidButton) {
2345 processMidButtonClick(ev);
2349 if (ev->button() != Qt::LeftButton)
return;
2350 if (!_screenWindow)
return;
2355 getCharacterPosition(ev->pos(), charLine, charColumn);
2357 QPoint pos(charColumn, charLine);
2360 if (!_mouseMarks && !(ev->modifiers() & Qt::ShiftModifier)) {
2365 pos.y() + 1 + _scrollBar->value() - _scrollBar->maximum(),
2370 _screenWindow->clearSelection();
2371 QPoint bgnSel = pos;
2372 QPoint endSel = pos;
2373 int i =
loc(bgnSel.x(), bgnSel.y());
2375 _iPntSel.ry() += _scrollBar->value();
2377 _wordSelectionMode =
true;
2380 const QChar selClass =
charClass(_image[i]);
2384 while (((x > 0) || (bgnSel.y() > 0 && (_lineProperties[bgnSel.y() - 1] &
LINE_WRAPPED)))
2385 &&
charClass(_image[i - 1]) == selClass) {
2390 x = _usedColumns - 1;
2396 _screenWindow->setSelectionStart(bgnSel.x() , bgnSel.y() ,
false);
2399 i =
loc(endSel.x(), endSel.y());
2401 while (((x < _usedColumns - 1) || (endSel.y() < _usedLines - 1 && (_lineProperties[endSel.y()] &
LINE_WRAPPED)))
2402 &&
charClass(_image[i + 1]) == selClass) {
2404 if (x < _usedColumns - 1) {
2415 if (((_image[i].rendition & RE_EXTENDED_CHAR) == 0) &&
2416 (QChar(_image[i].character) ==
'@') &&
2417 ((endSel.x() - bgnSel.x()) > 0)) {
2423 _screenWindow->setSelectionEnd(endSel.x() , endSel.y());
2428 _possibleTripleClick =
true;
2430 QTimer::singleShot(QApplication::doubleClickInterval(),
this,
2431 SLOT(tripleClickTimeout()));
2437 if (ev->orientation() != Qt::Vertical)
2440 const int modifiers = ev->modifiers();
2441 const int delta = ev->delta();
2461 const bool canScroll = _scrollBar->maximum() > 0;
2463 _scrollBar->event(ev);
2472 const int keyCode = delta > 0 ? Qt::Key_Up : Qt::Key_Down;
2473 QKeyEvent keyEvent(QEvent::KeyPress, keyCode, Qt::NoModifier);
2476 const int degrees = delta / 8;
2477 const int lines = abs(degrees) / 5;
2479 for (
int i = 0; i <
lines; i++)
2487 getCharacterPosition(ev->pos() , charLine , charColumn);
2491 charLine + 1 + _scrollBar->value() - _scrollBar->maximum() ,
2496 void TerminalDisplay::tripleClickTimeout()
2498 _possibleTripleClick =
false;
2501 void TerminalDisplay::viewScrolledByUser()
2510 QPoint TerminalDisplay::findLineStart(
const QPoint &pnt)
2512 const int visibleScreenLines = _lineProperties.size();
2513 const int topVisibleLine = _screenWindow->currentLine();
2514 Screen *screen = _screenWindow->screen();
2516 int lineInHistory= line + topVisibleLine;
2518 QVector<LineProperty> lineProperties = _lineProperties;
2520 while (lineInHistory > 0) {
2521 for (; line > 0; line--, lineInHistory--) {
2524 return QPoint(0, lineInHistory - topVisibleLine);
2528 if (lineInHistory < 1)
2532 int newRegionStart = qMax(0, lineInHistory - visibleScreenLines);
2534 line = lineInHistory - newRegionStart;
2536 return QPoint(0, lineInHistory - topVisibleLine);
2542 QPoint TerminalDisplay::findLineEnd(
const QPoint &pnt)
2544 const int visibleScreenLines = _lineProperties.size();
2545 const int topVisibleLine = _screenWindow->currentLine();
2546 const int maxY = _screenWindow->lineCount() - 1;
2547 Screen *screen = _screenWindow->screen();
2549 int lineInHistory= line + topVisibleLine;
2551 QVector<LineProperty> lineProperties = _lineProperties;
2553 while (lineInHistory < maxY) {
2554 for (; line < lineProperties.count() && lineInHistory < maxY; line++, lineInHistory++) {
2557 return QPoint(_columns - 1, lineInHistory - topVisibleLine);
2562 lineProperties = screen->
getLineProperties(lineInHistory, qMin(lineInHistory + visibleScreenLines, maxY));
2564 return QPoint(_columns - 1, lineInHistory - topVisibleLine);
2569 if (!_screenWindow)
return;
2573 getCharacterPosition(ev->pos(), charLine, charColumn);
2574 _iPntSel = QPoint(charColumn, charLine);
2576 _screenWindow->clearSelection();
2578 _lineSelectionMode =
true;
2579 _wordSelectionMode =
false;
2583 while (_iPntSel.y() > 0 && (_lineProperties[_iPntSel.y() - 1] &
LINE_WRAPPED))
2588 int i =
loc(_iPntSel.x(), _iPntSel.y());
2589 const QChar selClass =
charClass(_image[i]);
2590 int x = _iPntSel.x();
2593 (_iPntSel.y() > 0 && (_lineProperties[_iPntSel.y() - 1] &
LINE_WRAPPED))
2595 &&
charClass(_image[i - 1]) == selClass) {
2605 _screenWindow->setSelectionStart(x , _iPntSel.y() ,
false);
2606 _tripleSelBegin = QPoint(x, _iPntSel.y());
2609 _iPntSel = QPoint(charColumn, charLine);
2610 _tripleSelBegin = findLineStart(_iPntSel);
2611 _screenWindow->setSelectionStart(0 , _tripleSelBegin.y() ,
false);
2614 _iPntSel = findLineEnd(_iPntSel);
2615 _screenWindow->setSelectionEnd(_iPntSel.x() , _iPntSel.y());
2619 _iPntSel.ry() += _scrollBar->value();
2629 return QWidget::focusNextPrevChild(next);
2635 ushort extendedCharLength = 0;
2637 if (chars && extendedCharLength > 0) {
2638 const QString s = QString::fromUtf16(chars, extendedCharLength);
2639 if (_wordCharacters.contains(s, Qt::CaseInsensitive))
2641 bool allLetterOrNumber =
true;
2642 for (
int i = 0; allLetterOrNumber && i < s.size(); ++i)
2643 allLetterOrNumber = s.at(i).isLetterOrNumber();
2644 return allLetterOrNumber ?
'a' : s.at(0);
2649 if (qch.isSpace())
return ' ';
2651 if (qch.isLetterOrNumber() || _wordCharacters.contains(qch, Qt::CaseInsensitive))
2660 _wordCharacters = wc;
2669 setCursor(_mouseMarks ? Qt::IBeamCursor : Qt::ArrowCursor);
2682 void TerminalDisplay::doPaste(QString text,
bool appendReturn)
2690 if (text.length() > 8000) {
2691 if (KMessageBox::warningContinueCancel(window(),
2692 i18np(
"Are you sure you want to paste %1 character?",
2693 "Are you sure you want to paste %1 characters?",
2695 i18n(
"Confirm Paste"),
2696 KStandardGuiItem::cont(),
2697 KStandardGuiItem::cancel(),
2698 "ShowPasteHugeTextWarning") == KMessageBox::Cancel)
2702 if (!text.isEmpty()) {
2703 text.replace(
'\n',
'\r');
2705 QKeyEvent e(QEvent::KeyPress, 0, Qt::NoModifier, text);
2712 _autoCopySelectedText = enabled;
2717 _middleClickPasteMode = mode;
2725 QString text = _screenWindow->selectedText(_preserveLineBreaks, _trimTrailingSpaces);
2729 QApplication::clipboard()->setText(text, QClipboard::Selection);
2731 if (_autoCopySelectedText)
2732 QApplication::clipboard()->setText(text, QClipboard::Clipboard);
2740 QString text = _screenWindow->selectedText(_preserveLineBreaks, _trimTrailingSpaces);
2744 QApplication::clipboard()->setText(text, QClipboard::Clipboard);
2749 QString text = QApplication::clipboard()->text(QClipboard::Clipboard);
2750 doPaste(text, appendEnter);
2755 QString text = QApplication::clipboard()->text(QClipboard::Selection);
2756 doPaste(text, appendEnter);
2767 if (!event->commitString().isEmpty()) {
2768 QKeyEvent keyEvent(QEvent::KeyPress, 0, Qt::NoModifier, event->commitString());
2772 _inputMethodData.preeditString =
event->preeditString();
2773 update(preeditRect() | _inputMethodData.previousPreeditRect);
2780 const QPoint cursorPos = cursorPosition();
2782 case Qt::ImMicroFocus:
2783 return imageToWidget(QRect(cursorPos.x(), cursorPos.y(), 1, 1));
2788 case Qt::ImCursorPosition:
2790 return cursorPos.x();
2792 case Qt::ImSurroundingText: {
2795 QTextStream stream(&lineText);
2797 decoder.
begin(&stream);
2798 decoder.
decodeLine(&_image[
loc(0, cursorPos.y())], _usedColumns, _lineProperties[cursorPos.y()]);
2803 case Qt::ImCurrentSelection:
2813 QRect TerminalDisplay::preeditRect()
const
2815 const int preeditLength =
string_width(_inputMethodData.preeditString);
2817 if (preeditLength == 0)
2820 return QRect(_contentRect.left() + _fontWidth * cursorPosition().x(),
2821 _contentRect.top() + _fontHeight * cursorPosition().y(),
2822 _fontWidth * preeditLength,
2826 void TerminalDisplay::drawInputMethodPreeditString(QPainter& painter ,
const QRect& rect)
2828 if (_inputMethodData.preeditString.isEmpty())
2831 const QPoint cursorPos = cursorPosition();
2833 bool invertColors =
false;
2836 const Character* style = &_image[
loc(cursorPos.x(), cursorPos.y())];
2838 drawBackground(painter, rect, background,
true);
2839 drawCursor(painter, rect, foreground, background, invertColors);
2840 drawCharacters(painter, rect, _inputMethodData.preeditString, style, invertColors);
2842 _inputMethodData.previousPreeditRect = rect;
2853 _flowControlWarningEnabled = enable;
2864 if (!_outputSuspendedLabel) {
2870 _outputSuspendedLabel =
new QLabel(i18n(
"<qt>Output has been "
2871 "<a href=\"http://en.wikipedia.org/wiki/Flow_control\">suspended</a>"
2872 " by pressing Ctrl+S."
2873 " Press <b>Ctrl+Q</b> to resume.</qt>"),
2876 QPalette palette(_outputSuspendedLabel->palette());
2877 KColorScheme::adjustBackground(palette, KColorScheme::NeutralBackground);
2878 _outputSuspendedLabel->setPalette(palette);
2879 _outputSuspendedLabel->setAutoFillBackground(
true);
2880 _outputSuspendedLabel->setBackgroundRole(QPalette::Base);
2881 _outputSuspendedLabel->setFont(KGlobalSettings::generalFont());
2882 _outputSuspendedLabel->setContentsMargins(5, 5, 5, 5);
2885 _outputSuspendedLabel->setTextInteractionFlags(Qt::LinksAccessibleByMouse |
2886 Qt::LinksAccessibleByKeyboard);
2887 _outputSuspendedLabel->setOpenExternalLinks(
true);
2888 _outputSuspendedLabel->setVisible(
false);
2890 _gridLayout->addWidget(_outputSuspendedLabel);
2891 _gridLayout->addItem(
new QSpacerItem(0, 0, QSizePolicy::Expanding,
2892 QSizePolicy::Expanding),
2896 _outputSuspendedLabel->setVisible(suspended);
2901 _screenWindow->scrollBy(mode, amount, _scrollFullPage);
2902 _screenWindow->setTrackOutput(_screenWindow->atEndOfOutput());
2905 viewScrolledByUser();
2910 _screenWindow->screen()->setCurrentTerminalDisplay(
this);
2915 if (_allowBlinkingCursor) {
2916 _blinkCursorTimer->start();
2917 if (_cursorBlinking) {
2921 Q_ASSERT(_cursorBlinking ==
false);
2926 #if QT_VERSION >= 0x040800 // added in Qt 4.8.0
2927 #ifndef QT_NO_ACCESSIBILITY
2928 QAccessible::updateAccessibility(
this, 0, QAccessible::TextCaretMoved);
2935 bool TerminalDisplay::handleShortcutOverrideEvent(QKeyEvent* keyEvent)
2937 const int modifiers = keyEvent->modifiers();
2942 if (modifiers != Qt::NoModifier) {
2943 int modifierCount = 0;
2944 unsigned int currentModifier = Qt::ShiftModifier;
2946 while (currentModifier <= Qt::KeypadModifier) {
2947 if (modifiers & currentModifier)
2949 currentModifier <<= 1;
2951 if (modifierCount < 2) {
2952 bool override =
false;
2963 int keyCode = keyEvent->key() | modifiers;
2967 case Qt::Key_Delete:
2970 case Qt::Key_Backspace:
2974 case Qt::Key_Period:
2984 bool eventHandled =
false;
2985 switch (event->type()) {
2986 case QEvent::ShortcutOverride:
2987 eventHandled = handleShortcutOverrideEvent(static_cast<QKeyEvent*>(event));
2989 case QEvent::PaletteChange:
2990 case QEvent::ApplicationPaletteChange:
2991 _scrollBar->setPalette(QApplication::palette());
2996 return eventHandled ?
true : QWidget::event(event);
3002 if (event->reason() != QContextMenuEvent::Mouse) {
3023 void TerminalDisplay::unmaskBell()
3025 _bellMasked =
false;
3033 switch (_bellMode) {
3035 KNotification::beep();
3042 KNotification::event(hasFocus() ?
"BellVisible" :
"BellInvisible",
3043 message, QPixmap(),
this);
3056 QTimer::singleShot(500,
this, SLOT(unmaskBell()));
3062 QTimer::singleShot(200,
this, SLOT(swapFGBGColors()));
3065 void TerminalDisplay::swapFGBGColors()
3087 if (event->mimeData()->hasFormat(
"text/plain") ||
3088 event->mimeData()->hasFormat(
"text/uri-list")) {
3089 event->acceptProposedAction();
3095 KUrl::List urls = KUrl::List::fromMimeData(event->mimeData());
3098 if (!urls.isEmpty()) {
3099 for (
int i = 0 ; i < urls.count() ; i++) {
3100 KUrl url = KIO::NetAccess::mostLocalUrl(urls[i] , 0);
3103 if (url.isLocalFile())
3104 urlText = url.path();
3106 urlText = url.url();
3110 urlText = KShell::quoteArg(urlText);
3112 dropText += urlText;
3118 #if defined(HAVE_LIBKONQ)
3121 if (_sessionController && _sessionController->
url().isLocalFile()) {
3125 QAction* pasteAction =
new QAction(i18n(
"&Paste Location"),
this);
3126 pasteAction->setData(dropText);
3127 connect(pasteAction, SIGNAL(triggered()),
this, SLOT(dropMenuPasteActionTriggered()));
3130 additionalActions.append(pasteAction);
3132 if (urls.count() == 1) {
3133 const KUrl url = KIO::NetAccess::mostLocalUrl(urls[0] , 0);
3135 if (url.isLocalFile()) {
3136 const QFileInfo fileInfo(url.path());
3138 if (fileInfo.isDir()) {
3139 QAction* cdAction =
new QAction(i18n(
"Change &Directory To"),
this);
3140 dropText = QLatin1String(
" cd ") + dropText + QChar(
'\n');
3141 cdAction->setData(dropText);
3142 connect(cdAction, SIGNAL(triggered()),
this, SLOT(dropMenuCdActionTriggered()));
3143 additionalActions.append(cdAction);
3148 KUrl target(_sessionController->
currentDir());
3150 KonqOperations::doDrop(KFileItem(), target, event,
this, additionalActions);
3157 dropText =
event->mimeData()->text();
3160 if (event->mimeData()->hasFormat(
"text/plain") ||
3161 event->mimeData()->hasFormat(
"text/uri-list")) {
3166 void TerminalDisplay::dropMenuPasteActionTriggered()
3169 const QAction* action = qobject_cast<
const QAction*>(sender());
3176 void TerminalDisplay::dropMenuCdActionTriggered()
3179 const QAction* action = qobject_cast<
const QAction*>(sender());
3190 QMimeData* mimeData =
new QMimeData;
3191 mimeData->setText(QApplication::clipboard()->text(QClipboard::Selection));
3198 _sessionController = controller;
3203 return _sessionController;
3210 parent->installEventFilter(
this);
3214 if (event->timerId() != _timerId)
3217 QMouseEvent mouseEvent(QEvent::MouseMove,
3218 widget()->mapFromGlobal(QCursor::pos()),
3223 QApplication::sendEvent(widget(), &mouseEvent);
3227 Q_ASSERT(watched == parent());
3230 QMouseEvent* mouseEvent = (QMouseEvent*)event;
3231 switch (event->type()) {
3232 case QEvent::MouseMove: {
3233 bool mouseInWidget = widget()->rect().contains(mouseEvent->pos());
3234 if (mouseInWidget) {
3236 killTimer(_timerId);
3240 if (!_timerId && (mouseEvent->buttons() & Qt::LeftButton))
3241 _timerId = startTimer(100);
3246 case QEvent::MouseButtonRelease: {
3247 if (_timerId && (mouseEvent->buttons() & ~Qt::LeftButton)) {
3248 killTimer(_timerId);
3260 #include "TerminalDisplay.moc"
virtual void resizeEvent(QResizeEvent *event)
Select from the current cursor position to the end of the line.
void setWordCharacters(const QString &wc)
Sets which characters, in addition to letters and numbers, are regarded as being part of a word for t...
LineEncode
A table for emulating the simple (single width) unicode drawing chars.
virtual void end()
End decoding.
void setScroll(int cursor, int lines)
Sets the current position and range of the display's scroll bar.
virtual void focusOutEvent(QFocusEvent *event)
Provides the menu actions to manipulate a single terminal session and view pair.
bool mouseWheelZoom()
Returns the whether zoom terminal on Ctrl+mousewheel is enabled.
virtual void mouseReleaseEvent(QMouseEvent *event)
void setBlinkingCursorEnabled(bool blink)
Specifies whether or not the cursor can blink.
virtual void showEvent(QShowEvent *event)
void setWallpaper(ColorSchemeWallpaper::Ptr p)
Sets the background picture.
void setBackgroundColor(const QColor &color)
Sets the background of the display to the specified color.
quint16 character
The unicode character value for this character.
CursorShapeEnum
This enum describes the shapes used to draw the cursor in terminal displays.
void setVTFont(const QFont &font)
Sets the font used to draw the display.
void setFlowControlWarningEnabled(bool enabled)
Changes whether the flow control warning box should be shown when the flow control stop key (Ctrl+S) ...
void updateImage()
Causes the terminal display to fetch the latest character image from the associated terminal screen (...
virtual KUrl url() const
Returns the URL current associated with a view.
virtual void mouseMoveEvent(QMouseEvent *event)
void updateLineProperties()
Causes the terminal display to fetch the latest line status flags from the associated terminal screen...
virtual void activate(QObject *object=0)=0
Causes the action associated with a hotspot to be triggered.
static ExtendedCharTable instance
The global ExtendedCharTable instance.
#define DEFAULT_FORE_COLOR
Draw a line underneath the cursor's position.
Represents an area of text which matched the pattern a particular filter has been looking for...
Filter::HotSpot * hotSpotAt(int line, int column) const
Returns the first hotspot which occurs at line, column or 0 if no hotspot was found.
void processFilters()
Updates the filters in the display's filter chain.
void bell(const QString &message)
Shows a notification that a bell event has occurred in the terminal.
virtual void contextMenuEvent(QContextMenuEvent *event)
void setBellMode(int mode)
Sets the type of effect used to alert the user when a 'bell' occurs in the terminal session...
QChar charClass(const Character &ch) const
void outputSuspended(bool suspended)
Causes the widget to display or hide a message informing the user that terminal output has been suspe...
virtual void inputMethodEvent(QInputMethodEvent *event)
const int LINE_DOUBLEWIDTH
virtual void mouseDoubleClickEvent(QMouseEvent *event)
static const quint32 LineChars[]
Paste from X11 Selection.
Select the whole line underneath the cursor.
void keyPressedSignal(QKeyEvent *event)
Emitted when the user presses a key whilst the terminal widget has focus.
int startLine() const
Returns the line when the hotspot area starts.
static void drawLineChar(QPainter &paint, int x, int y, int w, int h, uchar code)
ScrollBarPositionEnum
This enum describes the positions where the terminal display's scroll bar may be placed.
virtual void decodeLine(const Character *const characters, int count, LineProperty properties)
Converts a line of terminal characters with associated properties into a text string and writes the s...
QColor getBackgroundColor() const
Gets the background of the display.
void setKeyboardCursorColor(const QColor &color)
Sets the color used to draw the keyboard cursor.
Do not show the scroll-bar.
int endLine() const
Returns the line where the hotspot area ends.
void setScrollFullPage(bool fullPage)
Use a solid rectangular block to draw the cursor.
void setAutoCopySelectedText(bool enabled)
Always draw text in this color with a bold weight.
static bool isLineCharString(const QString &string)
A terminal character decoder which produces plain text, ignoring colors and other appearance-related ...
virtual void paintEvent(QPaintEvent *event)
void setUsesMouse(bool usesMouse)
Sets whether the program whose output is being displayed in the view is interested in mouse events...
void overrideShortcutCheck(QKeyEvent *keyEvent, bool &override)
When a shortcut which is also a valid terminal key sequence is pressed while the terminal widget has ...
static const Character DefaultChar
A single character in the terminal which consists of a unicode character value, foreground and backgr...
trigger system notification.
virtual void wheelEvent(QWheelEvent *event)
void setForegroundColor(const QColor &color)
Sets the text of the display to the specified color.
void mouseSignal(int button, int column, int line, int eventType)
A mouse event occurred.
int lines() const
Returns the number of lines of text which can be displayed in the widget.
void setSearchStartToWindowCurrentLine()
set start line to the first or last line (depending on the reverse search setting) in the terminal di...
Enum::CursorShapeEnum keyboardCursorShape() const
Returns the shape of the keyboard cursor.
void changedContentSizeSignal(int height, int width)
QColor keyboardCursorColor() const
Returns the color of the keyboard cursor, or an invalid color if the keyboard cursor color is set to ...
virtual ~TerminalDisplay()
SessionController * sessionController()
An entry in a terminal display's color palette.
virtual bool focusNextPrevChild(bool next)
bool isSupportedLineChar(quint16 codePoint)
Unicode character in the range of U+2500 ~ U+257F are known as line characters, or box-drawing charac...
KSharedPtr< ColorSchemeWallpaper > Ptr
const QChar LTR_OVERRIDE_CHAR(0x202D)
Provides a window onto a section of a terminal screen.
int bellMode() const
Returns the type of effect used to alert the user when a 'bell' occurs in the terminal session...
FontWeight
Specifies the weight to use when drawing text with this color.
An image of characters with associated attributes.
virtual bool event(QEvent *event)
ushort * lookupExtendedChar(ushort hash, ushort &length) const
Looks up and returns a pointer to a sequence of unicode characters which was added to the table using...
virtual void dragEnterEvent(QDragEnterEvent *event)
void copyToX11Selection()
Copies the selected text to the X11 Selection.
bool scrollFullPage() const
void setColorTable(const ColorEntry table[])
Sets the terminal color palette used by the display.
void setFixedSize(int columns, int lines)
virtual QVariant inputMethodQuery(Qt::InputMethodQuery query) const
QColor color(const ColorEntry *palette) const
Returns the color within the specified color palette.
CharacterColor backgroundColor
The color used to draw this character's background.
void changedFontMetricSignal(int height, int width)
void setScrollBarPosition(Enum::ScrollBarPositionEnum position)
Specifies whether the terminal display has a vertical scroll bar, and if so whether it is shown on th...
void setCenterContents(bool enable)
Sets whether the contents are centered between the margins.
void setMiddleClickPasteMode(Enum::MiddleClickPasteModeEnum mode)
void setSessionController(SessionController *controller)
int columns() const
Returns the number of characters of text which can be displayed on each line in the widget...
void setOpacity(qreal opacity)
Sets the opacity of the terminal display.
virtual void fontChange(const QFont &)
virtual void focusInEvent(QFocusEvent *event)
virtual void setFont(const QFont &)
Reimplemented.
void setLineSpacing(uint)
void scrollBarPositionChanged(int value)
Type type() const
Returns the type of the hotspot.
virtual void mousePressEvent(QMouseEvent *event)
virtual QList< QAction * > actions()
Returns a list of actions associated with the hotspot which can be used in a menu or toolbar...
Describes the color of a single character in the terminal.
void setSize(int columns, int lines)
void setMargin(int margin)
Sets the display's contents margins.
void setRandomSeed(uint seed)
Sets the seed used to generate random colors for the display (in color schemes that support them)...
void setKeyboardCursorShape(Enum::CursorShapeEnum shape)
Sets the shape of the keyboard cursor.
virtual void hideEvent(QHideEvent *event)
A chain which allows a group of filters to be processed as one.
ColorEntry::FontWeight fontWeight(const ColorEntry *base) const
Returns true if this character should always be drawn in bold when it is drawn with the specified pal...
virtual void begin(QTextStream *output)
Begin decoding characters.
void increaseFontSize()
Increases the font size.
MiddleClickPasteModeEnum
This enum describes the source from which mouse middle click pastes data .
struct Konsole::TerminalDisplay::DragInfo _dragInfo
void scrollScreenWindow(enum ScreenWindow::RelativeScrollMode mode, int amount)
Scrolls current ScreenWindow.
QAccessibleInterface * accessibleInterfaceFactory(const QString &key, QObject *object)
This function installs the factory function which lets Qt instantiate the QAccessibleInterface for th...
void setScreenWindow(ScreenWindow *window)
Sets the terminal screen section which is displayed in this widget.
Use an 'I' shape, similar to that used in text editing applications, to draw the cursor.
TerminalDisplay(QWidget *parent=0)
Constructs a new terminal display widget with the specified parent.
ScreenWindow * screenWindow() const
Returns the terminal screen section which is displayed in this widget.
This class serves as a place for putting enum definitions that are used or referenced in multiple pla...
A filter chain which processes character images from terminal displays.
int endColumn() const
Returns the column on endLine() where the hotspot area ends.
void setImage(const Character *const image, int lines, int columns, const QVector< LineProperty > &lineProperties)
Set the current terminal image to image.
QList< QAction * > filterActions(const QPoint &position)
Returns a list of menu actions created by the filters for the content at the given position...
void pasteFromClipboard(bool appendEnter=false)
Pastes the content of the clipboard into the display.
const ColorEntry * colorTable() const
Returns the terminal color palette used by the display.
static const ColorEntry defaultTable[]
void copyToClipboard()
Copies the selected text to the system clipboard.
trigger visual bell(inverting the display's colors briefly).
Show the scroll-bar on the right of the terminal display.
virtual void keyPressEvent(QKeyEvent *event)
QColor color
The color value of this entry for display.
void pasteFromX11Selection(bool appendEnter=false)
Pastes the content of the X11 selection into the display.
void mouseTripleClickEvent(QMouseEvent *event)
uint randomSeed() const
Returns the seed used to generate random colors for the display (in color schemes that support them)...
Use the current font weight set by the terminal application.
RelativeScrollMode
Describes the units which scrollBy() moves the window by.
void configureRequest(const QPoint &position)
Emitted when the user right clicks on the display, or right-clicks with the Shift key held down if us...
void setBlinkingTextEnabled(bool blink)
Specifies whether or not text can blink.
Class implementing the QAccessibleInterface for the terminal display.
A widget which displays output from a terminal emulation and sends input keypresses and mouse activit...
void visualBell()
Play a visual bell for prompt or warning.
virtual void dropEvent(QDropEvent *event)
bool usesMouse() const
See setUsesMouse()
virtual QString currentDir() const
Returns the current directory associated with a view.
QVector< LineProperty > getLineProperties(int startLine, int endLine) const
Returns the additional attributes associated with lines in the image.
int startColumn() const
Returns the column on startLine() where the hotspot area starts.
quint8 rendition
A combination of RENDITION flags which specify options for drawing the character. ...
Show the scroll-bar on the left of the terminal display.
QFont getVTFont()
Returns the font used to draw characters in the display.
int string_width(const QString &text)
virtual void leaveEvent(QEvent *event)
void sendStringToEmu(const char *)
void process()
Processes each filter in the chain.
FilterChain * filterChain() const
Returns the display's filter chain.
void decreaseFontSize()
Decreases the font size.
CharacterColor foregroundColor
The foreground color used to draw this character.
virtual void extendSelection(const QPoint &pos)
QList< Filter::HotSpot * > hotSpots() const
Returns a list of all the hotspots in all the chain's filters.
const int RE_EXTENDED_CHAR
void printContent(QPainter &painter, bool friendly)
const int LINE_DOUBLEHEIGHT
#define DEFAULT_BACK_COLOR