|
|
|
/***************************************************************************
|
|
|
|
* Copyright (C) 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 "icndocument.h"
|
|
|
|
#include "item.h"
|
|
|
|
#include "itemgroup.h"
|
|
|
|
#include "mechanicsdocument.h"
|
|
|
|
|
|
|
|
#include <tqtimer.h>
|
|
|
|
|
|
|
|
|
|
|
|
ItemGroup::ItemGroup( ItemDocument *view, const char *name )
|
|
|
|
: TQObject( view, name )
|
|
|
|
{
|
|
|
|
m_activeItem = 0l;
|
|
|
|
b_itemsAreSameType = true;
|
|
|
|
p_view = view;
|
|
|
|
p_icnDocument = dynamic_cast<ICNDocument*>(p_view);
|
|
|
|
p_mechanicsDocument = dynamic_cast<MechanicsDocument*>(p_view);
|
|
|
|
TQTimer::singleShot( 0, this, TQT_SLOT(getViewPtrs()) );
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
ItemGroup::~ItemGroup()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void ItemGroup::getViewPtrs()
|
|
|
|
{
|
|
|
|
p_icnDocument = dynamic_cast<ICNDocument*>(p_view);
|
|
|
|
p_mechanicsDocument = dynamic_cast<MechanicsDocument*>(p_view);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
ItemList ItemGroup::items( bool excludeParentedItems ) const
|
|
|
|
{
|
|
|
|
if (excludeParentedItems)
|
|
|
|
return m_itemList;
|
|
|
|
|
|
|
|
ItemList items = m_itemList;
|
|
|
|
ItemList parents = m_itemList;
|
|
|
|
|
|
|
|
uint oldSize = items.size();
|
|
|
|
do
|
|
|
|
{
|
|
|
|
oldSize = items.size();
|
|
|
|
ItemList children;
|
|
|
|
|
|
|
|
ItemList::iterator end = parents.end();
|
|
|
|
for ( ItemList::iterator it = parents.begin(); it != end; ++it )
|
|
|
|
children += (*it)->children();
|
|
|
|
|
|
|
|
end = children.end();
|
|
|
|
for ( ItemList::iterator it = children.begin(); it != end; ++it )
|
|
|
|
{
|
|
|
|
if ( children.contains(*it) > 1 )
|
|
|
|
*it = 0l;
|
|
|
|
}
|
|
|
|
children.remove((Item*)0l);
|
|
|
|
|
|
|
|
items += children;
|
|
|
|
parents = children;
|
|
|
|
}
|
|
|
|
while ( oldSize != items.size() );
|
|
|
|
|
|
|
|
return items;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool ItemGroup::itemsHaveSameDataValue( const TQString &id ) const
|
|
|
|
{
|
|
|
|
if ( m_itemList.size() < 1 ) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!itemsAreSameType()) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
ItemList::const_iterator it = m_itemList.begin();
|
|
|
|
const ItemList::const_iterator end = m_itemList.end();
|
|
|
|
TQVariant firstData = (*it)->property(id)->value();
|
|
|
|
for ( ++it; it != end; ++it )
|
|
|
|
{
|
|
|
|
if ( (*it) && (*it)->property(id) && (*it)->property(id)->value() != firstData ) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool ItemGroup::itemsHaveSameData() const
|
|
|
|
{
|
|
|
|
if ( m_itemList.size() < 1 ) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!itemsAreSameType()) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
VariantDataMap *variantMap = m_itemList.first()->variantMap();
|
|
|
|
const VariantDataMap::const_iterator vitEnd = variantMap->end();
|
|
|
|
for ( VariantDataMap::const_iterator vit = variantMap->begin(); vit != vitEnd; ++vit )
|
|
|
|
{
|
|
|
|
if ( !itemsHaveSameDataValue(vit.key()) ) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool ItemGroup::itemsHaveDefaultData() const
|
|
|
|
{
|
|
|
|
if (!itemsHaveSameData()) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( m_itemList.size() < 1 ) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
VariantDataMap *variantMap = (*m_itemList.begin())->variantMap();
|
|
|
|
const VariantDataMap::const_iterator vitEnd = variantMap->end();
|
|
|
|
for ( VariantDataMap::const_iterator vit = variantMap->begin(); vit != vitEnd; ++vit )
|
|
|
|
{
|
|
|
|
if ( !vit.data()->isHidden() && vit.data()->value() != vit.data()->defaultValue() )
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void ItemGroup::registerItem( Item *item )
|
|
|
|
{
|
|
|
|
if ( !item || m_itemList.contains(item) ) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
m_itemList += item;
|
|
|
|
updateAreSameStatus();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void ItemGroup::unregisterItem( Item *item )
|
|
|
|
{
|
|
|
|
if ( m_itemList.remove(item) > 0 ) {
|
|
|
|
updateAreSameStatus();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void ItemGroup::updateAreSameStatus()
|
|
|
|
{
|
|
|
|
b_itemsAreSameType = true;
|
|
|
|
|
|
|
|
if ( m_itemList.size() < 2 ) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
TQString activeId = (*m_itemList.begin())->id();
|
|
|
|
int discardIndex = activeId.findRev("__");
|
|
|
|
if ( discardIndex != -1 ) activeId.truncate(discardIndex);
|
|
|
|
|
|
|
|
const ItemList::iterator end = m_itemList.end();
|
|
|
|
for ( ItemList::iterator it = ++m_itemList.begin(); it != end && b_itemsAreSameType; ++it )
|
|
|
|
{
|
|
|
|
if (*it)
|
|
|
|
{
|
|
|
|
TQString id = (*it)->id();
|
|
|
|
discardIndex = id.findRev("__");
|
|
|
|
if ( discardIndex != -1 ) id.truncate(discardIndex);
|
|
|
|
if ( id != activeId )
|
|
|
|
{
|
|
|
|
b_itemsAreSameType = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void ItemGroup::slotAlignHorizontally()
|
|
|
|
{
|
|
|
|
if ( m_itemList.size() < 2 )
|
|
|
|
return;
|
|
|
|
|
|
|
|
double avg_y = 0.;
|
|
|
|
|
|
|
|
const ItemList::iterator end = m_itemList.end();
|
|
|
|
for ( ItemList::iterator it = m_itemList.begin(); it != end; ++it )
|
|
|
|
avg_y += (*it)->y();
|
|
|
|
|
|
|
|
int new_y = int(avg_y/(8*m_itemList.size()))*8+4;
|
|
|
|
|
|
|
|
for ( ItemList::iterator it = m_itemList.begin(); it != end; ++it )
|
|
|
|
(*it)->move( (*it)->x(), new_y );
|
|
|
|
|
|
|
|
p_icnDocument->requestStateSave();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void ItemGroup::slotAlignVertically()
|
|
|
|
{
|
|
|
|
if ( m_itemList.size() < 2 )
|
|
|
|
return;
|
|
|
|
|
|
|
|
double avg_x = 0.;
|
|
|
|
|
|
|
|
const ItemList::iterator end = m_itemList.end();
|
|
|
|
for ( ItemList::iterator it = m_itemList.begin(); it != end; ++it )
|
|
|
|
avg_x += (*it)->x();
|
|
|
|
|
|
|
|
int new_x = int(avg_x/(8*m_itemList.size()))*8+4;
|
|
|
|
|
|
|
|
for ( ItemList::iterator it = m_itemList.begin(); it != end; ++it )
|
|
|
|
(*it)->move( new_x, (*it)->y() );
|
|
|
|
|
|
|
|
p_icnDocument->requestStateSave();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void ItemGroup::slotDistributeHorizontally()
|
|
|
|
{
|
|
|
|
if ( m_itemList.size() < 2 )
|
|
|
|
return;
|
|
|
|
|
|
|
|
// We sort the items by their horizontal position so that we can calculate
|
|
|
|
// an average spacing
|
|
|
|
typedef std::multimap< double, Item * > DIMap;
|
|
|
|
|
|
|
|
DIMap ranked;
|
|
|
|
const ItemList::iterator ilend = m_itemList.end();
|
|
|
|
for ( ItemList::iterator it = m_itemList.begin(); it != ilend; ++it )
|
|
|
|
ranked.insert( std::make_pair( (*it)->x(), *it ) );
|
|
|
|
|
|
|
|
double avg_spacing = 0;
|
|
|
|
|
|
|
|
Item * previous = 0l;
|
|
|
|
const DIMap::iterator rankedEnd = ranked.end();
|
|
|
|
for ( DIMap::iterator it = ranked.begin(); it != rankedEnd; ++it )
|
|
|
|
{
|
|
|
|
Item * item = it->second;
|
|
|
|
if (previous)
|
|
|
|
{
|
|
|
|
double spacing = item->x() + item->offsetX() - (previous->x() + previous->width() + previous->offsetX());
|
|
|
|
avg_spacing += spacing;
|
|
|
|
}
|
|
|
|
previous = item;
|
|
|
|
}
|
|
|
|
|
|
|
|
avg_spacing /= (m_itemList.size()-1);
|
|
|
|
|
|
|
|
DIMap::iterator it = ranked.begin();
|
|
|
|
// Position that we are up to
|
|
|
|
double at = it->second->x() + it->second->width() + it->second->offsetX();
|
|
|
|
for ( ++it; it != rankedEnd; ++it )
|
|
|
|
{
|
|
|
|
Item * item = it->second;
|
|
|
|
double new_x = at - item->offsetX() + avg_spacing;
|
|
|
|
item->move( int(new_x/8)*8+4, item->y() );
|
|
|
|
at = new_x + item->width() + item->offsetX();
|
|
|
|
}
|
|
|
|
|
|
|
|
p_icnDocument->requestStateSave();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void ItemGroup::slotDistributeVertically()
|
|
|
|
{
|
|
|
|
if ( m_itemList.size() < 2 )
|
|
|
|
return;
|
|
|
|
|
|
|
|
// We sort the items by their horizontal position so that we can calculate
|
|
|
|
// an average spacing
|
|
|
|
typedef std::multimap< double, Item * > DIMap;
|
|
|
|
|
|
|
|
DIMap ranked;
|
|
|
|
const ItemList::iterator ilend = m_itemList.end();
|
|
|
|
for ( ItemList::iterator it = m_itemList.begin(); it != ilend; ++it )
|
|
|
|
ranked.insert( std::make_pair( (*it)->y(), *it ) );
|
|
|
|
|
|
|
|
double avg_spacing = 0;
|
|
|
|
|
|
|
|
Item * previous = 0l;
|
|
|
|
const DIMap::iterator rankedEnd = ranked.end();
|
|
|
|
for ( DIMap::iterator it = ranked.begin(); it != rankedEnd; ++it )
|
|
|
|
{
|
|
|
|
Item * item = it->second;
|
|
|
|
if (previous)
|
|
|
|
{
|
|
|
|
double spacing = item->y() + item->offsetY() - (previous->y() + previous->height() + previous->offsetY());
|
|
|
|
avg_spacing += spacing;
|
|
|
|
}
|
|
|
|
previous = item;
|
|
|
|
}
|
|
|
|
|
|
|
|
avg_spacing /= (m_itemList.size()-1);
|
|
|
|
|
|
|
|
DIMap::iterator it = ranked.begin();
|
|
|
|
// Position that we are up to
|
|
|
|
double at = it->second->y() + it->second->height() + it->second->offsetY();
|
|
|
|
for ( ++it; it != rankedEnd; ++it )
|
|
|
|
{
|
|
|
|
Item * item = it->second;
|
|
|
|
double new_y = at - item->offsetY() + avg_spacing;
|
|
|
|
item->move( item->x(), int(new_y/8)*8+4 );
|
|
|
|
at = new_y + item->height() + item->offsetY();
|
|
|
|
}
|
|
|
|
|
|
|
|
p_icnDocument->requestStateSave();
|
|
|
|
}
|
|
|
|
|
|
|
|
#include "itemgroup.moc"
|