summaryrefslogtreecommitdiffstats
path: root/src/item.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/item.cpp')
-rw-r--r--src/item.cpp599
1 files changed, 599 insertions, 0 deletions
diff --git a/src/item.cpp b/src/item.cpp
new file mode 100644
index 0000000..1cbf7e3
--- /dev/null
+++ b/src/item.cpp
@@ -0,0 +1,599 @@
+/***************************************************************************
+ * 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);
+}
+
+
+void Item::moveBy( double dx, double dy )
+{
+ QCanvasPolygon::moveBy(dx,dy);
+ emit movedBy( dx, dy );
+}
+
+
+void Item::setChanged()
+{
+ if (b_deleted)
+ return;
+
+ if (canvas())
+ canvas()->setChanged(boundingRect());
+}
+
+
+void Item::setItemPoints( const QPointArray & pa, bool setSizeFromPoints )
+{
+ m_itemPoints = pa;
+ if (setSizeFromPoints)
+ setSize( m_itemPoints.boundingRect() );
+ itemPointsChanged();
+}
+
+
+void Item::itemPointsChanged()
+{
+ setPoints(m_itemPoints);
+}
+
+
+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()
+{
+}
+
+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;
+}
+
+
+void Item::setSelected( bool yes )
+{
+ if ( isSelected() == yes ) {
+ return;
+ }
+ QCanvasPolygon::setSelected(yes);
+ yes ? (emit selected(this)) : (emit unselected(this));
+}
+
+
+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();
+}
+
+
+int Item::level() const
+{
+ return p_parentItem ? p_parentItem->level()+1 : 0;
+}
+
+
+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;
+}
+
+
+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();
+}
+
+
+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();
+}
+
+
+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;
+}
+
+
+void Item::setRaised( bool isRaised )
+{
+ m_bIsRaised = isRaised;
+ // We'll get called later to update our Z
+}
+
+
+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);
+ }
+}
+
+
+int Item::getNumberPre( double num )
+{
+ return (int)(num/getMultiplier(num));
+}
+
+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))];
+}
+
+double Item::getMultiplier( double num )
+{
+ if ( num == 0. ) return 1.;
+ else return std::pow( 10, 3*std::floor(std::log10(std::abs(num))/3) );
+}
+
+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);
+}
+
+
+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"