/****************************************************************************
** DialogFiles
**
**   Created : December 2008
**        by : Varol Okan using XEmacs
** Copyright : (c) Varol Okan
**   License : GPL v 2.0
**
****************************************************************************/

#include <stdlib.h> // 0 system ( ... )
#include <unistd.h>

#include <qinputdialog.h>
#include <qapplication.h>
#include <qprogressbar.h>
#include <qpushbutton.h>
#include <qmessagebox.h>
#include <qscrollview.h>
#include <qtabwidget.h>
#include <qpopupmenu.h>
#include <qcheckbox.h>
#include <qiconview.h>
#include <qfileinfo.h>
#include <qlineedit.h>
#include <qgroupbox.h>
#include <qpainter.h>
#include <qtoolbox.h>
#include <qlayout.h>
#include <qcursor.h>
#include <qslider.h>
#include <qheader.h>
#include <qregexp.h>
#include <qtimer.h>
#include <qlabel.h>
#include <qdir.h>

#include "global.h"
#include "previewer.h"
#include "qdvdauthor.h"
#include "dialogfiles.h"
#include "dialogdelta.h"
#include "sourcetoolbar.h"
#include "dialogvfolder.h"
#include "filepreviewdialog.h"
#include "qplayer/mediacreator.h"
#include "qplayer/listviewfileitem.h"
#include "xml_slideshow.h"
#include "importsrt.h"
#include "importssa.h"

#include "dialogimages.h"

#define COLOR_QUICK_SELECTED 250, 150, 50
#define COLOR_QUICK_NORMAL   170, 170, 255

#ifndef DEBUG_INFO
#define debug_cout printf
#else
void debug_cout(const char *, ...){};
#endif


namespace Input
{

const int GroupView::m_iSize       = 45;
int  DialogFiles::m_iThumbnailSize = 100;
bool DialogFiles::m_bStars         = true;
bool DialogFiles::m_bName          = true;
bool DialogFiles::m_bDate          = true;
bool DialogFiles::m_bLength        = true;
DialogFiles *DialogFiles::m_pIAmAlive = NULL; // There can only be one.
QMap <unsigned long long, DialogFiles::Manual *> DialogFiles::m_mapOfManualChange;


// Here we define the pixmaps for the directory tree
// as taken from the DirList example.
// These are static char fields which is more an ancient c-style
// but it'll save us the hassle of adding it to the project file
// plus keeping the pixs around.
static const char *xpmFolderClosed[]={
    "16 16 9 1",
    "g c #808080",
    "b c #c0c000",
    "e c #c0c0c0",
    "# c #000000",
    "c c #ffff00",
    ". c None",
    "a c #585858",
    "f c #a0a0a4",
    "d c #ffffff",
    "..###...........",
    ".#abc##.........",
    ".#daabc#####....",
    ".#ddeaabbccc#...",
    ".#dedeeabbbba...",
    ".#edeeeeaaaab#..",
    ".#deeeeeeefe#ba.",
    ".#eeeeeeefef#ba.",
    ".#eeeeeefeff#ba.",
    ".#eeeeefefff#ba.",
    ".##geefeffff#ba.",
    "...##gefffff#ba.",
    ".....##fffff#ba.",
    ".......##fff#b##",
    ".........##f#b##",
    "...........####."};

static const char *xpmFolderOpen[]={
    "16 16 11 1",
    "# c #000000",
    "g c #c0c0c0",
    "e c #303030",
    "a c #ffa858",
    "b c #808080",
    "d c #a0a0a4",
    "f c #585858",
    "c c #ffdca8",
    "h c #dcdcdc",
    "i c #ffffff",
    ". c None",
    "....###.........",
    "....#ab##.......",
    "....#acab####...",
    "###.#acccccca#..",
    "#ddefaaaccccca#.",
    "#bdddbaaaacccab#",
    ".eddddbbaaaacab#",
    ".#bddggdbbaaaab#",
    "..edgdggggbbaab#",
    "..#bgggghghdaab#",
    "...ebhggghicfab#",
    "....#edhhiiidab#",
    "......#egiiicfb#",
    "........#egiibb#",
    "..........#egib#",
    "............#ee#"};

static const char *xpmFolderLocked[]={
    "16 16 10 1",
    "h c #808080",
    "b c #ffa858",
    "f c #c0c0c0",
    "e c #c05800",
    "# c #000000",
    "c c #ffdca8",
    ". c None",
    "a c #585858",
    "g c #a0a0a4",
    "d c #ffffff",
    "..#a#...........",
    ".#abc####.......",
    ".#daa#eee#......",
    ".#ddf#e##b#.....",
    ".#dfd#e#bcb##...",
    ".#fdccc#daaab#..",
    ".#dfbbbccgfg#ba.",
    ".#ffb#ebbfgg#ba.",
    ".#ffbbe#bggg#ba.",
    ".#fffbbebggg#ba.",
    ".##hf#ebbggg#ba.",
    "...###e#gggg#ba.",
    ".....#e#gggg#ba.",
    "......###ggg#b##",
    ".........##g#b##",
    "...........####."};

  // from 2005 in Deutsch : http://www.pro-linux.de/t_multimedia/dvd-video-disk.html
  //

  // After playing with the dialog:
  // - Reset ProgressBar if/when reaching 100%
  // - Feature to show total lenth of selected videos.
  // - Feature to enlarge one of the thumbnails ( so the icons are mini but you can see focus on one Item )
  //   - Maybe similar to fish eye ? That would be cool
  // - Feature : remove all groups

  // - For larger projects it would be usefull to split it into sub projects to increase load time.
  //   - Work on one menu at a time.

  // - Implement play ( qsFileName ) through internal player instead of external.
  // o Implement Cache
  //   - implement Cache::Thumbs::cleanCacheDB
  //   - Implement slotAutoOpen ( m_pTimerAutoOpen )
  // - Implement smart scanning. After three false images, cancel scanning
  //   - Mark those who can not be scanned ( Film Frame left / Right )

GroupView::Item::Item ( QListView *pView, QString qsLabel, bool bAlt )
  : QListViewItem ( pView, qsLabel )
{
  pCache          = NULL;
  bAlternateColor = bAlt;
  pSourceFileInfo = NULL;

  setDragEnabled ( true );
}

GroupView::Item::Item ( QListView *pView, Item *pAfter, QString qsLabel, bool bAlt )
  : QListViewItem ( pView, pAfter, qsLabel )
{
  pCache          = NULL;
  bAlternateColor = bAlt;
  pSourceFileInfo = NULL;

  setDragEnabled ( true );
}

GroupView::Item::~Item ( )
{
}

void GroupView::Item::paintCell ( QPainter *p, const QColorGroup & cg, int column, int width, int align)
{
  QColorGroup theColors = cg;
  if ( isSelected ( ) )   {
    theColors.setColor(QColorGroup::Base, theColors.highlight() );
    theColors.setColor(QColorGroup::Text, theColors.highlightedText() );
  }
  QColor colorAlternate ( 250, 250, 250 );
  if ( bAlternateColor )   // every second file we change the color slightly
       colorAlternate  = QColor ( 235, 235, 235 );
  theColors.setColor ( QColorGroup::Base, colorAlternate );
  QListViewItem::paintCell ( p, theColors, column, width, align );
}

int GroupView::Item::width (  const QFontMetrics &fontMetrics, const QListView *pListView, int iColumn ) const
{
  int iWidth = QListViewItem::width ( fontMetrics, pListView, iColumn );
  QWidget *pToolbox = pListView->parentWidget ( )->parentWidget ( )->parentWidget ( );

  if ( iWidth < pToolbox->width ( ) )
       iWidth = pToolbox->width ( );

  return iWidth;
}

GroupView::GroupView ( QWidget *pParent, QIconView *pIconView, DialogFiles *pDialog, SourceFileEntry *pEntry )
  : QListView ( pParent )
{
  setAcceptDrops ( true );
  setSorting     (   -1 );
  setAllColumnsShowFocus ( true );
  addColumn ( "Entry" );
  header  ( )->hide ( );
  m_pPreview   = pIconView; // the main IconView ( DialogFiles::m_pPreview )
  m_pDialog    = pDialog;   // Only required to obtain DialogFiles::Thumbs structure for pSourceFileInfo pointer
  m_pSlideshow = NULL;
  m_pSourceFileEntry = pEntry;
}

GroupView::GroupView ( QWidget *pParent, SourceFileEntry *pEntry )
  : QListView ( pParent )
{
  setAcceptDrops ( true );
  setSorting     (   -1 );
  setAllColumnsShowFocus ( true );
  addColumn ( "Entry" );
  header  ( )->hide ( );
  m_pPreview   = NULL;  // the main IconView ( DialogFiles::m_pPreview )
  m_pDialog    = NULL;  // Only required to obtain DialogFiles::Thumbs structure for pSourceFileInfo pointer
  m_pSlideshow = NULL;
  m_pSourceFileEntry = pEntry;
}

GroupView::GroupView ( QWidget *pParent, QIconView *pIconView, DialogFiles *pDialog, CXmlSlideshow *pSlideshow )
  : QListView ( pParent )
{
  setAcceptDrops ( true );
  setSorting     (   -1 );
  setAllColumnsShowFocus ( true );
  addColumn ( "Entry" );
  header  ( )->hide ( );
  m_pPreview         = pIconView; // the main IconView ( DialogFiles::m_pPreview )
  m_pDialog          = pDialog;      // Only required to obtain DialogFiles::Thumbs structure for pSourceFileInfo pointer
  m_pSourceFileEntry = NULL;
  m_pSlideshow       = pSlideshow;
}

GroupView::~GroupView ( )
{
  // Slideshows and SourceFileEntries are deleted in DialogFiles::deleteGroups
}

void GroupView::append ( void *pDialogThumbs )
{
  DialogFiles::Thumbs *pThumbs = (DialogFiles::Thumbs *)pDialogThumbs;

  if ( ! pThumbs || ! pThumbs->pCache )
    return;

  if ( ! pThumbs->pCache->arrayOfThumbs )
         pThumbs->pCache->loadImages  ( );

  QFileInfo fileInfo ( pThumbs->pCache->qsFileName );
  Item   *pItem     = new Item ( this, fileInfo.fileName ( ), true );
  QPixmap thePixmap = QPixmap ( pThumbs->pCache->arrayOfThumbs[0]->smoothScale ( GroupView::m_iSize, GroupView::m_iSize, QImage::ScaleMin) );
  pItem->pCache     = pThumbs->pCache;
  pItem->setPixmap ( 0, thePixmap );
  // this is in case we have a SourceFileInfo stored in the Thumbs
  pItem->pSourceFileInfo = pThumbs->pSourceFileInfo;

  //m_pDialog->clearPreview ( );
  //QTimer::singleShot ( 10, this, SLOT ( slotAlternateColors ( ) ) );
}

QString GroupView::groupName ( )
{
  if ( sourceFileEntry ( ) )
    return sourceFileEntry ( )->qsDisplayName;
  return QString ( "NoName" );
}

void GroupView::setGroupName ( QString &qsName )
{
  if ( sourceFileEntry ( ) )
       sourceFileEntry ( )->qsDisplayName = qsName;
}

void GroupView::dragEnterEvent ( QDragEnterEvent *pEvent )
{
  // Tell the Widget that we accept ImageDrops ...
  // This is necessary otherwise the dropEvent does not occur.

  // Image is coming from itself and Icon is coming from the m_pPreview
  pEvent->accept ( QIconDrag::canDecode ( pEvent ) || QImageDrag::canDecode ( pEvent ) );
}

QDragObject *GroupView::dragObject ( )
{
  QDragObject *pDragObject = NULL;
  Item *pItem = (Item *)selectedItem ( );

  if ( ! pItem )
    return QListView::dragObject ( );

  if ( pItem->pCache ) {
    if ( ! pItem->pCache->arrayOfThumbs )
           pItem->pCache->loadImages  ( );
    QImage  theImage;
    QPixmap thePixmap =  QPixmap ( pItem->pCache->arrayOfThumbs[0]->smoothScale ( 100, 100, QImage::ScaleMin) );
    pDragObject = new QImageDrag ( theImage, this );
    pDragObject->setPixmap ( thePixmap );
  }
//	pDragObject->drag();
//	pDragObject->dragMove();
//	pDragObject->dragCopy();
  return pDragObject;
}

void GroupView::dropEvent ( QDropEvent *pDropEvent )
{
  Item *pTarget = (Item *)itemAt ( pDropEvent->pos ( ) );

  if ( pDropEvent->source ( ) == this ) {
    // Dropped from me to me. meaning we want to re-order
    Item *pSource = (Item *)selectedItem ( );
    if ( pSource && pTarget ) {
      // Here we will find out which is first in the list
      Item *pTemp = (Item *)pTarget->nextSibling ( );
      while ( pTemp ) {
	if  ( pTemp == pSource ) {
	  break;
	}
	pTemp = (Item *)pTemp->nextSibling ( );
      }
      if ( pTemp ) { // then we drag from the bottom
	if ( pTarget->itemAbove ( ) )
	  pSource->moveItem ( pTarget->itemAbove ( ) );
	else { // put as the top item
	  pSource->moveItem ( pTarget );
	  pTarget->moveItem ( pSource );
	}
      }
      else
	pSource->moveItem ( pTarget );
    }
    else if ( pSource ) // add to the end
      pSource->moveItem ( lastItem ( ) );
  }
  else if ( pDropEvent->source ( ) == m_pPreview->viewport ( ) ) {
    // Coming from the IconView.
    QString   qsFileName;
    QFileInfo fileInfo;
    QImage    theImage;
    QValueList<QIconViewItem *>listToBeDeleted;
    QIconViewItem *pIcon = m_pPreview->firstItem ( );
    Cache::Thumbs::Entry *pCache = NULL;
    SourceFileInfo *pSourceFileInfo;
    while ( pIcon ) {
      if  ( pIcon->isSelected ( ) ){
	qsFileName = pIcon->key ( );
	fileInfo.setFile ( qsFileName );
	pCache = Global::pThumbsCache->find ( qsFileName, m_pDialog->isImageDialog ( qsFileName ) );
	if ( pCache ) {
	  pSourceFileInfo = m_pDialog->findSourceFileInfo ( pIcon );
	  if ( ! pCache->arrayOfThumbs )
	         pCache->loadImages  ( );

	  Item   *pItem     = new Item ( this, pTarget, fileInfo.fileName ( ), true );
	  pItem->pCache     = pCache;

          if ( pCache->getMatrix ( ) )  {
               theImage = pCache->arrayOfThumbs[0]->xForm ( *pCache->getMatrix ( ) );
               theImage = theImage.smoothScale ( GroupView::m_iSize, GroupView::m_iSize, QImage::ScaleMin );
          }
          else
            theImage = pCache->arrayOfThumbs[0]->smoothScale ( GroupView::m_iSize, GroupView::m_iSize, QImage::ScaleMin );

	  QPixmap thePixmap = QPixmap  ( theImage );
//	  QPixmap thePixmap = QPixmap  ( pCache->arrayOfThumbs[0]->smoothScale ( GroupView::m_iSize, GroupView::m_iSize, QImage::ScaleMin) );
	  pItem->setPixmap ( 0, thePixmap );
	  if ( pTarget ) // this is in case we drop onto the top item
	    pTarget->moveItem ( pItem );
	  else
	    pItem->moveItem ( lastItem ( ) ); // we drop to the bottom of the list.
	  // this is in case we have a SourceFileINfo stored in the Thumbs
	  pItem->pSourceFileInfo = pSourceFileInfo;
	  listToBeDeleted.append ( pIcon );
	}
      }
      pIcon = pIcon->nextItem ( );
    }
    QValueList<QIconViewItem *>::iterator it = listToBeDeleted.begin ( );
    m_pDialog->lock ( );
    while ( it != listToBeDeleted.end ( ) )  {
      pIcon = *it++;
      m_pDialog->removeThumb ( pIcon );
      delete pIcon;
    }
    m_pDialog->unlock ( );
  }
  QTimer::singleShot ( 10, this, SLOT ( slotAlternateColors ( ) ) );
}

void GroupView::slotAlternateColors ( )
{
  Item *pItem = (Item *)firstChild ( );
  bool bAlternate = true;
  while ( pItem ) {
    bAlternate = ! bAlternate;
    pItem->bAlternateColor = bAlternate;
    pItem->repaint ( );
    pItem = (Item *)pItem->nextSibling ( );
  }
}

void GroupView::timerEvent ( QTimerEvent *pEvent )
{
  // called back after the thumbs have been rendered in the CacheThumbs class.
  if ( (const uint)pEvent->timerId ( ) == MEDIASCANNER_EVENT + 5 ) { // TYPE_MULTI_THUMB
    QImage  theImage;
    QPixmap thePixmap;
    GroupView::Item      *pItem  = NULL;
    Cache::Thumbs::Entry *pEntry = NULL;
    QValueList<Cache::Thumbs::Entry *>list = Global::pThumbsCache->getScannedThumbs ( );
    QValueList<Cache::Thumbs::Entry *>::iterator it;
    it = list. begin ( );
    while ( it != list.end ( ) ) {
      pEntry = *it++;
      // Next we have to find the corresponding Item in the ListView 
      pItem = (GroupView::Item *)firstChild ( );
      while ( pItem ) {
	if  ( pItem->pCache == pEntry ) {
	  pEntry->iScanStatus = 0;
	  if ( ! pEntry->arrayOfThumbs )
	         pEntry->loadImages  ( );
	  theImage = pEntry->arrayOfThumbs[0]->smoothScale ( m_iSize, m_iSize, QImage::ScaleMin );
	  thePixmap.convertFromImage ( theImage );
	  pItem->setPixmap ( 0, thePixmap );
	  break;
	}
	pItem = (GroupView::Item *)pItem->nextSibling ( );
      }
    }
  }
  m_pDialog->m_bCanClose = true;
}

SourceFileEntry *GroupView::sourceFileEntry ( )
{
  return m_pSourceFileEntry;
}

CXmlSlideshow *GroupView::slideshow ( )
{
  return m_pSlideshow;
}

void GroupView::setSlideshow ( CXmlSlideshow *pSlideshow )
{
  m_pSlideshow = pSlideshow;
}

DialogFiles::ThumbnailRequest::ThumbnailRequest ( DialogFiles *pDialog )
  : ExecuteJob ( pDialog )
{
  pImage          = new QImage;
  pOwnerItem      = NULL;
  pParent         = pDialog;
  iNumberOfThumbs = 0;
}

DialogFiles::ThumbnailRequest::ThumbnailRequest ( DialogFiles *pDialog, QIconViewItem *pItem, QString qsFile, uint iNr )
  : ExecuteJob ( pDialog )
{
  pImage          = new QImage;
  pOwnerItem      = pItem;
  pParent         = pDialog;
  iNumberOfThumbs = iNr;
  qsFileName      = qsFile;
}

DialogFiles::ThumbnailRequest::~ThumbnailRequest ( )
{
  if ( pImage )
    delete pImage;
}

bool DialogFiles::ThumbnailRequest::response ( )
{
  if ( ( ! pParent ) || ( ! DialogFiles::isMyself ( pParent ) ) )
    return false;

  if ( ! pParent->isValid ( pOwnerItem ) )
    return false;

  // Rather then copy data back and forth I simply steal the pointer to the QImage object
  QImage *pTempImage = pImage;
  pImage = NULL;
  bool bMarkIcon = bSuccess && ( iNumberOfThumbs > 1 );
  pParent->initWork ( pOwnerItem, pTempImage, bMarkIcon );

  // This is the response to the first thumbnail
  // If we return successfully we want to get the length of the video
  // And we want to get a number of other thumbnails or this item.
  if ( bSuccess && ( iNumberOfThumbs > 1 ) ) {
    MultiThumbRequest *pRequest = new MultiThumbRequest ( pParent, pOwnerItem, qsFileName, pTempImage, iNumberOfThumbs );
    // Since we are still in the worker thread we can not register this one with the MediaScanner
    // Thus we call a timer to get us into the main thread.
    pParent->registerRequest ( pRequest );
  }

  return true;
}

void DialogFiles::registerRequest ( MultiThumbRequest *pRequest )
{
  m_mutexRequest.lock     ( );
  m_listOfRequests.append ( pRequest );
  m_mutexRequest.unlock   ( );

  QTimer::singleShot      ( 10, this, SLOT ( slotRegisterRequests ( ) ) );
}

void DialogFiles::slotRegisterRequests ( )
{
  uint t;
  QValueList<MultiThumbRequest *> listTemp;
  MultiThumbRequest *pRequest = NULL;

  m_mutexRequest.lock ( );
  {
    for ( t=0; t<m_listOfRequests.count ( ); t++ )
      listTemp.append ( m_listOfRequests[t] );

    m_listOfRequests.clear ( );
  }
  m_mutexRequest.unlock ( );

  int iProgress = m_pProgressBar->totalSteps ( );
  for ( t=0; t<listTemp.count ( ); t++ ) {
    pRequest = listTemp[t];
    if ( isValid ( pRequest->pOwnerItem ) ) {
      MediaCreator::registerWithMediaScanner ( pRequest );
      iProgress += pRequest->iNumberOfThumbs;
      markIcon  (  pRequest->pOwnerItem, 1 );
    }
    else
      delete pRequest;
  }

  // resetWait will skip over the 5 second wait at the end of the event loop
  MediaCreator::pPreviewObject->resetWait ( );

  // Oh oh, there is more work to be done ...
  m_pProgressBar->setTotalSteps ( iProgress );
  m_pProgressBar->setProgress ( m_iProgress );

  debug_cout ( "DialogFiles::slotRegisterRequests Registered <%d> andResetWait\n", (int)listTemp.count ( ) );
  listTemp.clear ( );
}

void DialogFiles::play ( Cache::Thumbs::Entry *pEntry, QIconViewItem *pItem )
{
  m_pPreviewer->setItem ( pEntry, pItem );
}

void DialogFiles::lock ( )
{
  m_mutex.lock ( );
}

void DialogFiles::unlock ( )
{
  m_mutex.unlock ( );
}

bool DialogFiles::lockDialog ( )
{
  m_mutexDialog.lock ( );
  return ( m_pIAmAlive );
}

void DialogFiles::unlockDialog ( )
{
  m_mutexDialog.unlock ( );
}

bool DialogFiles::isImageDialog ( )
{
  return m_bIsImageDialog;
}

bool DialogFiles::isImageDialog ( QString qsFileName )
{
  // This function is called for the ImageDialog, which can have either images or vids.
  //return m_bIsImageDialog;
  QFileInfo fileInfo ( qsFileName );
  QString qsVids = Global::pApp->getVidFilter ( );
  if ( qsVids.find ( fileInfo.extension ( FALSE ) ) > -1 )
    return false;
  return m_bIsImageDialog;
}

DialogFiles::MultiThumbRequest::MultiThumbRequest ( DialogFiles *pDialog, QIconViewItem *pItem, QString qsFile, QImage *pFirstImage, uint iThumbs )
  : ThumbnailRequest ( pDialog )
{
  theType         = TYPE_MULTI_THUMB;
  pParent         = pDialog;
  pOwnerItem      = pItem;
  qsFileName      = qsFile;
  iNumberOfThumbs = iThumbs;
  iSize           = pDialog->thumbnailSize ( );
  iDelta          = -1;
  iMovieLength    = -1;
  iCurrentThumb   =  0;

  // Init the array
  *pFirstImage = pFirstImage->smoothScale ( 300, 300, QImage::ScaleMin );

  arrayOfThumbs      = new QImage *[iThumbs];
  for ( uint t=0; t<iThumbs; t++ )
    arrayOfThumbs[t] = new QImage ( *pFirstImage );
}

DialogFiles::MultiThumbRequest::~MultiThumbRequest ( )
{
  if ( arrayOfThumbs ) {
    for ( uint t=0; t<iNumberOfThumbs; t++ )
      delete arrayOfThumbs[t];
    delete arrayOfThumbs;
  }
  if ( pImage )
    delete pImage;
  pImage = NULL;
}

bool DialogFiles::MultiThumbRequest::response ( )
{
  if ( ( ! pParent ) || ( ! DialogFiles::isMyself ( pParent ) ) )
    return false;

  if ( ! pParent->isValid ( pOwnerItem ) )
    return false;

  // qsFileName holds the length of the video and no longer the name
  if ( iMovieLength < 0 ) {
    // The first time around we have to init the offset

    Utils theUtils;
    QFileInfo fileInfo ( pOwnerItem->key ( ) );
    iMovieLength    = theUtils.getMsFromString ( qsFileName );
    // Look we want to have the end displayed even with rounding errors.
    iDelta          = (long)( (double)( iMovieLength - 500 ) / ( iNumberOfThumbs - 1 ) );
    if ( iDelta < 500 ) // sanity check
      iDelta        = (long)( (double)( iMovieLength - (iDelta/2) ) / ( iNumberOfThumbs - 1 ) );
    iCurrentThumb   = 1;
    QString  qsFile = fileInfo.fileName ( );
    debug_cout ( "DialogFiles::MultiThumbRequest::response <%s> = movieLength<%d> NrOfTh<%d> delta<%d>\n", 
	     qsFileName.ascii(), (int)iMovieLength, (int)iNumberOfThumbs, (int)iDelta );
    pOwnerItem->setText ( qsFile + "\n" + qsFileName );

    if ( iMSecondsOffset < 0 )
         createThumbs ( );

    iMSecondsOffset = iDelta;
    return true;
  }

  // here we store the image and increase the iMSecOffset for the next thumbnail.
  if ( iCurrentThumb < iNumberOfThumbs )  {
    if ( ! pImage->isNull ( ) )
      *arrayOfThumbs[iCurrentThumb] = pImage->smoothScale ( 300, 300, QImage::ScaleMin );
  }

  debug_cout ( "DialogFiles::MultiThumbRequest::response iCurrent<%d> movieLength<%d> of<%d> <%p>\n",
             (int)iCurrentThumb, (int)iMovieLength, (int)iMSecondsOffset, pParent );

  iMSecondsOffset = ++iCurrentThumb * iDelta;

  if ( ( iMSecondsOffset >= iMovieLength ) || ( iMSecondsOffset < 0 ) )
    createThumbs ( );

  return true;
}

void DialogFiles::MultiThumbRequest::createThumbs ( )
{
  // coming here is the last time we get to for this MultiThumbRequest
  // In other words we have all screenshots.
  if ( ! DialogFiles::isMyself ( pParent ) )
    return;

  if ( ! pParent->isValid ( pOwnerItem ) )
    return;

  if ( ! pParent->lockDialog ( ) )
    return;

  // So the first thing we ought to do is to store this entry into the cache.
  QString qsFile;
  qsFile = pOwnerItem->key ( );
  Cache::Thumbs::Entry *pCache = NULL;
  pCache = Global::pThumbsCache->append ( qsFile, qsFileName, iNumberOfThumbs, arrayOfThumbs );

  // Next we create the required object for this dialog.
  Thumbs *pThumbs       = new Thumbs;
  pThumbs->pOwnerItem   = pOwnerItem;
  pThumbs->iNumberOfPix = iNumberOfThumbs;
  pThumbs->arrayOfPix   = new QPixmap *[iNumberOfThumbs];
  pThumbs->pCache       = pCache;

  for ( uint t=0; t<iNumberOfThumbs; t++ ) {
    pThumbs->arrayOfPix[t] = new QPixmap;
    pParent->createPix ( pThumbs, t );
  }

  // the array of pointers to the QImage objects reside now in the cache.
  bool bSetIcon = true;
  arrayOfThumbs = NULL;
  pParent->append ( pThumbs );
  if ( iMSecondsOffset  > 0 ) // if DV format then scan MetaInfo
    bSetIcon =  ! ( pParent->initScanDV ( pThumbs ) );
  pParent->addProgress ( iNumberOfThumbs );
  // If there is no scanning for DV Meta Data then we should refresh the icon here
  if ( bSetIcon )
    pOwnerItem->setPixmap ( *pThumbs->arrayOfPix[0] );
  pParent->unlockDialog ( );
}

DialogFiles::WorkWaiting::WorkWaiting ( QIconViewItem *pViewItem, QImage *pImg, bool bMark )
{
  pItem     = pViewItem;
  pImage    = pImg;
  bMarkIcon = bMark;
}

DialogFiles::WorkWaiting::~WorkWaiting ( )
{
  if ( pImage )
    delete pImage;
  pImage = NULL;
};

ScanDVDate::ScanDVDate ( DialogFiles *pDlg, QString qsFile, QIconViewItem *pItm )
{
  pDialog    = pDlg;
  pItem      = pItm;
  qsFileName = qsFile;
  bExited    = false;

  Utils theUtils;
  QString qsTool = theUtils.getToolPath ( "dv2sub" );

  addArgument ( qsTool );
  addArgument (  "-d"  );
  addArgument ( qsFileName ); // fileName

  connect ( this, SIGNAL ( processExited ( ) ), this, SLOT ( slotExited ( ) ) );

  start ( ); // kick off the worker thread
}

ScanDVDate::~ScanDVDate ( )
{
}

void ScanDVDate::ScanDVDate::slotExited ( )
{
  Cache::Thumbs::Entry *pEntry = NULL;
  QDateTime theDate;
  QRegExp rx    (  "\\d.*" );
  rx.setMinimal ( true );

  bExited = true;
  // Should be something like : "\tCreation Date: 2000-04-03 14:07:45"
  QString qsStdout = QProcess::readStdout ( );
  qsStdout.remove ( "\t" );
  qsStdout.remove ( "\n" );

  int     iPos   = rx.search      ( qsStdout, 0 );
  QString qsDate = qsStdout.right ( qsStdout.length ( ) - iPos );
  if ( qsDate.length ( ) > 1 ) {
    theDate = QDateTime::fromString ( qsDate, Qt::ISODate ); //"yyyy-MM-dd hh:mm:ss" );
    if ( theDate.isValid ( ) ) {
      // Okay we seem to have a valid date at hand.

      // Fisrst we change the date in the cache ...
      pEntry = Global::pThumbsCache->find ( qsFileName );
      if ( pEntry ) {
        pEntry->dateCreated = theDate;
        Global::pThumbsCache->saveCacheDB ( );
      }
      // Next we update the pItem ...
      pDialog->initWork ( pItem, NULL, false );

      QApplication::postEvent ( pDialog, new QTimerEvent ( MEDIASCANNER_EVENT + 4 ) );
      return;
    }
  }
  // there was an error so the progress needs to be decreased.
  pDialog->addProgress ( -1 );
  QApplication::postEvent ( pDialog, new QTimerEvent ( MEDIASCANNER_EVENT + 4 ) );
}

bool ScanDVDate::hasExited ( )
{
  return bExited;
}

DialogFiles::DirItem::DirItem ( QListView *pParentView, QString qsPath )
  : QListViewItem ( pParentView )
{
  pParent    = NULL;
  bReadable  = QDir( qsPath ).isReadable ( );
  qsPathName = qsPath;
  setPixmap ( 0, QPixmap( xpmFolderOpen ) );
  setText   ( 0, QFileInfo ( qsPath ).fileName ( ) );
  setText   ( 1, bReadable ? "Dir" : "Unreadable Dir" );
  setExpandable ( TRUE );
}

DialogFiles::DirItem::DirItem ( DirItem *pParentItem, QString qsPath )
  : QListViewItem ( pParentItem )
{
  QDir theDir ( qsPath );
  theDir.setFilter ( QDir::Dirs );

  pParent    = pParentItem;
  bReadable  = theDir.isReadable ( );
  qsPathName = qsPath;
  if ( qsPath[qsPath.length ()-1] != '/' )
    qsPathName = qsPathName + "/";
  if ( theDir.count ( ) > 2 ) {
    setPixmap ( 0, QPixmap( xpmFolderOpen ) );
    setExpandable ( TRUE );
  }
  else {
    setPixmap ( 0, QPixmap( xpmFolderLocked ) );
    setExpandable ( FALSE );
  }

  setText ( 0, QFileInfo ( qsPath ).fileName ( ) );
  setText ( 1, bReadable ? "Dir" : "Unreadable Dir" );
}

void DialogFiles::DirItem::setOpen ( bool bOpen )
{
  if ( bOpen )
    setPixmap ( 0, QPixmap( xpmFolderOpen ) );
  else
    setPixmap ( 0, QPixmap( xpmFolderClosed ) ); //FolderClosed );

  if ( bOpen && ! childCount ( ) ) {
    QString qsDir ( qsPathName );
    QDir  thisDir ( qsDir );
    if ( !thisDir.isReadable ( ) ) {
      bReadable = false;
      setExpandable ( FALSE );
      return;
    }

    listView ( )->setUpdatesEnabled ( FALSE );
    const QFileInfoList *pFiles = thisDir.entryInfoList ( );
    if ( pFiles ) {
      QFileInfoListIterator it( *pFiles );
      QFileInfo *pFileInfo;
      while( (pFileInfo = it.current ( ) ) != 0 )  {
        ++it;
        if ( ( pFileInfo->fileName ( ) == "."  ) || 
	     ( pFileInfo->fileName ( ) == ".." ) )
	  continue;
        else if ( pFileInfo->isDir ( ) )
	  new DirItem ( this, pFileInfo->absFilePath ( ) );  //pFileInfo->fileName ( ) );
      }
    }
    listView ( )->setUpdatesEnabled ( TRUE );
  }
  QListViewItem::setOpen( bOpen );
}

DialogFiles::DirItem *DialogFiles::DirItem::findSubDir ( QString qsSubDir )
{
  DirItem *pDirItem = (DirItem *)firstChild ( );
  while ( pDirItem ) {
    if ( pDirItem->text ( 0 ) == qsSubDir )
      return pDirItem;
    pDirItem = (DirItem *)pDirItem->nextSibling ( );
  }
  return NULL;
}

QString DialogFiles::DirItem::dir ( )
{
  return qsPathName;
}

DialogFiles::Manual::Manual ( )
{
  iHashValue = 0LL;
}

DialogFiles::Manual::~Manual ( )
{
  QMap<unsigned long long, Change *>::iterator it = mapOfChange.begin ( );
  while ( it != mapOfChange.end ( ) )
    delete *it++; //.data ( );
  mapOfChange.clear  ( );
}

DialogFiles::Manual::Change::Change ( )
{
  iHashValue = 0LL;
}

DialogFiles::Manual::Change::~Change ( )
{
  clearAudioList    ( );
  clearSubtitleList ( );
}

void DialogFiles::Manual::Change::clearAudioList ( )
{
  QValueList<Audio *>::iterator it = audioList.begin ( );
  while ( it != audioList.end ( ) )
    delete *it++;
  audioList.clear ( );
}

void DialogFiles::Manual::Change::clearSubtitleList ( )
{
  QValueList<SubtitleEntry *>::iterator it = subtitleList.begin ( );
  while ( it != subtitleList.end ( ) )
    delete *it++;
  subtitleList.clear ( );
}

void DialogFiles::Manual::Change::copyAudioList ( QValueList<Audio *> &original )
{
  clearAudioList ( );

  Audio *pAudio;
  QValueList<Audio *>::iterator it = original.begin ( );
  while ( it != original.end ( ) )  {
     pAudio   = new Audio;
    *pAudio   = *(*it++);
     audioList.append ( pAudio );
  }
}

void DialogFiles::Manual::Change::copySubtitleList ( QValueList<SubtitleEntry *>  &original )
{
  clearSubtitleList ( );

  SubtitleEntry *pSubtitle;
  QValueList<SubtitleEntry *>::iterator it = original.begin ( );
  while ( it  != original.end ( ) )  {
     pSubtitle = new SubtitleEntry;
    *pSubtitle = *(*it++);
     subtitleList.append  ( pSubtitle );
  }
}

QValueList<Audio *> DialogFiles::Manual::Change::copyAudioList ( )
{
  QValueList<Audio *> list;
  Audio *pAudio;
  QValueList<Audio *>::iterator it = audioList.begin ( );
  while ( it != audioList.end ( ) )  {
     pAudio   = new Audio;
    *pAudio   = *(*it++);
     list.append ( pAudio );
  }
  return list;
}

QValueList<SubtitleEntry *> DialogFiles::Manual::Change::copySubtitleList ( )
{
  QValueList<SubtitleEntry *> list;
  SubtitleEntry *pSubtitle;
  QValueList<SubtitleEntry *>::iterator it = subtitleList.begin ( );
  while ( it  != subtitleList.end ( ) )  {
     pSubtitle = new SubtitleEntry;
    *pSubtitle = *(*it++);
     list.append  ( pSubtitle );
  }
  return list;
}

DialogFiles::VFSelectItem::VFSelectItem ( bool bAlt, QListBox *pParent, const QString &text )
  : QListBoxText ( pParent, text )
{
  bAlternate = bAlt;
}

void DialogFiles::VFSelectItem::paint ( QPainter *pPainter )
{
  QColor colorAlternate ( 250, 250, 250 );
  if ( isSelected ( ) )
    colorAlternate  = QColor ( 255, 150, 50 );
  else if ( bAlternate )   // every second file we change the color slightly
    colorAlternate  = QColor ( 235, 235, 235 );
  pPainter->fillRect  ( pPainter->viewport ( ), colorAlternate );
  QListBoxText::paint ( pPainter );
}

int DialogFiles::VFSelectItem::height ( const QListBox * ) const
{
  return 50;
}

DialogFiles::Thumbs::Thumbs ( )
{
  pSourceFileInfo = NULL; // only set if the item is created through a drop from a GroupView.
  arrayOfPix      = NULL;
  pOwnerItem      = NULL;
  pCache          = NULL;
  iNumberOfPix    = 0;
  iCurrentPix     = 0;
}

DialogFiles::Thumbs::~Thumbs ( )
{
  clearSubtitles ( );
  clearAudio     ( );
  if ( arrayOfPix ) {
    for ( uint t=0; t<iNumberOfPix; t++ )
      delete arrayOfPix[t];
    delete []arrayOfPix;
  }
}

void DialogFiles::Thumbs::clearAudio ( )
{
  QValueList<Audio *>::iterator it = audioList.begin ( );
  while ( it != audioList.end ( ) )
    delete *it++;

  audioList.clear ( );
}

void DialogFiles::Thumbs::clearSubtitles ( )
{
  QValueList<SubtitleEntry *>::iterator it = subtitleList.begin ( );
  while ( it != subtitleList.end ( ) )
    delete *it++;

  subtitleList.clear ( );
}

bool DialogFiles::Thumbs::findTracks ( )
{
  // This function will scan the files directory and add any audio file
  // to the Thumbs, which contains the same baseName
  QDir         theDir;
  QFileInfo    fileInfo;
  QStringList  list;
  QStringList::iterator it;
  QString qsBaseName, qsPath, qsFileName, qsVideoFileName, qsLang, qsTemp, qsFilter, qsExt;
  bool bFound, bAudio, bSubtitle, bIgnoreSubtitleFiles, bIgnoreAudioFiles;
  unsigned long  long iPathHash = 0LL, iFileHash = 0LL;
  int iSubtitleNumber = 0;
  Manual::Change *pChange = NULL;
  bIgnoreAudioFiles = bIgnoreSubtitleFiles = false;

  if ( pSourceFileInfo )
    qsVideoFileName = pSourceFileInfo->qsFileName;
  else if ( pCache )
    qsVideoFileName = pCache->qsFileName;
  else return false;

  fileInfo.setFile ( qsVideoFileName );
  qsBaseName = fileInfo.baseName ( );
  qsPath     = fileInfo.dirPath  ( TRUE );
  theDir.setPath ( qsPath );
  qsFilter   = qsBaseName + "*";

  iPathHash = Global::pThumbsCache->hashFromPath ( qsPath );
  iFileHash = Global::pThumbsCache->hashFromFile ( qsVideoFileName );
  Manual *pManual = DialogFiles::m_mapOfManualChange[iPathHash];

  clearSubtitles ( );
  clearAudio     ( );

  // Here we check if we have User modified audio tracks or subtitle tracks.
  if ( pManual )  {
    pChange = pManual->mapOfChange[iFileHash];
    if ( pChange )  {
      // Yep, so lets see audio OR subtitles OR both.
      if ( pChange->audioList.size ( ) > 0 )  {
        bIgnoreAudioFiles = true;
        audioList = pChange->copyAudioList ( );
      }
      if ( pChange->subtitleList.size ( ) > 0 )  {
        bIgnoreSubtitleFiles = true;
        subtitleList = pChange->copySubtitleList ( );
      }
    }
  }

  if ( bIgnoreAudioFiles && bIgnoreSubtitleFiles )
    return true;

  list = theDir.entryList ( qsFilter, QDir::Files );
  it   = list.begin ( );
  while ( it != list.end ( ) )  {
    qsFileName = *it++;

    fileInfo.setFile ( qsFileName );
    qsExt = fileInfo.extension ( FALSE ).lower ( );

    // for efficiency we'll check for the extensions up front.
    bSubtitle = bAudio = false;
    if ( ( qsExt == "srt" ) || ( qsExt == "saa" ) || ( qsExt == "ass" ) )
      bSubtitle = true;
    else if ( ( qsExt == "ac3" ) || ( qsExt == "mp3" ) || ( qsExt == "mp2" ) ||
              ( qsExt == "mpa" ) || ( qsExt == "m2a" ) || ( qsExt == "ogg" ) ||
              ( qsExt == "wav" ) || ( qsExt == "mpega" ) )
      bAudio = true;

    if ( ! bAudio && ! bSubtitle )
      continue; // I don't know what you are but I don't want you

    // First we search for language codes ...
    qsTemp = fileInfo.baseName ( TRUE );
    qsTemp.remove ( qsBaseName );
    qsLang = Global::qsDefaultLanguage;
    if ( qsTemp.length ( ) >  3 )
      qsTemp = qsTemp.right ( 3 );
    if ( qsTemp.length ( ) >= 2 )  {
      if ( ( qsTemp[0] == '.' ) || ( qsTemp[0] == '_' ) || ( qsTemp[0] == '-' ) )
        qsTemp = qsTemp.right ( qsTemp.length ( ) -1 );
      qsLang = qsTemp.left  ( 2 );
    }

    // Check if we have this track already present
    qsFileName = qsPath + "/" + qsFileName;
    bFound = false;

    // Sort out subtitle files
    if ( bSubtitle && ! bIgnoreSubtitleFiles )  {
      // Check if we have this audio track already present
      for ( uint t=0; t<subtitleList.count ( ); t++ ) {
        if ( subtitleList[t]->m_qsFileName == qsFileName )  {
          bFound = true;
          break;
        }
      }
      if ( ( ! bFound ) && ( subtitleList.count ( ) <= MAX_SUBTITLES ) ) {
        // Now we can create the new Audio entry if not already existing
        SubtitleEntry *pSubtitle     = new SubtitleEntry;
        pSubtitle->m_qsFileName      = qsFileName;
        pSubtitle->m_iSubtitleNumber = iSubtitleNumber++;
        pSubtitle->m_qsIso639        = qsLang;
        subtitleList.append ( pSubtitle );
      }
      continue;
    }

    // sort out audio files
    if ( ( ! bAudio ) || ( bIgnoreAudioFiles ) )
      continue;

    // Check if we have this audio track already present
    for ( uint t=0; t<audioList.count ( ); t++ ) {
      if ( audioList[t]->qsFileName == qsFileName )  {
        bFound = true;
        break;
      }
    }
    if ( ( ! bFound ) && ( audioList.count ( ) <= MAX_AUDIO ) ) {
      // Now we can create the new Audio entry if not already existing
      Audio *pAudio        = new Audio;
      pAudio->qsFileName   = qsFileName;
      pAudio->qsIso639     = qsLang;
      pAudio->iAudioNumber = audioList.count ( ) + 1;
      audioList.append ( pAudio );
    }
  }

  if ( ! pManual )  {
    pManual = new Manual;
    pManual->qsPath = qsPath;
    pManual->iHashValue = iPathHash;
    DialogFiles::m_mapOfManualChange[iPathHash] = pManual;
  }
  if ( ! pChange )  {
    pChange = new Manual::Change;
    pChange->qsFileName = qsVideoFileName;
    pChange->iHashValue = iFileHash;
    pChange->copyAudioList    (    audioList );
    pChange->copySubtitleList ( subtitleList );
    pManual->mapOfChange[iFileHash] =  pChange;
  }

  return true;
}

void DialogFiles::Thumbs::toggleAudioTrack ( Audio *pAudio )
{
  // This function will toggle the Audio entry in mapOfManualChange
  bool bFound = false;
  unsigned long long iPathHash, iFileHash;
  Manual         *pManual = NULL;
  Manual::Change *pChange = NULL;
  getManualChange ( pManual, pChange, iPathHash, iFileHash );

  if ( pChange )  {
    Audio *pAudio2;
    QValueList<Audio *>::iterator it = pChange->audioList.begin ( );
    while ( it != pChange->audioList.end ( ) )  {
      pAudio2 = *it++;
      if ( pAudio2->qsFileName == pAudio->qsFileName )  {
        pChange->audioList.remove ( pAudio2 );
        delete pAudio2;
        bFound = true;
      }
    }
    if ( ! bFound )  {
       pAudio2 = new Audio;
      *pAudio2 = *pAudio;
       pChange->audioList.append ( pAudio2 );
    }
  }
}

void DialogFiles::Thumbs::toggleSubtitleTrack ( SubtitleEntry *pSubtitle )
{
  bool bFound = false;
  unsigned long long iPathHash, iFileHash;
  Manual         *pManual = NULL;
  Manual::Change *pChange = NULL;
  getManualChange ( pManual, pChange, iPathHash, iFileHash );

  if ( pChange )  {
    SubtitleEntry *pSubtitle2;
    QValueList<SubtitleEntry *>::iterator it = pChange->subtitleList.begin ( );
    while ( it != pChange->subtitleList.end ( ) )  {
      pSubtitle2 = *it++;
      if ( pSubtitle2->m_qsFileName == pSubtitle->m_qsFileName )  {
        pChange->subtitleList.remove ( pSubtitle2 );
        delete pSubtitle2;
        bFound = true;
      }
    }
    if ( ! bFound )  {
       pSubtitle2 = new SubtitleEntry;
      *pSubtitle2 = *pSubtitle;
       pChange->subtitleList.append ( pSubtitle2 );
    }
  }
}

bool DialogFiles::Thumbs::audioTrackEnabled ( QString &qsAudioFile )
{
  // This function will check the mapOfManualChange to see if the audio file is part of it.
  // Note: once you loose the Thumbs object, the disabled tracks will no longer be displayed
  //       and you will have to refresh the tracks
  Manual::Change *pChange = NULL;
  getManualChange ( pChange );
  if ( pChange )  {
    Audio *pAudio;
    QValueList<Audio *>::iterator it = pChange->audioList.begin ( );
    while ( it != pChange->audioList.end ( ) )  {
      pAudio = *it++;
      if ( pAudio->qsFileName == qsAudioFile )
        return true;
    }
  }
  else
    return true;

  return false;
}

bool DialogFiles::Thumbs::subtitleTrackEnabled ( QString &qsSubtitleFile )
{
  Manual::Change   *pChange = NULL;
  getManualChange ( pChange );
  if ( pChange )  {
    SubtitleEntry *pSubtitle;
    QValueList<SubtitleEntry *>::iterator it = pChange->subtitleList.begin ( );
    while ( it != pChange->subtitleList.end ( ) )  {
      pSubtitle = *it++;
      if ( pSubtitle->m_qsFileName == qsSubtitleFile )
        return true;
    }
  }
  else
    return true;

  return false;
}

bool DialogFiles::Thumbs::getManualChange ( DialogFiles::Manual::Change *&pChange )
{
  DialogFiles::Manual *pManual = NULL;
  unsigned long long iHash1, iHash2;

  return getManualChange ( pManual, pChange, iHash1, iHash2 );
}

bool DialogFiles::Thumbs::getManualChange ( DialogFiles::Manual *&pManual, DialogFiles::Manual::Change *&pChange, unsigned long long &iPathHash, unsigned long long &iFileHash )
{
  QFileInfo fileInfo;
  QString qsPath, qsFileName;
  pManual   = NULL;
  pChange   = NULL;
  iPathHash =  0LL;
  iFileHash =  0LL;

  if ( pSourceFileInfo )
    qsFileName = pSourceFileInfo->qsFileName;
  else if ( pCache )
    qsFileName = pCache->qsFileName;
  else return false;

  fileInfo.setFile ( qsFileName );
  qsPath = fileInfo.dirPath ( TRUE );

  iPathHash = Global::pThumbsCache->hashFromPath ( qsPath );
  iFileHash = Global::pThumbsCache->hashFromFile ( qsFileName );

  pManual   = DialogFiles::m_mapOfManualChange[iPathHash];
  if ( pManual )  {
    pChange   = pManual->mapOfChange[iFileHash];
    return true;
  }
  return false;
}

/****************************************************************
 **
 ** The actual Dialog starts here.
 **
 ****************************************************************/
DialogFiles::DialogFiles ( QWidget *pParent, bool bIsImageDialog, const char *pName, WFlags f )
  : uiDialogFiles ( pParent, pName, f )
{
  m_bIsImageDialog = bIsImageDialog;
  m_pIAmAlive = this;
}

DialogFiles::~DialogFiles ( )
{
  m_pIAmAlive = NULL;
  lockDialog ( );

  // First we should remove outstanding tasks ...
  MediaCreator::unregisterFromMediaScanner ( this );

  if ( m_pVirtualFolderDialog )
    delete m_pVirtualFolderDialog;
  if ( m_pTimerAutoOpen )
    delete m_pTimerAutoOpen;
  if ( m_pTimerScanDir )
    delete m_pTimerScanDir;
  if ( m_pTimerThumbing )
    delete m_pTimerThumbing;
  if ( m_pPreviewer )
       delete m_pPreviewer;

  m_pVirtualFolderDialog = NULL;
  m_pTimerAutoOpen       = NULL;
  m_pTimerScanDir        = NULL;
  m_pTimerThumbing       = NULL;
  m_pPreviewer           = NULL;

  uint t;
  for ( t=0; t<m_listOfThumbs.count ( ); t++ )
    delete m_listOfThumbs[t];
  m_listOfThumbs.clear ( );
  unlockDialog ( );
}

bool DialogFiles::isMyself ( DialogFiles *pDialog )
{
  return ( DialogFiles::m_pIAmAlive == pDialog );
}

void DialogFiles::initMe ( )
{
  m_pVirtualFolderDialog = NULL;
  m_pActiveQuickButton   = NULL;
  m_pActiveThumbs        = NULL;
  m_pTimerAutoOpen       = NULL;
  m_pTimerThumbing       = NULL;
  m_pTimerScanDir        = NULL;
  m_pContextMenu         = NULL;
  m_pToolbox             = NULL;
  m_pScrollView          = NULL;
  m_bCanClose            = true;
  m_bCanChangeIcons      = true;
  m_bTooSmallForText     = ( m_iThumbnailSize < 51 );
  m_iProgress            = 0;
  m_iMultiThumbNumber    = 10; // Number of thumbs per video
  m_pPreviewer = new Previewer ( m_pFramePreview, m_pPreview );

  // Next we create the scrollView and the ToolBox for th groups.
  createScrollView ( );

  QFont theFont        ( QApplication::font ( ) );
  theFont.setBold      ( TRUE );
  theFont.setPointSize ( 8 );
  m_pPreview->setFont  ( theFont );

  m_pCheckStars ->setChecked ( m_bStars  );
  m_pCheckName  ->setChecked ( m_bName   );
  m_pCheckDate  ->setChecked ( m_bDate   );
  m_pCheckLength->setChecked ( m_bLength );

  m_pListViewVirtual->setAllColumnsShowFocus ( true );
  m_pToolbox->removeItem ( m_pToolbox->item  ( 0  ) );
  initMapOfChange    ( );
  initDirectories    ( );
  initVirtualFolders ( );
  initGroups         ( );
  m_pButtonReload->setEnabled ( false );

  // And finally we connect the other 'stuff' 
  connect ( m_pButtonOk,     SIGNAL ( clicked ( ) ), this, SLOT ( accept     ( ) ) );
  connect ( m_pButtonCancel, SIGNAL ( clicked ( ) ), this, SLOT ( reject     ( ) ) );
  connect ( m_pButtonPlay,   SIGNAL ( clicked ( ) ), this, SLOT ( slotPlay   ( ) ) );
  connect ( m_pButtonRefresh,SIGNAL ( clicked ( ) ), this, SLOT ( slotRefresh( ) ) );
  connect ( m_pButtonReload, SIGNAL ( clicked ( ) ), this, SLOT ( slotReload ( ) ) );

  connect ( m_pButtonAutoGroup, SIGNAL ( clicked ( ) ), this, SLOT ( slotAutoGroup ( ) ) );
  connect ( m_pCheckStars,   SIGNAL ( toggled ( bool ) ), this, SLOT ( slotAttrib ( bool ) ) );
  connect ( m_pCheckName,    SIGNAL ( toggled ( bool ) ), this, SLOT ( slotAttrib ( bool ) ) );
  connect ( m_pCheckDate,    SIGNAL ( toggled ( bool ) ), this, SLOT ( slotAttrib ( bool ) ) );
  connect ( m_pCheckLength,  SIGNAL ( toggled ( bool ) ), this, SLOT ( slotAttrib ( bool ) ) );

  connect ( m_pPreview, SIGNAL ( mouseButtonClicked ( int, QIconViewItem *, const QPoint & ) ),
                this,   SLOT ( slotPreviewClicked ( int, QIconViewItem *, const QPoint & ) ) );
  connect ( m_pPreview, SIGNAL ( rightButtonPressed ( QIconViewItem *,      const QPoint & ) ),
                this,   SLOT ( slotPreviewPressed ( QIconViewItem *,      const QPoint & ) ) );
  connect ( m_pPreview, SIGNAL ( dropped ( QDropEvent *, const QValueList<QIconDragItem> & ) ),
                this,   SLOT ( slotDroppedOnPreview ( QDropEvent *, const QValueList<QIconDragItem> & ) ) );
  connect ( m_pPreview, SIGNAL ( selectionChanged ( ) ), this, SLOT ( slotIconSelectionChanged ( ) ) );

  m_pGroupTab->resize ( 260, m_pGroupTab->height   ( ) );
}

void DialogFiles::createScrollView ( )
{
  QGridLayout *pLayout = new QGridLayout ( m_pToolFrame, 1, 1, 0, 6, "m_pLayout1");
  uint iFlags = Qt::WStaticContents;
#if (QT_VERSION > 0x0301FF)
  iFlags |= Qt::WNoAutoErase;
#else
  iFlags |= Qt::WPaintClever;
#endif
  m_pScrollView = new QScrollView     ( m_pToolFrame, "DFToolFRame", iFlags );
  m_pToolbox    = new QToolBox        ( m_pScrollView->viewport ( ), "DFScrollView", iFlags );
  m_pScrollView->addChild             ( m_pToolbox );
  m_pScrollView->setVScrollBarMode    ( QScrollView::AlwaysOn );
  pLayout->addWidget ( m_pScrollView, 0, 0 );
  QTimer::singleShot ( 10, this, SLOT ( slotResizeScrollView ( ) ) );
}

void DialogFiles::slotResizeScrollView ( )
{
  int iWidth  = m_pGroupTab->width  ( ) -  38;
  int iHeight = m_pGroupTab->height ( ) - 100;
  int iCount  = m_pToolbox->count   ( );
  if ( iWidth  <  50 )
       iWidth  = 200;
  if ( iHeight <  50 )
       iHeight = 200;
  if ( iHeight < iCount * 30 + 130 )
       iHeight = iCount * 30 + 130;
  if ( ( m_pToolbox->width ( )  !=  iWidth ) || ( m_pToolbox->height ( ) != iHeight ) )
         m_pToolbox->setFixedSize ( iWidth, iHeight );
  // Ugly workaround to refresh to the proper extensions
  // Why don't we have resize signals anywhere ?
  QTimer::singleShot ( 1500, this, SLOT ( slotResizeScrollView ( ) ) );
}

void DialogFiles::initMapOfChange ( )
{
  // Here we set the entries in the map to the current SourceFileEntry's settings
  uint t, i, iCount = Global::pApp->sourceFileCount ( );
  unsigned long long iPathHash, iFileHash;
  QValueList<SourceFileInfo *>::iterator it;
  SourceFileEntry *pEntry;
  SourceFileInfo  *pInfo;
  Manual::Change  *pChange   = NULL;
  Manual          *pManual   = NULL;
  SubtitleEntry   *pSubtitle = NULL;
  Audio           *pAudio    = NULL;
  Thumbs thumbs;

  for ( t=0; t<iCount; t++ )  {
    pEntry = Global::pApp->sourceFileEntry ( t );
    it = pEntry->listFileInfos.begin ( );
    while ( it != pEntry->listFileInfos.end ( ) )  {
      pInfo = *it++;
      if ( ( pInfo->audioCount ( ) < 1 ) && ( pInfo->subtitleCount ( ) < 1 ) )
        continue;

      thumbs.pSourceFileInfo = pInfo;
      thumbs.getManualChange ( pManual, pChange, iPathHash, iFileHash );
      if ( ! pManual )  {
        QFileInfo fileInfo   ( pInfo->qsFileName );
        QString qsPath = fileInfo.dirPath ( TRUE );
        pManual = new Manual;
        pManual->qsPath     = qsPath;
        pManual->iHashValue = iPathHash;
        DialogFiles::m_mapOfManualChange[iPathHash] = pManual;
      }
      if ( ! pChange )  {
        pChange = new Manual::Change;
        pChange->qsFileName = pInfo->qsFileName;
        pChange->iHashValue = iFileHash;
        pManual->mapOfChange[iFileHash] = pChange;
      }

      if ( pInfo->audioCount ( ) > 0 )  {
        pChange->clearAudioList    ( );
        for ( i=0; i<MAX_AUDIO;  i++ )  {
          if (  pInfo->arrayAudio[i] )  {
            pAudio = new Audio;
           *pAudio = *pInfo->arrayAudio[i];
            pChange->audioList.append ( pAudio );
          }
        }
      }
      if ( pInfo->subtitleCount  ( ) > 0 )  {
        pChange->clearSubtitleList     ( );
        for ( i=0; i<MAX_SUBTITLES;  i++ )  {
          if (  pInfo->arraySubtitles[i] )  {
            pSubtitle = new SubtitleEntry;
           *pSubtitle = *pInfo->arraySubtitles[i];
            pChange->subtitleList.append ( pSubtitle );
          }
        }
      }
    }
  }
}

void DialogFiles::initDirectories( )
{
  // Initialize the Quick buttons
  m_pButtonProject  ->setPixmap( QPixmap::fromMimeSource ( "project.png" ));
  m_pButtonDocuments->setPixmap( QPixmap::fromMimeSource ( "documents.png" ));
  m_pButtonDesktop  ->setPixmap( QPixmap::fromMimeSource ( "desktop.png" ));
  m_pButtonHome     ->setPixmap( QPixmap::fromMimeSource ( "home.png" ));
  m_pButtonRoot     ->setPixmap( QPixmap::fromMimeSource ( "root.png" ));
  m_pButtonTemp     ->setPixmap( QPixmap::fromMimeSource ( "temp.png" ));

  m_qsProjectDir   = Global::qsProjectPath; //QDir::currentDirPath() + QString ("/");
  m_qsHomeDir      = QDir::homeDirPath() + QString ("/");
  m_qsRootDir      = QDir::rootDirPath();
  m_qsDocumentsDir = m_qsHomeDir + QString ("Desktop/Documents/");
  m_qsDesktopDir   = m_qsHomeDir + QString ("Desktop/");
  m_qsTempDir      = Global::qsTempPath;
  if ( m_qsTempDir[m_qsTempDir.length ( )-1] != '/' )
    m_qsTempDir  = m_qsTempDir + "/";
  if ( m_qsProjectDir[m_qsProjectDir.length ( )-1] != '/' )
    m_qsProjectDir  = m_qsProjectDir + "/";

  // Here we refine the Desktop directory ...
  QString qsRCDir = m_qsHomeDir + QString (".kderc");
  QString qsDesktopDir;
  bool bFound = findDesktopDir ( qsRCDir );
  if ( ! bFound )  {
    qsRCDir = QString ("/etc/kderc");
    bFound  = findDesktopDir ( qsRCDir );
  }
  if ( bFound )  {
    // So we found the kde default directory, we should use it
    // instead of my dummy directory (if present).
    QFile file ( Global::qsTempPath + QString ( "/lucas.txt" ) );
    file.open (IO_ReadOnly);
    m_qsDesktopDir = QString ();
    QString qsLine;
    while ( file.readLine ( qsLine, 2048 ) > -1 )
      qsDesktopDir += qsLine;

    file.close ( );
    if ( qsDesktopDir.length ( ) > 1 )
       m_qsDesktopDir = qsDesktopDir;
  }
  // And we should also search for a Documents directory ...
  const char *pArray[5] = {"Documents/", "documents/", "MyDocuments/", "myDocuments/", "mydocuments/" };
  QString qsDocs, qsPreDir = m_qsDesktopDir;
  QDir docDir;
  int t, i;
  // The first time we are looking under the desktop directory for the documents directory.
  for (i=0;i<2;i++)	{
    for (t=0;t<5;t++)	{
      qsDocs = qsPreDir + QString (pArray[t]);
      docDir.setPath(qsDocs);
      if (docDir.exists())	{
	m_qsDocumentsDir = qsDocs;
	t = i = 6; 	// exit both loops ...
      }
    }
    qsPreDir = m_qsHomeDir;	// the second time around we are searching in the Home Directory
  }

  m_pTimerAutoOpen = new QTimer ( this );
  m_pTimerScanDir  = new QTimer ( this );
  m_pTimerThumbing = new QTimer ( this );
  connect ( m_pTimerAutoOpen, SIGNAL( timeout ( ) ), this, SLOT ( slotAutoOpen ( ) ) );
  connect ( m_pTimerScanDir,  SIGNAL( timeout ( ) ), this, SLOT ( slotScanDir  ( ) ) );
  connect ( m_pTimerThumbing, SIGNAL( timeout ( ) ), this, SLOT ( slotThumbing ( ) ) );

  connect ( m_pButtonProject,   SIGNAL (clicked ()), this, SLOT (slotQuickDir()) );
  connect ( m_pButtonDocuments, SIGNAL (clicked ()), this, SLOT (slotQuickDir()) );
  connect ( m_pButtonDesktop,   SIGNAL (clicked ()), this, SLOT (slotQuickDir()) );
  connect ( m_pButtonHome,      SIGNAL (clicked ()), this, SLOT (slotQuickDir()) );
  connect ( m_pButtonRoot,      SIGNAL (clicked ()), this, SLOT (slotQuickDir()) );
  connect ( m_pButtonTemp,      SIGNAL (clicked ()), this, SLOT (slotQuickDir()) );

  // next we take care of the Tree control
  m_pTreeList->setTreeStepSize ( 20 );
  m_pTreeList->setAcceptDrops ( TRUE );
  m_pTreeList->setSelectionMode( QListView::Single );
  m_pTreeList->setAllColumnsShowFocus       ( TRUE );
  m_pTreeList->viewport ( )->setAcceptDrops ( TRUE );

  QString qsCurrentPath = Global::qsCurrentPath;

  const QFileInfoList *pRoots = QDir::drives ( );
  QPtrListIterator<QFileInfo> it(*pRoots);
  DirItem   *pItem;
  QFileInfo *pFileInfo = it;
  while ( pFileInfo ) {
    pItem = new DirItem ( m_pTreeList, pFileInfo->absFilePath ( ) );
    if ( pRoots->count ( ) <= 1 )
      pItem->setOpen( TRUE );

    pItem->setDragEnabled ( TRUE );
    pItem->setDropEnabled ( TRUE );
    pFileInfo = ++it;
  }
  setCurrentDir      ( Global::qsCurrentPath );
  m_pEditSize->setText    ( QString (  "%1"  ).arg ( m_iThumbnailSize ) );
  m_pSliderSize->setValue ( m_iThumbnailSize );

  connect ( m_pTreeList,   SIGNAL ( currentChanged(QListViewItem *) ), this, SLOT( slotDirectoryChanged(QListViewItem *) ) );
  connect ( m_pSliderSize, SIGNAL ( valueChanged ( int ) ), this, SLOT ( slotSizeChanged   ( int ) ) );
  connect ( m_pSliderSize, SIGNAL ( sliderReleased   ( ) ), this, SLOT ( slotSizeReleased  ( ) ) );
}

void DialogFiles::initVirtualFolders ( )
{
  uint t;
  int iWidth, iHeight;

  QPixmap thePixmap, tempPixmap;
  QImage  theImage,  emptyImage ( 64, 64, 32 );
  QImage  scaledStar, theStar = QImage::fromMimeSource ( "star.png" );

  // because Qt is sharing QImage resources, the required empty image has to be done this way.
  emptyImage.setAlphaBuffer ( FALSE );
  emptyImage.fill ( 0x00000000 );
  emptyImage.setAlphaBuffer ( TRUE  );
  emptyImage.fill ( 0xFFFFFFFF );

  scaledStar = theStar.smoothScale ( 40, 40, QImage::ScaleMin );
  theImage   = emptyImage.copy ( );
  bitBlt ( &theImage, 12, 12,  &scaledStar );
  thePixmap.convertFromImage (  theImage );
  m_pButtonStar1->setPixmap  ( thePixmap );

  // Next we need to scale ...
  iWidth   = (int)( emptyImage.width  ( ) / 2.0 );
  iHeight  = (int)( emptyImage.height ( ) / 2.0 );
  scaledStar = theStar.smoothScale ( iWidth, iHeight, QImage::ScaleMin );

  // Here we create the two Stars-Button
  theImage = emptyImage.copy ( );
  bitBlt ( &theImage,      0,       0,  &scaledStar );
  bitBlt ( &theImage, iWidth, iHeight,  &scaledStar );
  thePixmap.convertFromImage (  theImage );
  m_pButtonStar2->setPixmap  ( thePixmap );

  // And since we have this in place we can also create the 4 Star-Button right next
  bitBlt ( &theImage, iWidth,       0,  &scaledStar );
  bitBlt ( &theImage,      0, iHeight,  &scaledStar );
  thePixmap.convertFromImage (  theImage );
  m_pButtonStar4->setPixmap  ( thePixmap );

  // Next we will create the 3 Star-Button
  theImage = emptyImage.copy ( );
  bitBlt ( &theImage, (int)(iWidth/2.0), 0, &scaledStar );
  bitBlt ( &theImage,      0, iHeight, &scaledStar );
  bitBlt ( &theImage, iWidth, iHeight, &scaledStar );
  thePixmap.convertFromImage (  theImage );
  m_pButtonStar3->setPixmap  ( thePixmap );

  // Time to scale again
  iWidth   = (int)( emptyImage.width  ( ) / 3.0 );
  iHeight  = (int)( emptyImage.height ( ) / 3.0 );
  scaledStar = theStar.smoothScale ( iWidth, iHeight, QImage::ScaleMin );

  // Next on the todo list is the 6 Star-Button
  theImage = emptyImage.copy ( );
  bitBlt ( &theImage,        0,         0, &scaledStar );
  bitBlt ( &theImage,   iWidth,         0, &scaledStar );
  bitBlt ( &theImage, 2*iWidth,         0, &scaledStar );
  bitBlt ( &theImage,        0, 2*iHeight, &scaledStar );
  bitBlt ( &theImage,   iWidth, 2*iHeight, &scaledStar );
  bitBlt ( &theImage, 2*iWidth, 2*iHeight, &scaledStar );
  thePixmap.convertFromImage (  theImage );
  m_pButtonStar6->setPixmap  ( thePixmap );

  // Last we create the 5 Star-Button
  theImage = emptyImage.copy ( );
  bitBlt ( &theImage,        0,         0, &scaledStar );
  bitBlt ( &theImage, 2*iWidth,         0, &scaledStar );
  bitBlt ( &theImage,        0, 2*iHeight, &scaledStar );
  bitBlt ( &theImage, 2*iWidth, 2*iHeight, &scaledStar );
  bitBlt ( &theImage,   iWidth,   iHeight, &scaledStar );
  thePixmap.convertFromImage (  theImage );
  m_pButtonStar5->setPixmap  ( thePixmap );

  // Next we will create the pixmaps for the context menu
  iWidth = 20;
  emptyImage = emptyImage.scale    ( 6*iWidth, iWidth );
  scaledStar = theStar.smoothScale (   iWidth, iWidth, QImage::ScaleMin );
  theImage   = emptyImage.copy ( );
  for ( t=0; t<6; t++ ) {
    bitBlt ( &theImage, t*iWidth, 0,  &scaledStar );
    m_pixMenuStars[t].convertFromImage ( theImage );
  }

  // Next we will init the QListViewVirtual
  m_pListViewVirtual->setSorting ( FALSE );
  QString qsDate, qsCount;
  Cache::Thumbs::VirtualFolder *pVFolder = NULL;
  QValueList<Cache::Thumbs::VirtualFolder *>::iterator it;
  QValueList<Cache::Thumbs::VirtualFolder *>list = Global::pThumbsCache->getVirtualFolders ( isImageDialog ( ) );
  it = list.begin ( );
  while ( it != list.end ( ) ) {
    pVFolder  = *it++;
    qsCount   = QString ( "%1" ).arg ( pVFolder->listOfFiles.count ( ) );
    qsDate    = pVFolder->dateCreated.toString ( "yyyy/MM/dd hh:mm:ss" );
    new QListViewItem ( m_pListViewVirtual, pVFolder->qsFolderName, qsCount, qsDate );
  }

  createIconStars ( );

  connect ( m_pButtonStar1, SIGNAL( clicked ( ) ), this, SLOT ( slotSelectByStars ( ) ) );
  connect ( m_pButtonStar2, SIGNAL( clicked ( ) ), this, SLOT ( slotSelectByStars ( ) ) );
  connect ( m_pButtonStar3, SIGNAL( clicked ( ) ), this, SLOT ( slotSelectByStars ( ) ) );
  connect ( m_pButtonStar4, SIGNAL( clicked ( ) ), this, SLOT ( slotSelectByStars ( ) ) );
  connect ( m_pButtonStar5, SIGNAL( clicked ( ) ), this, SLOT ( slotSelectByStars ( ) ) );
  connect ( m_pButtonStar6, SIGNAL( clicked ( ) ), this, SLOT ( slotSelectByStars ( ) ) );

  connect ( m_pButtonAddVirtual,    SIGNAL ( clicked ( ) ), this, SLOT ( slotAddVirtual    ( ) ) );
  connect ( m_pButtonEditVirtual,   SIGNAL ( clicked ( ) ), this, SLOT ( slotEditVirtual   ( ) ) );
  connect ( m_pButtonDeleteVirtual, SIGNAL ( clicked ( ) ), this, SLOT ( slotDeleteVirtual ( ) ) );
  connect ( m_pListViewVirtual,     SIGNAL ( selectionChanged  ( ) ), this, SLOT( slotVirtualChanged (  ) ) );
  connect ( m_pListViewVirtual,     SIGNAL ( doubleClicked     (QListViewItem *, const QPoint &, int ) ), this, SLOT( slotShowVirtual (QListViewItem *, const QPoint &, int) ) );
  connect ( m_pListViewVirtual,     SIGNAL ( rightButtonClicked(QListViewItem *, const QPoint &, int ) ), this, SLOT( slotVirtualContextMenu (QListViewItem *, const QPoint &, int) ) );
}

void DialogFiles::clearMapOfChange ( )
{
  QMap<unsigned long long, Manual *>::iterator it = m_mapOfManualChange.begin ( );
  while ( it != m_mapOfManualChange.end ( ) )
    delete *it++; //.data ( );
  m_mapOfManualChange.clear  ( );
}

void DialogFiles::createIconStars ( )
{
  uint t, i, iSize, iX, iHalf;
  QImage  scaledStar, theStar = QImage::fromMimeSource ( "star.png" );

  iSize      = m_iThumbnailSize / 6;
  scaledStar = theStar.smoothScale ( iSize, iSize, QImage::ScaleMin );

  QImage theImage, emptyImage ( m_iThumbnailSize+4, iSize+2, 32 );
  emptyImage.fill ( 0xFFFFFFFF );

  iHalf = (int)((float)m_iThumbnailSize / 2.0f);
  for ( t=0; t<7; t++ ) {
    theImage = emptyImage.copy ( );
    iX = 2 + iHalf - ( t * ( iSize / 2 ) );
    for ( i=0; i<t; i++  ) {
      bitBlt ( &theImage, iX, 2, &scaledStar );
      iX += iSize;
    }
    m_pixIconStars[t].convertFromImage ( theImage );
  }
}

void DialogFiles::initGroups ( )
{
  // Here we init the already existing groups ...
  int t;
  SourceFileEntry *pEntry;

  // Init the Group tab.
  // I do it this way to keep DialogFiles as generic as possible
  // Maybe some future use in other programs ...
  for ( t=0; t<Global::pApp->sourceFileCount ( ); t++ )  {
      pEntry = Global::pApp->sourceFileEntry( t );
      if ( pEntry && !pEntry->bSoundSource )
           addGroup ( pEntry );
  }

  // Next we ensure we have at least one group.
  if ( m_pToolbox->count ( ) < 1 ) {
    QString qsTitle = isImageDialog ( ) ? tr ( "Slide 1" ) : tr ( "First Group" );
    QStringList emptyList;
    addGroup ( qsTitle, emptyList );
  }

  connect ( m_pButtonNew,    SIGNAL ( clicked ( ) ), this, SLOT ( slotAddGroup    ( ) ) );
  connect ( m_pButtonEdit,   SIGNAL ( clicked ( ) ), this, SLOT ( slotEditGroup   ( ) ) );
  connect ( m_pButtonDelete, SIGNAL ( clicked ( ) ), this, SLOT ( slotDeleteGroup ( ) ) );
}

void DialogFiles::slotAddGroup ( )
{
  QStringList emptyList;
  QString qsHeader = tr ( "Enter name for new group." );
  QString qsLabel  = tr ( "Enter Group Name : " );
  if ( isImageDialog ( ) )  {
    qsHeader = tr ( "Enter name for new Slideshow." );
    qsLabel  = tr ( "Enter Slideshow Name : " );
  }
  QString qsTitle  = QInputDialog::getText ( qsHeader, qsLabel );
  if ( qsTitle.isEmpty ( ) )
    return;

  GroupView *pGroupView = new GroupView ( m_pToolbox, m_pPreview, this );
  connect  ( pGroupView, SIGNAL ( contextMenuRequested ( QListViewItem *, const QPoint &, int ) ), this, SLOT ( slotGroupContextMenu ( QListViewItem *, const QPoint &, int ) ) );
  m_pToolbox->addItem ( pGroupView, qsTitle );
  m_pToolbox->setCurrentItem   ( pGroupView );
//  QTimer::singleShot ( 10, this, SLOT ( slotResizeScrollView ( ) ) );
}

void DialogFiles::slotEditGroup ( )
{
  int iIdx = m_pToolbox->currentIndex ( );
  QString qsCurrent = m_pToolbox->itemLabel ( iIdx );
  QString qsHeader  = tr ( "Enter name for current group." );
  QString qsLabel   = tr ( "Enter Group Name : " );
  QString qsTitle   = QInputDialog::getText ( qsHeader, qsLabel, QLineEdit::Normal, qsCurrent );
  if ( qsTitle.isEmpty ( ) )
    return;

  m_pToolbox->setItemLabel ( iIdx, qsTitle );
}

void DialogFiles::slotDeleteGroup ( )
{
  int      iIdx       = m_pToolbox->currentIndex ( );
  QString  qsLabel    = m_pToolbox->itemLabel  ( iIdx );
  QWidget *pGroupView = m_pToolbox->item       ( iIdx );
  if ( QMessageBox::warning ( this, tr ( "Warning Delete Source Group." ),
         tr ( "Are you sure you want to delete the group\n%1" ).arg ( qsLabel ), 
         QMessageBox::Yes, QMessageBox::No ) == QMessageBox::Yes )  {
    m_pToolbox->removeItem ( pGroupView );
    delete pGroupView;
  }
//  QTimer::singleShot ( 10, this, SLOT ( slotResizeScrollView ( ) ) );
}

GroupView *DialogFiles::addGroup ( QString &qsTitle, QStringList &list )
{
  uint      t;
  bool      bAlternate = true;
  QFileInfo fileInfo;
  QPixmap   thePixmap, errorPixmap;
  Cache::Thumbs::Entry *pCache;
  GroupView::Item *pItem      = NULL;
  GroupView       *pGroupView = new GroupView ( m_pToolbox, m_pPreview, this );
  QImage theImage ( QImage ( ).fromMimeSource ( "error.jpg" ) );

  theImage = theImage.smoothScale ( GroupView::m_iSize, GroupView::m_iSize );
  errorPixmap.convertFromImage ( theImage );

  for ( t=0; t<list.count ( ); t++ ) {
    pCache = Global::pThumbsCache->find ( list[t], isImageDialog ( ) );
    fileInfo.setFile      ( list[t] );
    bAlternate = ! bAlternate;
    pItem = new GroupView::Item ( pGroupView, fileInfo.fileName ( ), bAlternate );
    if ( pCache )  {
      pItem->pCache = pCache;
      if ( ! pCache->arrayOfThumbs )
             pCache->loadImages ( );
      if ( pCache->arrayOfThumbs && pCache->arrayOfThumbs[0] ) {
           theImage = pCache->arrayOfThumbs[0]->smoothScale ( GroupView::m_iSize, GroupView::m_iSize, QImage::ScaleMin );
           thePixmap.convertFromImage ( theImage );
          pItem->setPixmap ( 0, thePixmap );
      }
      else
        pItem->setPixmap ( 0, errorPixmap );
    }
    else
      pItem->setPixmap ( 0, errorPixmap );
  }
  connect  ( pGroupView, SIGNAL ( contextMenuRequested ( QListViewItem *, const QPoint &, int ) ), this, SLOT ( slotGroupContextMenu ( QListViewItem *, const QPoint &, int ) ) );

  // And finally we can add the listBox to the ToolBox
  m_pToolbox->addItem ( pGroupView, uniqueGroupName ( qsTitle ) );
//  QTimer::singleShot  ( 10, this, SLOT ( slotResizeScrollView ( ) ) );
  return pGroupView;
}

GroupView *DialogFiles::addGroup ( SourceFileEntry *pEntry )
{
  if ( ! pEntry )
    return NULL;

  // This flag is indicating that the slideshow is not yet done rendering.
  if ( pEntry->bIsSlideshow  )
    return NULL;

  int      t;
  bool      bAlternate = true;
  QFileInfo fileInfo;
  QPixmap   thePixmap, errorPixmap;
  SourceFileInfo *pInfo = NULL;
  Cache::Thumbs::Entry *pCache;
  GroupView::Item *pItem      = NULL;
  GroupView       *pGroupView = new GroupView ( m_pToolbox, m_pPreview, this, pEntry );
  QImage theImage ( QImage ( ).fromMimeSource ( "error.jpg" ) );

  theImage = theImage.smoothScale ( GroupView::m_iSize, GroupView::m_iSize );
  errorPixmap.convertFromImage ( theImage );

  for ( t=(int)pEntry->listFileInfos.count ( )-1; t>=0; t-- ) {
    pInfo  = pEntry->listFileInfos[t];
    pCache = Global::pThumbsCache->find ( pInfo->qsFileName, isImageDialog ( ) );
    fileInfo.setFile ( pInfo->qsFileName );
    bAlternate = ! bAlternate;
    pItem = new GroupView::Item ( pGroupView, fileInfo.fileName ( ), bAlternate );
    pItem->pSourceFileInfo = pInfo;
    if ( pCache )  {
      pItem->pCache = pCache;
      if ( ! pCache->arrayOfThumbs )
        pCache->loadImages ( );
      if ( pCache->arrayOfThumbs && pCache->arrayOfThumbs[0] ) {
        theImage = pCache->arrayOfThumbs[0]->smoothScale ( GroupView::m_iSize, GroupView::m_iSize, QImage::ScaleMin );
        thePixmap.convertFromImage ( theImage );
        pItem->setPixmap ( 0, thePixmap );
      }
      else
        pItem->setPixmap ( 0, errorPixmap );
    }
    else
      pItem->setPixmap ( 0, errorPixmap );
  }
  connect  ( pGroupView, SIGNAL ( contextMenuRequested ( QListViewItem *, const QPoint &, int ) ), this, SLOT ( slotGroupContextMenu ( QListViewItem *, const QPoint &, int ) ) );

  // And finally we can add the listBox to the ToolBox
  m_pToolbox->addItem ( pGroupView, uniqueGroupName ( pEntry->qsDisplayName ) );
//  QTimer::singleShot  ( 10, this, SLOT ( slotResizeScrollView ( ) ) );
  return pGroupView;
}

QString DialogFiles::uniqueGroupName ( QString qsName )
{
  // This fnction will make sure all Groups hold a uniue name.
  int  t, iCount  = 0;
  QString qsGroup, qsReturn;
  bool     bFound = true;
  QRegExp rx ( ".*_\\d" );

  qsReturn = qsName.remove ( rx );
  while ( bFound ) {
    bFound = false;
    for ( t=0; t<m_pToolbox->count ( ); t++ ) {
      qsGroup = m_pToolbox->itemLabel ( t );
      if ( qsGroup == qsReturn ) {
	qsReturn    = qsName + QString ( "_%1" ).arg ( ++iCount, 2 );
	bFound      = true; // re-do the while loop
	break; // leave for - loop
      }
    }
  }
  return qsReturn;
}

void DialogFiles::addSourceToGroup ( GroupView *pGroupView )
{
  int t;
  QFileInfo        fileInfo;
  QImage           theImage;
  QPixmap          thePixmap;
  QString          qsMovieFilter;
  QStringList      list;
  GroupView::Item *pItem;
  qsMovieFilter =  getDirFilter ( );
  list          =  FilePreviewDialog::getOpenFileNames ( NULL, Global::qsCurrentPath, QString ("Movies ( ") + qsMovieFilter + QString (" );;All ( * )"));
  if ( list.count ( ) < 1 )
    return;

  Cache::Thumbs::Entry *pEntry = NULL;
  for ( t=(int)list.count ( )-1; t>=0; t-- ) {
    pEntry = Global::pThumbsCache->find ( list[t], isImageDialog ( ) );
    fileInfo.setFile ( list[t] );
    if ( pEntry )  {
      pItem  = new GroupView::Item ( pGroupView, fileInfo.fileName ( ), true );
      if ( ! pEntry->arrayOfThumbs )
             pEntry->loadImages  ( );
      if ( pEntry->getMatrix ( ) )  {
           theImage = pEntry->arrayOfThumbs[0]->xForm ( *pEntry->getMatrix ( ) );
           theImage = theImage.smoothScale ( GroupView::m_iSize, GroupView::m_iSize, QImage::ScaleMin );
      }
      else
        theImage = pEntry->arrayOfThumbs[0]->smoothScale ( GroupView::m_iSize, GroupView::m_iSize, QImage::ScaleMin );
    }
    else {
      // No cache entry exists. So we have to create one.
      pEntry   = Global::pThumbsCache->append ( list[t], pGroupView );
      pItem    = new GroupView::Item ( pGroupView, fileInfo.fileName ( ), true );
      theImage = QImage ( ).fromMimeSource( "please_wait.jpg" );
      theImage = theImage.smoothScale ( GroupView::m_iSize, GroupView::m_iSize, QImage::ScaleMin );
      m_bCanClose = false;
    }
    thePixmap.convertFromImage ( theImage );
    pItem->setPixmap ( 0, thePixmap );
    pItem->pCache = pEntry;
  }
  QTimer::singleShot ( 10, pGroupView, SLOT ( slotAlternateColors ( ) ) );
}

bool DialogFiles::findDesktopDir ( QString qsDir )
{
  // This function takes an input file and searches it for the Desktop=... entry.
  // It will then invoke the shell to write the absolute path into a file in the temp directory.
  bool bReturn = false;
  QFile file ( qsDir );
  if ( file.open ( IO_ReadOnly ) ) {
    QTextStream stream( &file );
    QString line;
    while ( !stream.atEnd() ) {
      line = stream.readLine(); // line of text excluding '\n'
      if (line.find ("Desktop=") != -1)	{
	// found the coresponding line Desktop=$HOME/KDesktop or similar
	QStringList theList;
	theList = QStringList::split( QString("="), line );
	if ( theList.count() > 1 )  {
	  QString qsDesktop = theList[1];
	  if ( qsDesktop[ qsDesktop.length ( )-1 ] != '/' )
	       qsDesktop = qsDesktop + "/";
	  // here we get the complete path to the Desktop ...
	  QString command = QString ("echo -n ") + qsDesktop + QString ( " > " ) + Global::qsTempPath + QString ("/lucas.txt");
	  if ( system (command) == -1 )
	    bReturn = false;
	  bReturn = true;
	}
      }
    }
    file.close();
  }
  return bReturn;
}

void DialogFiles::timerEvent ( QTimerEvent *pEvent )
{
  // Called from the worker threads after a thumbnail has been generated.
  if ( pEvent->timerId ( ) == MEDIASCANNER_EVENT + 4 ) {
    int t;
    QPixmap  thePixmap;
    WorkWaiting *pWork;
    QValueList<WorkWaiting *> tempList;
    // to decrease threading issues, we quickly remove the used Work objects from the member list.
    lock ( );
    for ( t=0;t<(int)m_listOfWorkToDo.count ( ); t++ ) {
      pWork = m_listOfWorkToDo [ t ];
      m_listOfWorkToDo.remove( pWork );
      tempList.append ( pWork );
    }
    unlock ( );
    for ( t=0;t<(int)tempList.count ( ); t++ ) {
      pWork = tempList [ t ];
      if ( pWork->pItem && pWork->pImage ) {
	// We have to also make sure the item is still valid.
//        if ( ! lockDialog ( ) )
//          return;
	QIconViewItem *pValid = m_pPreview->firstItem ( );
	while ( pValid &&  m_pIAmAlive ) {
	  if  ( pWork->pItem == pValid ) {
	    createPix (  &thePixmap, pWork->pImage );
	    pWork->pItem->setPixmap    ( thePixmap );
	    if ( pWork->bMarkIcon )
	      markIcon ( pWork->pItem, 1 );

	    break;
	  }
	  pValid = pValid->nextItem ( );
	}
//	unlockDialog ( );
      }
      else if ( pWork->pItem ) {
	// Here we return from ScanDVDate and want to update the item
//        if ( ! lockDialog ( ) )
//          return;
	Thumbs   *pThumbs;
	QValueList<Thumbs *>::iterator it = m_listOfThumbs.begin ( );
	while ( it != m_listOfThumbs.end ( ) && m_pIAmAlive ) {
	  pThumbs = *it++;
	  if ( pThumbs->pOwnerItem->key ( ) == pWork->pItem->key ( ) ) {
	    setIconText ( pThumbs ); // Update Icon with new dateInfo
	    pThumbs->pOwnerItem->setPixmap ( *pThumbs->arrayOfPix[0] );
	    break;
	  }
	}
//	unlockDialog ( );
      }

      delete pWork;
      m_pProgressBar->setProgress ( m_iProgress ++ );
    }
    if ( (int)m_iProgress >= m_pProgressBar->totalSteps ( )-2 )
      m_pPreview->arrangeItemsInGrid ( TRUE );

    ScanDVDate *pScan = NULL;
    for ( t=0; t<(int)m_listOfDVScansToDo.count ( ); t++ ) {
      pScan = m_listOfDVScansToDo[t];
      if ( pScan->hasExited ( ) ) {
	m_listOfDVScansToDo.remove ( pScan );
	delete pScan;
      }
    }
  }
  else if ( pEvent->timerId ( ) == MEDIASCANNER_EVENT + 5 ) {
    debug_cout ( "MultiThumbRequest timer event. \n" );
    // Called after user manually reloads an image.
//    if ( ! lockDialog ( ) )
//      return;

    QPixmap thePixmap;
    Thumbs *pThumbs = NULL;
    QIconViewItem *pItem = NULL;
    Cache::Thumbs::Entry *pEntry = NULL;
    QValueList<Cache::Thumbs::Entry *>list = Global::pThumbsCache->getScannedThumbs ( );
    QValueList<Cache::Thumbs::Entry *>::iterator it;
    QValueList<Thumbs *>::iterator it2;
    bool bFound = false;

    it = list. begin ( );
    while ( it != list.end ( ) ) {
      pEntry = *it++;
      // Next we have to find the corresponding Item in the ListView 
      //int iCurrent = 0, iTotal = m_listOfThumbs.count ( );
      it2 = m_listOfThumbs.begin ( );
      while ( it2 != m_listOfThumbs.end ( ) && m_pIAmAlive ) {
	pThumbs = *it2++;
	if  ( pThumbs->pCache == pEntry ) {
	  pEntry->iScanStatus = 0;
	  if ( ! pEntry->arrayOfThumbs )
	         pEntry->loadImages  ( );

	  createPix ( pThumbs, 0 );
	  pThumbs->pOwnerItem->setPixmap ( *pThumbs->arrayOfPix[0] );
	  bFound = true;
	  break; // exit inner while loop
	}
      }
      if ( ! bFound ) {
	it2 = m_listOfThumbs.begin ( );
	while ( it2 != m_listOfThumbs.end ( ) && m_pIAmAlive ) {
	  pThumbs = *it2++;
	  if  ( pThumbs->pOwnerItem == pItem ) {
	    pEntry->iScanStatus = 0;
	    if ( ! pEntry->arrayOfThumbs )
	      pEntry->loadImages  ( );

	    createPix ( pThumbs, 0 );
	    pThumbs->pOwnerItem->setPixmap ( *pThumbs->arrayOfPix[0] );
	    bFound = true;
	    break; // exit inner while loop
	  }
	}
      }
    }
//    unlockDialog ( );
  }

  m_bCanChangeIcons = true;
  uiDialogFiles::timerEvent ( pEvent );
}

void DialogFiles::initWork ( QIconViewItem *pItem, QImage *pImage, bool bMarkIcon )
{
  WorkWaiting *pNewWork = new WorkWaiting ( pItem, pImage, bMarkIcon );
  lock   ( );
  m_listOfWorkToDo.append ( pNewWork );
  unlock ( );
}

// Virtual function overloaded in DialogImages
void DialogFiles::newThumbnailRequest ( QIconViewItem *pItem )
{
  ThumbnailRequest *pRequest = new ThumbnailRequest ( this, pItem, pItem->key ( ), m_iMultiThumbNumber );
  MediaCreator::registerWithMediaScanner ( pRequest );
}

bool DialogFiles::initScanDV ( Thumbs *pThumbs )
{
  // Also let me check if we have a dv file which we can scan for met info
  ScanDVDate *pScan = NULL;
  QFileInfo fileInfo ( pThumbs->pCache->qsFileName );
  if ( fileInfo.extension  ( ).lower ( ) == "dv" ) {
    pScan = new ScanDVDate ( this, pThumbs->pCache->qsFileName, pThumbs->pOwnerItem );
    // TODO: Might need to get pushed to main loop
    markIcon ( pThumbs->pOwnerItem, 2 );
    addProgress ( 1 ); // add on more thing to do.
    lock   ( );
    m_listOfDVScansToDo.append ( pScan );
    unlock ( );
    return true;
  }
  return false;
}

uint DialogFiles::thumbnailSize ( )
{
  return m_iThumbnailSize;
}

void DialogFiles::slotIconSelectionChanged ( )
{
  // Here we enable / disable the Buttons 
  QIconViewItem *pIcon = m_pPreview->firstItem ( );
  int iCount = 0;

  while  ( pIcon ) {
    if   ( pIcon->isSelected ( )  ) {
      if ( ++iCount > 1 )
	break;
    }
    pIcon = pIcon->nextItem ( );
  }

  m_pButtonReload->setEnabled ( iCount  > 0 );
  m_pButtonPlay->setEnabled   ( iCount == 1 );
}

void DialogFiles::slotPreviewPressed ( QIconViewItem *pItem, const QPoint &pos )
{
  if ( ! pItem )// User clicked on empty space in QIconView ( m_pPreview )
    showBasicMenu   ( pos );
  else
    showContextMenu ( pos, pItem );
}

void DialogFiles::slotPreviewClicked ( int iButton, QIconViewItem *pItem, const QPoint & )
{
  if ( ! pItem )
    return; // User clicked on empty space in QIconView ( m_pPreview )

  if ( iButton == Qt::RightButton )
    return;

  pItem->setSelected ( false );
  if ( m_pTimerThumbing->isActive ( ) )
       stopThumbing  ( );
  else {
    uint t;
    Thumbs *pThumb  = NULL;
    for ( t=0; t<m_listOfThumbs.count ( ); t++ ) {
      pThumb  =  m_listOfThumbs[t];
      if ( pThumb->pOwnerItem == pItem ) {
	// If we click the second time on a item we should stop the animation
	if ( m_pActiveThumbs == pThumb )
	  break;
	
	m_pActiveThumbs = pThumb;
	m_pTimerThumbing->start ( 1500 ); // Set timer to a nicely paced 1.5 seconds.
	return;
      }
    }
  }
  m_pActiveThumbs = NULL;
}

//////////////////////////////////
QPixmap &DialogFiles::createMenuHeader ( QString qsText, QSize size )
{
  static QPixmap header;
  header = QPixmap ( size );
  header.fill  ( 0x9999DD );
  QPainter painter ( &header );
  painter.drawText ( 0, 0, size.width ( ), size.height ( ), Qt::AlignCenter, qsText );

  return header;
}

void DialogFiles::slotAudioSubtitle ( int iID )
{
  if ( m_pContextMenu )
    delete m_pContextMenu;
  m_pContextMenu = NULL;

  Thumbs *pThumbs = NULL;
  QValueList<Thumbs *>::iterator it = m_listOfThumbs.begin ( );
  while ( it != m_listOfThumbs.end ( ) ) {
    pThumbs = *it++;
    if ( pThumbs->pOwnerItem->isSelected ( ) ) {
      break;
    }
  }
  if ( ! pThumbs )
    return;

  unsigned long long iPathHash, iFileHash;
  Manual         *pManual = NULL;
  Manual::Change *pChange = NULL;

  if ( iID == 98 )  { // reset entries
    // remove the mapOfManualChange entry and re-load the track info from the directory.
    bool bHasManualChange = pThumbs->getManualChange ( pManual, pChange, iPathHash, iFileHash );
    if ( bHasManualChange )  {
      if ( pManual && pChange )  {
        pManual->mapOfChange.remove ( iFileHash );
        delete pChange;
        pThumbs->findTracks ( );
      }
      if ( pManual && pManual->mapOfChange.count ( ) < 1 )  {
        pManual->mapOfChange.remove ( iPathHash );
        delete pManual;
      }
    }
  }
  else if ( iID == 99 )  { // Don't add tracks
    bool bHasManualChange = pThumbs->getManualChange ( pManual, pChange, iPathHash, iFileHash );
    if ( bHasManualChange )  {
      // To disregard all found tracks, we leave the Change entry but clear the lists
      pChange->clearAudioList     ( );
      pChange->clearSubtitleList  ( );
      // Should we do this here or in accepted () ???
      if ( pThumbs->pSourceFileInfo )  {
           pThumbs->pSourceFileInfo->deleteAudio     ( );
           pThumbs->pSourceFileInfo->deleteSubtitles ( );
      }
    }
  }
  else if ( iID < 200 )  {
    // User toggled a Audio track
    int iIdx = iID - 100;
    if ( iIdx+1 > (int)pThumbs->audioList.count ( ) )
      return;
    Audio *pAudio = pThumbs->audioList[iIdx];
    pThumbs->toggleAudioTrack ( pAudio );
  }
  else if ( iID >= 200 )  {
    // user toggled a sutitle track
    int iIdx = iID - 200;
    if ( iIdx+1 > (int)pThumbs->subtitleList.count ( ) )
      return;
    SubtitleEntry *pSubtitle = pThumbs->subtitleList[iIdx];
    pThumbs->toggleSubtitleTrack ( pSubtitle );
  }
}

/////////////////////////////////

void DialogFiles::showContextMenu ( const QPoint &pos, QIconViewItem * )
{
  int t, iID, iIDs[12], iStarRating = -2;
  Thumbs     *pThumbs = NULL;
  if ( m_pContextMenu )
    delete m_pContextMenu;
  m_pContextMenu = new QPopupMenu ( this );
  m_pContextMenu->setCheckable ( TRUE );

  QIconViewItem *pIcon = m_pPreview->firstItem ( );
  QValueList<QIconViewItem *>listIcons;
  QValueList<QIconViewItem *>::iterator it2;
  QValueList<Thumbs *>listSelected;
  QValueList<Thumbs *>::iterator it;

  while ( pIcon ) {
    if  ( pIcon->isSelected ( )  )
      listIcons.append   ( pIcon );
    pIcon = pIcon->nextItem ( );
  }

  it = m_listOfThumbs.begin ( );
  while ( it != m_listOfThumbs.end ( ) ) {
    pThumbs = *it++;
    if ( pThumbs->pOwnerItem->isSelected ( ) ) {
      listSelected.append ( pThumbs );
      if ( iStarRating == -2 )
           iStarRating  = (int)pThumbs->pCache->iStarRating;
      if ( iStarRating != (int)pThumbs->pCache->iStarRating )
           iStarRating  = -1;
    }
  }

  QPoint globalPos = pos, globalPos2 = pos;
  QPopupMenu *pStackMenu;
  pStackMenu = NULL;

  if ( listSelected.count ( ) == 1 )  {
    // Display language / subtitle menu only for single selectoin.
    Audio         *pAudio    =  NULL;
    SubtitleEntry *pSubtitle =  NULL;
    bool bHasAudioTracks     = false;
    bool bHasSubtitleTracks  = false;
    bool    bChecked         = false;
    int     iTrackNr;
    Utils   theUtils;
    QSize   size;
    QString qsTrackNr, qsFileName;
    QFileInfo fileInfo;

    pThumbs = listSelected[0];
    if ( pThumbs->audioList.count ( ) > 0 )
      bHasAudioTracks    = true;
    if ( pThumbs->subtitleList.count ( ) > 0 )
      bHasSubtitleTracks = true;

    if ( bHasAudioTracks || bHasSubtitleTracks )  {
      pStackMenu = new  QPopupMenu (  this  );
      pStackMenu->insertItem  ( tr ( "&Reload all entries" ),  98 );
      size = pStackMenu->sizeHint  ( );
      pStackMenu->insertItem  ( tr ( "&Don't add tracks" ),    99 );
      if ( ( size.width ( ) < 5 ) || ( size.height ( ) < 5 ) )
        size =  QSize ( 100, 15 );

      if ( bHasAudioTracks )  {
        pStackMenu->insertSeparator  ( );
        iID = pStackMenu->insertItem ( createMenuHeader ( tr ( "Audio tracks :" ), size ) );
        pStackMenu->setItemEnabled   ( iID, FALSE );
        iID      = 100;
        iTrackNr =   0;
        for ( t=0; t<(int)pThumbs->audioList.count ( ); t++ )  {
          pAudio     = pThumbs->audioList[t];
          fileInfo.setFile ( pAudio->qsFileName );
          qsFileName = fileInfo.fileName ( );
          qsTrackNr  = "x";
          // To decide if the track is enabled or not, we'll have to inquire the mapOfManualChange - entry
          bChecked  = pThumbs->audioTrackEnabled ( pAudio->qsFileName );
          if ( bChecked )  {
            iTrackNr ++;
            qsTrackNr = QString ( "%1" ).arg ( pAudio->iAudioNumber ); //iTrackNr );
          }
          iID = pStackMenu->insertItem ( tr ( "[%1]<%2> %3" ).arg ( qsTrackNr ).arg ( pAudio->qsIso639 ).arg ( qsFileName ), iID );
          pStackMenu->setItemChecked   ( iID++, bChecked );
        }
      }
      if ( bHasSubtitleTracks )  {
        pStackMenu->insertSeparator  ( );
        iID = pStackMenu->insertItem ( createMenuHeader ( tr ( "Subtitle tracks :" ), size ) );
        pStackMenu->setItemEnabled   ( iID, FALSE );
        iID         = 200;
        iTrackNr    =   0;
        for ( t=0; t<(int)pThumbs->subtitleList.count ( ); t++ )  {
          pSubtitle  = pThumbs->subtitleList[t];
          fileInfo.setFile ( pSubtitle->m_qsFileName );
          qsFileName = fileInfo.fileName ( );
          qsTrackNr  = "x";
          bChecked   = pThumbs->subtitleTrackEnabled ( pSubtitle->m_qsFileName );
          if ( bChecked )  {
            iTrackNr ++;
            qsTrackNr = QString ( "%1" ).arg ( pSubtitle->m_iSubtitleNumber ); //iTrackNr );
          }

          pStackMenu->insertItem      ( tr ( "[%1]<%2> %3" ).arg ( qsTrackNr ).arg ( pSubtitle->m_qsIso639 ).arg ( qsFileName ), iID );
          pStackMenu->setItemChecked  ( iID++, bChecked );
        }
      }
      globalPos.setY    ( globalPos.y ( ) - 65 );
      globalPos.setX    ( globalPos.x ( ) - pStackMenu->sizeHint ( ).width ( ) - 4 );
      connect ( pStackMenu, SIGNAL ( activated ( int ) ), this, SLOT ( slotAudioSubtitle ( int ) ) );
      pStackMenu->popup ( globalPos, 3 );
    }
  }

  iIDs[6]  = m_pContextMenu->insertItem ( tr ( "&Play" ),                   9 );
  iIDs[7]  = m_pContextMenu->insertItem ( tr ( "to &Source Group ..." ),   10 );
  iIDs[8]  = m_pContextMenu->insertItem ( tr ( "to &Virtual Folder ..." ), 11 );
  iIDs[9]  = m_pContextMenu->insertItem ( tr ( "&Reload" ),                12 );
  iIDs[10] = m_pContextMenu->insertItem ( tr ( "R&emove" ),                13 );
  if ( listIcons.count ( ) == listSelected.count ( ) ) {
    m_pContextMenu->insertSeparator ( );
    iIDs[11] = m_pContextMenu->insertItem ( tr ( "No Stars" ),              1 );
    for ( t=0; t<6; t++ )
      iIDs[t] = m_pContextMenu->insertItem( m_pixMenuStars[t], t+2 );
  }
  if ( listIcons.count ( ) < 1 ) {
    delete m_pContextMenu;
    m_pContextMenu = NULL;
    if ( pStackMenu )
      delete pStackMenu;
    return;
  }
  else if ( listIcons.count ( ) > 1 )
    m_pContextMenu->setItemEnabled ( iIDs[6], false );

  if ( listIcons.count ( ) != listSelected.count ( ) ) {
    m_pContextMenu->setItemEnabled ( iIDs[7], false );
    m_pContextMenu->setItemEnabled ( iIDs[8], false );
  }

  if ( iStarRating > -1 )
    m_pContextMenu->setItemChecked ( iStarRating + 1, TRUE );

  // last we check if we do have VirtualFolders ...
  if ( m_pListViewVirtual->childCount ( ) == 0 )
    m_pContextMenu->setItemEnabled ( iIDs[8],  FALSE );

  globalPos2.setY   ( globalPos2.y ( ) - 110 );
  iID = m_pContextMenu->exec ( globalPos2 );

  if ( iID == 0 ) { // Nothing selected ...
    delete m_pContextMenu;
    m_pContextMenu = NULL;
    if ( pStackMenu )
      delete pStackMenu;
    return;
  }

  stopThumbing ( );
  if ( ( iID > 0 ) && ( iID < 8 ) ) {  // StarRating
    if ( ! lockDialog ( ) )
      return;

    it = listSelected.begin ( );
    while ( it != listSelected.end ( ) ) {
      pThumbs = *it++;
      pThumbs->pCache->iStarRating = iID - 1;
      recreateThumbs  ( pThumbs );
    }
    Global::pThumbsCache->saveCacheDB ( );
    unlockDialog ( );
  }
  else if (  iID ==   9 ) {  // Play
    if ( listSelected.count ( ) )  {
      pThumbs = listSelected[0];
      play ( pThumbs->pCache, pThumbs->pOwnerItem );
    }
  }
  else if (  iID ==  10 )    // toSourceGroup
    toSourceGroup   ( 3 );
  else if (  iID ==  11 )    // toVirtualFolder
    toVirtualFolder ( 3 );
  else if (  iID ==  12 )    // Reload
    slotReload ( );
  else if (  iID ==  13 ) {  // Remove
    lock ( );
    it = listSelected.begin ( );
    while ( it != listSelected.end ( ) ) {
      pThumbs = *it++;
      m_listOfThumbs.remove  ( pThumbs );
      listIcons.remove ( pThumbs->pOwnerItem );
      if ( m_pActiveThumbs == pThumbs )
           m_pTimerThumbing->stop   ( );
      delete pThumbs->pOwnerItem;
      delete pThumbs;
    }
    it2 = listIcons.begin ( );
    while  (  it2 != listIcons.end ( ) )
      delete *it2++;
    unlock ( );
  }

  if ( pStackMenu )
    delete pStackMenu;
  delete m_pContextMenu;
  m_pContextMenu = NULL;
}

void DialogFiles::showBasicMenu ( const QPoint &pos )
{
  int t, iID, iIDs[7];
  QPopupMenu *pMenu   = new QPopupMenu ( this );
  pMenu->setCheckable ( TRUE );

  QIconViewItem *pIcon = m_pPreview->firstItem ( );
  QValueList<QIconViewItem *>listFailed;
  QValueList<QIconViewItem *>::iterator it2;
  QValueList<Thumbs *>listSelected;
  QValueList<Thumbs *>::iterator it;

  while ( pIcon ) {
    listFailed.append ( pIcon );
    pIcon = pIcon->nextItem ( );
  }

  it = m_listOfThumbs.begin ( );
  while ( it != m_listOfThumbs.end ( ) )
    listFailed.remove ( (*it++)->pOwnerItem );

  //maybe submenu ...
  iIDs[0] = pMenu->insertItem ( tr ( "All to &Virtual Folder ..." ), 1 );
  iIDs[1] = pMenu->insertItem ( tr ( "All to &Source Group ..." ),   2 );
  iIDs[2] = pMenu->insertItem ( tr ( "&Remove failed Thumbs" ),      3 );
  iIDs[3] = pMenu->insertItem ( tr ( "Re&load failed Thumbs" ),      4 );
  pMenu->insertSeparator ( );
  iIDs[4] = pMenu->insertItem ( tr ( "&Auto Group" ),                5 );
  iIDs[5] = pMenu->insertItem ( tr ( "&Refresh" ),                   6 );
  iIDs[6] = pMenu->insertItem ( tr ( "&Clear" ),                     7 );

  if ( m_pPreview->count ( ) < 1 ) {
    for ( t=0; t<7; t++ )
      pMenu->setItemEnabled ( iIDs[t], false );      
  }
  else if ( listFailed.count ( ) < 1 ) {
    pMenu->setItemEnabled ( iIDs[2], false );
    pMenu->setItemEnabled ( iIDs[3], false );
  }

  iID = pMenu->exec ( pos );

  if ( iID == 0 ) { // Nothing selected ...
    delete pMenu;
    return;
  }

  stopThumbing ( );
  if ( iID ==  1 ) // All to Virtual Folder
    toVirtualFolder ( 2 );
  else if ( iID  == 2 ) // All to Source Group
    toSourceGroup ( 2 );
  else if ( iID  == 3 ) { // Remove Failed
    it2 = listFailed.begin ( );
    while ( it2 != listFailed.end ( ) )
      delete *it2++;
  }
  else if ( iID == 4 ) { // Reload Failed
    // In case we have some error Icons around ...
    QPixmap thePixmap;
    QImage  theImage = QImage ( QImage ( ).fromMimeSource ( "please_wait.jpg" ) );
    createPix ( &thePixmap, &theImage );

    it2 = listFailed.begin ( );
    while ( it2 != listFailed.end ( ) ) {
      QIconViewItem    *pItem = *it2++;
      pItem->setPixmap ( thePixmap );
      newThumbnailRequest  ( pItem );
    }
    m_pPreview->arrangeItemsInGrid ( TRUE );
  }
  else if ( iID == 5 )  // Auto Group
    slotAutoGroup  ( );
  else if ( iID == 6 )  // Refresh
    slotRefresh    ( );
  else if ( iID == 7 )  // Clear
    clearPreview   ( );

  delete pMenu;
}

QValueList<QListViewItem *> DialogFiles::getSelectedVirtual ( )
{
  QValueList<QListViewItem *> list;
  QListViewItem *pItem = m_pListViewVirtual->firstChild ( );
  while ( pItem )  {
     if ( pItem->isSelected ( ) )
       list.append ( pItem );
    pItem = pItem->nextSibling ( );
  }
  return list;
}

void DialogFiles::slotDroppedOnPreview ( QDropEvent *pDropEvent, const QValueList<QIconDragItem> & )
{
  // First we check if it comes from one of the Groups
  if (  pDropEvent->source ( ) == m_pToolbox->currentItem ( ) )
    currentSourceToPreview ( );
}

void DialogFiles::currentSourceToPreview ( )
{
  // Okay this drop comes from a Group
  Thumbs    *pThumbs     = NULL;
  GroupView *pGroupView  = (GroupView       *)m_pToolbox->currentItem ( ); 
  GroupView::Item *pItem = (GroupView::Item *)pGroupView->currentItem ( );
  if ( ! lockDialog ( ) )
    return;

  if ( pItem ) {
    setQuickDir      ( -1 );
    setVirtualFolder ( -1 );
    m_qsCurrentDir = "/";

    // gotcha ...
    pThumbs = createFromCache ( pItem->pCache );
    pThumbs->pSourceFileInfo  = pItem->pSourceFileInfo;
    delete pItem;
    QTimer::singleShot ( 10, pGroupView, SLOT ( slotAlternateColors ( ) ) );
  }
  unlockDialog ( );
}

void DialogFiles::allSourcesToPreview ( )
{
  // Okay this drop comes from a Group
  Thumbs    *pThumbs     = NULL;
  GroupView *pGroupView  = (GroupView       *)m_pToolbox->currentItem ( ); 
  GroupView::Item *pItem = (GroupView::Item *)pGroupView->firstChild  ( );
  GroupView::Item *pTemp = NULL;
  if ( pItem ) {
    setQuickDir      ( -1 );
    setVirtualFolder ( -1 );
    m_qsCurrentDir = "/";
  }

  if ( ! lockDialog ( ) )
    return;

  while ( pItem ) {
    // gotcha ...
    pThumbs = createFromCache ( pItem->pCache );
    if ( pThumbs ) {
      pThumbs->pSourceFileInfo  = pItem->pSourceFileInfo;
      pTemp = (GroupView::Item *)pItem->nextSibling ( );
      delete  pItem;
      pItem = pTemp;
    }
    else
      pItem = (GroupView::Item *)pItem->nextSibling ( );
  }

  QTimer::singleShot ( 10, pGroupView, SLOT ( slotAlternateColors ( ) ) );
  unlockDialog ( );
}

void DialogFiles::slotVirtualChanged ( )
{
  bool bEnabled = false;
  QValueList<QListViewItem *> list = getSelectedVirtual ( );
  if ( list.count ( ) > 0 )
    bEnabled = true;

  m_pButtonEditVirtual  ->setEnabled ( bEnabled );
  m_pButtonDeleteVirtual->setEnabled ( bEnabled );
}

void DialogFiles::slotShowVirtual ( QListViewItem *pItem, const QPoint &, int iReset )
{
  if ( ! pItem )
    return;

  // reset button states
  setVirtualFolder ( -1 );
  setQuickDir      ( -1 );
  m_qsCurrentDir = "/";

  QCursor myCursor ( QCursor::WaitCursor );
  QApplication::setOverrideCursor ( myCursor );

  QString qsFolderName = pItem->text ( 0 );

  unsigned long long iHashValue;
  Cache::Thumbs::Entry *pEntry = NULL;
  Cache::Thumbs::VirtualFolder *pFolder = Global::pThumbsCache->findVirtualFolder ( qsFolderName, isImageDialog ( ) );
  if ( pFolder ) {

    if ( ! lockDialog ( ) )
      return;

    if ( iReset != -1 )
       clearPreview ( );

    m_iProgress = 0;
    m_pProgressBar->reset ( );
    m_pProgressBar->setTotalSteps ( pFolder->listOfFiles.count ( ) );
    int iCount  = 0;
    QValueList<Cache::Thumbs::VirtualFolder::VFile *>::iterator it;
    it = pFolder->listOfFiles.begin ( );
    while ( it != pFolder->listOfFiles.end ( ) ) {
      iHashValue = (*it++)->iFileHashValue;
      pEntry = Global::pThumbsCache->find  ( iHashValue, isImageDialog ( ) );
      if ( ! pEntry && isImageDialog ( ) )
             pEntry = Global::pThumbsCache->find ( iHashValue, false );
      if (   pEntry )
        createFromCache ( pEntry );

      iCount ++;
      if ( iCount%5 == 0 ) {
        m_pProgressBar->setProgress ( iCount );
        qApp->processEvents ( );
      }
    }
    m_pProgressBar->reset ( );
    unlockDialog ( );
  }

  QApplication::restoreOverrideCursor ( );
}

void DialogFiles::slotVirtualContextMenu ( QListViewItem *pItem, const QPoint &pos, int )
{
  QPopupMenu *pMenu   = new QPopupMenu  ( this );
  int iIDs[4];

  iIDs[0] = pMenu->insertItem ( tr ( "&Show" ),   1 );
  iIDs[0] = pMenu->insertItem ( tr ( "&Clone" ),  2 );
  pMenu->insertSeparator ( );
  iIDs[1] = pMenu->insertItem ( tr ( "&Add" ),    3 );
  iIDs[2] = pMenu->insertItem ( tr ( "&Edit" ),   4 );
  iIDs[3] = pMenu->insertItem ( tr ( "&Delete" ), 5 );

  if ( ! pItem ) {
    pMenu->setItemEnabled ( iIDs[0], false );
    pMenu->setItemEnabled ( iIDs[2], false );
    pMenu->setItemEnabled ( iIDs[3], false );
  }

  int iID = pMenu->exec  ( pos );

  if ( iID == 1 )  {
   clearPreview ( );
   QValueList<QListViewItem *>list = getSelectedVirtual ( );
    for ( uint t=0; t<list.count ( ); t ++ )
      slotShowVirtual ( list[t], pos, -1 ); // col );
  }
  else if  ( iID == 2 )
    slotCloneVirtual( );
  else if  ( iID == 3 )
    slotAddVirtual  ( );
  else if  ( iID == 4 )
    slotEditVirtual ( );
  else if  ( iID == 5 )
    slotDeleteVirtual ( );
  delete pMenu;
}

void DialogFiles::toVirtualFolder ( int iFromSourceGroup )
{
  // Pops open a new QListBox based Dialog.
  // No Ok / Cancel et. simply clicking on the
  // VirtualFolder Item will assign the object to this folder.
  bool bAlternate = false;
  if ( m_pVirtualFolderDialog )
    delete m_pVirtualFolderDialog;

  m_pTabWidget->setCurrentPage ( 1 );

  m_pVirtualFolderDialog = new QListBox ( NULL, "Test", Qt::WType_Dialog | Qt::WShowModal | Qt::WStyle_NoBorder  | Qt::WStyle_StaysOnTop );
  m_pVirtualFolderDialog->resize ( 200, 450 );

  QListViewItem *pFolder = m_pListViewVirtual->firstChild ( );
  while ( pFolder ) {
    bAlternate = ! bAlternate;
    new VFSelectItem ( bAlternate, m_pVirtualFolderDialog, pFolder->text ( 0 ) );
    pFolder = pFolder->nextSibling ( );
  }

  if ( iFromSourceGroup == 1 )
    connect ( m_pVirtualFolderDialog, SIGNAL ( pressed ( QListBoxItem * ) ), this, SLOT ( slotSourceToVirtualFolder ( QListBoxItem * ) ) );
  else if ( iFromSourceGroup == 2 )
    connect ( m_pVirtualFolderDialog, SIGNAL ( pressed ( QListBoxItem * ) ), this, SLOT ( slotAllToVirtualFolder ( QListBoxItem * ) ) );
  else
    connect ( m_pVirtualFolderDialog, SIGNAL ( pressed ( QListBoxItem * ) ), this, SLOT ( slotToVirtualFolder ( QListBoxItem * ) ) );
  m_pVirtualFolderDialog->show ( );
}

void DialogFiles::toSourceGroup ( int iFromSourceGroup )
{
  // Pops open a new QListBox based Dialog.
  // No Ok / Cancel et. simply clicking on the
  // VirtualFolder Item will assign the object to this folder.
  int t;
  bool bAlternate = false;
  if ( m_pVirtualFolderDialog )
    delete m_pVirtualFolderDialog;

  m_pVirtualFolderDialog = new QListBox ( NULL, "Test", Qt::WType_Dialog | Qt::WShowModal | Qt::WStyle_NoBorder  | Qt::WStyle_StaysOnTop );
  m_pVirtualFolderDialog->resize ( 200, 450 );

  for ( t=0; t<m_pToolbox->count ( ); t++ ) {
    bAlternate = ! bAlternate;
    new VFSelectItem ( bAlternate, m_pVirtualFolderDialog, m_pToolbox->itemLabel ( t ) );
  }

  if ( iFromSourceGroup == 1 )
    connect ( m_pVirtualFolderDialog, SIGNAL ( pressed ( QListBoxItem * ) ), this, SLOT ( slotSourceToSourceGroup ( QListBoxItem * ) ) );
  else if ( iFromSourceGroup == 2 )
    connect ( m_pVirtualFolderDialog, SIGNAL ( pressed ( QListBoxItem * ) ), this, SLOT ( slotAllToSourceGroup ( QListBoxItem * ) ) );
  else
    connect ( m_pVirtualFolderDialog, SIGNAL ( pressed ( QListBoxItem * ) ), this, SLOT ( slotToSourceGroup ( QListBoxItem * ) ) );
  m_pVirtualFolderDialog->show ( );
}

void DialogFiles::slotToVirtualFolder ( QListBoxItem *pSelItem )
{
  uint t, i;
  bool bSelected = true;
  QListViewItem *pFolderItem = NULL;
  VFSelectItem  *pItem = (VFSelectItem *)pSelItem;
  Cache::Thumbs::VirtualFolder *pVirtualFolder = NULL;
  Thumbs       *pThumbs;
  QValueList<Thumbs *>::iterator it;

  // This function is only called from m_pVirtualFolderDialog
  disconnect ( m_pVirtualFolderDialog );
  if ( pItem )  {
    QString qsFolderName = pItem->text ( );
    pVirtualFolder = Global::pThumbsCache->findVirtualFolder ( qsFolderName, isImageDialog ( ) );
    if ( pVirtualFolder ) {
      // First we have to get the selected items
      it = m_listOfThumbs.begin ( );
      while ( it != m_listOfThumbs.end ( ) ) {
	pThumbs = *it++;
	if ( pThumbs->pOwnerItem->isSelected ( ) )
	  pVirtualFolder->append ( pThumbs->pCache );
      }
      pFolderItem = m_pListViewVirtual->firstChild ( );
      while ( pFolderItem ) {
	if  ( pFolderItem->text ( 0 ) == qsFolderName )
	  break;
	pFolderItem = pFolderItem->nextSibling ( );
      }
      if ( pFolderItem )
	   pFolderItem->setText ( 1, QString ( "%1" ).arg ( pVirtualFolder->count ( ) ) );
      // And finally we give som visual feedback
      for ( t=0; t<9; t++ )  {
	m_pVirtualFolderDialog->setSelected ( pItem, bSelected );
	bSelected = ! bSelected;
	for ( i=0; i<10; i++ )  {
	  usleep ( 8000 ); // 8 ms
	  qApp->processEvents ( );
	}
      }
    }
    Global::pThumbsCache->saveVirtualFolder ( isImageDialog ( ) );
  }
  delete m_pVirtualFolderDialog;
  m_pVirtualFolderDialog = NULL;
}

void DialogFiles::slotAllToVirtualFolder ( QListBoxItem *pSelItem )
{
  uint t, i;
  bool bSelected = true;
  QListViewItem *pFolderItem = NULL;
  VFSelectItem  *pItem = (VFSelectItem *)pSelItem;
  Cache::Thumbs::VirtualFolder *pVirtualFolder = NULL;
  //Thumbs       *pThumbs;
  QValueList<Thumbs *>::iterator it;

  // This function is only called from m_pVirtualFolderDialog
  disconnect ( m_pVirtualFolderDialog );
  if ( pItem )  {
    QString qsFolderName = pItem->text ( );
    pVirtualFolder = Global::pThumbsCache->findVirtualFolder ( qsFolderName, isImageDialog ( ) );
    if ( pVirtualFolder ) {
      // First we have to get the selected items
      it = m_listOfThumbs.begin ( );
      while ( it != m_listOfThumbs.end ( ) )
	pVirtualFolder->append ( (*it++)->pCache );

      pFolderItem = m_pListViewVirtual->firstChild ( );
      while ( pFolderItem ) {
	if  ( pFolderItem->text ( 0 ) == qsFolderName )
	  break;
	pFolderItem = pFolderItem->nextSibling ( );
      }
      if ( pFolderItem )
	   pFolderItem->setText ( 1, QString ( "%1" ).arg ( pVirtualFolder->count ( ) ) );
      // And finally we give some visual feedback
      for ( t=0; t<9; t++ )  {
	m_pVirtualFolderDialog->setSelected ( pItem, bSelected );
	bSelected = ! bSelected;
	for ( i=0; i<10; i++ )  {
	  usleep ( 8000 ); // 8 ms
	  qApp->processEvents ( );
	}
      }
    }
    Global::pThumbsCache->saveVirtualFolder ( isImageDialog ( ) );
  }
  delete m_pVirtualFolderDialog;
  m_pVirtualFolderDialog = NULL;
}

void DialogFiles::slotSourceToVirtualFolder ( QListBoxItem *pSelItem )
{
  uint t, i;
  bool bSelected = true;
  QListViewItem *pFolderItem = NULL;
  VFSelectItem  *pItem = (VFSelectItem *)pSelItem;
  Cache::Thumbs::VirtualFolder *pVirtualFolder = NULL;

  // This function is only called from m_pVirtualFolderDialog
  disconnect ( m_pVirtualFolderDialog );
  if ( pItem )  {
    QString qsFolderName = pItem->text ( );
    pVirtualFolder = Global::pThumbsCache->findVirtualFolder ( qsFolderName, isImageDialog ( ) );
    if ( pVirtualFolder ) {
      // Here we determine the current selected SourceFileInfo
      GroupView *pGroupView       = (GroupView       *)m_pToolbox->currentItem ( ); 
      GroupView::Item *pGroupItem = (GroupView::Item *)pGroupView->currentItem ( );
      if ( pGroupItem ) // gotcha ...
        pVirtualFolder->append ( pGroupItem->pCache );
      // Next we change the number on the VirtualFolder
      pFolderItem = m_pListViewVirtual->firstChild ( );
      while ( pFolderItem ) {
        if  ( pFolderItem->text ( 0 ) == qsFolderName )
          break;
        pFolderItem = pFolderItem->nextSibling ( );
      }
      if ( pFolderItem )
           pFolderItem->setText ( 1, QString ( "%1" ).arg ( pVirtualFolder->count ( ) ) );
      // And finally we give som visual feedback
      for ( t=0; t<9; t++ )  {
        m_pVirtualFolderDialog->setSelected ( pItem, bSelected );
        bSelected = ! bSelected;
        for ( i=0; i<10; i++ )  {
          usleep ( 8000 ); // 8 ms
          qApp->processEvents ( );
        }
      }
    }
    Global::pThumbsCache->saveVirtualFolder ( isImageDialog ( ) );
  }
  delete m_pVirtualFolderDialog;
  m_pVirtualFolderDialog = NULL;
}

void DialogFiles::slotToSourceGroup ( QListBoxItem *pSelItem )
{
  Thumbs       *pThumbs;
  QValueList<Thumbs *>::iterator it;
  bool       bSelected  = true;
  int        t, i;
  QFileInfo  fileInfo;
  QImage     theImage;
  QPixmap    thePixmap;
  GroupView *pGroupView = NULL;
  GroupView::Item *pItem;

  // This function is only called from m_pVirtualFolderDialog
  disconnect ( m_pVirtualFolderDialog );
  if ( pSelItem ) {
    QString qsEntryName  =  pSelItem->text  ( );
    for  ( t=0; t<m_pToolbox->count  ( ); t++ ) {
      if ( m_pToolbox->itemLabel    ( t ) == qsEntryName ) {
	pGroupView = (GroupView *)m_pToolbox->item(  t  );
	break;
      }
    }
    if ( pGroupView ) {
      // First we have to get the selected items
      it = m_listOfThumbs.begin ( );
      while ( it != m_listOfThumbs.end ( ) ) {
	pThumbs = *it++;
	if ( pThumbs->pOwnerItem->isSelected ( ) ) {
	  fileInfo.setFile ( pThumbs->pCache->qsFileName );
	  if ( pThumbs->pCache )  {
	    if ( ! pThumbs->pCache->arrayOfThumbs )
	           pThumbs->pCache->loadImages  ( );
	    if (   pThumbs->pCache->getMatrix ( ) )  {
	      theImage = pThumbs->pCache->arrayOfThumbs[0]->xForm ( *pThumbs->pCache->getMatrix ( ) );
	      theImage = theImage.smoothScale ( GroupView::m_iSize, GroupView::m_iSize, QImage::ScaleMin );
	    }
	    else
	      theImage = pThumbs->pCache->arrayOfThumbs[0]->smoothScale ( GroupView::m_iSize, GroupView::m_iSize, QImage::ScaleMin );
	    thePixmap.convertFromImage ( theImage );
	    //pGroupView->insertItem ( thePixmap, fileInfo.fileName ( ) );
	    pItem = new GroupView::Item ( pGroupView, fileInfo.fileName ( ), true );
	    pItem->setPixmap ( 0, thePixmap );
	    pItem->pCache  =  pThumbs->pCache;
	  }
	}
      } // end while loop
      // And finally we give som visual feedback
      for ( t=0; t<9; t++ )  {
	m_pVirtualFolderDialog->setSelected ( pSelItem, bSelected );
	bSelected = ! bSelected;
	for ( i=0; i<10; i++ )  {
	  usleep ( 8000 ); // 8 ms
	  qApp->processEvents ( );
	}
      }
    }
  }
  delete m_pVirtualFolderDialog;
  m_pVirtualFolderDialog = NULL;
}

void DialogFiles::slotAllToSourceGroup ( QListBoxItem *pSelItem )
{
  Thumbs       *pThumbs;
  QValueList<Thumbs *>::iterator it;
  bool       bSelected  = true;
  int        t, i;
  QFileInfo  fileInfo;
  QImage     theImage;
  QPixmap    thePixmap;
  GroupView *pGroupView  = NULL;
  GroupView::Item *pItem = NULL;

  // This function is only called from m_pVirtualFolderDialog
  disconnect ( m_pVirtualFolderDialog );
  if ( pSelItem ) {
    QString qsEntryName  =  pSelItem->text  ( );
    for  ( t=0; t<m_pToolbox->count  ( ); t++ ) {
      if ( m_pToolbox->itemLabel    ( t ) == qsEntryName ) {
	pGroupView = (GroupView *)m_pToolbox->item(  t  );
	break;
      }
    }
    if ( pGroupView ) {
      // First we have to get the selected items
      it = m_listOfThumbs.end ( );
      while ( it != m_listOfThumbs.begin ( ) ) {
	pThumbs = *--it;
	fileInfo.setFile ( pThumbs->pCache->qsFileName );
	if ( pThumbs->pCache )  {
	  if ( ! pThumbs->pCache->arrayOfThumbs )
	         pThumbs->pCache->loadImages  ( );
	  if (   pThumbs->pCache->getMatrix ( ) )  {
	    theImage = pThumbs->pCache->arrayOfThumbs[0]->xForm ( *pThumbs->pCache->getMatrix ( ) );
	    theImage = theImage.smoothScale ( GroupView::m_iSize, GroupView::m_iSize, QImage::ScaleMin );
	  }
	  else
	    theImage = pThumbs->pCache->arrayOfThumbs[0]->smoothScale ( GroupView::m_iSize, GroupView::m_iSize, QImage::ScaleMin );
	  thePixmap.convertFromImage ( theImage );
	  //pGroupView->insertItem ( thePixmap, fileInfo.fileName ( ) );
	  pItem = new GroupView::Item ( pGroupView, fileInfo.fileName ( ), true );
	  pItem->setPixmap ( 0, thePixmap );
	  pItem->pCache  =  pThumbs->pCache;
	}
      } // end while loop
      // And finally we give some visual feedback
      for ( t=0; t<9; t++ )  {
	m_pVirtualFolderDialog->setSelected ( pSelItem, bSelected );
	bSelected = ! bSelected;
	for ( i=0; i<10; i++ )  {
	  usleep ( 8000 ); // 8 ms
	  qApp->processEvents ( );
	}
      }
    }
  }
  delete m_pVirtualFolderDialog;
  m_pVirtualFolderDialog = NULL;
}

void DialogFiles::slotSourceToSourceGroup ( QListBoxItem *pSelItem )
{
  bool      bSelected  = true;
  int       t, i;
  QFileInfo fileInfo;
  QPixmap   thePixmap;
  GroupView *pTargetGroup = NULL;
  GroupView *pSourceGroup = NULL;
  GroupView::Item *pSourceItem, *pTargetItem;

  // This function is only called from m_pVirtualFolderDialog
  disconnect ( m_pVirtualFolderDialog );
  if ( pSelItem ) {
    // First we get th GroupView where we want to move this item to.
    QString qsEntryName  =  pSelItem->text ( );
    for  ( t=0; t<m_pToolbox->count ( ); t++ ) {
      if ( m_pToolbox->itemLabel   ( t ) == qsEntryName ) {
	pTargetGroup = (GroupView *)m_pToolbox->item(  t  );
	break;
      }
    }
    pSourceGroup = (GroupView *)m_pToolbox->currentItem ( );
    if ( pTargetGroup && pSourceGroup )  {
      // First we have to get the selected items
      pSourceItem  = (GroupView::Item *)pSourceGroup->currentItem ( );
      if ( pSourceItem )  {
	// gotcha ...
	pTargetItem = new GroupView::Item ( pTargetGroup, pSourceItem->text ( 0 ), true );
	const QPixmap *pPixmap = pSourceItem->pixmap ( 0 );
	if ( pPixmap )
	  pTargetItem->setPixmap ( 0, *pPixmap );
	pTargetItem->pSourceFileInfo = pSourceItem->pSourceFileInfo;
	pTargetItem->pCache          = pSourceItem->pCache;
	// FInally we can delete the source item
	delete pSourceItem;
      }

      // And finally we give som visual feedback
      for ( t=0; t<9; t++ )  {
	m_pVirtualFolderDialog->setSelected ( pSelItem, bSelected );
	bSelected = ! bSelected;
	for ( i=0; i<10; i++ )  {
	  usleep ( 8000 ); // 8 ms
	  qApp->processEvents ( );
	}
      }
    }
  }
  delete m_pVirtualFolderDialog;
  m_pVirtualFolderDialog = NULL;
  if ( pTargetGroup )
    QTimer::singleShot ( 10, pTargetGroup, SLOT ( slotAlternateColors ( ) ) );
  if ( pSourceGroup )
    QTimer::singleShot ( 10, pSourceGroup, SLOT ( slotAlternateColors ( ) ) );
}

void DialogFiles::slotAddVirtual ( )
{
  QString qsHeader = tr ( "Enter name for Virtual Folder" );
  QString qsLabel  = tr ( "Enter name : " );
  QString qsNewFolder = QInputDialog::getText ( qsHeader, qsLabel );
  if ( qsNewFolder.isEmpty ( ) )
    return;

  unsigned int iFolderHash = Global::pThumbsCache->addVirtualFolder ( qsNewFolder, isImageDialog ( ) );
  if ( iFolderHash == 0 )
    return; // folder exists already.

  QString qsDate = QDateTime::currentDateTime ( ).toString ( "yyyy/MM/dd hh:mm:ss" );
  new QListViewItem ( m_pListViewVirtual, qsNewFolder, "0",  qsDate );
  Global::pThumbsCache->saveVirtualFolder ( isImageDialog ( ) );
}

void DialogFiles::slotCloneVirtual ( )
{
  QValueList<QListViewItem *>list = getSelectedVirtual ( );

  for ( uint t=0; t<list.count ( ); t++ )  {
    QListViewItem *pItem = list[t];
    QString qsFolderName = pItem ? pItem->text ( 0 ) : "";
    Cache::Thumbs::VirtualFolder *pFolder = Global::pThumbsCache->findVirtualFolder ( qsFolderName, isImageDialog ( ) );

    if ( pFolder ) {
      pFolder = pFolder->clone ( );
      QString qsDate = QDateTime::currentDateTime ( ).toString ( "yyyy/MM/dd hh:mm:ss" );
      new QListViewItem ( m_pListViewVirtual, pFolder->qsFolderName, QString ( "%1" ).arg ( pFolder->count ( ) ),  qsDate );
    }
  }
  if ( list.count ( ) > 0 )
    Global::pThumbsCache->saveVirtualFolder ( isImageDialog ( ) );
}

void DialogFiles::slotEditVirtual ( )
{
  QValueList<QListViewItem *> list = getSelectedVirtual ( );
  if ( list.count ( ) != 1 )
    return;

  DialogVFolder theDialog ( this );

  QListViewItem *pItem = list[0];
  QString qsFolderName = pItem ? pItem->text ( 0 ) : "";
  Cache::Thumbs::VirtualFolder *pFolder = Global::pThumbsCache->findVirtualFolder ( qsFolderName, isImageDialog ( ) );

  if ( pFolder ) {
    theDialog.initMe ( qsFolderName, isImageDialog ( ) );
    if ( theDialog.exec ( ) == QDialog::Accepted )  {
      // Next we get the info from the dialog and add it to the Virtual Folder
      pFolder->clear ( );
      QValueList<Cache::Thumbs::Entry *>list = theDialog.getEntries ( );
      QValueList<Cache::Thumbs::Entry *>::iterator it;
      it = list.begin ( );
      while ( it != list.end ( ) )
        pFolder->append (  *it++ );

      pItem->setText ( 1, QString ( "%1" ).arg ( list.count ( ) ) );
      Global::pThumbsCache->saveVirtualFolder ( isImageDialog ( ) );
    }
  }
}

void DialogFiles::slotDeleteVirtual ( )
{
  QValueList<QListViewItem *> list = getSelectedVirtual ( );
  if ( list.count ( ) > 0 ) {
    QString qsFolderName;
    QListViewItem *pItem = NULL;
    for ( uint t=0;  t<list.count ( ); t++ )
      qsFolderName += "\n" + list[t]->text ( 0 );
    if ( QMessageBox::warning ( this, tr ( "Warning Delete Virtual Folder." ),
           tr ( "Are you sure you want to delete the Virtual Folder\n%1" ).arg ( qsFolderName ), 
           QMessageBox::Yes, QMessageBox::No ) == QMessageBox::Yes )  {
      for ( uint t=0; t<list.count ( ); t++ )  {
        pItem = list[t];
        delete pItem; 
      }
      m_pButtonEditVirtual  ->setEnabled ( FALSE );
      m_pButtonDeleteVirtual->setEnabled ( FALSE );
      Global::pThumbsCache->deleteVirtualFolder ( qsFolderName, isImageDialog ( ) );
    }
  }
}

void DialogFiles::slotGroupContextMenu ( QListViewItem *pSelItem, const QPoint &pos, int )
{
  QPopupMenu *pMenu   = new QPopupMenu  ( this );
  int iIDs[8];
  iIDs[0] = pMenu->insertItem ( tr ( "to &Source Group ..." ),   1 ); // move this entry to different Group
  iIDs[1] = pMenu->insertItem ( tr ( "to &Virtual Folder ..." ), 2 ); // move this entry to Virtual Folder
  iIDs[2] = pMenu->insertItem ( tr ( "to &Preview -=>" ),        3 ); // move all entries to m_pPreview
  iIDs[3] = pMenu->insertItem ( tr ( "All &to Preview -=>" ),    4 ); // move all entries to m_pPreview
  if ( ! isImageDialog ( ) )
    iIDs[4] = pMenu->insertItem ( tr ( "&Play" ),                5 ); // play in player
  else
    iIDs[4] = pMenu->insertItem ( tr ( "C&omments ..." ),        5 ); // Edit Comment
  pMenu->insertSeparator ( );
  iIDs[5] = pMenu->insertItem ( tr ( "&Add" ),                   6 ); // add a new entry
  iIDs[6] = pMenu->insertItem ( tr ( "&Remove" ),                7 ); // remove this one entry
  iIDs[7] = pMenu->insertItem ( tr ( "&Clear All" ),             8 ); // simply remove entries

  if ( ! pSelItem ) {
    pMenu->setItemEnabled ( iIDs[0], false );
    pMenu->setItemEnabled ( iIDs[1], false );
    pMenu->setItemEnabled ( iIDs[2], false );
    pMenu->setItemEnabled ( iIDs[4], false );
    pMenu->setItemEnabled ( iIDs[6], false );
  }

  int iID = pMenu->exec  ( pos );

  GroupView::Item *pItem = (GroupView::Item *)pSelItem;
  GroupView *pGroupView  = (GroupView *)m_pToolbox->currentItem ( );

  if ( iID == 1 )       // to Source 
    toSourceGroup  ( 1 );
  else if ( iID == 2 )  // to Virtual
    toVirtualFolder( 1 );
  else if ( iID == 3 )  // to Preview
    currentSourceToPreview ( );
  else if ( iID == 4 )  // to Preview
    allSourcesToPreview    ( );
  else if ( iID == 5 )  // Play
    play  ( pItem->pCache );
  else if ( iID == 6 )  // Add
    addSourceToGroup ( pGroupView );
  else if ( iID == 7 )  // Remove
    delete pItem;
  else if ( iID == 8 ){ // Clear All
    GroupView::Item *pGroupItem, *pTemp;
    iID = m_pToolbox->currentIndex ( );
    QString qsLabel = m_pToolbox->itemLabel ( iID );
    if ( QMessageBox::warning ( this, tr ( "Warning Removing all Sources." ),
	   tr ( "Are you sure you want to remove all sources from group\n%1" ).arg ( qsLabel ), 
           QMessageBox::Yes, QMessageBox::No ) == QMessageBox::Yes )  {
      if ( pGroupView )  {
	pGroupItem = (GroupView::Item *)pGroupView->firstChild ( );
	while ( pGroupItem ) {
	  pTemp = (GroupView::Item *)pGroupItem->nextSibling ( );
	  delete  pGroupItem;
	  pGroupItem = pTemp;
	}
      }
    }
  }

  delete pMenu;
}

void DialogFiles::slotPlay ( )
{
  Thumbs *pThumbs;
  QValueList<Thumbs *>::iterator it;

  it = m_listOfThumbs.begin ( );
  while ( it != m_listOfThumbs.end ( ) ) {
    pThumbs = *it++;
    if ( pThumbs->pOwnerItem->isSelected ( ) ) {
      play  ( pThumbs->pCache, pThumbs->pOwnerItem );
      return;
    }
  }
}

void DialogFiles::slotDirectoryChanged ( QListViewItem *pItem )
{
  DirItem *pDirItem = (DirItem *)pItem;
  m_pActiveQuickButton = NULL;
  setCurrentDir ( pDirItem->dir ( ) );
  debug_cout ( "DialogFiles::slotDirectoryChanged <%s>\n", pDirItem->dir ( ).ascii ( ) );
}

void DialogFiles::slotAutoOpen ( )
{
  // This function is called from m_pTimerAutoOpen
  printf ( "AutoOpen NOW ...\n" );
}

void DialogFiles::slotQuickDir()
{
  // here we handle the quick directory buttons on the left side
  // of this dialog. They ought to be tagglod uniquely.
  QPushButton *pButtonArray[6] = {m_pButtonProject, m_pButtonDocuments, m_pButtonDesktop,
				  m_pButtonHome, m_pButtonRoot, m_pButtonTemp};
  QString *pStringArray[6] = {&m_qsProjectDir, &m_qsDocumentsDir, &m_qsDesktopDir,
			      &m_qsHomeDir, &m_qsRootDir, &m_qsTempDir};

  int t;

  setVirtualFolder ( -1 );
  for (t=0;t<6;t++)	{
    if ( ( pButtonArray[t]->isOn ( ) ) && 
	 ( pButtonArray[t] != m_pActiveQuickButton ) ) {
      setCurrentDir ( *pStringArray[t] );
    }
  }
}

void DialogFiles::setQuickDir ( int iCurrent )
{
  QPushButton *pButtonArray[6] = {m_pButtonProject, m_pButtonDocuments, m_pButtonDesktop,
				  m_pButtonHome, m_pButtonRoot, m_pButtonTemp};
  QLabel *pLabelArray[6] = {m_pLabelProject, m_pLabelDocuments, m_pLabelDesktop,
			    m_pLabelHome, m_pLabelRoot, m_pLabelTemp};

  int t;
  for  ( t=0; t<6; t++ )  {
    if ( t == iCurrent )  {
      m_pActiveQuickButton = pButtonArray[t];
      pButtonArray[t]->setOn (true);
      pButtonArray[t]->setPaletteBackgroundColor( QColor( COLOR_QUICK_SELECTED ) );
      pLabelArray[t] ->setPaletteBackgroundColor( QColor( COLOR_QUICK_SELECTED ) );
    }
    else  {
      pButtonArray[t]->setOn (false);
      pButtonArray[t]->setPaletteBackgroundColor( QColor( COLOR_QUICK_NORMAL ) );
      pLabelArray[t] ->setPaletteBackgroundColor( QColor( COLOR_QUICK_NORMAL ) );
    }
  }
}

void DialogFiles::setCurrentDir ( QString qsDir )
{
  int t, iCurrent = -1;
  for ( t=0; t<6; t++ )  {
    if ( qsDir == m_qsProjectDir )
      iCurrent = 0;
    else if ( qsDir == m_qsDocumentsDir )
      iCurrent = 1;
    else if ( qsDir == m_qsDesktopDir )
      iCurrent = 2;
    else if ( qsDir == m_qsHomeDir )
      iCurrent = 3;
    else if ( qsDir == m_qsRootDir )
      iCurrent = 4;
    else if ( qsDir == m_qsTempDir )
      iCurrent = 5;
  }

  if ( qsDir.right ( 1 ) != "/" )
    qsDir += "/";
  m_qsCurrentDir        = qsDir;
  Global::qsCurrentPath = qsDir;

  // We switch directories, so lets skip out of the preview generation ...
  MediaCreator::unregisterFromMediaScanner ( this );
  m_iProgress = 0;
  m_pProgressBar->reset ( );
  m_pProgressBar->setTotalSteps ( 0 );

  setQuickDir ( iCurrent );
  setTreeDir  (    qsDir );
  m_pTimerScanDir->start ( 333 ); // set timer to 333 ms
}

QString DialogFiles::currentDir ( )
{
  return m_qsCurrentDir;
}

void DialogFiles::setTreeDir ( QString qsDir )
{
  uint t;
  QStringList treeList = QStringList::split ( '/', qsDir );
  DirItem    *pSubDir;
  DirItem    *pDirItem = (DirItem *)m_pTreeList->firstChild ( );

  QCursor myCursor     ( QCursor::WaitCursor );
  QApplication::setOverrideCursor ( myCursor );

  for ( t=0; t<treeList.count ( ); t++ ) {
    pSubDir = pDirItem->findSubDir ( treeList[t] );
    if ( ! pSubDir ) {
      pDirItem->setOpen ( true );
      pSubDir = pDirItem->findSubDir ( treeList[t] );
      if ( ! pSubDir )
        break; // exit for - loop.
    }
    pDirItem = pSubDir;
  }
  if ( pDirItem ) {
    m_pTreeList->ensureItemVisible ( pDirItem );
    m_pTreeList->setSelected ( pDirItem, TRUE );
    pDirItem->setOpen ( true );
  }
  QApplication::restoreOverrideCursor ( );
}

/**************************************************
 **
 ** Here are the functions for the VirtualFolder tab
 **
 **************************************************/
void DialogFiles::slotSelectByStars ( )
{
  // The user wants to see only the videos 
  // with the selected numbe of stars
  QPushButton *array[] = { m_pButtonStar1, m_pButtonStar2, m_pButtonStar3, m_pButtonStar4, m_pButtonStar5, m_pButtonStar6 };
  QPushButton *pButton = NULL;

  setQuickDir ( -1 ); // This will set all QuickDirButtons to unselected
  m_qsCurrentDir = "";
  m_pActiveQuickButton = NULL;
  uint t, iCurrent = 0;
  for  ( t=0; t<6; t++ )  {
    if ( array[t]->hasMouse ( ) ) {
      iCurrent = t;
      pButton  = array[t];
      setVirtualFolder ( t );
    }
  }
  iCurrent ++;

  if ( ! pButton )
    return;

  if ( ! lockDialog ( ) )
    return;

  clearPreview ( );
  QCursor myCursor ( QCursor::WaitCursor );
  QApplication::setOverrideCursor ( myCursor );

  QValueList<Cache::Thumbs::Entry *>::iterator it;
  QValueList<Cache::Thumbs::Entry *>list = Global::pThumbsCache->getThumbsByStar ( iCurrent, isImageDialog ( ) );
  it = list.begin ( );
  while ( it != list.end ( ) )
    createFromCache  ( *it++ );

  updateTitlebar ( );
  QApplication::restoreOverrideCursor ( );
  unlockDialog ( );
}

// Allways protected by lockDialog ( )
DialogFiles::Thumbs *DialogFiles::createFromCache ( Cache::Thumbs::Entry *pCache )
{
  if ( ! pCache )
    return NULL;

  QIconViewItem *pItem;
  QString   qsFileName;

  m_pButtonAutoGroup->setEnabled ( true );

  pItem = new QIconViewItem ( m_pPreview );
  pItem->setKey ( pCache->qsFileName );

  Thumbs *pThumbs       = new Thumbs;
  pThumbs->pOwnerItem   = pItem;
  pThumbs->iNumberOfPix = pCache->iNumberOfThumbs;
  pThumbs->arrayOfPix   = new QPixmap *[pCache->iNumberOfThumbs];
  pThumbs->pCache       = pCache;
  if ( ! pCache->arrayOfThumbs )
         pCache->loadImages  ( );

  for ( uint i=0; i<pCache->iNumberOfThumbs; i++ ) {
    pThumbs->arrayOfPix[i] = new QPixmap;
    createPix ( pThumbs, i );
  }

  addPlayButton ( pItem, pThumbs->arrayOfPix[0] );
  setIconText   ( pThumbs );
  append ( pThumbs );
  return   pThumbs;
}

void DialogFiles::markIcon ( QIconViewItem *pItem, int iWhich )
{
  if ( ( ! pItem ) || ( iWhich > 2 ) )
    return;

  QPixmap copy;
  QImage  play;
  copy = *( pItem->pixmap ( ) );
  QPainter painter  ( &copy );

  if ( iWhich == 1 )
    play = QImage ( ).fromMimeSource ( "create_thumbs.png" );
  else
    play = QImage ( ).fromMimeSource ( "scan_dv.png" );

  play = play.smoothScale ( m_iThumbnailSize, m_iThumbnailSize );
  painter.drawImage ( 0, 0, play );
  pItem->setPixmap  ( copy );
}

void DialogFiles::setIconText ( QIconViewItem *pItem )
{
  if ( ! pItem )
    return;

  if ( m_bTooSmallForText )  {
    pItem->setText ( QString::null );
    return;
  }

  QString   qsText;
  QFileInfo fileInfo( pItem->key ( ) );

  if ( m_bName )
    qsText = fileInfo.fileName ( );

  if ( m_bDate )
    qsText += ( m_bName ? tr ( "\nD=" ) : tr ( "D=" ) ) + fileInfo.created ( ).toString ( "yy/MM/dd" );
  if ( m_bStars )
    qsText += ( ( m_bName || m_bDate ) ? tr ( "\nT=" ) : tr ( "T=" ) ) + fileInfo.created ( ).toString ( "hh:mm:ss" );

  if ( m_bLength )
    qsText += ( m_bName || m_bDate || m_bStars ) ? tr( "\nL=XX:XX:XX" ) : tr ( "L=XX:XX:XX" );

  pItem->setText ( qsText );
}

void DialogFiles::setIconText ( DialogFiles::Thumbs *pThumbs )
{
  if ( ( ! pThumbs ) || ( ! isValid ( pThumbs ) ) )
    return;

  if ( m_bTooSmallForText )  {
    pThumbs->pOwnerItem->setText ( QString::null );
    return;
  }

  QString   qsText;
  QFileInfo fileInfo ( pThumbs->pOwnerItem->key ( ) );

  if ( m_bName )
    qsText = fileInfo.fileName ( );

  if ( m_bDate )
    qsText += ( m_bName ? tr ( "\nD=" ) : tr ( "D=" ) ) + pThumbs->pCache->dateCreated.toString ( "yy/MM/dd" );
  if ( m_bStars )
    qsText += ( ( m_bName || m_bDate ) ? tr ( "\nT=" ) : tr ( "T=" ) ) + pThumbs->pCache->dateCreated.toString ( "hh:mm:ss" );

  if ( m_bLength )
    qsText += ( ( m_bName || m_bDate || m_bStars ) ? tr ( "\nL=" ) : tr ( "L=" ) ) + pThumbs->pCache->qsLength;

  pThumbs->pOwnerItem->setText ( qsText );
}

bool DialogFiles::isValid ( DialogFiles::Thumbs *pThumbs )
{
  QValueList<Thumbs *>::iterator it = m_listOfThumbs.begin ( );
  while ( it != m_listOfThumbs.end ( ) )  {
    if ( pThumbs == *it++ )
      return true;
  }
  return false;
}

bool DialogFiles::isValid ( QIconViewItem *pItem )
{
  QIconViewItem *pExisting = m_pPreview->firstItem ( );
  while ( pExisting ) {
    if  ( pExisting == pItem )
      return true;
    pExisting = pExisting->nextItem ( );
  }
  return false;
}

bool DialogFiles::removeThumb ( QIconViewItem *pItem )
{
  Thumbs   *pThumbs;
  QValueList<Thumbs *>::iterator it;
  it = m_listOfThumbs.begin ( );
  while ( it != m_listOfThumbs.end ( ) ) {
    pThumbs = *it++;
    if  ( pThumbs->pOwnerItem == pItem )  {
      if( m_pActiveThumbs   == pThumbs )
          stopThumbing ( );
      m_listOfThumbs.remove  ( pThumbs );
      delete pThumbs;
      return true;
    }
  }
  return false;
}

void DialogFiles::addPlayButton ( QIconViewItem *pItem, QPixmap *pPixmap )
{
  if ( ! pItem )
    return;

  int iX, iY, iFrameHeight, iDotSize;
  QPixmap copy;

  if ( pPixmap )
    copy = *pPixmap;
  else
    copy = *(pItem->pixmap ( ) );

  if ( ( 0 ) && ( m_iThumbnailSize > 50 ) ) {
    // Hmmm, this looks nice but prevents the >Preview< part of the thumbnails
    // So for now we'll disable this feature
    QImage  semi ( m_iThumbnailSize, m_iThumbnailSize, 32 );
    QImage  play  =  QImage  ( ).fromMimeSource ( "button_play.png" ); //( "thumbs_play.png" );
    QPainter painter   ( &copy );

    semi.fill    ( 0xAAAAAAFF  );
    semi.setAlphaBuffer ( true );

    // Draw the PlayButton
    iX = (int)( ( m_iThumbnailSize - play.width  ( ) ) / 2.0 ) + 2;
    iY = (int)( ( m_iThumbnailSize - play.height ( ) ) / 2.0 ) + 2;
    painter.drawImage (  2,  2, semi );
    painter.drawImage ( iX, iY, play );

    // Draw the MovieFrame
    QBrush blackBrush ( QColor (   0,   0,   0 ) );
    QBrush whiteBrush ( QColor ( 220, 220, 255 ) );
    iDotSize     =  6;
    iFrameHeight = 12;
    iY = m_iThumbnailSize - iFrameHeight + 2;
    iX = 4;
    painter.fillRect  ( 2,  2, m_iThumbnailSize, iFrameHeight, blackBrush );
    painter.fillRect  ( 2, iY, m_iThumbnailSize, iFrameHeight, blackBrush );

    while ( iX < (int)m_iThumbnailSize ) {
      painter.fillRect ( iX,    5, iDotSize, iDotSize, whiteBrush );
      painter.fillRect ( iX, iY+3, iDotSize, iDotSize, whiteBrush );
      iX += iDotSize + 4;
    }
  }
  pItem->setPixmap ( copy );
}

// Allways proteced through lockDialog ( )
void DialogFiles::recreateThumbs ( Thumbs *pThumbs )
{
  if ( ( ! pThumbs ) || ( ! pThumbs->pCache ) )
    return;

  if ( ! pThumbs->pCache->arrayOfThumbs )
         pThumbs->pCache->loadImages  ( );

  for ( uint i=0; i < pThumbs->pCache->iNumberOfThumbs; i++ )
    createPix ( pThumbs, i );

  pThumbs->pOwnerItem->setPixmap ( *pThumbs->arrayOfPix[pThumbs->iCurrentPix] );
}

SourceFileInfo *DialogFiles::findSourceFileInfo ( QIconViewItem *pIcon )
{
  Thumbs   *pThumbs = NULL;
  QValueList<Thumbs *>::iterator it;
  it = m_listOfThumbs.begin ( );
  while ( it != m_listOfThumbs.end ( ) ) {
    pThumbs = *it++;
    if  ( pThumbs->pOwnerItem == pIcon )
      return  pThumbs->pSourceFileInfo;
  }
  return NULL;
}

void DialogFiles::setVirtualFolder ( int iFolder )
{
  // The user wants to see only the videos 
  // with the selected numbe of stars
  QPushButton *array[] = { m_pButtonStar1, m_pButtonStar2, m_pButtonStar3, m_pButtonStar4, m_pButtonStar5, m_pButtonStar6 };
  int t;
  for ( t=0; t<6; t++ )  {
    if ( t == iFolder )  {
      array[t]->setOn (  true );
      array[t]->setPaletteBackgroundColor( QColor( COLOR_QUICK_SELECTED ) );
    }
    else {
      array[t]->setOn ( false );
      array[t]->setPaletteBackgroundColor( QColor( COLOR_QUICK_NORMAL ) );
    }
  }
}

/**************************************************
 **
 ** Here the actual work starts.
 **
 ** first we are going to read in the directory,
 ** - displaying all movies with a temp thumb
 ** - scanning in the first frame of each movie
 ** - scan in X more preview thumbs per movie
 **
 **************************************************/

void DialogFiles::slotScanDir ( )
{
  // called from the following timer from within setCurrentDir
  m_pTimerScanDir->stop ( );
  QDir        theDir ( m_qsCurrentDir );
  QString     qsFilter    = getDirFilter ( );
  QStringList listOfFiles = theDir.entryList ( qsFilter, QDir::Files );
  QStringList listOfVideos;

  QStringList::Iterator it;
  it = listOfFiles.begin ( );
  // Make sure we always have the abs Path in m_qsCurrentPath
  m_qsCurrentDir = theDir.absPath ( ) + "/";

  while ( it != listOfFiles.end ( ) )
    listOfVideos.append ( m_qsCurrentDir + *it++ );

  clearPreview ( );
  load ( listOfVideos );
}

QString DialogFiles::getDirFilter ( )
{
  return Global::pApp->getMovieFilter ( );
}

void DialogFiles::load ( QStringList &listOfVideos )
{
  QImage    theImage;
  QPixmap   thePixmap;
  QString   qsFileName, qsFile;
  QFileInfo fileInfo;
  QIconViewItem *pItem = NULL;

  if ( listOfVideos.count ( ) < 1 ) {
    m_pButtonAutoGroup->setEnabled ( false );
    return;
  }
  m_pButtonAutoGroup->setEnabled ( true );

  QCursor myCursor ( QCursor::WaitCursor );
  QApplication::setOverrideCursor ( myCursor );

  m_iProgress            = 0;
  m_bExitScannFunction   = true; // DialogImages. Exit loop
  m_pProgressBar->reset ( );
  m_pProgressBar->setTotalSteps ( listOfVideos.count ( ) );
  // First we should remove outstanding tasks ...
  MediaCreator::unregisterFromMediaScanner ( this );

  if ( ! lockDialog ( ) )
    return;

  theImage = QImage ( QImage ( ).fromMimeSource ( "please_wait.jpg" ) );
  createPix ( &thePixmap, &theImage );

  Cache::Thumbs::Entry *pCache = NULL;
  // get the first frame as the initial thumbnail.
  QStringList::iterator it = listOfVideos.begin ( );
  while ( it != listOfVideos.end ( ) )  {
    qsFileName = *it++;
    fileInfo.setFile ( qsFileName );
    qsFile = fileInfo.fileName  ( );
    pItem  = new  QIconViewItem ( m_pPreview ); //, qsFile+"\nXX:XX:XX" );
    pItem->setKey ( qsFileName ); // pItem->text will be changed after scan returns with a preview
    pCache = Global::pThumbsCache->find ( qsFileName, isImageDialog ( qsFileName ) );
    if ( pCache )  {
      Thumbs  *pThumbs      = new Thumbs;
      pThumbs->pOwnerItem   = pItem;
      pThumbs->iNumberOfPix = pCache->iNumberOfThumbs;
      pThumbs->arrayOfPix   = new QPixmap *[pCache->iNumberOfThumbs];
      pThumbs->pCache       = pCache;
      if ( ! pCache->arrayOfThumbs )
             pCache->loadImages  ( );

      for ( uint i=0; i<pCache->iNumberOfThumbs; i++ )  {
        pThumbs->arrayOfPix[i] = new QPixmap;
        createPix ( pThumbs, i );
      }
      addPlayButton ( pItem, pThumbs->arrayOfPix[0] );
      setIconText   ( pThumbs );
      append ( pThumbs );
      m_iProgress++;
    }
    else  {
      // We could not find the information in the cache so we have to create it
      pItem->setPixmap ( thePixmap );
      setIconText          ( pItem );
      newThumbnailRequest  ( pItem );
    }
    m_pProgressBar->setProgress ( m_iProgress );
  }
  m_pPreview->arrangeItemsInGrid ( TRUE );

  m_pProgressBar->setProgress ( m_iProgress );
  updateTitlebar ( );
  unlockDialog   ( );
  QApplication::restoreOverrideCursor     ( );
}

void DialogFiles::createPix ( Thumbs *pThumbs, uint iIdx )
{
  if ( ! pThumbs || ! pThumbs->pCache )
    return;

  if ( ! isValid ( pThumbs->pOwnerItem ) )
    return;

  float fPos = 0.0f;
  Cache::Thumbs::Entry *pCache = pThumbs->pCache;
  if ( pCache->iNumberOfThumbs > 1 )
       fPos = (float)iIdx / (pCache->iNumberOfThumbs-1);

  if ( pCache->getMatrix ( ) ) {
    QImage tempImage = pCache->arrayOfThumbs[iIdx]->xForm ( *pCache->getMatrix ( ) );
    createPix ( pThumbs->arrayOfPix[iIdx], &tempImage, fPos, pCache->iStarRating );
  }
  else
    createPix ( pThumbs->arrayOfPix[iIdx], pCache->arrayOfThumbs[iIdx], fPos, pCache->iStarRating );
}

void DialogFiles::createPix ( QPixmap *pTarget, QImage *pSource, float fPosition, int iStarRating )
{
  if ( ( ! pTarget ) || ( ! pSource ) )
    return;

  int iBorder    = 2; // add 2 * 2 = 4 to m_iThumbnailSize
  int iThumbSize = m_iThumbnailSize + 2 * iBorder;
  int iPosLength = 0;
  int iWidth, iHeight, iX, iY;
  QPixmap scaledPix;
  QImage  scaledImage;

  scaledImage = pSource->smoothScale ( m_iThumbnailSize, m_iThumbnailSize, QImage::ScaleMin );
  scaledPix.convertFromImage ( scaledImage );

  iPosLength = (int)(fPosition * iThumbSize);
  *pTarget   = QPixmap   ( iThumbSize, iThumbSize + m_pixIconStars[0].height ( ) );

  QPainter thePainter    (    pTarget    );
  QColor   clrBlue       ( 120, 120, 255 );
  QColor   clrDBlue      (  20,  20, 180 );
  pTarget->fill ( QColor ( 222, 222, 222 ) );
  iWidth  = scaledPix.width  ( );
  iHeight = scaledPix.height ( );
  iX = (int)((iThumbSize - iWidth ) / 2.0 );
  iY = (int)((iThumbSize - iHeight) / 2.0 );

  // First we center the image and copy it over
  copyBlt ( pTarget, iX, iY, &scaledPix, 0, 0, iWidth, iHeight );

  // Next we draw the Frame
  thePainter.setPen   ( clrBlue  );
  thePainter.drawLine (            0,            0, iThumbSize-1,            0 );
  thePainter.drawLine ( iThumbSize-1,            0, iThumbSize-1, iThumbSize-1 );
  thePainter.drawLine ( iThumbSize-1, iThumbSize-1,            0, iThumbSize-1 );
  thePainter.drawLine (            0, iThumbSize-1,            0,            0 );

  // next we check for StarRatings icons
  if ( iStarRating  < 0 )
       iStarRating  = 0;
  if ( iStarRating >= 0 )
    copyBlt ( pTarget, 0, m_iThumbnailSize+4, &m_pixIconStars[iStarRating] );

  // and lastly we draw the progress bar
  if ( iPosLength > 0 ) {
    thePainter.setPen   ( clrDBlue );
    thePainter.drawLine ( 0, iThumbSize+0,  iPosLength, iThumbSize+0 );
    thePainter.drawLine ( 0, iThumbSize+1,  iPosLength, iThumbSize+1 );
  }
}

void DialogFiles::slotSizeReleased ( )
{
  stopThumbing ( );
  bool bOkay;
  int  iNewSize = m_pEditSize->text ( ).toInt ( &bOkay );
  if ( bOkay ) {
    m_iThumbnailSize = iNewSize;
    resizeIcons ( iNewSize );
  }
}

void DialogFiles::slotSizeChanged ( int iNewSize )
{
  m_pEditSize ->setText ( QString ( "%1" ).arg ( iNewSize ) );
  m_iThumbnailSize  = iNewSize;
}

void DialogFiles::slotThumbing ( )
{
  // called from the timer every 1.5 seconds
  if ( ! m_pActiveThumbs ) {
    stopThumbing ( );
    return;
  }
  // Increase the current counter.
  m_pActiveThumbs->iCurrentPix ++;
  if ( m_pActiveThumbs->iCurrentPix >= m_pActiveThumbs->iNumberOfPix )
       m_pActiveThumbs->iCurrentPix  = 0;
  m_pActiveThumbs->pOwnerItem->setPixmap ( *m_pActiveThumbs->arrayOfPix[m_pActiveThumbs->iCurrentPix] );
}

void DialogFiles::stopThumbing ( )
{
  m_pTimerThumbing->stop ( );
  if ( ! m_pActiveThumbs )
    return;

  if ( m_pActiveThumbs->iCurrentPix >= m_pActiveThumbs->iNumberOfPix )
       m_pActiveThumbs->iCurrentPix  = 0;

  addPlayButton ( m_pActiveThumbs->pOwnerItem, m_pActiveThumbs->arrayOfPix[m_pActiveThumbs->iCurrentPix] );
  m_pActiveThumbs = NULL;
}

void DialogFiles::append ( Thumbs *pThumbs )
{
  lock   ( );
  m_listOfThumbs.append ( pThumbs );
  unlock ( );

  // Let us check the directory if there are some additional audio tracks.
  pThumbs->findTracks ( );

  setIconText ( pThumbs );
}

void DialogFiles::resizeIcons ( int iNewSize )
{
  uint   iNumberOfPix = 10;
  uint   t, iX, iY;
  double fRatio = 1.0;
  Thumbs *pThumbs;
  QValueList<Thumbs *>::iterator it;

  if ( m_listOfThumbs.count ( ) < 1 )
    return;

  it = m_listOfThumbs.begin ( );
  pThumbs = m_listOfThumbs[0];
  if ( ! pThumbs )
    return;

  QCursor myCursor ( QCursor::WaitCursor );
  QApplication::setOverrideCursor ( myCursor );
  m_bCanClose       = false;
  m_bCanChangeIcons = false;

  iNumberOfPix = pThumbs->iNumberOfPix;
  // keep the 4 extra pixels for the pixmap of the pOwnerItem in mind.
  fRatio = (double)(4.0+iNewSize) / pThumbs->pOwnerItem->pixmap ( )->width  ( );
  bool bReDrawText   = ( ( iNewSize < 51 ) != m_bTooSmallForText );
  m_bTooSmallForText =   ( iNewSize < 51 );

  m_pProgressBar->reset ( );
  m_pProgressBar->setTotalSteps ( ( m_listOfThumbs.count ( )-1 ) * iNumberOfPix );
  m_iProgress = 0;
  qApp->processEvents ( );
  // First we should resize m_pixIconStars [6]

  if ( ! lockDialog ( ) )
    return;

  createIconStars ( );
  // the first iteration we'll go through the first image only and set the IconViewItems image.
  while ( it != m_listOfThumbs.end ( ) )  {
    pThumbs   = *it++;
    if ( ! pThumbs->pCache->arrayOfThumbs )
           pThumbs->pCache->loadImages  ( );

    iX = (int)( fRatio * pThumbs->pOwnerItem->x ( ) );
    iY = (int)( fRatio * pThumbs->pOwnerItem->y ( ) );
    createPix ( pThumbs, 0 );

    pThumbs->pOwnerItem->setPixmap ( *pThumbs->arrayOfPix[0] );
    pThumbs->pOwnerItem->move      ( iX, iY );

    if ( bReDrawText )
      setIconText ( pThumbs );
  }
  m_iProgress = m_listOfThumbs.count ( );
  m_pPreview->updateContents  ( );
  m_pProgressBar->setProgress ( m_iProgress );
  qApp->processEvents ( );

  // Second run through will generate all remaining thumbs ...
  it = m_listOfThumbs.begin ( );
  while ( it != m_listOfThumbs.end ( ) ) {
    pThumbs = *it++;
    for (  t=1; t<pThumbs->iNumberOfPix; t++)
      createPix ( pThumbs, t );

    addPlayButton ( pThumbs->pOwnerItem, pThumbs->arrayOfPix[pThumbs->iCurrentPix] );

    m_iProgress  += (pThumbs->iNumberOfPix - 1);
    m_pProgressBar->setProgress ( m_iProgress );
    qApp->processEvents ( );
  }

  m_pProgressBar->reset ( );
  QApplication::restoreOverrideCursor ( );
  unlockDialog ( );

  m_bCanClose       = true;
  m_bCanChangeIcons = true;
}

void DialogFiles::addProgress ( int iAddProgress )
{
  // Called from another thread ...
  m_iProgress += iAddProgress;
  QTimer::singleShot ( 10, this, SLOT ( slotSetProgress ( ) ) );
}

void DialogFiles::slotSetProgress ( )
{
  // Update in main thread
  m_pProgressBar->setProgress ( m_iProgress );
}

void DialogFiles::slotAttrib ( bool )
{
  // One of the attribute check boxes was pushed.
  m_bStars  = m_pCheckStars ->isOn ( );
  m_bName   = m_pCheckName  ->isOn ( );
  m_bDate   = m_pCheckDate  ->isOn ( );
  m_bLength = m_pCheckLength->isOn ( );

  QString qsText;
  QFileInfo fileInfo;
  QValueList<QIconViewItem *> fullList;
  QIconViewItem *pItem = m_pPreview->firstItem ( );
  while ( pItem ) {
    fullList.append ( pItem );
    pItem = pItem->nextItem ( );
  }

  // First we handle all items which we have a Thumbs - structure for.
  Thumbs   *pThumbs;
  QValueList<Thumbs *>::iterator it = m_listOfThumbs.begin ( );
  while ( it != m_listOfThumbs.end ( ) ) {
    pThumbs = *it++;
    // no longer required to handle
    fullList.remove ( pThumbs->pOwnerItem );
    setIconText ( pThumbs );
  }

  QValueList<QIconViewItem *>::iterator it2 = fullList.begin ( );
  while ( it2 != fullList.end ( ) )
    setIconText ( *it2++ );
}

void DialogFiles::slotAutoGroup ( )
{
  static unsigned int iGroupDelta = 60 * 60 * 24; // = 86400 == one day
  static unsigned int iMinNumber  = 1;

  m_pTabWidget->setCurrentPage ( 2 );

  bool    bFound;//,    bOkay;
  Thumbs *pThumbs,  *pTemp;
  QValueList<Thumbs *>list;
  QValueList<Thumbs *>::iterator it2, it = m_listOfThumbs.begin ( );
  int iSecsTo;
  unsigned int iVideoCount = 0;

  if ( m_listOfThumbs.count ( ) < 1 )
    return;

  DialogDelta deltaDialog ( this, isImageDialog ( ), iGroupDelta, iMinNumber );
  if ( deltaDialog.exec ( ) == QDialog::Rejected )
    return;

  iGroupDelta = deltaDialog.groupDelta ( );
  iMinNumber  = deltaDialog.minNumber  ( );

  // In order to build groups we have to sort by date
  while ( it != m_listOfThumbs.end ( ) ) {
    pThumbs = *it++;
    bFound = false;
    it2 = list.begin ( );
    while ( it2 != list.end ( ) ) {
      pTemp = *it2;
      // Simple bubble sort to keep things ... well ... simple.
      if ( pTemp->pCache->dateCreated > pThumbs->pCache->dateCreated ) {
        list.insert ( it2, pThumbs ); // insert before it2
        bFound = true;
        break;
      }
      it2 ++;
    }
    if ( ! bFound )
      list.append ( pThumbs );
  }

  // There is one special check in case there is only one Group in the GroupView which is empty ...
  if ( ( list.count ( ) > 0 ) && ( m_pToolbox->count ( ) == 1 ) )  {
    GroupView *pGroupView = (GroupView *)m_pToolbox->item ( 0 );
    if ( pGroupView && pGroupView->childCount ( ) == 0 )  {
      m_pToolbox->removeItem ( pGroupView );
      delete pGroupView;
    }
  }

  // At this point we should have the thumbs sorted by date in the list
//  it = list.begin ( );
  it = list.end ( );
  QStringList emptyList;
  GroupView  *pGroupView;
  QString     qsDate, qsDateFormat = tr ( "(yyyy/MM/dd)" );
  if ( list.count ( ) > 0 ) {
    pTemp  = *--it;
    if ( isImageDialog ( ) )
      qsDate = tr ( "Images " ) + pTemp->pCache->dateCreated.toString ( qsDateFormat );
    else
      qsDate = tr ( "Videos " ) + pTemp->pCache->dateCreated.toString ( qsDateFormat );
    //printf ( "<%010d> <%s> <%s>\n", 0, pTemp->pCache->dateCreated.toString ( ).ascii ( ), pThumbs->pCache->qsFileName.ascii ( ) );
    pGroupView  = addGroup ( qsDate, emptyList );
    pGroupView->append ( pTemp );
    while ( it != list.begin ( ) ) {
      pThumbs  = *--it;
      //iSecsTo  = pTemp->pCache->dateCreated.secsTo ( pThumbs->pCache->dateCreated );
      iSecsTo  = pThumbs->pCache->dateCreated.secsTo ( pTemp->pCache->dateCreated );
      if ( iSecsTo <  0 )
           iSecsTo *=-1;
      //printf ( "<%010d> <%s> <%s>\n", iSecsTo, pThumbs->pCache->dateCreated.toString ( ).ascii ( ), pThumbs->pCache->qsFileName.ascii ( ) );
      if ( ( (unsigned int)iSecsTo > iGroupDelta ) && ( iVideoCount >= iMinNumber ) )  {
        if ( isImageDialog ( ) )
          qsDate = tr ( "Images " ) + pThumbs->pCache->dateCreated.toString ( qsDateFormat );
        else
          qsDate = tr ( "Videos " ) + pThumbs->pCache->dateCreated.toString ( qsDateFormat );
        QTimer::singleShot ( 10, pGroupView, SLOT ( slotAlternateColors ( ) ) );
        pGroupView  = addGroup ( qsDate, emptyList );
        pTemp = pThumbs;
        iVideoCount = 0;
      }
      iVideoCount ++;
      pGroupView->append ( pThumbs );
//      pTemp = pThumbs;
    }
    QTimer::singleShot ( 10, pGroupView, SLOT ( slotAlternateColors ( ) ) );
    clearPreview ( );
  }
}

void DialogFiles::slotReload ( )
{
  Thumbs *pThumbs = NULL;
  QImage  theImage;
  QPixmap thePixmap;

  QIconViewItem *pIcon = m_pPreview->firstItem ( );
  QValueList<QIconViewItem *>listIcons;
  QValueList<QIconViewItem *>::iterator it2;
  QValueList<Thumbs *>listSelected;
  QValueList<Thumbs *>::iterator it;

  if ( ! lockDialog ( ) )
    return;

  while ( pIcon ) {
    if  ( pIcon->isSelected ( )  )
      listIcons.append   ( pIcon );
    pIcon = pIcon->nextItem ( );
  }
  if ( listIcons.count ( ) < 1 )  {
    unlockDialog ( );
    return;
  }

  it = m_listOfThumbs.begin ( );
  while ( it != m_listOfThumbs.end ( ) ) {
    pThumbs = *it++;
    if ( pThumbs->pOwnerItem->isSelected ( ) )
      listSelected.append ( pThumbs );
  }

  it = listSelected.begin ( );
  theImage = QImage ( QImage ( ).fromMimeSource ( "please_wait.jpg" ) );
  createPix ( &thePixmap, &theImage );

  while ( it != listSelected.end  ( ) ) {
    pThumbs = *it++;
    pThumbs->pCache->scanImages ( this );
    listIcons.remove  ( pThumbs->pOwnerItem );
    pThumbs->pOwnerItem->setPixmap ( thePixmap );
    m_bCanClose       = false;
    m_bCanChangeIcons = false;
  }
  // In case we have some error Icons around ...
  it2 = listIcons.begin ( );
  while ( it2 != listIcons.end ( ) ) {
    QIconViewItem    *pItem = *it2++;
    pItem->setPixmap ( thePixmap );
    newThumbnailRequest  ( pItem );
  }
  m_pPreview->arrangeItemsInGrid ( TRUE );
  unlockDialog ( );
}

void DialogFiles::slotRefresh ( )
{
  // Here we erase all Icons and reload / recreate them
  QIconViewItem *pIcon = m_pPreview->firstItem ( );
  QStringList    list;

  while ( pIcon ) {
    list.append ( pIcon->key( ) );
    pIcon = pIcon->nextItem ( );
  }

  clearPreview ( );
  load    ( list );
}

void DialogFiles::clearPreview ( )
{
  uint t;
  lock ( );
  stopThumbing ( );

  for ( t=0; t<m_listOfThumbs.count ( ); t++ ) {
    delete m_listOfThumbs[t];
  }
  m_pPreview->clear    ( );
  m_listOfThumbs.clear ( );

  if ( m_pPreviewer )
       m_pPreviewer->clear ( );

  m_pButtonAutoGroup->setEnabled ( false );
  updateTitlebar ( );

  unlock ( );
}

void DialogFiles::updateTitlebar( )
{
  QString qsTitle = tr ( "Select / Sort / Group Source Files" );
  if ( isImageDialog ( ) )  {
    if ( m_pPreview->count ( ) > 0 )
      qsTitle += tr ( " [%1 Images]" ). arg ( m_pPreview->count ( ) );
  }
  else  {
    if ( m_pPreview->count ( ) > 0 )
      qsTitle += tr ( " [%1 Videos]" ). arg ( m_pPreview->count ( ) );
  }
  setCaption ( qsTitle );
}

void DialogFiles::accept ( )
{
  // Here we build the SourceFileEntries from the information in m_pToolbox
  int t;
  GroupView *pGroupView       = NULL;
  GroupView::Item *pGroupItem = NULL;
  SourceFileEntry *pEntry     = NULL;
  SourceFileInfo  *pInfo      = NULL;

  if ( ! m_bCanClose ) {
    if ( QMessageBox::warning ( this, tr ( "Can't close." ), tr ( "Can not close dialog while waiting for MediaScanner to finish.\nDo you want to force Quit ?" ), QMessageBox::Yes, QMessageBox::No ) == QMessageBox::No )
      return;
  }

  for ( t=0; t<m_pToolbox->count ( ); t++ ) {
    pGroupView = (GroupView *)m_pToolbox->item ( t );
    if ( pGroupView ) {
      pEntry     = NULL;
      pGroupItem = (GroupView::Item *)pGroupView->firstChild ( );
      if ( pGroupItem ) {
	pEntry = new SourceFileEntry;
	QString qsCurrentName  = m_pToolbox->itemLabel ( t );
	// If a SourceFileEntry exists for this GroupView, then we'll copy over the information.
	if ( pGroupView->sourceFileEntry ( ) ) {
	  copyEntry ( pEntry, pGroupView->sourceFileEntry ( ) );
	  if ( pEntry->qsDisplayName != qsCurrentName )  {
	       Global::pApp->replaceSourceDisplayName ( pEntry->qsDisplayName, qsCurrentName );
	  }
	}
	// And finally we set the name of the entry
	pEntry->qsDisplayName  = qsCurrentName;
      }
      while ( pGroupItem ) {
	pInfo = new SourceFileInfo;
	if ( pGroupItem->pSourceFileInfo )  {
	  *pInfo = *pGroupItem->pSourceFileInfo;
	   pInfo->pPreview = pGroupItem->pSourceFileInfo->pPreview;
	   pGroupItem->pSourceFileInfo->pPreview = NULL;
	}
	else if ( pGroupItem->pCache ) {
	  pInfo->qsFileName  = pGroupItem->pCache->qsFileName;
	  pInfo->qsLength    = pGroupItem->pCache->qsLength;
	  pInfo->bUpdateInfo = true;
	}
	pEntry->listFileInfos.append ( pInfo );
	pGroupItem = (GroupView::Item *)pGroupItem->nextSibling ( );
      }
      if ( pEntry )  {
        applyManualChange     ( pEntry );
        m_listOfGroups.append ( pEntry );
      }
    }
  }

  // Some special handling if the user has not used a group I.e. the first and only group is empty
  // BUT the user has selected some files ...
  if ( m_pToolbox->count ( ) == 1 )  {
    pGroupView = (GroupView *)m_pToolbox->item ( 0 );
    if ( pGroupView && ( pGroupView->childCount ( ) == 0 ) && ( m_listOfThumbs.count ( ) > 0 ) )  {
      if (  lockDialog ( ) )  {
        SourceFileEntry *pEntry = new SourceFileEntry;
        QValueList<Thumbs *>::iterator it = m_listOfThumbs.begin ( );
        while ( it != m_listOfThumbs.end ( ) ) {
          Thumbs *pThumbs = *it++;
          if ( pThumbs->pOwnerItem && pThumbs->pCache && pThumbs->pOwnerItem->isSelected ( ) )  {
            SourceFileInfo *pInfo = new SourceFileInfo;
            pInfo->qsFileName     = pThumbs->pCache->qsFileName;
            pInfo->bUpdateInfo    = true;
            pEntry->listFileInfos.append ( pInfo );
          }
        }
        if ( pEntry->listFileInfos.size( ) > 0 )  {
          applyManualChange     ( pEntry );
          m_listOfGroups.append ( pEntry );
        }
        else
          delete pEntry;
      }
      unlockDialog ( );
    }
  }

  QDialog::accept ( );
}

void DialogFiles::reject ( )
{
  if ( ! m_bCanClose ) {
    if ( QMessageBox::warning ( this, tr ( "Can't close." ), tr ( "Can not close dialog while waiting for MediaScanner to finish.\nDo you want to force Quit ?" ), QMessageBox::Yes, QMessageBox::No ) == QMessageBox::No )
      return;
  }
  uiDialogFiles::reject ( );
}

QValueList<SourceFileEntry *> &DialogFiles::getGroups ( )
{
  return m_listOfGroups;
}

void DialogFiles::copyEntry ( SourceFileEntry *pTarget, SourceFileEntry *pSource )
{
  int t;
  pTarget->qsDisplayName = pSource->qsDisplayName;
  pTarget->listChapters  = pSource->listChapters;
  pTarget->bSoundSource  = pSource->bSoundSource;
  pTarget->bIsSlideshow  = pSource->bIsSlideshow;
  pTarget->iJumpStart    = pSource->iJumpStart;
  pTarget->iTitleset     = pSource->iTitleset;
  pTarget->iTitle        = pSource->iTitle;
  pTarget->qsPre         = pSource->qsPre;
  pTarget->qsPost        = pSource->qsPost;
  pTarget->iPause        = pSource->iPause;
  for ( t=0; t<MAX_AUDIO; t++ )
    pTarget->arrayAudioEntries[t]    = pSource->arrayAudioEntries [t];
  for ( t=0; t<MAX_SUBTITLES; t++ )
    pTarget->arraySubtitleEntries[t] = pSource->arraySubtitleEntries [t];
}

void DialogFiles::applyManualChange ( SourceFileEntry *pTarget )
{
  // Here we get the ManualChange over to the SourceFileInfo.
  SourceFileInfo *pInfo;
  unsigned long long iPathHash, iFileHash;
  Manual         *pManual = NULL;
  Manual::Change *pChange = NULL;
  Thumbs thumbs;

  QValueList<Audio          *>  listAudio;
  QValueList<SubtitleEntry  *>  listSubtitles;
  QValueList<SourceFileInfo *>::iterator it = pTarget->listFileInfos.begin ( );
  while ( it != pTarget->listFileInfos.end ( ) )  {
    pInfo = *it++;
    thumbs.pSourceFileInfo = pInfo;
    thumbs.getManualChange ( pManual, pChange, iPathHash, iFileHash );
    if ( pChange )  {
      listAudio = pChange->copyAudioList ( );
      mergeAudioTracks  ( listAudio, pInfo );

      listSubtitles = pChange->copySubtitleList ( );
      mergeSubtitleTracks  ( listSubtitles, pInfo );
    }
  }
  // Finally we synch the Entrie Audio tracks to the info's
  pTarget->synchTracks ( );
}

void DialogFiles::mergeAudioTracks ( QValueList<Audio *> &list, SourceFileInfo *pInfo )
{
  QValueList<Audio *>::iterator it;
  QValueList<Audio *> tempList;
  Audio *pAudio, *pExists;
  bool bFound;

  it = list.begin ( );
  while ( it != list.end ( ) )  {
    pAudio = *it++;
    if ( ( pAudio->iAudioNumber > 0 ) && ( pAudio->iAudioNumber < MAX_AUDIO ) )  {
      // First we check if the Audio track exists
      bFound = false;
      for ( int t=0; t<MAX_AUDIO; t++ )  {
        pExists = pInfo->arrayAudio[t];
        if ( pExists && pExists->qsFileName == pAudio->qsFileName )  {
          // so the track exists, lets copy over the info we want to change and keep what we wan to keep.
          // E.g. pTranscodingInterface.
          pExists->iAudioNumber = pAudio->iAudioNumber;
          pExists->qsIso639     = pAudio->qsIso639;
          tempList.append ( pExists );
          pInfo->arrayAudio[t] = NULL;
          t = MAX_AUDIO; // exit for - loop
          bFound = true;
        }
      }
      if ( ! bFound )  {
        tempList.append ( pAudio );
        list.remove     ( pAudio );
      }
    }
  }
  // After we saved all records we want to keep, we can delete the rest ( if any )
  pInfo->deleteAudio  ( );
  // And then fill in the blanks
  //int iAudioNumber  =  0;
  it = tempList.begin ( );
  while ( it != tempList.end ( ) )  {
    pAudio = *it++;
    //pAudio->iAudioNumber = iAudioNumber++;
    pInfo->arrayAudio[pAudio->iAudioNumber] = pAudio;
  }
  // Lastly we can delete the temporary objects in list
  it = list.begin ( );
  while ( it != list.end ( ) )
    delete *it++;
  list.clear ( );
}

void DialogFiles::mergeSubtitleTracks ( QValueList<SubtitleEntry *> &list, SourceFileInfo *pInfo )
{
  bool bFound;
  Subtitles     *pSubtitle, *pExists;
  SubtitleEntry *pSubtitleEntry;
  QValueList<Subtitles *> tempList;
  QValueList<Subtitles *>::iterator it2;
  QValueList<SubtitleEntry *>::iterator it = list.begin ( );
  while ( it != list.end ( ) )  {
    pSubtitleEntry = *it++;
    if ( ( pSubtitleEntry->m_iSubtitleNumber > 0 ) && ( pSubtitleEntry->m_iSubtitleNumber < MAX_SUBTITLES ) )  {
      // First we check if the Subtitle track exists
      bFound = false;
      for ( int t=0; t<MAX_SUBTITLES; t++ )  {
        pExists = pInfo->arraySubtitles[t];
        if ( pExists && ( pExists->m_qsFileName.length ( ) > 0 ) && ( pExists->m_qsFileName == pSubtitleEntry->m_qsFileName ) )  {
          pExists->m_iSubtitleNumber = pSubtitleEntry->m_iSubtitleNumber;
          pExists->m_qsIso639        = pSubtitleEntry->m_qsIso639;
          // Note at this point we do NOT re-load the subtitle file, as I assume the user made changes to the file.
          pInfo->arraySubtitles[t]   = NULL;
          tempList.append ( pExists );
          bFound = true;
          t = MAX_SUBTITLES; // exit for - loop
        }
      }
      // unfortunately we can not rely on the file name alone as the user could have created the subtitle
      // rather than load it from file.
      // So the next check is to see if the track itself is already occupied.
      pExists = pInfo->arraySubtitles[pSubtitleEntry->m_iSubtitleNumber];
      if ( ! bFound && pExists )  {
          pExists->m_qsIso639 = pSubtitleEntry->m_qsIso639;
          tempList.append ( pExists );
          pInfo->arraySubtitles[pSubtitleEntry->m_iSubtitleNumber] = NULL;
          bFound = true;
      }
      if ( bFound )  {
        list.remove ( pSubtitleEntry );
        delete pSubtitleEntry;
      }
    }
  }
  // After we saved all records we want to keep, we can delete the rest ( if any )
  pInfo->deleteSubtitles ( );
  // And then fill in the blanks
  //int iSubtitleNumber = 0;
  it2 = tempList.begin ( );
  while ( it2 != tempList.end ( ) )  {
    pSubtitle  = *it2++;
    //pSubtitle->m_iSubtitleNumber = iSubtitleNumber++;
    pInfo->arraySubtitles[pSubtitle->m_iSubtitleNumber] = pSubtitle;
  }

  // After we took care of the already existing subtitles, we'll handle newly assigned Subtitles here.
  QFileInfo fileInfo;
  Import::Srt srtImporter;
  Import::Ssa ssaImporter;
  Import::BaseSubtitle *pImporter = &ssaImporter;

  it = list.begin ( );
  while ( it != list.end ( ) )  {
    pSubtitleEntry = *it++;

    pImporter   = &ssaImporter;
    fileInfo.setFile ( pSubtitleEntry->m_qsFileName );
    if ( fileInfo.extension ( false ).lower ( ) == "srt" )
      pImporter = &srtImporter;

    if ( pImporter->readFile ( pSubtitleEntry->m_qsFileName ) )  {
      pSubtitle = new Subtitles ( 0, 0 );
      pSubtitle->m_qsIso639        = pSubtitleEntry->m_qsIso639;
      pSubtitle->m_qsFileName      = pSubtitleEntry->m_qsFileName;
      //pSubtitle->m_iSubtitleNumber   = iSubtitleNumber++;
      pSubtitle->m_iSubtitleNumber = pSubtitleEntry->m_iSubtitleNumber;
      pSubtitle->m_listOfSubtitles = pImporter->takeSubtitles ( );
      // this should never happen ... but to be save ...
      if ( pInfo->arraySubtitles[pSubtitle->m_iSubtitleNumber] )
        delete pInfo->arraySubtitles[pSubtitle->m_iSubtitleNumber];
      pInfo->arraySubtitles[pSubtitle->m_iSubtitleNumber] = pSubtitle;
    }
    // And finally we can delete the SubtitleEntry.
    delete pSubtitleEntry;
  }
  list.clear ( );
}

}; // end namespace Input
