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