/*****************************************************************************
 ** Class SubtitlesGui
 **
 **   Created :
 **        by : Varol Okan
 ** Copyright : (c) Varol Okan
 **   License : GPL v 2.0
 **
 ** This is a sub-project to 'Q' DVD-Author to handle the subtitles - tab
 ** of the main application
 **
 *****************************************************************************/
#ifdef QDVD_LINUX 
#include <unistd.h>
#endif

#include <qtable.h>
#include <qimage.h>
#include <qtimer.h>
#include <qlayout.h>
#include <qslider.h>
#include <qspinbox.h>
#include <qpainter.h>
#include <qlistbox.h>
#include <qfileinfo.h>
#include <qtextedit.h>
#include <qcombobox.h>
#include <qcheckbox.h>
#include <qlineedit.h>
#include <qlcdnumber.h>
#include <qtabwidget.h>
#include <qscrollview.h>
#include <qfiledialog.h>
#include <qdragobject.h>
#include <qpushbutton.h>
#include <qinputdialog.h>
#include <qcolordialog.h>
#include <qfontdatabase.h>

#include "utils.h"
#include "global.h"
#include "importsrt.h"
#include "importssa.h"
#include "exportsrt.h"
#include "exportssa.h"
#include "messagebox.h"
#include "qdvdauthor.h"
#include "subtitlesgui.h"
#include "listviewmedia.h"
#include "sourcefileentry.h"
#include "uidialogsubtitle.h"
#include "qplayer/mediacreator.h"

MediaLabel::MediaLabel ( SubtitlesGui *pSubtitlesGui, QWidget *pParent, const char *pName, WFlags flags )
  : QLabel ( pParent, pName, flags )
{
  setAcceptDrops ( true );
  setText ( "<FONT COLOR=ORANGE SIZE=+5><CENTER>Please drag<BR>a<BR>video source</CENTER></FONT>" );
  m_pSubtitlesGui = pSubtitlesGui;
}

MediaLabel::~MediaLabel ( )
{
}

void MediaLabel::dropEvent ( QDropEvent *pEvent ) 
{
  QImage  theImage;
  QString theText;

  if ( QImageDrag::decode( pEvent, theImage ) )
    m_pSubtitlesGui->insertDraggedObject ( pEvent, theImage );
  if ( QTextDrag::decode( pEvent, theText ) )
    m_pSubtitlesGui->insertDraggedText   ( pEvent, theText  );
}

void MediaLabel::dragEnterEvent( QDragEnterEvent *pEvent )
{
  pEvent->accept( QTextDrag::canDecode  ( pEvent ) ||
		  QImageDrag::canDecode ( pEvent )  );
}


PreviewLabel::PreviewLabel ( SubtitlesGui *pSubtitlesGui, QWidget *pParent, const char *pName, WFlags flags )
  : QLabel ( pParent, pName, flags )
{
  m_pSubtitlesGui = pSubtitlesGui;
}

PreviewLabel::~PreviewLabel ( )
{
}

void PreviewLabel::mouseDoubleClickEvent ( QMouseEvent * )
{
  m_pSubtitlesGui->previewDoubleClick ( );
}

void PreviewLabel::mousePressEvent ( QMouseEvent *pEvent )
{
  m_lastPos = pEvent->pos ( );
}

void PreviewLabel::mouseMoveEvent ( QMouseEvent *pEvent )
{
  if ( pEvent->state ( ) & LeftButton )  {
    QPoint pos = m_lastPos - pEvent->pos ( );
    m_pSubtitlesGui->scrollPreview ( pos.x ( ), pos.y ( ) );
    m_lastPos  = pEvent->pos ( );
    m_lastPos += pos;
  }
  else
    m_lastPos = pEvent->pos ( );
}


SubtitlesGui::SubtitlesGui ( QDVDAuthor *pDVDAuthor, QWidget *pParent, const char *pName, WFlags flags)
  : uiSubtitles ( pParent, pName, flags )
{
  m_pTableSubtitles->setShowGrid ( true );
  m_pTableSubtitles->setNumCols  ( 4 );
  m_pDVDAuthor      = pDVDAuthor;
  m_pLayout         = NULL;
  m_pDragLabel      = NULL;
  m_pSubtitles      = NULL;
  m_pSourceFileInfo = NULL;
  m_pMediaInterface = NULL;
  m_pSelectItem     = NULL;
  m_iVideoWidth     = 720;
  m_iVideoHeight    = 480;
  m_iOrigSubtitlesState    = (int)Subtitles::STATE_MANUAL;
  m_iCurrentSubtitleNumber = 0;
  m_iAlignement     = Qt::AlignLeft;
  m_strStartTime    = QString ("00:00:00.000");
  m_strEndTime      = QString ("00:00:00.000");
  initMe  ( );
}

SubtitlesGui::~SubtitlesGui ()
{
  // If the app is closed then we should store the info...
  releaseSourceFileInfo ( );

  if ( m_pDragLabel )
    delete m_pDragLabel;
}

void SubtitlesGui::initMe ( )
{
  m_pLayout    = new QGridLayout (       m_pFramePreview );
  m_pDragLabel = new MediaLabel  ( this, m_pFramePreview );

  m_foregroundColor.setRgb   ( m_pFrameFontColor      ->paletteBackgroundColor ( ).rgb ( ) );
  m_backgroundColor.setRgb   ( m_pFrameBackgroundColor->paletteBackgroundColor ( ).rgb ( ) );
  m_foregroundColor.setAlpha ( 0 );
  m_backgroundColor.setAlpha ( 0 );

  m_pLayout->addWidget ( m_pDragLabel, 0, 0 );
  m_pListViewSubtitles->setSelectionMode ( QListView::Single );

  m_pMediaInterface = MediaCreator::createPreferredWidget ( m_pFramePreview, "MediaWidget" );
  // This is take care of in the polish ( ) function for Xine and not necessary for MPlayer ...
  m_pMediaInterface->initMediaEngine    ( );
  m_pMediaInterface->getWidget ( )->setAcceptDrops ( true );
  m_pMediaInterface->getWidget ( )->hide( );
  m_pTableSubtitles->setNumRows  ( 0 );
  m_pEditTransparency->setText   ( "0.00" );
  m_pEditBGTransparency->setText ( "0.00" );
  QWidget *pTabTextFont = m_pTabWidget->page ( 3 );
  if ( pTabTextFont )
       m_pTabWidget->setTabEnabled ( pTabTextFont, false );

  QGridLayout *pLayout;
  uint iFlags = 0;
#if (QT_VERSION > 0x0301FF)
  iFlags = Qt::WNoAutoErase;
#else
  iFlags = Qt::WPaintClever;
#endif

  pLayout       = new QGridLayout  ( m_pLabelPreview, 1, 1, 2, 2, "pFramePreviewLayout");
  m_pScrollView = new QScrollView  ( m_pLabelPreview, "m_pScrollView", iFlags );
  m_pPreview    = new PreviewLabel ( this, m_pScrollView,  "pPreview", iFlags );
  m_pScrollView->addChild ( m_pPreview );
  m_pPreview->resize      (  720, 480  );
  m_pPreview->setPaletteBackgroundColor ( m_pLabelPreview->paletteBackgroundColor ( ) );
  pLayout->addWidget      ( m_pScrollView, 0, 0 );
  m_enPreviewMode = ModeFitWindow; //ModeScroll;

  // Next we init the font selection...
  QFontDatabase database;
  QStringList listFonts = database.families();
  m_pListFonts->insertStringList(listFonts);
  // Next we search for a good starting font ...
  uint t, iIndex;
  QString fontName;
  for (iIndex=0;iIndex<m_pListFonts->count();iIndex++)	{
    fontName = m_pListFonts->text(iIndex);
    if (fontName == QString ("Arial"))
      break;
    else if (fontName == QString ("Courier"))
      break;
    else if (fontName == QString ("Times New Roman"))
      break;
    else if (fontName == QString ("Times"))
      break;
    else if (fontName == QString ("Nimbus Sans L"))
      break;
    else if (fontName == QString ("Sans Serif"))
      break;
  }
  if ( iIndex < listFonts.count ( ) )
    fontName = m_pListFonts->text(iIndex);
  else
    fontName = m_pListFonts->text( 0 );

  m_pEditX->setText(  "0"  );
  m_pEditY->setText( "350" );
  m_pEditWidth->setText  ( QString ( "%1" ).arg ( m_iVideoWidth  ) );
  m_pEditHeight->setText ( QString ( "%1" ).arg ( m_iVideoHeight ) );

  QStringList listStyles = database.styles (   fontName );
  m_pComboFontStyle->insertStringList      ( listStyles );

  iIndex = 0;
  for ( t=0; t<listStyles.count ( ); t++ )  {
    if ( listStyles[t].find ( "bold", 0, FALSE ) > -1 )  {
      iIndex = t;
      break;
    }
  }
  QString styleName = m_pComboFontStyle->text ( iIndex );
  m_pComboFontStyle->setCurrentItem ( iIndex );

  // Here we get the sizes of the font.
  QValueList<int> listSizes = database.pointSizes ( fontName );
  if ( listSizes.isEmpty ( ) )  {
    listSizes = database.smoothSizes ( fontName, styleName );
    if ( listSizes.isEmpty ( ) )  {
      listSizes = database.standardSizes ( );
    }
  }
  // So lets say we can set the fontFamily at least ...
  m_pListFonts->setCurrentItem(iIndex);
  // And here we take care of the FontSize ...
  iIndex = 0;
  for (t=0;t<listSizes.count();t++)	{
    m_pComboFontSizes->insertItem (QString ("%1").arg(listSizes[t]));
    if (listSizes[t] < 29)	// Lets get at least a nice big raedable size
      iIndex = t;
  }
  m_pComboFontSizes->setCurrentItem (iIndex);

  m_pTextEdit->setTextFormat ( PlainText );
  m_pButtonFit->setOn        (  true );
  m_pEditWidth->setEnabled   ( false );
  m_pEditHeight->setEnabled  ( false );

  // Finally we set up the callback routines ...
  connect ( m_pEditX,            SIGNAL ( lostFocus    ( ) ), this, SLOT( slotRenderPreview ( ) ) );
  connect ( m_pEditY,            SIGNAL ( lostFocus    ( ) ), this, SLOT( slotRenderPreview ( ) ) );
  connect ( m_pEditWidth,        SIGNAL ( lostFocus    ( ) ), this, SLOT( slotRenderPreview ( ) ) );
  connect ( m_pEditHeight,       SIGNAL ( lostFocus    ( ) ), this, SLOT( slotRenderPreview ( ) ) );

  connect ( m_pListFonts,        SIGNAL ( highlighted (int)), this, SLOT( slotFontFamilyChanged ( int ) ) );
  connect ( m_pComboFontStyle,   SIGNAL ( activated   (int)), this, SLOT( slotFontStyleChanged  ( int ) ) );
  connect ( m_pComboFontSizes,   SIGNAL ( activated   (int)), this, SLOT( slotFontSizeChanged   ( int ) ) );
  connect ( m_pButtonLeft,       SIGNAL ( toggled    (bool)), this, SLOT( slotLeft     ( bool ) ) );
  connect ( m_pButtonCenter,     SIGNAL ( toggled    (bool)), this, SLOT( slotCenter   ( bool ) ) );
  connect ( m_pButtonRight,      SIGNAL ( toggled    (bool)), this, SLOT( slotRight    ( bool ) ) );
  connect ( m_pButtonJustify,    SIGNAL ( toggled    (bool)), this, SLOT( slotJustify  ( bool ) ) );
  connect ( m_pButtonVTop,       SIGNAL ( toggled    (bool)), this, SLOT( slotVTop     ( bool ) ) );
  connect ( m_pButtonVCenter,    SIGNAL ( toggled    (bool)), this, SLOT( slotVCenter  ( bool ) ) );
  connect ( m_pButtonVBottom,    SIGNAL ( toggled    (bool)), this, SLOT( slotVBottom  ( bool ) ) );
  connect ( m_pButtonFit,        SIGNAL ( toggled    (bool)), this, SLOT( slotFit      ( bool ) ) );
  connect ( m_pMediaInterface,   SIGNAL ( signalNewPosition ( int, const QString & ) ), this, SLOT ( slotNewPosition( int, const QString & ) ) );
  connect ( m_pMediaInterface,   SIGNAL ( signalNewPosition ( long ) ),                 this, SLOT ( slotNewPosition( long ) ) );
  connect ( m_pButtonBackgroundColor,SIGNAL(clicked() ), this, SLOT ( slotBackgroundColor() ) );
  connect ( m_pButtonFontColor,  SIGNAL ( clicked ( ) ), this, SLOT ( slotFontColor     ( ) ) );
  connect ( m_pButtonCloseSource,SIGNAL ( clicked ( ) ), this, SLOT ( slotCloseSource   ( ) ) );
  connect ( m_pButtonFB,         SIGNAL ( clicked ( ) ), this, SLOT ( slotMediaFB       ( ) ) );
  connect ( m_pButtonBack,       SIGNAL ( clicked ( ) ), this, SLOT ( slotMediaBack     ( ) ) );
  connect ( m_pButtonStop,       SIGNAL ( clicked ( ) ), this, SLOT ( slotMediaStop     ( ) ) );
  connect ( m_pButtonPlay,       SIGNAL ( clicked ( ) ), this, SLOT ( slotMediaPlay     ( ) ) );
  connect ( m_pButtonPlayStop,   SIGNAL ( clicked ( ) ), this, SLOT ( slotMediaPlayStop ( ) ) );
  connect ( m_pButtonFF,         SIGNAL ( clicked ( ) ), this, SLOT ( slotMediaFF       ( ) ) );
  connect ( m_pButtonAddNew,     SIGNAL ( clicked ( ) ), this, SLOT ( slotAddNew        ( ) ) );
  connect ( m_pButtonStart,      SIGNAL ( clicked ( ) ), this, SLOT ( slotStart         ( ) ) );
  connect ( m_pButtonEnd,        SIGNAL ( clicked ( ) ), this, SLOT ( slotEnd           ( ) ) );
  connect ( m_pButtonImport,     SIGNAL ( clicked ( ) ), this, SLOT ( slotImport        ( ) ) );
  connect ( m_pButtonExport,     SIGNAL ( clicked ( ) ), this, SLOT ( slotExport        ( ) ) );
  connect ( m_pButtonClear,      SIGNAL ( clicked ( ) ), this, SLOT ( slotClear         ( ) ) );
  connect ( m_pButtonDelete,     SIGNAL ( clicked ( ) ), this, SLOT ( slotDelete        ( ) ) );
  connect ( m_pButtonDeleteLine, SIGNAL ( clicked ( ) ), this, SLOT ( slotDeleteLine    ( ) ) );
  connect ( m_pButtonChange,     SIGNAL ( clicked ( ) ), this, SLOT ( slotChange        ( ) ) );
  connect ( m_pButtonApplyAll,   SIGNAL ( clicked ( ) ), this, SLOT ( slotApplyToAll    ( ) ) );
  connect ( m_pButtonSearchText, SIGNAL ( clicked ( ) ), this, SLOT ( slotSearchText    ( ) ) );
  connect ( m_pButtonAddSubtitle,SIGNAL ( clicked ( ) ), this, SLOT ( slotAddSubtitle   ( ) ) );
  connect ( m_pCheckOutline,     SIGNAL ( toggled (bool)),this,SLOT ( slotOutline  ( bool ) ) );
  connect ( m_pCheckUnderline,   SIGNAL ( toggled (bool)),this,SLOT ( slotUnderline( bool ) ) );

  connect ( m_pListViewSubtitles,    SIGNAL ( selectionChanged ( QListViewItem * ) ),this, SLOT ( slotSubtitleChanged     ( QListViewItem * ) ) );
  connect ( m_pSliderVolume,         SIGNAL ( sliderMoved ( int ) ), this, SLOT ( slotVolumeChanged        ( int ) ) );
  connect ( m_pSliderTransparency,   SIGNAL ( sliderMoved ( int ) ), this, SLOT ( slotTransparencyChanged  ( int ) ) );
  connect ( m_pSliderBGTransparency, SIGNAL ( sliderMoved ( int ) ), this, SLOT ( slotBGTransparencyChanged( int ) ) );
  connect ( m_pSliderTransparency,   SIGNAL ( sliderReleased  ( ) ), this, SLOT ( slotRenderPreview        (     ) ) );
  connect ( m_pSliderBGTransparency, SIGNAL ( sliderReleased  ( ) ), this, SLOT ( slotRenderPreview        (     ) ) );
  connect ( m_pSliderPos,            SIGNAL ( sliderMoved ( int ) ), this, SLOT ( slotPositionChanged      ( int ) ) );
  connect ( m_pCheckTextBasedSubtitles,SIGNAL(    toggled ( bool) ), this, SLOT ( slotTextOnly             ( bool) ) );
  connect ( m_pTabWidget,   SIGNAL ( currentChanged ( QWidget * ) ), this, SLOT ( slotTabChanged     ( QWidget * ) ) );

  updateButtons ( );
  updateFont   ( 2 );  // Need m_iAlignement ...
}

void SubtitlesGui::updateButtons ()
{
  if ( m_pButtonLeft->isOn ( ) )
    m_pButtonLeft->setPixmap ( QPixmap ( ).fromMimeSource ( "text_cleft.png" ) );
  else
    m_pButtonLeft->setPixmap ( QPixmap ( ).fromMimeSource ( "text_left.png" ) );

  if ( m_pButtonCenter->isOn ( ) )
    m_pButtonCenter->setPixmap ( QPixmap ( ).fromMimeSource ( "text_ccenter.png" ) );
  else
    m_pButtonCenter->setPixmap ( QPixmap ( ).fromMimeSource ( "text_center.png" ) );

  if ( m_pButtonRight->isOn ( ) )
    m_pButtonRight->setPixmap ( QPixmap ( ).fromMimeSource ( "text_cright.png" ) );
  else
    m_pButtonRight->setPixmap ( QPixmap ( ).fromMimeSource ( "text_right.png" ) );

  if ( m_pButtonJustify->isOn ( ) )
    m_pButtonJustify->setPixmap ( QPixmap ( ).fromMimeSource ( "text_cjustify.png" ) );
  else
    m_pButtonJustify->setPixmap ( QPixmap ( ).fromMimeSource ( "text_justify.png" ) );

  if ( m_pButtonVTop->isOn ( ) )
    m_pButtonVTop->setPixmap ( QPixmap ( ).fromMimeSource ( "text_cvtop.png" ) );
  else
    m_pButtonVTop->setPixmap ( QPixmap ( ).fromMimeSource ( "text_vtop.png"  ) );

  if ( m_pButtonVCenter->isOn ( ) )
    m_pButtonVCenter->setPixmap ( QPixmap ( ).fromMimeSource ( "text_cvcenter.png" ) );
  else
    m_pButtonVCenter->setPixmap ( QPixmap ( ).fromMimeSource ( "text_vcenter.png" ) );

  if ( m_pButtonVBottom->isOn ( ) )
    m_pButtonVBottom->setPixmap ( QPixmap ( ).fromMimeSource ( "text_cvbottom.png" ) );
  else
    m_pButtonVBottom->setPixmap ( QPixmap ( ).fromMimeSource ( "text_vbottom.png" ) );

  if ( m_pButtonFit->isOn ( ) )
    m_pButtonFit->setPixmap ( QPixmap ( ).fromMimeSource ( "text_cfit.png" ) );
  else
    m_pButtonFit->setPixmap ( QPixmap ( ).fromMimeSource ( "text_fit.png" ) );
}

bool SubtitlesGui::getSubtitleRect ( QRect &rect )
{
  int  x, y, w, h;
  bool bOkay;
  x = m_pEditX->text ( ).toInt ( &bOkay );
  if ( ! bOkay )
    x  = 0;
  y = m_pEditY->text ( ).toInt ( &bOkay );
  if ( ! bOkay )
    y  = 0;
  w = m_pEditWidth->text ( ).toInt ( &bOkay );
  if ( ! m_pEditWidth->isEnabled ( ) || ! bOkay )
    w  = m_iVideoWidth;
  h = m_pEditHeight->text ( ).toInt ( &bOkay );
  if ( ! m_pEditHeight->isEnabled ( ) || ! bOkay )
    h  = m_iVideoHeight;
  rect = QRect ( x, y, w, h );

  // return if the values were set by the user
  return ( ( x != 0 ) || ( y != 0 ) || ( w != m_iVideoWidth ) || ( h != m_iVideoHeight ) );
}

void SubtitlesGui::slotRenderPreview ( )
{
  QRect rect;
  getSubtitleRect ( rect );
  if ( rect.x ( ) >= m_iVideoWidth )  {
    m_pEditX->setText  ( QString ( "%1" ).arg ( m_iVideoWidth - 40 ) );
    rect.setX ( m_iVideoWidth - 40 );
  }
  if ( rect.y ( ) >= m_iVideoHeight )  {
    m_pEditY->setText  ( QString ( "%1" ).arg ( m_iVideoHeight - 40 ) );
    rect.setY ( m_iVideoHeight - 40 );
  }

  if ( rect.x ( ) + rect.width  ( ) > m_iVideoWidth  )
    m_pEditWidth->setText  ( QString ( "%1" ).arg ( m_iVideoWidth  - rect.x ( ) ) );
  if ( rect.y ( ) + rect.height ( ) > m_iVideoHeight )
    m_pEditHeight->setText ( QString ( "%1" ).arg ( m_iVideoHeight - rect.y ( ) ) );
  renderPreview ( );
}

void SubtitlesGui::renderPreview ( )
{
  if ( m_pCheckTextBasedSubtitles->isChecked ( ) )  {
    // Note: the Geo-tab is grayed out if Text Based Subtitles are selected. So this won't be seen.
    m_pLabelPreview->setText ( "Can't render Preview for Text based Subtitles." );
    return;
  }

  int t, j, iWidth, iHeight;

  QPainter thePainter;
  QRect    subtitleRect, boundingRect;
  getSubtitleRect  ( subtitleRect );
  iWidth  = subtitleRect.width  ( );
  iHeight = subtitleRect.height ( );

  QImage   theImage;
  QString  qsText  ( "ABC abc" );

  QPixmap  preview ( iWidth, iHeight );
  Utils    theUtils;
  QRgb     theColor, colors[ MAX_SUBTITLE_COLORS ];
  Rgba     subColors[ MAX_SUBTITLE_COLORS ];

  QFont     font  = getFont ( );
  int  iFontSize  = font.pointSize ( );
  if ( iFontSize == -1 ) {
       iFontSize  = font.pixelSize ( );
       if ( iFontSize == -1 )
            iFontSize =  24;
  }
  iFontSize *= 3;

  bool   bFit     = m_pButtonFit  ->isOn ( );
  int    iOutline = m_pEditOutline->text ( ).toInt   ( );
  if ( ( m_pEditBGTransparency->text     ( ).toFloat ( ) > 0.99999 ) || ( ! m_pCheckOutline->isChecked ( ) ) )
         iOutline = 0;

  subColors[0] = m_backgroundColor;
  subColors[1] = m_foregroundColor;
  subColors[2] = Rgba ( START_SELECTED_COLOR );

  // Now we do some magic with colors ...
  // we will set the Background Color to be completely GREEN
  // and we set the foreground color to be completely RED
  // Then we do the drawing
  // After the drawing has been done we wll reduce the colors in the palette to MAX_SUBTITLE_COLORS (4)
  // Lastly we will replace the RED VALUES with the actual requested foreground color.
  // We will use the GREEN color as the transparency value for the color.
  // Note: color0 = background / color1 actual foreground / 
  //       color[2 .. MAX_SUBTITLE_COLORS] = fading foreground to background with delta transparency
  colors[0] = 0x0000FF00; // background
  colors[1] = 0x00FF0000; // foreground

  int   iMaxColors = MAX_SUBTITLE_COLORS - 2;
  float fDelta   = (float)0xFF / (iMaxColors+1);
  int   iBGRed, iBGGreen, iBGBlue, iRed, iGreen, iBlue, iTransparency;
  for ( t=0;t<iMaxColors;t++ ) {
    iGreen  = (int)((t+1) * fDelta);
    iRed    = 255 - iGreen;
    colors[t+2] = ( iRed << 16 ) + ( iGreen << 8 );
  }

  QPen thePen ( colors[1], 2, Qt::DashDotLine );
  int  iDiameter = iOutline*2 + 1;
  QImage theBrush;
  if ( iOutline > 0 ) {
    // First we need to create a brush to follow ...
    QPixmap  createCircle ( iDiameter, iDiameter ); //, 1 ); // monochrome pixmap
    QPainter circlePainter;
    QPen     circlePen  ( colors[1], 1, Qt::SolidLine );
    circlePainter.begin ( &createCircle ); {
      createCircle.fill ( colors[0] );
      circlePainter.setPen   ( circlePen );
      circlePainter.setBrush ( QBrush ( colors[1] ) );
      circlePainter.drawEllipse ( 0, 0, iDiameter, iDiameter );
    } circlePainter.end ( );
    theBrush = createCircle.convertToImage ( );
    // Then we reduce the colors to the max avail color space.
    theUtils.reduceColors ( theBrush, 2, (QRgb *)&colors );
  }

  // First we should fill the drawing board with the propper background  color.
  QPixmap theDrawingBoard ( iWidth, iHeight );
  thePainter.begin ( &theDrawingBoard  ); {
    theDrawingBoard.fill( colors[0] );
    thePainter.setPen   ( thePen );
    thePainter.setBrush ( QBrush ( colors[0] ) );
    thePainter.setFont  ( font );

    // Here we draw onto the drawing board
    QRect temp ( 0, 0, iWidth, iHeight );
    thePainter.drawText ( temp, Qt::DontClip | Qt::WordBreak | m_iAlignement, qsText, -1, &boundingRect );

    int x, y, w, h;

    x = 0;
    y = 0;
    w = subtitleRect.width  ( ); // should be iWidth
    h = subtitleRect.height ( ); // should be iHeight
    // We should always adjust the height
    if ( bFit )  {
      x = boundingRect.x      ( ) - iOutline;
      y = boundingRect.y      ( ) - iOutline;
      w = boundingRect.width  ( ) + 2 * iOutline;
      h = boundingRect.height ( ) + 2 * iOutline;
      if ( x <  0 )       x = 0;
      if ( y <  0 )       y = 0;
      if ( w >= iWidth  ) w = iWidth -1;
      if ( h >= iHeight ) h = iHeight-1;
      subtitleRect = QRect ( x + subtitleRect.x ( ), y + subtitleRect.y ( ), w, h );
    }
//printf ( "%s::%d  <%s> w<%d> h<%d> subtitleRect<%d,%d x %d,%d> vs boundingRect<%d,%d x %d,%d> vs actual<%d,%d x %d,%d>\n", __FUNCTION__, __LINE__, qsText.ascii ( ), iWidth, iHeight, subtitleRect.x ( ), subtitleRect.y ( ), subtitleRect.width ( ), subtitleRect.height ( ), boundingRect.x ( ), boundingRect.y ( ), boundingRect.width ( ), boundingRect.height ( ), x, y, w, h );

    // create new dimensioned pixmap
    QPixmap thePixmap = QPixmap ( w, h );
#if ( QT_VERSION > 0x0301FF )
    copyBlt ( &thePixmap, 0, 0, &theDrawingBoard, x, y, w, h );
#else
    bitBlt  ( &thePixmap, 0, 0, &theDrawingBoard, x, y, w, h, Qt::CopyROP);
#endif
    theImage = thePixmap.convertToImage ( );
  }  thePainter.end ( );
  // Enable transparency ...
  theImage.setAlphaBuffer ( true );

  // Then we reduce the colors to the max avail color space.
  theUtils.reduceColors ( theImage, MAX_SUBTITLE_COLORS, (QRgb *)&colors );

  // next we generate the backround color ...
  theColor = subColors[0].rgb( ) & 0x00FFFFFF;
  iBGRed   = qRed   ( theColor );
  iBGGreen = qGreen ( theColor );
  iBGBlue  = qBlue  ( theColor );
  theImage.setColor ( 0, subColors[0].rgb ( ) );

  // and then the rest of the colors
  theColor = subColors[1].rgb( ) & 0x00FFFFFF;
  iRed     = qRed   ( theColor );
  iGreen   = qGreen ( theColor );
  iBlue    = qBlue  ( theColor );

  // Here we'll blend the max 4 colors for the subtitles
  for ( j=1; j<MAX_SUBTITLE_COLORS; j++ ) {
    int iDelta, r, g, b;
    iTransparency = 255 - (( colors[j] & 0xFF00 ) >> 8); // shift green to get the base transparency value
    // which must be added to the multiplied by the user defined transparency
    fDelta = (float)(255 - subColors[j].alpha ( ) ) / 0xFF;
    iTransparency = (int)( fDelta * (255-iTransparency ) ) + iTransparency;

    iDelta = ( (colors[j] & 0xFF0000 ) >> 16 );
    fDelta = (float)(0xFF - iDelta) / 0xFF;
    r = iRed   + (int)( ( iBGRed   - iRed   ) * fDelta );
    g = iGreen + (int)( ( iBGGreen - iGreen ) * fDelta );
    b = iBlue  + (int)( ( iBGBlue  - iBlue  ) * fDelta );

    theColor  = qRgba ( r, g, b, iTransparency );
    theImage.setColor ( j, theColor );
  }

  if ( iOutline > 0 ) {
    // Next is to inclrease the number of colors to 4
    theImage.setNumColors ( 4 );
    //theImage.setColor ( 3, 0xFF101010 ); // FF == Opaque // 00=Transparent
    theImage.setColor ( 0, 0x00000000 );
    theImage.setColor ( 3, subColors[0].rgb ( ) ); //real deal ...
    // Okay, we have outline enabled which means we should replace all background color with either 
    // transparency or with the pixelcolor of the backdrop or with the pixel color of the generated subtitle.
    int w, h, x, y, xb, yb, brushX, brushY, idx;
    w = theImage.width  ( );
    h = theImage.height ( );

    int pIdx;
    for ( x=0; x<w; x++ ) {
      for ( y=0; y<h; y++ ) { // Image x, and y ...
        // here we take m_iOutline number of pixels before and after an set them to the fourth color.
        pIdx = theImage.pixelIndex ( x, y );
        if ( ( pIdx == 1 ) || ( pIdx == 2 ) ) { // not background
          // So we should underlay the brush ...
          for ( yb=0; yb<iDiameter; yb++ ) { // copy brush over ...
            brushY = y - iOutline + yb;
            if ( ( brushY < 0 ) || ( brushY >= h ) )  // out of bounds
              continue;
            for ( xb=0; xb<iDiameter; xb++ ) {
              brushX = x - iOutline + xb; 
              if ( ( brushX < 0 ) || ( brushX >= w ) ) // out of bounds
                continue;
              idx = theImage.pixelIndex ( brushX, brushY );
              if ( ( idx == 0 ) && ( theBrush.pixelIndex ( xb, yb ) == 1 ) )
                theImage.setPixel   ( brushX, brushY, 3 );
            }
          }
        }
      }
    }
  }

  displayPreview ( theImage, subtitleRect );
}

void SubtitlesGui::displayPreview ( QImage &theSubtitle, QRect &subtitleRect )
{
  QImage  imgPreview;
  QPixmap preview;
  int dx, dy, iWidth, iHeight;
  float fScaleX, fScaleY;

  dx      = subtitleRect.x      ( );
  dy      = subtitleRect.y      ( );
  iWidth  = subtitleRect.width  ( );
  iHeight = subtitleRect.height ( );
  fScaleX = fScaleY = 2.0;

  // Next we get the default.jpg from mimeSource
  imgPreview = QImage::fromMimeSource   ( "default.jpg" ).copy ( );
  if ( m_enPreviewMode == ModeScroll )  {
    fScaleX = fScaleY = 1.0;
    imgPreview = imgPreview.smoothScale ( m_iVideoWidth, m_iVideoHeight );
  }
  else if ( m_enPreviewMode == ModeHalfScroll )   {
    fScaleX = fScaleY = 0.5;
    int iW = (int)( fScaleX * m_iVideoWidth  );
    int iH = (int)( fScaleY * m_iVideoHeight );
    theSubtitle = theSubtitle.smoothScale ( (int)(fScaleX * theSubtitle.width ( ) ), (int)(fScaleY * theSubtitle.height ( ) ) );
    if ( ( imgPreview.width ( ) != iW ) || ( imgPreview.height ( ) != iH ) )
           imgPreview = imgPreview.smoothScale ( iW,  iH );
  }
  else if ( m_enPreviewMode == ModeFitWindow )   {
    // In this part, fScale has to be the ration of the defImgRes to the videoRes
    // bc bitBlt copies the subtitle to the full sized defImg
    fScaleX = (float)imgPreview.width  ( ) / m_iVideoWidth;
    fScaleY = (float)imgPreview.height ( ) / m_iVideoHeight;
    theSubtitle = theSubtitle.smoothScale ( (int)(fScaleX * iWidth), (int)(fScaleY * iHeight) );
  }

  bitBlt ( &imgPreview, (int)(dx * fScaleX), (int)(dy * fScaleY), &theSubtitle );

  if ( m_enPreviewMode == ModeFitWindow )
    imgPreview = imgPreview.smoothScale ( m_pScrollView->width ( ) - 6, m_pScrollView->height ( ) - 6, QImage::ScaleMin );

  preview.convertFromImage ( imgPreview );
  m_pPreview->setPixmap    (    preview );
}

void SubtitlesGui::previewDoubleClick ( )
{
  if ( m_enPreviewMode == ModeFitWindow )
       m_enPreviewMode  = ModeHalfScroll;
  else if ( m_enPreviewMode == ModeHalfScroll )
       m_enPreviewMode  = ModeScroll;
  else
       m_enPreviewMode  = ModeFitWindow;
  renderPreview ( );
}

void SubtitlesGui::scrollPreview ( int iDeltaX, int iDeltaY )
{
  m_pScrollView->scrollBy ( iDeltaX, iDeltaY );
}

bool SubtitlesGui::event ( QEvent *pEvent )
{
  //F1 = key<4144> == Qt::Key_F1
  //printf ( "Event<%d>\n", pEvent->type ( ) );
  if ( pEvent->type() == QEvent::KeyPress ) {
    QKeyEvent *pKeyEvent = (QKeyEvent *)pEvent;
    if ( pKeyEvent->key ( ) == Qt::Key_F1 )
      printf ( "<%s> = key<%d> ascii<%d>\n", pKeyEvent->text ( ).ascii(), pKeyEvent->key ( ), pKeyEvent->ascii() );
  }
  return uiSubtitles::event ( pEvent );
}

void SubtitlesGui::resetMediaWidget ()
{
  if ( m_pDragLabel ) {
    int iWidth, iHeight;
    iWidth  = m_pFramePreview->geometry ().width();
    iHeight = m_pFramePreview->geometry ().height();

    m_pDragLabel->show ( );
    m_pDragLabel->setGeometry ( 0, 0, iWidth, iHeight );
    m_pDragLabel->setText  ( "<FONT COLOR=ORANGE SIZE=+5><CENTER>Please drag<BR>a<BR>video source</CENTER></FONT>" );
    m_pTabSubtitles->setTabLabel ( m_pTabSubtitles->page ( 0 ), "No source selected." );
  }
}

///////////////////////////////////////////////////////////
//
// signal/slot handler
//
//////////////////////////////////////////////////////////
void SubtitlesGui::slotAddSubtitle ( )
{
  addSubtitle ( QString::null );
}

bool SubtitlesGui::addSubtitle ( QString qsFileName )
{
  int  t,  iValue, iFirstNewSubtitleNumber;
  QString  qsText, qsLang, qsCode;
  Utils theUtils;
  SourceFileEntry *pEntry = NULL;

  uiDialogSubtitle theDialog;
  t = 0; qsLang = "something";
  theDialog.m_pComboLanguage->clear ( );

  iFirstNewSubtitleNumber = 0;
  if ( m_pSourceFileInfo ) {
    for ( t=0; t<MAX_SUBTITLES; t++ ) {
      if ( ! m_pSourceFileInfo->arraySubtitles [ t ] ) 
        break;
    }
    iFirstNewSubtitleNumber = t;
  }
  //  theDialog.m_pComboLanguage->insertItem ( tr ( "Language" ) );
  while ( ! qsLang.isEmpty ( ) ) {
    qsLang = theUtils.iso639 (  qsText,  false,  t++ );
    theDialog.m_pComboLanguage->insertItem ( qsLang );
  }
  theDialog.m_pComboLanguage->setCurrentText ( "English" );
  theDialog.m_pSpinboxNumber->setValue ( iFirstNewSubtitleNumber );

  if ( theDialog.exec ( ) == QDialog::Rejected )
    return false;

  iValue = theDialog.m_pSpinboxNumber->value ( );
  if ( m_pSourceFileInfo ) {
    if ( ! sanityCheckSubtitleTrack ( iValue ) )
      return false;
    if ( m_pSourceFileInfo->arraySubtitles[iValue] ) {
      QFileInfo fileInfo ( m_pSourceFileInfo->qsFileName );
      // the subtitle already exists in the sourcefileinfo.
      if ( MessageBox::question ( this, tr ( "Subtitle exists" ), tr ( "Warning, the subtitle number %1 exists already.\nDo you want to remove the current subtitle %2 from the file %3 ?" ).arg ( iValue ).arg ( iValue ).arg ( fileInfo.fileName ( ) ), 
          QMessageBox::Yes, QMessageBox::No ) == QMessageBox::No )
        return false;
    }
    qsLang = theDialog.m_pComboLanguage->currentText ( );
    qsCode = theUtils.iso639 ( qsLang, true );

    // First we attach the new subtitle - object to the SourceFileInfo ...
    if ( m_pSourceFileInfo->arraySubtitles[iValue] )
      delete m_pSourceFileInfo->arraySubtitles[iValue];

    m_pSourceFileInfo->arraySubtitles [ iValue ] = new Subtitles ( m_iVideoWidth, m_iVideoHeight );
    m_pSourceFileInfo->arraySubtitles [ iValue ]->m_iSubtitleNumber = iValue;
    m_pSourceFileInfo->arraySubtitles [ iValue ]->m_qsFileName      = qsFileName;
    m_pSourceFileInfo->arraySubtitles [ iValue ]->m_qsIso639        = qsCode;
    // And finally also set the SourceFileEntry ( which is the parent )
    pEntry = sourceFileEntry ( m_pSourceFileInfo );
    if ( pEntry ) {
      pEntry->arraySubtitleEntries [ iValue ].m_iSubtitleNumber = iValue;
      pEntry->arraySubtitleEntries [ iValue ].m_qsIso639        = qsCode;
    }
    m_iCurrentSubtitleNumber = iValue;

    if ( m_pSubtitles )
      delete m_pSubtitles;
    m_pSubtitles = NULL;
    initNewSourceFileInfo ( true );
    // Finally we should highlight the newly added Item ...
    QListViewItem *pItem = m_pListViewSubtitles->firstChild ( );
    while ( pItem ) {
      if ( pItem->text( 0 ).toInt ( ) == iValue ) {
        m_pSelectItem = pItem;
        QTimer::singleShot ( 10, this, SLOT ( slotSetSelectedItem ( ) ) );
        break;
      }
      pItem = pItem->nextSibling ( );
    }
  }

  return true;
}

bool SubtitlesGui::sanityCheckSubtitleTrack ( int &iSubtitle )
{
  // This function will check the sourceFileEntry and all attached 
  // SourceFileInfos if the ubtitle track is aready in use.
  // If not this function will return and leave iSubtitle unchanged.
  // If it is in use the subtitle number will be changed.
  SourceFileEntry *pEntry = sourceFileEntry ( m_pSourceFileInfo );
  SourceFileInfo  *pInfo;
  int t, iNewSubtitle;
  bool bFound = false;
  if ( pEntry ) {
    if ( pEntry->arraySubtitleEntries[ iSubtitle ].m_iSubtitleNumber == -1 )
      return true;  // All is well
    // The next step is to ensure that the current SourceFileInfo is 
    // not the only one using this Subtitle
    for ( t=0; t<(int)pEntry->listFileInfos.count ( ); t++ ) {
      pInfo = pEntry->listFileInfos[t];
      if ( pInfo == m_pSourceFileInfo )
	continue;
      if ( pInfo->arraySubtitles [ iSubtitle ] ) {
	bFound = true;
	break; // exit for - loop
      }
    }
    if ( !bFound )
      return true; // Okay the current subtitle is only used by the current SourceFileInfo ... No harm.

    for ( iNewSubtitle=0; iNewSubtitle<MAX_SUBTITLES; iNewSubtitle++ ) {
      if ( pEntry->arraySubtitleEntries[iNewSubtitle].m_iSubtitleNumber == -1 ) {
	break;
      }
    }
    if ( iNewSubtitle>MAX_SUBTITLES-1 ) {
      MessageBox::warning ( this, tr ( "Too many Subtitles." ), tr ( "Too many subtitles for the SourceFileEntry\n%1\nPlease remove a subtitle track first before trying to add a new one." ).arg ( pEntry->qsDisplayName ) );
      return false;
    }
    if ( MessageBox::question ( this, tr ( "Subtitle track %1 already in use." ).arg ( iSubtitle ), 
	   tr ( "Subtitle track %1 already in use.\nProposing track %2 instead." ).arg ( iSubtitle ).arg ( iNewSubtitle ),
	   QMessageBox::Ok, QMessageBox::Cancel) == QMessageBox::Ok ) {
      // Okay at this point we can change the subtitle number
      iSubtitle = iNewSubtitle;
      return true;
    }
  }
  return false;
}

void SubtitlesGui::slotSetSelectedItem ( )
{
  m_pListViewSubtitles->clearSelection ( );
  if ( m_pSelectItem ) {
    m_pSelectItem->setSelected ( true );
    m_pListViewSubtitles->setCurrentItem ( m_pSelectItem );
  }
  m_pSelectItem = NULL;
}

SourceFileEntry *SubtitlesGui::sourceFileEntry ( SourceFileInfo *pInfo )
{
  int t, i;
  SourceFileEntry *pEntry;
  if ( pInfo ) {
    for ( t=0;t<(int)m_pDVDAuthor->sourceFileCount ( );t++) {
      pEntry =  m_pDVDAuthor->sourceFileEntry ( t );
      for ( i=0; i<(int)pEntry->listFileInfos.count ( ); i++ ) {
	if ( pEntry->listFileInfos[i] == m_pSourceFileInfo )
	  return pEntry;
      }
    }
  }
  return NULL;
}

void SubtitlesGui::slotSubtitleChanged ( QListViewItem * )
{
  bool bOk;
  int  iIndex;
  SourceFileInfo *pTemp = m_pSourceFileInfo;
  QString qsText;

  QListViewItem *pItem = m_pListViewSubtitles->currentItem ( );
  qsText = pItem->text ( 0 );
  iIndex = qsText.toInt ( &bOk );
  if ( ( ! bOk ) || ( iIndex == m_iCurrentSubtitleNumber ) )
    return;

  releaseSourceFileInfo ( );
  // now that we stored the current subtitle, we can set the new values ...
  m_iCurrentSubtitleNumber = iIndex;
  m_pSourceFileInfo        = pTemp;

  // Check if no subtitle exists yet for this subtitle index, then let us create one.
  if ( m_pSourceFileInfo ) {
    if ( ! m_pSourceFileInfo->arraySubtitles [ m_iCurrentSubtitleNumber ] )
           m_pSourceFileInfo->arraySubtitles [ m_iCurrentSubtitleNumber ] = new Subtitles ( m_iVideoWidth, m_iVideoHeight );
    m_pSourceFileInfo->arraySubtitles [ m_iCurrentSubtitleNumber ]->m_iSubtitleNumber = m_iCurrentSubtitleNumber;
  }

  m_pTextEdit->setText  ( tr ( "Language changed" ) );
  initNewSourceFileInfo ( false );
}

void SubtitlesGui::slotNewPosition(int iPos, const QString &qsTime )
{
  // iPos [0 .. 65535]
  m_pSliderPos->setValue (iPos);
  m_strCurrentTime = qsTime.left ( 12 );
  m_pLCDNumberTime->display ( m_strCurrentTime );
}

void SubtitlesGui::slotNewPosition( long iTimeInMS )
{
  static uint iCurrentSubtitle = 0;
  static bool bCleared = false;
  uint t, iCounter;
  Subtitles::entry *pEntry;
  // Here we set the subtitle to the current one
  // Note: I tried to optimize this function for speed ...
  if ( m_pSubtitles ) {
    iCounter = m_pSubtitles->m_listOfSubtitles.count();
    for (t=iCurrentSubtitle;t<iCounter;t++) {
      pEntry = m_pSubtitles->m_listOfSubtitles[t];
      if ( ( iTimeInMS < pEntry->iTimeStop ) && ( iTimeInMS >= pEntry->iTimeStart ) )  {
	// found in time range
        if ( t != iCurrentSubtitle ) { // deon't need to redraw the same text over again
	  m_pTextEdit->setText ( pEntry->qsText );
	  m_pTextEdit->setAlignment ( m_iAlignement );
	  iCurrentSubtitle = t;
	  displayRow ( t );
	  bCleared = false;
        }
	return;
      }
      else if ( ( ! bCleared ) && ( iTimeInMS > m_pSubtitles->m_listOfSubtitles[ iCurrentSubtitle ]->iTimeStop ) ) {
	// clear the text if it is out of bound.
	m_pTextEdit->setText ( "" );
	m_pTableSubtitles->clearSelection ( );
	bCleared = true;
      }
      else if ( iTimeInMS < pEntry->iTimeStart )
      	break;
    } // could not find the entry in the first loop ...
    for (t=0;t<iCurrentSubtitle;t++) {
      pEntry = m_pSubtitles->m_listOfSubtitles[t];
      if ( ( iTimeInMS < pEntry->iTimeStop ) && ( iTimeInMS >= pEntry->iTimeStart ) )  {
        if ( t != iCurrentSubtitle ) {
	  m_pTextEdit->setText ( pEntry->qsText );
	  m_pTextEdit->setAlignment ( m_iAlignement );
	  bCleared = false;
	  iCurrentSubtitle = t;
	  displayRow ( t );
	}
	return;
      }
      else if ( ( ! bCleared ) && ( iTimeInMS > m_pSubtitles->m_listOfSubtitles[ iCurrentSubtitle ]->iTimeStop ) ) {
	bCleared = true;
	m_pTextEdit->setText ( "" );
	m_pTableSubtitles->clearSelection ( );
      }
      else if ( iTimeInMS < pEntry->iTimeStop )
	return;
    }
  }
}

void SubtitlesGui::slotCloseSource ()
{
  if ( m_pDragLabel )  {
    if ( ! m_pDragLabel->isVisible ( ) ) {
      // case we have dropped a movie and played at least a bit of it.
      int iWidth, iHeight;
      iWidth  = m_pFramePreview->geometry ( ).width ( );
      iHeight = m_pFramePreview->geometry ( ).height( );

      m_pMediaInterface->stop ( );
      m_pLayout->remove ( m_pMediaInterface->getWidget ( ) );
      m_pMediaInterface->getWidget( )->hide ( );

      //      resetMediaWidget      ( );
      m_pLayout->addWidget  ( m_pDragLabel, 0, 0 );
      //      releaseSourceFileInfo ( );
    }
    resetMediaWidget      ( );
    releaseSourceFileInfo ( );
    m_pListViewSubtitles->clear ( );
    //    else if ( m_pDragLabel->text ( ) != "No source selected." ) {
    //      // case we have dropped a movie but have not yet started playing him.
    //      resetMediaWidget      ( );
    //      releaseSourceFileInfo ( );
    //    }
  }
}

void SubtitlesGui::slotMediaFB ()
{
  if ( ( m_pMediaInterface ) && ( m_pSourceFileInfo ) )
    m_pMediaInterface->setSpeed ( 0.25 );
}

void SubtitlesGui::slotMediaBack ()
{
  if ( ( m_pMediaInterface ) && ( m_pSourceFileInfo ) )
    m_pMediaInterface->setSpeed ( 0.5 );
}

void SubtitlesGui::slotMediaStop ()
{
  if ( ( m_pMediaInterface ) && ( m_pSourceFileInfo ) ) 
    m_pMediaInterface->stop ( );
  m_pButtonStop->setPaletteBackgroundColor ( QColor ( "#F48A3E" ) );
  m_qsCurrentURL = QString();
}

void SubtitlesGui::slotMediaPause ()
{
  if ( ( m_pMediaInterface ) && ( m_pSourceFileInfo ) ) {
    m_pMediaInterface->pause    ( );
    if ( m_pMediaInterface->isPaused ( ) )
      m_pButtonStop->setEnabled (  true );
    else
      m_pButtonStop->setEnabled ( false );
  }
}

void SubtitlesGui::slotMediaPlay ()
{
  if ( ( m_pMediaInterface ) && ( m_pSourceFileInfo ) ) {
    // Need the info from the tabel in the structure for easier access ...
    createSubtitles ( );
    if ( m_qsCurrentURL == m_pSourceFileInfo->qsFileName ) {
      slotMediaPause ( );
      return;
    }

    m_qsCurrentURL = m_pSourceFileInfo->qsFileName;
    int iWidth, iHeight;
    QFileInfo fileInfo;
    QString qsFileName;
    iWidth  = m_pFramePreview->geometry ().width();
    iHeight = m_pFramePreview->geometry ().height();
    m_pLayout->remove           ( m_pDragLabel );
    m_pDragLabel->hide          ( );
    m_pMediaInterface->getWidget( )->show ( );
    m_pMediaInterface->getWidget( )->setGeometry ( 0, 0, iWidth, iHeight );

    m_pLayout->addWidget        ( m_pMediaInterface->getWidget (), 0, 0 );
    m_pMediaInterface->playMRL  ( m_pSourceFileInfo->qsFileName );
    fileInfo.setFile ( m_pSourceFileInfo->qsFileName );
    m_pTabSubtitles->setTabLabel ( m_pTabSubtitles->page ( 0 ), fileInfo.fileName () );
    m_pButtonStop->setEnabled ( false );
    m_pButtonStop->setPaletteBackgroundColor ( QColor ( "#ff2020" ) );
  }
}

void SubtitlesGui::slotMediaPlayStop ()
{
  if ( ( m_pMediaInterface ) && ( m_pSourceFileInfo ) ) {
    if ( ! m_pMediaInterface->isPlaying () )
      m_pMediaInterface->play ( );
    else if ( m_pMediaInterface->isPaused ( ) )
      slotMediaPause ( );
    QTimer::singleShot ( 5000, this, SLOT ( slotMediaPause ( ) ) );
  }
}

void SubtitlesGui::slotMediaFF ()
{
  if ( ( m_pMediaInterface ) && ( m_pSourceFileInfo ) )
    m_pMediaInterface->setSpeed ( 2.0 );
}

void SubtitlesGui::slotAddNew ()
{
  // This function will take the vlaues of m_pLCDNumberStart m_pLCDNumberEnd
  // and stuff it in the appropriate spot in the table.
  // Some sanity check are beeing made to prevent two entries at the same time.
  uint t;
  int   iRow = 0;
  long  iStartTime, iEndTime;
  QTime timeStart, timeEnd, nullTime;
  Subtitles::entry *pEntry, *pNewEntry, *pNextEntry = NULL;

  if ( m_pTextEdit->text ().length () < 2 )  {
    MessageBox::warning ( NULL, tr ( "No text" ), tr ( "Please enter text first."), QMessageBox::Ok, QMessageBox::NoButton );
    return;
  }

  timeStart = QTime::fromString ( m_strStartTime );
  timeEnd   = QTime::fromString ( m_strEndTime   );
  // first we should convert the times into mseconds ...
  iStartTime = nullTime.msecsTo ( timeStart );
  iEndTime   = nullTime.msecsTo ( timeEnd   );

  if ( iStartTime > iEndTime ) {
    long iTemp = iStartTime;
    iStartTime = iEndTime;
    iEndTime   = iTemp;
  }

  if ( ! m_pSubtitles )
    m_pSubtitles = new Subtitles ( m_iVideoWidth, m_iVideoHeight );

  for (t=0;t<m_pSubtitles->m_listOfSubtitles.count ();t++) {
    pEntry = m_pSubtitles->m_listOfSubtitles[t];
    iRow = t+1;

    if ( iStartTime >= pEntry->iTimeStart )
      continue;
    if ( t > 0 )
      pEntry = m_pSubtitles->m_listOfSubtitles[t-1];

    if ( ( iStartTime > pEntry->iTimeStart ) && ( iStartTime <= pEntry->iTimeStop   ) ) {
      // In this case. The new entry starts inside an already existing entry.
      //  ....[start] ....[newStart]....[end]... time ->

      // So we should change the current existing entry
      pEntry->iTimeStop  = iStartTime-1; // move the end before the start of the new entry ...
      if ( pEntry->iTimeStop < 0 )  // should never happen but ...
	pEntry->iTimeStop = 0;
      pEntry->qsTimeStop = m_pSubtitles->getStringFromTime ( pEntry->iTimeStop );
    }

    //    if ( t+1 < m_pSubtitles->listOfSubtitles.count () ) {
      pNextEntry =  m_pSubtitles->m_listOfSubtitles[t];
      if ( iEndTime >= pNextEntry->iTimeStart ) {
	// here we move the start of the next entry after the end of the new entry
	//  ....[end] ....[startNew]....[start]....[endNew]... time ->
	
	pNextEntry->iTimeStart   = iEndTime + 1;
	pNextEntry->qsTimeStart  = m_pSubtitles->getStringFromTime ( pNextEntry->iTimeStart );
	if ( pNextEntry->iTimeStart > pNextEntry->iTimeStop ) {
	  pNextEntry->iTimeStop  = pNextEntry->iTimeStart + 100; // make at least 100 mSecs 
	  pNextEntry->qsTimeStop = m_pSubtitles->getStringFromTime ( pNextEntry->iTimeStop );
	}
      }
      //    }
    // and exit the loop ...
    break;
  }
  // TODO: do the scaling until we are in normal teritory again 
  // I.e. until start < end.
  pNewEntry = new Subtitles::entry;
  pNewEntry->qsTimeStart = m_pSubtitles->getStringFromTime ( iStartTime );
  pNewEntry->qsTimeStop  = m_pSubtitles->getStringFromTime ( iEndTime   );
  pNewEntry->iTimeStart  = iStartTime;
  pNewEntry->iTimeStop   = iEndTime;
  pNewEntry->qsText      = m_pTextEdit->text ();

  QValueList<Subtitles::entry *>::iterator iter;
  iter = m_pSubtitles->m_listOfSubtitles.find ( pNextEntry );
  m_pSubtitles->m_listOfSubtitles.insert ( iter, pNewEntry );

  // Last is to fix the index ...
  for ( t=0;t< m_pSubtitles->m_listOfSubtitles.count ();t++)
    m_pSubtitles->m_listOfSubtitles[t]->iIndex = t;

  createTableEntries ( );

  // Oh and we should copy the end-time to the start-time
  m_pLCDNumberStart->display ( m_strEndTime );
  m_strStartTime = m_strEndTime;
}

void SubtitlesGui::slotStart ()
{
  m_pLCDNumberStart->display ( m_strCurrentTime );
  m_strStartTime = m_strCurrentTime;
}

void SubtitlesGui::slotEnd ()
{
  m_pLCDNumberEnd->display ( m_strCurrentTime );
  if ( ! m_pMediaInterface->isPaused ( ) )
    slotMediaPause ( );
  m_strEndTime = m_strCurrentTime;
}

void SubtitlesGui::slotImport ()
{
  uint t;
  Subtitles::entry *pEntry;
  QString qsImportFile = QFileDialog::getOpenFileName ( Global::qsCurrentPath, QObject::tr ( "Subtitle files (*.srt *.SRT *.ssa *.SSA *.ass *.ASS)"), NULL, QObject::tr ( "Open Subtitles File" ) );

  QFileInfo fileInfo ( qsImportFile );
  Global::qsCurrentPath = fileInfo.dirPath ( true );

  Import::Srt srtImporter;
  Import::Ssa ssaImporter;
  Import::BaseSubtitle *pImporter = &ssaImporter;
  if ( fileInfo.extension ( false ).lower ( ) == "srt" )
    pImporter = &srtImporter;

  if ( pImporter->readFile ( qsImportFile ) )  {
    // first we should store the current table in the subtitles
    SourceFileInfo *pInfo = m_pSourceFileInfo;
    releaseSourceFileInfo ( );
    m_pSourceFileInfo = pInfo;

    // Okay we can now proceed ...
    if ( !addSubtitle ( pImporter->getFileName ( ) ) ) // ask user of subtitle number, sets all required vars
      return;

    QValueList<Subtitles::entry *> list = pImporter->getSubtitles ( );
    m_pTableSubtitles->setNumRows ( list.count ( ) );
    for ( t=0; t<list.count ( ); t++ )  {
      pEntry = list[t];
      m_pTableSubtitles->setText ( t, 0, QString ( "%1" ).arg ( pEntry->iIndex ) );
      m_pTableSubtitles->setText ( t, 1, pEntry->qsTimeStart );
      m_pTableSubtitles->setText ( t, 2, pEntry->qsTimeStop  );
      m_pTableSubtitles->setText ( t, 3, pEntry->qsText      );
    }
    createSubtitles ( );
  }
}

void SubtitlesGui::slotExport ()
{
  QString qsExportFile = QFileDialog::getSaveFileName ( Global::qsCurrentPath, tr ( "Subtitle files (*.srt *.SRT *.ass *.ASS)"), NULL, tr ( "Save Subtitles File" ) );
  if ( qsExportFile.isEmpty ( ) )
    return;

  QFileInfo fileInfo ( qsExportFile );
  Global::qsCurrentPath = fileInfo.dirPath ( true );

  Export::Srt srtExporter;
  Export::Ssa ssaExporter;
  Export::BaseSubtitle *pExporter = &ssaExporter;
  if ( fileInfo.extension ( false ) == "srt" )
    pExporter = &srtExporter;

  if ( createSubtitles ( ) )
       pExporter->writeFile ( m_pSubtitles, qsExportFile );
  m_pSubtitles->m_qsFileName = qsExportFile;
}

void SubtitlesGui::slotClear ()
{
  if ( m_pTableSubtitles->numRows () > 10 )
    if ( MessageBox::warning ( NULL, tr("Attention:"), tr("Are you sure you want to delete the current subtitles ?"), QMessageBox::Yes, QMessageBox::No ) == QMessageBox::No )
      return;

  if ( m_pSourceFileInfo && m_pSourceFileInfo->arraySubtitles [ m_iCurrentSubtitleNumber ] ) {
    delete m_pSourceFileInfo->arraySubtitles [  m_iCurrentSubtitleNumber ];
    m_pSourceFileInfo->arraySubtitles [  m_iCurrentSubtitleNumber ] = NULL;
  }
  if ( m_pSubtitles )
    delete m_pSubtitles;
  m_pSubtitles = NULL;
  m_pTableSubtitles->setNumRows ( 0 );
}

bool SubtitlesGui::createSubtitles ( )
{
  uint t;
  QString qsIso639, qsFileName;
  if ( m_pSubtitles ) {
    qsIso639   = m_pSubtitles->m_qsIso639;
    qsFileName = m_pSubtitles->m_qsFileName;
    delete m_pSubtitles;
  }
  m_pSubtitles = NULL;

  // If no subtitles ... then we should leave m_pSubtitles NULL
  //if ( m_pTableSubtitles->numRows ( ) < 1 )
  //  return true;

  int iHAlignment, iVAlignment;
  Subtitles::entry *pEntry;
  QRect theRect ( m_pEditX->text().toInt (),  m_pEditY->text().toInt (),  m_pEditWidth->text().toInt (),  m_pEditHeight->text().toInt () );

  iVAlignment = 1; // bottom ...
  if ( m_pButtonVCenter->isOn ( ) )
    iVAlignment = 2;
  else if ( m_pButtonVTop->isOn ( ) )
    iVAlignment = 3;
  else if ( m_pButtonVBottom->isOn ( ) )
    iVAlignment = 4;

  iHAlignment = 1;
  if ( m_pButtonLeft->isOn ( ) )
    iHAlignment = 2;
  else if ( m_pButtonRight->isOn ( ) )
    iHAlignment = 3;
  else if ( m_pButtonJustify->isOn ( ) )
    iHAlignment = 4;

  m_pSubtitles = new Subtitles ( m_iVideoWidth, m_iVideoHeight );
  m_pSubtitles->m_bFit             = m_pButtonFit->isOn ( );
  m_pSubtitles->m_iOutline         = -1;
  if ( m_pCheckOutline->isChecked ( ) )
       m_pSubtitles->m_iOutline    = m_pEditOutline->text( ).toInt ( );
  m_pSubtitles->m_font             = m_qfFont;
  m_pSubtitles->m_rect             = theRect;
  m_pSubtitles->m_qsFileName       = qsFileName;
  m_pSubtitles->m_qsIso639         = qsIso639;
  m_pSubtitles->m_iSubtitleNumber  = m_iCurrentSubtitleNumber;
  m_pSubtitles->m_alignment        = QPoint ( iHAlignment, iVAlignment );

  m_backgroundColor.setAlpha ( (unsigned char)( ( 1.0 - m_pEditBGTransparency->text().toFloat () ) * 255.0 ) );
  m_foregroundColor.setAlpha ( (unsigned char)( ( 1.0 - m_pEditTransparency  ->text().toFloat () ) * 255.0 ) );
  m_pSubtitles->m_subColors[0] = m_backgroundColor;
  m_pSubtitles->m_subColors[1] = m_foregroundColor;

  for (t=0;t<(uint)m_pTableSubtitles->numRows ();t++) {
    pEntry = new Subtitles::entry;
    //    pEntry->iIndex      = t;
    pEntry->iIndex      = m_pTableSubtitles->text ( t, 0 ).toInt();
    pEntry->qsTimeStart = m_pTableSubtitles->text ( t, 1 ).stripWhiteSpace ( );
    pEntry->qsTimeStop  = m_pTableSubtitles->text ( t, 2 ).stripWhiteSpace ( );
    pEntry->qsText      = m_pTableSubtitles->text ( t, 3 );
    pEntry->iTimeStart  = m_pSubtitles->getTimeFromString ( pEntry->qsTimeStart );
    pEntry->iTimeStop   = m_pSubtitles->getTimeFromString ( pEntry->qsTimeStop  );
    m_pSubtitles->m_listOfSubtitles.append ( pEntry );
  }
  return true;
}

void SubtitlesGui::createTableEntries ()
{
  uint t;
  Subtitles::entry *pEntry;
  if ( ! m_pSubtitles )
    return;

  m_pTableSubtitles->setNumRows ( m_pSubtitles->m_listOfSubtitles.count ( ) );
  for ( t=0; t<m_pSubtitles->m_listOfSubtitles.count ( ); t++ )  {
    pEntry = m_pSubtitles->m_listOfSubtitles[t];
    m_pTableSubtitles->setText ( t, 0, QString ( "%1" ).arg ( pEntry->iIndex ) );
    m_pTableSubtitles->setText ( t, 1, pEntry->qsTimeStart );
    m_pTableSubtitles->setText ( t, 2, pEntry->qsTimeStop  );
    m_pTableSubtitles->setText ( t, 3, pEntry->qsText      );
  }
  m_pEditX->setText (  QString ( "%1" ).arg ( m_pSubtitles->m_rect.x ( ) ) );
  m_pEditY->setText (  QString ( "%1" ).arg ( m_pSubtitles->m_rect.y ( ) ) );
  if (  m_pSubtitles->m_rect.width  ( ) > 5 )
    m_pEditWidth ->setText( QString ( "%1" ).arg ( m_pSubtitles->m_rect.width ( ) ) );
  if (  m_pSubtitles->m_rect.height ( ) > 5 )
    m_pEditHeight->setText( QString ( "%1" ).arg ( m_pSubtitles->m_rect.height( ) ) );
}

void SubtitlesGui::slotChange ()
{
  //  QListViewItem *pItem = m_pListViewSubtitles->currentItem ( );
  QListViewItem *pItem = m_pListViewSubtitles->selectedItem ( );
  if ( pItem ) {
    bool   bOkay;
    Utils  theUtils;
    int t, iNumber, iNewNumber;
    uiDialogSubtitle theDialog;
    QString qsNewLang, qsNumber;
    Subtitles *pSubtitle;

    qsNumber = pItem->text    ( 0 );
    iNumber  = qsNumber.toInt ( &bOkay );
    if ( ! bOkay )
      return;

    t = 0; qsNewLang = "something";
    theDialog.m_pComboLanguage->clear ( );
    while ( ! qsNewLang.isEmpty ( ) ) {
      qsNewLang = theUtils.iso639 ( qsNumber,  false,  t++ );
      theDialog.m_pComboLanguage->insertItem ( qsNewLang );
    }
    theDialog.m_pSpinboxNumber->setValue ( iNumber );
    theDialog.m_pComboLanguage->setCurrentText ( pItem->text ( 2 ) );

    if ( theDialog.exec ( ) == QDialog::Rejected )
      return;

    iNewNumber = theDialog.m_pSpinboxNumber->value ( );
    if ( iNewNumber != iNumber ) {

      if ( ! sanityCheckSubtitleTrack ( iNewNumber ) )
	return;

      if ( m_pSourceFileInfo->arraySubtitles[ iNewNumber ] ) {
	QFileInfo fileInfo ( m_pSourceFileInfo->qsFileName );
	if ( MessageBox::question ( this, tr ( "Subtitle exists" ), tr ( "Warning, the subtitle number %1 exists already.\nDo you want to remove the current subtitle %2 from the file %3 ?" ).arg ( iNewNumber ).arg ( iNewNumber ).arg ( fileInfo.fileName ( ) ), 
				    QMessageBox::Yes, QMessageBox::No ) == QMessageBox::No )
	  return;
	delete m_pSourceFileInfo->arraySubtitles[ iNewNumber ];
	m_pSourceFileInfo->arraySubtitles[ iNewNumber ] = NULL;
      }
      m_pSourceFileInfo->arraySubtitles[ iNewNumber ] = m_pSourceFileInfo->arraySubtitles[ iNumber ];
      m_pSourceFileInfo->arraySubtitles[ iNewNumber ]->m_iSubtitleNumber = iNewNumber;
      m_pSourceFileInfo->arraySubtitles[ iNumber    ] = NULL;
      m_iCurrentSubtitleNumber = iNewNumber;
      if ( m_pSubtitles )
	   m_pSubtitles->m_iSubtitleNumber = iNewNumber;
      pItem->setText ( 0, QString ( "%1" ).arg ( iNewNumber ) );
    }
    qsNewLang = theDialog.m_pComboLanguage->currentText ( );
    pItem->setText ( 2, qsNewLang );
    qsNewLang = theUtils.iso639 ( qsNewLang, true ); // get code in exchange for lang.
    pItem->setText ( 1, qsNewLang );
    if ( m_pSourceFileInfo->arraySubtitles[ iNewNumber ]->m_qsIso639 != qsNewLang ) {
         m_pSourceFileInfo->arraySubtitles[ iNewNumber ]->m_qsIso639  = qsNewLang;
	 if ( m_pSubtitles )
	      m_pSubtitles->m_qsIso639 = qsNewLang;
    }
    SourceFileEntry *pEntry = sourceFileEntry ( m_pSourceFileInfo );
    if ( pEntry ) {
      pEntry->arraySubtitleEntries [ iNewNumber ].m_iSubtitleNumber = iNewNumber;
      pEntry->arraySubtitleEntries [ iNewNumber ].m_qsIso639        = qsNewLang;
      // next we adjust all other SFInfos as well.
      for ( t=0; t<(int)pEntry->listFileInfos.count ( ); t++ ) {
	if ( pEntry->listFileInfos[ t ]->qsFileName == m_pSourceFileInfo->qsFileName ) 
	  continue;
	pSubtitle = pEntry->listFileInfos[ t ]->arraySubtitles [ iNewNumber ];
	if ( pSubtitle ) {
	  pSubtitle->m_iSubtitleNumber = iNewNumber;
	  pSubtitle->m_qsIso639        = qsNewLang;
	}
      }
    }
  }
}

void SubtitlesGui::slotDelete ()
{
  int t;
  QListViewItem *pItem = m_pListViewSubtitles->currentItem ( );
  if ( pItem ) {
    bool bOkay;
    int  iNumber;

    iNumber = pItem->text ( 0 ).toInt ( &bOkay );
    if ( ! bOkay )
      return;

    if ( m_pSubtitles )
      delete m_pSubtitles;
    m_pSubtitles = NULL;
    if ( m_pSourceFileInfo->arraySubtitles [ iNumber ] ) {
      delete m_pSourceFileInfo->arraySubtitles [ iNumber ];
      m_pSourceFileInfo->arraySubtitles [ iNumber ] = NULL;
    }
    m_pTableSubtitles->setNumRows ( 0 );
    delete pItem;
    pItem =  m_pListViewSubtitles->firstChild ( );
    m_pListViewSubtitles->setSelected ( pItem, true );
    // Finally check if that was the last sourceFileInfo of this SourceFileEntry
    // and if so also unset the subtitle entry.
    SourceFileInfo  *pInfo;
    SourceFileEntry *pEntry = sourceFileEntry ( m_pSourceFileInfo );
    if (pEntry ) {
      for ( t=0; t<(int)pEntry->listFileInfos.count ( ); t++ ) {
	pInfo = pEntry->listFileInfos[t];
	if ( pInfo == m_pSourceFileInfo )
	  continue;
	// Check if we are done here ...
	if ( pInfo->arraySubtitles [ iNumber ] )
	  return;
      }
      // Holla, we are still around here, which means this WAS the last Subtitle to be 
      // referenced by a SourceFileInfo ...
      pEntry->arraySubtitleEntries [ iNumber ].m_iSubtitleNumber = -1;
      pEntry->arraySubtitleEntries [ iNumber ].m_qsIso639        = "";
    }
  }
}

void SubtitlesGui::slotDeleteLine ()
{
  int t;
  QValueList<int> rows;
  for ( t=0;t<m_pTableSubtitles->numRows ();t++) {
    if ( m_pTableSubtitles->isRowSelected ( t, true ) )
      rows.append ( t );
  }
  QMemArray<int> array ( rows.count () );
  for (t=0;t<(int)rows.count ();t++)
    array[t] = rows[t];

  m_pTableSubtitles->removeRows ( array );
  createSubtitles ();
}

void SubtitlesGui::slotTabChanged ( QWidget * )
{
  // PageIndex = 2 => Ta with preview ...
  if ( m_pTabWidget->currentPageIndex ( ) == 2 )
    renderPreview ( );
}

void SubtitlesGui::slotTextOnly ( bool bChecked )
{
  // TODO: Currently not implemented.
  // But it should go something like that ...
  QWidget *p;
  for ( int t=1;t<4;t++ ) {
    if ( t == 3 ) 
      bChecked = !bChecked;
    p = m_pTabWidget->page ( t );
    //    if ( p )  bChecked ? p->hide ( ) : p->show ( );
    if ( p )  m_pTabWidget->setTabEnabled ( p, !bChecked );
  }
}

void SubtitlesGui::slotApplyToAll ( )
{
  // This function will take the settings from the currebt selected subtitle and apply it to all subtitles.
  if ( ! m_pSubtitles )  {
    MessageBox::warning ( NULL, tr ( "No Subtitle selected" ), tr ( "Please select the subtitle you want to apply the setting to all other subtitles first.\n"), QMessageBox::Ok, QMessageBox::NoButton);
    return;
  }

  createSubtitles ( );
  int t;
  Subtitles *pSub = NULL;
  for ( t=0; t<MAX_SUBTITLES; t++ )  {
    pSub = m_pSourceFileInfo->arraySubtitles [ t ];
    if ( ( m_iCurrentSubtitleNumber != t ) && pSub )  {
      pSub->m_bFit         = m_pSubtitles->m_bFit;
      pSub->m_iOutline     = m_pSubtitles->m_iOutline;
      pSub->m_font         = m_pSubtitles->m_font;
      pSub->m_rect         = m_pSubtitles->m_rect;
//      pSub->m_qsFileName   = m_pSubtitles->m_qsFileName;
//      pSub->m_qsIso639     = m_pSubtitles->m_qsIso639;
      pSub->m_alignment    = m_pSubtitles->m_alignment;
      pSub->m_subColors[0] = m_pSubtitles->m_subColors[0];
      pSub->m_subColors[1] = m_pSubtitles->m_subColors[1];
    }
  }
}

void SubtitlesGui::slotSearchText ()
{
  QString qsText, qsCellText;
  bool    bOkay;
  int     t;
  qsText = QInputDialog::getText (tr("Search for text"), tr("Please give the search string."),
				     QLineEdit::Normal, qsText, &bOkay, this );
  if ( bOkay && ( ! qsText.isEmpty ( ) ) ) {
    m_pTableSubtitles->clearSelection ( );
    for ( t=0; t<m_pTableSubtitles->numRows ( ); t++ ) {
      qsCellText = m_pTableSubtitles->text ( t, 3 );
      if ( qsCellText.find  ( qsText ) > -1 )
           m_pTableSubtitles->selectRow ( t );
    }
  }
}

void SubtitlesGui::slotFontColor ()
{
  bool    bOkay;
  QRgb    rgb;
  Rgba    rgba = m_foregroundColor;
  QString qsTransparency;
  float    fTransparency   = 1.0 - m_pEditTransparency->text ( ).toFloat ( );
  unsigned char iForegroundTransparency = (unsigned char)( fTransparency * 0xFF );

  rgba.setAlpha  ( iForegroundTransparency );
  rgb = QColorDialog::getRgba ( rgba.rgb ( ), &bOkay );
  if ( ! bOkay )
    return;

  rgba.setRgb ( rgb );
  // Extract the transparency information in percentage
  fTransparency = 1.0f - ((float)rgba.alpha ( ) / 0xFF );

  // Set Slider, Color, and Text widgets.
  qsTransparency.sprintf ( "%0.2f",  fTransparency );
  m_pEditTransparency->setText    ( qsTransparency );
  m_pSliderTransparency->setValue ( rgba.alpha ( ) );

  setForegroundColor ( rgba );
  renderPreview ( );
}

void SubtitlesGui::slotBackgroundColor ()
{
  bool    bOkay;
  QRgb    rgb;
  Rgba    rgba = m_backgroundColor;
  QString qsBGTransparency;
  float    fBGTransparency = 1.0 - m_pEditBGTransparency->text ( ).toFloat ( );
  unsigned char iBackgroundTransparency = (unsigned char) ( fBGTransparency * 0xFF );

  rgba.setAlpha  ( iBackgroundTransparency );
  rgb = QColorDialog::getRgba ( rgba.rgb ( ), &bOkay );
  if ( ! bOkay )
    return;

  rgba.setRgb ( rgb );
  fBGTransparency = 1.0 - ((float)rgba.alpha ( ) / 0xFF );

  // Set Slider, Color, and Text widgets.
  qsBGTransparency.sprintf ( "%0.2f",  fBGTransparency );
  m_pEditBGTransparency->setText    ( qsBGTransparency );
  m_pSliderBGTransparency->setValue ( rgba.alpha   ( ) );

  setBackgroundColor ( rgba );
  renderPreview ( );
}

void SubtitlesGui::slotFontFamilyChanged(int)
{
  m_pTextEdit->setFixedWidth ( m_pTextEdit->width ( ) );
  updateFont ( 0 );
}

void SubtitlesGui::slotFontStyleChanged(int)
{
  m_pTextEdit->setFixedWidth ( m_pTextEdit->width ( ) );
  updateFont ( 1 );
}

void SubtitlesGui::slotFontSizeChanged(int)
{
  m_pTextEdit->setFixedWidth ( m_pTextEdit->width ( ) );
  updateFont ( 2 );
}

void SubtitlesGui::slotLeft (bool)
{
  if ( m_pButtonLeft->isOn  ( ) )  {
    m_pButtonCenter ->setOn ( false );
    m_pButtonRight  ->setOn ( false );
    m_pButtonJustify->setOn ( false );
    updateFont ( 2 );
  }
}

void SubtitlesGui::slotCenter (bool)
{
  if ( m_pButtonCenter->isOn ( ) )  {
    m_pButtonLeft    ->setOn ( false );
    m_pButtonRight   ->setOn ( false );
    m_pButtonJustify ->setOn ( false );
    updateFont ( 2 );
  }
}

void SubtitlesGui::slotRight (bool)
{
  if ( m_pButtonRight->isOn ( ) )  {
    m_pButtonCenter ->setOn ( false );
    m_pButtonLeft   ->setOn ( false );
    m_pButtonJustify->setOn ( false );
    updateFont ( 2 );
  }
}

void SubtitlesGui::slotJustify (bool)
{
  if ( m_pButtonJustify->isOn ( )  )  {
    m_pButtonCenter->setOn ( false );
    m_pButtonLeft  ->setOn ( false );
    m_pButtonRight ->setOn ( false );
  }
  updateFont ( 2 );
}

void SubtitlesGui::slotVTop (bool)
{
  if ( m_pButtonVTop->isOn  ( ) )  {
    m_pButtonVCenter->setOn ( false );
    m_pButtonVBottom->setOn ( false );
    updateFont ( 2 );
  }
}

void SubtitlesGui::slotVCenter (bool)
{
  if ( m_pButtonVCenter->isOn  ( )  )  {
    m_pButtonVTop->setOn    ( false );
    m_pButtonVBottom->setOn ( false );
    updateFont ( 2 );
  }
}

void SubtitlesGui::slotVBottom (bool)
{
  if ( m_pButtonVBottom->isOn  ( )  )  {
    m_pButtonVTop->setOn    ( false );
    m_pButtonVCenter->setOn ( false );
    updateFont ( 2 );
  }
}

void SubtitlesGui::slotFit (bool bFitForIt)
{
  // here we enable - disable the coordinates if the user wants to
  // fit the box to the text extension.
  m_pEditWidth-> setEnabled( ! bFitForIt );
  m_pEditHeight->setEnabled( ! bFitForIt );
  updateFont ( 2 );
}

void SubtitlesGui::slotUnderline (bool)
{
  updateFont ( 2 );
}

void SubtitlesGui::slotOutline ( bool bCheck )
{
  m_pEditOutline->setEnabled ( bCheck );
  if ( bCheck && m_pSubtitles ) {
    if ( m_pSubtitles->m_iOutline < 1 )
         m_pSubtitles->m_iOutline = 2;
    m_pEditOutline->setText ( QString ( "%1" ).arg ( m_pSubtitles->m_iOutline ) );
  }
  updateFont ( 2 );
}

void SubtitlesGui::slotVolumeChanged ( int iVolume )
{
  float fVolume = (float) (100 - iVolume ) / 100.0;
  if ( m_pMediaInterface )
       m_pMediaInterface->setVolume ( fVolume );
}

void SubtitlesGui::slotPositionChanged ( int iPosition)
{
  if ( m_pMediaInterface )
       m_pMediaInterface->setPosition ( iPosition );
}

void SubtitlesGui::slotTransparencyChanged ( int iValue )
{
  float fValue = 1.0f - ((float)iValue / 255.0 );
  QString qsValue;
  qsValue.sprintf ( "%0.2f", fValue );
  m_pEditTransparency->setText ( qsValue );
  m_foregroundColor.setAlpha   (  iValue );
}

void SubtitlesGui::slotBGTransparencyChanged ( int iValue )
{
  float fValue = 1.0f - ((float)iValue / 255.0 );
  QString qsValue;
  qsValue.sprintf ( "%0.2f", fValue );
  m_pEditBGTransparency->setText ( qsValue );
  m_backgroundColor.setAlpha     (  iValue );
}

int SubtitlesGui::findString (QStringList &list, QString string)
{
  for (uint t=0;t<list.count();t++)	{
    if (list[t] == string)
      return t;
  }
  return -1;
}

void SubtitlesGui::updateFont ( uint iSwitch )
{
  uint t;
  int iIndex;
  // First see what styles are avail ...
  QFontDatabase database;
  QString fontName  = m_pListFonts->text      ( m_pListFonts->currentItem ( ) );
  QString styleName = m_pComboFontStyle->text ( m_pComboFontStyle->currentItem ( ) );
  int iFontSize     = m_pComboFontSizes->text ( m_pComboFontSizes->currentItem ( ) ).toInt ( );

  switch ( iSwitch )  {
  case 0:  {
    // The fontName has changed, so we need to get the styles avail for this new font.
    QStringList listStyles = database.styles ( fontName );
    m_pComboFontStyle->clear ( );
    m_pComboFontStyle->insertStringList ( listStyles );
    iIndex = findString ( listStyles, styleName );
    if ( iIndex == -1 )
         iIndex  =  0;
    styleName = m_pComboFontStyle->text ( iIndex );
    m_pComboFontStyle->setCurrentItem   ( iIndex );
  }
  case 1:
    // The style has changed
    m_pComboFontSizes->clear();
    QValueList<int> listSizes = database.pointSizes(fontName);
    if ( listSizes.isEmpty ( ) )  {
      listSizes = database.smoothSizes(fontName, styleName);
      if ( listSizes.isEmpty ( ) )  {
           listSizes = database.standardSizes();
      }
    }
    iIndex =0;
    for ( t=0; t<listSizes.count ( ); t++ )  {
      m_pComboFontSizes->insertItem ( QString ( "%1" ).arg ( listSizes[t] ) );
      if ( listSizes[t] == iFontSize )
           iIndex = t;
    }
    m_pComboFontSizes->setCurrentItem ( iIndex );
  }
  QString qsText = m_pTextEdit->text ( );
  int iAlignement;
  iAlignement = Qt::AlignLeft;
  if ( m_pButtonCenter->isOn ( ) )
    iAlignement =  Qt::AlignHCenter;
  else if ( m_pButtonRight->isOn ( ) )
    iAlignement = Qt::AlignRight;
  else if ( m_pButtonJustify->isOn ( ) )
    iAlignement = Qt::AlignJustify;

  m_pTextEdit->setText ( qsText );
  // and last we update the TextEdit accordingly
  if ( m_pButtonVTop->isOn ( ) )
    iAlignement |= Qt::AlignTop;
  else if ( m_pButtonVCenter->isOn ( ) )
    iAlignement |= Qt::AlignVCenter;
  else if ( m_pButtonVBottom->isOn ( ) )
    iAlignement |= Qt::AlignBottom;
  m_iAlignement = iAlignement;
  m_pTextEdit->setAlignment ( iAlignement );
  updateButtons ( );
  m_pTextEdit->setFont ( getFont ( ) );
  renderPreview ( );
}

QFont &SubtitlesGui::getFont ()
{
  QFontDatabase database;

  QString qsFamily = m_pListFonts->text ( m_pListFonts->currentItem ( ) );
  QString qsStyle  = m_pComboFontStyle->text(m_pComboFontStyle->currentItem ( ) );
  int iPointSize   = m_pComboFontSizes->text(m_pComboFontSizes->currentItem ( ) ).toInt ( );
  m_qfFont =  database.font( qsFamily, qsStyle, iPointSize );
  m_qfFont.setUnderline ( m_pCheckUnderline->isChecked ( ) );
  // m_qfFont.setStrikeOut ( m_pCheckStrikeout->isChecked ( ) );

  return m_qfFont;
}

void SubtitlesGui::setBackgroundColor  ( Rgba &newColor )
{
  m_pFrameBackgroundColor->setPaletteBackgroundColor ( newColor.color ( ) );
  update ( );
  m_pTextEdit->setPaletteBackgroundColor ( newColor.color ( ) );
  m_backgroundColor = newColor;
  renderPreview ( );
}

void SubtitlesGui::setForegroundColor ( Rgba &newColor )
{
  m_pFrameFontColor->setPaletteBackgroundColor ( newColor.color ( ) );
  m_pTextEdit->setPaletteForegroundColor       ( newColor.color ( ) );
  m_foregroundColor = newColor;
  renderPreview ( );
}

void SubtitlesGui::insertDraggedObject ( QDropEvent *pDropEvent, QImage &theImage )
{
  // The first thing to check is if this drop was initiated in the Toolbar
  if ( pDropEvent->source() && (QString("m_pListViewAllSources") == pDropEvent->source()->name()) ) {
    QFileInfo fileInfo;
    ListViewMedia   *pListViewMedia   = (ListViewMedia *)pDropEvent->source();
    SourceFileEntry *pSourceFileEntry = pListViewMedia->draggingSourceFileEntry();
    SourceFileInfo  *pSourceFileInfo  = pListViewMedia->draggingSourceFileInfo();
    if ( pSourceFileEntry && pSourceFileEntry->bSoundSource )  {	// No adding of a sound source !
      MessageBox::warning (NULL, tr("Can not add."), tr ("This is a sound source.\nI can currently not add this type of source.\n"), QMessageBox::Ok, QMessageBox::NoButton);
      return;
    }
    if ( pSourceFileEntry && pSourceFileEntry->bIsSlideshow )	{
      MessageBox::warning (NULL, tr("Can not add."), tr ("The slideshow is still beeing created.\nI can not add it at this moment.\n"), QMessageBox::Ok, QMessageBox::NoButton);
      return;
    }
    if ( ( ! pSourceFileInfo ) && ( pSourceFileEntry ) ) // Okay here we split between adding one button
      pSourceFileInfo = pSourceFileEntry->listFileInfos[0];
    if ( ! pSourceFileInfo )
      return; // error

    QPixmap theBackground;
    QSize   imgSize;
    releaseSourceFileInfo ( );
    // insert the sourceFileInfo ...
    theImage = *pSourceFileInfo->pPreview;
    imgSize  = m_pDragLabel->size   ( );
    theImage = theImage.smoothScale ( imgSize.width ( ) - 5, imgSize.height ( ) - 5, QImage::ScaleMin );
    theBackground.convertFromImage  ( theImage      );
    m_pDragLabel->setPixmap         ( theBackground );

    m_pSourceFileInfo = pSourceFileInfo;
    fileInfo.setFile  ( pSourceFileInfo->qsFileName );
    m_pTabSubtitles->setTabLabel  ( m_pTabSubtitles->page ( 0 ), fileInfo.fileName () );
    pListViewMedia->resetDragging ( );
    initNewSourceFileInfo         ( true );
  }
}

void SubtitlesGui::insertDraggedText (QDropEvent *, QString &theDroppedText )
{
  // theText should hold the name to a movie file ...
  QString theFile = theDroppedText;
  theFile.remove ( "file:" );

  QFileInfo fileInfo ( theFile );
  if ( fileInfo.exists () && m_pDVDAuthor ) {
    SourceFileInfo *pSourceFileInfo;
    QImage  theImage = QImage::fromMimeSource ( "to_vcd.png" );
    QPixmap thePixmap;
    pSourceFileInfo = findSourceFileInfo ( theFile );
    if ( ! pSourceFileInfo ) {
      QStringList listOfMovies;
      listOfMovies.append        ( theFile );
      m_pDVDAuthor->addMovieList ( listOfMovies );
      pSourceFileInfo = findSourceFileInfo ( theFile );
    }
    if ( ! pSourceFileInfo )
      return;

    // clear up the current subtitles ...
    releaseSourceFileInfo ();
    m_pSourceFileInfo = pSourceFileInfo;
    theImage = *m_pSourceFileInfo->pPreview;

    theImage = theImage.smoothScale ( m_pDragLabel->size(), QImage::ScaleMin );
    thePixmap.convertFromImage ( theImage  );
    m_pDragLabel->setPixmap    ( thePixmap );
    // And finally set the tab label and clear the current subtitles ...
    m_pTabSubtitles->setTabLabel ( m_pTabSubtitles->page ( 0 ), fileInfo.fileName () );
    initNewSourceFileInfo ( true );
  }
}

// returns the SourceFileInfo of the given file name or NULL
SourceFileInfo *SubtitlesGui::findSourceFileInfo ( QString &theFile )
{
  uint t, i;
  SourceFileEntry *pEntry;

  if ( ! m_pDVDAuthor )
    return NULL;

  // Okay we assume a movie file. Now lets check if this file is already in a sourceFileEntry ...
  for ( t=0;t<(uint)m_pDVDAuthor->sourceFileCount ( );t++) {
    pEntry =  m_pDVDAuthor->sourceFileEntry ( t );
    for ( i=0;i<pEntry->listFileInfos.count ( ); i++ ) {
      if ( pEntry->listFileInfos[t]->qsFileName == theFile ) {
	return pEntry->listFileInfos[t];
      }
    }
  }
  return NULL;
}

void SubtitlesGui::releaseSourceFileInfo ()
{
  // this function connects the sourcefileinfo object and the subtitles object.
  QFileInfo fileInfo;
  Utils     theUtils;
  QString   qsXmlFile;
  // first we create the subtitles locally to have the latest and greatest ...
  if ( m_pSourceFileInfo ) {
    createSubtitles ( );

    if ( m_pSourceFileInfo->arraySubtitles [ m_iCurrentSubtitleNumber ] )
      delete m_pSourceFileInfo->arraySubtitles [ m_iCurrentSubtitleNumber ];
    m_pSourceFileInfo->arraySubtitles [ m_iCurrentSubtitleNumber ] = NULL;

    // next we can clear the table ...
    m_pTableSubtitles->setNumRows ( 0 );
    // Okay if we do not have a language AND the list is empty then regard this subtitle as deleted.
    if ( m_pSubtitles && ( m_pSubtitles->m_qsIso639.isEmpty ( ) ) && m_pSubtitles->m_listOfSubtitles.count ( ) < 1 ) {
      m_pSourceFileInfo = NULL;
      return;
    }

    if ( m_pSubtitles ) {
      fileInfo.setFile ( m_pSourceFileInfo->qsFileName );
      m_pSubtitles->m_qsTempFile = QString ("%1/%2/%3/subtitles.vob").arg (Global::qsTempPath).arg (Global::qsProjectName).arg (fileInfo.baseName ( TRUE ));
    }
    // next we move the local subtitles object into the sourceFileInfo  - object
    fileInfo.setFile ( m_pSourceFileInfo->qsFileName );
    qsXmlFile.sprintf ( "/subtitle_%d.xml", m_iCurrentSubtitleNumber );
    qsXmlFile = theUtils.getTempFile ( fileInfo.baseName ( TRUE ) ) + qsXmlFile;
    m_pSubtitles->m_qsXmlFile      = qsXmlFile;
    m_pSubtitles->m_bTextSubtitles = m_pCheckTextBasedSubtitles->isChecked ( );
    m_pSubtitles->m_subtitleState  = (Subtitles::enState)m_iOrigSubtitlesState;
    if ( m_pSubtitles->m_bTextSubtitles ) {
      m_pSubtitles->m_qsTextFont = m_pEditTextFont->text ( );
      if ( m_pSubtitles->m_qsTextFont.isEmpty ( ) )
           m_pSubtitles->m_qsTextFont = "Vera";
      m_pSubtitles->m_iTextFontSize = m_pSpinTextSize->value ( );
      if ( m_pSubtitles->m_iTextFontSize < 8 )
           m_pSubtitles->m_iTextFontSize = 24;
    }

    m_pSourceFileInfo->arraySubtitles [ m_iCurrentSubtitleNumber ] = m_pSubtitles;

    // Okay we can release the SourceFileInfo - object.
    m_pSourceFileInfo = NULL;
  }
  else if ( m_pSubtitles )
    delete m_pSubtitles;
  m_pSubtitles = NULL;
}

Subtitles *SubtitlesGui::getSubtitles ( bool bCreateNew )
{
  if ( bCreateNew ) {
    QString qsLang, qsFileName;
    // We will create a vanilla Subtitles - object
    if ( m_pSubtitles ) {
      qsFileName = m_pSubtitles->m_qsFileName;
      qsLang     = m_pSubtitles->m_qsIso639;
      delete       m_pSubtitles;
    }

    m_pSubtitles = new Subtitles ( m_iVideoWidth, m_iVideoHeight );
    m_pSubtitles->m_qsFileName = qsFileName;
    m_pSubtitles->m_qsIso639   = qsLang;
    m_pTableSubtitles->setNumRows ( 0 );
  }
  else // Or the default we create the Subtitles from the table.
    createSubtitles ( );

  return m_pSubtitles;
}

void SubtitlesGui::initNewSourceFileInfo ( bool bRecreateListView )
{
  // For now comment this dialog out ..
  if ( 0 && m_pSourceFileInfo &&  m_pSourceFileInfo->arraySubtitles [ m_iCurrentSubtitleNumber ] && m_pSubtitles ) {
    if (MessageBox::warning (NULL, QObject::tr("Which should I keep ?"), 
			     QObject::tr ("I detected that there is already a Subtitle number %1 in the Dialog and in the Source.\nYou can have up to 32 Subtitles associated with one movie.\n\nShould I delete the Subtitles in the Dialog ?\n").arg ( m_iCurrentSubtitleNumber ), 
			     QMessageBox::Yes, QMessageBox::No) == QMessageBox::No )
      return; // Note at this point table and Subtitles-object are in sync
  }

  if ( m_pSubtitles )
    delete m_pSubtitles;
  m_pSubtitles = NULL;

  if ( ! m_pSourceFileInfo )
    return;

  Utils theUtils;
  int   t, iWidth, iHeight;
  iWidth  = theUtils.getWHFromResolution ( m_pSourceFileInfo->qsResolution, true  );
  iHeight = theUtils.getWHFromResolution ( m_pSourceFileInfo->qsResolution, false );
  if ( ! iWidth  )
    iWidth  = 720;
  if ( ! iHeight )
    iHeight = 480;

  m_iVideoWidth  = iWidth;
  m_iVideoHeight = iHeight;

  m_pEditX->setText( "0" );
  m_pEditY->setText( "0" );
  m_pEditWidth->setText  ( QString ("%1").arg ( iWidth  ) );
  m_pEditHeight->setText ( QString ("%1").arg ( iHeight ) );
  m_pEditTransparency->setText   ( "0.00" );
  m_pEditBGTransparency->setText ( "0.00" );

  if ( ! m_pSourceFileInfo->arraySubtitles [ m_iCurrentSubtitleNumber ] ) {
    for ( t=0; t<MAX_SUBTITLES; t++ ) { 
      if ( m_pSourceFileInfo->arraySubtitles [ t ] ) {
        m_iCurrentSubtitleNumber = t;
      }
    }
  }
  if ( ! m_pSourceFileInfo->arraySubtitles [ m_iCurrentSubtitleNumber ] ) {
    // In other words, this SourceFileInfo does not have any subtitles.
    Rgba rgbInitialBackground ( START_SUBTITLEBG_COLOR );
    Rgba rgbInitialForeground ( START_SUBTITLEFG_COLOR );
    m_iCurrentSubtitleNumber      = 0;
    m_pTableSubtitles->setNumRows ( 0 );
    m_pListViewSubtitles->clear    ( );
    setBackgroundColor ( rgbInitialBackground );
    setForegroundColor ( rgbInitialForeground );
    return;
  }

  m_pSubtitles =  new Subtitles ( m_iVideoWidth, m_iVideoHeight );
 *m_pSubtitles = *m_pSourceFileInfo->arraySubtitles [ m_iCurrentSubtitleNumber ];

  m_pButtonFit->setOn         ( m_pSubtitles->m_bFit );
  m_pCheckOutline->setChecked ( m_pSubtitles->m_iOutline > 0 );
  m_pEditOutline->setEnabled  ( m_pSubtitles->m_iOutline > 0 );
  m_pEditOutline->setText     ( QString ( "%1" ).arg ( m_pSubtitles->m_iOutline ) );

  m_pCheckTextBasedSubtitles->setChecked ( m_pSubtitles->m_bTextSubtitles );
  m_pEditTextFont->setText    ( m_pSubtitles->m_qsTextFont );
  m_pSpinTextSize->setValue   ( m_pSubtitles->m_iTextFontSize );
  slotTextOnly ( m_pSubtitles->m_bTextSubtitles );
  m_pCheckUnderline->setChecked ( m_pSubtitles->m_font.underline ( ) );
  m_iOrigSubtitlesState = m_pSubtitles->m_subtitleState;

  switch ( m_pSubtitles->m_alignment.x ( ) ) {
  case 2:
    m_pButtonLeft->setOn    ( true );
    break;
  case 3:
    m_pButtonRight->setOn   ( true );
    break;
  case 4:
    m_pButtonJustify->setOn ( true );
    break;
  default:
    m_pButtonCenter->setOn  ( true );
  }

  switch ( m_pSubtitles->m_alignment.y ( ) )  {
  case 3:
    m_pButtonVTop->setOn    ( true );
  break;
  case 4:
    m_pButtonVBottom->setOn ( true );
  break;
  default:
    m_pButtonVCenter->setOn ( true );
  }

  updateButtons ( );

  QString qsValue, qsValue2, qsIso639, qsLang;
  int iFontSize = m_pSubtitles->m_font.pointSize ();
  qsValue2.sprintf ("%0.2f", 1.0 - (float)m_pSubtitles->m_subColors[0].alpha ( ) / 255.0 );
  qsValue.sprintf  ("%0.2f", 1.0 - (float)m_pSubtitles->m_subColors[1].alpha ( ) / 255.0 );

  m_backgroundColor = m_pSubtitles->m_subColors[0];
  m_foregroundColor = m_pSubtitles->m_subColors[1];

  m_pEditBGTransparency->setText    ( qsValue2 );
  m_pEditTransparency  ->setText    ( qsValue  );
  m_pSliderBGTransparency->setValue ( m_pSubtitles->m_subColors[0].alpha ( ) ); // 0==Background color
  m_pSliderTransparency->setValue   ( m_pSubtitles->m_subColors[1].alpha ( ) ); // 1==Foreground color

  m_pFrameBackgroundColor->setPaletteBackgroundColor    ( m_pSubtitles->m_subColors  [0].rgb ( ) );
  m_pFrameFontColor->setPaletteBackgroundColor          ( m_pSubtitles->m_subColors  [1].rgb ( ) );
  m_pTextEdit->setPaletteBackgroundColor                ( m_pSubtitles->m_subColors  [0].rgb ( ) );
  m_pTextEdit->setPaletteForegroundColor                ( m_pSubtitles->m_subColors  [1].rgb ( ) );
  m_pListFonts->setCurrentItem ( m_pListFonts->findItem ( m_pSubtitles->m_font.family( ) ) );
  if ( iFontSize > 0 )
    m_pComboFontSizes->setCurrentText                   ( QString("%1").arg(iFontSize) );

  if ( bRecreateListView ) {
    m_pListViewSubtitles->clear ( );
    for ( t=0; t<MAX_SUBTITLES; t++ ) {
      if ( m_pSourceFileInfo->arraySubtitles [ t ]  ) {
        qsIso639 = m_pSourceFileInfo->arraySubtitles [ t ]->m_qsIso639;
        qsLang   = theUtils.iso639 ( qsIso639, false );
        if ( qsLang.isEmpty   ( ) )
          qsLang   = "--";
        if ( qsIso639.isEmpty ( ) )
          qsIso639 = "--";
        new QListViewItem( m_pListViewSubtitles, QString ( "%1" ).arg ( t ), qsIso639, qsLang );
      }
    }
  }

  createTableEntries ( );
  createSubtitles    ( );
  updateFont        ( 2 );
}

void SubtitlesGui::displayRow ( int iRow )
{
  if ( ! m_pTableSubtitles ) 
    return;
  m_pTableSubtitles->ensureCellVisible ( iRow,   1 );
  m_pTableSubtitles->ensureCellVisible ( iRow+9, 1 );
  m_pTableSubtitles->clearSelection    (           );
  m_pTableSubtitles->selectRow         ( iRow      );
}
