/****************************************************************************
** MenuPreview class
**
** Created: Tue Feb 02 22:06:51 2004
**      by: Varol Okan using Kate
**
** This class is the encapsulation of the MenuPreview.
**
** The MenuPreview is derived off the ButtonPreview and used 
** to display a DVD Menu.
** The ButtonPreview is the preview class used in the ButtonObject
** to display the different levels of a buttonObject.
**
**
****************************************************************************/

#include <sys/stat.h>
#include <sys/types.h>
#include <stdlib.h>

#include <qfiledialog.h>
#include <qdragobject.h>
#include <qpopupmenu.h>
#include <qlineedit.h>
#include <qcheckbox.h>
#include <qtextedit.h>
#include <qpainter.h>
#include <qregexp.h>
#include <qcursor.h>
#include <qtimer.h>
#include <qimage.h>

#include "global.h"
#include "dvdmenuundoobject.h"
#include "xml_dvd.h"
#include "buttonpreview.h"
#include "dialogtextfont.h"
#include "dialogbutton.h"
#include "menupreview.h"
#include "menuobject.h"
#include "frameobject.h"
#include "textobject.h"
#include "imageobject.h"
#include "movieobject.h"
#include "buttonobject.h"
#include "sourcefileentry.h"
#include "objectcollection.h"
#include "listviewmedia.h"
#include "dialogresize.h"
#include "dialogshadow.h"
#include "messagebox.h"
#include "filepreviewdialog.h"
#include "qplayer/engines/dummywidget.h"
#include "qplayer/mediacreator.h"
#include "qplayer/mediainfo.h"

#include "dialogimage2.h"
#include "dialogalign.h"

MenuPreview::MenuPreview(QWidget * parent, const char * name, WFlags f)
  : ButtonPreview   ( parent, name, f ),
    m_pDialogButton ( NULL )
{
  initMe (NULL);
  setAcceptDrops(true);

  connect ( &m_selectionObject, SIGNAL ( signalMoveOnStack ( MenuObject *, int ) ), this, SLOT ( slotMoveOnStack ( MenuObject *, int ) ) );
  connect ( &m_selectionObject, SIGNAL ( signalShadowMe    ( MenuObject * ) ),      this, SLOT ( slotAddShadow   ( MenuObject * ) ) );
  connect ( &m_selectionObject, SIGNAL ( signalDeleteMe    ( MenuObject * ) ),      this, SLOT ( slotDeleteObject( MenuObject * ) ) );
  connect ( &m_selectionObject, SIGNAL ( signalAlignSelection ( ) ), this, SLOT ( slotAlignSelection  ( ) ) );
}

MenuPreview::~MenuPreview()
{
  if ( m_pDialogButton )
    delete m_pDialogButton;
  m_pDialogButton = NULL;
}

MenuPreview &MenuPreview::operator = ( MenuPreview &theOther )
{
  m_bIsSubMenu   = theOther.m_bIsSubMenu;
  m_bIsMovieMenu = theOther.m_bIsMovieMenu;
  m_pPgcColors   = theOther.m_pPgcColors;
  m_bImageButton = theOther.m_bImageButton;
  m_doubleBuffer = theOther.m_doubleBuffer;
  ButtonPreview *pMe    = (ButtonPreview *)this;
  ButtonPreview *pOther = (ButtonPreview *)&theOther;
  *pMe = *pOther;

  uint t;
  MenuObject  *pObject;
  // At this point we have new objects but none of them are connected to any signals / slots ...
  for ( t=0; t<objectCount ( ); t++ ) {
    pObject  = menuObject ( t );
    if ( ! pObject )
      continue;

    connectStdSlots ( pObject, true );
  }

  return *this;
}

void MenuPreview::initMe (QColor *pColors)
{
  m_iCreateObjectStyle = TypeNone;
  m_iPointerState      = StateNormal;
  m_pActiveObject      = NULL;
  m_pDialogButton      = NULL;
  m_bIsSubMenu         = false;
  m_bIsMovieMenu       = false;
  m_bImageButton       = true;
  m_pPgcColors         = pColors;
}

void MenuPreview::clear (QColor *pColors)
{
	uint t;

	if ( m_pDialogButton )
	  delete m_pDialogButton;
	m_pDialogButton = NULL;

	initMe ( pColors );

	// Clear the undoBuffer and create an new one.
	if (m_pUndoBuffer)
		delete m_pUndoBuffer;
	m_pUndoBuffer = new UndoBuffer(MAX_UNDO_DEPTH);

	for (t=0;t<m_listMenuObjects.count ();t++)
		delete m_listMenuObjects.at(t);
	m_listMenuObjects.clear ();
	m_backgroundPixmap = QPixmap();
}

void MenuPreview::setIsSubMenu(bool bIsSubmenu)
{
	// This function is only here to flag that the MenuPreview is part of a SubMenu and
	// Not a VMGM, or something else.
	m_bIsSubMenu = bIsSubmenu;
}

void MenuPreview::setIsMovieMenu(bool bIsMovieMenu)
{
	// This function is only here to flag that the MenuPreview is part of a SubMenu and
	// Not a VMGM, or something else.
	m_bIsMovieMenu = bIsMovieMenu;
}

void MenuPreview::setImageButton  (bool bImageButton)
{
	m_bImageButton = bImageButton;
}

bool MenuPreview::createContextMenu ( QPoint globalPos )
{
  Utils theUtil;
  bool bPal  = true;
  bool bNtsc = true;
  if ( theUtil.getFormat( m_backgroundPixmap.width ( ), m_backgroundPixmap.height ( ) ) >= FORMAT_PAL1 )
    bNtsc = false;
  if ( theUtil.getFormat( m_backgroundPixmap.width ( ), m_backgroundPixmap.height ( ) ) <= FORMAT_NTSC4 )
    bPal  = false;

  QPopupMenu *pMenu = new QPopupMenu (this);
  pMenu->insertItem ( tr ("Add Frame"), this, SLOT ( slotAddFrameObject ( ) ) );
  pMenu->insertItem ( tr ("Add Text") , this, SLOT ( slotAddTextObject  ( ) ) );
  pMenu->insertItem ( tr ("Add Image"), this, SLOT ( slotAddImageObject ( ) ) );
  pMenu->insertItem ( tr ("Add Movie"), this, SLOT ( slotAddMovieObject ( ) ) );
  if ( Global::pCopyObject )
    pMenu->insertItem ( tr ("Paste (%1)").arg ( Global::pCopyObject->objectType ( ) ),     this, SLOT ( slotPaste ( ) ) );
  //pMenu->insertItem ( tr ("Add Collection"), this, SLOT(slotAddCollection()));
  //	if (m_bIsMovieMenu)	{
  pMenu->insertSeparator ();
  pMenu->insertItem (tr ("Properties ..."), this, SLOT(slotEditTimeline()));
  //	}
  if (m_bIsSubMenu)	{
    pMenu->insertSeparator ();
    pMenu->insertItem (tr ("Rename Menu"), this, SLOT(slotRenameMenu()));
    pMenu->insertItem (tr ("Delete Menu"), this, SLOT(slotDeleteMenu()));
  }
  pMenu->insertItem (tr ("Clone Menu"), this, SLOT ( slotCloneMenu ( ) ) );
  if ( bNtsc )
    pMenu->insertItem (tr ("Convert to PAL" ), this, SLOT ( slotConvertToPAL  ( ) ) );
  if ( bPal  )
    pMenu->insertItem (tr ("Convert to NTSC"), this, SLOT ( slotConvertToNTSC ( ) ) );
  pMenu->exec(globalPos);
      
  delete pMenu;
  return true;
}

void MenuPreview::mouseDoubleClickEvent	(QMouseEvent *pEvent)
{
	m_pActiveObject = NULL;
	// First we let the base class have it ...
	ButtonPreview::mouseDoubleClickEvent(pEvent);
}

void MenuPreview::mousePressEvent (QMouseEvent *pEvent)
{
  // First we let the base class have it ...
  m_bMouseEventDone = false;
  if ( m_selectionObject.mousePressEvent ( pEvent ) )
    return;

  if ( m_iPointerState != StateSelected )
    ButtonPreview::mousePressEvent ( pEvent );
  // Here we check if the mouse click appeared withtin one of the MenuObjects,
  // in which case the Object will take over the mouse handling ...
  if (m_bMouseEventDone) {
    m_iPointerState = StateNormal; // added to change state after Add Shadow was selected from ContextMenu...
    return;
  }

  //  char arrayState[][30]={ "StateUnknown", "StateNormal", "StateMoveSelected", "StateReadyToCreate", "StateCreating", "StateSelecting", "StateSelected" };
  //  printf ("MenuPreview::mousePressEvent pointerState<%s>\n", arrayState[m_iPointerState]);

  QPoint      thePos  = pEvent->pos ( );
  MenuObject *pObject = childContains ( thePos );

  if ( ( pObject != NULL ) && ( m_iPointerState != StateSelected ) )	{
    m_pActiveObject = pObject;
    update();
    return;
  }
  // Okay the user actually clicked in the MenuPreview ...
  // The left mouse button was clicked.
  // If the user is in creation mode, then we handle this one
  if (pEvent->button () == LeftButton) {
    // if the state is not StateReadyToCreate then we want to select
    if ( m_iPointerState == StateReadyToCreate ) {
      m_iPointerState = StateCreating;
      drawBackground   ( m_doubleBuffer );
      setMouseTracking ( true );
    }
    else if ( m_iPointerState == StateSelected ) {
      if ( m_selectionObject.mouseOver ( pEvent->pos () ) ) {
	m_iPointerState = StateMoveSelected;
	m_selectionObject.setMoveState ( false );
	m_selectionObject.setCurrentMousePos ( (QPoint &) pEvent->pos ( ) );
	drawBackground   ( m_doubleBuffer );
	setMouseTracking ( true );
      }
    }
    else  {
      if ( m_backgroundPixmap.isNull () )
	return;
      m_iPointerState = StateSelecting; 
      setMouseCursor ( MouseCrossCursor );	// signals to be awaiting the next mouse click
      // which will then generate the rectangle for this text button.
      m_selectionObject.clear ( );
      m_pActiveObject = &m_selectionObject;
      drawBackground   ( m_doubleBuffer );
    }
    // Okay, at this point we know the user is creating an object.
    m_rectCurrentObject.setX(pEvent->pos().x());
    m_rectCurrentObject.setY(pEvent->pos().y());
    return;
  }
  // The right mousebutton was pressed means that we should display the context drop down menu.
  setMouseCursor ( MousePointerCursor );
  m_iPointerState = StateNormal;
  
  createContextMenu ( pEvent->globalPos  ( ) );
}

void MenuPreview::mouseReleaseEvent (QMouseEvent *pEvent)
{
  // The user is doing something. Let us activate the drawing algol.
  m_rectCurrentObject.setRight  ( pEvent->pos( ).x ( ) );
  m_rectCurrentObject.setBottom ( pEvent->pos( ).y ( ) );

  //  char arrayState[][30]={ "StateUnknown", "StateNormal", "StateMoveSelected", "StateReadyToCreate", "StateCreating", "StateSelecting", "StateSelected" };
  //  printf ("MenuPreview::mouseReleaseEvent pointerState<%s>\n", arrayState[m_iPointerState]);

  if (pEvent->button () == LeftButton) 	{
    m_doubleBuffer = QPixmap ( );
    switch ( m_iPointerState ) {
    case StateMoveSelected: {
      m_iPointerState = StateSelected;
      m_selectionObject.setMoveState ( false );
      updatePixmap ();
      return;
    }
    case StateCreating: {
      // First we let the base class have it ...
      m_bMouseEventDone = false;
      ButtonPreview::mouseReleaseEvent(pEvent);
      // Here we check if the mouse click appeared withtin one of the MenuObjects,
      // in which case the Object will take over the mouse handling ...
      if ( m_bMouseEventDone ) 
	setMouseTracking ( false );

      m_pActiveObject = NULL;
      switch ( m_iCreateObjectStyle )	{
      case FrameType :
        createFrameObject ();
	break;
      case TextType :
	createTextObject();
	break;
      case ImageType :
        createImageObject();
      break;
      case MovieType :
        createMovieObject ();
	break;
      } // switch createObjectStyle
      m_iPointerState = StateNormal;
      return;
    } // end of case StateCreating
    case StateSelected: {
      m_pActiveObject = NULL;
      m_iPointerState = StateNormal;
      m_selectionObject.setMoveState ( false );
      update ( );
      setMouseTracking ( false );
      return;
    }
    case StateSelecting: {
      if ( m_selectionObject.getCount () > 0 ) {
	m_iPointerState = StateSelected;
	setMouseTracking ( true ); // to change cursor shapes.
      }
      else {
	m_iPointerState = StateNormal;
	setMouseTracking ( false );
      }
      setMouseCursor ( MousePointerCursor );
      update ();
      return;
    }
    case StateNormal:        // nothing to do if we are in Normal Mouse Mode
    case StateReadyToCreate: // Should neve happen ...
    case StateUnknown:       // Something went wrong ...
    default:                 // should never get here
      if ( m_pActiveObject )
	   m_pActiveObject->mouseReleaseEvent ( pEvent ); // will call updatePixmap
      else
	   updatePixmap ( );
      m_pActiveObject = NULL;
      setMouseTracking ( false );
      return;
    }
  } //  end if LeftButton
}

void MenuPreview::mouseMoveEvent (QMouseEvent *pEvent)
{
  //  char arrayState[][30]={ "StateUnknown", "StateNormal", "StateMoveSelected", "StateReadyToCreate", "StateCreating", "StateSelecting", "StateSelected" };
  //  printf ("MenuPreview::mouseMoveEvent pointerState<%s>\n", arrayState[m_iPointerState]);

  switch ( m_iPointerState ) {
  // The one state I dont need to care ...
  case StateReadyToCreate:
    return;
  case StateMoveSelected:
    m_selectionObject.mouseMoveEvent ( pEvent );
    { // doubleBuffer does move the objecs as well, which I don't want
      // I simply want to get rid of the flicker ...
      QPixmap temp ( m_doubleBuffer );
      QPainter thePainter;
      thePainter.begin ( &temp, this );
      m_selectionObject.drawSelected ( &thePainter );
      thePainter.end ( );
      bitBlt ( this, 0, 0, &temp );
    }
  break;
  case StateSelected: {
    // this case will take care of the state when multile objects have been selected
    // and now the user is aboout to move those selected objects around.
    // for this in-between-state, we want to display the mouse move cursor
    // if inside one of the selected objects.
    //    if ( m_selectionObject.mouseOver ( pEvent->pos () ) )
    bool bMouseOver =  m_selectionObject.mouseOver ( pEvent->pos () );
    //    printf ( "MenuPreview::mouseMoveEvent mouseOver<%s> - <%dx%d>\n", bMouseOver ? "true" : "false", pEvent->pos().x(), pEvent->pos().y() );
    if ( bMouseOver )
      setMouseCursor ( MouseMoveCursor    );
    else 
      setMouseCursor ( MousePointerCursor );
    //    m_selectionObject.mouseMoveEvent ( pEvent );
    //update ( );
    return;
  }
  case StateSelecting:
  case StateCreating: {
    // Okay at this point we have m_rectCurrentObject.x, and .y set
    // Here we draw the dynamicly changing size of the rect.
    
    // First we clear the contents of the previous rectangle
    int iX, iY;
    iX  = pEvent->pos ( ).x ( );
    iY  = pEvent->pos ( ).y ( );
    m_rectCurrentObject.setRight  ( iX );
    m_rectCurrentObject.setBottom ( iY );
    
    // Double buffering ...
    QPen     thePen   ( QColor ( 255,  30,  30 ), 2, Qt::DashDotLine );
    QBrush   theBrush ( QColor ( 100, 255, 100 ),  Qt::Dense6Pattern );
    QPainter thePainter;
    QPixmap doubleBuffer;
    if ( m_doubleBuffer.isNull( ) )
      thePainter.begin      ( this );
    else {
      doubleBuffer = QPixmap ( m_doubleBuffer );
      thePainter.begin  ( &doubleBuffer, this );
    }

    if ( m_iPointerState  == StateSelecting ) {
      thePen = QPen  ( QColor ( 100, 255, 100 ), 1, Qt::SolidLine );
      thePainter.setBrush ( theBrush );
      checkSelection ( ); // Any objects added to m_selectionObject ?
    }
    else
      thePen = QPen (QColor (255, 30,30), 2, Qt::DashDotLine);

    thePainter.setPen   ( thePen );
    m_selectionObject.drawSelected ( &thePainter );
    thePainter.drawRect ( m_rectCurrentObject    );
    thePainter.drawText ( iX+5, iY+15, QString   ( "%1 : %2" ).arg( m_rectCurrentObject.width ( ) ).arg( m_rectCurrentObject.height ( ) ) );

    thePainter.end ( );  
    if ( ! m_doubleBuffer.isNull ( ) )
      bitBlt ( this, 0, 0, &doubleBuffer );
  }
  break;
  case StateUnknown:
  case StateNormal:
  default:
    // This part will move the active object(s) around ...
    //  if ( m_pActiveObject && m_iPointerState != StateSelecting ) {
    if ( m_pActiveObject ) {
      m_pActiveObject->mouseMoveEvent(pEvent);
      update ( );
      return;
    }
  }
}

void MenuPreview::checkSelection ()
{
  // Check if any object has been captured by the selection box.
  uint t;
  m_selectionObject.clear ( );
  QRect rect = m_rectCurrentObject.normalize ();
  for ( t=0;t<m_listMenuObjects.count ( );t++) {
    if ( rect.intersects ( m_listMenuObjects.at ( t )->boundingRect ( ) ) ) {
      MenuObject *pObject = m_listMenuObjects.at ( t );
      m_selectionObject.append ( pObject, false );
    }
  }
}

void MenuPreview::slotEditTimeline ()
{
  emit (signalEditTimeline ());
}

void MenuPreview::slotPaste ( )
{
  if ( ! Global::pCopyObject )
    return;

  MenuObject *pNewObject;
  if ( ( Global::pCopyObject->objectType ( ) == QString ( OBJECT_COLLECTION ) ) ||
       ( Global::pCopyObject->objectType ( ) == QString ( SELECTION_OBJECT  ) ) ) {
    ObjectCollection *pCollection =  (ObjectCollection *) Global::pCopyObject;
    int t, iCount = pCollection->getCount ( );
    for ( t=0; t<iCount; t++ ) {
      pNewObject = pCollection->getObject ( t )->clone ( this );
      paste ( pNewObject );
    }      
  }
  else {
    pNewObject = Global::pCopyObject->clone ( this );
    paste ( pNewObject );
  }
}


void MenuPreview::paste ( MenuObject *pNewObject )
{
  QRegExp rx;
  QString qsNewName;
  // In order to see the new object I will move it 10 x 10 ...
  QRect theRect = pNewObject->rect ( );
  int iWidth  = theRect.width  ( );
  int iHeight = theRect.height ( );
  theRect.setX ( theRect.x ( ) - 10 );
  theRect.setY ( theRect.y ( ) - 10 );
  theRect.setWidth    ( iWidth  );
  theRect.setHeight   ( iHeight );
  pNewObject->setRect ( theRect );

  // assign a unique object name ...
  qsNewName = pNewObject->name ( );
  // Here we remove the prefix 
  rx.setPattern ( "Copy\\s*\\(\\d*\\)" );
  qsNewName.remove ( rx );
  rx.setPattern ( "^Copy" );
  qsNewName.remove ( rx );
  rx.setPattern ( "^\\s*" );
  qsNewName.remove ( rx );
  // to get a true unique name ...
  qsNewName = uniqueObjectName ( QString ( "Copy " ), qsNewName );
  pNewObject->setName ( qsNewName );

  //pNewObject->mouseReleaseEvent ( NULL );
  connectStdSlots ( pNewObject, true );
  addMenuObject   ( pNewObject );
  pNewObject->mouseReleaseEvent ( NULL );
}

void MenuPreview::dropEvent (QDropEvent *pDropEvent)
{
	QImage  theImage;
	QString theText;

	if (QImageDrag::decode(pDropEvent, theImage) )	{
		if (theImage.isNull())
			return;
		// insert Image, movie or ButtonObject.
		insertDraggedObject(pDropEvent, theImage);
		// And check if it comes with text or image only ...
		if (QTextDrag::decode(pDropEvent, theText) ) 	{
			insertDraggedText(pDropEvent, theText);
			emit (signalDroppedSomething (DroppedImageAndText));
		}
	}
	else if (QTextDrag::decode(pDropEvent, theText) ) 	{
		// Insert TextObject
		insertDraggedText(pDropEvent, theText);
		emit (signalDroppedSomething (DroppedText));
	}
}

MenuObject *MenuPreview::insertDraggedText (QDropEvent *pEvent, QString &theText)
{
	QRect rect;
	if (pEvent)
		rect = QRect(pEvent->pos().x(), pEvent->pos().y(),1,1);

	TextObject *pTextObject = new TextObject (this);
	pTextObject->setRect(rect);
	pTextObject->setText (theText);
	m_listMenuObjects.append (pTextObject);

	// Here we connect the signal to the slot ...
	connectStdSlots ( pTextObject, true );

	undoBuffer()->push (new DVDMenuUndoObject(DVDMenuUndoObject::DRAGGED_TEXT, pTextObject));
	emit (signalUpdateStructure());
	updatePixmap();
	return pTextObject;
}

MenuObject *MenuPreview::insertDraggedObject (QDropEvent *pDropEvent, QImage &theImage)
{ 
	MenuObject *pMenuObject = NULL;
	// The first thing to check is if this drop was initiated in the Toolbar
	if ( pDropEvent->source() && (QString("m_pListViewAllSources") == pDropEvent->source()->name()) )	{
		ListViewMedia   *pListViewMedia   = (ListViewMedia *)pDropEvent->source();
		SourceFileEntry *pSourceFileEntry = pListViewMedia->draggingSourceFileEntry();
		SourceFileInfo  *pSourceFileInfo  = pListViewMedia->draggingSourceFileInfo();
		if ( pSourceFileEntry->bSoundSource )  {	// No adding of a sound source !
			MessageBox::warning (NULL, tr("Can not add."), tr ("This is a sound source.\nI can currently not add this type of source.\n"), QMessageBox::Ok, QMessageBox::NoButton);
			return NULL;
		}
		if ( pSourceFileEntry->bIsSlideshow )	{
			MessageBox::warning (NULL, tr("Can not add."), tr ("The slideshow is still beeing created.\nI can not add it at this moment.\n"), QMessageBox::Ok, QMessageBox::NoButton);
			return NULL;
		}
		if ( pSourceFileInfo)	// Okay here we split between adding one button
			pMenuObject = insertDraggedSourceInfo  (pDropEvent, theImage);	// ButtonObject
		else	// Or we dragged the full SourceEntry and will use the defined Layout
			if (pSourceFileEntry->listFileInfos.count() == 1)	// Now only one movie in the Entry ... Booooring ...
				pMenuObject = insertDraggedSourceInfo(pDropEvent, theImage);	// ButtonObject
			else
				pMenuObject = insertDraggedSourceInfo(pDropEvent, theImage);	// Temp solution ...
// FIXME: 
// For now we defer this to the next major release so we can release 0.0.9 some time
// This is supposed to create a whole bunch of menus inclusive backgroud and buttons.
//				pMenuObject = insertDraggedSourceEntry ();	// ObjectCollection
		// Last but not lease we re-set the dragging Sources so we have clean hands ...
		pListViewMedia->resetDragging();
	}
	else	// The source came from some source outside QDVDAuthor.
		pMenuObject = insertDraggedImage (pDropEvent, theImage);	// ImageObject
	return pMenuObject;
}

#include "layoutwizard.h"
MenuObject *MenuPreview::insertDraggedSourceEntry(QDropEvent *pDropEvent, QImage &)
{
// FIXME: This function should be handled in DVDAuthor as it will create additional menus.
	uint t;
	ObjectCollection *pObjectCollection = new ObjectCollection;
	// The wizard will take care of the spacing plus the overlay
	LayoutWizard *pWizard = new LayoutWizard;
//	pWizard->


	ButtonObject *pButtonObject = NULL;
	// Note that at this point we KNOW that the source is coming from the ListViewAllSources - toolbar !!!
	ListViewMedia *pListViewMedia = (ListViewMedia *)pDropEvent->source();
	SourceFileEntry *pSourceFileEntry = pListViewMedia->draggingSourceFileEntry();
	SourceFileInfo  *pSourceFileInfo  = NULL;

	for (t=0;t<pSourceFileEntry->listFileInfos.count();t++)	{
		pSourceFileInfo  = pSourceFileEntry->listFileInfos[t];
		pButtonObject = (ButtonObject *)createButtonObject ();
		pObjectCollection->append (pButtonObject);
	}
	m_listMenuObjects.remove(pObjectCollection);
	delete pWizard;
	return pObjectCollection;
}

MenuObject *MenuPreview::insertDraggedSourceInfo(QDropEvent *pDropEvent, QImage &theImage)
{
	QPixmap thePixmap;
	MenuObject *pMenuObject = NULL;
	// Note that at this point we KNOW that the source is coming from the ListViewAllSources - toolbar !!!
	ListViewMedia   *pListViewMedia   = (ListViewMedia *)pDropEvent->source    ();
	SourceFileEntry *pSourceFileEntry = pListViewMedia->draggingSourceFileEntry();
	SourceFileInfo  *pSourceFileInfo  = pListViewMedia->draggingSourceFileInfo ();
	if (!pSourceFileInfo)
		pSourceFileInfo = pSourceFileEntry->listFileInfos[0];
	if (!pSourceFileInfo)	// If still no luck then return ...
		return NULL;
	// First we create a MenuObject (ImageObject or MovieObject)
	if (m_bImageButton)
		pMenuObject = insertDraggedImage (pDropEvent, theImage);
	else	{
	        pMenuObject = insertDraggedMovie (pDropEvent, theImage, pSourceFileInfo->iMSecPreview );
		// Here we set the real name of the Movie file and not the one of the screenshot.
		((MovieObject *)pMenuObject)->setFile (pSourceFileInfo->qsFileName);
	}
	// But since we want to create a Button here, we remove it again from the object list.
	m_listMenuObjects.remove(pMenuObject);
	// Okay the image/movie came from the right source so we actually want a button ...
	ButtonObject *pButtonObject = new ButtonObject (this);
	// Now we generate two copies ...
	MenuObject *pNewSelected, *pNewHighlighted;

	QColor colorHighlighted (START_HIGHLIGHTED_COLOR);
	QColor colorSelected    (START_SELECTED_COLOR);
	if (m_pPgcColors)	{
		colorHighlighted	= m_pPgcColors[1];
		colorSelected		= m_pPgcColors[2];
	}

	pNewSelected    = new FrameObject;
	pNewHighlighted = new FrameObject;
	pNewSelected   ->setRect(pMenuObject->rect());
	pNewHighlighted->setRect(pMenuObject->rect());
	((FrameObject *)(pNewSelected))   ->setFrameWidth(10);
	((FrameObject *)(pNewHighlighted))->setFrameWidth(10);
	// Next we give some color the the diffenrent states
	((FrameObject *)(pNewSelected))   ->setFrameColor (colorSelected);
	((FrameObject *)(pNewHighlighted))->setFrameColor (colorHighlighted);

	pButtonObject->appendNormal      (pMenuObject);
	pButtonObject->appendSelected    (pNewSelected);
	pButtonObject->appendHighlighted (pNewHighlighted);

	pButtonObject->setName(newButtonName());
	// Next we should give the button the same attributes as the NormalState ...
	// rect and boundingRect are taken care of in drawContent
//	pButtonObject->setModifiers(*pMenuObject->modifiers());

	// Okay now we should wed the new Button with the SourceFileInfo - entry ...
	QString qsAction = QString ("jump") + QString (STRING_SEPARATOR);
	QFileInfo fileInfo;
	QString qsFileName;

	// Let us set a default name for the MenuObject first
	fileInfo.setFile(pSourceFileInfo->qsFileName);
	qsFileName = fileInfo.fileName ();
	pMenuObject->setName (qsFileName);

	// The we set some action for the BUttonObject.
	if (pSourceFileEntry)
		qsAction += pSourceFileEntry->qsDisplayName + QString (STRING_SEPARATOR);
	qsAction += qsFileName + QString (STRING_SEPARATOR) + QString ("00:00:00.000");
	pButtonObject->setAction (qsAction);
	pButtonObject->setSourceFileEntry (pSourceFileEntry);

	// and here we append the button object as a new item in the MenuObject list.
	m_listMenuObjects.append(pButtonObject);
	// And finally we connect everything ...
	//	void signalMoveOnStack          (MenuObject *, int);

	connectStdSlots ( pButtonObject, true );
	//	connect (pNewSelected,    SIGNAL(signalDeleteMe(MenuObject *)), this, SLOT(slotDeleteObject(MenuObject *)));
	//	connect (pNewHighlighted, SIGNAL(signalDeleteMe(MenuObject *)), this, SLOT(slotDeleteObject(MenuObject *)));
	//	connect (pButtonObject,   SIGNAL(signalUnbuttonMe(ButtonObject *)),this, SLOT(slotUnbutton(ButtonObject *)));
	//	connect (pButtonObject,   SIGNAL(signalCreateButtonDialog(ButtonObject *)),this, SLOT(slotCreateButtonDialog(ButtonObject *)));
	// After all of this we also want to create a text object ...
	QString qsWhatDidWeDragg = fileInfo.baseName();
	insertDraggedText (NULL, qsWhatDidWeDragg);
	// and then re-position those ... calls DVDMenu::slotDroppedSomething
	if (m_bImageButton)
		emit (signalDroppedSomething (DroppedImageAndText));
	else
		emit (signalDroppedSomething (DroppedMovieAndText));

	// And last we take care of the Undo stuff
	undoBuffer()->push (new DVDMenuUndoObject(DVDMenuUndoObject::DRAGGED_BUTTON, pButtonObject));

	emit (signalUpdateStructure());
	updatePixmap();
	return pButtonObject;
}

// Here we insert a dragged image, which came from somewhere ...
MenuObject *MenuPreview::insertDraggedImage (QDropEvent *pDropEvent, QImage &theImage)
{
	QPixmap thePixmap;
	QString qsFileName;
	QRect   theRect;
	int iWidth, iHeight;
	Utils theUtil;
	QPoint thePoint (pDropEvent->pos());

	qsFileName = theUtil.getUniqueTempFile(DRAGGED_IMAGE_NAME);
	theImage.save (qsFileName, "PNG");

	iWidth  = theImage.width();
	iHeight = theImage.height();
	// Here we resize if neccesary ...
	if(  (theImage.width() > 720) || (theImage.height() > 576) )	{
		CResizeDialog *pResizeDialog = new CResizeDialog ();
		pResizeDialog->setImage(&theImage);
		pResizeDialog->exec ();
		iWidth  = pResizeDialog->m_pEditWidth ->text().toInt();
		iHeight = pResizeDialog->m_pEditHeight->text().toInt();
//		iFormat = pResizeDialog->m_iFormat;
		if (iWidth  < 1) iWidth  = 150;
		if (iHeight < 1) iHeight = 150;
		thePixmap = *pResizeDialog->m_pPixmapPreview->pixmap ();
	}
	else	// If not then we simply take the current Image ..
		thePixmap.convertFromImage (theImage);
	theRect   = QRect(thePoint.x(), thePoint.y(), iWidth, iHeight);
	ImageObject *pImageObject = new ImageObject (this);
	pImageObject->setZoom   (1.0f);
	pImageObject->setRect   (theRect);
	pImageObject->setPixmap (thePixmap);
	pImageObject->setFile   (qsFileName);
	m_pActiveObject = pImageObject;

	// And last we connect the signals
	connectStdSlots ( pImageObject, true );
	//	connect (pImageObject, SIGNAL(signalModifyMe(MenuObject *)), this, SLOT(slotModifyObject(MenuObject *)));
	m_listMenuObjects.append(pImageObject);

	// And last we take care of the Undo stuff
	undoBuffer()->push (new DVDMenuUndoObject(DVDMenuUndoObject::DRAGGED_IMAGE, (MenuObject *)pImageObject));
	emit (signalUpdateStructure());
	updatePixmap();
	return pImageObject;
}

MenuObject *MenuPreview::insertDraggedMovie (QDropEvent *pDropEvent, QImage &theImage, long iMSecPreviewOffset )
{
	QPixmap thePixmap;
	QRect   theRect;
	int iWidth, iHeight;
	Utils theUtil;
	QPoint thePoint (pDropEvent->pos());

	iWidth  = theImage.width();
	iHeight = theImage.height();
	QSize theSize = theImage.size();
	// Here we resize if neccesary ...
	if(  (theImage.width() > 720) || (theImage.height() > 576) )	{
		CResizeDialog *pResizeDialog = new CResizeDialog ();
		pResizeDialog->setImage(&theImage);
		pResizeDialog->exec ();
		iWidth  = pResizeDialog->m_pEditWidth ->text().toInt();
		iHeight = pResizeDialog->m_pEditHeight->text().toInt();
//		iFormat = pResizeDialog->m_iFormat;
		if (iWidth  < 1) iWidth  = 150;
		if (iHeight < 1) iHeight = 150;
		thePixmap = *pResizeDialog->m_pPixmapPreview->pixmap ();
		delete pResizeDialog;
	}
	else	// If not then we simply take the current Image ..
		thePixmap.convertFromImage (theImage);
	theRect   = QRect(thePoint.x(), thePoint.y(), iWidth, iHeight);
	MovieObject *pMovieObject = new MovieObject (this);
	pMovieObject->setZoom        ( 1.0f );
	pMovieObject->setRect        ( theRect );
	pMovieObject->setPixmap      ( thePixmap );
	pMovieObject->setMSecPreview ( iMSecPreviewOffset );
//	pMovieObject->setFile        ( qsFileName );
	pMovieObject->setMovieSize   ( theSize );
	m_pActiveObject = pMovieObject;
	emit (signalCreatedMovieObject (pMovieObject, true));	// registerToRender

	// And last we connect the signals
	connectStdSlots ( pMovieObject, true );
	//	connect (pMovieObject, SIGNAL(signalModifyMe(MenuObject *)), this, SLOT(slotModifyObject(MenuObject *)));
	m_listMenuObjects.append(pMovieObject);
	// And last we take care of the Undo stuff
	undoBuffer()->push (new DVDMenuUndoObject(DVDMenuUndoObject::DRAGGED_MOVIE, (MenuObject *)pMovieObject));
	// Call QDVDAuthor::
	emit (signalUpdateStructure());
	updatePixmap();
	return pMovieObject;
}

void MenuPreview::dragEnterEvent(QDragEnterEvent *pEvent)
{
	// Tell the Widget that we accept ImageDrops ...
	// This is necessary otherwise the dropEvent does not occur.
	pEvent->accept(QImageDrag::canDecode(pEvent) || QTextDrag::canDecode(pEvent));
	setMouseTracking ( false );
}

bool MenuPreview::readProjectFile (QDomNode &theNode)
{
	uint t;
	ButtonObject tempButton;
	MovieObject  tempMovieObject;
	if (m_pDialogButton)
		delete m_pDialogButton;
	m_pDialogButton = NULL;
	QDomNode xmlPreview = theNode.firstChild();
	while ( !xmlPreview.isNull () )	{
		// Here we created a MenuObject, we also want to
		MenuObject *pNewObject = readObject (xmlPreview);
		// add it to the list ...
		if (pNewObject)	{
			pNewObject->readProjectFile ( xmlPreview );
			m_listMenuObjects.append    ( pNewObject );
		}
		// So lets get the next sibling ... until we hit the end of DVDMenu ...
		xmlPreview = xmlPreview.nextSibling();
	}

	// we need to make one more step here 
	// since we stored the Display Name for ButtonObjects and we need the SourceFileEntry pointer ...
	for (t=0;t<m_listMenuObjects.count();t++)	{
		if (m_listMenuObjects.at (t)->objectType() == tempButton.objectType())	{
			m_pActiveObject = m_listMenuObjects.at(t);
			emit (signalRequestSourceFiles());
		}
	}
	return true;
}

MenuObject *MenuPreview::readObject (QDomNode &objectNode)
{
	// This function wil create an MenuObject-derived object
	// depending on the info from the QDomNode - object
	QDomElement theElement = objectNode.toElement();
	QString tagName = theElement.tagName();
	QString nodeText = theElement.text ();

	// Okay, this is ugly but after all it is the simplest of all xml file structure.
	// No need to get fancy ...
	MenuObject *pNewObject = NULL;
	if (tagName == FRAME_OBJECT)
		pNewObject = createFrameObject  (false);
	else if (tagName == TEXT_OBJECT)
		pNewObject = createTextObject   (false);
	else if (tagName == IMAGE_OBJECT)
		pNewObject = createImageObject  (false);
	else if (tagName == MOVIE_OBJECT)
		pNewObject = createMovieObject  (false);
	else if (tagName == BUTTON_OBJECT)	{
		pNewObject = createButtonObject (false);
		// A small special handling for the Buttons ...
		// Funky, since the above function itself calls this function here ...
		((ButtonObject *)pNewObject)->readObjects(objectNode, this);
	}
	else if (tagName == OBJECT_COLLECTION)	{
		pNewObject = createObjectCollection (false);
		// A small special handling for the Buttons ...
		// Funky, since the above function itself calls this function here ...
		((ObjectCollection *)pNewObject)->readObjects(objectNode, this);
	}
	else if (tagName == IGNORE_OBJECT)
		pNewObject = NULL;
	else
		printf ("Warning: MenuPreview::readObject -=> wrong XML Node <%s>\nContinuing ...\n",
				(const char *)tagName);
	// And finally, if we created a MenuObject, we also want to
	// add it to the list ...
	if (pNewObject)
		pNewObject->readProjectFile ( objectNode );
	// So lets get the next sibling ... until we hit hte end of DVDMenu ...
	return pNewObject;
}

bool MenuPreview::writeProjectFile (QDomElement &theElement)
{
	uint t;
	for (t=0;t<m_listMenuObjects.count();t++)	{
		if (!m_listMenuObjects.at(t)->writeProjectFile( theElement ))
			return false;
	}
	return true;
}

// The following slots will add a button to the Menu.
void MenuPreview::slotAddFrameObject()
{
  setMouseCursor ( MouseCrossCursor );	// signals to be awaiting the next mouse click
  // which will then generate the rectangle for this text button.
  m_iCreateObjectStyle = FrameType;
  m_iPointerState      = StateReadyToCreate;
}

void MenuPreview::slotAddTextObject()
{
  setMouseCursor ( MouseCrossCursor );	// signals to be awaiting the next mouse click
  // which will then generate the rectangle for this text button.
  m_iCreateObjectStyle = TextType;
  m_iPointerState      = StateReadyToCreate;
}

void MenuPreview::slotAddImageObject ()
{
  setMouseCursor ( MouseCrossCursor );	// signals to be awaiting the next mouse click
  // which will then generate the rectangle for this text button.
  m_iCreateObjectStyle = ImageType;
  m_iPointerState      = StateReadyToCreate;
}

void MenuPreview::slotAddMovieObject ()
{
  setMouseCursor ( MouseCrossCursor );	// signals to be awaiting the next mouse click
  // which will then generate the rectangle for this text button.
  m_iCreateObjectStyle = MovieType;
  m_iPointerState      = StateReadyToCreate;
}

void MenuPreview::slotAddCollection()
{
  setMouseCursor ( MouseCrossCursor );	// signals to be awaiting the next mouse click
  // which will then generate the rectangle for this text button.
  m_iCreateObjectStyle = CollectionType;
  m_iPointerState      = StateReadyToCreate;
}

void MenuPreview::createAnimationData (QString &qsMenuName, long iMaxFrames)
{
	uint t;
	QFile     theFile;
	QFileInfo fileInfo;
	QString qsFileName, qsCommand;

	for (t=0;t<m_listMenuObjects.count ();t++)	{
		// First we check each object if m_qsAnimation is empty
		if (m_listMenuObjects.at(t)->animation().isEmpty())
			continue;
		// Next we check if the contents is a fileName (to the data file)
		if (m_listMenuObjects.at(t)->animation ().contains ("\n") < 2)	{
			// Assume fileName
			fileInfo.setFile (m_listMenuObjects.at(t)->animation());
			if (fileInfo.exists())	{
				m_listMenuObjects.at(t)->loadAnimationData (m_listMenuObjects.at(t)->animation(), iMaxFrames);
				continue;
			}
		}
		// Finally we assume it is a script to generate the data ...
		qsFileName=QString("%1/%2/%3/%4").arg(Global::qsTempPath).arg(Global::qsProjectName).arg(qsMenuName).arg(m_listMenuObjects.at(t)->name ());
		theFile.setName (qsFileName+QString(".sh"));
		if (theFile.open (IO_WriteOnly))	{
			QTextStream theStream ( &theFile );
			theStream << m_listMenuObjects.at(t)->animation ();
			theFile.close ();
		}
		// next we change the mode to executable ...
		chmod (qsFileName+QString(".sh"), 0777);// S_IEXEC | S_IRUSR | S_IWRITE);
		qsCommand = QString ("\"%1.sh\" 2>/dev/null > \"%2.dat\"").arg (qsFileName).arg(qsFileName);
//printf ("MenuPreview::createAnimationData <%s>\n", (const char *)qsCommand);
		if ( system ( qsCommand ) == -1 )
			return;
		qsFileName += QString (".dat");
		// Check if the file has some size to it ...
		fileInfo.setFile (qsFileName);
		if (fileInfo.size() < 1)	{
			// TODO: write to the conversion log of this menu ...
			continue;
		}
		m_listMenuObjects.at(t)->loadAnimationData (qsFileName, iMaxFrames);
	}
}

MenuObject *MenuPreview::createFrameObject(bool bShowDialog)
{
	FrameObject *pFrameObject = new FrameObject ( this );
	pFrameObject->setRect        ( m_rectCurrentObject );
	pFrameObject->setFrameWidth  ( 4 );
 	pFrameObject->setFrameColor  ( QColor ( START_FRAME_COLOR ) );
	if (bShowDialog)	{
		m_listMenuObjects.append ( pFrameObject );
		emit ( signalUpdateStructure ( ) );
		updatePixmap ( );
	}
	// Here we connect the signal to the slot ...
	connectStdSlots ( pFrameObject, true );

	return pFrameObject;
}

MenuObject *MenuPreview::createTextObject(bool bShowDialog)
{
	TextObject *pTextObject = NULL;
	if (bShowDialog)	{
		DialogTextFont fontDialog (this);
		fontDialog.setRect(m_rectCurrentObject);
		if (fontDialog.exec() == QDialog::Rejected)
			return NULL;

		pTextObject = new TextObject (this);
		QString qsText = fontDialog.getText();
		pTextObject->setRect (fontDialog.getRect());
//		pTextObject->setRect (m_rectCurrentObject);
		pTextObject->setFont (fontDialog.getFont());
		pTextObject->setText (qsText);
		pTextObject->setAnimation (fontDialog.getAnimation () );
		pTextObject->setTextAlign(fontDialog.getTextAlign());
		pTextObject->setBackgroundColor (fontDialog.getBackgroundColor());
		pTextObject->setForegroundColor (fontDialog.getForegroundColor());
		pTextObject->modifiers ()->fTransparency = fontDialog.getTransparency();
		// Checks wether the user wants to fit the size of the button to the text or not.
		if (fontDialog.getFit())	{
			QRect rect = pTextObject->rect();
			rect.setWidth (1);
			rect.setHeight(1);
			pTextObject->setRect(rect);
		}
		m_listMenuObjects.append (pTextObject);
		emit (signalUpdateStructure());
		updatePixmap();
		pTextObject->update ();
	}
	else
		pTextObject = new TextObject (this);

	// Here we connect the signal to the slot ...
	connectStdSlots ( pTextObject, true );
	return pTextObject;
}

MenuObject *MenuPreview::createImageObject(bool bShowDialog)
{
	ImageObject *pImageObject = NULL;

	if (bShowDialog)	{
	  // The first step is to get the image name
	  QString qsImageFilter      = "*.jpg *.jpeg *.png *.xbm *.bmp *.JPG *.JPEG *.PNG *.XBM *.BMP";

	  //	  QString qsImageName = QFileDialog::getOpenFileName(Global::qsCurrentPath, tr("Image Files (*.jpg *.jpeg *.png *.xbm *.bmp *.JPG *.JPEG *.PNG *.XBM *.BMP)"), this,
	  QString qsImageName = FilePreviewDialog::getOpenFileName ( NULL, Global::qsCurrentPath, QString ("Images ( ") + qsImageFilter + QString (" );;All ( * )"), this, 
	      tr("Select image"), tr("Select a image object."));
	  if (qsImageName.isNull())
	    return NULL;
	  
	  QFileInfo fileInfo  (qsImageName);
	  Global::qsCurrentPath = fileInfo.filePath();

	  // Here we create the Pixmap in the right scale
	  QImage theImage (qsImageName);
	  int iWidth, iHeight;
	  float fZoom;
	  // Keep aspect ratio
	  iWidth  = m_rectCurrentObject.width();
	  iHeight = (int)((float)theImage.height()/theImage.width()*m_rectCurrentObject.width());
	  fZoom = ((float)m_rectCurrentObject.width() / theImage.width());
	  // Convert the image and generate the Pixmap
	  theImage = theImage.smoothScale (iWidth, iHeight);	//, QImage::ScaleMin);
	  QPixmap thePixmap;
	  thePixmap.convertFromImage(theImage);
	  // Clear memory ...
	  theImage = QImage ();
	  // And here we adopt the rect the user has drawn.
	  m_rectCurrentObject.setHeight(iHeight);
	  // Finally we create the ImageObject
	  pImageObject = new ImageObject (this);
	  pImageObject->setRect (m_rectCurrentObject);
	  pImageObject->setZoom (fZoom);	// We want to say Zoom = 1.0 even if the original size is already zoomed.
	  pImageObject->setFile(qsImageName);
	  pImageObject->setPixmap(thePixmap);

	  m_listMenuObjects.append (pImageObject);
	  emit (signalUpdateStructure());
	  updatePixmap();
	}
	else
	  pImageObject = new ImageObject (this);
	
	// And last we connect the signals
	connectStdSlots ( pImageObject, true );
	//	connect (pImageObject, SIGNAL(signalModifyMe(MenuObject *)), this, SLOT(slotModifyObject(MenuObject *)));

	return pImageObject;
}

MenuObject *MenuPreview::createMovieObject(bool bShowDialog)
{
	MovieObject *pMovieObject = NULL;

	if (bShowDialog)	{
		QPixmap thePixmap;
		// The first step is to get the movie name
		// to speed things up we create a dummyMediaInfo first
		MediaInfo *pMediaInfo = (MediaInfo *) new DummyInfo ();
		QString qsFilter = tr ("Movie Files (%1)").arg(pMediaInfo->getExtensions (true));


		//QString qsMovieName = QFileDialog::getOpenFileName(Global::qsCurrentPath, qsFilter, this, 
		//	tr("Select movie"), tr("Select a movie object."));
		QString qsMovieName = FilePreviewDialog::getOpenFileName ( NULL, Global::qsCurrentPath, QString ("Movies ( ") + qsFilter + QString (" );;All ( * )"), this, 
			tr("Select image"), tr("Select a image object."));
		if (qsMovieName.isNull())
			return NULL;
		QCursor myCursor (QCursor::WaitCursor);
		setCursor (myCursor);
		// Here we need to get a screenshot, thus the dummy won't do !!!
		delete pMediaInfo;

		QFileInfo fileInfo  (qsMovieName);
		Global::qsCurrentPath = fileInfo.filePath();

		// Here we create the Pixmap in the right scale
		QImage theImage = QImage().fromMimeSource("please_wait.jpg");

		int   iHeight;
		QSize theSize = m_rectCurrentObject.size();
		theImage = theImage.smoothScale (theSize, QImage::ScaleFree);
		// Keep aspect ratio
		iHeight = (int)((float)theImage.height()/theImage.width()*m_rectCurrentObject.width());
		thePixmap.convertFromImage(theImage);
		// Clear memory ...
		theImage = QImage ();
		// And here we adopt the rect the user has drawn.
		m_rectCurrentObject.setHeight(iHeight);
		// Finally we create the ImageObject
		pMovieObject = new MovieObject (this);
		pMovieObject->setRect     (m_rectCurrentObject);
		pMovieObject->setZoom     (1.0f);	// We want to say Zoom = 1.0 even if the original size is already zoomed.
		pMovieObject->setFile     (qsMovieName);
		pMovieObject->setPixmap   (thePixmap);
		pMovieObject->setMovieSize(theSize);

		m_listMenuObjects.append (pMovieObject);
		emit (signalUpdateStructure());
		updatePixmap();

		// Next we register to receive a preview image of the movie file ...
		MediaCreator::registerWithMediaScanner (pMovieObject, qsMovieName, pMovieObject->previewImage());

		// We need this to obtain a pointer to the assoziated DVDMenu ...
		emit (signalCreatedMovieObject (pMovieObject, true)); // inclusive render request ...

		myCursor = QCursor(QCursor::ArrowCursor);
		setCursor (myCursor);
	}
	else	{
		pMovieObject = new MovieObject (this);
		// We need this to obtain a pointer to the assoziated DVDMenu ... But no render request ...
		emit (signalCreatedMovieObject (pMovieObject, false));
	}

	// And last we connect the signals
	connectStdSlots ( pMovieObject, true );
	//	connect (pMovieObject, SIGNAL(signalModifyMe(MenuObject *)), this, SLOT(slotModifyObject(MenuObject *)));
	return pMovieObject;
}

MenuObject *MenuPreview::createButtonObject(bool bShowDialog)
{
  ButtonObject *pButtonObject = new ButtonObject (this);

  if (bShowDialog)	{
    m_listMenuObjects.append (pButtonObject);
    emit (signalUpdateStructure());
    updatePixmap();
  }
  
  // And finally we connect everything ...
  connectStdSlots ( pButtonObject, true );
  return pButtonObject;
}

MenuObject *MenuPreview::createObjectCollection(bool)
{
	MessageBox::warning (NULL, tr ("Not Implemented yet."), tr ("createObjectCollection : Not Implemented yet."),
		QMessageBox::Ok ,  QMessageBox::Cancel);
	updatePixmap();
	return NULL;
}

void MenuPreview::setVisibleRegion (bool bVisibleOn)
{
	m_bDrawVisibleRegion = bVisibleOn;
	updatePixmap ();
}

void MenuPreview::slotDefineAsButton ( MenuObject *pTheObject )
{
  defineAsButton ( pTheObject, true );
}

ButtonObject *MenuPreview::defineAsButton ( MenuObject *pTheObject, bool bShowDialog )
{
	// This is interesting ...
	// first we need to create a ButtonObject,
	// which we then furnish with three copies of this TextObject
	// Namely: Normal, Selected, and Highlighted ...
	m_listMenuObjects.remove ( pTheObject );
	ButtonObject *pButtonObject = new ButtonObject ( this );
	// Now we generate two copies ...
	MenuObject *pNewSelected, *pNewHighlighted;
	TextObject  textObject;
	FrameObject frameObject;

	QColor colorTransparent ( TRANSPARENT_COLOR       );
 	QColor colorHighlighted ( START_HIGHLIGHTED_COLOR );
	QColor colorSelected    ( START_SELECTED_COLOR    );
	QColor colorSpare       ( TRANSPARENT_COLOR       );
	if (m_pPgcColors)	{
		colorTransparent = m_pPgcColors[0];
 		colorHighlighted = m_pPgcColors[1];
		colorSelected	 = m_pPgcColors[2];
		colorSpare       = m_pPgcColors[3];
	}

	pNewSelected = pNewHighlighted = NULL;
	if ( pTheObject->objectType ( ) == textObject.objectType ( ) )  {
		pNewSelected    = pTheObject->clone ( );
		pNewHighlighted = pTheObject->clone ( );
		// Only the 'normal' object should have a shadow
		pNewSelected   ->setShadow ( NULL );
		pNewHighlighted->setShadow ( NULL );
		// Next we give some color differences for the different states (TextObjects)
		((TextObject *)(pNewSelected))   ->setForegroundColor (colorSelected);
		((TextObject *)(pNewHighlighted))->setForegroundColor (colorHighlighted);
		// Also here we ensure that the Textbackground for selected / highlighted is always transparent
		// The background color has already been put onto the actual background image.
		((TextObject *)(pNewSelected))   ->setBackgroundColor (colorTransparent);
		((TextObject *)(pNewHighlighted))->setBackgroundColor (colorTransparent);
		// The layers should not be aliased ...
		((TextObject *)(pNewSelected))   ->setStyleStrategy   (QFont::NoAntialias);
		((TextObject *)(pNewHighlighted))->setStyleStrategy   (QFont::NoAntialias);
		// And finally we do not want transparency (yet)
		((TextObject *)(pNewSelected))   ->modifiers()->fTransparency = 0.0f;
		((TextObject *)(pNewHighlighted))->modifiers()->fTransparency = 0.0f;
	}
	else	{	// All but Text Objects get a frame for starters
		// Okay we want 1:1 for FrameObjects
		if (pTheObject->objectType() == frameObject.objectType())	{
			pNewSelected    = pTheObject->clone();
			pNewHighlighted = pTheObject->clone();
		}
		else	{	// for ImageObject, and MovieObject a standard frame
			pNewSelected    = new FrameObject;
			pNewHighlighted = new FrameObject;
			pNewSelected->setRect        (  pTheObject->rect      ( ) );
			pNewHighlighted->setRect     (  pTheObject->rect      ( ) );
			pNewSelected->setModifiers   ( *pTheObject->modifiers ( ) );
			pNewHighlighted->setModifiers( *pTheObject->modifiers ( ) );
			((FrameObject *)(pNewSelected))->setFrameWidth       ( 10 );
			((FrameObject *)(pNewHighlighted))->setFrameWidth    ( 10 );
		}
		// Next we give some color the the diffenrent states
		((FrameObject *)(pNewSelected))   ->setFrameColor ( colorSelected    );
		((FrameObject *)(pNewHighlighted))->setFrameColor ( colorHighlighted );
	}
	pButtonObject->appendNormal      ( pTheObject      );
	pButtonObject->appendSelected    ( pNewSelected    );
	pButtonObject->appendHighlighted ( pNewHighlighted );

	pButtonObject->setName ( newButtonName ( ) );
	// Next we should give the button the same attributes as the NormalState ...
	// rect and boundingRect are taken care of in drawContent
	pButtonObject->setModifiers ( *pTheObject->modifiers ( ) );

	// and here we append the button object as a new item in the MenuObject list.
	m_listMenuObjects.append ( pButtonObject );
	m_pActiveObject = NULL;

	if ( bShowDialog ) {
	  // Create the buttonDialog, so the user can change things around ...
	  slotCreateButtonDialog ( pButtonObject );
	  if ( m_pDialogButton )
	       m_pDialogButton->setButtonCreation ( true );
	}
	// And finally we connect everything ...
	connectStdSlots ( pButtonObject, true );
	return pButtonObject;
}

void MenuPreview::slotCreateButtonDialog(ButtonObject *pButtonObject)
{
	uint t;
	// Here we generate a list of all Buttons in the current Menu. This is needed in the ButtonDialog
	// to  offer a list of possible targets.
	QStringList listMenuButtons;
	ButtonObject tempButton;

	for (t=0;t<m_listMenuObjects.count();t++)	{
		if (m_listMenuObjects.at(t)->objectType() == tempButton.objectType())	{
			listMenuButtons.append(m_listMenuObjects.at(t)->name());
		}
	}

	// Second step is to invoke the ButtonDialog ...
	m_pDialogButton = new DialogButton(this);
	m_pDialogButton->initMe(pButtonObject, this);
	m_pDialogButton->setMenuButtons (listMenuButtons);
	m_pDialogButton->show();
	connect (m_pDialogButton, SIGNAL(signalUpdateStructure()), this, SLOT(slotUpdateStructure()));
	connect (m_pDialogButton, SIGNAL(signalUpdatePixmap()),    this, SLOT(slotUpdatePixmap()));
	connect (m_pDialogButton, SIGNAL(destroyed()),             this, SLOT(slotDestroyedButtonDialog()));

	m_pActiveObject = NULL;
	// Go to DVDAuthor::slotRerquestSourceFiles.
	// Will return to respondSourceFiles() ...
	emit (signalRequestSourceFiles());
	// Will return to respondSubMenus() ...
	emit (signalRequestSubMenus());
	emit (signalUpdateStructure());
}

void MenuPreview::respondSourceFiles (QValueList<SourceFileEntry *>listSourceFileEntries)
{
	// If m_pActiveObject is set this means that we called for the SourceFileList from
	// readObject ...
	if (m_pActiveObject)	{
		ButtonObject *pCreatedButton = (ButtonObject *)m_pActiveObject;
		// Here we connect the Button, which was created in readObject
		uint t;
		for (t=0;t<listSourceFileEntries.count();t++)	{
//			QString qs = pCreatedButton->sourceDisplayName();
// printf ("MenuPreview::respondSourceFiles <%s>\n", (const char *)pCreatedButton->sourceDisplayName());
			if (listSourceFileEntries[t]->qsDisplayName == pCreatedButton->sourceDisplayName())	{
				pCreatedButton->setSourceFileEntry(listSourceFileEntries[t]);
				break;
			}
		}
		// And set this one to NULL
		m_pActiveObject = NULL;
	}
	// First check if this was triggered from slotCreateButtonDialog
	else if ( m_pDialogButton )
	 	  m_pDialogButton->setSourceFiles(listSourceFileEntries);
}

void MenuPreview::respondSubMenus (QStringList listSubMenus)
{
	// Okay, this is the return of the above emit(signalRequestSubMenus()) - call
	// Coming back from DVDMenu::slotRequestSubMenus()
	if (!m_pDialogButton)
		return;
	m_pDialogButton->setSubMenus(listSubMenus);
}

void MenuPreview::slotDestroyedButtonDialog()
{
  // The Button dialog was destroyed. So we should set the pointer to NULL;
  m_pDialogButton = NULL;
}

void MenuPreview::slotUpdateStructure()
{
	// simply reache this call on to CDVDMenu ...
	emit (signalUpdateStructure());
}

void MenuPreview::slotUpdatePixmap()
{
	updatePixmap();
}

void MenuPreview::slotDeleteObject(MenuObject *pObject)
{
	// simply do the same as the base class but also update the structureView ...
	ButtonPreview::slotDeleteObject(pObject);
	updatePixmap();
	emit (signalUpdateStructure());
}

void MenuPreview::slotAddShadow ( MenuObject *pObject ) 
{
  QPixmap thePixmap ( m_backgroundPixmap );
  if ( m_backgroundPixmap.isNull ( ) )
    thePixmap = QPixmap ( 720, 480 );

  // Here we create the background without the current object
  // (we want to move that one around right ?)
  QPainter thePainter(&thePixmap);
  if ( pObject == &m_selectionObject ) {
    for ( uint t=0; t<m_listMenuObjects.count ( ); t++ )  {
      if ( ! m_selectionObject.contains ( m_listMenuObjects.at ( t ) ) )
	m_listMenuObjects.at ( t )->drawContents ( &thePainter );
    }
  }
  else {
    for (  uint t=0; t<m_listMenuObjects.count ( ); t++ )  {
      if ( m_listMenuObjects.at ( t ) != pObject )
	m_listMenuObjects.at ( t )->drawContents ( &thePainter );
    }
  }

  DialogShadow dialog ( this );
  dialog.initMe       ( pObject,    &thePixmap );
  if ( dialog.exec    ( ) == QDialog::Rejected )
    return;

  updatePixmap ( );
}

void MenuPreview::slotModifyObject ( MenuObject *pObject )
{
  QPixmap thePixmap ( m_backgroundPixmap );
  if ( m_backgroundPixmap.isNull ( ) )
    thePixmap = QPixmap ( 720, 480 );

  // Here we create the background without the current object
  // (we want to move that one around right ?)
  QPainter thePainter(&thePixmap);
  for ( uint t=0; t<m_listMenuObjects.count ( ); t++ )  {
    if ( m_listMenuObjects.at ( t ) != pObject)
      m_listMenuObjects.at ( t )->drawContents ( &thePainter );
  }

  ImageObject *pImageObject = (ImageObject *)pObject;
  DialogImage2 dialog ( this );
  dialog.initMe       ( pImageObject, &thePixmap );
  if (   dialog.exec  ( )  ==  QDialog::Rejected )
    return;

  updatePixmap ( );
}

void MenuPreview::slotAlignSelection ( )
{
  QPixmap thePixmap ( m_backgroundPixmap );
  if ( m_backgroundPixmap.isNull ( ) )
    thePixmap = QPixmap ( 720, 480 );

  // Here we create the background without the current object
  // (we want to move that one around right ?)
  int t;
  QPainter thePainter(&thePixmap);
  QPtrList <MenuObject> listOfObjectsToDraw;
  listOfObjectsToDraw = m_listMenuObjects;

  for ( t=0; t<m_selectionObject.getCount ( ); t++ )
    listOfObjectsToDraw.remove ( m_selectionObject.getObject ( t ) );

  for ( t=0; t<(int)listOfObjectsToDraw.count ( ); t++ )
    listOfObjectsToDraw.at ( t )->drawContents ( &thePainter );

  DialogAlign theDialog ( this );
  theDialog.initMe ( &m_selectionObject, &thePixmap );
  theDialog.exec   ( );
}

/* Here we have the fast version.
 the difference is that the image is taken from pPreview->setImage(pImage->pixmap()); (think thumbnail),
 rather then from the pImage->fileName - original file.
 I could also eliminater the setStartZoom thingy ...

 Problem :
 The problem here however is the wrong location at start of the dialog and also the
 pixelation after a couple of zoom, new dialog, stretch, new dialog rotate etc.
 Solution :
 Need to implement a re-fresh of the image from the file after the dialog is done
 This would be a perfect background task which refreshes the pImage->pixmap() automatically after
 the next drawContents() - call
 Benefit :
 This would save the loading of the (probably big) pixmap from file and the re-sizing to the
 thumbnail size.
 It would speed up the creation of the ImageDialog
void MenuPreview::slotModifyObject(MenuObject *pObject)
{
	// This function is only used from the ImageObject so far.

	// Need to modify internal handling and eliminate the dependance of the
	// m_pImage->src - fileName.
	// Rather check if the Image is already in Memory.
	ImageObject *pImage = (ImageObject *)pObject;
	// The following struct will hold the modifier information ...
	ImagePreview *pPreview;		// The ImagePreview - class
	QString qsBackgroundImage;	// Null is okay ... for now.
	CXmlSlideshow::img_struct theImageStruct;
	ImageManipulator *pManipulator = new ImageManipulator;

	// Here we set the name of the Image
//	theImageStruct.src = pImage->fileName();
	theImageStruct.pModifier = (void *)pManipulator;

	// Here we init the Manipulator values.
	*pManipulator = pImage->manipulator();
	// Note that we store the fRealZoom under fStartZoom in the ImagePreview.
	pManipulator->fZoom   = 1.0;
	pManipulator->iStartX = pImage->rect().x();
	pManipulator->iStartY = pImage->rect().y();
//	pManipulator->backgroundFileName = qsBackgroundImage;

	DialogImage imageDialog(this);
	// Before we initialize this we need to look at the modifiers of this ImageObject.

	imageDialog.initMe ((void *)&theImageStruct, qsBackgroundImage);
	pPreview = imageDialog.getPreview();
	// This is the StartZoom factor, we take every call to this Dialog at Zoom 1.0 in the GUI.
//	pPreview->setStartZoom (pImage->zoom());
	pPreview->setImage     (pImage->pixmap());
	if (!m_backgroundPixmap.isNull())	{
		// Here we create the background without the current object
		// (we want to move that one around right ?)
		QPixmap thePixmap(m_backgroundPixmap);
		QPainter thePainter(&thePixmap);
		for (uint t=0;t<m_listMenuObjects.count();t++)	{
			if (m_listMenuObjects[t] != pImage)
				m_listMenuObjects[t]->drawContents (&thePainter);
		}
		pPreview->setBackground(thePixmap, false);
	}
	pPreview->refreshPreview();
	if (imageDialog.exec() == QDialog::Rejected)
		return;
	// Here we recoup all information ...
	pManipulator = (ImageManipulator *)theImageStruct.pModifier;
	pImage->manipulator() = *pManipulator;
	pImage->setPixmap (pPreview->getObject());
	QRect newRect = pPreview->getRect();
	// Next we need to compensate for the ImageObjects drawing offset (rect/2)
	pImage->setRect(newRect);
	updatePixmap();
}
*/

void MenuPreview::slotUnbutton(ButtonObject *pButton)
{
  uint t=0;
  MenuObject *pObject;
  disconnect ( pButton );
  m_listMenuObjects.remove(pButton);

  for (t=0;t<pButton->getNormalCount();t++)	{
    pObject = pButton->getNormal(t);
    pObject->setCurrentMousePos (pButton->currentMousePos());
    m_listMenuObjects.append ( pObject );
    pObject->disconnect ( );
    connectStdSlots ( pObject, true );
  }
  for (t=0;t<pButton->getHighlightedCount();t++)	{
    pObject = pButton->getHighlighted(t);
    delete pObject;
  }
  for (t=0;t<pButton->getSelectedCount();t++)	{
    pObject = pButton->getSelected(t);
    delete pObject;
  }
  delete pButton;
  
  emit (signalUpdateStructure());
}

void MenuPreview::slotDeleteMenu()
{
	// This function is called when the user wants to delete the current DVDMenu.
	// It passes the request right through to the QDVDAuthor - class
	// NOTE: the timer ensures that we get out of mousePressEvent before deleting this objcet.
	QTimer::singleShot (500, this, SLOT(slotEmitDeleteMe()));
}

void MenuPreview::slotEmitDeleteMe()
{
	emit ( signalDeleteMe ( ) );
}

void MenuPreview::slotRenameMenu()
{
	// This function is called when the user wants to change the name of this SubMenu.
	// It passes the request right through the the main QDVDAuthor class.
	emit ( signalRenameMe ( ) );
}

void MenuPreview::slotCloneMenu()
{
	// This function is called when the user wants to change the name of this SubMenu.
	// It passes the request right through the the main QDVDAuthor class.
	emit ( signalCloneMe ( ) );
}

void MenuPreview::slotConvertToPAL ( )
{
	// This function is called when the user wants to convert the current menu to PAL
	// It passes the request right through the the main QDVDAuthor class.
	emit ( signalConvertMe ( true ) );
}

void MenuPreview::slotConvertToNTSC ( )
{
	// This function is called when the user wants to convert the current menu to NTSC
	// It passes the request right through the the main QDVDAuthor class.
	emit ( signalConvertMe ( false ) );
}

QString &MenuPreview::newButtonName()
{
  // This function searches the existing Buttons for it's names and picks the first name which is not in use.
  uint t, iButtonNr;
  bool bContinue = true;
  iButtonNr = 2;
  ButtonObject tempButton;
  static QString qsButtonName;
  qsButtonName = QString ("Button 1");
  while (bContinue)	{
    bContinue = false;	// default is the assumption we won't find the same name, thus exit after ...
    for (t=0;t<m_listMenuObjects.count();t++)	{
      if (m_listMenuObjects.at(t)->objectType() == tempButton.objectType())	{
	if (m_listMenuObjects.at(t)->name () == qsButtonName)	{
	  qsButtonName = QString ("Button %1").arg(iButtonNr++);
	  bContinue = true;	// crap, got to do it again ...
	  break;
	}
      }
    }
  }
  return qsButtonName;
}

QString MenuPreview::uniqueObjectName ( QString qsPrefix, QString qsSuffix )
{
  uint t, iCounter;
  bool bContinue = true;
  QString qsObjectName;

  iCounter = 1;
  qsObjectName = QString ("%1 %2").arg ( qsPrefix ).arg( qsSuffix );
  while ( bContinue )	{
    bContinue = false;	// default is the assumption we won't find the same name, thus exit after ...
    for ( t=0; t<m_listMenuObjects.count(); t++ )  {
      if ( m_listMenuObjects.at ( t )->name ( ) == qsObjectName )  {
	qsObjectName = QString ("%1(%2) %3").arg ( qsPrefix ).arg ( iCounter++).arg ( qsSuffix );
	bContinue = true;	// crap, got to do it again ...
	break;
      }
    }
  }

  return qsObjectName;
}

void MenuPreview::connectStdSlots (MenuObject *pObject, bool bAddExtraSlots )
{
  //printf ( "%s::%s::%d count<%d> obj<%p>\n", __FILE__, __FUNCTION__, __LINE__, m_listMenuObjects.count ( ), pObject );
  connect (pObject, SIGNAL ( signalUpdateStructure( ) ),              this, SLOT ( slotUpdateStructure( ) ) );
  connect (pObject, SIGNAL ( signalUpdatePixmap   ( ) ),              this, SLOT ( slotUpdatePixmap   ( ) ) );
  connect (pObject, SIGNAL ( signalDefineAsButton ( MenuObject * ) ), this, SLOT ( slotDefineAsButton ( MenuObject * ) ) );
  connect (pObject, SIGNAL ( signalDeleteMe       ( MenuObject * ) ), this, SLOT ( slotDeleteObject   ( MenuObject * ) ) );
  connect (pObject, SIGNAL ( signalShadowMe       ( MenuObject * ) ), this, SLOT ( slotAddShadow      ( MenuObject * ) ) );
  connect (pObject, SIGNAL ( signalMoveOnStack( MenuObject *, int) ), this, SLOT ( slotMoveOnStack    ( MenuObject *, int ) ) );
  if ( bAddExtraSlots ) {
    uint i;
    ImageObject  tempImage;
    MovieObject  tempMovie;
    ButtonObject tempButton;
    if ( pObject->objectType ( ) == tempButton.objectType ( ) ) {
      ButtonObject *pButton = (ButtonObject *)pObject;
      for ( i=0; i < pButton->getNormalCount ( ) ; i++ )
	connectStdSlots ( pButton->getNormal ( (int)i ), true );
      for ( i=0; i<pButton->getSelectedCount ( ) ; i++ )
	connect (  pButton->getSelected     ( i ), SIGNAL ( signalDeleteMe (MenuObject *) ), this, SLOT(slotDeleteObject (MenuObject *) ) );
      for ( i=0; i<pButton->getHighlightedCount ( ) ; i++ )
	connect (  pButton->getHighlighted  ( i ), SIGNAL ( signalDeleteMe (MenuObject *) ), this, SLOT(slotDeleteObject (MenuObject *) ) );

      connect ( pButton, SIGNAL(signalUnbuttonMe(ButtonObject *)), this, SLOT(slotUnbutton(ButtonObject *)));
      connect ( pButton, SIGNAL(signalCreateButtonDialog(ButtonObject *)), this, SLOT(slotCreateButtonDialog(ButtonObject *)));
    }
    else if ( ( pObject->objectType ( ) == tempImage.objectType ( ) ) ||
	      ( pObject->objectType ( ) == tempMovie.objectType ( ) ) )
      connect ( pObject, SIGNAL ( signalModifyMe (MenuObject *) ), this, SLOT ( slotModifyObject (MenuObject *) ) );
  }
}

