File indexing completed on 2024-12-08 05:08:39
0001 /*************************************************************************** 0002 * Copyright (C) 2005 by David Saxton * 0003 * david@bluehaze.org * 0004 * * 0005 * This program is free software; you can redistribute it and/or modify * 0006 * it under the terms of the GNU General Public License as published by * 0007 * the Free Software Foundation; either version 2 of the License, or * 0008 * (at your option) any later version. * 0009 ***************************************************************************/ 0010 0011 #include "itemgroup.h" 0012 #include "icndocument.h" 0013 #include "item.h" 0014 #include "mechanicsdocument.h" 0015 #include "utils.h" 0016 0017 #include <QTimer> 0018 #include <map> 0019 0020 ItemGroup::ItemGroup(ItemDocument *view) 0021 : QObject(view) 0022 { 0023 m_activeItem = nullptr; 0024 b_itemsAreSameType = true; 0025 p_view = view; 0026 p_icnDocument = dynamic_cast<ICNDocument *>(p_view); 0027 p_mechanicsDocument = dynamic_cast<MechanicsDocument *>(p_view); 0028 QTimer::singleShot(0, this, SLOT(getViewPtrs())); 0029 } 0030 0031 ItemGroup::~ItemGroup() 0032 { 0033 } 0034 0035 void ItemGroup::getViewPtrs() 0036 { 0037 p_icnDocument = dynamic_cast<ICNDocument *>(p_view); 0038 p_mechanicsDocument = dynamic_cast<MechanicsDocument *>(p_view); 0039 } 0040 0041 ItemList ItemGroup::items(bool excludeParentedItems) const 0042 { 0043 if (excludeParentedItems) 0044 return m_itemList; 0045 0046 ItemList items = m_itemList; 0047 ItemList parents = m_itemList; 0048 0049 int oldSize = items.size(); 0050 do { 0051 oldSize = items.size(); 0052 ItemList children; 0053 0054 ItemList::iterator end = parents.end(); 0055 for (ItemList::iterator it = parents.begin(); it != end; ++it) 0056 children += (*it)->children(); 0057 0058 end = children.end(); 0059 for (ItemList::iterator it = children.begin(); it != end; ++it) { 0060 if (children.count(*it) > 1) 0061 *it = nullptr; 0062 } 0063 children.removeAll(static_cast<Item *>(nullptr)); 0064 0065 items += children; 0066 parents = children; 0067 } while (oldSize != items.size()); 0068 0069 return items; 0070 } 0071 0072 bool ItemGroup::itemsHaveSameDataValue(const QString &id) const 0073 { 0074 if (m_itemList.size() < 1) { 0075 return true; 0076 } 0077 0078 if (!itemsAreSameType()) { 0079 return false; 0080 } 0081 0082 ItemList::const_iterator it = m_itemList.begin(); 0083 const ItemList::const_iterator end = m_itemList.end(); 0084 QVariant firstData = (*it)->property(id)->value(); 0085 for (++it; it != end; ++it) { 0086 if ((*it) && (*it)->property(id) && (*it)->property(id)->value() != firstData) { 0087 return false; 0088 } 0089 } 0090 return true; 0091 } 0092 0093 bool ItemGroup::itemsHaveSameData() const 0094 { 0095 if (m_itemList.size() < 1) { 0096 return true; 0097 } 0098 0099 if (!itemsAreSameType()) { 0100 return false; 0101 } 0102 0103 VariantDataMap *variantMap = m_itemList.first()->variantMap(); 0104 const VariantDataMap::const_iterator vitEnd = variantMap->end(); 0105 for (VariantDataMap::const_iterator vit = variantMap->begin(); vit != vitEnd; ++vit) { 0106 if (!itemsHaveSameDataValue(vit.key())) { 0107 return false; 0108 } 0109 } 0110 return true; 0111 } 0112 0113 bool ItemGroup::itemsHaveDefaultData() const 0114 { 0115 if (!itemsHaveSameData()) { 0116 return false; 0117 } 0118 0119 if (m_itemList.size() < 1) { 0120 return true; 0121 } 0122 0123 VariantDataMap *variantMap = (*m_itemList.begin())->variantMap(); 0124 const VariantDataMap::const_iterator vitEnd = variantMap->end(); 0125 for (VariantDataMap::const_iterator vit = variantMap->begin(); vit != vitEnd; ++vit) { 0126 if (!vit.value()->isHidden() && vit.value()->value() != vit.value()->defaultValue()) 0127 return false; 0128 } 0129 return true; 0130 } 0131 0132 void ItemGroup::registerItem(Item *item) 0133 { 0134 if (!item || m_itemList.contains(item)) { 0135 return; 0136 } 0137 0138 m_itemList += item; 0139 updateAreSameStatus(); 0140 } 0141 0142 void ItemGroup::unregisterItem(Item *item) 0143 { 0144 if (m_itemList.removeAll(item) > 0) { 0145 updateAreSameStatus(); 0146 } 0147 } 0148 0149 void ItemGroup::updateAreSameStatus() 0150 { 0151 b_itemsAreSameType = true; 0152 0153 if (m_itemList.size() < 2) { 0154 return; 0155 } 0156 0157 QString activeId = (*m_itemList.begin())->id(); 0158 int discardIndex = activeId.lastIndexOf("__"); 0159 if (discardIndex != -1) 0160 activeId.truncate(discardIndex); 0161 0162 const ItemList::iterator end = m_itemList.end(); 0163 for (ItemList::iterator it = ++m_itemList.begin(); it != end && b_itemsAreSameType; ++it) { 0164 if (*it) { 0165 QString id = (*it)->id(); 0166 discardIndex = id.lastIndexOf("__"); 0167 if (discardIndex != -1) 0168 id.truncate(discardIndex); 0169 if (id != activeId) { 0170 b_itemsAreSameType = false; 0171 } 0172 } 0173 } 0174 } 0175 0176 void ItemGroup::slotAlignHorizontally() 0177 { 0178 if (m_itemList.size() < 2) 0179 return; 0180 0181 double avg_y = 0.; 0182 0183 const ItemList::iterator end = m_itemList.end(); 0184 for (ItemList::iterator it = m_itemList.begin(); it != end; ++it) 0185 avg_y += (*it)->y(); 0186 0187 int new_y = int(avg_y / (8 * m_itemList.size())) * 8 + 4; 0188 0189 for (ItemList::iterator it = m_itemList.begin(); it != end; ++it) 0190 (*it)->move((*it)->x(), new_y); 0191 0192 p_icnDocument->requestStateSave(); 0193 } 0194 0195 void ItemGroup::slotAlignVertically() 0196 { 0197 if (m_itemList.size() < 2) 0198 return; 0199 0200 double avg_x = 0.; 0201 0202 const ItemList::iterator end = m_itemList.end(); 0203 for (ItemList::iterator it = m_itemList.begin(); it != end; ++it) 0204 avg_x += (*it)->x(); 0205 0206 int new_x = int(avg_x / (8 * m_itemList.size())) * 8 + 4; 0207 0208 for (ItemList::iterator it = m_itemList.begin(); it != end; ++it) 0209 (*it)->move(new_x, (*it)->y()); 0210 0211 p_icnDocument->requestStateSave(); 0212 } 0213 0214 void ItemGroup::slotDistributeHorizontally() 0215 { 0216 if (m_itemList.size() < 2) 0217 return; 0218 0219 // We sort the items by their horizontal position so that we can calculate 0220 // an average spacing 0221 typedef std::multimap<double, Item *> DIMap; 0222 0223 DIMap ranked; 0224 const ItemList::iterator ilend = m_itemList.end(); 0225 for (ItemList::iterator it = m_itemList.begin(); it != ilend; ++it) 0226 ranked.insert(std::make_pair((*it)->x(), *it)); 0227 0228 double avg_spacing = 0; 0229 0230 Item *previous = nullptr; 0231 const DIMap::iterator rankedEnd = ranked.end(); 0232 for (DIMap::iterator it = ranked.begin(); it != rankedEnd; ++it) { 0233 Item *item = it->second; 0234 if (previous) { 0235 double spacing = item->x() + item->offsetX() - (previous->x() + previous->width() + previous->offsetX()); 0236 avg_spacing += spacing; 0237 } 0238 previous = item; 0239 } 0240 0241 avg_spacing /= (m_itemList.size() - 1); 0242 0243 DIMap::iterator it = ranked.begin(); 0244 // Position that we are up to 0245 double at = it->second->x() + it->second->width() + it->second->offsetX(); 0246 for (++it; it != rankedEnd; ++it) { 0247 Item *item = it->second; 0248 double new_x = at - item->offsetX() + avg_spacing; 0249 item->move(snapToCanvas(new_x), item->y()); 0250 at = new_x + item->width() + item->offsetX(); 0251 } 0252 0253 p_icnDocument->requestStateSave(); 0254 } 0255 0256 void ItemGroup::slotDistributeVertically() 0257 { 0258 if (m_itemList.size() < 2) 0259 return; 0260 0261 // We sort the items by their horizontal position so that we can calculate 0262 // an average spacing 0263 typedef std::multimap<double, Item *> DIMap; 0264 0265 DIMap ranked; 0266 const ItemList::iterator ilend = m_itemList.end(); 0267 for (ItemList::iterator it = m_itemList.begin(); it != ilend; ++it) 0268 ranked.insert(std::make_pair((*it)->y(), *it)); 0269 0270 double avg_spacing = 0; 0271 0272 Item *previous = nullptr; 0273 const DIMap::iterator rankedEnd = ranked.end(); 0274 for (DIMap::iterator it = ranked.begin(); it != rankedEnd; ++it) { 0275 Item *item = it->second; 0276 if (previous) { 0277 double spacing = item->y() + item->offsetY() - (previous->y() + previous->height() + previous->offsetY()); 0278 avg_spacing += spacing; 0279 } 0280 previous = item; 0281 } 0282 0283 avg_spacing /= (m_itemList.size() - 1); 0284 0285 DIMap::iterator it = ranked.begin(); 0286 // Position that we are up to 0287 double at = it->second->y() + it->second->height() + it->second->offsetY(); 0288 for (++it; it != rankedEnd; ++it) { 0289 Item *item = it->second; 0290 double new_y = at - item->offsetY() + avg_spacing; 0291 item->move(item->x(), snapToCanvas(new_y)); 0292 at = new_y + item->height() + item->offsetY(); 0293 } 0294 0295 p_icnDocument->requestStateSave(); 0296 } 0297 0298 #include "moc_itemgroup.cpp"