File indexing completed on 2024-04-28 07:39:35

0001 /*
0002     SPDX-FileCopyrightText: 2007 Vladimir Kuznetsov <ks.vladimir@gmail.com>
0003 
0004     SPDX-License-Identifier: GPL-2.0-or-later
0005 */
0006 
0007 #include "clipboard.h"
0008 
0009 #include <QApplication>
0010 #include <QBuffer>
0011 #include <QClipboard>
0012 #include <QDebug>
0013 #include <QMimeData>
0014 
0015 #include <stepcore/factory.h>
0016 #include <stepcore/world.h>
0017 #include <stepcore/xmlfile.h>
0018 
0019 namespace
0020 {
0021 class CopyHelper
0022 {
0023 public:
0024     void addItem(const StepCore::Item* item);
0025     StepCore::World* createWorld();
0026     
0027 private:
0028     void fillMap(const StepCore::Object* item, StepCore::Object* copy);
0029     void fixItemLinks(StepCore::Item* item);
0030     
0031     QHash<const StepCore::Object*, StepCore::Object*> _copyMap;
0032     QList<StepCore::Item*> _items;
0033 };
0034 
0035 void CopyHelper::addItem(const StepCore::Item* item)
0036 {
0037     StepCore::Object *copy = item->metaObject()->cloneObject(*item);
0038     
0039     _items << static_cast<StepCore::Item*>(copy);
0040     fillMap(item, copy);
0041 }
0042 
0043 StepCore::World* CopyHelper::createWorld()
0044 {
0045     StepCore::World *world = new StepCore::World;
0046     
0047     foreach (StepCore::Item* item, _items) {
0048         world->addItem(item);
0049     }
0050     
0051     StepCore::ItemList items;
0052     world->allItems(&items);
0053     foreach (StepCore::Item* item, items) {
0054         fixItemLinks(item);
0055     }
0056     
0057     _items.clear();
0058     _copyMap.clear();
0059     
0060     return world;
0061 }
0062 
0063 void CopyHelper::fillMap(const StepCore::Object* item, StepCore::Object* copy)
0064 {
0065     _copyMap.insert(item, copy);
0066     
0067     if (item->metaObject()->inherits<StepCore::ItemGroup>()) {
0068         const StepCore::ItemGroup* group =
0069             static_cast<const StepCore::ItemGroup*>(item);
0070         StepCore::ItemGroup* copiedGroup =
0071             static_cast<StepCore::ItemGroup*>(copy);
0072         
0073         StepCore::ItemList items;
0074         group->allItems(&items);
0075         StepCore::ItemList copiedItems;
0076         copiedGroup->allItems(&copiedItems);
0077         
0078         for (StepCore::ItemList::size_type n = 0; n < items.size(); ++n) {
0079             _copyMap.insert(items[n], copiedItems[n]);
0080         }
0081     }
0082 }
0083 
0084 void CopyHelper::fixItemLinks(StepCore::Item* item)
0085 {
0086     const StepCore::MetaObject* mobj = item->metaObject();
0087     
0088     for (int i = 0; i < mobj->propertyCount(); ++i) {
0089         const StepCore::MetaProperty* pr = mobj->property(i);
0090         
0091         if (pr->userTypeId() == qMetaTypeId<StepCore::Object*>()) {
0092             QVariant v = pr->readVariant(item);
0093             StepCore::Object *obj = v.value<StepCore::Object*>();
0094             StepCore::Object *copy = _copyMap.value(obj, nullptr);
0095             pr->writeVariant(item, QVariant::fromValue(copy));
0096         }
0097     }
0098 }
0099 }
0100 
0101 Clipboard::Clipboard(QObject* parent) : QObject(parent), _canPaste(hasData())
0102 {
0103     connect(QApplication::clipboard(), &QClipboard::dataChanged,
0104             this, &Clipboard::dataChanged);
0105 }
0106 
0107 
0108 void Clipboard::copy(const QList<StepCore::Item*>& items)
0109 {
0110     CopyHelper helper;
0111     
0112     foreach (const StepCore::Item* item, items) {
0113         helper.addItem(item);
0114     }
0115     
0116     QScopedPointer<StepCore::World> world(helper.createWorld());
0117     
0118     QBuffer buffer;
0119     buffer.open(QBuffer::WriteOnly);
0120     StepCore::XmlFile xmlfile(&buffer);
0121     if (!xmlfile.save(world.data())) {
0122         // Serialization of items failed
0123         qWarning() << xmlfile.errorString();
0124         return;
0125     }
0126     
0127     QMimeData *mimedata = new QMimeData;
0128     mimedata->setData(QStringLiteral("application/x-step"), buffer.data());
0129     
0130     QClipboard *clipboard = QApplication::clipboard();
0131     clipboard->setMimeData(mimedata);
0132 }
0133 
0134 QList<StepCore::Item*> Clipboard::paste(const StepCore::Factory* factory)
0135 {
0136     QClipboard *clipboard = QApplication::clipboard();
0137     const QMimeData *mimedata = clipboard->mimeData();
0138     
0139     if (!mimedata->hasFormat(QStringLiteral("application/x-step"))) {
0140         // No Step data available
0141         qWarning() << "No Step data on the clipboard";
0142         return QList<StepCore::Item*>();
0143     }
0144     
0145     QByteArray data(mimedata->data(QStringLiteral("application/x-step")));
0146     QBuffer buffer(&data);
0147     buffer.open(QBuffer::ReadOnly);
0148     StepCore::XmlFile xmlfile(&buffer);
0149     
0150     StepCore::World world;
0151     if (!xmlfile.load(&world, factory)) {
0152         // Deserialization of items failed
0153         qCritical() << xmlfile.errorString();
0154         return QList<StepCore::Item*>();
0155     }
0156     
0157     QList<StepCore::Item*> qitems;
0158     foreach (StepCore::Item* item, world.items()) {
0159         world.removeItem(item);
0160         qitems << item;
0161     }
0162     
0163     return qitems;
0164 }
0165 
0166 void Clipboard::dataChanged()
0167 {
0168     bool canPaste = hasData();
0169     
0170     if (canPaste != _canPaste) {
0171         _canPaste = canPaste;
0172         emit canPasteChanged(canPaste);
0173     }
0174 }
0175 
0176 bool Clipboard::hasData() const
0177 {
0178     QClipboard *clipboard = QApplication::clipboard();
0179     const QMimeData *mimedata = clipboard->mimeData();
0180     
0181     return mimedata->hasFormat(QStringLiteral("application/x-step"));
0182 }
0183 
0184 #include "moc_clipboard.cpp"