1 /* This file is part of the KDE project
2    Copyright (C) 2003 Lucijan Busch <lucijan@gmx.at>
3    Copyright (C) 2004 Cedric Pasteur <cedric.pasteur@free.fr>
4    Copyright (C) 2006-2010 Jarosław Staniek <staniek@kde.org>
5 
6    This library is free software; you can redistribute it and/or
7    modify it under the terms of the GNU Library General Public
8    License as published by the Free Software Foundation; either
9    version 2 of the License, or (at your option) any later version.
10 
11    This library is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14    Library General Public License for more details.
15 
16    You should have received a copy of the GNU Library General Public License
17    along with this library; see the file COPYING.LIB.  If not, write to
18    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19  * Boston, MA 02110-1301, USA.
20 */
21 
22 #include <QDebug>
23 #include <QWidget>
24 #include <QVariant>
25 #include <QTextStream>
26 #include <QDomElement>
27 
28 #include "form.h"
29 #include "container.h"
30 #include "objecttree.h"
31 
32 
33 using namespace KFormDesigner;
34 
35 /////////////////////////////////////////////////////////////////////////////////////////
36 /////////////////        ObjectTreeItem                                    /////////////
37 ////////////////////////////////////////////////////////////////////////////////////////
38 
39 class Q_DECL_HIDDEN ObjectTreeItem::Private
40 {
41 public:
42     Private(const QString &classn, const QString &name_, QWidget *widget_,
43             Container *parentContainer_, Container *c);
44 
45     ~Private();
46 
47     QString className;
48     QString name;
49     ObjectTreeList children;
50     QPointer<Container> container;
51     QHash<QString, QVariant> props;
52     QHash<QString, QVariant> *subprops;
53     QString  unknownProps;
54     QHash<QByteArray, QString> pixmapNames;
55     ObjectTreeItem* parent;
56     QPointer<QWidget> widget;
57     QPointer<EventEater> eater;
58 
59     bool  enabled;
60 
61     int row, col, rowspan, colspan;
62     bool span;
63 };
64 
Private(const QString & classn,const QString & name_,QWidget * widget_,Container * parentContainer_,Container * c)65 ObjectTreeItem::Private::Private(const QString &classn, const QString &name_, QWidget *widget_,
66                         Container *parentContainer_, Container *c)
67     : className(classn), name(name_), container(c)
68     , subprops(0), parent(0), widget(widget_), eater(new EventEater(widget_, parentContainer_))
69     , enabled(true), row(-1), col(-1), rowspan(-1), colspan(-1), span(false)
70 {
71 
72 }
73 
~Private()74 ObjectTreeItem::Private::~Private()
75 {
76     delete subprops;
77 }
78 
ObjectTreeItem(const QString & classn,const QString & name,QWidget * widget,Container * parentContainer,Container * container)79 ObjectTreeItem::ObjectTreeItem(const QString &classn, const QString &name, QWidget *widget,
80                                Container *parentContainer, Container *container)
81     : d(new Private(classn, name, widget, parentContainer, container))
82 {
83     //qDebug() << classn << name << widget->objectName() << "parentContainer:" << parentContainer << "container:" << container;
84 }
85 
~ObjectTreeItem()86 ObjectTreeItem::~ObjectTreeItem()
87 {
88     delete d;
89 }
90 
91 void
rename(const QString & name)92 ObjectTreeItem::rename(const QString &name)
93 {
94     d->name = name;
95 }
96 
97 void
addChild(ObjectTreeItem * c)98 ObjectTreeItem::addChild(ObjectTreeItem *c)
99 {
100     d->children.append(c);
101     c->setParent(this);
102 }
103 
104 void
removeChild(ObjectTreeItem * c)105 ObjectTreeItem::removeChild(ObjectTreeItem *c)
106 {
107     d->children.removeAt( d->children.indexOf(c) );
108 }
109 
110 void
addModifiedProperty(const QByteArray & property,const QVariant & oldValue)111 ObjectTreeItem::addModifiedProperty(const QByteArray &property, const QVariant &oldValue)
112 {
113     if (property == "objectName")
114         return;
115 
116     if (!d->props.contains(property)) {
117         d->props.insert(property, oldValue);
118         //qDebug() << "Added this property in the list: " << property << " oldValue: " << oldValue;
119     }
120 }
121 
122 void
addSubproperty(const QByteArray & property,const QVariant & value)123 ObjectTreeItem::addSubproperty(const QByteArray &property, const QVariant& value)
124 {
125     if (!d->subprops)
126         d->subprops = new QHash<QString, QVariant>();
127     if (!d->props.contains(property))
128         d->subprops->insert(property, value);
129 }
130 
131 void
storeUnknownProperty(QDomElement & el)132 ObjectTreeItem::storeUnknownProperty(QDomElement &el)
133 {
134     if (!el.isNull()) {
135         QTextStream ts(&d->unknownProps, QIODevice::WriteOnly | QIODevice::Append);
136         el.save(ts, 0);
137     }
138 }
139 
unknownProperties()140 QString ObjectTreeItem::unknownProperties()
141 {
142     return d->unknownProps;
143 }
144 
setUnknownProperties(const QString & set)145 void ObjectTreeItem::setUnknownProperties(const QString &set)
146 {
147     d->unknownProps = set;
148 }
149 
150 void
setPixmapName(const QByteArray & property,const QString & name)151 ObjectTreeItem::setPixmapName(const QByteArray &property, const QString &name)
152 {
153     d->pixmapNames.insert(property, name);
154 }
155 
156 QString
pixmapName(const QByteArray & property)157 ObjectTreeItem::pixmapName(const QByteArray &property)
158 {
159     return d->pixmapNames.value(property);
160 }
161 
162 void
setGridPos(int row,int col,int rowspan,int colspan)163 ObjectTreeItem::setGridPos(int row, int col, int rowspan, int colspan)
164 {
165     d->row = row;  d->col = col;
166     d->rowspan = rowspan;
167     d->colspan = colspan;
168     if (colspan || rowspan)
169         d->span = true;
170     else
171         d->span = false;
172 }
173 
subproperties() const174 QHash<QString, QVariant>* ObjectTreeItem::subproperties() const
175 {
176     return d->subprops;
177 }
178 
setEnabled(bool enabled)179 void ObjectTreeItem::setEnabled(bool enabled)
180 {
181     d->enabled = enabled;
182 }
183 
isEnabled() const184 bool ObjectTreeItem::isEnabled() const
185 {
186     return d->enabled;
187 }
188 
gridRow() const189 int ObjectTreeItem::gridRow() const
190 {
191     return d->row;
192 }
193 
gridCol() const194 int ObjectTreeItem::gridCol() const
195 {
196     return d->col;
197 }
198 
gridRowSpan() const199 int ObjectTreeItem::gridRowSpan() const
200 {
201     return d->rowspan;
202 }
203 
gridColSpan() const204 int ObjectTreeItem::gridColSpan() const
205 {
206     return d->colspan;
207 }
208 
spanMultipleCells() const209 bool ObjectTreeItem::spanMultipleCells() const
210 {
211     return d->span;
212 }
213 
name() const214 QString ObjectTreeItem::name() const
215 {
216     return d->name;
217 }
218 
className() const219 QString ObjectTreeItem::className() const
220 {
221     return d->className;
222 }
223 
widget() const224 QWidget* ObjectTreeItem::widget() const
225 {
226     return d->widget;
227 }
228 
eventEater() const229 EventEater* ObjectTreeItem::eventEater() const
230 {
231     return d->eater;
232 }
233 
parent() const234 ObjectTreeItem* ObjectTreeItem::parent() const
235 {
236     return d->parent;
237 }
238 
children()239 ObjectTreeList* ObjectTreeItem::children()
240 {
241     return &d->children;
242 }
243 
modifiedProperties() const244 const QHash<QString, QVariant>* ObjectTreeItem::modifiedProperties() const
245 {
246     return &d->props;
247 }
248 
container() const249 Container* ObjectTreeItem::container() const
250 {
251     return d->container;
252 }
253 
setWidget(QWidget * w)254 void ObjectTreeItem::setWidget(QWidget *w)
255 {
256     d->widget = w;
257 }
258 
setParent(ObjectTreeItem * parent)259 void ObjectTreeItem::setParent(ObjectTreeItem *parent)
260 {
261     d->parent = parent;
262 }
263 
264 
265 /////////////////////////////////////////////////////////////////////////////////////////
266 ///                      ObjectTree                                             /////////
267 ////////////////////////////////////////////////////////////////////////////////////////
268 
269 class Q_DECL_HIDDEN ObjectTree::Private
270 {
271 public:
Private()272     Private()
273     {
274 
275     }
276 
~Private()277     ~Private()
278     {
279 
280     }
281 
282     ObjectTreeHash treeHash;
283 };
284 
ObjectTree(const QString & classn,const QString & name,QWidget * widget,Container * container)285 ObjectTree::ObjectTree(const QString &classn, const QString &name, QWidget *widget, Container *container)
286     : ObjectTreeItem(classn, name, widget, container, container), d(new Private())
287 {
288 }
289 
~ObjectTree()290 ObjectTree::~ObjectTree()
291 {
292     while (!children()->isEmpty()) {
293         removeItem(children()->first());
294     }
295     delete d;
296 }
297 
298 bool
rename(const QString & oldname,const QString & newname)299 ObjectTree::rename(const QString &oldname, const QString &newname)
300 {
301     if (oldname == name()) {
302         ObjectTreeItem::rename(newname);
303         return true;
304     }
305 
306     ObjectTreeItem *it = lookup(oldname);
307     if (!it)
308         return false;
309 
310     it->rename(newname);
311     d->treeHash.remove(oldname);
312     d->treeHash.insert(newname, it);
313 
314     return true;
315 }
316 
317 bool
reparent(const QString & name,const QString & newparent)318 ObjectTree::reparent(const QString &name, const QString &newparent)
319 {
320     ObjectTreeItem *item = lookup(name);
321     if (!item)   return false;
322     ObjectTreeItem *parent = lookup(newparent);
323     if (!parent)   return false;
324 
325     item->parent()->removeChild(item);
326     parent->addChild(item);
327     return true;
328 }
329 
330 ObjectTreeItem*
lookup(const QString & name)331 ObjectTree::lookup(const QString &name)
332 {
333     if (name == this->name())
334         return this;
335     else
336         return d->treeHash.value(name);
337 }
338 
339 void
addItem(ObjectTreeItem * parent,ObjectTreeItem * c)340 ObjectTree::addItem(ObjectTreeItem *parent, ObjectTreeItem *c)
341 {
342     d->treeHash.insert(c->name(), c);
343 
344     if (!parent)
345         parent = this;
346     parent->addChild(c);
347     container()->form()->emitChildAdded(c);
348 
349     //qDebug() << "adding " << c->name() << " to " << parent->name();
350 }
351 
352 void
removeItem(const QString & name)353 ObjectTree::removeItem(const QString &name)
354 {
355     ObjectTreeItem *c = lookup(name);
356     removeItem(c);
357 }
358 
359 void
removeItem(ObjectTreeItem * c)360 ObjectTree::removeItem(ObjectTreeItem *c)
361 {
362     if (container() && container()->form())
363         container()->form()->emitChildRemoved(c);
364 
365     foreach (ObjectTreeItem *titem, *c->children()) {
366         removeItem(titem->name());
367     }
368 
369     d->treeHash.remove(c->name());
370     c->parent()->removeChild(c);
371     delete c;
372 }
373 
374 QByteArray
generateUniqueName(const QByteArray & prefix,bool numberSuffixRequired)375 ObjectTree::generateUniqueName(const QByteArray &prefix, bool numberSuffixRequired)
376 {
377     if (!numberSuffixRequired && !lookup(prefix))
378         return prefix;
379     QString name(prefix);
380     int i = 2; //start from 2, i.e. we have: "widget", "widget2", etc.
381     while (lookup(name + QString::number(i)))
382         i++;
383 
384     return (name + QString::number(i)).toLatin1();
385 }
386 
hash()387 ObjectTreeHash* ObjectTree::hash()
388 {
389     return &d->treeHash;
390 }
391