/***************************************************************************
* 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 <tqbitarray.h>
# include <tqlayout.h>
# include <tqtimer.h>
const int minPrefixExp = - 24 ;
const int maxPrefixExp = 24 ;
const int numPrefix = int ( ( maxPrefixExp - minPrefixExp ) / 3 ) + 1 ;
const TQString SIprefix [ ] = { " y " , " z " , " a " , " f " , " p " , " n " , TQChar ( 0xB5 ) , " m " , " " , " k " , " M " , " G " , " T " , " P " , " E " , " Z " , " Y " } ;
Item : : Item ( ItemDocument * itemDocument , bool newItem , const TQString & id )
: TQObject ( ) , TQCanvasPolygon ( itemDocument - > canvas ( ) )
{
m_bDynamicContent = false ;
m_bIsRaised = false ;
m_bDoneCreation = false ;
p_parentItem = 0l ;
b_deleted = false ;
p_itemDocument = itemDocument ;
m_baseZ = - 1 ;
if ( TQFontInfo ( 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 ( ) ) ;
TQCanvasPolygon : : 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 )
{
TQCanvasPolygon : : moveBy ( dx , dy ) ;
emit movedBy ( dx , dy ) ;
}
void Item : : setChanged ( )
{
if ( b_deleted )
return ;
if ( canvas ( ) )
canvas ( ) - > setChanged ( boundingRect ( ) ) ;
}
void Item : : setItemPoints ( const TQPointArray & pa , bool setSizeFromPoints )
{
m_itemPoints = pa ;
if ( setSizeFromPoints )
setSize ( m_itemPoints . boundingRect ( ) ) ;
itemPointsChanged ( ) ;
}
void Item : : itemPointsChanged ( )
{
setPoints ( m_itemPoints ) ;
}
void Item : : setSize ( TQRect 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 ( TQPointArray ( 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 TQStringMap : : const_iterator stringEnd = itemData . dataString . end ( ) ;
for ( TQStringMap : : 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 TQColorMap : : const_iterator colorEnd = itemData . dataColor . end ( ) ;
for ( TQColorMap : : 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 ( TQVariant ( it . data ( ) ) ) ;
}
const TQBitArrayMap : : const_iterator rawEnd = itemData . dataRaw . end ( ) ;
for ( TQBitArrayMap : : 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 TQValueList < 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;
// TQString 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 ( ) ) ;
TQFrame * frame = dlg - > makeMainWidget ( ) ;
TQVBoxLayout * layout = new TQVBoxLayout ( 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 , TQT_SIGNAL ( user1Clicked ( ) ) , textEdit , TQT_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 ;
}
TQCanvasPolygon : : 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 , TQT_SIGNAL ( removed ( Item * ) ) , this , TQT_SLOT ( removeItem ( ) ) ) ;
oldParentItem - > removeChild ( this ) ;
}
if ( newParentItem )
{
if ( newParentItem - > contains ( this ) ) ;
// kdError() << k_funcinfo << "Already a child of " << newParentItem << endl;
else
{
connect ( newParentItem , TQT_SIGNAL ( removed ( Item * ) ) , this , TQT_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 , TQT_SIGNAL ( removed ( Item * ) ) , this , TQT_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 , TQT_SIGNAL ( removed ( Item * ) ) , this , TQT_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 ) ) ;
}
TQString 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 TQString & _mag )
{
TQString 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 = TQChar ( 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 TQString & id ) const
{
Variant * variant = property ( id ) ;
return variant ? variant - > value ( ) . toDouble ( ) : 0.0 ;
}
int Item : : dataInt ( const TQString & id ) const
{
Variant * variant = property ( id ) ;
return variant ? variant - > value ( ) . toInt ( ) : 0 ;
}
bool Item : : dataBool ( const TQString & id ) const
{
Variant * variant = property ( id ) ;
return variant ? variant - > value ( ) . toBool ( ) : false ;
}
TQString Item : : dataString ( const TQString & id ) const
{
Variant * variant = property ( id ) ;
return variant ? variant - > value ( ) . toString ( ) : TQString ( ) ;
}
TQColor Item : : dataColor ( const TQString & id ) const
{
Variant * variant = property ( id ) ;
return variant ? variant - > value ( ) . toColor ( ) : TQt : : black ;
}
Variant * Item : : createProperty ( const TQString & id , Variant : : Type : : Value type )
{
if ( ! m_variantData . contains ( id ) )
{
m_variantData [ id ] = new Variant ( type ) ;
if ( m_bDoneCreation )
connect ( m_variantData [ id ] , TQT_SIGNAL ( valueChanged ( TQVariant , TQVariant ) ) , this , TQT_SLOT ( dataChanged ( ) ) ) ;
}
return m_variantData [ id ] ;
}
Variant * Item : : property ( const TQString & 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 TQString & 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 ( ) , TQT_SIGNAL ( valueChanged ( TQVariant , TQVariant ) ) , this , TQT_SLOT ( dataChanged ( ) ) ) ;
dataChanged ( ) ;
}
//END Data stuff
# include "item.moc"