Logo Search packages:      
Sourcecode: ktechlab version File versions  Download package

item.cpp

/***************************************************************************
 *   Copyright (C) 2004-2005 by David Saxton                               *
 *   david@bluehaze.org                                                    *
 *                                                                         *
 *   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.                                   *
 ***************************************************************************/

#include "itemdocument.h"
#include "itemdocumentdata.h"
#include "core/ktlconfig.h"

#include <cmath>
#include <kdebug.h>
#include <kdialogbase.h>
#include <ktextedit.h>
#include <qbitarray.h>
#include <qlayout.h>
#include <qtimer.h>

const int minPrefixExp = -24;
const int maxPrefixExp = 24;
const int numPrefix = int((maxPrefixExp-minPrefixExp)/3)+1;
const QString SIprefix[] = {"y","z","a","f","p","n",QChar(0xB5),"m","","k","M","G","T","P","E","Z","Y"};


Item::Item( ItemDocument *itemDocument, bool newItem, const QString &id )
      : QObject(), QCanvasPolygon( itemDocument->canvas() )
{
      m_bDynamicContent = false;
      m_bIsRaised = false;
      m_bDoneCreation = false;
      p_parentItem = 0l;
      b_deleted = false;
      p_itemDocument = itemDocument;
      m_baseZ = -1;
      
      if ( QFontInfo(m_font).pixelSize() > 11 ) // It has to be > 11, not > 12, as (I think) pixelSize() rounds off the actual size
            m_font.setPixelSize(12);
      
      if (newItem)
            m_id = p_itemDocument->generateUID(id);
      
      else
      {
            m_id = id;
            p_itemDocument->registerUID(id);
      }
}


Item::~Item()
{
      p_itemDocument->requestEvent( ItemDocument::ItemDocumentEvent::ResizeCanvasToItems );
      p_itemDocument->unregisterUID( id() );
      
      QCanvasPolygon::hide();
      
      const VariantDataMap::iterator variantDataEnd = m_variantData.end();
      for ( VariantDataMap::iterator it = m_variantData.begin(); it != variantDataEnd; ++it )
            delete it.data();
      m_variantData.clear();
}


void Item::removeItem()
{
      if (b_deleted)
            return;
      b_deleted = true;
      
      hide();
      setCanvas(0l);
      emit removed(this);
      p_itemDocument->appendDeleteList(this);
}


00081 void Item::moveBy( double dx, double dy )
{
      QCanvasPolygon::moveBy(dx,dy);
      emit movedBy( dx, dy );
}


00088 void Item::setChanged()
{
      if (b_deleted)
            return;
      
      if (canvas())
            canvas()->setChanged(boundingRect());
}


00098 void Item::setItemPoints( const QPointArray & pa, bool setSizeFromPoints )
{
      m_itemPoints = pa;
      if (setSizeFromPoints)
            setSize( m_itemPoints.boundingRect() );
      itemPointsChanged();
}


00107 void Item::itemPointsChanged()
{
      setPoints(m_itemPoints);
}


00113 void Item::setSize( QRect sizeRect, bool forceItemPoints )
{
      if ( m_sizeRect == sizeRect && !forceItemPoints )
            return;
      
      if ( !preResize(sizeRect) )
            return;
      
      canvas()->setChanged(areaPoints().boundingRect());
      m_sizeRect = sizeRect;
      if ( m_itemPoints.isEmpty() || forceItemPoints )
      {
            setItemPoints( QPointArray( m_sizeRect ), false );
      }
      canvas()->setChanged(areaPoints().boundingRect());
      postResize();
      emit resized();
}


ItemData Item::itemData() const
{
      ItemData itemData;
      
      itemData.type = m_type;
      itemData.x = x();
      itemData.y = y();
      
      if ( !parentItem() )
            itemData.z = m_baseZ;
      
      itemData.size = m_sizeRect;
      itemData.setSize = canResize();
      
      if (p_parentItem)
            itemData.parentId = p_parentItem->id();
      
      const VariantDataMap::const_iterator end = m_variantData.end();
      for ( VariantDataMap::const_iterator it = m_variantData.begin(); it != end; ++it )
      {
            switch( it.data()->type() )
            {
                  case Variant::Type::String:
                  case Variant::Type::FileName:
                  case Variant::Type::Port:
                  case Variant::Type::Pin:
                  case Variant::Type::VarName:
                  case Variant::Type::Combo:
                  case Variant::Type::Select:
                  case Variant::Type::Multiline:
                  case Variant::Type::SevenSegment:
                  case Variant::Type::KeyPad:
                  {
                        itemData.dataString[it.key()] = it.data()->value().toString();
                        break;
                  }
                  case Variant::Type::Int:
                  case Variant::Type::Double:
                  {
                        itemData.dataNumber[it.key()] = it.data()->value().toDouble();
                        break;
                  }
                  case Variant::Type::Color:
                  {
                        itemData.dataColor[it.key()] = it.data()->value().toColor();
                        break;
                  }
                  case Variant::Type::Bool:
                  {
                        itemData.dataBool[it.key()] = it.data()->value().toBool();
                        break;
                  }
                  case Variant::Type::Raw:
                  {
                        itemData.dataRaw[it.key()] = it.data()->value().toBitArray();
                        break;
                  }
                  case Variant::Type::PenStyle:
                  case Variant::Type::PenCapStyle:
                  {
                        // These types are only created from DrawPart, and that class
                        // deals with these, so we can ignore them
                        break;
                  }
                  case Variant::Type::None:
                  {
                        // ? Maybe obsoleted data...
                        break;
                  }
            }
      }
      
      return itemData;
}


void Item::restoreFromItemData( const ItemData &itemData )
{
      move( itemData.x, itemData.y );
      if ( canResize() )
            setSize( itemData.size );
      
      Item *parentItem = p_itemDocument->itemWithID( itemData.parentId );
      if (parentItem)
            setParentItem(parentItem);
      else
            m_baseZ = itemData.z;
      
      //BEGIN Restore data
      const QStringMap::const_iterator stringEnd = itemData.dataString.end();
      for ( QStringMap::const_iterator it = itemData.dataString.begin(); it != stringEnd; ++it )
      {
            if ( hasProperty(it.key()) )
                  property( it.key() )->setValue( it.data() );
      }
      
      const DoubleMap::const_iterator numberEnd = itemData.dataNumber.end();
      for ( DoubleMap::const_iterator it = itemData.dataNumber.begin(); it != numberEnd; ++it )
      {
            if ( hasProperty(it.key()) )
                  property( it.key() )->setValue( it.data() );
      }
      
      const QColorMap::const_iterator colorEnd = itemData.dataColor.end();
      for ( QColorMap::const_iterator it = itemData.dataColor.begin(); it != colorEnd; ++it )
      {
            if ( hasProperty(it.key()) )
                  property( it.key() )->setValue( it.data() );
      }
      
      const BoolMap::const_iterator boolEnd = itemData.dataBool.end();
      for ( BoolMap::const_iterator it = itemData.dataBool.begin(); it != boolEnd; ++it )
      {
            if ( hasProperty(it.key()) )
                  property( it.key() )->setValue( QVariant( it.data(), 0 ) );
      }
      
      const QBitArrayMap::const_iterator rawEnd = itemData.dataRaw.end();
      for ( QBitArrayMap::const_iterator it = itemData.dataRaw.begin(); it != rawEnd; ++it )
      {
            if ( hasProperty(it.key()) )
                  property( it.key() )->setValue( it.data() );
      }
      //END Restore Data
}


bool Item::mousePressEvent( const EventInfo &eventInfo )
{
      Q_UNUSED(eventInfo);
      return false;
}
bool Item::mouseReleaseEvent( const EventInfo &eventInfo )
{
      Q_UNUSED(eventInfo);
      return false;
}
bool Item::mouseMoveEvent( const EventInfo &eventInfo )
{
      Q_UNUSED(eventInfo);
      return false;
}
bool Item::wheelEvent( const EventInfo &eventInfo )
{
      Q_UNUSED(eventInfo);
      return false;
}
void Item::enterEvent()
{
}
void Item::leaveEvent()
{
}

00287 bool Item::mouseDoubleClickEvent( const EventInfo &eventInfo )
{
      Q_UNUSED(eventInfo);
      
      typedef QValueList<Variant*> VarPtrLst;
      VarPtrLst list;
      const VariantDataMap::iterator variantDataEnd = m_variantData.end();
      for ( VariantDataMap::iterator it = m_variantData.begin(); it != variantDataEnd; ++it )
      {
            if ( it.data()->type() == Variant::Type::Multiline ) {
                  list.append(it.data());
            }
      }
      if ( list.count() > 1 )
      {
            kdWarning() << "Item::mouseDoubleClickEvent: Can't handle more than one multiline data"<<endl;
            return false;
      }
      else if ( list.isEmpty() )
            return false;
      
      Variant *v = *(list.at(0));
      
      /// @todo Replace this with KInputDialog::getMultiLineText for KDE 3.3
//    bool ok;
//    QString text = KInputDialog::getMultiLineText( v->caption(), "", v->getValue(), ok );

      KDialogBase *dlg = new KDialogBase( 0l, "", true, v->editorCaption(), KDialogBase::Ok|KDialogBase::Cancel|KDialogBase::User1, KDialogBase::Ok, false, KStdGuiItem::clear() );
      QFrame *frame = dlg->makeMainWidget();
      QVBoxLayout *layout = new QVBoxLayout( frame, 0, dlg->spacingHint() );
      KTextEdit *textEdit = new KTextEdit( frame );
      textEdit->setTextFormat( PlainText );
      textEdit->setText( v->value().toString() );
      layout->addWidget( textEdit, 10 );
      textEdit->setFocus();
      connect( dlg, SIGNAL( user1Clicked() ), textEdit, SLOT( clear() ) );
      dlg->setMinimumWidth( 600 );
      if ( dlg->exec() == KDialogBase::Accepted )
      {
            v->setValue( textEdit->text() );
            dataChanged();
            p_itemDocument->setModified(true);
      }
      delete dlg;
      
      return true;
}


00336 void Item::setSelected( bool yes )
{
      if ( isSelected() == yes ) {
            return;
      }
      QCanvasPolygon::setSelected(yes);
      yes ? (emit selected(this)) : (emit unselected(this));
}


00346 void Item::setParentItem( Item *newParentItem )
{
//    kdDebug() << k_funcinfo << "this = "<<this<<" newParentItem = "<<newParentItem<<endl;
      if ( newParentItem == p_parentItem )
            return;
      
      Item *oldParentItem = p_parentItem;
      
      if (oldParentItem)
      {
            disconnect( oldParentItem, SIGNAL(removed(Item*)), this, SLOT(removeItem()) );
            oldParentItem->removeChild(this);
      }
      
      if (newParentItem)
      {
            if ( newParentItem->contains(this) );
//                kdError() << k_funcinfo << "Already a child of " << newParentItem << endl;
            else
            {
                  connect( newParentItem, SIGNAL(removed(Item*)), this, SLOT(removeItem()) );
                  newParentItem->addChild(this);
            }
      }
      
      p_parentItem = newParentItem;
      (void)level();
      reparented( oldParentItem, newParentItem );
      p_itemDocument->slotUpdateZOrdering();
}


00378 int Item::level() const
{
      return p_parentItem ? p_parentItem->level()+1 : 0;
}


00384 ItemList Item::children( bool includeGrandChildren ) const
{
      if (!includeGrandChildren)
            return m_children;
      
      ItemList children = m_children;
      ItemList::const_iterator end = m_children.end();
      for ( ItemList::const_iterator it = m_children.begin(); it != end; ++it )
      {
            if (!*it)
                  continue;
            
            children += (*it)->children(true);
      }
      
      return children;
}


00403 void Item::addChild( Item *child )
{
      if ( !child )
            return;
      
      if ( child->contains(this) )
      {
//          kdError() << k_funcinfo << "Attempting to add a child to this item that is already a parent of this item. Incest results in stack overflow." << endl;
            return;
      }
      
      if ( contains( child, true ) )
      {
//          kdError() << k_funcinfo << "Already have child " << child << endl;
            return;
      }
      
      m_children.append(child);
      connect( child, SIGNAL(removed(Item* )), this, SLOT(removeChild(Item* )) );
      
      child->setParentItem(this);
      childAdded(child);
      p_itemDocument->slotUpdateZOrdering();
}


00429 void Item::removeChild( Item *child )
{
      if ( !child || !m_children.contains(child) )
            return;
      
      m_children.remove(child);
      disconnect( child, SIGNAL(removed(Item* )), this, SLOT(removeChild(Item* )) );
      
      childRemoved(child);
      p_itemDocument->slotUpdateZOrdering();
}


00442 bool Item::contains( Item *item, bool direct ) const
{
      const ItemList::const_iterator end = m_children.end();
      for ( ItemList::const_iterator it = m_children.begin(); it != end; ++it )
      {
            if ( (Item*)*it == item || ( !direct && (*it)->contains( item, false ) ) )
                  return true;
      }
      return false;
}


00454 void Item::setRaised( bool isRaised )
{
      m_bIsRaised = isRaised;
      // We'll get called later to update our Z
}


00461 void Item::updateZ( int baseZ )
{
      m_baseZ = baseZ;
      double z = ItemDocument::Z::Item + (ItemDocument::Z::DeltaItem)*baseZ;
      
      if ( isRaised() )
            z += ItemDocument::Z::RaisedItem - ItemDocument::Z::Item;
      
      setZ(z);
      
      const ItemList::const_iterator end = m_children.end();
      for ( ItemList::const_iterator it = m_children.begin(); it != end; ++it )
      {
            if (*it)
                  (*it)->updateZ(baseZ+1);
      }
}


00480 int Item::getNumberPre( double num )
{
      return (int)(num/getMultiplier(num));
}

00485 QString Item::getNumberMag( double num )
{
      if ( num == 0. ) return "";
      const double exp_n = std::log10(std::abs(num));
      if ( exp_n < minPrefixExp+3 ) return SIprefix[0];
      else if ( exp_n >= maxPrefixExp ) return SIprefix[numPrefix-1];
      else return SIprefix[(int)std::floor((double)(exp_n/3))-(int)floor(double(minPrefixExp/3))];
}

00494 double Item::getMultiplier( double num )
{
      if ( num == 0. ) return 1.;
      else return std::pow( 10, 3*std::floor(std::log10(std::abs(num))/3) );
}

00500 double Item::getMultiplier( const QString &_mag )
{
      QString mag;
      // Allow the user to enter in "u" instead of mu, as unfortunately many keyboards don't have the mu key
      if ( _mag == "u" )
            mag = QChar(0xB5);
      else
            mag = _mag;
      
      for ( int i=0; i<numPrefix; ++i )
      {
            if ( mag == SIprefix[i] )
            {
                  return std::pow( 10., (i*3)+minPrefixExp );
            }
      }
      
      // I think it is safer to return '1' if the unit is unknown
      return 1.;
//    return pow( 10., maxPrefixExp+3. );
}



//BEGIN Data stuff
double Item::dataDouble( const QString & id ) const
{
      Variant * variant = property(id);
      return variant ? variant->value().toDouble() : 0.0;
}


int Item::dataInt( const QString & id ) const
{
      Variant * variant = property(id);
      return variant ? variant->value().toInt() : 0;
}


bool Item::dataBool( const QString & id ) const
{
      Variant * variant = property(id);
      return variant ? variant->value().toBool() : false;
}


QString Item::dataString( const QString & id ) const
{
      Variant * variant = property(id);
      return variant ? variant->value().toString() : QString::null;
}


QColor Item::dataColor( const QString & id ) const
{
      Variant * variant = property(id);
      return variant ? variant->value().toColor() : Qt::black;
}


Variant * Item::createProperty( const QString & id, Variant::Type::Value type )
{
      if ( !m_variantData.contains(id) )
      {
            m_variantData[id] = new Variant(type);
            if (m_bDoneCreation)
                  connect( m_variantData[id], SIGNAL(valueChanged(QVariant,QVariant)), this, SLOT(dataChanged()) );
      }
      
      return m_variantData[id];
}


Variant * Item::property( const QString & id ) const
{
      if ( m_variantData.contains(id) )
            return m_variantData[id];
      
      kdError() << k_funcinfo << " No such property with id " << id << endl;
      return 0l;
}


bool Item::hasProperty( const QString & id ) const
{
      return m_variantData.contains(id);
}


00589 void Item::finishedCreation( )
{
      m_bDoneCreation = true;
      const VariantDataMap::iterator end = m_variantData.end();
      for ( VariantDataMap::iterator it = m_variantData.begin(); it != end; ++it )
            connect( it.data(), SIGNAL(valueChanged(QVariant,QVariant)), this, SLOT(dataChanged()) );
      dataChanged();
}
//END Data stuff

#include "item.moc"

Generated by  Doxygen 1.6.0   Back to index