1 /* This file is part of Step.
2 * Copyright (C) 2007 Vladimir Kuznetsov <ks.vladimir@gmail.com>
3 *
4 * Step is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * Step is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with Step; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
17 */
18
19 #include "clipboard.h"
20
21 #include <QApplication>
22 #include <QBuffer>
23 #include <QClipboard>
24 #include <QDebug>
25 #include <QMimeData>
26
27 #include <stepcore/factory.h>
28 #include <stepcore/world.h>
29 #include <stepcore/xmlfile.h>
30
31 namespace
32 {
33 class CopyHelper
34 {
35 public:
36 void addItem(const StepCore::Item* item);
37 StepCore::World* createWorld();
38
39 private:
40 void fillMap(const StepCore::Object* item, StepCore::Object* copy);
41 void fixItemLinks(StepCore::Item* item);
42
43 QHash<const StepCore::Object*, StepCore::Object*> _copyMap;
44 QList<StepCore::Item*> _items;
45 };
46
addItem(const StepCore::Item * item)47 void CopyHelper::addItem(const StepCore::Item* item)
48 {
49 StepCore::Object *copy = item->metaObject()->cloneObject(*item);
50
51 _items << static_cast<StepCore::Item*>(copy);
52 fillMap(item, copy);
53 }
54
createWorld()55 StepCore::World* CopyHelper::createWorld()
56 {
57 StepCore::World *world = new StepCore::World;
58
59 foreach (StepCore::Item* item, _items) {
60 world->addItem(item);
61 }
62
63 StepCore::ItemList items;
64 world->allItems(&items);
65 foreach (StepCore::Item* item, items) {
66 fixItemLinks(item);
67 }
68
69 _items.clear();
70 _copyMap.clear();
71
72 return world;
73 }
74
fillMap(const StepCore::Object * item,StepCore::Object * copy)75 void CopyHelper::fillMap(const StepCore::Object* item, StepCore::Object* copy)
76 {
77 _copyMap.insert(item, copy);
78
79 if (item->metaObject()->inherits<StepCore::ItemGroup>()) {
80 const StepCore::ItemGroup* group =
81 static_cast<const StepCore::ItemGroup*>(item);
82 StepCore::ItemGroup* copiedGroup =
83 static_cast<StepCore::ItemGroup*>(copy);
84
85 StepCore::ItemList items;
86 group->allItems(&items);
87 StepCore::ItemList copiedItems;
88 copiedGroup->allItems(&copiedItems);
89
90 for (StepCore::ItemList::size_type n = 0; n < items.size(); ++n) {
91 _copyMap.insert(items[n], copiedItems[n]);
92 }
93 }
94 }
95
fixItemLinks(StepCore::Item * item)96 void CopyHelper::fixItemLinks(StepCore::Item* item)
97 {
98 const StepCore::MetaObject* mobj = item->metaObject();
99
100 for (int i = 0; i < mobj->propertyCount(); ++i) {
101 const StepCore::MetaProperty* pr = mobj->property(i);
102
103 if (pr->userTypeId() == qMetaTypeId<StepCore::Object*>()) {
104 QVariant v = pr->readVariant(item);
105 StepCore::Object *obj = v.value<StepCore::Object*>();
106 StepCore::Object *copy = _copyMap.value(obj, 0);
107 pr->writeVariant(item, QVariant::fromValue(copy));
108 }
109 }
110 }
111 }
112
Clipboard(QObject * parent)113 Clipboard::Clipboard(QObject* parent) : QObject(parent), _canPaste(hasData())
114 {
115 connect(QApplication::clipboard(), &QClipboard::dataChanged,
116 this, &Clipboard::dataChanged);
117 }
118
119
copy(const QList<StepCore::Item * > & items)120 void Clipboard::copy(const QList<StepCore::Item*>& items)
121 {
122 CopyHelper helper;
123
124 foreach (const StepCore::Item* item, items) {
125 helper.addItem(item);
126 }
127
128 QScopedPointer<StepCore::World> world(helper.createWorld());
129
130 QBuffer buffer;
131 buffer.open(QBuffer::WriteOnly);
132 StepCore::XmlFile xmlfile(&buffer);
133 if (!xmlfile.save(world.data())) {
134 // Serialization of items failed
135 qWarning() << xmlfile.errorString();
136 return;
137 }
138
139 QMimeData *mimedata = new QMimeData;
140 mimedata->setData(QStringLiteral("application/x-step"), buffer.data());
141
142 QClipboard *clipboard = QApplication::clipboard();
143 clipboard->setMimeData(mimedata);
144 }
145
paste(const StepCore::Factory * factory)146 QList<StepCore::Item*> Clipboard::paste(const StepCore::Factory* factory)
147 {
148 QClipboard *clipboard = QApplication::clipboard();
149 const QMimeData *mimedata = clipboard->mimeData();
150
151 if (!mimedata->hasFormat(QStringLiteral("application/x-step"))) {
152 // No Step data available
153 qWarning() << "No Step data on the clipboard";
154 return QList<StepCore::Item*>();
155 }
156
157 QByteArray data(mimedata->data(QStringLiteral("application/x-step")));
158 QBuffer buffer(&data);
159 buffer.open(QBuffer::ReadOnly);
160 StepCore::XmlFile xmlfile(&buffer);
161
162 StepCore::World world;
163 if (!xmlfile.load(&world, factory)) {
164 // Deserialization of items failed
165 qCritical() << xmlfile.errorString();
166 return QList<StepCore::Item*>();
167 }
168
169 QList<StepCore::Item*> qitems;
170 foreach (StepCore::Item* item, world.items()) {
171 world.removeItem(item);
172 qitems << item;
173 }
174
175 return qitems;
176 }
177
dataChanged()178 void Clipboard::dataChanged()
179 {
180 bool canPaste = hasData();
181
182 if (canPaste != _canPaste) {
183 _canPaste = canPaste;
184 emit canPasteChanged(canPaste);
185 }
186 }
187
hasData() const188 bool Clipboard::hasData() const
189 {
190 QClipboard *clipboard = QApplication::clipboard();
191 const QMimeData *mimedata = clipboard->mimeData();
192
193 return mimedata->hasFormat(QStringLiteral("application/x-step"));
194 }
195