/****************************************************************************
** SelectionObject class 
**
**   Created : Tue Mar 02 22:06:51 2006
**        by : Varol Okan using Kate
** Copyright : (c) Varol Okan
**   License : GPL v 2.0
**
** 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 );
  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::setRect ( QRect &theRect )
{
  if ( m_listObjectCollection.count ( ) > 0 )  {
    MenuObject *pObject = m_listObjectCollection[0]->pObject;
    QRect currentRect = pObject->rect ( );
    int iDeltaX = theRect.x ( ) - currentRect.x ( );
    int iDeltaY = theRect.y ( ) - currentRect.y ( );

    MenuObject::setRect ( theRect );
    QRect rect;
    uint t;
    for ( t=0; t<m_listObjectCollection.count ( ); t++ )  {
      pObject  = m_listObjectCollection[t]->pObject;
      rect.setX ( pObject->rect ( ).x ( ) + iDeltaX );
      rect.setY ( pObject->rect ( ).y ( ) + iDeltaY );
      rect.setWidth   ( pObject->rect ( ).width ( ) );
      rect.setHeight  ( pObject->rect ( ).height( ) );
      pObject->setRect( rect );
    }
  }
}

QRect &SelectionObject::rect ( )
{
  if ( m_listObjectCollection.count ( ) > 0 )
    return m_listObjectCollection[0]->pObject->rect ( );
  return MenuObject::rect ( );
}

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 )
{
  m_currentMousePos = thePos;
  if ( m_listObjectCollection.count ( ) > 0 )
       MenuObject::setRect ( m_listObjectCollection[0]->pObject->rect ( ) );

  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 ( );
}
