source: ogBrowser-Git/qtermwidget/src/Emulation.cpp @ 9d8d163

jenkinsmain
Last change on this file since 9d8d163 was 050d67a, checked in by adelcastillo <adelcastillo@…>, 16 years ago

Ahora el browser tiene consola en vez del output.
Pasado todo el sistema de compilacion a cmake.

git-svn-id: https://opengnsys.es/svn/trunk@408 a21b9725-9963-47de-94b9-378ad31fedc9

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