/* vim: sw=4 et
 *
 * Copyright (C) 2002 George Staikos <staikos@kde.org>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public License
 * along with this library; see the file COPYING.LIB.  If not, write to
 * the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 * Boston, MA 02111-1307, USA.
 */

#include <qapplication.h>
#include <qlabel.h>
#include <qmessagebox.h>
#include <qpainter.h>
#include <qtimer.h>
#include <qcolor.h>

#include <dcopclient.h>
#include <dcopobject.h>
#include <kapplication.h>
#include <kdebug.h>
#include <klocale.h>
#include <kmessagebox.h>
#include <kglobal.h>
#include <kstandarddirs.h>
#include <kfiledialog.h>
#include <kconfig.h>

#include <stdlib.h>
#include <unistd.h>
#include <assert.h>

#include "pluginfactory.h"
#include "chwizard.h"
#include "viewmanager.h"
#include "channelscanner.h"
#include "channelstore.h"
#include "view.h"
#include "audiomanager.h"
#include "osdmanager.h"
#include "channelimportdlg.h"
#include "miscmanager.h"
#include "statusmanager.h"

#include "qtvision.h"
#include "qtvision.moc"



QtVision::QtVision( QObject *parent, const char *name) 
         :QObject( parent, name ? name : "qtvision" ),
          DCOPObject( "QtVisionIface" ), _view(0), _vsrc(0), 
          _number(""), _prevChannel(-1)

{
    _mm = 0;
    _osd = 0;
    _sm = 0;
    _am = 0;
    _pf = new PluginFactory(this);
    grabPix.resize( 200, 200 );
    grabPix.fill( Qt::blue );
    KGlobal::dirs()->addResourceType("qtvision", "share/apps/qtvision");
    _quitting = false;    
    connect(qApp, SIGNAL(aboutToQuit()), this, SLOT(aboutToQuit()));       
        
    _config = new KConfig ("qtvisionrc");
    
    _cfg = new ConfigData (_config);
    
    if (_cfg->load() == -1)
    {
        kdFatal() << "QtVision::QtVision: Unable to read config file..." << endl;
        exit (1);
    }
    
    // Force the audio manager to initialize and set the volume
    _am = new AudioManager(this);
    connect(_am, SIGNAL(volumeChanged(int,int)), this, SIGNAL(volumeChanged(int,int)));
      
    _viewmng = new ViewManager( this );

    // Register with DCOP
    if ( !kapp->dcopClient()->isRegistered() ) {
      kapp->dcopClient()->registerAs( "qtvisioniface" );
      kapp->dcopClient()->setDefaultObject( objId() );
    }

    _cs = new ChannelStore( this, this, "channel_store" );

    if (_cfg->firstTime) {
        kdDebug() << "This is a first run.  let's ask to migrate.." << endl;
        doMigration();
    }
    
    // Restore the volume settings...
    _muted = _cfg->volumeMuted;    
    ChannelVolState.left = _cfg->volumeLeft;
    ChannelVolState.right = _cfg->volumeRight;    

    _keypresstimer = new QTimer(parent);
    connect(_keypresstimer, SIGNAL(timeout()), this, SLOT(slotKeyPressTimeout()));

    _sm = new StatusManager;
    connect(this, SIGNAL(channelChanged(int)), _sm, SIGNAL(channelChanged()));
}

QtVision::~QtVision()
{
    _cs->save();
    stopDevice();
    
    // Save volume related settings...
    _cfg->volumeMuted = _muted;
    _cfg->volumeLeft = _am->volumeLeft();
    _cfg->volumeRight= _am->volumeRight();
    
    delete _cfg;
    delete _config;
    delete _viewmng;
    delete _keypresstimer;
    delete _am;
    delete _sm;
    delete _mm;
    delete _osd;
    delete _pf;

    _cfg = 0;
    _config = 0;
    _viewmng = 0;
    _keypresstimer = 0;
    _am = 0;
    _sm = 0;
    _mm = 0;
    _osd = 0;
    _pf = 0;
}

DCOPRef QtVision::channelStoreIface()
{
    return DCOPRef( _cs );
}

DCOPRef QtVision::channelIface()
{
    return DCOPRef( _chan );
}

void QtVision::start()
{
    kdDebug () << "QtVision::start: Set initial volume settings... " << endl;    
    
    // -2 is a bogus value used during initialization to stop ::setChannel
    // from storing the current device volume settings when restoring the
    // previous channel.  See ::setChannel.
    ChannelVolState.changeEventId = -2;
    
    // Make sure the volume mute state is restored...
    _muted = !_muted;
    volumeMute();
     
    emit volumeChanged (ChannelVolState.left, ChannelVolState.right);
    kdDebug () << "QtVision::start: Emitted volume settings...." << endl;
    
    if ( !_view )
        return;

    bool started = false;
    if ( _cfg->autoStart ) {
        started = tryAutoStart();
    }

    if ( !started )
        selectDevice();

    if ( !_vsrc ) {
        kdWarning() << "QtVision::start() No device selected" << endl;
        return;
    }
}

void QtVision::stop()
{
    if ( !_view )
        return;
    
    // Preserve the volume state incase this is 
    // invoked through DCOP.
    if (_am) {
        ChannelVolState.left = _am->volumeLeft ();
        ChannelVolState.right = _am->volumeRight ();
        kdDebug () << "QtVision::stop: Volume => left = " <<  ChannelVolState.left
                   <<  ", right = " << ChannelVolState.right << endl;
    }
               
    stopDevice();    
}

bool QtVision::tryAutoStart()
{
    kdDebug() << "QtVision::tryAutoStart()" << endl;
    assert(_vsrc == 0);

    QString dev = _cfg->prevDev;
    if ( dev.isEmpty() )
        return false;

    QString src = _cfg->prevSrc;
    if ( src.isEmpty() )
        return false;

    kdDebug() << "QtVision::tryAutoStart() Trying device '" << dev
              << "', and source '" << src << "'" << endl;

    for (PluginDesc *plug = _pf->videoPlugins().first(); plug;
                     plug = _pf->videoPlugins().next()) {
        QVSourcePlugin *v = _pf->getVideoPlugin(plug,screen());
        if (!v)
            continue;
        v->probeDevices();
        for (QStringList::ConstIterator it = v->deviceList().begin();
                                         it != v->deviceList().end();
                                                                 ++it) {
            if (*it == dev) {
                if (v->sourceList(dev).contains(src)) {
                    v->setDevice(dev);
                    setDevice(v);
                    setSource(src);
                    startCapture();
                    return true;
                }
            }
        }
        delete v;
    }

    return false;  // didn't work
}


void QtVision::selectDevice()
{
    kdDebug() << "QtVision::selectDevice()" << endl;

    do {
        int rc = _viewmng->launchSourceDialog( _view );
        if ( rc == QDialog::Rejected )
            return;
    } while( !hasDevice() );

    kdDebug() << "QtVision::selectDevice() Starting capture" << endl;
    startCapture();
}

void QtVision::setSource( const QString &src )
{
    if (_vsrc) {
        _vsrc->setSource(src);
        _cfg->prevSrc = src;
    }
}

void QtVision::setDevice( QVSourcePlugin *dev )
{
    stopDevice();
    _vsrc = dev;
    _osd->setColourKey(_vsrc->colourKey());
    if (dev) {
        kdDebug() << "Device set to: " << dev->device() << endl;
        _cfg->prevDev = dev->device();
    }

    emit deviceChanged( _vsrc );
    _view->repaint();
}


void QtVision::startCapture()
{
    kdDebug() << "QtVision::startCapture()" << endl;

    if (!_vsrc)
        return;
    
    if (_cfg->loadTuning(_vsrc->device(), _vsrc->source()) >= 0) {
        kdDebug() << "QTVision::startCapture() : Setting attributes" << endl;
        kdDebug() << "brightness = " << _cfg->brightness << " colour = " 
                  << _cfg->colour << " hue = " << _cfg->hue << " contrast = " 
                  << _cfg->contrast << endl;

        setBrightness(_cfg->brightness);
        setColour(_cfg->colour);
        setHue(_cfg->hue);
        setContrast(_cfg->contrast);
        setWhiteness(_cfg->whiteness);

        if (_cs->fileName().isEmpty()) {
            if (_cfg->channelFile.isEmpty()) {
                // create a new Channel file.
                _cs->load();
                _cfg->channelFile = _cs->fileName();
            } else {
                // load the Channel file
                _cs->load(_cfg->channelFile);
            }
        } else { 
            if (_cs->fileName() != _cfg->channelFile && !_cfg->channelFile.isEmpty()) {
                // load a different Channel file
                _cs->load(_cfg->channelFile);
            }
        }
    }

    if (_cs->isEmpty()) {
        importDefaultChannels();
    } else if (_cfg->firstTime) {
        setChannel(_cs->channelAt(0));
    } else {
        Channel *x = _cs->channelNumber(_cfg->lastChannel);
        Channel *y = x;

        if (!x)
            x = _cs->channelAt(0);

        while (x && !x->enabled() && x != y)
            x = _cs->channelAfter(x);

        setChannel(x);
    }

    kdDebug() << "QtVision::startCapture() -- starting video now!" << endl;
    if (_vsrc->startVideo() != 0)
        kdDebug() << "QtVision::startCapture() - ERROR STARTING VIDEO!" << endl;
}


void QtVision::stopDevice()
{
    if ( _vsrc ) {
        setMuteVolume (true);
        _cfg->lastSource = _vsrc->source();
        _cfg->saveTuning(_vsrc->device(), _vsrc->source());
        _vsrc->stopVideo();
        delete _vsrc;
        _vsrc = 0;
        
        emit deviceChanged( _vsrc );
    }    
}


void QtVision::openChannelFile()
{
    QString p = KGlobal::dirs()->saveLocation("qtvision");
    QString fn = KFileDialog::getOpenFileName(p, QString("*"), _view, i18n("Select a Channel file..."));

    openChannelFile(fn);
}

void QtVision::importChannelFile()
{
    QString p = KGlobal::dirs()->saveLocation("qtvision");
    QString fn = KFileDialog::getOpenFileName(p, QString("*"), _view, i18n("Select a channel file..."));

    if (fn.isEmpty())
        return;

    ChannelStore tcs( this, 0 );
    if (tcs.load(fn)) {
        _cs->addChannels(tcs);
    }
}

void QtVision::openChannelFile(const QString &filename)
{
    if (filename.isEmpty())
        return;

    _cs->clear();
    
    if (_cs->load(filename)) {
        _cfg->channelFile = filename;
        kdDebug() << "QtVision::openChannelFile(" << filename << ")" << endl;
        Channel *x = _cs->channelNumber(_cfg->lastChannel);
        Channel *y = x;

        if (!x)
            x = _cs->channelAt(0);

        while (x && !x->enabled() && x != y)
            x = _cs->channelAfter(x);

        _prevChannel = -1;
        setChannel(x);
    }
}


bool QtVision::doMigration()
{
    KGlobal::dirs()->addResourceType("kwintv", "share/apps/kwintv");
    QString p = KGlobal::dirs()->saveLocation("kwintv");

    if (p.isEmpty())
      return false;

    p += "/default.ch";

    if (!QFile::exists(p))
      return false;

    if (KMessageBox::Yes !=
      KMessageBox::questionYesNo(NULL, 
          i18n("Migrate old KWinTV configuration?"),
          i18n("QtVision"))) {
      return false;
    }

    _cs->setName("");
    bool rc = importLegacyChannels();
    _cfg->channelFile = _cs->fileName();  // set to the default name
    return rc;
}


bool QtVision::importLegacyChannels()
{
    KGlobal::dirs()->addResourceType("kwintv", "share/apps/kwintv");

    QString p = KGlobal::dirs()->saveLocation("kwintv");

    if (p.isEmpty())
      return false;

    p += "/default.ch";

    if (!QFile::exists(p))
      return false;

    QString oldname = _cs->fileName();
    openChannelFile(p);
    _cs->setName(oldname);
    _cfg->channelFile = oldname;
    Channel *x = _cs->channelNumber(_cfg->lastChannel);
    Channel *y = x;

    if (!x)
        x = _cs->channelAt(0);

    while (x && !x->enabled() && x != y)
        x = _cs->channelAfter(x);

    _prevChannel = -1;
    setChannel(x);

    return true;
}


void QtVision::importDefaultChannels()
{
    ChannelImportDlg *dlg = new ChannelImportDlg(_view);
    dlg->setDriver(this);
    dlg->populateWithDefaults();
    int rc = dlg->exec();

    if (rc == QDialog::Accepted) {
        QString fn = dlg->selectedFile();
        if (!fn.isEmpty()) {
            QString oldname = _cs->fileName();
            _cs->clear();
            _cs->load(fn);
            _cs->setName(oldname);
            if (_cfg->channelFile.isEmpty())
                _cfg->channelFile = oldname;

            Channel *x = _cs->channelNumber(_cfg->lastChannel);
            Channel *y = x;
            
            if (!x)
                x = _cs->channelAt(0);

            while (x && !x->enabled() && x != y)
                x = _cs->channelAfter(x);
            
            _prevChannel = -1;
            setChannel(x);
        }
    }

    delete dlg;
}

QString QtVision::channelName() const
{
    return _chan->name();
}

int QtVision::channelNumber() const
{
    return _chan->number();
}


void QtVision::setChannel( Channel *channel )
{
    if (!channel)
        return;

    //kdDebug() << "QtVision::setChannel()" << endl;
    
    if (_chan)
      _prevChannel = _chan->number ();
    
    _chan = channel;
    
    _cfg->lastChannel = _chan->number();               
     
    kdDebug() << "QtVision::setChannel(): emit channel changed" << endl;
    emit channelChanged( _chan->number() );
    emit channelChanged( _chan->name() );
    emit channelChanged( _chan );
     
    if (_vsrc) {
        kdDebug() << "QtVision::setChannel() to frequency: " << _chan->freq() << endl;
        _osd->displayChannel(_chan->number(), _chan->name());
        
        if (_am && !_muted) {
            if (ChannelVolState.changeEventId == -1) {
                kdDebug() << "QTVision::setChannel(): Volume => left = "
                          << ChannelVolState.left << ", right = "
                          << ChannelVolState.right << endl;
                ChannelVolState.left = _am->volumeLeft();
                ChannelVolState.right = _am->volumeRight();
            }
            
            _am->setVolume (0, 0);
            ChannelVolState.changeEventId = startTimer(_cfg->volumeRestoreDelay);
        }
        
        _vsrc->setFrequency(_chan->freq());
    }
}


void QtVision::setChannel(int channel)
{
    kdDebug () << "QTVision::setChannel (int)" << endl;
    // Ignore request if the channel number
    if (_chan && _chan->number () == channel)
    {
        _prevChannel = channel;
        return;
    }
        
    if (_cs->channelNumber(channel))
        setChannel(_cs->channelNumber(channel));
    else {
        if (_chan) {
            // if the new channel is not valid, just repeat the original number
            // so that the LCD display knows what to show
            kdDebug() << "emitting channelChanged((int) " << _chan->number() << ")" << endl;
            emit channelChanged(_chan->number());
        }
    }
    
    return;
} // setChannel


void QtVision::channelUp()
{
    Channel *c = _cs->channelAfter(_chan);

    if (!c)
        return;

    // skip channels that the user has disabled
    while (!c->enabled() && c != _chan)
        c = _cs->channelAfter(c);
    setChannel( c );
}


void QtVision::channelDown()
{
    Channel *c = _cs->channelBefore(_chan);

    if (!c)
        return;

    // skip channels that the user has disabled
    while (!c->enabled() && c != _chan)
        c = _cs->channelBefore(c);
    setChannel( c );
}

void QtVision::previousChannel()
{
    if (_prevChannel != -1)
      setChannel (_prevChannel);
}

void QtVision::setVideoDesktop( bool on )
{
    if (!_vsrc || _quitting)
      return;

    QByteArray qba;
    QDataStream arg(qba, IO_WriteOnly);
    
    arg << (bool)true;
    bool rc = kapp->dcopClient()->send("kdesktop", "KDesktopIface", "setVRoot(bool)", qba);
    
    kdDebug() << "kdesktop setVRoot returned " << (rc ? "true" : "false") << endl;
    if (_vsrc->canVideoDesktop())
        _vsrc->setVideoDesktop(on);

    // FIXME: this is an ugly hack really.  It won't work with other
    //        desktops (vroots), and it's not the right place for
    //        this anyways.
    if (!on) {
      rc = kapp->dcopClient()->send("kdesktop", "KDesktopIface", "refresh()", qba);
      kdDebug() << "kdesktop refresh returned " << (rc ? "true" : "false") << endl;
    }
}

void QtVision::startVideo()
{
    _vsrc->startVideo();
}

void QtVision::stopVideo()
{
    _vsrc->stopVideo();
}

void QtVision::snapshot()
{
    _vsrc->grabStill( &grabPix );
    grabPix.save( "test.png", "PNG" );
//    KMessageBox::sorry(_view, i18n("Error grabbing image."), i18n("QtVision"));
}

void QtVision::settings()
{
    _viewmng->launchSettings( _view );
}


void QtVision::setTunerMode( int mode )
{
    _cfg->nps = mode;
    if (_vsrc && _vsrc->needsNorm())
        _vsrc->setNorm(mode);
}


void QtVision::volumeMute()
{
    _muted = !_muted;
    setMuteVolume (_muted);
    emit volumeMuted (_muted);
}

void QtVision::setMuteVolume (bool mute)
{
    if ( _am ) {
        _am->setMuted(mute);
        kdDebug() << "QtVision::setMuteVolume(): Mixer says volume is "
                  << (_am->muted() ? "Muted" : "Not Muted")
                  << endl;    
    }
    if ( _vsrc ) {
        _vsrc->setMuted(mute);
        kdDebug() << "QtVision::setMuteVolume(): Tuner says volume is "
                  << (_am->muted() ? "Muted" : "Not Muted")
                  << endl;    
    }
}

void QtVision::volumeUp() {
    setVolume(_am->volumeLeft()+1, _am->volumeRight()+1);
}

void QtVision::volumeDown() {
    setVolume(_am->volumeLeft()-1, _am->volumeRight()-1);
}

void QtVision::setVolume(int left, int right) {
    // Unmute, set the flag to unmute and emit
    // a volumeMuted signal to update the GUI
    if (_muted)
    {
      _muted = false;
      emit volumeMuted (_muted);
    }
    
    _am->setVolume(left, right);
    emit volumeChanged(_am->volumeLeft(), _am->volumeRight());
}

void QtVision::setVolume(int vol) {
    setVolume(vol, vol);
}

QtVisionView *QtVision::createScreen( QWidget *parent, const char *name )
{
    _view = new QtVisionView( parent, name ? name : "qtvision_screen" );
    // Init the OSD
    _osd = new OSDManager(this, _view);
    // Load the other misc plugins
    _mm = new MiscManager(this, _view);

    // Make sure the TV background is black (looks best)
    _view->setPaletteBackgroundColor( QColor( 0, 0, 0 ) );

    // Check the setting of "Fix Aspect Ratio" and apply it.
    // The "Aspect Ratio Mode" determines how the algorithm works.
    if ( _cfg->fixAR ) {
      _view->setFixedAspectRatio( ASPECT_RATIO_NORMAL, _cfg->ARmode );
    } else {
      _view->setFixedAspectRatio( ASPECT_RATIO_NONE, _cfg->ARmode );
    }

    connect(_view, SIGNAL(resized(int,int)), this, SLOT(viewResized(int,int)));
    connect(_view, SIGNAL(moved(int,int)), this, SLOT(viewMoved(int,int)));
    connect(_view, SIGNAL(channelUp()), this, SLOT(channelUp()));
    connect(_view, SIGNAL(channelDown()), this, SLOT(channelDown()));
    connect(_view, SIGNAL(numberKeyPressed(int)), this, SLOT(processNumberKeyEvent(int)));

    connect(this, SIGNAL(volumeChanged(int,int)), _osd, SLOT(displayVolume(int,int)));
    connect(this, SIGNAL(volumeMuted(bool)), _osd, SLOT(displayMuted(bool)));
    connect(this, SIGNAL(channelText(const QString &)), _osd, SLOT(displayMisc(const QString &)));

    // Connect the _viewmanager's signals to the slots to propagate configuration _changes
    connect(_viewmng, SIGNAL(setFixedAspectRatio(bool, int)), _view,
            SLOT(setFixedAspectRatio(bool, int)));

    return _view;
}


void QtVision::viewResized(int w, int h)
{
    if (_vsrc) {
        _vsrc->viewResized(w,h);
    }
}


void QtVision::viewMoved(int x, int y)
{
    if (_vsrc) {
        _vsrc->viewMoved(x,y);
    }
}


int QtVision::launchWizard()
{
    if ( !hasDevice() ) {
      selectDevice();
      if ( !hasDevice() )
          return QDialog::Rejected;
    }

    return _viewmng->launchWizard( _view );
}


void QtVision::setBrightness(int val)
{
    if (_vsrc) {
        _vsrc->setBrightness(val);
        _cfg->brightness = val;
    }
}

void QtVision::setColour(int val)
{
    if (_vsrc) {
        _vsrc->setColour(val);
        _cfg->colour = val;
    }
}

void QtVision::setHue(int val)
{
    if (_vsrc) {
        _vsrc->setHue(val);
        _cfg->hue = val;
    }
}

void QtVision::setContrast(int val)
{
    if (_vsrc) {
        _vsrc->setContrast(val);
        _cfg->contrast = val;
    }
}

void QtVision::setWhiteness(int val)
{
    if (_vsrc) {
        _vsrc->setWhiteness(val);
        _cfg->whiteness = val;
    }
}


int QtVision::brightness() {
    if (_vsrc) {
        return _vsrc->brightness();
    }
    return 0;
}


QColor QtVision::colourKey() {
    if (_vsrc) {
        return _vsrc->colourKey();
    }
    return QColor();
}


int QtVision::colour() {
    if (_vsrc) {
        return _vsrc->colour();
    }
    return 0;
}


int QtVision::hue() {
    if (_vsrc) {
        return _vsrc->hue();
    }
    return 0;
}


int QtVision::contrast() {
    if (_vsrc) {
        return _vsrc->contrast();
    }
    return 0;
}


int QtVision::whiteness() {
    if (_vsrc) {
        return _vsrc->whiteness();
    }
    return 0;
}


void QtVision::aboutToQuit() {
    _quitting = true;
}

void QtVision::timerEvent (QTimerEvent *ev) {
    if (ev) {
        if (ChannelVolState.changeEventId == ev->timerId ()) {
        
            kdDebug() << "QtVision::timerEvent: restoreVolume, event id = "
                      << ev->timerId () << ", Left volume = " << ChannelVolState.left
                      << ", Right volume = " << ChannelVolState.right
                      << endl;
                      
            // Restore the volume to whatever level it was before
            // change channel requests.
            if (_am)
                _am->setVolume (ChannelVolState.left, ChannelVolState.right);

            ChannelVolState.changeEventId = -1;
        }
        killTimer (ev->timerId());
    }
}

void QtVision::processNumberKeyEvent(int key)
{
    if (_mm->filterNumberKey(key))
        return;
    if (_keypresstimer->isActive())
        _keypresstimer->stop();

    // key == -1 means ENTER was pressed. Simply force a 
    // channel change and return...
    if (key == -1)
    {
        slotKeyPressTimeout ();
        return;
    }

    Q_ASSERT (_cs);

    // Get the highest channel number...
    Channel * ch = _cs->channelAt (_cs->count()-1);
    Q_ASSERT (ch);
    int maxChNum = ch->number();

    // For every '0' entered before the number lower the max channel by
    // 10 times
    int len = _number.length();
        
    for (int i = 0; i < len && _number[i] == '0'; i++)
        maxChNum /= 10;

    _number += QString::number(key);

    // If by entering another digit you can get a number lesser than
    // the highest channel number configured/detected, start a timer
    // (wait for that next keypress).
    // Otherwise, simply tune to the channel.
    if (_number.toInt() * 10 < maxChNum) {
        kdDebug() << "channelText(" << _number.rightJustify(3,'-') << ")" << endl;
        emit channelText(_number.rightJustify(3,'-'));
        _keypresstimer->start(2000, true);  // start the count-down timer
    } else {
        if (_number != "0")
            _keypresstimer->singleShot(0, this, SLOT(slotKeyPressTimeout()));
    } // else
}// processNumberKeyEvent


void QtVision::slotKeyPressTimeout()
{
    if (_number != "0") {
        kdDebug() << "QtVision: calling setChannel(" << _number << ")" << endl;
        setChannel(_number.toInt());
    }

    _number = "";
    return;
} // slotKeyPressTimeout
