GNU Octave  8.1.0
A high-level interpreted language, primarily intended for numerical computations, mostly compatible with Matlab
TerminalView.cpp
Go to the documentation of this file.
1 /*
2  This file is part of Konsole, a terminal emulator for KDE.
3 
4  Copyright (C) 2006-7 by Robert Knight <robertknight@gmail.com>
5  Copyright (C) 1997,1998 by Lars Doelle <lars.doelle@on-line.de>
6 
7  Rewritten for QT4 by e_k <e_k at users.sourceforge.net>, Copyright (C)2008
8  Copyright (C) 2012-2019 Jacob Dawid <jacob.dawid@cybercatalyst.com>
9 
10  This program is free software: you can redistribute it and/or modify
11  it under the terms of the GNU General Public License as published by
12  the Free Software Foundation; either version 2 of the License, or
13  (at your option) any later version.
14 
15  This program is distributed in the hope that it will be useful,
16  but WITHOUT ANY WARRANTY; without even the implied warranty of
17  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18  GNU General Public License for more details.
19 
20  You should have received a copy of the GNU General Public License
21  along with this program; if not, write to the Free Software
22  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
23  02110-1301 USA.
24 */
25 
26 #if defined (HAVE_CONFIG_H)
27 # include "config.h"
28 #endif
29 
30 #include "qt-utils.h"
31 
32 // Own
33 #include "unix/TerminalView.h"
34 
35 // Qt
36 #include <QApplication>
37 #include <QBoxLayout>
38 #include <QClipboard>
39 #include <QKeyEvent>
40 #include <QtCore/QEvent>
41 #include <QtCore/QTime>
42 #include <QtCore/QFile>
43 #include <QGridLayout>
44 #include <QLabel>
45 #include <QLayout>
46 #include <QPainter>
47 #include <QPixmap>
48 #include <QScrollBar>
49 #include <QStyle>
50 #include <QToolTip>
51 #include <QtCore>
52 #include <QtGui>
53 
54 #include "unix/Filter.h"
55 #include "unix/konsole_wcwidth.h"
56 #include "unix/ScreenWindow.h"
58 
59 #include <signal.h>
60 
61 #ifndef loc
62 #define loc(X,Y) ((Y)*_columns+(X))
63 #endif
64 
65 #define yMouseScroll 1
66 
67 #define REPCHAR "ABCDEFGHIJKLMNOPQRSTUVWXYZ" \
68  "abcdefgjijklmnopqrstuvwxyz" \
69  "0123456789./+@"
70 
71 // scroll increment used when dragging selection at top/bottom of window.
72 
73 // static
75 
76 /* ------------------------------------------------------------------------- */
77 /* */
78 /* Colors */
79 /* */
80 /* ------------------------------------------------------------------------- */
81 
82 /* Note that we use ANSI color order (bgr), while IBMPC color order is (rgb)
83 
84  Code 0 1 2 3 4 5 6 7
85  ----------- ------- ------- ------- ------- ------- ------- ------- -------
86  ANSI (bgr) Black Red Green Yellow Blue Magenta Cyan White
87  IBMPC (rgb) Black Blue Green Cyan Red Magenta Yellow White
88 */
89 
91 {
92  return _screenWindow;
93 }
95 {
96  // disconnect existing screen window if any
97  if ( _screenWindow )
98  {
99  disconnect( _screenWindow , nullptr , this , nullptr );
100  }
101 
102  _screenWindow = window;
103 
104  if ( window )
105  {
106  //#warning "The order here is not specified - does it matter whether updateImage or updateLineProperties comes first?"
107  connect( _screenWindow , SIGNAL(outputChanged()) , this , SLOT(updateLineProperties()) );
108  connect( _screenWindow , SIGNAL(outputChanged()) , this , SLOT(updateImage()) );
109  window->setWindowLines(_lines);
110  }
111 }
112 
114 {
115  return _colorTable;
116 }
117 
119 {
120  for (int i = 0; i < TABLE_COLORS; i++)
121  _colorTable[i] = table[i];
122 
123  QPalette p = palette();
124  p.setColor( backgroundRole(), _colorTable[DEFAULT_BACK_COLOR].color );
125  setPalette( p );
126 
127  // Avoid propagating the palette change to the scroll bar
128  _scrollBar->setPalette( QApplication::palette() );
129 
130  update();
131 }
132 
133 /* ------------------------------------------------------------------------- */
134 /* */
135 /* Font */
136 /* */
137 /* ------------------------------------------------------------------------- */
138 
139 /*
140  The VT100 has 32 special graphical characters. The usual vt100 extended
141  xterm fonts have these at 0x00..0x1f.
142 
143  QT's iso mapping leaves 0x00..0x7f without any changes. But the graphicals
144  come in here as proper unicode characters.
145 
146  We treat non-iso10646 fonts as VT100 extended and do the required mapping
147  from unicode to 0x00..0x1f. The remaining translation is then left to the
148  QCodec.
149 */
150 
151 // assert for i in [0..31] : vt100extended(vt100_graphics[i]) == i.
152 
153 unsigned short vt100_graphics[32] =
154 { // 0/8 1/9 2/10 3/11 4/12 5/13 6/14 7/15
155  0x0020, 0x25C6, 0x2592, 0x2409, 0x240c, 0x240d, 0x240a, 0x00b0,
156  0x00b1, 0x2424, 0x240b, 0x2518, 0x2510, 0x250c, 0x2514, 0x253c,
157  0xF800, 0xF801, 0x2500, 0xF803, 0xF804, 0x251c, 0x2524, 0x2534,
158  0x252c, 0x2502, 0x2264, 0x2265, 0x03C0, 0x2260, 0x00A3, 0x00b7
159 };
160 
161 void TerminalView::fontChange(const QFont&)
162 {
163  QFontMetrics fm(font());
164  _fontHeight = fm.height() + _lineSpacing;
165 
166 
167  // waba TerminalDisplay 1.123:
168  // "Base character width on widest ASCII character. This prevents too wide
169  // characters in the presence of double wide (e.g. Japanese) characters."
170  // Get the width from representative normal width characters
172  / (double)strlen(REPCHAR));
173 
174  _fixedFont = true;
175 
177  for(unsigned int i=1; i< strlen(REPCHAR); i++)
178  {
180  {
181  _fixedFont = false;
182  break;
183  }
184  }
185 
186 
187  if (_fontWidth < 1)
188  _fontWidth = 1;
189 
190  _fontAscent = fm.ascent();
191 
193  //parentWidget()->setFixedWidth(_fontWidth * 80 + _leftMargin);
194  propagateSize();
195  update();
196 }
197 
198 void TerminalView::setVTFont(const QFont& f)
199 {
200  QFont font = f;
201 
202  QFontMetrics metrics(font);
203 
204  if ( metrics.height() < height() && metrics.maxWidth() < width() )
205  {
206  // hint that text should be drawn without anti-aliasing.
207  // depending on the user's font configuration, this may not be respected
208  if (!_antialiasText)
209  font.setStyleStrategy( QFont::NoAntialias );
210 
211  // experimental optimization. Konsole assumes that the terminal is using a
212  // mono-spaced font, in which case kerning information should have an effect.
213  // Disabling kerning saves some computation when rendering text.
214  // font.setKerning(false);
215 
216  int strategy = font.styleStrategy();
217 #if defined (HAVE_QFONT_FORCE_INTEGER_METRICS)
218  strategy |= QFont::ForceIntegerMetrics;
219 #endif
220  font.setStyleStrategy(QFont::StyleStrategy(strategy));
221 
222  QWidget::setFont(font);
223  fontChange(font);
224  }
225 }
226 
227 void TerminalView::setFont(const QFont &)
228 {
229  // ignore font change request if not coming from konsole itself
230 }
231 
232 /* ------------------------------------------------------------------------- */
233 /* */
234 /* Constructor / Destructor */
235 /* */
236 /* ------------------------------------------------------------------------- */
237 
239  :QWidget(parent)
240  ,_screenWindow(nullptr)
241  ,_allowBell(true)
242  ,_gridLayout(nullptr)
243  ,_fontHeight(1)
244  ,_fontWidth(1)
245  ,_fontAscent(1)
246  ,_lines(1)
247  ,_columns(1)
248  ,_usedLines(1)
249  ,_usedColumns(1)
250  ,_contentHeight(1)
251  ,_contentWidth(1)
252  ,_image(nullptr)
253  ,_randomSeed(0)
254  ,_resizing(false)
255  ,_terminalSizeHint(false)
256  ,_terminalSizeStartup(true)
257  ,_disabledBracketedPasteMode(false)
258  ,_actSel(0)
259  ,_wordSelectionMode(false)
260  ,_lineSelectionMode(false)
261  ,_preserveLineBreaks(false)
262  ,_columnSelectionMode(false)
263  ,_scrollbarLocation(NoScrollBar)
264  ,_wordCharacters(":@-./_~")
265  ,_bellMode(SystemBeepBell)
266  ,_blinking(false)
267  ,_cursorBlinking(false)
268  ,_hasBlinkingCursor(false)
269  ,_ctrlDrag(false)
270  ,_tripleClickMode(SelectWholeLine)
271  ,_isFixedSize(false)
272  ,_possibleTripleClick(false)
273  ,_resizeWidget(nullptr)
274  ,_resizeTimer(nullptr)
275  ,_outputSuspendedLabel(nullptr)
276  ,_lineSpacing(0)
277  ,_colorsInverted(false)
278  ,_blendColor(qRgba(0,0,0,0xff))
279  ,_filterChain(new TerminalImageFilterChain())
280  ,_cursorShape(BlockCursor)
281  ,_readonly(false)
282 {
283  // terminal applications are not designed with Right-To-Left in mind,
284  // so the layout is forced to Left-To-Right
285  setLayoutDirection(Qt::LeftToRight);
286 
287  // The offsets are not yet calculated.
288  // Do not calculate these too often to be more smoothly when resizing
289  // konsole in opaque mode.
292 
293  // create scroll bar for scrolling output up and down
294  // set the scroll bar's slider to occupy the whole area of the scroll bar initially
295  _scrollBar = new QScrollBar(this);
296  setScroll(0,0);
297  _scrollBar->setCursor( Qt::ArrowCursor );
298  connect(_scrollBar, SIGNAL(valueChanged(int)), this,
299  SLOT(scrollBarPositionChanged(int)));
300 
301  // setup timers for blinking cursor and text
302  _blinkTimer = new QTimer(this);
303  connect(_blinkTimer, SIGNAL(timeout()), this, SLOT(blinkEvent()));
304 
305  _blinkCursorTimer = new QTimer(this);
306  connect(_blinkCursorTimer, SIGNAL(timeout()), this, SLOT(blinkCursorEvent()));
307 
308  _process_filter_timer = new QTimer (this);
309  connect (_process_filter_timer, SIGNAL (timeout ()),
310  this, SLOT (processFilters ()));
311  _process_filter_timer->start (300);
312 
313  // QCursor::setAutoHideCursor( this, true );
314 
315  setUsesMouse(true);
316  setBracketedPasteMode(false);
318  setMouseTracking(true);
319 
320  // Enable drag and drop
321  setAcceptDrops(true); // attempt
323 
324  setFocusPolicy( Qt::WheelFocus );
325 
326  // enable input method support
327  setAttribute(Qt::WA_InputMethodEnabled, true);
328 
329  // this is an important optimization, it tells Qt
330  // that TerminalDisplay will handle repainting its entire area.
331  setAttribute(Qt::WA_OpaquePaintEvent);
332 
333  _gridLayout = new QGridLayout(this);
334  _gridLayout->setMargin(0);
335 
336  setLayout( _gridLayout );
337 }
338 
340 {
341  qApp->removeEventFilter( this );
342 
343  delete[] _image;
344 
345  delete _gridLayout;
346  delete _outputSuspendedLabel;
347  delete _filterChain;
348 }
349 
350 /* ------------------------------------------------------------------------- */
351 /* */
352 /* Display Operations */
353 /* */
354 /* ------------------------------------------------------------------------- */
355 
356 /**
357  A table for emulating the simple (single width) unicode drawing chars.
358  It represents the 250x - 257x glyphs. If it's zero, we can't use it.
359  if it's not, it's encoded as follows: imagine a 5x5 grid where the points are numbered
360  0 to 24 left to top, top to bottom. Each point is represented by the corresponding bit.
361 
362  Then, the pixels basically have the following interpretation:
363  _|||_
364  -...-
365  -...-
366  -...-
367  _|||_
368 
369 where _ = none
370  | = vertical line.
371  - = horizontal line.
372  */
373 
374 
376 {
377  TopL = (1<<1),
378  TopC = (1<<2),
379  TopR = (1<<3),
380 
381  LeftT = (1<<5),
382  Int11 = (1<<6),
383  Int12 = (1<<7),
384  Int13 = (1<<8),
385  RightT = (1<<9),
386 
387  LeftC = (1<<10),
388  Int21 = (1<<11),
389  Int22 = (1<<12),
390  Int23 = (1<<13),
391  RightC = (1<<14),
392 
393  LeftB = (1<<15),
394  Int31 = (1<<16),
395  Int32 = (1<<17),
396  Int33 = (1<<18),
397  RightB = (1<<19),
398 
399  BotL = (1<<21),
400  BotC = (1<<22),
401  BotR = (1<<23)
402 };
403 
405 {
406  _cursorShape = shape;
407 }
409 {
410  return _cursorShape;
411 }
412 void TerminalView::setKeyboardCursorColor(bool useForegroundColor, const QColor& color)
413 {
414  if (useForegroundColor)
415  _cursorColor = QColor(); // an invalid color means that
416  // the foreground color of the
417  // current character should
418  // be used
419 
420  else
421  _cursorColor = color;
422 }
424 {
425  return _cursorColor;
426 }
427 
428 void TerminalView::drawBackground(QPainter& painter, const QRect& rect, const QColor& backgroundColor)
429 {
430  // the area of the widget showing the contents of the terminal display is drawn
431  // using the background color from the color scheme set with setColorTable()
432  //
433  // the area of the widget behind the scroll-bar is drawn using the background
434  // brush from the scroll-bar's palette, to give the effect of the scroll-bar
435  // being outside of the terminal display and visual consistency with other KDE
436  // applications.
437  //
438  QRect scrollBarArea = _scrollBar->isVisible() ?
439  rect.intersected(_scrollBar->geometry()) :
440  QRect();
441 
442  QRegion contentsRegion = QRegion(rect).subtracted(scrollBarArea);
443  QRect contentsRect = contentsRegion.boundingRect();
444 
445  painter.fillRect(contentsRect, backgroundColor);
446  painter.fillRect(scrollBarArea,_scrollBar->palette().window());
447 }
448 
450  const QRect& rect,
451  const QColor& foregroundColor,
452  const QColor& /*backgroundColor*/,
453  bool& invertCharacterColor)
454 {
455  QRect cursorRect = rect;
456  cursorRect.setHeight(_fontHeight - _lineSpacing - 1);
457 
458  if (!_cursorBlinking)
459  {
460  if ( _cursorColor.isValid() )
461  painter.setPen(_cursorColor);
462  else {
463  painter.setPen(foregroundColor);
464  }
465 
466  if ( _cursorShape == BlockCursor )
467  {
468  // draw the cursor outline, adjusting the area so that
469  // it is draw entirely inside 'rect'
470  int penWidth = qMax(1,painter.pen().width());
471 
472  painter.drawRect(cursorRect.adjusted(penWidth/2,
473  penWidth/2,
474  - penWidth/2 - penWidth%2,
475  - penWidth/2 - penWidth%2));
476  if ( hasFocus() )
477  {
478  painter.fillRect(cursorRect, _cursorColor.isValid() ? _cursorColor : foregroundColor);
479 
480  if ( !_cursorColor.isValid() )
481  {
482  // invert the colour used to draw the text to ensure that the character at
483  // the cursor position is readable
484  invertCharacterColor = true;
485  }
486  }
487  }
488  else if ( _cursorShape == UnderlineCursor )
489  painter.drawLine(cursorRect.left(),
490  cursorRect.bottom(),
491  cursorRect.right(),
492  cursorRect.bottom());
493  else if ( _cursorShape == IBeamCursor )
494  painter.drawLine(cursorRect.left(),
495  cursorRect.top(),
496  cursorRect.left(),
497  cursorRect.bottom());
498 
499  }
500 }
501 
503  const QRect& rect,
504  const QString& text,
505  const Character* style,
506  bool invertCharacterColor)
507 {
508  // don't draw text which is currently blinking
509  if ( _blinking && (style->rendition & RE_BLINK) )
510  return;
511 
512  // setup bold and underline
513  bool useBold = style->rendition & RE_BOLD || style->isBold(_colorTable) || font().bold();
514  bool useUnderline = style->rendition & RE_UNDERLINE || font().underline();
515 
516  QFont font = painter.font();
517  if ( font.bold() != useBold
518  || font.underline() != useUnderline )
519  {
520  font.setBold(useBold);
521  font.setUnderline(useUnderline);
522  painter.setFont(font);
523  }
524 
525  const CharacterColor& textColor = ( invertCharacterColor ? style->backgroundColor : style->foregroundColor );
526  const QColor color = textColor.color(_colorTable);
527 
528  QPen pen = painter.pen();
529  if ( pen.color() != color )
530  {
531  pen.setColor(color);
532  painter.setPen(color);
533  }
534  // draw text
535  // the drawText(rect,flags,string) overload is used here with null flags
536  // instead of drawText(rect,string) because the (rect,string) overload causes
537  // the application's default layout direction to be used instead of
538  // the widget-specific layout direction, which should always be
539  // Qt::LeftToRight for this widget
540  painter.drawText(rect,0,text);
541 }
542 
544  const QRect& rect,
545  const QString& text,
546  const Character* style)
547 {
548  painter.save();
549 
550  // setup painter
551  const QColor foregroundColor = style->foregroundColor.color(_colorTable);
552  const QColor backgroundColor = style->backgroundColor.color(_colorTable);
553 
554  // draw background if different from the display's background color
555  if ( backgroundColor != palette().window().color() )
556  drawBackground(painter,rect,backgroundColor);
557 
558  // draw cursor shape if the current character is the cursor
559  // this may alter the foreground and background colors
560  bool invertCharacterColor = false;
561 
562  if ( style->rendition & RE_CURSOR )
563  drawCursor(painter,rect,foregroundColor,backgroundColor,invertCharacterColor);
564  // draw text
565  drawCharacters(painter,rect,text,style,invertCharacterColor);
566 
567  painter.restore();
568 }
569 
571 uint TerminalView::randomSeed() const { return _randomSeed; }
572 
573 #if 0
574 /*!
575  Set XIM Position
576 */
577 void TerminalDisplay::setCursorPos(const int curx, const int cury)
578 {
579  QPoint tL = contentsRect().topLeft();
580  int tLx = tL.x();
581  int tLy = tL.y();
582 
583  int xpos, ypos;
584  ypos = _topMargin + tLy + _fontHeight*(cury-1) + _fontAscent;
585  xpos = _leftMargin + tLx + _fontWidth*curx;
586  //setMicroFocusHint(xpos, ypos, 0, _fontHeight); //### ???
587  // fprintf(stderr, "x/y = %d/%d\txpos/ypos = %d/%d\n", curx, cury, xpos, ypos);
588  _cursorLine = cury;
589  _cursorCol = curx;
590 }
591 #endif
592 
593 // scrolls the image by 'lines', down if lines > 0 or up otherwise.
594 //
595 // the terminal emulation keeps track of the scrolling of the character
596 // image as it receives input, and when the view is updated, it calls scrollImage()
597 // with the final scroll amount. this improves performance because scrolling the
598 // display is much cheaper than re-rendering all the text for the
599 // part of the image which has moved up or down.
600 // Instead only new lines have to be drawn
601 //
602 // note: it is important that the area of the display which is
603 // scrolled aligns properly with the character grid -
604 // which has a top left point at (_leftMargin,_topMargin) ,
605 // a cell width of _fontWidth and a cell height of _fontHeight).
606 void TerminalView::scrollImage(int lines , const QRect& screenWindowRegion)
607 {
608  // if the flow control warning is enabled this will interfere with the
609  // scrolling optimisations and cause artifacts. the simple solution here
610  // is to just disable the optimisation whilst it is visible
611  if ( _outputSuspendedLabel && _outputSuspendedLabel->isVisible() ) {
612  return;
613  }
614 
615  // constrain the region to the display
616  // the bottom of the region is capped to the number of lines in the display's
617  // internal image - 2, so that the height of 'region' is strictly less
618  // than the height of the internal image.
619  QRect region = screenWindowRegion;
620  region.setBottom( qMin(region.bottom(),this->_lines-2) );
621 
622  if (lines == 0
623  || _image == nullptr
624  || !region.isValid()
625  || (region.top() + abs(lines)) >= region.bottom()
626  || this->_lines <= region.height() )
627  return;
628 
629  QRect scrollRect;
630 
631  void* firstCharPos = &_image[ region.top() * this->_columns ];
632  void* lastCharPos = &_image[ (region.top() + abs(lines)) * this->_columns ];
633 
634  int top = _topMargin + (region.top() * _fontHeight);
635  int linesToMove = region.height() - abs(lines);
636  int bytesToMove = linesToMove *
637  this->_columns *
638  sizeof(Character);
639 
640  Q_ASSERT( linesToMove > 0 );
641  Q_ASSERT( bytesToMove > 0 );
642 
643  //scroll internal image
644  if ( lines > 0 )
645  {
646  // check that the memory areas that we are going to move are valid
647  Q_ASSERT( (char*)lastCharPos + bytesToMove <
648  (char*)(_image + (this->_lines * this->_columns)) );
649 
650  Q_ASSERT( (lines*this->_columns) < _imageSize );
651 
652  //scroll internal image down
653  memmove( firstCharPos , lastCharPos , bytesToMove );
654 
655  //set region of display to scroll, making sure that
656  //the region aligns correctly to the character grid
657  scrollRect = QRect( _leftMargin , top,
658  this->_usedColumns * _fontWidth ,
659  linesToMove * _fontHeight );
660  }
661  else
662  {
663  // check that the memory areas that we are going to move are valid
664  Q_ASSERT( (char*)firstCharPos + bytesToMove <
665  (char*)(_image + (this->_lines * this->_columns)) );
666 
667  //scroll internal image up
668  memmove( lastCharPos , firstCharPos , bytesToMove );
669 
670  //set region of the display to scroll, making sure that
671  //the region aligns correctly to the character grid
672  QPoint topPoint( _leftMargin , top + abs(lines)*_fontHeight );
673 
674  scrollRect = QRect( topPoint ,
675  QSize( this->_usedColumns*_fontWidth ,
676  linesToMove * _fontHeight ));
677  }
678 
679  //scroll the display vertically to match internal _image
680  scroll( 0 , _fontHeight * (-lines) , scrollRect );
681 }
682 
684 {
685  QRegion region;
686  foreach( Filter::HotSpot* hotSpot , _filterChain->hotSpots() )
687  {
688  QRect rect;
689  rect.setLeft(hotSpot->startColumn());
690  rect.setTop(hotSpot->startLine());
691  rect.setRight(hotSpot->endColumn());
692  rect.setBottom(hotSpot->endLine());
693 
694  region |= imageToWidget(rect);
695  }
696  return region;
697 }
698 
700 {
701  if (!_screenWindow)
702  return;
703 
704  QRegion preUpdateHotSpots = hotSpotRegion();
705 
706  // use _screenWindow->getImage() here rather than _image because
707  // other classes may call processFilters() when this display's
708  // ScreenWindow emits a scrolled() signal - which will happen before
709  // updateImage() is called on the display and therefore _image is
710  // out of date at this point
711  _filterChain->setImage( _screenWindow->getImage(),
712  _screenWindow->windowLines(),
713  _screenWindow->windowColumns(),
714  _screenWindow->getLineProperties() );
716 
717  QRegion postUpdateHotSpots = hotSpotRegion();
718 
719  update( preUpdateHotSpots | postUpdateHotSpots );
720 }
721 
723 {
724  if ( !_screenWindow )
725  return;
727 
728  // optimization - scroll the existing image where possible and
729  // avoid expensive text drawing for parts of the image that
730  // can simply be moved up or down
731  scrollImage( _screenWindow->scrollCount() ,
732  _screenWindow->scrollRegion() );
733  _screenWindow->resetScrollCount();
734 
735  Character* const newimg = _screenWindow->getImage();
736  int lines = _screenWindow->windowLines();
737  int columns = _screenWindow->windowColumns();
738 
739  setScroll( _screenWindow->currentLine() , _screenWindow->lineCount() );
740 
741  if (!_image)
742  updateImageSize(); // Create _image
743 
744  Q_ASSERT( this->_usedLines <= this->_lines );
745  Q_ASSERT( this->_usedColumns <= this->_columns );
746 
747  int y,x,len;
748 
749  QPoint tL = contentsRect().topLeft();
750 
751  int tLx = tL.x();
752  int tLy = tL.y();
753  _hasBlinker = false;
754 
755  CharacterColor cf; // undefined
756  CharacterColor _clipboard; // undefined
757  int cr = -1; // undefined
758 
759  const int linesToUpdate = qMin(this->_lines, qMax(0,lines ));
760  const int columnsToUpdate = qMin(this->_columns,qMax(0,columns));
761 
762  QChar *disstrU = new QChar[columnsToUpdate];
763  char *dirtyMask = new char[columnsToUpdate+2];
764  QRegion dirtyRegion;
765 
766  // debugging variable, this records the number of lines that are found to
767  // be 'dirty' ( ie. have changed from the old _image to the new _image ) and
768  // which therefore need to be repainted
769  int dirtyLineCount = 0;
770 
771  for (y = 0; y < linesToUpdate; y++)
772  {
773  const Character* currentLine = &_image[y*this->_columns];
774  const Character* const newLine = &newimg[y*columns];
775 
776  bool updateLine = false;
777 
778  // The dirty mask indicates which characters need repainting. We also
779  // mark surrounding neighbours dirty, in case the character exceeds
780  // its cell boundaries
781  memset(dirtyMask, 0, columnsToUpdate+2);
782 
783  for( x = 0 ; x < columnsToUpdate ; x++)
784  {
785  if ( newLine[x] != currentLine[x] )
786  {
787  dirtyMask[x] = true;
788  }
789  }
790 
791  if (!_resizing) // not while _resizing, we're expecting a paintEvent
792  for (x = 0; x < columnsToUpdate; x++)
793  {
794  _hasBlinker |= (newLine[x].rendition & RE_BLINK);
795 
796  // Start drawing if this character or the next one differs.
797  // We also take the next one into account to handle the situation
798  // where characters exceed their cell width.
799  if (dirtyMask[x])
800  {
801  quint16 c = newLine[x+0].character;
802  if ( !c )
803  continue;
804  int p = 0;
805  disstrU[p++] = c; //fontMap(c);
806  bool doubleWidth = (x+1 == columnsToUpdate) ? false : (newLine[x+1].character == 0);
807  cr = newLine[x].rendition;
808  _clipboard = newLine[x].backgroundColor;
809  if (newLine[x].foregroundColor != cf) cf = newLine[x].foregroundColor;
810  int lln = columnsToUpdate - x;
811  for (len = 1; len < lln; len++)
812  {
813  const Character& ch = newLine[x+len];
814 
815  if (!ch.character)
816  continue; // Skip trailing part of multi-col chars.
817 
818  bool nextIsDoubleWidth = (x+len+1 == columnsToUpdate) ? false : (newLine[x+len+1].character == 0);
819 
820  if ( ch.foregroundColor != cf ||
821  ch.backgroundColor != _clipboard ||
822  ch.rendition != cr ||
823  !dirtyMask[x+len] ||
824  nextIsDoubleWidth != doubleWidth )
825  break;
826 
827  disstrU[p++] = c; //fontMap(c);
828  }
829 
830  QString unistr(disstrU, p);
831 
832  bool saveFixedFont = _fixedFont;
833  if (doubleWidth)
834  _fixedFont = false;
835 
836  updateLine = true;
837 
838  _fixedFont = saveFixedFont;
839  x += len - 1;
840  }
841 
842  }
843 
844  //both the top and bottom halves of double height _lines must always be redrawn
845  //although both top and bottom halves contain the same characters, only
846  //the top one is actually
847  //drawn.
848  if (_lineProperties.count() > y)
849  updateLine |= (_lineProperties[y] & LINE_DOUBLEHEIGHT);
850 
851  // if the characters on the line are different in the old and the new _image
852  // then this line must be repainted.
853  if (updateLine)
854  {
855  dirtyLineCount++;
856 
857  // add the area occupied by this line to the region which needs to be
858  // repainted
859  QRect dirtyRect = QRect( _leftMargin+tLx ,
860  _topMargin+tLy+_fontHeight*y ,
861  _fontWidth * columnsToUpdate ,
862  _fontHeight );
863 
864  dirtyRegion |= dirtyRect;
865  }
866 
867  // replace the line of characters in the old _image with the
868  // current line of the new _image
869  memcpy((void*)currentLine,(const void*)newLine,columnsToUpdate*sizeof(Character));
870  }
871 
872  // if the new _image is smaller than the previous _image, then ensure that the area
873  // outside the new _image is cleared
874  if ( linesToUpdate < _usedLines )
875  {
876  dirtyRegion |= QRect( _leftMargin+tLx ,
877  _topMargin+tLy+_fontHeight*linesToUpdate ,
878  _fontWidth * this->_columns ,
879  _fontHeight * (_usedLines-linesToUpdate) );
880  }
881  _usedLines = linesToUpdate;
882 
883  if ( columnsToUpdate < _usedColumns )
884  {
885  dirtyRegion |= QRect( _leftMargin+tLx+columnsToUpdate*_fontWidth ,
886  _topMargin+tLy ,
887  _fontWidth * (_usedColumns-columnsToUpdate) ,
888  _fontHeight * this->_lines );
889  }
890  _usedColumns = columnsToUpdate;
891 
892  dirtyRegion |= _inputMethodData.previousPreeditRect;
893 
894  // update the parts of the display which have changed
895  update(dirtyRegion);
896 
897  if ( _hasBlinker && !_blinkTimer->isActive()) _blinkTimer->start( BLINK_DELAY );
898  if (!_hasBlinker && _blinkTimer->isActive()) { _blinkTimer->stop(); _blinking = false; }
899  delete[] dirtyMask;
900  delete[] disstrU;
901 
902 }
903 
905 {
906  if (_terminalSizeHint && isVisible())
907  {
908  if (_terminalSizeStartup) {
909  _terminalSizeStartup=false;
910  return;
911  }
912  if (!_resizeWidget)
913  {
914  _resizeWidget = new QLabel(("Size: XXX x XXX"), this);
915  _resizeWidget->setMinimumWidth(octave::qt_fontmetrics_horizontal_advance(_resizeWidget->fontMetrics(), "Size: XXX x XXX"));
916  _resizeWidget->setMinimumHeight(_resizeWidget->sizeHint().height());
917  _resizeWidget->setAlignment(Qt::AlignCenter);
918 
919  _resizeWidget->setStyleSheet("background-color:palette(window);border-style:solid;border-width:1px;border-color:palette(dark)");
920 
921  _resizeTimer = new QTimer(this);
922  _resizeTimer->setSingleShot(true);
923  connect(_resizeTimer, SIGNAL(timeout()), _resizeWidget, SLOT(hide()));
924 
925  }
926  QString sizeStr = QString("Size: %1 x %2").arg(_columns).arg(_lines);
927  _resizeWidget->setText(sizeStr);
928  _resizeWidget->move((width()-_resizeWidget->width())/2,
929  (height()-_resizeWidget->height())/2+20);
930  _resizeWidget->show();
931  _resizeTimer->start(1000);
932  }
933 }
934 
936 {
937  _hasBlinkingCursor=blink;
938 
939  setBlinkingCursorState(blink);
940 }
941 
943 {
944  if (blink && !_blinkCursorTimer->isActive())
946 
947  if (!blink && _blinkCursorTimer->isActive())
948  {
949  _blinkCursorTimer->stop();
950  if (_cursorBlinking)
952  }
953 }
954 
955 void TerminalView::paintEvent( QPaintEvent* pe )
956 {
957  updateImage();
958  //qDebug("%s %d paintEvent", __FILE__, __LINE__);
959  QPainter paint(this);
960  //qDebug("%s %d paintEvent %d %d", __FILE__, __LINE__, paint.window().top(), paint.window().right());
961 
962 #if defined (HAVE_QREGION_ITERATORS)
963  for (QRect rect : (pe->region() & contentsRect()))
964 #else
965  foreach (QRect rect, (pe->region() & contentsRect()).rects())
966 #endif
967  {
968  drawBackground(paint,rect,palette().window().color());
969  drawContents(paint, rect);
970  }
971  // drawBackground(paint,contentsRect(),palette().background().color(), true /* use opacity setting */);
972  // drawContents(paint, contentsRect());
974  paintFilters(paint);
975  paint.end();
976 }
977 
978 void TerminalView::focusInEvent(QFocusEvent *focusEvent)
979 {
981  updateImage();
982  repaint();
983  update();
984 
985  QWidget::focusInEvent(focusEvent);
986 }
987 
988 void TerminalView::focusOutEvent(QFocusEvent *focusEvent)
989 {
990  // Force the cursor to be redrawn.
991  _cursorBlinking = true;
992  setBlinkingCursorState(false);
993 
994  QWidget::focusOutEvent(focusEvent);
995 }
996 
998 {
999  if (_screenWindow)
1000  return _screenWindow->cursorPosition();
1001  else
1002  return QPoint(0,0);
1003 }
1004 
1006 {
1007  const int preeditLength = string_width(_inputMethodData.preeditString);
1008 
1009  if ( preeditLength == 0 )
1010  return QRect();
1011 
1012  return QRect(_leftMargin + _fontWidth*cursorPosition().x(),
1014  _fontWidth*preeditLength,
1015  _fontHeight);
1016 }
1017 
1018 void TerminalView::drawInputMethodPreeditString(QPainter& painter , const QRect& rect)
1019 {
1020  if ( _inputMethodData.preeditString.isEmpty() ) {
1021  return;
1022  }
1023  const QPoint cursorPos = cursorPosition();
1024 
1025  bool invertColors = false;
1026  const QColor background = _colorTable[DEFAULT_BACK_COLOR].color;
1027  const QColor foreground = _colorTable[DEFAULT_FORE_COLOR].color;
1028  const Character* style = &_image[loc(cursorPos.x(),cursorPos.y())];
1029 
1030  drawBackground(painter,rect,background);
1031  drawCursor(painter,rect,foreground,background,invertColors);
1032  drawCharacters(painter,rect,_inputMethodData.preeditString,style,invertColors);
1033 
1035 }
1036 
1038 {
1039  return _filterChain;
1040 }
1041 
1043 {
1044  //qDebug("%s %d paintFilters", __FILE__, __LINE__);
1045 
1046  // get color of character under mouse and use it to draw
1047  // lines for filters
1048  QPoint cursorPos = mapFromGlobal(QCursor::pos());
1049  int cursorLine;
1050  int cursorColumn;
1051  getCharacterPosition( cursorPos , cursorLine , cursorColumn );
1052  Character cursorCharacter = _image[loc(cursorColumn,cursorLine)];
1053 
1054  painter.setPen( QPen(cursorCharacter.foregroundColor.color(colorTable())) );
1055 
1056  // iterate over hotspots identified by the display's currently active filters
1057  // and draw appropriate visuals to indicate the presence of the hotspot
1058 
1060  QListIterator<Filter::HotSpot*> iter(spots);
1061  while (iter.hasNext())
1062  {
1063  Filter::HotSpot* spot = iter.next();
1064 
1065  for ( int line = spot->startLine() ; line <= spot->endLine() ; line++ )
1066  {
1067  int startColumn = 0;
1068  int endColumn = _columns-1; // TODO use number of _columns which are actually
1069  // occupied on this line rather than the width of the
1070  // display in _columns
1071 
1072  // ignore whitespace at the end of the lines
1073  while ( QChar(_image[loc(endColumn,line)].character).isSpace() && endColumn > 0 )
1074  endColumn--;
1075 
1076  // increment here because the column which we want to set 'endColumn' to
1077  // is the first whitespace character at the end of the line
1078  endColumn++;
1079 
1080  if ( line == spot->startLine() )
1081  startColumn = spot->startColumn();
1082  if ( line == spot->endLine() )
1083  endColumn = spot->endColumn();
1084 
1085  // subtract one pixel from
1086  // the right and bottom so that
1087  // we do not overdraw adjacent
1088  // hotspots
1089  //
1090  // subtracting one pixel from all sides also prevents an edge case where
1091  // moving the mouse outside a link could still leave it underlined
1092  // because the check below for the position of the cursor
1093  // finds it on the border of the target area
1094  QRect r;
1095  r.setCoords( startColumn*_fontWidth + 1, line*_fontHeight + 1,
1096  endColumn*_fontWidth - 1, (line+1)*_fontHeight - 1 );
1097 
1098  // Underline link hotspots
1099  if ( spot->type() == Filter::Link ||
1100  spot->type() == Filter::ErrorLink)
1101  {
1102  QFontMetrics metrics(font());
1103 
1104  // find the baseline (which is the invisible line that the
1105  // characters in the font sit on
1106  int baseline = r.bottom() + 1;
1107  // find the position of the underline below that
1108  int underlinePos = baseline + metrics.underlinePos();
1109 
1110  if (r.contains (mapFromGlobal(QCursor::pos())))
1111  {
1112  if (spot->type () == Filter::ErrorLink)
1113  painter.setPen (QColor (255,0,0));
1114  painter.drawLine (r.left(), underlinePos,
1115  r.right() + 2, underlinePos);
1116  }
1117  }
1118  // Marker hotspots simply have a transparent rectanglular shape
1119  // drawn on top of them
1120  else if ( spot->type() == Filter::Marker )
1121  {
1122  //TODO - Do not use a hardcoded colour for this
1123  painter.fillRect(r,QBrush(QColor(255,0,0,120)));
1124  }
1125 
1126  }
1127  }
1128 }
1129 void TerminalView::drawContents(QPainter &paint, const QRect &rect)
1130 {
1131  //qDebug("%s %d drawContents and rect x=%d y=%d w=%d h=%d", __FILE__, __LINE__, rect.x(), rect.y(),rect.width(),rect.height());
1132 
1133  QPoint topLeft = contentsRect().topLeft();
1134  // Take the topmost vertical position for the view.
1135  int topLeftY = topLeft.y();
1136 
1137  // In Konsole, the view has been centered. Don't do that here, since there
1138  // are strange hopping effects during a resize when the view does no match
1139  // exactly the widget width.
1140  // int topLeftX = (_contentWidth - _usedColumns * _fontWidth) / 2;
1141  int topLeftX = 0;
1142 
1143  int leftUpperX = qMin(_usedColumns-1, qMax(0, qFloor((rect.left() - topLeftX - _leftMargin ) / _fontWidth)));
1144  int leftUpperY = qMin(_usedLines-1, qMax(0, qFloor((rect.top() - topLeftY - _topMargin ) / _fontHeight)));
1145  int rightLowerX = qMin(_usedColumns-1, qMax(0, qFloor((rect.right() - topLeftX - _leftMargin ) / _fontWidth)));
1146  int rightLowerY = qMin(_usedLines-1, qMax(0, qFloor((rect.bottom() - topLeftY - _topMargin ) / _fontHeight)));
1147 
1148  const int bufferSize = _usedColumns;
1149  QChar *disstrU = new QChar[bufferSize];
1150  for (int y = leftUpperY; y <= rightLowerY; y++)
1151  {
1152  quint16 c = _image[loc(leftUpperX,y)].character;
1153  int x = leftUpperX;
1154  if(!c && x)
1155  x--; // Search for start of multi-column character
1156  for (; x <= rightLowerX; x++)
1157  {
1158  int len = 1;
1159  int p = 0;
1160 
1161  // is this a single character or a sequence of characters ?
1162  if ( _image[loc(x,y)].rendition & RE_EXTENDED_CHAR )
1163  {
1164  // sequence of characters
1165  ushort extendedCharLength = 0;
1166  ushort* chars = ExtendedCharTable::instance
1167  .lookupExtendedChar(_image[loc(x,y)].charSequence,extendedCharLength);
1168  for ( int index = 0 ; index < extendedCharLength ; index++ )
1169  {
1170  Q_ASSERT( p < bufferSize );
1171  disstrU[p++] = chars[index];
1172  }
1173  }
1174  else
1175  {
1176  // single character
1177  c = _image[loc(x,y)].character;
1178  if (c)
1179  {
1180  Q_ASSERT( p < bufferSize );
1181  disstrU[p++] = c; //fontMap(c);
1182  }
1183  }
1184 
1185  bool doubleWidth = (_image[ qMin(loc(x,y)+1,_imageSize) ].character == 0);
1186  CharacterColor currentForeground = _image[loc(x,y)].foregroundColor;
1187  CharacterColor currentBackground = _image[loc(x,y)].backgroundColor;
1188  quint8 currentRendition = _image[loc(x,y)].rendition;
1189 
1190  while (x+len <= rightLowerX &&
1191  _image[loc(x+len,y)].foregroundColor == currentForeground &&
1192  _image[loc(x+len,y)].backgroundColor == currentBackground &&
1193  _image[loc(x+len,y)].rendition == currentRendition &&
1194  (_image[ qMin(loc(x+len,y)+1,_imageSize) ].character == 0) == doubleWidth)
1195  {
1196  c = _image[loc(x+len,y)].character;
1197  if (c)
1198  disstrU[p++] = c; //fontMap(c);
1199  if (doubleWidth) // assert((_image[loc(x+len,y)+1].character == 0)), see above if condition
1200  len++; // Skip trailing part of multi-column character
1201  len++;
1202  }
1203  if ((x+len < _usedColumns) && (!_image[loc(x+len,y)].character))
1204  len++; // Adjust for trailing part of multi-column character
1205 
1206  bool save__fixedFont = _fixedFont;
1207  if (doubleWidth)
1208  _fixedFont = false;
1209  QString unistr(disstrU,p);
1210 
1211  if (y < _lineProperties.size())
1212  {
1213  if (_lineProperties[y] & LINE_DOUBLEWIDTH) {
1214  paint.scale(2,1);
1215  }
1216 
1218  paint.scale(1,2);
1219  }
1220  }
1221 
1222  // calculate the area in which the text will be drawn
1223  QRect textArea = QRect( _leftMargin+topLeftX+_fontWidth*x ,
1224  _topMargin+topLeftY+_fontHeight*y ,
1225  _fontWidth*len,
1226  _fontHeight);
1227 
1228  // move the calculated area to take account of scaling applied to the painter.
1229  // the position of the area from the origin (0,0) is scaled
1230  // by the opposite of whatever
1231  // transformation has been applied to the painter. this ensures that
1232  // painting does actually start from textArea.topLeft()
1233  // (instead of textArea.topLeft() * painter-scale)
1234  QTransform inverted = paint.transform().inverted();
1235  textArea.moveCenter( inverted.map(textArea.center()) );
1236 
1237 
1238  //paint text fragment
1239  drawTextFragment( paint,
1240  textArea,
1241  unistr,
1242  &_image[loc(x,y)] );
1243 
1244 
1245  _fixedFont = save__fixedFont;
1246 
1247  //reset back to single-width, single-height _lines
1248  paint.resetTransform();
1249 
1250  if (y < _lineProperties.size()-1)
1251  {
1252  //double-height _lines are represented by two adjacent _lines
1253  //containing the same characters
1254  //both _lines will have the LINE_DOUBLEHEIGHT attribute.
1255  //If the current line has the LINE_DOUBLEHEIGHT attribute,
1256  //we can therefore skip the next line
1258  y++;
1259  }
1260  x += len - 1;
1261  } // for x
1262  } // for y
1263  delete [] disstrU;
1264 }
1265 
1267 {
1268  _blinking = !_blinking;
1269 
1270  //TODO: Optimise to only repaint the areas of the widget
1271  // where there is blinking text
1272  // rather than repainting the whole widget.
1273  update();
1274 }
1275 
1276 QRect TerminalView::imageToWidget(const QRect& imageArea) const
1277 {
1278  //qDebug("%s %d imageToWidget", __FILE__, __LINE__);
1279  QRect result;
1280  result.setLeft( _leftMargin + _fontWidth * imageArea.left() );
1281  result.setTop( _topMargin + _fontHeight * imageArea.top() );
1282  result.setWidth( _fontWidth * imageArea.width() );
1283  result.setHeight( _fontHeight * imageArea.height() );
1284 
1285  return result;
1286 }
1287 
1289 {
1290  if (_hasBlinkingCursor)
1292  else
1293  _cursorBlinking = false;
1294 
1295  QRect cursorRect = imageToWidget( QRect(cursorPosition(),QSize(1,1)) );
1296 
1297  update(cursorRect);
1298 }
1299 
1300 /* ------------------------------------------------------------------------- */
1301 /* */
1302 /* Resizing */
1303 /* */
1304 /* ------------------------------------------------------------------------- */
1305 
1306 void TerminalView::resizeEvent(QResizeEvent*)
1307 {
1308  updateImageSize();
1309 }
1310 
1312 {
1313  if (_isFixedSize)
1314  {
1316  QWidget::setFixedSize(sizeHint());
1317  parentWidget()->adjustSize();
1318  parentWidget()->setFixedSize(parentWidget()->sizeHint());
1319  return;
1320  }
1321  if (_image)
1322  updateImageSize();
1323 }
1324 
1326 {
1327  //qDebug("%s %d updateImageSize", __FILE__, __LINE__);
1328  Character* oldimg = _image;
1329  int oldlin = _lines;
1330  int oldcol = _columns;
1331 
1332  makeImage();
1333 
1334 
1335  // copy the old image to reduce flicker
1336  int lines = qMin(oldlin,_lines);
1337  int columns = qMin(oldcol,_columns);
1338 
1339  //qDebug("%s %d updateImageSize", __FILE__, __LINE__);
1340  if (oldimg)
1341  {
1342  for (int line = 0; line < lines; line++)
1343  {
1344  memcpy((void*)&_image[_columns*line],
1345  (void*)&oldimg[oldcol*line],columns*sizeof(Character));
1346  }
1347  delete[] oldimg;
1348  }
1349 
1350  //qDebug("%s %d updateImageSize", __FILE__, __LINE__);
1351  if (_screenWindow)
1352  _screenWindow->setWindowLines(_lines);
1353 
1354  _resizing = (oldlin!=_lines) || (oldcol!=_columns);
1355 
1356  if ( _resizing )
1357  {
1358  //qDebug("%s %d updateImageSize", __FILE__, __LINE__);
1360 #if defined (SIGWINCH)
1361  ::raise (SIGWINCH);
1362 #endif
1363  emit changedContentSizeSignal(_contentHeight, _contentWidth); // expose resizeEvent
1364  }
1365  //qDebug("%s %d updateImageSize", __FILE__, __LINE__);
1366 
1367  _resizing = false;
1368 }
1369 
1370 //showEvent and hideEvent are reimplemented here so that it appears to other classes that the
1371 //display has been resized when the display is hidden or shown.
1372 //
1373 //this allows
1374 //TODO: Perhaps it would be better to have separate signals for show and hide instead of using
1375 //the same signal as the one for a content size change
1376 void TerminalView::showEvent(QShowEvent*)
1377 {
1379 }
1380 void TerminalView::hideEvent(QHideEvent*)
1381 {
1383 }
1384 
1385 /* ------------------------------------------------------------------------- */
1386 /* */
1387 /* Scrollbar */
1388 /* */
1389 /* ------------------------------------------------------------------------- */
1390 
1392 {
1393  if ( !_screenWindow )
1394  return;
1395 
1396  _screenWindow->scrollTo( _scrollBar->value() );
1397 
1398  // if the thumb has been moved to the bottom of the _scrollBar then set
1399  // the display to automatically track new output,
1400  // that is, scroll down automatically
1401  // to how new _lines as they are added
1402  const bool atEndOfOutput = (_scrollBar->value() == _scrollBar->maximum());
1403  _screenWindow->setTrackOutput( atEndOfOutput );
1404 
1405  updateImage();
1406 }
1407 
1408 void TerminalView::setScroll(int cursor, int slines)
1409 {
1410  //qDebug("%s %d setScroll", __FILE__, __LINE__);
1411  // update _scrollBar if the range or value has changed,
1412  // otherwise return
1413  //
1414  // setting the range or value of a _scrollBar will always trigger
1415  // a repaint, so it should be avoided if it is not necessary
1416  if ( _scrollBar->minimum() == 0 &&
1417  _scrollBar->maximum() == (slines - _lines) &&
1418  _scrollBar->value() == cursor )
1419  {
1420  return;
1421  }
1422 
1423  disconnect(_scrollBar, SIGNAL(valueChanged(int)), this, SLOT(scrollBarPositionChanged(int)));
1424  _scrollBar->setRange(0,slines - _lines);
1425  _scrollBar->setSingleStep(1);
1426  _scrollBar->setPageStep(_lines);
1427  _scrollBar->setValue(cursor);
1428  connect(_scrollBar, SIGNAL(valueChanged(int)), this, SLOT(scrollBarPositionChanged(int)));
1429 }
1430 
1432 {
1433  if (_scrollbarLocation == position) {
1434  // return;
1435  }
1436 
1437  if ( position == NoScrollBar )
1438  _scrollBar->hide();
1439  else
1440  _scrollBar->show();
1441 
1442  _topMargin = _leftMargin = 1;
1443  _scrollbarLocation = position;
1444 
1445  propagateSize();
1446  update();
1447 }
1448 
1449 void TerminalView::mousePressEvent(QMouseEvent* ev)
1450 {
1451  if ( _possibleTripleClick && (ev->button()==Qt::LeftButton) ) {
1453  return;
1454  }
1455 
1456  if ( !contentsRect().contains(ev->pos()) ) return;
1457 
1458  if ( !_screenWindow ) return;
1459 
1460  int charLine;
1461  int charColumn;
1462  getCharacterPosition(ev->pos(),charLine,charColumn);
1463  QPoint pos = QPoint(charColumn,charLine);
1464 
1465  if ( ev->button() == Qt::LeftButton)
1466  {
1467 
1468  Filter::HotSpot* spot = _filterChain->hotSpotAt(charLine,charColumn);
1469  if ( spot &&
1470  (spot->type() == Filter::Link || spot->type() == Filter::ErrorLink))
1471  {
1472  QList<QAction*> actions = spot->actions ();
1473  if (actions.length ())
1474  actions.at (0)->activate (QAction::Trigger);
1475  return;
1476  }
1477 
1478  _lineSelectionMode = false;
1479  _wordSelectionMode = false;
1480 
1481  emit isBusySelecting(true); // Keep it steady...
1482  // Drag only when the Control key is hold
1483  bool selected = false;
1484 
1485  // The receiver of the testIsSelected() signal will adjust
1486  // 'selected' accordingly.
1487  //emit testIsSelected(pos.x(), pos.y(), selected);
1488 
1489  selected = _screenWindow->isSelected(pos.x(),pos.y());
1490 
1491  if ((!_ctrlDrag || ev->modifiers() & Qt::ControlModifier) && selected ) {
1492  // The user clicked inside selected text
1494  dragInfo.start = ev->pos();
1495  }
1496  else {
1497  // No reason to ever start a drag event
1498  dragInfo.state = diNone;
1499 
1500  _preserveLineBreaks = !( ( ev->modifiers() & Qt::ControlModifier ) && !(ev->modifiers() & Qt::AltModifier) );
1501  _columnSelectionMode = (ev->modifiers() & Qt::AltModifier) && (ev->modifiers() & Qt::ControlModifier);
1502 
1503  if (_mouseMarks || (ev->modifiers() & Qt::ShiftModifier))
1504  {
1505  _screenWindow->clearSelection();
1506 
1507  //emit clearSelectionSignal();
1508  pos.ry() += _scrollBar->value();
1509  _iPntSel = _pntSel = pos;
1510  _actSel = 1; // left mouse button pressed but nothing selected yet.
1511 
1512  }
1513  else
1514  {
1515  emit mouseSignal( 0, charColumn + 1, charLine + 1 +_scrollBar->value() -_scrollBar->maximum() , 0);
1516  }
1517  }
1518  }
1519  else if ( ev->button() == Qt::MiddleButton )
1520  {
1521  if ( _mouseMarks || (!_mouseMarks && (ev->modifiers() & Qt::ShiftModifier)) )
1522  emitSelection(true,ev->modifiers() & Qt::ControlModifier);
1523  else
1524  emit mouseSignal( 1, charColumn +1, charLine +1 +_scrollBar->value() -_scrollBar->maximum() , 0);
1525  }
1526  else if ( ev->button() == Qt::RightButton )
1527  {
1528  if (_mouseMarks || (ev->modifiers() & Qt::ShiftModifier))
1529  {
1530  emit configureRequest( this,
1531  ev->modifiers() & (Qt::ShiftModifier|Qt::ControlModifier),
1532  ev->pos()
1533  );
1534  }
1535  else
1536  emit mouseSignal( 2, charColumn +1, charLine +1 +_scrollBar->value() -_scrollBar->maximum() , 0);
1537  }
1538 
1539  QWidget::mousePressEvent (ev);
1540 }
1541 
1543 {
1544  int charLine, charColumn;
1545  getCharacterPosition(position,charLine,charColumn);
1546 
1547  Filter::HotSpot* spot = _filterChain->hotSpotAt(charLine,charColumn);
1548 
1549  return spot ? spot->actions() : QList<QAction*>();
1550 }
1551 
1552 void TerminalView::mouseMoveEvent(QMouseEvent* ev)
1553 {
1554  int charLine = 0;
1555  int charColumn = 0;
1556 
1557  getCharacterPosition(ev->pos(),charLine,charColumn);
1558 
1559  // handle filters
1560  // change link hot-spot appearance on mouse-over
1561  Filter::HotSpot* spot = _filterChain->hotSpotAt(charLine,charColumn);
1562  if ( spot &&
1563  (spot->type() == Filter::Link || spot->type() == Filter::ErrorLink))
1564  {
1565  // change mouse cursor when mouse is over links
1566  if (! _mouseOverHotspotArea.isValid())
1567  setCursor (Qt::PointingHandCursor);
1568 
1569  QRect previousHotspotArea = _mouseOverHotspotArea;
1570  _mouseOverHotspotArea.setCoords( qMin(spot->startColumn() , spot->endColumn()) * _fontWidth,
1571  spot->startLine() * _fontHeight,
1572  qMax(spot->startColumn() , spot->endColumn()) * _fontHeight,
1573  (spot->endLine()+1) * _fontHeight );
1574 
1575  // display tooltips when mousing over links
1576  // TODO: Extend this to work with filter types other than links
1577  const QString& tooltip = spot->tooltip();
1578  if ( !tooltip.isEmpty() )
1579  {
1580  QToolTip::showText( mapToGlobal(ev->pos()) , tooltip , this , _mouseOverHotspotArea );
1581  }
1582 
1583  update( _mouseOverHotspotArea | previousHotspotArea );
1584  }
1585  else if ( _mouseOverHotspotArea.isValid() )
1586  {
1587  setUsesMouse (true);
1588  update( _mouseOverHotspotArea );
1589  // set hotspot area to an invalid rectangle
1590  _mouseOverHotspotArea = QRect();
1591  }
1592 
1593  // for auto-hiding the cursor, we need mouseTracking
1594  if (ev->buttons() == Qt::NoButton ) return;
1595 
1596  // if the terminal is interested in mouse movements
1597  // then emit a mouse movement signal, unless the shift
1598  // key is being held down, which overrides this.
1599  if (!_mouseMarks && !(ev->modifiers() & Qt::ShiftModifier))
1600  {
1601  int button = 3;
1602  if (ev->buttons() & Qt::LeftButton)
1603  button = 0;
1604  if (ev->buttons() & Qt::MiddleButton)
1605  button = 1;
1606  if (ev->buttons() & Qt::RightButton)
1607  button = 2;
1608 
1609 
1610  emit mouseSignal( button,
1611  charColumn + 1,
1612  charLine + 1 +_scrollBar->value() -_scrollBar->maximum(),
1613  1 );
1614 
1615  return;
1616  }
1617 
1618  if (dragInfo.state == diPending)
1619  {
1620  // we had a mouse down, but haven't confirmed a drag yet
1621  // if the mouse has moved sufficiently, we will confirm
1622 
1623  int distance = 10; //KGlobalSettings::dndEventDelay();
1624  if ( ev->x() > dragInfo.start.x() + distance || ev->x() < dragInfo.start.x() - distance ||
1625  ev->y() > dragInfo.start.y() + distance || ev->y() < dragInfo.start.y() - distance)
1626  {
1627  // we've left the drag square, we can start a real drag operation now
1628  emit isBusySelecting(false); // Ok.. we can breath again.
1629 
1630  _screenWindow->clearSelection();
1631  doDrag();
1632  }
1633  return;
1634  }
1635  else if (dragInfo.state == diDragging)
1636  {
1637  // this isn't technically needed because mouseMoveEvent is suppressed during
1638  // Qt drag operations, replaced by dragMoveEvent
1639  return;
1640  }
1641 
1642  if (_actSel == 0) return;
1643 
1644  // don't extend selection while pasting
1645  if (ev->buttons() & Qt::MiddleButton) return;
1646 
1647  extendSelection( ev->pos() );
1648 }
1649 
1650 #if 0
1651 void TerminalDisplay::setSelectionEnd()
1652 {
1653  extendSelection( _configureRequestPoint );
1654 }
1655 #endif
1656 
1657 void TerminalView::extendSelection(const QPoint& position) {
1658  QPoint pos = position;
1659 
1660  if (!_screenWindow) {
1661  return;
1662  }
1663 
1664  QPoint tL = contentsRect().topLeft();
1665  int tLx = tL.x();
1666  int tLy = tL.y();
1667  int scroll = _scrollBar->value();
1668 
1669  // we're in the process of moving the mouse with the left button pressed
1670  // the mouse cursor will kept caught within the bounds of the text in
1671  // this widget.
1672 
1673  // Adjust position within text area bounds. See FIXME above.
1674  if (pos.x() < tLx + _leftMargin) {
1675  pos.setX(tLx + _leftMargin);
1676  }
1677  if (pos.x() > tLx + _leftMargin + _usedColumns * _fontWidth - 1) {
1678  pos.setX(tLx + _leftMargin + _usedColumns * _fontWidth);
1679  }
1680  if (pos.y() < tLy + _topMargin) {
1681  pos.setY(tLy + _topMargin);
1682  }
1683  if (pos.y() > tLy + _topMargin + _usedLines * _fontHeight - 1) {
1684  pos.setY(tLy + _topMargin + _usedLines * _fontHeight - 1);
1685  }
1686 
1687  if (pos.y() == tLy + _topMargin + _usedLines * _fontHeight - 1) {
1688  _scrollBar->setValue(_scrollBar->value() + yMouseScroll); // scrollforward
1689  }
1690  if (pos.y() == tLy + _topMargin) {
1691  _scrollBar->setValue(_scrollBar->value() - yMouseScroll); // scrollback
1692  }
1693 
1694  int charColumn = 0;
1695  int charLine = 0;
1696  getCharacterPosition(pos, charLine, charColumn);
1697 
1698  QPoint here = QPoint(charColumn, charLine);
1699  QPoint ohere(here);
1700  QPoint _iPntSelCorr = _iPntSel;
1701  _iPntSelCorr.ry() -= _scrollBar->value();
1702  QPoint _pntSelCorr = _pntSel;
1703  _pntSelCorr.ry() -= _scrollBar->value();
1704  bool swapping = false;
1705 
1706  if (_wordSelectionMode) {
1707  // Extend to word boundaries
1708  int i = 0;
1709  int selClass = 0;
1710 
1711  bool left_not_right = (here.y() < _iPntSelCorr.y() ||
1712  (here.y() == _iPntSelCorr.y() && here.x() < _iPntSelCorr.x()));
1713  bool old_left_not_right = (_pntSelCorr.y() < _iPntSelCorr.y() ||
1714  (_pntSelCorr.y() == _iPntSelCorr.y() && _pntSelCorr.x() < _iPntSelCorr.x()));
1715  swapping = left_not_right != old_left_not_right;
1716 
1717  // Find left (left_not_right ? from here : from start)
1718  QPoint left = left_not_right ? here : _iPntSelCorr;
1719  i = loc(left.x(), left.y());
1720  if (i >= 0 && i <= _imageSize) {
1721  selClass = charClass(_image[i].character);
1722  while (((left.x() > 0) || (left.y() > 0 && (_lineProperties[left.y() - 1] & LINE_WRAPPED)))
1723  && charClass(_image[i - 1].character) == selClass) {
1724  i--;
1725  if (left.x() > 0) {
1726  left.rx()--;
1727  } else {
1728  left.rx() = _usedColumns - 1;
1729  left.ry()--;
1730  }
1731  }
1732  }
1733 
1734  // Find left (left_not_right ? from start : from here)
1735  QPoint right = left_not_right ? _iPntSelCorr : here;
1736  i = loc(right.x(), right.y());
1737  if (i >= 0 && i <= _imageSize) {
1738  selClass = charClass(_image[i].character);
1739  while (((right.x() < _usedColumns - 1) || (right.y() < _usedLines - 1 && (_lineProperties[right.y()] & LINE_WRAPPED)))
1740  && charClass(_image[i + 1].character) == selClass) {
1741  i++;
1742  if (right.x() < _usedColumns - 1) {
1743  right.rx()++;
1744  } else {
1745  right.rx() = 0;
1746  right.ry()++;
1747  }
1748  }
1749  }
1750 
1751  // Pick which is start (ohere) and which is extension (here)
1752  if (left_not_right) {
1753  here = left;
1754  ohere = right;
1755  } else {
1756  here = right;
1757  ohere = left;
1758  }
1759  ohere.rx()++;
1760  }
1761 
1762  if (_lineSelectionMode) {
1763  // Extend to complete line
1764  bool above_not_below = (here.y() < _iPntSelCorr.y());
1765 
1766  QPoint above = above_not_below ? here : _iPntSelCorr;
1767  QPoint below = above_not_below ? _iPntSelCorr : here;
1768 
1769  while (above.y() > 0 && (_lineProperties[above.y() - 1] & LINE_WRAPPED)) {
1770  above.ry()--;
1771  }
1772  while (below.y() < _usedLines - 1 && (_lineProperties[below.y()] & LINE_WRAPPED)) {
1773  below.ry()++;
1774  }
1775 
1776  above.setX(0);
1777  below.setX(_usedColumns - 1);
1778 
1779  // Pick which is start (ohere) and which is extension (here)
1780  if (above_not_below) {
1781  here = above;
1782  ohere = below;
1783  } else {
1784  here = below;
1785  ohere = above;
1786  }
1787 
1788  QPoint newSelBegin = QPoint(ohere.x(), ohere.y());
1789  swapping = !(_tripleSelBegin == newSelBegin);
1790  _tripleSelBegin = newSelBegin;
1791 
1792  ohere.rx()++;
1793  }
1794 
1795  int offset = 0;
1797  int i = 0;
1798  int selClass = 0;
1799 
1800  bool left_not_right = (here.y() < _iPntSelCorr.y() ||
1801  (here.y() == _iPntSelCorr.y() && here.x() < _iPntSelCorr.x()));
1802  bool old_left_not_right = (_pntSelCorr.y() < _iPntSelCorr.y() ||
1803  (_pntSelCorr.y() == _iPntSelCorr.y() && _pntSelCorr.x() < _iPntSelCorr.x()));
1804  swapping = left_not_right != old_left_not_right;
1805 
1806  // Find left (left_not_right ? from here : from start)
1807  QPoint left = left_not_right ? here : _iPntSelCorr;
1808 
1809  // Find left (left_not_right ? from start : from here)
1810  QPoint right = left_not_right ? _iPntSelCorr : here;
1811  if (right.x() > 0 && !_columnSelectionMode) {
1812  i = loc(right.x(), right.y());
1813  if (i >= 0 && i <= _imageSize) {
1814  selClass = charClass(_image[i - 1].character);
1815  if (selClass == ' ') {
1816  while (right.x() < _usedColumns - 1 && charClass(_image[i + 1].character) == selClass && (right.y() < _usedLines - 1) &&
1817  !(_lineProperties[right.y()] & LINE_WRAPPED)) {
1818  i++;
1819  right.rx()++;
1820  }
1821  if (right.x() < _usedColumns - 1) {
1822  right = left_not_right ? _iPntSelCorr : here;
1823  } else {
1824  right.rx()++; // will be balanced later because of offset=-1;
1825  }
1826  }
1827  }
1828  }
1829 
1830  // Pick which is start (ohere) and which is extension (here)
1831  if (left_not_right) {
1832  here = left;
1833  ohere = right;
1834  offset = 0;
1835  } else {
1836  here = right;
1837  ohere = left;
1838  offset = -1;
1839  }
1840  }
1841 
1842  if ((here == _pntSelCorr) && (scroll == _scrollBar->value())) {
1843  return; // not moved
1844  }
1845 
1846  if (here == ohere) {
1847  return; // It's not left, it's not right.
1848  }
1849 
1850  if (_actSel < 2 || swapping) {
1852  _screenWindow->setSelectionStart(ohere.x(), ohere.y(), true);
1853  } else {
1854  _screenWindow->setSelectionStart(ohere.x() - 1 - offset , ohere.y(), false);
1855  }
1856 
1857  }
1858 
1859  _actSel = 2; // within selection
1860  _pntSel = here;
1861  _pntSel.ry() += _scrollBar->value();
1862 
1864  _screenWindow->setSelectionEnd(here.x(), here.y());
1865  } else {
1866  _screenWindow->setSelectionEnd(here.x() + offset, here.y());
1867  }
1868 }
1869 
1870 void TerminalView::mouseReleaseEvent(QMouseEvent* ev)
1871 {
1872  if ( !_screenWindow )
1873  return;
1874 
1875  int charLine;
1876  int charColumn;
1877  getCharacterPosition(ev->pos(),charLine,charColumn);
1878 
1879  if ( ev->button() == Qt::LeftButton)
1880  {
1881  emit isBusySelecting(false);
1882  if(dragInfo.state == diPending)
1883  {
1884  // We had a drag event pending but never confirmed. Kill selection
1885  _screenWindow->clearSelection();
1886  //emit clearSelectionSignal();
1887  }
1888  else
1889  {
1890  if ( _actSel > 1 )
1891  {
1893  }
1894 
1895  _actSel = 0;
1896 
1897  //FIXME: emits a release event even if the mouse is
1898  // outside the range. The procedure used in `mouseMoveEvent'
1899  // applies here, too.
1900 
1901  if (!_mouseMarks && !(ev->modifiers() & Qt::ShiftModifier))
1902  emit mouseSignal( 3, // release
1903  charColumn + 1,
1904  charLine + 1 +_scrollBar->value() -_scrollBar->maximum() , 0);
1905  }
1906  dragInfo.state = diNone;
1907  }
1908 
1909 
1910  if ( !_mouseMarks &&
1911  ((ev->button() == Qt::RightButton && !(ev->modifiers() & Qt::ShiftModifier))
1912  || ev->button() == Qt::MiddleButton) )
1913  {
1914  emit mouseSignal( 3,
1915  charColumn + 1,
1916  charLine + 1 +_scrollBar->value() -_scrollBar->maximum() ,
1917  0);
1918  }
1919 
1920  QWidget::mouseReleaseEvent(ev);
1921 }
1922 
1923 void TerminalView::getCharacterPosition(const QPoint& widgetPoint,int& line,int& column) const
1924 {
1925 
1926  column = (widgetPoint.x() + _fontWidth/2 -contentsRect().left()-_leftMargin) / _fontWidth;
1927  line = (widgetPoint.y()-contentsRect().top()-_topMargin) / _fontHeight;
1928 
1929  if ( line < 0 )
1930  line = 0;
1931  if ( column < 0 )
1932  column = 0;
1933 
1934  if ( line >= _usedLines )
1935  line = _usedLines-1;
1936 
1937  // the column value returned can be equal to _usedColumns, which
1938  // is the position just after the last character displayed in a line.
1939  //
1940  // this is required so that the user can select characters in the right-most
1941  // column (or left-most for right-to-left input)
1942  if ( column > _usedColumns )
1943  column = _usedColumns;
1944 }
1945 
1947 {
1948  if ( !_screenWindow )
1949  return;
1950 
1951  _lineProperties = _screenWindow->getLineProperties();
1952 }
1953 
1955 {
1956  if ( ev->button() != Qt::LeftButton) return;
1957  if ( !_screenWindow ) return;
1958 
1959  int charLine = 0;
1960  int charColumn = 0;
1961 
1962  getCharacterPosition(ev->pos(),charLine,charColumn);
1963 
1964  QPoint pos(charColumn,charLine);
1965 
1966  // pass on double click as two clicks.
1967  if (!_mouseMarks && !(ev->modifiers() & Qt::ShiftModifier))
1968  {
1969  // Send just _ONE_ click event, since the first click of the double click
1970  // was already sent by the click handler
1971  emit mouseSignal( 0,
1972  pos.x()+1,
1973  pos.y()+1 +_scrollBar->value() -_scrollBar->maximum(),
1974  0 ); // left button
1975  return;
1976  }
1977 
1978  _screenWindow->clearSelection();
1979  QPoint bgnSel = pos;
1980  QPoint endSel = pos;
1981  int i = loc(bgnSel.x(),bgnSel.y());
1982  _iPntSel = bgnSel;
1983  _iPntSel.ry() += _scrollBar->value();
1984 
1985  _wordSelectionMode = true;
1986 
1987  // find word boundaries...
1988  int selClass = charClass(_image[i].character);
1989  {
1990  // find the start of the word
1991  int x = bgnSel.x();
1992  while ( ((x>0) || (bgnSel.y()>0 && (_lineProperties[bgnSel.y()-1] & LINE_WRAPPED) ))
1993  && charClass(_image[i-1].character) == selClass )
1994  {
1995  i--;
1996  if (x>0)
1997  x--;
1998  else
1999  {
2000  x=_usedColumns-1;
2001  bgnSel.ry()--;
2002  }
2003  }
2004 
2005  bgnSel.setX(x);
2006  _screenWindow->setSelectionStart( bgnSel.x() , bgnSel.y() , false );
2007 
2008  // find the end of the word
2009  i = loc( endSel.x(), endSel.y() );
2010  x = endSel.x();
2011  while( ((x<_usedColumns-1) || (endSel.y()<_usedLines-1 && (_lineProperties[endSel.y()] & LINE_WRAPPED) ))
2012  && charClass(_image[i+1].character) == selClass )
2013  {
2014  i++;
2015  if (x<_usedColumns-1)
2016  x++;
2017  else
2018  {
2019  x=0;
2020  endSel.ry()++;
2021  }
2022  }
2023 
2024  endSel.setX(x);
2025 
2026  // In word selection mode don't select @ (64) if at end of word.
2027  if ( ( QChar( _image[i].character ) == '@' ) && ( ( endSel.x() - bgnSel.x() ) > 0 ) )
2028  endSel.setX( x - 1 );
2029 
2030 
2031  _actSel = 2; // within selection
2032 
2033  _screenWindow->setSelectionEnd( endSel.x() , endSel.y() );
2034 
2036  }
2037 
2038  _possibleTripleClick=true;
2039 
2040  QTimer::singleShot(QApplication::doubleClickInterval(),this,
2041  SLOT(tripleClickTimeout()));
2042 }
2043 
2044 void TerminalView::wheelEvent( QWheelEvent* ev )
2045 {
2046 #if defined (HAVE_QWHEELEVENT_ANGLEDELTA)
2047  if (ev->angleDelta().y() == 0)
2048  return;
2049 #else
2050  if (ev->orientation() != Qt::Vertical)
2051  return;
2052 #endif
2053 
2054  if ( _mouseMarks )
2055  _scrollBar->event(ev);
2056  else
2057  {
2058  int charLine;
2059  int charColumn;
2060 #if defined (HAVE_QWHEELEVENT_POSITION)
2061  QPoint pos = ev->position().toPoint();
2062 #else
2063  QPoint pos = ev->pos();
2064 #endif
2065  getCharacterPosition( pos , charLine , charColumn );
2066 
2067 #if defined (HAVE_QWHEELEVENT_ANGLEDELTA)
2068  int delta = ev->angleDelta().y();
2069 #else
2070  int delta = ev->delta();
2071 #endif
2072  emit mouseSignal( delta > 0 ? 4 : 5,
2073  charColumn + 1,
2074  charLine + 1 +_scrollBar->value() -_scrollBar->maximum() ,
2075  0);
2076  }
2077 }
2078 
2080 {
2081  _possibleTripleClick=false;
2082 }
2083 
2085 {
2086  if ( !_screenWindow ) return;
2087 
2088  int charLine;
2089  int charColumn;
2090  getCharacterPosition(ev->pos(),charLine,charColumn);
2091  _iPntSel = QPoint(charColumn,charLine);
2092 
2093  _screenWindow->clearSelection();
2094 
2095  _lineSelectionMode = true;
2096  _wordSelectionMode = false;
2097 
2098  _actSel = 2; // within selection
2099  emit isBusySelecting(true); // Keep it steady...
2100 
2101  while (_iPntSel.y()>0 && (_lineProperties[_iPntSel.y()-1] & LINE_WRAPPED) )
2102  _iPntSel.ry()--;
2103 
2105  // find word boundary start
2106  int i = loc(_iPntSel.x(),_iPntSel.y());
2107  int selClass = charClass(_image[i].character);
2108  int x = _iPntSel.x();
2109 
2110  while ( ((x>0) ||
2111  (_iPntSel.y()>0 && (_lineProperties[_iPntSel.y()-1] & LINE_WRAPPED) )
2112  )
2113  && charClass(_image[i-1].character) == selClass )
2114  {
2115  i--;
2116  if (x>0)
2117  x--;
2118  else
2119  {
2120  x=_columns-1;
2121  _iPntSel.ry()--;
2122  }
2123  }
2124 
2125  _screenWindow->setSelectionStart( x , _iPntSel.y() , false );
2126  _tripleSelBegin = QPoint( x, _iPntSel.y() );
2127  }
2128  else if (_tripleClickMode == SelectWholeLine) {
2129  _screenWindow->setSelectionStart( 0 , _iPntSel.y() , false );
2130  _tripleSelBegin = QPoint( 0, _iPntSel.y() );
2131  }
2132 
2133  while (_iPntSel.y()<_lines-1 && (_lineProperties[_iPntSel.y()] & LINE_WRAPPED) )
2134  _iPntSel.ry()++;
2135 
2136  _screenWindow->setSelectionEnd( _columns - 1 , _iPntSel.y() );
2137 
2139 
2140  _iPntSel.ry() += _scrollBar->value();
2141 
2142  emit tripleClicked( _screenWindow->selectedText( _preserveLineBreaks ) );
2143 }
2144 
2145 
2147 {
2148  if (next)
2149  return false; // This disables changing the active part in konqueror
2150  // when pressing Tab
2151  return QWidget::focusNextPrevChild( next );
2152 }
2153 
2154 
2155 int TerminalView::charClass(quint16 ch) const
2156 {
2157  QChar qch=QChar(ch);
2158  if ( qch.isSpace() ) return ' ';
2159 
2160  if ( qch.isLetterOrNumber() || _wordCharacters.contains(qch, Qt::CaseInsensitive ) )
2161  return 'a';
2162 
2163  // Everything else is weird
2164  return 1;
2165 }
2166 
2167 void TerminalView::setWordCharacters(const QString& wc)
2168 {
2169  _wordCharacters = wc;
2170 }
2171 
2173 {
2174  _mouseMarks = on;
2175  setCursor( _mouseMarks ? Qt::IBeamCursor : Qt::ArrowCursor );
2176 }
2178 {
2179  return _mouseMarks;
2180 }
2181 
2183 {
2184  _bracketedPasteMode = on;
2185 }
2187 {
2188  return _bracketedPasteMode;
2189 }
2190 
2191 
2192 /* ------------------------------------------------------------------------- */
2193 /* */
2194 /* Clipboard */
2195 /* */
2196 /* ------------------------------------------------------------------------- */
2197 
2198 #undef KeyPress
2199 
2200 void TerminalView::emitSelection(bool useXselection,bool appendReturn)
2201 {
2202  if ( !_screenWindow )
2203  return;
2204 
2205  // Paste Clipboard by simulating keypress events
2206  QString text = QApplication::clipboard()->text(useXselection ? QClipboard::Selection :
2207  QClipboard::Clipboard);
2208  if(appendReturn)
2209  text.append("\r");
2210  if ( ! text.isEmpty() )
2211  {
2212  text.replace("\n", "\r");
2214  bracketText(text);
2215  else if (text.contains ("\t"))
2216  {
2217  qWarning ("converting TAB to SPC in pasted text before processing");
2218  text.replace ("\t", " ");
2219  }
2220  QKeyEvent e(QEvent::KeyPress, 0, Qt::NoModifier, text);
2221  emit keyPressedSignal(&e); // expose as a big fat keypress event
2222 
2223  _screenWindow->clearSelection();
2224  }
2225 }
2226 
2227 void TerminalView::bracketText(QString& text)
2228 {
2229  text.prepend("\033[200~");
2230  text.append("\033[201~");
2231 }
2232 
2233 void TerminalView::setSelection(const QString& t)
2234 {
2235  QApplication::clipboard()->setText(t, QClipboard::Selection);
2236 }
2237 
2238 void TerminalView::copyClipboard(bool extra_interrupt)
2239 {
2240  if ( !_screenWindow || !hasFocus())
2241  return;
2242 
2243  QString text = _screenWindow->selectedText(_preserveLineBreaks);
2244 
2245  if (text.isEmpty ())
2246  {
2247  if (! extra_interrupt)
2248  emit interrupt_signal ();
2249  }
2250  else
2251  QApplication::clipboard()->setText(text);
2252 }
2253 
2255 {
2256  if(hasFocus ())
2257  {
2258  emitSelection(false,false);
2259  }
2260 }
2261 
2263 {
2264  if ( !_screenWindow || !hasFocus())
2265  return;
2266 
2267  _screenWindow->setSelectionStart(0,-_screenWindow->currentLine(), false);
2268  //_screenWindow->setSelectionEnd(_screenWindow->windowColumns(),
2269  // _screenWindow->windowLines());
2270 
2271  _screenWindow->setSelectionEnd(_screenWindow->columnCount(),
2272  _screenWindow->windowLines());
2273 }
2274 
2275 
2277 {
2278  emitSelection(true,false);
2279 }
2280 
2281 
2282 /* ------------------------------------------------------------------------- */
2283 /* */
2284 /* Keyboard */
2285 /* */
2286 /* ------------------------------------------------------------------------- */
2287 
2288 void TerminalView::keyPressEvent( QKeyEvent* event )
2289 {
2290  //qDebug("%s %d keyPressEvent and key is %d", __FILE__, __LINE__, event->key());
2291 
2292  bool emitKeyPressSignal = true;
2293 
2294  // Keyboard-based navigation
2295  if ( event->modifiers() == Qt::ShiftModifier )
2296  {
2297  bool update = true;
2298 
2299  if ( event->key() == Qt::Key_PageUp )
2300  {
2301  //qDebug("%s %d pageup", __FILE__, __LINE__);
2302  _screenWindow->scrollBy( ScreenWindow::ScrollPages , -1 );
2303  }
2304  else if ( event->key() == Qt::Key_PageDown )
2305  {
2306  //qDebug("%s %d pagedown", __FILE__, __LINE__);
2307  _screenWindow->scrollBy( ScreenWindow::ScrollPages , 1 );
2308  }
2309  else if ( event->key() == Qt::Key_Up )
2310  {
2311  //qDebug("%s %d keyup", __FILE__, __LINE__);
2312  _screenWindow->scrollBy( ScreenWindow::ScrollLines , -1 );
2313  }
2314  else if ( event->key() == Qt::Key_Down )
2315  {
2316  //qDebug("%s %d keydown", __FILE__, __LINE__);
2317  _screenWindow->scrollBy( ScreenWindow::ScrollLines , 1 );
2318  }
2319  else {
2320  update = false;
2321  }
2322 
2323  if ( update )
2324  {
2325  //qDebug("%s %d updating", __FILE__, __LINE__);
2326  _screenWindow->setTrackOutput( _screenWindow->atEndOfOutput() );
2327 
2329  updateImage();
2330 
2331  // do not send key press to terminal
2332  emitKeyPressSignal = false;
2333  }
2334  }
2335 
2336  _screenWindow->setTrackOutput( true );
2337 
2338  _actSel=0; // Key stroke implies a screen update, so TerminalDisplay won't
2339  // know where the current selection is.
2340 
2341  if (_hasBlinkingCursor)
2342  {
2344  if (_cursorBlinking)
2345  blinkCursorEvent();
2346  else
2347  _cursorBlinking = false;
2348  }
2349 
2350  if ( emitKeyPressSignal && !_readonly )
2351  emit keyPressedSignal(event);
2352 
2353  if (_readonly) {
2354  event->ignore();
2355  }
2356  else {
2357  event->accept();
2358  }
2359 }
2360 
2361 void TerminalView::inputMethodEvent( QInputMethodEvent* event )
2362 {
2363  QKeyEvent keyEvent(QEvent::KeyPress,0,Qt::NoModifier,event->commitString());
2364  emit keyPressedSignal(&keyEvent);
2365 
2366  _inputMethodData.preeditString = event->preeditString();
2368 
2369  event->accept();
2370 }
2371 QVariant TerminalView::inputMethodQuery( Qt::InputMethodQuery query ) const
2372 {
2373  const QPoint cursorPos = _screenWindow ? _screenWindow->cursorPosition() : QPoint(0,0);
2374  switch ( query )
2375  {
2376 #if defined (HAVE_QT_IMCURSORRECTANGLE_ENUM_VALUE)
2377  case Qt::ImCursorRectangle:
2378 #else
2379  case Qt::ImMicroFocus:
2380 #endif
2381  return imageToWidget(QRect(cursorPos.x(),cursorPos.y(),1,1));
2382  break;
2383  case Qt::ImFont:
2384  return font();
2385  break;
2386  case Qt::ImCursorPosition:
2387  // return the cursor position within the current line
2388  return cursorPos.x();
2389  break;
2390  case Qt::ImSurroundingText:
2391  {
2392  // return the text from the current line
2393  QString lineText;
2394  QTextStream stream(&lineText);
2395  PlainTextDecoder decoder;
2396  decoder.begin(&stream);
2397  decoder.decodeLine(&_image[loc(0,cursorPos.y())],_usedColumns,_lineProperties[cursorPos.y()]);
2398  decoder.end();
2399  return lineText;
2400  }
2401  break;
2402  case Qt::ImCurrentSelection:
2403  return QString();
2404  break;
2405  default:
2406  break;
2407  }
2408 
2409  return QVariant();
2410 }
2411 
2413 {
2414  _bellMode=mode;
2415 }
2416 
2418 {
2419  _allowBell = true;
2420 }
2421 
2423 {
2424  ColorEntry color = _colorTable[1];
2425  _colorTable[1]=_colorTable[0];
2426  _colorTable[0]= color;
2428  update();
2429 }
2430 
2432 {
2433  // We initialize _image[_imageSize] too. See makeImage()
2434  for (int i = 0; i <= _imageSize; i++)
2435  {
2436  _image[i].character = ' ';
2442  }
2443 }
2444 
2446 {
2447  _scrollBar->resize(QApplication::style()->pixelMetric(QStyle::PM_ScrollBarExtent),
2448  contentsRect().height());
2449  switch(_scrollbarLocation)
2450  {
2451  case NoScrollBar :
2453  _contentWidth = contentsRect().width() - 2 * DEFAULT_LEFT_MARGIN;
2454  break;
2455  case ScrollBarLeft :
2457  _contentWidth = contentsRect().width() - 2 * DEFAULT_LEFT_MARGIN - _scrollBar->width();
2458  _scrollBar->move(contentsRect().topLeft());
2459  break;
2460  case ScrollBarRight:
2462  _contentWidth = contentsRect().width() - 2 * DEFAULT_LEFT_MARGIN - _scrollBar->width();
2463  _scrollBar->move(contentsRect().topRight() - QPoint(_scrollBar->width()-1,0));
2464  break;
2465  }
2466 
2468  _contentHeight = contentsRect().height() - 2 * DEFAULT_TOP_MARGIN + /* mysterious */ 1;
2469 
2470  if (!_isFixedSize)
2471  {
2472  // ensure that display is always at least one column wide
2473  _columns = qMax(1,qFloor(_contentWidth / _fontWidth));
2475 
2476  // ensure that display is always at least one line high
2477  _lines = qMax(1, qFloor(_contentHeight / _fontHeight));
2478  _usedLines = qMin(_usedLines,_lines);
2479  }
2480 }
2481 
2483 {
2484  //qDebug("%s %d makeImage", __FILE__, __LINE__);
2485  calcGeometry();
2486 
2487  // confirm that array will be of non-zero size, since the painting code
2488  // assumes a non-zero array length
2489  Q_ASSERT( _lines > 0 && _columns > 0 );
2490  Q_ASSERT( _usedLines <= _lines && _usedColumns <= _columns );
2491 
2493 
2494  // We over-commit one character so that we can be more relaxed in dealing with
2495  // certain boundary conditions: _image[_imageSize] is a valid but unused position
2496  _image = new Character[_imageSize+1];
2497 
2498  clearImage();
2499 }
2500 
2501 // calculate the needed size
2502 void TerminalView::setSize(int columns, int lines)
2503 {
2504  //FIXME - Not quite correct, a small amount of additional space
2505  // will be used for margins, the scrollbar etc.
2506  // we need to allow for this so that '_size' does allow
2507  // enough room for the specified number of columns and lines to fit
2508 
2509  QSize newSize = QSize( columns * _fontWidth ,
2510  lines * _fontHeight );
2511 
2512  if ( newSize != size() )
2513  {
2514  _size = newSize;
2515  updateGeometry();
2516  }
2517 }
2518 
2519 void TerminalView::setFixedSize(int cols, int lins)
2520 {
2521  _isFixedSize = true;
2522 
2523  //ensure that display is at least one line by one column in size
2524  _columns = qMax(1,cols);
2525  _lines = qMax(1,lins);
2527  _usedLines = qMin(_usedLines,_lines);
2528 
2529  if (_image)
2530  {
2531  delete[] _image;
2532  makeImage();
2533  }
2534  setSize(cols, lins);
2535  QWidget::setFixedSize(_size);
2536 }
2537 
2539 {
2540  return _size;
2541 }
2542 
2543 
2544 /* --------------------------------------------------------------------- */
2545 /* */
2546 /* Drag & Drop */
2547 /* */
2548 /* --------------------------------------------------------------------- */
2549 
2550 void TerminalView::dragEnterEvent(QDragEnterEvent* event)
2551 {
2552  if (event->mimeData()->hasFormat("text/plain"))
2553  event->acceptProposedAction();
2554 }
2555 
2556 void TerminalView::dropEvent(QDropEvent* event)
2557 {
2558  // KUrl::List urls = KUrl::List::fromMimeData(event->mimeData());
2559 
2560  QString dropText;
2561 
2562  if (event->mimeData ()->hasUrls ())
2563  {
2564  foreach (QUrl url, event->mimeData ()->urls ())
2565  {
2566  if(dropText.length () > 0)
2567  dropText += '\n';
2568  dropText += url.toLocalFile ();
2569  }
2570  }
2571 
2572  /* if (!urls.isEmpty())
2573  {
2574  for ( int i = 0 ; i < urls.count() ; i++ )
2575  {
2576  KUrl url = KIO::NetAccess::mostLocalUrl( urls[i] , 0 );
2577  QString urlText;
2578 
2579  if (url.isLocalFile())
2580  urlText = url.path();
2581  else
2582  urlText = url.url();
2583 
2584  // in future it may be useful to be able to insert file names with drag-and-drop
2585  // without quoting them (this only affects paths with spaces in)
2586  urlText = KShell::quoteArg(urlText);
2587 
2588  dropText += urlText;
2589 
2590  if ( i != urls.count()-1 )
2591  dropText += ' ';
2592  }
2593  }
2594  else
2595  {
2596  dropText = event->mimeData()->text();
2597  }
2598 */
2599  if(event->mimeData()->hasFormat("text/plain"))
2600  {
2601  emit sendStringToEmu(dropText.toLocal8Bit());
2602  }
2603 }
2604 
2606 {
2608  dragInfo.dragObject = new QDrag(this);
2609  QMimeData *mimeData = new QMimeData;
2610  mimeData->setText(QApplication::clipboard()->text(QClipboard::Selection));
2611  dragInfo.dragObject->setMimeData(mimeData);
2612  dragInfo.dragObject->exec(Qt::CopyAction);
2613  // Don't delete the QTextDrag object. Qt will delete it when it's done with it.
2614 }
2615 
2616 void TerminalView::outputSuspended(bool suspended)
2617 {
2618  //create the label when this function is first called
2619  if (!_outputSuspendedLabel)
2620  {
2621  //This label includes a link to an English language website
2622  //describing the 'flow control' (Xon/Xoff) feature found in almost
2623  //all terminal emulators.
2624  //If there isn't a suitable article available in the target language the link
2625  //can simply be removed.
2626  _outputSuspendedLabel = new QLabel( ("<qt>Output has been "
2627  "<a href=\"http://en.wikipedia.org/wiki/XON\">suspended</a>"
2628  " by pressing Ctrl+S."
2629  " Press <b>Ctrl+Q</b> to resume.</qt>"),
2630  this );
2631 
2632  QPalette palette(_outputSuspendedLabel->palette());
2633 
2634  palette.setColor(QPalette::Normal, QPalette::WindowText, QColor(Qt::white));
2635  palette.setColor(QPalette::Normal, QPalette::Window, QColor(Qt::black));
2636  // KColorScheme::adjustForeground(palette,KColorScheme::NeutralText);
2637  // KColorScheme::adjustBackground(palette,KColorScheme::NeutralBackground);
2638  _outputSuspendedLabel->setPalette(palette);
2639  _outputSuspendedLabel->setAutoFillBackground(true);
2640  _outputSuspendedLabel->setBackgroundRole(QPalette::Base);
2641  _outputSuspendedLabel->setFont(QApplication::font());
2642  _outputSuspendedLabel->setMargin(5);
2643 
2644  //enable activation of "Xon/Xoff" link in label
2645  _outputSuspendedLabel->setTextInteractionFlags(Qt::LinksAccessibleByMouse |
2646  Qt::LinksAccessibleByKeyboard);
2647  _outputSuspendedLabel->setOpenExternalLinks(true);
2648  _outputSuspendedLabel->setVisible(false);
2649 
2650  _gridLayout->addWidget(_outputSuspendedLabel);
2651  _gridLayout->addItem( new QSpacerItem(0,0,QSizePolicy::Expanding,
2652  QSizePolicy::Expanding),
2653  1,0);
2654 
2655  }
2656 
2657  _outputSuspendedLabel->setVisible(suspended);
2658 }
2659 
2661 {
2662  return _lineSpacing;
2663 }
2664 
2666 {
2667  _lineSpacing = i;
2668  setVTFont(font()); // Trigger an update.
2669 }
2670 
2672 {
2673  QString text = _screenWindow->selectedText (_preserveLineBreaks);
2674  return text;
2675 }
2676 
2677 void
2679 {
2680  // Disable the timer for processing the filter chain, since this might time
2681  // consuming
2682  if (visible)
2683  _process_filter_timer->start (300);
2684  else
2685  _process_filter_timer->stop ();
2686 }
#define COLOR_SPACE_DEFAULT
#define TABLE_COLORS
#define DEFAULT_FORE_COLOR
#define DEFAULT_BACK_COLOR
static const ColorEntry base_color_table[(2 *(2+8))]
static const int LINE_DOUBLEHEIGHT
Definition: Character.h:39
#define RE_UNDERLINE
Definition: Character.h:44
#define RE_EXTENDED_CHAR
Definition: Character.h:48
#define RE_CURSOR
Definition: Character.h:47
static const int LINE_WRAPPED
Definition: Character.h:37
#define DEFAULT_RENDITION
Definition: Character.h:41
static const int LINE_DOUBLEWIDTH
Definition: Character.h:38
#define RE_BOLD
Definition: Character.h:42
#define RE_BLINK
Definition: Character.h:43
#define yMouseScroll
#define REPCHAR
LineEncode
A table for emulating the simple (single width) unicode drawing chars.
@ BotR
@ Int21
@ LeftB
@ Int31
@ Int12
@ Int33
@ RightT
@ Int22
@ TopR
@ TopL
@ TopC
@ Int32
@ Int13
@ Int11
@ Int23
@ BotL
@ LeftC
@ LeftT
@ BotC
@ RightB
@ RightC
unsigned short vt100_graphics[32]
#define loc(X, Y)
Describes the color of a single character in the terminal.
QColor color(const ColorEntry *palette) const
Returns the color within the specified color @palette.
A single character in the terminal which consists of a unicode character value, foreground and backgr...
Definition: Character.h:56
CharacterColor backgroundColor
The color used to draw this character's background.
Definition: Character.h:92
CharacterColor foregroundColor
The foreground color used to draw this character.
Definition: Character.h:90
quint16 character
The unicode character value for this character.
Definition: Character.h:75
quint8 rendition
A combination of RENDITION flags which specify options for drawing the character.
Definition: Character.h:87
bool isBold(const ColorEntry *base) const
Returns true if this character should always be drawn in bold when it is drawn with the specified pal...
Definition: Character.h:142
An entry in a terminal display's color palette.
QColor color
The color value of this entry for display.
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...
Definition: Emulation.cpp:406
static ExtendedCharTable instance
The global ExtendedCharTable instance.
Definition: Character.h:191
A chain which allows a group of filters to be processed as one.
Definition: Filter.h:362
void process()
Processes each filter in the chain.
Definition: Filter.cpp:75
Filter::HotSpot * hotSpotAt(int line, int column) const
Returns the first hotspot which occurs at line, column or 0 if no hotspot was found.
Definition: Filter.cpp:85
QList< Filter::HotSpot * > hotSpots() const
Returns a list of all the hotspots in all the chain's filters.
Definition: Filter.cpp:101
virtual QString tooltip() const
Returns the text of a tooltip to be shown when the mouse moves over the hotspot, or an empty string i...
Definition: Filter.cpp:294
int endLine() const
Returns the line where the hotspot area ends.
Definition: Filter.cpp:306
int startLine() const
Returns the line when the hotspot area starts.
Definition: Filter.cpp:302
int endColumn() const
Returns the column on endLine() where the hotspot area ends.
Definition: Filter.cpp:314
virtual QList< QAction * > actions()
Returns a list of actions associated with the hotspot which can be used in a menu or toolbar.
Definition: Filter.cpp:298
Type type() const
Returns the type of the hotspot.
Definition: Filter.cpp:318
int startColumn() const
Returns the column on startLine() where the hotspot area starts.
Definition: Filter.cpp:310
@ Link
Definition: Filter.h:79
@ Marker
Definition: Filter.h:81
@ ErrorLink
Definition: Filter.h:83
A terminal character decoder which produces plain text, ignoring colours and other appearance-related...
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...
virtual void begin(QTextStream *output)
Begin decoding characters.
virtual void end()
End decoding.
Provides a window onto a section of a terminal screen.
Definition: ScreenWindow.h:52
void setWindowLines(int lines)
Sets the number of lines in the window.
A filter chain which processes character images from terminal displays.
Definition: Filter.h:396
void setImage(const Character *const image, int lines, int columns, const QVector< LineProperty > &lineProperties)
Set the current terminal image to image.
Definition: Filter.cpp:125
void selectAll()
selects all content
virtual void showEvent(QShowEvent *)
double _fontWidth
Definition: TerminalView.h:635
QPoint _tripleSelBegin
Definition: TerminalView.h:674
FilterChain * filterChain() const
Returns the display's filter chain.
QGridLayout * _gridLayout
Definition: TerminalView.h:630
uint randomSeed() const
Returns the seed used to generate random colors for the display (in color schemes that support them).
QRect preeditRect() const
virtual void inputMethodEvent(QInputMethodEvent *event)
bool _columnSelectionMode
Definition: TerminalView.h:679
void setWordCharacters(const QString &wc)
Sets which characters, in addition to letters and numbers, are regarded as being part of a word for t...
void processFilters()
Updates the filters in the display's filter chain.
static const int BLINK_DELAY
Definition: TerminalView.h:745
bool _colorsInverted
Definition: TerminalView.h:717
void updateLineProperties()
Causes the terminal display to fetch the latest line status flags from the associated terminal screen...
virtual void extendSelection(const QPoint &pos)
void pasteClipboard()
Pastes the content of the clipboard into the display.
static const int DEFAULT_TOP_MARGIN
Definition: TerminalView.h:747
void sendStringToEmu(const char *)
virtual void resizeEvent(QResizeEvent *)
bool _wordSelectionMode
Definition: TerminalView.h:676
QVector< LineProperty > _lineProperties
Definition: TerminalView.h:660
void drawInputMethodPreeditString(QPainter &painter, const QRect &rect)
void drawBackground(QPainter &painter, const QRect &rect, const QColor &color)
virtual void setFont(const QFont &)
Reimplemented.
void drawCursor(QPainter &painter, const QRect &rect, const QColor &foregroundColor, const QColor &backgroundColor, bool &invertColors)
void drawTextFragment(QPainter &painter, const QRect &rect, const QString &text, const Character *style)
void getCharacterPosition(const QPoint &widgetPoint, int &line, int &column) const
virtual void hideEvent(QHideEvent *)
QTimer * _blinkCursorTimer
Definition: TerminalView.h:695
void setBellMode(int mode)
Sets the type of effect used to alert the user when a 'bell' occurs in the terminal session.
bool _bracketedPasteMode
Definition: TerminalView.h:669
void setUsesMouse(bool usesMouse)
Sets whether the program whoose output is being displayed in the view is interested in mouse events.
void changedFontMetricSignal(int height, int width)
virtual void mouseReleaseEvent(QMouseEvent *)
void scrollBarPositionChanged(int value)
static const int DEFAULT_LEFT_MARGIN
Definition: TerminalView.h:746
void setScroll(int cursor, int lines)
Sets the current position and range of the display's scroll bar.
void configureRequest(TerminalView *, int state, const QPoint &position)
Emitted when the user right clicks on the display, or right-clicks with the Shift key held down if us...
void setRandomSeed(uint seed)
Sets the seed used to generate random colors for the display (in color schemes that support them).
void isBusySelecting(bool)
void copyClipboard(bool extra_interrupt)
Copies the selected text to the clipboard.
void interrupt_signal(void)
QPoint cursorPosition() const
@ SelectForwardsFromCursor
Select from the current cursor position to the end of the line.
Definition: TerminalView.h:151
@ SelectWholeLine
Select the whole line underneath the cursor.
Definition: TerminalView.h:149
void setColorTable(const ColorEntry table[])
Sets the terminal color palette used by the display.
void setScrollBarPosition(ScrollBarPosition position)
Specifies whether the terminal display has a vertical scroll bar, and if so whether it is shown on th...
ScreenWindow * screenWindow() const
Returns the terminal screen section which is displayed in this widget.
void setKeyboardCursorShape(KeyboardCursorShape shape)
Sets the shape of the keyboard cursor.
bool _lineSelectionMode
Definition: TerminalView.h:677
Character * _image
Definition: TerminalView.h:656
void focusInEvent(QFocusEvent *focusEvent)
QScrollBar * _scrollBar
Definition: TerminalView.h:682
QPointer< ScreenWindow > _screenWindow
Definition: TerminalView.h:626
TerminalImageFilterChain * _filterChain
Definition: TerminalView.h:725
virtual bool focusNextPrevChild(bool next)
void setScreenWindow(ScreenWindow *window)
Sets the terminal screen section which is displayed in this widget.
virtual int charClass(quint16) const
void setKeyboardCursorColor(bool useForegroundColor, const QColor &color)
Sets the color used to draw the keyboard cursor.
ColorEntry _colorTable[TABLE_COLORS]
Definition: TerminalView.h:662
bool _hasBlinkingCursor
Definition: TerminalView.h:690
TripleClickMode _tripleClickMode
Definition: TerminalView.h:692
bool _terminalSizeStartup
Definition: TerminalView.h:667
bool _preserveLineBreaks
Definition: TerminalView.h:678
void bracketText(QString &text)
change and wrap text corresponding to paste mode
void setVTFont(const QFont &font)
Sets the font used to draw the display.
QString selectedText()
QRect _mouseOverHotspotArea
Definition: TerminalView.h:726
QSize sizeHint() const
void updateImage()
Causes the terminal display to fetch the latest character image from the associated terminal screen (...
int columns()
Returns the number of characters of text which can be displayed on each line in the widget.
Definition: TerminalView.h:237
virtual ~TerminalView()
void propagateSize()
void blinkCursorEvent()
virtual void mouseMoveEvent(QMouseEvent *)
InputMethodData _inputMethodData
Definition: TerminalView.h:740
void focusOutEvent(QFocusEvent *focusEvent)
void mouseSignal(int button, int column, int line, int eventType)
A mouse event occurred.
bool _cursorBlinking
Definition: TerminalView.h:689
void setSelection(const QString &t)
void setBlinkingCursor(bool blink)
Specifies whether or not the cursor blinks.
void drawCharacters(QPainter &painter, const QRect &rect, const QString &text, const Character *style, bool invertCharacterColor)
bool usesMouse() const
See setUsesMouse()
virtual void mousePressEvent(QMouseEvent *)
KeyboardCursorShape _cursorShape
Definition: TerminalView.h:728
QTimer * _blinkTimer
Definition: TerminalView.h:694
virtual QVariant inputMethodQuery(Qt::InputMethodQuery query) const
virtual void mouseDoubleClickEvent(QMouseEvent *ev)
QClipboard * _clipboard
Definition: TerminalView.h:681
void paintFilters(QPainter &painter)
QList< QAction * > filterActions(const QPoint &position)
Returns a list of menu actions created by the filters for the content at the given position.
virtual void keyPressEvent(QKeyEvent *event)
ScrollBarPosition
This enum describes the location where the scroll bar is positioned in the display widget.
Definition: TerminalView.h:92
@ ScrollBarLeft
Show the scroll bar on the left side of the display.
Definition: TerminalView.h:96
@ NoScrollBar
Do not show the scroll bar.
Definition: TerminalView.h:94
@ ScrollBarRight
Show the scroll bar on the right side of the display.
Definition: TerminalView.h:98
QPoint _pntSel
Definition: TerminalView.h:673
virtual void dropEvent(QDropEvent *event)
QRect imageToWidget(const QRect &imageArea) const
void updateImageSize()
virtual void dragEnterEvent(QDragEnterEvent *event)
void setFixedSize(int cols, int lins)
void setBlinkingCursorState(bool blink)
int lines()
Returns the number of lines of text which can be displayed in the widget.
Definition: TerminalView.h:229
virtual void fontChange(const QFont &font)
void tripleClickTimeout()
virtual void wheelEvent(QWheelEvent *)
QLabel * _outputSuspendedLabel
Definition: TerminalView.h:713
struct TerminalView::_dragInfo dragInfo
bool _terminalSizeHint
Definition: TerminalView.h:666
KeyboardCursorShape
This enum describes the available shapes for the keyboard cursor.
Definition: TerminalView.h:171
@ UnderlineCursor
A single flat line which occupies the space at the bottom of the cursor character's area.
Definition: TerminalView.h:178
@ IBeamCursor
An cursor shaped like the capital letter 'I', similar to the IBeam cursor used in Qt/KDE text editors...
Definition: TerminalView.h:183
@ BlockCursor
A rectangular block which covers the entire area of the cursor character.
Definition: TerminalView.h:173
QColor keyboardCursorColor() const
Returns the color of the keyboard cursor, or an invalid color if the keyboard cursor color is set to ...
KeyboardCursorShape keyboardCursorShape() const
Returns the shape of the keyboard cursor.
void setLineSpacing(uint)
QPoint _iPntSel
Definition: TerminalView.h:672
void outputSuspended(bool suspended)
Causes the widget to display or hide a message informing the user that terminal output has been suspe...
void swapColorTable()
double _fontHeight
Definition: TerminalView.h:634
bool _disabledBracketedPasteMode
Definition: TerminalView.h:670
const ColorEntry * colorTable() const
Returns the terminal color palette used by the display.
virtual void paintEvent(QPaintEvent *)
bool bracketedPasteMode() const
void pasteSelection()
Pastes the content of the selection into the display.
void visibility_changed(bool visible)
Is called, when the terminal's visibility has changed in order to stop orstart timers etc.
void tripleClicked(const QString &text)
uint lineSpacing() const
QTimer * _resizeTimer
Definition: TerminalView.h:707
void setSize(int cols, int lins)
void showResizeNotification()
QRegion hotSpotRegion() const
QString _wordCharacters
Definition: TerminalView.h:684
ScrollBarPosition _scrollbarLocation
Definition: TerminalView.h:683
TerminalView(QWidget *parent=nullptr)
Constructs a new terminal display widget with the specified parent.
void keyPressedSignal(QKeyEvent *e)
Emitted when the user presses a key whilst the terminal widget has focus.
void setBracketedPasteMode(bool bracketedPasteMode)
QLabel * _resizeWidget
Definition: TerminalView.h:706
void changedContentSizeSignal(int height, int width)
void mouseTripleClickEvent(QMouseEvent *ev)
static bool _antialiasText
Definition: TerminalView.h:742
void emitSelection(bool useXselection, bool appendReturn)
void drawContents(QPainter &paint, const QRect &rect)
bool _possibleTripleClick
Definition: TerminalView.h:702
QTimer * _process_filter_timer
Definition: TerminalView.h:696
void scrollImage(int lines, const QRect &region)
QColor _cursorColor
Definition: TerminalView.h:732
int string_width(const QString &txt)
F77_RET_T const F77_DBLE * x
F77_RET_T const F77_DBLE const F77_DBLE * f
T * r
Definition: mx-inlines.cc:773
T::size_type strlen(const typename T::value_type *str)
Definition: oct-string.cc:85
static T abs(T x)
Definition: pr-output.cc:1678
int qt_fontmetrics_horizontal_advance(const QFontMetrics &fm, QChar ch)
Definition: qt-utils.h:48
static uint32_t * next
Definition: randmtzig.cc:192
static int left
Definition: randmtzig.cc:194
F77_RET_T len
Definition: xerbla.cc:61