File indexing completed on 2024-06-09 05:39:53

0001 /***************************************************************************
0002  *   Copyright (C) 2004-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 "iteminterface.h"
0012 #include "circuitview.h"
0013 #include "cnitem.h"
0014 #include "cnitemgroup.h"
0015 #include "colorutils.h"
0016 #include "contexthelp.h"
0017 #include "doublespinbox.h"
0018 #include "itemdocument.h"
0019 #include "itemeditor.h"
0020 #include "itemview.h"
0021 #include "ktechlab.h"
0022 
0023 #include <KColorCombo>
0024 #include <KComboBox>
0025 #include <KLineEdit>
0026 #include <KToolBar>
0027 #include <KUrlRequester>
0028 #include <KXMLGUIFactory>
0029 #include <kio_version.h>
0030 
0031 #include <QApplication>
0032 #include <QCheckBox>
0033 #include <QLabel>
0034 #include <QSpinBox>
0035 
0036 #include <cassert>
0037 
0038 #include <ktechlab_debug.h>
0039 
0040 ItemInterface *ItemInterface::m_pSelf = nullptr;
0041 
0042 ItemInterface *ItemInterface::self()
0043 {
0044     if (!m_pSelf)
0045         m_pSelf = new ItemInterface();
0046 
0047     return m_pSelf;
0048 }
0049 
0050 ItemInterface::ItemInterface()
0051     : QObject(KTechlab::self())
0052     , m_isInTbDataChanged(false)
0053 {
0054     m_pActiveItemEditorToolBar = nullptr;
0055     p_cvb = nullptr;
0056     p_itemGroup = nullptr;
0057     p_lastItem = nullptr;
0058     m_currentActionTicket = -1;
0059     m_toolBarWidgetID = -1;
0060 }
0061 
0062 ItemInterface::~ItemInterface()
0063 {
0064 }
0065 
0066 void ItemInterface::slotGetActionTicket()
0067 {
0068     m_currentActionTicket = p_cvb ? p_cvb->getActionTicket() : -1;
0069 }
0070 
0071 void ItemInterface::slotItemDocumentChanged(ItemDocument *doc)
0072 {
0073     slotClearAll();
0074     if (ItemDocument *itemDocument = dynamic_cast<ItemDocument *>(static_cast<Document *>(p_cvb))) {
0075         disconnect(itemDocument, &ItemDocument::selectionChanged, this, &ItemInterface::slotUpdateItemInterface);
0076     }
0077 
0078     p_itemGroup = nullptr;
0079     p_cvb = doc;
0080 
0081     slotGetActionTicket();
0082 
0083     if (!p_cvb)
0084         return;
0085 
0086     connect(p_cvb, &ItemDocument::selectionChanged, this, &ItemInterface::slotUpdateItemInterface);
0087 
0088     p_itemGroup = p_cvb->selectList();
0089 
0090     slotUpdateItemInterface();
0091 }
0092 
0093 void ItemInterface::clearItemEditorToolBar()
0094 {
0095     if (m_pActiveItemEditorToolBar && m_toolBarWidgetID != -1) {
0096         // m_pActiveItemEditorToolBar->removeItem(m_toolBarWidgetID); // TODO add proper replacmenet
0097         m_pActiveItemEditorToolBar->clear();
0098     }
0099     m_toolBarWidgetID = -1;
0100     itemEditTBCleared();
0101 }
0102 
0103 void ItemInterface::slotClearAll()
0104 {
0105     ContextHelp::self()->slotClear();
0106     ItemEditor::self()->slotClear();
0107     clearItemEditorToolBar();
0108     p_lastItem = nullptr;
0109 }
0110 
0111 void ItemInterface::slotMultipleSelected()
0112 {
0113     ContextHelp::self()->slotMultipleSelected();
0114     ItemEditor::self()->slotMultipleSelected();
0115     clearItemEditorToolBar();
0116     p_lastItem = nullptr;
0117 }
0118 
0119 void ItemInterface::slotUpdateItemInterface()
0120 {
0121     if (!p_itemGroup)
0122         return;
0123 
0124     slotGetActionTicket();
0125     updateItemActions();
0126 
0127     if (!p_itemGroup->itemsAreSameType()) {
0128         slotMultipleSelected();
0129         return;
0130     }
0131     if (p_lastItem && p_itemGroup->activeItem()) {
0132         ItemEditor::self()->itemGroupUpdated(p_itemGroup);
0133         return;
0134     }
0135 
0136     p_lastItem = p_itemGroup->activeItem();
0137     if (!p_lastItem) {
0138         slotClearAll();
0139         return;
0140     }
0141 
0142     ContextHelp::self()->slotUpdate(p_lastItem);
0143     ItemEditor::self()->slotUpdate(p_itemGroup);
0144     if (CNItem *cnItem = dynamic_cast<CNItem *>(static_cast<Item *>(p_lastItem))) {
0145         ItemEditor::self()->slotUpdate(cnItem);
0146     }
0147 
0148     // Update item editor toolbar
0149     if (ItemView *itemView = dynamic_cast<ItemView *>(p_cvb->activeView())) {
0150         if (KTechlab *ktl = KTechlab::self()) {
0151             if ((m_pActiveItemEditorToolBar = dynamic_cast<KToolBar *>(ktl->factory()->container("itemEditorTB", itemView)))) {
0152                 // m_pActiveItemEditorToolBar->setFullSize( true ); // TODO proper replacement
0153                 m_pActiveItemEditorToolBar->adjustSize();
0154                 QWidget *widget = configWidget();
0155                 m_toolBarWidgetID = 1;
0156                 // m_pActiveItemEditorToolBar->insertWidget( m_toolBarWidgetID, 0, widget ); // TODO properly fix
0157                 m_pActiveItemEditorToolBar->addWidget(widget);
0158             }
0159         }
0160     }
0161 }
0162 
0163 void ItemInterface::updateItemActions()
0164 {
0165     ItemView *itemView = (static_cast<ItemDocument *>(p_cvb)) ? dynamic_cast<ItemView *>(p_cvb->activeView()) : nullptr;
0166     if (!itemView)
0167         return;
0168 
0169     bool itemsSelected = p_itemGroup && p_itemGroup->itemCount();
0170 
0171     itemView->actionByName("edit_raise")->setEnabled(itemsSelected);
0172     itemView->actionByName("edit_lower")->setEnabled(itemsSelected);
0173 
0174     if (KTechlab::self()) {
0175         KTechlab::self()->actionByName("edit_cut")->setEnabled(itemsSelected);
0176         KTechlab::self()->actionByName("edit_copy")->setEnabled(itemsSelected);
0177     }
0178 
0179     CNItemGroup *cnItemGroup = dynamic_cast<CNItemGroup *>(static_cast<ItemGroup *>(p_itemGroup));
0180     CircuitView *circuitView = dynamic_cast<CircuitView *>(itemView);
0181 
0182     if (cnItemGroup && circuitView) {
0183         bool canFlip = cnItemGroup->canFlip();
0184         circuitView->actionByName("edit_flip_horizontally")->setEnabled(canFlip);
0185         circuitView->actionByName("edit_flip_vertically")->setEnabled(canFlip);
0186 
0187         bool canRotate = cnItemGroup->canRotate();
0188         circuitView->actionByName("edit_rotate_ccw")->setEnabled(canRotate);
0189         circuitView->actionByName("edit_rotate_cw")->setEnabled(canRotate);
0190     }
0191 }
0192 
0193 void ItemInterface::setFlowPartOrientation(unsigned orientation)
0194 {
0195     CNItemGroup *cnItemGroup = dynamic_cast<CNItemGroup *>(static_cast<ItemGroup *>(p_itemGroup));
0196     if (!cnItemGroup)
0197         return;
0198 
0199     cnItemGroup->setFlowPartOrientation(orientation);
0200 }
0201 
0202 void ItemInterface::setComponentOrientation(int angleDegrees, bool flipped)
0203 {
0204     CNItemGroup *cnItemGroup = dynamic_cast<CNItemGroup *>(static_cast<ItemGroup *>(p_itemGroup));
0205     if (!cnItemGroup)
0206         return;
0207 
0208     cnItemGroup->setComponentOrientation(angleDegrees, flipped);
0209 }
0210 
0211 void ItemInterface::itemEditTBCleared()
0212 {
0213     m_stringLineEditMap.clear();
0214     m_stringComboBoxMap.clear();
0215     m_stringURLReqMap.clear();
0216     m_intSpinBoxMap.clear();
0217     m_doubleSpinBoxMap.clear();
0218     m_colorComboMap.clear();
0219     m_boolCheckMap.clear();
0220 }
0221 
0222 // The bool specifies whether advanced data should be shown
0223 QWidget *ItemInterface::configWidget()
0224 {
0225     if (!p_itemGroup || !p_itemGroup->activeItem() || !m_pActiveItemEditorToolBar)
0226         return nullptr;
0227 
0228     VariantDataMap *variantMap = p_itemGroup->activeItem()->variantMap();
0229 
0230     QWidget *parent = m_pActiveItemEditorToolBar;
0231 
0232     // Create new widget with the toolbar or dialog as the parent
0233     QWidget *configWidget = new QWidget(parent /*, "tbConfigWidget" */);
0234     configWidget->setObjectName("tbConfigWidget");
0235     {
0236         // 2018.12.02
0237         // configWidget->setSizePolicy( QSizePolicy( QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding, 1, 1 ) );
0238         QSizePolicy p(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding);
0239         p.setHorizontalStretch(1);
0240         p.setVerticalStretch(1);
0241         configWidget->setSizePolicy(p);
0242     }
0243 
0244     QHBoxLayout *configLayout = new QHBoxLayout(configWidget);
0245     //  configLayout->setAutoAdd( true );
0246     configLayout->setSpacing(6);
0247     configLayout->setMargin(0);
0248 
0249     //  configLayout->addItem( new QSpacerItem( 0, 0,  QSizePolicy::Expanding, QSizePolicy::Fixed ) );
0250 
0251     const VariantDataMap::iterator vaEnd = variantMap->end();
0252     for (VariantDataMap::iterator vait = variantMap->begin(); vait != vaEnd; ++vait) {
0253         if (vait.value()->isHidden() || vait.value()->isAdvanced())
0254             continue;
0255 
0256         const Variant::Type::Value type = vait.value()->type();
0257 
0258         // common to all types apart from bool
0259         QString toolbarCaption = vait.value()->toolbarCaption();
0260         if (type != Variant::Type::Bool && !toolbarCaption.isEmpty())
0261             configLayout->addWidget(new QLabel(toolbarCaption, configWidget));
0262 
0263         QWidget *editWidget = nullptr; // Should be set to the created widget
0264 
0265         switch (type) {
0266         case Variant::Type::Port:
0267         case Variant::Type::Pin:
0268         case Variant::Type::VarName:
0269         case Variant::Type::Combo:
0270         case Variant::Type::Select:
0271         case Variant::Type::KeyPad:
0272         case Variant::Type::SevenSegment: {
0273             QString value = vait.value()->displayString();
0274             if (!value.isEmpty() && !vait.value()->allowed().contains(value))
0275                 vait.value()->appendAllowed(value);
0276 
0277             const QStringList allowed = vait.value()->allowed();
0278 
0279             KComboBox *box = new KComboBox(configWidget);
0280 
0281             box->insertItems(box->count(), allowed);
0282             box->setCurrentItem(value);
0283 
0284             if (type == Variant::Type::VarName || type == Variant::Type::Combo)
0285                 box->setEditable(true);
0286 
0287             m_stringComboBoxMap[vait.key()] = box;
0288             connectMapWidget(box, SIGNAL(editTextChanged(const QString &)));
0289             connectMapWidget(box, SIGNAL(activated(const QString &)));
0290 
0291             connect(*vait, SIGNAL(valueChangedStrAndTrue(const QString &, bool)), box, SLOT(setCurrentItem(const QString &, bool)));
0292 
0293             editWidget = box;
0294             break;
0295         }
0296         case Variant::Type::FileName: {
0297             qCDebug(KTL_LOG) << "create FileName";
0298             QString value = vait.value()->value().toString();
0299             if (!vait.value()->allowed().contains(value))
0300                 vait.value()->appendAllowed(value);
0301 
0302             const QStringList allowed = vait.value()->allowed();
0303 
0304             KUrlComboRequester *urlreq = new KUrlComboRequester(configWidget);
0305 #if KIO_VERSION >= QT_VERSION_CHECK(5, 108, 0)
0306             urlreq->setNameFilters(vait.value()->fileFilters().toQtStyleStringList());
0307 #else
0308             urlreq->setFilter(vait.value()->fileFilters().toKDEStyleString());
0309 #endif
0310             connectMapWidget(urlreq, SIGNAL(urlSelected(QUrl)));
0311             m_stringURLReqMap[vait.key()] = urlreq;
0312 
0313             KComboBox *box = urlreq->comboBox();
0314             box->insertItems(box->count(), allowed);
0315             box->setEditable(true);
0316 
0317             // Note this has to be called after inserting the allowed list
0318             urlreq->setUrl(QUrl::fromLocalFile(vait.value()->value().toString()));
0319 
0320             // Generally we only want a file name once the user has finished typing out the full file name.
0321             connectMapWidget(box, SIGNAL(returnPressed(const QString &)));
0322             connectMapWidget(box, SIGNAL(activated(const QString &)));
0323 
0324             connect(*vait, SIGNAL(valueChanged(const QString &)), box, SLOT(setEditText(const QString &)));
0325 
0326             editWidget = urlreq;
0327             break;
0328         }
0329         case Variant::Type::String: {
0330             KLineEdit *edit = new KLineEdit(configWidget);
0331 
0332             edit->setText(vait.value()->value().toString());
0333             connectMapWidget(edit, SIGNAL(textChanged(const QString &)));
0334             m_stringLineEditMap[vait.key()] = edit;
0335             editWidget = edit;
0336 
0337             connect(*vait, SIGNAL(valueChanged(const QString &)), edit, SLOT(setText(const QString &)));
0338 
0339             break;
0340         }
0341         case Variant::Type::Int: {
0342             QSpinBox *spin = new QSpinBox(configWidget);
0343             spin->setMinimum(int(vait.value()->minValue()));
0344             spin->setMaximum(int(vait.value()->maxValue()));
0345             spin->setValue(vait.value()->value().toInt());
0346 
0347             connectMapWidget(spin, SIGNAL(valueChanged(int)));
0348             m_intSpinBoxMap[vait.key()] = spin;
0349             editWidget = spin;
0350 
0351             connect(*vait, SIGNAL(valueChanged(int)), spin, SLOT(setValue(int)));
0352 
0353             break;
0354         }
0355         case Variant::Type::Double: {
0356             DoubleSpinBox *spin = new DoubleSpinBox(vait.value()->minValue(), vait.value()->maxValue(), vait.value()->minAbsValue(), vait.value()->value().toDouble(), vait.value()->unit(), configWidget);
0357 
0358             connectMapWidget(spin, SIGNAL(valueChanged(double)));
0359             m_doubleSpinBoxMap[vait.key()] = spin;
0360             editWidget = spin;
0361 
0362             connect(*vait, SIGNAL(valueChanged(double)), spin, SLOT(setValue(double)));
0363 
0364             break;
0365         }
0366         case Variant::Type::Color: {
0367             QColor value = vait.value()->value().value<QColor>();
0368 
0369             KColorCombo *colorBox = ColorUtils::createColorCombo(static_cast<ColorUtils::ColorScheme>(vait.value()->colorScheme()), configWidget);
0370 
0371             colorBox->setColor(value);
0372             connectMapWidget(colorBox, SIGNAL(activated(const QColor &)));
0373             m_colorComboMap[vait.key()] = colorBox;
0374 
0375             connect(*vait, SIGNAL(valueChanged(const QColor &)), colorBox, SLOT(setColor(const QColor &)));
0376 
0377             editWidget = colorBox;
0378             break;
0379         }
0380         case Variant::Type::Bool: {
0381             const bool value = vait.value()->value().toBool();
0382             QCheckBox *box = new QCheckBox(vait.value()->toolbarCaption(), configWidget);
0383 
0384             box->setChecked(value);
0385             connectMapWidget(box, SIGNAL(toggled(bool)));
0386             m_boolCheckMap[vait.key()] = box;
0387 
0388             connect(*vait, SIGNAL(valueChanged(bool)), box, SLOT(setChecked(bool)));
0389 
0390             editWidget = box;
0391             break;
0392         }
0393         case Variant::Type::Raw:
0394         case Variant::Type::PenStyle:
0395         case Variant::Type::PenCapStyle:
0396         case Variant::Type::Multiline:
0397         case Variant::Type::RichText:
0398         case Variant::Type::None: {
0399             // Do nothing, as these data types are not handled in the toolbar
0400             break;
0401         }
0402         }
0403 
0404         if (!editWidget)
0405             continue;
0406 
0407         const int widgetH = QFontMetrics(configWidget->font()).height() + 2;
0408         editWidget->setMinimumHeight(widgetH); // note: this is hack-ish; something is not ok with the layout
0409         editWidget->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
0410 
0411         // In the case of the toolbar, we don't want it too high
0412         if (editWidget->height() > parent->height() - 2)
0413             editWidget->setMaximumHeight(parent->height() - 2);
0414 
0415         switch (type) {
0416         case Variant::Type::VarName:
0417         case Variant::Type::Combo:
0418         case Variant::Type::String: {
0419             QSizePolicy p(QSizePolicy::MinimumExpanding, QSizePolicy::Fixed /*, 1, 1 */);
0420             p.setHorizontalStretch(1);
0421             p.setVerticalStretch(1);
0422 
0423             editWidget->setSizePolicy(p);
0424             editWidget->setMaximumWidth(250);
0425             break;
0426         }
0427 
0428         case Variant::Type::FileName:
0429         case Variant::Type::Port:
0430         case Variant::Type::Pin:
0431         case Variant::Type::Select:
0432         case Variant::Type::KeyPad:
0433         case Variant::Type::SevenSegment:
0434         case Variant::Type::Int:
0435         case Variant::Type::Double:
0436         case Variant::Type::Color:
0437         case Variant::Type::Bool:
0438         case Variant::Type::Raw:
0439         case Variant::Type::PenStyle:
0440         case Variant::Type::PenCapStyle:
0441         case Variant::Type::Multiline:
0442         case Variant::Type::RichText:
0443         case Variant::Type::None:
0444             break;
0445         }
0446 
0447         configLayout->addWidget(editWidget);
0448     }
0449 
0450     configLayout->addItem(new QSpacerItem(0, 0, QSizePolicy::Expanding, QSizePolicy::Fixed));
0451 
0452     return configWidget;
0453 }
0454 
0455 void ItemInterface::connectMapWidget(QWidget *widget, const char *_signal)
0456 {
0457     connect(widget, _signal, this, SLOT(tbDataChanged()));
0458 }
0459 
0460 // TODO move to separate file
0461 struct BoolLock {
0462     bool *m_flagPtr;
0463     BoolLock(bool *flagPtr)
0464         : m_flagPtr(flagPtr)
0465     {
0466         if (m_flagPtr == nullptr) {
0467             qCCritical(KTL_LOG) << "nullptr flagPtr";
0468             return;
0469         }
0470         if (*m_flagPtr == true) {
0471             qCWarning(KTL_LOG) << "flag expected to be false, addr=" << m_flagPtr << " Doing nothing";
0472             m_flagPtr = nullptr;
0473         } else {
0474             *m_flagPtr = true;
0475         }
0476     }
0477     ~BoolLock()
0478     {
0479         if (m_flagPtr != nullptr) {
0480             *m_flagPtr = false;
0481         }
0482     }
0483 };
0484 
0485 void ItemInterface::tbDataChanged()
0486 {
0487     qCDebug(KTL_LOG) << "begin";
0488     if (m_isInTbDataChanged) {
0489         qCDebug(KTL_LOG) << "avoiding recursion, returning";
0490         return;
0491     }
0492     BoolLock inTbChangedLock(&m_isInTbDataChanged);
0493     // Manual string values
0494     const KLineEditMap::iterator m_stringLineEditMapEnd = m_stringLineEditMap.end();
0495     for (KLineEditMap::iterator leit = m_stringLineEditMap.begin(); leit != m_stringLineEditMapEnd; ++leit) {
0496         slotSetData(leit.key(), leit.value()->text());
0497     }
0498 
0499     // String values from comboboxes
0500     const KComboBoxMap::iterator m_stringComboBoxMapEnd = m_stringComboBoxMap.end();
0501     for (KComboBoxMap::iterator cmit = m_stringComboBoxMap.begin(); cmit != m_stringComboBoxMapEnd; ++cmit) {
0502         qCDebug(KTL_LOG) << "set KCombo data for " << cmit.key() << " to " << cmit.value()->currentText();
0503         slotSetData(cmit.key(), cmit.value()->currentText());
0504     }
0505 
0506     // Colors values from colorcombos
0507     const KColorComboMap::iterator m_colorComboMapEnd = m_colorComboMap.end();
0508     for (KColorComboMap::iterator ccit = m_colorComboMap.begin(); ccit != m_colorComboMapEnd; ++ccit) {
0509         slotSetData(ccit.key(), ccit.value()->color());
0510     }
0511 
0512     // Bool values from checkboxes
0513     const QCheckBoxMap::iterator m_boolCheckMapEnd = m_boolCheckMap.end();
0514     for (QCheckBoxMap::iterator chit = m_boolCheckMap.begin(); chit != m_boolCheckMapEnd; ++chit) {
0515         slotSetData(chit.key(), chit.value()->isChecked());
0516     }
0517 
0518     const IntSpinBoxMap::iterator m_intSpinBoxMapEnd = m_intSpinBoxMap.end();
0519     for (IntSpinBoxMap::iterator it = m_intSpinBoxMap.begin(); it != m_intSpinBoxMapEnd; ++it) {
0520         slotSetData(it.key(), it.value()->value());
0521     }
0522 
0523     // (?) Combined values from spin boxes and combo boxes
0524     // (?) Get values from all spin boxes
0525 
0526     const DoubleSpinBoxMap::iterator m_doubleSpinBoxMapEnd = m_doubleSpinBoxMap.end();
0527     for (DoubleSpinBoxMap::iterator sbit = m_doubleSpinBoxMap.begin(); sbit != m_doubleSpinBoxMapEnd; ++sbit) {
0528         //      VariantDataMap::iterator vait = variantData.find(sbit.key());
0529         slotSetData(sbit.key(), sbit.value()->value());
0530     }
0531 
0532     // Filenames from KUrlRequesters
0533     const KUrlReqMap::iterator m_stringURLReqMapEnd = m_stringURLReqMap.end();
0534     for (KUrlReqMap::iterator urlit = m_stringURLReqMap.begin(); urlit != m_stringURLReqMapEnd; ++urlit) {
0535         qCDebug(KTL_LOG) << "set kurlrequester data for " << urlit.key() << " to " << urlit.value()->url();
0536         QVariant urlVar(urlit.value()->url().path());
0537         qCDebug(KTL_LOG) << "urlVar=" << urlVar << " urlVar.toUrl=" << urlVar.toUrl();
0538         slotSetData(urlit.key(), urlVar);
0539     }
0540 
0541     if (p_cvb)
0542         p_cvb->setModified(true);
0543 }
0544 
0545 void ItemInterface::setProperty(Variant *v)
0546 {
0547     slotSetData(v->id(), v->value());
0548 }
0549 
0550 void ItemInterface::slotSetData(const QString &id, QVariant value)
0551 {
0552     if (!p_itemGroup || (p_itemGroup->itemCount() == 0)) {
0553         qCDebug(KTL_LOG) << "p_itemGroup not valid:" << p_itemGroup;
0554         return;
0555     }
0556 
0557     if (!p_itemGroup->itemsAreSameType()) {
0558         qCDebug(KTL_LOG) << "Items are not the same type!";
0559         return;
0560     }
0561     qCDebug(KTL_LOG) << "id=" << id << " value=" << value;
0562 
0563     const ItemList itemList = p_itemGroup->items(true);
0564     const ItemList::const_iterator end = itemList.end();
0565     for (ItemList::const_iterator it = itemList.begin(); it != end; ++it) {
0566         if (*it)
0567             (*it)->property(id)->setValue(value);
0568     }
0569 
0570     if (p_cvb)
0571         p_cvb->setModified(true);
0572 
0573     ItemEditor::self()->itemGroupUpdated(p_itemGroup);
0574 
0575     if (p_cvb)
0576         p_cvb->requestStateSave(m_currentActionTicket);
0577 }
0578 
0579 #include "moc_iteminterface.cpp"