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

« back to all changes in this revision

Viewing changes to src/plugins/grass/qtermwidget/Emulation.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
 
 
4
    Copyright (C) 2007 Robert Knight <robertknight@gmail.com>
 
5
    Copyright (C) 1997,1998 by Lars Doelle <lars.doelle@on-line.de>
 
6
    Copyright (C) 1996 by Matthias Ettrich <ettrich@kde.org>
 
7
 
 
8
    Rewritten for QT4 by e_k <e_k at users.sourceforge.net>, Copyright (C)2008
 
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 "Emulation.h"
 
28
 
 
29
// System
 
30
#include <assert.h>
 
31
#include <stdio.h>
 
32
#include <stdlib.h>
 
33
#include <unistd.h>
 
34
 
 
35
// Qt
 
36
#include <QtGui/QApplication>
 
37
#include <QtGui/QClipboard>
 
38
#include <QtCore/QHash>
 
39
#include <QtGui/QKeyEvent>
 
40
#include <QtCore/QRegExp>
 
41
#include <QtCore/QTextStream>
 
42
#include <QtCore/QThread>
 
43
 
 
44
#include <QtCore/QTime>
 
45
 
 
46
// Konsole
 
47
#include "KeyboardTranslator.h"
 
48
#include "Screen.h"
 
49
#include "TerminalCharacterDecoder.h"
 
50
#include "ScreenWindow.h"
 
51
 
 
52
using namespace Konsole;
 
53
 
 
54
/* ------------------------------------------------------------------------- */
 
55
/*                                                                           */
 
56
/*                               Emulation                                  */
 
57
/*                                                                           */
 
58
/* ------------------------------------------------------------------------- */
 
59
 
 
60
//#define CNTL(c) ((c)-'@')
 
61
 
 
62
/*!
 
63
*/
 
64
 
 
65
Emulation::Emulation() :
 
66
    _currentScreen( 0 ),
 
67
    _codec( 0 ),
 
68
    _decoder( 0 ),
 
69
    _keyTranslator( 0 ),
 
70
    _usesMouse( false )
 
71
{
 
72
 
 
73
  // create screens with a default size
 
74
  _screen[0] = new Screen( 40, 80 );
 
75
  _screen[1] = new Screen( 40, 80 );
 
76
  _currentScreen = _screen[0];
 
77
 
 
78
  QObject::connect( &_bulkTimer1, SIGNAL( timeout() ), this, SLOT( showBulk() ) );
 
79
  QObject::connect( &_bulkTimer2, SIGNAL( timeout() ), this, SLOT( showBulk() ) );
 
80
 
 
81
  // listen for mouse status changes
 
82
  connect( this , SIGNAL( programUsesMouseChanged( bool ) ) ,
 
83
           SLOT( usesMouseChanged( bool ) ) );
 
84
}
 
85
 
 
86
bool Emulation::programUsesMouse() const
 
87
{
 
88
  return _usesMouse;
 
89
}
 
90
 
 
91
void Emulation::usesMouseChanged( bool usesMouse )
 
92
{
 
93
  _usesMouse = usesMouse;
 
94
}
 
95
 
 
96
ScreenWindow* Emulation::createWindow()
 
97
{
 
98
  ScreenWindow* window = new ScreenWindow();
 
99
  window->setScreen( _currentScreen );
 
100
  _windows << window;
 
101
 
 
102
  connect( window , SIGNAL( selectionChanged() ),
 
103
           this , SLOT( bufferedUpdate() ) );
 
104
 
 
105
  connect( this , SIGNAL( outputChanged() ),
 
106
           window , SLOT( notifyOutputChanged() ) );
 
107
  return window;
 
108
}
 
109
 
 
110
/*!
 
111
*/
 
112
 
 
113
Emulation::~Emulation()
 
114
{
 
115
  QListIterator<ScreenWindow*> windowIter( _windows );
 
116
 
 
117
  while ( windowIter.hasNext() )
 
118
  {
 
119
    delete windowIter.next();
 
120
  }
 
121
 
 
122
  delete _screen[0];
 
123
  delete _screen[1];
 
124
  delete _decoder;
 
125
}
 
126
 
 
127
/*! change between primary and alternate _screen
 
128
*/
 
129
 
 
130
void Emulation::setScreen( int n )
 
131
{
 
132
  Screen *old = _currentScreen;
 
133
  _currentScreen = _screen[n&1];
 
134
  if ( _currentScreen != old )
 
135
  {
 
136
    old->setBusySelecting( false );
 
137
 
 
138
    // tell all windows onto this emulation to switch to the newly active _screen
 
139
    QListIterator<ScreenWindow*> windowIter( _windows );
 
140
    while ( windowIter.hasNext() )
 
141
    {
 
142
      windowIter.next()->setScreen( _currentScreen );
 
143
    }
 
144
  }
 
145
}
 
146
 
 
147
void Emulation::clearHistory()
 
148
{
 
149
  _screen[0]->setScroll( _screen[0]->getScroll() , false );
 
150
}
 
151
void Emulation::setHistory( const HistoryType& t )
 
152
{
 
153
  _screen[0]->setScroll( t );
 
154
 
 
155
  showBulk();
 
156
}
 
157
 
 
158
const HistoryType& Emulation::history()
 
159
{
 
160
  return _screen[0]->getScroll();
 
161
}
 
162
 
 
163
void Emulation::setCodec( const QTextCodec * qtc )
 
164
{
 
165
  Q_ASSERT( qtc );
 
166
 
 
167
  _codec = qtc;
 
168
  delete _decoder;
 
169
  _decoder = _codec->makeDecoder();
 
170
 
 
171
  emit useUtf8Request( utf8() );
 
172
}
 
173
 
 
174
void Emulation::setCodec( EmulationCodec codec )
 
175
{
 
176
  if ( codec == Utf8Codec )
 
177
    setCodec( QTextCodec::codecForName( "utf8" ) );
 
178
  else if ( codec == LocaleCodec )
 
179
    setCodec( QTextCodec::codecForLocale() );
 
180
}
 
181
 
 
182
void Emulation::setKeyBindings( const QString& name )
 
183
{
 
184
  _keyTranslator = KeyboardTranslatorManager::instance()->findTranslator( name );
 
185
}
 
186
 
 
187
QString Emulation::keyBindings()
 
188
{
 
189
  return _keyTranslator->name();
 
190
}
 
191
 
 
192
 
 
193
// Interpreting Codes ---------------------------------------------------------
 
194
 
 
195
/*
 
196
   This section deals with decoding the incoming character stream.
 
197
   Decoding means here, that the stream is first separated into `tokens'
 
198
   which are then mapped to a `meaning' provided as operations by the
 
199
   `Screen' class.
 
200
*/
 
201
 
 
202
/*!
 
203
*/
 
204
 
 
205
void Emulation::receiveChar( int c )
 
206
// process application unicode input to terminal
 
207
// this is a trivial scanner
 
208
{
 
209
  c &= 0xff;
 
210
  switch ( c )
 
211
  {
 
212
    case '\b'      : _currentScreen->BackSpace();                 break;
 
213
    case '\t'      : _currentScreen->Tabulate();                  break;
 
214
    case '\n'      : _currentScreen->NewLine();                   break;
 
215
    case '\r'      : _currentScreen->Return();                    break;
 
216
    case 0x07      : emit stateSet( NOTIFYBELL );
 
217
      break;
 
218
    default        : _currentScreen->ShowCharacter( c );            break;
 
219
  };
 
220
}
 
221
 
 
222
/* ------------------------------------------------------------------------- */
 
223
/*                                                                           */
 
224
/*                             Keyboard Handling                             */
 
225
/*                                                                           */
 
226
/* ------------------------------------------------------------------------- */
 
227
 
 
228
/*!
 
229
*/
 
230
 
 
231
void Emulation::sendKeyEvent( QKeyEvent* ev )
 
232
{
 
233
  emit stateSet( NOTIFYNORMAL );
 
234
 
 
235
  if ( !ev->text().isEmpty() )
 
236
  { // A block of text
 
237
    // Note that the text is proper unicode.
 
238
    // We should do a conversion here, but since this
 
239
    // routine will never be used, we simply emit plain ascii.
 
240
    //emit sendBlock(ev->text().toAscii(),ev->text().length());
 
241
    emit sendData( ev->text().toUtf8(), ev->text().length() );
 
242
  }
 
243
}
 
244
 
 
245
void Emulation::sendString( const char*, int )
 
246
{
 
247
  // default implementation does nothing
 
248
}
 
249
 
 
250
void Emulation::sendMouseEvent( int /*buttons*/, int /*column*/, int /*row*/, int /*eventType*/ )
 
251
{
 
252
  // default implementation does nothing
 
253
}
 
254
 
 
255
// Unblocking, Byte to Unicode translation --------------------------------- --
 
256
 
 
257
/*
 
258
   We are doing code conversion from locale to unicode first.
 
259
TODO: Character composition from the old code.  See #96536
 
260
*/
 
261
 
 
262
void Emulation::receiveData( const char* text, int length )
 
263
{
 
264
  emit stateSet( NOTIFYACTIVITY );
 
265
 
 
266
  bufferedUpdate();
 
267
 
 
268
  QString unicodeText = _decoder->toUnicode( text, length );
 
269
 
 
270
  //send characters to terminal emulator
 
271
  for ( int i = 0; i < unicodeText.length(); i++ )
 
272
  {
 
273
    receiveChar( unicodeText[i].unicode() );
 
274
  }
 
275
 
 
276
  //look for z-modem indicator
 
277
  //-- someone who understands more about z-modems that I do may be able to move
 
278
  //this check into the above for loop?
 
279
  for ( int i = 0; i < length; i++ )
 
280
  {
 
281
    if ( text[i] == '\030' )
 
282
    {
 
283
      if (( length - i - 1 > 3 ) && ( strncmp( text + i + 1, "B00", 3 ) == 0 ) )
 
284
        emit zmodemDetected();
 
285
    }
 
286
  }
 
287
}
 
288
 
 
289
//OLDER VERSION
 
290
//This version of onRcvBlock was commented out because
 
291
//  a)  It decoded incoming characters one-by-one, which is slow in the current version of Qt (4.2 tech preview)
 
292
//  b)  It messed up decoding of non-ASCII characters, with the result that (for example) chinese characters
 
293
//      were not printed properly.
 
294
//
 
295
//There is something about stopping the _decoder if "we get a control code halfway a multi-byte sequence" (see below)
 
296
//which hasn't been ported into the newer function (above).  Hopefully someone who understands this better
 
297
//can find an alternative way of handling the check.
 
298
 
 
299
 
 
300
/*void Emulation::onRcvBlock(const char *s, int len)
 
301
{
 
302
  emit notifySessionState(NOTIFYACTIVITY);
 
303
 
 
304
  bufferedUpdate();
 
305
  for (int i = 0; i < len; i++)
 
306
  {
 
307
 
 
308
    QString result = _decoder->toUnicode(&s[i],1);
 
309
    int reslen = result.length();
 
310
 
 
311
    // If we get a control code halfway a multi-byte sequence
 
312
    // we flush the _decoder and continue with the control code.
 
313
    if ((s[i] < 32) && (s[i] > 0))
 
314
    {
 
315
       // Flush _decoder
 
316
       while(!result.length())
 
317
          result = _decoder->toUnicode(&s[i],1);
 
318
       reslen = 1;
 
319
       result.resize(reslen);
 
320
       result[0] = QChar(s[i]);
 
321
    }
 
322
 
 
323
    for (int j = 0; j < reslen; j++)
 
324
    {
 
325
      if (result[j].characterategory() == QChar::Mark_NonSpacing)
 
326
         _currentScreen->compose(result.mid(j,1));
 
327
      else
 
328
         onRcvChar(result[j].unicode());
 
329
    }
 
330
    if (s[i] == '\030')
 
331
    {
 
332
      if ((len-i-1 > 3) && (strncmp(s+i+1, "B00", 3) == 0))
 
333
        emit zmodemDetected();
 
334
    }
 
335
  }
 
336
}*/
 
337
 
 
338
// Selection --------------------------------------------------------------- --
 
339
 
 
340
#if 0
 
341
void Emulation::onSelectionBegin( const int x, const int y, const bool columnmode )
 
342
{
 
343
  if ( !connected ) return;
 
344
  _currentScreen->setSelectionStart( x, y, columnmode );
 
345
  showBulk();
 
346
}
 
347
 
 
348
void Emulation::onSelectionExtend( const int x, const int y )
 
349
{
 
350
  if ( !connected ) return;
 
351
  _currentScreen->setSelectionEnd( x, y );
 
352
  showBulk();
 
353
}
 
354
 
 
355
void Emulation::setSelection( const bool preserve_line_breaks )
 
356
{
 
357
  if ( !connected ) return;
 
358
  QString t = _currentScreen->selectedText( preserve_line_breaks );
 
359
  if ( !t.isNull() )
 
360
  {
 
361
    QListIterator< TerminalDisplay* > viewIter( _views );
 
362
 
 
363
    while ( viewIter.hasNext() )
 
364
      viewIter.next()->setSelection( t );
 
365
  }
 
366
}
 
367
 
 
368
void Emulation::testIsSelected( const int x, const int y, bool &selected )
 
369
{
 
370
  if ( !connected ) return;
 
371
  selected = _currentScreen->isSelected( x, y );
 
372
}
 
373
 
 
374
void Emulation::clearSelection()
 
375
{
 
376
  if ( !connected ) return;
 
377
  _currentScreen->clearSelection();
 
378
  showBulk();
 
379
}
 
380
 
 
381
#endif
 
382
 
 
383
void Emulation::writeToStream( TerminalCharacterDecoder* _decoder ,
 
384
                               int startLine ,
 
385
                               int endLine )
 
386
{
 
387
  _currentScreen->writeToStream( _decoder, startLine, endLine );
 
388
}
 
389
 
 
390
int Emulation::lineCount()
 
391
{
 
392
  // sum number of lines currently on _screen plus number of lines in history
 
393
  return _currentScreen->getLines() + _currentScreen->getHistLines();
 
394
}
 
395
 
 
396
// Refreshing -------------------------------------------------------------- --
 
397
 
 
398
#define BULK_TIMEOUT1 10
 
399
#define BULK_TIMEOUT2 40
 
400
 
 
401
/*!
 
402
*/
 
403
void Emulation::showBulk()
 
404
{
 
405
  _bulkTimer1.stop();
 
406
  _bulkTimer2.stop();
 
407
 
 
408
  emit outputChanged();
 
409
 
 
410
  _currentScreen->resetScrolledLines();
 
411
  _currentScreen->resetDroppedLines();
 
412
}
 
413
 
 
414
void Emulation::bufferedUpdate()
 
415
{
 
416
  _bulkTimer1.setSingleShot( true );
 
417
  _bulkTimer1.start( BULK_TIMEOUT1 );
 
418
  if ( !_bulkTimer2.isActive() )
 
419
  {
 
420
    _bulkTimer2.setSingleShot( true );
 
421
    _bulkTimer2.start( BULK_TIMEOUT2 );
 
422
  }
 
423
}
 
424
 
 
425
char Emulation::getErase() const
 
426
{
 
427
  return '\b';
 
428
}
 
429
 
 
430
void Emulation::setImageSize( int lines, int columns )
 
431
{
 
432
  //kDebug() << "Resizing image to: " << lines << "by" << columns << QTime::currentTime().msec();
 
433
  Q_ASSERT( lines > 0 );
 
434
  Q_ASSERT( columns > 0 );
 
435
 
 
436
  _screen[0]->resizeImage( lines, columns );
 
437
  _screen[1]->resizeImage( lines, columns );
 
438
 
 
439
  emit imageSizeChanged( lines, columns );
 
440
 
 
441
  bufferedUpdate();
 
442
}
 
443
 
 
444
QSize Emulation::imageSize()
 
445
{
 
446
  return QSize( _currentScreen->getColumns(), _currentScreen->getLines() );
 
447
}
 
448
 
 
449
ushort ExtendedCharTable::extendedCharHash( ushort* unicodePoints , ushort length ) const
 
450
{
 
451
  ushort hash = 0;
 
452
  for ( ushort i = 0 ; i < length ; i++ )
 
453
  {
 
454
    hash = 31 * hash + unicodePoints[i];
 
455
  }
 
456
  return hash;
 
457
}
 
458
bool ExtendedCharTable::extendedCharMatch( ushort hash , ushort* unicodePoints , ushort length ) const
 
459
{
 
460
  ushort* entry = extendedCharTable[hash];
 
461
 
 
462
  // compare given length with stored sequence length ( given as the first ushort in the
 
463
  // stored buffer )
 
464
  if ( entry == 0 || entry[0] != length )
 
465
    return false;
 
466
  // if the lengths match, each character must be checked.  the stored buffer starts at
 
467
  // entry[1]
 
468
  for ( int i = 0 ; i < length ; i++ )
 
469
  {
 
470
    if ( entry[i+1] != unicodePoints[i] )
 
471
      return false;
 
472
  }
 
473
  return true;
 
474
}
 
475
ushort ExtendedCharTable::createExtendedChar( ushort* unicodePoints , ushort length )
 
476
{
 
477
  // look for this sequence of points in the table
 
478
  ushort hash = extendedCharHash( unicodePoints, length );
 
479
 
 
480
  // check existing entry for match
 
481
  while ( extendedCharTable.contains( hash ) )
 
482
  {
 
483
    if ( extendedCharMatch( hash, unicodePoints, length ) )
 
484
    {
 
485
      // this sequence already has an entry in the table,
 
486
      // return its hash
 
487
      return hash;
 
488
    }
 
489
    else
 
490
    {
 
491
      // if hash is already used by another, different sequence of unicode character
 
492
      // points then try next hash
 
493
      hash++;
 
494
    }
 
495
  }
 
496
 
 
497
 
 
498
  // add the new sequence to the table and
 
499
  // return that index
 
500
  ushort* buffer = new ushort[length+1];
 
501
  buffer[0] = length;
 
502
  for ( int i = 0 ; i < length ; i++ )
 
503
    buffer[i+1] = unicodePoints[i];
 
504
 
 
505
  extendedCharTable.insert( hash, buffer );
 
506
 
 
507
  return hash;
 
508
}
 
509
 
 
510
ushort* ExtendedCharTable::lookupExtendedChar( ushort hash , ushort& length ) const
 
511
{
 
512
  // lookup index in table and if found, set the length
 
513
  // argument and return a pointer to the character sequence
 
514
 
 
515
  ushort* buffer = extendedCharTable[hash];
 
516
  if ( buffer )
 
517
  {
 
518
    length = buffer[0];
 
519
    return buffer + 1;
 
520
  }
 
521
  else
 
522
  {
 
523
    length = 0;
 
524
    return 0;
 
525
  }
 
526
}
 
527
 
 
528
ExtendedCharTable::ExtendedCharTable()
 
529
{
 
530
}
 
531
ExtendedCharTable::~ExtendedCharTable()
 
532
{
 
533
  // free all allocated character buffers
 
534
  QHashIterator<ushort, ushort*> iter( extendedCharTable );
 
535
  while ( iter.hasNext() )
 
536
  {
 
537
    iter.next();
 
538
    delete[] iter.value();
 
539
  }
 
540
}
 
541
 
 
542
// global instance
 
543
ExtendedCharTable ExtendedCharTable::instance;
 
544
 
 
545
 
 
546
//#include "moc_Emulation.cpp"
 
547