~ubuntu-branches/ubuntu/wily/qgis/wily

« back to all changes in this revision

Viewing changes to src/plugins/grass/qtermwidget/Screen.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Johan Van de Wauw
  • Date: 2010-07-11 20:23:24 UTC
  • mfrom: (3.1.4 squeeze)
  • Revision ID: james.westby@ubuntu.com-20100711202324-5ktghxa7hracohmr
Tags: 1.4.0+12730-3ubuntu1
* Merge from Debian unstable (LP: #540941).
* Fix compilation issues with QT 4.7
* Add build-depends on libqt4-webkit-dev 

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
    This file is part of Konsole, an X terminal.
 
3
    Copyright (C) 1997,1998 by Lars Doelle <lars.doelle@on-line.de>
 
4
 
 
5
    Rewritten for QT4 by e_k <e_k at users.sourceforge.net>, Copyright (C)2008
 
6
 
 
7
    This program is free software; you can redistribute it and/or modify
 
8
    it under the terms of the GNU General Public License as published by
 
9
    the Free Software Foundation; either version 2 of the License, or
 
10
    (at your option) any later version.
 
11
 
 
12
    This program is distributed in the hope that it will be useful,
 
13
    but WITHOUT ANY WARRANTY; without even the implied warranty of
 
14
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
15
    GNU General Public License for more details.
 
16
 
 
17
    You should have received a copy of the GNU General Public License
 
18
    along with this program; if not, write to the Free Software
 
19
    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
 
20
    02110-1301  USA.
 
21
*/
 
22
 
 
23
// Own
 
24
#include "Screen.h"
 
25
 
 
26
// Standard
 
27
#include <stdio.h>
 
28
#include <stdlib.h>
 
29
#include <unistd.h>
 
30
#include <assert.h>
 
31
#include <string.h>
 
32
#include <ctype.h>
 
33
 
 
34
// Qt
 
35
#include <QtCore/QTextStream>
 
36
#include <QtCore/QDate>
 
37
 
 
38
// Konsole
 
39
#include "konsole_wcwidth.h"
 
40
#include "TerminalCharacterDecoder.h"
 
41
 
 
42
using namespace Konsole;
 
43
 
 
44
//FIXME: this is emulation specific. Use false for xterm, true for ANSI.
 
45
//FIXME: see if we can get this from terminfo.
 
46
#define BS_CLEARS false
 
47
 
 
48
//Macro to convert x,y position on screen to position within an image.
 
49
//
 
50
//Originally the image was stored as one large contiguous block of
 
51
//memory, so a position within the image could be represented as an
 
52
//offset from the beginning of the block.  For efficiency reasons this
 
53
//is no longer the case.
 
54
//Many internal parts of this class still use this representation for parameters and so on,
 
55
//notably moveImage() and clearImage().
 
56
//This macro converts from an X,Y position into an image offset.
 
57
#ifndef loc
 
58
#define loc(X,Y) ((Y)*columns+(X))
 
59
#endif
 
60
 
 
61
 
 
62
Character Screen::defaultChar = Character( ' ',
 
63
                                CharacterColor( COLOR_SPACE_DEFAULT, DEFAULT_FORE_COLOR ),
 
64
                                CharacterColor( COLOR_SPACE_DEFAULT, DEFAULT_BACK_COLOR ),
 
65
                                DEFAULT_RENDITION );
 
66
 
 
67
//#define REVERSE_WRAPPED_LINES  // for wrapped line debug
 
68
 
 
69
Screen::Screen( int l, int c )
 
70
    : lines( l ),
 
71
    columns( c ),
 
72
    screenLines( new ImageLine[lines+1] ),
 
73
    _scrolledLines( 0 ),
 
74
    _droppedLines( 0 ),
 
75
    hist( new HistoryScrollNone() ),
 
76
    cuX( 0 ), cuY( 0 ),
 
77
    cu_re( 0 ),
 
78
    tmargin( 0 ), bmargin( 0 ),
 
79
    tabstops( 0 ),
 
80
    sel_begin( 0 ), sel_TL( 0 ), sel_BR( 0 ),
 
81
    sel_busy( false ),
 
82
    columnmode( false ),
 
83
    ef_fg( CharacterColor() ), ef_bg( CharacterColor() ), ef_re( 0 ),
 
84
    sa_cuX( 0 ), sa_cuY( 0 ),
 
85
    sa_cu_re( 0 ),
 
86
    lastPos( -1 )
 
87
{
 
88
  lineProperties.resize( lines + 1 );
 
89
  for ( int i = 0; i < lines + 1; i++ )
 
90
    lineProperties[i] = LINE_DEFAULT;
 
91
 
 
92
  initTabStops();
 
93
  clearSelection();
 
94
  reset();
 
95
}
 
96
 
 
97
/*! Destructor
 
98
*/
 
99
 
 
100
Screen::~Screen()
 
101
{
 
102
  delete[] screenLines;
 
103
  delete[] tabstops;
 
104
  delete hist;
 
105
}
 
106
 
 
107
/* ------------------------------------------------------------------------- */
 
108
/*                                                                           */
 
109
/* Normalized                    Screen Operations                           */
 
110
/*                                                                           */
 
111
/* ------------------------------------------------------------------------- */
 
112
 
 
113
// Cursor Setting --------------------------------------------------------------
 
114
 
 
115
/*! \section Cursor
 
116
 
 
117
    The `cursor' is a location within the screen that is implicitely used in
 
118
    many operations. The operations within this section allow to manipulate
 
119
    the cursor explicitly and to obtain it's value.
 
120
 
 
121
    The position of the cursor is guarantied to be between (including) 0 and
 
122
    `columns-1' and `lines-1'.
 
123
*/
 
124
 
 
125
/*!
 
126
    Move the cursor up.
 
127
 
 
128
    The cursor will not be moved beyond the top margin.
 
129
*/
 
130
 
 
131
void Screen::cursorUp( int n )
 
132
//=CUU
 
133
{
 
134
  if ( n == 0 ) n = 1; // Default
 
135
  int stop = cuY < tmargin ? 0 : tmargin;
 
136
  cuX = qMin( columns - 1, cuX ); // nowrap!
 
137
  cuY = qMax( stop, cuY - n );
 
138
}
 
139
 
 
140
/*!
 
141
    Move the cursor down.
 
142
 
 
143
    The cursor will not be moved beyond the bottom margin.
 
144
*/
 
145
 
 
146
void Screen::cursorDown( int n )
 
147
//=CUD
 
148
{
 
149
  if ( n == 0 ) n = 1; // Default
 
150
  int stop = cuY > bmargin ? lines - 1 : bmargin;
 
151
  cuX = qMin( columns - 1, cuX ); // nowrap!
 
152
  cuY = qMin( stop, cuY + n );
 
153
}
 
154
 
 
155
/*!
 
156
    Move the cursor left.
 
157
 
 
158
    The cursor will not move beyond the first column.
 
159
*/
 
160
 
 
161
void Screen::cursorLeft( int n )
 
162
//=CUB
 
163
{
 
164
  if ( n == 0 ) n = 1; // Default
 
165
  cuX = qMin( columns - 1, cuX ); // nowrap!
 
166
  cuX = qMax( 0, cuX - n );
 
167
}
 
168
 
 
169
/*!
 
170
    Move the cursor left.
 
171
 
 
172
    The cursor will not move beyond the rightmost column.
 
173
*/
 
174
 
 
175
void Screen::cursorRight( int n )
 
176
//=CUF
 
177
{
 
178
  if ( n == 0 ) n = 1; // Default
 
179
  cuX = qMin( columns - 1, cuX + n );
 
180
}
 
181
 
 
182
void Screen::setMargins( int top, int bot )
 
183
//=STBM
 
184
{
 
185
  if ( top == 0 ) top = 1;    // Default
 
186
  if ( bot == 0 ) bot = lines;  // Default
 
187
  top = top - 1;              // Adjust to internal lineno
 
188
  bot = bot - 1;              // Adjust to internal lineno
 
189
  if ( !( 0 <= top && top < bot && bot < lines ) )
 
190
  {
 
191
    qDebug() << " setRegion(" << top << "," << bot << ") : bad range.";
 
192
    return;                   // Default error action: ignore
 
193
  }
 
194
  tmargin = top;
 
195
  bmargin = bot;
 
196
  cuX = 0;
 
197
  cuY = getMode( MODE_Origin ) ? top : 0;
 
198
 
 
199
}
 
200
 
 
201
int Screen::topMargin() const
 
202
{
 
203
  return tmargin;
 
204
}
 
205
int Screen::bottomMargin() const
 
206
{
 
207
  return bmargin;
 
208
}
 
209
 
 
210
void Screen::index()
 
211
//=IND
 
212
{
 
213
  if ( cuY == bmargin )
 
214
  {
 
215
    scrollUp( 1 );
 
216
  }
 
217
  else if ( cuY < lines - 1 )
 
218
    cuY += 1;
 
219
}
 
220
 
 
221
void Screen::reverseIndex()
 
222
//=RI
 
223
{
 
224
  if ( cuY == tmargin )
 
225
    scrollDown( tmargin, 1 );
 
226
  else if ( cuY > 0 )
 
227
    cuY -= 1;
 
228
}
 
229
 
 
230
/*!
 
231
    Move the cursor to the begin of the next line.
 
232
 
 
233
    If cursor is on bottom margin, the region between the
 
234
    actual top and bottom margin is scrolled up.
 
235
*/
 
236
 
 
237
void Screen::NextLine()
 
238
//=NEL
 
239
{
 
240
  Return(); index();
 
241
}
 
242
 
 
243
void Screen::eraseChars( int n )
 
244
{
 
245
  if ( n == 0 ) n = 1; // Default
 
246
  int p = qMax( 0, qMin( cuX + n - 1, columns - 1 ) );
 
247
  clearImage( loc( cuX, cuY ), loc( p, cuY ), ' ' );
 
248
}
 
249
 
 
250
void Screen::deleteChars( int n )
 
251
{
 
252
  Q_ASSERT( n >= 0 );
 
253
 
 
254
  // always delete at least one char
 
255
  if ( n == 0 )
 
256
    n = 1;
 
257
 
 
258
  // if cursor is beyond the end of the line there is nothing to do
 
259
  if ( cuX >= screenLines[cuY].count() )
 
260
    return;
 
261
 
 
262
  if ( cuX + n >= screenLines[cuY].count() )
 
263
    n = screenLines[cuY].count() - 1 - cuX;
 
264
 
 
265
  Q_ASSERT( n >= 0 );
 
266
  Q_ASSERT( cuX + n < screenLines[cuY].count() );
 
267
 
 
268
  screenLines[cuY].remove( cuX, n );
 
269
}
 
270
 
 
271
void Screen::insertChars( int n )
 
272
{
 
273
  if ( n == 0 ) n = 1; // Default
 
274
 
 
275
  if ( screenLines[cuY].size() < cuX )
 
276
    screenLines[cuY].resize( cuX );
 
277
 
 
278
  screenLines[cuY].insert( cuX, n, ' ' );
 
279
 
 
280
  if ( screenLines[cuY].count() > columns )
 
281
    screenLines[cuY].resize( columns );
 
282
}
 
283
 
 
284
void Screen::deleteLines( int n )
 
285
{
 
286
  if ( n == 0 ) n = 1; // Default
 
287
  scrollUp( cuY, n );
 
288
}
 
289
 
 
290
/*! insert `n' lines at the cursor position.
 
291
 
 
292
    The cursor is not moved by the operation.
 
293
*/
 
294
 
 
295
void Screen::insertLines( int n )
 
296
{
 
297
  if ( n == 0 ) n = 1; // Default
 
298
  scrollDown( cuY, n );
 
299
}
 
300
 
 
301
// Mode Operations -----------------------------------------------------------
 
302
 
 
303
/*! Set a specific mode. */
 
304
 
 
305
void Screen::setMode( int m )
 
306
{
 
307
  currParm.mode[m] = true;
 
308
  switch ( m )
 
309
  {
 
310
    case MODE_Origin : cuX = 0; cuY = tmargin; break; //FIXME: home
 
311
  }
 
312
}
 
313
 
 
314
/*! Reset a specific mode. */
 
315
 
 
316
void Screen::resetMode( int m )
 
317
{
 
318
  currParm.mode[m] = false;
 
319
  switch ( m )
 
320
  {
 
321
    case MODE_Origin : cuX = 0; cuY = 0; break; //FIXME: home
 
322
  }
 
323
}
 
324
 
 
325
/*! Save a specific mode. */
 
326
 
 
327
void Screen::saveMode( int m )
 
328
{
 
329
  saveParm.mode[m] = currParm.mode[m];
 
330
}
 
331
 
 
332
/*! Restore a specific mode. */
 
333
 
 
334
void Screen::restoreMode( int m )
 
335
{
 
336
  currParm.mode[m] = saveParm.mode[m];
 
337
}
 
338
 
 
339
bool Screen::getMode( int m ) const
 
340
{
 
341
  return currParm.mode[m];
 
342
}
 
343
 
 
344
void Screen::saveCursor()
 
345
{
 
346
  sa_cuX     = cuX;
 
347
  sa_cuY     = cuY;
 
348
  sa_cu_re   = cu_re;
 
349
  sa_cu_fg   = cu_fg;
 
350
  sa_cu_bg   = cu_bg;
 
351
}
 
352
 
 
353
void Screen::restoreCursor()
 
354
{
 
355
  cuX     = qMin( sa_cuX, columns - 1 );
 
356
  cuY     = qMin( sa_cuY, lines - 1 );
 
357
  cu_re   = sa_cu_re;
 
358
  cu_fg   = sa_cu_fg;
 
359
  cu_bg   = sa_cu_bg;
 
360
  effectiveRendition();
 
361
}
 
362
 
 
363
/* ------------------------------------------------------------------------- */
 
364
/*                                                                           */
 
365
/*                             Screen Operations                             */
 
366
/*                                                                           */
 
367
/* ------------------------------------------------------------------------- */
 
368
 
 
369
/*! Resize the screen image
 
370
 
 
371
    The topmost left position is maintained, while lower lines
 
372
    or right hand side columns might be removed or filled with
 
373
    spaces to fit the new size.
 
374
 
 
375
    The region setting is reset to the whole screen and the
 
376
    tab positions reinitialized.
 
377
 
 
378
    If the new image is narrower than the old image then text on lines
 
379
    which extends past the end of the new image is preserved so that it becomes
 
380
    visible again if the screen is later resized to make it larger.
 
381
*/
 
382
 
 
383
void Screen::resizeImage( int new_lines, int new_columns )
 
384
{
 
385
  if (( new_lines == lines ) && ( new_columns == columns ) ) return;
 
386
 
 
387
  if ( cuY > new_lines - 1 )
 
388
  { // attempt to preserve focus and lines
 
389
    bmargin = lines - 1; //FIXME: margin lost
 
390
    for ( int i = 0; i < cuY - ( new_lines - 1 ); i++ )
 
391
    {
 
392
      addHistLine(); scrollUp( 0, 1 );
 
393
    }
 
394
  }
 
395
 
 
396
  // create new screen lines and copy from old to new
 
397
 
 
398
  ImageLine* newScreenLines = new ImageLine[new_lines+1];
 
399
  for ( int i = 0; i < qMin( lines - 1, new_lines + 1 ) ; i++ )
 
400
    newScreenLines[i] = screenLines[i];
 
401
  for ( int i = lines; ( i > 0 ) && ( i < new_lines + 1 ); i++ )
 
402
    newScreenLines[i].resize( new_columns );
 
403
 
 
404
  lineProperties.resize( new_lines + 1 );
 
405
  for ( int i = lines; ( i > 0 ) && ( i < new_lines + 1 ); i++ )
 
406
    lineProperties[i] = LINE_DEFAULT;
 
407
 
 
408
  clearSelection();
 
409
 
 
410
  delete[] screenLines;
 
411
  screenLines = newScreenLines;
 
412
 
 
413
  lines = new_lines;
 
414
  columns = new_columns;
 
415
  cuX = qMin( cuX, columns - 1 );
 
416
  cuY = qMin( cuY, lines - 1 );
 
417
 
 
418
  // FIXME: try to keep values, evtl.
 
419
  tmargin = 0;
 
420
  bmargin = lines - 1;
 
421
  initTabStops();
 
422
  clearSelection();
 
423
}
 
424
 
 
425
void Screen::setDefaultMargins()
 
426
{
 
427
  tmargin = 0;
 
428
  bmargin = lines - 1;
 
429
}
 
430
 
 
431
 
 
432
/*
 
433
   Clarifying rendition here and in the display.
 
434
 
 
435
   currently, the display's color table is
 
436
     0       1       2 .. 9    10 .. 17
 
437
     dft_fg, dft_bg, dim 0..7, intensive 0..7
 
438
 
 
439
   cu_fg, cu_bg contain values 0..8;
 
440
   - 0    = default color
 
441
   - 1..8 = ansi specified color
 
442
 
 
443
   re_fg, re_bg contain values 0..17
 
444
   due to the TerminalDisplay's color table
 
445
 
 
446
   rendition attributes are
 
447
 
 
448
      attr           widget screen
 
449
      -------------- ------ ------
 
450
      RE_UNDERLINE     XX     XX    affects foreground only
 
451
      RE_BLINK         XX     XX    affects foreground only
 
452
      RE_BOLD          XX     XX    affects foreground only
 
453
      RE_REVERSE       --     XX
 
454
      RE_TRANSPARENT   XX     --    affects background only
 
455
      RE_INTENSIVE     XX     --    affects foreground only
 
456
 
 
457
   Note that RE_BOLD is used in both widget
 
458
   and screen rendition. Since xterm/vt102
 
459
   is to poor to distinguish between bold
 
460
   (which is a font attribute) and intensive
 
461
   (which is a color attribute), we translate
 
462
   this and RE_BOLD in falls eventually appart
 
463
   into RE_BOLD and RE_INTENSIVE.
 
464
*/
 
465
 
 
466
void Screen::reverseRendition( Character& p ) const
 
467
{
 
468
  CharacterColor f = p.foregroundColor;
 
469
  CharacterColor b = p.backgroundColor;
 
470
 
 
471
  p.foregroundColor = b;
 
472
  p.backgroundColor = f; //p->r &= ~RE_TRANSPARENT;
 
473
}
 
474
 
 
475
void Screen::effectiveRendition()
 
476
// calculate rendition
 
477
{
 
478
  //copy "current rendition" straight into "effective rendition", which is then later copied directly
 
479
  //into the image[] array which holds the characters and their appearance properties.
 
480
  //- The old version below filtered out all attributes other than underline and blink at this stage,
 
481
  //so that they would not be copied into the image[] array and hence would not be visible by TerminalDisplay
 
482
  //which actually paints the screen using the information from the image[] array.
 
483
  //I don't know why it did this, but I'm fairly sure it was the wrong thing to do.  The net result
 
484
  //was that bold text wasn't printed in bold by Konsole.
 
485
  ef_re = cu_re;
 
486
 
 
487
  //OLD VERSION:
 
488
  //ef_re = cu_re & (RE_UNDERLINE | RE_BLINK);
 
489
 
 
490
  if ( cu_re & RE_REVERSE )
 
491
  {
 
492
    ef_fg = cu_bg;
 
493
    ef_bg = cu_fg;
 
494
  }
 
495
  else
 
496
  {
 
497
    ef_fg = cu_fg;
 
498
    ef_bg = cu_bg;
 
499
  }
 
500
 
 
501
  if ( cu_re & RE_BOLD )
 
502
    ef_fg.toggleIntensive();
 
503
}
 
504
 
 
505
/*!
 
506
    returns the image.
 
507
 
 
508
    Get the size of the image by \sa getLines and \sa getColumns.
 
509
 
 
510
    NOTE that the image returned by this function must later be
 
511
    freed.
 
512
 
 
513
*/
 
514
 
 
515
void Screen::copyFromHistory( Character* dest, int startLine, int count ) const
 
516
{
 
517
  Q_ASSERT( startLine >= 0 && count > 0 && startLine + count <= hist->getLines() );
 
518
 
 
519
  for ( int line = startLine; line < startLine + count; line++ )
 
520
  {
 
521
    const int length = qMin( columns, hist->getLineLen( line ) );
 
522
    const int destLineOffset  = ( line - startLine ) * columns;
 
523
 
 
524
    hist->getCells( line, 0, length, dest + destLineOffset );
 
525
 
 
526
    for ( int column = length; column < columns; column++ )
 
527
      dest[destLineOffset+column] = defaultChar;
 
528
 
 
529
    // invert selected text
 
530
    if ( sel_begin != -1 )
 
531
    {
 
532
      for ( int column = 0; column < columns; column++ )
 
533
      {
 
534
        if ( isSelected( column, line ) )
 
535
        {
 
536
          reverseRendition( dest[destLineOffset + column] );
 
537
        }
 
538
      }
 
539
    }
 
540
  }
 
541
}
 
542
 
 
543
void Screen::copyFromScreen( Character* dest , int startLine , int count ) const
 
544
{
 
545
  Q_ASSERT( startLine >= 0 && count > 0 && startLine + count <= lines );
 
546
 
 
547
  for ( int line = startLine; line < ( startLine + count ) ; line++ )
 
548
  {
 
549
    int srcLineStartIndex  = line * columns;
 
550
    int destLineStartIndex = ( line - startLine ) * columns;
 
551
 
 
552
    for ( int column = 0; column < columns; column++ )
 
553
    {
 
554
      int srcIndex = srcLineStartIndex + column;
 
555
      int destIndex = destLineStartIndex + column;
 
556
 
 
557
      dest[destIndex] = screenLines[srcIndex/columns].value( srcIndex % columns, defaultChar );
 
558
 
 
559
      // invert selected text
 
560
      if ( sel_begin != -1 && isSelected( column, line + hist->getLines() ) )
 
561
        reverseRendition( dest[destIndex] );
 
562
    }
 
563
 
 
564
  }
 
565
}
 
566
 
 
567
void Screen::getImage( Character* dest, int size, int startLine, int endLine ) const
 
568
{
 
569
  Q_ASSERT( startLine >= 0 );
 
570
  Q_ASSERT( endLine >= startLine && endLine < hist->getLines() + lines );
 
571
 
 
572
  const int mergedLines = endLine - startLine + 1;
 
573
 
 
574
  Q_ASSERT( size >= mergedLines * columns );
 
575
 
 
576
  const int linesInHistoryBuffer = qBound( 0, hist->getLines() - startLine, mergedLines );
 
577
  const int linesInScreenBuffer = mergedLines - linesInHistoryBuffer;
 
578
 
 
579
  // copy lines from history buffer
 
580
  if ( linesInHistoryBuffer > 0 )
 
581
  {
 
582
    copyFromHistory( dest, startLine, linesInHistoryBuffer );
 
583
  }
 
584
 
 
585
  // copy lines from screen buffer
 
586
  if ( linesInScreenBuffer > 0 )
 
587
  {
 
588
    copyFromScreen( dest + linesInHistoryBuffer*columns,
 
589
                    startLine + linesInHistoryBuffer - hist->getLines(),
 
590
                    linesInScreenBuffer );
 
591
  }
 
592
 
 
593
  // invert display when in screen mode
 
594
  if ( getMode( MODE_Screen ) )
 
595
  {
 
596
    for ( int i = 0; i < mergedLines*columns; i++ )
 
597
      reverseRendition( dest[i] ); // for reverse display
 
598
  }
 
599
 
 
600
  // mark the character at the current cursor position
 
601
  int cursorIndex = loc( cuX, cuY + linesInHistoryBuffer );
 
602
  if ( getMode( MODE_Cursor ) && cursorIndex < columns*mergedLines )
 
603
    dest[cursorIndex].rendition |= RE_CURSOR;
 
604
}
 
605
 
 
606
QVector<LineProperty> Screen::getLineProperties( int startLine , int endLine ) const
 
607
{
 
608
  Q_ASSERT( startLine >= 0 );
 
609
  Q_ASSERT( endLine >= startLine && endLine < hist->getLines() + lines );
 
610
 
 
611
  const int mergedLines = endLine - startLine + 1;
 
612
  const int linesInHistory = qBound( 0, hist->getLines() - startLine, mergedLines );
 
613
  const int linesInScreen = mergedLines - linesInHistory;
 
614
 
 
615
  QVector<LineProperty> result( mergedLines );
 
616
  int index = 0;
 
617
 
 
618
  // copy properties for lines in history
 
619
  for ( int line = startLine; line < startLine + linesInHistory; line++ )
 
620
  {
 
621
    //TODO Support for line properties other than wrapped lines
 
622
    if ( hist->isWrappedLine( line ) )
 
623
    {
 
624
      result[index] = ( LineProperty )( result[index] | LINE_WRAPPED );
 
625
    }
 
626
    index++;
 
627
  }
 
628
 
 
629
  // copy properties for lines in screen buffer
 
630
  const int firstScreenLine = startLine + linesInHistory - hist->getLines();
 
631
  for ( int line = firstScreenLine; line < firstScreenLine + linesInScreen; line++ )
 
632
  {
 
633
    result[index] = lineProperties[line];
 
634
    index++;
 
635
  }
 
636
 
 
637
  return result;
 
638
}
 
639
 
 
640
/*!
 
641
*/
 
642
 
 
643
void Screen::reset( bool clearScreen )
 
644
{
 
645
  setMode( MODE_Wrap ); saveMode( MODE_Wrap );  // wrap at end of margin
 
646
  resetMode( MODE_Origin ); saveMode( MODE_Origin );  // position refere to [1,1]
 
647
  resetMode( MODE_Insert ); saveMode( MODE_Insert );  // overstroke
 
648
  setMode( MODE_Cursor );                       // cursor visible
 
649
  resetMode( MODE_Screen );                       // screen not inverse
 
650
  resetMode( MODE_NewLine );
 
651
 
 
652
  tmargin = 0;
 
653
  bmargin = lines - 1;
 
654
 
 
655
  setDefaultRendition();
 
656
  saveCursor();
 
657
 
 
658
  if ( clearScreen )
 
659
    clear();
 
660
}
 
661
 
 
662
/*! Clear the entire screen and home the cursor.
 
663
*/
 
664
 
 
665
void Screen::clear()
 
666
{
 
667
  clearEntireScreen();
 
668
  home();
 
669
}
 
670
 
 
671
void Screen::BackSpace()
 
672
{
 
673
  cuX = qMin( columns - 1, cuX ); // nowrap!
 
674
  cuX = qMax( 0, cuX - 1 );
 
675
// if (BS_CLEARS) image[loc(cuX,cuY)].character = ' ';
 
676
 
 
677
  if ( screenLines[cuY].size() < cuX + 1 )
 
678
    screenLines[cuY].resize( cuX + 1 );
 
679
 
 
680
  if ( BS_CLEARS ) screenLines[cuY][cuX].character = ' ';
 
681
}
 
682
 
 
683
void Screen::Tabulate( int n )
 
684
{
 
685
  // note that TAB is a format effector (does not write ' ');
 
686
  if ( n == 0 ) n = 1;
 
687
  while (( n > 0 ) && ( cuX < columns - 1 ) )
 
688
  {
 
689
    cursorRight( 1 ); while (( cuX < columns - 1 ) && !tabstops[cuX] ) cursorRight( 1 );
 
690
    n--;
 
691
  }
 
692
}
 
693
 
 
694
void Screen::backTabulate( int n )
 
695
{
 
696
  // note that TAB is a format effector (does not write ' ');
 
697
  if ( n == 0 ) n = 1;
 
698
  while (( n > 0 ) && ( cuX > 0 ) )
 
699
  {
 
700
    cursorLeft( 1 ); while (( cuX > 0 ) && !tabstops[cuX] ) cursorLeft( 1 );
 
701
    n--;
 
702
  }
 
703
}
 
704
 
 
705
void Screen::clearTabStops()
 
706
{
 
707
  for ( int i = 0; i < columns; i++ ) tabstops[i] = false;
 
708
}
 
709
 
 
710
void Screen::changeTabStop( bool set )
 
711
{
 
712
  if ( cuX >= columns ) return;
 
713
  tabstops[cuX] = set;
 
714
}
 
715
 
 
716
void Screen::initTabStops()
 
717
{
 
718
  delete[] tabstops;
 
719
  tabstops = new bool[columns];
 
720
 
 
721
  // Arrg! The 1st tabstop has to be one longer than the other.
 
722
  // i.e. the kids start counting from 0 instead of 1.
 
723
  // Other programs might behave correctly. Be aware.
 
724
  for ( int i = 0; i < columns; i++ ) tabstops[i] = ( i % 8 == 0 && i != 0 );
 
725
}
 
726
 
 
727
/*!
 
728
   This behaves either as IND (Screen::Index) or as NEL (Screen::NextLine)
 
729
   depending on the NewLine Mode (LNM). This mode also
 
730
   affects the key sequence returned for newline ([CR]LF).
 
731
*/
 
732
 
 
733
void Screen::NewLine()
 
734
{
 
735
  if ( getMode( MODE_NewLine ) ) Return();
 
736
  index();
 
737
}
 
738
 
 
739
/*! put `c' literally onto the screen at the current cursor position.
 
740
 
 
741
    VT100 uses the convention to produce an automatic newline (am)
 
742
    with the *first* character that would fall onto the next line (xenl).
 
743
*/
 
744
 
 
745
void Screen::checkSelection( int from, int to )
 
746
{
 
747
  if ( sel_begin == -1 ) return;
 
748
  int scr_TL = loc( 0, hist->getLines() );
 
749
  //Clear entire selection if it overlaps region [from, to]
 
750
  if (( sel_BR > ( from + scr_TL ) ) && ( sel_TL < ( to + scr_TL ) ) )
 
751
  {
 
752
    clearSelection();
 
753
  }
 
754
}
 
755
 
 
756
void Screen::ShowCharacter( unsigned short c )
 
757
{
 
758
  // Note that VT100 does wrapping BEFORE putting the character.
 
759
  // This has impact on the assumption of valid cursor positions.
 
760
  // We indicate the fact that a newline has to be triggered by
 
761
  // putting the cursor one right to the last column of the screen.
 
762
 
 
763
  int w = konsole_wcwidth( c );
 
764
 
 
765
  if ( w <= 0 )
 
766
    return;
 
767
 
 
768
  if ( cuX + w > columns )
 
769
  {
 
770
    if ( getMode( MODE_Wrap ) )
 
771
    {
 
772
      lineProperties[cuY] = ( LineProperty )( lineProperties[cuY] | LINE_WRAPPED );
 
773
      NextLine();
 
774
    }
 
775
    else
 
776
      cuX = columns - w;
 
777
  }
 
778
 
 
779
  // ensure current line vector has enough elements
 
780
  int size = screenLines[cuY].size();
 
781
  if ( size == 0 && cuY > 0 )
 
782
  {
 
783
    screenLines[cuY].resize( qMax( screenLines[cuY-1].size() , cuX + w ) );
 
784
  }
 
785
  else
 
786
  {
 
787
    if ( size < cuX + w )
 
788
    {
 
789
      screenLines[cuY].resize( cuX + w );
 
790
    }
 
791
  }
 
792
 
 
793
  if ( getMode( MODE_Insert ) ) insertChars( w );
 
794
 
 
795
  lastPos = loc( cuX, cuY );
 
796
 
 
797
  // check if selection is still valid.
 
798
  checkSelection( cuX, cuY );
 
799
 
 
800
  Character& currentChar = screenLines[cuY][cuX];
 
801
 
 
802
  currentChar.character = c;
 
803
  currentChar.foregroundColor = ef_fg;
 
804
  currentChar.backgroundColor = ef_bg;
 
805
  currentChar.rendition = ef_re;
 
806
 
 
807
  int i = 0;
 
808
  int newCursorX = cuX + w--;
 
809
  while ( w )
 
810
  {
 
811
    i++;
 
812
 
 
813
    if ( screenLines[cuY].size() < cuX + i + 1 )
 
814
      screenLines[cuY].resize( cuX + i + 1 );
 
815
 
 
816
    Character& ch = screenLines[cuY][cuX + i];
 
817
    ch.character = 0;
 
818
    ch.foregroundColor = ef_fg;
 
819
    ch.backgroundColor = ef_bg;
 
820
    ch.rendition = ef_re;
 
821
 
 
822
    w--;
 
823
  }
 
824
  cuX = newCursorX;
 
825
}
 
826
 
 
827
void Screen::compose( const QString& /*compose*/ )
 
828
{
 
829
  Q_ASSERT( 0 /*Not implemented yet*/ );
 
830
 
 
831
  /*  if (lastPos == -1)
 
832
       return;
 
833
 
 
834
    QChar c(image[lastPos].character);
 
835
    compose.prepend(c);
 
836
    //compose.compose(); ### FIXME!
 
837
    image[lastPos].character = compose[0].unicode();*/
 
838
}
 
839
 
 
840
int Screen::scrolledLines() const
 
841
{
 
842
  return _scrolledLines;
 
843
}
 
844
int Screen::droppedLines() const
 
845
{
 
846
  return _droppedLines;
 
847
}
 
848
void Screen::resetDroppedLines()
 
849
{
 
850
  _droppedLines = 0;
 
851
}
 
852
void Screen::resetScrolledLines()
 
853
{
 
854
  //kDebug() << "scrolled lines reset";
 
855
 
 
856
  _scrolledLines = 0;
 
857
}
 
858
 
 
859
// Region commands -------------------------------------------------------------
 
860
 
 
861
void Screen::scrollUp( int n )
 
862
{
 
863
  if ( n == 0 ) n = 1; // Default
 
864
  if ( tmargin == 0 ) addHistLine(); // hist.history
 
865
  scrollUp( tmargin, n );
 
866
}
 
867
 
 
868
/*! scroll up `n' lines within current region.
 
869
    The `n' new lines are cleared.
 
870
    \sa setRegion \sa scrollDown
 
871
*/
 
872
 
 
873
QRect Screen::lastScrolledRegion() const
 
874
{
 
875
  return _lastScrolledRegion;
 
876
}
 
877
 
 
878
void Screen::scrollUp( int from, int n )
 
879
{
 
880
  if ( n <= 0 || from + n > bmargin ) return;
 
881
 
 
882
  _scrolledLines -= n;
 
883
  _lastScrolledRegion = QRect( 0, tmargin, columns - 1, ( bmargin - tmargin ) );
 
884
 
 
885
  //FIXME: make sure `tmargin', `bmargin', `from', `n' is in bounds.
 
886
  moveImage( loc( 0, from ), loc( 0, from + n ), loc( columns - 1, bmargin ) );
 
887
  clearImage( loc( 0, bmargin - n + 1 ), loc( columns - 1, bmargin ), ' ' );
 
888
}
 
889
 
 
890
void Screen::scrollDown( int n )
 
891
{
 
892
  if ( n == 0 ) n = 1; // Default
 
893
  scrollDown( tmargin, n );
 
894
}
 
895
 
 
896
/*! scroll down `n' lines within current region.
 
897
    The `n' new lines are cleared.
 
898
    \sa setRegion \sa scrollUp
 
899
*/
 
900
 
 
901
void Screen::scrollDown( int from, int n )
 
902
{
 
903
 
 
904
  //kDebug() << "Screen::scrollDown( from: " << from << " , n: " << n << ")";
 
905
 
 
906
  _scrolledLines += n;
 
907
 
 
908
//FIXME: make sure `tmargin', `bmargin', `from', `n' is in bounds.
 
909
  if ( n <= 0 ) return;
 
910
  if ( from > bmargin ) return;
 
911
  if ( from + n > bmargin ) n = bmargin - from;
 
912
  moveImage( loc( 0, from + n ), loc( 0, from ), loc( columns - 1, bmargin - n ) );
 
913
  clearImage( loc( 0, from ), loc( columns - 1, from + n - 1 ), ' ' );
 
914
}
 
915
 
 
916
void Screen::setCursorYX( int y, int x )
 
917
{
 
918
  setCursorY( y ); setCursorX( x );
 
919
}
 
920
 
 
921
void Screen::setCursorX( int x )
 
922
{
 
923
  if ( x == 0 ) x = 1; // Default
 
924
  x -= 1; // Adjust
 
925
  cuX = qMax( 0, qMin( columns - 1, x ) );
 
926
}
 
927
 
 
928
void Screen::setCursorY( int y )
 
929
{
 
930
  if ( y == 0 ) y = 1; // Default
 
931
  y -= 1; // Adjust
 
932
  cuY = qMax( 0, qMin( lines  - 1, y + ( getMode( MODE_Origin ) ? tmargin : 0 ) ) );
 
933
}
 
934
 
 
935
void Screen::home()
 
936
{
 
937
  cuX = 0;
 
938
  cuY = 0;
 
939
}
 
940
 
 
941
void Screen::Return()
 
942
{
 
943
  cuX = 0;
 
944
}
 
945
 
 
946
int Screen::getCursorX() const
 
947
{
 
948
  return cuX;
 
949
}
 
950
 
 
951
int Screen::getCursorY() const
 
952
{
 
953
  return cuY;
 
954
}
 
955
 
 
956
// Erasing ---------------------------------------------------------------------
 
957
 
 
958
/*! \section Erasing
 
959
 
 
960
    This group of operations erase parts of the screen contents by filling
 
961
    it with spaces colored due to the current rendition settings.
 
962
 
 
963
    Althought the cursor position is involved in most of these operations,
 
964
    it is never modified by them.
 
965
*/
 
966
 
 
967
/*! fill screen between (including) `loca' (start) and `loce' (end) with spaces.
 
968
 
 
969
    This is an internal helper functions. The parameter types are internal
 
970
    addresses of within the screen image and make use of the way how the
 
971
    screen matrix is mapped to the image vector.
 
972
*/
 
973
 
 
974
void Screen::clearImage( int loca, int loce, char c )
 
975
{
 
976
  int scr_TL = loc( 0, hist->getLines() );
 
977
  //FIXME: check positions
 
978
 
 
979
  //Clear entire selection if it overlaps region to be moved...
 
980
  if (( sel_BR > ( loca + scr_TL ) ) && ( sel_TL < ( loce + scr_TL ) ) )
 
981
  {
 
982
    clearSelection();
 
983
  }
 
984
 
 
985
  int topLine = loca / columns;
 
986
  int bottomLine = loce / columns;
 
987
 
 
988
  Character clearCh( c, cu_fg, cu_bg, DEFAULT_RENDITION );
 
989
 
 
990
  //if the character being used to clear the area is the same as the
 
991
  //default character, the affected lines can simply be shrunk.
 
992
  bool isDefaultCh = ( clearCh == Character() );
 
993
 
 
994
  for ( int y = topLine; y <= bottomLine; y++ )
 
995
  {
 
996
    lineProperties[y] = 0;
 
997
 
 
998
    int endCol = ( y == bottomLine ) ? loce % columns : columns - 1;
 
999
    int startCol = ( y == topLine ) ? loca % columns : 0;
 
1000
 
 
1001
    QVector<Character>& line = screenLines[y];
 
1002
 
 
1003
    if ( isDefaultCh && endCol == columns - 1 )
 
1004
    {
 
1005
      line.resize( startCol );
 
1006
    }
 
1007
    else
 
1008
    {
 
1009
      if ( line.size() < endCol + 1 )
 
1010
        line.resize( endCol + 1 );
 
1011
 
 
1012
      Character* data = line.data();
 
1013
      for ( int i = startCol; i <= endCol; i++ )
 
1014
        data[i] = clearCh;
 
1015
    }
 
1016
  }
 
1017
}
 
1018
 
 
1019
/*! move image between (including) `sourceBegin' and `sourceEnd' to 'dest'.
 
1020
 
 
1021
    The 'dest', 'sourceBegin' and 'sourceEnd' parameters can be generated using
 
1022
    the loc(column,line) macro.
 
1023
 
 
1024
NOTE:  moveImage() can only move whole lines.
 
1025
 
 
1026
    This is an internal helper functions. The parameter types are internal
 
1027
    addresses of within the screen image and make use of the way how the
 
1028
    screen matrix is mapped to the image vector.
 
1029
*/
 
1030
 
 
1031
void Screen::moveImage( int dest, int sourceBegin, int sourceEnd )
 
1032
{
 
1033
  //kDebug() << "moving image from (" << (sourceBegin/columns)
 
1034
  //    << "," << (sourceEnd/columns) << ") to " <<
 
1035
  //    (dest/columns);
 
1036
 
 
1037
  Q_ASSERT( sourceBegin <= sourceEnd );
 
1038
 
 
1039
  int lines = ( sourceEnd - sourceBegin ) / columns;
 
1040
 
 
1041
  //move screen image and line properties:
 
1042
  //the source and destination areas of the image may overlap,
 
1043
  //so it matters that we do the copy in the right order -
 
1044
  //forwards if dest < sourceBegin or backwards otherwise.
 
1045
  //(search the web for 'memmove implementation' for details)
 
1046
  if ( dest < sourceBegin )
 
1047
  {
 
1048
    for ( int i = 0; i <= lines; i++ )
 
1049
    {
 
1050
      screenLines[( dest/columns )+i ] = screenLines[( sourceBegin/columns )+i ];
 
1051
      lineProperties[( dest/columns )+i] = lineProperties[( sourceBegin/columns )+i];
 
1052
    }
 
1053
  }
 
1054
  else
 
1055
  {
 
1056
    for ( int i = lines; i >= 0; i-- )
 
1057
    {
 
1058
      screenLines[( dest/columns )+i ] = screenLines[( sourceBegin/columns )+i ];
 
1059
      lineProperties[( dest/columns )+i] = lineProperties[( sourceBegin/columns )+i];
 
1060
    }
 
1061
  }
 
1062
 
 
1063
  if ( lastPos != -1 )
 
1064
  {
 
1065
    int diff = dest - sourceBegin; // Scroll by this amount
 
1066
    lastPos += diff;
 
1067
    if (( lastPos < 0 ) || ( lastPos >= ( lines*columns ) ) )
 
1068
      lastPos = -1;
 
1069
  }
 
1070
 
 
1071
  // Adjust selection to follow scroll.
 
1072
  if ( sel_begin != -1 )
 
1073
  {
 
1074
    bool beginIsTL = ( sel_begin == sel_TL );
 
1075
    int diff = dest - sourceBegin; // Scroll by this amount
 
1076
    int scr_TL = loc( 0, hist->getLines() );
 
1077
    int srca = sourceBegin + scr_TL; // Translate index from screen to global
 
1078
    int srce = sourceEnd + scr_TL; // Translate index from screen to global
 
1079
    int desta = srca + diff;
 
1080
    int deste = srce + diff;
 
1081
 
 
1082
    if (( sel_TL >= srca ) && ( sel_TL <= srce ) )
 
1083
      sel_TL += diff;
 
1084
    else if (( sel_TL >= desta ) && ( sel_TL <= deste ) )
 
1085
      sel_BR = -1; // Clear selection (see below)
 
1086
 
 
1087
    if (( sel_BR >= srca ) && ( sel_BR <= srce ) )
 
1088
      sel_BR += diff;
 
1089
    else if (( sel_BR >= desta ) && ( sel_BR <= deste ) )
 
1090
      sel_BR = -1; // Clear selection (see below)
 
1091
 
 
1092
    if ( sel_BR < 0 )
 
1093
    {
 
1094
      clearSelection();
 
1095
    }
 
1096
    else
 
1097
    {
 
1098
      if ( sel_TL < 0 )
 
1099
        sel_TL = 0;
 
1100
    }
 
1101
 
 
1102
    if ( beginIsTL )
 
1103
      sel_begin = sel_TL;
 
1104
    else
 
1105
      sel_begin = sel_BR;
 
1106
  }
 
1107
}
 
1108
 
 
1109
void Screen::clearToEndOfScreen()
 
1110
{
 
1111
  clearImage( loc( cuX, cuY ), loc( columns - 1, lines - 1 ), ' ' );
 
1112
}
 
1113
 
 
1114
void Screen::clearToBeginOfScreen()
 
1115
{
 
1116
  clearImage( loc( 0, 0 ), loc( cuX, cuY ), ' ' );
 
1117
}
 
1118
 
 
1119
void Screen::clearEntireScreen()
 
1120
{
 
1121
  // Add entire screen to history
 
1122
  for ( int i = 0; i < ( lines - 1 ); i++ )
 
1123
  {
 
1124
    addHistLine(); scrollUp( 0, 1 );
 
1125
  }
 
1126
 
 
1127
  clearImage( loc( 0, 0 ), loc( columns - 1, lines - 1 ), ' ' );
 
1128
}
 
1129
 
 
1130
/*! fill screen with 'E'
 
1131
    This is to aid screen alignment
 
1132
*/
 
1133
 
 
1134
void Screen::helpAlign()
 
1135
{
 
1136
  clearImage( loc( 0, 0 ), loc( columns - 1, lines - 1 ), 'E' );
 
1137
}
 
1138
 
 
1139
void Screen::clearToEndOfLine()
 
1140
{
 
1141
  clearImage( loc( cuX, cuY ), loc( columns - 1, cuY ), ' ' );
 
1142
}
 
1143
 
 
1144
void Screen::clearToBeginOfLine()
 
1145
{
 
1146
  clearImage( loc( 0, cuY ), loc( cuX, cuY ), ' ' );
 
1147
}
 
1148
 
 
1149
void Screen::clearEntireLine()
 
1150
{
 
1151
  clearImage( loc( 0, cuY ), loc( columns - 1, cuY ), ' ' );
 
1152
}
 
1153
 
 
1154
void Screen::setRendition( int re )
 
1155
{
 
1156
  cu_re |= re;
 
1157
  effectiveRendition();
 
1158
}
 
1159
 
 
1160
void Screen::resetRendition( int re )
 
1161
{
 
1162
  cu_re &= ~re;
 
1163
  effectiveRendition();
 
1164
}
 
1165
 
 
1166
void Screen::setDefaultRendition()
 
1167
{
 
1168
  setForeColor( COLOR_SPACE_DEFAULT, DEFAULT_FORE_COLOR );
 
1169
  setBackColor( COLOR_SPACE_DEFAULT, DEFAULT_BACK_COLOR );
 
1170
  cu_re   = DEFAULT_RENDITION;
 
1171
  effectiveRendition();
 
1172
}
 
1173
 
 
1174
void Screen::setForeColor( int space, int color )
 
1175
{
 
1176
  cu_fg = CharacterColor( space, color );
 
1177
 
 
1178
  if ( cu_fg.isValid() )
 
1179
    effectiveRendition();
 
1180
  else
 
1181
    setForeColor( COLOR_SPACE_DEFAULT, DEFAULT_FORE_COLOR );
 
1182
}
 
1183
 
 
1184
void Screen::setBackColor( int space, int color )
 
1185
{
 
1186
  cu_bg = CharacterColor( space, color );
 
1187
 
 
1188
  if ( cu_bg.isValid() )
 
1189
    effectiveRendition();
 
1190
  else
 
1191
    setBackColor( COLOR_SPACE_DEFAULT, DEFAULT_BACK_COLOR );
 
1192
}
 
1193
 
 
1194
/* ------------------------------------------------------------------------- */
 
1195
/*                                                                           */
 
1196
/*                            Marking & Selection                            */
 
1197
/*                                                                           */
 
1198
/* ------------------------------------------------------------------------- */
 
1199
 
 
1200
void Screen::clearSelection()
 
1201
{
 
1202
  sel_BR = -1;
 
1203
  sel_TL = -1;
 
1204
  sel_begin = -1;
 
1205
}
 
1206
 
 
1207
void Screen::getSelectionStart( int& column , int& line )
 
1208
{
 
1209
  if ( sel_TL != -1 )
 
1210
  {
 
1211
    column = sel_TL % columns;
 
1212
    line = sel_TL / columns;
 
1213
  }
 
1214
  else
 
1215
  {
 
1216
    column = cuX + getHistLines();
 
1217
    line = cuY + getHistLines();
 
1218
  }
 
1219
}
 
1220
void Screen::getSelectionEnd( int& column , int& line )
 
1221
{
 
1222
  if ( sel_BR != -1 )
 
1223
  {
 
1224
    column = sel_BR % columns;
 
1225
    line = sel_BR / columns;
 
1226
  }
 
1227
  else
 
1228
  {
 
1229
    column = cuX + getHistLines();
 
1230
    line = cuY + getHistLines();
 
1231
  }
 
1232
}
 
1233
void Screen::setSelectionStart( /*const ScreenCursor& viewCursor ,*/ const int x, const int y, const bool mode )
 
1234
{
 
1235
//  kDebug(1211) << "setSelBeginXY(" << x << "," << y << ")";
 
1236
  sel_begin = loc( x, y ); //+histCursor) ;
 
1237
 
 
1238
  /* FIXME, HACK to correct for x too far to the right... */
 
1239
  if ( x == columns ) sel_begin--;
 
1240
 
 
1241
  sel_BR = sel_begin;
 
1242
  sel_TL = sel_begin;
 
1243
  columnmode = mode;
 
1244
}
 
1245
 
 
1246
void Screen::setSelectionEnd( const int x, const int y )
 
1247
{
 
1248
//  kDebug(1211) << "setSelExtentXY(" << x << "," << y << ")";
 
1249
  if ( sel_begin == -1 ) return;
 
1250
  int l =  loc( x, y ); // + histCursor);
 
1251
 
 
1252
  if ( l < sel_begin )
 
1253
  {
 
1254
    sel_TL = l;
 
1255
    sel_BR = sel_begin;
 
1256
  }
 
1257
  else
 
1258
  {
 
1259
    /* FIXME, HACK to correct for x too far to the right... */
 
1260
    if ( x == columns ) l--;
 
1261
 
 
1262
    sel_TL = sel_begin;
 
1263
    sel_BR = l;
 
1264
  }
 
1265
}
 
1266
 
 
1267
bool Screen::isSelected( const int x, const int y ) const
 
1268
{
 
1269
  if ( columnmode )
 
1270
  {
 
1271
    int sel_Left, sel_Right;
 
1272
    if ( sel_TL % columns < sel_BR % columns )
 
1273
    {
 
1274
      sel_Left = sel_TL; sel_Right = sel_BR;
 
1275
    }
 
1276
    else
 
1277
    {
 
1278
      sel_Left = sel_BR; sel_Right = sel_TL;
 
1279
    }
 
1280
    return ( x >= sel_Left % columns ) && ( x <= sel_Right % columns ) &&
 
1281
           ( y >= sel_TL / columns ) && ( y <= sel_BR / columns );
 
1282
    //( y+histCursor >= sel_TL / columns ) && ( y+histCursor <= sel_BR / columns );
 
1283
  }
 
1284
  else
 
1285
  {
 
1286
    //int pos = loc(x,y+histCursor);
 
1287
    int pos = loc( x, y );
 
1288
    return ( pos >= sel_TL && pos <= sel_BR );
 
1289
  }
 
1290
}
 
1291
 
 
1292
QString Screen::selectedText( bool preserveLineBreaks )
 
1293
{
 
1294
  QString result;
 
1295
  QTextStream stream( &result, QIODevice::ReadWrite );
 
1296
 
 
1297
  PlainTextDecoder decoder;
 
1298
  decoder.begin( &stream );
 
1299
  writeSelectionToStream( &decoder , preserveLineBreaks );
 
1300
  decoder.end();
 
1301
 
 
1302
  return result;
 
1303
}
 
1304
 
 
1305
bool Screen::isSelectionValid() const
 
1306
{
 
1307
  return ( sel_TL >= 0 && sel_BR >= 0 );
 
1308
}
 
1309
 
 
1310
void Screen::writeSelectionToStream( TerminalCharacterDecoder* decoder ,
 
1311
                                     bool preserveLineBreaks )
 
1312
{
 
1313
  // do nothing if selection is invalid
 
1314
  if ( !isSelectionValid() )
 
1315
    return;
 
1316
 
 
1317
  int top = sel_TL / columns;
 
1318
  int left = sel_TL % columns;
 
1319
 
 
1320
  int bottom = sel_BR / columns;
 
1321
  int right = sel_BR % columns;
 
1322
 
 
1323
  Q_ASSERT( top >= 0 && left >= 0 && bottom >= 0 && right >= 0 );
 
1324
 
 
1325
  //kDebug() << "sel_TL = " << sel_TL;
 
1326
  //kDebug() << "columns = " << columns;
 
1327
 
 
1328
  for ( int y = top; y <= bottom; y++ )
 
1329
  {
 
1330
    int start = 0;
 
1331
    if ( y == top || columnmode ) start = left;
 
1332
 
 
1333
    int count = -1;
 
1334
    if ( y == bottom || columnmode ) count = right - start + 1;
 
1335
 
 
1336
    const bool appendNewLine = ( y != bottom );
 
1337
    copyLineToStream( y,
 
1338
                      start,
 
1339
                      count,
 
1340
                      decoder,
 
1341
                      appendNewLine,
 
1342
                      preserveLineBreaks );
 
1343
  }
 
1344
}
 
1345
 
 
1346
 
 
1347
void Screen::copyLineToStream( int line ,
 
1348
                               int start,
 
1349
                               int count,
 
1350
                               TerminalCharacterDecoder* decoder,
 
1351
                               bool appendNewLine,
 
1352
                               bool preserveLineBreaks )
 
1353
{
 
1354
  //buffer to hold characters for decoding
 
1355
  //the buffer is static to avoid initialising every
 
1356
  //element on each call to copyLineToStream
 
1357
  //(which is unnecessary since all elements will be overwritten anyway)
 
1358
  static const int MAX_CHARS = 1024;
 
1359
  static Character characterBuffer[MAX_CHARS];
 
1360
 
 
1361
  assert( count < MAX_CHARS );
 
1362
 
 
1363
  LineProperty currentLineProperties = 0;
 
1364
 
 
1365
  //determine if the line is in the history buffer or the screen image
 
1366
  if ( line < hist->getLines() )
 
1367
  {
 
1368
    const int lineLength = hist->getLineLen( line );
 
1369
 
 
1370
    // ensure that start position is before end of line
 
1371
    start = qMin( start, qMax( 0, lineLength - 1 ) );
 
1372
 
 
1373
    //retrieve line from history buffer
 
1374
    if ( count == -1 )
 
1375
    {
 
1376
      count = lineLength - start;
 
1377
    }
 
1378
    else
 
1379
    {
 
1380
      count = qMin( start + count, lineLength ) - start;
 
1381
    }
 
1382
 
 
1383
    // safety checks
 
1384
    assert( start >= 0 );
 
1385
    assert( count >= 0 );
 
1386
    assert(( start + count ) <= hist->getLineLen( line ) );
 
1387
 
 
1388
    hist->getCells( line, start, count, characterBuffer );
 
1389
 
 
1390
    if ( hist->isWrappedLine( line ) )
 
1391
      currentLineProperties |= LINE_WRAPPED;
 
1392
  }
 
1393
  else
 
1394
  {
 
1395
    if ( count == -1 )
 
1396
      count = columns - start;
 
1397
 
 
1398
    assert( count >= 0 );
 
1399
 
 
1400
    const int screenLine = line - hist->getLines();
 
1401
 
 
1402
    Character* data = screenLines[screenLine].data();
 
1403
    int length = screenLines[screenLine].count();
 
1404
 
 
1405
    //retrieve line from screen image
 
1406
    for ( int i = start; i < qMin( start + count, length ); i++ )
 
1407
    {
 
1408
      characterBuffer[i-start] = data[i];
 
1409
    }
 
1410
 
 
1411
    // count cannot be any greater than length
 
1412
    count = qBound( 0, count, length - start );
 
1413
 
 
1414
    Q_ASSERT( screenLine < lineProperties.count() );
 
1415
    currentLineProperties |= lineProperties[screenLine];
 
1416
  }
 
1417
 
 
1418
  //do not decode trailing whitespace characters
 
1419
  for ( int i = count - 1 ; i >= 0; i-- )
 
1420
    if ( QChar( characterBuffer[i].character ).isSpace() )
 
1421
      count--;
 
1422
    else
 
1423
      break;
 
1424
 
 
1425
  // add new line character at end
 
1426
  const bool omitLineBreak = ( currentLineProperties & LINE_WRAPPED ) ||
 
1427
                             !preserveLineBreaks;
 
1428
 
 
1429
  if ( !omitLineBreak && appendNewLine && ( count + 1 < MAX_CHARS ) )
 
1430
  {
 
1431
    characterBuffer[count] = '\n';
 
1432
    count++;
 
1433
  }
 
1434
 
 
1435
  //decode line and write to text stream
 
1436
  decoder->decodeLine(( Character* ) characterBuffer ,
 
1437
                      count, currentLineProperties );
 
1438
}
 
1439
 
 
1440
// Method below has been removed because of its reliance on 'histCursor'
 
1441
// and I want to restrict the methods which have knowledge of the scroll position
 
1442
// to just those which deal with selection and supplying final screen images.
 
1443
//
 
1444
/*void Screen::writeToStream(QTextStream* stream , TerminalCharacterDecoder* decoder) {
 
1445
  sel_begin = 0;
 
1446
  sel_BR = sel_begin;
 
1447
  sel_TL = sel_begin;
 
1448
  setSelectionEnd(columns-1,lines-1+hist->getLines()-histCursor);
 
1449
 
 
1450
  writeSelectionToStream(stream,decoder);
 
1451
 
 
1452
  clearSelection();
 
1453
}*/
 
1454
 
 
1455
void Screen::writeToStream( TerminalCharacterDecoder* decoder, int from, int to )
 
1456
{
 
1457
  sel_begin = loc( 0, from );
 
1458
  sel_TL = sel_begin;
 
1459
  sel_BR = loc( columns - 1, to );
 
1460
  writeSelectionToStream( decoder );
 
1461
  clearSelection();
 
1462
}
 
1463
 
 
1464
QString Screen::getHistoryLine( int no )
 
1465
{
 
1466
  sel_begin = loc( 0, no );
 
1467
  sel_TL = sel_begin;
 
1468
  sel_BR = loc( columns - 1, no );
 
1469
  return selectedText( false );
 
1470
}
 
1471
 
 
1472
void Screen::addHistLine()
 
1473
{
 
1474
  // add line to history buffer
 
1475
  // we have to take care about scrolling, too...
 
1476
 
 
1477
  if ( hasScroll() )
 
1478
  {
 
1479
    int oldHistLines = hist->getLines();
 
1480
 
 
1481
    hist->addCellsVector( screenLines[0] );
 
1482
    hist->addLine( lineProperties[0] & LINE_WRAPPED );
 
1483
 
 
1484
    int newHistLines = hist->getLines();
 
1485
 
 
1486
    bool beginIsTL = ( sel_begin == sel_TL );
 
1487
 
 
1488
    // If the history is full, increment the count
 
1489
    // of dropped lines
 
1490
    if ( newHistLines == oldHistLines )
 
1491
      _droppedLines++;
 
1492
 
 
1493
    // Adjust selection for the new point of reference
 
1494
    if ( newHistLines > oldHistLines )
 
1495
    {
 
1496
      if ( sel_begin != -1 )
 
1497
      {
 
1498
        sel_TL += columns;
 
1499
        sel_BR += columns;
 
1500
      }
 
1501
    }
 
1502
 
 
1503
    if ( sel_begin != -1 )
 
1504
    {
 
1505
      // Scroll selection in history up
 
1506
      int top_BR = loc( 0, 1 + newHistLines );
 
1507
 
 
1508
      if ( sel_TL < top_BR )
 
1509
        sel_TL -= columns;
 
1510
 
 
1511
      if ( sel_BR < top_BR )
 
1512
        sel_BR -= columns;
 
1513
 
 
1514
      if ( sel_BR < 0 )
 
1515
      {
 
1516
        clearSelection();
 
1517
      }
 
1518
      else
 
1519
      {
 
1520
        if ( sel_TL < 0 )
 
1521
          sel_TL = 0;
 
1522
      }
 
1523
 
 
1524
      if ( beginIsTL )
 
1525
        sel_begin = sel_TL;
 
1526
      else
 
1527
        sel_begin = sel_BR;
 
1528
    }
 
1529
  }
 
1530
 
 
1531
}
 
1532
 
 
1533
int Screen::getHistLines()
 
1534
{
 
1535
  return hist->getLines();
 
1536
}
 
1537
 
 
1538
void Screen::setScroll( const HistoryType& t , bool copyPreviousScroll )
 
1539
{
 
1540
  clearSelection();
 
1541
 
 
1542
  if ( copyPreviousScroll )
 
1543
    hist = t.scroll( hist );
 
1544
  else
 
1545
  {
 
1546
    HistoryScroll* oldScroll = hist;
 
1547
    hist = t.scroll( 0 );
 
1548
    delete oldScroll;
 
1549
  }
 
1550
}
 
1551
 
 
1552
bool Screen::hasScroll()
 
1553
{
 
1554
  return hist->hasScroll();
 
1555
}
 
1556
 
 
1557
const HistoryType& Screen::getScroll()
 
1558
{
 
1559
  return hist->getType();
 
1560
}
 
1561
 
 
1562
void Screen::setLineProperty( LineProperty property , bool enable )
 
1563
{
 
1564
  if ( enable )
 
1565
  {
 
1566
    lineProperties[cuY] = ( LineProperty )( lineProperties[cuY] | property );
 
1567
  }
 
1568
  else
 
1569
  {
 
1570
    lineProperties[cuY] = ( LineProperty )( lineProperties[cuY] & ~property );
 
1571
  }
 
1572
}
 
1573
void Screen::fillWithDefaultChar( Character* dest, int count )
 
1574
{
 
1575
  for ( int i = 0; i < count; i++ )
 
1576
    dest[i] = defaultChar;
 
1577
}