/***************************************************************************
 *   Copyright (C) 2004 by Hans Oischinger                                 *
 *   hans.oischinger@kdemail.net                                           *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 *   This program is distributed in the hope that it will be useful,       *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU General Public License for more details.                          *
 *                                                                         *
 *   You should have received a copy of the GNU General Public License     *
 *   along with this program; if not, write to the                         *
 *   Free Software Foundation, Inc.,                                       *
 *   51 Franklin Steet, Fifth Floor, Boston, MA 02110-1301, USA.             *
 ***************************************************************************/
#include "attributelistview.h"

// Elements
#include "elements/elementnode.h"
#include "elements/elementtreeiterator.h"
#include "elements/attribute.h"
#include "elements/lengthattribute.h"
#include "elements/animatedlengthattr.h"
#include "elements/transformlist.h"
#include "elements/elementselection.h"

// Core
#include "core/direktorinstance.h"
#include "core/elementdatabase.h"

// Visitors
#include "visitors/vpropertyitemcreator.h"

// KDE
#include <kdebug.h>

AttributeListView::AttributeListView(QWidget *parent, const char *name)
    : KListView(parent, name),
    m_element(0),
    m_lastSelectedItem(0)
{
  // Set the selected element
  onSelectionModified();
  connect ( this, SIGNAL(currentChanged( QListViewItem*) ), SLOT( onCurrentChanged( QListViewItem*) ) );
}

/**
 * Hide the editor widget of the Item that has just lost focus
 * and select the item that received focus
 */
void AttributeListView::onCurrentChanged( QListViewItem* e )
{
  if (m_lastSelectedItem)
    m_lastSelectedItem->hideEditor();
  m_lastSelectedItem = static_cast<AttributeListViewItem*>(e);
  if (m_lastSelectedItem)
    m_lastSelectedItem->showEditor();
}

void AttributeListView::clear()
{
  onCurrentChanged(0);
  KListView::clear();
}


AttributeListView::~AttributeListView()
{}

void AttributeListView::onElementInserted( ElementNode* )
{}

void AttributeListView::onElementRemoved( ElementNode* e )
{
  kdDebug() << k_funcinfo << endl;

  // Remove Elements from
  ElementTreeIterator itr( e ); // TODO: This could be const
  for( ; itr.current(); itr.next() )
    if ( m_element == itr.current() )
    {
      kdDebug() << "AttributeListView::onElementRemoved() - Removing element " << itr.current()->className() << endl;
      m_element = 0;
      clear();
    }
}

void AttributeListView::onElementModified( ElementNode *e )
{
  kdDebug() << "AttributeListView::onElementModified()" << endl;
  if ( e == m_element )
  {
    clear();
    setElement(e);
  }
}

void AttributeListView::onSelectionModified( )
{
  clear();
  setElement( Kast::self()->elementDB().selection().elements().first() );
}

void AttributeListView::setElement(ElementNode* element)
{
  clear();
  m_element = element;
  if (!m_element)
    return;

  VPropertyItemCreator createProps(this);
  element->accept( createProps );
}





// Qt
#include <qheader.h>
#include <qhbox.h>
#include <qlayout.h>

/**
AttributeListViewItem Base Class
*/
AttributeListViewItem::AttributeListViewItem( ElementNode *holder, Attribute*, QListView * parent, QListViewItem * after )
    : KListViewItem(parent, after),
    m_element(holder),
    m_editorContainer(0),
    m_editor(0)
{}

AttributeListViewItem::~AttributeListViewItem( )
{}

void AttributeListViewItem::activate( )
{
  //showEditor();
}

void AttributeListViewItem::showEditor()
{
  if( !isEnabled() )
    return;
  createEditWidget()->show();
  placeEditWidget();
}

void AttributeListViewItem::hideEditor()
{
  createEditWidget()->hide();
}

void AttributeListViewItem::placeEditWidget()
{
  QWidget* editWidget = createEditWidget();

  // Get the rectangle for our widget
  QListView* lv = listView();
  QRect r = lv->itemRect( this );
  if ( !r.size().isValid() )
  {
    lv->ensureItemVisible( this );
    r = lv->itemRect( this );
  }

  r.setX( lv->header()->sectionPos( 1 ) );
  r.setWidth( lv->header()->sectionSize( 1 ) - 1 );
  r = QRect( lv->viewportToContents( r.topLeft() ), r.size() );

  editWidget->setGeometry(r);
}

QWidget* AttributeListViewItem::createEditWidget()
{
  if ( m_editorContainer )
  {
    return m_editorContainer;
  }

  m_editorContainer = new QHBox(listView()->viewport());
  if (!m_editor)
    kdWarning() << "AttributeListViewItem::createEditWidget() - m_editor has not been set by concrete subclass" << endl;
  else
  {
    m_editor->reparent( m_editorContainer, 0, QPoint(0,0) );
    m_editorContainer->setStretchFactor( m_editor, 100);
    //m_editor->resize( m_editorContainer->width(),
    //                       m_editorContainer->height() );
  }

  m_editorContainer->hide();
  return m_editorContainer;
}


#include <klineedit.h>
#include "commands/esetgenericattrcmd.h"
#include "core/svghelper.h"
/**
LengthListViewItem Class
*/
LengthListViewItem::LengthListViewItem( ElementNode *holder, LengthAttribute* attribute,
                                        QListView* parent, QListViewItem* after )
    : AttributeListViewItem(holder, attribute, parent, after),
    m_animAttr(0),
    m_lineEdit(0)
{
  m_attr = attribute;
  readFromAttr();
  setText( 1, QString().setNum(m_attr->valueInSpecifiedUnits()).append(m_attr->readableSpecifiedUnits()) );
  setEnabled( m_attr->isValid() );
}

LengthListViewItem::LengthListViewItem( ElementNode * holder, AnimatedLength * attribute, bool showAnimVal,
                                        QListView* parent, QListViewItem* after )
    : AttributeListViewItem(holder, attribute, parent, after),
    m_lineEdit(0)
{
  m_animAttr = attribute;
  if (showAnimVal)
    m_attr = &m_animAttr->animVal();
  else
    m_attr = &m_animAttr->baseVal();

  readFromAttr();
  setText( 1, QString().setNum(m_attr->valueInSpecifiedUnits()).append(m_attr->readableSpecifiedUnits()) );
  setEnabled( m_attr->isValid() );
}

LengthListViewItem::~LengthListViewItem( )
{}

Attribute* LengthListViewItem::attribute() const
{
  return m_attr;
}

void LengthListViewItem::readFromAttr()
{
  setText( 1, QString().setNum(m_attr->valueInSpecifiedUnits()).append(m_attr->readableSpecifiedUnits()) );
  setEnabled( m_attr->isValid() );
}

void LengthListViewItem::showEditor()
{
  // Create LineEdit if not exists
  if (!m_lineEdit)
  {
    m_lineEdit = new KLineEdit( 0, "LengthListViewItem KLineEdit" );
    m_editor = m_lineEdit;
    connect( m_lineEdit, SIGNAL( returnPressed() ), SLOT( slotEdited() ) );
  }
  // Set pos&size and show it
  AttributeListViewItem::showEditor();

  // Fill with data
  m_lineEdit->setText( text(1) );
  m_lineEdit->selectAll();
  m_lineEdit->setFocus();
}

void LengthListViewItem::slotEdited()
{
  unsigned int unitType = 0;
  float value = SVGHelper::extractLength(m_lineEdit->text(), unitType );
  LengthAttribute newAttr( value, unitType );

  ESetGenericAttrCMD *cmd = new ESetGenericAttrCMD( m_element, *m_animAttr, newAttr );
  Kast::self()->addCommand(cmd);
  // Don't call this when the element sets elementModified().. we may be deleted// readFromAttr();

}


#include "elements/number.h"
#include "elements/animatednumber.h"
/**
NumberListViewItem Class
 */
NumberListViewItem::NumberListViewItem( ElementNode *holder, Number* attribute,
                                        QListView * parent, QListViewItem * after )
    : AttributeListViewItem(holder, attribute, parent, after),
    m_animAttr(0),
    m_lineEdit(0)
{
  m_attr = attribute;
  readFromAttr();
}

NumberListViewItem::NumberListViewItem( ElementNode * holder, AnimatedNumber * attribute,
                                      bool showAnimVal, QListView * parent, QListViewItem * after )
    : AttributeListViewItem(holder, attribute, parent, after),
    m_lineEdit(0)
{
  m_animAttr = attribute;
  if (showAnimVal)
    m_attr = &m_animAttr->animVal();
  else
    m_attr = &m_animAttr->baseVal();

  readFromAttr();
}

NumberListViewItem::~NumberListViewItem( )
{}

Attribute* NumberListViewItem::attribute() const
{
  return m_attr;
}

void NumberListViewItem::readFromAttr()
{
  setText( 1, QString().setNum(m_attr->value()) );
  setEnabled( m_attr->isValid() );
}

void NumberListViewItem::showEditor()
{
  // Create LineEdit if not exists
  if (!m_lineEdit)
  {
    m_lineEdit = new KLineEdit( 0, "NumberListViewItem KLineEdit" );
    m_editor = m_lineEdit;
    connect( m_lineEdit, SIGNAL( returnPressed() ), SLOT( slotEdited() ) );
  }
  // Set pos&size and show it
  AttributeListViewItem::showEditor();

  // Fill with data
  m_lineEdit->setText( text(1) );
  m_lineEdit->selectAll();
  m_lineEdit->setFocus();
}

void NumberListViewItem::slotEdited()
{
  Number newAttr(m_lineEdit->text());

  ESetGenericAttrCMD *cmd = new ESetGenericAttrCMD( m_element, *m_animAttr, newAttr );
  Kast::self()->addCommand(cmd);
  // Don't call this when the element sets elementModified().. we may be deleted// readFromAttr();
}



#include "elements/fillattribute.h"
/**
FillAttrListViewItem Class
 */
FillAttrListViewItem::FillAttrListViewItem( ElementNode *holder, FillAttribute* attribute,
    QListView * parent, QListViewItem * after )
    : AttributeListViewItem(holder, attribute, parent, after)
{
  m_attr = attribute;
  setText( 1, m_attr->readableFillType() );
  setEnabled( m_attr->isValid() );
}

FillAttrListViewItem::~FillAttrListViewItem( )
{}

Attribute* FillAttrListViewItem::attribute() const
{
  return m_attr;
}


#include "elements/strokeattribute.h"
/**
StrokeAttrListViewItem Class
 */
StrokeAttrListViewItem::StrokeAttrListViewItem( ElementNode *holder, StrokeAttribute* attribute,
    QListView * parent, QListViewItem * after )
    : AttributeListViewItem(holder, attribute, parent, after)
{
  m_attr = attribute;
  setText( 1, m_attr->readableStrokeType() );
  setEnabled( m_attr->isValid() );
}

StrokeAttrListViewItem::~StrokeAttrListViewItem( )
{}

Attribute* StrokeAttrListViewItem::attribute() const
{
  return m_attr;
}


#include <kcolorbutton.h>
#include "elements/colorattribute.h"
#include "elements/animatedcolorattr.h"
/**
ColorListViewItem Class
 */
ColorListViewItem::ColorListViewItem( ElementNode *holder, ColorAttribute* attribute,
                                      QListView * parent, QListViewItem * after )
    : AttributeListViewItem(holder, attribute, parent, after),
    m_animAttr(0),
    m_colorButton(0)
{
  m_attr = attribute;
  readFromAttr();
}

ColorListViewItem::ColorListViewItem( ElementNode * holder, AnimatedColor * attribute,
                                      bool showAnimVal, QListView * parent, QListViewItem * after )
    : AttributeListViewItem(holder, attribute, parent, after),
    m_colorButton(0)
{
  m_animAttr = attribute;
  if (showAnimVal)
    m_attr = &m_animAttr->animVal();
  else
    m_attr = &m_animAttr->baseVal();

  readFromAttr();
}

ColorListViewItem::~ColorListViewItem()
{}

Attribute* ColorListViewItem::attribute() const
{
  return m_attr;
}

void ColorListViewItem::readFromAttr()
{
  setText( 1, m_attr->qColor().name() );
  setEnabled( m_attr->isValid() );
}

void ColorListViewItem::showEditor()
{
  // Create LineEdit if not exists
  if (!m_colorButton)
  {
    m_colorButton = new KColorButton( 0, "NumberListViewItem KLineEdit" );
    m_editor = m_colorButton;
    connect( m_colorButton, SIGNAL( changed(const QColor &) ), SLOT( slotEdited(const QColor &) ) );
  }
  // Set pos&size and show it
  AttributeListViewItem::showEditor();

  // Fill with data
  m_colorButton->blockSignals(true);
  m_colorButton->setColor( m_attr->qColor() );
  m_colorButton->blockSignals(false);
  m_colorButton->setFocus();
}

void ColorListViewItem::slotEdited(const QColor &)
{
  ColorAttribute newAttr( m_colorButton->color() );

  ESetGenericAttrCMD *cmd = new ESetGenericAttrCMD( m_element, *m_animAttr, newAttr );  // FIXME. we need an element here
  Kast::self()->addCommand(cmd);
  // Don't call this when the element sets elementModified().. we may be deleted// readFromAttr();
}



/**
TransformListViewItem Class
*/
TransformListViewItem::TransformListViewItem( ElementNode *holder, Transform * attribute,
    QListView * parent, QListViewItem * after )
    : AttributeListViewItem(holder, attribute, parent, after)
{
  m_attr = attribute;
  //setText( 1, QString().setNum(m_attr->value()) );
  QString col1 = attribute->getReadableTransformMetaType();

  if (attribute->transformMetaType() == Transform::TRANSFORM_SKEWX )
    col1.append(": ").append( QString().setNum( m_attr->getSkewX()) );
  else if (attribute->transformMetaType() == Transform::TRANSFORM_SKEWY )
    col1.append(": ").append( QString().setNum( m_attr->getSkewY()) );
  else if (attribute->transformMetaType() == Transform::TRANSFORM_ROTATE )
    col1.append(": ").append( QString().setNum( m_attr->getRotateAngle()) );
  else if (attribute->transformMetaType() == Transform::TRANSFORM_SCALE )
    col1.append(": ").append( QString().setNum( m_attr->getScaleX()) ).append(",").append(
      QString().setNum( m_attr->getScaleY() ) );
  else if (attribute->transformMetaType() == Transform::TRANSFORM_TRANSLATE )
    col1.append(": ").append( QString().setNum( m_attr->getTranslateX()) ).append(",").append(
      QString().setNum( m_attr->getTranslateY() ) );

  setText( 1, col1 );
  setEnabled( m_attr->isValid() );
}

TransformListViewItem::~ TransformListViewItem()
{}

Attribute* TransformListViewItem::attribute() const
{
  return m_attr;
}


#include "elements/enumeration.h"
/**
AnimatedEnumListViewItem Class
 */
EnumListViewItem::EnumListViewItem( ElementNode *holder, Enumeration* attribute,
                                    QListView * parent, QListViewItem * after )
    : AttributeListViewItem(holder, attribute, parent, after)
{
  m_attr = attribute;
  setText( 1, QString().setNum(m_attr->value()) );
  setEnabled( m_attr->isValid() );
}

EnumListViewItem::~EnumListViewItem( )
{}

Attribute* EnumListViewItem::attribute() const
{
  return m_attr;
}


#include "elements/urireference.h"
/**
URIRefListViewItem Class
 */
URIRefListViewItem::URIRefListViewItem( ElementNode *holder, URIReference* attribute,
                                        QListView * parent, QListViewItem * after )
    : AttributeListViewItem(holder, attribute, parent, after)
{
  m_attr = attribute;
  setText( 1, m_attr->getURI() );
  setEnabled( m_attr->isValid() );
}

URIRefListViewItem::~URIRefListViewItem( )
{}

Attribute* URIRefListViewItem::attribute() const
{
  return m_attr;
}


#include "elements/timeattribute.h"
/**
TimeListViewItem Class
 */
TimeListViewItem::TimeListViewItem( ElementNode *holder, TimeAttribute* attribute,
                                    QListView * parent, QListViewItem * after )
    : AttributeListViewItem(holder, attribute, parent, after)
{
  m_attr = attribute;
  setText( 1, QString().setNum(m_attr->value()) );
  setEnabled( m_attr->isValid() );
}

TimeListViewItem::~TimeListViewItem( )
{}

Attribute* TimeListViewItem::attribute() const
{
  return m_attr;
}



#include "attributelistview.moc"
