~larryprice/acolyterm/release-0.1

« back to all changes in this revision

Viewing changes to src/plugin/konsole/History.cpp

  • Committer: Larry Price
  • Date: 2016-06-15 14:47:59 UTC
  • Revision ID: larry.price@canonical.com-20160615144759-6wopn0gxwgta3x1n
Updating QMLTermWidget and removing unnecessary konsole codebase

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 1997,1998 by Lars Doelle <lars.doelle@on-line.de>
4
 
 
5
 
    This program is free software; you can redistribute it and/or modify
6
 
    it under the terms of the GNU General Public License as published by
7
 
    the Free Software Foundation; either version 2 of the License, or
8
 
    (at your option) any later version.
9
 
 
10
 
    This program is distributed in the hope that it will be useful,
11
 
    but WITHOUT ANY WARRANTY; without even the implied warranty of
12
 
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
 
    GNU General Public License for more details.
14
 
 
15
 
    You should have received a copy of the GNU General Public License
16
 
    along with this program; if not, write to the Free Software
17
 
    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
18
 
    02110-1301  USA.
19
 
*/
20
 
 
21
 
// Own
22
 
#include "History.h"
23
 
 
24
 
// System
25
 
#include <iostream>
26
 
#include <stdlib.h>
27
 
#include <assert.h>
28
 
#include <stdio.h>
29
 
#include <sys/types.h>
30
 
#include <sys/mman.h>
31
 
#include <unistd.h>
32
 
#include <errno.h>
33
 
 
34
 
#include <QtDebug>
35
 
 
36
 
// KDE
37
 
//#include <kde_file.h>
38
 
//#include <kdebug.h>
39
 
 
40
 
// Reasonable line size
41
 
#define LINE_SIZE    1024
42
 
#define KDE_lseek lseek
43
 
 
44
 
 
45
 
/*
46
 
   An arbitrary long scroll.
47
 
 
48
 
   One can modify the scroll only by adding either cells
49
 
   or newlines, but access it randomly.
50
 
 
51
 
   The model is that of an arbitrary wide typewriter scroll
52
 
   in that the scroll is a serie of lines and each line is
53
 
   a serie of cells with no overwriting permitted.
54
 
 
55
 
   The implementation provides arbitrary length and numbers
56
 
   of cells and line/column indexed read access to the scroll
57
 
   at constant costs.
58
 
 
59
 
KDE4: Can we use QTemporaryFile here, instead of KTempFile?
60
 
 
61
 
FIXME: some complain about the history buffer comsuming the
62
 
       memory of their machines. This problem is critical
63
 
       since the history does not behave gracefully in cases
64
 
       where the memory is used up completely.
65
 
 
66
 
       I put in a workaround that should handle it problem
67
 
       now gracefully. I'm not satisfied with the solution.
68
 
 
69
 
FIXME: Terminating the history is not properly indicated
70
 
       in the menu. We should throw a signal.
71
 
 
72
 
FIXME: There is noticeable decrease in speed, also. Perhaps,
73
 
       there whole feature needs to be revisited therefore.
74
 
       Disadvantage of a more elaborated, say block-oriented
75
 
       scheme with wrap around would be it's complexity.
76
 
*/
77
 
 
78
 
//FIXME: tempory replacement for tmpfile
79
 
//       this is here one for debugging purpose.
80
 
 
81
 
//#define tmpfile xTmpFile
82
 
 
83
 
// History File ///////////////////////////////////////////
84
 
 
85
 
/*
86
 
  A Row(X) data type which allows adding elements to the end.
87
 
*/
88
 
 
89
 
HistoryFile::HistoryFile()
90
 
  : ion(-1),
91
 
    length(0),
92
 
    fileMap(0)
93
 
{
94
 
  if (tmpFile.open())
95
 
  {
96
 
    tmpFile.setAutoRemove(true);
97
 
    ion = tmpFile.handle();
98
 
  }
99
 
}
100
 
 
101
 
HistoryFile::~HistoryFile()
102
 
{
103
 
    if (fileMap)
104
 
        unmap();
105
 
}
106
 
 
107
 
//TODO:  Mapping the entire file in will cause problems if the history file becomes exceedingly large,
108
 
//(ie. larger than available memory).  HistoryFile::map() should only map in sections of the file at a time,
109
 
//to avoid this.
110
 
void HistoryFile::map()
111
 
{
112
 
    assert( fileMap == 0 );
113
 
 
114
 
    fileMap = (char*)mmap( 0 , length , PROT_READ , MAP_PRIVATE , ion , 0 );
115
 
 
116
 
    //if mmap'ing fails, fall back to the read-lseek combination
117
 
    if ( fileMap == MAP_FAILED )
118
 
    {
119
 
            readWriteBalance = 0;
120
 
            fileMap = 0;
121
 
            qDebug() << __FILE__ << __LINE__ << ": mmap'ing history failed.  errno = " << errno;
122
 
    }
123
 
}
124
 
 
125
 
void HistoryFile::unmap()
126
 
{
127
 
    int result = munmap( fileMap , length );
128
 
    assert( result == 0 ); Q_UNUSED( result );
129
 
 
130
 
    fileMap = 0;
131
 
}
132
 
 
133
 
bool HistoryFile::isMapped()
134
 
{
135
 
    return (fileMap != 0);
136
 
}
137
 
 
138
 
void HistoryFile::add(const unsigned char* bytes, int len)
139
 
{
140
 
  if ( fileMap )
141
 
          unmap();
142
 
 
143
 
  readWriteBalance++;
144
 
 
145
 
  int rc = 0;
146
 
 
147
 
  rc = KDE_lseek(ion,length,SEEK_SET); if (rc < 0) { perror("HistoryFile::add.seek"); return; }
148
 
  rc = write(ion,bytes,len);       if (rc < 0) { perror("HistoryFile::add.write"); return; }
149
 
  length += rc;
150
 
}
151
 
 
152
 
void HistoryFile::get(unsigned char* bytes, int len, int loc)
153
 
{
154
 
  //count number of get() calls vs. number of add() calls.
155
 
  //If there are many more get() calls compared with add()
156
 
  //calls (decided by using MAP_THRESHOLD) then mmap the log
157
 
  //file to improve performance.
158
 
  readWriteBalance--;
159
 
  if ( !fileMap && readWriteBalance < MAP_THRESHOLD )
160
 
          map();
161
 
 
162
 
  if ( fileMap )
163
 
  {
164
 
    for (int i=0;i<len;i++)
165
 
            bytes[i]=fileMap[loc+i];
166
 
  }
167
 
  else
168
 
  {
169
 
      int rc = 0;
170
 
 
171
 
      if (loc < 0 || len < 0 || loc + len > length)
172
 
        fprintf(stderr,"getHist(...,%d,%d): invalid args.\n",len,loc);
173
 
      rc = KDE_lseek(ion,loc,SEEK_SET); if (rc < 0) { perror("HistoryFile::get.seek"); return; }
174
 
      rc = read(ion,bytes,len);     if (rc < 0) { perror("HistoryFile::get.read"); return; }
175
 
  }
176
 
}
177
 
 
178
 
int HistoryFile::len()
179
 
{
180
 
  return length;
181
 
}
182
 
 
183
 
 
184
 
// History Scroll abstract base class //////////////////////////////////////
185
 
 
186
 
 
187
 
HistoryScroll::HistoryScroll(HistoryType* t)
188
 
  : m_histType(t)
189
 
{
190
 
}
191
 
 
192
 
HistoryScroll::~HistoryScroll()
193
 
{
194
 
  delete m_histType;
195
 
}
196
 
 
197
 
bool HistoryScroll::hasScroll()
198
 
{
199
 
  return true;
200
 
}
201
 
 
202
 
// History Scroll File //////////////////////////////////////
203
 
 
204
 
/*
205
 
   The history scroll makes a Row(Row(Cell)) from
206
 
   two history buffers. The index buffer contains
207
 
   start of line positions which refere to the cells
208
 
   buffer.
209
 
 
210
 
   Note that index[0] addresses the second line
211
 
   (line #1), while the first line (line #0) starts
212
 
   at 0 in cells.
213
 
*/
214
 
 
215
 
HistoryScrollFile::HistoryScrollFile(const QString &logFileName)
216
 
  : HistoryScroll(new HistoryTypeFile(logFileName)),
217
 
  m_logFileName(logFileName)
218
 
{
219
 
}
220
 
 
221
 
HistoryScrollFile::~HistoryScrollFile()
222
 
{
223
 
}
224
 
 
225
 
int HistoryScrollFile::getLines()
226
 
{
227
 
  return index.len() / sizeof(int);
228
 
}
229
 
 
230
 
int HistoryScrollFile::getLineLen(int lineno)
231
 
{
232
 
  return (startOfLine(lineno+1) - startOfLine(lineno)) / sizeof(Character);
233
 
}
234
 
 
235
 
bool HistoryScrollFile::isWrappedLine(int lineno)
236
 
{
237
 
  if (lineno>=0 && lineno <= getLines()) {
238
 
    unsigned char flag;
239
 
    lineflags.get((unsigned char*)&flag,sizeof(unsigned char),(lineno)*sizeof(unsigned char));
240
 
    return flag;
241
 
  }
242
 
  return false;
243
 
}
244
 
 
245
 
int HistoryScrollFile::startOfLine(int lineno)
246
 
{
247
 
  if (lineno <= 0) return 0;
248
 
  if (lineno <= getLines())
249
 
    {
250
 
 
251
 
    if (!index.isMapped())
252
 
            index.map();
253
 
 
254
 
    int res;
255
 
    index.get((unsigned char*)&res,sizeof(int),(lineno-1)*sizeof(int));
256
 
    return res;
257
 
    }
258
 
  return cells.len();
259
 
}
260
 
 
261
 
void HistoryScrollFile::getCells(int lineno, int colno, int count, Character res[])
262
 
{
263
 
  cells.get((unsigned char*)res,count*sizeof(Character),startOfLine(lineno)+colno*sizeof(Character));
264
 
}
265
 
 
266
 
void HistoryScrollFile::addCells(const Character text[], int count)
267
 
{
268
 
  cells.add((unsigned char*)text,count*sizeof(Character));
269
 
}
270
 
 
271
 
void HistoryScrollFile::addLine(bool previousWrapped)
272
 
{
273
 
  if (index.isMapped())
274
 
          index.unmap();
275
 
 
276
 
  int locn = cells.len();
277
 
  index.add((unsigned char*)&locn,sizeof(int));
278
 
  unsigned char flags = previousWrapped ? 0x01 : 0x00;
279
 
  lineflags.add((unsigned char*)&flags,sizeof(unsigned char));
280
 
}
281
 
 
282
 
 
283
 
// History Scroll Buffer //////////////////////////////////////
284
 
HistoryScrollBuffer::HistoryScrollBuffer(unsigned int maxLineCount)
285
 
  : HistoryScroll(new HistoryTypeBuffer(maxLineCount))
286
 
   ,_historyBuffer()
287
 
   ,_maxLineCount(0)
288
 
   ,_usedLines(0)
289
 
   ,_head(0)
290
 
{
291
 
  setMaxNbLines(maxLineCount);
292
 
}
293
 
 
294
 
HistoryScrollBuffer::~HistoryScrollBuffer()
295
 
{
296
 
    delete[] _historyBuffer;
297
 
}
298
 
 
299
 
void HistoryScrollBuffer::addCellsVector(const QVector<Character>& cells)
300
 
{
301
 
    _head++;
302
 
    if ( _usedLines < _maxLineCount )
303
 
        _usedLines++;
304
 
 
305
 
    if ( _head >= _maxLineCount )
306
 
    {
307
 
        _head = 0;
308
 
    }
309
 
 
310
 
    _historyBuffer[bufferIndex(_usedLines-1)] = cells;
311
 
    _wrappedLine[bufferIndex(_usedLines-1)] = false;
312
 
}
313
 
void HistoryScrollBuffer::addCells(const Character a[], int count)
314
 
{
315
 
  HistoryLine newLine(count);
316
 
  qCopy(a,a+count,newLine.begin());
317
 
 
318
 
  addCellsVector(newLine);
319
 
}
320
 
 
321
 
void HistoryScrollBuffer::addLine(bool previousWrapped)
322
 
{
323
 
    _wrappedLine[bufferIndex(_usedLines-1)] = previousWrapped;
324
 
}
325
 
 
326
 
int HistoryScrollBuffer::getLines()
327
 
{
328
 
    return _usedLines;
329
 
}
330
 
 
331
 
int HistoryScrollBuffer::getLineLen(int lineNumber)
332
 
{
333
 
  Q_ASSERT( lineNumber >= 0 && lineNumber < _maxLineCount );
334
 
 
335
 
  if ( lineNumber < _usedLines )
336
 
  {
337
 
    return _historyBuffer[bufferIndex(lineNumber)].size();
338
 
  }
339
 
  else
340
 
  {
341
 
    return 0;
342
 
  }
343
 
}
344
 
 
345
 
bool HistoryScrollBuffer::isWrappedLine(int lineNumber)
346
 
{
347
 
  Q_ASSERT( lineNumber >= 0 && lineNumber < _maxLineCount );
348
 
 
349
 
  if (lineNumber < _usedLines)
350
 
  {
351
 
    //kDebug() << "Line" << lineNumber << "wrapped is" << _wrappedLine[bufferIndex(lineNumber)];
352
 
    return _wrappedLine[bufferIndex(lineNumber)];
353
 
  }
354
 
  else
355
 
    return false;
356
 
}
357
 
 
358
 
void HistoryScrollBuffer::getCells(int lineNumber, int startColumn, int count, Character buffer[])
359
 
{
360
 
  if ( count == 0 ) return;
361
 
 
362
 
  Q_ASSERT( lineNumber < _maxLineCount );
363
 
 
364
 
  if (lineNumber >= _usedLines)
365
 
  {
366
 
    memset(buffer, 0, count * sizeof(Character));
367
 
    return;
368
 
  }
369
 
 
370
 
  const HistoryLine& line = _historyBuffer[bufferIndex(lineNumber)];
371
 
 
372
 
  //kDebug() << "startCol " << startColumn;
373
 
  //kDebug() << "line.size() " << line.size();
374
 
  //kDebug() << "count " << count;
375
 
 
376
 
  Q_ASSERT( startColumn <= line.size() - count );
377
 
 
378
 
  memcpy(buffer, line.constData() + startColumn , count * sizeof(Character));
379
 
}
380
 
 
381
 
void HistoryScrollBuffer::setMaxNbLines(unsigned int lineCount)
382
 
{
383
 
    HistoryLine* oldBuffer = _historyBuffer;
384
 
    HistoryLine* newBuffer = new HistoryLine[lineCount];
385
 
 
386
 
    for ( int i = 0 ; i < qMin(_usedLines,(int)lineCount) ; i++ )
387
 
    {
388
 
        newBuffer[i] = oldBuffer[bufferIndex(i)];
389
 
    }
390
 
 
391
 
    _usedLines = qMin(_usedLines,(int)lineCount);
392
 
    _maxLineCount = lineCount;
393
 
    _head = ( _usedLines == _maxLineCount ) ? 0 : _usedLines-1;
394
 
 
395
 
    _historyBuffer = newBuffer;
396
 
    delete[] oldBuffer;
397
 
 
398
 
    _wrappedLine.resize(lineCount);
399
 
    dynamic_cast<HistoryTypeBuffer*>(m_histType)->m_nbLines = lineCount;
400
 
}
401
 
 
402
 
int HistoryScrollBuffer::bufferIndex(int lineNumber)
403
 
{
404
 
    Q_ASSERT( lineNumber >= 0 );
405
 
    Q_ASSERT( lineNumber < _maxLineCount );
406
 
    Q_ASSERT( (_usedLines == _maxLineCount) || lineNumber <= _head );
407
 
 
408
 
    if ( _usedLines == _maxLineCount )
409
 
    {
410
 
        return (_head+lineNumber+1) % _maxLineCount;
411
 
    }
412
 
    else
413
 
    {
414
 
        return lineNumber;
415
 
    }
416
 
}
417
 
 
418
 
 
419
 
// History Scroll None //////////////////////////////////////
420
 
 
421
 
HistoryScrollNone::HistoryScrollNone()
422
 
  : HistoryScroll(new HistoryTypeNone())
423
 
{
424
 
}
425
 
 
426
 
HistoryScrollNone::~HistoryScrollNone()
427
 
{
428
 
}
429
 
 
430
 
bool HistoryScrollNone::hasScroll()
431
 
{
432
 
  return false;
433
 
}
434
 
 
435
 
int  HistoryScrollNone::getLines()
436
 
{
437
 
  return 0;
438
 
}
439
 
 
440
 
int  HistoryScrollNone::getLineLen(int)
441
 
{
442
 
  return 0;
443
 
}
444
 
 
445
 
bool HistoryScrollNone::isWrappedLine(int /*lineno*/)
446
 
{
447
 
  return false;
448
 
}
449
 
 
450
 
void HistoryScrollNone::getCells(int, int, int, Character [])
451
 
{
452
 
}
453
 
 
454
 
void HistoryScrollNone::addCells(const Character [], int)
455
 
{
456
 
}
457
 
 
458
 
void HistoryScrollNone::addLine(bool)
459
 
{
460
 
}
461
 
 
462
 
// History Scroll BlockArray //////////////////////////////////////
463
 
 
464
 
HistoryScrollBlockArray::HistoryScrollBlockArray(size_t size)
465
 
  : HistoryScroll(new HistoryTypeBlockArray(size))
466
 
{
467
 
  m_blockArray.setHistorySize(size); // nb. of lines.
468
 
}
469
 
 
470
 
HistoryScrollBlockArray::~HistoryScrollBlockArray()
471
 
{
472
 
}
473
 
 
474
 
int  HistoryScrollBlockArray::getLines()
475
 
{
476
 
  return m_lineLengths.count();
477
 
}
478
 
 
479
 
int  HistoryScrollBlockArray::getLineLen(int lineno)
480
 
{
481
 
    if ( m_lineLengths.contains(lineno) )
482
 
        return m_lineLengths[lineno];
483
 
    else
484
 
        return 0;
485
 
}
486
 
 
487
 
bool HistoryScrollBlockArray::isWrappedLine(int /*lineno*/)
488
 
{
489
 
  return false;
490
 
}
491
 
 
492
 
void HistoryScrollBlockArray::getCells(int lineno, int colno,
493
 
                                       int count, Character res[])
494
 
{
495
 
  if (!count) return;
496
 
 
497
 
  const Block *b = m_blockArray.at(lineno);
498
 
 
499
 
  if (!b) {
500
 
    memset(res, 0, count * sizeof(Character)); // still better than random data
501
 
    return;
502
 
  }
503
 
 
504
 
  assert(((colno + count) * sizeof(Character)) < ENTRIES);
505
 
  memcpy(res, b->data + (colno * sizeof(Character)), count * sizeof(Character));
506
 
}
507
 
 
508
 
void HistoryScrollBlockArray::addCells(const Character a[], int count)
509
 
{
510
 
  Block *b = m_blockArray.lastBlock();
511
 
 
512
 
  if (!b) return;
513
 
 
514
 
  // put cells in block's data
515
 
  assert((count * sizeof(Character)) < ENTRIES);
516
 
 
517
 
  memset(b->data, 0, ENTRIES);
518
 
 
519
 
  memcpy(b->data, a, count * sizeof(Character));
520
 
  b->size = count * sizeof(Character);
521
 
 
522
 
  size_t res = m_blockArray.newBlock();
523
 
  assert (res > 0);
524
 
  Q_UNUSED( res );
525
 
 
526
 
  m_lineLengths.insert(m_blockArray.getCurrent(), count);
527
 
}
528
 
 
529
 
void HistoryScrollBlockArray::addLine(bool)
530
 
{
531
 
}
532
 
 
533
 
////////////////////////////////////////////////////////////////
534
 
// Compact History Scroll //////////////////////////////////////
535
 
////////////////////////////////////////////////////////////////
536
 
void* CompactHistoryBlock::allocate ( size_t length )
537
 
{
538
 
 Q_ASSERT ( length > 0 );
539
 
  if ( tail-blockStart+length > blockLength )
540
 
    return NULL;
541
 
 
542
 
  void* block = tail;
543
 
  tail += length;
544
 
  //kDebug() << "allocated " << length << " bytes at address " << block;
545
 
  allocCount++;
546
 
  return block;
547
 
}
548
 
 
549
 
void CompactHistoryBlock::deallocate ( )
550
 
{
551
 
  allocCount--;
552
 
  Q_ASSERT ( allocCount >= 0 );
553
 
}
554
 
 
555
 
void* CompactHistoryBlockList::allocate(size_t size)
556
 
{
557
 
  CompactHistoryBlock* block;
558
 
  if ( list.isEmpty() || list.last()->remaining() < size)
559
 
  {
560
 
    block = new CompactHistoryBlock();
561
 
    list.append ( block );
562
 
    //kDebug() << "new block created, remaining " << block->remaining() << "number of blocks=" << list.size();
563
 
  }
564
 
  else
565
 
  {
566
 
    block = list.last();
567
 
    //kDebug() << "old block used, remaining " << block->remaining();
568
 
  }
569
 
  return block->allocate(size);
570
 
}
571
 
 
572
 
void CompactHistoryBlockList::deallocate(void* ptr)
573
 
{
574
 
  Q_ASSERT( !list.isEmpty());
575
 
 
576
 
  int i=0;
577
 
  CompactHistoryBlock *block = list.at(i);
578
 
  while ( i<list.size() && !block->contains(ptr) )
579
 
  {
580
 
    i++;
581
 
    block=list.at(i);
582
 
  }
583
 
 
584
 
  Q_ASSERT( i<list.size() );
585
 
 
586
 
  block->deallocate();
587
 
 
588
 
  if (!block->isInUse())
589
 
  {
590
 
    list.removeAt(i);
591
 
    delete block;
592
 
    //kDebug() << "block deleted, new size = " << list.size();
593
 
  }
594
 
}
595
 
 
596
 
CompactHistoryBlockList::~CompactHistoryBlockList()
597
 
{
598
 
  qDeleteAll ( list.begin(), list.end() );
599
 
  list.clear();
600
 
}
601
 
 
602
 
void* CompactHistoryLine::operator new (size_t size, CompactHistoryBlockList& blockList)
603
 
{
604
 
  return blockList.allocate(size);
605
 
}
606
 
 
607
 
CompactHistoryLine::CompactHistoryLine ( const TextLine& line, CompactHistoryBlockList& bList )
608
 
  : blockList(bList),
609
 
    formatLength(0)
610
 
{
611
 
  length=line.size();
612
 
 
613
 
  if (line.size() > 0) {
614
 
    formatLength=1;
615
 
    int k=1;
616
 
 
617
 
    // count number of different formats in this text line
618
 
    Character c = line[0];
619
 
    while ( k<length )
620
 
    {
621
 
      if ( !(line[k].equalsFormat(c)))
622
 
      {
623
 
        formatLength++; // format change detected
624
 
        c=line[k];
625
 
      }
626
 
      k++;
627
 
    }
628
 
 
629
 
    //kDebug() << "number of different formats in string: " << formatLength;
630
 
    formatArray = (CharacterFormat*) blockList.allocate(sizeof(CharacterFormat)*formatLength);
631
 
    Q_ASSERT (formatArray!=NULL);
632
 
    text = (quint16*) blockList.allocate(sizeof(quint16)*line.size());
633
 
    Q_ASSERT (text!=NULL);
634
 
 
635
 
    length=line.size();
636
 
    formatLength=formatLength;
637
 
    wrapped=false;
638
 
 
639
 
    // record formats and their positions in the format array
640
 
    c=line[0];
641
 
    formatArray[0].setFormat ( c );
642
 
    formatArray[0].startPos=0;                        // there's always at least 1 format (for the entire line, unless a change happens)
643
 
 
644
 
    k=1;                                              // look for possible format changes
645
 
    int j=1;
646
 
    while ( k<length && j<formatLength )
647
 
    {
648
 
      if (!(line[k].equalsFormat(c)))
649
 
      {
650
 
        c=line[k];
651
 
        formatArray[j].setFormat(c);
652
 
        formatArray[j].startPos=k;
653
 
        //kDebug() << "format entry " << j << " at pos " << formatArray[j].startPos << " " << &(formatArray[j].startPos) ;
654
 
        j++;
655
 
      }
656
 
      k++;
657
 
    }
658
 
 
659
 
    // copy character values
660
 
    for ( int i=0; i<line.size(); i++ )
661
 
    {
662
 
      text[i]=line[i].character;
663
 
      //kDebug() << "char " << i << " at mem " << &(text[i]);
664
 
    }
665
 
  }
666
 
  //kDebug() << "line created, length " << length << " at " << &(length);
667
 
}
668
 
 
669
 
CompactHistoryLine::~CompactHistoryLine()
670
 
{
671
 
  //kDebug() << "~CHL";
672
 
  if (length>0) {
673
 
    blockList.deallocate(text);
674
 
    blockList.deallocate(formatArray);
675
 
  }
676
 
  blockList.deallocate(this);
677
 
}
678
 
 
679
 
void CompactHistoryLine::getCharacter ( int index, Character &r )
680
 
{
681
 
  Q_ASSERT ( index < length );
682
 
  int formatPos=0;
683
 
  while ( ( formatPos+1 ) < formatLength && index >= formatArray[formatPos+1].startPos )
684
 
    formatPos++;
685
 
 
686
 
  r.character=text[index];
687
 
  r.rendition = formatArray[formatPos].rendition;
688
 
  r.foregroundColor = formatArray[formatPos].fgColor;
689
 
  r.backgroundColor = formatArray[formatPos].bgColor;
690
 
}
691
 
 
692
 
void CompactHistoryLine::getCharacters ( Character* array, int length, int startColumn )
693
 
{
694
 
  Q_ASSERT ( startColumn >= 0 && length >= 0 );
695
 
  Q_ASSERT ( startColumn+length <= ( int ) getLength() );
696
 
 
697
 
  for ( int i=startColumn; i<length+startColumn; i++ )
698
 
  {
699
 
    getCharacter ( i, array[i-startColumn] );
700
 
  }
701
 
}
702
 
 
703
 
CompactHistoryScroll::CompactHistoryScroll ( unsigned int maxLineCount )
704
 
    : HistoryScroll ( new CompactHistoryType ( maxLineCount ) )
705
 
    ,lines()
706
 
    ,blockList()
707
 
{
708
 
  //kDebug() << "scroll of length " << maxLineCount << " created";
709
 
  setMaxNbLines ( maxLineCount );
710
 
}
711
 
 
712
 
CompactHistoryScroll::~CompactHistoryScroll()
713
 
{
714
 
  qDeleteAll ( lines.begin(), lines.end() );
715
 
  lines.clear();
716
 
}
717
 
 
718
 
void CompactHistoryScroll::addCellsVector ( const TextLine& cells )
719
 
{
720
 
  CompactHistoryLine *line;
721
 
  line = new(blockList) CompactHistoryLine ( cells, blockList );
722
 
 
723
 
  if ( lines.size() > ( int ) _maxLineCount )
724
 
  {
725
 
    delete lines.takeAt ( 0 );
726
 
  }
727
 
  lines.append ( line );
728
 
}
729
 
 
730
 
void CompactHistoryScroll::addCells ( const Character a[], int count )
731
 
{
732
 
  TextLine newLine ( count );
733
 
  qCopy ( a,a+count,newLine.begin() );
734
 
  addCellsVector ( newLine );
735
 
}
736
 
 
737
 
void CompactHistoryScroll::addLine ( bool previousWrapped )
738
 
{
739
 
  CompactHistoryLine *line = lines.last();
740
 
  //kDebug() << "last line at address " << line;
741
 
  line->setWrapped(previousWrapped);
742
 
}
743
 
 
744
 
int CompactHistoryScroll::getLines()
745
 
{
746
 
  return lines.size();
747
 
}
748
 
 
749
 
int CompactHistoryScroll::getLineLen ( int lineNumber )
750
 
{
751
 
  Q_ASSERT ( lineNumber >= 0 && lineNumber < lines.size() );
752
 
  CompactHistoryLine* line = lines[lineNumber];
753
 
  //kDebug() << "request for line at address " << line;
754
 
  return line->getLength();
755
 
}
756
 
 
757
 
 
758
 
void CompactHistoryScroll::getCells ( int lineNumber, int startColumn, int count, Character buffer[] )
759
 
{
760
 
  if ( count == 0 ) return;
761
 
  Q_ASSERT ( lineNumber < lines.size() );
762
 
  CompactHistoryLine* line = lines[lineNumber];
763
 
  Q_ASSERT ( startColumn >= 0 );
764
 
  Q_ASSERT ( (unsigned int)startColumn <= line->getLength() - count );
765
 
  line->getCharacters ( buffer, count, startColumn );
766
 
}
767
 
 
768
 
void CompactHistoryScroll::setMaxNbLines ( unsigned int lineCount )
769
 
{
770
 
  _maxLineCount = lineCount;
771
 
 
772
 
  while (lines.size() > (int) lineCount) {
773
 
    delete lines.takeAt(0);
774
 
  }
775
 
  //kDebug() << "set max lines to: " << _maxLineCount;
776
 
}
777
 
 
778
 
bool CompactHistoryScroll::isWrappedLine ( int lineNumber )
779
 
{
780
 
  Q_ASSERT ( lineNumber < lines.size() );
781
 
  return lines[lineNumber]->isWrapped();
782
 
}
783
 
 
784
 
 
785
 
//////////////////////////////////////////////////////////////////////
786
 
// History Types
787
 
//////////////////////////////////////////////////////////////////////
788
 
 
789
 
HistoryType::HistoryType()
790
 
{
791
 
}
792
 
 
793
 
HistoryType::~HistoryType()
794
 
{
795
 
}
796
 
 
797
 
//////////////////////////////
798
 
 
799
 
HistoryTypeNone::HistoryTypeNone()
800
 
{
801
 
}
802
 
 
803
 
bool HistoryTypeNone::isEnabled() const
804
 
{
805
 
  return false;
806
 
}
807
 
 
808
 
HistoryScroll* HistoryTypeNone::scroll(HistoryScroll *old) const
809
 
{
810
 
  delete old;
811
 
  return new HistoryScrollNone();
812
 
}
813
 
 
814
 
int HistoryTypeNone::maximumLineCount() const
815
 
{
816
 
  return 0;
817
 
}
818
 
 
819
 
//////////////////////////////
820
 
 
821
 
HistoryTypeBlockArray::HistoryTypeBlockArray(size_t size)
822
 
  : m_size(size)
823
 
{
824
 
}
825
 
 
826
 
bool HistoryTypeBlockArray::isEnabled() const
827
 
{
828
 
  return true;
829
 
}
830
 
 
831
 
int HistoryTypeBlockArray::maximumLineCount() const
832
 
{
833
 
  return m_size;
834
 
}
835
 
 
836
 
HistoryScroll* HistoryTypeBlockArray::scroll(HistoryScroll *old) const
837
 
{
838
 
  delete old;
839
 
  return new HistoryScrollBlockArray(m_size);
840
 
}
841
 
 
842
 
 
843
 
//////////////////////////////
844
 
 
845
 
HistoryTypeBuffer::HistoryTypeBuffer(unsigned int nbLines)
846
 
  : m_nbLines(nbLines)
847
 
{
848
 
}
849
 
 
850
 
bool HistoryTypeBuffer::isEnabled() const
851
 
{
852
 
  return true;
853
 
}
854
 
 
855
 
int HistoryTypeBuffer::maximumLineCount() const
856
 
{
857
 
  return m_nbLines;
858
 
}
859
 
 
860
 
HistoryScroll* HistoryTypeBuffer::scroll(HistoryScroll *old) const
861
 
{
862
 
  if (old)
863
 
  {
864
 
    HistoryScrollBuffer *oldBuffer = dynamic_cast<HistoryScrollBuffer*>(old);
865
 
    if (oldBuffer)
866
 
    {
867
 
       oldBuffer->setMaxNbLines(m_nbLines);
868
 
       return oldBuffer;
869
 
    }
870
 
 
871
 
    HistoryScroll *newScroll = new HistoryScrollBuffer(m_nbLines);
872
 
    int lines = old->getLines();
873
 
    int startLine = 0;
874
 
    if (lines > (int) m_nbLines)
875
 
       startLine = lines - m_nbLines;
876
 
 
877
 
    Character line[LINE_SIZE];
878
 
    for(int i = startLine; i < lines; i++)
879
 
    {
880
 
       int size = old->getLineLen(i);
881
 
       if (size > LINE_SIZE)
882
 
       {
883
 
          Character *tmp_line = new Character[size];
884
 
          old->getCells(i, 0, size, tmp_line);
885
 
          newScroll->addCells(tmp_line, size);
886
 
          newScroll->addLine(old->isWrappedLine(i));
887
 
          delete [] tmp_line;
888
 
       }
889
 
       else
890
 
       {
891
 
          old->getCells(i, 0, size, line);
892
 
          newScroll->addCells(line, size);
893
 
          newScroll->addLine(old->isWrappedLine(i));
894
 
       }
895
 
    }
896
 
    delete old;
897
 
    return newScroll;
898
 
  }
899
 
  return new HistoryScrollBuffer(m_nbLines);
900
 
}
901
 
 
902
 
//////////////////////////////
903
 
 
904
 
HistoryTypeFile::HistoryTypeFile(const QString& fileName)
905
 
  : m_fileName(fileName)
906
 
{
907
 
}
908
 
 
909
 
bool HistoryTypeFile::isEnabled() const
910
 
{
911
 
  return true;
912
 
}
913
 
 
914
 
const QString& HistoryTypeFile::getFileName() const
915
 
{
916
 
  return m_fileName;
917
 
}
918
 
 
919
 
HistoryScroll* HistoryTypeFile::scroll(HistoryScroll *old) const
920
 
{
921
 
  if (dynamic_cast<HistoryFile *>(old))
922
 
     return old; // Unchanged.
923
 
 
924
 
  HistoryScroll *newScroll = new HistoryScrollFile(m_fileName);
925
 
 
926
 
  Character line[LINE_SIZE];
927
 
  int lines = (old != 0) ? old->getLines() : 0;
928
 
  for(int i = 0; i < lines; i++)
929
 
  {
930
 
     int size = old->getLineLen(i);
931
 
     if (size > LINE_SIZE)
932
 
     {
933
 
        Character *tmp_line = new Character[size];
934
 
        old->getCells(i, 0, size, tmp_line);
935
 
        newScroll->addCells(tmp_line, size);
936
 
        newScroll->addLine(old->isWrappedLine(i));
937
 
        delete [] tmp_line;
938
 
     }
939
 
     else
940
 
     {
941
 
        old->getCells(i, 0, size, line);
942
 
        newScroll->addCells(line, size);
943
 
        newScroll->addLine(old->isWrappedLine(i));
944
 
     }
945
 
  }
946
 
 
947
 
  delete old;
948
 
  return newScroll;
949
 
}
950
 
 
951
 
int HistoryTypeFile::maximumLineCount() const
952
 
{
953
 
  return 0;
954
 
}
955
 
 
956
 
//////////////////////////////
957
 
 
958
 
CompactHistoryType::CompactHistoryType ( unsigned int nbLines )
959
 
    : m_nbLines ( nbLines )
960
 
{
961
 
}
962
 
 
963
 
bool CompactHistoryType::isEnabled() const
964
 
{
965
 
  return true;
966
 
}
967
 
 
968
 
int CompactHistoryType::maximumLineCount() const
969
 
{
970
 
  return m_nbLines;
971
 
}
972
 
 
973
 
HistoryScroll* CompactHistoryType::scroll ( HistoryScroll *old ) const
974
 
{
975
 
  if ( old )
976
 
  {
977
 
    CompactHistoryScroll *oldBuffer = dynamic_cast<CompactHistoryScroll*> ( old );
978
 
    if ( oldBuffer )
979
 
    {
980
 
      oldBuffer->setMaxNbLines ( m_nbLines );
981
 
      return oldBuffer;
982
 
    }
983
 
    delete old;
984
 
  }
985
 
  return new CompactHistoryScroll ( m_nbLines );
986
 
}