/****************************************************************************
** SelectionObject class 
**
** Created: Tue Mar 02 22:06:51 2006
**      by: Varol Okan using Kate
**
** This class is the encapsulation of the ObjectCollection.
**
** The ObjectCollection is not yet finished. It is intended to hold a list
** of MenuObject's which are linked to each other. Meaning if you move 
** the collection each member of it will move the same extend.
**
** Another use is to create a template which will fit the images/movies
** into a fixed scheme.
**
****************************************************************************/

#include <qpen.h>
#include <qbrush.h>
#include <qpainter.h>
#include <qpopupmenu.h>

#include "xml_dvd.h"
#include "menuobject.h"
#include "shadowobject.h"
#include "selectionobject.h"

SelectionObject::SelectionObject ( QWidget *pParent )
  : ObjectCollection ( pParent )
{
  m_qsObjectType = QString ( SELECTION_OBJECT );
  //printf ( "%s::%s : %d Obj<%p> = active<%s>\n", __FILE__, __FUNCTION__, __LINE__, this, isActive ( ) ? "true" : "false"  );
  resetObjectStates ( );
  setActive ( true );
}

SelectionObject::~SelectionObject ( )
{
  resetObjectStates ( );
  clear ( );
  clearShadows ( );
}

void SelectionObject::resetObjectStates ( )
{
  uint t;
  for (t=0;t<m_listObjectCollection.count();t++)
    m_listObjectCollection[t]->pObject->setObjectState ( MenuObject::StateUnknown );
}

void SelectionObject::setMoveState ( bool bSetMoving )
{
  uint t;
  MenuObject::enState enState = MenuObject::StateMoveObject;
  if ( ! bSetMoving )
    enState = MenuObject::StateUnknown;

  for (t=0;t<m_listObjectCollection.count();t++) {
    m_listObjectCollection[t]->pObject->setObjectState ( enState );
    m_listObjectCollection[t]->pObject->setActive ( bSetMoving );
  }
}

void SelectionObject::setCurrentMousePos ( QPoint &thePos )
{
  uint t;
  for (t=0;t<m_listObjectCollection.count();t++) {
    m_listObjectCollection[t]->pObject->setCurrentMousePos ( thePos );
  }
}

void SelectionObject::drawSelected ( QPainter *pPainter )
{
  MenuObject *pObject;
  QWMatrix    theMatrix;
  QPoint      centerPos;
  QBrush      theBrush   ( QColor ( 100, 255, 100 ), Qt::Dense6Pattern );
  QPen        thePen     ( QColor ( 100, 255, 100 ), 1,  Qt::SolidLine );
  // Here we calculate the center point of gravity (rotation)
  uint t;
  for (t=0;t<m_listObjectCollection.count();t++) {
    pObject = m_listObjectCollection[t]->pObject;

    centerPos.setX (pObject->rect().x() + (int)((float)pObject->rect().width () / 2.0));
    centerPos.setY (pObject->rect().y() + (int)((float)pObject->rect().height() / 2.0));
    // Here we define the cenetered rect.
    QRect theRect ((int)-(pObject->rect().width()/ 2.0), (int)-(pObject->rect().height()/2.0), pObject->rect().width(), pObject->rect().height());
    
    // First we translate to the appropriate location,
    theMatrix.translate ((double)centerPos.x(), (double)centerPos.y());
    
    //. then we apply the other modifications ...
    theMatrix.scale  ( pObject->modifiers ( )->fScaleX, pObject->modifiers ( )->fScaleY );
    theMatrix.shear  ( pObject->modifiers ( )->fShearX, pObject->modifiers ( )->fShearY  );
    theMatrix.rotate ( pObject->modifiers ( )->fRotate );
  
    pPainter->setWorldMatrix(theMatrix);
    
    pPainter->setBrush ( theBrush );
    pPainter->setPen   (  thePen  );
    pPainter->drawRect (  theRect );
    
    theMatrix.reset();
  }
  pPainter->setWorldMatrix(theMatrix);  
}

void SelectionObject::drawContents ( QPainter *pPainter )
{
  if ( isActive  ( ) )
    drawSelected ( pPainter );
  else
    ObjectCollection::drawContents ( pPainter );
}

void SelectionObject::drawShadows ( QPainter *pPainter )
{
  uint t;
  for ( t=0; t<m_listOfShadows.count ( ); t++ ) {
    m_listOfShadows[ t ]->drawContents ( pPainter );
  }
}

bool SelectionObject::find ( MenuObject *pObject )
{
  uint t;
  for (t=0;t<m_listObjectCollection.count();t++) {
    if ( m_listObjectCollection[t]->pObject == pObject ) 
      return true;
  }
  return false;
}

// returns if the mouse is within one of the selected objects
// AND sets the state accordingly
bool SelectionObject::mouseOver ( QPoint const &thePoint )
{
  uint t;
  for (t=0;t<m_listObjectCollection.count();t++) {
    if ( m_listObjectCollection[t]->pObject->boundingRect ().contains ( thePoint ) ) {
      setMoveState ( true );
      return true;
    }
  }
  setMoveState ( false );
  return false;
}

bool SelectionObject::mousePressEvent ( QMouseEvent *pEvent )
{
  uint t;
  if ( pEvent->button ( ) == RightButton ) {
    for (t=0;t<m_listObjectCollection.count();t++)  {
      if ( m_listObjectCollection [t]->pObject->boundingRect ( ).contains ( pEvent->pos ( ) ) ) {
	createContextMenu ( pEvent->globalPos ( ) );
	return true;
      }
    }
  }
  return false;
}

bool SelectionObject::createContextMenu ( QPoint globalPos )
{  
  if (m_pContextMenu)
    delete m_pContextMenu;
  
  if ( m_listObjectCollection.count ( ) < 1 ) 
    return false;

  QString qsShadow = tr ( "Apply Shadows ..." );
  // First we check if all selected objects have the same shadow ...
  if ( shadow ( ) )
    qsShadow = tr ( "Edit Shadows ..." );

  m_pContextMenu = new QPopupMenu(m_pParent);

  if ( getCount ( ) > 1 ) 
    m_pContextMenu->insertItem ( tr ( "Align ..." ), this, SLOT ( slotAlign     ( ) ) );
  m_pContextMenu->insertItem   ( qsShadow,           this, SLOT ( slotAddShadow ( ) ) );
  m_pContextMenu->insertSeparator ( );
  m_pContextMenu->insertItem   ( tr ("Delete"),      this, SLOT ( slotDelete    ( ) ) );
  m_pContextMenu->insertItem   ( tr ("Cut") ,        this, SLOT ( slotCut       ( ) ) );
  m_pContextMenu->insertItem   ( tr ("Copy"),        this, SLOT ( slotCopy      ( ) ) );
  m_pContextMenu->insertSeparator ( );
  m_pContextMenu->insertItem   ( tr ("To Front"),    this, SLOT ( slotToFront   ( ) ) );
  m_pContextMenu->insertItem   ( tr ("To Back"),     this, SLOT ( slotToBack    ( ) ) );
  m_pContextMenu->exec         ( globalPos, 1 );
  
  if (m_pContextMenu)
    delete m_pContextMenu;
  m_pContextMenu = NULL;

  return true;
}

void SelectionObject::setActive ( bool bActive )
{
  uint t;
  for (t=0;t<m_listObjectCollection.count();t++)
    m_listObjectCollection[t]->pObject->setActive ( false );
  ObjectCollection::setActive ( bActive );
}

void SelectionObject::updateShadows ( ShadowObject *pParentShadow, bool bRecreate )
{
  uint t;
  ShadowObject *pShadow;
  MenuObject *pMenuObject;

  if ( bRecreate ) {
    clearShadows ( );
    for (t=0;t<m_listObjectCollection.count();t++)  {
      pMenuObject = m_listObjectCollection[ t ]->pObject;
      pShadow = new ShadowObject ( pMenuObject );
      if ( pParentShadow )
        *pShadow = *pParentShadow;
      pShadow->updateShadow  ( bRecreate );
      m_listOfShadows.append ( pShadow );
    } 
  }
  else {
    for (t=0;t<m_listOfShadows.count();t++)  {
      pShadow = m_listOfShadows[ t ];      
      if ( pParentShadow )
        *pShadow = *pParentShadow;
      pShadow->updateShadow  ( bRecreate );
    } 
  }
}

void SelectionObject::clearShadows ( )
{
  uint t;
  for (t=0;t<m_listOfShadows.count();t++)
    delete m_listOfShadows[t];

  m_listOfShadows.clear ();
}

void SelectionObject::setShadow ( MenuObject *pShadow ) 
{
  uint t;
  if ( pShadow ) {
    for (t=0;t<m_listOfShadows.count();t++)
      m_listOfShadows[t]->m_pMenuObject->setShadow ( m_listOfShadows[t] );

    m_listOfShadows.clear ();
  }
  else 
    ObjectCollection::setShadow ( NULL );
}

MenuObject *SelectionObject::shadow ( )
{
  uint t;
  // Special handling, only return a pointer if all shadows are equal.
  MenuObject   *pObject1=NULL, *pObject2=NULL, *pShadow0=NULL;
  ShadowObject *pShadow1=NULL, *pShadow2=NULL;
  pObject1 = m_listObjectCollection [ 0 ]->pObject;
  if ( pObject1 )
       pShadow0 = pObject1->shadow ( );

  for (t=1;t<m_listObjectCollection.count ( );t++ ) {
    pObject2 = m_listObjectCollection [ t ]->pObject;
    if ( pObject1 && pObject2 ) {
      pShadow1 = (ShadowObject *)pObject1->shadow ( );
      pShadow2 = (ShadowObject *)pObject2->shadow ( );
      if ( pShadow1 && pShadow2 && ( *pShadow1 == *pShadow2 ) )
	continue;
      
      return NULL;
    }
  }
  return pShadow0;
}

void SelectionObject::slotAlign ( )
{
  emit ( signalAlignSelection ( ) );
}

void SelectionObject::slotCut ( )
{
  slotCopy   ( );
  slotDelete ( );
}

void SelectionObject::slotDelete ( )
{
  uint t;
  for (t=0;t<m_listObjectCollection.count();t++) {
    m_listObjectCollection[t]->bDeleteMe = false;
    emit ( signalDeleteMe ( m_listObjectCollection[t]->pObject ) );
    delete m_listObjectCollection[t];
  }
  m_listObjectCollection.clear ( );
}
