summaryrefslogtreecommitdiffstats
path: root/kexi/formeditor
diff options
context:
space:
mode:
authortpearson <tpearson@283d02a7-25f6-0310-bc7c-ecb5cbfe19da>2010-01-20 01:29:50 +0000
committertpearson <tpearson@283d02a7-25f6-0310-bc7c-ecb5cbfe19da>2010-01-20 01:29:50 +0000
commit8362bf63dea22bbf6736609b0f49c152f975eb63 (patch)
tree0eea3928e39e50fae91d4e68b21b1e6cbae25604 /kexi/formeditor
downloadkoffice-8362bf63dea22bbf6736609b0f49c152f975eb63.tar.gz
koffice-8362bf63dea22bbf6736609b0f49c152f975eb63.zip
Added old abandoned KDE3 version of koffice
git-svn-id: svn://anonsvn.kde.org/home/kde/branches/trinity/applications/koffice@1077364 283d02a7-25f6-0310-bc7c-ecb5cbfe19da
Diffstat (limited to 'kexi/formeditor')
-rw-r--r--kexi/formeditor/Makefile.am34
-rw-r--r--kexi/formeditor/TODO66
-rw-r--r--kexi/formeditor/commands.cpp1601
-rw-r--r--kexi/formeditor/commands.h380
-rw-r--r--kexi/formeditor/connectiondialog.cpp420
-rw-r--r--kexi/formeditor/connectiondialog.h114
-rw-r--r--kexi/formeditor/container.cpp1182
-rw-r--r--kexi/formeditor/container.h248
-rw-r--r--kexi/formeditor/editlistviewdialog.cpp460
-rw-r--r--kexi/formeditor/editlistviewdialog.h93
-rw-r--r--kexi/formeditor/events.cpp145
-rw-r--r--kexi/formeditor/events.h78
-rw-r--r--kexi/formeditor/factories/Makefile.am20
-rw-r--r--kexi/formeditor/factories/containerfactory.cpp936
-rw-r--r--kexi/formeditor/factories/containerfactory.h271
-rw-r--r--kexi/formeditor/factories/kformdesigner_containers.desktop53
-rw-r--r--kexi/formeditor/factories/kformdesigner_stdwidgets.desktop55
-rw-r--r--kexi/formeditor/factories/stdwidgetfactory.cpp984
-rw-r--r--kexi/formeditor/factories/stdwidgetfactory.h99
-rw-r--r--kexi/formeditor/form.cpp600
-rw-r--r--kexi/formeditor/form.h397
-rw-r--r--kexi/formeditor/formIO.cpp1626
-rw-r--r--kexi/formeditor/formIO.h222
-rw-r--r--kexi/formeditor/formmanager.cpp1716
-rw-r--r--kexi/formeditor/formmanager.h496
-rw-r--r--kexi/formeditor/kdevelop_plugin/Makefile.am21
-rw-r--r--kexi/formeditor/kdevelop_plugin/kfd_kdev_part.cpp694
-rw-r--r--kexi/formeditor/kdevelop_plugin/kfd_kdev_part.h139
-rw-r--r--kexi/formeditor/kdevelop_plugin/kformdesigner_kdev_part.desktop50
-rw-r--r--kexi/formeditor/kdevelop_plugin/kformdesigner_part.rc129
-rw-r--r--kexi/formeditor/kdevelop_plugin/kformdesigner_part_shell.rc142
-rw-r--r--kexi/formeditor/kfdpixmapedit.cpp59
-rw-r--r--kexi/formeditor/kfdpixmapedit.h44
-rw-r--r--kexi/formeditor/libactionwidget.cpp52
-rw-r--r--kexi/formeditor/libactionwidget.h60
-rw-r--r--kexi/formeditor/objecttree.cpp244
-rw-r--r--kexi/formeditor/objecttree.h184
-rw-r--r--kexi/formeditor/objecttreeview.cpp377
-rw-r--r--kexi/formeditor/objecttreeview.h129
-rw-r--r--kexi/formeditor/resizehandle.cpp339
-rw-r--r--kexi/formeditor/resizehandle.h102
-rw-r--r--kexi/formeditor/richtextdialog.cpp210
-rw-r--r--kexi/formeditor/richtextdialog.h63
-rw-r--r--kexi/formeditor/scripting/Makefile.am18
-rw-r--r--kexi/formeditor/scripting/formscript.cpp109
-rw-r--r--kexi/formeditor/scripting/formscript.h78
-rw-r--r--kexi/formeditor/scripting/scriptIO.cpp186
-rw-r--r--kexi/formeditor/scripting/scriptIO.h64
-rw-r--r--kexi/formeditor/scripting/scriptmanager.cpp70
-rw-r--r--kexi/formeditor/scripting/scriptmanager.h69
-rw-r--r--kexi/formeditor/spring.cpp158
-rw-r--r--kexi/formeditor/spring.h74
-rw-r--r--kexi/formeditor/tabstopdialog.cpp168
-rw-r--r--kexi/formeditor/tabstopdialog.h63
-rw-r--r--kexi/formeditor/test/Makefile.am46
-rw-r--r--kexi/formeditor/test/cr16-app-kformdesigner.pngbin0 -> 493 bytes
-rw-r--r--kexi/formeditor/test/cr22-app-kformdesigner.pngbin0 -> 733 bytes
-rw-r--r--kexi/formeditor/test/cr32-app-kformdesigner.pngbin0 -> 1126 bytes
-rw-r--r--kexi/formeditor/test/kfd_mainwindow.cpp88
-rw-r--r--kexi/formeditor/test/kfd_mainwindow.h46
-rw-r--r--kexi/formeditor/test/kfd_mainwindow.rc26
-rw-r--r--kexi/formeditor/test/kfd_part.cpp729
-rw-r--r--kexi/formeditor/test/kfd_part.h142
-rw-r--r--kexi/formeditor/test/kformdesigner.desktop61
-rw-r--r--kexi/formeditor/test/kformdesigner_part.desktop52
-rw-r--r--kexi/formeditor/test/kformdesigner_part.rc125
-rw-r--r--kexi/formeditor/test/kformdesigner_part_shell.rc138
-rw-r--r--kexi/formeditor/test/main.cpp81
-rw-r--r--kexi/formeditor/utils.cpp184
-rw-r--r--kexi/formeditor/utils.h113
-rw-r--r--kexi/formeditor/widgetfactory.cpp725
-rw-r--r--kexi/formeditor/widgetfactory.desktop53
-rw-r--r--kexi/formeditor/widgetfactory.h518
-rw-r--r--kexi/formeditor/widgetlibrary.cpp769
-rw-r--r--kexi/formeditor/widgetlibrary.h212
-rw-r--r--kexi/formeditor/widgetpropertyset.cpp1120
-rw-r--r--kexi/formeditor/widgetpropertyset.h206
-rw-r--r--kexi/formeditor/widgetwithsubpropertiesinterface.cpp98
-rw-r--r--kexi/formeditor/widgetwithsubpropertiesinterface.h72
79 files changed, 21995 insertions, 0 deletions
diff --git a/kexi/formeditor/Makefile.am b/kexi/formeditor/Makefile.am
new file mode 100644
index 00000000..8f8aacbe
--- /dev/null
+++ b/kexi/formeditor/Makefile.am
@@ -0,0 +1,34 @@
+include $(top_srcdir)/kexi/Makefile.global
+
+INCLUDES = -I$(top_srcdir)/kexi/widget -I$(top_srcdir)/kexi/widget/utils \
+ -I$(top_srcdir)/kexi/widget/tableview \
+ -I$(top_srcdir)/kexi/core \
+ -I$(top_srcdir)/kexi \
+ -I$(top_srcdir)/lib/kofficecore \
+ -I$(top_srcdir)/lib -I$(top_srcdir)/lib/koproperty $(all_includes)
+
+lib_LTLIBRARIES = libkformdesigner.la
+libkformdesigner_la_LDFLAGS = -no-undefined $(all_libraries) $(VER_INFO)
+libkformdesigner_la_SOURCES = container.cpp resizehandle.cpp widgetfactory.cpp \
+ widgetlibrary.cpp libactionwidget.cpp form.cpp \
+ objecttree.cpp formIO.cpp formmanager.cpp objecttreeview.cpp spring.cpp \
+ commands.cpp events.cpp connectiondialog.cpp richtextdialog.cpp \
+ tabstopdialog.cpp editlistviewdialog.cpp utils.cpp widgetpropertyset.cpp \
+ kfdpixmapedit.cpp widgetwithsubpropertiesinterface.cpp
+
+METASOURCES = AUTO
+libkformdesigner_la_LIBADD = \
+ $(top_builddir)/kexi/widget/libkexiextendedwidgets.la \
+ $(top_builddir)/kexi/widget/utils/libkexiguiutils.la \
+ $(top_builddir)/kexi/widget/tableview/libkexidatatable.la \
+ $(top_builddir)/lib/koproperty/libkoproperty.la \
+ $(LIB_KPARTS)
+
+servicetypesdir = $(kde_servicetypesdir)
+servicetypes_DATA=widgetfactory.desktop
+
+SUBDIRS = . factories #test #scripting #kdevelop_plugin
+
+messages: rc.cpp
+ $(EXTRACTRC) `find . -name "*.rc" -o -name "*.ui"` >> rc.cpp
+ $(XGETTEXT) `find . -name "*.cpp" -o -name "*.h"` -o $(podir)/kformdesigner.pot
diff --git a/kexi/formeditor/TODO b/kexi/formeditor/TODO
new file mode 100644
index 00000000..611d5c0c
--- /dev/null
+++ b/kexi/formeditor/TODO
@@ -0,0 +1,66 @@
+^^^^^^^^^^^^^^^ IMPORTANT ^^^^^^^^^^^^^^^^^^^^^^
+**** New Features : ******
+* KMainWindow support : Make an action editor + a toolbar editor (as in MozillaFirebird ?) + a menu editor
+ (see Gambas and askk other devs if they already have done this)
+* Automatically set label name to the text
+* Create an event editor and manage signals/slots (EventBuffer ?)
+ HOWEVER, SIGNAL/SLOT ISSUES (js):
+ 1. signals/slots mechanism is hard to use for average folks
+ 2. it may be easily simplified to avoid confusing them
+ 3. TrollTech would try to get influence on the Kexi Project
+ because of violating their licenses, if we'd like to expose
+ all their technologies so plainly
+ (at least commercial) license mentions that there cannot be
+ a project that is a replacement of the Qt developed out of the Qt)
+ 4. It wouldn't hurt to ask them, as well.
+* Add many other widgets :-)
+* Create db-aware widget factory
+
+****** Bugfixes/Changes : *****
+* Add a grouping ability to Widget
+* Switch WifdgetInfo::className() to QCString
+* Make subform open design when double-clickng
+
+^^^^^^^^^^^^^^^^^^ OTHER ^^^^^^^^^^^^^^^^^^^^^^^^
+* Move tab between two QTabWidgets by drag'n drop
+* Better editor for iconview
+* during inline editing: CTRL+Enter could insert \n
+
+^^^^^^^^^^^^^^^^ DONE ^^^^^^^^^^^^^^
+* Finish sync between Form and ObjectTreeView (2/21/04)
+* Only QTabWidget should be selected, not pages (2/21/04)
+* Add a minimum size for created widgets (using size hint) (2/21/04)
+* Move the pasted widget a little to avoid to have two widgets at the same pos (2/21/04)
+* Make FormManager independant of the parent container (ie no longer depends on QWorkspace) (2/23/04)
+* Fix pixmaps in Property Editor (2/24/04)
+* Properties names and values are now i18n'ed (2/24/04)
+* Add a classname and filename member into Form (2/24/04)
+* Add support for layouts and special container (HBox, VBox ...) and spacers (partially 2/27/04)
+* Allow Multiple selection : edit common properties (colors, font..),copy/cut them at one time, ... (2/28/04)
+* Move multiple selected widgets at one time (2/29/04)
+* Added real support for old values (2/29/04)
+* Form previewing stuff (3/01/04)
+* QByteArray methods in FormIO (3/01/04)
+* Undo support(3/05/04)
+* Alignment and layout properties also support old values (3/06/04)
+* Better handling of multiple widgets in ObjectPropertyBuffer : each widget has its own old value, so reset will act as expected (3/07/04)
+* Remove all these " Q*** " names (3/08/04)
+* When double-clicking on a QLabel or a QLabel (others ?), the widget should be inline-editable (also on creation) (3/11/04)
+* Add many other widgets :-) (part I : all basic widgets) (3/20/04)
+* Add grid layout (3/27/04)
+* Add many other widgets :-) (part II : all basic containers + more widgets) (4/13/04)
+* Change tab position by drag'n drop (4/14/04)
+* Icons in ObjectTreeView(in branch) + context menu (4/14/04)
+* Modify Spacer for better compatibility (save orientation and expanding) (4/19/04)
+* Rich text editor (see BasKet source) (4/20/04)
+* Allow to select multiple widgets by drawing a rectangle on form (4/22/04)
+* Add a "Lay out Vertcally / horizontally " menu item when multiple widgets are selected (4/22/04)
+* Select all widgets when pasted (8/05/04)
+* Handle tab stops (8/05/04)
+* Make ObjectTreeView handle multiple widgets (11/05/04)
+* Manage label buddies using a popup menu (24/05/04)
+* dragging with CTRL key can cause object's copying (25/05/04)
+* Create a PixmapCollection with an editor which allow to choose pixmaps by path or from KDE icons, no inline saving of pixmaps (9/06/04)
+* Make actions toggable (with KToggleAction) (js 11/06/04)
+* Make FormWidget pure virtual (17/06/04)
+* Resize label to fit the text (22/06/04)
diff --git a/kexi/formeditor/commands.cpp b/kexi/formeditor/commands.cpp
new file mode 100644
index 00000000..ca4f0f20
--- /dev/null
+++ b/kexi/formeditor/commands.cpp
@@ -0,0 +1,1601 @@
+/* This file is part of the KDE project
+ Copyright (C) 2004 Cedric Pasteur <cedric.pasteur@free.fr>
+ Copyright (C) 2005 Jaroslaw Staniek <js@iidea.pl>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+*/
+#include <qdom.h>
+#include <qwidget.h>
+#include <qlayout.h>
+#include <qlabel.h>
+#include <qsplitter.h>
+#include <qmetaobject.h>
+
+#include <kdebug.h>
+#include <klocale.h>
+#include <kpopupmenu.h>
+#include <kmessagebox.h>
+#include <kaccelmanager.h>
+
+#include "formIO.h"
+#include "container.h"
+#include "objecttree.h"
+#include "formmanager.h"
+#include "form.h"
+#include "widgetlibrary.h"
+#include "events.h"
+#include "utils.h"
+#include "widgetpropertyset.h"
+#include "widgetwithsubpropertiesinterface.h"
+#include <koproperty/property.h>
+
+#include "commands.h"
+
+using namespace KFormDesigner;
+
+// Command
+
+Command::Command()
+ : KCommand()
+{
+}
+
+Command::~Command()
+{
+}
+
+// PropertyCommand
+
+PropertyCommand::PropertyCommand(WidgetPropertySet *set, const QCString &wname,
+ const QVariant &oldValue, const QVariant &value, const QCString &property)
+ : Command(), m_propSet(set), m_value(value), m_property(property)
+{
+ m_oldvalues.insert(wname, oldValue);
+}
+
+PropertyCommand::PropertyCommand(WidgetPropertySet *set, const QMap<QCString, QVariant> &oldvalues,
+ const QVariant &value, const QCString &property)
+ : Command(), m_propSet(set), m_value(value), m_oldvalues(oldvalues), m_property(property)
+{
+}
+
+/*
+MultiCommand::MultiCommand()
+{
+}
+
+MultiCommandGroup::addSubCommand(PropertyCommand* subCommand)
+ : Command(), m_propSet(set), m_value(value), m_oldvalues(oldvalues), m_property(property)
+{
+}
+*/
+
+void
+PropertyCommand::setValue(const QVariant &value)
+{
+ m_value = value;
+ emit FormManager::self()->dirty(FormManager::self()->activeForm());
+}
+
+void
+PropertyCommand::execute()
+{
+ FormManager::self()->activeForm()->selectFormWidget();
+ m_propSet->setUndoing(true);
+
+ QMap<QCString, QVariant>::ConstIterator endIt = m_oldvalues.constEnd();
+ for(QMap<QCString, QVariant>::ConstIterator it = m_oldvalues.constBegin(); it != endIt; ++it)
+ {
+ ObjectTreeItem* item = FormManager::self()->activeForm()->objectTree()->lookup(it.key());
+ if (item) {//we're checking for item!=0 because the name could be of a form widget
+ FormManager::self()->activeForm()->setSelectedWidget(item->widget(), true);
+ }
+ }
+
+ (*m_propSet)[m_property] = m_value;
+ m_propSet->setUndoing(false);
+}
+
+void
+PropertyCommand::unexecute()
+{
+ FormManager::self()->activeForm()->selectFormWidget();
+ m_propSet->setUndoing(true);
+
+ QMap<QCString, QVariant>::ConstIterator endIt = m_oldvalues.constEnd();
+ for(QMap<QCString, QVariant>::ConstIterator it = m_oldvalues.constBegin(); it != endIt; ++it)
+ {
+ ObjectTreeItem* item = FormManager::self()->activeForm()->objectTree()->lookup(it.key());
+ if (!item)
+ continue; //better this than a crash
+ QWidget *widg = item->widget();
+ FormManager::self()->activeForm()->setSelectedWidget(widg, true);
+ //m_propSet->setSelectedWidget(widg, true);
+
+ WidgetWithSubpropertiesInterface* subpropIface = dynamic_cast<WidgetWithSubpropertiesInterface*>(widg);
+ QWidget *subWidget = (subpropIface && subpropIface->subwidget()) ? subpropIface->subwidget() : widg;
+ if (-1!=subWidget->metaObject()->findProperty( m_property, true ))
+ subWidget->setProperty(m_property, it.data());
+ }
+
+ (*m_propSet)[m_property] = m_oldvalues.begin().data();
+ m_propSet->setUndoing(false);
+}
+
+QString
+PropertyCommand::name() const
+{
+ if(m_oldvalues.count() >= 2)
+ return i18n("Change \"%1\" property for multiple widgets" ).arg(m_property);
+ else
+ return i18n("Change \"%1\" property for widget \"%2\"" ).arg(m_property).arg(m_oldvalues.begin().key());
+}
+
+void
+PropertyCommand::debug()
+{
+ kdDebug() << "PropertyCommand: name=\"" << name() << "\" widgets=" << m_oldvalues.keys()
+ << " value=" << m_value << " oldValues=" << m_oldvalues.values() << endl;
+}
+
+// GeometryPropertyCommand (for multiples widgets)
+
+GeometryPropertyCommand::GeometryPropertyCommand(WidgetPropertySet *set,
+ const QStringList &names, const QPoint& oldPos)
+ : Command(), m_propSet(set), m_names(names), m_oldPos(oldPos)
+{
+}
+
+void
+GeometryPropertyCommand::execute()
+{
+ m_propSet->setUndoing(true);
+ int dx = m_pos.x() - m_oldPos.x();
+ int dy = m_pos.y() - m_oldPos.y();
+
+ QStringList::ConstIterator endIt = m_names.constEnd();
+ // We move every widget in our list by (dx, dy)
+ for(QStringList::ConstIterator it = m_names.constBegin(); it != endIt; ++it)
+ {
+ ObjectTreeItem* item = FormManager::self()->activeForm()->objectTree()->lookup(*it);
+ if (!item)
+ continue; //better this than a crash
+ QWidget *w = item->widget();
+ w->move(w->x() + dx, w->y() + dy);
+ }
+ m_propSet->setUndoing(false);
+}
+
+void
+GeometryPropertyCommand::unexecute()
+{
+ m_propSet->setUndoing(true);
+ int dx = m_pos.x() - m_oldPos.x();
+ int dy = m_pos.y() - m_oldPos.y();
+
+ QStringList::ConstIterator endIt = m_names.constEnd();
+ // We move every widget in our list by (-dx, -dy) to undo the move
+ for(QStringList::ConstIterator it = m_names.constBegin(); it != endIt; ++it)
+ {
+ ObjectTreeItem* item = FormManager::self()->activeForm()->objectTree()->lookup(*it);
+ if (!item)
+ continue; //better this than a crash
+ QWidget *w = item->widget();
+ w->move(w->x() - dx, w->y() - dy);
+ }
+ m_propSet->setUndoing(false);
+}
+
+void
+GeometryPropertyCommand::setPos(const QPoint& pos)
+{
+ m_pos = pos;
+ emit FormManager::self()->dirty(FormManager::self()->activeForm());
+}
+
+QString
+GeometryPropertyCommand::name() const
+{
+ return i18n("Move multiple widgets");
+}
+
+void
+GeometryPropertyCommand::debug()
+{
+ kdDebug() << "GeometryPropertyCommand: pos=" << m_pos << " oldPos=" << m_oldPos
+ << " widgets=" << m_names << endl;
+}
+
+///////////////// AlignWidgetsCommand ////////
+
+AlignWidgetsCommand::AlignWidgetsCommand(int type, WidgetList &list, Form *form)
+: Command(), m_form(form), m_type(type)
+{
+ for(QWidget *w = list.first(); w; w = list.next())
+ m_pos.insert(w->name(), w->pos());
+}
+
+void
+AlignWidgetsCommand::execute()
+{
+ // To avoid creation of GeometryPropertyCommand
+ m_form->selectFormWidget();
+
+ int gridX = m_form->gridSize();
+ int gridY = m_form->gridSize();
+ QWidget *parentWidget = m_form->selectedWidgets()->first()->parentWidget();
+ int tmpx, tmpy;
+
+ WidgetList list;
+ QMap<QCString, QPoint>::ConstIterator endIt = m_pos.constEnd();
+ for(QMap<QCString, QPoint>::ConstIterator it = m_pos.constBegin(); it != endIt; ++it)
+ {
+ ObjectTreeItem *item = m_form->objectTree()->lookup(it.key());
+ if(item && item->widget())
+ list.append(item->widget());
+ }
+
+ switch(m_type)
+ {
+ case AlignToGrid:
+ {
+ for(QWidget *w = list.first(); w; w = list.next())
+ {
+ tmpx = int( (float)w->x() / ((float)gridX) + 0.5 ) * gridX;
+ tmpy = int( (float)w->y() / ((float)gridY) + 0.5 ) * gridY;
+
+ if((tmpx != w->x()) || (tmpy != w->y()))
+ w->move(tmpx, tmpy);
+ }
+ break;
+ }
+
+ case AlignToLeft:
+ {
+ tmpx = parentWidget->width();
+ for(QWidget *w = list.first(); w; w = list.next())
+ {
+ if(w->x() < tmpx)
+ tmpx = w->x();
+ }
+
+ for(QWidget *w = list.first(); w; w = list.next())
+ w->move(tmpx, w->y());
+ break;
+ }
+
+ case AlignToRight:
+ {
+ tmpx = 0;
+ for(QWidget *w = list.first(); w; w = list.next())
+ {
+ if(w->x() + w->width() > tmpx)
+ tmpx = w->x() + w->width();
+ }
+
+ for(QWidget *w = list.first(); w; w = list.next())
+ w->move(tmpx - w->width(), w->y());
+ break;
+ }
+
+ case AlignToTop:
+ {
+ tmpy = parentWidget->height();
+ for(QWidget *w = list.first(); w; w = list.next())
+ {
+ if(w->y() < tmpy)
+ tmpy = w->y();
+ }
+
+ for(QWidget *w = list.first(); w; w = list.next())
+ w->move(w->x(), tmpy);
+ break;
+ }
+
+ case AlignToBottom:
+ {
+ tmpy = 0;
+ for(QWidget *w = list.first(); w; w = list.next())
+ {
+ if(w->y() + w->height() > tmpy)
+ tmpy = w->y() + w->height();
+ }
+
+ for(QWidget *w = list.first(); w; w = list.next())
+ w->move(w->x(), tmpy - w->height());
+ break;
+ }
+
+ default:
+ return;
+ }
+
+ // We restore selection
+ for(QWidget *w = list.first(); w; w = list.next())
+ m_form->setSelectedWidget(w, true);
+}
+
+void
+AlignWidgetsCommand::unexecute()
+{
+ // To avoid creation of GeometryPropertyCommand
+ m_form->selectFormWidget();
+ // We move widgets to their original pos
+ QMap<QCString, QPoint>::ConstIterator endIt = m_pos.constEnd();
+ for(QMap<QCString, QPoint>::ConstIterator it = m_pos.constBegin(); it != endIt; ++it)
+ {
+ ObjectTreeItem *item = m_form->objectTree()->lookup(it.key());
+ if(item && item->widget())
+ item->widget()->move( m_pos[item->widget()->name()] );
+ m_form->setSelectedWidget(item->widget(), true); // We restore selection
+ }
+}
+
+QString
+AlignWidgetsCommand::name() const
+{
+ switch(m_type)
+ {
+ case AlignToGrid:
+ return i18n("Align Widgets to Grid");
+ case AlignToLeft:
+ return i18n("Align Widgets to Left");
+ case AlignToRight:
+ return i18n("Align Widgets to Right");
+ case AlignToTop:
+ return i18n("Align Widgets to Top");
+ case AlignToBottom:
+ return i18n("Align Widgets to Bottom");
+ default:
+ return QString::null;
+ }
+}
+
+void
+AlignWidgetsCommand::debug()
+{
+ kdDebug() << "AlignWidgetsCommand: name=\"" << name() << "\" form=" << m_form->widget()->name()
+ << " widgets=" << m_pos.keys() << endl;
+}
+
+///// AdjustSizeCommand ///////////
+
+AdjustSizeCommand::AdjustSizeCommand(int type, WidgetList &list, Form *form)
+: Command(), m_form(form), m_type(type)
+{
+ for(QWidget *w = list.first(); w; w = list.next())
+ {
+ if(w->parentWidget() && w->parentWidget()->isA("QWidgetStack"))
+ {
+ w = w->parentWidget(); // widget is WidgetStack page
+ if(w->parentWidget() && w->parentWidget()->inherits("QTabWidget")) // widget is tabwidget page
+ w = w->parentWidget();
+ }
+
+ m_sizes.insert(w->name(), w->size());
+ if(m_type == SizeToGrid) // SizeToGrid also move widgets
+ m_pos.insert(w->name(), w->pos());
+ }
+}
+
+void
+AdjustSizeCommand::execute()
+{
+ // To avoid creation of GeometryPropertyCommand
+ m_form->selectFormWidget();
+
+ int gridX = m_form->gridSize();
+ int gridY = m_form->gridSize();
+ int tmpw=0, tmph=0;
+
+ WidgetList list;
+ QMap<QCString, QSize>::ConstIterator endIt = m_sizes.constEnd();
+ for(QMap<QCString, QSize>::ConstIterator it = m_sizes.constBegin(); it != endIt; ++it)
+ {
+ ObjectTreeItem *item = m_form->objectTree()->lookup(it.key());
+ if(item && item->widget())
+ list.append(item->widget());
+ }
+
+ switch(m_type)
+ {
+ case SizeToGrid:
+ {
+ int tmpx=0, tmpy=0;
+ // same as in 'Align to Grid' + for the size
+ for(QWidget *w = list.first(); w; w = list.next())
+ {
+ tmpx = int( (float)w->x() / ((float)gridX) + 0.5 ) * gridX;
+ tmpy = int( (float)w->y() / ((float)gridY) + 0.5 ) * gridY;
+ tmpw = int( (float)w->width() / ((float)gridX) + 0.5 ) * gridX;
+ tmph = int( (float)w->height() / ((float)gridY) + 0.5 ) * gridY;
+
+ if((tmpx != w->x()) || (tmpy != w->y()))
+ w->move(tmpx, tmpy);
+ if((tmpw != w->width()) || (tmph != w->height()))
+ w->resize(tmpw, tmph);
+ }
+ break;
+ }
+
+ case SizeToFit:
+ {
+ for(QWidget *w = list.first(); w; w = list.next()) {
+ ObjectTreeItem *item = m_form->objectTree()->lookup(w->name());
+ if(item && !item->children()->isEmpty()) { // container
+ QSize s;
+ if(item->container() && item->container()->layout())
+ s = w->sizeHint();
+ else
+ s = getSizeFromChildren(item);
+ // minimum size for containers
+ if(s.width() < 30)
+ s.setWidth(30);
+ if(s.height() < 30)
+ s.setHeight(30);
+ // small hack for flow layouts
+ int type = item->container() ? item->container()->layoutType() : Container::NoLayout;
+ if(type == Container::HFlow)
+ s.setWidth(s.width() + 5);
+ else if(type == Container::VFlow)
+ s.setHeight(s.height() + 5);
+ w->resize(s);
+ }
+ else if(item && item->container()) // empty container
+ w->resize(item->container()->form()->gridSize() * 5, item->container()->form()->gridSize() * 5); // basic size
+ else {
+ QSize sizeHint(w->sizeHint());
+ if (sizeHint.isValid())
+ w->resize(sizeHint);
+ }
+ }
+ break;
+ }
+
+ case SizeToSmallWidth:
+ {
+ for(QWidget *w = list.first(); w; w = list.next())
+ {
+ if((tmpw == 0) || (w->width() < tmpw))
+ tmpw = w->width();
+ }
+
+ for(QWidget *w = list.first(); w; w = list.next())
+ {
+ if(tmpw != w->width())
+ w->resize(tmpw, w->height());
+ }
+ break;
+ }
+
+ case SizeToBigWidth:
+ {
+ for(QWidget *w = list.first(); w; w = list.next())
+ {
+ if(w->width() > tmpw)
+ tmpw = w->width();
+ }
+
+ for(QWidget *w = list.first(); w; w = list.next())
+ {
+ if(tmpw != w->width())
+ w->resize(tmpw, w->height());
+ }
+ break;
+ }
+
+ case SizeToSmallHeight:
+ {
+ for(QWidget *w = list.first(); w; w = list.next())
+ {
+ if((tmph == 0) || (w->height() < tmph))
+ tmph = w->height();
+ }
+
+ for(QWidget *w = list.first(); w; w = list.next())
+ {
+ if(tmph != w->height())
+ w->resize(w->width(), tmph);
+ }
+ break;
+ }
+
+ case SizeToBigHeight:
+ {
+ for(QWidget *w = list.first(); w; w = list.next())
+ {
+ if(w->height() > tmph)
+ tmph = w->height();
+ }
+
+ for(QWidget *w = list.first(); w; w = list.next())
+ {
+ if(tmph != w->height())
+ w->resize(w->width(), tmph);
+ }
+ break;
+ }
+
+ default:
+ break;
+ }
+
+ // We restore selection
+ for(QWidget *w = list.first(); w; w = list.next())
+ m_form->setSelectedWidget(w, true);
+}
+
+QSize
+AdjustSizeCommand::getSizeFromChildren(ObjectTreeItem *item)
+{
+ if(!item->container()) // multi pages containers (eg tabwidget)
+ {
+ QSize s;
+ // get size for each container, and keep the biggest one
+ for(ObjectTreeItem *tree = item->children()->first(); tree; tree = item->children()->next())
+ s = s.expandedTo(getSizeFromChildren(tree));
+ return s;
+ }
+
+ int tmpw = 0, tmph = 0;
+ for(ObjectTreeItem *tree = item->children()->first(); tree; tree = item->children()->next()) {
+ if(!tree->widget())
+ continue;
+ tmpw = QMAX(tmpw, tree->widget()->geometry().right());
+ tmph = QMAX(tmph, tree->widget()->geometry().bottom());
+ }
+
+ return QSize(tmpw, tmph) + QSize(10, 10);
+}
+
+void
+AdjustSizeCommand::unexecute()
+{
+ // To avoid creation of GeometryPropertyCommand
+ m_form->selectFormWidget();
+ // We resize widgets to their original size
+ QMap<QCString, QSize>::ConstIterator endIt = m_sizes.constEnd();
+ for(QMap<QCString, QSize>::ConstIterator it = m_sizes.constBegin(); it != endIt; ++it)
+ {
+ ObjectTreeItem *item = m_form->objectTree()->lookup(it.key());
+ if(item && item->widget())
+ {
+ item->widget()->resize( m_sizes[item->widget()->name()] );
+ if(m_type == SizeToGrid)
+ item->widget()->move( m_pos[item->widget()->name()] );
+ m_form->setSelectedWidget(item->widget(), true); // We restore selection
+ }
+ }
+}
+
+QString
+AdjustSizeCommand::name() const
+{
+ switch(m_type)
+ {
+ case SizeToGrid:
+ return i18n("Resize Widgets to Grid");
+ case SizeToFit:
+ return i18n("Resize Widgets to Fit Contents");
+ case SizeToSmallWidth:
+ return i18n("Resize Widgets to Narrowest");
+ case SizeToBigWidth:
+ return i18n("Resize Widgets to Widest");
+ case SizeToSmallHeight:
+ return i18n("Resize Widgets to Shortest");
+ case SizeToBigHeight:
+ return i18n("Resize Widgets to Tallest");
+ default:
+ return QString::null;
+ }
+}
+
+void
+AdjustSizeCommand::debug()
+{
+ kdDebug() << "AdjustSizeCommand: name=\"" << name() << "\" form=" << m_form->widget()->name()
+ << " widgets=" << m_sizes.keys() << endl;
+}
+
+// LayoutPropertyCommand
+
+LayoutPropertyCommand::LayoutPropertyCommand(WidgetPropertySet *buf, const QCString &wname,
+ const QVariant &oldValue, const QVariant &value)
+ : PropertyCommand(buf, wname, oldValue, value, "layout")
+{
+ m_form = FormManager::self()->activeForm();
+ ObjectTreeItem* titem = m_form->objectTree()->lookup(wname);
+ if (!titem)
+ return; //better this than a crash
+ Container *m_container = titem->container();
+ // We save the geometry of each wigdet
+ for(ObjectTreeItem *it = m_container->objectTree()->children()->first(); it; it = m_container->objectTree()->children()->next())
+ m_geometries.insert(it->name().latin1(), it->widget()->geometry());
+}
+
+void
+LayoutPropertyCommand::execute()
+{
+ PropertyCommand::execute();
+}
+
+void
+LayoutPropertyCommand::unexecute()
+{
+ ObjectTreeItem* titem = m_form->objectTree()->lookup(m_oldvalues.begin().key());
+ if (!titem)
+ return; //better this than a crash
+ Container *m_container = titem->container();
+ m_container->setLayout(Container::NoLayout);
+ // We put every widget back in its old location
+ QMap<QCString,QRect>::ConstIterator endIt = m_geometries.constEnd();
+ for(QMap<QCString,QRect>::ConstIterator it = m_geometries.constBegin(); it != endIt; ++it)
+ {
+ ObjectTreeItem *tree = m_container->form()->objectTree()->lookup(it.key());
+ if(tree)
+ tree->widget()->setGeometry(it.data());
+ }
+
+ PropertyCommand::unexecute();
+}
+
+QString
+LayoutPropertyCommand::name() const
+{
+ return i18n("Change layout of widget \"%1\"").arg(m_oldvalues.begin().key());
+}
+
+void
+LayoutPropertyCommand::debug()
+{
+ kdDebug() << "LayoutPropertyCommand: name=\"" << name() << "\" oldValue=" << m_oldvalues.keys()
+ << " value=" << m_value << endl;
+}
+
+// InsertWidgetCommand
+
+InsertWidgetCommand::InsertWidgetCommand(Container *container)
+ : Command()
+{
+ m_containername = container->widget()->name();
+ m_form = container->form();
+ m_class = FormManager::self()->selectedClass();
+ m_insertRect = container->m_insertRect;
+ m_point = container->m_insertBegin;
+ m_name = container->form()->objectTree()->generateUniqueName(
+ container->form()->library()->namePrefix(m_class).latin1(),
+ /*!numberSuffixRequired*/false);
+}
+
+InsertWidgetCommand::InsertWidgetCommand(Container *container,
+ const QCString& className, const QPoint& pos, const QCString& namePrefix)
+ : Command()
+{
+ m_containername = container->widget()->name();
+ m_form = container->form();
+ m_class = className;
+ //m_insertRect is null (default)
+ m_point = pos;
+ if (namePrefix.isEmpty()) {
+ m_name = container->form()->objectTree()->generateUniqueName(
+ container->form()->library()->namePrefix(m_class).latin1() );
+ }
+ else {
+ m_name = container->form()->objectTree()->generateUniqueName(
+ namePrefix, false /*!numberSuffixRequired*/ );
+ }
+}
+
+void
+InsertWidgetCommand::execute()
+{
+ if (!m_form->objectTree())
+ return;
+ ObjectTreeItem* titem = m_form->objectTree()->lookup(m_containername);
+ if (!titem)
+ return; //better this than a crash
+ Container *m_container = titem->container();
+ int options = WidgetFactory::DesignViewMode | WidgetFactory::AnyOrientation;
+ if (m_container->form()->library()->internalProperty(m_class, "orientationSelectionPopup")=="1") {
+ if(m_insertRect.isValid()) {
+ if (m_insertRect.width() < m_insertRect.height()) {
+ options |= WidgetFactory::VerticalOrientation;
+ options ^= WidgetFactory::AnyOrientation;
+ }
+ else if (m_insertRect.width() > m_insertRect.height()) {
+ options |= WidgetFactory::HorizontalOrientation;
+ options ^= WidgetFactory::AnyOrientation;
+ }
+ }
+ if (options & WidgetFactory::AnyOrientation) {
+ options ^= WidgetFactory::AnyOrientation;
+ options |= m_container->form()->library()->showOrientationSelectionPopup(
+ m_class, m_container->m_container,
+ m_container->form()->widget()->mapToGlobal(m_point));
+ if (options & WidgetFactory::AnyOrientation)
+ return; //cancelled
+ }
+ }
+ else
+ options |= WidgetFactory::AnyOrientation;
+
+ QWidget *w = m_container->form()->library()->createWidget(m_class, m_container->m_container, m_name,
+ m_container, options);
+
+ if(!w) {
+ FormManager::self()->stopInsert();
+ WidgetInfo *winfo = m_container->form()->library()->widgetInfoForClassName(m_class);
+ KMessageBox::sorry(FormManager::self()->activeForm() ? FormManager::self()->activeForm()->widget() : 0,
+ i18n("Could not insert widget of type \"%1\". A problem with widget's creation encountered.")
+ .arg(winfo ? winfo->name() : QString::null));
+ kdWarning() << "InsertWidgetCommand::execute() ERROR: widget creation failed" << endl;
+ return;
+ }
+#if KDE_VERSION >= KDE_MAKE_VERSION(3,4,0)
+//! @todo allow setting this for data view mode as well
+ if (m_form->designMode()) {
+ //don't generate accelerators for widgets in design mode
+ KAcceleratorManager::setNoAccel(w);
+ }
+#endif
+
+ // if the insertRect is invalid (ie only one point), we use widget' size hint
+ if(( (m_insertRect.width() < 21) && (m_insertRect.height() < 21)))
+ {
+ QSize s = w->sizeHint();
+
+ if(s.isEmpty())
+ s = QSize(20, 20); // Minimum size to avoid creating a (0,0) widget
+ int x, y;
+ if(m_insertRect.isValid())
+ {
+ x = m_insertRect.x();
+ y = m_insertRect.y();
+ }
+ else
+ {
+ x = m_point.x();
+ y = m_point.y();
+ }
+ m_insertRect = QRect(x, y, s.width() + 16/* add some space so more text can be entered*/,
+ s.height());
+ }
+ w->move(m_insertRect.x(), m_insertRect.y());
+ w->resize(m_insertRect.width()-1, m_insertRect.height()-1); // -1 is not to hide dots
+ w->setStyle(&(m_container->widget()->style()));
+ w->setBackgroundOrigin(QWidget::ParentOrigin);
+ w->show();
+
+ FormManager::self()->stopInsert();
+
+ // ObjectTreeItem object already exists for widgets which corresponds to a Container
+ // it's already created in Container's constructor
+ ObjectTreeItem *item = m_container->form()->objectTree()->lookup(m_name);
+ if (!item) { //not yet created...
+ m_container->form()->objectTree()->addItem(m_container->m_tree,
+ item = new ObjectTreeItem(m_container->form()->library()->displayName(m_class), m_name, w, m_container)
+ );
+ }
+ //assign item for its widget if it supports DesignTimeDynamicChildWidgetHandler interface
+ //(e.g. KexiDBAutoField)
+ if (m_form->designMode() && dynamic_cast<DesignTimeDynamicChildWidgetHandler*>(w)) {
+ dynamic_cast<DesignTimeDynamicChildWidgetHandler*>(w)->assignItem(item);
+ }
+
+ // We add the autoSaveProperties in the modifProp list of the ObjectTreeItem, so that they are saved later
+ QValueList<QCString> list(m_container->form()->library()->autoSaveProperties(w->className()));
+
+ QValueList<QCString>::ConstIterator endIt = list.constEnd();
+ for(QValueList<QCString>::ConstIterator it = list.constBegin(); it != endIt; ++it)
+ item->addModifiedProperty(*it, w->property(*it));
+
+ m_container->reloadLayout(); // reload the layout to take the new wigdet into account
+
+ m_container->setSelectedWidget(w, false);
+ if (m_container->form()->library()->internalProperty(w->className(),
+ "dontStartEditingOnInserting").isEmpty())
+ {
+ m_container->form()->library()->startEditing(
+ w->className(), w, item->container() ? item->container() : m_container); // we edit the widget on creation
+ }
+//! @todo update widget's width for entered text's metrics
+ kdDebug() << "Container::eventFilter(): widget added " << this << endl;
+}
+
+void
+InsertWidgetCommand::unexecute()
+{
+ ObjectTreeItem* titem = m_form->objectTree()->lookup(m_name);
+ if (!titem)
+ return; //better this than a crash
+ QWidget *m_widget = titem->widget();
+ Container *m_container = m_form->objectTree()->lookup(m_containername)->container();
+ m_container->deleteWidget(m_widget);
+}
+
+QString
+InsertWidgetCommand::name() const
+{
+ if(!m_name.isEmpty())
+ return i18n("Insert widget \"%1\"").arg(m_name);
+ else
+ return i18n("Insert widget");
+}
+
+void
+InsertWidgetCommand::debug()
+{
+ kdDebug() << "InsertWidgetCommand: name=\"" << name() << "\" generatedName=" << m_name
+ << " container=" << m_containername
+ << " form=" << m_form->widget()->name() << " class=" << m_class
+ << " rect=" << m_insertRect << " pos=" << m_point << endl;
+}
+
+/// CreateLayoutCommand ///////////////
+
+CreateLayoutCommand::CreateLayoutCommand(int layoutType, WidgetList &list, Form *form)
+ : m_form(form), m_type(layoutType)
+{
+ WidgetList *m_list=0;
+ switch(layoutType)
+ {
+ case Container::HBox:
+ case Container::Grid:
+ case Container::HSplitter:
+ case Container::HFlow:
+ m_list = new HorWidgetList(form->toplevelContainer()->widget()); break;
+ case Container::VBox:
+ case Container::VSplitter:
+ case Container::VFlow:
+ m_list = new VerWidgetList(form->toplevelContainer()->widget()); break;
+ }
+ for(QWidget *w = list.first(); w; w = list.next())
+ m_list->append(w);
+ m_list->sort(); // we sort them now, before creating the layout
+
+ for(QWidget *w = m_list->first(); w; w = m_list->next())
+ m_pos.insert(w->name(), w->geometry());
+ ObjectTreeItem *item = form->objectTree()->lookup(m_list->first()->name());
+ if(item && item->parent()->container())
+ m_containername = item->parent()->name();
+ delete m_list;
+}
+
+void
+CreateLayoutCommand::execute()
+{
+ WidgetLibrary *lib = m_form->library();
+ if(!lib)
+ return;
+ ObjectTreeItem* titem = m_form->objectTree()->lookup(m_containername);
+ Container *container = titem ? titem->container() : 0;
+ if(!container)
+ container = m_form->toplevelContainer(); // use toplevelContainer by default
+
+ QCString classname;
+ switch(m_type) {
+ case Container::HSplitter: case Container::VSplitter:
+ classname = "QSplitter"; break;
+ default:
+ classname = Container::layoutTypeToString(m_type).latin1();
+ }
+
+ if(m_name.isEmpty())// the name must be generated only once
+ m_name = m_form->objectTree()->generateUniqueName(classname);
+
+ QWidget *w = lib->createWidget(classname, container->widget(), m_name.latin1(), container);
+#if KDE_VERSION >= KDE_MAKE_VERSION(3,4,0)
+//! @todo allow setting this for data view mode as well
+ if (w) {
+ if (m_form->designMode()) {
+ //don't generate accelerators for widgets in design mode
+ KAcceleratorManager::setNoAccel(w);
+ }
+ }
+#endif
+ ObjectTreeItem *tree = w ? m_form->objectTree()->lookup(w->name()) : 0;
+ if(!tree)
+ return;
+
+ container->setSelectedWidget(0, false);
+ w->move(m_pos.begin().data().topLeft()); // we move the layout at the position of the topleft widget
+ // sizeHint of these widgets depends on geometry, so give them appropriate geometry
+ if(m_type == Container::HFlow)
+ w->resize( QSize(700, 20) );
+ else if(m_type == Container::VFlow)
+ w->resize( QSize(20, 700));
+ w->show();
+
+ // We reparent every widget to the Layout and insert them into it
+ QMap<QCString,QRect>::ConstIterator endIt = m_pos.constEnd();
+ for(QMap<QCString,QRect>::ConstIterator it = m_pos.constBegin(); it != endIt; ++it)
+ {
+ ObjectTreeItem *item = m_form->objectTree()->lookup(it.key());
+ if(item && item->widget())
+ {
+ item->widget()->reparent(w, item->widget()->pos(), true);
+ item->eventEater()->setContainer(tree->container());
+ m_form->objectTree()->reparent(item->name(), m_name);
+ }
+ }
+
+ if(m_type == Container::HSplitter)
+ ((QSplitter*)w)->setOrientation(QSplitter::Horizontal);
+ else if(m_type == Container::VSplitter)
+ ((QSplitter*)w)->setOrientation(QSplitter::Vertical);
+ else if(tree->container()) {
+ tree->container()->setLayout((Container::LayoutType)m_type);
+ w->resize(tree->container()->layout()->sizeHint()); // the layout doesn't have its own size
+ }
+
+ container->setSelectedWidget(w, false);
+ FormManager::self()->windowChanged(m_form->widget()); // to reload the ObjectTreeView
+}
+
+void
+CreateLayoutCommand::unexecute()
+{
+ ObjectTreeItem *parent = m_form->objectTree()->lookup(m_containername);
+ if(!parent)
+ parent = m_form->objectTree();
+
+ // We reparent every widget to the Container and take them out of the layout
+ QMap<QCString,QRect>::ConstIterator endIt = m_pos.constEnd();
+ for(QMap<QCString,QRect>::ConstIterator it = m_pos.constBegin(); it != endIt; ++it)
+ {
+ ObjectTreeItem *item = m_form->objectTree()->lookup(it.key());
+ if(item && item->widget())
+ {
+ item->widget()->reparent(parent->widget(), QPoint(0,0), true);
+ item->eventEater()->setContainer(parent->container());
+ if(m_pos[it.key()].isValid())
+ item->widget()->setGeometry(m_pos[it.key()]);
+ m_form->objectTree()->reparent(item->name(), m_containername);
+ }
+ }
+
+ if(!parent->container())
+ return;
+ ObjectTreeItem* titem = m_form->objectTree()->lookup(m_name);
+ if (!titem)
+ return; //better this than a crash
+ QWidget *w = titem->widget();
+ parent->container()->deleteWidget(w); // delete the layout widget
+ FormManager::self()->windowChanged(m_form->widget()); // to reload ObjectTreeView
+}
+
+QString
+CreateLayoutCommand::name() const
+{
+ switch(m_type)
+ {
+ case Container::HBox:
+ return i18n("Group Widgets Horizontally");
+ case Container::VBox:
+ return i18n("Group Widgets Vertically");
+ case Container::Grid:
+ return i18n("Group Widgets in a Grid");
+ case Container::HSplitter:
+ return i18n("Group Widgets Horizontally in a Splitter");
+ case Container::VSplitter:
+ return i18n("Group Widgets Vertically in a Splitter");
+ case Container::HFlow:
+ return i18n("Group Widgets By Rows");
+ case Container::VFlow:
+ return i18n("Group Widgets Vertically By Columns");
+ default:
+ return i18n("Group widgets");
+ }
+}
+
+void
+CreateLayoutCommand::debug()
+{
+ kdDebug() << "CreateLayoutCommand: name=\"" << name() << "\" generatedName=" << m_name
+ << " widgets=" << m_pos.keys() << " container=" << m_containername
+ << " form=" << m_form->widget()->name() << endl;
+}
+
+/// BreakLayoutCommand ///////////////
+
+BreakLayoutCommand::BreakLayoutCommand(Container *container)
+ : CreateLayoutCommand()
+{
+ m_containername = container->toplevel()->widget()->name();
+ m_name = container->widget()->name();
+ m_form = container->form();
+ m_type = container->layoutType();
+
+ for(ObjectTreeItem *tree = container->objectTree()->children()->first(); tree; tree = container->objectTree()->children()->next())
+ {
+ QRect r(container->widget()->mapTo(container->widget()->parentWidget(), tree->widget()->pos()), tree->widget()->size());
+ m_pos.insert(tree->widget()->name(), r);
+ }
+}
+
+void
+BreakLayoutCommand::execute()
+{
+ CreateLayoutCommand::unexecute();
+}
+
+void
+BreakLayoutCommand::unexecute()
+{
+ CreateLayoutCommand::execute();
+}
+
+QString
+BreakLayoutCommand::name() const
+{
+ return i18n("Break Layout: \"%1\"").arg(m_name);
+}
+
+void
+BreakLayoutCommand::debug()
+{
+ kdDebug() << "BreakLayoutCommand: name=\"" << name()
+ << " widgets=" << m_pos.keys() << " container=" << m_containername
+ << " form=" << m_form->widget()->name() << endl;
+}
+
+// PasteWidgetCommand
+
+PasteWidgetCommand::PasteWidgetCommand(QDomDocument &domDoc, Container *container, const QPoint& p)
+ : m_point(p)
+{
+ m_data = domDoc.toCString();
+ m_containername = container->widget()->name();
+ m_form = container->form();
+
+ if(domDoc.namedItem("UI").firstChild().nextSibling().toElement().tagName() != "widget")
+ return;
+
+ QRect boundingRect;
+ for(QDomNode n = domDoc.namedItem("UI").firstChild(); !n.isNull(); n = n.nextSibling()) // more than one widget
+ {
+ if(n.toElement().tagName() != "widget")
+ continue;
+ QDomElement el = n.toElement();
+
+ QDomElement rect;
+ for(QDomNode n = el.firstChild(); !n.isNull(); n = n.nextSibling())
+ {
+ if((n.toElement().tagName() == "property") && (n.toElement().attribute("name") == "geometry"))
+ rect = n.firstChild().toElement();
+ }
+
+ QDomElement x = rect.namedItem("x").toElement();
+ QDomElement y = rect.namedItem("y").toElement();
+ QDomElement wi = rect.namedItem("width").toElement();
+ QDomElement h = rect.namedItem("height").toElement();
+
+ int rx = x.text().toInt();
+ int ry = y.text().toInt();
+ int rw = wi.text().toInt();
+ int rh = h.text().toInt();
+ QRect r(rx, ry, rw, rh);
+ boundingRect = boundingRect.unite(r);
+ }
+
+ m_point = m_point - boundingRect.topLeft();
+}
+
+void
+PasteWidgetCommand::execute()
+{
+ ObjectTreeItem* titem = m_form->objectTree()->lookup(m_containername);
+ if (!titem)
+ return; //better this than a crash
+ Container *container = titem->container();
+ QString errMsg;
+ int errLine;
+ int errCol;
+ QDomDocument domDoc("UI");
+ bool parsed = domDoc.setContent(m_data, false, &errMsg, &errLine, &errCol);
+
+ if(!parsed)
+ {
+ kdDebug() << "WidgetWatcher::load(): " << errMsg << endl;
+ kdDebug() << "WidgetWatcher::load(): line: " << errLine << " col: " << errCol << endl;
+ return;
+ }
+
+ //FormIO::setCurrentForm(m_container->form());
+
+ kdDebug() << domDoc.toString() << endl;
+ if(!domDoc.namedItem("UI").hasChildNodes()) // nothing in the doc
+ return;
+ if(domDoc.namedItem("UI").firstChild().nextSibling().toElement().tagName() != "widget") // only one widget, so we can paste it at cursor pos
+ {
+ QDomElement el = domDoc.namedItem("UI").firstChild().toElement();
+ fixNames(el);
+ if(m_point.isNull())
+ fixPos(el, container);
+ else
+ changePos(el, m_point);
+
+ m_form->setInteractiveMode(false);
+ FormIO::loadWidget(container, el);
+ m_form->setInteractiveMode(true);
+ }
+ else for(QDomNode n = domDoc.namedItem("UI").firstChild(); !n.isNull(); n = n.nextSibling()) // more than one widget
+ {
+ if(n.toElement().tagName() != "widget")
+ continue;
+ QDomElement el = n.toElement();
+ fixNames(el);
+ if(!m_point.isNull())
+ moveWidgetBy(el, container, m_point);
+ else {
+ fixPos(el, container);
+ kdDebug() << "jdkjfldfksmfkdfjmqdsklfjdkkfmsqfksdfsm" << endl;
+ }
+
+ m_form->setInteractiveMode(false);
+ FormIO::loadWidget(container, el);
+ m_form->setInteractiveMode(true);
+ }
+
+ //FormIO::setCurrentForm(0);
+ m_names.clear();
+ // We store the names of all the created widgets, to delete them later
+ for(QDomNode n = domDoc.namedItem("UI").firstChild(); !n.isNull(); n = n.nextSibling())
+ {
+ if(n.toElement().tagName() != "widget")
+ continue;
+ for(QDomNode m = n.firstChild(); !m.isNull(); n = m.nextSibling())
+ {
+ if((m.toElement().tagName() == "property") && (m.toElement().attribute("name") == "name"))
+ {
+ m_names.append(m.toElement().text());
+ break;
+ }
+ }
+ }
+
+ container->form()->selectFormWidget();
+ QStringList::ConstIterator endIt = m_names.constEnd();
+ for(QStringList::ConstIterator it = m_names.constBegin(); it != endIt; ++it) // We select all the pasted widgets
+ {
+ ObjectTreeItem *item = m_form->objectTree()->lookup(*it);
+ if(item)
+ container->setSelectedWidget(item->widget(), true);
+ }
+}
+
+void
+PasteWidgetCommand::unexecute()
+{
+ ObjectTreeItem* titem = m_form->objectTree()->lookup(m_containername);
+ if (!titem)
+ return; //better this than a crash
+ Container *container = titem->container();
+ // We just delete all the widgets we have created
+ QStringList::ConstIterator endIt = m_names.constEnd();
+ for(QStringList::ConstIterator it = m_names.constBegin(); it != endIt; ++it)
+ {
+ ObjectTreeItem* titem = container->form()->objectTree()->lookup(*it);
+ if (!titem)
+ continue; //better this than a crash
+ QWidget *w = titem->widget();
+ container->deleteWidget(w);
+ }
+}
+
+QString
+PasteWidgetCommand::name() const
+{
+ return i18n("Paste");
+}
+
+void
+//QDomElement
+PasteWidgetCommand::changePos(QDomElement &el, const QPoint &newpos)
+{
+ //QDomElement el = widg.cloneNode(true).toElement();
+ QDomElement rect;
+ // Find the widget geometry if there is one
+ for(QDomNode n = el.firstChild(); !n.isNull(); n = n.nextSibling())
+ {
+ if((n.toElement().tagName() == "property") && (n.toElement().attribute("name") == "geometry"))
+ rect = n.firstChild().toElement();
+ }
+
+ QDomElement x = rect.namedItem("x").toElement();
+ x.removeChild(x.firstChild());
+ QDomText valueX = el.ownerDocument().createTextNode(QString::number(newpos.x()));
+ x.appendChild(valueX);
+
+ QDomElement y = rect.namedItem("y").toElement();
+ y.removeChild(y.firstChild());
+ QDomText valueY = el.ownerDocument().createTextNode(QString::number(newpos.y()));
+ y.appendChild(valueY);
+
+ //return el;
+}
+
+void
+PasteWidgetCommand::fixPos(QDomElement &el, Container *container)
+{
+/* QDomElement rect;
+ for(QDomNode n = el.firstChild(); !n.isNull(); n = n.nextSibling())
+ {
+ if((n.toElement().tagName() == "property") && (n.toElement().attribute("name") == "geometry"))
+ rect = n.firstChild().toElement();
+ }
+
+ QDomElement x = rect.namedItem("x").toElement();
+ QDomElement y = rect.namedItem("y").toElement();
+ QDomElement wi = rect.namedItem("width").toElement();
+ QDomElement h = rect.namedItem("height").toElement();
+
+ int rx = x.text().toInt();
+ int ry = y.text().toInt();
+ int rw = wi.text().toInt();
+ int rh = h.text().toInt();
+ QRect r(rx, ry, rw, rh);
+
+ QWidget *w = m_form->widget()->childAt(r.x() + 6, r.y() + 6, false);
+ if(!w)
+ return;
+
+ while((w->geometry() == r) && (w != 0))// there is already a widget there, with the same size
+ {
+ w = m_form->widget()->childAt(w->x() + 16, w->y() + 16, false);
+ r.moveBy(10,10);
+ }
+
+ // the pasted wigdet should stay inside container's boundaries
+ if(r.x() < 0)
+ r.moveLeft(0);
+ else if(r.right() > container->widget()->width())
+ r.moveLeft(container->widget()->width() - r.width());
+
+ if(r.y() < 0)
+ r.moveTop(0);
+ else if(r.bottom() > container->widget()->height())
+ r.moveTop(container->widget()->height() - r.height());
+
+ if(r != QRect(rx, ry, rw, rh))
+ //return el;
+ //else
+ changePos(el, QPoint(r.x(), r.y()));
+*/
+ moveWidgetBy(el, container, QPoint(0, 0));
+}
+
+void
+PasteWidgetCommand::moveWidgetBy(QDomElement &el, Container *container, const QPoint &p)
+{
+ QDomElement rect;
+ for(QDomNode n = el.firstChild(); !n.isNull(); n = n.nextSibling())
+ {
+ if((n.toElement().tagName() == "property") && (n.toElement().attribute("name") == "geometry"))
+ rect = n.firstChild().toElement();
+ }
+
+ QDomElement x = rect.namedItem("x").toElement();
+ QDomElement y = rect.namedItem("y").toElement();
+ QDomElement wi = rect.namedItem("width").toElement();
+ QDomElement h = rect.namedItem("height").toElement();
+
+ int rx = x.text().toInt();
+ int ry = y.text().toInt();
+ int rw = wi.text().toInt();
+ int rh = h.text().toInt();
+ QRect r(rx + p.x(), ry + p.y(), rw, rh);
+ kdDebug() << "Moving widget by " << p << " from " << rx << " " << ry << " to " << r.topLeft() << endl;
+
+ QWidget *w = m_form->widget()->childAt(r.x() + 6, r.y() + 6, false);
+
+ while(w && (w->geometry() == r))// there is already a widget there, with the same size
+ {
+ w = m_form->widget()->childAt(w->x() + 16, w->y() + 16, false);
+ r.moveBy(10,10);
+ }
+
+ // the pasted wigdet should stay inside container's boundaries
+ if(r.x() < 0)
+ r.moveLeft(0);
+ else if(r.right() > container->widget()->width())
+ r.moveLeft(container->widget()->width() - r.width());
+
+ if(r.y() < 0)
+ r.moveTop(0);
+ else if(r.bottom() > container->widget()->height())
+ r.moveTop(container->widget()->height() - r.height());
+
+ if(r != QRect(rx, ry, rw, rh))
+ //return el;
+ //else
+ changePos(el, QPoint(r.x(), r.y()));
+}
+
+void
+PasteWidgetCommand::fixNames(QDomElement &el)
+{
+ QString wname;
+ for(QDomNode n = el.firstChild(); !n.isNull(); n = n.nextSibling())
+ {
+ if((n.toElement().tagName() == "property") && (n.toElement().attribute("name") == "name"))
+ {
+ wname = n.toElement().text();
+ while(m_form->objectTree()->lookup(wname)) // name already exists
+ {
+ bool ok;
+ int num = wname.right(1).toInt(&ok, 10);
+ if(ok)
+ wname = wname.left(wname.length()-1) + QString::number(num+1);
+ else
+ wname += "2";
+ }
+ if(wname != n.toElement().text()) // we change the name, so we recreate the element
+ {
+ n.removeChild(n.firstChild());
+ QDomElement type = el.ownerDocument().createElement("string");
+ QDomText valueE = el.ownerDocument().createTextNode(wname);
+ type.appendChild(valueE);
+ n.toElement().appendChild(type);
+ }
+
+ }
+ if(n.toElement().tagName() == "widget") // fix child widgets names
+ {
+ QDomElement child = n.toElement();
+ fixNames(child);
+ }
+ }
+}
+
+void
+PasteWidgetCommand::debug()
+{
+ kdDebug() << "PasteWidgetCommand: pos=" << m_point
+ << " widgets=" << m_names << " container=" << m_containername
+ << " form=" << m_form->widget()->name()
+ << " data=\"" << m_data.left(80) << "...\"" << endl;
+}
+
+// DeleteWidgetCommand
+
+DeleteWidgetCommand::DeleteWidgetCommand(WidgetList &list, Form *form)
+ : Command(), m_form(form)
+{
+ m_domDoc = QDomDocument("UI");
+ m_domDoc.appendChild(m_domDoc.createElement("UI"));
+
+ QDomElement parent = m_domDoc.namedItem("UI").toElement();
+
+ //for(QWidget *w = list.first(); w; w = list.next())
+ /*for(WidgetListIterator it(list); it.current() != 0; ++it)
+ {
+ QWidget *w = it.current();
+ // Don't delete tabwidget or widgetstack pages
+ if(w->parentWidget()->inherits("QWidgetStack"))
+ {
+ list.remove(w);
+ continue;
+ }
+ }*/
+ removeChildrenFromList(list);
+
+ for(WidgetListIterator it(list); it.current() != 0; ++it)
+ {
+ ObjectTreeItem *item = m_form->objectTree()->lookup(it.current()->name());
+ if (!item)
+ return;
+
+ // We need to store both parentContainer and parentWidget as they may be different (eg for TabWidget page)
+ m_containers.insert(item->name().latin1(), m_form->parentContainer(item->widget())->widget()->name());
+ m_parents.insert(item->name().latin1(), item->parent()->name().latin1());
+ FormIO::saveWidget(item, parent, m_domDoc);
+ form->connectionBuffer()->saveAllConnectionsForWidget(item->widget()->name(), m_domDoc);
+ }
+
+ FormIO::cleanClipboard(parent);
+}
+
+void
+DeleteWidgetCommand::execute()
+{
+ Container *containerToSelect = 0;
+
+ QMap<QCString,QCString>::ConstIterator endIt = m_containers.constEnd();
+ for(QMap<QCString,QCString>::ConstIterator it = m_containers.constBegin(); it != endIt; ++it)
+ {
+ ObjectTreeItem *item = m_form->objectTree()->lookup(it.key());
+ if (!item || !item->widget())
+ continue;
+
+ Container *cont = m_form->parentContainer(item->widget());
+ if (!containerToSelect)
+ containerToSelect = cont;
+ cont->deleteWidget(item->widget());
+ }
+ //now we've nothing selecte: select parent container
+ if (containerToSelect)
+ m_form->setSelectedWidget( containerToSelect->widget() );
+}
+
+void
+DeleteWidgetCommand::unexecute()
+{
+ QCString wname;
+ m_form->setInteractiveMode(false);
+ for(QDomNode n = m_domDoc.namedItem("UI").firstChild(); !n.isNull(); n = n.nextSibling())
+ {
+ if(n.toElement().tagName() == "connections") // restore the widget connections
+ m_form->connectionBuffer()->load(n);
+ if(n.toElement().tagName() != "widget")
+ continue;
+ // We need first to know the name of the widget
+ for(QDomNode m = n.firstChild(); !m.isNull(); n = m.nextSibling())
+ {
+ if((m.toElement().tagName() == "property") && (m.toElement().attribute("name") == "name"))
+ {
+ wname = m.toElement().text().latin1();
+ break;
+ }
+ }
+
+ ObjectTreeItem* titem = m_form->objectTree()->lookup(m_containers[wname]);
+ if (!titem)
+ return; //better this than a crash
+ Container *cont = titem->container();
+ ObjectTreeItem *parent = m_form->objectTree()->lookup(m_parents[wname]);
+ QDomElement widg = n.toElement();
+ if(parent)
+ FormIO::loadWidget(cont, widg, parent->widget());
+ else
+ FormIO::loadWidget(cont, widg);
+ }
+ m_form->setInteractiveMode(true);
+}
+
+QString
+DeleteWidgetCommand::name() const
+{
+ return i18n("Delete widget");
+}
+
+void
+DeleteWidgetCommand::debug()
+{
+ kdDebug() << "DeleteWidgetCommand: containers=" << m_containers.keys()
+ << " parents=" << m_parents.keys() << " form=" << m_form->widget()->name() << endl;
+}
+
+// CutWidgetCommand
+
+CutWidgetCommand::CutWidgetCommand(WidgetList &list, Form *form)
+ : DeleteWidgetCommand(list, form)
+{}
+
+void
+CutWidgetCommand::execute()
+{
+ DeleteWidgetCommand::execute();
+ m_data = FormManager::self()->m_domDoc.toCString();
+ FormManager::self()->m_domDoc.setContent(m_domDoc.toCString());
+}
+
+void
+CutWidgetCommand::unexecute()
+{
+ DeleteWidgetCommand::unexecute();
+ FormManager::self()->m_domDoc.setContent(m_data);
+}
+
+QString
+CutWidgetCommand::name() const
+{
+ return i18n("Cut");
+}
+
+void
+CutWidgetCommand::debug()
+{
+ kdDebug() << "CutWidgetCommand: containers=" << m_containers.keys()
+ << " parents=" << m_parents.keys() << " form=" << m_form->widget()->name()
+ << " data=\"" << m_data.left(80) << "...\"" << endl;
+}
+
+// CommandGroup
+
+namespace KFormDesigner {
+class CommandGroup::SubCommands : public KMacroCommand
+{
+ public:
+ SubCommands( const QString & name )
+ : KMacroCommand(name)
+ {
+ }
+ const QPtrList<KCommand>& commands() const { return m_commands; }
+};
+}
+
+CommandGroup::CommandGroup( const QString & name, WidgetPropertySet *propSet )
+ : Command()
+ , m_subCommands(new SubCommands(name))
+ , m_propSet(propSet)
+{
+}
+
+CommandGroup::~CommandGroup()
+{
+ delete m_subCommands;
+}
+
+const QPtrList<KCommand>& CommandGroup::commands() const
+{
+ return m_subCommands->commands();
+}
+
+void CommandGroup::addCommand(KCommand *command, bool allowExecute)
+{
+ if (!command)
+ return;
+
+ m_subCommands->addCommand(command);
+ if (!allowExecute)
+ m_commandsShouldntBeExecuted.insert(command, (char*)1);
+}
+
+void CommandGroup::execute()
+{
+ FormManager::self()->blockPropertyEditorUpdating(this);
+ for (QPtrListIterator<KCommand> it(m_subCommands->commands()); it.current(); ++it) {
+ if (!m_commandsShouldntBeExecuted[it.current()])
+ it.current()->execute();
+ }
+ FormManager::self()->unblockPropertyEditorUpdating(this, m_propSet);
+}
+
+void CommandGroup::unexecute()
+{
+ FormManager::self()->blockPropertyEditorUpdating(this);
+ m_subCommands->unexecute();
+ FormManager::self()->unblockPropertyEditorUpdating(this, m_propSet);
+}
+
+QString CommandGroup::name() const
+{
+ return m_subCommands->name();
+}
+
+void CommandGroup::resetAllowExecuteFlags()
+{
+ m_commandsShouldntBeExecuted.clear();
+}
+
+void
+CommandGroup::debug()
+{
+ kdDebug() << "*CommandGroup: name=\"" << name() << "\" #=" << m_subCommands->commands().count() << endl;
+ uint i = 1;
+ for (QPtrListIterator<KCommand> it(m_subCommands->commands()); it.current(); ++it, i++) {
+ kdDebug() << "#" << i << ":"
+ << (m_commandsShouldntBeExecuted[it.current()] ? "!" : "") << "allowExecute:" << endl;
+ if (dynamic_cast<Command*>(it.current()))
+ dynamic_cast<Command*>(it.current())->debug();
+ else if (dynamic_cast<CommandGroup*>(it.current()))
+ dynamic_cast<CommandGroup*>(it.current())->debug();
+ else
+ kdDebug() << "(other KCommand)" << endl;
+ }
+ kdDebug() << "End of CommandGroup" << endl;
+}
diff --git a/kexi/formeditor/commands.h b/kexi/formeditor/commands.h
new file mode 100644
index 00000000..619ef791
--- /dev/null
+++ b/kexi/formeditor/commands.h
@@ -0,0 +1,380 @@
+/* This file is part of the KDE project
+ Copyright (C) 2004 Cedric Pasteur <cedric.pasteur@free.fr>
+ Copyright (C) 2005 Jaroslaw Staniek <js@iidea.pl>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+*/
+
+#ifndef KFORMEDITOR_COMMANDS_H
+#define KFORMEDITOR_COMMANDS_H
+
+#include <qmap.h>
+#include <qdict.h>
+#include <qptrlist.h>
+#include <qptrdict.h>
+#include <qvariant.h>
+#include <qdom.h>
+
+#include <kcommand.h>
+#include "utils.h"
+
+class QWidget;
+class QRect;
+class QPoint;
+class QStringList;
+class QCString;
+
+namespace KFormDesigner {
+
+class WidgetPropertySet;
+class ObjectTreeItem;
+class Container;
+class Form;
+
+//! Base class for KFormDesigner's commands
+class KFORMEDITOR_EXPORT Command : public KCommand
+{
+ public:
+ Command();
+ virtual ~Command();
+
+ virtual void debug() = 0;
+};
+
+/*! This command is used when changing a property for one or more widgets. \a oldvalues is a QMap
+ of the old values of the property for every widget, to allow reverting the change. \a value is
+ the new value of the property. You can use the simpler constructor for a single widget.
+ */
+class KFORMEDITOR_EXPORT PropertyCommand : public Command
+{
+ public:
+ PropertyCommand(WidgetPropertySet *set, const QCString &wname, const QVariant &oldValue,
+ const QVariant &value, const QCString &property);
+ PropertyCommand(WidgetPropertySet *set, const QMap<QCString, QVariant> &oldvalues,
+ const QVariant &value, const QCString &property);
+
+ virtual void execute();
+ virtual void unexecute();
+ virtual QString name() const;
+ QCString property() const { return m_property; }
+
+ void setValue(const QVariant &value);
+ const QMap<QCString, QVariant>& oldValues() const { return m_oldvalues; }
+ virtual void debug();
+
+ protected:
+ WidgetPropertySet *m_propSet;
+ QVariant m_value;
+ QMap<QCString, QVariant> m_oldvalues;
+ QCString m_property;
+};
+
+/*! This command is used when moving multiples widgets at the same time, while holding Ctrl or Shift.
+ You need to supply a list of widget names, and the position of the cursor before moving. Use setPos()
+ to tell the new cursor pos every time it changes.*/
+class KFORMEDITOR_EXPORT GeometryPropertyCommand : public Command
+{
+ public:
+ GeometryPropertyCommand(WidgetPropertySet *set, const QStringList &names, const QPoint& oldPos);
+
+ virtual void execute();
+ virtual void unexecute();
+ virtual QString name() const;
+ void setPos(const QPoint& pos);
+ virtual void debug();
+
+ protected:
+ WidgetPropertySet *m_propSet;
+ QStringList m_names;
+ QPoint m_oldPos;
+ QPoint m_pos;
+};
+
+/*! This command is used when an item in 'Align Widgets position' is selected. You just need
+to give the list of widget names (the selected ones), and the
+ type of alignment (see the enum for possible values). */
+class KFORMEDITOR_EXPORT AlignWidgetsCommand : public Command
+{
+ public:
+ enum { AlignToGrid = 100, AlignToLeft, AlignToRight, AlignToTop, AlignToBottom };
+
+ AlignWidgetsCommand(int type, WidgetList &list, Form *form);
+
+ virtual void execute();
+ virtual void unexecute();
+ virtual QString name() const;
+ virtual void debug();
+
+ protected:
+ Form *m_form;
+ int m_type;
+ QMap<QCString, QPoint> m_pos;
+};
+
+/*! This command is used when an item in 'Adjust Widgets Size' is selected. You just need
+ to give the list of widget names (the selected ones), and the
+ type of size modification (see the enum for possible values). */
+class KFORMEDITOR_EXPORT AdjustSizeCommand : public Command
+{
+ public:
+ enum { SizeToGrid = 200, SizeToFit, SizeToSmallWidth, SizeToBigWidth,
+ SizeToSmallHeight, SizeToBigHeight };
+
+ AdjustSizeCommand(int type, WidgetList &list, Form *form);
+
+ virtual void execute();
+ virtual void unexecute();
+ virtual QString name() const;
+ virtual void debug();
+
+ protected:
+ QSize getSizeFromChildren(ObjectTreeItem *item);
+
+ protected:
+ Form *m_form;
+ int m_type;
+ QMap<QCString, QPoint> m_pos;
+ QMap<QCString, QSize> m_sizes;
+};
+
+/*! This command is used when switching the layout of a Container. It remembers the old pos
+ of every widget inside the Container. */
+class KFORMEDITOR_EXPORT LayoutPropertyCommand : public PropertyCommand
+{
+ public:
+ LayoutPropertyCommand(WidgetPropertySet *set, const QCString &wname,
+ const QVariant &oldValue, const QVariant &value);
+
+ virtual void execute();
+ virtual void unexecute();
+ virtual QString name() const;
+ virtual void debug();
+
+ protected:
+ Form *m_form;
+ QMap<QCString,QRect> m_geometries;
+};
+
+/*! This command is used when inserting a widger using toolbar or menu. You only need to give
+the parent Container and the widget pos.
+ The other information is taken from FormManager. */
+class KFORMEDITOR_EXPORT InsertWidgetCommand : public Command
+{
+ public:
+ InsertWidgetCommand(Container *container);
+
+ /*! This ctor allows to set explicit class name and position.
+ Used for dropping widgets on the form surface.
+ If \a namePrefix is empty, widget's unique name is constructed using
+ hint for \a className (WidgetLibrary::namePrefix()),
+ otherwise, \a namePrefix is used to generate widget's name.
+ This allows e.g. inserting a widgets having name constructed using
+ */
+ InsertWidgetCommand(Container *container, const QCString& className,
+ const QPoint& pos, const QCString& namePrefix = QCString());
+
+ virtual void execute();
+ virtual void unexecute();
+ virtual QString name() const;
+ virtual void debug();
+
+ //! \return inserted widget's name
+ QCString widgetName() const { return m_name; }
+
+ protected:
+ Form *m_form;
+ QString m_containername;
+ QPoint m_point;
+ QCString m_name;
+ QCString m_class;
+ QRect m_insertRect;
+};
+
+/*! This command is used when creating a layout from some widgets using "Lay out in..." menu item.
+ It remembers the old pos of every widget, and takes care of updating ObjectTree too. You need
+ to supply a WidgetList of the selected widgets. */
+class KFORMEDITOR_EXPORT CreateLayoutCommand : public Command
+{
+ public:
+ CreateLayoutCommand(int layoutType, WidgetList &list, Form *form);
+ CreateLayoutCommand() {;} // for BreakLayoutCommand
+
+ virtual void execute();
+ virtual void unexecute();
+ virtual QString name() const;
+ virtual void debug();
+
+ protected:
+ Form *m_form;
+ QString m_containername;
+ QString m_name;
+ QMap<QCString,QRect> m_pos;
+ int m_type;
+};
+
+/*! This command is used when the 'Break Layout' menu item is selected. It does exactly the
+ opposite of CreateLayoutCommand. */
+class KFORMEDITOR_EXPORT BreakLayoutCommand : public CreateLayoutCommand
+{
+ public:
+ BreakLayoutCommand(Container *container);
+
+ virtual void execute();
+ virtual void unexecute();
+ virtual QString name() const;
+ virtual void debug();
+};
+
+/*! This command is used when pasting widgets. You need to give the QDomDocument containing
+the widget(s) to paste, and optionnally the point where to paste widgets. */
+class KFORMEDITOR_EXPORT PasteWidgetCommand : public Command
+{
+ public:
+ PasteWidgetCommand(QDomDocument &domDoc, Container *container, const QPoint& p = QPoint());
+
+ virtual void execute();
+ virtual void unexecute();
+ virtual QString name() const;
+ virtual void debug();
+
+ protected:
+ /*! Internal function used to change the coordinates of a widget to \a newpos
+ before pasting it (to paste it at the position of the contextual menu). It modifies
+ the "geometry" property of the QDomElement representing the widget. */
+ void changePos(QDomElement &widg, const QPoint &newpos);
+ /*! Internal function used to fix the coordinates of a widget before pasting it
+ (to avoid having two widgets at the same position). It moves the widget by
+ (10, 10) increment (several times if there are already pasted widgets at this position). */
+ void fixPos(QDomElement &el, Container *container);
+ void moveWidgetBy(QDomElement &el, Container *container, const QPoint &p);
+ /*! Internal function used to fix the names of the widgets before pasting them.
+ It prevents from pasting a widget with
+ the same name as an actual widget. The child widgets are also fixed recursively.\n
+ If the name of the widget ends with a number (eg "QLineEdit1"), the new name is
+ just incremented by one (eg becomes "QLineEdit2"). Otherwise, a "2" is just
+ appended at the end of the name (eg "myWidget" becomes "myWidget2"). */
+ void fixNames(QDomElement &el);
+
+ protected:
+ Form *m_form;
+ QCString m_data;
+ QString m_containername;
+ QPoint m_point;
+ QStringList m_names;
+};
+
+/*! This command is used when deleting a widget using the "Delete" menu item.
+You need to give a WidgetList of the selected widgets. */
+class KFORMEDITOR_EXPORT DeleteWidgetCommand : public Command
+{
+ public:
+ DeleteWidgetCommand(WidgetList &list, Form *form);
+
+ virtual void execute();
+ virtual void unexecute();
+ virtual QString name() const;
+ virtual void debug();
+
+ protected:
+ QDomDocument m_domDoc;
+ Form *m_form;
+ QMap<QCString, QCString> m_containers;
+ QMap<QCString, QCString> m_parents;
+};
+
+/*! This command is used when cutting widgets. It is basically a DeleteWidgetCommand
+which also updates the clipboard contents. */
+class KFORMEDITOR_EXPORT CutWidgetCommand : public DeleteWidgetCommand
+{
+ public:
+ CutWidgetCommand(WidgetList &list, Form *form);
+
+ virtual void execute();
+ virtual void unexecute();
+ virtual QString name() const;
+ virtual void debug();
+
+ protected:
+ QCString m_data;
+};
+
+/*! A Command Group is a command that holds several subcommands.
+ It will appear as one to the user and in the command history,
+ but it can use the implementation of multiple commands internally.
+ It extends KMacroCommand by providing the list of commands executed.
+ Selected subcommands can be marked as nonexecutable by adding them using
+ addCommand(KCommand *command, bool allowExecute) special method.
+*/
+class KFORMEDITOR_EXPORT CommandGroup : public Command
+{
+ public:
+ CommandGroup( const QString & name, WidgetPropertySet *propSet );
+ virtual ~CommandGroup();
+
+ /*! Like KmacroCommand::addCommand(KCommand*)
+ but if \a allowExecute is false, \a command will not be executed
+ as a subcommand when CommandGroup::execute() is called.
+
+ This is useful e.g. in KexiFormView::insertAutoFields(),
+ where a number of subcommands of InsertWidgetCommand type and subcommands
+ is groupped using CommandGroup but some of these subcommands are executed
+ before executing CommandGroup::execute().
+
+ If \a allowExecute is true, this method behaves exactly like
+ KmacroCommand::addCommand(KCommand*).
+
+ Note that unexecute() doesn't check \a allowExecute flag:
+ all subcommands will be unexecuted (in reverse order
+ to the one in which they were added).
+ */
+ void addCommand(KCommand *command, bool allowExecute);
+
+ /*! Executes all subcommands added to this group
+ in the same order as they were added. Subcommands added with
+ addCommand(KCommand *command, bool allowExecute) where allowExecute == false,
+ will not be executed. */
+ virtual void execute();
+
+ /*! Unexecutes all subcommands added to this group,
+ (in reversed order). */
+ virtual void unexecute();
+
+ virtual QString name() const;
+
+ /*! \return a list of all subcommands of this group.
+ Note that if a given subcommand is a group itself,
+ it will not be expanded to subcommands on this list. */
+ const QPtrList<KCommand>& commands() const;
+
+ /*! Resets all 'allowExecute' flags that was set in addCommand().
+ Call this after calling CommandGroup::execute() to ensure that
+ in the future, when REDO is be executed, all subcommands will be executed. */
+ void resetAllowExecuteFlags();
+
+ virtual void debug();
+
+ protected:
+ class SubCommands;
+ SubCommands *m_subCommands;
+ //! Used to store pointers to subcommands that shouldn't be executed
+ //! on CommandGroup::execute()
+ QPtrDict<char> m_commandsShouldntBeExecuted;
+ WidgetPropertySet *m_propSet;
+};
+
+}
+
+#endif
diff --git a/kexi/formeditor/connectiondialog.cpp b/kexi/formeditor/connectiondialog.cpp
new file mode 100644
index 00000000..a40348e7
--- /dev/null
+++ b/kexi/formeditor/connectiondialog.cpp
@@ -0,0 +1,420 @@
+/* This file is part of the KDE project
+ Copyright (C) 2004 Cedric Pasteur <cedric.pasteur@free.fr>
+ Copyright (C) 2004 Jaroslaw Staniek <js@iidea.pl>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+*/
+
+#include <qlayout.h>
+#include <qhbox.h>
+#include <qlabel.h>
+#include <qregexp.h>
+#include <qmetaobject.h>
+#include <qstrlist.h>
+
+#include <kpushbutton.h>
+#include <kiconloader.h>
+#include <kmessagebox.h>
+#include <kdebug.h>
+#include <klocale.h>
+
+#include "kexitableview.h"
+#include "kexitableviewdata.h"
+#include "events.h"
+#include "form.h"
+#include "formmanager.h"
+#include "objecttree.h"
+
+#include "connectiondialog.h"
+
+namespace KFormDesigner {
+
+/////////////////////////////////////////////////////////////////////////////////
+///////////// The dialog to edit or add/remove connections //////////////////////
+/////////////////////////////////////////////////////////////////////////////////
+ConnectionDialog::ConnectionDialog(QWidget *parent)
+: KDialogBase(parent, "connections_dialog", true, i18n("Edit Form Connections"),
+ Ok|Cancel|Details, Ok, false)
+, m_buffer(0)
+{
+ QFrame *frame = makeMainWidget();
+ QHBoxLayout *layout = new QHBoxLayout(frame, 0, 6);
+
+ // Setup the details widget /////////
+ QHBox *details = new QHBox(frame);
+ setDetailsWidget(details);
+ setDetails(true);
+
+ m_pixmapLabel = new QLabel(details);
+ m_pixmapLabel->setFixedWidth( int(IconSize(KIcon::Desktop) * 1.5) );
+ m_pixmapLabel->setAlignment(AlignHCenter | AlignTop);
+
+ m_textLabel = new QLabel(details);
+ m_textLabel->setAlignment(AlignLeft | AlignTop);
+ //setStatusOk();
+
+ // And the KexiTableView ////////
+ m_data = new KexiTableViewData();
+ m_table = new KexiTableView(0, frame, "connections_tableview");
+ m_table->setSpreadSheetMode();
+ m_table->setInsertingEnabled(true);
+ initTable();
+ m_table->setData(m_data, false);
+ m_table->adjustColumnWidthToContents(0);
+ layout->addWidget(m_table);
+
+ //// Setup the icon toolbar /////////////////
+ QVBoxLayout *vlayout = new QVBoxLayout(layout, 3);
+ KPushButton *newItem = new KPushButton(SmallIconSet("filenew"), i18n("&New Connection"), frame);
+ vlayout->addWidget(newItem);
+ m_buttons.insert(BAdd, newItem);
+ connect(newItem, SIGNAL(clicked()), this, SLOT(newItem()));
+
+ KPushButton *delItem = new KPushButton(SmallIconSet("editdelete"), i18n("&Remove Connection"), frame);
+ vlayout->addWidget(delItem);
+ m_buttons.insert(BRemove, delItem);
+ connect(delItem, SIGNAL(clicked()), this, SLOT(removeItem()));
+
+ vlayout->addStretch();
+
+ setInitialSize(QSize(600, 300));
+ //setWFlags(WDestructiveClose);
+
+ connect(m_table,SIGNAL(cellSelected(int, int)), this, SLOT(slotCellSelected(int, int)));
+ connect(m_table->data(), SIGNAL(rowInserted(KexiTableItem*,bool)), this, SLOT(slotRowInserted(KexiTableItem*,bool)));
+ this->newItem();
+}
+
+void
+ConnectionDialog::initTable()
+{
+ KexiTableViewColumn *col0 = new KexiTableViewColumn(i18n("OK?"), KexiDB::Field::Text);
+ col0->field()->setSubType("KIcon");
+ col0->setReadOnly(true);
+ col0->field()->setDescription(i18n("Connection correctness"));
+ m_data->addColumn(col0);
+
+ KexiTableViewColumn *col1 = new KexiTableViewColumn(i18n("Sender"), KexiDB::Field::Enum);
+ m_widgetsColumnData = new KexiTableViewData(KexiDB::Field::Text, KexiDB::Field::Text);
+ col1->setRelatedData( m_widgetsColumnData );
+ m_data->addColumn(col1);
+
+ KexiTableViewColumn *col2 = new KexiTableViewColumn(i18n("Signal"), KexiDB::Field::Enum);
+ m_signalsColumnData = new KexiTableViewData(KexiDB::Field::Text, KexiDB::Field::Text);
+ col2->setRelatedData( m_signalsColumnData );
+ m_data->addColumn(col2);
+
+ KexiTableViewColumn *col3 = new KexiTableViewColumn(i18n("Receiver"), KexiDB::Field::Enum);
+ col3->setRelatedData( m_widgetsColumnData );
+ m_data->addColumn(col3);
+
+ KexiTableViewColumn *col4 = new KexiTableViewColumn(i18n("Slot"), KexiDB::Field::Enum);
+ m_slotsColumnData = new KexiTableViewData(KexiDB::Field::Text, KexiDB::Field::Text);
+ col4->setRelatedData( m_slotsColumnData );
+ m_data->addColumn(col4);
+
+ QValueList<int> c;
+ c << 2 << 4;
+ m_table->maximizeColumnsWidth(c);
+ m_table->setColumnStretchEnabled( true, 4 );
+
+ connect(m_data, SIGNAL(aboutToChangeCell(KexiTableItem*, int, QVariant&, KexiDB::ResultInfo*)),
+ this,SLOT(slotCellChanged(KexiTableItem*, int, QVariant, KexiDB::ResultInfo*)));
+ connect(m_data, SIGNAL(rowUpdated(KexiTableItem*)), this, SLOT(checkConnection(KexiTableItem *)));
+ connect(m_table, SIGNAL(itemSelected(KexiTableItem *)), this, SLOT(checkConnection(KexiTableItem *)));
+}
+
+void
+ConnectionDialog::exec(Form *form)
+{
+ m_form = form;
+ updateTableData();
+
+ KDialogBase::exec();
+}
+
+void ConnectionDialog::slotCellSelected(int col, int row)
+{
+ m_buttons[BRemove]->setEnabled( row < m_table->rows() );
+ KexiTableItem *item = m_table->itemAt(row);
+ if (!item)
+ return;
+ if(col == 2) // signal col
+ updateSignalList(item);
+ else if(col == 4) // slot col
+ updateSlotList(item);
+}
+
+void ConnectionDialog::slotRowInserted(KexiTableItem* item,bool)
+{
+ m_buffer->append(new Connection());
+ checkConnection( item );
+}
+
+void
+ConnectionDialog::slotOk()
+{
+ // First we update our buffer contents
+ for(int i=0; i < m_table->rows(); i++)
+ {
+ KexiTableItem *item = m_table->itemAt(i);
+ Connection *c = m_buffer->at(i);
+
+ c->setSender( (*item)[1].toString() );
+ c->setSignal( (*item)[2].toString() );
+ c->setReceiver( (*item)[3].toString() );
+ c->setSlot( (*item)[4].toString() );
+ }
+
+ // then me make it replace form's current one
+ delete m_form->connectionBuffer();
+ m_form->setConnectionBuffer(m_buffer);
+
+ QDialog::accept();
+}
+
+void
+ConnectionDialog::updateTableData()
+{
+ // First we update the columns data
+ ObjectTreeDict *dict = new ObjectTreeDict( *(m_form->objectTree()->dict()) );
+ ObjectTreeDictIterator it(*dict);
+ for(; it.current(); ++it)
+ {
+ KexiTableItem *item = m_widgetsColumnData->createItem(); //new KexiTableItem(2);
+ (*item)[0] = it.current()->name();
+ (*item)[1] = (*item)[0];
+ m_widgetsColumnData->append(item);
+ }
+ delete dict;
+
+ // Then we fill the columns with the form connections
+ for(Connection *c = m_form->connectionBuffer()->first(); c ; c = m_form->connectionBuffer()->next())
+ {
+ KexiTableItem *item = m_table->data()->createItem(); //new KexiTableItem(5);
+ (*item)[1] = c->sender();
+ (*item)[2] = c->signal();
+ (*item)[3] = c->receiver();
+ (*item)[4] = c->slot();
+ m_table->insertItem(item, m_table->rows());
+ }
+
+ m_buffer = new ConnectionBuffer(*(m_form->connectionBuffer()));
+}
+
+void
+ConnectionDialog::setStatusOk(KexiTableItem *item)
+{
+ m_pixmapLabel->setPixmap( DesktopIcon("button_ok") );
+ m_textLabel->setText("<qt><h2>The connection is OK.</h2></qt>");
+
+ if (!item)
+ item = m_table->selectedItem();
+ if (m_table->currentRow() >= m_table->rows())
+ item = 0;
+
+ if (item)
+ (*item)[0] = "button_ok";
+ else {
+ m_pixmapLabel->setPixmap( QPixmap() );
+ m_textLabel->setText(QString::null);
+ }
+}
+
+void
+ConnectionDialog::setStatusError(const QString &msg, KexiTableItem *item)
+{
+ m_pixmapLabel->setPixmap( DesktopIcon("button_cancel") );
+ m_textLabel->setText("<qt><h2>The connection is invalid.</h2></qt>" + msg);
+
+ if (!item)
+ item = m_table->selectedItem();
+ if (m_table->currentRow() >= m_table->rows())
+ item = 0;
+
+ if (item)
+ (*item)[0] = "button_cancel";
+ else {
+ m_pixmapLabel->setPixmap( QPixmap() );
+ m_textLabel->setText(QString::null);
+ }
+}
+
+void
+ConnectionDialog::slotCellChanged(KexiTableItem *item, int col, QVariant&, KexiDB::ResultInfo*)
+{
+ switch(col)
+ {
+ // sender changed, we clear siganl and slot
+ case 1:
+ (*item)[2] = QString("");
+ // signal or receiver changed, we clear the slot cell
+ case 2:
+ case 3:
+ {
+ (*item)[4] = QString("");
+ break;
+ }
+ default:
+ break;
+ }
+}
+
+void
+ConnectionDialog::updateSlotList(KexiTableItem *item)
+{
+ m_slotsColumnData->deleteAllRows();
+ QString widget = (*item)[1].toString();
+ QString signal = (*item)[2].toString();
+
+ if((widget.isEmpty()) || signal.isEmpty())
+ return;
+ ObjectTreeItem *tree = m_form->objectTree()->lookup(widget);
+ if(!tree || !tree->widget())
+ return;
+
+ QString signalArg(signal);
+ signalArg = signalArg.remove( QRegExp(".*[(]|[)]") );
+
+ QStrList slotList = tree->widget()->metaObject()->slotNames(true);
+ QStrListIterator it(slotList);
+ for(; it.current() != 0; ++it)
+ {
+ // we add the slot only if it is compatible with the signal
+ QString slotArg(*it);
+ slotArg = slotArg.remove( QRegExp(".*[(]|[)]") );
+
+ if(!signalArg.startsWith(slotArg, true) && (!signal.isEmpty())) // args not compatible
+ continue;
+
+ KexiTableItem *item = m_slotsColumnData->createItem(); //new KexiTableItem(2);
+ (*item)[0] = QString(*it);
+ (*item)[1] = (*item)[0];
+ m_slotsColumnData->append(item);
+ }
+}
+
+void
+ConnectionDialog::updateSignalList(KexiTableItem *item)
+{
+ ObjectTreeItem *tree = m_form->objectTree()->lookup((*item)[1].toString());
+ if(!tree || !tree->widget())
+ return;
+
+ m_signalsColumnData->deleteAllRows();
+ QStrList signalList = tree->widget()->metaObject()->signalNames(true);
+ QStrListIterator it(signalList);
+ for(; it.current() != 0; ++it)
+ {
+ KexiTableItem *item = m_signalsColumnData->createItem(); //new KexiTableItem(2);
+ (*item)[0] = QString(*it);
+ (*item)[1] = (*item)[0];
+ m_signalsColumnData->append(item);
+ }
+}
+
+void
+ConnectionDialog::checkConnection(KexiTableItem *item)
+{
+ // First we check if one column is empty
+ for(int i = 1; i < 5; i++)
+ {
+ if( !item || (*item)[i].toString().isEmpty())
+ {
+ setStatusError( i18n("<qt>You have not selected item: <b>%1</b>.</qt>").arg(m_data->column(i)->captionAliasOrName()),
+ item);
+ return;
+ }
+ }
+
+ // Then we check if signal/slot args are compatible
+ QString signal = (*item)[2].toString();
+ signal = signal.remove( QRegExp(".*[(]|[)]") ); // just keep the args list
+ QString slot = (*item)[4].toString();
+ slot = slot.remove( QRegExp(".*[(]|[)]") );
+
+ if(!signal.startsWith(slot, true))
+ {
+ setStatusError( i18n("The signal/slot arguments are not compatible."), item);
+ return;
+ }
+
+ setStatusOk(item);
+}
+
+void
+ConnectionDialog::newItem()
+{
+ m_table->acceptRowEdit();
+ m_table->setCursorPosition(m_table->rows(), 1);
+}
+
+void
+ConnectionDialog::newItemByDragnDrop()
+{
+ KFormDesigner::FormManager::self()->startCreatingConnection();
+ connect(KFormDesigner::FormManager::self(), SIGNAL(connectionAborted(KFormDesigner::Form*)), this, SLOT(slotConnectionAborted(KFormDesigner::Form*)));
+ connect(KFormDesigner::FormManager::self(), SIGNAL(connectionCreated(KFormDesigner::Form*, Connection&)), this, SLOT(slotConnectionCreated(KFormDesigner::Form*, Connection&)) );
+
+ hide();
+}
+
+void
+ConnectionDialog::slotConnectionCreated(KFormDesigner::Form *form, Connection &connection)
+{
+ show();
+ if(form != m_form)
+ return;
+
+ Connection *c = new Connection(connection);
+ KexiTableItem *item = m_table->data()->createItem(); //new KexiTableItem(5);
+ (*item)[1] = c->sender();
+ (*item)[2] = c->signal();
+ (*item)[3] = c->receiver();
+ (*item)[4] = c->slot();
+ m_table->insertItem(item, m_table->rows());
+ m_buffer->append(c);
+}
+
+void
+ConnectionDialog::slotConnectionAborted(KFormDesigner::Form *form)
+{
+ show();
+ if(form != m_form)
+ return;
+
+ newItem();
+}
+
+void
+ConnectionDialog::removeItem()
+{
+ if(m_table->currentRow() == -1 || m_table->currentRow()>=m_table->rows())
+ return;
+
+ int confirm = KMessageBox::warningContinueCancel(parentWidget(),
+ QString("<qt>")+i18n("Do you want to delete this connection ?")+"</qt>", QString::null, KGuiItem(i18n("&Delete Connection")),
+ "dontAskBeforeDeleteConnection"/*config entry*/);
+ if(confirm == KMessageBox::Cancel)
+ return;
+
+ m_buffer->remove(m_table->currentRow());
+ m_table->deleteItem(m_table->selectedItem());
+}
+
+}
+
+#include "connectiondialog.moc"
diff --git a/kexi/formeditor/connectiondialog.h b/kexi/formeditor/connectiondialog.h
new file mode 100644
index 00000000..3e6ac07b
--- /dev/null
+++ b/kexi/formeditor/connectiondialog.h
@@ -0,0 +1,114 @@
+/* This file is part of the KDE project
+ Copyright (C) 2004 Cedric Pasteur <cedric.pasteur@free.fr>
+ Copyright (C) 2004 Jaroslaw Staniek <js@iidea.pl>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+*/
+
+#ifndef FORMCONNECTIONDIALOG_H
+#define FORMCONNECTIONDIALOG_H
+
+#include <qintdict.h>
+#include <kdialogbase.h>
+
+namespace KexiDB {
+ class ResultInfo;
+}
+
+class QLabel;
+class QButton;
+class KexiTableView;
+class KexiTableViewData;
+class KexiTableItem;
+
+namespace KFormDesigner {
+
+class Form;
+class ConnectionBuffer;
+class Connection;
+
+
+/*! This dialog is used to edit the connections of a form. It uses KexiTableView for this. There is also a details widget (icon + text)) that shows correctness
+ of current connection. */
+class KFORMEDITOR_EXPORT ConnectionDialog : public KDialogBase
+{
+ Q_OBJECT
+
+ public:
+ ConnectionDialog(QWidget *parent);
+ ~ConnectionDialog() {;}
+
+ /*! Displays as modal dialog, to edit connections in Form::connectionBuffer(). */
+ void exec(Form *form);
+
+ protected:
+ /*! Used when connection is ok. Displays a message in details widget and changes icon in 'OK?' column. */
+ void setStatusOk(KexiTableItem *item = 0);
+ /*! Used when connection is wrong. Displays a message in details widget and changes icon in 'OK?' column. \a msg is
+ the message explaining what's wrong. */
+ void setStatusError(const QString &msg, KexiTableItem *item = 0);
+ //! Inits table data, columns, etc.
+ void initTable();
+ /*! Updates the widget list (shown in receiver and sender columns). Then fill in the table with the connections in m_buffer. */
+ void updateTableData();
+ /*! Updates the slot list, according to the receiver name, and only shows those who are compatible with signal args. */
+ void updateSlotList(KexiTableItem *item);
+ //! Updates the signal list, according to the sender name.
+ void updateSignalList(KexiTableItem *item);
+
+ protected slots:
+ /*! Slot called when the user modifies a cell. Signal and/or slot cells are cleared if necessary (not valid anymore). */
+ void slotCellChanged(KexiTableItem*, int, QVariant&, KexiDB::ResultInfo*);
+ /*! This function checks if the connection represented by KexiTableItem \a item is valid. It checks if all args (sender, receiver, signal and slot)
+ are given, and then if signal/slot args are compatible (should be always true, as we don't show non-compatible slots). It calls \ref setStatusOk()
+ or \ref setStatusError() following the result of checks. */
+ void checkConnection(KexiTableItem *item);
+
+ /*! Hides the dialog and allow the user to create the Connection by drag-and-drop in the Form itself. Currently disabled in the GUI.
+ \sa FormManager::startCreatingConnection() */
+ void newItemByDragnDrop();
+ /*! Creates a new item. It just moves the cursor to the last empty row. */
+ void newItem();
+ void removeItem();
+
+ /*! This slot is called when the user ends connection creation (when in drag-and-drop mode). The dialog is restored,
+ and the created connection is added to the list. */
+ void slotConnectionCreated(KFormDesigner::Form *form, KFormDesigner::Connection &connection);
+ /*! This slot is called when the user aborts connection creation (when in drag-and-drop mode). The dialog is restored,
+ and an empty connection is created. */
+ void slotConnectionAborted(KFormDesigner::Form *form);
+
+ void slotCellSelected(int col, int row);
+ void slotRowInserted(KexiTableItem*,bool);
+
+ /*! Slot called when the user presses 'Ok' button. The Form::connectionBuffer() is deleted, created again and filled with Connection.
+ If the user presses 'Cancel', nothing happens. */
+ virtual void slotOk();
+
+ protected:
+ enum {BAdd = 10, BRemove};
+ Form *m_form;
+ ConnectionBuffer *m_buffer;
+ KexiTableView *m_table;
+ KexiTableViewData *m_data;
+ KexiTableViewData *m_widgetsColumnData, *m_slotsColumnData, *m_signalsColumnData;
+ QLabel *m_pixmapLabel, *m_textLabel;
+ QIntDict<QButton> m_buttons; //! dict of button (for disabling them)
+};
+
+}
+
+#endif
diff --git a/kexi/formeditor/container.cpp b/kexi/formeditor/container.cpp
new file mode 100644
index 00000000..75a6dea6
--- /dev/null
+++ b/kexi/formeditor/container.cpp
@@ -0,0 +1,1182 @@
+/* This file is part of the KDE project
+ Copyright (C) 2003 Lucijan Busch <lucijan@gmx.at>
+ Copyright (C) 2004 Cedric Pasteur <cedric.pasteur@free.fr>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+*/
+
+#include <qpainter.h>
+#include <qpixmap.h>
+#include <qrect.h>
+#include <qevent.h>
+#include <qvaluevector.h>
+#include <qlayout.h>
+#include <qcursor.h>
+
+#include <kdebug.h>
+#include <klocale.h>
+#include <kpopupmenu.h>
+
+#include <cstdlib> // for abs()
+
+#include "utils.h"
+#include "container.h"
+#include "widgetlibrary.h"
+#include "objecttree.h"
+#include "form.h"
+#include "formmanager.h"
+#include "commands.h"
+#include "events.h"
+#include "kexiflowlayout.h"
+
+using namespace KFormDesigner;
+
+EventEater::EventEater(QWidget *widget, QObject *container)
+ : QObject(container)
+{
+ m_widget = widget;
+ m_container = container;
+
+ installRecursiveEventFilter(m_widget, this);
+}
+
+bool
+EventEater::eventFilter(QObject *, QEvent *ev)
+{
+ if(!m_container)
+ return false;
+
+ // When the user click the empty part of tab bar, only MouseReleaseEvent is sent,
+ // we need to simulate the Press event
+ if(ev->type() == QEvent::MouseButtonRelease && m_widget->inherits("QTabWidget"))
+ {
+ QMouseEvent *mev = static_cast<QMouseEvent*>(ev);
+ if(mev->button() == LeftButton)
+ {
+ QMouseEvent *myev = new QMouseEvent(QEvent::MouseButtonPress, mev->pos(), mev->button(), mev->state());
+ m_container->eventFilter(m_widget, myev);
+ delete myev;
+ //return true;
+ }
+ }
+// else if(ev->type() == QEvent::ChildInserted) {
+ // widget's children have changed, we need to reinstall filter
+// installRecursiveEventFilter(m_widget, this);
+// }
+
+ return m_container->eventFilter(m_widget, ev);
+}
+
+EventEater::~EventEater()
+{
+ if(m_widget)
+ removeRecursiveEventFilter(m_widget, this);
+}
+
+// Container itself
+
+Container::Container(Container *toplevel, QWidget *container, QObject *parent, const char *name)
+: QObject(parent, name)
+, m_insertBegin(-1,-1)
+, m_mousePressEventReceived(false)
+, m_mouseReleaseEvent(QEvent::None, QPoint(), 0, 0)
+{
+ m_container = container;
+ m_toplevel = toplevel;
+
+ m_moving = 0;
+ m_tree = 0;
+ m_form = toplevel ? toplevel->form() : 0;
+ m_layout = 0;
+ m_layType = NoLayout;
+ m_state = DoingNothing;
+
+ QCString classname = container->className();
+ if((classname == "HBox") || (classname == "Grid") || (classname == "VBox") ||
+ (classname == "HFlow") || (classname == "VFlow"))
+ m_margin = 4; // those containers don't have frames, so little margin
+ else
+ m_margin = m_form ? m_form->defaultMargin() : 0;
+ m_spacing = m_form ? m_form->defaultSpacing() : 0;
+
+ if(toplevel)
+ {
+ ObjectTreeItem *it = new ObjectTreeItem(m_form->library()->displayName(classname),
+ widget()->name(), widget(), this, this);
+ setObjectTree(it);
+
+ if(parent->isWidgetType())
+ {
+ QString n = parent->name();
+ ObjectTreeItem *parent = m_form->objectTree()->lookup(n);
+ m_form->objectTree()->addItem(parent, it);
+ }
+ else
+ m_form->objectTree()->addItem(toplevel->objectTree(), it);
+
+ connect(toplevel, SIGNAL(destroyed()), this, SLOT(widgetDeleted()));
+ }
+
+ connect(container, SIGNAL(destroyed()), this, SLOT(widgetDeleted()));
+}
+
+Container::~Container()
+{
+ kdDebug() << " Container being deleted this == " << name() << endl;
+}
+
+void
+Container::setForm(Form *form)
+{
+ m_form = form;
+ m_margin = m_form ? m_form->defaultMargin() : 0;
+ m_spacing = m_form ? m_form->defaultSpacing() : 0;
+}
+
+bool
+Container::eventFilter(QObject *s, QEvent *e)
+{
+// kdDebug() << e->type() << endl;
+ switch(e->type())
+ {
+ case QEvent::MouseButtonPress:
+ {
+ m_insertBegin = QPoint(-1, -1);
+ m_mousePressEventReceived = true;
+
+ kdDebug() << "QEvent::MouseButtonPress sender object = " << s->name()
+ << "of type " << s->className() << endl;
+ kdDebug() << "QEvent::MouseButtonPress this = " << name() << endl;
+
+ m_moving = static_cast<QWidget*>(s);
+ QMouseEvent *mev = static_cast<QMouseEvent*>(e);
+ m_grab = QPoint(mev->x(), mev->y());
+
+ // we are drawing a connection
+ if(FormManager::self()->isCreatingConnection()) {
+ drawConnection(mev);
+ return true;
+ }
+
+ if(((mev->state() == ControlButton) || (mev->state() == ShiftButton))
+ && (!FormManager::self()->isInserting())) // multiple selection mode
+ {
+ if(m_form->selectedWidgets()->findRef(m_moving) != -1) // widget is already selected
+ {
+ if(m_form->selectedWidgets()->count() > 1) // we remove it from selection
+ unSelectWidget(m_moving);
+ else // the widget is the only selected, so it means we want to copy it
+ {
+ //m_copyRect = m_moving->geometry();
+ m_state = CopyingWidget;
+ if(m_form->formWidget())
+ m_form->formWidget()->initBuffer();
+ }
+ }
+ else // the widget is not yet selected, we add it
+ setSelectedWidget(m_moving, true, (mev->button() == RightButton));
+ }
+ else if((m_form->selectedWidgets()->count() > 1))//&& (!m_form->manager()->isInserting())) // more than one widget selected
+ {
+ if(m_form->selectedWidgets()->findRef(m_moving) == -1) // widget is not selected, it becomes the only selected widget
+ setSelectedWidget(m_moving, false, (mev->button() == RightButton));
+ // If the widget is already selected, we do nothing (to ease widget moving, etc.)
+ }
+ else// if(!m_form->manager()->isInserting())
+ setSelectedWidget(m_moving, false, (mev->button() == RightButton));
+
+ // we are inserting a widget or drawing a selection rect in the form
+ if((/*s == m_container &&*/ FormManager::self()->isInserting()) || ((s == m_container) && !m_toplevel))
+ {
+ int tmpx,tmpy;
+ if(!FormManager::self()->snapWidgetsToGrid() || (mev->state() == (LeftButton|ControlButton|AltButton)))
+ {
+ tmpx = mev->x();
+ tmpy = mev->y();
+ }
+ else
+ {
+ int gridX = m_form->gridSize();
+ int gridY = m_form->gridSize();
+ tmpx = int( (float)mev->x() / ((float)gridX) + 0.5 ); // snap to grid
+ tmpx *= gridX;
+ tmpy = int( (float)mev->y() / ((float)gridY) + 0.5 );
+ tmpy *= gridX;
+ }
+
+ m_insertBegin = (static_cast<QWidget*>(s))->mapTo(m_container, QPoint(tmpx, tmpy));
+ if(m_form->formWidget())
+ m_form->formWidget()->initBuffer();
+
+ if(!FormManager::self()->isInserting())
+ m_state = DrawingSelectionRect;
+ }
+ else {
+ if(s->inherits("QTabWidget")) // to allow changing page by clicking tab
+ return false;
+ }
+
+ if (m_objectForMouseReleaseEvent) {
+ const bool res = handleMouseReleaseEvent(m_objectForMouseReleaseEvent, &m_mouseReleaseEvent);
+ m_objectForMouseReleaseEvent = 0;
+ return res;
+ }
+ return true;
+ }
+
+ case QEvent::MouseButtonRelease:
+ {
+ QMouseEvent *mev = static_cast<QMouseEvent*>(e);
+ if (!m_mousePressEventReceived) {
+ m_mouseReleaseEvent = *mev;
+ m_objectForMouseReleaseEvent = s;
+ return true;
+ }
+ m_mousePressEventReceived = false;
+ m_objectForMouseReleaseEvent = 0;
+ return handleMouseReleaseEvent(s, mev);
+ }
+
+ case QEvent::MouseMove:
+ {
+ QMouseEvent *mev = static_cast<QMouseEvent*>(e);
+ if(m_insertBegin!=QPoint(-1,-1) && FormManager::self()->isInserting() && ((mev->state() == LeftButton) || (mev->state() == (LeftButton|ControlButton)) ||
+ (mev->state() == (LeftButton|ControlButton|AltButton)) || (mev->state() == (LeftButton|ShiftButton)) ) )
+ // draw the insert rect
+ {
+ drawInsertRect(mev, s);
+ return true;
+ }
+ // Creating a connection, we highlight sender and receiver, and we draw a link between them
+ else if(FormManager::self()->isCreatingConnection() && !FormManager::self()->createdConnection()->sender().isNull())
+ {
+ ObjectTreeItem *tree = m_form->objectTree()->lookup(FormManager::self()->createdConnection()->sender());
+ if(!tree || !tree->widget())
+ return true;
+
+ if(m_form->formWidget() && (tree->widget() != s))
+ m_form->formWidget()->highlightWidgets(tree->widget(), static_cast<QWidget*>(s));
+ }
+ else if(m_insertBegin!=QPoint(-1,-1) && s == m_container && !m_toplevel && (mev->state() != ControlButton) && !FormManager::self()->isCreatingConnection()) // draw the selection rect
+ {
+ if((mev->state() != LeftButton) || /*m_inlineEditing*/ m_state == InlineEditing)
+ return true;
+ int topx = (m_insertBegin.x() < mev->x()) ? m_insertBegin.x() : mev->x();
+ int topy = (m_insertBegin.y() < mev->y()) ? m_insertBegin.y() : mev->y();
+ int botx = (m_insertBegin.x() > mev->x()) ? m_insertBegin.x() : mev->x();
+ int boty = (m_insertBegin.y() > mev->y()) ? m_insertBegin.y() : mev->y();
+ QRect r = QRect(QPoint(topx, topy), QPoint(botx, boty));
+ m_insertRect = r;
+
+ if(m_form->formWidget())
+ m_form->formWidget()->drawRect(r, 1);
+
+ m_state = DoingNothing;
+ return true;
+ }
+ else if(mev->state() == (LeftButton|ControlButton)) // draw the insert rect for the copied widget
+ {
+ if(s == m_container)// || (m_form->selectedWidgets()->count() > 1))
+ return true;
+ drawCopiedWidgetRect(mev);
+ return true;
+ }
+ else if( ( (mev->state() == Qt::LeftButton) || (mev->state() == (LeftButton|ControlButton|AltButton)) )
+ && !FormManager::self()->isInserting() && (m_state != CopyingWidget)) // we are dragging the widget(s) to move it
+ {
+ if(!m_toplevel && m_moving == m_container) // no effect for form
+ return false;
+ if((!m_moving) || (!m_moving->parentWidget()))// || (m_moving->parentWidget()->inherits("QWidgetStack")))
+ return true;
+
+ moveSelectedWidgetsBy(mev->x() - m_grab.x(), mev->y() - m_grab.y());
+ m_state = MovingWidget;
+ }
+
+ return true; // eat
+ }
+
+ case QEvent::Paint: // Draw the dotted background
+ {
+ if(s != m_container)
+ return false;
+ int gridX = m_form->gridSize();
+ int gridY = m_form->gridSize();
+
+ QPainter p(m_container);
+ p.setPen(QPen(white, 2));
+ p.setRasterOp(XorROP);
+ int cols = m_container->width() / gridX;
+ int rows = m_container->height() / gridY;
+
+ for(int rowcursor = 1; rowcursor <= rows; ++rowcursor)
+ {
+ for(int colcursor = 1; colcursor <= cols; ++colcursor)
+ {
+ p.drawPoint(-1 + colcursor *gridX, -1 + rowcursor *gridY);
+ }
+ }
+
+ return false;
+ }
+
+ case QEvent::Resize: // we are resizing a widget, so we set m_move to true -> the layout will be reloaded when releasing mouse
+ {
+ if(m_form->interactiveMode())
+ m_state = MovingWidget;
+ break;
+ }
+
+ //case QEvent::AccelOverride:
+ case QEvent::KeyPress:
+ {
+ QKeyEvent *kev = static_cast<QKeyEvent*>(e);
+
+ if(kev->key() == Key_F2) // pressing F2 == double-clicking
+ {
+ m_state = InlineEditing;
+ QWidget *w;
+
+ // try to find the widget which was clicked last and should be edited
+ if(m_form->selectedWidgets()->count() == 1)
+ w = m_form->selectedWidgets()->first();
+ else if(m_form->selectedWidgets()->findRef(m_moving) != -1)
+ w = m_moving;
+ else
+ w = m_form->selectedWidgets()->last();
+ m_form->library()->startEditing(w->className(), w, this);
+ }
+ else if(kev->key() == Key_Escape)
+ {
+ if(FormManager::self()->isCreatingConnection())
+ FormManager::self()->stopCreatingConnection();
+ else if(FormManager::self()->isInserting())
+ FormManager::self()->stopInsert();
+ return true;
+ }
+ else if((kev->key() == Key_Control) && (m_state == MovingWidget))
+ {
+ if(!m_moving)
+ return true;
+ // we simulate a mouse move event to update screen
+ QMouseEvent *mev = new QMouseEvent(QEvent::MouseMove, m_moving->mapFromGlobal(QCursor::pos()), NoButton,
+ LeftButton|ControlButton );
+ eventFilter(m_moving, mev);
+ delete mev;
+ }
+ else if(kev->key() == FormManager::self()->contextMenuKey())
+ {
+ FormManager::self()->createContextMenu(static_cast<QWidget*>(s), this, false);
+ return true;
+ }
+ else if (kev->key() == Key_Delete)
+ {
+ FormManager::self()->deleteWidget();
+ return true;
+ }
+ // directional buttons move the widget
+ else if(kev->key() == Key_Left){ // move the widget of gridX to the left
+ moveSelectedWidgetsBy(-form()->gridSize(), 0);
+ return true;
+ }
+ else if(kev->key() == Key_Right){ // move the widget of gridX to the right
+ moveSelectedWidgetsBy(form()->gridSize(), 0);
+ return true;
+ }
+ else if(kev->key() == Key_Up){ // move the widget of gridY to the top
+ moveSelectedWidgetsBy(0, - form()->gridSize());
+ return true;
+ }
+ else if(kev->key() == Key_Down){ // move the widget of gridX to the bottom
+ moveSelectedWidgetsBy(0, form()->gridSize());
+ return true;
+ }
+ else if((kev->key() == Key_Tab) || (kev->key() == Key_BackTab)){
+ ObjectTreeItem *item = form()->objectTree()->lookup(form()->selectedWidgets()->first()->name());
+ if(!item || !item->parent())
+ return true;
+ ObjectTreeList *list = item->parent()->children();
+ if(list->count() == 1)
+ return true;
+ int index = list->findRef(item);
+
+ if(kev->key() == Key_BackTab){
+ if(index == 0) // go back to the last item
+ index = list->count() - 1;
+ else
+ index = index - 1;
+ }
+ else {
+ if(index == int(list->count() - 1)) // go back to the first item
+ index = 0;
+ else
+ index = index + 1;
+ }
+
+ ObjectTreeItem *nextItem = list->at(index);
+ if(nextItem && nextItem->widget())
+ form()->setSelectedWidget(nextItem->widget(), false);
+ }
+ return true;
+ }
+
+ case QEvent::KeyRelease:
+ {
+ QKeyEvent *kev = static_cast<QKeyEvent*>(e);
+ if((kev->key() == Key_Control) && (m_state == CopyingWidget)) {
+ // cancel copying
+ //m_copyRect = QRect();
+ if(m_form->formWidget())
+ m_form->formWidget()->clearForm();
+ }
+ return true;
+ }
+
+ case QEvent::MouseButtonDblClick: // editing
+ {
+ kdDebug() << "Container: Mouse dbl click for widget " << s->name() << endl;
+ QWidget *w = static_cast<QWidget*>(s);
+ if(!w)
+ return false;
+
+ //m_inlineEditing = true;
+ m_state = InlineEditing;
+ m_form->library()->startEditing(w->className(), w, this);
+ return true;
+ }
+
+ case QEvent::ContextMenu:
+ case QEvent::Enter:
+ case QEvent::Leave:
+ case QEvent::FocusIn:
+ case QEvent::FocusOut:
+// case QEvent::DragEnter:
+// case QEvent::DragMove:
+// case QEvent::DragLeave:
+ return true; // eat them
+
+ default:
+ return false; // let the widget do the rest ...
+ }
+ return false;
+}
+
+bool
+Container::handleMouseReleaseEvent(QObject *s, QMouseEvent *mev)
+{
+ if(FormManager::self()->isInserting()) // we insert the widget at cursor pos
+ {
+ if(m_form->formWidget())
+ m_form->formWidget()->clearForm();
+ KCommand *com = new InsertWidgetCommand(this/*, mev->pos()*/);
+ m_form->addCommand(com, true);
+ m_insertBegin = QPoint(-1,-1);
+ m_insertRect = QRect();
+ return true;
+ }
+ else if(s == m_container && !m_toplevel && (mev->button() != RightButton) && m_insertRect.isValid()) // we are drawing a rect to select widgets
+ {
+ drawSelectionRect(mev);
+ return true;
+ }
+ if(mev->button() == RightButton) // Right-click -> context menu
+ {
+ FormManager::self()->createContextMenu(static_cast<QWidget*>(s), this);
+ }
+ else if(mev->state() == (Qt::LeftButton|Qt::ControlButton))// && (m_copyRect.isValid()))
+ {
+ // copying a widget by Ctrl+dragging
+
+ if(m_form->formWidget())
+ m_form->formWidget()->clearForm();
+ if(s == m_container) // should have no effect on form
+ return true;
+
+ // prevent accidental copying of widget (when moving mouse a little while selecting)
+ if( ( (mev->pos().x() - m_grab.x()) < form()->gridSize() && (m_grab.x() - mev->pos().x()) < form()->gridSize() ) &&
+ ( (mev->pos().y() - m_grab.y()) < form()->gridSize() && (m_grab.y() - mev->pos().y()) < form()->gridSize() ) )
+ {
+ kdDebug() << "The widget has not been moved. No copying" << endl;
+ return true;
+ }
+
+ m_form->setInteractiveMode(false);
+ // We simulate copy and paste
+ FormManager::self()->copyWidget();
+ if(m_form->selectedWidgets()->count() > 1)
+ FormManager::self()->setInsertPoint( mev->pos() );
+ else
+ FormManager::self()->setInsertPoint( static_cast<QWidget*>(s)->mapTo(m_container, mev->pos() - m_grab) );
+ FormManager::self()->pasteWidget();
+ m_form->setInteractiveMode(true);
+
+ //m_initialPos = QPoint();
+ }
+ else if(m_state == MovingWidget) // one widget has been moved, so we need to update the layout
+ reloadLayout();
+
+ // cancel copying as user released Ctrl before releasing mouse button
+ m_insertBegin = QPoint(-1,-1);
+ m_insertRect = QRect();
+ m_state = DoingNothing;
+ return true; // eat
+}
+
+void
+Container::setSelectedWidget(QWidget *w, bool add, bool dontRaise, bool moreWillBeSelected)
+{
+ if (w)
+ kdDebug() << "slotSelectionChanged " << w->name()<< endl;
+
+ if(!w)
+ {
+ m_form->setSelectedWidget(m_container);
+ return;
+ }
+
+ m_form->setSelectedWidget(w, add, dontRaise, moreWillBeSelected);
+}
+
+void
+Container::unSelectWidget(QWidget *w)
+{
+ if(!w)
+ return;
+
+ m_form->unSelectWidget(w);
+}
+
+Container*
+Container::toplevel()
+{
+ if(m_toplevel)
+ return m_toplevel;
+ else
+ return this;
+}
+
+void
+Container::deleteWidget(QWidget *w)
+{
+ if(!w)
+ return;
+// kdDebug() << "Deleting a widget: " << w->name() << endl;
+ m_form->objectTree()->removeItem(w->name());
+ FormManager::self()->deleteWidgetLater( w );
+ m_form->setSelectedWidget(m_container);
+}
+
+void
+Container::widgetDeleted()
+{
+ m_container = 0;
+ deleteLater();
+}
+
+/// Layout functions
+
+void
+Container::setLayout(LayoutType type)
+{
+ if(m_layType == type)
+ return;
+
+ delete m_layout;
+ m_layout = 0;
+ m_layType = type;
+
+ switch(type)
+ {
+ case HBox:
+ {
+ m_layout = (QLayout*) new QHBoxLayout(m_container, m_margin, m_spacing);
+ createBoxLayout(new HorWidgetList(m_form->toplevelContainer()->widget()));
+ break;
+ }
+ case VBox:
+ {
+ m_layout = (QLayout*) new QVBoxLayout(m_container, m_margin, m_spacing);
+ createBoxLayout(new VerWidgetList(m_form->toplevelContainer()->widget()));
+ break;
+ }
+ case Grid:
+ {
+ createGridLayout();
+ break;
+ }
+ case HFlow:
+ {
+ KexiFlowLayout *flow = new KexiFlowLayout(m_container,m_margin, m_spacing);
+ flow->setOrientation(Horizontal);
+ m_layout = (QLayout*)flow;
+ createFlowLayout();
+ break;
+ }
+ case VFlow:
+ {
+ KexiFlowLayout *flow = new KexiFlowLayout(m_container,m_margin, m_spacing);
+ flow->setOrientation(Vertical);
+ m_layout = (QLayout*)flow;
+ createFlowLayout();
+ break;
+ }
+ default:
+ {
+ m_layType = NoLayout;
+ return;
+ }
+ }
+ m_container->setGeometry(m_container->geometry()); // just update layout
+ m_layout->activate();
+}
+
+void
+Container::reloadLayout()
+{
+ LayoutType type = m_layType;
+ setLayout(NoLayout);
+ setLayout(type);
+}
+
+void
+Container::createBoxLayout(WidgetList *list)
+{
+ QBoxLayout *layout = static_cast<QBoxLayout*>(m_layout);
+
+ for(ObjectTreeItem *tree = m_tree->children()->first(); tree; tree = m_tree->children()->next())
+ list->append( tree->widget());
+ list->sort();
+
+ for(QWidget *obj = list->first(); obj; obj = list->next())
+ layout->addWidget(obj);
+ delete list;
+}
+
+void
+Container::createFlowLayout()
+{
+ KexiFlowLayout *flow = dynamic_cast<KexiFlowLayout*>(m_layout);
+ if(!flow || m_tree->children()->isEmpty())
+ return;
+
+ const int offset = 15;
+ WidgetList *list=0, *list2=0;
+ if(flow->orientation() == Horizontal) {
+ list = new VerWidgetList(m_form->toplevelContainer()->widget());
+ list2 = new HorWidgetList(m_form->toplevelContainer()->widget());
+ }
+ else {
+ list = new HorWidgetList(m_form->toplevelContainer()->widget());
+ list2 = new VerWidgetList(m_form->toplevelContainer()->widget());
+ }
+
+ // fill the list
+ for(ObjectTreeItem *tree = m_tree->children()->first(); tree; tree = m_tree->children()->next())
+ list->append( tree->widget());
+ list->sort();
+
+ if(flow->orientation() == Horizontal) {
+ int y = list->first()->y();
+ for(QWidget *w = list->first(); w; w = list->next()) {
+ if( (w->y() > y +offset)) {
+ // start a new line
+ list2->sort();
+ for(QWidget *obj = list2->first(); obj; obj = list2->next())
+ flow->add(obj);
+ list2->clear();
+ y = w->y();
+ }
+ list2->append(w);
+ }
+
+ list2->sort(); // don't forget the last line
+ for(QWidget *obj = list2->first(); obj; obj = list2->next())
+ flow->add(obj);
+ }
+ else {
+ int x = list->first()->x();
+ for(QWidget *w = list->first(); w; w = list->next()) {
+ if( (w->x() > x +offset)) {
+ // start a new column
+ list2->sort();
+ for(QWidget *obj = list2->first(); obj; obj = list2->next())
+ flow->add(obj);
+ list2->clear();
+ x = w->x();
+ }
+ list2->append(w);
+ }
+
+ list2->sort(); // don't forget the last column
+ for(QWidget *obj = list2->first(); obj; obj = list2->next())
+ flow->add(obj);
+ }
+
+ delete list;
+ delete list2;
+}
+
+void
+Container::createGridLayout(bool testOnly)
+{
+ //Those lists sort widgets by y and x
+ VerWidgetList *vlist = new VerWidgetList(m_form->toplevelContainer()->widget());
+ HorWidgetList *hlist = new HorWidgetList(m_form->toplevelContainer()->widget());
+ // The vector are used to store the x (or y) beginning of each column (or row)
+ QValueVector<int> cols;
+ QValueVector<int> rows;
+ int end=-1000;
+ bool same = false;
+
+ for(ObjectTreeItem *tree = m_tree->children()->first(); tree; tree = m_tree->children()->next())
+ vlist->append( tree->widget());
+ vlist->sort();
+
+ for(ObjectTreeItem *tree = m_tree->children()->first(); tree; tree = m_tree->children()->next())
+ hlist->append( tree->widget());
+ hlist->sort();
+
+ // First we need to make sure that two widgets won't be in the same row,
+ // ie that no widget overlap another one
+ if(!testOnly) {
+ for(WidgetListIterator it(*vlist); it.current() != 0; ++it)
+ {
+ QWidget *w = it.current();
+ WidgetListIterator it2 = it;
+
+ for(; it2.current() != 0; ++it2) {
+ QWidget *nextw = it2.current();
+ if((w->y() >= nextw->y()) || (nextw->y() >= w->geometry().bottom()))
+ break;
+
+ if(!w->geometry().intersects(nextw->geometry()))
+ break;
+ // If the geometries of the two widgets intersect each other,
+ // we move one of the widget to the rght or bottom of the other
+ if((nextw->y() - w->y()) > abs(nextw->x() - w->x()))
+ nextw->move(nextw->x(), w->geometry().bottom()+1);
+ else if(nextw->x() >= w->x())
+ nextw->move(w->geometry().right()+1, nextw->y());
+ else
+ w->move(nextw->geometry().right()+1, nextw->y());
+ }
+ }
+ }
+
+ // Then we count the number of rows in the layout, and set their beginnings
+ for(WidgetListIterator it(*vlist); it.current() != 0; ++it)
+ {
+ QWidget *w = it.current();
+ WidgetListIterator it2 = it;
+ if(!same) { // this widget will make a new row
+ end = w->geometry().bottom();
+ rows.append(w->y());
+ }
+
+ // If same == true, it means we are in the same row as prev widget
+ // (so no need to create a new column)
+ ++it2;
+ if(!it2.current())
+ break;
+
+ QWidget *nextw = it2.current();
+ if(nextw->y() >= end)
+ same = false;
+ else {
+ same = !(same && (nextw->y() >= w->geometry().bottom()));
+ if(!same)
+ end = w->geometry().bottom();
+ }
+ }
+ kdDebug() << "the new grid will have n rows: n == " << rows.size() << endl;
+
+ end = -10000;
+ same = false;
+ // We do the same thing for the columns
+ for(WidgetListIterator it(*hlist); it.current() != 0; ++it)
+ {
+ QWidget *w = it.current();
+ WidgetListIterator it2 = it;
+ if(!same) {
+ end = w->geometry().right();
+ cols.append(w->x());
+ }
+
+ ++it2;
+ if(!it2.current())
+ break;
+
+ QWidget *nextw = it2.current();
+ if(nextw->x() >= end)
+ same = false;
+ else {
+ same = !(same && (nextw->x() >= w->geometry().right()));
+ if(!same)
+ end = w->geometry().right();
+ }
+ }
+ kdDebug() << "the new grid will have n columns: n == " << cols.size() << endl;
+
+ // We create the layout ..
+ QGridLayout *layout=0;
+ if(!testOnly) {
+ layout = new QGridLayout(m_container, rows.size(), cols.size(), m_margin, m_spacing, "grid");
+ m_layout = (QLayout*)layout;
+ }
+
+ // .. and we fill it with widgets
+ for(WidgetListIterator it(*vlist); it.current() != 0; ++it)
+ {
+ QWidget *w = it.current();
+ QRect r = w->geometry();
+ uint wcol=0, wrow=0, endrow=0, endcol=0;
+ uint i = 0;
+
+ // We look for widget row(s) ..
+ while(r.y() >= rows[i])
+ {
+ if(rows.size() <= i+1) // we are the last row
+ {
+ wrow = i;
+ break;
+ }
+ if(r.y() < rows[i+1])
+ {
+ wrow = i; // the widget will be in this row
+ uint j = i + 1;
+ // Then we check if the widget needs to span multiple rows
+ while(rows.size() >= j+1 && r.bottom() > rows[j])
+ {
+ endrow = j;
+ j++;
+ }
+
+ break;
+ }
+ i++;
+ }
+ //kdDebug() << "the widget " << w->name() << " wil be in the row " << wrow <<
+ //" and will go to the row " << endrow << endl;
+
+ // .. and column(s)
+ i = 0;
+ while(r.x() >= cols[i])
+ {
+ if(cols.size() <= i+1) // last column
+ {
+ wcol = i;
+ break;
+ }
+ if(r.x() < cols[i+1])
+ {
+ wcol = i;
+ uint j = i + 1;
+ // Then we check if the widget needs to span multiple columns
+ while(cols.size() >= j+1 && r.right() > cols[j])
+ {
+ endcol = j;
+ j++;
+ }
+
+ break;
+ }
+ i++;
+ }
+ //kdDebug() << "the widget " << w->name() << " wil be in the col " << wcol <<
+ // " and will go to the col " << endcol << endl;
+
+ ObjectTreeItem *item = m_form->objectTree()->lookup(w->name());
+ if(!endrow && !endcol) {
+ if(!testOnly)
+ layout->addWidget(w, wrow, wcol);
+ item->setGridPos(wrow, wcol, 0, 0);
+ }
+ else {
+ if(!endcol) endcol = wcol;
+ if(!endrow) endrow = wrow;
+ if(!testOnly)
+ layout->addMultiCellWidget(w, wrow, endrow, wcol, endcol);
+ item->setGridPos(wrow, wcol, endrow-wrow+1, endcol-wcol+1);
+ }
+ }
+}
+
+QString
+Container::layoutTypeToString(int type)
+{
+ switch(type)
+ {
+ case HBox: return "HBox";
+ case VBox: return "VBox";
+ case Grid: return "Grid";
+ case HFlow: return "HFlow";
+ case VFlow: return "VFlow";
+ default: return "NoLayout";
+ }
+}
+
+Container::LayoutType
+Container::stringToLayoutType(const QString &name)
+{
+ if(name == "HBox") return HBox;
+ if(name == "VBox") return VBox;
+ if(name == "Grid") return Grid;
+ if(name == "HFlow") return HFlow;
+ if(name == "VFlow") return VFlow;
+ return NoLayout;
+}
+
+/// Drawing functions used by eventFilter
+void
+Container::drawConnection(QMouseEvent *mev)
+{
+ if(mev->button() != LeftButton)
+ {
+ FormManager::self()->resetCreatedConnection();
+ return;
+ }
+ // First click, we select the sender and display menu to choose signal
+ if(FormManager::self()->createdConnection()->sender().isNull())
+ {
+ FormManager::self()->createdConnection()->setSender(m_moving->name());
+ if(m_form->formWidget())
+ {
+ m_form->formWidget()->initBuffer();
+ m_form->formWidget()->highlightWidgets(m_moving, 0/*, QPoint()*/);
+ }
+ FormManager::self()->createSignalMenu(m_moving);
+ return;
+ }
+ // the user clicked outside the menu, we cancel the connection
+ if(FormManager::self()->createdConnection()->signal().isNull())
+ {
+ FormManager::self()->stopCreatingConnection();
+ return;
+ }
+ // second click to choose the receiver
+ if(FormManager::self()->createdConnection()->receiver().isNull())
+ {
+ FormManager::self()->createdConnection()->setReceiver(m_moving->name());
+ FormManager::self()->createSlotMenu(m_moving);
+ m_container->repaint();
+ return;
+ }
+ // the user clicked outside the menu, we cancel the connection
+ if(FormManager::self()->createdConnection()->slot().isNull())
+ {
+ FormManager::self()->stopCreatingConnection();
+ return;
+ }
+}
+
+void
+Container::drawSelectionRect(QMouseEvent *mev)
+{
+ //finish drawing unclipped selection rectangle: clear the surface
+ if(m_form->formWidget())
+ m_form->formWidget()->clearForm();
+ int topx = (m_insertBegin.x() < mev->x()) ? m_insertBegin.x() : mev->x();
+ int topy = (m_insertBegin.y() < mev->y()) ? m_insertBegin.y() : mev->y();
+ int botx = (m_insertBegin.x() > mev->x()) ? m_insertBegin.x() : mev->x();
+ int boty = (m_insertBegin.y() > mev->y()) ? m_insertBegin.y() : mev->y();
+ QRect r = QRect(QPoint(topx, topy), QPoint(botx, boty));
+
+ setSelectedWidget(m_container, false);
+ QWidget *widgetToSelect = 0;
+ // We check which widgets are in the rect and select them
+ for(ObjectTreeItem *item = m_tree->children()->first(); item; item = m_tree->children()->next())
+ {
+ QWidget *w = item->widget();
+ if(!w)
+ continue;
+ if(w->geometry().intersects(r) && w != m_container) {
+ if (widgetToSelect)
+ setSelectedWidget(widgetToSelect, true/*add*/, false/*raise*/, true/*moreWillBeSelected*/);
+ widgetToSelect = w; //select later
+ }
+ }
+ if (widgetToSelect) //the last one left
+ setSelectedWidget(widgetToSelect, true/*add*/, false/*raise*/, false/*!moreWillBeSelected*/);
+
+ m_insertRect = QRect();
+ m_state = DoingNothing;
+ m_container->repaint();
+}
+
+void
+Container::drawInsertRect(QMouseEvent *mev, QObject *s)
+{
+ int tmpx, tmpy;
+ QPoint pos = static_cast<QWidget*>(s)->mapTo(m_container, mev->pos());
+ int gridX = m_form->gridSize();
+ int gridY = m_form->gridSize();
+ if(!FormManager::self()->snapWidgetsToGrid() || (mev->state() == (LeftButton|ControlButton|AltButton)) )
+ {
+ tmpx = pos.x();
+ tmpy = pos.y();
+ }
+ else
+ {
+ tmpx = int( (float) pos.x() / ((float)gridX) + 0.5);
+ tmpx *= gridX;
+ tmpy = int( (float)pos.y() / ((float)gridY) + 0.5);
+ tmpy *= gridX;
+ }
+
+ int topx = (m_insertBegin.x() < tmpx) ? m_insertBegin.x() : tmpx;
+ int topy = (m_insertBegin.y() < tmpy) ? m_insertBegin.y() : tmpy;
+ int botx = (m_insertBegin.x() > tmpx) ? m_insertBegin.x() : tmpx;
+ int boty = (m_insertBegin.y() > tmpy) ? m_insertBegin.y() : tmpy;
+ m_insertRect = QRect(QPoint(topx, topy), QPoint(botx, boty));
+
+ if(m_insertRect.x() < 0)
+ m_insertRect.setLeft(0);
+ if(m_insertRect.y() < 0)
+ m_insertRect.setTop(0);
+ if(m_insertRect.right() > m_container->width())
+ m_insertRect.setRight(m_container->width());
+ if(m_insertRect.bottom() > m_container->height())
+ m_insertRect.setBottom(m_container->height());
+
+ if(FormManager::self()->isInserting() && m_insertRect.isValid())
+ {
+ if(m_form->formWidget())
+ {
+ QRect drawRect = QRect(m_container->mapTo(m_form->widget(), m_insertRect.topLeft())
+ , m_insertRect.size());
+ m_form->formWidget()->drawRect(drawRect, 2);
+ }
+ }
+}
+
+void
+Container::drawCopiedWidgetRect(QMouseEvent *mev)
+{
+ // We've been dragging a widget, but Ctrl was hold, so we start copy
+ if(m_state == MovingWidget) {
+ //FormManager::self()->undo(); // undo last moving
+ //m_moving->move(m_initialPos);
+ if(m_form->formWidget()) {
+ m_container->repaint();
+ m_form->formWidget()->initBuffer();
+ }
+ m_state = CopyingWidget;
+ }
+
+ //m_copyRect.moveTopLeft(m_container->mapFromGlobal( mev->globalPos()) - m_grab);
+
+ if(m_form->formWidget()) {
+ QValueList<QRect> rectList;
+ for(QWidget *w = m_form->selectedWidgets()->first(); w; w = m_form->selectedWidgets()->next()) {
+ QRect drawRect = w->geometry();
+ QPoint p = mev->pos() - m_grab;
+ drawRect.moveBy(p.x(), p.y());
+ p = m_container->mapTo(m_form->widget(), QPoint(0, 0));
+ //drawRect = QRect( ((QWidget*)s)->mapTo(m_form->widget(), drawRect.topLeft()), drawRect.size());
+ drawRect.moveBy(p.x(), p.y());
+ rectList.append(drawRect);
+ }
+
+ m_form->formWidget()->drawRects(rectList, 2);
+ }
+}
+
+/// Other functions used by eventFilter
+void
+Container::moveSelectedWidgetsBy(int realdx, int realdy, QMouseEvent *mev)
+{
+ if (m_form->selectedWidget() == m_form->widget())
+ return; //do not move top-level widget
+
+ const int gridX = m_form->gridSize();
+ const int gridY = m_form->gridSize();
+ int dx=realdx, dy=realdy;
+
+ for(QWidget *w = m_form->selectedWidgets()->first(); w; w = m_form->selectedWidgets()->next())
+ {
+ if(!w || !w->parent() || w->parent()->inherits("QTabWidget") || w->parent()->inherits("QWidgetStack"))
+ continue;
+
+ if(w->parentWidget() && w->parentWidget()->isA("QWidgetStack"))
+ {
+ w = w->parentWidget(); // widget is WidgetStack page
+ if(w->parentWidget() && w->parentWidget()->inherits("QTabWidget")) // widget is tabwidget page
+ w = w->parentWidget();
+ }
+
+ int tmpx = w->x() + realdx;
+ int tmpy = w->y() + realdy;
+ if(tmpx < 0)
+ dx = QMAX(0 - w->x(), dx); // because dx is <0
+ else if(tmpx > w->parentWidget()->width() - gridX)
+ dx = QMIN(w->parentWidget()->width() - gridX - w->x(), dx);
+
+ if(tmpy < 0)
+ dy = QMAX(0 - w->y(), dy); // because dy is <0
+ else if(tmpy > w->parentWidget()->height() - gridY)
+ dy = QMIN(w->parentWidget()->height() - gridY - w->y(), dy);
+ }
+
+ for(QWidget *w = m_form->selectedWidgets()->first(); w; w = m_form->selectedWidgets()->next())
+ {
+ // Don't move tab widget pages (or widget stack pages)
+ if(!w || !w->parent() || w->parent()->inherits("QTabWidget") || w->parent()->inherits("QWidgetStack"))
+ continue;
+
+ if(w->parentWidget() && w->parentWidget()->isA("QWidgetStack"))
+ {
+ w = w->parentWidget(); // widget is WidgetStack page
+ if(w->parentWidget() && w->parentWidget()->inherits("QTabWidget")) // widget is tabwidget page
+ w = w->parentWidget();
+ }
+
+ int tmpx, tmpy;
+ if(!FormManager::self()->snapWidgetsToGrid() || (mev && mev->state() == (LeftButton|ControlButton|AltButton)) )
+ {
+ tmpx = w->x() + dx;
+ tmpy = w->y() + dy;
+ }
+ else
+ {
+ tmpx = int( float( w->x() + dx) / float(gridX) + 0.5) * gridX;
+ tmpy = int( float( w->y() + dy) / float(gridY) + 0.5) * gridY;
+ }
+
+ if((tmpx != w->x()) || (tmpy != w->y()))
+ w->move(tmpx,tmpy);
+ }
+}
+
+////////////
+
+DesignTimeDynamicChildWidgetHandler::DesignTimeDynamicChildWidgetHandler()
+ : m_item(0)
+{
+}
+
+DesignTimeDynamicChildWidgetHandler::~DesignTimeDynamicChildWidgetHandler()
+{
+}
+
+void
+DesignTimeDynamicChildWidgetHandler::childWidgetAdded(QWidget* w)
+{
+ if (m_item) {
+ installRecursiveEventFilter(w, m_item->eventEater());
+ }
+}
+
+#include "container.moc"
diff --git a/kexi/formeditor/container.h b/kexi/formeditor/container.h
new file mode 100644
index 00000000..b7036aa7
--- /dev/null
+++ b/kexi/formeditor/container.h
@@ -0,0 +1,248 @@
+/* This file is part of the KDE project
+ Copyright (C) 2003 Lucijan Busch <lucijan@gmx.at>
+ Copyright (C) 2004 Cedric Pasteur <cedric.pasteur@free.fr>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+*/
+
+#ifndef FORMEDITORCONTAINER_H
+#define FORMEDITORCONTAINER_H
+
+#include <qobject.h>
+#include <qguardedptr.h>
+#include <qptrlist.h>
+#include <qwidget.h>
+
+#include "utils.h"
+
+class QEvent;
+class QWidget;
+class QLayout;
+
+namespace KFormDesigner {
+
+class Container;
+class WidgetLibrary;
+class ObjectTreeItem;
+class Form;
+
+/**
+ * This class is used to filter the events from any widget (and all its subwidgets)
+ * and direct it to the Container.
+ */
+//! A class for redirecting events
+class KFORMEDITOR_EXPORT EventEater : public QObject
+{
+ Q_OBJECT
+
+ public:
+ /*! Constructs eater object. All events for \a widget and it's subwidgets
+ will be redirected to \a container. \a container will be also parent of eater object,
+ so you don't need to care about deleting it. */
+ EventEater(QWidget *widget, QObject *container);
+ ~EventEater();
+
+ //! Sets the object which will receive the events
+ void setContainer(QObject *container) { m_container = container; }
+ bool eventFilter(QObject *o, QEvent *ev);
+
+ private:
+ QGuardedPtr<QWidget> m_widget;
+ QGuardedPtr<QObject> m_container;
+};
+
+/**
+ * This class makes a container out of any QWidget. You can then create child widgets, and
+ the background is dotted.
+ */
+//! A class to make a container from any widget
+class KFORMEDITOR_EXPORT Container : public QObject
+{
+ Q_OBJECT
+
+ public:
+ enum LayoutType { NoLayout=0, HBox, VBox, Grid, HFlow, VFlow, /* special types */ HSplitter, VSplitter };
+
+ /**
+ * Creates a Container from the widget \a container, which have
+ \a toplevel as parent Container. */
+ Container(Container *toplevel, QWidget *container, QObject *parent=0, const char *name=0);
+ virtual ~Container();
+
+ //! \return a pointer to the toplevel Container, or 0 if this Container is toplevel
+ Container* toplevel();
+
+ //! \return The form this Container belongs to.
+ Form* form() const { return m_form; }
+
+ //! \return The watched widget.
+ QWidget* widget() const { return m_container; }
+
+ //! \return The ObjectTreeItem associated with this Container's widget.
+ ObjectTreeItem* objectTree() const { return m_tree; }
+
+ //! Sets the Form which this Container belongs to.
+ void setForm(Form *form);
+
+ /*! Sets the ObjectTree of this Container.\n
+ * NOTE: this is needed only if we are toplevel. */
+ void setObjectTree(ObjectTreeItem *t) { m_tree = t; }
+
+ //! \return a pointer to the QLayout of this Container, or 0 if there is not.
+ QLayout* layout() const { return m_layout; }
+
+ //! \return the type of the layout associated to this Container's widget (see LayoutType enum).
+ LayoutType layoutType() const { return m_layType; }
+
+ //! \return the margin of this Container.
+ int layoutMargin() { return m_margin; }
+
+ //! \return the spacing of this Container.
+ int layoutSpacing() { return m_spacing; }
+
+ /*! Sets this Container to use \a type of layout. The widget are inserted
+ automatically in the layout following their positions.
+ \sa createBoxLayout(), createGridLayout() */
+ void setLayout(LayoutType type);
+
+ //! Sets the spacing of this Container.
+ void setLayoutSpacing(int spacing) { m_spacing = spacing;}
+
+ //! Sets the margin of this Container.
+ void setLayoutMargin(int margin) { m_margin = margin;}
+
+ //! \return the string representing the layoutType \a type.
+ static QString layoutTypeToString(int type);
+
+ //! \return the LayoutType (an int) for a given layout name.
+ static LayoutType stringToLayoutType(const QString &name);
+
+ /*! Stops the inline editing of the current widget (as when you click
+ on another widget or press Esc). */
+ void stopInlineEditing() { m_state = DoingNothing; }
+
+ /*! This is the main function of Container, which filters the event sent
+ to the watched widget.\n It takes care of drawing the background and
+ the insert rect, of creating the new child widgets, of moving the widgets
+ and pop up a menu when right-clicking. */
+ virtual bool eventFilter(QObject *o, QEvent *e);
+
+ public slots:
+ /*! Sets \a selected to be the selected widget of this container
+ (and so of the Form). If \a add is true, the formerly selected widget
+ is still selected, and the new one is just added. If false, \a selected
+ replace the actually selected widget. If \a dontRaise is true, then
+ the widget \a selected (and its parent) won't be raised (eg when you
+ select widget in ObjectTreeView).
+ \sa Form::setSelectedWidget() */
+ void setSelectedWidget(QWidget *selected, bool add, bool dontRaise=false,
+ bool moreWillBeSelected = false);
+
+ /*! Unselects the widget \a w. The widget is removed from the Form's list
+ and its resizeHandles are removed. */
+ void unSelectWidget(QWidget *w);
+
+ /*! Deletes the widget \a w. Removes it from ObjectTree, and sets selection
+ to Container's widget. */
+ void deleteWidget(QWidget *w);
+
+ /*! Recreates the Container layout. Calls this when a widget has been moved
+ or added to update the layout. */
+ void reloadLayout();
+
+ protected slots:
+ /*! This slot is called when the watched widget is deleted. Deletes the Container too. */
+ void widgetDeleted();
+
+ protected:
+ /*! Internal function to create a HBoxLayout or VBoxLayout for this container.
+ \a list is a subclass of QObjectList that can sort widgets
+ following their position (such as HorWidgetList or VerWidgetList). */
+ void createBoxLayout(WidgetList *list);
+
+ /*! Internal function to create a KexiFlowLayout. */
+ void createFlowLayout();
+
+ /*! Internal function to create a GridLayout. if \a testOnly is true, the layout
+ is simulated, and only the widget's grid info aris filled. */
+ void createGridLayout(bool testOnly=false);
+
+ void drawConnection(QMouseEvent *mev);
+ void drawSelectionRect(QMouseEvent *mev);
+ void drawInsertRect(QMouseEvent *mev, QObject *s);
+ void drawCopiedWidgetRect(QMouseEvent *mev);
+
+ void moveSelectedWidgetsBy(int realdx, int realdy, QMouseEvent *mev=0);
+
+ private:
+ bool handleMouseReleaseEvent(QObject *s, QMouseEvent *mev);
+
+ // the watched container and it's toplevel one...
+ QGuardedPtr<QWidget> m_container;
+ QGuardedPtr<Container> m_toplevel;
+
+ int m_state;
+ enum { DoingNothing = 100, DrawingSelectionRect, CopyingWidget,
+ MovingWidget, InlineEditing };
+
+ // Layout
+ QLayout *m_layout;
+ LayoutType m_layType;
+ int m_margin, m_spacing;
+
+ // moving etc.
+ QPoint m_grab;
+ //QPoint m_initialPos;
+ QGuardedPtr<QWidget> m_moving;
+ //QRect m_copyRect;
+
+ //inserting
+ QPoint m_insertBegin;
+ QRect m_insertRect;
+ ObjectTreeItem *m_tree;
+
+ QGuardedPtr<Form> m_form;
+ bool m_mousePressEventReceived;
+ QMouseEvent m_mouseReleaseEvent;
+ QGuardedPtr<QObject> m_objectForMouseReleaseEvent;
+
+ friend class InsertWidgetCommand;
+ friend class PasteWidgetCommand;
+ friend class DeleteWidgetCommand;
+ friend class FormIO;
+};
+
+//! Interface for adding dynamically created (at design time) widget to event eater.
+/*! This is currently used by KexiDBFieldEdit from Kexi forms. */
+class KFORMEDITOR_EXPORT DesignTimeDynamicChildWidgetHandler
+{
+ public:
+ DesignTimeDynamicChildWidgetHandler();
+ ~DesignTimeDynamicChildWidgetHandler();
+
+ protected:
+ void childWidgetAdded(QWidget* w);
+ void assignItem(ObjectTreeItem* item) { m_item = item; }
+
+ private:
+ ObjectTreeItem* m_item;
+ friend class InsertWidgetCommand;
+ friend class FormIO;
+};
+
+}
+
+#endif
diff --git a/kexi/formeditor/editlistviewdialog.cpp b/kexi/formeditor/editlistviewdialog.cpp
new file mode 100644
index 00000000..5b128ec8
--- /dev/null
+++ b/kexi/formeditor/editlistviewdialog.cpp
@@ -0,0 +1,460 @@
+/* This file is part of the KDE project
+ Copyright (C) 2004 Cedric Pasteur <cedric.pasteur@free.fr>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+*/
+#include <qheader.h>
+#include <qlayout.h>
+
+#include <klistview.h>
+#include <ktabwidget.h>
+#include <klistbox.h>
+#include <kiconloader.h>
+#include <kdebug.h>
+#include <klocale.h>
+
+#include <koproperty/editor.h>
+#include <koproperty/set.h>
+#include <koproperty/property.h>
+
+#include "editlistviewdialog.h"
+
+namespace KFormDesigner {
+
+//////////////////////////////////////////////////////////////////////////////////
+/// A Dialog to edit the contents of a listview /////////////////////
+/////////////////////////////////////////////////////////////////////////////////
+
+EditListViewDialog::EditListViewDialog(QWidget *parent)
+//js(kde3.2 dependent) : KDialogBase(Tabbed, 0/* WFlags */, parent, "editlistview_dialog", true, i18n("Edit listview contents"), Ok|Cancel, Ok, false)
+: KDialogBase(Tabbed, i18n("Edit Listview Contents"), Ok|Cancel, Ok, parent, "editlistview_dialog", true /* modal */, false)
+{
+ m_column = addPage(i18n("Columns"));
+ m_contents = addPage(i18n("Contents"));
+
+ ///////// Setup the "Contents" page /////////////////////////////
+ QHBoxLayout *layout = new QHBoxLayout(m_contents, 0, 6);
+
+ //// Setup the icon toolbar /////////////////
+ QVBoxLayout *vlayout = new QVBoxLayout(layout, 3);
+ QToolButton *newRow = new QToolButton(m_contents);
+ newRow->setIconSet(BarIconSet("edit_add"));
+ newRow->setTextLabel(i18n("&Add Item"), true);
+ vlayout->addWidget(newRow);
+ m_buttons.insert(BNewRow, newRow);
+ connect(newRow, SIGNAL(clicked()), this, SLOT(newRow()));
+
+ QToolButton *newChild = new QToolButton(m_contents);
+ newChild->setIconSet(BarIconSet("1rightarrow"));
+ newChild->setTextLabel(i18n("New &Subitem"), true);
+ vlayout->addWidget(newChild);
+ m_buttons.insert(BNewChild, newChild);
+ connect(newChild, SIGNAL(clicked()), this, SLOT(newChildRow()));
+
+ QToolButton *delRow = new QToolButton(m_contents);
+ delRow->setIconSet(BarIconSet("edit_remove"));
+ delRow->setTextLabel(i18n("&Remove Item"), true);
+ vlayout->addWidget(delRow);
+ m_buttons.insert(BRemRow, delRow);
+ connect(delRow, SIGNAL(clicked()), this, SLOT(removeRow()));
+
+ QToolButton *rowUp = new QToolButton(m_contents);
+ rowUp->setIconSet(BarIconSet("1uparrow"));
+ rowUp->setTextLabel(i18n("Move Item &Up"), true);
+ vlayout->addWidget(rowUp);
+ m_buttons.insert(BRowUp, rowUp);
+ connect(rowUp, SIGNAL(clicked()), this, SLOT(MoveRowUp()));
+
+ QToolButton *rowDown = new QToolButton(m_contents);
+ rowDown->setIconSet(BarIconSet("1downarrow"));
+ rowDown->setTextLabel(i18n("Move Item &Down"), true);
+ vlayout->addWidget(rowDown);
+ m_buttons.insert(BRowDown, rowDown);
+ connect(rowDown, SIGNAL(clicked()), this, SLOT(MoveRowDown()));
+ vlayout->addStretch();
+
+ //// The listview ///////////
+ m_listview = new KListView(m_contents, "editlistview_listview");
+ m_listview->setItemsRenameable(true);
+ m_listview->setItemsMovable(true);
+ m_listview->setDragEnabled(true);
+ m_listview->setAllColumnsShowFocus(true);
+ m_listview->setRootIsDecorated(true);
+ m_listview->setDropVisualizer(true);
+ m_listview->setAcceptDrops(true);
+ m_listview->setSorting(-1);
+ layout->addWidget(m_listview);
+ m_listview->setFocus();
+ connect(m_listview, SIGNAL(currentChanged(QListViewItem*)), this, SLOT(updateButtons(QListViewItem*)));
+ connect(m_listview, SIGNAL(moved(QListViewItem*, QListViewItem*, QListViewItem*)), this, SLOT(updateButtons(QListViewItem*)));
+
+ /////////////////// Setup the columns page ////////////////
+ QHBoxLayout *hbox = new QHBoxLayout(m_column, 0, 6);
+
+ // The "item properties" field
+ m_editor = new KoProperty::Editor(m_column, "editcolumn_propeditor");
+ m_propSet = new KoProperty::Set(this, "columns");
+ m_propSet->addProperty(new KoProperty::Property("caption", "Caption", i18n("Caption"),i18n("Caption")));
+ m_propSet->addProperty(new KoProperty::Property("width", 100, i18n("Width"), i18n("Width")));
+ m_propSet->addProperty(new KoProperty::Property("clickable", QVariant(true, 3), i18n("Clickable"), i18n("Clickable") ));
+ m_propSet->addProperty(new KoProperty::Property("resizable", QVariant(true, 3), i18n("Resizable"), i18n("Resizable") ));
+ m_propSet->addProperty(new KoProperty::Property("fullwidth", QVariant(false, 3), i18n("Full Width"), i18n("Full Width") ));
+ m_editor->changeSet(m_propSet);
+ connect(m_propSet, SIGNAL(propertyChanged(KoProperty::Set & KoProperty::Property&)),
+ this, SLOT(changeProperty(KoProperty::Set & KoProperty::Property&)));
+
+ // Setup the icon toolbar //////////
+ QVBoxLayout *vbox = new QVBoxLayout(hbox, 3);
+ QToolButton *add = new QToolButton(m_column);
+ add->setIconSet(BarIconSet("edit_add"));
+ add->setTextLabel(i18n("&Add Item"), true);
+ vbox->addWidget(add);
+ m_buttons.insert(BColAdd, add);
+ connect(add, SIGNAL(clicked()), this, SLOT(newItem()));
+
+ QToolButton *remove = new QToolButton(m_column);
+ remove->setIconSet(BarIconSet("edit_remove"));
+ remove->setTextLabel(i18n("&Remove Item"), true);
+ vbox->addWidget(remove);
+ m_buttons.insert(BColRem, remove);
+ connect(remove, SIGNAL(clicked()), this, SLOT(removeItem()));
+
+ QToolButton *up = new QToolButton(m_column);
+ up->setIconSet(BarIconSet("1uparrow"));
+ up->setTextLabel(i18n("Move Item &Up"), true);
+ vbox->addWidget(up);
+ m_buttons.insert(BColUp, up);
+ connect(up, SIGNAL(clicked()), this, SLOT(MoveItemUp()));
+
+ QToolButton *down = new QToolButton(m_column);
+ down->setIconSet(BarIconSet("1downarrow"));
+ down->setTextLabel(i18n("Move Item &Down"), true);
+ vbox->addWidget(down);
+ m_buttons.insert(BColDown, down);
+ connect(down, SIGNAL(clicked()), this, SLOT(MoveItemDown()));
+ vbox->addStretch();
+
+ // The listbox with columns name /////
+ m_listbox = new KListBox(m_column, "editlistview_columns");
+ m_listbox->setFocus();
+ hbox->insertWidget(0, m_listbox);
+ hbox->addWidget(m_editor);
+ connect(m_listbox, SIGNAL(currentChanged(QListBoxItem*)), this, SLOT(updateItemProperties(QListBoxItem*)));
+
+ //// Init dialog and display it ////////////////////////
+ setInitialSize(QSize(500, 300), true);
+}
+
+int
+EditListViewDialog::exec(QListView *listview)
+{
+ if(!listview)
+ {
+ kdDebug() << "EditListViewDialog ERROR: no listview " << endl;
+ return 0;
+ }
+
+ // We copy the contents of the listview into our listview
+ for(int i = 0; i < listview->columns(); i++)
+ {
+ m_listview->addColumn(listview->columnText(i), listview->columnWidth(i));
+ m_listview->header()->setClickEnabled(listview->header()->isClickEnabled(i), i);
+ m_listview->header()->setResizeEnabled(listview->header()->isResizeEnabled(i), i);
+ m_listview->header()->setStretchEnabled(listview->header()->isStretchEnabled(i), i);
+ m_listview->setRenameable(i, true);
+ }
+ QListViewItem *item = listview->firstChild();
+ while(item) {
+ loadChildNodes(m_listview, item, 0);
+ item = item->nextSibling();
+ }
+
+ m_listview->setSelected(m_listview->firstChild(), true);
+ if(!m_listview->firstChild())
+ updateButtons(0);
+
+ for(int i = 0; i < listview->columns(); i++)
+ m_listbox->insertItem(listview->columnText(i));
+ m_listbox->setSelected(0, true);
+
+ // and we exec the dialog
+ int r = KDialogBase::exec();
+ if(r == QDialog::Accepted)
+ {
+ listview->clear();
+ // We copy the contents of our listview back in the listview
+ for(int i = 0; i < m_listview->columns(); i++)
+ {
+ if(listview->columns() <= i)
+ listview->addColumn(m_listview->columnText(i), m_listview->columnWidth(i));
+ else
+ {
+ listview->setColumnText(i, m_listview->columnText(i));
+ listview->setColumnWidth(i, m_listview->columnWidth(i));
+ }
+ listview->header()->setClickEnabled(m_listview->header()->isClickEnabled(i), i);
+ listview->header()->setResizeEnabled(m_listview->header()->isResizeEnabled(i), i);
+ listview->header()->setStretchEnabled(m_listview->header()->isStretchEnabled(i), i);
+ }
+
+ QListViewItem *item = m_listview->firstChild();
+ while(item)
+ {
+ loadChildNodes(listview, item, 0);
+ item = item->nextSibling();
+ }
+ }
+ return r;
+}
+
+/// Columns page slots ///////
+void
+EditListViewDialog::changeProperty(KoProperty::Set& set, KoProperty::Property& property)
+{
+ if(&set != m_propSet)
+ return;
+
+ QString name = property.name();
+ QVariant value = property.value();
+ if(name == "caption") {
+ m_propSet->blockSignals(true); // we need to block signals because changeItem will modify selection, and call updateItemProperties
+ m_listbox->changeItem(value.toString(), m_listbox->currentItem());
+ m_listview->setColumnText(m_listbox->currentItem(), value.toString());
+ m_propSet->blockSignals(false);
+ }
+ else if(name == "width")
+ m_listview->setColumnWidth(m_listbox->currentItem(), value.toInt());
+ else if(name == "resizable")
+ m_listview->header()->setResizeEnabled(value.toBool(), m_listbox->currentItem());
+ else if(name == "clickable")
+ m_listview->header()->setClickEnabled(value.toBool(), m_listbox->currentItem());
+ else if(name == "fullwidth")
+ m_listview->header()->setStretchEnabled(value.toBool(), m_listbox->currentItem());
+}
+
+void
+EditListViewDialog::updateItemProperties(QListBoxItem *item)
+{
+ if(!item)
+ return;
+
+ int id = m_listbox->index(item);
+ if(m_propSet) {
+ m_propSet->blockSignals(true); // we don't want changeProperty to be called
+ (*m_propSet)["caption"].setValue(m_listview->columnText(id), false);
+ (*m_propSet)["width"].setValue(m_listview->columnWidth(id), false);
+ (*m_propSet)["clickable"].setValue(QVariant(m_listview->header()->isClickEnabled(id), 4), false);
+ (*m_propSet)["resizable"].setValue(QVariant(m_listview->header()->isResizeEnabled(id), 4), false);
+ (*m_propSet)["fullwidth"].setValue(QVariant(m_listview->header()->isStretchEnabled(id), 4), false);
+ m_propSet->blockSignals(false);
+ m_editor->changeSet(m_propSet);
+ }
+
+ m_buttons[BColUp]->setEnabled(item->prev());
+ m_buttons[BColDown]->setEnabled(item->next());
+}
+
+void
+EditListViewDialog::newItem()
+{
+ m_listbox->insertItem(i18n("New Column"));
+ m_listview->addColumn(i18n("New Column"));
+ m_listview->setRenameable(m_listview->columns() - 1, true);
+ m_listbox->setCurrentItem(m_listbox->count() - 1);
+ m_buttons[BColRem]->setEnabled(true);
+}
+
+void
+EditListViewDialog::removeItem()
+{
+ int current = m_listbox->currentItem();
+ if(m_listbox->item(current + 1))
+ m_listbox->setCurrentItem(current +1);
+ else
+ m_listbox->setCurrentItem(current - 1);
+
+ m_listview->removeColumn(current);
+ m_listbox->removeItem(current);
+ if(m_listbox->count() == 0)
+ m_buttons[BColRem]->setEnabled(false);
+}
+
+void
+EditListViewDialog::MoveItemUp()
+{
+ int current = m_listbox->currentItem();
+ QString text = m_listbox->text(current);
+ m_listbox->blockSignals(true);
+
+ m_listbox->changeItem(m_listbox->text(current - 1), current);
+ m_listview->setColumnText(current, m_listview->columnText(current - 1));
+ m_listview->setColumnWidth(current, m_listview->columnWidth(current - 1));
+ m_listview->header()->setClickEnabled(m_listview->header()->isClickEnabled(current - 1), current);
+ m_listview->header()->setResizeEnabled(m_listview->header()->isResizeEnabled(current - 1), current);
+ m_listview->header()->setStretchEnabled(m_listview->header()->isStretchEnabled(current - 1), current);
+
+ m_listbox->changeItem(text, current - 1);
+ m_listview->setColumnText(current - 1, (*m_propSet)["caption"].value().toString());
+ m_listview->setColumnWidth(current - 1,(*m_propSet)["width"].value().toBool());
+ m_listview->header()->setClickEnabled((*m_propSet)["clickable"].value().toBool(), current - 1);
+ m_listview->header()->setResizeEnabled((*m_propSet)["resizable"].value().toBool(), current - 1);
+ m_listview->header()->setStretchEnabled((*m_propSet)["fullwidth"].value().toBool(), current - 1);
+
+ m_listbox->blockSignals(false);
+ m_listbox->setCurrentItem(current - 1);
+}
+
+void
+EditListViewDialog::MoveItemDown()
+{
+ int current = m_listbox->currentItem();
+ QString text = m_listbox->text(current);
+ m_listbox->blockSignals(true);
+
+ m_listbox->changeItem(m_listbox->text(current+1), current);
+ m_listview->setColumnText(current, m_listview->columnText(current + 1));
+ m_listview->setColumnWidth(current, m_listview->columnWidth(current + 1));
+ m_listview->header()->setClickEnabled(m_listview->header()->isClickEnabled(current + 1), current);
+ m_listview->header()->setResizeEnabled(m_listview->header()->isResizeEnabled(current + 1), current);
+ m_listview->header()->setStretchEnabled(m_listview->header()->isStretchEnabled(current + 1), current);
+
+ m_listbox->changeItem(text, current+1);
+ m_listview->setColumnText(current + 1, (*m_propSet)["caption"].value().toString());
+ m_listview->setColumnWidth(current + 1,(*m_propSet)["width"].value().toBool());
+ m_listview->header()->setClickEnabled((*m_propSet)["clickable"].value().toBool(), current + 1);
+ m_listview->header()->setResizeEnabled((*m_propSet)["resizable"].value().toBool(), current + 1);
+ m_listview->header()->setStretchEnabled((*m_propSet)["fullwidth"].value().toBool(), current + 1);
+
+ m_listbox->blockSignals(false);
+ m_listbox->setCurrentItem(current + 1);
+}
+
+
+/// Contents page slots ////////
+void
+EditListViewDialog::updateButtons(QListViewItem *item)
+{
+ if(!item)
+ {
+ for(int i = BNewChild; i <= BRowDown; i++)
+ m_buttons[i]->setEnabled(false);
+ return;
+ }
+
+ m_buttons[BNewChild]->setEnabled(true);
+ m_buttons[BRemRow]->setEnabled(true);
+ m_buttons[BRowUp]->setEnabled( (item->itemAbove() && (item->itemAbove()->parent() == item->parent())) );
+ m_buttons[BRowDown]->setEnabled(item->nextSibling());
+}
+
+void
+EditListViewDialog::loadChildNodes(QListView *listview, QListViewItem *item, QListViewItem *parent)
+{
+ QListViewItem *newItem;
+ if(listview->inherits("KListView"))
+ {
+ if(parent)
+ newItem = new KListViewItem(parent);
+ else
+ newItem = new KListViewItem(listview);
+ }
+ else
+ {
+ if(parent)
+ newItem = new QListViewItem(parent);
+ else
+ newItem = new QListViewItem(listview);
+ }
+
+ // We need to move the item at the end, which is the expected behaviour (by default it is inserted at the beginning)
+ QListViewItem *last;
+ if(parent)
+ last = parent->firstChild();
+ else
+ last = listview->firstChild();
+
+ while(last->nextSibling())
+ last = last->nextSibling();
+ newItem->moveItem(last);
+
+ // We copy the text of all the columns
+ for(int i = 0; i < listview->columns(); i++)
+ newItem->setText(i, item->text(i));
+
+ QListViewItem *child = item->firstChild();
+ if(child)
+ newItem->setOpen(true);
+ while(child) {
+ loadChildNodes(listview, child, newItem);
+ child = child->nextSibling();
+ }
+}
+
+void
+EditListViewDialog::newRow()
+{
+ KListViewItem *parent = (KListViewItem*)m_listview->selectedItem();
+ if(parent)
+ parent = (KListViewItem*)parent->parent();
+ KListViewItem *item;
+ if(parent)
+ item = new KListViewItem(parent, m_listview->selectedItem());
+ else
+ item = new KListViewItem(m_listview, m_listview->selectedItem());
+ item->setText(0, i18n("New Item"));
+ m_listview->setCurrentItem(item);
+}
+
+void
+EditListViewDialog::newChildRow()
+{
+ KListViewItem *parent = (KListViewItem*)m_listview->currentItem();
+ KListViewItem *item;
+ if(parent)
+ item = new KListViewItem(parent);
+ else
+ item = new KListViewItem(m_listview, m_listview->currentItem());
+ item->setText(0, i18n("Sub Item"));
+
+ m_listview->setCurrentItem(item);
+ parent->setOpen(true);
+}
+
+void
+EditListViewDialog::removeRow()
+{
+ delete m_listview->currentItem();
+}
+
+void
+EditListViewDialog::MoveRowUp()
+{
+ QListViewItem *item = m_listview->currentItem()->itemAbove();
+ item->moveItem(m_listview->currentItem());
+ updateButtons(m_listview->currentItem());
+}
+
+void
+EditListViewDialog::MoveRowDown()
+{
+ QListViewItem *before = m_listview->currentItem();
+ before->moveItem(before->nextSibling());
+ updateButtons(before);
+}
+
+}
+
+#include "editlistviewdialog.moc"
diff --git a/kexi/formeditor/editlistviewdialog.h b/kexi/formeditor/editlistviewdialog.h
new file mode 100644
index 00000000..09de4429
--- /dev/null
+++ b/kexi/formeditor/editlistviewdialog.h
@@ -0,0 +1,93 @@
+/* This file is part of the KDE project
+ Copyright (C) 2004 Cedric Pasteur <cedric.pasteur@free.fr>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+*/
+
+#ifndef EDITLISTVIEW_DIALOG_H
+#define EDITLISTVIEW_DIALOG_H
+
+#include <qintdict.h>
+#include <qtoolbutton.h>
+#include <kdialogbase.h>
+
+class QFrame;
+class QListView;
+class QListViewItem;
+class KListViewItem;
+class KListView;
+class KListBox;
+class QListBoxItem;
+
+namespace KoProperty {
+ class Property;
+ class Set;
+ class Editor;
+}
+
+namespace KFormDesigner {
+
+//! A dialog to edit the contents of a listvuew (KListView or QListView)
+/*! The dialog contains two pages, one to edit columns and one to edit ist items.
+ KoProperty::Editor is used in columns to edit column properties
+ (there are two properties not supported by Qt Designer: 'width' and 'resizable').
+ The user can enter list contents inside the list
+ using KListViewItem::setRenameable(). Pixmaps are not yet supported. */
+class KFORMEDITOR_EXPORT EditListViewDialog : public KDialogBase
+{
+ Q_OBJECT
+
+ public:
+ EditListViewDialog(QWidget *parent);
+ ~EditListViewDialog() {}
+
+ int exec(QListView *listview);
+
+ public slots:
+ // Columns page
+ void updateItemProperties(QListBoxItem*);
+ void newItem();
+ void removeItem();
+ void MoveItemUp();
+ void MoveItemDown();
+ void changeProperty(KoProperty::Set& set, KoProperty::Property& property);
+
+ // Contents page
+ void updateButtons(QListViewItem*);
+ void newRow();
+ void newChildRow();
+ void removeRow();
+ void MoveRowUp();
+ void MoveRowDown();
+
+ protected:
+ /*! Loads all child items of \a item into \a listview (may be different from the \a items 's listview) as child of \a parent item.
+ This is used to copy the contents of a listview into another listview. */
+ void loadChildNodes(QListView *listview, QListViewItem *item, QListViewItem *parent);
+
+ protected:
+ enum { BNewRow = 10, BNewChild, BRemRow, BRowUp, BRowDown , BColAdd = 20, BColRem, BColUp, BColDown };
+ KoProperty::Editor *m_editor;
+ KoProperty::Set *m_propSet;
+ QFrame *m_contents, *m_column;
+ KListBox *m_listbox;
+ KListView *m_listview;
+ QIntDict<QToolButton> m_buttons;
+};
+
+}
+
+#endif
diff --git a/kexi/formeditor/events.cpp b/kexi/formeditor/events.cpp
new file mode 100644
index 00000000..e96b9f4f
--- /dev/null
+++ b/kexi/formeditor/events.cpp
@@ -0,0 +1,145 @@
+/* This file is part of the KDE project
+ Copyright (C) 2004 Cedric Pasteur <cedric.pasteur@free.fr>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+*/
+
+#include <qdom.h>
+#include <kdebug.h>
+
+#include "events.h"
+
+namespace KFormDesigner {
+
+Connection::Connection(const QString &sender, const QString &signal,
+ const QString &receiver, const QString &slot)
+{
+ m_sender = sender;
+ m_signal = signal;
+ m_receiver = receiver;
+ m_slot = slot;
+}
+
+ ///////////////////////////////////////
+
+ConnectionBuffer::ConnectionBuffer()
+{
+ setAutoDelete(true);
+}
+
+void
+ConnectionBuffer::fixName(const QString &oldName, const QString &newName)
+{
+ for(Connection *c = first(); c; c = next())
+ {
+ if(c->sender() == oldName)
+ c->setSender(newName);
+ if(c->receiver() == oldName)
+ c->setReceiver(newName);
+ }
+}
+
+ConnectionBuffer*
+ConnectionBuffer::allConnectionsForWidget(const QString &widget)
+{
+ ConnectionBuffer *list = new ConnectionBuffer();
+ list->setAutoDelete(false); // or it will delete all our connections
+ for(Connection *c = first(); c; c = next())
+ {
+ if((c->sender() == widget) || (c->receiver() == widget))
+ list->append(c);
+ }
+
+ return list;
+}
+
+void
+ConnectionBuffer::save(QDomNode &parentNode)
+{
+ if(isEmpty())
+ return;
+
+ QDomDocument domDoc = parentNode.ownerDocument();
+ QDomElement connections;
+ if(!parentNode.namedItem("connections").isNull())
+ connections = parentNode.namedItem("connections").toElement();
+ else
+ connections = domDoc.createElement("connections");
+ parentNode.appendChild(connections);
+
+ for(Connection *c = first(); c; c = next())
+ {
+ QDomElement connection = domDoc.createElement("connection");
+ connection.setAttribute("language", "C++");
+ connections.appendChild(connection);
+
+ QDomElement sender = domDoc.createElement("sender");
+ connection.appendChild(sender);
+ QDomText senderText = domDoc.createTextNode(c->sender());
+ sender.appendChild(senderText);
+
+ QDomElement signal = domDoc.createElement("signal");
+ connection.appendChild(signal);
+ QDomText signalText = domDoc.createTextNode(c->signal());
+ signal.appendChild(signalText);
+
+ QDomElement receiver = domDoc.createElement("receiver");
+ connection.appendChild(receiver);
+ QDomText receiverText = domDoc.createTextNode(c->receiver());
+ receiver.appendChild(receiverText);
+
+ QDomElement slot = domDoc.createElement("slot");
+ connection.appendChild(slot);
+ QDomText slotText = domDoc.createTextNode(c->slot());
+ slot.appendChild(slotText);
+ }
+}
+
+void
+ConnectionBuffer::saveAllConnectionsForWidget(const QString &widget, QDomNode parentNode)
+{
+ ConnectionBuffer *buff = allConnectionsForWidget(widget);
+ buff->save(parentNode);
+ delete buff;
+}
+
+void
+ConnectionBuffer::load(QDomNode node)
+{
+ for(QDomNode n = node.firstChild(); !n.isNull(); n = n.nextSibling())
+ {
+ Connection *conn = new Connection();
+ conn->setSender(n.namedItem("sender").toElement().text());
+ conn->setSignal(n.namedItem("signal").toElement().text());
+ conn->setReceiver(n.namedItem("receiver").toElement().text());
+ conn->setSlot(n.namedItem("slot").toElement().text());
+ append(conn);
+ }
+}
+
+void
+ConnectionBuffer::removeAllConnectionsForWidget(const QString &widget)
+{
+ for(Connection *c = first(); c; c = next())
+ {
+ if((c->sender() == widget) || (c->receiver() == widget))
+ removeRef(c);
+ }
+}
+
+}
+
+//#include "events.moc"
diff --git a/kexi/formeditor/events.h b/kexi/formeditor/events.h
new file mode 100644
index 00000000..c9e1b2cd
--- /dev/null
+++ b/kexi/formeditor/events.h
@@ -0,0 +1,78 @@
+/* This file is part of the KDE project
+ Copyright (C) 2004 Cedric Pasteur <cedric.pasteur@free.fr>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+*/
+
+#ifndef KFORMDESIGNEREVENTS_H
+#define KFORMDESIGNEREVENTS_H
+
+#include <qptrlist.h>
+#include <qstring.h>
+
+class QDomNode;
+
+namespace KFormDesigner {
+
+class KFORMEDITOR_EXPORT Connection
+{
+ public:
+ Connection(const QString &sender, const QString &signal,
+ const QString &receiver, const QString &slot);
+ Connection() {;}
+ ~Connection() {;}
+
+ QString sender() const { return m_sender; }
+ QString receiver() const { return m_receiver; }
+ QString signal() const { return m_signal; }
+ QString slot() const { return m_slot; }
+
+ void setSender(const QString &v) { m_sender = v; }
+ void setReceiver(const QString &v) { m_receiver = v; }
+ void setSignal(const QString &v) { m_signal = v; }
+ void setSlot(const QString &v) { m_slot = v; }
+
+ protected:
+ QString m_sender;
+ QString m_signal;
+ QString m_receiver;
+ QString m_slot;
+};
+
+typedef QPtrList<Connection> ConnectionList;
+
+class KFORMEDITOR_EXPORT ConnectionBuffer : public ConnectionList
+{
+ public:
+ ConnectionBuffer();
+ ~ConnectionBuffer() {;}
+
+ void save(QDomNode &parentNode);
+ void load(QDomNode parentNode);
+
+ /*! This function is called when a widget is renamed from \a oldname
+ to \a newname. All the Connections for this widget are updated. */
+ void fixName(const QString &oldname, const QString &newName);
+
+ ConnectionBuffer* allConnectionsForWidget(const QString &widget);
+ void saveAllConnectionsForWidget(const QString &widget, QDomNode parentNode);
+ void removeAllConnectionsForWidget(const QString &widget);
+};
+
+}
+
+#endif
+
diff --git a/kexi/formeditor/factories/Makefile.am b/kexi/formeditor/factories/Makefile.am
new file mode 100644
index 00000000..e19bf6b3
--- /dev/null
+++ b/kexi/formeditor/factories/Makefile.am
@@ -0,0 +1,20 @@
+include $(top_srcdir)/kexi/Makefile.global
+
+INCLUDES = -I$(top_srcdir)/kexi -I$(top_srcdir)/kexi/formeditor \
+ -I$(top_srcdir)/kexi/core \
+ -I$(top_srcdir)/lib -I$(top_srcdir)/lib/koproperty -I$(top_srcdir)/lib/kofficecore $(all_includes)
+kde_module_LTLIBRARIES = kformdesigner_containers.la kformdesigner_stdwidgets.la
+kformdesigner_containers_la_LDFLAGS = $(all_libraries) $(KDE_PLUGIN) $(VER_INFO) -module
+kformdesigner_containers_la_SOURCES = containerfactory.cpp
+kformdesigner_containers_la_LIBADD = $(top_builddir)/kexi/formeditor/libkformdesigner.la
+
+kformdesigner_stdwidgets_la_LDFLAGS = $(all_libraries) $(KDE_PLUGIN) $(VER_INFO) -module
+kformdesigner_stdwidgets_la_SOURCES = stdwidgetfactory.cpp
+kformdesigner_stdwidgets_la_LIBADD = $(top_builddir)/kexi/formeditor/libkformdesigner.la
+
+
+servicesdir=$(kde_servicesdir)/kformdesigner
+services_DATA = kformdesigner_containers.desktop kformdesigner_stdwidgets.desktop
+
+METASOURCES = AUTO
+
diff --git a/kexi/formeditor/factories/containerfactory.cpp b/kexi/formeditor/factories/containerfactory.cpp
new file mode 100644
index 00000000..d098c290
--- /dev/null
+++ b/kexi/formeditor/factories/containerfactory.cpp
@@ -0,0 +1,936 @@
+/* This file is part of the KDE project
+ Copyright (C) 2003 Lucijan Busch <lucijan@kde.org>
+ Copyright (C) 2004 Cedric Pasteur <cedric.pasteur@free.fr>
+ Copyright (C) 2006-2007 Jaroslaw Staniek <js@iidea.pl>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+*/
+
+#include <qwidgetstack.h>
+#include <qframe.h>
+#include <qbuttongroup.h>
+#include <qwidget.h>
+#include <qhbox.h>
+#include <qvbox.h>
+#include <qstring.h>
+#include <qpopupmenu.h>
+#include <qdom.h>
+#include <qevent.h>
+#include <qobjectlist.h>
+#include <qpainter.h>
+#include <qvaluevector.h>
+#include <qfileinfo.h>
+#include <qscrollview.h>
+#include <qtabbar.h>
+#include <qsplitter.h>
+#include <qlayout.h>
+
+#include <kiconloader.h>
+#include <kgenericfactory.h>
+#include <ktextedit.h>
+#include <klineedit.h>
+#include <klocale.h>
+#include <kdebug.h>
+#include <kdeversion.h>
+
+#include "containerfactory.h"
+#include "container.h"
+#include "form.h"
+#include "formIO.h"
+#include "objecttree.h"
+#include "commands.h"
+#include "formmanager.h"
+#include "widgetlibrary.h"
+#include <formeditor/utils.h>
+
+#if KDE_VERSION < KDE_MAKE_VERSION(3,1,9)
+# define KInputDialog QInputDialog
+# include <qinputdialog.h>
+# include <qlineedit.h>
+#else
+# include <kinputdialog.h>
+#endif
+
+ContainerWidget::ContainerWidget(QWidget *parent, const char *name)
+ : QWidget(parent, name)
+{
+}
+
+ContainerWidget::~ContainerWidget()
+{
+}
+
+QSize ContainerWidget::sizeHint() const
+{
+ return QSize(30,30); //default
+}
+
+void ContainerWidget::dragMoveEvent( QDragMoveEvent *e )
+{
+ QWidget::dragMoveEvent(e);
+ emit handleDragMoveEvent(e);
+}
+
+void ContainerWidget::dropEvent( QDropEvent *e )
+{
+ QWidget::dropEvent(e);
+ emit handleDropEvent(e);
+}
+
+////////////////////////
+
+GroupBox::GroupBox(const QString & title, QWidget *parent, const char *name)
+ : QGroupBox(title, parent, name)
+{
+}
+
+GroupBox::~GroupBox()
+{
+}
+
+void GroupBox::dragMoveEvent( QDragMoveEvent *e )
+{
+ QGroupBox::dragMoveEvent(e);
+ emit handleDragMoveEvent(e);
+}
+
+void GroupBox::dropEvent( QDropEvent *e )
+{
+ QGroupBox::dropEvent(e);
+ emit handleDropEvent(e);
+}
+
+////////////////////////
+
+KFDTabWidget::KFDTabWidget(QWidget *parent, const char *name)
+ : KFormDesigner::TabWidget(parent, name)
+{
+}
+
+KFDTabWidget::~KFDTabWidget()
+{
+}
+
+QSize
+KFDTabWidget::sizeHint() const
+{
+ QSize s(30,30); // default min size
+ for(int i=0; i < count(); i++)
+ s = s.expandedTo( KFormDesigner::getSizeFromChildren(page(i)) );
+
+ return s + QSize(10/*margin*/, tabBar()->height() + 20/*margin*/);
+}
+
+void KFDTabWidget::dragMoveEvent( QDragMoveEvent *e )
+{
+ TabWidgetBase::dragMoveEvent( e );
+ if (dynamic_cast<ContainerWidget*>(currentPage()))
+ emit dynamic_cast<ContainerWidget*>(currentPage())->handleDragMoveEvent(e);
+ emit handleDragMoveEvent(e);
+}
+
+void KFDTabWidget::dropEvent( QDropEvent *e )
+{
+ TabWidgetBase::dropEvent( e );
+ if (dynamic_cast<ContainerWidget*>(currentPage()))
+ emit dynamic_cast<ContainerWidget*>(currentPage())->handleDropEvent(e);
+ emit handleDropEvent(e);
+}
+
+/// Various layout widgets /////////////////:
+
+HBox::HBox(QWidget *parent, const char *name)
+ : QFrame(parent, name), m_preview(false)
+{}
+
+void
+HBox::paintEvent(QPaintEvent *)
+{
+ if(m_preview) return;
+ QPainter p(this);
+ p.setPen(QPen(red, 2, Qt::DashLine));
+ p.drawRect(1, 1, width()-1, height() - 1);
+}
+
+VBox::VBox(QWidget *parent, const char *name)
+ : QFrame(parent, name), m_preview(false)
+{}
+
+void
+VBox::paintEvent(QPaintEvent *)
+{
+ if(m_preview) return;
+ QPainter p(this);
+ p.setPen(QPen(blue, 2, Qt::DashLine));
+ p.drawRect(1, 1, width()-1, height() - 1);
+}
+
+Grid::Grid(QWidget *parent, const char *name)
+ : QFrame(parent, name), m_preview(false)
+{}
+
+void
+Grid::paintEvent(QPaintEvent *)
+{
+ if(m_preview) return;
+ QPainter p(this);
+ p.setPen(QPen(darkGreen, 2, Qt::DashLine));
+ p.drawRect(1, 1, width()-1, height() - 1);
+}
+
+HFlow::HFlow(QWidget *parent, const char *name)
+ : QFrame(parent, name), m_preview(false)
+{}
+
+void
+HFlow::paintEvent(QPaintEvent *)
+{
+ if(m_preview) return;
+ QPainter p(this);
+ p.setPen(QPen(magenta, 2, Qt::DashLine));
+ p.drawRect(1, 1, width()-1, height() - 1);
+}
+
+VFlow::VFlow(QWidget *parent, const char *name)
+ : QFrame(parent, name), m_preview(false)
+{}
+
+void
+VFlow::paintEvent(QPaintEvent *)
+{
+ if(m_preview) return;
+ QPainter p(this);
+ p.setPen(QPen(cyan, 2, Qt::DashLine));
+ p.drawRect(1, 1, width()-1, height() - 1);
+}
+
+QSize
+VFlow::sizeHint() const
+{
+ if(layout())
+ return layout()->sizeHint();
+ else
+ return QSize(700, 50); // default
+}
+
+/////// Tab related KCommand (to allow tab creation/deletion undoing)
+
+InsertPageCommand::InsertPageCommand(KFormDesigner::Container *container, QWidget *parent)
+ : KCommand()
+{
+ m_containername = container->widget()->name();
+ m_form = container->form();
+ m_parentname = parent->name();
+ m_pageid = -1;
+}
+
+void
+InsertPageCommand::execute()
+{
+ KFormDesigner::Container *container = m_form->objectTree()->lookup(m_containername)->container();
+ QWidget *parent = m_form->objectTree()->lookup(m_parentname)->widget();
+ if(m_name.isEmpty()) {
+ m_name = container->form()->objectTree()->generateUniqueName(
+ container->form()->library()->displayName("QWidget").latin1(),
+ /*!numberSuffixRequired*/false);
+ }
+
+ QWidget *page = container->form()->library()->createWidget("QWidget", parent, m_name.latin1(), container);
+// QWidget *page = new ContainerWidget(parent, m_name.latin1());
+// new KFormDesigner::Container(container, page, parent);
+
+ QCString classname = parent->className();
+ if(classname == "KFDTabWidget")
+ {
+ TabWidgetBase *tab = dynamic_cast<TabWidgetBase*>(parent);
+ QString n = i18n("Page %1").arg(tab->count() + 1);
+ tab->addTab(page, n);
+ tab->showPage(page);
+
+ KFormDesigner::ObjectTreeItem *item = container->form()->objectTree()->lookup(m_name);
+ item->addModifiedProperty("title", n);
+ }
+ else if(classname == "QWidgetStack")
+ {
+ QWidgetStack *stack = (QWidgetStack*)parent;
+ stack->addWidget(page, m_pageid);
+ stack->raiseWidget(page);
+ m_pageid = stack->id(page);
+
+ KFormDesigner::ObjectTreeItem *item = container->form()->objectTree()->lookup(m_name);
+ item->addModifiedProperty("id", stack->id(page));
+ }
+}
+
+void
+InsertPageCommand::unexecute()
+{
+ QWidget *page = m_form->objectTree()->lookup(m_name)->widget();
+ QWidget *parent = m_form->objectTree()->lookup(m_parentname)->widget();
+
+ KFormDesigner::WidgetList list;
+ list.append(page);
+ KCommand *com = new KFormDesigner::DeleteWidgetCommand(list, m_form);
+
+ QCString classname = parent->className();
+ if(classname == "KFDTabWidget")
+ {
+ TabWidgetBase *tab = dynamic_cast<TabWidgetBase*>(parent);
+ tab->removePage(page);
+ }
+ else if(classname == "QWidgetStack")
+ {
+ QWidgetStack *stack = (QWidgetStack*)parent;
+ int id = stack->id(page) - 1;
+ while(!stack->widget(id))
+ id--;
+
+ stack->raiseWidget(id);
+ stack->removeWidget(page);
+ }
+
+ com->execute();
+ delete com;
+}
+
+QString
+InsertPageCommand::name() const
+{
+ return i18n("Add Page");
+}
+
+/////// Sub forms ////////////////////////:
+
+SubForm::SubForm(QWidget *parent, const char *name)
+: QScrollView(parent, name), m_form(0), m_widget(0)
+{
+ setFrameStyle(QFrame::WinPanel | QFrame::Sunken);
+ viewport()->setPaletteBackgroundColor(colorGroup().mid());
+}
+
+void
+SubForm::setFormName(const QString &name)
+{
+ if(name.isEmpty())
+ return;
+
+ QFileInfo info(name);
+ if(!info.exists()
+ || (KFormDesigner::FormManager::self()->activeForm()
+ && (info.fileName() == KFormDesigner::FormManager::self()->activeForm()->filename()) ) )
+ return; // we check if this is valid form
+
+ // we create the container widget
+ delete m_widget;
+ m_widget = new QWidget(viewport(), "subform_widget");
+// m_widget->show();
+ addChild(m_widget);
+ m_form = new KFormDesigner::Form(
+ KFormDesigner::FormManager::self()->activeForm()->library(), this->name());
+ m_form->createToplevel(m_widget);
+
+ // and load the sub form
+ KFormDesigner::FormIO::loadFormFromFile(m_form, m_widget, name);
+ m_form->setDesignMode(false);
+
+ m_formName = name;
+
+}
+
+///// The factory /////////////////////////
+
+ContainerFactory::ContainerFactory(QObject *parent, const char *, const QStringList &)
+ : KFormDesigner::WidgetFactory(parent, "containers")
+{
+ KFormDesigner::WidgetInfo *wBtnGroup = new KFormDesigner::WidgetInfo(this);
+ wBtnGroup->setPixmap("frame");
+ wBtnGroup->setClassName("QButtonGroup");
+ wBtnGroup->setName(i18n("Button Group"));
+ wBtnGroup->setNamePrefix(
+ i18n("Widget name. This string will be used to name widgets of this class. It must _not_ contain white spaces and non latin1 characters.", "buttonGroup"));
+ wBtnGroup->setDescription(i18n("A simple container to group buttons"));
+ addClass(wBtnGroup);
+
+ KFormDesigner::WidgetInfo *wTabWidget = new KFormDesigner::WidgetInfo(this);
+ wTabWidget->setPixmap("tabwidget");
+ wTabWidget->setClassName("KFDTabWidget");
+#if KDE_VERSION >= KDE_MAKE_VERSION(3,1,9)
+ wTabWidget->addAlternateClassName("KTabWidget");
+ wTabWidget->addAlternateClassName("QTabWidget");
+//tmp: wTabWidget->setSavingName("QTabWidget");
+ wTabWidget->setSavingName("KTabWidget");
+#else
+ wTabWidget->setSavingName("QTabWidget");
+#endif
+ wTabWidget->setIncludeFileName("ktabwidget.h");
+ wTabWidget->setName(i18n("Tab Widget"));
+ wTabWidget->setNamePrefix(
+ i18n("Widget name. This string will be used to name widgets of this class. It must _not_ contain white spaces and non latin1 characters.", "tabWidget"));
+ wTabWidget->setDescription(i18n("A widget to display multiple pages using tabs"));
+ addClass(wTabWidget);
+
+ KFormDesigner::WidgetInfo *wWidget = new KFormDesigner::WidgetInfo(this);
+ wWidget->setPixmap("frame");
+ wWidget->setClassName("QWidget");
+ wWidget->addAlternateClassName("ContainerWidget");
+ wWidget->setName(i18n("Basic container"));
+ wWidget->setNamePrefix(
+ i18n("Widget name. This string will be used to name widgets of this class. It must _not_ contain white spaces and non latin1 characters.", "container"));
+ wWidget->setDescription(i18n("An empty container with no frame"));
+ addClass(wWidget);
+
+ KFormDesigner::WidgetInfo *wGroupBox = new KFormDesigner::WidgetInfo(this);
+ wGroupBox->setPixmap("groupbox");
+ wGroupBox->setClassName("QGroupBox");
+ wGroupBox->addAlternateClassName("GroupBox");
+ wGroupBox->setName(i18n("Group Box"));
+ wGroupBox->setNamePrefix(
+ i18n("Widget name. This string will be used to name widgets of this class. It must _not_ contain white spaces and non latin1 characters.", "groupBox"));
+ wGroupBox->setDescription(i18n("A container to group some widgets"));
+ addClass(wGroupBox);
+
+ KFormDesigner::WidgetInfo *wFrame = new KFormDesigner::WidgetInfo(this);
+ wFrame->setPixmap("frame");
+ wFrame->setClassName("QFrame");
+ wFrame->setName(i18n("Frame"));
+ wFrame->setNamePrefix(
+ i18n("Widget name. This string will be used to name widgets of this class. It must _not_ contain white spaces and non latin1 characters.", "frame"));
+ wFrame->setDescription(i18n("A simple frame container"));
+ addClass(wFrame);
+
+ KFormDesigner::WidgetInfo *wWidgetStack = new KFormDesigner::WidgetInfo(this);
+ wWidgetStack->setPixmap("widgetstack");
+ wWidgetStack->setClassName("QWidgetStack");
+ wWidgetStack->setName(i18n("Widget Stack"));
+ wWidgetStack->setNamePrefix(
+ i18n("Widget name. This string will be used to name widgets of this class. It must _not_ contain white spaces and non latin1 characters.", "widgetStack"));
+ wWidgetStack->setDescription(i18n("A container with multiple pages"));
+ addClass(wWidgetStack);
+
+ KFormDesigner::WidgetInfo *wHBox = new KFormDesigner::WidgetInfo(this);
+ wHBox->setPixmap("frame");
+ wHBox->setClassName("HBox");
+ wHBox->setName(i18n("Horizontal Box"));
+ wHBox->setNamePrefix(
+ i18n("Widget name. This string will be used to name widgets of this class. It must _not_ contain white spaces and non latin1 characters.", "horizontalBox"));
+ wHBox->setDescription(i18n("A simple container to group widgets horizontally"));
+ addClass(wHBox);
+
+ KFormDesigner::WidgetInfo *wVBox = new KFormDesigner::WidgetInfo(this);
+ wVBox->setPixmap("frame");
+ wVBox->setClassName("VBox");
+ wVBox->setName(i18n("Vertical Box"));
+ wVBox->setNamePrefix(
+ i18n("Widget name. This string will be used to name widgets of this class. It must _not_ contain white spaces and non latin1 characters.", "verticalBox"));
+ wVBox->setDescription(i18n("A simple container to group widgets vertically"));
+ addClass(wVBox);
+
+ KFormDesigner::WidgetInfo *wGrid = new KFormDesigner::WidgetInfo(this);
+ wGrid->setPixmap("frame");
+ wGrid->setClassName("Grid");
+ wGrid->setName(i18n("Grid Box"));
+ wGrid->setNamePrefix(
+ i18n("Widget name. This string will be used to name widgets of this class. It must _not_ contain white spaces and non latin1 characters.", "gridBox"));
+ wGrid->setDescription(i18n("A simple container to group widgets in a grid"));
+ addClass(wGrid);
+
+ KFormDesigner::WidgetInfo *wSplitter = new KFormDesigner::WidgetInfo(this);
+//! @todo horizontal/vertical splitter icons
+ wSplitter->setPixmap("frame");
+ wSplitter->setClassName("Splitter");
+ wSplitter->addAlternateClassName("QSplitter");
+ wSplitter->setName(i18n("Splitter"));
+ wSplitter->setNamePrefix(
+ i18n("Widget name. This string will be used to name widgets of this class. It must _not_ contain white spaces and non latin1 characters.", "splitter"));
+ wSplitter->setDescription(i18n("A container that enables user to resize its children"));
+ addClass(wSplitter);
+
+ KFormDesigner::WidgetInfo *wHFlow = new KFormDesigner::WidgetInfo(this);
+//! @todo hflow icon
+ wHFlow->setPixmap("frame");
+ wHFlow->setClassName("HFlow");
+ wHFlow->setName(i18n("Row Layout"));
+ wHFlow->setNamePrefix(
+ i18n("Widget name. This string will be used to name widgets of this class. It must _not_ contain white spaces and non latin1 characters.", "rowLayout"));
+ wHFlow->setDescription(i18n("A simple container to group widgets by rows"));
+ addClass(wHFlow);
+
+ KFormDesigner::WidgetInfo *wVFlow = new KFormDesigner::WidgetInfo(this);
+//! @todo vflow icon
+ wVFlow->setPixmap("frame");
+ wVFlow->setClassName("VFlow");
+ wVFlow->setName(i18n("Column Layout"));
+ wVFlow->setNamePrefix(
+ i18n("Widget name. This string will be used to name widgets of this class. It must _not_ contain white spaces and non latin1 characters.", "columnLayout"));
+ wVFlow->setDescription(i18n("A simple container to group widgets by columns"));
+ addClass(wVFlow);
+
+ KFormDesigner::WidgetInfo *wSubForm = new KFormDesigner::WidgetInfo(this);
+ wSubForm->setPixmap("form");
+ wSubForm->setClassName("SubForm");
+ wSubForm->setName(i18n("Sub Form"));
+ wSubForm->setNamePrefix(
+ i18n("Widget name. This string will be used to name widgets of this class. It must _not_ contain white spaces and non latin1 characters.", "subForm"));
+ wSubForm->setDescription(i18n("A form widget included in another Form"));
+ wSubForm->setAutoSyncForProperty( "formName", false );
+ addClass(wSubForm);
+
+ //groupbox
+ m_propDesc["title"] = i18n("Title");
+ m_propDesc["flat"] = i18n("Flat");
+
+ //tab widget
+ m_propDesc["tabPosition"] = i18n("Tab Position");
+ m_propDesc["currentPage"] = i18n("Current Page");
+ m_propDesc["tabShape"] = i18n("Tab Shape");
+
+ m_propDesc["tabPosition"] = i18n("Tab Position");
+ m_propDesc["tabPosition"] = i18n("Tab Position");
+
+ m_propValDesc["Rounded"] = i18n("for Tab Shape", "Rounded");
+ m_propValDesc["Triangular"] = i18n("for Tab Shape", "Triangular");
+}
+
+QWidget*
+ContainerFactory::createWidget(const QCString &c, QWidget *p, const char *n,
+ KFormDesigner::Container *container, int options)
+{
+ if(c == "QButtonGroup")
+ {
+ QString text = container->form()->library()->textForWidgetName(n, c);
+ QButtonGroup *w = new QButtonGroup(/*i18n("Button Group")*/text, p, n);
+ new KFormDesigner::Container(container, w, container);
+ return w;
+ }
+ else if(c == "KFDTabWidget")
+ {
+ KFDTabWidget *tab = new KFDTabWidget(p, n);
+#if defined(USE_KTabWidget) && KDE_VERSION >= KDE_MAKE_VERSION(3,1,9)
+ tab->setTabReorderingEnabled(true);
+ connect(tab, SIGNAL(movedTab(int,int)), this, SLOT(reorderTabs(int,int)));
+#endif
+ container->form()->objectTree()->addItem(container->objectTree(),
+ new KFormDesigner::ObjectTreeItem(
+ container->form()->library()->displayName(c), n, tab, container));
+// m_manager = container->form()->manager();
+
+ // if we are loading, don't add this tab
+ if(container->form()->interactiveMode())
+ {
+ //m_widget=tab;
+ setWidget(tab, container);
+// m_container=container;
+ addTabPage();
+ }
+
+ return tab;
+ }
+ else if(c == "QWidget" || c=="ContainerWidget")
+ {
+ QWidget *w = new ContainerWidget(p, n);
+ new KFormDesigner::Container(container, w, p);
+ return w;
+ }
+ else if(c == "QGroupBox" || c == "GroupBox")
+ {
+ QString text = container->form()->library()->textForWidgetName(n, c);
+ QGroupBox *w = new GroupBox(text, p, n);
+ new KFormDesigner::Container(container, w, container);
+ return w;
+ }
+ else if(c == "QFrame")
+ {
+ QFrame *w = new QFrame(p, n);
+ w->setLineWidth(2);
+ w->setFrameStyle(QFrame::StyledPanel|QFrame::Raised);
+ new KFormDesigner::Container(container, w, container);
+ return w;
+ }
+ else if(c == "QWidgetStack")
+ {
+ QWidgetStack *stack = new QWidgetStack(p, n);
+ stack->setLineWidth(2);
+ stack->setFrameStyle(QFrame::StyledPanel|QFrame::Raised);
+ container->form()->objectTree()->addItem( container->objectTree(),
+ new KFormDesigner::ObjectTreeItem(
+ container->form()->library()->displayName(c), n, stack, container));
+
+ if(container->form()->interactiveMode())
+ {
+ //m_widget = stack;
+ setWidget(stack, container);
+// m_container = container;
+ addStackPage();
+ }
+ return stack;
+ }
+ else if(c == "HBox") {
+ HBox *w = new HBox(p, n);
+ new KFormDesigner::Container(container, w, container);
+ return w;
+ }
+ else if(c == "VBox") {
+ VBox *w = new VBox(p, n);
+ new KFormDesigner::Container(container, w, container);
+ return w;
+ }
+ else if(c == "Grid") {
+ Grid *w = new Grid(p, n);
+ new KFormDesigner::Container(container, w, container);
+ return w;
+ }
+ else if(c == "HFlow") {
+ HFlow *w = new HFlow(p, n);
+ new KFormDesigner::Container(container, w, container);
+ return w;
+ }
+ else if(c == "VFlow") {
+ VFlow *w = new VFlow(p, n);
+ new KFormDesigner::Container(container, w, container);
+ return w;
+ }
+ else if(c == "SubForm") {
+ SubForm *subform = new SubForm(p, n);
+ return subform;
+ }
+ else if(c == "QSplitter") {
+ QSplitter *split = new QSplitter(p, n);
+ if (0 == (options & WidgetFactory::AnyOrientation))
+ split->setOrientation(
+ (options & WidgetFactory::VerticalOrientation) ? Qt::Vertical : Qt::Horizontal);
+ new KFormDesigner::Container(container, split, container);
+ return split;
+ }
+
+ return 0;
+}
+
+bool
+ContainerFactory::previewWidget(const QCString &classname, QWidget *widget, KFormDesigner::Container *container)
+{
+ if(classname == "WidgetStack")
+ {
+ QWidgetStack *stack = ((QWidgetStack*)widget);
+ KFormDesigner::ObjectTreeItem *tree = container->form()->objectTree()->lookup(widget->name());
+ if(!tree->modifiedProperties()->contains("frameShape"))
+ stack->setFrameStyle(QFrame::NoFrame);
+ }
+ else if(classname == "HBox")
+ ((HBox*)widget)->setPreviewMode();
+ else if(classname == "VBox")
+ ((VBox*)widget)->setPreviewMode();
+ else if(classname == "Grid")
+ ((Grid*)widget)->setPreviewMode();
+ else if(classname == "HFlow")
+ ((HFlow*)widget)->setPreviewMode();
+ else if(classname == "VFlow")
+ ((VFlow*)widget)->setPreviewMode();
+ else
+ return false;
+ return true;
+}
+
+bool
+ContainerFactory::createMenuActions(const QCString &classname, QWidget *w, QPopupMenu *menu,
+ KFormDesigner::Container *container)
+{
+ setWidget(w, container);
+ //m_widget = w;
+// m_container = container;
+
+ if((classname == "KFDTabWidget") || (w->parentWidget()->parentWidget()->inherits("QTabWidget")))
+ {
+ if(w->parentWidget()->parentWidget()->inherits("QTabWidget"))
+ {
+ //m_widget = w->parentWidget()->parentWidget();
+ setWidget(w->parentWidget()->parentWidget(), m_container->toplevel());
+// m_container = m_container->toplevel();
+ }
+
+ int id = menu->insertItem(SmallIconSet("tab_new"), i18n("Add Page"), this, SLOT(addTabPage()) );
+ id = menu->insertItem(SmallIconSet("edit"), i18n("Rename Page..."), this, SLOT(renameTabPage()));
+ id = menu->insertItem(SmallIconSet("tab_remove"), i18n("Remove Page"), this, SLOT(removeTabPage()));
+// if( dynamic_cast<TabWidgetBase*>(m_widget)->count() == 1)
+ if( dynamic_cast<TabWidgetBase*>(widget())->count() == 1)
+ menu->setItemEnabled(id, false);
+ return true;
+ }
+ else if(w->parentWidget()->isA("QWidgetStack") && !w->parentWidget()->parentWidget()->inherits("QTabWidget"))
+ {
+ //m_widget = w->parentWidget();
+ QWidgetStack *stack = (QWidgetStack*)w->parentWidget(); //m_widget;
+ setWidget(
+ w->parentWidget(),
+ container->form()->objectTree()->lookup(stack->name())->parent()->container()
+ );
+// m_container = container->form()->objectTree()->lookup(m_widget->name())->parent()->container();
+// m_container = container->form()->objectTree()->lookup(stack->name())->parent()->container();
+
+ int id = menu->insertItem(SmallIconSet("tab_new"), i18n("Add Page"), this, SLOT(addStackPage()) );
+
+ id = menu->insertItem(SmallIconSet("tab_remove"), i18n("Remove Page"), this, SLOT(removeStackPage()) );
+// if( ((QWidgetStack*)m_widget)->children()->count() == 4) // == the stack has only one page
+ if(stack->children()->count() == 4) // == the stack has only one page
+ menu->setItemEnabled(id, false);
+
+ id = menu->insertItem(SmallIconSet("next"), i18n("Jump to Next Page"), this, SLOT(nextStackPage()));
+ if(!stack->widget(stack->id(stack->visibleWidget())+1))
+ menu->setItemEnabled(id, false);
+
+ id = menu->insertItem(SmallIconSet("previous"), i18n("Jump to Previous Page"), this, SLOT(prevStackPage()));
+ if(!stack->widget(stack->id(stack->visibleWidget()) -1) )
+ menu->setItemEnabled(id, false);
+ return true;
+ }
+ return false;
+}
+
+bool
+ContainerFactory::startEditing(const QCString &classname, QWidget *w, KFormDesigner::Container *container)
+{
+ m_container = container;
+ if(classname == "QButtonGroup")
+ {
+ QButtonGroup *group = static_cast<QButtonGroup*>(w);
+ QRect r = QRect(group->x()+2, group->y()-5, group->width()-10, w->fontMetrics().height() + 10);
+ createEditor(classname, group->title(), group, container, r, Qt::AlignAuto);
+ return true;
+ }
+ if(classname == "QGroupBox" || classname == "GroupBox")
+ {
+ QGroupBox *group = static_cast<QGroupBox*>(w);
+ QRect r = QRect(group->x()+2, group->y()-5, group->width()-10, w->fontMetrics().height() + 10);
+ createEditor(classname, group->title(), group, container, r, Qt::AlignAuto);
+ return true;
+ }
+ return false;
+}
+
+bool
+ContainerFactory::saveSpecialProperty(const QCString &, const QString &name, const QVariant &, QWidget *w, QDomElement &parentNode, QDomDocument &parent)
+{
+ if((name == "title") && (w->parentWidget()->parentWidget()->inherits("QTabWidget")))
+ {
+ TabWidgetBase *tab = dynamic_cast<TabWidgetBase*>(w->parentWidget()->parentWidget());
+ KFormDesigner::FormIO::savePropertyElement(parentNode, parent, "attribute", "title", tab->tabLabel(w));
+ }
+ else if((name == "id") && (w->parentWidget()->isA("QWidgetStack")))
+ {
+ QWidgetStack *stack = (QWidgetStack*)w->parentWidget();
+ KFormDesigner::FormIO::savePropertyElement(parentNode, parent, "attribute", "id", stack->id(w));
+ }
+ else
+ return false;
+ return true;
+}
+
+bool
+ContainerFactory::readSpecialProperty(const QCString &, QDomElement &node, QWidget *w, KFormDesigner::ObjectTreeItem *item)
+{
+ QString name = node.attribute("name");
+ if((name == "title") && (item->parent()->widget()->inherits("QTabWidget")))
+ {
+ TabWidgetBase *tab = dynamic_cast<TabWidgetBase*>(w->parentWidget());
+ tab->addTab(w, node.firstChild().toElement().text());
+ item->addModifiedProperty("title", node.firstChild().toElement().text());
+ return true;
+ }
+
+ if((name == "id") && (w->parentWidget()->isA("QWidgetStack")))
+ {
+ QWidgetStack *stack = (QWidgetStack*)w->parentWidget();
+ int id = KFormDesigner::FormIO::readPropertyValue(node.firstChild(), w, name).toInt();
+ stack->addWidget(w, id);
+ stack->raiseWidget(w);
+ item->addModifiedProperty("id", id);
+ return true;
+ }
+
+ return false;
+}
+
+QValueList<QCString>
+ContainerFactory::autoSaveProperties(const QCString &c)
+{
+ QValueList<QCString> lst;
+// if(c == "SubForm")
+// lst << "formName";
+ if(c == "QSplitter")
+ lst << "orientation";
+ return lst;
+}
+
+bool
+ContainerFactory::isPropertyVisibleInternal(const QCString &classname,
+ QWidget *w, const QCString &property, bool isTopLevel)
+{
+ bool ok = true;
+
+ if((classname == "HBox") || (classname == "VBox") || (classname == "Grid") ||
+ (classname == "HFlow") || (classname == "VFlow"))
+ {
+ return property == "name" || property == "geometry";
+ }
+ else if (classname == "QGroupBox" || classname=="GroupBox") {
+ ok =
+#ifdef KEXI_NO_UNFINISHED
+/*! @todo Hidden for now in Kexi. "checkable" and "checked" props need adding
+a fake properties which will allow to properly work in design mode, otherwise
+child widgets become frozen when checked==true */
+ (m_showAdvancedProperties || (property != "checkable" && property != "checked")) &&
+#endif
+ true
+ ;
+ }
+ else if (classname == "KFDTabWidget") {
+ ok = (m_showAdvancedProperties || (property != "tabReorderingEnabled" && property != "hoverCloseButton" && property != "hoverCloseButtonDelayed"));
+ }
+
+ return ok && WidgetFactory::isPropertyVisibleInternal(classname, w, property, isTopLevel);
+}
+
+bool
+ContainerFactory::changeText(const QString &text)
+{
+ changeProperty("title", text, m_container->form());
+ return true;
+}
+
+void
+ContainerFactory::resizeEditor(QWidget *editor, QWidget *widget, const QCString &)
+{
+ QSize s = widget->size();
+ editor->move(widget->x() + 2, widget->y() - 5);
+ editor->resize(s.width() - 20, widget->fontMetrics().height() +10);
+}
+
+// Widget Specific slots used in menu items
+
+void ContainerFactory::addTabPage()
+{
+// if (!m_widget->inherits("QTabWidget"))
+ if (!widget()->inherits("QTabWidget"))
+ return;
+ KCommand *com = new InsertPageCommand(m_container, widget());
+ if(dynamic_cast<TabWidgetBase*>(widget())->count() == 0)
+ {
+ com->execute();
+ delete com;
+ }
+ else
+ m_container->form()->addCommand(com, true);
+}
+
+void ContainerFactory::removeTabPage()
+{
+ if (!widget()->inherits("QTabWidget"))
+ return;
+ TabWidgetBase *tab = dynamic_cast<TabWidgetBase*>(widget());
+ QWidget *w = tab->currentPage();
+
+ KFormDesigner::WidgetList list;
+ list.append(w);
+ KCommand *com = new KFormDesigner::DeleteWidgetCommand(list, m_container->form());
+ tab->removePage(w);
+ m_container->form()->addCommand(com, true);
+}
+
+void ContainerFactory::renameTabPage()
+{
+ if (!widget()->inherits("QTabWidget"))
+ return;
+ TabWidgetBase *tab = dynamic_cast<TabWidgetBase*>(widget());
+ QWidget *w = tab->currentPage();
+ bool ok;
+
+ QString name = KInputDialog::getText(i18n("New Page Title"), i18n("Enter a new title for the current page:"),
+#if KDE_VERSION < KDE_MAKE_VERSION(3,1,9)
+ QLineEdit::Normal,
+#endif
+ tab->tabLabel(w), &ok, w->topLevelWidget());
+ if(ok)
+ tab->changeTab(w, name);
+}
+
+void ContainerFactory::reorderTabs(int oldpos, int newpos)
+{
+ KFormDesigner::ObjectTreeItem *tab
+ = KFormDesigner::FormManager::self()->activeForm()->objectTree()->lookup(sender()->name());
+ if(!tab)
+ return;
+
+ KFormDesigner::ObjectTreeItem *item = tab->children()->take(oldpos);
+ tab->children()->insert(newpos, item);
+}
+
+void ContainerFactory::addStackPage()
+{
+ if (!widget()->isA("QWidgetStack"))
+ return;
+ KCommand *com = new InsertPageCommand(m_container, widget());
+ if(!((QWidgetStack*)widget())->visibleWidget())
+ {
+ com->execute();
+ delete com;
+ }
+ else
+ m_container->form()->addCommand(com, true);
+}
+
+void ContainerFactory::removeStackPage()
+{
+ if (!widget()->isA("QWidgetStack"))
+ return;
+ QWidgetStack *stack = (QWidgetStack*)widget();
+ QWidget *page = stack->visibleWidget();
+
+ KFormDesigner::WidgetList list;
+ list.append(page);
+ KCommand *com = new KFormDesigner::DeleteWidgetCommand(list, m_container->form());
+
+ // raise prev widget
+ int id = stack->id(page) - 1;
+ while(!stack->widget(id))
+ id--;
+ stack->raiseWidget(id);
+
+ stack->removeWidget(page);
+ m_container->form()->addCommand(com, true);
+}
+
+void ContainerFactory::prevStackPage()
+{
+ QWidgetStack *stack = (QWidgetStack*)widget();
+ int id = stack->id(stack->visibleWidget()) - 1;
+ if(stack->widget(id))
+ stack->raiseWidget(id);
+}
+
+void ContainerFactory::nextStackPage()
+{
+ QWidgetStack *stack = (QWidgetStack*)widget();
+ int id = stack->id(stack->visibleWidget()) + 1;
+ if(stack->widget(id))
+ stack->raiseWidget(id);
+}
+
+ContainerFactory::~ContainerFactory()
+{
+}
+
+KFORMDESIGNER_WIDGET_FACTORY(ContainerFactory, containers)
+
+#include "containerfactory.moc"
diff --git a/kexi/formeditor/factories/containerfactory.h b/kexi/formeditor/factories/containerfactory.h
new file mode 100644
index 00000000..1092d852
--- /dev/null
+++ b/kexi/formeditor/factories/containerfactory.h
@@ -0,0 +1,271 @@
+/* This file is part of the KDE project
+ Copyright (C) 2003 Lucijan Busch <lucijan@kde.org>
+ Copyright (C) 2004 Cedric Pasteur <cedric.pasteur@free.fr>
+ Copyright (C) 2006-2007 Jaroslaw Staniek <js@iidea.pl>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+*/
+
+#ifndef CONTAINERFACTORY_H
+#define CONTAINERFACTORY_H
+
+#include <kcommand.h>
+
+#include "widgetfactory.h"
+#include "../utils.h"
+
+namespace KFormDesigner
+{
+ class Form;
+ class FormManager;
+ class Container;
+}
+
+class InsertPageCommand : public KCommand
+{
+ public:
+ InsertPageCommand(KFormDesigner::Container *container, QWidget *widget);
+
+ virtual void execute();
+ virtual void unexecute();
+ virtual QString name() const;
+
+ protected:
+ KFormDesigner::Form *m_form;
+ QString m_containername;
+ QString m_name;
+ QString m_parentname;
+ int m_pageid;
+};
+
+//! Helper widget (used when using 'Lay out horizontally')
+class KFORMEDITOR_EXPORT HBox : public QFrame
+{
+ Q_OBJECT
+
+ public:
+ HBox(QWidget *parent, const char *name);
+ virtual ~HBox(){;}
+ void setPreviewMode() {m_preview = true;}
+ virtual void paintEvent(QPaintEvent *ev);
+
+ protected:
+ bool m_preview;
+};
+
+//! Helper widget (used when using 'Lay out vertically')
+class KFORMEDITOR_EXPORT VBox : public QFrame
+{
+ Q_OBJECT
+
+ public:
+ VBox(QWidget *parent, const char *name);
+ virtual ~VBox(){;}
+ void setPreviewMode() {m_preview = true;}
+ virtual void paintEvent(QPaintEvent *ev);
+
+ protected:
+ bool m_preview;
+};
+
+//! Helper widget (used when using 'Lay out in a grid')
+class KFORMEDITOR_EXPORT Grid : public QFrame
+{
+ Q_OBJECT
+
+ public:
+ Grid(QWidget *parent, const char *name);
+ virtual ~Grid(){;}
+ void setPreviewMode() {m_preview = true;}
+ virtual void paintEvent(QPaintEvent *ev);
+
+ protected:
+ bool m_preview;
+};
+
+//! Helper widget (used when using 'Lay out with horizontal flow')
+class KFORMEDITOR_EXPORT HFlow : public QFrame
+{
+ Q_OBJECT
+
+ public:
+ HFlow(QWidget *parent, const char *name);
+ virtual ~HFlow(){;}
+ void setPreviewMode() {m_preview = true;}
+ virtual void paintEvent(QPaintEvent *ev);
+
+ protected:
+ bool m_preview;
+};
+
+//! Helper widget (used when using 'Lay out with horizontal flow')
+class KFORMEDITOR_EXPORT VFlow : public QFrame
+{
+ Q_OBJECT
+
+ public:
+ VFlow(QWidget *parent, const char *name);
+ virtual ~VFlow(){;}
+ void setPreviewMode() {m_preview = true;}
+ virtual void paintEvent(QPaintEvent *ev);
+ virtual QSize sizeHint() const;
+
+ protected:
+ bool m_preview;
+};
+
+//! A simple container widget
+class KFORMEDITOR_EXPORT ContainerWidget : public QWidget
+{
+ Q_OBJECT
+
+ friend class KFDTabWidget;
+
+ public:
+ ContainerWidget(QWidget *parent, const char *name);
+ virtual ~ContainerWidget();
+
+ virtual QSize sizeHint() const;
+
+ //! Used to emit handleDragMoveEvent() signal needed to control dragging over the container's surface
+ virtual void dragMoveEvent( QDragMoveEvent *e );
+
+ //! Used to emit handleDropEvent() signal needed to control dropping on the container's surface
+ virtual void dropEvent( QDropEvent *e );
+
+ signals:
+ //! Needed to control dragging over the container's surface
+ void handleDragMoveEvent(QDragMoveEvent *e);
+
+ //! Needed to control dropping on the container's surface
+ void handleDropEvent(QDropEvent *e);
+};
+
+//! A tab widget
+class KFORMEDITOR_EXPORT KFDTabWidget : public KFormDesigner::TabWidget
+{
+ Q_OBJECT
+
+ public:
+ KFDTabWidget(QWidget *parent, const char *name);
+ virtual ~KFDTabWidget();
+
+ virtual QSize sizeHint() const;
+
+ //! Used to emit handleDragMoveEvent() signal needed to control dragging over the container's surface
+ virtual void dragMoveEvent( QDragMoveEvent *e );
+
+ //! Used to emit handleDropEvent() signal needed to control dropping on the container's surface
+ virtual void dropEvent( QDropEvent *e );
+
+ signals:
+ //! Needed to control dragging over the container's surface
+ void handleDragMoveEvent(QDragMoveEvent *e);
+
+ //! Needed to control dropping on the container's surface
+ void handleDropEvent(QDropEvent *e);
+};
+
+//! A group box widget
+class KFORMEDITOR_EXPORT GroupBox : public QGroupBox
+{
+ Q_OBJECT
+
+ public:
+ GroupBox(const QString & title, QWidget *parent, const char *name);
+ virtual ~GroupBox();
+
+ //! Used to emit handleDragMoveEvent() signal needed to control dragging over the container's surface
+ virtual void dragMoveEvent( QDragMoveEvent *e );
+
+ //! Used to emit handleDropEvent() signal needed to control dropping on the container's surface
+ virtual void dropEvent( QDropEvent *e );
+
+ signals:
+ //! Needed to control dragging over the container's surface
+ void handleDragMoveEvent(QDragMoveEvent *e);
+
+ //! Needed to control dropping on the container's surface
+ void handleDropEvent(QDropEvent *e);
+};
+
+//! A form embedded as a widget inside other form
+class KFORMEDITOR_EXPORT SubForm : public QScrollView
+{
+ Q_OBJECT
+ Q_PROPERTY(QString formName READ formName WRITE setFormName DESIGNABLE true)
+
+ public:
+ SubForm(QWidget *parent, const char *name);
+ ~SubForm() {}
+
+ //! \return the name of the subform inside the db
+ QString formName() const { return m_formName; }
+ void setFormName(const QString &name);
+
+ private:
+// KFormDesigner::FormManager *m_manager;
+ KFormDesigner::Form *m_form;
+ QWidget *m_widget;
+ QString m_formName;
+};
+
+//! Standard Factory for all container widgets
+class ContainerFactory : public KFormDesigner::WidgetFactory
+{
+ Q_OBJECT
+
+ public:
+ ContainerFactory(QObject *parent, const char *name, const QStringList &args);
+ virtual ~ContainerFactory();
+
+ virtual QWidget *createWidget(const QCString & classname, QWidget *parent, const char *name, KFormDesigner::Container *container,
+ int options = DefaultOptions);
+ virtual bool createMenuActions(const QCString& classname, QWidget *w, QPopupMenu *menu,
+ KFormDesigner::Container *container);
+ virtual bool startEditing(const QCString &classname, QWidget *w,
+ KFormDesigner::Container *container);
+ virtual bool previewWidget(const QCString &classname, QWidget *widget,
+ KFormDesigner::Container *container);
+ virtual bool saveSpecialProperty(const QCString &classname, const QString &name,
+ const QVariant &value, QWidget *w, QDomElement &parentNode, QDomDocument &parent);
+ virtual bool readSpecialProperty(const QCString &classname, QDomElement &node, QWidget *w,
+ KFormDesigner::ObjectTreeItem *item);
+ virtual QValueList<QCString> autoSaveProperties(const QCString &classname);
+
+ protected:
+ virtual bool isPropertyVisibleInternal(const QCString &classname, QWidget *w,
+ const QCString &property, bool isTopLevel);
+ virtual bool changeText(const QString &newText);
+ virtual void resizeEditor(QWidget *editor, QWidget *widget, const QCString &classname);
+
+ public slots:
+ void addTabPage();
+ void addStackPage();
+ void renameTabPage();
+ void removeTabPage();
+ void removeStackPage();
+ void prevStackPage();
+ void nextStackPage();
+ void reorderTabs(int oldpos, int newpos);
+
+ private:
+// QWidget *m_widget;
+// KFormDesigner::Container *m_container;
+// KFormDesigner::FormManager *m_manager;
+};
+
+#endif
diff --git a/kexi/formeditor/factories/kformdesigner_containers.desktop b/kexi/formeditor/factories/kformdesigner_containers.desktop
new file mode 100644
index 00000000..ae30820c
--- /dev/null
+++ b/kexi/formeditor/factories/kformdesigner_containers.desktop
@@ -0,0 +1,53 @@
+[Desktop Entry]
+Type=Service
+ServiceTypes=KFormDesigner/WidgetFactory
+
+Name=Container Widgets
+Name[bg]=Контейнери
+Name[ca]=Estris contenidors
+Name[cy]=Celfigion Cynhwysydd
+Name[da]=Container-kontroller
+Name[de]=Container-Elemente
+Name[el]=Γραφικά συστατικά υποδοχείς
+Name[eo]=Ujaj fenestraĵoj
+Name[es]=Widgets contenedores
+Name[et]=Konteinervidinad
+Name[eu]=Trepeta edukitzaileak
+Name[fa]=عناصر محتوی
+Name[fi]=Säiliön osat
+Name[fr]=Conteneur d'éléments graphiques
+Name[fy]=Kontainerwidgets
+Name[gl]=Elementos Contedores
+Name[he]=כלי קיבול
+Name[hr]=Sadržajni widgeti
+Name[hu]=Tartóelemek
+Name[is]=Geymihlutir
+Name[it]=Oggetti contenitori
+Name[ja]=コンテナウィジェット
+Name[km]=ធាតុ​ក្រាហ្វិក​កុងតឺន័រ
+Name[lv]=Konteinera logdaļa
+Name[ms]=Widget Bekas
+Name[nb]=Beholder-elementer
+Name[nds]=Gelaatselementen
+Name[ne]=कन्टेनर विजेट
+Name[nl]=Containerwidgets
+Name[nn]=Kjeraldelement
+Name[pl]=Kontrolki pojemników
+Name[pt]=Elementos Contentores
+Name[pt_BR]=Widgets Recipientes
+Name[ru]=Контейнеры
+Name[se]=Lihtteáđat
+Name[sk]=Kontajnerové komponenty
+Name[sl]=Vsebovalni gradniki
+Name[sr]=Контејнерске контроле
+Name[sr@Latn]=Kontejnerske kontrole
+Name[sv]=Omgivande komponenter
+Name[ta]=கொள்கலன் சாளர உருக்கள்
+Name[tr]= Containers
+Name[uk]=Віджети контейнера
+Name[zh_CN]=容器部件
+Name[zh_TW]=容器視窗元件
+
+X-KDE-Library=kformdesigner_containers
+X-KFormDesigner-FactoryGroup=
+X-KFormDesigner-WidgetFactoryVersion=2
diff --git a/kexi/formeditor/factories/kformdesigner_stdwidgets.desktop b/kexi/formeditor/factories/kformdesigner_stdwidgets.desktop
new file mode 100644
index 00000000..d5d599fa
--- /dev/null
+++ b/kexi/formeditor/factories/kformdesigner_stdwidgets.desktop
@@ -0,0 +1,55 @@
+[Desktop Entry]
+Type=Service
+ServiceTypes=KFormDesigner/WidgetFactory
+
+Name=Basic Widgets
+Name[bg]=Основни графични обекти
+Name[br]=Widgets Diazez
+Name[ca]=Estris estàndard
+Name[cy]=Celfigion Sylfaenol
+Name[da]=Basale kontroller
+Name[de]=Basis-Elemente
+Name[el]=Βασικά γραφικά συστατικά
+Name[eo]=Bazaj fenestraĵoj
+Name[es]=Widgets básicos
+Name[et]=Standardvidinad
+Name[eu]=Oinarrizko trepetak
+Name[fa]=عناصر پایه‌ای
+Name[fi]=yleiset elementit
+Name[fr]=Éléments graphiques basiques
+Name[fy]=Basiswidgets
+Name[gl]=Elementos Básicos
+Name[he]=פריטים בסיסיים
+Name[hr]=Osnovni widgeti
+Name[hu]=Alapelemek
+Name[is]=Grunnhlutir
+Name[it]=Oggetti di base
+Name[ja]=基本的なウィジェット
+Name[km]=ធាតុក្រាហ្វិកមូលដ្ឋាន
+Name[lv]=Pamata logdaļas
+Name[ms]=Widget Asas
+Name[nb]=Elementære elementer
+Name[nds]=Grundelementen
+Name[ne]=आधारभूत विजेट
+Name[nl]=Basiswidgets
+Name[nn]=Grunnleggjande element
+Name[pl]=Proste kontrolki
+Name[pt]=Elementos Básicos
+Name[pt_BR]=Widgets Básicos
+Name[ru]=Стандартные виджеты
+Name[se]=Oktageardanis áđat
+Name[sk]=Základné komponenty
+Name[sl]=Osnovni gradniki
+Name[sr]=Основне контроле
+Name[sr@Latn]=Osnovne kontrole
+Name[sv]=Standardkomponenter
+Name[ta]=அடிப்படை சாளர உருக்கள்
+Name[uk]=Основні віджети
+Name[uz]=Oddiy vidjetlar
+Name[uz@cyrillic]=Оддий виджетлар
+Name[zh_CN]=基本部件
+Name[zh_TW]=基本視窗元件
+
+X-KDE-Library=kformdesigner_stdwidgets
+X-KFormDesigner-FactoryGroup=
+X-KFormDesigner-WidgetFactoryVersion=2
diff --git a/kexi/formeditor/factories/stdwidgetfactory.cpp b/kexi/formeditor/factories/stdwidgetfactory.cpp
new file mode 100644
index 00000000..fade100a
--- /dev/null
+++ b/kexi/formeditor/factories/stdwidgetfactory.cpp
@@ -0,0 +1,984 @@
+/***************************************************************************
+ * Copyright (C) 2003 by Lucijan Busch <lucijan@kde.org> *
+ * Copyright (C) 2004 Cedric Pasteur <cedric.pasteur@free.fr> *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU Library General Public License as *
+ * published by the Free Software Foundation; either version 2 of the *
+ * License, or (at your option) any later version. *
+ ***************************************************************************/
+
+#include <qlabel.h>
+#include <qpopupmenu.h>
+#include <qcursor.h>
+#include <qradiobutton.h>
+#include <qcheckbox.h>
+#include <qslider.h>
+#include <qobjectlist.h>
+#include <qstring.h>
+#include <qvariant.h>
+#include <qheader.h>
+#include <qdom.h>
+#include <qstyle.h>
+#include <qvaluevector.h>
+
+#include <klineedit.h>
+#include <kpushbutton.h>
+#include <knuminput.h>
+#include <kcombobox.h>
+#include <klistbox.h>
+#include <ktextedit.h>
+#include <klistview.h>
+#include <kprogress.h>
+#include <kiconloader.h>
+#include <kgenericfactory.h>
+#include <klocale.h>
+#include <kdebug.h>
+#include <kdeversion.h>
+
+#if KDE_VERSION < KDE_MAKE_VERSION(3,1,9)
+# include <qdatetimeedit.h>
+# define KTimeWidget QTimeEdit
+# define KDateWidget QDateEdit
+# define KDateTimeWidget QDateTimeEdit
+#else
+# include <ktimewidget.h>
+# include <kdatewidget.h>
+# include <kdatetimewidget.h>
+#endif
+
+#include "spring.h"
+#include "formIO.h"
+#include "form.h"
+#include "formmanager.h"
+#include "widgetlibrary.h"
+#include "widgetpropertyset.h"
+#include <koproperty/property.h>
+
+#include "stdwidgetfactory.h"
+
+// Some widgets subclass to allow event filtering and some other things
+KexiPictureLabel::KexiPictureLabel(const QPixmap &pix, QWidget *parent, const char *name)
+ : QLabel(parent, name)
+{
+ setPixmap(pix);
+ setScaledContents(false);
+}
+
+bool
+KexiPictureLabel::setProperty(const char *name, const QVariant &value)
+{
+ if(QString(name) == "pixmap")
+ resize(value.toPixmap().height(), value.toPixmap().width());
+ return QLabel::setProperty(name, value);
+}
+
+Line::Line(Qt::Orientation orient, QWidget *parent, const char *name)
+ : QFrame(parent, name)
+{
+ setFrameShadow(Sunken);
+ if(orient == Horizontal)
+ setFrameShape(HLine);
+ else
+ setFrameShape(VLine);
+}
+
+void
+Line::setOrientation(Qt::Orientation orient)
+{
+ if(orient == Horizontal)
+ setFrameShape(HLine);
+ else
+ setFrameShape(VLine);
+}
+
+Qt::Orientation
+Line::orientation() const
+{
+ if(frameShape() == HLine)
+ return Horizontal;
+ else
+ return Vertical;
+}
+
+// The factory itself
+
+StdWidgetFactory::StdWidgetFactory(QObject *parent, const char *, const QStringList &)
+ : KFormDesigner::WidgetFactory(parent, "stdwidgets")
+{
+ KFormDesigner::WidgetInfo *wFormWidget = new KFormDesigner::WidgetInfo(this);
+ wFormWidget->setPixmap("form");
+ wFormWidget->setClassName("FormWidgetBase");
+ wFormWidget->setName(i18n("Form"));
+ wFormWidget->setNamePrefix(i18n("This string will be used to name widgets of this class. It must _not_ contain white "
+ "spaces and non latin1 characters.", "form"));
+ wFormWidget->setDescription(i18n("A simple form widget"));
+ addClass(wFormWidget);
+
+ KFormDesigner::WidgetInfo *wCustomWidget = new KFormDesigner::WidgetInfo(this);
+ wCustomWidget->setPixmap("unknown_widget");
+ wCustomWidget->setClassName("CustomWidget");
+ wCustomWidget->setName(i18n("Custom Widget"));
+ wCustomWidget->setNamePrefix(i18n("This string will be used to name widgets of this class. It must _not_ contain white "
+ "spaces and non latin1 characters.", "customWidget"));
+ wCustomWidget->setDescription(i18n("A custom or non-supported widget"));
+ addClass(wCustomWidget);
+
+ KFormDesigner::WidgetInfo *wLabel = new KFormDesigner::WidgetInfo(this);
+ wLabel->setPixmap("label");
+ wLabel->setClassName("QLabel");
+ wLabel->setName(i18n("Text Label"));
+ wLabel->setNamePrefix(
+ i18n("Widget name. This string will be used to name widgets of this class. It must _not_ contain white spaces and non latin1 characters.", "label"));
+ wLabel->setDescription(i18n("A widget to display text"));
+ addClass(wLabel);
+
+ KFormDesigner::WidgetInfo *wPixLabel = new KFormDesigner::WidgetInfo(this);
+ wPixLabel->setPixmap("pixmaplabel");
+ wPixLabel->setClassName("KexiPictureLabel");
+ wPixLabel->setName(i18n("Picture Label"));
+//! @todo Qt designer compatibility: maybe use this class when QLabel has a pixmap set...?
+ //wPixLabel->addAlternateClassName("QLabel");
+ wPixLabel->setSavingName("KexiPictureLabel");
+ wPixLabel->setNamePrefix(
+ i18n("Widget name. This string will be used to name widgets of this class. It must _not_ contain white spaces and non latin1 characters.", "picture"));
+ wPixLabel->setDescription(i18n("A widget to display pictures"));
+ addClass(wPixLabel);
+
+ KFormDesigner::WidgetInfo *wLineEdit = new KFormDesigner::WidgetInfo(this);
+ wLineEdit->setPixmap("lineedit");
+ wLineEdit->setClassName("KLineEdit");
+ wLineEdit->addAlternateClassName("QLineEdit");
+ wLineEdit->setIncludeFileName("klineedit.h");
+ wLineEdit->setName(i18n("Line Edit"));
+ wLineEdit->setNamePrefix(
+ i18n("Widget name. This string will be used to name widgets of this class. It must _not_ contain white spaces and non latin1 characters.", "lineEdit"));
+ wLineEdit->setDescription(i18n("A widget to input text"));
+ addClass(wLineEdit);
+
+ KFormDesigner::WidgetInfo *wSpring = new KFormDesigner::WidgetInfo(this);
+ wSpring->setPixmap("spring");
+ wSpring->setClassName("Spring");
+ wSpring->setName(i18n("Spring"));
+ wSpring->setNamePrefix(
+ i18n("Widget name. This string will be used to name widgets of this class. It must _not_ contain white spaces and non latin1 characters.", "spring"));
+ wSpring->setDescription(i18n("A spring to place between widgets"));
+ addClass(wSpring);
+
+ KFormDesigner::WidgetInfo *wPushButton = new KFormDesigner::WidgetInfo(this);
+ wPushButton->setPixmap("button");
+ wPushButton->setClassName("KPushButton");
+ wPushButton->addAlternateClassName("QPushButton");
+ wPushButton->setIncludeFileName("kpushbutton.h");
+ wPushButton->setName(i18n("Push Button"));
+ wPushButton->setNamePrefix(
+ i18n("Widget name. This string will be used to name widgets of this class. It must _not_ contain white spaces and non latin1 characters.", "button"));
+ wPushButton->setDescription(i18n("A simple push button to execute actions"));
+ addClass(wPushButton);
+
+ KFormDesigner::WidgetInfo *wRadioButton = new KFormDesigner::WidgetInfo(this);
+ wRadioButton->setPixmap("radio");
+ wRadioButton->setClassName("QRadioButton");
+ wRadioButton->setName(i18n("Option Button"));
+ wRadioButton->setNamePrefix(
+ i18n("Widget name. This string will be used to name widgets of this class. It must _not_ contain white spaces and non latin1 characters.", "optionButton"));
+ wRadioButton->setDescription(i18n("An option button with text or pixmap label"));
+ addClass(wRadioButton);
+
+ KFormDesigner::WidgetInfo *wCheckBox = new KFormDesigner::WidgetInfo(this);
+ wCheckBox->setPixmap("check");
+ wCheckBox->setClassName("QCheckBox");
+ wCheckBox->setName(i18n("Check Box"));
+ wCheckBox->setNamePrefix(
+ i18n("Widget name. This string will be used to name widgets of this class. It must _not_ contain white spaces and non latin1 characters.", "checkBox"));
+ wCheckBox->setDescription(i18n("A check box with text or pixmap label"));
+ addClass(wCheckBox);
+
+ KFormDesigner::WidgetInfo *wSpinBox = new KFormDesigner::WidgetInfo(this);
+ wSpinBox->setPixmap("spin");
+ wSpinBox->setClassName("KIntSpinBox");
+ wSpinBox->addAlternateClassName("QSpinBox");
+ wSpinBox->setIncludeFileName("knuminput.h");
+ wSpinBox->setName(i18n("Spin Box"));
+ wSpinBox->setNamePrefix(
+ i18n("Widget name. This string will be used to name widgets of this class. It must _not_ contain white spaces and non latin1 characters.", "spinBox"));
+ wSpinBox->setDescription(i18n("A spin box widget"));
+ addClass(wSpinBox);
+
+ KFormDesigner::WidgetInfo *wComboBox = new KFormDesigner::WidgetInfo(this);
+ wComboBox->setPixmap("combo");
+ wComboBox->setClassName("KComboBox");
+ wComboBox->addAlternateClassName("QComboBox");
+ wComboBox->setIncludeFileName("kcombobox.h");
+ wComboBox->setName(i18n("Combo Box"));
+ wComboBox->setNamePrefix(
+ i18n("Widget name. This string will be used to name widgets of this class. It must _not_ contain white spaces and non latin1 characters.", "comboBox"));
+ wComboBox->setDescription(i18n("A combo box widget"));
+ addClass(wComboBox);
+
+ KFormDesigner::WidgetInfo *wListBox = new KFormDesigner::WidgetInfo(this);
+ wListBox->setPixmap("listbox");
+ wListBox->setClassName("KListBox");
+ wListBox->addAlternateClassName("QListBox");
+ wListBox->setIncludeFileName("klistbox.h");
+ wListBox->setName(i18n("List Box"));
+ wListBox->setNamePrefix(
+ i18n("Widget name. This string will be used to name widgets of this class. It must _not_ contain white spaces and non latin1 characters.", "listBox"));
+ wListBox->setDescription(i18n("A simple list widget"));
+ addClass(wListBox);
+
+ KFormDesigner::WidgetInfo *wTextEdit = new KFormDesigner::WidgetInfo(this);
+ wTextEdit->setPixmap("textedit");
+ wTextEdit->setClassName("KTextEdit");
+ wTextEdit->addAlternateClassName("QTextEdit");
+ wTextEdit->setIncludeFileName("ktextedit.h");
+ wTextEdit->setName(i18n("Text Editor"));
+ wTextEdit->setNamePrefix(
+ i18n("Widget name. This string will be used to name widgets of this class. It must _not_ contain white spaces and non latin1 characters.", "textEditor"));
+ wTextEdit->setDescription(i18n("A simple single-page rich text editor"));
+ addClass(wTextEdit);
+
+ KFormDesigner::WidgetInfo *wListView = new KFormDesigner::WidgetInfo(this);
+ wListView->setPixmap("listview");
+ wListView->setClassName("KListView");
+ wListView->addAlternateClassName("QListView");
+ wListView->setIncludeFileName("klistview.h");
+ wListView->setName(i18n("List View"));
+ wListView->setNamePrefix(
+ i18n("Widget name. This string will be used to name widgets of this class. It must _not_ contain white spaces and non latin1 characters.", "listView"));
+ wListView->setDescription(i18n("A list (or tree) widget"));
+ addClass(wListView);
+
+ KFormDesigner::WidgetInfo *wSlider = new KFormDesigner::WidgetInfo(this);
+ wSlider->setPixmap("slider");
+ wSlider->setClassName("QSlider");
+ wSlider->setName(i18n("Slider"));
+ wSlider->setNamePrefix(
+ i18n("Widget name. This string will be used to name widgets of this class. It must _not_ contain white spaces and non latin1 characters.", "slider"));
+ wSlider->setDescription(i18n("An horizontal slider"));
+ addClass(wSlider);
+
+ KFormDesigner::WidgetInfo *wProgressBar = new KFormDesigner::WidgetInfo(this);
+ wProgressBar->setPixmap("progress");
+ wProgressBar->setClassName("KProgress");
+ wProgressBar->addAlternateClassName("QProgressBar");
+ wProgressBar->setIncludeFileName("kprogress.h");
+ wProgressBar->setName(i18n("Progress Bar"));
+ wProgressBar->setNamePrefix(
+ i18n("Widget name. This string will be used to name widgets of this class. It must _not_ contain white spaces and non latin1 characters.", "progressBar"));
+ wProgressBar->setDescription(i18n("A progress indicator widget"));
+ addClass(wProgressBar);
+
+ KFormDesigner::WidgetInfo *wLine = new KFormDesigner::WidgetInfo(this);
+ wLine->setPixmap("line");
+ wLine->setClassName("Line");
+ wLine->setName(i18n("Line"));
+ wLine->setNamePrefix(
+ i18n("Widget name. This string will be used to name widgets of this class. It must _not_ contain white spaces and non latin1 characters.", "line"));
+ wLine->setDescription(i18n("A line to be used as a separator"));
+ addClass(wLine);
+
+ KFormDesigner::WidgetInfo *wDate = new KFormDesigner::WidgetInfo(this);
+ wDate->setPixmap("dateedit");
+ wDate->setClassName("KDateWidget");
+#if KDE_VERSION >= KDE_MAKE_VERSION(3,1,9)
+ wDate->addAlternateClassName("QDateEdit");
+ wDate->setIncludeFileName("kdatewidget.h");
+#endif
+ wDate->setName(i18n("Date Widget"));
+ wDate->setNamePrefix(
+ i18n("Widget name. This string will be used to name widgets of this class. It must _not_ contain white spaces and non latin1 characters.", "dateWidget"));
+ wDate->setDescription(i18n("A widget to input and display a date"));
+ addClass(wDate);
+
+ KFormDesigner::WidgetInfo *wTime = new KFormDesigner::WidgetInfo(this);
+ wTime->setPixmap("timeedit");
+ wTime->setClassName("KTimeWidget");
+#if KDE_VERSION >= KDE_MAKE_VERSION(3,1,9)
+ wTime->addAlternateClassName("QTimeEdit");
+ wTime->setIncludeFileName("ktimewidget.h");
+#endif
+ wTime->setName(i18n("Time Widget"));
+ wTime->setNamePrefix(
+ i18n("Widget name. This string will be used to name widgets of this class. It must _not_ contain white spaces and non latin1 characters.", "timeWidget"));
+ wTime->setDescription(i18n("A widget to input and display a time"));
+ addClass(wTime);
+
+ KFormDesigner::WidgetInfo *wDateTime = new KFormDesigner::WidgetInfo(this);
+ wDateTime->setPixmap("datetimeedit");
+ wDateTime->setClassName("KDateTimeWidget");
+#if KDE_VERSION >= KDE_MAKE_VERSION(3,1,9)
+ wDateTime->addAlternateClassName("QDateTimeEdit");
+ wDateTime->setIncludeFileName("kdatetimewidget.h");
+#endif
+ wDateTime->setName(i18n("Date/Time Widget"));
+ wDateTime->setNamePrefix(
+ i18n("Widget name. This string will be used to name widgets of this class. It must _not_ contain white spaces and non latin1 characters.", "dateTimeWidget"));
+ wDateTime->setDescription(i18n("A widget to input and display a time and a date"));
+ addClass(wDateTime);
+
+ m_propDesc["toggleButton"] = i18n("Toggle");
+ m_propDesc["autoRepeat"] = i18n("Auto Repeat");
+ m_propDesc["autoDefault"] = i18n("Auto Default");
+ m_propDesc["default"] = i18n("Default");
+ m_propDesc["flat"] = i18n("Flat");
+ m_propDesc["echoMode"] =
+ i18n("Echo mode for Line Edit widget eg. Normal, NoEcho, Password","Echo Mode");
+ m_propDesc["indent"] = i18n("Indent");
+ //line
+ m_propDesc["orientation"] = i18n("Orientation");
+ //checkbox
+ m_propDesc["checked"] = i18n("Checked checkbox", "Checked");
+ m_propDesc["tristate"] = i18n("Tristate checkbox", "Tristate");
+
+ //for EchoMode
+ m_propValDesc["Normal"] = i18n("For Echo Mode", "Normal");
+ m_propValDesc["NoEcho"] = i18n("For Echo Mode", "No Echo");
+ m_propValDesc["Password"] = i18n("For Echo Mode", "Password");
+
+ //for spring
+ m_propDesc["sizeType"] = i18n("Size Type");
+
+ //for labels
+ m_propDesc["textFormat"] = i18n("Text Format");
+ m_propValDesc["PlainText"] = i18n("For Text Format", "Plain");
+ m_propValDesc["RichText"] = i18n("For Text Format", "Hypertext");
+ m_propValDesc["AutoText"] = i18n("For Text Format", "Auto");
+ m_propValDesc["LogText"] = i18n("For Text Format", "Log");
+
+ //KTextEdit
+ m_propDesc["tabStopWidth"] = i18n("Tab Stop Width");
+ m_propDesc["tabChangesFocus"] = i18n("Tab Changes Focus");
+ m_propDesc["wrapPolicy"] = i18n("Word Wrap Policy");
+ m_propValDesc["AtWordBoundary"] = i18n("For Word Wrap Policy", "At Word Boundary");
+ m_propValDesc["Anywhere"] = i18n("For Word Wrap Policy", "Anywhere");
+ m_propValDesc["AtWordOrDocumentBoundary"] = i18n("For Word Wrap Policy", "At Word Boundary If Possible");
+ m_propDesc["wordWrap"] = i18n("Word Wrapping");
+ m_propDesc["wrapColumnOrWidth"] = i18n("Word Wrap Position");
+ m_propValDesc["NoWrap"] = i18n("For Word Wrap Position", "None");
+ m_propValDesc["WidgetWidth"] = i18n("For Word Wrap Position", "Widget's Width");
+ m_propValDesc["FixedPixelWidth"] = i18n("For Word Wrap Position", "In Pixels");
+ m_propValDesc["FixedColumnWidth"] = i18n("For Word Wrap Position", "In Columns");
+ m_propDesc["linkUnderline"] = i18n("Links Underlined");
+
+ //internal props
+ setInternalProperty("Line","orientationSelectionPopup","1");
+ setInternalProperty("Line","orientationSelectionPopup:horizontalIcon","line_horizontal");
+ setInternalProperty("Line","orientationSelectionPopup:verticalIcon","line_vertical");
+ setInternalProperty("Line","orientationSelectionPopup:horizontalText",i18n("Insert &Horizontal Line"));
+ setInternalProperty("Line","orientationSelectionPopup:verticalText",i18n("Insert &Vertical Line"));
+ setInternalProperty("Spring","orientationSelectionPopup","1");
+ setInternalProperty("Spring","orientationSelectionPopup:horizontalIcon","spring");
+ setInternalProperty("Spring","orientationSelectionPopup:verticalIcon","spring_vertical");
+ setInternalProperty("Spring","orientationSelectionPopup:horizontalText",i18n("Insert &Horizontal Spring"));
+ setInternalProperty("Spring","orientationSelectionPopup:verticalText",i18n("Insert &Vertical Spring"));
+}
+
+StdWidgetFactory::~StdWidgetFactory()
+{
+}
+
+QWidget*
+StdWidgetFactory::createWidget(const QCString &c, QWidget *p, const char *n,
+ KFormDesigner::Container *container, int options)
+{
+ QWidget *w=0;
+ QString text( container->form()->library()->textForWidgetName(n, c) );
+ const bool designMode = options & KFormDesigner::WidgetFactory::DesignViewMode;
+
+ if(c == "QLabel")
+ w = new QLabel(text, p, n);
+ else if(c == "KexiPictureLabel")
+ w = new KexiPictureLabel(DesktopIcon("image"), p, n);
+
+ else if(c == "KLineEdit")
+ {
+ w = new KLineEdit(p, n);
+ if (designMode)
+ w->setCursor(QCursor(Qt::ArrowCursor));
+ }
+ else if(c == "KPushButton")
+ w = new KPushButton(/*i18n("Button")*/text, p, n);
+
+ else if(c == "QRadioButton")
+ w = new QRadioButton(/*i18n("Radio Button")*/text, p, n);
+
+ else if(c == "QCheckBox")
+ w = new QCheckBox(/*i18n("Check Box")*/text, p, n);
+
+ else if(c == "KIntSpinBox")
+ w = new KIntSpinBox(p, n);
+
+ else if(c == "KComboBox")
+ w = new KComboBox(p, n);
+
+ else if(c == "KListBox")
+ w = new KListBox(p, n);
+
+ else if(c == "KTextEdit")
+ w = new KTextEdit(/*i18n("Enter your text here")*/text, QString::null, p, n);
+
+ else if(c == "KListView")
+ {
+ w = new KListView(p, n);
+ if(container->form()->interactiveMode())
+ ((KListView*)w)->addColumn(i18n("Column 1"));
+ ((KListView*)w)->setRootIsDecorated(true);
+ }
+ else if(c == "QSlider")
+ w = new QSlider(Qt::Horizontal, p, n);
+
+ else if(c == "KProgress")
+ w = new KProgress(p, n);
+
+ else if(c == "KDateWidget")
+ w = new KDateWidget(QDate::currentDate(), p, n);
+
+ else if(c == "KTimeWidget")
+ w = new KTimeWidget(QTime::currentTime(), p, n);
+
+ else if(c == "KDateTimeWidget")
+ w = new KDateTimeWidget(QDateTime::currentDateTime(), p, n);
+
+ else if(c == "Line")
+ w = new Line(options & WidgetFactory::VerticalOrientation ? Line::Vertical : Line::Horizontal, p, n);
+
+ else if(c == "Spring") {
+ w = new Spring(p, n);
+ if (0 == (options & WidgetFactory::AnyOrientation))
+ static_cast<Spring*>(w)->setOrientation(
+ (options & WidgetFactory::VerticalOrientation) ? Qt::Vertical : Qt::Horizontal);
+ }
+
+ if(w)
+ return w;
+
+ kdDebug() << "WARNING :: w == 0 " << endl;
+ return 0;
+}
+
+bool
+StdWidgetFactory::previewWidget(const QCString &classname, QWidget *widget, KFormDesigner::Container *)
+{
+ if(classname == "Spring") {
+ ((Spring*)widget)->setPreviewMode();
+ return true;
+ }
+ return false;
+}
+
+bool
+StdWidgetFactory::createMenuActions(const QCString &classname, QWidget *, QPopupMenu *menu,
+ KFormDesigner::Container *)
+{
+ if((classname == "QLabel") || (classname == "KTextEdit"))
+ {
+ menu->insertItem(SmallIconSet("edit"), i18n("Edit Rich Text"), this, SLOT(editText()));
+ return true;
+ }
+ else if(classname == "KListView")
+ {
+ menu->insertItem(SmallIconSet("edit"), i18n("Edit Listview Contents"), this, SLOT(editListContents()));
+ return true;
+ }
+
+ return false;
+}
+
+bool
+StdWidgetFactory::startEditing(const QCString &classname, QWidget *w, KFormDesigner::Container *container)
+{
+ setWidget(w, container);
+// m_container = container;
+ if(classname == "KLineEdit")
+ {
+ KLineEdit *lineedit = static_cast<KLineEdit*>(w);
+ createEditor(classname, lineedit->text(), lineedit, container, lineedit->geometry(), lineedit->alignment(), true);
+ return true;
+ }
+ else if(classname == "QLabel")
+ {
+ QLabel *label = static_cast<QLabel*>(w);
+ if(label->textFormat() == RichText)
+ {
+ //m_widget = w;
+// setWidget(w, container);
+ editText();
+ }
+ else
+ createEditor(classname, label->text(), label, container, label->geometry(), label->alignment());
+ return true;
+ }
+ else if(classname == "KPushButton")
+ {
+ KPushButton *push = static_cast<KPushButton*>(w);
+ QRect r = w->style().subRect(QStyle::SR_PushButtonContents, w);
+ QRect editorRect = QRect(push->x() + r.x(), push->y() + r.y(), r.width(), r.height());
+ //r.setX(r.x() + 5);
+ //r.setY(r.y() + 5);
+ //r.setWidth(r.width()-10);
+ //r.setHeight(r.height() - 10);
+ createEditor(classname, push->text(), push, container, editorRect, Qt::AlignCenter, false, false, Qt::PaletteButton);
+ return true;
+ }
+ else if(classname == "QRadioButton")
+ {
+ QRadioButton *radio = static_cast<QRadioButton*>(w);
+ QRect r = w->style().subRect(QStyle::SR_RadioButtonContents, w);
+ QRect editorRect = QRect(radio->x() + r.x(), radio->y() + r.y(), r.width(), r.height());
+ createEditor(classname, radio->text(), radio, container, editorRect, Qt::AlignAuto);
+ return true;
+ }
+ else if(classname == "QCheckBox")
+ {
+ QCheckBox *check = static_cast<QCheckBox*>(w);
+ //QRect r(check->geometry());
+ //r.setX(r.x() + 20);
+ QRect r = w->style().subRect(QStyle::SR_CheckBoxContents, w);
+ QRect editorRect = QRect(check->x() + r.x(), check->y() + r.y(), r.width(), r.height());
+ createEditor(classname, check->text(), check, container, editorRect, Qt::AlignAuto);
+ return true;
+ }
+ else if((classname == "KComboBox") || (classname == "KListBox"))
+ {
+ QStringList list;
+ if(classname == "KListBox")
+ {
+ KListBox *listbox = (KListBox*)w;
+ for(uint i=0; i < listbox->count(); i++)
+ list.append(listbox->text(i));
+ }
+ else if(classname == "KComboBox")
+ {
+ KComboBox *combo = (KComboBox*)w;
+ for(int i=0; i < combo->count(); i++)
+ list.append(combo->text(i));
+ }
+
+ if(editList(w, list))
+ {
+ if(classname == "KListBox")
+ {
+ ((KListBox*)w)->clear();
+ ((KListBox*)w)->insertStringList(list);
+ }
+ else if(classname == "KComboBox")
+ {
+ ((KComboBox*)w)->clear();
+ ((KComboBox*)w)->insertStringList(list);
+ }
+ }
+ return true;
+ }
+ else if((classname == "KTextEdit") || (classname == "KDateTimeWidget") || (classname == "KTimeWidget") ||
+ (classname == "KDateWidget") || (classname == "KIntSpinBox")) {
+ disableFilter(w, container);
+ return true;
+ }
+ return false;
+}
+
+bool
+StdWidgetFactory::clearWidgetContent(const QCString &classname, QWidget *w)
+{
+ if(classname == "KLineEdit")
+ ((KLineEdit*)w)->clear();
+ else if(classname == "KListBox")
+ ((KListBox*)w)->clear();
+ else if(classname == "KListView")
+ ((KListView*)w)->clear();
+ else if(classname == "KComboBox")
+ ((KComboBox*)w)->clear();
+ else if(classname == "KTextEdit")
+ ((KTextEdit*)w)->clear();
+ else
+ return false;
+ return true;
+}
+
+bool
+StdWidgetFactory::changeText(const QString &text)
+{
+ QCString n = WidgetFactory::widget()->className();
+ QWidget *w = WidgetFactory::widget();
+ if(n == "KIntSpinBox")
+ ((KIntSpinBox*)w)->setValue(text.toInt());
+ else
+ changeProperty("text", text, m_container->form());
+
+ /* By-hand method not needed as sizeHint() can do that for us
+ QFontMetrics fm = w->fontMetrics();
+ QSize s(fm.width( text ), fm.height());
+ int width;
+ if(n == "QLabel") // labels are resized to fit the text
+ {
+ w->resize(w->sizeHint());
+ WidgetFactory::m_editor->resize(w->size());
+ return;
+ }
+ // and other widgets are just enlarged if needed
+ else if(n == "KPushButton")
+ width = w->style().sizeFromContents( QStyle::CT_PushButton, w, s).width();
+ else if(n == "QCheckBox")
+ width = w->style().sizeFromContents( QStyle::CT_CheckBox, w, s).width();
+ else if(n == "QRadioButton")
+ width = w->style().sizeFromContents( QStyle::CT_RadioButton, w, s).width();
+ else
+ return;
+ int width = w->sizeHint().width();*/
+
+#if 0 //not needed here, size hint is used on creation in InsertWidgetCommand::execute()
+ if(w->width() < width)
+ {
+ w->resize(width, w->height() );
+ //WidgetFactory::m_editor->resize(w->size());
+ }
+#endif
+ return true;
+}
+
+void
+StdWidgetFactory::resizeEditor(QWidget *editor, QWidget *widget, const QCString &classname)
+{
+ QSize s = widget->size();
+ QPoint p = widget->pos();
+ QRect r;
+
+ if(classname == "QRadioButton")
+ {
+ r = widget->style().subRect(QStyle::SR_RadioButtonContents, widget);
+ p += r.topLeft();
+ s.setWidth(r.width());
+ }
+ else if(classname == "QCheckBox")
+ {
+ r = widget->style().subRect(QStyle::SR_CheckBoxContents, widget);
+ p += r.topLeft();
+ s.setWidth(r.width());
+ }
+ else if(classname == "KPushButton")
+ {
+ r = widget->style().subRect(QStyle::SR_PushButtonContents, widget);
+ p += r.topLeft();
+ s = r.size();
+ }
+
+ editor->resize(s);
+ editor->move(p);
+}
+
+bool
+StdWidgetFactory::saveSpecialProperty(const QCString &classname, const QString &name, const QVariant &, QWidget *w, QDomElement &parentNode, QDomDocument &domDoc)
+{
+ if(name == "list_items" && classname == "KComboBox")
+ {
+ KComboBox *combo = (KComboBox*)w;
+ for(int i=0; i < combo->count(); i++)
+ {
+ QDomElement item = domDoc.createElement("item");
+ KFormDesigner::FormIO::savePropertyElement(item, domDoc, "property", "text", combo->text(i));
+ parentNode.appendChild(item);
+ }
+ return true;
+ }
+ else if(name == "list_items" && classname == "KListBox")
+ {
+ KListBox *listbox = (KListBox*)w;
+ for(uint i=0; i < listbox->count(); i++)
+ {
+ QDomElement item = domDoc.createElement("item");
+ KFormDesigner::FormIO::savePropertyElement(item, domDoc, "property", "text", listbox->text(i));
+ parentNode.appendChild(item);
+ }
+ return true;
+ }
+ else if(name == "list_contents" && classname == "KListView")
+ {
+ KListView *listview = (KListView*)w;
+ // First we save the columns
+ for(int i = 0; i < listview->columns(); i++)
+ {
+ QDomElement item = domDoc.createElement("column");
+ KFormDesigner::FormIO::savePropertyElement(item, domDoc, "property", "text", listview->columnText(i));
+ KFormDesigner::FormIO::savePropertyElement(item, domDoc, "property", "width", listview->columnWidth(i));
+ KFormDesigner::FormIO::savePropertyElement(item, domDoc, "property", "resizable", listview->header()->isResizeEnabled(i));
+ KFormDesigner::FormIO::savePropertyElement(item, domDoc, "property", "clickable", listview->header()->isClickEnabled(i));
+ KFormDesigner::FormIO::savePropertyElement(item, domDoc, "property", "fullwidth", listview->header()->isStretchEnabled(i));
+ parentNode.appendChild(item);
+ }
+
+ // Then we save the list view items
+ QListViewItem *item = listview->firstChild();
+ while(item)
+ {
+ saveListItem(item, parentNode, domDoc);
+ item = item->nextSibling();
+ }
+ return true;
+ }
+
+ return false;
+}
+
+void
+StdWidgetFactory::saveListItem(QListViewItem *item, QDomNode &parentNode, QDomDocument &domDoc)
+{
+ QDomElement element = domDoc.createElement("item");
+ parentNode.appendChild(element);
+
+ // We save the text of each column
+ for(int i = 0; i < item->listView()->columns(); i++)
+ KFormDesigner::FormIO::savePropertyElement(element, domDoc, "property", "text", item->text(i));
+
+ // Then we save every sub items
+ QListViewItem *child = item->firstChild();
+ while(child)
+ {
+ saveListItem(child, element, domDoc);
+ child = child->nextSibling();
+ }
+}
+
+bool
+StdWidgetFactory::readSpecialProperty(const QCString &classname, QDomElement &node, QWidget *w, KFormDesigner::ObjectTreeItem *)
+{
+ QString tag = node.tagName();
+ QString name = node.attribute("name");
+
+ if((tag == "item") && (classname == "KComboBox"))
+ {
+ KComboBox *combo = (KComboBox*)w;
+ QVariant val = KFormDesigner::FormIO::readPropertyValue(node.firstChild().firstChild(), w, name);
+ if(val.canCast(QVariant::Pixmap))
+ combo->insertItem(val.toPixmap());
+ else
+ combo->insertItem(val.toString());
+ return true;
+ }
+
+ if((tag == "item") && (classname == "KListBox"))
+ {
+ KListBox *listbox = (KListBox*)w;
+ QVariant val = KFormDesigner::FormIO::readPropertyValue(node.firstChild().firstChild(), w, name);
+ if(val.canCast(QVariant::Pixmap))
+ listbox->insertItem(val.toPixmap());
+ else
+ listbox->insertItem(val.toString());
+ return true;
+ }
+
+ if((tag == "column") && (classname == "KListView"))
+ {
+ KListView *listview = (KListView*)w;
+ int id=0;
+ for(QDomNode n = node.firstChild(); !n.isNull(); n = n.nextSibling())
+ {
+ QString prop = n.toElement().attribute("name");
+ QVariant val = KFormDesigner::FormIO::readPropertyValue(n.firstChild(), w, name);
+ if(prop == "text")
+ id = listview->addColumn(val.toString());
+ else if(prop == "width")
+ listview->setColumnWidth(id, val.toInt());
+ else if(prop == "resizable")
+ listview->header()->setResizeEnabled(val.toBool(), id);
+ else if(prop == "clickable")
+ listview->header()->setClickEnabled(val.toBool(), id);
+ else if(prop == "fullwidth")
+ listview->header()->setStretchEnabled(val.toBool(), id);
+ }
+ return true;
+ }
+ else if((tag == "item") && (classname == "KListView"))
+ {
+ KListView *listview = (KListView*)w;
+ readListItem(node, 0, listview);
+ return true;
+ }
+
+ return false;
+}
+
+void
+StdWidgetFactory::readListItem(QDomElement &node, QListViewItem *parent, KListView *listview)
+{
+ QListViewItem *item;
+ if(parent)
+ item = new KListViewItem(parent);
+ else
+ item = new KListViewItem(listview);
+
+ // We need to move the item at the end of the list
+ QListViewItem *last;
+ if(parent)
+ last = parent->firstChild();
+ else
+ last = listview->firstChild();
+
+ while(last->nextSibling())
+ last = last->nextSibling();
+ item->moveItem(last);
+
+ int i = 0;
+ for(QDomNode n = node.firstChild(); !n.isNull(); n = n.nextSibling())
+ {
+ QDomElement childEl = n.toElement();
+ QString prop = childEl.attribute("name");
+ QString tag = childEl.tagName();
+
+ // We read sub items
+ if(tag == "item")
+ {
+ item->setOpen(true);
+ readListItem(childEl, item, listview);
+ }
+ // and column texts
+ else if((tag == "property") && (prop == "text"))
+ {
+ QVariant val = KFormDesigner::FormIO::readPropertyValue(n.firstChild(), listview, "item");
+ item->setText(i, val.toString());
+ i++;
+ }
+ }
+}
+
+bool
+StdWidgetFactory::isPropertyVisibleInternal(const QCString &classname,
+ QWidget *w, const QCString &property, bool isTopLevel)
+{
+ bool ok = true;
+ if(classname == "FormWidgetBase")
+ {
+ if(property == "iconText"
+ || property == "geometry" /*nonsense for toplevel widget*/)
+ return false;
+ }
+ else if (classname == "CustomWidget")
+ {
+ }
+ else if(classname == "Spring")
+ {
+ return Spring::isPropertyVisible(property);
+ }
+ else if(classname == "KexiPictureLabel")
+ {
+ if((property == "text") || (property == "indent") || (property == "textFormat") || (property == "font") || (property == "alignment"))
+ return false;
+ }
+ else if(classname == "QLabel")
+ {
+ if(property == "pixmap")
+ return false;
+ }
+ else if(classname == "KLineEdit")
+ {
+ if(property == "vAlign")
+ return false;
+ }
+ else if(classname == "KTextEdit")
+ ok = m_showAdvancedProperties ||
+ property!="undoDepth"
+ && property!="undoRedoEnabled" //always true!
+ && property!="dragAutoScroll" //always true!
+ && property!="overwriteMode" //always false!
+ && property!="resizePolicy"
+ && property!="autoFormatting" //too complex
+#ifdef KEXI_NO_UNFINISHED
+ && property!="paper"
+#endif
+ ;
+ else if(classname == "Line")
+ {
+ if((property == "frameShape") || (property == "font") || (property == "margin"))
+ return false;
+ }
+ else if(classname=="QCheckBox")
+ {
+ ok = m_showAdvancedProperties || (property != "autoRepeat");
+ }
+ else if(classname=="QRadioButton")
+ {
+ ok = m_showAdvancedProperties || (property != "autoRepeat");
+ }
+ else if(classname=="KPushButton")
+ {
+//! @todo reenable autoDefault / default if the top level window is dialog...
+ ok = m_showAdvancedProperties || (property != "autoDefault" && property != "default");
+ }
+ return ok && WidgetFactory::isPropertyVisibleInternal(classname, w, property, isTopLevel);
+}
+
+QValueList<QCString>
+StdWidgetFactory::autoSaveProperties(const QCString &classname)
+{
+ QValueList<QCString> l;
+
+ if(classname == "QLabel")
+ l << "text";
+ if(classname == "KPushButton")
+ l << "text";
+ else if(classname == "KexiPictureLabel")
+ l << "pixmap";
+ else if(classname == "KComboBox")
+ l << "list_items";
+ else if(classname == "KListBox")
+ l << "list_items";
+ else if(classname == "KListView")
+ l << "list_contents";
+ else if(classname == "Line")
+ l << "orientation";
+ else if(classname == "KTimeWidget")
+ l << "time";
+ else if(classname == "KDateWidget")
+ l << "date";
+ else if(classname == "KDateTimeWidget")
+ l << "dateTime";
+ else if(classname == "Spring")
+ l << "sizeType" << "orientation";
+ else if(classname == "KTextEdit")
+ l << "textFormat" << "text";
+
+ return l;
+}
+
+void
+StdWidgetFactory::editText()
+{
+ QCString classname = widget()->className();
+ QString text;
+ if(classname == "KTextEdit")
+ text = ((KTextEdit*)widget())->text();
+ else if(classname == "QLabel")
+ text = ((QLabel*)widget())->text();
+
+ if(editRichText(widget(), text))
+ {
+ changeProperty("textFormat", "RichText", m_container->form());
+ changeProperty("text", text, m_container->form());
+ }
+
+ if(classname == "QLabel")
+ widget()->resize(widget()->sizeHint());
+}
+
+void
+StdWidgetFactory::editListContents()
+{
+ if(widget()->inherits("QListView"))
+ editListView((QListView*)widget());
+}
+
+void
+StdWidgetFactory::setPropertyOptions( KFormDesigner::WidgetPropertySet& buf, const KFormDesigner::WidgetInfo& info, QWidget *w )
+{
+ Q_UNUSED( info );
+ Q_UNUSED( w );
+
+ if (buf.contains("indent")) {
+ buf["indent"].setOption("min", -1);
+ buf["indent"].setOption("minValueText", i18n("default indent value", "default"));
+ }
+}
+
+KFORMDESIGNER_WIDGET_FACTORY(StdWidgetFactory, stdwidgets)
+
+#include "stdwidgetfactory.moc"
+
diff --git a/kexi/formeditor/factories/stdwidgetfactory.h b/kexi/formeditor/factories/stdwidgetfactory.h
new file mode 100644
index 00000000..c0e56c5b
--- /dev/null
+++ b/kexi/formeditor/factories/stdwidgetfactory.h
@@ -0,0 +1,99 @@
+/* This file is part of the KDE project
+ Copyright (C) 2004 Cedric Pasteur <cedric.pasteur@free.fr>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+*/
+
+#ifndef STDWIDGETFACTORY_H
+#define STDWIDGETFACTORY_H
+
+#include <qframe.h>
+
+#include "widgetfactory.h"
+#include "container.h"
+
+class KFORMEDITOR_EXPORT KexiPictureLabel : public QLabel
+{
+ Q_OBJECT
+
+ public:
+ KexiPictureLabel(const QPixmap &pix, QWidget *parent, const char *name);
+ ~KexiPictureLabel(){;}
+
+ virtual bool setProperty(const char *name, const QVariant &value);
+};
+
+class KFORMEDITOR_EXPORT Line : public QFrame
+{
+ Q_OBJECT
+ Q_PROPERTY(Orientation orientation READ orientation WRITE setOrientation)
+
+ public:
+ Line(Orientation orient, QWidget *parent, const char *name);
+ ~Line(){;}
+
+ void setOrientation(Orientation orient);
+ Orientation orientation() const;
+};
+
+//! Factory for all basic widgets, including Spring (not containers)
+class StdWidgetFactory : public KFormDesigner::WidgetFactory
+{
+ Q_OBJECT
+
+ public:
+ StdWidgetFactory(QObject *parent, const char *name, const QStringList &args);
+ ~StdWidgetFactory();
+
+ virtual QWidget *createWidget(const QCString &c, QWidget *p, const char *n,
+ KFormDesigner::Container *container, int options = DefaultOptions);
+
+ virtual bool createMenuActions(const QCString &classname, QWidget *w, QPopupMenu *menu,
+ KFormDesigner::Container *container);
+ virtual bool startEditing(const QCString &classname, QWidget *w,
+ KFormDesigner::Container *container);
+ virtual bool previewWidget(const QCString &classname, QWidget *widget,
+ KFormDesigner::Container *container);
+ virtual bool clearWidgetContent(const QCString &classname, QWidget *w);
+
+ virtual bool saveSpecialProperty(const QCString &classname,
+ const QString &name, const QVariant &value, QWidget *w,
+ QDomElement &parentNode, QDomDocument &parent);
+ virtual bool readSpecialProperty(const QCString &classname, QDomElement &node,
+ QWidget *w, KFormDesigner::ObjectTreeItem *item);
+ virtual QValueList<QCString> autoSaveProperties(const QCString &classname);
+
+ virtual void setPropertyOptions( KFormDesigner::WidgetPropertySet& buf,
+ const KFormDesigner::WidgetInfo& info, QWidget *w );
+
+ public slots:
+ void editText();
+ void editListContents();
+
+ protected:
+ virtual bool isPropertyVisibleInternal(const QCString &classname, QWidget *w,
+ const QCString &property, bool isTopLevel);
+ virtual bool changeText(const QString &newText);
+ virtual void resizeEditor(QWidget *editor, QWidget *widget, const QCString &classname);
+ void saveListItem(QListViewItem *item, QDomNode &parentNode, QDomDocument &domDoc);
+ void readListItem(QDomElement &node, QListViewItem *parent, KListView *listview);
+
+ private:
+// KFormDesigner::Container *m_container;
+// QWidget *m_widget;
+};
+
+#endif
diff --git a/kexi/formeditor/form.cpp b/kexi/formeditor/form.cpp
new file mode 100644
index 00000000..a5d57002
--- /dev/null
+++ b/kexi/formeditor/form.cpp
@@ -0,0 +1,600 @@
+/* This file is part of the KDE project
+ Copyright (C) 2003 Lucijan Busch <lucijan@gmx.at>
+ Copyright (C) 2004 Cedric Pasteur <cedric.pasteur@free.fr>
+ Copyright (C) 2004-2007 Jaroslaw Staniek <js@iidea.pl>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+*/
+
+#include <qwidget.h>
+#include <qlabel.h>
+#include <qobjectlist.h>
+#include <qptrdict.h>
+
+#include <kdebug.h>
+#include <klocale.h>
+#include <kcommand.h>
+#include <kaction.h>
+#include <kmessagebox.h>
+
+#include "container.h"
+#include "objecttree.h"
+#include "widgetpropertyset.h"
+#include "formIO.h"
+#include "formmanager.h"
+#include "widgetlibrary.h"
+#include "spring.h"
+#include "pixmapcollection.h"
+#include "events.h"
+#include "utils.h"
+#include "form.h"
+#include <koproperty/property.h>
+#include <kexiutils/utils.h>
+
+using namespace KFormDesigner;
+
+FormPrivate::FormPrivate()
+{
+ toplevel = 0;
+ topTree = 0;
+ widget = 0;
+ resizeHandles.setAutoDelete(true);
+ dirty = false;
+ interactive = true;
+ design = true;
+ autoTabstops = false;
+ tabstops.setAutoDelete(false);
+ connBuffer = new ConnectionBuffer();
+ formatVersion = KFormDesigner::version();
+ originalFormatVersion = KFormDesigner::version();
+}
+
+FormPrivate::~FormPrivate()
+{
+ delete history;
+ delete topTree;
+ delete connBuffer;
+ connBuffer = 0;
+ resizeHandles.setAutoDelete(false);
+ // otherwise, it tries to delete widgets which doesn't exist anymore
+}
+
+//--------------------------------------
+
+FormWidget::FormWidget()
+ : m_form(0)
+{
+}
+
+FormWidget::~FormWidget()
+{
+ if (m_form) {
+ m_form->setFormWidget(0);
+ }
+}
+
+//--------------------------------------
+
+Form::Form(WidgetLibrary* library, const char *name, bool designMode)
+ : QObject(library, name)
+ , m_lib(library)
+{
+ d = new FormPrivate();
+// d->manager = manager;
+ d->design = designMode;
+
+ // Init actions
+ d->collection = new KActionCollection(0, this);
+ d->history = new KCommandHistory(d->collection, true);
+ connect(d->history, SIGNAL(commandExecuted()), this, SLOT(slotCommandExecuted()));
+ connect(d->history, SIGNAL(documentRestored()), this, SLOT(slotFormRestored()));
+}
+
+Form::~Form()
+{
+ emit destroying();
+ delete d;
+ d = 0;
+}
+
+QWidget*
+Form::widget() const
+{
+ if(d->topTree)
+ return d->topTree->widget();
+ else if(d->toplevel)
+ return d->toplevel->widget();
+ else // preview form
+ return d->widget;
+}
+
+//////////////// Container -related functions ///////////////////////
+
+void
+Form::createToplevel(QWidget *container, FormWidget *formWidget, const QCString &)
+{
+ kdDebug() << "Form::createToplevel() container= "<< (container ? container->name() : "<NULL>")
+ << " formWidget=" << formWidget << "className=" << name() << endl;
+
+ setFormWidget( formWidget );
+ d->toplevel = new Container(0, container, this, name());
+ d->topTree = new ObjectTree(i18n("Form"), container->name(), container, d->toplevel);
+ d->toplevel->setObjectTree(d->topTree);
+ d->toplevel->setForm(this);
+ d->pixcollection = new PixmapCollection(container->name(), this);
+
+ d->topTree->setWidget(container);
+//! todo: copy caption in Kexi from object's caption
+// d->topTree->addModifiedProperty("caption", name());
+ //m_topTree->addModifiedProperty("icon");
+
+ connect(container, SIGNAL(destroyed()), this, SLOT(formDeleted()));
+
+ kdDebug() << "Form::createToplevel(): d->toplevel=" << d->toplevel << endl;
+}
+
+
+Container*
+Form::activeContainer()
+{
+ ObjectTreeItem *it;
+ if(d->selected.count() == 0)
+ return d->toplevel;
+
+ if(d->selected.count() == 1)
+ it = d->topTree->lookup(d->selected.last()->name());
+ else
+ it = commonParentContainer( &(d->selected) );
+
+ if (!it)
+ return 0;
+ if(it->container())
+ return it->container();
+ else
+ return it->parent()->container();
+}
+
+ObjectTreeItem*
+Form::commonParentContainer(WidgetList *wlist)
+{
+ ObjectTreeItem *item = 0;
+ WidgetList *list = new WidgetList();
+
+ // Creates a list of all widget parents
+ for(QWidget *w = wlist->first(); w; w = wlist->next())
+ {
+ if(list->findRef(w->parentWidget()) == -1)
+ list->append(w->parentWidget());
+ }
+
+ removeChildrenFromList(*list);
+
+ // one widget remains == the container we are looking for
+ if(list->count() == 1)
+ item = d->topTree->lookup(list->first()->name());
+ else // we need to go one level up
+ item = commonParentContainer(list);
+
+ delete list;
+ return item;
+}
+
+Container*
+Form::parentContainer(QWidget *w)
+{
+ ObjectTreeItem *it;
+ if(!w)
+ return 0;
+ // it = d->topTree->lookup(d->selected.last()->name());
+ //else
+ it = d->topTree->lookup(w->name());
+
+ if(it->parent()->container())
+ return it->parent()->container();
+ else
+ return it->parent()->parent()->container();
+}
+
+
+
+void
+Form::setDesignMode(bool design)
+{
+ d->design = design;
+ if(!design)
+ {
+ ObjectTreeDict *dict = new ObjectTreeDict( *(d->topTree->dict()) );
+ ObjectTreeDictIterator it(*dict);
+ for(; it.current(); ++it)
+ m_lib->previewWidget(it.current()->widget()->className(), it.current()->widget(), d->toplevel);
+ delete dict;
+
+ d->widget = d->topTree->widget();
+ delete (d->topTree);
+ d->topTree = 0;
+ delete (d->toplevel);
+ d->toplevel = 0;
+ }
+}
+
+
+///////////////////////////// Selection stuff ///////////////////////
+
+void
+Form::setSelectedWidget(QWidget *w, bool add, bool dontRaise, bool moreWillBeSelected)
+{
+ if((d->selected.isEmpty()) || (w == widget()) || (d->selected.first() == widget()))
+ add = false;
+
+ if(!w)
+ {
+ setSelectedWidget(widget());
+ return;
+ }
+
+ //raise selected widget and all possible parents
+ QWidget *wtmp = w;
+ while(!dontRaise && wtmp && wtmp->parentWidget() && (wtmp != widget()))
+ {
+ wtmp->raise();
+ if(d->resizeHandles[ wtmp->name() ])
+ d->resizeHandles[ wtmp->name() ]->raise();
+ wtmp = wtmp->parentWidget();
+ }
+
+ if (wtmp)
+ wtmp->setFocus();
+
+ if(!add)
+ {
+ d->selected.clear();
+ d->resizeHandles.clear();
+ }
+ d->selected.append(w);
+ emit selectionChanged(w, add, moreWillBeSelected);
+ emitActionSignals(false);
+
+ // WidgetStack and TabWidget pages widgets shouldn't have resize handles, but their parent
+ if(!FormManager::self()->isTopLevel(w) && w->parentWidget() && w->parentWidget()->isA("QWidgetStack"))
+ {
+ w = w->parentWidget();
+ if(w->parentWidget() && w->parentWidget()->inherits("QTabWidget"))
+ w = w->parentWidget();
+ }
+
+ if(w && w != widget())
+ d->resizeHandles.insert(w->name(), new ResizeHandleSet(w, this));
+}
+
+ResizeHandleSet*
+Form::resizeHandlesForWidget(QWidget* w)
+{
+ return d->resizeHandles[w->name()];
+}
+
+void
+Form::unSelectWidget(QWidget *w)
+{
+ d->selected.remove(w);
+ d->resizeHandles.remove(w->name());
+}
+
+void
+Form::selectFormWidget()
+{
+ setSelectedWidget(widget(), false);
+}
+
+void
+Form::clearSelection()
+{
+ d->selected.clear();
+ d->resizeHandles.clear();
+ emit selectionChanged(0, false);
+ emitActionSignals(false);
+}
+
+void
+Form::emitActionSignals(bool withUndoAction)
+{
+ // Update menu and toolbar items
+ if(d->selected.count() > 1)
+ FormManager::self()->emitWidgetSelected(this, true);
+ else if(d->selected.first() != widget())
+ FormManager::self()->emitWidgetSelected(this, false);
+ else
+ FormManager::self()->emitFormWidgetSelected(this);
+
+ if(!withUndoAction)
+ return;
+
+ KAction *undoAction = d->collection->action("edit_undo");
+ if(undoAction)
+ FormManager::self()->emitUndoEnabled(undoAction->isEnabled(), undoAction->text());
+
+ KAction *redoAction = d->collection->action("edit_redo");
+ if(redoAction)
+ FormManager::self()->emitRedoEnabled(redoAction->isEnabled(), redoAction->text());
+}
+
+void
+Form::emitSelectionSignals()
+{
+ emit selectionChanged(selectedWidgets()->first(), false);
+// for(QWidget *w = selectedWidgets()->next(); w; w = selectedWidgets()->next())
+// emit selectionChanged(selectedWidgets()->first(), true);
+ for (WidgetListIterator it(*selectedWidgets()); it.current(); ++it)
+ emit selectionChanged(it.current(), true);
+}
+
+/////////////////////////// Various slots and signals /////////////////////
+void
+Form::formDeleted()
+{
+// clearSelection();
+ d->selected.clear();
+ d->resizeHandles.setAutoDelete(false);
+ d->resizeHandles.clear();
+ d->resizeHandles.setAutoDelete(true);
+// emit selectionChanged(0, false);
+// emitActionSignals(false);
+
+ FormManager::self()->deleteForm(this);
+ //delete this;
+ deleteLater();
+}
+
+void
+Form::changeName(const QCString &oldname, const QCString &newname)
+{
+ if(oldname == newname)
+ return;
+ if(!d->topTree->rename(oldname, newname)) // rename failed
+ {
+ KMessageBox::sorry(widget()->topLevelWidget(),
+ i18n("Renaming widget \"%1\" to \"%2\" failed.").arg(oldname).arg(newname));
+//moved to WidgetPropertySet::slotChangeProperty()
+// KMessageBox::sorry(widget()->topLevelWidget(),
+// i18n("A widget with this name already exists. "
+// "Please choose another name or rename existing widget."));
+ kdDebug() << "Form::changeName() : ERROR : A widget named " << newname << " already exists" << endl;
+ FormManager::self()->propertySet()->property("name") = QVariant(oldname);
+ }
+ else
+ {
+ d->connBuffer->fixName(oldname, newname);
+ ResizeHandleSet *temp = d->resizeHandles.take(oldname);
+ d->resizeHandles.insert(newname, temp);
+ }
+}
+
+void
+Form::emitChildAdded(ObjectTreeItem *item)
+{
+ addWidgetToTabStops(item);
+ emit childAdded(item);
+}
+
+void
+Form::emitChildRemoved(ObjectTreeItem *item)
+{
+ d->tabstops.remove(item);
+ if(d->connBuffer)
+ d->connBuffer->removeAllConnectionsForWidget(item->name());
+ emit childRemoved(item);
+}
+
+void
+Form::addCommand(KCommand *command, bool execute)
+{
+ emit FormManager::self()->dirty(this, true);
+ d->dirty = true;
+ d->history->addCommand(command, execute);
+ if(!execute) // simulate command to activate 'undo' menu
+ slotCommandExecuted();
+}
+
+void
+Form::clearCommandHistory()
+{
+ d->history->clear();
+ FormManager::self()->emitUndoEnabled(false, QString::null);
+ FormManager::self()->emitRedoEnabled(false, QString::null);
+}
+
+void
+Form::slotCommandExecuted()
+{
+ emit FormManager::self()->dirty(this, true);
+ d->dirty = true;
+ // because actions text is changed after the commandExecuted() signal is emitted
+ QTimer::singleShot(10, this, SLOT(emitUndoEnabled()));
+ QTimer::singleShot(10, this, SLOT(emitRedoEnabled()));
+}
+
+void
+Form::emitUndoEnabled()
+{
+ KAction *undoAction = d->collection->action("edit_undo");
+ if(undoAction)
+ FormManager::self()->emitUndoEnabled(undoAction->isEnabled(), undoAction->text());
+}
+
+void
+Form::emitRedoEnabled()
+{
+ KAction *redoAction = d->collection->action("edit_redo");
+ if(redoAction)
+ FormManager::self()->emitRedoEnabled(redoAction->isEnabled(), redoAction->text());
+}
+
+void
+Form::slotFormRestored()
+{
+ emit FormManager::self()->dirty(this, false);
+ d->dirty = false;
+}
+
+
+/////////////////////////// Tab stops ////////////////////////
+
+void
+Form::addWidgetToTabStops(ObjectTreeItem *it)
+{
+ QWidget *w = it->widget();
+ if(!w)
+ return;
+ if(!(w->focusPolicy() & QWidget::TabFocus))
+ {
+ if (!w->children())
+ return;
+ // For composed widgets, we check if one of the child can have focus
+ for(QObjectListIterator chIt(*w->children()); chIt.current(); ++chIt) {
+ if(chIt.current()->isWidgetType()) {//QWidget::TabFocus flag will be checked later!
+ if(d->tabstops.findRef(it) == -1) {
+ d->tabstops.append(it);
+ return;
+ }
+ }
+ }
+ }
+ else if(d->tabstops.findRef(it) == -1) // not yet in the list
+ d->tabstops.append(it);
+}
+
+void
+Form::updateTabStopsOrder()
+{
+ for (ObjectTreeListIterator it(d->tabstops);it.current();) {
+ if(!(it.current()->widget()->focusPolicy() & QWidget::TabFocus)) {
+ kexidbg << "Form::updateTabStopsOrder(): widget removed because has no TabFocus: " << it.current()->widget()->name() << endl;
+ d->tabstops.remove( it.current() );
+ }
+ else
+ ++it;
+ }
+}
+
+//! Collects all the containers reculsively. Used by Form::autoAssignTabStops().
+void collectContainers(ObjectTreeItem* item, QPtrDict<char>& containers)
+{
+ if (!item->container())
+ return;
+ if (!containers[ item->container() ]) {
+ kdDebug() << "collectContainers() " << item->container()->objectTree()->className()
+ << " " << item->container()->objectTree()->name() << endl;
+ containers.insert( item->container(), (const char *)1 );
+ }
+ for (ObjectTreeListIterator it(*item->children()); it.current(); ++it)
+ collectContainers(it.current(), containers);
+}
+
+void
+Form::autoAssignTabStops()
+{
+ VerWidgetList list(toplevelContainer()->widget());
+ HorWidgetList hlist(toplevelContainer()->widget());
+
+ // 1. Collect all the containers, as we'll be sorting widgets groupped by containers
+ QPtrDict<char> containers;
+
+ collectContainers( toplevelContainer()->objectTree(), containers );
+
+ foreach_list(ObjectTreeListIterator, it, d->tabstops) {
+ if(it.current()->widget()) {
+ kdDebug() << "Form::autoAssignTabStops() widget to sort: " << it.current()->widget() << endl;
+ list.append(it.current()->widget());
+ }
+ }
+
+ list.sort();
+ foreach_list(QPtrListIterator<QWidget>, iter, list)
+ kdDebug() << iter.current()->className() << " " << iter.current()->name() << endl;
+
+ d->tabstops.clear();
+
+ /// We automatically sort widget from the top-left to bottom-right corner
+ //! \todo Handle RTL layout (ie from top-right to bottom-left)
+ foreach_list(WidgetListIterator, it, list) {
+ QWidget *w = it.current();
+ hlist.append(w);
+
+ ++it;
+ QWidget *nextw = it.current();
+ QObject *page_w = 0;
+ KFormDesigner::TabWidget *tab_w = KFormDesigner::findParent<KFormDesigner::TabWidget>(w, "KFormDesigner::TabWidget", page_w);
+ while (nextw) {
+ if (KexiUtils::hasParent(w, nextw)) // do not group (sort) widgets where on is a child of another
+ break;
+ if (nextw->y() >= (w->y() + 20))
+ break;
+ if (tab_w) {
+ QObject *page_nextw = 0;
+ KFormDesigner::TabWidget *tab_nextw = KFormDesigner::findParent<KFormDesigner::TabWidget>(nextw, "KFormDesigner::TabWidget", page_nextw);
+ if (tab_w == tab_nextw) {
+ if (page_w != page_nextw) // 'nextw' widget within different tab page
+ break;
+ }
+ }
+ hlist.append(nextw);
+ ++it;
+ nextw = it.current();
+ }
+ hlist.sort();
+
+ for(WidgetListIterator it2(hlist); it2.current() != 0; ++it2) {
+ ObjectTreeItem *tree = d->topTree->lookup(it2.current()->name());
+ if(tree) {
+ kdDebug() << "Form::autoAssignTabStops() adding " << tree->name() << endl;
+ d->tabstops.append(tree);
+ }
+ }
+
+ --it;
+ hlist.clear();
+ }
+}
+
+uint Form::formatVersion() const
+{
+ return d->formatVersion;
+}
+
+void Form::setFormatVersion(uint ver)
+{
+ d->formatVersion = ver;
+}
+uint Form::originalFormatVersion() const
+{
+ return d->originalFormatVersion;
+}
+
+void Form::setOriginalFormatVersion(uint ver)
+{
+ d->originalFormatVersion = ver;
+}
+
+void Form::setFormWidget(FormWidget* w)
+{
+ if (!d)
+ return;
+ d->formWidget = w;
+ if (!d->formWidget)
+ return;
+ d->formWidget->m_form = this;
+}
+
+#include "form.moc"
diff --git a/kexi/formeditor/form.h b/kexi/formeditor/form.h
new file mode 100644
index 00000000..899da955
--- /dev/null
+++ b/kexi/formeditor/form.h
@@ -0,0 +1,397 @@
+/* This file is part of the KDE project
+ Copyright (C) 2003 Lucijan Busch <lucijan@gmx.at>
+ Copyright (C) 2004 Cedric Pasteur <cedric.pasteur@free.fr>
+ Copyright (C) 2004-2007 Jaroslaw Staniek <js@iidea.pl>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+*/
+
+#ifndef KFORMDESIGNERFORM_H
+#define KFORMDESIGNERFORM_H
+
+#include <qobject.h>
+#include <qptrlist.h>
+
+#include "resizehandle.h"
+#include "utils.h"
+#include "objecttree.h"
+
+class QWidget;
+class QDomElement;
+class KActionCollection;
+class KCommandHistory;
+class KCommand;
+class PixmapCollection;
+
+namespace KFormDesigner {
+
+class Container;
+class WidgetPropertySet;
+class WidgetLibrary;
+class FormManager;
+class ObjectTree;
+class ObjectTreeItem;
+class ConnectionBuffer;
+
+//! Base (virtual) class for all form widgets
+/*! You need to inherit this class, and implement the drawing functions. This is necessary
+ because you cannot inherit QWidget twice, and we want form widgets to be any widget.
+ See FormWidgetBase in test/kfd_part.cpp and just copy functions there. */
+class KFORMEDITOR_EXPORT FormWidget
+{
+ public:
+ FormWidget();
+ virtual ~FormWidget();
+
+ /*! This function draws the rects in the \a list in the Form, above of all widgets,
+ using double-buffering. \a type can be 1 (selection rect)
+ or 2 (insert rect, dotted). */
+
+ virtual void drawRects(const QValueList<QRect> &list, int type) = 0;
+
+ virtual void drawRect(const QRect &r, int type) = 0;
+
+ /*! This function inits the buffer used for double-buffering. Called before drawing rect. */
+ virtual void initBuffer() = 0;
+
+ /*! Clears the form, ie pastes the whole buffer to repaint the Form. */
+ virtual void clearForm() = 0;
+
+ /*! This function highlights two widgets (to is optional), which are
+ sender and receiver, and draws a link between them. */
+ virtual void highlightWidgets(QWidget *from, QWidget *to) = 0;
+
+ protected:
+ Form *m_form;
+
+ friend class Form;
+};
+
+//! @internal
+class FormPrivate
+{
+ public:
+ FormPrivate();
+ ~FormPrivate();
+
+// FormManager *manager;
+ QGuardedPtr<Container> toplevel;
+ ObjectTree *topTree;
+ QGuardedPtr<QWidget> widget;
+
+ WidgetList selected;
+ ResizeHandleSet::Dict resizeHandles;
+
+ bool dirty;
+ bool interactive;
+ bool design;
+ QString filename;
+
+ KCommandHistory *history;
+ KActionCollection *collection;
+
+ ObjectTreeList tabstops;
+ bool autoTabstops;
+ ConnectionBuffer *connBuffer;
+
+ PixmapCollection *pixcollection;
+
+ //! This map is used to store cursor shapes before inserting (so we can restore them later)
+ QMap<QObject*,QCursor> cursors;
+
+ //!This string list is used to store the widgets which hasMouseTracking() == true (eg lineedits)
+ QStringList *mouseTrackers;
+
+ FormWidget *formWidget;
+
+ //! A set of head properties to be stored in a .ui file.
+ //! This includes KFD format version.
+ QMap<QCString,QString> headerProperties;
+
+ //! Format version, set by FormIO or on creating a new form.
+ uint formatVersion;
+ //! Format version, set by FormIO's loader or on creating a new form.
+ uint originalFormatVersion;
+};
+
+/*!
+ This class represents one form and holds the corresponding ObjectTree and Containers.
+ It takes care of widget selection and pasting widgets.
+ **/
+ //! A simple class representing a form
+class KFORMEDITOR_EXPORT Form : public QObject
+{
+ Q_OBJECT
+
+ public:
+ /*! Creates a simple Form, child of the FormManager \a manager.
+ */
+ Form(WidgetLibrary* library, const char *name=0, bool designMode = true);
+ ~Form();
+
+ //! \return A pointer to the WidgetLibrary supporting this form.
+ WidgetLibrary* library() const { return m_lib; }
+
+ /*!
+ Creates a toplevel widget out of another widget.
+ \a container will become the Form toplevel widget,
+ will be associated to an ObjectTree and so on.
+ \code QWidget *toplevel = new QWidget(this);
+ form->createToplevel(toplevel); \endcode
+ */
+ void createToplevel(QWidget *container, FormWidget *formWidget =0,
+ const QCString &classname="QWidget");
+
+ /*! \return the toplevel Container or 0 if this is a preview Form or createToplevel()
+ has not been called yet. */
+ Container* toplevelContainer() const { return d->toplevel; }
+
+ //! \return the FormWidget that holds this Form
+ FormWidget* formWidget() const { return d->formWidget; }
+
+ //! \return a pointer to this form's ObjectTree.
+ ObjectTree* objectTree() const { return d->topTree; }
+
+ //! \return the form's toplevel widget, or 0 if designMode() == false.
+ QWidget* widget() const;
+
+// //! \return the FormManager parent of this form.
+// FormManager* manager() const { return d->manager; }
+
+ /*! \return A pointer to the currently active Container, ie the parent Container for a simple widget,
+ and the widget's Container if it is itself a container.
+ */
+ Container* activeContainer();
+
+ /*! \return A pointer to the parent Container of the currently selected widget.
+ It is the same as activeContainer() for a simple widget, but unlike this function
+ it will also return the parent Container if the widget itself is a Container.
+ */
+ Container* parentContainer(QWidget *w=0);
+
+ /*! \return The \ref Container which is a parent of all widgets in \a wlist.
+ Used by \ref activeContainer(), and to find where
+ to paste widgets when multiple widgets are selected. */
+ ObjectTreeItem* commonParentContainer(WidgetList *wlist);
+
+ //! \return the list of currently selected widgets in this form
+ WidgetList* selectedWidgets() const {return &(d->selected);}
+
+ /*! \return currently selected widget in this form,
+ or 0 if there is no widget selected or more than one widget selected.
+ \see selectedWidgets() */
+ QWidget* selectedWidget() const { return d->selected.count()==1 ? d->selected.first() : 0; }
+
+ /*! Emits the action signals, and optionaly the undo/redo related signals
+ if \a withUndoAction == true. See \a FormManager for signals description. */
+ void emitActionSignals(bool withUndoAction=true);
+
+ /*! Emits again all signal related to selection (ie Form::selectionChanged()).
+ Called eg when the user has the focus again. */
+ void emitSelectionSignals();
+
+ /*! Sets the Form interactivity mode. Form is not interactive when
+ pasting widgets, or loading a Form.
+ */
+ void setInteractiveMode(bool interactive) { d->interactive = interactive; }
+
+ /*! \return true if the Form is being updated by the user, ie the created
+ widget were drawn on the Form.
+ \return false if the Form is being updated by the program, ie the widget
+ are created by FormIO, and so composed widgets
+ should not be populated automatically (such as QTabWidget).
+ */
+ bool interactiveMode() const { return d->interactive; }
+
+ /*! If \a design is true, the Form is in Design Mode (by default).
+ If \a design is false, then the Form is in Preview Mode, so
+ the ObjectTree and the Containers are removed. */
+ void setDesignMode(bool design);
+
+ //! \return The actual mode of the Form.
+ bool designMode() const { return d->design; }
+
+ bool isModified() { return d->dirty; }
+
+ //! \return the distance between two dots in the form background.
+//! @todo make gridSize configurable at global level
+ int gridSize() { return 10; }
+
+ //! \return the default margin for all the layout inside this Form.
+ int defaultMargin() { return 11;}
+
+ //! \return the default spacing for all the layout inside this Form.
+ int defaultSpacing() { return 6;}
+
+ /*! This function is used by ObjectTree to emit childAdded() signal (as it is not a QObject). */
+ void emitChildAdded(ObjectTreeItem *item);
+
+ /*! This function is used by ObjectTree to emit childRemoved() signal (as it is not a QObject). */
+ void emitChildRemoved(ObjectTreeItem *item);
+
+ /*! \return The filename of the UI file this Form was saved to,
+ or QString::null if the Form hasn't be saved yet. */
+ QString filename() const { return d->filename; }
+
+ //! Sets the filename of this Form to \a filename.
+ void setFilename(const QString &file) { d->filename = file; }
+
+ KCommandHistory* commandHistory() const { return d->history; }
+ ConnectionBuffer* connectionBuffer() const { return d->connBuffer; }
+ PixmapCollection* pixmapCollection() const { return d->pixcollection; }
+
+ /*! Adds a widget in the form's command history. Please use it instead
+ of calling directly actionCollection()->addCommand(). */
+ void addCommand(KCommand *command, bool execute);
+
+ /*! Clears form's command history. */
+ void clearCommandHistory();
+
+ /*! \return A pointer to this Form tabstops list : it contains all the widget
+ that can have focus ( ie no labels, etc)
+ in the order of the tabs.*/
+ ObjectTreeList* tabStops() const { return &(d->tabstops); }
+
+ inline ObjectTreeListIterator tabStopsIterator() const { return ObjectTreeListIterator(d->tabstops); }
+
+ /*! Called (e.g. by KexiDBForm) when certain widgets can have updated focusPolicy properties
+ these having no TabFocus flags set are removed from tabStops() list. */
+ void updateTabStopsOrder();
+
+ /*! Adds the widget at the end of tabstops list. Called on widget creation. */
+ void addWidgetToTabStops(ObjectTreeItem *it);
+
+ /*! \return True if the Form automatically handles tab stops. */
+ bool autoTabStops() const { return d->autoTabstops; }
+
+ /*! If \a autoTab is true, then the Form will automatically handle tab stops,
+ and the "Edit Tab Order" dialog will be disabled.
+ The tab widget will be set from the top-left to the bottom-right corner.\n
+ If \ autoTab is false, then it's up to the user to change tab stops
+ (which are by default in order of creation).*/
+ void setAutoTabStops(bool autoTab) { d->autoTabstops = autoTab;}
+
+ /*! Tells the Form to reassign the tab stops because the widget layout has changed
+ (called for example before saving or displaying the tab order dialog).
+ Automatically sorts widget from the top-left to bottom-right corner.
+ Widget can be grouped with containers. In paticular, for tab widgets,
+ child widgets should ordered by parent tab's order. */
+ void autoAssignTabStops();
+
+#ifdef KEXI_DEBUG_GUI
+ //! For debugging purposes
+ QString m_recentlyLoadedUICode;
+#endif
+
+ /*! Internal: called by ResizeHandle when mouse move event causes first
+ resize handle's dragging. As a result, current widget's editing (if any)
+ is finished - see WidgetFactory::resetEditor(). */
+// void resizeHandleDraggingStarted(QWidget *draggedWidget);
+
+ ResizeHandleSet* resizeHandlesForWidget(QWidget* w);
+
+ /*! A set of value/key pairs provided to be stored as attributes in
+ <kfd:customHeader/> XML element (saved as a first child of \<UI> element). */
+ QMap<QCString,QString>* headerProperties() const { return &d->headerProperties; }
+
+ //! \return format version number for this form.
+ //! For new forms it is equal to KFormDesigner::version().
+ uint formatVersion() const;
+ void setFormatVersion(uint ver);
+
+ //! \return original format version number for this form (as loaded from .ui XML string)
+ //! For new forms it is equal to KFormDesigner::version().
+ uint originalFormatVersion() const;
+ void setOriginalFormatVersion(uint ver);
+
+ public slots:
+ /*! This slot is called when the name of a widget was changed in Property Editor.
+ It renames the ObjectTreeItem associated to this widget.
+ */
+ void changeName(const QCString &oldname, const QCString &newname);
+
+ /*! Sets \a selected to be the selected widget of this Form.
+ If \a add is true, the formerly selected widget is still selected,
+ and the new one is just added. If false, \a selected replace the actually selected widget.
+ The form widget is always selected alone.
+ \a moreWillBeSelected indicates whether more widgets will be selected soon
+ (so for multiselection we should not update the property pane before the last widget is selected) */
+ void setSelectedWidget(QWidget *selected, bool add=false, bool dontRaise=false,
+ bool moreWillBeSelected = false);
+
+ /*! Unselects the widget \a w. Te widget is removed from the Cntainer 's list
+ and its resizeHandle is removed. */
+ void unSelectWidget(QWidget *w);
+
+ /*! Sets the form widget (it will be uniquely selected widget). */
+ void selectFormWidget();
+
+ void clearSelection();
+
+ protected slots:
+ /*! This slot is called when the toplevel widget of this Form is deleted
+ (ie the window closed) so that the Form gets deleted at the same time.
+ */
+ void formDeleted();
+
+ void emitUndoEnabled();
+ void emitRedoEnabled();
+
+ /*! This slot is called when a command is executed. The undo/redo signals
+ are emitted to update actions. */
+ void slotCommandExecuted();
+
+ /*! This slot is called when form is restored, ie when the user has undone
+ all actions. The form modified flag is updated, and
+ \ref FormManager::dirty() is called. */
+ void slotFormRestored();
+
+ signals:
+ /*! This signal is emitted by setSelectedWidget() when user selects a new widget,
+ to update both Property Editor and ObjectTreeView.
+ \a w is the newly selected widget.
+ */
+ void selectionChanged(QWidget *w, bool add, bool moreWillBeSelected = false);
+
+ /*! This signal is emitted when a new widget is created, to update ObjectTreeView.
+ \a it is the ObjectTreeItem representing this new widget.
+ */
+ void childAdded(ObjectTreeItem *it);
+
+ /*! This signal is emitted when a widget is deleted, to update ObjectTreeView.
+ \a it is the ObjectTreeItem representing this deleted widget.
+ */
+ void childRemoved(ObjectTreeItem *it);
+
+ //! This signal emitted when Form is about to be destroyed
+ void destroying();
+
+ protected:
+ void setConnectionBuffer(ConnectionBuffer *b) { d->connBuffer = b; }
+
+ void setFormWidget(FormWidget* w);
+ private:
+ WidgetLibrary *m_lib;
+ FormPrivate *d;
+
+ friend class FormManager;
+ friend class FormWidget;
+ friend class ConnectionDialog;
+};
+
+}
+
+#endif
diff --git a/kexi/formeditor/formIO.cpp b/kexi/formeditor/formIO.cpp
new file mode 100644
index 00000000..2327fb91
--- /dev/null
+++ b/kexi/formeditor/formIO.cpp
@@ -0,0 +1,1626 @@
+/* This file is part of the KDE project
+ Copyright (C) 2004 Cedric Pasteur <cedric.pasteur@free.fr>
+ Copyright (C) 2005-2007 Jaroslaw Staniek <js@iidea.pl>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+*/
+
+#include <kdebug.h>
+
+#include <qmetaobject.h>
+#include <qdom.h>
+#include <qfile.h>
+#include <qtextstream.h>
+#include <qcursor.h>
+#include <qbuffer.h>
+#include <qimage.h>
+#include <qlayout.h>
+#include <qobjectlist.h>
+#include <qdatetime.h>
+#include <qlabel.h>
+#include <qpainter.h>
+
+#include <kfiledialog.h>
+#include <klocale.h>
+#include <kcommand.h>
+#include <kaccelmanager.h>
+
+#include "form.h"
+#include "container.h"
+#include "objecttree.h"
+#include "formmanager.h"
+#include "widgetlibrary.h"
+#include "spring.h"
+#include "pixmapcollection.h"
+#include "events.h"
+#include "utils.h"
+#include "kexiflowlayout.h"
+#include "widgetwithsubpropertiesinterface.h"
+#include "formIO.h"
+
+/// A blank widget used when the class name is not supported
+CustomWidget::CustomWidget(const QCString &className, QWidget *parent, const char *name)
+: QWidget(parent, name), m_className(className)
+{
+ setBackgroundMode(Qt::PaletteDark);
+}
+
+CustomWidget::~CustomWidget()
+{
+}
+
+void
+CustomWidget::paintEvent(QPaintEvent *)
+{
+ QPainter p(this);
+ p.setPen(palette().active().text());
+ QRect r(rect());
+ r.setX(r.x()+2);
+ p.drawText(r, Qt::AlignTop, m_className);
+}
+
+using namespace KFormDesigner;
+
+QDict<QLabel> *FormIO::m_buddies = 0;
+ObjectTreeItem *FormIO::m_currentItem = 0;
+Form *FormIO::m_currentForm = 0;
+bool FormIO::m_savePixmapsInline = false;
+
+// FormIO itself
+
+KFORMEDITOR_EXPORT uint KFormDesigner::version()
+{
+ return KFORMDESIGNER_VERSION;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+///////////// Saving/loading functions //////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////////
+
+FormIO::FormIO()
+{
+}
+
+FormIO::~FormIO()
+{
+}
+
+bool
+FormIO::saveFormToFile(Form *form, const QString &filename)
+{
+ QString m_filename;
+ if(!form->filename().isNull() && filename.isNull())
+ m_filename = form->filename();
+
+ if(filename.isNull())
+ {
+ m_filename = KFileDialog::getSaveFileName(QString::null, i18n("*.ui|Qt Designer UI Files"));
+ if(m_filename.isNull())
+ return false;
+ }
+ else
+ m_filename = filename;
+ form->setFilename(m_filename);
+
+ QDomDocument domDoc;
+ if (!saveFormToDom(form, domDoc))
+ return false;
+
+ QFile file(m_filename);
+ if (!file.open(IO_WriteOnly))
+ return false;
+
+ QTextStream stream(&file);
+ stream << domDoc.toString(3) << endl;
+ file.close();
+
+ return true;
+}
+
+bool
+FormIO::saveFormToByteArray(Form *form, QByteArray &dest)
+{
+ QDomDocument domDoc;
+ if (!saveFormToDom(form, domDoc))
+ return false;
+ dest = domDoc.toCString();
+ return true;
+}
+
+bool
+FormIO::saveFormToString(Form *form, QString &dest, int indent)
+{
+ QDomDocument domDoc;
+ if (!saveFormToDom(form, domDoc))
+ return false;
+ dest = domDoc.toString(indent);
+ return true;
+}
+
+bool
+FormIO::saveFormToDom(Form *form, QDomDocument &domDoc)
+{
+ m_currentForm = form;
+
+ domDoc = QDomDocument("UI");
+ QDomElement uiElement = domDoc.createElement("UI");
+ domDoc.appendChild(uiElement);
+ uiElement.setAttribute("version", "3.1");
+ uiElement.setAttribute("stdsetdef", 1);
+
+ //update format version information
+ form->headerProperties()->insert("version", QString::number(form->formatVersion()));
+ //custom properties
+ QDomElement headerPropertiesEl = domDoc.createElement("kfd:customHeader");
+ for (QMapConstIterator<QCString,QString> it=form->headerProperties()->constBegin(); it!=form->headerProperties()->constEnd(); ++it) {
+ headerPropertiesEl.setAttribute(it.key(), it.data());
+ }
+ uiElement.appendChild(headerPropertiesEl);
+
+ /// We save the savePixmapsInline property in the Form
+ QDomElement inlinePix = domDoc.createElement("pixmapinproject");
+ uiElement.appendChild(inlinePix);
+
+ // We create the top class element
+ QDomElement baseClass = domDoc.createElement("class");
+ uiElement.appendChild(baseClass);
+ QDomText baseClassV = domDoc.createTextNode("QWidget");
+ baseClass.appendChild(baseClassV);
+
+ // Save the toplevel widgets, and so the whole Form
+ saveWidget(form->objectTree(), uiElement, domDoc);
+
+ // We then save the layoutdefaults element
+ QDomElement layoutDefaults = domDoc.createElement("layoutDefaults");
+ layoutDefaults.setAttribute("spacing", QString::number(form->defaultSpacing()));
+ layoutDefaults.setAttribute("margin", QString::number(form->defaultMargin()));
+ uiElement.appendChild(layoutDefaults);
+
+ /// Save tab Stops
+ if(form->autoTabStops())
+ form->autoAssignTabStops();
+ QDomElement tabStops = domDoc.createElement("tabstops");
+ uiElement.appendChild(tabStops);
+ for(ObjectTreeListIterator it( form->tabStopsIterator() ); it.current(); ++it)
+ {
+ QDomElement tabstop = domDoc.createElement("tabstop");
+ tabStops.appendChild(tabstop);
+ QDomText tabStopText = domDoc.createTextNode(it.current()->name());
+ tabstop.appendChild(tabStopText);
+ }
+
+ // Save the Form 's PixmapCollection
+ form->pixmapCollection()->save(uiElement);
+ // Save the Form connections
+ form->connectionBuffer()->save(uiElement);
+
+ form->commandHistory()->documentSaved();
+
+ m_currentForm = 0;
+ m_currentItem = 0;
+ //m_currentWidget = 0;
+
+ return true;
+}
+
+bool
+FormIO::loadFormFromByteArray(Form *form, QWidget *container, QByteArray &src, bool preview)
+{
+ QString errMsg;
+ int errLine;
+ int errCol;
+
+ QDomDocument inBuf;
+ bool parsed = inBuf.setContent(src, false, &errMsg, &errLine, &errCol);
+
+ if(!parsed)
+ {
+ kdDebug() << "WidgetWatcher::load(): " << errMsg << endl;
+ kdDebug() << "WidgetWatcher::load(): line: " << errLine << " col: " << errCol << endl;
+ return false;
+ }
+
+ if (!loadFormFromDom(form, container, inBuf))
+ return false;
+ if(preview)
+ form->setDesignMode(false);
+ return true;
+}
+
+bool
+FormIO::loadFormFromString(Form *form, QWidget *container, QString &src, bool preview)
+{
+ QString errMsg;
+ int errLine;
+ int errCol;
+
+#ifdef KEXI_DEBUG_GUI
+ form->m_recentlyLoadedUICode = src;
+#endif
+
+ QDomDocument inBuf;
+ bool parsed = inBuf.setContent(src, false, &errMsg, &errLine, &errCol);
+
+ if(!parsed)
+ {
+ kdDebug() << "WidgetWatcher::load(): " << errMsg << endl;
+ kdDebug() << "WidgetWatcher::load(): line: " << errLine << " col: " << errCol << endl;
+ return false;
+ }
+
+ if (!loadFormFromDom(form, container, inBuf))
+ return false;
+ if(preview)
+ form->setDesignMode(false);
+ return true;
+}
+
+bool
+FormIO::loadFormFromFile(Form *form, QWidget *container, const QString &filename)
+{
+ QString errMsg;
+ int errLine;
+ int errCol;
+ QString m_filename;
+
+ if(filename.isNull())
+ {
+ m_filename = KFileDialog::getOpenFileName(QString::null, i18n("*.ui|Qt Designer UI Files"));
+ if(m_filename.isNull())
+ return false;
+ }
+ else
+ m_filename = filename;
+
+ QFile file(m_filename);
+ if(!file.open(IO_ReadOnly))
+ {
+ kdDebug() << "Cannot open the file " << filename << endl;
+ return false;
+ }
+ QTextStream stream(&file);
+ QString text = stream.read();
+
+ QDomDocument inBuf;
+ bool parsed = inBuf.setContent(text, false, &errMsg, &errLine, &errCol);
+
+ if(!parsed)
+ {
+ kdDebug() << "WidgetWatcher::load(): " << errMsg << endl;
+ kdDebug() << "WidgetWatcher::load(): line: " << errLine << " col: " << errCol << endl;
+ return false;
+ }
+
+ return loadFormFromDom(form, container, inBuf);
+}
+
+bool
+FormIO::loadFormFromDom(Form *form, QWidget *container, QDomDocument &inBuf)
+{
+ m_currentForm = form;
+
+ QDomElement ui = inBuf.namedItem("UI").toElement();
+
+ //custom properties
+ form->headerProperties()->clear();
+ QDomElement headerPropertiesEl = ui.namedItem("kfd:customHeader").toElement();
+ QDomAttr attr = headerPropertiesEl.firstChild().toAttr();
+ while (!attr.isNull() && attr.isAttr()) {
+ form->headerProperties()->insert(attr.name().latin1(), attr.value());
+ attr = attr.nextSibling().toAttr();
+ }
+ //update format version information
+ uint ver = 1; //the default
+ if (form->headerProperties()->contains("version")) {
+ bool ok;
+ uint v = (*form->headerProperties())["version"].toUInt(&ok);
+ if (ok)
+ ver = v;
+ }
+ kdDebug() << "FormIO::loadFormFromDom(): original format version: " << ver << endl;
+ form->setOriginalFormatVersion( ver );
+ if (ver < KFormDesigner::version()) {
+//! @todo We can either 1) convert from old format and later save in a new one or 2) keep old format.
+//! To do this we may need to look at the original format version number.
+ kdDebug() << "FormIO::loadFormFromDom(): original format is older than current: " << KFormDesigner::version() << endl;
+ form->setFormatVersion( KFormDesigner::version() );
+ }
+ else
+ form->setFormatVersion( ver );
+
+ if (ver > KFormDesigner::version()) {
+//! @todo display information about too new format and that "some information will not be available".
+ kdDebug() << "FormIO::loadFormFromDom(): original format is newer than current: " << KFormDesigner::version() << endl;
+ }
+
+ // Load the pixmap collection
+ m_savePixmapsInline = ( (ui.namedItem("pixmapinproject").isNull()) || (!ui.namedItem("images").isNull()) );
+ form->pixmapCollection()->load(ui.namedItem("collection"));
+
+ QDomElement element = ui.namedItem("widget").toElement();
+ createToplevelWidget(form, container, element);
+
+ // Loading the tabstops
+ QDomElement tabStops = ui.namedItem("tabstops").toElement();
+// if(tabStops.isNull())
+// return 1;
+ if(!tabStops.isNull()) {
+ int i = 0;
+ uint itemsNotFound = 0;
+ for(QDomNode n = tabStops.firstChild(); !n.isNull(); n = n.nextSibling(), i++)
+ {
+ QString name = n.toElement().text();
+ ObjectTreeItem *item = form->objectTree()->lookup(name);
+ if(!item)
+ {
+ kdDebug() << "FormIO::loadFormFromDom ERROR : no ObjectTreeItem " << endl;
+ continue;
+ }
+ const int index = form->tabStops()->findRef(item);
+ /* Compute a real destination index: "a number of not found items so far". */
+ const int realIndex = i - itemsNotFound;
+ if((index != -1) && (index != realIndex)) // the widget is not in the same place, so we move it
+ {
+ form->tabStops()->remove(item);
+ form->tabStops()->insert(realIndex, item);
+ }
+ if(index == -1) {
+ itemsNotFound++;
+ kdDebug() << "FormIO: item '" << name << "' not in list" << endl;
+ }
+ }
+ }
+
+ // Load the form connections
+ form->connectionBuffer()->load(ui.namedItem("connections"));
+
+ m_currentForm = 0;
+ m_currentItem = 0;
+
+ return true;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+///////////// Functions to save/load properties /////////////////////////////
+/////////////////////////////////////////////////////////////////////////////
+
+void
+FormIO::savePropertyValue(QDomElement &parentNode, QDomDocument &parent, const char *name,
+ const QVariant &value, QWidget *w, WidgetLibrary *lib)
+{
+ // Widget specific properties and attributes ///////////////
+// kdDebug() << "FormIO::savePropertyValue() Saving the property: " << name << endl;
+ WidgetWithSubpropertiesInterface* subpropIface = dynamic_cast<WidgetWithSubpropertiesInterface*>(w);
+ QWidget *subwidget = w;
+ bool addSubwidgetFlag = false;
+ int propertyId = w->metaObject()->findProperty(name, true);
+ if (propertyId == -1 && subpropIface && subpropIface->subwidget()) { // try property from subwidget
+ subwidget = subpropIface->subwidget();
+ propertyId = subpropIface->subwidget()->metaObject()->findProperty(name, true);
+ addSubwidgetFlag = true;
+ }
+ if(propertyId == -1)
+ {
+ kdDebug() << "FormIO::savePropertyValue() The object doesn't have this property. Let's try the WidgetLibrary." << endl;
+ if(lib)
+ lib->saveSpecialProperty(w->className(), name, value, w, parentNode, parent);
+ return;
+ }
+
+ const QMetaProperty *meta = subwidget->metaObject()->property(propertyId, true);
+ if (!meta->stored( subwidget )) //not storable
+ return;
+ QDomElement propertyE = parent.createElement("property");
+ propertyE.setAttribute("name", name);
+ if (addSubwidgetFlag)
+ propertyE.setAttribute("subwidget", "true");
+
+ if(meta && meta->isEnumType())
+ {
+ // this property is enum or set type
+ QDomElement type;
+ QDomText valueE;
+
+ if(meta->isSetType())
+ {
+ QStringList list = QStringList::fromStrList(meta->valueToKeys(value.toInt()));
+ type = parent.createElement("set");
+ valueE = parent.createTextNode(list.join("|"));
+ type.appendChild(valueE);
+ }
+ else
+ {
+ QString s = meta->valueToKey(value.toInt());
+ type = parent.createElement("enum");
+ valueE = parent.createTextNode(s);
+ type.appendChild(valueE);
+ }
+ propertyE.appendChild(type);
+ parentNode.appendChild(propertyE);
+ return;
+ }
+
+ if(value.type() == QVariant::Pixmap) {
+ QDomText valueE;
+ QDomElement type = parent.createElement("pixmap");
+ QCString property = propertyE.attribute("name").latin1();
+//todo QCString pixmapName = m_currentItem->widget()->property("pixmapName").toCString();
+ if(m_savePixmapsInline /* (js)too risky: || m_currentItem->pixmapName(property).isNull() */)
+ valueE = parent.createTextNode(saveImage(parent, value.toPixmap()));
+ else
+ valueE = parent.createTextNode(m_currentItem->pixmapName(property));
+ type.appendChild(valueE);
+ propertyE.appendChild(type);
+ parentNode.appendChild(propertyE);
+ return;
+ }
+
+ // Saving a "normal" property
+ writeVariant(parent, propertyE, value);
+ parentNode.appendChild(propertyE);
+}
+
+void
+FormIO::writeVariant(QDomDocument &parent, QDomElement &parentNode, QVariant value)
+{
+ QDomElement type;
+ QDomText valueE;
+
+ switch(value.type())
+ {
+ case QVariant::String:
+ {
+ type = parent.createElement("string");
+ valueE = parent.createTextNode(value.toString());
+ type.appendChild(valueE);
+ break;
+ }
+ case QVariant::CString:
+ {
+ type = parent.createElement("cstring");
+ valueE = parent.createTextNode(value.toString());
+ type.appendChild(valueE);
+ break;
+ }
+ case QVariant::Rect:
+ {
+ type = parent.createElement("rect");
+ QDomElement x = parent.createElement("x");
+ QDomElement y = parent.createElement("y");
+ QDomElement w = parent.createElement("width");
+ QDomElement h = parent.createElement("height");
+ QDomText valueX = parent.createTextNode(QString::number(value.toRect().x()));
+ QDomText valueY = parent.createTextNode(QString::number(value.toRect().y()));
+ QDomText valueW = parent.createTextNode(QString::number(value.toRect().width()));
+ QDomText valueH = parent.createTextNode(QString::number(value.toRect().height()));
+
+ x.appendChild(valueX);
+ y.appendChild(valueY);
+ w.appendChild(valueW);
+ h.appendChild(valueH);
+
+ type.appendChild(x);
+ type.appendChild(y);
+ type.appendChild(w);
+ type.appendChild(h);
+ break;
+ }
+ case QVariant::Color:
+ {
+ type = parent.createElement("color");
+ QDomElement r = parent.createElement("red");
+ QDomElement g = parent.createElement("green");
+ QDomElement b = parent.createElement("blue");
+ QDomText valueR = parent.createTextNode(QString::number(value.toColor().red()));
+ QDomText valueG = parent.createTextNode(QString::number(value.toColor().green()));
+ QDomText valueB = parent.createTextNode(QString::number(value.toColor().blue()));
+
+ r.appendChild(valueR);
+ g.appendChild(valueG);
+ b.appendChild(valueB);
+
+ type.appendChild(r);
+ type.appendChild(g);
+ type.appendChild(b);
+ break;
+ }
+ case QVariant::Bool:
+ {
+ type = parent.createElement("bool");
+ //valueE = parent.createTextNode(QString::number(value.toBool()));
+ valueE = parent.createTextNode(value.toBool() ? "true" : "false");
+ type.appendChild(valueE);
+ break;
+ }
+ case QVariant::Int:
+ case QVariant::UInt:
+ {
+ type = parent.createElement("number");
+ valueE = parent.createTextNode(QString::number(value.toInt()));
+ type.appendChild(valueE);
+ break;
+ }
+ case QVariant::Size:
+ {
+ type = parent.createElement("size");
+ QDomElement w = parent.createElement("width");
+ QDomElement h = parent.createElement("height");
+ QDomText valueW = parent.createTextNode(QString::number(value.toSize().width()));
+ QDomText valueH = parent.createTextNode(QString::number(value.toSize().height()));
+
+ w.appendChild(valueW);
+ h.appendChild(valueH);
+
+ type.appendChild(w);
+ type.appendChild(h);
+ break;
+ }
+ case QVariant::Point:
+ {
+ type = parent.createElement("point");
+ QDomElement x = parent.createElement("x");
+ QDomElement y = parent.createElement("y");
+ QDomText valueX = parent.createTextNode(QString::number(value.toPoint().x()));
+ QDomText valueY = parent.createTextNode(QString::number(value.toPoint().y()));
+
+ x.appendChild(valueX);
+ y.appendChild(valueY);
+
+ type.appendChild(x);
+ type.appendChild(y);
+ break;
+ }
+ case QVariant::Font:
+ {
+ type = parent.createElement("font");
+ QDomElement f = parent.createElement("family");
+ QDomElement p = parent.createElement("pointsize");
+ QDomElement w = parent.createElement("weight");
+ QDomElement b = parent.createElement("bold");
+ QDomElement i = parent.createElement("italic");
+ QDomElement u = parent.createElement("underline");
+ QDomElement s = parent.createElement("strikeout");
+ QDomText valueF = parent.createTextNode(value.toFont().family());
+ QDomText valueP = parent.createTextNode(QString::number(value.toFont().pointSize()));
+ QDomText valueW = parent.createTextNode(QString::number(value.toFont().weight()));
+ QDomText valueB = parent.createTextNode(QString::number(value.toFont().bold()));
+ QDomText valueI = parent.createTextNode(QString::number(value.toFont().italic()));
+ QDomText valueU = parent.createTextNode(QString::number(value.toFont().underline()));
+ QDomText valueS = parent.createTextNode(QString::number(value.toFont().strikeOut()));
+
+ f.appendChild(valueF);
+ p.appendChild(valueP);
+ w.appendChild(valueW);
+ b.appendChild(valueB);
+ i.appendChild(valueI);
+ u.appendChild(valueU);
+ s.appendChild(valueS);
+
+ type.appendChild(f);
+ type.appendChild(p);
+ type.appendChild(w);
+ type.appendChild(b);
+ type.appendChild(i);
+ type.appendChild(u);
+ type.appendChild(s);
+ break;
+ }
+ case QVariant::Cursor:
+ {
+ type = parent.createElement("cursor");
+ valueE = parent.createTextNode(QString::number(value.toCursor().shape()));
+ type.appendChild(valueE);
+ break;
+ }
+ case QVariant::SizePolicy:
+ {
+ type = parent.createElement("sizepolicy");
+ QDomElement h = parent.createElement("hsizetype");
+ QDomElement v = parent.createElement("vsizetype");
+ QDomElement hs = parent.createElement("horstretch");
+ QDomElement vs = parent.createElement("verstretch");
+ QDomText valueH = parent.createTextNode(QString::number(value.toSizePolicy().horData()));
+ QDomText valueV = parent.createTextNode(QString::number(value.toSizePolicy().verData()));
+ QDomText valueHS = parent.createTextNode(QString::number(value.toSizePolicy().horStretch()));
+ QDomText valueVS = parent.createTextNode(QString::number(value.toSizePolicy().verStretch()));
+
+ h.appendChild(valueH);
+ v.appendChild(valueV);
+ hs.appendChild(valueHS);
+ vs.appendChild(valueVS);
+
+ type.appendChild(h);
+ type.appendChild(v);
+ type.appendChild(hs);
+ type.appendChild(vs);
+ break;
+ }
+ case QVariant::Time:
+ {
+ type = parent.createElement("time");
+ QDomElement h = parent.createElement("hour");
+ QDomElement m = parent.createElement("minute");
+ QDomElement s = parent.createElement("second");
+ QDomText valueH = parent.createTextNode(QString::number(value.toTime().hour()));
+ QDomText valueM = parent.createTextNode(QString::number(value.toTime().minute()));
+ QDomText valueS = parent.createTextNode(QString::number(value.toTime().second()));
+
+ h.appendChild(valueH);
+ m.appendChild(valueM);
+ s.appendChild(valueS);
+
+ type.appendChild(h);
+ type.appendChild(m);
+ type.appendChild(s);
+ break;
+ }
+ case QVariant::Date:
+ {
+ type = parent.createElement("date");
+ QDomElement y = parent.createElement("year");
+ QDomElement m = parent.createElement("month");
+ QDomElement d = parent.createElement("day");
+ QDomText valueY = parent.createTextNode(QString::number(value.toDate().year()));
+ QDomText valueM = parent.createTextNode(QString::number(value.toDate().month()));
+ QDomText valueD = parent.createTextNode(QString::number(value.toDate().day()));
+
+ y.appendChild(valueY);
+ m.appendChild(valueM);
+ d.appendChild(valueD);
+
+ type.appendChild(y);
+ type.appendChild(m);
+ type.appendChild(d);
+ break;
+ }
+ case QVariant::DateTime:
+ {
+ type = parent.createElement("datetime");
+ QDomElement h = parent.createElement("hour");
+ QDomElement m = parent.createElement("minute");
+ QDomElement s = parent.createElement("second");
+ QDomElement y = parent.createElement("year");
+ QDomElement mo = parent.createElement("month");
+ QDomElement d = parent.createElement("day");
+ QDomText valueH = parent.createTextNode(QString::number(value.toDateTime().time().hour()));
+ QDomText valueM = parent.createTextNode(QString::number(value.toDateTime().time().minute()));
+ QDomText valueS = parent.createTextNode(QString::number(value.toDateTime().time().second()));
+ QDomText valueY = parent.createTextNode(QString::number(value.toDateTime().date().year()));
+ QDomText valueMo = parent.createTextNode(QString::number(value.toDateTime().date().month()));
+ QDomText valueD = parent.createTextNode(QString::number(value.toDateTime().date().day()));
+
+ h.appendChild(valueH);
+ m.appendChild(valueM);
+ s.appendChild(valueS);
+ y.appendChild(valueY);
+ mo.appendChild(valueMo);
+ d.appendChild(valueD);
+
+ type.appendChild(h);
+ type.appendChild(m);
+ type.appendChild(s);
+ type.appendChild(y);
+ type.appendChild(mo);
+ type.appendChild(d);
+ break;
+ }
+ default:
+ break;
+ }
+
+ parentNode.appendChild(type);
+}
+
+void
+FormIO::savePropertyElement(QDomElement &parentNode, QDomDocument &domDoc, const QString &tagName, const QString &property, const QVariant &value)
+{
+ QDomElement propertyE = domDoc.createElement(tagName);
+ propertyE.setAttribute("name", property);
+ writeVariant(domDoc, propertyE, value);
+ parentNode.appendChild(propertyE);
+}
+
+QVariant
+FormIO::readPropertyValue(QDomNode node, QObject *obj, const QString &name)
+{
+ QDomElement tag = node.toElement();
+ QString text = tag.text();
+ QString type = tag.tagName();
+
+ if(type == "string" || type == "cstring")
+ return text;
+ else if(type == "rect")
+ {
+ QDomElement x = node.namedItem("x").toElement();
+ QDomElement y = node.namedItem("y").toElement();
+ QDomElement w = node.namedItem("width").toElement();
+ QDomElement h = node.namedItem("height").toElement();
+
+ int rx = x.text().toInt();
+ int ry = y.text().toInt();
+ int rw = w.text().toInt();
+ int rh = h.text().toInt();
+
+ return QRect(rx, ry, rw, rh);
+ }
+ else if(type == "color")
+ {
+ QDomElement r = node.namedItem("red").toElement();
+ QDomElement g = node.namedItem("green").toElement();
+ QDomElement b = node.namedItem("blue").toElement();
+
+ int red = r.text().toInt();
+ int green = g.text().toInt();
+ int blue = b.text().toInt();
+
+ return QColor(red, green, blue);
+ }
+ else if(type == "bool")
+ {
+ if(text == "true")
+ return QVariant(true, 3);
+ else if(text == "false")
+ return QVariant(false, 3);
+ return QVariant(text.toInt(), 3);
+ }
+ else if(type == "number")
+ {
+ return text.toInt();
+ }
+ else if(type == "size")
+ {
+ QDomElement w = node.namedItem("width").toElement();
+ QDomElement h = node.namedItem("height").toElement();
+
+ return QSize(w.text().toInt(), h.text().toInt());
+ }
+ else if(type == "point")
+ {
+ QDomElement x = node.namedItem("x").toElement();
+ QDomElement y = node.namedItem("y").toElement();
+
+ return QPoint(x.text().toInt(), y.text().toInt());
+ }
+ else if(type == "font")
+ {
+ QDomElement fa = node.namedItem("family").toElement();
+ QDomElement p = node.namedItem("pointsize").toElement();
+ QDomElement w = node.namedItem("weight").toElement();
+ QDomElement b = node.namedItem("bold").toElement();
+ QDomElement i = node.namedItem("italic").toElement();
+ QDomElement u = node.namedItem("underline").toElement();
+ QDomElement s = node.namedItem("strikeout").toElement();
+
+ QFont f;
+ f.setFamily(fa.text());
+ f.setPointSize(p.text().toInt());
+ f.setWeight(w.text().toInt());
+ f.setBold(b.text().toInt());
+ f.setItalic(i.text().toInt());
+ f.setUnderline(u.text().toInt());
+ f.setStrikeOut(s.text().toInt());
+
+ return f;
+ }
+ else if(type == "cursor")
+ {
+ return QCursor(text.toInt());
+ }
+ else if(type == "time")
+ {
+ QDomElement h = node.namedItem("hour").toElement();
+ QDomElement m = node.namedItem("minute").toElement();
+ QDomElement s = node.namedItem("second").toElement();
+
+ return QTime(h.text().toInt(), m.text().toInt(), s.text().toInt());
+ }
+ else if(type == "date")
+ {
+ QDomElement y = node.namedItem("year").toElement();
+ QDomElement m = node.namedItem("month").toElement();
+ QDomElement d = node.namedItem("day").toElement();
+
+ return QDate(y.text().toInt(), m.text().toInt(), d.text().toInt());
+ }
+ else if(type == "datetime")
+ {
+ QDomElement h = node.namedItem("hour").toElement();
+ QDomElement m = node.namedItem("minute").toElement();
+ QDomElement s = node.namedItem("second").toElement();
+ QDomElement y = node.namedItem("year").toElement();
+ QDomElement mo = node.namedItem("month").toElement();
+ QDomElement d = node.namedItem("day").toElement();
+
+ QTime t(h.text().toInt(), m.text().toInt(), s.text().toInt());
+ QDate da(y.text().toInt(), mo.text().toInt(), d.text().toInt());
+
+ return QDateTime(da, t);
+ }
+ else if(type == "sizepolicy")
+ {
+ QDomElement h = node.namedItem("hsizetype").toElement();
+ QDomElement v = node.namedItem("vsizetype").toElement();
+ QDomElement hs = node.namedItem("horstretch").toElement();
+ QDomElement vs = node.namedItem("verstretch").toElement();
+
+ QSizePolicy s;
+ s.setHorData((QSizePolicy::SizeType)h.text().toInt());
+ s.setVerData((QSizePolicy::SizeType)v.text().toInt());
+ s.setHorStretch(hs.text().toInt());
+ s.setVerStretch(vs.text().toInt());
+ return s;
+ }
+ else if(type == "pixmap")
+ {
+ if(m_savePixmapsInline || !m_currentForm || !m_currentItem || !m_currentForm->pixmapCollection()->contains(text))
+ return loadImage(tag.ownerDocument(), text);
+ else
+ {
+ m_currentItem->setPixmapName(name.latin1(), text);
+ return m_currentForm->pixmapCollection()->getPixmap(text);
+ }
+ return QVariant(QPixmap());
+ }
+ else if(type == "enum")
+ return text;
+ else if(type == "set")
+ {
+ WidgetWithSubpropertiesInterface* subpropIface = dynamic_cast<WidgetWithSubpropertiesInterface*>(obj);
+ QObject *subobject = (subpropIface && subpropIface->subwidget()) ? subpropIface->subwidget() : obj;
+ const int count = subobject->metaObject()->findProperty(name.latin1(), true);
+ const QMetaProperty *meta = count!=-1 ? subobject->metaObject()->property(count, true) : 0;
+
+ if (meta) {
+ if (meta->isSetType()) {
+ QStrList keys;
+ const QStringList list( QStringList::split("|", text) );
+ for (QStringList::ConstIterator it = list.constBegin(); it != list.constEnd(); ++it)
+ keys.append((*it).latin1());
+
+ return meta->keysToValue(keys);
+ }
+ }
+ else {
+ // Metaproperty not found, probably because subwidget is not created.
+ // We will return a string list here with hope that names will
+ // be resolved and translated into an integer value later when subwidget is created,
+ // e.g. near KexiFormView::updateValuesForSubproperties()
+ return QStringList::split("|", text);
+ }
+ }
+ return QVariant();
+}
+
+/////////////////////////////////////////////////////////////////////////////
+///////////// Functions to save/load widgets ////////////////////////////////
+/////////////////////////////////////////////////////////////////////////////
+
+void
+FormIO::saveWidget(ObjectTreeItem *item, QDomElement &parent, QDomDocument &domDoc, bool insideGridLayout)
+{
+ if (!item)
+ return;
+ bool savedAlignment = false;
+ // we let Spring class handle saving itself
+ if(item->className() == "Spring")
+ {
+ Spring::saveSpring(item, parent, domDoc, insideGridLayout);
+ return;
+ }
+
+ bool resetCurrentForm = false;
+ m_currentItem = item;
+ if(!m_currentForm) // copying widget
+ {
+ resetCurrentForm = true;
+ m_currentForm = item->container() ? item->container()->form() : item->parent()->container()->form();
+ }
+
+
+ WidgetLibrary *lib = m_currentForm->library();
+// if(item->container())
+// lib = item->container()->form()->manager()->lib();
+// else
+// lib = item->parent()->container()->form()->manager()->lib();
+
+ // We create the "widget" element
+ QDomElement tclass = domDoc.createElement("widget");
+ parent.appendChild(tclass);
+
+ if(insideGridLayout)
+ {
+ tclass.setAttribute("row", item->gridRow());
+ tclass.setAttribute("column", item->gridCol());
+ if(item->spanMultipleCells())
+ {
+ tclass.setAttribute("rowspan", item->gridRowSpan());
+ tclass.setAttribute("colspan", item->gridColSpan());
+ }
+ }
+
+ if(!item->parent()) // Toplevel widget
+ tclass.setAttribute("class", "QWidget");
+ // For compatibility, HBox, VBox and Grid are saved as "QLayoutWidget"
+ else if(item->widget()->isA("HBox") || item->widget()->isA("VBox") || item->widget()->isA("Grid")
+ || item->widget()->isA("HFlow") || item->widget()->isA("VFlow"))
+ tclass.setAttribute("class", "QLayoutWidget");
+ else if(item->widget()->isA("CustomWidget"))
+ tclass.setAttribute("class", item->className());
+ else // Normal widgets
+ tclass.setAttribute("class", lib->savingName(item->widget()->className()) );
+
+ savePropertyValue(tclass, domDoc, "name", item->widget()->property("name"), item->widget());
+
+ // Important: save dataSource property FIRST before properties like "alignment"
+ // - needed when subproperties are defined after subwidget creation, and subwidget is created after setting "dataSource"
+ // (this is the case for KexiDBAutoField)
+//! @todo more properties like "dataSource" may needed here...
+// if (-1 != item->widget()->metaObject()->findProperty("dataSource"))
+ // savePropertyValue(tclass, domDoc, "dataSource", item->widget()->property("dataSource"), item->widget());
+
+ // We don't want to save the geometry if the widget is inside a layout (so parent.tagName() == "grid" for example)
+ if(item && !item->parent()) {
+ // save form widget size, but not its position
+ savePropertyValue(tclass, domDoc, "geometry",
+ QRect( QPoint(0,0), item->widget()->size()),
+ item->widget());
+ }
+ // normal widget (if == "UI', it means we're copying widget)
+ else if(parent.tagName() == "widget" || parent.tagName() == "UI")
+ savePropertyValue(tclass, domDoc, "geometry", item->widget()->property("geometry"), item->widget());
+
+ // Save the buddy widget for a label
+ if(item->widget()->inherits("QLabel") && ((QLabel*)item->widget())->buddy())
+ savePropertyElement(tclass, domDoc, "property", "buddy", ((QLabel*)item->widget())->buddy()->name());
+
+ // We save every property in the modifProp list of the ObjectTreeItem
+ QVariantMap *map = new QVariantMap( *(item->modifiedProperties()) );
+ QMap<QString,QVariant>::ConstIterator endIt = map->constEnd();
+ for(QMap<QString,QVariant>::ConstIterator it = map->constBegin(); it != endIt; ++it)
+ {
+ const QCString name( it.key().latin1() );
+ if(name == "hAlign" || name == "vAlign" || name == "wordbreak" || name == "alignment") {
+ if(!savedAlignment) // not to save it twice
+ {
+ savePropertyValue(tclass, domDoc, "alignment", item->widget()->property("alignment"), item->widget());
+ savedAlignment = true;
+ }
+ }
+ else if(name == "name" || name == "geometry" || name == "layout") {
+ // these have already been saved
+ }
+ else {
+ savePropertyValue(tclass, domDoc, it.key().latin1(), item->widget()->property(it.key().latin1()),
+ item->widget(), lib);
+ }
+ }
+ delete map;
+
+ if(item->widget()->isA("CustomWidget")) {
+ QDomDocument doc("TEMP");
+ doc.setContent(item->m_unknownProps);
+ for(QDomNode n = doc.firstChild(); !n.isNull(); n = n.nextSibling()) {
+ tclass.appendChild(n.cloneNode());
+ }
+
+ }
+ // Saving container 's layout if there is one
+ QDomElement layout;
+ if(item->container() && item->container()->layoutType() != Container::NoLayout)
+ {
+ if(item->container()->layout()) // there is a layout
+ {
+ layout = domDoc.createElement("temp");
+ savePropertyValue(layout, domDoc, "name", "unnamed", item->widget());
+ if(item->modifiedProperties()->contains("layoutMargin"))
+ savePropertyElement(layout, domDoc, "property", "margin", item->container()->layoutMargin());
+ if(item->modifiedProperties()->contains("layoutSpacing"))
+ savePropertyElement(layout, domDoc, "property", "spacing", item->container()->layoutSpacing());
+ tclass.appendChild(layout);
+ }
+ }
+
+ int layoutType = item->container() ? item->container()->layoutType() : Container::NoLayout;
+ switch(layoutType) {
+ case Container::Grid: // grid layout
+ {
+ layout.setTagName("grid");
+ for(ObjectTreeItem *objIt = item->children()->first(); objIt; objIt = item->children()->next())
+ saveWidget(objIt, layout, domDoc, true);
+ break;
+ }
+ case Container::HBox: case Container::VBox:
+ {
+ // as we don't save geometry, we need to sort widgets in the right order, not creation order
+ WidgetList *list;
+ if(layout.tagName() == "hbox") {
+ list = new HorWidgetList(item->container()->form()->toplevelContainer()->widget());
+ layout.setTagName("hbox");
+ }
+ else {
+ list = new VerWidgetList(item->container()->form()->toplevelContainer()->widget());
+ layout.setTagName("vbox");
+ }
+
+ for(ObjectTreeItem *objTree = item->children()->first(); objTree; objTree = item->children()->next())
+ list->append(objTree->widget());
+ list->sort();
+
+ for(QWidget *obj = list->first(); obj; obj = list->next()) {
+ ObjectTreeItem *titem = item->container()->form()->objectTree()->lookup(obj->name());
+ if(item)
+ saveWidget(titem, layout, domDoc);
+ }
+ delete list;
+ break;
+ }
+ case Container::HFlow: case Container::VFlow:
+ {
+ layout.setTagName("grid");
+ KexiFlowLayout *flow = static_cast<KexiFlowLayout*>(item->container()->layout());
+ if(!flow) break;
+ WidgetList *list = (WidgetList*)flow->widgetList();
+
+ // save some special properties
+ savePropertyElement(layout, domDoc, "property", "customLayout", Container::layoutTypeToString(item->container()->layoutType()) );
+ savePropertyElement(layout, domDoc, "property", "justify", QVariant(static_cast<KexiFlowLayout*>(item->container()->layout())->isJustified(), 3) );
+
+ // fill the widget's grid info, ie just simulate grid layout
+ item->container()->createGridLayout(true);
+ for(QWidget *obj = list->first(); obj; obj = list->next()) {
+ ObjectTreeItem *titem = item->container()->form()->objectTree()->lookup(obj->name());
+ if(item)
+ saveWidget(titem, layout, domDoc, true); // save grid info for compatibility with QtDesigner
+ }
+ delete list;
+ break;
+ }
+ default:
+ {
+ for(ObjectTreeItem *objIt = item->children()->first(); objIt; objIt = item->children()->next())
+ saveWidget(objIt, tclass, domDoc);
+ }
+ }
+
+ addIncludeFileName(lib->includeFileName(item->widget()->className()), domDoc);
+
+ if(resetCurrentForm)
+ m_currentForm = 0;
+ m_currentItem = 0;
+}
+
+void
+FormIO::cleanClipboard(QDomElement &uiElement)
+{
+ // remove includehints element not needed
+ if(!uiElement.namedItem("includehints").isNull())
+ uiElement.removeChild(uiElement.namedItem("includehints"));
+ // and ensure images and connection are at the end
+ if(!uiElement.namedItem("connections").isNull())
+ uiElement.insertAfter(uiElement.namedItem("connections"), QDomNode());
+ if(!uiElement.namedItem("images").isNull())
+ uiElement.insertAfter(uiElement.namedItem("images"), QDomNode());
+}
+
+void
+FormIO::loadWidget(Container *container, const QDomElement &el, QWidget *parent)
+{
+ bool resetCurrentForm = false;
+ if(!m_currentForm) // pasting widget
+ {
+ resetCurrentForm = true;
+ m_currentForm = container->form();
+ }
+
+ // We first look for the widget's name
+ QString wname;
+ for(QDomNode n = el.firstChild(); !n.isNull(); n = n.nextSibling())
+ {
+ if((n.toElement().tagName() == "property") && (n.toElement().attribute("name") == "name"))
+ {
+ wname = n.toElement().text();
+ break;
+ }
+ }
+
+ QWidget *w;
+ QCString classname, alternate;
+ // We translate some name (for compatibility)
+ if(el.tagName() == "spacer")
+ classname = "Spring";
+ else if(el.attribute("class") == "QLayoutWidget")
+ {
+ for(QDomNode n = el.firstChild(); !n.isNull(); n = n.nextSibling())
+ {
+ QString tagName = n.toElement().tagName();
+ if(tagName == "property")
+ continue;
+ if(tagName == "hbox")
+ classname = "HBox";
+ else if(tagName == "vbox")
+ classname = "VBox";
+ else if(tagName == "grid") {
+ // first, see if it is flow layout
+ for(QDomNode child = n.firstChild(); !child.isNull(); child = child.nextSibling()) {
+ if((child.toElement().tagName() == "property")
+ && (child.toElement().attribute("name") == "customLayout"))
+ {
+ classname = child.toElement().text().latin1();
+ break;
+ }
+ }
+
+ if(classname.isEmpty()) // normal grid
+ classname = "Grid";
+ }
+ }
+ }
+ else
+ // We check if this classname is an alternate one, and replace it if necessary
+ {
+ classname = el.attribute("class").latin1();
+ alternate = container->form()->library()->classNameForAlternate(classname);
+ }
+
+ if(alternate == "CustomWidget")
+ w = new CustomWidget(classname, container->widget(), wname.latin1());
+ else
+ {
+ if(!alternate.isNull())
+ classname = alternate;
+
+ int widgetOptions = WidgetFactory::DefaultOptions;
+ if (!container->form()->designMode()) {
+ widgetOptions ^= WidgetFactory::DesignViewMode;
+ }
+
+ if(!parent)
+ w = container->form()->library()->createWidget(classname, container->widget(),
+ wname.latin1(), container, widgetOptions);
+ else
+ w = container->form()->library()->createWidget(classname, parent, wname.latin1(),
+ container, widgetOptions);
+ }
+
+ if(!w)
+ return;
+#if KDE_VERSION >= KDE_MAKE_VERSION(3,4,0)
+//! @todo allow setting this for data view mode as well
+ if (m_currentForm->designMode()) {
+ //don't generate accelerators for widgets in design mode
+ KAcceleratorManager::setNoAccel(w);
+ }
+#endif
+ w->setStyle(&(container->widget()->style()));
+ w->show();
+
+ // We create and insert the ObjectTreeItem at the good place in the ObjectTree
+ ObjectTreeItem *item = container->form()->objectTree()->lookup(wname);
+ if (!item) {
+ // not yet created
+ item = new ObjectTreeItem(container->form()->library()->displayName(classname),
+ wname, w, container);
+ if(parent) {
+ ObjectTreeItem *titem = container->form()->objectTree()->lookup(parent->name());
+ if(titem)
+ container->form()->objectTree()->addItem(titem, item);
+ else
+ kdDebug() << "FORMIO :: ERROR no parent widget " << endl;
+ }
+ else
+ container->form()->objectTree()->addItem(container->objectTree(), item);
+ }
+ //assign item for its widget if it supports DesignTimeDynamicChildWidgetHandler interface
+ //(e.g. KexiDBAutoField)
+ if (container->form()->designMode() && dynamic_cast<DesignTimeDynamicChildWidgetHandler*>(w)) {
+ dynamic_cast<DesignTimeDynamicChildWidgetHandler*>(w)->assignItem(item);
+ }
+
+ m_currentItem = item;
+ // if we are inside a Grid, we need to insert the widget in the good cell
+ if(container->layoutType() == Container::Grid) {
+ QGridLayout *layout = (QGridLayout*)container->layout();
+ if(el.hasAttribute("rowspan")) { // widget spans multiple cells
+ if(layout)
+ layout->addMultiCellWidget(w, el.attribute("row").toInt(), el.attribute("row").toInt() + el.attribute("rowspan").toInt()-1,
+ el.attribute("column").toInt(), el.attribute("column").toInt() + el.attribute("colspan").toInt()-1);
+ item->setGridPos(el.attribute("row").toInt(), el.attribute("column").toInt(), el.attribute("rowspan").toInt(),
+ el.attribute("colspan").toInt());
+ }
+ else {
+ if(layout)
+ layout->addWidget(w, el.attribute("row").toInt(), el.attribute("column").toInt());
+ item->setGridPos(el.attribute("row").toInt(), el.attribute("column").toInt(), 0, 0);
+ }
+ }
+ else if(container->layout())
+ container->layout()->add(w);
+
+ readChildNodes(item, container, el, w);
+
+ if(item->container() && item->container()->layout())
+ item->container()->layout()->activate();
+
+ // We add the autoSaveProperties in the modifProp list of the ObjectTreeItem, so that they are saved later
+ QValueList<QCString> list(container->form()->library()->autoSaveProperties(w->className()));
+ QValueList<QCString>::ConstIterator endIt = list.constEnd();
+ KFormDesigner::WidgetWithSubpropertiesInterface* subpropIface
+ = dynamic_cast<KFormDesigner::WidgetWithSubpropertiesInterface*>(w);
+ QWidget *subwidget = (subpropIface && subpropIface->subwidget()) ? subpropIface->subwidget() : w;
+ for(QValueList<QCString>::ConstIterator it = list.constBegin(); it != endIt; ++it) {
+ if(subwidget->metaObject()->findProperty(*it, true) != -1)
+ item->addModifiedProperty(*it, subwidget->property(*it));
+ }
+
+ if(resetCurrentForm)
+ m_currentForm = 0;
+ m_currentItem = 0;
+}
+
+void
+FormIO::createToplevelWidget(Form *form, QWidget *container, QDomElement &el)
+{
+ // We first look for the widget's name
+ QString wname;
+ for(QDomNode n = el.firstChild(); !n.isNull(); n = n.nextSibling())
+ {
+ if((n.toElement().tagName() == "property") && (n.toElement().attribute("name") == "name"))
+ {
+ wname = n.toElement().text();
+ break;
+ }
+
+ }
+ // And rename the widget and its ObjectTreeItem
+ container->setName(wname.latin1());
+ if(form->objectTree())
+ form->objectTree()->rename(form->objectTree()->name(), wname);
+ form->setInteractiveMode(false);
+
+ QDict<QLabel> *oldBuddies = 0;
+ if(m_buddies) // save old buddies (for subforms)
+ oldBuddies = m_buddies;
+ m_buddies = new QDict<QLabel>();
+ m_currentItem = form->objectTree();
+
+ readChildNodes(form->objectTree(), form->toplevelContainer(), el, container);
+
+ // Now the Form is fully loaded, we can assign the buddies
+ QDictIterator<QLabel> it(*m_buddies);
+ for(; it.current(); ++it)
+ {
+ ObjectTreeItem *item = form->objectTree()->lookup(it.currentKey());
+ if(!item || !item->widget())
+ {
+ kdDebug() << "Cannot assign buddy for widget " << it.current()->name() << " to " << it.currentKey() << endl;
+ continue;
+ }
+ it.current()->setBuddy(item->widget());
+ }
+ delete m_buddies;
+ m_buddies = oldBuddies; // and restore it
+
+ m_currentItem = 0;
+
+ form->setInteractiveMode(true);
+}
+
+void
+FormIO::readChildNodes(ObjectTreeItem *item, Container *container, const QDomElement &el, QWidget *w)
+{
+ QString eltag = el.tagName();
+
+ WidgetWithSubpropertiesInterface* subpropIface = dynamic_cast<WidgetWithSubpropertiesInterface*>(w);
+ QWidget *subwidget = (subpropIface && subpropIface->subwidget()) ? subpropIface->subwidget() : w;
+
+ for(QDomNode n = el.firstChild(); !n.isNull(); n = n.nextSibling())
+ {
+ QString tag = n.toElement().tagName();
+ QDomElement node = n.toElement();
+
+ if((tag == "property") || (tag == "attribute"))
+ {
+ QString name = node.attribute("name");
+ //if(name == "geometry")
+ // hasGeometryProp = true;
+ if( ((eltag == "grid") || (eltag == "hbox") || (eltag == "vbox")) &&
+ (name == "name")) // we don't care about layout names
+ continue;
+
+ if (node.attribute("subwidget")=="true") {
+ //this is property for subwidget: remember it for delayed setting
+ //because now the subwidget could be not created yet (true e.g. for KexiDBAutoField)
+ const QVariant val( readPropertyValue(node.firstChild(), w, name) );
+ kdDebug() << val.toStringList() << endl;
+ item->addSubproperty( name.latin1(), val );
+ //subwidget->setProperty(name.latin1(), val);
+ item->addModifiedProperty( name.latin1(), val );
+ continue;
+ }
+
+ // We cannot assign the buddy now as the buddy widget may not be created yet
+ if(name == "buddy")
+ m_buddies->insert(readPropertyValue(node.firstChild(), w, name).toString(), (QLabel*)w);
+ else if(((eltag == "grid") || (eltag == "hbox") || (eltag == "vbox")) &&
+ item->container() && item->container()->layout()) {
+ // We load the margin of a Layout
+ if(name == "margin") {
+ int margin = readPropertyValue(node.firstChild(), w, name).toInt();
+ item->container()->setLayoutMargin(margin);
+ item->container()->layout()->setMargin(margin);
+ }
+ // We load the spacing of a Layout
+ else if(name == "spacing") {
+ int spacing = readPropertyValue(node.firstChild(), w, name).toInt();
+ item->container()->setLayoutSpacing(spacing);
+ item->container()->layout()->setSpacing(spacing);
+ }
+ else if((name == "justify")){
+ bool justify = readPropertyValue(node.firstChild(), w, name).toBool();
+ KexiFlowLayout *flow = static_cast<KexiFlowLayout*>(item->container()->layout());
+ if(flow)
+ flow->setJustified(justify);
+ }
+ }
+ // If the object doesn't have this property, we let the Factory handle it (maybe a special property)
+ else if(subwidget->metaObject()->findProperty(name.latin1(), true) == -1)
+ {
+ if(w->className() == QString::fromLatin1("CustomWidget"))
+ item->storeUnknownProperty(node);
+ else {
+ bool read = container->form()->library()->readSpecialProperty(
+ w->className(), node, w, item);
+ if(!read) // the factory doesn't support this property neither
+ item->storeUnknownProperty(node);
+ }
+ }
+ else // we have a normal property, let's load it
+ {
+ QVariant val( readPropertyValue(node.firstChild(), w, name) );
+ if(name == "geometry" && dynamic_cast<FormWidget*>(w)) {
+ //fix geometry if needed - this is top level form widget
+ QRect r( val.toRect() );
+ if (r.left()<0) //negative X!
+ r.moveLeft(0);
+ if (r.top()<0) //negative Y!
+ r.moveTop(0);
+ val = r;
+ }
+ subwidget->setProperty(name.latin1(), val);
+// int count = w->metaObject()->findProperty(name, true);
+// const QMetaProperty *meta = w->metaObject()->property(count, true);
+// if(meta && meta->isEnumType()) {
+// val = w->property(name.latin1()); //update: we want a numeric value of enum
+// }
+ item->addModifiedProperty(name.latin1(), val);
+ }
+ }
+ else if(tag == "widget") // a child widget
+ {
+ if(item->container()) // we are a Container
+ loadWidget(item->container(), node);
+ else
+ loadWidget(container, node, w);
+ }
+ else if(tag == "spacer") {
+ loadWidget(container, node, w);
+ }
+ else if(tag == "grid") {
+ // first, see if it is flow layout
+ QString layoutName;
+ for(QDomNode child = node.firstChild(); !child.isNull(); child = child.nextSibling()) {
+ if((child.toElement().tagName() == "property") && (child.toElement().attribute("name") == "customLayout")) {
+ layoutName = child.toElement().text();
+ break;
+ }
+ }
+
+ if(layoutName == "HFlow") {
+ item->container()->m_layType = Container::HFlow;
+ KexiFlowLayout *layout = new KexiFlowLayout(item->widget());
+ layout->setOrientation(Horizontal);
+ item->container()->m_layout = (QLayout*)layout;
+ }
+ else if(layoutName == "VFlow") {
+ item->container()->m_layType = Container::VFlow;
+ KexiFlowLayout *layout = new KexiFlowLayout(item->widget());
+ layout->setOrientation(Vertical);
+ item->container()->m_layout = (QLayout*)layout;
+ }
+ else { // grid layout
+ item->container()->m_layType = Container::Grid;
+ QGridLayout *layout = new QGridLayout(item->widget(), 1, 1);
+ item->container()->m_layout = (QLayout*)layout;
+ }
+ readChildNodes(item, container, node, w);
+ }
+ else if(tag == "vbox") {
+ item->container()->m_layType = Container::VBox;
+ QVBoxLayout *layout = new QVBoxLayout(item->widget());
+ item->container()->m_layout = (QLayout*)layout;
+ readChildNodes(item, container, node, w);
+ }
+ else if(tag == "hbox") {
+ item->container()->m_layType = Container::HBox;
+ QHBoxLayout *layout = new QHBoxLayout(item->widget());
+ item->container()->m_layout = (QLayout*)layout;
+ readChildNodes(item, container, node, w);
+ }
+ else {// unknown tag, we let the Factory handle it
+ if(w->className() == QString::fromLatin1("CustomWidget"))
+ item->storeUnknownProperty(node);
+ else {
+ bool read = container->form()->library()->readSpecialProperty(
+ w->className(), node, w, item);
+ if(!read) // the factory doesn't suport this property neither
+ item->storeUnknownProperty(node);
+ }
+ }
+ }
+}
+
+/////////////////////////////////////////////////////////////////////////////
+///////////// Helper functions //////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////////
+
+void
+FormIO::addIncludeFileName(const QString &include, QDomDocument &domDoc)
+{
+ if(include.isEmpty())
+ return;
+
+ QDomElement includes;
+ QDomElement uiEl = domDoc.namedItem("UI").toElement();
+ if(uiEl.namedItem("includehints").isNull())
+ {
+ includes = domDoc.createElement("includehints");
+ uiEl.appendChild(includes);
+ }
+ else
+ includes = uiEl.namedItem("includehints").toElement();
+
+ // Check if this include has already been saved, and return if it is the case
+ for(QDomNode n = includes.firstChild(); !n.isNull(); n = n.nextSibling())
+ {
+ if(n.toElement().text() == include)
+ return;
+ }
+
+ QDomElement includeHint = domDoc.createElement("includehint");
+ includes.appendChild(includeHint);
+ QDomText includeText = domDoc.createTextNode(include);
+ includeHint.appendChild(includeText);
+}
+
+//////// Qt Designer code: these two functions were copied (and adapted) from Qt Designer for compatibility ////////
+
+QString
+FormIO::saveImage(QDomDocument &domDoc, const QPixmap &pixmap)
+{
+ QDomNode node = domDoc.namedItem("images");
+ QDomElement images;
+ if(node.isNull())
+ {
+ images = domDoc.createElement("images");
+ QDomElement ui = domDoc.namedItem("UI").toElement();
+ ui.appendChild(images);
+ }
+ else
+ images = node.toElement();
+
+ int count = images.childNodes().count();
+ QDomElement image = domDoc.createElement("image");
+ QString name = "image" + QString::number(count);
+ image.setAttribute("name", name);
+
+ QImage img = pixmap.convertToImage();
+ QByteArray ba;
+ QBuffer buf(ba);
+ buf.open( IO_WriteOnly | IO_Translate );
+ QString format = img.depth() > 1 ? "XPM" : "XBM";
+ QImageIO iio( &buf, format.latin1() );
+ iio.setImage( img );
+ iio.write();
+ buf.close();
+ QByteArray bazip = qCompress( ba );
+ ulong len = bazip.size();
+
+ QDomElement data = domDoc.createElement("data");
+ data.setAttribute("format", format + ".GZ");
+ data.setAttribute("length", ba.size());
+
+ static const char hexchars[] = "0123456789abcdef";
+ QString content;
+ for(int i = 4; i < (int)len; ++i)
+ {
+ uchar s = (uchar) bazip[i];
+ content += hexchars[s >> 4];
+ content += hexchars[s & 0x0f];
+ }
+
+ QDomText text = domDoc.createTextNode(content);
+ data.appendChild(text);
+ image.appendChild(data);
+ images.appendChild(image);
+
+ return name;
+}
+
+QPixmap
+FormIO::loadImage(QDomDocument domDoc, const QString& name)
+{
+ QDomElement images = domDoc.namedItem("UI").namedItem("images").toElement();
+ if(images.isNull())
+ return 0;
+
+ QDomElement image;
+ for(QDomNode n = images.firstChild(); !n.isNull(); n = n.nextSibling())
+ {
+ if((n.toElement().tagName() == "image") && (n.toElement().attribute("name") == name))
+ {
+ image = n.toElement();
+ break;
+ }
+ }
+
+ QPixmap pix;
+ QString data = image.namedItem("data").toElement().text();
+ const int lengthOffset = 4;
+ int baSize = data.length() / 2 + lengthOffset;
+ uchar *ba = new uchar[baSize];
+ for(int i = lengthOffset; i < baSize; ++i)
+ {
+ char h = data[2 * (i-lengthOffset)].latin1();
+ char l = data[2 * (i-lengthOffset) + 1].latin1();
+ uchar r = 0;
+ if(h <= '9')
+ r += h - '0';
+ else
+ r += h - 'a' + 10;
+ r = r << 4;
+ if(l <= '9')
+ r += l - '0';
+ else
+ r += l - 'a' + 10;
+ ba[i] = r;
+ }
+
+ QString format = image.namedItem("data").toElement().attribute("format", "PNG");
+ if((format == "XPM.GZ") || (format == "XBM.GZ"))
+ {
+ ulong len = image.attribute("length").toULong();
+ if(len < data.length() * 5)
+ len = data.length() * 5;
+ // qUncompress() expects the first 4 bytes to be the expected length of
+ // the uncompressed data
+ ba[0] = ( len & 0xff000000 ) >> 24;
+ ba[1] = ( len & 0x00ff0000 ) >> 16;
+ ba[2] = ( len & 0x0000ff00 ) >> 8;
+ ba[3] = ( len & 0x000000ff );
+ QByteArray baunzip = qUncompress(ba, baSize);
+ pix.loadFromData( (const uchar*)baunzip.data(), baunzip.size(), format.left(format.find('.')).latin1() );
+ }
+ else
+ pix.loadFromData( (const uchar*)ba+lengthOffset, baSize-lengthOffset, format.latin1() );
+
+ delete[] ba;
+
+ return pix;
+}
+
+//////// End of Qt Designer code ////////////////////////////////////////////////////////
+
+#include "formIO.moc"
diff --git a/kexi/formeditor/formIO.h b/kexi/formeditor/formIO.h
new file mode 100644
index 00000000..b7337182
--- /dev/null
+++ b/kexi/formeditor/formIO.h
@@ -0,0 +1,222 @@
+/* This file is part of the KDE project
+ Copyright (C) 2004 Cedric Pasteur <cedric.pasteur@free.fr>
+ Copyright (C) 2005-2007 Jaroslaw Staniek <js@iidea.pl>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+*/
+
+#ifndef FORMIO_H
+#define FORMIO_H
+
+#include <qobject.h>
+#include <qdict.h>
+#include <qstring.h>
+#include <qwidget.h>
+#include <qmap.h>
+
+class QString;
+class QDomElement;
+class QDomNode;
+class QDomDocument;
+class QDomText;
+class QVariant;
+class QLabel;
+
+//! A blank widget displayed when class is not supported
+class KFORMEDITOR_EXPORT CustomWidget : public QWidget
+{
+ Q_OBJECT
+
+ public:
+ CustomWidget(const QCString &className, QWidget *parent, const char *name);
+ virtual ~CustomWidget();
+
+ virtual void paintEvent(QPaintEvent *ev);
+
+ private:
+ QCString m_className;
+};
+
+namespace KFormDesigner {
+
+class WidgetPropertySet;
+class Form;
+class ObjectTreeItem;
+class Container;
+class WidgetLibrary;
+
+//! KFormDesigner API version number. Increased on every breaking of backward compatibility.
+//! Use KFormDesigner::version() to get real version number of the library.
+#define KFORMDESIGNER_VERSION 2
+
+//! \return KFormDesigner API version number for this library. This information is stored
+KFORMEDITOR_EXPORT uint version();
+
+/** This class act as a namespace for all .ui files related functions, ie saving/loading .ui files.
+ You don't need to create a FormIO object, as all methods are static.\n
+ This class is able to read and write Forms to .ui files, and to save each type of properties, including set and enum
+ properties, and pixmaps(pixmap-related code was taken from Qt Designer).
+ **/
+ //! A class to save/load forms from .ui files
+class KFORMEDITOR_EXPORT FormIO : public QObject
+{
+ Q_OBJECT
+
+ public:
+ FormIO();
+ ~FormIO();
+
+ /*! Save the Form in the \a domDoc QDomDocument. Called by saveForm().
+ \return true if saving succeeded.
+ \sa saveForm() */
+ static bool saveFormToDom(Form *form, QDomDocument &domDoc);
+
+ /*! Save the Form \a form to the file \a filename. If \a filename is null or not given,
+ a Save File dialog will be shown to choose dest file.
+ \return true if saving succeeded.
+ \todo Add errors code and error dialog
+ */
+ static bool saveFormToFile(Form *form, const QString &filename=QString::null);
+
+ /*! Saves the Form to the \a dest string. \a indent can be specified to apply indentation.
+ \return true if saving succeeded.
+ \sa saveForm()
+ */
+ static bool saveFormToString(Form *form, QString &dest, int indent = 0);
+
+ /*! Saves the \a form inside the \a dest QByteArray.
+ \return true if saving succeeded.
+ \sa saveFormToDom(), saveForm()
+ */
+ static bool saveFormToByteArray(Form *form, QByteArray &dest);
+
+ /*! Loads a form from the \a domDoc QDomDocument. Called by loadForm() and loadFormData().
+ \return true if loading succeeded. */
+ static bool loadFormFromDom(Form *form, QWidget *container, QDomDocument &domDoc);
+
+ /*! Loads a form from the \a src QByteArray.
+ \sa loadFormFromDom(), loadForm().
+ \return true if loading succeeded.
+ */
+ static bool loadFormFromByteArray(Form *form, QWidget *container, QByteArray &src,
+ bool preview=false);
+
+ static bool loadFormFromString(Form *form, QWidget *container, QString &src, bool preview=false);
+
+ /*! Loads the .ui file \a filename in the Form \a form. If \a filename is null or not given,
+ a Open File dialog will be shown to select the file to open.
+ createToplevelWidget() is used to load the Form's toplevel widget.
+ \return true if loading succeeded.
+ \todo Add errors code and error dialog
+ */
+ static bool loadFormFromFile(Form *form, QWidget *container, const QString &filename=QString::null);
+
+ /*! Saves the widget associated to the ObjectTreeItem \a item into DOM document \a domDoc,
+ with \a parent as parent node.
+ It calls readPropertyValue() for each object property, readAttribute() for each attribute and
+ itself to save child widgets.\n
+ \return true if saving succeeded.
+ This is used to copy/paste widgets.
+ */
+ static void saveWidget(ObjectTreeItem *item, QDomElement &parent, QDomDocument &domDoc,
+ bool insideGridLayout=false);
+
+ /*! Cleans the "UI" QDomElement after saving widget. It deletes the "includes" element
+ not needed when pasting, and make sure all the "widget" elements are at the beginning.
+ Call this after copying a widget, before pasting.*/
+ static void cleanClipboard(QDomElement &uiElement);
+
+ /*! Loads the widget associated to the QDomElement \a el into the Container \a container,
+ with \a parent as parent widget.
+ If parent = 0, the Container::widget() is used as parent widget.
+ This is used to copy/paste widgets.
+ */
+ static void loadWidget(Container *container,
+ const QDomElement &el, QWidget *parent=0);
+
+ /*! Save an element in the \a domDoc as child of \a parentNode.
+ The element will be saved like this :
+ \code <$(tagName) name = "$(property)">< value_as_XML ><$(tagName)/>
+ \endcode
+ */
+ static void savePropertyElement(QDomElement &parentNode, QDomDocument &domDoc, const QString &tagName,
+ const QString &property, const QVariant &value);
+
+ /*! Read an object property in the DOM doc.
+ \param node the QDomNode of the property
+ \param obj the widget whose property is being read
+ \param name the name of the property being read
+ */
+ static QVariant readPropertyValue(QDomNode node, QObject *obj, const QString &name);
+
+ /*! Write an object property in the DOM doc.
+ \param parentNode the DOM document to write to
+ \param name the name of the property being saved
+ \param value the value of this property
+ \param w the widget whose property is being saved
+ \param lib the widget library for which the property is being saved
+
+ Properties of subwidget are saved with subwidget="true" arribute added
+ to 'property' XML element.
+ */
+ static void savePropertyValue(QDomElement &parentNode, QDomDocument &parent, const char *name,
+ const QVariant &value, QWidget *w, WidgetLibrary *lib=0);
+
+ protected:
+ /*! Saves the QVariant \a value as text to be included in an xml file, with \a parentNode.*/
+ static void writeVariant(QDomDocument &parent, QDomElement &parentNode, QVariant value);
+
+ /*! Creates a toplevel widget from the QDomElement \a element in the Form \a form,
+ with \a parent as parent widget.
+ It calls readPropertyValue() and loadWidget() to load child widgets.
+ */
+ static void createToplevelWidget(Form *form, QWidget *container, QDomElement &element);
+
+ /*! \return the name of the pixmap saved, to use to access it
+ This function save the QPixmap \a pixmap into the DOM document \a domDoc.
+ The pixmap is converted to XPM and compressed for compatibility with Qt Designer.
+ Encoding code is taken from Designer.
+ */
+ static QString saveImage(QDomDocument &domDoc, const QPixmap &pixmap);
+
+ /*! \return the loaded pixmap
+ This function loads the pixmap named \a name in the DOM document \a domDoc.
+ Decoding code is taken from QT Designer.
+ */
+ static QPixmap loadImage(QDomDocument domDoc, const QString& name);
+
+ /*! Reads the child nodes of a "widget" element. */
+ static void readChildNodes(ObjectTreeItem *tree, Container *container,
+ const QDomElement &el, QWidget *w);
+
+ /*! Adds an include file name to be saved in the "includehints" part of .ui file,
+ which is needed by uic. */
+ static void addIncludeFileName(const QString &include, QDomDocument &domDoc);
+
+ private:
+ // This dict stores buddies associations until the Form is completely loaded.
+ static QDict<QLabel> *m_buddies;
+
+ /// Instead of having to pass these for every functions, we just store them in the class
+ //static QWidgdet *m_currentWidget;
+ static ObjectTreeItem *m_currentItem;
+ static Form *m_currentForm;
+ static bool m_savePixmapsInline;
+};
+
+}
+
+#endif
diff --git a/kexi/formeditor/formmanager.cpp b/kexi/formeditor/formmanager.cpp
new file mode 100644
index 00000000..20b40cf9
--- /dev/null
+++ b/kexi/formeditor/formmanager.cpp
@@ -0,0 +1,1716 @@
+/* This file is part of the KDE project
+ Copyright (C) 2004 Cedric Pasteur <cedric.pasteur@free.fr>
+ Copyright (C) 2005 Jaroslaw Staniek <js@iidea.pl>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+*/
+
+#include <kdebug.h>
+
+#include <qworkspace.h>
+#include <qcursor.h>
+#include <qstring.h>
+#include <qlabel.h>
+#include <qobjectlist.h>
+#include <qstylefactory.h>
+#include <qmetaobject.h>
+#include <qregexp.h>
+#include <qvaluevector.h>
+#include <qvbox.h>
+
+#include <klocale.h>
+#include <kiconloader.h>
+#include <kpopupmenu.h>
+#include <kstdaction.h>
+#include <kaction.h>
+#include <kxmlguiclient.h>
+#include <kmainwindow.h>
+#include <kmessagebox.h>
+#include <kconfig.h>
+#include <kstyle.h>
+#include <kactionclasses.h>
+#include <kapplication.h>
+#include <kglobal.h>
+#include <kglobalsettings.h>
+#include <kdialogbase.h>
+#include <ktextedit.h>
+#include <ktabwidget.h>
+#include <kfontdialog.h>
+
+#include <kdeversion.h>
+#if KDE_VERSION >= KDE_MAKE_VERSION(3,1,9) && !defined(Q_WS_WIN)
+# include <kactioncollection.h>
+#endif
+
+#include "widgetpropertyset.h"
+#include "objecttree.h"
+#include "widgetlibrary.h"
+#include "form.h"
+#include "container.h"
+#include "formIO.h"
+#include "objecttreeview.h"
+#include "commands.h"
+#include "tabstopdialog.h"
+#include "connectiondialog.h"
+#include "pixmapcollection.h"
+#include "events.h"
+#include "utils.h"
+#include "kfdpixmapedit.h"
+#include <koproperty/editor.h>
+#include <koproperty/property.h>
+#include <koproperty/factory.h>
+
+#include "formmanager.h"
+
+#define KFD_NO_STYLES //disables; styles support needs improvements
+
+namespace KFormDesigner {
+
+//! @internal
+class PropertyFactory : public KoProperty::CustomPropertyFactory
+{
+ public:
+ PropertyFactory(QObject *parent)
+ : KoProperty::CustomPropertyFactory(parent)
+// m_manager(manager)
+ {
+ }
+ virtual ~PropertyFactory() {}
+
+ KoProperty::CustomProperty* createCustomProperty(KoProperty::Property *) { return 0;}
+
+ KoProperty::Widget* createCustomWidget(KoProperty::Property *prop)
+ {
+ return new KFDPixmapEdit(prop);
+ }
+};
+
+}
+
+using namespace KFormDesigner;
+
+static KStaticDeleter<FormManager> m_managerDeleter;
+FormManager* FormManager::_self = 0L;
+
+FormManager::FormManager(QObject *parent, int options, const char *name)
+ : QObject(parent, name)
+#ifdef KEXI_DEBUG_GUI
+ , m_uiCodeDialog(0)
+ , m_options(options)
+#endif
+ , m_objectBlockingPropertyEditorUpdating(0)
+ , m_isRedoing(false)
+{
+ Q_UNUSED(options);
+#ifdef KEXI_STANDALONE
+ KGlobal::locale()->insertCatalogue("standalone_kformdesigner");
+#else
+ KGlobal::locale()->insertCatalogue("kformdesigner");
+#endif
+
+ connect( kapp, SIGNAL( settingsChanged(int) ), SLOT( slotSettingsChanged(int) ) );
+ slotSettingsChanged(KApplication::SETTINGS_SHORTCUTS);
+
+//moved to createWidgetLibrary() m_lib = new WidgetLibrary(this, supportedFactoryGroups);
+ m_propSet = new WidgetPropertySet(this);
+
+ //unused m_editor = 0;
+ m_active = 0;
+ m_inserting = false;
+ m_drawingSlot = false;
+ m_collection = 0;
+ m_connection = 0;
+ m_popup = 0;
+ m_treeview = 0;
+ m_emitSelectionSignalsUpdatesPropertySet = false;
+ m_domDoc.appendChild(m_domDoc.createElement("UI"));
+
+ m_deleteWidgetLater_list.setAutoDelete(true);
+ connect( &m_deleteWidgetLater_timer, SIGNAL(timeout()), this, SLOT(deleteWidgetLaterTimeout()));
+ connect( this, SIGNAL(connectionCreated(KFormDesigner::Form*, KFormDesigner::Connection&)),
+ this, SLOT(slotConnectionCreated(KFormDesigner::Form*, KFormDesigner::Connection&)));
+
+ // register kfd custom editors
+ KoProperty::FactoryManager::self()->registerFactoryForEditor(KoProperty::Pixmap,
+ new PropertyFactory(KoProperty::FactoryManager::self()));
+}
+
+FormManager::~FormManager()
+{
+ m_managerDeleter.setObject(_self, 0, false); //safe
+ delete m_popup;
+ delete m_connection;
+#ifdef KEXI_DEBUG_GUI
+ delete m_uiCodeDialog;
+#endif
+// delete m_propFactory;
+}
+
+
+FormManager* FormManager::self()
+{
+ return _self;
+}
+
+WidgetLibrary*
+FormManager::createWidgetLibrary(FormManager* m, const QStringList& supportedFactoryGroups)
+{
+ if(!_self)
+ m_managerDeleter.setObject( _self, m );
+ return new WidgetLibrary(_self, supportedFactoryGroups);
+}
+
+void
+FormManager::setEditor(KoProperty::Editor *editor)
+{
+ m_editor = editor;
+
+ if(editor)
+ editor->changeSet(m_propSet->set());
+}
+
+void
+FormManager::setObjectTreeView(ObjectTreeView *treeview)
+{
+ m_treeview = treeview;
+ if (m_treeview)
+ connect(m_propSet, SIGNAL(widgetNameChanged(const QCString&, const QCString&)),
+ m_treeview, SLOT(renameItem(const QCString&, const QCString&)));
+}
+
+ActionList
+FormManager::createActions(WidgetLibrary *lib, KActionCollection* collection, KXMLGUIClient* client)
+{
+ m_collection = collection;
+
+ ActionList actions = lib->createWidgetActions(client, m_collection, this, SLOT(insertWidget(const QCString &)));
+
+ if (m_options & HideSignalSlotConnections)
+ m_dragConnection = 0;
+ else {
+ m_dragConnection = new KToggleAction(i18n("Connect Signals/Slots"),
+ "signalslot", KShortcut(0), this, SLOT(startCreatingConnection()), m_collection,
+ "drag_connection");
+ //to be exclusive with any 'widget' action
+ m_dragConnection->setExclusiveGroup("LibActionWidgets");
+ m_dragConnection->setChecked(false);
+ actions.append(m_dragConnection);
+ }
+
+ m_pointer = new KToggleAction(i18n("Pointer"), "mouse_pointer", KShortcut(0),
+ this, SLOT(slotPointerClicked()), m_collection, "pointer");
+ m_pointer->setExclusiveGroup("LibActionWidgets"); //to be exclusive with any 'widget' action
+ m_pointer->setChecked(true);
+ actions.append(m_pointer);
+
+ m_snapToGrid = new KToggleAction(i18n("Snap to Grid"), QString::null, KShortcut(0),
+ 0, 0, m_collection, "snap_to_grid");
+ m_snapToGrid->setChecked(true);
+ actions.append(m_snapToGrid);
+
+ // Create the Style selection action (with a combo box in toolbar and submenu items)
+ KSelectAction *m_style = new KSelectAction( i18n("Style"), KShortcut(0),
+ this, SLOT(slotStyle()), m_collection, "change_style");
+ m_style->setEditable(false);
+
+ KGlobal::config()->setGroup("General");
+ QString currentStyle = QString::fromLatin1(kapp->style().name()).lower();
+ const QStringList styles = QStyleFactory::keys();
+ m_style->setItems(styles);
+ m_style->setCurrentItem(0);
+
+ QStringList::ConstIterator endIt = styles.constEnd();
+ int idx = 0;
+ for (QStringList::ConstIterator it = styles.constBegin(); it != endIt; ++it, ++idx)
+ {
+ if ((*it).lower() == currentStyle) {
+ m_style->setCurrentItem(idx);
+ break;
+ }
+ }
+
+ m_style->setToolTip(i18n("Set the current view style."));
+ m_style->setMenuAccelsEnabled(true);
+ actions.append(m_style);
+
+ lib->addCustomWidgetActions(m_collection);
+
+ return actions;
+}
+
+bool
+FormManager::isPasteEnabled()
+{
+ return m_domDoc.namedItem("UI").hasChildNodes();
+}
+
+void
+FormManager::undo()
+{
+ if(!activeForm() || !activeForm()->objectTree())
+ return;
+
+ activeForm()->commandHistory()->undo();
+}
+
+void
+FormManager::redo()
+{
+ if(!activeForm() || !activeForm()->objectTree())
+ return;
+
+ m_isRedoing = true;
+ activeForm()->commandHistory()->redo();
+ m_isRedoing = false;
+}
+
+void
+FormManager::insertWidget(const QCString &classname)
+{
+ if(m_drawingSlot)
+ stopCreatingConnection();
+
+ m_inserting = true;
+
+ Form *form;
+ for(form = m_forms.first(); form; form = m_forms.next())
+ {
+// form->d->cursors = new QMap<QString, QCursor>();
+ if (form->toplevelContainer())
+ form->widget()->setCursor(QCursor(CrossCursor));
+ QObjectList *l = form->widget()->queryList( "QWidget" );
+ for(QObject *o = l->first(); o; o = l->next())
+ {
+ if( ((QWidget*)o)->ownCursor() )
+ {
+// form->d->cursors->insert(o->name(), ((QWidget*)o)->cursor());
+ form->d->cursors.insert(o, static_cast<QWidget*>(o)->cursor());
+ static_cast<QWidget*>(o)->setCursor(QCursor(Qt::CrossCursor));
+ }
+
+ }
+ delete l;
+ }
+
+ m_selectedClass = classname;
+ m_pointer->setChecked(false);
+}
+
+void
+FormManager::stopInsert()
+{
+ if(m_drawingSlot)
+ stopCreatingConnection();
+ if(!m_inserting)
+ return;
+
+//#ifndef KEXI_NO_CURSOR_PROPERTY
+ Form *form;
+ for(form = m_forms.first(); form; form = m_forms.next())
+ {
+ form->widget()->unsetCursor();
+ QObjectList *l = form->widget()->queryList( "QWidget" );
+ for(QObject *o = l->first(); o; o = l->next())
+ {
+ static_cast<QWidget*>(o)->unsetCursor();
+#if 0
+ if( ((QWidget*)o)->ownCursor()) {
+ QMap<QObject*,QCursor>::ConstIterator curIt( form->d->cursors.find(o) );
+ if (curIt!=form->d->cursors.constEnd())
+ static_cast<QWidget*>(o)->setCursor( *curIt );
+// ((QWidget*)o)->setCursor( (*(form->d->cursors))[o->name()] ) ;
+ }
+#endif
+ }
+ delete l;
+// delete (form->d->cursors);
+// form->d->cursors = 0;
+ }
+//#endif
+ m_inserting = false;
+ m_pointer->setChecked(true);
+}
+
+void
+FormManager::slotPointerClicked()
+{
+ if(m_inserting)
+ stopInsert();
+ else if(m_dragConnection)
+ stopCreatingConnection();
+}
+
+void
+FormManager::startCreatingConnection()
+{
+ if (m_options & HideSignalSlotConnections)
+ return;
+
+ if(m_inserting)
+ stopInsert();
+
+ // We set a Pointing hand cursor while drawing the connection
+ Form *form;
+ for(form = m_forms.first(); form; form = m_forms.next())
+ {
+// form->d->cursors = new QMap<QString, QCursor>();
+ form->d->mouseTrackers = new QStringList();
+ if (form->toplevelContainer())
+ {
+ form->widget()->setCursor(QCursor(PointingHandCursor));
+ form->widget()->setMouseTracking(true);
+ }
+ QObjectList *l = form->widget()->queryList( "QWidget" );
+ for(QObject *o = l->first(); o; o = l->next())
+ {
+ QWidget *w = static_cast<QWidget*>(o);
+ if( w->ownCursor() )
+ {
+ form->d->cursors.insert(w, w->cursor());
+// form->d->cursors->insert(w->name(), w->cursor());
+ w->setCursor(QCursor(PointingHandCursor ));
+ }
+ if(w->hasMouseTracking())
+ form->d->mouseTrackers->append(w->name());
+ w->setMouseTracking(true);
+ }
+ delete l;
+ }
+ delete m_connection;
+ m_connection = new Connection();
+ m_drawingSlot = true;
+ if (m_dragConnection)
+ m_dragConnection->setChecked(true);
+}
+
+void
+FormManager::resetCreatedConnection()
+{
+ if (m_options & HideSignalSlotConnections)
+ return;
+
+ delete m_connection;
+ m_connection = new Connection();
+
+ if(m_active && m_active->formWidget()) {
+ Form *ff = (Form*)m_active;
+ FormWidget *fw = 0;
+ if (ff)
+ fw = ff->formWidget();
+ m_active->formWidget()->clearForm();
+ }
+ if (m_active && m_active->widget())
+ m_active->widget()->repaint();
+}
+
+void
+FormManager::stopCreatingConnection()
+{
+ if (m_options & HideSignalSlotConnections)
+ return;
+ if(!m_drawingSlot)
+ return;
+
+ if(m_active && m_active->formWidget())
+ m_active->formWidget()->clearForm();
+
+ Form *form;
+ for(form = m_forms.first(); form; form = m_forms.next())
+ {
+ form->widget()->unsetCursor();
+ form->widget()->setMouseTracking(false);
+ QObjectList *l = form->widget()->queryList( "QWidget" );
+ for(QObject *o = l->first(); o; o = l->next())
+ {
+ QWidget *w = (QWidget*)o;
+ if( w->ownCursor()) {
+ QMap<QObject*,QCursor>::ConstIterator curIt( form->d->cursors.find(o) );
+ if (curIt!=form->d->cursors.constEnd())
+ static_cast<QWidget*>(o)->setCursor( *curIt );
+ }
+// w->setCursor( (*(form->d->cursors))[o->name()] ) ;
+ w->setMouseTracking( !form->d->mouseTrackers->grep(w->name()).isEmpty() );
+ }
+ delete l;
+// delete (form->d->cursors);
+// form->d->cursors = 0;
+ delete (form->d->mouseTrackers);
+ form->d->mouseTrackers = 0;
+ }
+
+ if(m_connection->slot().isNull())
+ emit connectionAborted(activeForm());
+ delete m_connection;
+ m_connection = 0;
+ m_drawingSlot = false;
+ m_pointer->setChecked(true);
+}
+
+bool
+FormManager::snapWidgetsToGrid()
+{
+ return m_snapToGrid->isChecked();
+}
+
+void
+FormManager::windowChanged(QWidget *w)
+{
+ kdDebug() << "FormManager::windowChanged("
+ << (w ? (QString(w->className())+" "+w->name()) : QString("0")) << ")" << endl;
+
+ if(!w)
+ {
+ m_active = 0;
+ if(m_treeview)
+ m_treeview->setForm(0);
+ emit propertySetSwitched(0);
+ if(isCreatingConnection())
+ stopCreatingConnection();
+
+ emitNoFormSelected();
+ return;
+ }
+
+ Form *previousActive = m_active;
+ Form *form;
+ for(form = m_forms.first(); form; form = m_forms.next())
+ {
+ if(form->toplevelContainer() && form->widget() == w)
+ {
+ if(m_treeview)
+ m_treeview->setForm(form);
+ //if(m_propSet)
+ // m_propList->setCollection(form->pixmapCollection());
+
+ kdDebug() << "FormManager::windowChanged() active form is " << form->objectTree()->name() << endl;
+
+ if(m_collection)
+ {
+#ifndef KFD_NO_STYLES
+ // update the 'style' action
+ KSelectAction *m_style = (KSelectAction*)m_collection->action("change_style", "KSelectAction");
+ const QString currentStyle = form->widget()->style().name();
+ const QStringList styles = m_style->items();
+
+ int idx = 0;
+ QStringList::ConstIterator endIt = styles.constEnd();
+ for (QStringList::ConstIterator it = styles.constBegin(); it != endIt; ++it, ++idx)
+ {
+ if ((*it).lower() == currentStyle) {
+ kdDebug() << "Updating the style to " << currentStyle << endl;
+ m_style->setCurrentItem(idx);
+ break;
+ }
+ }
+#endif
+ }
+
+ if((form != previousActive) && isCreatingConnection())
+ resetCreatedConnection();
+
+ m_active = form;
+
+ emit dirty(form, form->isModified());
+ // update actions state
+ m_active->emitActionSignals();
+ //update the buffer too
+ form->emitSelectionSignals();
+ if (!m_emitSelectionSignalsUpdatesPropertySet)
+ showPropertySet( propertySet(), true );
+ return;
+ }
+ }
+
+ for(form = m_preview.first(); form; form = m_preview.next())
+ {
+ kdDebug() << (form->widget() ? form->widget()->name() : "") << endl;
+ if(form->toplevelContainer() && form->widget() == w) {
+ kdDebug() << "FormManager::windowChanged() active preview form is " << form->widget()->name() << endl;
+
+ if(m_collection)
+ {
+#ifndef KFD_NO_STYLES
+ // update the 'style' action
+ KSelectAction *m_style = (KSelectAction*)m_collection->action("change_style", "KSelectAction");
+ const QString currentStyle = form->widget()->style().name();
+ const QStringList styles = m_style->items();
+
+ int idx = 0;
+ QStringList::ConstIterator endIt = styles.constEnd();
+ for (QStringList::ConstIterator it = styles.constBegin(); it != endIt; ++it, ++idx)
+ {
+ if ((*it).lower() == currentStyle) {
+ kdDebug() << "Updating the style to " << currentStyle << endl;
+ m_style->setCurrentItem(idx);
+ break;
+ }
+ }
+#endif
+
+ resetCreatedConnection();
+ m_active = form;
+
+ emit dirty(form, false);
+ emitNoFormSelected();
+ showPropertySet(0);
+ return;
+ }
+ }
+ }
+ //m_active = 0;
+}
+
+Form*
+FormManager::activeForm() const
+{
+ return m_active;
+}
+
+Form*
+FormManager::formForWidget(QWidget *w)
+{
+ for(Form *form = m_forms.first(); form; form = m_forms.next()) {
+ if(form->toplevelContainer() && form->widget() == w)
+ return form;
+ }
+
+ return 0; // not one of toplevel widgets
+}
+
+void
+FormManager::deleteForm(Form *form)
+{
+ if (!form)
+ return;
+ if(m_forms.find(form) == -1)
+ m_preview.remove(form);
+ else
+ m_forms.remove(form);
+
+ if(m_forms.count() == 0) {
+ m_active = 0;
+ emit propertySetSwitched(0);
+ }
+}
+
+void
+FormManager::importForm(Form *form, bool preview)
+{
+ if(!preview)
+ initForm(form);
+ else
+ {
+ m_preview.append(form);
+ form->setDesignMode(false);
+ }
+}
+
+void
+FormManager::initForm(Form *form)
+{
+ m_forms.append(form);
+
+ if(m_treeview)
+ m_treeview->setForm(form);
+
+ m_active = form;
+
+ connect(form, SIGNAL(selectionChanged(QWidget*, bool, bool)),
+ m_propSet, SLOT(setSelectedWidgetWithoutReload(QWidget*, bool, bool)));
+ if(m_treeview)
+ {
+ connect(form, SIGNAL(selectionChanged(QWidget*, bool, bool)),
+ m_treeview, SLOT(setSelectedWidget(QWidget*, bool)));
+ connect(form, SIGNAL(childAdded(ObjectTreeItem* )), m_treeview, SLOT(addItem(ObjectTreeItem*)));
+ connect(form, SIGNAL(childRemoved(ObjectTreeItem* )), m_treeview, SLOT(removeItem(ObjectTreeItem*)));
+ }
+ connect(m_propSet, SIGNAL(widgetNameChanged(const QCString&, const QCString&)),
+ form, SLOT(changeName(const QCString&, const QCString&)));
+
+ form->setSelectedWidget(form->widget());
+ windowChanged(form->widget());
+}
+
+void
+FormManager::previewForm(Form *form, QWidget *container, Form *toForm)
+{
+ if(!form || !container || !form->objectTree())
+ return;
+ QDomDocument domDoc;
+ if (!FormIO::saveFormToDom(form, domDoc))
+ return;
+
+ Form *myform;
+ if(!toForm)
+ myform = new Form(form->library(), form->objectTree()->name().latin1(),
+ false/*!designMode, we need to set it early enough*/);
+ else
+ myform = toForm;
+ myform->createToplevel(container);
+ container->setStyle( &(form->widget()->style()) );
+
+ if (!FormIO::loadFormFromDom(myform, container, domDoc)) {
+ delete myform;
+ return;
+ }
+
+ myform->setDesignMode(false);
+ m_preview.append(myform);
+ container->show();
+}
+
+/*
+bool
+FormManager::loadFormFromDomInternal(Form *form, QWidget *container, QDomDocument &inBuf)
+{
+ return FormIO::loadFormFromDom(myform, container, domDoc);
+}
+
+bool
+FormManager::saveFormToStringInternal(Form *form, QString &dest, int indent)
+{
+ return KFormDesigner::FormIO::saveFormToString(form, dest, indent);
+}*/
+
+bool
+FormManager::isTopLevel(QWidget *w)
+{
+ if(!activeForm() || !activeForm()->objectTree())
+ return false;
+
+// kdDebug() << "FormManager::isTopLevel(): for: " << w->name() << " = "
+// << activeForm()->objectTree()->lookup(w->name())<< endl;
+
+ ObjectTreeItem *item = activeForm()->objectTree()->lookup(w->name());
+ if(!item)
+ return true;
+
+ return (!item->parent());
+}
+
+void
+FormManager::deleteWidget()
+{
+ if(!activeForm() || !activeForm()->objectTree())
+ return;
+
+ QPtrList<QWidget> *list = activeForm()->selectedWidgets();
+ if(list->isEmpty())
+ return;
+
+ if (activeForm()->widget() == list->first()) {
+ //toplevel form is selected, cannot delete it
+ return;
+ }
+
+ KCommand *com = new DeleteWidgetCommand(*list, activeForm());
+ activeForm()->addCommand(com, true);
+}
+
+void
+FormManager::copyWidget()
+{
+ if (!activeForm() || !activeForm()->objectTree())
+ return;
+
+ QPtrList<QWidget> *list = activeForm()->selectedWidgets();
+ if(list->isEmpty())
+ return;
+
+ removeChildrenFromList(*list);
+
+ // We clear the current clipboard
+ m_domDoc.setContent(QString(), true);
+ QDomElement parent = m_domDoc.createElement("UI");
+ m_domDoc.appendChild(parent);
+
+ QWidget *w;
+ for(w = list->first(); w; w = list->next())
+ {
+ ObjectTreeItem *it = activeForm()->objectTree()->lookup(w->name());
+ if (!it)
+ continue;
+
+ FormIO::saveWidget(it, parent, m_domDoc);
+ }
+
+ FormIO::cleanClipboard(parent);
+
+ activeForm()->emitActionSignals(); // to update 'Paste' item state
+}
+
+void
+FormManager::cutWidget()
+{
+ if(!activeForm() || !activeForm()->objectTree())
+ return;
+
+ QPtrList<QWidget> *list = activeForm()->selectedWidgets();
+ if(list->isEmpty())
+ return;
+
+ KCommand *com = new CutWidgetCommand(*list, activeForm());
+ activeForm()->addCommand(com, true);
+}
+
+void
+FormManager::pasteWidget()
+{
+ if(!m_domDoc.namedItem("UI").hasChildNodes())
+ return;
+ if(!activeForm() || !activeForm()->objectTree())
+ return;
+
+ KCommand *com = new PasteWidgetCommand(m_domDoc, activeForm()->activeContainer(), m_insertPoint);
+ activeForm()->addCommand(com, true);
+}
+
+void
+FormManager::setInsertPoint(const QPoint &p)
+{
+ m_insertPoint = p;
+}
+
+void
+FormManager::createSignalMenu(QWidget *w)
+{
+ m_sigSlotMenu = new KPopupMenu();
+ m_sigSlotMenu->insertTitle(SmallIcon("connection"), i18n("Signals"));
+
+ QStrList list = w->metaObject()->signalNames(true);
+ QStrListIterator it(list);
+ for(; it.current() != 0; ++it)
+ m_sigSlotMenu->insertItem(*it);
+
+ int result = m_sigSlotMenu->exec(QCursor::pos());
+ if(result == -1)
+ resetCreatedConnection();
+ else
+ menuSignalChosen(result);
+
+ delete m_sigSlotMenu;
+ m_sigSlotMenu = 0;
+}
+
+void
+FormManager::createSlotMenu(QWidget *w)
+{
+ m_sigSlotMenu = new KPopupMenu();
+ m_sigSlotMenu->insertTitle(SmallIcon("connection"), i18n("Slots"));
+
+ QString signalArg( m_connection->signal().remove( QRegExp(".*[(]|[)]") ) );
+
+ QStrList list = w->metaObject()->slotNames(true);
+ QStrListIterator it(list);
+ for(; it.current() != 0; ++it)
+ {
+ // we add the slot only if it is compatible with the signal
+ QString slotArg(*it);
+ slotArg = slotArg.remove( QRegExp(".*[(]|[)]") );
+ if(!signalArg.startsWith(slotArg, true)) // args not compatible
+ continue;
+
+ m_sigSlotMenu->insertItem(*it);
+ }
+
+ int result = m_sigSlotMenu->exec(QCursor::pos());
+ if(result == -1)
+ resetCreatedConnection();
+ else
+ menuSignalChosen(result);
+
+ delete m_sigSlotMenu;
+ m_sigSlotMenu = 0;
+}
+
+void
+FormManager::createContextMenu(QWidget *w, Container *container, bool popupAtCursor)
+{
+ if(!activeForm() || !activeForm()->widget())
+ return;
+ const bool toplevelWidgetSelected = activeForm()->widget() == w;
+ const uint widgetsCount = container->form()->selectedWidgets()->count();
+ const bool multiple = widgetsCount > 1;
+ //const bool enableRemove = w != m_active->widget();
+ // We only enablelayout creation if more than one widget with the same parent are selected
+ const bool enableLayout = multiple || w == container->widget();
+
+ m_menuWidget = w;
+ QString n = container->form()->library()->displayName(w->className());
+// QValueVector<int> menuIds();
+
+ if (!m_popup) {
+ m_popup = new KPopupMenu();
+ }
+ else {
+ m_popup->clear();
+ }
+
+ //set title
+ if(!multiple)
+ {
+ if(w == container->form()->widget())
+ m_popup->insertTitle(SmallIcon("form"), i18n("%1 : Form").arg(w->name()) );
+ else
+ m_popup->insertTitle( SmallIcon(
+ container->form()->library()->iconName(w->className())), QString(w->name()) + " : " + n );
+ }
+ else
+ m_popup->insertTitle(SmallIcon("multiple_obj"), i18n("Multiple Widgets")
+ + QString(" (%1)").arg(widgetsCount));
+
+ KAction *a;
+#define PLUG_ACTION(_name, forceVisible) \
+ { a = action(_name); \
+ if (a && (forceVisible || a->isEnabled())) { \
+ if (separatorNeeded) \
+ m_popup->insertSeparator(); \
+ separatorNeeded = false; \
+ a->plug(m_popup); \
+ } \
+ }
+
+ bool separatorNeeded = false;
+
+ PLUG_ACTION("edit_cut", !toplevelWidgetSelected);
+ PLUG_ACTION("edit_copy", !toplevelWidgetSelected);
+ PLUG_ACTION("edit_paste", true);
+ PLUG_ACTION("edit_delete", !toplevelWidgetSelected);
+ separatorNeeded = true;
+ PLUG_ACTION("layout_menu", enableLayout);
+ PLUG_ACTION("break_layout", enableLayout);
+ separatorNeeded = true;
+ PLUG_ACTION("align_menu", !toplevelWidgetSelected);
+ PLUG_ACTION("adjust_size_menu", !toplevelWidgetSelected);
+ separatorNeeded = true;
+
+ // We create the buddy menu
+ if(!multiple && w->inherits("QLabel") && ((QLabel*)w)->text().contains("&") && (((QLabel*)w)->textFormat() != RichText))
+ {
+ if (separatorNeeded)
+ m_popup->insertSeparator();
+
+ KPopupMenu *sub = new KPopupMenu(w);
+ QWidget *buddy = ((QLabel*)w)->buddy();
+
+ sub->insertItem(i18n("No Buddy"), MenuNoBuddy);
+ if(!buddy)
+ sub->setItemChecked(MenuNoBuddy, true);
+ sub->insertSeparator();
+
+ // add all the widgets that can have focus
+ for(ObjectTreeListIterator it( container->form()->tabStopsIterator() ); it.current(); ++it)
+ {
+ int index = sub->insertItem(
+ SmallIcon(container->form()->library()->iconName(it.current()->className().latin1())),
+ it.current()->name());
+ if(it.current()->widget() == buddy)
+ sub->setItemChecked(index, true);
+ }
+
+ /*int id =*/ m_popup->insertItem(i18n("Choose Buddy..."), sub);
+// menuIds->append(id);
+ connect(sub, SIGNAL(activated(int)), this, SLOT(buddyChosen(int)));
+
+ separatorNeeded = true;
+ }
+
+ //int sigid=0;
+#ifdef KEXI_DEBUG_GUI
+ if(!multiple && !(m_options & HideEventsInPopupMenu))
+ {
+ if (separatorNeeded)
+ m_popup->insertSeparator();
+
+ // We create the signals menu
+ KPopupMenu *sigMenu = new KPopupMenu();
+ QStrList list = w->metaObject()->signalNames(true);
+ QStrListIterator it(list);
+ for(; it.current() != 0; ++it)
+ sigMenu->insertItem(*it);
+
+ int id = m_popup->insertItem(SmallIconSet(""), i18n("Events"), sigMenu);
+// menuIds->append(id);
+ if(list.isEmpty())
+ m_popup->setItemEnabled(id, false);
+ connect(sigMenu, SIGNAL(activated(int)), this, SLOT(menuSignalChosen(int)));
+ separatorNeeded = true;
+ }
+#endif
+
+ // Other items
+ if(!multiple)
+ {
+ int lastID = -1;
+ if (separatorNeeded) {
+ lastID = m_popup->insertSeparator();
+ }
+ const uint oldIndex = m_popup->count()-1;
+ container->form()->library()->createMenuActions(w->className(), w, m_popup, container);
+ if (oldIndex == (m_popup->count()-1)) {
+// for (uint i=oldIndex; i<m_popup->count(); i++) {
+// int id = m_popup->idAt( i );
+// if (id!=-1)
+// menuIds->append( id );
+// }
+ //nothing added
+ if (separatorNeeded) {
+ m_popup->removeItem( lastID );
+// menuIds->pop_back();
+ }
+ }
+ }
+
+ //show the popup at the selected widget
+ QPoint popupPos;
+ if (popupAtCursor) {
+ popupPos = QCursor::pos();
+ }
+ else {
+ WidgetList *lst = container->form()->selectedWidgets();
+ QWidget * sel_w = lst ? lst->first() : container->form()->selectedWidget();
+ popupPos = sel_w ? sel_w->mapToGlobal(QPoint(sel_w->width()/2, sel_w->height()/2)) : QCursor::pos();
+ }
+ m_insertPoint = container->widget()->mapFromGlobal(popupPos);
+ m_popup->exec(popupPos);//QCursor::pos());
+ m_insertPoint = QPoint();
+
+// QValueVector<int>::iterator it;
+// for(it = menuIds->begin(); it != menuIds->end(); ++it)
+// m_popup->removeItem(*it);
+}
+
+void
+FormManager::buddyChosen(int id)
+{
+ if(!m_menuWidget)
+ return;
+ QLabel *label = static_cast<QLabel*>((QWidget*)m_menuWidget);
+
+ if(id == MenuNoBuddy)
+ {
+ label->setBuddy(0);
+ return;
+ }
+
+ ObjectTreeItem *item = activeForm()->objectTree()->lookup(m_popup->text(id));
+ if(!item || !item->widget())
+ return;
+ label->setBuddy(item->widget());
+}
+
+void
+FormManager::menuSignalChosen(int id)
+{
+ if (m_options & HideSignalSlotConnections)
+ return;
+
+ //if(!m_menuWidget)
+ // return;
+ if(m_drawingSlot && m_sigSlotMenu)
+ {
+ if( m_connection->receiver().isNull() )
+ m_connection->setSignal(m_sigSlotMenu->text(id));
+ else
+ {
+ m_connection->setSlot(m_sigSlotMenu->text(id));
+ kdDebug() << "Finished creating the connection: sender=" << m_connection->sender() << "; signal=" << m_connection->signal() <<
+ "; receiver=" << m_connection->receiver() << "; slot=" << m_connection->slot() << endl;
+ emit connectionCreated(activeForm(), *m_connection);
+ stopCreatingConnection();
+ }
+ }
+ else if(m_menuWidget)
+ emit createFormSlot(m_active, m_menuWidget->name(), m_popup->text(id));
+}
+
+void
+FormManager::slotConnectionCreated(Form *form, Connection &connection)
+{
+ if (m_options & HideSignalSlotConnections)
+ return;
+ if(!form)
+ return;
+
+ Connection *c = new Connection(connection);
+ form->connectionBuffer()->append(c);
+}
+
+void
+FormManager::layoutHBox()
+{
+ createLayout(Container::HBox);
+}
+
+void
+FormManager::layoutVBox()
+{
+ createLayout(Container::VBox);
+}
+
+void
+FormManager::layoutGrid()
+{
+ createLayout(Container::Grid);
+}
+
+void
+FormManager::layoutHSplitter()
+{
+ createLayout(Container::HSplitter);
+}
+
+void
+FormManager::layoutVSplitter()
+{
+ createLayout(Container::VSplitter);
+}
+
+void
+FormManager::layoutHFlow()
+{
+ createLayout(Container::HFlow);
+}
+
+void
+FormManager::layoutVFlow()
+{
+ createLayout(Container::VFlow);
+}
+
+void
+FormManager::createLayout(int layoutType)
+{
+ WidgetList *list = m_active->selectedWidgets();
+ // if only one widget is selected (a container), we modify its layout
+ if (list->isEmpty()) {//sanity check
+ kdWarning() << "FormManager::createLayout(): list is empty!" << endl;
+ return;
+ }
+ if(list->count() == 1)
+ {
+ ObjectTreeItem *item = m_active->objectTree()->lookup(list->first()->name());
+ if(!item || !item->container() || !m_propSet->contains("layout"))
+ return;
+ (*m_propSet)["layout"] = Container::layoutTypeToString(layoutType);
+ return;
+ }
+
+ QWidget *parent = list->first()->parentWidget();
+ for(QWidget *w = list->first(); w; w = list->next())
+ {
+ kdDebug() << "comparing widget " << w->name() << " whose parent is " << w->parentWidget()->name() << " insteaed of " << parent->name() << endl;
+ if(w->parentWidget() != parent)
+ {
+ KMessageBox::sorry(m_active->widget()->topLevelWidget(), i18n("<b>Cannot create the layout.</b>\n"
+ "All selected widgets must have the same parent."));
+ kdDebug() << "FormManager::createLayout() widgets don't have the same parent widget" << endl;
+ return;
+ }
+ }
+
+ KCommand *com = new CreateLayoutCommand(layoutType, *list, m_active);
+ m_active->addCommand(com, true);
+}
+
+void
+FormManager::breakLayout()
+{
+ if(!activeForm() || !activeForm()->objectTree())
+ return;
+
+ Container *container = activeForm()->activeContainer();
+ QCString c( container->widget()->className() );
+
+ if((c == "Grid") || (c == "VBox") || (c == "HBox") || (c == "HFlow") || (c == "VFlow"))
+ {
+ KCommand *com = new BreakLayoutCommand(container);
+ m_active->addCommand(com, true);
+ }
+ else // normal container
+ {
+ if(activeForm()->selectedWidgets()->count() == 1)
+ (*m_propSet)["layout"] = "NoLayout";
+ else
+ container->setLayout(Container::NoLayout);
+ }
+}
+
+void
+FormManager::showPropertySet(WidgetPropertySet *set, bool forceReload, const QCString& propertyToSelect)
+{
+ if (m_objectBlockingPropertyEditorUpdating)
+ return;
+
+/*unused if(m_editor) {
+ if (propertyToSelect.isEmpty() && forceReload)
+ m_editor->changeSet(set ? set->set() : 0, propertyToSelect);
+ else
+ m_editor->changeSet(set ? set->set() : 0);
+ }*/
+
+ emit propertySetSwitched(set ? set->set(): 0, /*preservePrevSelection*/forceReload, propertyToSelect);
+}
+
+void
+FormManager::blockPropertyEditorUpdating(void *blockingObject)
+{
+ if (!blockingObject || m_objectBlockingPropertyEditorUpdating)
+ return;
+ m_objectBlockingPropertyEditorUpdating = blockingObject;
+}
+
+void
+FormManager::unblockPropertyEditorUpdating(void *blockingObject, WidgetPropertySet *set)
+{
+ if (!blockingObject || m_objectBlockingPropertyEditorUpdating!=blockingObject)
+ return;
+
+ m_objectBlockingPropertyEditorUpdating = 0;
+ showPropertySet(set, true/*forceReload*/);
+}
+
+void
+FormManager::editTabOrder()
+{
+ if(!activeForm() || !activeForm()->objectTree())
+ return;
+ QWidget *topLevel = m_active->widget()->topLevelWidget();
+ TabStopDialog dlg(topLevel);
+ //const bool oldAutoTabStops = m_active->autoTabStops();
+ if (dlg.exec(m_active) == QDialog::Accepted) {
+ //inform about changing "autoTabStop" property
+ // -- this will be received eg. by Kexi, so custom "autoTabStop" property can be updated
+ emit autoTabStopsSet(m_active, dlg.autoTabStops());
+ //force set dirty
+ emit dirty(m_active, true);
+ }
+}
+
+void
+FormManager::slotStyle()
+{
+ if(!activeForm())
+ return;
+
+ KSelectAction *m_style = (KSelectAction*)m_collection->action("change_style", "KSelectAction");
+ QString style = m_style->currentText();
+ activeForm()->widget()->setStyle( style);
+
+ QObjectList *l = activeForm()->widget()->queryList( "QWidget" );
+ for(QObject *o = l->first(); o; o = l->next())
+ (static_cast<QWidget*>(o))->setStyle( style );
+ delete l;
+}
+
+void
+FormManager::editFormPixmapCollection()
+{
+ if(!activeForm() || !activeForm()->objectTree())
+ return;
+
+ PixmapCollectionEditor dialog(activeForm()->pixmapCollection(), activeForm()->widget()->topLevelWidget());
+ dialog.exec();
+}
+
+void
+FormManager::editConnections()
+{
+ if (m_options & HideSignalSlotConnections)
+ return;
+ if(!activeForm() || !activeForm()->objectTree())
+ return;
+
+ ConnectionDialog dialog(activeForm()->widget()->topLevelWidget());
+ dialog.exec(activeForm());
+}
+
+void
+FormManager::alignWidgets(int type)
+{
+ if(!activeForm() || !activeForm()->objectTree() || (activeForm()->selectedWidgets()->count() < 2))
+ return;
+
+ QWidget *parentWidget = activeForm()->selectedWidgets()->first()->parentWidget();
+
+ for(QWidget *w = activeForm()->selectedWidgets()->first(); w; w = activeForm()->selectedWidgets()->next())
+ {
+ if(w->parentWidget() != parentWidget)
+ {
+ kdDebug() << "FormManager::alignWidgets() type ==" << type << " widgets don't have the same parent widget" << endl;
+ return;
+ }
+ }
+
+ KCommand *com = new AlignWidgetsCommand(type, *(activeForm()->selectedWidgets()), activeForm());
+ activeForm()->addCommand(com, true);
+}
+
+void
+FormManager::alignWidgetsToLeft()
+{
+ alignWidgets(AlignWidgetsCommand::AlignToLeft);
+}
+
+void
+FormManager::alignWidgetsToRight()
+{
+ alignWidgets(AlignWidgetsCommand::AlignToRight);
+}
+
+void
+FormManager::alignWidgetsToTop()
+{
+ alignWidgets(AlignWidgetsCommand::AlignToTop);
+}
+
+void
+FormManager::alignWidgetsToBottom()
+{
+ alignWidgets(AlignWidgetsCommand::AlignToBottom);
+}
+
+void
+FormManager::adjustWidgetSize()
+{
+ if(!activeForm() || !activeForm()->objectTree())
+ return;
+
+ KCommand *com = new AdjustSizeCommand(AdjustSizeCommand::SizeToFit, *(activeForm()->selectedWidgets()), activeForm());
+ activeForm()->addCommand(com, true);
+}
+
+void
+FormManager::alignWidgetsToGrid()
+{
+ if(!activeForm() || !activeForm()->objectTree())
+ return;
+
+ KCommand *com = new AlignWidgetsCommand(AlignWidgetsCommand::AlignToGrid, *(activeForm()->selectedWidgets()), activeForm());
+ activeForm()->addCommand(com, true);
+}
+
+void
+FormManager::adjustSizeToGrid()
+{
+ if(!activeForm() || !activeForm()->objectTree())
+ return;
+
+ KCommand *com = new AdjustSizeCommand(AdjustSizeCommand::SizeToGrid, *(activeForm()->selectedWidgets()), activeForm());
+ activeForm()->addCommand(com, true);
+}
+
+void
+FormManager::adjustWidthToSmall()
+{
+ if(!activeForm() || !activeForm()->objectTree())
+ return;
+
+ KCommand *com = new AdjustSizeCommand(AdjustSizeCommand::SizeToSmallWidth, *(activeForm()->selectedWidgets()), activeForm());
+ activeForm()->addCommand(com, true);
+}
+
+void
+FormManager::adjustWidthToBig()
+{
+ if(!activeForm() || !activeForm()->objectTree())
+ return;
+
+ KCommand *com = new AdjustSizeCommand(AdjustSizeCommand::SizeToBigWidth, *(activeForm()->selectedWidgets()), activeForm());
+ activeForm()->addCommand(com, true);
+}
+
+void
+FormManager::adjustHeightToSmall()
+{
+ if(!activeForm() || !activeForm()->objectTree())
+ return;
+
+ KCommand *com = new AdjustSizeCommand(AdjustSizeCommand::SizeToSmallHeight, *(activeForm()->selectedWidgets()), activeForm());
+ activeForm()->addCommand(com, true);
+}
+
+void
+FormManager::adjustHeightToBig()
+{
+ if(!activeForm() || !activeForm()->objectTree())
+ return;
+
+ KCommand *com = new AdjustSizeCommand(AdjustSizeCommand::SizeToBigHeight, *(activeForm()->selectedWidgets()), activeForm());
+ activeForm()->addCommand(com, true);
+}
+
+void
+FormManager::bringWidgetToFront()
+{
+ if(!activeForm() || !activeForm()->objectTree())
+ return;
+
+ for(QWidget *w = activeForm()->selectedWidgets()->first(); w; w = activeForm()->selectedWidgets()->next())
+ w->raise();
+}
+
+void
+FormManager::sendWidgetToBack()
+{
+ if(!activeForm() || !activeForm()->objectTree())
+ return;
+
+ for(QWidget *w = activeForm()->selectedWidgets()->first(); w; w = activeForm()->selectedWidgets()->next())
+ w->lower();
+}
+
+void
+FormManager::selectAll()
+{
+ if(!activeForm() || !activeForm()->objectTree())
+ return;
+
+ activeForm()->selectFormWidget();
+ uint count = activeForm()->objectTree()->children()->count();
+ for(ObjectTreeItem *it = activeForm()->objectTree()->children()->first(); it;
+ it = activeForm()->objectTree()->children()->next(), count--)
+ {
+ activeForm()->setSelectedWidget(it->widget(), /*add*/true, /*raise*/false, /*moreWillBeSelected*/count>1);
+ }
+}
+
+void
+FormManager::clearWidgetContent()
+{
+ if(!activeForm() || !activeForm()->objectTree())
+ return;
+
+ for(QWidget *w = activeForm()->selectedWidgets()->first(); w; w = activeForm()->selectedWidgets()->next())
+ activeForm()->library()->clearWidgetContent(w->className(), w);
+}
+
+void
+FormManager::deleteWidgetLater( QWidget *w )
+{
+ w->hide();
+ w->reparent(0, WType_TopLevel, QPoint(0,0));
+ m_deleteWidgetLater_list.append( w );
+ m_deleteWidgetLater_timer.start( 100, true );
+}
+
+void
+FormManager::deleteWidgetLaterTimeout()
+{
+ m_deleteWidgetLater_list.clear();
+}
+
+void
+FormManager::showFormUICode()
+{
+#ifdef KEXI_DEBUG_GUI
+ if(!activeForm())
+ return;
+
+ QString uiCode;
+ if (!FormIO::saveFormToString(activeForm(), uiCode, 3)) {
+ //! @todo show err?
+ return;
+ }
+
+ if (!m_uiCodeDialog) {
+ m_uiCodeDialog = new KDialogBase(0, "uiwindow", true, i18n("Form's UI Code"),
+ KDialogBase::Close, KDialogBase::Close);
+ m_uiCodeDialog->resize(700, 600);
+ QVBox *box = m_uiCodeDialog->makeVBoxMainWidget();
+ KTabWidget* tab = new KTabWidget(box);
+
+ m_currentUICodeDialogEditor = new KTextEdit(QString::null, QString::null, tab);
+ tab->addTab( m_currentUICodeDialogEditor, i18n("Current"));
+ m_currentUICodeDialogEditor->setReadOnly(true);
+ QFont f( m_currentUICodeDialogEditor->font() );
+ f.setFamily("courier");
+ m_currentUICodeDialogEditor->setFont(f);
+ m_currentUICodeDialogEditor->setTextFormat(Qt::PlainText);
+
+ m_originalUICodeDialogEditor = new KTextEdit(QString::null, QString::null, tab);
+ tab->addTab( m_originalUICodeDialogEditor, i18n("Original"));
+ m_originalUICodeDialogEditor->setReadOnly(true);
+ m_originalUICodeDialogEditor->setFont(f);
+ m_originalUICodeDialogEditor->setTextFormat(Qt::PlainText);
+ }
+ m_currentUICodeDialogEditor->setText( uiCode );
+ //indent and set our original doc as well:
+ QDomDocument doc;
+ doc.setContent( activeForm()->m_recentlyLoadedUICode );
+ m_originalUICodeDialogEditor->setText( doc.toString( 3 ) );
+ m_uiCodeDialog->show();
+#endif
+}
+
+void
+FormManager::slotSettingsChanged(int category)
+{
+ if (category==KApplication::SETTINGS_SHORTCUTS) {
+ m_contextMenuKey = KGlobalSettings::contextMenuKey();
+ }
+}
+
+void
+FormManager::emitWidgetSelected( KFormDesigner::Form* form, bool multiple )
+{
+ enableFormActions();
+ // Enable edit actions
+ enableAction("edit_copy", true);
+ enableAction("edit_cut", true);
+ enableAction("edit_delete", true);
+ enableAction("clear_contents", true);
+
+ // 'Align Widgets' menu
+ enableAction("align_menu", multiple);
+ enableAction("align_to_left", multiple);
+ enableAction("align_to_right", multiple);
+ enableAction("align_to_top", multiple);
+ enableAction("align_to_bottom", multiple);
+
+ enableAction("adjust_size_menu", true);
+ enableAction("adjust_width_small", multiple);
+ enableAction("adjust_width_big", multiple);
+ enableAction("adjust_height_small", multiple);
+ enableAction("adjust_height_big", multiple);
+
+ enableAction("format_raise", true);
+ enableAction("format_lower", true);
+
+ WidgetList *wlist = form->selectedWidgets();
+ bool fontEnabled = false;
+ for (WidgetListIterator it(*wlist); it.current(); ++it) {
+ if (-1 != it.current()->metaObject()->findProperty("font", true)) {
+ fontEnabled = true;
+ break;
+ }
+ }
+ enableAction("format_font", fontEnabled);
+
+ // If the widgets selected is a container, we enable layout actions
+ bool containerSelected = false;
+ if(!multiple)
+ {
+ KFormDesigner::ObjectTreeItem *item = 0;
+ if (form->selectedWidgets()->first())
+ form->objectTree()->lookup( form->selectedWidgets()->first()->name() );
+ if(item && item->container())
+ containerSelected = true;
+ }
+ const bool twoSelected = form->selectedWidgets()->count()==2;
+ // Layout actions
+ enableAction("layout_menu", multiple || containerSelected);
+ enableAction("layout_hbox", multiple || containerSelected);
+ enableAction("layout_vbox", multiple || containerSelected);
+ enableAction("layout_grid", multiple || containerSelected);
+ enableAction("layout_hsplitter", twoSelected);
+ enableAction("layout_vsplitter", twoSelected);
+
+ KFormDesigner::Container *container = activeForm() ? activeForm()->activeContainer() : 0;
+ if (container)
+ enableAction("break_layout", (container->layoutType() != KFormDesigner::Container::NoLayout));
+
+ emit widgetSelected(form, true);
+}
+
+void
+FormManager::emitFormWidgetSelected( KFormDesigner::Form* form )
+{
+// disableWidgetActions();
+ enableAction("edit_copy", false);
+ enableAction("edit_cut", false);
+ enableAction("edit_delete", false);
+ enableAction("clear_contents", false);
+
+ // Disable format functions
+ enableAction("align_menu", false);
+ enableAction("align_to_left", false);
+ enableAction("align_to_right", false);
+ enableAction("align_to_top", false);
+ enableAction("align_to_bottom", false);
+ enableAction("adjust_size_menu", false);
+ enableAction("format_raise", false);
+ enableAction("format_lower", false);
+
+ enableAction("format_font", false);
+
+ enableFormActions();
+
+ const bool twoSelected = form->selectedWidgets()->count()==2;
+ const bool hasChildren = !form->objectTree()->children()->isEmpty();
+
+ // Layout actions
+ enableAction("layout_menu", hasChildren);
+ enableAction("layout_hbox", hasChildren);
+ enableAction("layout_vbox", hasChildren);
+ enableAction("layout_grid", hasChildren);
+ enableAction("layout_hsplitter", twoSelected);
+ enableAction("layout_vsplitter", twoSelected);
+ enableAction("break_layout", (form->toplevelContainer()->layoutType() != KFormDesigner::Container::NoLayout));
+
+ emit formWidgetSelected( form );
+}
+
+void
+FormManager::emitNoFormSelected()
+{
+ disableWidgetActions();
+
+ // Disable edit actions
+// enableAction("edit_paste", false);
+// enableAction("edit_undo", false);
+// enableAction("edit_redo", false);
+
+ // Disable 'Tools' actions
+ enableAction("pixmap_collection", false);
+ if (!(m_options & HideSignalSlotConnections))
+ enableAction("form_connections", false);
+ enableAction("taborder", false);
+ enableAction("change_style", activeForm()!=0);
+
+ // Disable items in 'File'
+ if (!(m_options & SkipFileActions)) {
+ enableAction("file_save", false);
+ enableAction("file_save_as", false);
+ enableAction("preview_form", false);
+ }
+
+ emit noFormSelected();
+}
+
+void
+FormManager::enableFormActions()
+{
+ // Enable 'Tools' actions
+ enableAction("pixmap_collection", true);
+ if (!(m_options & HideSignalSlotConnections))
+ enableAction("form_connections", true);
+ enableAction("taborder", true);
+ enableAction("change_style", true);
+
+ // Enable items in 'File'
+ if (!(m_options & SkipFileActions)) {
+ enableAction("file_save", true);
+ enableAction("file_save_as", true);
+ enableAction("preview_form", true);
+ }
+
+ enableAction("edit_paste", isPasteEnabled());
+ enableAction("edit_select_all", true);
+}
+
+void
+FormManager::disableWidgetActions()
+{
+ // Disable edit actions
+ enableAction("edit_copy", false);
+ enableAction("edit_cut", false);
+ enableAction("edit_delete", false);
+ enableAction("clear_contents", false);
+
+ // Disable format functions
+ enableAction("align_menu", false);
+ enableAction("align_to_left", false);
+ enableAction("align_to_right", false);
+ enableAction("align_to_top", false);
+ enableAction("align_to_bottom", false);
+ enableAction("adjust_size_menu", false);
+ enableAction("format_raise", false);
+ enableAction("format_lower", false);
+
+ enableAction("layout_menu", false);
+ enableAction("layout_hbox", false);
+ enableAction("layout_vbox", false);
+ enableAction("layout_grid", false);
+ enableAction("layout_hsplitter", false);
+ enableAction("layout_vsplitter", false);
+ enableAction("break_layout", false);
+}
+
+void
+FormManager::emitUndoEnabled(bool enabled, const QString &text)
+{
+ enableAction("edit_undo", enabled);
+ emit undoEnabled(enabled, text);
+}
+
+void
+FormManager::emitRedoEnabled(bool enabled, const QString &text)
+{
+ enableAction("edit_redo", enabled);
+ emit redoEnabled(enabled, text);
+}
+
+void
+FormManager::changeFont()
+{
+ if (!m_active)
+ return;
+ WidgetList *wlist = m_active->selectedWidgets();
+ WidgetList widgetsWithFontProperty;
+ QWidget *widget;
+ QFont font;
+ bool oneFontSelected = true;
+ for (WidgetListIterator it(*wlist); (widget = it.current()); ++it) {
+ if (m_active->library()->isPropertyVisible(widget->className(), widget, "font")) {
+ widgetsWithFontProperty.append(widget);
+ if (oneFontSelected) {
+ if (widgetsWithFontProperty.count()==1)
+ font = widget->font();
+ else if (font != widget->font())
+ oneFontSelected = false;
+ }
+ }
+ }
+ if (widgetsWithFontProperty.isEmpty())
+ return;
+ if (!oneFontSelected) //many different fonts selected: pick a font from toplevel conatiner
+ font = m_active->widget()->font();
+
+ if (1==widgetsWithFontProperty.count()) {
+ //single widget's settings
+ widget = widgetsWithFontProperty.first();
+ KoProperty::Property &fontProp = m_propSet->property("font");
+ if (QDialog::Accepted != KFontDialog::getFont(font, false, m_active->widget()))
+ return;
+ fontProp = font;
+ return;
+ }
+ //multiple widgets
+ int diffFlags=0;
+ if (QDialog::Accepted != KFontDialog::getFontDiff(font, diffFlags, false, m_active->widget())
+ || 0==diffFlags)
+ return;
+ //update font
+ for (WidgetListIterator it(widgetsWithFontProperty); (widget = it.current()); ++it) {
+ QFont prevFont( widget->font() );
+ if (diffFlags & KFontChooser::FontDiffFamily)
+ prevFont.setFamily( font.family() );
+ if (diffFlags & KFontChooser::FontDiffStyle) {
+ prevFont.setBold( font.bold() );
+ prevFont.setItalic( font.italic() );
+ }
+ if (diffFlags & KFontChooser::FontDiffSize)
+ prevFont.setPointSize( font.pointSize() );
+/*! @todo this modification is not added to UNDO BUFFER:
+ do it when KoProperty::Set supports multiple selections */
+ widget->setFont( prevFont );
+ //temporary fix for dirty flag:
+ emit dirty(m_active, true);
+ }
+}
+
+#include "formmanager.moc"
diff --git a/kexi/formeditor/formmanager.h b/kexi/formeditor/formmanager.h
new file mode 100644
index 00000000..48e00b0f
--- /dev/null
+++ b/kexi/formeditor/formmanager.h
@@ -0,0 +1,496 @@
+/* This file is part of the KDE project
+ Copyright (C) 2004 Cedric Pasteur <cedric.pasteur@free.fr>
+ Copyright (C) 2005 Jaroslaw Staniek <js@iidea.pl>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+*/
+
+#ifndef FORMMANAGER_H
+#define FORMMANAGER_H
+
+#include <qobject.h>
+#include <qdom.h>
+#include <qptrlist.h>
+#include <qtimer.h>
+#include <qguardedptr.h>
+#include <qstringlist.h>
+
+class QWidget;
+class QWorkspace;
+class KPopupMenu;
+class KActionCollection;
+class KAction;
+class KToggleAction;
+class KDialogBase;
+class KTextEdit;
+class KXMLGUIClient;
+class KMainWindow;
+
+namespace KoProperty {
+ class Editor;
+ class Set;
+ class Property;
+ class Widget;
+}
+
+namespace KFormDesigner {
+
+class WidgetPropertySet;
+class Form;
+class Container;
+class WidgetLibrary;
+class ObjectTreeView;
+class Connection;
+class FormManager;
+typedef QPtrList<KAction> ActionList;
+
+//! @internal
+//static FormManager* FormManager_static = 0;
+
+//! A class to manage (create/load/save) Forms
+/** This is Form Designer's main class, which is used by external APIs to access FormDesigner.
+ This is the class you have to use to integrate FormDesigner into another program.
+ It deals with creating, saving and loading Form, as well as widget insertion and copying.
+ It also ensures all the components (ObjectTreeView, Form and PropertyEditor) are synced,
+ and link them.
+ It holds the WidgetLibrary, the WidgetPropertySet, links to ObjectTreeView and PropertyEditor,
+ as well as the copied widget and the insert state.
+ **/
+class KFORMEDITOR_EXPORT FormManager : public QObject
+{
+ Q_OBJECT
+
+ public:
+ /*! Constructs FormManager object.
+ Using \a options you can control manager's behaviour, see Options. */
+ FormManager(QObject *parent = 0, int options = 0, const char *name = 0);
+
+ virtual ~FormManager();
+
+ //! Creates widget library for supportedFactoryGroups
+ //! and initializes FormManager singleton. \a m should be always the same for every call.
+ static WidgetLibrary* createWidgetLibrary(FormManager* m,
+ const QStringList& supportedFactoryGroups);
+
+ //! Access to FormManager singleton
+ static FormManager* self();
+
+ /*! Options for creating FormManager objects.
+ * These are really bit-flags and may be or-ed together.
+ */
+ enum Options { HideEventsInPopupMenu = 1, SkipFileActions = 2,
+ HideSignalSlotConnections = 4 }; //todo
+
+ /*! Creates all the KActions related to widget insertion, and plug them
+ into the \a collection. \a client XML GUI client is used to call
+ lib->addCustomWidgetActions(client).
+ These actions are automatically connected to \ref insertWidget() slot.
+ \return a QPtrList of the created actions.
+ */
+ ActionList createActions(WidgetLibrary *lib, KActionCollection* collection, KXMLGUIClient *client);
+
+ /*! Enables or disables actions \a name.
+ KFD uses KPart's, action collection here.
+ Kexi implements this to get (shared) actions defined elsewhere. */
+ virtual void enableAction( const char* name, bool enable ) = 0;
+
+ /*! \return action for \a name. @see enableAction() */
+ virtual KAction* action(const char* name) = 0;
+
+ bool isPasteEnabled();
+
+// //! \return A pointer to the WidgetLibrary owned by this Manager.
+// WidgetLibrary* lib() const { return m_lib; }
+
+ //! \return A pointer to the WidgetPropertySet owned by this Manager.
+ WidgetPropertySet* propertySet() const { return m_propSet; }
+
+ /*! \return true if one of the insert buttons was pressed and the forms
+ are ready to create a widget. */
+ bool isInserting() const { return m_inserting; }
+
+ /*! \return The name of the class being inserted, corresponding
+ to the menu item or the toolbar button clicked. */
+ QCString selectedClass() const { return m_selectedClass; }
+
+ /*! Sets the point where the pasted widget should be moved to. */
+ void setInsertPoint(const QPoint &p);
+
+ //! \return If we are creating a Connection by drag-and-drop or not.
+ bool isCreatingConnection() { return m_drawingSlot; }
+
+ //! \return the Connection being created.
+ Connection* createdConnection() { return m_connection; }
+
+ /*! Resets the Connection being created. We stay in Connection creation mode,
+ but we start a new connection (when the user clicks
+ outside of signals/slots menu). */
+ void resetCreatedConnection();
+
+ //! Creates and display a menu with all the signals of widget \a w.
+ void createSignalMenu(QWidget *w);
+
+ //! Creates and display a menu with all the slots of widget \a w.
+ void createSlotMenu(QWidget *w);
+
+ //! Emits the signal \ref createFormSlot(). Used by WidgetPropertySet.
+ void emitCreateSlot(const QString &widget, const QString &value)
+ { emit createFormSlot(m_active, widget, value); }
+
+ /*! \return The Form actually active and focused.
+ */
+ Form* activeForm() const;
+
+ /*! \return the Form whose toplevel widget is \a w, or 0
+ if there is not or the Form is in preview mode. */
+ Form* formForWidget(QWidget *w);
+
+ /*! \return true if \a w is a toplevel widget,
+ ie. it is the main widget of a Form (so it should have a caption ,
+ an icon ...) */
+ bool isTopLevel(QWidget *w);
+
+ //! \return A pointer to the KoProperty::Editor we use.
+ //unused KoProperty::Editor* propertyEditor() const { return m_editor; }
+
+ /*! Shows a property set \a set in a Property Editor.
+ If \a buff is 0, Property Editor will be cleared.
+ If \a forceReload is true, the set will be reloaded even
+ if it's the same as previous one.
+ If \a propertyToSelect is not empty, an item for this name will be selected
+ (usable when previously there was no set visible). */
+ virtual void showPropertySet(WidgetPropertySet *set, bool forceReload = false,
+ const QCString& propertyToSelect = QCString());
+
+ void blockPropertyEditorUpdating(void *blockingObject);
+
+ void unblockPropertyEditorUpdating(void *blockingObject, WidgetPropertySet *set);
+
+ /*! Sets the external property editor pane used by FormDesigner (it may be docked).*/
+ void setEditor(KoProperty::Editor *editor);
+
+ /*! Sets the external object tree view used by FormDesigner (it may be docked).
+ This function also connects appropriate signals and slots to ensure
+ sync with the current Form. */
+ void setObjectTreeView(ObjectTreeView *treeview);
+
+ /*! Previews the Form \a form using the widget \a w as toplevel container for this Form. */
+ void previewForm(Form *form, QWidget *w, Form *toForm=0);
+
+ /*! Adds a existing form w and changes it to a container */
+ void importForm(Form *form=0, bool preview=false);
+
+ /*! Deletes the Form \a form and removes it from our list. */
+ void deleteForm(Form *form);
+
+ /*! This function creates and displays the context menu corresponding to the widget \a w.
+ The menu item are disabled if necessary, and
+ the widget specific part is added (menu from the factory and buddy selection). */
+ void createContextMenu(QWidget *w, Container *container, bool popupAtCursor = true);
+
+ //! \return If we align widgets to grid or not.
+ bool snapWidgetsToGrid();
+
+ //! @internal used by Container
+ int contextMenuKey() const { return m_contextMenuKey; }
+
+ //! @internal
+ void emitWidgetSelected( KFormDesigner::Form* form, bool multiple );
+ //! @internal
+ void emitFormWidgetSelected( KFormDesigner::Form* form );
+ //! @internal
+ void emitNoFormSelected();
+
+ /*! @internal
+ \return true is redo action is being executed.
+ Used in WidgetPropertySet::slotPropertyChanged() */
+ bool isRedoing() const { return m_isRedoing; }
+
+ public slots:
+ /*! Deletes the selected widget in active Form and all of its children. */
+ void deleteWidget();
+
+ /*! Copies the slected widget and all its children of the active Form using an XML representation. */
+ void copyWidget();
+
+ /*! Cuts (ie Copies and deletes) the selected widget and all its children of
+ the active Form using an XML representation. */
+ void cutWidget();
+
+ /*! Pastes the XML representation of the copied or cut widget. The widget is
+ pasted when the user clicks the Form to
+ indicate the new position of the widget, or at the position of the contextual menu if there is one. */
+ void pasteWidget();
+
+ /*! Selects all toplevel widgets in trhe current form. */
+ void selectAll();
+
+ /*! Clears the contents of the selected widget(s) (eg for a line edit or a listview). */
+ void clearWidgetContent();
+
+ void undo();
+ void redo();
+
+ /*! Displays a dialog where the user can modify the tab order of the active Form,
+ by drag-n-drop or using up/down buttons. */
+ void editTabOrder();
+
+ /*! Adjusts the size of the selected widget, ie resize it to its size hint. */
+ void adjustWidgetSize();
+
+ /*! Creates a dialog to edit the \ref activeForm() PixmapCollection. */
+ void editFormPixmapCollection();
+
+ /*! Creates a dialog to edit the Connection of \ref activeForm(). */
+ void editConnections();
+
+ //! Lay out selected widgets using HBox layout (calls \ref CreateLayoutCommand).
+ void layoutHBox();
+ //! Lay out selected widgets using VBox layout.
+ void layoutVBox();
+ //! Lay out selected widgets using Grid layout.
+ void layoutGrid();
+ //! Lay out selected widgets in an horizontal splitter
+ void layoutHSplitter();
+ //! Lay out selected widgets in a verticak splitter
+ void layoutVSplitter();
+ //! Lay out selected widgets using HFlow layout
+ void layoutHFlow();
+ //! Lay out selected widgets using VFlow layout.
+ void layoutVFlow();
+
+ //! Breaks selected layout(calls \ref BreakLayoutCommand).
+ void breakLayout();
+
+ void alignWidgetsToLeft();
+ void alignWidgetsToRight();
+ void alignWidgetsToTop();
+ void alignWidgetsToBottom();
+ void alignWidgetsToGrid();
+
+ void adjustSizeToGrid();
+
+ //! Resize all selected widgets to the width of the narrowest widget.
+ void adjustWidthToSmall();
+
+ //! Resize all selected widgets to the width of the widest widget.
+ void adjustWidthToBig();
+
+ //! Resize all selected widgets to the height of the shortest widget.
+ void adjustHeightToSmall();
+
+ //! Resize all selected widgets to the height of the tallest widget.
+ void adjustHeightToBig();
+
+ void bringWidgetToFront();
+ void sendWidgetToBack();
+
+ /*! This slot is called when the user presses a "Widget" toolbar button
+ or a "Widget" menu item. Prepares all Forms for
+ creation of a new widget (ie changes cursor ...).
+ */
+ void insertWidget(const QCString &classname);
+
+ /*! Stops the current widget insertion (ie unset the cursor ...). */
+ void stopInsert();
+
+ //! Slot called when the user presses 'Pointer' icon. Switch to Default mode.
+ void slotPointerClicked();
+
+ //! Enter the Connection creation mode.
+ void startCreatingConnection();
+
+ //! Leave the Connection creation mode.
+ void stopCreatingConnection();
+
+ /*! Calls this slot when the window activated changes (eg connect
+ to QWorkspace::windowActivated(QWidget*)). You <b>need</b> to connect
+ to this slot, it will crash otherwise.
+ */
+ void windowChanged(QWidget *w);
+
+ //! Used to delayed widgets' deletion (in Container::deleteItem())
+ void deleteWidgetLater( QWidget *w );
+
+ /*! For debugging purposes only:
+ shows a text window containing contents of .ui XML definition of the current form. */
+ void showFormUICode();
+
+ /*! Executes font dialog and changes it for currently selected widget(s). */
+ void changeFont();
+
+ signals:
+ /*! This signal is emitted as the property set switched.
+ If \a forceReload is true, the set needs to be reloaded even
+ if it's the same as previous one. */
+ void propertySetSwitched(KoProperty::Set *set, bool forceReload = false, const QCString& propertyToSelect = QCString());
+
+ /*! This signal is emitted when any change is made to the Form \a form,
+ so it will need to be saved. */
+ void dirty(KFormDesigner::Form *form, bool isDirty=true);
+
+ /*! Signal emitted when a normal widget is selected inside \a form
+ (ie not form widget). If \a multiple is true,
+ then more than one widget is selected. Use this to update actions state. */
+ void widgetSelected(KFormDesigner::Form *form, bool multiple);
+
+ /*! Signal emitted when the form widget is selected inside \a form.
+ Use this to update actions state. */
+ void formWidgetSelected(KFormDesigner::Form *form);
+
+ /*! Signal emitted when no form (or a preview form) is selected.
+ Use this to update actions state. */
+ void noFormSelected();
+
+ /*! Signal emitted when undo action activation changes.
+ \a text is the full text of the action (including command name). */
+ void undoEnabled(bool enabled, const QString &text = QString::null);
+
+ /*! Signal emitted when redo action activation changes.
+ \a text is the full text of the action (including command name). */
+ void redoEnabled(bool enabled, const QString &text = QString::null);
+
+ /*! Signal emitted when the user choose a signal in 'Events' menu
+ in context menu, or in 'Events' in property editor.
+ The code editor should then create the slot connected to this signal. */
+ void createFormSlot(KFormDesigner::Form *form, const QString &widget, const QString &signal);
+
+ /*! Signal emitted when the Connection creation by drag-and-drop ends.
+ \a connection is the created Connection. You should copy it,
+ because it is deleted just after the signal is emitted. */
+ void connectionCreated(KFormDesigner::Form *form, KFormDesigner::Connection &connection);
+
+ /*! Signal emitted when the Connection creation by drag-and-drop is aborted by user. */
+ void connectionAborted(KFormDesigner::Form *form);
+
+ /*! Signal emitted when "autoTabStops" is changed. */
+ void autoTabStopsSet(KFormDesigner::Form *form, bool set);
+
+ /*! Signal emitted before the form gets finally deleted. \a form is still a valid pointer,
+ but the widgets inside the form are in unknown state. */
+ void aboutToDeleteForm(KFormDesigner::Form *form);
+
+ /*! Signal emitted when new form gets created. */
+ void formCreated(KFormDesigner::Form *form);
+
+ protected slots:
+ void deleteWidgetLaterTimeout();
+
+ /*! Slot called when a buddy is chosen in the buddy list. Sets the label buddy. */
+ void buddyChosen(int id);
+
+ /*! Slot called when the user chooses an item in signal (or slot) menu.
+ The \ref createdConnection() is updated, and the connection created
+ (for the signal menu). */
+ void menuSignalChosen(int id);
+
+ /*! Slot called when the user changes current style using combbox in toolbar or menu. */
+ void slotStyle();
+
+ void slotConnectionCreated(KFormDesigner::Form*, KFormDesigner::Connection&);
+
+ void slotSettingsChanged(int category);
+
+ protected:
+ /*! Inits the Form, adds it to m_forms, and conects slots. */
+ void initForm(Form *form);
+
+#if 0
+ /*! Default implementation just calls FormIO::loadFormFromDom().
+ Change this if you need to handle, eg. custom UI XML tags, as in Kexi's Form Designer. */
+ virtual bool loadFormFromDomInternal(Form *form, QWidget *container, QDomDocument &inBuf);
+
+ /*! Default implementation just calls FormIO::saveFormToString().
+ Change this if you need to handle, eg. custom UI XML tags, as in Kexi's Form Designer. */
+ virtual bool saveFormToStringInternal(Form *form, QString &dest, int indent = 0);
+#endif
+ /*! Function called by the "Lay out in..." menu items. It creates a layout from the
+ currently selected widgets (that must have the same parent).
+ Calls \ref CreateLayoutCommand. */
+ void createLayout(int layoutType);
+
+ /*! Function called by all other AlignWidgets*() function. Calls \ref AlignWidgetsCommand. */
+ void alignWidgets(int type);
+
+ void enableFormActions();
+ void disableWidgetActions();
+ void emitUndoEnabled(bool enabled, const QString &text);
+ void emitRedoEnabled(bool enabled, const QString &text);
+
+ /*! True if emitSelectionSignals() updates property set so showPropertySet() will
+ not be needed in windowChanged(). False by default. Set to true in KexiFormManager. */
+ bool m_emitSelectionSignalsUpdatesPropertySet : 1;
+
+ private:
+ static FormManager* _self;
+
+ //! Enum for menu items indexes
+ enum { MenuTitle = 200, MenuCopy, MenuCut, MenuPaste, MenuDelete, MenuHBox = 301,
+ MenuVBox, MenuGrid, MenuHSplitter, MenuVSplitter, MenuNoBuddy = 501 };
+
+ WidgetPropertySet *m_propSet;
+// WidgetLibrary *m_lib;
+ QGuardedPtr<KoProperty::Editor> m_editor;
+ QGuardedPtr<ObjectTreeView> m_treeview;
+ // Forms
+ QPtrList<Form> m_forms;
+ QPtrList<Form> m_preview;
+ QGuardedPtr<Form> m_active;
+
+ // Copy/Paste
+ QDomDocument m_domDoc;
+ KPopupMenu *m_popup;
+ QPoint m_insertPoint;
+ QGuardedPtr<QWidget> m_menuWidget;
+
+ // Insertion
+ bool m_inserting;
+ QCString m_selectedClass;
+
+ // Connection stuff
+ bool m_drawingSlot;
+ Connection *m_connection;
+ KPopupMenu *m_sigSlotMenu;
+
+ // Actions
+ KActionCollection *m_collection;
+ KToggleAction *m_pointer, *m_dragConnection, *m_snapToGrid;
+
+ //! Used to delayed widgets deletion
+ QTimer m_deleteWidgetLater_timer;
+ QPtrList<QWidget> m_deleteWidgetLater_list;
+
+#ifdef KEXI_DEBUG_GUI
+ KDialogBase *m_uiCodeDialog;
+ KTextEdit *m_currentUICodeDialogEditor;
+ KTextEdit *m_originalUICodeDialogEditor;
+#endif
+
+ int m_options; //!< @see Options enum
+ int m_contextMenuKey; //!< Id of context menu key (cached)
+
+ void *m_objectBlockingPropertyEditorUpdating;
+ bool m_isRedoing : 1;
+
+ friend class PropertyCommand;
+ friend class GeometryPropertyCommand;
+ friend class CutWidgetCommand;
+ friend class Form;
+};
+
+}
+
+#endif
diff --git a/kexi/formeditor/kdevelop_plugin/Makefile.am b/kexi/formeditor/kdevelop_plugin/Makefile.am
new file mode 100644
index 00000000..62507e9c
--- /dev/null
+++ b/kexi/formeditor/kdevelop_plugin/Makefile.am
@@ -0,0 +1,21 @@
+include $(top_srcdir)/kexi/Makefile.global
+
+INCLUDES = -I$(top_srcdir)/kexi/formeditor -I$(top_srcdir)/kexi/core $(all_includes)
+METASOURCES = AUTO
+
+# KFormDesigner KDevelop plugin
+kde_module_LTLIBRARIES = libkformdesigner_kdev_part.la
+
+libkformdesigner_kdev_part_la_SOURCES = kfd_kdev_part.cpp
+libkformdesigner_kdev_part_la_LDFLAGS = -module $(KDE_PLUGIN) $(VER_INFO) $(all_libraries)
+libkformdesigner_kdev_part_la_LIBADD = $(top_builddir)/kexi/formeditor/libkformdesigner.la \
+ -lkinterfacedesigner $(LIB_KFILE)
+
+# this is where the desktop file will go
+partdesktopdir = $(kde_servicesdir)
+partdesktop_DATA = kformdesigner_kdev_part.desktop
+
+# this is where the part's XML-GUI resource file goes
+partrcdir = $(kde_datadir)/kformdesigner_kdev_part
+partrc_DATA = kformdesigner_part.rc kformdesigner_part_shell.rc
+
diff --git a/kexi/formeditor/kdevelop_plugin/kfd_kdev_part.cpp b/kexi/formeditor/kdevelop_plugin/kfd_kdev_part.cpp
new file mode 100644
index 00000000..c3b6e448
--- /dev/null
+++ b/kexi/formeditor/kdevelop_plugin/kfd_kdev_part.cpp
@@ -0,0 +1,694 @@
+/* This file is part of the KDE project
+ Copyright (C) 2004 Cedric Pasteur <cedric.pasteur@free.fr>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+*/
+
+#include <qworkspace.h>
+#include <qdockarea.h>
+#include <qdockwindow.h>
+#include <qhbox.h>
+#include <qpainter.h>
+#include <qevent.h>
+#include <qobjectlist.h>
+
+#include <kdeversion.h>
+#include <kaction.h>
+#include <kinstance.h>
+#include <klocale.h>
+#include <kaboutdata.h>
+#include <kdebug.h>
+#include <kstdaction.h>
+#include <kapplication.h>
+#include <kiconloader.h>
+#include <kfiledialog.h>
+#include <klibloader.h>
+#include <kmessagebox.h>
+
+#include "form.h"
+#include "formIO.h"
+#include "objecttree.h"
+#include "container.h"
+#include "formmanager.h"
+#include "objecttreeview.h"
+
+#include "kfd_kdev_part.h"
+
+#define ENABLE_ACTION(name, enable) \
+ if(actionCollection()->action( name )) \
+ actionCollection()->action( name )->setEnabled( enable )
+
+KInstance *KFDFactory::m_instance = 0L;
+
+KFDFactory::KFDFactory()
+: KParts::Factory(0, "libkformdesigner_kdev_part")
+{}
+
+KFDFactory::~KFDFactory()
+{
+ if (m_instance)
+ {
+ delete m_instance->aboutData();
+ delete m_instance;
+ }
+
+ m_instance = 0;
+}
+
+KParts::Part*
+KFDFactory::createPartObject( QWidget *parentWidget, const char *, QObject *, const char *name,
+ const char *classname, const QStringList &args)
+{
+ bool readOnly = (classname == "KParts::ReadOnlyPart");
+ KFormDesignerKDevPart *part = new KFormDesignerKDevPart(parentWidget, name, readOnly, args);
+ return part;
+}
+
+KInstance*
+KFDFactory::instance()
+{
+ if (!m_instance)
+ m_instance = new KInstance(aboutData());
+ return m_instance;
+}
+
+KAboutData*
+KFDFactory::aboutData()
+{
+ KAboutData *about = new KAboutData("kformdesigner_kdev_part", I18N_NOOP("Form Designer Part"), "0.3");
+ return about;
+}
+
+// copied from kfd_part.cpp
+class KFDPart_FormManager : public KFormDesigner::FormManager
+{
+ public:
+ /*! Constructs FormManager object.
+ See WidgetLibrary's constructor documentation for information about
+ \a supportedFactoryGroups parameter.
+ Using \a options you can control manager's behaviour, see \ref Options. */
+ KFDPart_FormManager(KFormDesignerPart *part, int options = 0, const char *name = 0)
+ : KFormDesigner::FormManager(part, options, name)
+ , m_part(part)
+ {
+ }
+
+ virtual KAction* action( const char* name)
+ {
+ return m_part->actionCollection()->action( name );
+ }
+
+ virtual void enableAction( const char* name, bool enable ) {
+ if(m_part->actionCollection()->action( name ))
+ m_part->actionCollection()->action( name )->setEnabled( enable );
+ }
+
+ KFormDesignerPart *m_part;
+};
+
+//////////////
+
+KFormDesigner::WidgetLibrary* KFormDesignerKDevPart::static_formsLibrary = 0L;
+
+KFormDesignerKDevPart::KFormDesignerKDevPart(QWidget *parent, const char *name, bool readOnly, const QStringList &args)
+: Designer(parent, name), m_count(0)
+{
+ setInstance(KFDFactory::instance());
+ instance()->iconLoader()->addAppDir("kexi");
+ instance()->iconLoader()->addAppDir("kformdesigner");
+
+ setReadWrite(!readOnly);
+ m_uniqueFormMode = true;
+ m_openingFile = false;
+
+ if(!args.grep("multipleMode").isEmpty())
+ setUniqueFormMode(false);
+ m_inShell = (!args.grep("shell").isEmpty());
+
+ QHBox *container = new QHBox(parent, "kfd_container_widget");
+ container->setFocusPolicy(QWidget::ClickFocus);
+
+ m_workspace = new QWorkspace(container, "kfd_workspace");
+ m_workspace->show();
+ QStringList supportedFactoryGroups;
+/* @todo add configuration for supported factory groups */
+ static_formsLibrary = KFormDesigner::FormManager::createWidgetLibrary(
+ new KFDPart_FormManager(this, 0, "kfd_manager"), supportedFactoryGroups );
+
+ if(!readOnly)
+ {
+ QDockArea *dockArea = new QDockArea(Vertical, QDockArea::Reverse, container, "kfd_part_dockarea");
+
+ QDockWindow *dockTree = new QDockWindow(dockArea);
+ KFormDesigner::ObjectTreeView *view = new KFormDesigner::ObjectTreeView(dockTree);
+ dockTree->setWidget(view);
+ dockTree->setCaption(i18n("Objects"));
+ dockTree->setResizeEnabled(true);
+ dockTree->setFixedExtentWidth(256);
+
+ QDockWindow *dockEditor = new QDockWindow(dockArea);
+ KoProperty::Editor *editor = new KoProperty::Editor(dockEditor);
+ dockEditor->setWidget(editor);
+ dockEditor->setCaption(i18n("Properties"));
+ dockEditor->setResizeEnabled(true);
+
+ KFormDesigner::FormManager::self()->setEditor(editor);
+ KFormDesigner::FormManager::self()->setObjectTreeView(view);
+
+ setupActions();
+ setModified(false);
+
+ // action stuff
+ connect(KFormDesigner::FormManager::self(), SIGNAL(widgetSelected(KFormDesigner::Form*, bool)), SLOT(slotWidgetSelected(KFormDesigner::Form*, bool)));
+ connect(KFormDesigner::FormManager::self(), SIGNAL(formWidgetSelected(KFormDesigner::Form*)), SLOT(slotFormWidgetSelected(KFormDesigner::Form*)));
+ connect(KFormDesigner::FormManager::self(), SIGNAL(noFormSelected()), SLOT(slotNoFormSelected()));
+ connect(KFormDesigner::FormManager::self(), SIGNAL(undoEnabled(bool, const QString&)), SLOT(setUndoEnabled(bool, const QString&)));
+ connect(KFormDesigner::FormManager::self(), SIGNAL(redoEnabled(bool, const QString&)), SLOT(setRedoEnabled(bool, const QString&)));
+
+ connect(KFormDesigner::FormManager::self(), SIGNAL(dirty(KFormDesigner::Form*, bool)), this, SLOT(slotFormModified(KFormDesigner::Form*, bool)));
+
+ connect(KFormDesigner::FormManager::self(), SIGNAL(createFormSlot(KFormDesigner::Form*, const QString&, const QString&)),
+ this, SLOT(slotCreateFormSlot(KFormDesigner::Form*, const QString&, const QString &)));
+ }
+
+ container->show();
+ setWidget(container);
+ connect(m_workspace, SIGNAL(windowActivated(QWidget*)), KFormDesigner::FormManager::self(), SLOT(windowChanged(QWidget*)));
+ slotNoFormSelected();
+}
+
+KFormDesigner::WidgetLibrary* KFormDesignerKDevPart::formsLibrary()
+{
+ return static_formsLibrary;
+}
+
+void
+KFormDesignerKDevPart::setupActions()
+{
+ KStdAction::open(this, SLOT(open()), actionCollection());
+ KStdAction::openNew(this, SLOT(createBlankForm()), actionCollection());
+ KStdAction::save(this, SLOT(save()), actionCollection());
+ KStdAction::saveAs(this, SLOT(saveAs()), actionCollection());
+ KStdAction::cut(KFormDesigner::FormManager::self(), SLOT(cutWidget()), actionCollection());
+ KStdAction::copy(KFormDesigner::FormManager::self(), SLOT(copyWidget()), actionCollection());
+ KStdAction::paste(KFormDesigner::FormManager::self(), SLOT(pasteWidget()), actionCollection());
+ KStdAction::undo(KFormDesigner::FormManager::self(), SLOT(undo()), actionCollection());
+ KStdAction::redo(KFormDesigner::FormManager::self(), SLOT(redo()), actionCollection());
+ KStdAction::selectAll(KFormDesigner::FormManager::self(), SLOT(selectAll()), actionCollection());
+ new KAction(i18n("Clear Widget Contents"), "editclear", KShortcut(0), KFormDesigner::FormManager::self(), SLOT(clearWidgetContent()), actionCollection(), "clear_contents");
+ new KAction(i18n("Delete Widget"), "editdelete", KShortcut(0), KFormDesigner::FormManager::self(), SLOT(deleteWidget()), actionCollection(), "edit_delete");
+ new KAction(i18n("Preview Form"), "filequickprint", "Ctrl+T", this, SLOT(slotPreviewForm()), actionCollection(), "preview_form");
+ new KAction(i18n("Edit Tab Order"), "tab_order", KShortcut(0), KFormDesigner::FormManager::self(), SLOT(editTabOrder()), actionCollection(), "taborder");
+ new KAction(i18n("Edit Pixmap Collection"), "icons", KShortcut(0), KFormDesigner::FormManager::self(), SLOT(editFormPixmapCollection()), actionCollection(), "pixmap_collection");
+ new KAction(i18n("Edit Form Connections"), "connections", KShortcut(0), KFormDesigner::FormManager::self(), SLOT(editConnections()), actionCollection(), "form_connections");
+
+ new KAction(i18n("Lay Out Widgets &Horizontally"), QString::null, KShortcut(0), KFormDesigner::FormManager::self(), SLOT(layoutHBox()), actionCollection(), "layout_hbox");
+ new KAction(i18n("Lay Out Widgets &Vertically"), QString::null, KShortcut(0), KFormDesigner::FormManager::self(), SLOT(layoutVBox()), actionCollection(), "layout_vbox");
+ new KAction(i18n("Lay Out Widgets in &Grid"), QString::null, KShortcut(0), KFormDesigner::FormManager::self(), SLOT(layoutGrid()), actionCollection(), "layout_grid");
+ new KAction(i18n("&Break Layout"), QString::null, KShortcut(0), KFormDesigner::FormManager::self(), SLOT(breakLayout()), actionCollection(), "break_layout");
+
+ new KAction(i18n("Bring Widget to Front"), "raise", KShortcut(0), KFormDesigner::FormManager::self(), SLOT(bringWidgetToFront()), actionCollection(), "format_raise");
+ new KAction(i18n("Send Widget to Back"), "lower", KShortcut(0), KFormDesigner::FormManager::self(), SLOT(sendWidgetToBack()), actionCollection(), "format_lower");
+
+ KActionMenu *alignMenu = new KActionMenu(i18n("Align Widgets' Positions"), "aopos2grid", actionCollection(), "align_menu");
+ alignMenu->insert( new KAction(i18n("To Left"), "aoleft", KShortcut(0), KFormDesigner::FormManager::self(), SLOT(alignWidgetsToLeft()), actionCollection(), "align_to_left") );
+ alignMenu->insert( new KAction(i18n("To Right"), "aoright", KShortcut(0), KFormDesigner::FormManager::self(), SLOT(alignWidgetsToRight()), actionCollection(), "align_to_right") );
+ alignMenu->insert( new KAction(i18n("To Top"), "aotop", KShortcut(0), KFormDesigner::FormManager::self(), SLOT(alignWidgetsToTop()), actionCollection(), "align_to_top") );
+ alignMenu->insert( new KAction(i18n("To Bottom"), "aobottom", KShortcut(0), KFormDesigner::FormManager::self(), SLOT(alignWidgetsToBottom()), actionCollection(), "align_to_bottom") );
+ alignMenu->insert( new KAction(i18n("To Grid"), "aopos2grid", KShortcut(0), KFormDesigner::FormManager::self(), SLOT(alignWidgetsToGrid()), actionCollection(), "align_to_grid") );
+
+ KActionMenu *sizeMenu = new KActionMenu(i18n("Adjust Widgets' Sizes"), "aogrid", actionCollection(), "adjust_size_menu");
+ sizeMenu->insert( new KAction(i18n("To Fit"), "aofit", KShortcut(0), KFormDesigner::FormManager::self(), SLOT(adjustWidgetSize()), actionCollection(), "adjust_to_fit") );
+ sizeMenu->insert( new KAction(i18n("To Grid"), "aogrid", KShortcut(0), KFormDesigner::FormManager::self(), SLOT(adjustSizeToGrid()), actionCollection(), "adjust_size_grid") );
+ sizeMenu->insert( new KAction(i18n("To Shortest"), "aoshortest", KShortcut(0), KFormDesigner::FormManager::self(), SLOT(adjustHeightToSmall()), actionCollection(), "adjust_height_small") );
+ sizeMenu->insert( new KAction(i18n("To Tallest"), "aotallest", KShortcut(0), KFormDesigner::FormManager::self(), SLOT(adjustHeightToBig()), actionCollection(), "adjust_height_big") );
+ sizeMenu->insert( new KAction(i18n("To Narrowest"), "aonarrowest", KShortcut(0), KFormDesigner::FormManager::self(), SLOT(adjustWidthToSmall()), actionCollection(), "adjust_width_small") );
+ sizeMenu->insert( new KAction(i18n("To Widest"), "aowidest", KShortcut(0), KFormDesigner::FormManager::self(), SLOT(adjustWidthToBig()), actionCollection(), "adjust_width_big") );
+
+ if(m_inShell)
+ setXMLFile("kformdesigner_part_shell.rc");
+ else
+ setXMLFile("kformdesigner_part.rc");
+ KFormDesigner::FormManager::self()->createActions(formsLibrary(), actionCollection(), this);
+}
+
+void
+KFormDesignerKDevPart::createBlankForm()
+{
+ if(KFormDesigner::FormManager::self()->activeForm() && m_uniqueFormMode)
+ {
+ m_openingFile = true;
+ closeURL();
+ m_openingFile = false;
+ }
+
+ if(m_uniqueFormMode && KFormDesigner::FormManager::self()->activeForm() && !KFormDesigner::FormManager::self()->activeForm()->isModified() && KFormDesigner::FormManager::self()->activeForm()->filename().isNull())
+ return; // active form is already a blank one
+
+ QString n = i18n("Form") + QString::number(++m_count);
+ Form *form = new Form(formsLibrary(), n.latin1());
+ FormWidgetBase *w = new FormWidgetBase(this, m_workspace, n.latin1());
+
+ w->setCaption(n);
+ w->setIcon(SmallIcon("form"));
+ w->resize(350, 300);
+ w->show();
+ w->setFocus();
+
+ form->createToplevel(w, w);
+ KFormDesigner::FormManager::self()->importForm(form);
+}
+
+void
+KFormDesignerKDevPart::open()
+{
+ m_openingFile = true;
+ KURL url = KFileDialog::getOpenURL("::kformdesigner", i18n("*.ui|Qt Designer UI Files"), m_workspace->topLevelWidget());
+ if(!url.isEmpty())
+ ReadWritePart::openURL(url);
+ m_openingFile = false;
+}
+
+bool
+KFormDesignerKDevPart::openFile()
+{
+ Form *form = new Form(formsLibrary());
+ FormWidgetBase *w = new FormWidgetBase(this, m_workspace);
+ form->createToplevel(w, w);
+
+ if(!KFormDesigner::FormIO::loadForm(form, w, m_file))
+ {
+ delete form;
+ delete w;
+ return false;
+ }
+
+ w->show();
+ KFormDesigner::FormManager::self()->importForm(form, !isReadWrite());
+ return true;
+}
+
+bool
+KFormDesignerKDevPart::saveFile()
+{
+ KFormDesigner::FormIO::saveForm(KFormDesigner::FormManager::self()->activeForm(), m_file);
+ return true;
+}
+
+void
+KFormDesignerKDevPart::saveAs()
+{
+ KURL url = KFileDialog::getSaveURL("::kformdesigner", i18n("*.ui|Qt Designer UI Files"), m_workspace);
+ if(url.isEmpty())
+ return;
+ else
+ ReadWritePart::saveAs(url);
+}
+
+bool
+KFormDesignerKDevPart::closeForm(Form *form)
+{
+ int res = KMessageBox::warningYesNoCancel( m_workspace->topLevelWidget(),
+ i18n( "The form \"%1\" has been modified.\n"
+ "Do you want to save your changes or discard them?" ).arg( form->objectTree()->name() ),
+ i18n( "Close Form" ), KStdGuiItem::save(), KStdGuiItem::discard() );
+
+ if(res == KMessageBox::Yes)
+ save();
+
+ return (res != KMessageBox::Cancel);
+}
+
+bool
+KFormDesignerKDevPart::closeForms()
+{
+ QWidgetList list = m_workspace->windowList(QWorkspace::CreationOrder);
+ for(QWidget *w = list.first(); w; w = list.next())
+ if(w->close() == false)
+ return false;
+
+ return true;
+}
+
+bool
+KFormDesignerKDevPart::closeURL()
+{
+ if(!KFormDesigner::FormManager::self()->activeForm())
+ return true;
+
+ if(m_uniqueFormMode || !m_openingFile)
+ return closeForms();
+
+ return true;
+}
+
+void
+KFormDesignerKDevPart::slotFormModified(Form *, bool isDirty)
+{
+ setModified(isDirty);
+}
+
+void
+KFormDesignerKDevPart::slotPreviewForm()
+{
+ if(!KFormDesigner::FormManager::self()->activeForm())
+ return;
+
+ FormWidgetBase *w = new FormWidgetBase(this, m_workspace);
+ KFormDesigner::FormManager::self()->previewForm(KFormDesigner::FormManager::self()->activeForm(), w);
+}
+
+void
+KFormDesignerKDevPart::slotWidgetSelected(Form *form, bool multiple)
+{
+ enableFormActions();
+ // Enable edit actions
+ ENABLE_ACTION("edit_copy", true);
+ ENABLE_ACTION("edit_cut", true);
+ ENABLE_ACTION("edit_delete", true);
+ ENABLE_ACTION("clear_contents", true);
+
+ // 'Align Widgets' menu
+ ENABLE_ACTION("align_menu", multiple);
+ ENABLE_ACTION("align_to_left", multiple);
+ ENABLE_ACTION("align_to_right", multiple);
+ ENABLE_ACTION("align_to_top", multiple);
+ ENABLE_ACTION("align_to_bottom", multiple);
+
+ ENABLE_ACTION("adjust_size_menu", true);
+ ENABLE_ACTION("adjust_width_small", multiple);
+ ENABLE_ACTION("adjust_width_big", multiple);
+ ENABLE_ACTION("adjust_height_small", multiple);
+ ENABLE_ACTION("adjust_height_big", multiple);
+
+ ENABLE_ACTION("format_raise", true);
+ ENABLE_ACTION("format_lower", true);
+
+ // If the widgets selected is a container, we enable layout actions
+ if(!multiple)
+ {
+ KFormDesigner::ObjectTreeItem *item = form->objectTree()->lookup( form->selectedWidgets()->first()->name() );
+ if(item && item->container())
+ multiple = true;
+ }
+ // Layout actions
+ ENABLE_ACTION("layout_hbox", multiple);
+ ENABLE_ACTION("layout_vbox", multiple);
+ ENABLE_ACTION("layout_grid", multiple);
+
+ KFormDesigner::Container *container = KFormDesigner::FormManager::self()->activeForm()->activeContainer();
+ ENABLE_ACTION("break_layout", (container->layoutType() != KFormDesigner::Container::NoLayout));
+}
+
+void
+KFormDesignerKDevPart::slotFormWidgetSelected(Form *form)
+{
+ disableWidgetActions();
+ enableFormActions();
+
+ // Layout actions
+ ENABLE_ACTION("layout_hbox", true);
+ ENABLE_ACTION("layout_vbox", true);
+ ENABLE_ACTION("layout_grid", true);
+ ENABLE_ACTION("break_layout", (form->toplevelContainer()->layoutType() != KFormDesigner::Container::NoLayout));
+}
+
+void
+KFormDesignerKDevPart::slotNoFormSelected()
+{
+ disableWidgetActions();
+
+ // Disable paste action
+ ENABLE_ACTION("edit_paste", false);
+
+ ENABLE_ACTION("edit_undo", false);
+ ENABLE_ACTION("edit_redo", false);
+
+ // Disable 'Tools' actions
+ ENABLE_ACTION("pixmap_collection", false);
+ ENABLE_ACTION("form_connections", false);
+ ENABLE_ACTION("taborder", false);
+ ENABLE_ACTION("change_style", false);
+
+ // Disable items in 'File'
+ ENABLE_ACTION("file_save", false);
+ ENABLE_ACTION("file_save_as", false);
+ ENABLE_ACTION("preview_form", false);
+}
+
+void
+KFormDesignerKDevPart::enableFormActions()
+{
+ // Enable 'Tools' actions
+ ENABLE_ACTION("pixmap_collection", true);
+ ENABLE_ACTION("form_connections", true);
+ ENABLE_ACTION("taborder", true);
+ ENABLE_ACTION("change_style", true);
+
+ // Enable items in 'File'
+ ENABLE_ACTION("file_save", true);
+ ENABLE_ACTION("file_save_as", true);
+ ENABLE_ACTION("preview_form", true);
+
+ ENABLE_ACTION("edit_paste", KFormDesigner::FormManager::self()->isPasteEnabled());
+ ENABLE_ACTION("edit_select_all", true);
+}
+
+void
+KFormDesignerKDevPart::disableWidgetActions()
+{
+ // Disable edit actions
+ ENABLE_ACTION("edit_copy", false);
+ ENABLE_ACTION("edit_cut", false);
+ ENABLE_ACTION("edit_delete", false);
+ ENABLE_ACTION("clear_contents", false);
+
+ // Disable format functions
+ ENABLE_ACTION("align_menu", false);
+ ENABLE_ACTION("align_to_left", false);
+ ENABLE_ACTION("align_to_right", false);
+ ENABLE_ACTION("align_to_top", false);
+ ENABLE_ACTION("align_to_bottom", false);
+ ENABLE_ACTION("adjust_size_menu", false);
+ ENABLE_ACTION("format_raise", false);
+ ENABLE_ACTION("format_lower", false);
+
+ ENABLE_ACTION("layout_hbox", false);
+ ENABLE_ACTION("layout_vbox", false);
+ ENABLE_ACTION("layout_grid", false);
+ ENABLE_ACTION("break_layout", false);
+}
+
+void
+KFormDesignerKDevPart::setUndoEnabled(bool enabled, const QString &text)
+{
+ KAction *undoAction = actionCollection()->action("edit_undo");
+ if(undoAction)
+ {
+ undoAction->setEnabled(enabled);
+ if(!text.isNull())
+ undoAction->setText(text);
+ }
+}
+
+void
+KFormDesignerKDevPart::setRedoEnabled(bool enabled, const QString &text)
+{
+ KAction *redoAction = actionCollection()->action("edit_redo");
+ if(redoAction)
+ {
+ redoAction->setEnabled(enabled);
+ if(!text.isNull())
+ redoAction->setText(text);
+ }
+}
+
+void
+KFormDesignerKDevPart::slotCreateFormSlot(Form *form, const QString &widget, const QString &signal)
+{
+ Function f;
+ f.returnType = "void";
+ f.function = widget + "_" + signal;
+ f.specifier = "non virtual";
+ f.access = "public";
+ f.type = ftQtSlot;
+ emit addedFunction(designerType(), form->objectTree()->name(), f);
+}
+
+KFormDesignerKDevPart::~KFormDesignerKDevPart()
+{
+}
+
+
+////// FormWidgetBase : helper widget to draw rects on top of widgets
+
+//repaint all children widgets
+static void repaintAll(QWidget *w)
+{
+ QObjectList *list = w->queryList("QWidget");
+ QObjectListIt it(*list);
+ for (QObject *obj; (obj=it.current()); ++it ) {
+ static_cast<QWidget*>(obj)->repaint();
+ }
+ delete list;
+}
+
+void
+FormWidgetBase::drawRects(const QValueList<QRect> &list, int type)
+{
+ QPainter p;
+ p.begin(this, true);
+ bool unclipped = testWFlags( WPaintUnclipped );
+ setWFlags( WPaintUnclipped );
+
+ if (prev_rect.isValid()) {
+ //redraw prev. selection's rectangle
+ p.drawPixmap( QPoint(prev_rect.x()-2, prev_rect.y()-2), buffer, QRect(prev_rect.x()-2, prev_rect.y()-2, prev_rect.width()+4, prev_rect.height()+4));
+ }
+ p.setBrush(QBrush::NoBrush);
+ if(type == 1) // selection rect
+ p.setPen(QPen(white, 1, Qt::DotLine));
+ else if(type == 2) // insert rect
+ p.setPen(QPen(white, 2));
+ p.setRasterOp(XorROP);
+
+ prev_rect = QRect();
+ QValueList<QRect>::ConstIterator endIt = list.constEnd();
+ for(QValueList<QRect>::ConstIterator it = list.constBegin(); it != endIt; ++it) {
+ p.drawRect(*it);
+ prev_rect = prev_rect.unite(*it);
+ }
+
+ if (!unclipped)
+ clearWFlags( WPaintUnclipped );
+ p.end();
+}
+
+void
+FormWidgetBase::drawRect(const QRect& r, int type)
+{
+ QValueList<QRect> l;
+ l.append(r);
+ drawRects(l, type);
+}
+
+void
+FormWidgetBase::initRect()
+{
+ repaintAll(this);
+ buffer.resize( width(), height() );
+ buffer = QPixmap::grabWindow( winId() );
+ prev_rect = QRect();
+}
+
+void
+FormWidgetBase::clearRect()
+{
+ QPainter p;
+ p.begin(this, true);
+ bool unclipped = testWFlags( WPaintUnclipped );
+ setWFlags( WPaintUnclipped );
+
+ //redraw entire form surface
+ p.drawPixmap( QPoint(0,0), buffer, QRect(0,0,buffer.width(), buffer.height()) );
+
+ if (!unclipped)
+ clearWFlags( WPaintUnclipped );
+ p.end();
+
+ repaintAll(this);
+}
+
+void
+FormWidgetBase::highlightWidgets(QWidget *from, QWidget *to)//, const QPoint &point)
+{
+ QPoint fromPoint, toPoint;
+ if(from && from->parentWidget() && (from != this))
+ fromPoint = from->parentWidget()->mapTo(this, from->pos());
+ if(to && to->parentWidget() && (to != this))
+ toPoint = to->parentWidget()->mapTo(this, to->pos());
+
+ QPainter p;
+ p.begin(this, true);
+ bool unclipped = testWFlags( WPaintUnclipped );
+ setWFlags( WPaintUnclipped );
+
+ if (prev_rect.isValid()) {
+ //redraw prev. selection's rectangle
+ p.drawPixmap( QPoint(prev_rect.x(), prev_rect.y()), buffer, QRect(prev_rect.x(), prev_rect.y(), prev_rect.width(), prev_rect.height()));
+ }
+
+ p.setPen( QPen(Qt::red, 2) );
+
+ if(to)
+ {
+ QPixmap pix1 = QPixmap::grabWidget(from);
+ QPixmap pix2 = QPixmap::grabWidget(to);
+
+ if((from != this) && (to != this))
+ p.drawLine( from->parentWidget()->mapTo(this, from->geometry().center()), to->parentWidget()->mapTo(this, to->geometry().center()) );
+
+ p.drawPixmap(fromPoint.x(), fromPoint.y(), pix1);
+ p.drawPixmap(toPoint.x(), toPoint.y(), pix2);
+
+ if(to == this)
+ p.drawRoundRect(2, 2, width()-4, height()-4, 4, 4);
+ else
+ p.drawRoundRect(toPoint.x(), toPoint.y(), to->width(), to->height(), 5, 5);
+ }
+
+ if(from == this)
+ p.drawRoundRect(2, 2, width()-4, height()-4, 4, 4);
+ else
+ p.drawRoundRect(fromPoint.x(), fromPoint.y(), from->width(), from->height(), 5, 5);
+
+ if((to == this) || (from == this))
+ prev_rect = QRect(0, 0, buffer.width(), buffer.height());
+ else if(to)
+ {
+ prev_rect.setX( (fromPoint.x() < toPoint.x()) ? (fromPoint.x() - 5) : (toPoint.x() - 5) );
+ prev_rect.setY( (fromPoint.y() < toPoint.y()) ? (fromPoint.y() - 5) : (toPoint.y() - 5) );
+ prev_rect.setRight( (fromPoint.x() < toPoint.x()) ? (toPoint.x() + to->width() + 10) : (fromPoint.x() + from->width() + 10) );
+ prev_rect.setBottom( (fromPoint.y() < toPoint.y()) ? (toPoint.y() + to->height() + 10) : (fromPoint.y() + from->height() + 10) ) ;
+ }
+ else
+ prev_rect = QRect(fromPoint.x()- 5, fromPoint.y() -5, from->width() + 10, from->height() + 10);
+
+ if (!unclipped)
+ clearWFlags( WPaintUnclipped );
+ p.end();
+}
+
+void
+FormWidgetBase::closeEvent(QCloseEvent *ev)
+{
+ Form *form = KFormDesigner::FormManager::self()->formForWidget(this);
+ if(!form || !form->isModified() || !form->objectTree()) // == preview form
+ ev->accept();
+ else
+ {
+ bool close = m_part->closeForm(form);
+ if(close)
+ ev->accept();
+ else
+ ev->ignore();
+ }
+}
+
+K_EXPORT_COMPONENT_FACTORY(libkformdesigner_kdev_part, KFDFactory)
+
+#include "kfd_kdev_part.moc"
+
diff --git a/kexi/formeditor/kdevelop_plugin/kfd_kdev_part.h b/kexi/formeditor/kdevelop_plugin/kfd_kdev_part.h
new file mode 100644
index 00000000..52ce5f27
--- /dev/null
+++ b/kexi/formeditor/kdevelop_plugin/kfd_kdev_part.h
@@ -0,0 +1,139 @@
+/* This file is part of the KDE project
+ Copyright (C) 2004 Cedric Pasteur <cedric.pasteur@free.fr>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+*/
+
+#ifndef KFORMDESIGNER_KDEVELOP_PART_H
+#define KFORMDESIGNER_KDEVELOP_PART_H
+
+#include <qwidget.h>
+#include <qpixmap.h>
+
+#include <kinterfacedesigner/designer.h>
+#include <kparts/factory.h>
+
+#include "form.h"
+
+class KAboutData;
+class KInstance;
+class QWorkspace;
+class QCloseEvent;
+
+using KFormDesigner::Form;
+using namespace KInterfaceDesigner;
+
+class KFORMEDITOR_EXPORT KFDFactory : public KParts::Factory
+{
+ Q_OBJECT
+
+ public:
+ KFDFactory();
+ virtual ~KFDFactory();
+
+ virtual KParts::Part* createPartObject(QWidget *parentWidget=0, const char *widgetName=0, QObject *parent=0, const char *name=0,
+ const char *classname="KParts::Part", const QStringList &args=QStringList());
+
+ static KInstance *instance();
+ static KAboutData *aboutData();
+
+ private:
+ static KInstance *m_instance;
+};
+
+class KFORMEDITOR_EXPORT KFormDesignerKDevPart : public Designer
+{
+ Q_OBJECT
+
+ public:
+ KFormDesignerKDevPart(QWidget *parent, const char *name, bool readOnly=true, const QStringList &args=QStringList());
+ virtual ~KFormDesignerKDevPart();
+
+ virtual DesignerType designerType() { return QtDesigner; }
+ virtual void openProject(const QString &) {}
+
+// KFormDesigner::FormManager* manager() { return m_manager; }
+ void setUniqueFormMode(bool enable) { m_uniqueFormMode = enable; }
+
+ bool closeForm(Form *form);
+ bool closeForms();
+
+ virtual bool closeURL();
+
+ static KFormDesigner::WidgetLibrary* formsLibrary();
+
+ public slots:
+ /*! Creates a new blank Form. The new Form is shown and become the active Form. */
+ void createBlankForm();
+ /*! Loads a Form from a UI file. A "Open File" dialog is shown to select the file. The loaded Form is shown and becomes
+ the active Form. */
+ void open();
+ void slotPreviewForm();
+ void saveAs();
+ void slotCreateFormSlot(KFormDesigner::Form *form, const QString &widget, const QString &signal);
+
+ protected slots:
+ void slotWidgetSelected(KFormDesigner::Form *form, bool multiple);
+ void slotFormWidgetSelected(KFormDesigner::Form *form);
+ void slotNoFormSelected();
+ void slotFormModified(KFormDesigner::Form *form, bool isDirty);
+ void setUndoEnabled(bool enabled, const QString &text);
+ void setRedoEnabled(bool enabled, const QString &text);
+
+ protected:
+ virtual bool openFile();
+ virtual bool saveFile();
+ void disableWidgetActions();
+ void enableFormActions();
+ void setupActions();
+
+ private:
+ static KFormDesigner::WidgetLibrary* static_formsLibrary;
+// KFormDesigner::FormManager *m_manager;
+ QWorkspace *m_workspace;
+ int m_count;
+ bool m_uniqueFormMode;
+ bool m_openingFile;
+ bool m_inShell;
+};
+
+//! Helper: this widget is used to create form's surface
+class KFORMEDITOR_EXPORT FormWidgetBase : public QWidget, public KFormDesigner::FormWidget
+{
+ Q_OBJECT
+
+ public:
+ FormWidgetBase(KFormDesignerKDevPart *part, QWidget *parent = 0, const char *name = 0, int WFlags = WDestructiveClose)
+ : QWidget(parent, name, WFlags), m_part(part) {}
+ ~FormWidgetBase() {;}
+
+ void drawRect(const QRect& r, int type);
+ void drawRects(const QValueList<QRect> &list, int type);
+ void initRect();
+ void clearRect();
+ void highlightWidgets(QWidget *from, QWidget *to);//, const QPoint &p);
+
+ protected:
+ void closeEvent(QCloseEvent *ev);
+
+ private:
+ QPixmap buffer; //!< stores grabbed entire form's area for redraw
+ QRect prev_rect; //!< previously selected rectangle
+ KFormDesignerKDevPart *m_part;
+};
+
+#endif
+
diff --git a/kexi/formeditor/kdevelop_plugin/kformdesigner_kdev_part.desktop b/kexi/formeditor/kdevelop_plugin/kformdesigner_kdev_part.desktop
new file mode 100644
index 00000000..c94e628f
--- /dev/null
+++ b/kexi/formeditor/kdevelop_plugin/kformdesigner_kdev_part.desktop
@@ -0,0 +1,50 @@
+[Desktop Entry]
+Name=Form Designer KDevelop Plugin
+Name[bg]=Приставка на KDevelop за проектиране на форми
+Name[ca]=Endollat de disseny de formulari de KDevelop
+Name[cy]=Ategyn KDevelop: Dylunydd Ffurflenni
+Name[da]=Form Designer KDEvelop-plugin
+Name[de]=KDevelop-Modul zum Formularentwurf
+Name[el]=Πρόσθετο σχεδίασης φόρμας του KDevelop
+Name[eo]=Formulardesegnila kromaĵo por KDevelop
+Name[es]=Complemento de diseñador de formularios de KDevelop
+Name[et]=Vormikujundaja KDevelopi plugin
+Name[eu]=Formularioak diseinatzeko KDevelop-en plugina
+Name[fa]=وصلۀ KDevelop طراح برگه
+Name[fi]=KDevelopin lomakkeen suunnittelija -liitännäinen
+Name[fr]=Module externe KDevelop de composition d'interfaces graphiques
+Name[fy]=KDevelop-plugin FormDesigner
+Name[gl]=Plugin de Deseño de Formularios para Kdevelop
+Name[he]=תוסף מעצב טפסים ל־KDevelop
+Name[hr]=KDevelop dodatak dizajnera obrazaca
+Name[hu]=Űrlaptervező modul a KDevelophoz
+Name[is]=Form hönnunar KDevelop íforrit
+Name[it]=Plugin di KDevelop per il progetto dei moduli
+Name[ja]=フォームデザイナー Kdevelop プラグイン
+Name[km]=កម្មវិធី​ជំនួយ​កម្មវិធី​រចនា​សំណុំបែបបទ​សម្រាប់ KDevelop
+Name[lv]=KDevelop formu veidošanas spraudnis
+Name[ms]=Plugin KDevelop Pereka Bentuk Borang
+Name[nb]=KDevelop-tillegg for skjemautforming
+Name[nds]=KDevelop-Moduul för't Opstellen vun Kiekwarken
+Name[ne]=फारम डिजाइनकर्ता केडीई विकास प्लगइन
+Name[nl]=KDevelop-plugin FormDesigner
+Name[nn]=KDevelop-tillegg for skjemautforming
+Name[pl]=Wtyczka projektanta formularzy dla KDevelop
+Name[pt]='Plugin' para o KDevelop de Desenho de Formulários
+Name[pt_BR]=Plugin do Desenhista de Formulário do KDevelop
+Name[ru]=Модуль форм KDevelop
+Name[sk]=KDevelop modul na vytváranie formulárov (Form Designer)
+Name[sl]=Vstavek za oblikovanje obrazcev za KDevelop
+Name[sr]=Прикључак дизајнера форми за KDevelop
+Name[sr@Latn]=Priključak dizajnera formi za KDevelop
+Name[sv]=KDevelop insticksprogram för formulärkonstruktion
+Name[ta]=படிவ வடிவமைப்பாளர் கேடெவெலப் சொருகுப்பொருள்
+Name[tr]=FormTasarımcısı KDevelop Eklentisi
+Name[uk]=Втулок дизайнера форм KDevelop
+Name[zh_CN]=表单设计器 KDevelop 插件
+Name[zh_TW]=表單設計師 KDevelop 外掛程式
+MimeType=application/x-designer;
+ServiceTypes=KParts/ReadOnlyPart,KParts/ReadWritePart
+X-KDE-Library=libkformdesigner_kdev_part
+Type=Service
+InitialPreference=0
diff --git a/kexi/formeditor/kdevelop_plugin/kformdesigner_part.rc b/kexi/formeditor/kdevelop_plugin/kformdesigner_part.rc
new file mode 100644
index 00000000..3cadda53
--- /dev/null
+++ b/kexi/formeditor/kdevelop_plugin/kformdesigner_part.rc
@@ -0,0 +1,129 @@
+<!DOCTYPE kpartgui SYSTEM "kpartgui.dtd">
+<kpartgui name="kfd_part" version="1">
+
+<MenuBar>
+ <Menu name="edit" noMerge="1">
+ <Action name="edit_undo" group="edit_undo_merge"/>
+ <Action name="edit_redo" group="edit_undo_merge"/>
+ <Separator group="edit_undo_merge"/>
+ <Action name="edit_cut" group="edit_paste_merge"/>
+ <Action name="edit_copy" group="edit_paste_merge"/>
+ <Action name="edit_paste" group="edit_paste_merge"/>
+ <Action name="delete_widget" group="edit_paste_merge"/>
+ <Action name="clear_contents" group="edit_paste_merge"/>
+ <Action name="edit_select_all" group="edit_select_merge"/>
+ <Separator group="edit_paste_merge"/>
+ </Menu>
+ <Menu name="tools" noMerge="1">
+ <Merge/>
+ <Separator/>
+ <Action name="taborder"/>
+ <Action name="change_style"/>
+ <Action name="pixmap_collection"/>
+ <Action name="form_connections"/>
+ </Menu>
+ <Menu name="widgets" noMerge="1">
+ <text>&amp;Widgets</text>
+ <Merge/>
+ <Action name="pointer"/>
+ <Action name="drag_connection"/>
+ <Separator/>
+ <Action name="library_widget_SubForm"/>
+ <Action name="library_widget_QGroupBox"/>
+ <Action name="library_widget_MyTabWidget"/>
+ <Action name="library_widget_QWidgetStack"/>
+ <Action name="library_widget_QFrame"/>
+ <Separator/>
+ <Action name="library_widget_KLineEdit"/>
+ <Action name="library_widget_QLabel"/>
+ <Action name="library_widget_KexiPictureLabel"/>
+ <Action name="library_widget_KPushButton"/>
+ <Action name="library_widget_QRadioButton"/>
+ <Action name="library_widget_QCheckBox"/>
+ <Action name="library_widget_KIntSpinBox"/>
+ <Action name="library_widget_KComboBox"/>
+ <Action name="library_widget_KListBox"/>
+ <Action name="library_widget_KTextEdit"/>
+ <Action name="library_widget_KListView"/>
+ <Action name="library_widget_QSlider"/>
+ <Action name="library_widget_KProgress"/>
+ <Action name="library_widget_KTimeWidget"/>
+ <Action name="library_widget_KDateWidget"/>
+ <Action name="library_widget_KDateTimeWidget"/>
+ <Action name="library_widget_Line"/>
+ <Action name="library_widget_Spring"/>
+ </Menu>
+ <Menu name="format" noMerge="1">
+ <text>&amp;Format</text>
+ <Action name="snap_to_grid"/>
+ <Separator/>
+ <Action name="layout_hbox"/>
+ <Action name="layout_vbox"/>
+ <Action name="layout_grid"/>
+ <Action name="break_layout"/>
+ <Separator/>
+ <Action name="align_menu"/>
+ <Action name="adjust_size_menu"/>
+ <Separator/>
+ <Action name="format_raise"/>
+ <Action name="format_lower"/>
+ </Menu>
+</MenuBar>
+
+<ToolBar name="fileToolBar" noMerge="1"><text>Main Toolbar</text>
+ <Action name="preview_form"/>
+ <Separator/>
+ <Action name="edit_undo"/>
+ <Action name="edit_redo"/>
+ <Separator/>
+ <Action name="edit_cut"/>
+ <Action name="edit_copy"/>
+ <Action name="edit_paste"/>
+ <Action name="delete_widget"/>
+ <Action name="clear_contents"/>
+</ToolBar>
+<ToolBar name="containers" fullWidth="false" noMerge="1">
+ <text>Containers</text>
+ <Action name="library_widget_SubForm"/>
+ <Action name="library_widget_QGroupBox"/>
+ <Action name="library_widget_MyTabWidget"/>
+ <Action name="library_widget_QWidgetStack"/>
+ <Action name="library_widget_QFrame"/>
+</ToolBar>
+<ToolBar name="widgets" fullWidth="false" noMerge="1">
+ <text>Widgets</text>
+ <Action name="pointer"/>
+ <Action name="drag_connection"/>
+ <Separator/>
+ <Action name="library_widget_KLineEdit"/>
+ <Action name="library_widget_QLabel"/>
+ <Action name="library_widget_KexiPictureLabel"/>
+ <Action name="library_widget_KPushButton"/>
+ <Action name="library_widget_QRadioButton"/>
+ <Action name="library_widget_QCheckBox"/>
+ <Action name="library_widget_KIntSpinBox"/>
+ <Action name="library_widget_KComboBox"/>
+ <Action name="library_widget_KListBox"/>
+ <Action name="library_widget_KTextEdit"/>
+ <Action name="library_widget_KListView"/>
+ <Action name="library_widget_QSlider"/>
+ <Action name="library_widget_KProgress"/>
+ <Action name="library_widget_KTimeWidget"/>
+ <Action name="library_widget_KDateWidget"/>
+ <Action name="library_widget_KDateTimeWidget"/>
+ <Action name="library_widget_Line"/>
+ <Action name="library_widget_Spring"/>
+ <ActionList name="undo_actions" />
+</ToolBar>
+<ToolBar name="tools" fullWidth="false" noMerge="1">
+<text>Tools Toolbar</text>
+ <Action name="pixmap_collection"/>
+ <Action name="change_style"/>
+</ToolBar>
+<ToolBar name="format" fullWidth="false" noMerge="1">
+<text>Format Toolbar</text>
+ <Action name="align_menu"/>
+ <Action name="adjust_size_menu"/>
+</ToolBar>
+
+</kpartgui> \ No newline at end of file
diff --git a/kexi/formeditor/kdevelop_plugin/kformdesigner_part_shell.rc b/kexi/formeditor/kdevelop_plugin/kformdesigner_part_shell.rc
new file mode 100644
index 00000000..8b592752
--- /dev/null
+++ b/kexi/formeditor/kdevelop_plugin/kformdesigner_part_shell.rc
@@ -0,0 +1,142 @@
+<!DOCTYPE kpartgui SYSTEM "kpartgui.dtd">
+<kpartgui name="kfd_part" version="1">
+
+<MenuBar>
+ <Menu name="file" noMerge="1">
+ <Action name="file_new"/>
+ <Action name="file_open"/>
+ <Separator />
+ <Action name="file_save"/>
+ <Action name="file_save_as"/>
+ <Separator/>
+ </Menu>
+ <Menu name="edit" noMerge="1">
+ <Action name="edit_undo" group="edit_undo_merge"/>
+ <Action name="edit_redo" group="edit_undo_merge"/>
+ <Separator group="edit_undo_merge"/>
+ <Action name="edit_cut" group="edit_paste_merge"/>
+ <Action name="edit_copy" group="edit_paste_merge"/>
+ <Action name="edit_paste" group="edit_paste_merge"/>
+ <Action name="delete_widget" group="edit_paste_merge"/>
+ <Action name="clear_contents" group="edit_paste_merge"/>
+ <Separator group="edit_select_merge"/>
+ <Action name="edit_select_all" group="edit_select_merge"/>
+ <Separator group="edit_paste_merge"/>
+ </Menu>
+ <Menu name="view" noMerge="1">
+ <Action name="preview_form"/>
+ </Menu>
+ <Menu name="tools" noMerge="1">
+ <Action name="taborder"/>
+ <Action name="change_style"/>
+ <Action name="pixmap_collection"/>
+ <Action name="form_connections"/>
+ </Menu>
+ <Menu name="widgets" noMerge="1">
+ <text>&amp;Widgets</text>
+ <Merge/>
+ <Action name="pointer"/>
+ <Action name="drag_connection"/>
+ <Separator/>
+ <Action name="library_widget_SubForm"/>
+ <Action name="library_widget_QGroupBox"/>
+ <Action name="library_widget_MyTabWidget"/>
+ <Action name="library_widget_QWidgetStack"/>
+ <Action name="library_widget_QFrame"/>
+ <Separator/>
+ <Action name="library_widget_KLineEdit"/>
+ <Action name="library_widget_QLabel"/>
+ <Action name="library_widget_KexiPictureLabel"/>
+ <Action name="library_widget_KPushButton"/>
+ <Action name="library_widget_QRadioButton"/>
+ <Action name="library_widget_QCheckBox"/>
+ <Action name="library_widget_KIntSpinBox"/>
+ <Action name="library_widget_KComboBox"/>
+ <Action name="library_widget_KListBox"/>
+ <Action name="library_widget_KTextEdit"/>
+ <Action name="library_widget_KListView"/>
+ <Action name="library_widget_QSlider"/>
+ <Action name="library_widget_KProgress"/>
+ <Action name="library_widget_KTimeWidget"/>
+ <Action name="library_widget_KDateWidget"/>
+ <Action name="library_widget_KDateTimeWidget"/>
+ <Action name="library_widget_Line"/>
+ <Action name="library_widget_Spring"/>
+ </Menu>
+ <Menu name="format" noMerge="1">
+ <text>&amp;Format</text>
+ <Action name="snap_to_grid"/>
+ <Separator/>
+ <Action name="layout_hbox"/>
+ <Action name="layout_vbox"/>
+ <Action name="layout_grid"/>
+ <Action name="break_layout"/>
+ <Separator/>
+ <Action name="align_menu"/>
+ <Action name="adjust_size_menu"/>
+ <Separator/>
+ <Action name="format_raise"/>
+ <Action name="format_lower"/>
+ </Menu>
+</MenuBar>
+
+<ToolBar name="fileToolBar" noMerge="1"><text>Main Toolbar</text>
+ <Action name="file_new"/>
+ <Action name="file_open"/>
+ <Action name="file_save"/>
+ <Action name="preview_form"/>
+ <Separator/>
+ <Action name="edit_undo"/>
+ <Action name="edit_redo"/>
+ <Separator/>
+ <Action name="edit_cut"/>
+ <Action name="edit_copy"/>
+ <Action name="edit_paste"/>
+ <Action name="delete_widget"/>
+ <Action name="clear_contents"/>
+</ToolBar>
+<ToolBar name="containers" fullWidth="false" noMerge="1">
+ <text>Containers</text>
+ <Action name="library_widget_SubForm"/>
+ <Action name="library_widget_QGroupBox"/>
+ <Action name="library_widget_MyTabWidget"/>
+ <Action name="library_widget_QWidgetStack"/>
+ <Action name="library_widget_QFrame"/>
+</ToolBar>
+<ToolBar name="widgets" fullWidth="false" noMerge="1">
+ <text>Widgets</text>
+ <Action name="pointer"/>
+ <Action name="drag_connection"/>
+ <Separator/>
+ <Action name="library_widget_KLineEdit"/>
+ <Action name="library_widget_QLabel"/>
+ <Action name="library_widget_KexiPictureLabel"/>
+ <Action name="library_widget_KPushButton"/>
+ <Action name="library_widget_QRadioButton"/>
+ <Action name="library_widget_QCheckBox"/>
+ <Action name="library_widget_KIntSpinBox"/>
+ <Action name="library_widget_KComboBox"/>
+ <Action name="library_widget_KListBox"/>
+ <Action name="library_widget_KTextEdit"/>
+ <Action name="library_widget_KListView"/>
+ <Action name="library_widget_QSlider"/>
+ <Action name="library_widget_KProgress"/>
+ <Action name="library_widget_KTimeWidget"/>
+ <Action name="library_widget_KDateWidget"/>
+ <Action name="library_widget_KDateTimeWidget"/>
+ <Action name="library_widget_Line"/>
+ <Action name="library_widget_Spring"/>
+ <ActionList name="undo_actions" />
+</ToolBar>
+<ToolBar name="tools" fullWidth="false" noMerge="1">
+<text>Tools Toolbar</text>
+ <Action name="pixmap_collection"/>
+ <Action name="change_style"/>
+</ToolBar>
+<ToolBar name="format" fullWidth="false" noMerge="1">
+<text>Format Toolbar</text>
+ <Action name="align_menu"/>
+ <Action name="adjust_size_menu"/>
+</ToolBar>
+
+</kpartgui> \ No newline at end of file
diff --git a/kexi/formeditor/kfdpixmapedit.cpp b/kexi/formeditor/kfdpixmapedit.cpp
new file mode 100644
index 00000000..e8a96761
--- /dev/null
+++ b/kexi/formeditor/kfdpixmapedit.cpp
@@ -0,0 +1,59 @@
+/* This file is part of the KDE project
+ Copyright (C) 2004 Cedric Pasteur <cedric.pasteur@free.fr>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+*/
+
+#include "kfdpixmapedit.h"
+
+#include <kdebug.h>
+
+#include <koproperty/property.h>
+#include "pixmapcollection.h"
+#include "formmanager.h"
+#include "form.h"
+#include "objecttree.h"
+
+using namespace KFormDesigner;
+
+KFDPixmapEdit::KFDPixmapEdit(KoProperty::Property *property, QWidget *parent, const char *name)
+ : KoProperty::PixmapEdit(property, parent, name)
+{
+// m_manager = manager;
+}
+
+KFDPixmapEdit::~KFDPixmapEdit()
+{}
+
+void
+KFDPixmapEdit::selectPixmap()
+{
+ KoProperty::PixmapEdit::selectPixmap();
+#if 0 //will be reenabled for new image collection
+ if(!m_manager->activeForm() || !property())
+ return;
+
+ ObjectTreeItem *item = m_manager->activeForm()->objectTree()->lookup(m_manager->activeForm()->selectedWidget()->name());
+ QString name = item ? item->pixmapName(property()->name()) : "";
+ PixmapCollectionChooser dialog( m_manager->activeForm()->pixmapCollection(), name, topLevelWidget() );
+ if(dialog.exec() == QDialog::Accepted) {
+ setValue(dialog.pixmap(), true);
+ item->setPixmapName(property()->name(), dialog.pixmapName());
+ }
+#endif
+}
+
+#include "kfdpixmapedit.moc"
diff --git a/kexi/formeditor/kfdpixmapedit.h b/kexi/formeditor/kfdpixmapedit.h
new file mode 100644
index 00000000..0d183ea4
--- /dev/null
+++ b/kexi/formeditor/kfdpixmapedit.h
@@ -0,0 +1,44 @@
+/* This file is part of the KDE project
+ Copyright (C) 2004 Cedric Pasteur <cedric.pasteur@free.fr>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+*/
+
+#ifndef KFORMEDITOR_PIXMAPEDIT_H
+#define KFORMEDITOR_PIXMAPEDIT_H
+
+#include <koproperty/editors/pixmapedit.h>
+
+namespace KFormDesigner {
+
+class KFORMEDITOR_EXPORT KFDPixmapEdit : public KoProperty::PixmapEdit
+{
+ Q_OBJECT
+
+ public:
+ KFDPixmapEdit(KoProperty::Property *property, QWidget *parent=0, const char *name=0);
+ virtual ~KFDPixmapEdit();
+
+ public slots:
+ virtual void selectPixmap();
+
+ private:
+// FormManager *m_manager;
+};
+
+}
+
+#endif
diff --git a/kexi/formeditor/libactionwidget.cpp b/kexi/formeditor/libactionwidget.cpp
new file mode 100644
index 00000000..8a17c3c3
--- /dev/null
+++ b/kexi/formeditor/libactionwidget.cpp
@@ -0,0 +1,52 @@
+/* This file is part of the KDE project
+ Copyright (C) 2003 Lucijan Busch <lucijan@gmx.at>
+ Copyright (C) 2004 Jaroslaw Staniek <js@iidea.pl>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+*/
+
+#include <kdebug.h>
+
+#include "libactionwidget.h"
+#include "widgetfactory.h"
+
+using namespace KFormDesigner;
+
+LibActionWidget::LibActionWidget(WidgetInfo *w, KActionCollection *c)
+ : KToggleAction(w->name(), w->pixmap(), 0/*Key_F5*/, 0, 0 /*SLOT(slotWidget())*/,
+ c, QString("library_widget_" + w->className()).latin1())
+{
+// kdDebug() << "LibActionWidget::LibActionWidget(): " << QString("library_widget_" + w->className()).latin1() << endl;
+ m_className = w->className();
+ setExclusiveGroup("LibActionWidgets");
+ setToolTip(w->name());
+ setWhatsThis(w->description());
+// connect(this, SIGNAL(activated()), this, SLOT(slotWidget()));
+}
+
+void
+LibActionWidget::slotActivated()
+{
+ KToggleAction::slotActivated();
+ if (isChecked())
+ emit prepareInsert(m_className);
+}
+
+LibActionWidget::~LibActionWidget()
+{
+}
+
+#include "libactionwidget.moc"
diff --git a/kexi/formeditor/libactionwidget.h b/kexi/formeditor/libactionwidget.h
new file mode 100644
index 00000000..bfa45f6a
--- /dev/null
+++ b/kexi/formeditor/libactionwidget.h
@@ -0,0 +1,60 @@
+/* This file is part of the KDE project
+ Copyright (C) 2003 Lucijan Busch <lucijan@gmx.at>
+ Copyright (C) 2004 Jaroslaw Staniek <js@iidea.pl>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+*/
+
+#ifndef LIBACTIONWIDGET_H
+#define LIBACTIONWIDGET_H
+
+
+#include <kactionclasses.h>
+
+namespace KFormDesigner
+{
+
+class WidgetInfo;
+
+/**
+ * KToggleAction subclass which remembers the matching class name.
+ */
+class KFORMEDITOR_EXPORT LibActionWidget : public KToggleAction
+{
+ Q_OBJECT
+ public:
+ /** LibActionWidget object is initialized to be mutually
+ exclusive with all other LibActionWidget objects */
+ LibActionWidget(WidgetInfo *, KActionCollection *collection);
+ virtual ~LibActionWidget();
+
+ signals:
+ /**
+ * emits a signal containing the class name
+ */
+ void prepareInsert(const QCString &className);
+
+ protected slots:
+ /** reimplemented from KToggleAction */
+ virtual void slotActivated();
+
+ private:
+ QCString m_className;
+};
+
+}
+
+#endif
diff --git a/kexi/formeditor/objecttree.cpp b/kexi/formeditor/objecttree.cpp
new file mode 100644
index 00000000..d5708773
--- /dev/null
+++ b/kexi/formeditor/objecttree.cpp
@@ -0,0 +1,244 @@
+/* This file is part of the KDE project
+ Copyright (C) 2003 Lucijan Busch <lucijan@gmx.at>
+ Copyright (C) 2006 Jaroslaw Staniek <js@iidea.pl>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+*/
+
+#include <kdebug.h>
+#include <qwidget.h>
+#include <qvariant.h>
+#include <qdom.h>
+#include <qtextstream.h>
+
+#include "form.h"
+#include "container.h"
+#include "objecttree.h"
+
+
+using namespace KFormDesigner;
+
+/////////////////////////////////////////////////////////////////////////////////////////
+///////////////// ObjectTreeItem /////////////
+////////////////////////////////////////////////////////////////////////////////////////
+
+
+ObjectTreeItem::ObjectTreeItem(const QString &classn, const QString &name, QWidget *widget,
+ Container *parentContainer, Container *container)
+ : m_enabled(true), m_row(-1), m_col(-1), m_rowspan(-1), m_colspan(-1), m_span(false)
+{
+ m_className = classn;
+ m_name = name;
+ m_widget = widget;
+ m_container = container;
+ m_eater = new EventEater(widget, parentContainer);
+ m_parent = 0;
+ m_subprops = 0;
+}
+
+ObjectTreeItem::~ObjectTreeItem()
+{
+// kdDebug() << "ObjectTreeItem deleted: " << name() << endl;
+ delete m_subprops;
+}
+
+void
+ObjectTreeItem::rename(const QString &name)
+{
+ m_name = name;
+}
+
+void
+ObjectTreeItem::addChild(ObjectTreeItem *c)
+{
+ m_children.append(c);
+ c->setParent(this);
+}
+
+void
+ObjectTreeItem::removeChild(ObjectTreeItem *c)
+{
+ m_children.remove(c);
+}
+
+void
+ObjectTreeItem::addModifiedProperty(const QCString &property, const QVariant &oldValue)
+{
+ if(property == "name")
+ return;
+
+ if(!m_props.contains(property)) {
+ m_props.insert(property, oldValue);
+ kdDebug() << "ObjectTree::adModProperty(): Added this property in the list: " << property << " oldValue: " << oldValue << endl;
+ }
+}
+
+void
+ObjectTreeItem::addSubproperty(const QCString &property, const QVariant& value)
+{
+ if (!m_subprops)
+ m_subprops = new QMap<QString, QVariant>();
+ if (!m_props.contains(property))
+ m_subprops->insert( property, value );
+}
+
+void
+ObjectTreeItem::storeUnknownProperty(QDomElement &el)
+{
+ if(!el.isNull()) {
+ QTextStream ts(m_unknownProps, IO_WriteOnly|IO_Append );
+ el.save(ts, 0);
+ }
+}
+
+void
+ObjectTreeItem::setPixmapName(const QCString &property, const QString &name)
+{
+ m_pixmapNames[property] = name;
+}
+
+QString
+ObjectTreeItem::pixmapName(const QCString &property)
+{
+ if(m_pixmapNames.contains(property))
+ return m_pixmapNames[property];
+ return QString::null;
+}
+
+void
+ObjectTreeItem::setGridPos(int row, int col, int rowspan, int colspan)
+{
+ m_row = row; m_col = col;
+ m_rowspan = rowspan;
+ m_colspan = colspan;
+ if(colspan || rowspan)
+ m_span = true;
+ else
+ m_span = false;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+/// ObjectTree /////////
+////////////////////////////////////////////////////////////////////////////////////////
+
+ObjectTree::ObjectTree(const QString &classn, const QString &name, QWidget *widget, Container *container)
+ : ObjectTreeItem(classn, name, widget, container, container)
+{
+}
+
+ObjectTree::~ObjectTree()
+{
+// for(ObjectTreeItem *it = children()->first(); it; it = children()->next())
+// removeItem(it->name());
+ while (children()->first()) {
+ removeItem(children()->first());
+ }
+}
+
+bool
+ObjectTree::rename(const QString &oldname, const QString &newname)
+{
+ if(oldname == m_name)
+ {
+ ObjectTreeItem::rename(newname);
+ return true;
+ }
+
+ ObjectTreeItem *it = lookup(oldname);
+ if(!it)
+ return false;
+
+ it->rename(newname);
+ m_treeDict.remove(oldname);
+ m_treeDict.insert(newname, it);
+
+ return true;
+}
+
+bool
+ObjectTree::reparent(const QString &name, const QString &newparent)
+{
+ ObjectTreeItem *item = lookup(name);
+ if(!item) return false;
+ ObjectTreeItem *parent = lookup(newparent);
+ if(!parent) return false;
+
+ item->parent()->removeChild(item);
+ parent->addChild(item);
+ return true;
+}
+
+ObjectTreeItem*
+ObjectTree::lookup(const QString &name)
+{
+ if(name == this->name())
+ return this;
+ else
+ return m_treeDict[name];
+}
+
+void
+ObjectTree::addItem(ObjectTreeItem *parent, ObjectTreeItem *c)
+{
+ m_treeDict.insert(c->name(), c);
+
+ if(!parent)
+ parent = this;
+ parent->addChild(c);
+ m_container->form()->emitChildAdded(c);
+
+ kdDebug() << "ObjectTree::addItem(): adding " << c->name() << " to " << parent->name() << endl;
+}
+
+void
+ObjectTree::removeItem(const QString &name)
+{
+ ObjectTreeItem *c = lookup(name);
+ removeItem(c);
+}
+
+void
+ObjectTree::removeItem(ObjectTreeItem *c)
+{
+ if (m_container && m_container->form())
+ m_container->form()->emitChildRemoved(c);
+
+ for(ObjectTreeItem *it = c->children()->first(); it; it = c->children()->next())
+ removeItem(it->name());
+
+ m_treeDict.remove(c->name());
+ c->parent()->removeChild(c);
+ delete c;
+}
+
+QCString
+ObjectTree::generateUniqueName(const QCString &prefix, bool numberSuffixRequired)
+{
+ /* old way of naming widgets
+ int appendix = m_names[c] + 1;
+ QString name(c);
+ name.append(QString::number(appendix));
+ m_names[c] = appendix;*/
+ if (!numberSuffixRequired && !lookup(prefix))
+ return prefix;
+ QString name( prefix );
+ int i = 2; //start from 2, i.e. we have: "widget", "widget2", etc.
+ while(lookup(name + QString::number(i)))
+ i++;
+
+ return (name + QString::number(i)).latin1();
+}
+
diff --git a/kexi/formeditor/objecttree.h b/kexi/formeditor/objecttree.h
new file mode 100644
index 00000000..252ee54c
--- /dev/null
+++ b/kexi/formeditor/objecttree.h
@@ -0,0 +1,184 @@
+/* This file is part of the KDE project
+ Copyright (C) 2003 Lucijan Busch <lucijan@gmx.at>
+ Copyright (C) 2004 Cedric Pasteur <cedric.pasteur@free.fr>
+ Copyright (C) 2006 Jaroslaw Staniek <js@iidea.pl>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+*/
+
+#ifndef KFORMDESIGNEROBJECTTREE_H
+#define KFORMDESIGNEROBJECTTREE_H
+
+#include <qptrlist.h>
+#include <qmap.h>
+#include <qdict.h>
+#include <qvariant.h>
+#include <qstring.h>
+#include <qguardedptr.h>
+
+class QWidget;
+class QDomElement;
+
+namespace KFormDesigner {
+
+class ObjectTreeItem;
+class Container;
+class EventEater;
+
+//! @short An list of ObjectTreeItem pointers.
+typedef QPtrList<ObjectTreeItem> ObjectTreeList;
+
+//! @short An iterator for ObjectTreeList.
+typedef QPtrListIterator<ObjectTreeItem> ObjectTreeListIterator;
+
+//! @short A QString-based disctionary of ObjectTreeItem pointers.
+typedef QDict<ObjectTreeItem> ObjectTreeDict;
+
+//! @short An iterator for ObjectTreeDict.
+typedef QDictIterator<ObjectTreeItem> ObjectTreeDictIterator;
+
+//! @short A QString -> QVarinat map.
+typedef QMap<QString, QVariant> QVariantMap;
+
+//! @short A const iterator for QVariantMap.
+typedef QMapConstIterator<QString, QVariant> QVariantMapConstIterator;
+
+/*!
+ @short An item representing a widget
+ Holds the properties of a widget (classname, name, parent, children ..).
+ @author Lucijan Busch <lucijan@kde.org>
+ */
+class KFORMEDITOR_EXPORT ObjectTreeItem
+{
+ public:
+ ObjectTreeItem(const QString &className, const QString &name, QWidget *widget, Container *parentContainer, Container *container=0);
+ virtual ~ObjectTreeItem();
+
+ QString name() const { return m_name; }
+ QString className() const { return m_className; }
+ QWidget* widget() const { return m_widget; }
+ EventEater* eventEater() const { return m_eater; }
+ ObjectTreeItem* parent() const { return m_parent; }
+ ObjectTreeList* children() { return &m_children; }
+
+ /*! \return a QMap<QString, QVariant> of all modified properties for this widget.
+ The QVariant is the old value (ie first value) of the property whose name is the QString. */
+ const QVariantMap* modifiedProperties() const { return &m_props;}
+
+ //! \return the widget's Container, or 0 if the widget is not a Container.
+ Container* container() const { return m_container;}
+
+ void setWidget(QWidget *w) { m_widget = w; }
+ void setParent(ObjectTreeItem *parent) { m_parent = parent;}
+
+ void debug(int ident);
+ void rename(const QString &name);
+
+ void addChild(ObjectTreeItem *it);
+ void removeChild(ObjectTreeItem *it);
+
+ /*! Adds \a property in the list of the modified properties for this object.
+ These modified properties are written in the .ui files when saving the form.
+ */
+ void addModifiedProperty(const QCString &property, const QVariant &oldValue);
+ void storeUnknownProperty(QDomElement &el);
+
+ /*! Adds subproperty \a property value \a value (a property of subwidget).
+ Remembering it for delayed setting is needed because on loading
+ the subwidget could be not created yet (true e.g. for KexiDBAutoField). */
+ void addSubproperty(const QCString &property, const QVariant& value);
+
+ /*! \return subproperties for this item, added by addSubproperty()
+ or 0 is there are no subproperties. */
+ QMap<QString, QVariant>* subproperties() const { return m_subprops; }
+
+ void setPixmapName(const QCString &property, const QString &name);
+ QString pixmapName(const QCString &property);
+
+ void setEnabled(bool enabled) { m_enabled = enabled; }
+ bool isEnabled() const { return m_enabled; }
+
+ int gridRow() const { return m_row; }
+ int gridCol() const { return m_col; }
+ int gridRowSpan() const { return m_rowspan; }
+ int gridColSpan() const { return m_colspan; }
+ bool spanMultipleCells() const { return m_span; }
+ void setGridPos(int row, int col, int rowspan, int colspan);
+
+ protected:
+ QString m_className;
+ QString m_name;
+ ObjectTreeList m_children;
+ QGuardedPtr<Container> m_container;
+ QMap<QString, QVariant> m_props;
+ QMap<QString, QVariant> *m_subprops;
+ QString m_unknownProps;
+ QMap<QCString, QString> m_pixmapNames;
+ ObjectTreeItem* m_parent;
+ QGuardedPtr<QWidget> m_widget;
+ QGuardedPtr<EventEater> m_eater;
+
+ bool m_enabled;
+
+ int m_row, m_col, m_rowspan, m_colspan;
+ bool m_span;
+
+ friend class ObjectTree;
+ friend class FormIO;
+};
+
+/*! @short Represents all the objects available within a form.
+ This class holds ObjectTreeItem for each widget in a Form. */
+class KFORMEDITOR_EXPORT ObjectTree : public ObjectTreeItem
+{
+ public:
+ ObjectTree(const QString &className=QString::null, const QString &name=QString::null,
+ QWidget *widget=0, Container *container=0);
+ virtual ~ObjectTree();
+
+ /*! Renames the item named \a oldname to \a newname. \return false if widget named \a newname
+ already exists and renaming failed. */
+ bool rename(const QString &oldname, const QString &newname );
+ /*! Sets \a newparent as new parent for the item whose name is \a name. */
+ bool reparent(const QString &name, const QString &newparent);
+
+ /*! \return the ObjectTreeItem named \a name, or 0 if doesn't exist. */
+ ObjectTreeItem* lookup(const QString &name);
+
+ /*! \return a dict containing all ObjectTreeItem in this ObjectTree. If you want to iterate on
+ this dict, use ObjectTreeDictIterator. */
+ ObjectTreeDict* dict() { return &m_treeDict; }
+
+ void addItem(ObjectTreeItem *parent, ObjectTreeItem *c);
+ void removeItem(const QString &name);
+ void removeItem(ObjectTreeItem *c);
+
+ /*! Generates a new, unique name for a new widget using prefix \a prefix
+ (e.g. if \a prefix is "lineEdit", "lineEdit1" is returned).
+ \a prefix must be a valid identifier.
+ If \a numberSuffixRequired is true (the default) a number suffix is mandatory.
+ If \a numberSuffixRequired is false and there's a widget prefix \a prefix,
+ then \a prefix is returned (e.g. if \a prefix is "lineEdit", and "lineEdit" doesn't exist yet,
+ "lineEdit" is returned). */
+ QCString generateUniqueName(const QCString &prefix, bool numberSuffixRequired = true);
+
+ private:
+ ObjectTreeDict m_treeDict;
+};
+
+}
+
+#endif
diff --git a/kexi/formeditor/objecttreeview.cpp b/kexi/formeditor/objecttreeview.cpp
new file mode 100644
index 00000000..22ed6d7f
--- /dev/null
+++ b/kexi/formeditor/objecttreeview.cpp
@@ -0,0 +1,377 @@
+/* This file is part of the KDE project
+ Copyright (C) 2004 Cedric Pasteur <cedric.pasteur@free.fr>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+*/
+
+#include <kdebug.h>
+
+#include <qpainter.h>
+
+#include <kiconloader.h>
+#include <klocale.h>
+
+#include "objecttree.h"
+#include "form.h"
+#include "container.h"
+#include "formmanager.h"
+#include "widgetlibrary.h"
+
+#include "objecttreeview.h"
+
+using namespace KFormDesigner;
+
+ObjectTreeViewItem::ObjectTreeViewItem(ObjectTreeViewItem *parent, ObjectTreeItem *item)
+ : KListViewItem(parent, item->name(), item->className())
+{
+ m_item = item;
+}
+
+ObjectTreeViewItem::ObjectTreeViewItem(KListView *list, ObjectTreeItem *item)
+ : KListViewItem(list, item ? item->name() : QString::null, item ? item->className() : QString::null)
+{
+ m_item = item;
+}
+
+ObjectTreeViewItem::~ObjectTreeViewItem()
+{
+}
+
+QString
+ObjectTreeViewItem::name() const
+{
+ if(m_item)
+ return m_item->name();
+ else
+ return QString::null;
+}
+
+void
+ObjectTreeViewItem::paintCell(QPainter *p, const QColorGroup & cg, int column, int width, int align)
+{
+ int margin = listView()->itemMargin();
+ if(column == 1)
+ {
+ if(!m_item)
+ return;
+ KListViewItem::paintCell(p, cg, column, width, align);
+ }
+ else
+ {
+ if(!m_item)
+ return;
+
+ p->fillRect(0,0,width, height(), QBrush(backgroundColor()));
+
+ if(isSelected())
+ {
+ p->fillRect(0,0,width, height(), QBrush(cg.highlight()));
+ p->setPen(cg.highlightedText());
+ }
+
+ QFont f = listView()->font();
+ p->save();
+ if(isSelected())
+ f.setBold(true);
+ p->setFont(f);
+ if(depth() == 0) // for edit tab order dialog
+ {
+ QString iconName
+ = ((ObjectTreeView*)listView())->iconNameForClass(m_item->widget()->className());
+ p->drawPixmap(margin, (height() - IconSize(KIcon::Small))/2 , SmallIcon(iconName));
+ p->drawText(
+ QRect(2*margin + IconSize(KIcon::Small),0,width, height()-1),
+ Qt::AlignVCenter, m_item->name());
+ }
+ else
+ p->drawText(QRect(margin,0,width, height()-1), Qt::AlignVCenter, m_item->name());
+ p->restore();
+
+ p->setPen( QColor(200,200,200) ); //like in t.v.
+ p->drawLine(width-1, 0, width-1, height()-1);
+ }
+
+ p->setPen( QColor(200,200,200) ); //like in t.v.
+ p->drawLine(-150, height()-1, width, height()-1 );
+}
+
+void
+ObjectTreeViewItem::paintBranches(QPainter *p, const QColorGroup &cg, int w, int y, int h)
+{
+ p->eraseRect(0,0,w,h);
+ ObjectTreeViewItem *item = (ObjectTreeViewItem*)firstChild();
+ if(!item || !item->m_item || !item->m_item->widget())
+ return;
+
+ p->save();
+ p->translate(0,y);
+ while(item)
+ {
+ p->fillRect(0,0,w, item->height(), QBrush(item->backgroundColor()));
+ p->fillRect(-150,0,150, item->height(), QBrush(item->backgroundColor()));
+ p->save();
+ p->setPen( QColor(200,200,200) ); //like in t.v.
+ p->drawLine(-150, item->height()-1, w, item->height()-1 );
+ p->restore();
+
+ if(item->isSelected())
+ {
+ p->fillRect(0,0,w, item->height(), QBrush(cg.highlight()));
+ p->fillRect(-150,0,150, item->height(), QBrush(cg.highlight()));
+ }
+
+ QString iconName
+ = ((ObjectTreeView*)listView())->iconNameForClass(item->m_item->widget()->className());
+ p->drawPixmap(
+ (w - IconSize(KIcon::Small))/2, (item->height() - IconSize(KIcon::Small))/2 ,
+ SmallIcon(iconName));
+
+ p->translate(0, item->totalHeight());
+ item = (ObjectTreeViewItem*)item->nextSibling();
+ }
+ p->restore();
+}
+
+void
+ObjectTreeViewItem::setup()
+{
+ KListViewItem::setup();
+ if(!m_item)
+ setHeight(0);
+}
+
+void
+ObjectTreeViewItem::setOpen( bool o )
+{
+ //don't allow to collapse the node, user may be tricked because we're not displaying [+] marks
+ if (o)
+ KListViewItem::setOpen(o);
+}
+
+// ObjectTreeView itself ----------------
+
+ObjectTreeView::ObjectTreeView(QWidget *parent, const char *name, bool tabStop)
+ : KListView(parent, name)
+ , m_form(0)
+{
+ addColumn(i18n("Name"), 130);
+ addColumn(i18n("Widget's type", "Type"), 100);
+
+ installEventFilter(this);
+
+ connect((QObject*)header(), SIGNAL(sectionHandleDoubleClicked(int)), this, SLOT(slotColumnSizeChanged(int)));
+ if(!tabStop)
+ {
+ setSelectionModeExt(Extended);
+ connect(this, SIGNAL(selectionChanged()), this, SLOT(slotSelectionChanged()));
+ connect(this, SIGNAL(contextMenu(KListView *, QListViewItem *, const QPoint&)), this, SLOT(displayContextMenu(KListView*, QListViewItem*, const QPoint&)));
+ }
+
+ setFullWidth(true);
+ setAllColumnsShowFocus(true);
+ setItemMargin(3);
+ setSorting(-1);
+}
+
+ObjectTreeView::~ObjectTreeView()
+{
+}
+
+QSize
+ObjectTreeView::sizeHint() const
+{
+ return QSize( QFontMetrics(font()).width(columnText(0)+columnText(1)+" "),
+ KListView::sizeHint().height());
+}
+
+QString
+ObjectTreeView::iconNameForClass(const QCString &classname)
+{
+ return m_form->library()->iconName(classname);
+}
+
+void
+ObjectTreeView::slotColumnSizeChanged(int)
+{
+ setColumnWidth(1, viewport()->width() - columnWidth(0));
+}
+
+void
+ObjectTreeView::displayContextMenu(KListView *list, QListViewItem *item, const QPoint &)
+{
+ if(list != this || !m_form || !item)
+ return;
+
+ QWidget *w = ((ObjectTreeViewItem*)item)->m_item->widget();
+ if(!w)
+ return;
+
+ FormManager::self()->createContextMenu(w, m_form->activeContainer());
+}
+
+ObjectTreeViewItem*
+ObjectTreeView::findItem(const QString &name)
+{
+ QListViewItemIterator it(this);
+ while(it.current())
+ {
+ ObjectTreeViewItem *item = static_cast<ObjectTreeViewItem*>(it.current());
+ if(item->name() == name)
+ {
+ return item;
+ }
+ it++;
+ }
+ return 0;
+}
+
+void
+ObjectTreeView::setSelectedWidget(QWidget *w, bool add)
+{
+ blockSignals(true); // to avoid recursion
+
+ if(!w)
+ {
+ clearSelection();
+ blockSignals(false);
+ return;
+ }
+
+ if(selectedItems().count() == 0)
+ add = false;
+
+ if(!add)
+ clearSelection();
+
+
+ QListViewItem *item = (QListViewItem*) findItem(w->name());
+ if(!add)
+ {
+ setCurrentItem(item);
+ setSelectionAnchor(item);
+ setSelected(item, true);
+ }
+ else
+ setSelected(item, true);
+
+ blockSignals(false);
+}
+
+void
+ObjectTreeView::slotSelectionChanged()
+{
+ const bool hadFocus = hasFocus();
+ QPtrList<QListViewItem> list = selectedItems();
+ m_form->selectFormWidget();
+ for(QListViewItem *item = list.first(); item; item = list.next())
+ {
+ ObjectTreeViewItem *it = static_cast<ObjectTreeViewItem*>(item);
+ QWidget *w = it->objectTree()->widget();
+ if(w && (m_form->selectedWidgets()->findRef(w) == -1))
+ m_form->setSelectedWidget(w, true, true);
+ }
+ if (hadFocus)
+ setFocus(); //restore focus
+}
+
+void
+ObjectTreeView::addItem(ObjectTreeItem *item)
+{
+ ObjectTreeViewItem *parent=0;
+
+ parent = findItem(item->parent()->name());
+ if(!parent)
+ return;
+
+ loadTree(item, parent);
+}
+
+void
+ObjectTreeView::removeItem(ObjectTreeItem *item)
+{
+ if(!item)
+ return;
+ ObjectTreeViewItem *it = findItem(item->name());
+ delete it;
+}
+
+void
+ObjectTreeView::renameItem(const QCString &oldname, const QCString &newname)
+{
+ if(findItem(newname))
+ return;
+ ObjectTreeViewItem *item = findItem(oldname);
+ if(!item)
+ return;
+ item->setText(0, newname);
+}
+
+void
+ObjectTreeView::setForm(Form *form)
+{
+ if (m_form)
+ disconnect(m_form, SIGNAL(destroying()), this, SLOT(slotBeforeFormDestroyed()));
+ m_form = form;
+ m_topItem = 0;
+ clear();
+
+ if(!m_form)
+ return;
+
+ connect(m_form, SIGNAL(destroying()), this, SLOT(slotBeforeFormDestroyed()));
+
+ // Creates the hidden top Item
+ m_topItem = new ObjectTreeViewItem(this);
+ m_topItem->setSelectable(false);
+ m_topItem->setOpen(true);
+
+ ObjectTree *tree = m_form->objectTree();
+ loadTree(tree, m_topItem);
+
+ if(!form->selectedWidgets()->isEmpty())
+ setSelectedWidget(form->selectedWidgets()->first());
+ else
+ setSelectedWidget(form->widget());
+}
+
+void
+ObjectTreeView::slotBeforeFormDestroyed()
+{
+ setForm(0);
+}
+
+ObjectTreeViewItem*
+ObjectTreeView::loadTree(ObjectTreeItem *item, ObjectTreeViewItem *parent)
+{
+ if(!item)
+ return 0;
+ ObjectTreeViewItem *treeItem = new ObjectTreeViewItem(parent, item);
+ treeItem->setOpen(true);
+
+ // The item is inserted by default at the beginning, but we want it to be at the end, so we move it
+ QListViewItem *last = parent->firstChild();
+ while(last->nextSibling())
+ last = last->nextSibling();
+ treeItem->moveItem(last);
+
+ ObjectTreeList *list = item->children();
+ for(ObjectTreeItem *it = list->first(); it; it = list->next())
+ loadTree(it, treeItem);
+
+ return treeItem;
+}
+
+#include "objecttreeview.moc"
diff --git a/kexi/formeditor/objecttreeview.h b/kexi/formeditor/objecttreeview.h
new file mode 100644
index 00000000..393f3ba0
--- /dev/null
+++ b/kexi/formeditor/objecttreeview.h
@@ -0,0 +1,129 @@
+/* This file is part of the KDE project
+ Copyright (C) 2004 Cedric Pasteur <cedric.pasteur@free.fr>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+*/
+
+#ifndef OBJECTTREEVIEW_H
+#define OBJECTTREEVIEW_H
+
+#include <klistview.h>
+
+namespace KFormDesigner {
+
+class ObjectTreeItem;
+class Form;
+
+//! @short An item in ObjectTreeView associated with an ObjectTreeItem.
+class KFORMEDITOR_EXPORT ObjectTreeViewItem : public KListViewItem
+{
+ public:
+ ObjectTreeViewItem(ObjectTreeViewItem *parent, ObjectTreeItem *item);
+ ObjectTreeViewItem(KListView *list, ObjectTreeItem *item=0);
+ virtual ~ObjectTreeViewItem();
+
+ //! \return the item name, ie the ObjectTreeItem name
+ QString name() const;
+
+ //! \return the ObjectTreeItem associated to this item.
+ ObjectTreeItem* objectTree() const { return m_item; }
+
+ virtual void setOpen( bool o );
+
+ protected:
+ //! Reimplemented to draw custom contents (copied from Property Editor)
+ virtual void paintCell(QPainter *p, const QColorGroup & cg, int column, int width, int align);
+
+ //! Reimplemented to draw custom contents (copied from Property Editor)
+ virtual void paintBranches(QPainter *p, const QColorGroup &cg, int w, int y, int h);
+
+ //! Reimplemented to draw custom contents (copied from Property Editor)
+ virtual void setup();
+
+ private:
+ ObjectTreeItem *m_item;
+
+ friend class ObjectTreeView;
+};
+
+/*! @short A graphical view of Form's ObjectTree.
+ This is a KListView which represents an item for each widget in the form.
+ The actually selected widget is written bold
+ and selected. Clicking on a list item selects the corresponding widget in the Form.
+ */
+class KFORMEDITOR_EXPORT ObjectTreeView : public KListView
+{
+ Q_OBJECT
+
+ public:
+ ObjectTreeView(QWidget *parent=0, const char *name=0, bool tabStop = false);
+ virtual ~ObjectTreeView();
+
+ virtual QSize sizeHint() const;
+
+ /*! Sets \a form as the current Form in the list. The list will automatically
+ be filled with an item for each widget in the Form, and selection will be synced.
+ Nothing happens if \a form is already the current Form.
+ */
+ void setForm(Form *form);
+
+ //! \return the pixmap name for a given class, to be shown next to the widget name.
+ QString iconNameForClass(const QCString &classname);
+
+ public slots:
+ /*! Sets the widget \a w as selected item, so it will be written bold.
+ It is added to current selection if \a add is true. */
+ void setSelectedWidget(QWidget *w, bool add=false);
+
+ /*! Adds the ObjectTreeItem \a item in the list, with the appropriate parent. */
+ void addItem(ObjectTreeItem *item);
+
+ /*! Removess the ObjectTreeItem \a item from the list. */
+ void removeItem(ObjectTreeItem *item);
+
+ /*! Just renames the list item from \a oldname to \a newname. */
+ void renameItem(const QCString &oldname, const QCString &newname);
+
+ protected slots:
+ /*! This slot is called when the user right-click a list item.
+ The widget context menu is shown, as inisde the Form. */
+ void displayContextMenu(KListView *list, QListViewItem *item, const QPoint &p);
+
+ void slotColumnSizeChanged(int);
+
+ /*! The selected list item has changed, so we emit a signal to update the Form. */
+ void slotSelectionChanged();
+
+ /*! Called before Form object is destroyed. */
+ void slotBeforeFormDestroyed();
+
+ protected:
+ //! Internal function to fill the list.
+ ObjectTreeViewItem* loadTree(ObjectTreeItem *item, ObjectTreeViewItem *parent);
+
+ //! \return The item whose name is \a name.
+ ObjectTreeViewItem* findItem(const QString &name);
+
+ private:
+ Form *m_form;
+ ObjectTreeViewItem *m_topItem;
+
+ friend class TabStopDialog;
+};
+
+}
+
+#endif
diff --git a/kexi/formeditor/resizehandle.cpp b/kexi/formeditor/resizehandle.cpp
new file mode 100644
index 00000000..0731926f
--- /dev/null
+++ b/kexi/formeditor/resizehandle.cpp
@@ -0,0 +1,339 @@
+/* This file is part of the KDE libraries
+ Copyright (C) 2002 Joseph Wenninger <jowenn@kde.org>
+ Copyright (C) 2004 Cedric Pasteur <cedric.pasteur@free.fr>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License version 2 as published by the Free Software Foundation.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+*/
+
+#include <kdebug.h>
+#include <klocale.h>
+
+#include <qpainter.h>
+#include <qcursor.h>
+
+#include "form.h"
+#include "formmanager.h"
+#include "resizehandle.h"
+#include "container.h"
+#include "widgetfactory.h"
+#include "widgetlibrary.h"
+
+#define MINIMUM_WIDTH 10
+#define MINIMUM_HEIGHT 10
+
+using namespace KFormDesigner;
+
+ResizeHandle::ResizeHandle(ResizeHandleSet *set, HandlePos pos, bool editing)
+ : QWidget(set->m_widget->parentWidget()), m_set(set)
+{
+// setBackgroundMode(Qt::NoBackground);
+ m_dragging = false;
+ //m_editing = editing;
+ setEditingMode(editing);
+ setFixedWidth(6);
+ setFixedHeight(6);
+ m_pos = pos;
+ //m_buddy = buddy;
+ //buddy->installEventFilter(this);
+ m_set->m_widget->installEventFilter(this);
+//js installEventFilter(this);
+
+ updatePos();
+ show();
+}
+
+ResizeHandle::~ResizeHandle()
+{
+}
+
+void ResizeHandle::setEditingMode(bool editing)
+{
+ if(editing)
+ setBackgroundColor(blue);
+ else
+ setBackgroundColor(black);
+}
+
+void ResizeHandle::updatePos()
+{
+ switch (m_pos)
+ {
+ case TopLeft:
+ move(m_set->m_widget->x() - 3, m_set->m_widget->y() - 3);
+ setCursor(QCursor(SizeFDiagCursor));
+ break;
+ case TopCenter:
+ move(m_set->m_widget->x() + m_set->m_widget->width()/2 - 3, m_set->m_widget->y() - 3);
+ setCursor(QCursor(SizeVerCursor));
+ break;
+ case TopRight:
+ move(m_set->m_widget->x() + m_set->m_widget->width() - 3, m_set->m_widget->y() - 3);
+ setCursor(QCursor(SizeBDiagCursor));
+ break;
+ case LeftCenter:
+ move(m_set->m_widget->x() - 3, m_set->m_widget->y() + m_set->m_widget->height()/2 - 3);
+ setCursor(QCursor(SizeHorCursor));
+ break;
+ case RightCenter:
+ move(m_set->m_widget->x() + m_set->m_widget->width() - 3, m_set->m_widget->y() + m_set->m_widget->height()/2 - 3);
+ setCursor(QCursor(SizeHorCursor));
+ break;
+ case BottomLeft:
+ move(m_set->m_widget->x() - 3, m_set->m_widget->y() + m_set->m_widget->height() - 3);
+ setCursor(QCursor(SizeBDiagCursor));
+ break;
+ case BottomCenter:
+ move(m_set->m_widget->x() + m_set->m_widget->width()/2 - 3, m_set->m_widget->y() + m_set->m_widget->height() - 3);
+ setCursor(QCursor(SizeVerCursor));
+ break;
+ case BottomRight:
+ move(m_set->m_widget->x() + m_set->m_widget->width() - 3, m_set->m_widget->y() + m_set->m_widget->height() - 3);
+ setCursor(QCursor(SizeFDiagCursor));
+ break;
+ }
+}
+
+bool ResizeHandle::eventFilter(QObject *o, QEvent *ev)
+{
+ if (((ev->type() == QEvent::Move) || (ev->type() == QEvent::Resize)) && o == m_set->m_widget)
+ {
+ //QTimer::singleShot(0,this,SLOT(updatePos()));
+ updatePos();
+ }
+/* else if (ev->type() == QEvent::Paint && o == this) {
+ QPainter p;
+ p.begin(m_set->m_widget, true);
+ const bool unclipped = testWFlags( WPaintUnclipped );
+ setWFlags( WPaintUnclipped );
+
+ p.setPen(QPen(white, 10));
+ p.setRasterOp(XorROP);
+ p.drawRect( 20, 20, 100, 100 );//m_set->m_widget->x(), m_set->m_widget->y(), 150, 150 );
+ p.drawRect( m_set->m_widget->x(), m_set->m_widget->y(), 150, 150 );
+ if (!unclipped)
+ clearWFlags( WPaintUnclipped );
+ p.end();
+
+ return true;
+ }*/
+ return false;
+}
+
+void ResizeHandle::mousePressEvent(QMouseEvent *ev)
+{
+ const bool startDragging = !m_dragging;
+ m_dragging = true;
+ m_x = ev->x();
+ m_y = ev->y();
+ if (startDragging) {
+// m_form->resizeHandleDraggingStarted(m_set->widget());
+ WidgetFactory *wfactory = m_set->m_form->library()->factoryForClassName(m_set->widget()->className());
+ if (wfactory)
+ wfactory->resetEditor();
+ }
+}
+
+void ResizeHandle::mouseMoveEvent(QMouseEvent *ev)
+{
+ int gridX = m_set->m_form->gridSize();
+ int gridY = m_set->m_form->gridSize();
+
+ if (!m_dragging) return;
+ //if(m_editing) return;
+
+ int tmpx = m_set->m_widget->x();
+ int tmpy = m_set->m_widget->y();
+ int tmpw = m_set->m_widget->width();
+ int tmph = m_set->m_widget->height();
+
+ int dummyx = ev->x() - m_x;
+ int dummyy = ev->y() - m_y;
+
+ if(FormManager::self()->snapWidgetsToGrid() && (ev->state() != (LeftButton|ControlButton|AltButton)))
+ {
+ dummyy = (int) ( ((float)dummyy) / ((float)gridY) + 0.5 );
+ dummyy *= gridY;
+ dummyx = (int) ( ((float)dummyx) / ((float)gridX) + 0.5 );
+ dummyx *= gridX;
+ }
+
+ switch (m_pos)
+ {
+ case TopRight:
+ tmpw += dummyx;
+ tmpy += dummyy;
+ tmph -= dummyy;
+ break;
+ case RightCenter:
+ tmpw += dummyx;
+ break;
+ case BottomRight:
+ tmpw += dummyx;
+ tmph += dummyy;
+ break;
+ case TopCenter:
+ tmpy += dummyy;
+ tmph -= dummyy;
+ break;
+ case BottomCenter:
+ tmph=tmph+dummyy;
+ break;
+ case TopLeft:
+ tmpx += dummyx;
+ tmpw -= dummyx;
+ tmpy += dummyy;
+ tmph -= dummyy;
+ break;
+ case LeftCenter:
+ tmpx += dummyx;
+ tmpw -= dummyx;
+ break;
+ case BottomLeft:
+ tmpx += dummyx;
+ tmpw -= dummyx;
+ tmph += dummyy;
+ break;
+ }
+
+ // Not move the top-left corner further than the bottom-right corner
+ if(tmpx >= m_set->m_widget->x() + m_set->m_widget->width())
+ {
+ tmpx = m_set->m_widget->x() + m_set->m_widget->width() - MINIMUM_WIDTH;
+ tmpw = MINIMUM_WIDTH;
+ }
+
+ if(tmpy >= m_set->m_widget->y() + m_set->m_widget->height())
+ {
+ tmpy = m_set->m_widget->y() + m_set->m_widget->height() - MINIMUM_HEIGHT;
+ tmph = MINIMUM_HEIGHT;
+ }
+
+ // Do not resize a widget outside of parent boundaries
+ if(tmpx < 0)
+ {
+ tmpw += tmpx;
+ tmpx = 0;
+ }
+ else if(tmpx + tmpw > m_set->m_widget->parentWidget()->width())
+ tmpw = m_set->m_widget->parentWidget()->width() - tmpx;
+
+ if(tmpy < 0)
+ {
+ tmph += tmpy;
+ tmpy = 0;
+ }
+ else if(tmpy + tmph > m_set->m_widget->parentWidget()->height())
+ tmph = m_set->m_widget->parentWidget()->height() - tmpy;
+
+ const bool shouldBeMoved = (tmpx != m_set->m_widget->x()) || (tmpy != m_set->m_widget->y());
+ const bool shouldBeResized = (tmpw != m_set->m_widget->width()) || (tmph != m_set->m_widget->height());
+
+ if (shouldBeMoved && shouldBeResized)
+ m_set->m_widget->hide();
+
+ // Resize it
+ if (shouldBeResized)
+ {
+ // Keep a QSize(10, 10) minimum size
+ tmpw = (tmpw < MINIMUM_WIDTH) ? MINIMUM_WIDTH : tmpw;
+ tmph = (tmph < MINIMUM_HEIGHT) ? MINIMUM_HEIGHT : tmph;
+ m_set->m_widget->resize(tmpw,tmph);
+ }
+
+ // Move the widget if necessary
+ if (shouldBeMoved)
+ m_set->m_widget->move(tmpx,tmpy);
+
+ if (shouldBeMoved && shouldBeResized)
+ m_set->m_widget->show();
+}
+
+void ResizeHandle::mouseReleaseEvent(QMouseEvent *)
+{
+ m_dragging = false;
+}
+
+void ResizeHandle::paintEvent( QPaintEvent * )
+{
+ //draw XORed background
+
+ /*QPainter p(this);
+ p.setRasterOp(XorROP);
+ p.fillRect(QRect(0, 0, 6, 6),white);
+ bitBlt( this, QPoint(0,0), parentWidget(), rect(), XorROP);*/
+}
+
+/////////////// ResizeHandleSet //////////////////
+
+ResizeHandleSet::ResizeHandleSet(QWidget *modify, Form *form, bool editing)
+: QObject(modify->parentWidget()), /*m_widget(modify),*/ m_form(form)
+{
+ m_widget = 0;
+ /*QWidget *parent = modify->parentWidget();
+
+ handles[0] = new ResizeHandle( modify, ResizeHandle::TopLeft, editing);
+ handles[1] = new ResizeHandle( modify, ResizeHandle::TopCenter, editing);
+ handles[2] = new ResizeHandle( modify, ResizeHandle::TopRight, editing);
+ handles[3] = new ResizeHandle( modify, ResizeHandle::LeftCenter, editing);
+ handles[4] = new ResizeHandle( modify, ResizeHandle::RightCenter, editing);
+ handles[5] = new ResizeHandle( modify, ResizeHandle::BottomLeft, editing);
+ handles[6] = new ResizeHandle( modify, ResizeHandle::BottomCenter, editing);
+ handles[7] = new ResizeHandle( modify, ResizeHandle::BottomRight, editing);*/
+ setWidget(modify, editing);
+}
+
+ResizeHandleSet::~ResizeHandleSet()
+{
+ for (int i = 0; i < 8; i++)
+ delete m_handles[i];
+}
+
+void
+ResizeHandleSet::setWidget(QWidget *modify, bool editing)
+{
+ if(modify == m_widget)
+ return;
+
+ if(m_widget) {
+ for(int i = 0; i < 8; i++)
+ delete m_handles[i];
+ }
+
+ m_widget = modify;
+
+ m_handles[0] = new ResizeHandle(this, ResizeHandle::TopLeft, editing);
+ m_handles[1] = new ResizeHandle(this, ResizeHandle::TopCenter, editing);
+ m_handles[2] = new ResizeHandle(this, ResizeHandle::TopRight, editing);
+ m_handles[3] = new ResizeHandle(this, ResizeHandle::LeftCenter, editing);
+ m_handles[4] = new ResizeHandle(this, ResizeHandle::RightCenter, editing);
+ m_handles[5] = new ResizeHandle(this, ResizeHandle::BottomLeft, editing);
+ m_handles[6] = new ResizeHandle(this, ResizeHandle::BottomCenter, editing);
+ m_handles[7] = new ResizeHandle(this, ResizeHandle::BottomRight, editing);
+}
+
+void
+ResizeHandleSet::raise()
+{
+ for(int i = 0; i < 8; i++)
+ m_handles[i]->raise();
+}
+
+void ResizeHandleSet::setEditingMode(bool editing)
+{
+ for(int i = 0; i < 8; i++)
+ m_handles[i]->setEditingMode(editing);
+}
+
+#include "resizehandle.moc"
diff --git a/kexi/formeditor/resizehandle.h b/kexi/formeditor/resizehandle.h
new file mode 100644
index 00000000..15ddbf36
--- /dev/null
+++ b/kexi/formeditor/resizehandle.h
@@ -0,0 +1,102 @@
+/* This file is part of the KDE libraries
+ Copyright (C) 2002 Joseph Wenninger <jowenn@kde.org>
+ Copyright (C) 2004 Cedric Pasteur <cedric.pasteur@free.fr>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License version 2 as published by the Free Software Foundation.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+*/
+
+#ifndef KFE_RESIZEHANDLER_H
+#define KFE_RESIZEHANDLER_H
+
+#include <qdict.h>
+#include <qguardedptr.h>
+#include <qwidget.h>
+
+/**
+ *@author Joseph Wenninger
+ */
+
+namespace KFormDesigner
+{
+
+class Form;
+class ResizeHandleSet;
+
+/**
+* a single widget which represents a dot for resizing a widget
+* @author Joseph Wenninger
+*/
+class KFORMEDITOR_EXPORT ResizeHandle : public QWidget
+{
+ Q_OBJECT
+
+ public:
+ enum HandlePos { TopLeft = 0, TopCenter = 2, TopRight = 4, LeftCenter = 8, RightCenter = 16,
+ BottomLeft = 32, BottomCenter = 64, BottomRight = 128 };
+ ResizeHandle(ResizeHandleSet *set, HandlePos pos, bool editing=false);
+ virtual ~ResizeHandle();
+ void setEditingMode(bool editing);
+
+ protected:
+ virtual void mousePressEvent(QMouseEvent *ev);
+ virtual void mouseMoveEvent(QMouseEvent *ev);
+ virtual void mouseReleaseEvent(QMouseEvent *ev);
+ virtual void paintEvent( QPaintEvent *ev );
+
+ protected slots:
+ bool eventFilter(QObject *obj, QEvent *ev);
+ void updatePos();
+
+ private:
+ ResizeHandleSet *m_set;
+ HandlePos m_pos;
+ //QWidget *m_buddy;
+ bool m_dragging;
+ //bool m_editing;
+ int m_x;
+ int m_y;
+};
+
+/**
+* a set of resize handles (for resizing widgets)
+* @author Joseph Wenninger
+*/
+class KFORMEDITOR_EXPORT ResizeHandleSet: public QObject
+{
+ Q_OBJECT
+
+ public:
+ typedef QDict<ResizeHandleSet> Dict;
+
+ ResizeHandleSet(QWidget *modify, Form *form, bool editing = false);
+ ~ResizeHandleSet();
+
+ void setWidget(QWidget *modify, bool editing = false);
+ QWidget *widget() const { return m_widget; }
+ void raise();
+ void setEditingMode(bool editing);
+
+ private:
+ QGuardedPtr<ResizeHandle> m_handles[8];
+ QGuardedPtr<QWidget> m_widget;
+ QGuardedPtr<Form> m_form;
+ bool m_editing;
+
+ friend class ResizeHandle;
+};
+
+}
+
+#endif
diff --git a/kexi/formeditor/richtextdialog.cpp b/kexi/formeditor/richtextdialog.cpp
new file mode 100644
index 00000000..f4596ed5
--- /dev/null
+++ b/kexi/formeditor/richtextdialog.cpp
@@ -0,0 +1,210 @@
+/* This file is part of the KDE project
+ Copyright (C) 2004 Cedric Pasteur <cedric.pasteur@free.fr>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+*/
+#include <qlayout.h>
+
+#include <ktoolbar.h>
+#include <kfontcombo.h>
+#include <kcolorcombo.h>
+#include <ktoolbarradiogroup.h>
+#include <kdebug.h>
+#include <klocale.h>
+
+#include "richtextdialog.h"
+
+namespace KFormDesigner {
+
+//////////////////////////////////////////////////////////////////////////////////
+//////////////// A simple dialog to edit rich text ////////////////////////////
+//////////////////////////////////////////////////////////////////////////////////
+
+RichTextDialog::RichTextDialog(QWidget *parent, const QString &text)
+: KDialogBase(parent, "richtext_dialog", true, i18n("Edit Rich Text"), Ok|Cancel, Ok, false)
+{
+ QFrame *frame = makeMainWidget();
+ QVBoxLayout *l = new QVBoxLayout(frame);
+ l->setAutoAdd(true);
+
+ m_toolbar = new KToolBar(frame);
+ m_toolbar->setFlat(true);
+ m_toolbar->show();
+
+ m_fcombo = new KFontCombo(m_toolbar);
+ m_toolbar->insertWidget(TBFont, 40, m_fcombo);
+ connect(m_fcombo, SIGNAL(textChanged(const QString&)), this, SLOT(changeFont(const QString &)));
+
+ m_toolbar->insertSeparator();
+
+ m_colCombo = new KColorCombo(m_toolbar);
+ m_toolbar->insertWidget(TBColor, 30, m_colCombo);
+ connect(m_colCombo, SIGNAL(activated(const QColor&)), this, SLOT(changeColor(const QColor&)));
+
+ m_toolbar->insertButton("text_bold", TBBold, true, i18n("Bold"));
+ m_toolbar->insertButton("text_italic", TBItalic, true, i18n("Italic"));
+ m_toolbar->insertButton("text_under", TBUnder, true, i18n("Underline"));
+ m_toolbar->setToggle(TBBold, true);
+ m_toolbar->setToggle(TBItalic, true);
+ m_toolbar->setToggle(TBUnder, true);
+ m_toolbar->insertSeparator();
+
+ m_toolbar->insertButton("text_super", TBSuper, true, i18n("Superscript"));
+ m_toolbar->insertButton("text_sub", TBSub, true, i18n("Subscript"));
+ m_toolbar->setToggle(TBSuper, true);
+ m_toolbar->setToggle(TBSub, true);
+ m_toolbar->insertSeparator();
+
+ KToolBarRadioGroup *group = new KToolBarRadioGroup(m_toolbar);
+ m_toolbar->insertButton("text_left", TBLeft, true, i18n("Left Align"));
+ m_toolbar->setToggle(TBLeft, true);
+ group->addButton(TBLeft);
+ m_toolbar->insertButton("text_center", TBCenter, true, i18n("Centered"));
+ m_toolbar->setToggle(TBCenter, true);
+ group->addButton(TBCenter);
+ m_toolbar->insertButton("text_right", TBRight, true, i18n("Right Align"));
+ m_toolbar->setToggle(TBRight, true);
+ group->addButton(TBRight);
+ m_toolbar->insertButton("text_block", TBJustify, true, i18n("Justified"));
+ m_toolbar->setToggle(TBJustify, true);
+ group->addButton(TBJustify);
+
+ connect(m_toolbar, SIGNAL(toggled(int)), this, SLOT(buttonToggled(int)));
+
+ m_edit = new KTextEdit(text, QString::null, frame, "richtext_edit");
+ m_edit->setTextFormat(RichText);
+ m_edit->setFocus();
+
+ connect(m_edit, SIGNAL(cursorPositionChanged(int, int)), this, SLOT(cursorPositionChanged(int, int)));
+ connect(m_edit, SIGNAL(clicked(int, int)), this, SLOT(cursorPositionChanged(int, int)));
+ connect(m_edit, SIGNAL(currentVerticalAlignmentChanged(VerticalAlignment)), this, SLOT(slotVerticalAlignmentChanged(VerticalAlignment)));
+
+ m_edit->moveCursor(QTextEdit::MoveEnd, false);
+ cursorPositionChanged(0, 0);
+ m_edit->show();
+ frame->show();
+}
+
+QString
+RichTextDialog::text()
+{
+ return m_edit->text();
+}
+
+void
+RichTextDialog::changeFont(const QString &font)
+{
+ m_edit->setFamily(font);
+}
+
+void
+RichTextDialog::changeColor(const QColor &color)
+{
+ m_edit->setColor(color);
+}
+
+void
+RichTextDialog::buttonToggled(int id)
+{
+ bool isOn = m_toolbar->isButtonOn(id);
+
+ switch(id)
+ {
+ case TBBold: m_edit->setBold(isOn); break;
+ case TBItalic: m_edit->setItalic(isOn); break;
+ case TBUnder: m_edit->setUnderline(isOn); break;
+ case TBSuper:
+ {
+ if(isOn && m_toolbar->isButtonOn(TBSub))
+ m_toolbar->setButton(TBSub, false);
+ m_edit->setVerticalAlignment(isOn ? QTextEdit::AlignSuperScript : QTextEdit::AlignNormal);
+ break;
+ }
+ case TBSub:
+ {
+ if(isOn && m_toolbar->isButtonOn(TBSuper))
+ m_toolbar->setButton(TBSuper, false);
+ m_edit->setVerticalAlignment(isOn ? QTextEdit::AlignSubScript : QTextEdit::AlignNormal);
+ break;
+ }
+ case TBLeft: case TBCenter:
+ case TBRight: case TBJustify:
+ {
+ if(!isOn) break;
+ switch(id)
+ {
+ case TBLeft: m_edit->setAlignment(Qt::AlignLeft); break;
+ case TBCenter: m_edit->setAlignment(Qt::AlignCenter); break;
+ case TBRight: m_edit->setAlignment(Qt::AlignRight); break;
+ case TBJustify: m_edit->setAlignment(Qt::AlignJustify); break;
+ default: break;
+ }
+ }
+ default: break;
+ }
+
+}
+
+void
+RichTextDialog::cursorPositionChanged(int, int)
+{
+ m_fcombo->setCurrentFont(m_edit->currentFont().family());
+ m_colCombo->setColor(m_edit->color());
+ m_toolbar->setButton(TBBold, m_edit->bold());
+ m_toolbar->setButton(TBItalic, m_edit->italic());
+ m_toolbar->setButton(TBUnder, m_edit->underline());
+
+ int id = 0;
+ switch(m_edit->alignment())
+ {
+ case Qt::AlignLeft: id = TBLeft; break;
+ case Qt::AlignCenter: id = TBCenter; break;
+ case Qt::AlignRight: id = TBRight; break;
+ case Qt::AlignJustify: id = TBJustify; break;
+ default: id = TBLeft; break;
+ }
+ m_toolbar->setButton(id, true);
+}
+
+void
+RichTextDialog::slotVerticalAlignmentChanged(VerticalAlignment align)
+{
+ switch(align)
+ {
+ case QTextEdit::AlignSuperScript:
+ {
+ m_toolbar->setButton(TBSuper, true);
+ m_toolbar->setButton(TBSub, false);
+ break;
+ }
+ case QTextEdit::AlignSubScript:
+ {
+ m_toolbar->setButton(TBSub, true);
+ m_toolbar->setButton(TBSuper, false);
+ break;
+ }
+ default:
+ {
+ m_toolbar->setButton(TBSuper, false);
+ m_toolbar->setButton(TBSub, false);
+ }
+ }
+}
+
+
+}
+
+#include "richtextdialog.moc"
diff --git a/kexi/formeditor/richtextdialog.h b/kexi/formeditor/richtextdialog.h
new file mode 100644
index 00000000..83c96464
--- /dev/null
+++ b/kexi/formeditor/richtextdialog.h
@@ -0,0 +1,63 @@
+/* This file is part of the KDE project
+ Copyright (C) 2004 Cedric Pasteur <cedric.pasteur@free.fr>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+*/
+
+#ifndef RICHTEXTEDIT_DIALOG_H
+#define RICHTEXTEDIT_DIALOG_H
+
+#include <kdialogbase.h>
+#include <ktextedit.h>
+
+class KToolBar;
+class KFontCombo;
+class KColorCombo;
+
+namespace KFormDesigner {
+
+//! A simple dialog to edit rich text
+/*! It allows to change font name, style and color, alignment. */
+class KFORMEDITOR_EXPORT RichTextDialog : public KDialogBase
+{
+ Q_OBJECT
+
+ public:
+ RichTextDialog(QWidget *parent, const QString &text);
+ ~RichTextDialog(){;}
+
+ QString text();
+
+ enum VerticalAlignment{AlignNormal = QTextEdit::AlignNormal, AlignSuperScript = QTextEdit::AlignSuperScript, AlignSubScript = QTextEdit::AlignSubScript};
+
+ public slots:
+ void changeFont(const QString &);
+ void changeColor(const QColor&);
+ void buttonToggled(int);
+ void cursorPositionChanged(int, int);
+ void slotVerticalAlignmentChanged(VerticalAlignment align);
+
+ private:
+ enum { TBFont = 100, TBColor, TBBold, TBItalic, TBUnder, TBSuper, TBSub, TBLeft = 201, TBCenter, TBRight, TBJustify };
+ KToolBar *m_toolbar;
+ KTextEdit *m_edit;
+ KFontCombo *m_fcombo;
+ KColorCombo *m_colCombo;
+};
+
+}
+
+#endif
diff --git a/kexi/formeditor/scripting/Makefile.am b/kexi/formeditor/scripting/Makefile.am
new file mode 100644
index 00000000..f03ccfdf
--- /dev/null
+++ b/kexi/formeditor/scripting/Makefile.am
@@ -0,0 +1,18 @@
+include $(top_srcdir)/kexi/Makefile.global
+
+noinst_LTLIBRARIES = libkformdesigner_scripting.la
+
+libkformdesigner_scripting_la_SOURCES = formscript.cpp scriptIO.cpp scriptmanager.cpp
+
+libkformdesigner_scripting_la_LDFLAGS = $(all_libraries) -Wnounresolved
+libkformdesigner_scripting_la_LIBADD = $(top_builddir)/kexi/formeditor/libkformdesigner.la
+
+libkformdesigner_scripting_la_METASOURCES = AUTO
+
+SUBDIRS = .
+
+INCLUDES= -I$(top_srcdir)/kexi/formeditor \
+ -I$(top_srcdir)/kexi \
+ -I$(top_srcdir)/kexi/scripting \
+ -I$(top_srcdir)/kexi/core $(all_includes)
+
diff --git a/kexi/formeditor/scripting/formscript.cpp b/kexi/formeditor/scripting/formscript.cpp
new file mode 100644
index 00000000..b598066e
--- /dev/null
+++ b/kexi/formeditor/scripting/formscript.cpp
@@ -0,0 +1,109 @@
+/* This file is part of the KDE project
+ Copyright (C) 2004 Cedric Pasteur <cedric.pasteur@free.fr>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+*/
+
+#include "formscript.h"
+#include "scriptmanager.h"
+
+#include "form.h"
+#include "objecttree.h"
+// Kross Includes
+#include "main/manager.h"
+#include "main/scriptcontainer.h"
+#include "api/exception.h"
+
+#include <kdebug.h>
+
+using namespace KFormDesigner;
+
+FormScript::FormScript(Form *form, ScriptManager *manager, const char *name)
+ : QObject(manager, name), m_manager(manager), m_form(form)
+{
+ m_script = manager->krossManager()->getScriptContainer(form->widget()->name());
+}
+
+FormScript::~FormScript()
+{
+}
+
+QString
+FormScript::getCode(const QString &)
+{
+ /// \todo Allow to select only one function
+ return m_script->getCode();
+}
+
+void
+FormScript::setCode(const QString &code)
+{
+ m_script->setCode(code);
+}
+
+void
+FormScript::appendCode(const QString &code)
+{
+ QString s = m_script->getCode();
+ s.append("\n");
+ s.append(code);
+ m_script->setCode(s);
+}
+
+bool
+FormScript::execute(const QString &functionName)
+{
+ /// \todo support return value and arguments
+ try {
+ m_script->callFunction(functionName);
+ }
+ catch(Kross::Api::Exception& e) {
+ kdDebug() << QString("EXCEPTION type='%1' description='%2'").arg(e.type()).arg(e.description()) << endl;
+ return false;
+ }
+ return true;
+}
+
+void
+FormScript::connectEvents()
+{
+ if(!m_form || !m_form->objectTree())
+ return;
+ // first call addQObject for each widget in the Form
+ ObjectTreeDict *dict = m_form->objectTree()->dict();
+ ObjectTreeDictIterator it(*dict);
+ for(; it.current(); ++it)
+ m_script->addQObject(it.current()->widget());
+ m_script->addQObject(m_form->widget());
+
+ // Then we connect all signals
+ QValueListConstIterator<Event*> endIt = m_list.constEnd();
+ for(QValueListConstIterator<Event*> it = m_list.constBegin(); it != endIt; ++it) {
+ if( (*it)->type() == Event::Slot) {
+ connect((*it)->sender(), (*it)->signal(), (*it)->receiver(), (*it)->slot());
+ }
+ else if( (*it)->type() == Event::UserFunction) {
+ m_script->connect((*it)->sender(), (*it)->signal(), (*it)->slot());
+ }
+ else if( (*it)->type() == Event::Action) {
+ /// \todo connect signals with actions
+ }
+ }
+}
+
+
+#include "formscript.moc"
+
diff --git a/kexi/formeditor/scripting/formscript.h b/kexi/formeditor/scripting/formscript.h
new file mode 100644
index 00000000..e3d63d74
--- /dev/null
+++ b/kexi/formeditor/scripting/formscript.h
@@ -0,0 +1,78 @@
+/* This file is part of the KDE project
+ Copyright (C) 2004 Cedric Pasteur <cedric.pasteur@free.fr>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+*/
+
+#ifndef FORMSCRIPT_H
+#define FORMSCRIPT_H
+
+#include "kexievents.h"
+
+#include <qobject.h>
+#include <qstring.h>
+#include <ksharedptr.h>
+
+class ScriptManager;
+
+namespace KFormDesigner {
+ class Form;
+}
+
+namespace Kross {
+ namespace Api {
+ class ScriptContainer;
+ }
+}
+
+using namespace KFormDesigner;
+
+//! A class that stores the code and events related to a single form
+class FormScript : public QObject
+{
+ Q_OBJECT
+
+ public:
+ FormScript(Form *form, ScriptManager *manager, const char *name=0);
+ ~FormScript();
+
+ EventList* eventList() { return &m_list; }
+ Kross::Api::ScriptContainer* scriptContainer() { return m_script; }
+
+ /*! \return The code of funtionName. If parameter is empty, it returns the full code of this form.*/
+ QString getCode(const QString &functionName=QString::null);
+ /*! Replaces the actual form code with the string \a code.
+ Called eg by (future) script editor. */
+ void setCode(const QString &code);
+ /*! Adds the string \a code at the end of current code. Used to add a function in the script. */
+ void appendCode(const QString &code);
+
+ /*! Executes the \a functionName.
+ \todo how do we give parameters? */
+ bool execute(const QString &functionName);
+ /*! Really connects all events in the list.
+ Also calls Kross;;Api::Manager::addObject for each widget in the form to allow the user to
+ use these widgets in the script. */
+ void connectEvents();
+
+ private:
+ ScriptManager *m_manager;
+ Form *m_form;
+ KSharedPtr<Kross::Api::ScriptContainer> m_script;
+ EventList m_list;
+};
+
+#endif
diff --git a/kexi/formeditor/scripting/scriptIO.cpp b/kexi/formeditor/scripting/scriptIO.cpp
new file mode 100644
index 00000000..8620a8ae
--- /dev/null
+++ b/kexi/formeditor/scripting/scriptIO.cpp
@@ -0,0 +1,186 @@
+/* This file is part of the KDE project
+ Copyright (C) 2004 Cedric Pasteur <cedric.pasteur@free.fr>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+*/
+
+#include "scriptIO.h"
+#include "formscript.h"
+#include "kexievents.h"
+
+#include "form.h"
+#include "objecttree.h"
+// Kross includes
+#include "main/scriptcontainer.h"
+
+bool
+ScriptIO::saveFormEvents(QDomNode &parentNode, FormScript *formScript)
+{
+ QDomDocument domDoc = parentNode.ownerDocument();
+
+ // Save the form's code
+ if(!formScript->getCode().isEmpty()) {
+ QDomElement script = domDoc.createElement("script");
+ script.setAttribute("language", formScript->scriptContainer()->getInterpreterName());
+ parentNode.appendChild(script);
+ QDomText scriptCode = domDoc.createTextNode(formScript->getCode());
+ script.appendChild(scriptCode);
+ }
+
+ // Save all form events
+ if(!formScript->eventList()->isEmpty())
+ saveEventList(formScript->eventList(), parentNode);
+ return true;
+}
+
+bool
+ScriptIO::loadFormEvents(QDomNode &parentNode, Form *form, ScriptManager *manager)
+{
+ QDomElement script = parentNode.namedItem("script").toElement();
+ QDomElement events = parentNode.namedItem("events").toElement();
+
+ // Load script code
+ FormScript *formScript = new FormScript(form, manager);
+ if(!script.isNull()) {
+ formScript->scriptContainer()->setInterpreterName(script.attribute("language"));
+ formScript->setCode(script.text());
+ }
+
+ // Load all events in the EventList
+ if(!events.isNull()) {
+ for(QDomNode n = events.firstChild(); !n.isNull(); n = n.nextSibling())
+ loadEvent(n, formScript->eventList(), form);
+ }
+ return true;
+}
+
+bool
+ScriptIO::saveAllEventsForWidget(QObject *widget, FormScript *formScript, QDomNode &node)
+{
+ EventList *l = formScript->eventList()->allEventsForObject(widget);
+ saveEventList(l, node);
+ return true;
+}
+
+void
+ScriptIO::saveEvent(Event *event, QDomNode &parentNode)
+{
+ if(!event)
+ return;
+
+ QDomDocument domDoc = parentNode.ownerDocument();
+ QDomElement eventNode = domDoc.createElement("event");
+ eventNode.setAttribute("type", event->type());
+ parentNode.appendChild(eventNode);
+
+ switch(event->type()) {
+ case Event::Slot: {
+ QDomElement sender = domDoc.createElement("sender");
+ eventNode.appendChild(sender);
+ QDomText senderText = domDoc.createTextNode(event->sender() ? event->sender()->name() : "");
+ sender.appendChild(senderText);
+
+ QDomElement signal = domDoc.createElement("signal");
+ eventNode.appendChild(signal);
+ QDomText signalText = domDoc.createTextNode(event->signal());
+ signal.appendChild(signalText);
+
+ QDomElement receiver = domDoc.createElement("receiver");
+ eventNode.appendChild(receiver);
+ QDomText receiverText = domDoc.createTextNode(event->receiver() ? event->receiver()->name() : "");
+ receiver.appendChild(receiverText);
+
+ QDomElement slot = domDoc.createElement("slot");
+ eventNode.appendChild(slot);
+ QDomText slotText = domDoc.createTextNode(event->slot());
+ slot.appendChild(slotText);
+ break;
+ }
+
+ case Event::UserFunction: {
+ QDomElement sender = domDoc.createElement("sender");
+ eventNode.appendChild(sender);
+ QDomText senderText = domDoc.createTextNode(event->sender() ? event->sender()->name() : "");
+ sender.appendChild(senderText);
+
+ QDomElement signal = domDoc.createElement("signal");
+ eventNode.appendChild(signal);
+ QDomText signalText = domDoc.createTextNode(event->signal());
+ signal.appendChild(signalText);
+
+ QDomElement function = domDoc.createElement("function");
+ eventNode.appendChild(function);
+ QDomText functionText = domDoc.createTextNode(event->slot());
+ function.appendChild(functionText);
+ break;
+ }
+
+ case Event::Action:
+ // !\todo
+ break;
+
+ default:
+ break;
+ }
+}
+
+void
+ScriptIO::saveEventList(EventList *list, QDomNode &parentNode)
+{
+ if(!list || list->isEmpty())
+ return;
+
+ QDomDocument domDoc = parentNode.ownerDocument();
+ QDomElement events = domDoc.createElement("events");
+ parentNode.appendChild(events);
+
+ QValueListConstIterator<Event*> endIt = list->constEnd();
+ for(QValueListConstIterator<Event*> it = list->constBegin(); it != endIt; ++it)
+ saveEvent((*it), events);
+}
+
+void
+ScriptIO::loadEvent(QDomNode &node, EventList *list, Form *form)
+{
+ int type = node.toElement().attribute("type").toInt();
+ Event *event = new Event();
+
+ switch(type) {
+ case Event::Slot: {
+ ObjectTreeItem *sender = form->objectTree()->lookup(node.namedItem("sender").toElement().text());
+ event->setSender(sender ? sender->widget() : 0);
+ event->setSignal(node.namedItem("signal").toElement().text().local8Bit());
+ ObjectTreeItem *receiver = form->objectTree()->lookup(node.namedItem("receiver").toElement().text());
+ event->setReceiver(receiver ? receiver->widget() : 0);
+ event->setSlot(node.namedItem("slot").toElement().text().local8Bit());
+ event->setType(Event::Slot);
+ break;
+ }
+
+ case Event::UserFunction: {
+ ObjectTreeItem *sender = form->objectTree()->lookup(node.namedItem("sender").toElement().text());
+ event->setSender(sender ? sender->widget() : 0);
+ event->setSignal(node.namedItem("signal").toElement().text().local8Bit());
+ event->setSlot(node.namedItem("function").toElement().text().local8Bit());
+ event->setType(Event::UserFunction);
+ break;
+ }
+ default: break;
+ }
+
+ list->addEvent(event);
+}
+
diff --git a/kexi/formeditor/scripting/scriptIO.h b/kexi/formeditor/scripting/scriptIO.h
new file mode 100644
index 00000000..9fed06a6
--- /dev/null
+++ b/kexi/formeditor/scripting/scriptIO.h
@@ -0,0 +1,64 @@
+/* This file is part of the KDE project
+ Copyright (C) 2004 Cedric Pasteur <cedric.pasteur@free.fr>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SCRIPTIO_H
+#define SCRIPTIO_H
+
+#include <qdom.h>
+
+class QString;
+class QObject;
+class Event;
+class EventList;
+class ScriptManager;
+class FormScript;
+
+namespace KFormDesigner {
+ class Form;
+}
+
+using namespace KFormDesigner;
+
+//! A static class to deal with loading/saving events from/to XML
+class ScriptIO
+{
+ public:
+ /*! Save the evnts of a form.
+ Creates an \<events\> tag, and then one \<event\> tag for each event.
+ Each event contains \<sender\> and \<receiver\> tags, with attributes depending on event type. */
+ static bool saveFormEvents(QDomNode &parentNode, FormScript *script);
+ /*! Reads the \<events\> tag (\a parentNode), then creates and fills a FormScript object linked to this \a form.
+ The new FormScript object is then added to ScriptManager list.*/
+ static bool loadFormEvents(QDomNode &parentNode, Form *form, ScriptManager *manager);
+
+ /*! Save only the events related to widget \a name in the FormScript \a fscript.
+ Used eg when copying/pasting widgets to keep also events related to it.*/
+ static bool saveAllEventsForWidget(QObject *widget, FormScript *fscript, QDomNode &node);
+
+ static void saveEvent(Event *event, QDomNode &parentNode);
+ static void saveEventList(EventList *list, QDomNode &parentNode);
+ static void loadEvent(QDomNode &node, EventList *list, Form *form);
+
+ protected:
+ ScriptIO() {;}
+ ~ScriptIO() {;}
+};
+
+#endif
+
diff --git a/kexi/formeditor/scripting/scriptmanager.cpp b/kexi/formeditor/scripting/scriptmanager.cpp
new file mode 100644
index 00000000..c572c685
--- /dev/null
+++ b/kexi/formeditor/scripting/scriptmanager.cpp
@@ -0,0 +1,70 @@
+/* This file is part of the KDE project
+ Copyright (C) 2004 Cedric Pasteur <cedric.pasteur@free.fr>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+*/
+
+#include "scriptmanager.h"
+#include "formscript.h"
+
+#include "form.h"
+#include "formmanager.h"
+// Kross includes
+#include "main/manager.h"
+
+using KFormDesigner::Form;
+
+ScriptManager::ScriptManager(QObject *parent, const char *name)
+ : QObject(parent, name)
+{
+ m_manager = Kross::Api::Manager::scriptManager();
+ m_dict.setAutoDelete(true);
+}
+
+ScriptManager::~ScriptManager()
+{
+}
+
+FormScript*
+ScriptManager::newFormScript(Form *form)
+{
+ FormScript *script = new FormScript(form, this);
+ m_dict.insert(form, script);
+ return script;
+}
+
+FormScript*
+ScriptManager::scriptForForm(Form *form)
+{
+ return m_dict[form];
+}
+
+void
+ScriptManager::setFormManager(FormManager *manager)
+{
+ m_formManager = manager;
+ connect(m_formManager, SIGNAL(aboutToDeleteForm(KFormDesigner::Form*)), this, SLOT(slotFormDeleted(KFormDesigner::Form*)));
+ connect(m_formManager, SIGNAL(formCreated(KFormDesigner::Form*)), this, SLOT(newFormScript(KFormDesigner::Form*)));
+}
+
+void
+ScriptManager::slotFormDeleted(KFormDesigner::Form *form)
+{
+ m_dict.remove(form);
+}
+
+#include "scriptmanager.moc"
+
diff --git a/kexi/formeditor/scripting/scriptmanager.h b/kexi/formeditor/scripting/scriptmanager.h
new file mode 100644
index 00000000..258ce2cc
--- /dev/null
+++ b/kexi/formeditor/scripting/scriptmanager.h
@@ -0,0 +1,69 @@
+/* This file is part of the KDE project
+ Copyright (C) 2004 Cedric Pasteur <cedric.pasteur@free.fr>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SCRIPTMANAGER_H
+#define SCRIPTMANAGER_H
+
+#include <qobject.h>
+#include <qptrdict.h>
+
+class FormScript;
+
+namespace Kross {
+ namespace Api {
+ class Manager;
+ }
+}
+
+namespace KFormDesigner {
+ class FormManager;
+ class Form;
+}
+
+using namespace KFormDesigner;
+
+class ScriptManager : public QObject
+{
+ Q_OBJECT
+
+ public:
+ ScriptManager(QObject *parent=0, const char *name=0);
+ ~ScriptManager();
+
+ /*! \return The FormScript object associated to this Form. */
+ FormScript* scriptForForm(Form *form);
+
+ void setFormManager(FormManager *manager);
+ FormManager* formManager() { return m_formManager; }
+ Kross::Api::Manager* krossManager() { return m_manager; }
+
+ public slots:
+ /*! Called when a form is deleted. It is removed from the dict. */
+ void slotFormDeleted(KFormDesigner::Form *form);
+ /*! \return A new FormScript object associated to the Form \a form. */
+ FormScript* newFormScript(KFormDesigner::Form *form);
+
+ private:
+ Kross::Api::Manager *m_manager;
+ KFormDesigner::FormManager *m_formManager;
+ QPtrDict<FormScript> m_dict;
+};
+
+#endif
+
diff --git a/kexi/formeditor/spring.cpp b/kexi/formeditor/spring.cpp
new file mode 100644
index 00000000..e09cc2d7
--- /dev/null
+++ b/kexi/formeditor/spring.cpp
@@ -0,0 +1,158 @@
+/* This file is part of the KDE project
+ Copyright (C) 2004 Cedric Pasteur <cedric.pasteur@free.fr>
+ Copyright (C) 2005 Jaroslaw Staniek <js@iidea.pl>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+*/
+
+#include <qsizepolicy.h>
+#include <qpainter.h>
+#include <qdom.h>
+#include <qvariant.h>
+
+#include <kdebug.h>
+
+#include "objecttree.h"
+#include "container.h"
+#include "form.h"
+#include "formIO.h"
+#include "widgetlibrary.h"
+
+#include "spring.h"
+
+Spring::Spring(QWidget *parent, const char *name)
+ : QWidget(parent, name)
+{
+ m_edit = true;
+ m_orient = Horizontal;
+ setSizeType((SizeType)QSizePolicy::Expanding);
+}
+
+void
+Spring::setOrientation(Orientation orient)
+{
+ SizeType type = sizeType();
+ m_orient = orient;
+ setSizeType(type);
+ repaint();
+}
+
+Spring::SizeType
+Spring::sizeType() const
+{
+ if(m_orient == Vertical)
+ return (SizeType)sizePolicy().verData();
+ else
+ return (SizeType)sizePolicy().horData();
+}
+
+void
+Spring::setSizeType(SizeType size)
+{
+ if(m_orient == Vertical)
+ setSizePolicy(QSizePolicy::Minimum, (QSizePolicy::SizeType)size);
+ else
+ setSizePolicy( (QSizePolicy::SizeType)size, QSizePolicy::Minimum);
+}
+
+void
+Spring::paintEvent(QPaintEvent *ev)
+{
+ if(!m_edit)
+ return;
+
+ QPainter p(this);
+ if(!ev->erased())
+ p.eraseRect(0,0,width(), height());
+ p.setPen(QPen(Qt::white, 1));
+ p.setRasterOp(Qt::XorROP);
+ QPointArray pa(4);
+ if(m_orient == Vertical) {
+ uint part = (height()+16) / 16;
+ if (part<3)
+ part=3;
+ uint w = width()-1;
+ uint offset = 0;
+ for (uint i=0; i<4; i++, offset+=(part*4)) {
+ pa.putPoints(0, 4,
+ w/2,offset, w,offset+part, w,offset+part, w/2,offset+part*2);
+ p.drawCubicBezier(pa, 0);
+ pa.putPoints(0, 4,
+ w/2,offset+part*2, 0,offset+part*3, 0,offset+part*3, w/2,offset+part*4);
+ p.drawCubicBezier(pa, 0);
+ }
+ }
+ else {
+ uint part = (width()+16) / 16;
+ if (part<3)
+ part=3;
+ uint h = height()-1;
+ uint offset = 0;
+ for (uint i=0; i<4; i++, offset+=(part*4)) {
+ pa.putPoints(0, 4,
+ offset,h/2, offset+part,0, offset+part,0, offset+part*2,h/2);
+ p.drawCubicBezier(pa, 0);
+ pa.putPoints(0, 4,
+ offset+part*2,h/2, offset+part*3,h, offset+part*3,h, offset+part*4,h/2);
+ p.drawCubicBezier(pa, 0);
+ }
+ }
+}
+
+bool
+Spring::isPropertyVisible(const QCString &name)
+{
+ if((name == "name") || (name == "sizeType") || (name == "orientation") || (name == "geometry"))
+ return true;
+
+ return false;
+}
+
+
+void
+Spring::saveSpring(KFormDesigner::ObjectTreeItem *item, QDomElement &parentNode, QDomDocument &domDoc, bool insideGridLayout)
+{
+ QDomElement tclass = domDoc.createElement("spacer");
+ parentNode.appendChild(tclass);
+
+ if(insideGridLayout)
+ {
+ tclass.setAttribute("row", item->gridRow());
+ tclass.setAttribute("column", item->gridCol());
+ if(item->spanMultipleCells())
+ {
+ tclass.setAttribute("rowspan", item->gridRowSpan());
+ tclass.setAttribute("colspan", item->gridColSpan());
+ }
+ }
+
+ KFormDesigner::FormIO::savePropertyValue(tclass, domDoc, "name", item->widget()->property("name"), item->widget());
+
+ if(parentNode.tagName() == "widget")
+ KFormDesigner::FormIO::savePropertyValue(tclass, domDoc, "geometry", item->widget()->property("geometry"), item->widget());
+
+ if(!item->widget()->sizeHint().isValid())
+ KFormDesigner::FormIO::savePropertyValue(tclass, domDoc, "sizeHint", item->widget()->property("size"), item->widget());
+ else
+ KFormDesigner::FormIO::savePropertyValue(tclass, domDoc, "sizeHint", item->widget()->property("sizeHint"), item->widget());
+
+ KFormDesigner::FormIO::savePropertyValue(tclass, domDoc, "orientation", item->widget()->property("orientation"), item->widget());
+ KFormDesigner::FormIO::savePropertyValue(tclass, domDoc, "sizeType", item->widget()->property("sizeType"), item->widget());
+}
+
+
+#include "spring.moc"
+
diff --git a/kexi/formeditor/spring.h b/kexi/formeditor/spring.h
new file mode 100644
index 00000000..7ca3d35f
--- /dev/null
+++ b/kexi/formeditor/spring.h
@@ -0,0 +1,74 @@
+/* This file is part of the KDE project
+ Copyright (C) 2004 Cedric Pasteur <cedric.pasteur@free.fr>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SPACER_H
+#define SPACER_H
+
+#include <qwidget.h>
+
+class QDomElement;
+class QDomDocument;
+
+namespace KFormDesigner {
+
+class ObjectTreeItem;
+class Container;
+class WidgetLibrary;
+
+}
+
+class KFORMEDITOR_EXPORT Spring : public QWidget
+{
+ Q_OBJECT
+ Q_ENUMS(SizeType)
+ Q_PROPERTY(Orientation orientation READ orientation WRITE setOrientation)
+ Q_PROPERTY(SizeType sizeType READ sizeType WRITE setSizeType)
+
+ private:
+ enum {HSize = 6, HMask = 0x3f, VMask = HMask << HSize, MayGrow = 1, ExpMask = 2, MayShrink = 4 };
+ public:
+ enum SizeType {Fixed = 0, Minimum = MayGrow, Maximum = MayShrink, Preferred = MayGrow|MayShrink , MinimumExpanding = Minimum|ExpMask,
+ Expanding = MinimumExpanding|MayShrink };
+
+ public:
+ Spring(QWidget *parent, const char *name);
+ ~Spring() {;}
+
+ static bool isPropertyVisible(const QCString &name);
+ static void saveSpring(KFormDesigner::ObjectTreeItem *item, QDomElement &parent, QDomDocument &domDoc, bool insideGridLayout);
+
+ void setOrientation(Orientation orient);
+ Orientation orientation() const { return m_orient;}
+ void setSizeType(SizeType size);
+ SizeType sizeType() const;
+
+ void setPreviewMode() { m_edit = false; }
+
+ private:
+ void paintEvent(QPaintEvent *ev);
+
+ private:
+ Orientation m_orient;
+ bool m_edit;
+};
+
+
+#endif
+
+
diff --git a/kexi/formeditor/tabstopdialog.cpp b/kexi/formeditor/tabstopdialog.cpp
new file mode 100644
index 00000000..067c333a
--- /dev/null
+++ b/kexi/formeditor/tabstopdialog.cpp
@@ -0,0 +1,168 @@
+/* This file is part of the KDE project
+ Copyright (C) 2004 Cedric Pasteur <cedric.pasteur@free.fr>
+ Copyright (C) 2005 Jaroslaw Staniek <js@iidea.pl>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+*/
+#include <qlayout.h>
+#include <qcheckbox.h>
+#include <qtooltip.h>
+
+#include <kiconloader.h>
+#include <kdebug.h>
+#include <klocale.h>
+#include <kpushbutton.h>
+
+#include "form.h"
+#include "objecttreeview.h"
+
+#include "tabstopdialog.h"
+
+using namespace KFormDesigner;
+
+//////////////////////////////////////////////////////////////////////////////////
+////////// The Tab Stop Dialog to edit tab order ///////////////////////////////
+//////////////////////////////////////////////////////////////////////////////////
+
+TabStopDialog::TabStopDialog(QWidget *parent)
+: KDialogBase(parent, "tabstop_dialog", true, i18n("Edit Tab Order"), Ok|Cancel, Ok, false)
+{
+ QFrame *frame = makeMainWidget();
+ QGridLayout *l = new QGridLayout(frame, 2, 2, 0, 6);
+ m_treeview = new ObjectTreeView(frame, "tabstops_treeview", true);
+ m_treeview->setItemsMovable(true);
+ m_treeview->setDragEnabled(true);
+ m_treeview->setDropVisualizer(true);
+ m_treeview->setAcceptDrops(true);
+ m_treeview->setFocus();
+ l->addWidget(m_treeview, 0, 0);
+
+ m_treeview->m_form = 0;
+ connect(m_treeview, SIGNAL(currentChanged(QListViewItem*)), this, SLOT(updateButtons(QListViewItem*)));
+ connect(m_treeview, SIGNAL(moved(QListViewItem*, QListViewItem*, QListViewItem*)), this, SLOT(updateButtons(QListViewItem*)));
+
+ QVBoxLayout *vbox = new QVBoxLayout();
+ l->addLayout(vbox, 0, 1);
+ m_btnUp = new KPushButton(SmallIconSet("1uparrow"), i18n("Move Up"), frame);
+ QToolTip::add( m_btnUp, i18n("Move widget up") );
+ vbox->addWidget(m_btnUp);
+ connect(m_btnUp, SIGNAL(clicked()), this, SLOT(moveItemUp()));
+
+ m_btnDown = new KPushButton(SmallIconSet("1downarrow"), i18n("Move Down"), frame);
+ QToolTip::add( m_btnDown, i18n("Move widget down") );
+ vbox->addWidget(m_btnDown);
+ connect(m_btnDown, SIGNAL(clicked()), this, SLOT(moveItemDown()));
+ vbox->addStretch();
+
+ m_check = new QCheckBox(i18n("Handle tab order automatically"), frame, "tabstops_check");
+ connect(m_check, SIGNAL(toggled(bool)), this, SLOT(slotRadioClicked(bool)));
+ l->addMultiCellWidget(m_check, 1, 1, 0, 1);
+
+ updateGeometry();
+ setInitialSize(QSize(500+m_btnUp->width(), QMAX(400,m_treeview->height())));
+}
+
+TabStopDialog::~TabStopDialog()
+{
+}
+
+int TabStopDialog::exec(Form *form)
+{
+ m_treeview->clear();
+ m_treeview->m_form = form;
+
+ if(form->autoTabStops())
+ form->autoAssignTabStops();
+ form->updateTabStopsOrder();
+ ObjectTreeListIterator it( form->tabStopsIterator() );
+ it.toLast();
+ for(;it.current(); --it)
+ new ObjectTreeViewItem(m_treeview, it.current());
+
+ m_check->setChecked(form->autoTabStops());
+
+ if (m_treeview->firstChild()) {
+ m_treeview->setCurrentItem(m_treeview->firstChild());
+ m_treeview->setSelected(m_treeview->firstChild(), true);
+ }
+
+ if (QDialog::Rejected == KDialogBase::exec())
+ return QDialog::Rejected;
+
+ //accepted
+ form->setAutoTabStops(m_check->isChecked());
+ if(form->autoTabStops())
+ {
+ form->autoAssignTabStops();
+ return QDialog::Accepted;
+ }
+
+ //add items to the order list
+ form->tabStops()->clear();
+ ObjectTreeViewItem *item = (ObjectTreeViewItem*)m_treeview->firstChild();
+ while(item)
+ {
+ ObjectTreeItem *tree = item->objectTree();
+ if(tree)
+ form->tabStops()->append(tree);
+ item = (ObjectTreeViewItem*)item->nextSibling();
+ }
+ return QDialog::Accepted;
+}
+
+void
+TabStopDialog::moveItemUp()
+{
+ if (!m_treeview->selectedItem())
+ return;
+ QListViewItem *before = m_treeview->selectedItem()->itemAbove();
+ before->moveItem(m_treeview->selectedItem());
+ updateButtons(m_treeview->selectedItem());
+}
+
+void
+TabStopDialog::moveItemDown()
+{
+ QListViewItem *item = m_treeview->selectedItem();
+ if (!item)
+ return;
+ item->moveItem( item->nextSibling());
+ updateButtons(item);
+}
+
+void
+TabStopDialog::updateButtons(QListViewItem *item)
+{
+ m_btnUp->setEnabled( item && (item->itemAbove() && m_treeview->isEnabled()
+ /*&& (item->itemAbove()->parent() == item->parent()))*/ ));
+ m_btnDown->setEnabled( item && item->nextSibling() && m_treeview->isEnabled() );
+}
+
+void
+TabStopDialog::slotRadioClicked(bool isOn)
+{
+ m_treeview->setEnabled(!isOn);
+ updateButtons( m_treeview->selectedItem() );
+}
+
+bool
+TabStopDialog::autoTabStops() const
+{
+ return m_check->isChecked();
+}
+
+#include "tabstopdialog.moc"
+
diff --git a/kexi/formeditor/tabstopdialog.h b/kexi/formeditor/tabstopdialog.h
new file mode 100644
index 00000000..9ae6a88a
--- /dev/null
+++ b/kexi/formeditor/tabstopdialog.h
@@ -0,0 +1,63 @@
+/* This file is part of the KDE project
+ Copyright (C) 2004 Cedric Pasteur <cedric.pasteur@free.fr>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+*/
+
+#ifndef TABSTOPEDIT_DIALOG_H
+#define TABSTOPEDIT_DIALOG_H
+
+#include <kdialogbase.h>
+
+class QListViewItem;
+class QCheckBox;
+class QToolButton;
+class KPushButton;
+
+namespace KFormDesigner {
+
+class Form;
+class ObjectTreeView;
+
+//! A dialog to edit Form tab stops
+/*! The user can change the order by dragging list items or using buttons at the right.
+ The tab stops can be arranged automatically (see \ref Form::autoAssignTabStops()). */
+class KFORMEDITOR_EXPORT TabStopDialog : public KDialogBase
+{
+ Q_OBJECT
+
+ public:
+ TabStopDialog(QWidget *parent);
+ virtual ~TabStopDialog();
+
+ public slots:
+ int exec(KFormDesigner::Form *form);
+ void moveItemUp();
+ void moveItemDown();
+ void updateButtons(QListViewItem*);
+ void slotRadioClicked(bool isOn);
+
+ bool autoTabStops() const;
+
+ protected:
+ ObjectTreeView *m_treeview;
+ KPushButton *m_btnUp, *m_btnDown;
+ QCheckBox *m_check;
+};
+
+}
+
+#endif
diff --git a/kexi/formeditor/test/Makefile.am b/kexi/formeditor/test/Makefile.am
new file mode 100644
index 00000000..f039daeb
--- /dev/null
+++ b/kexi/formeditor/test/Makefile.am
@@ -0,0 +1,46 @@
+## Makefile.am for kformdesigner
+
+include $(top_srcdir)/kexi/Makefile.global
+
+# this is the program that gets installed. it's name is used for all
+# of the other Makefile.am variables
+bin_PROGRAMS = kformdesigner
+
+# set the include path for X, qt and KDE
+INCLUDES = -I$(top_srcdir)/kexi -I$(top_srcdir)/kexi/formeditor \
+ -I$(top_srcdir)/kexi/widget -I$(top_srcdir)/kexi/core \
+ -I$(top_srcdir)/lib -I$(top_srcdir)/lib/kofficecore $(all_includes)
+
+kformdesigner_LDFLAGS = $(KDE_RPATH) $(all_libraries)
+
+kformdesigner_LDADD = $(top_builddir)/kexi/formeditor/libkformdesigner.la
+
+kformdesigner_SOURCES = main.cpp kfd_mainwindow.cpp
+
+# client stuff
+
+METASOURCES = AUTO
+
+kdelnkdir = $(kde_appsdir)/Development
+kdelnk_DATA = kformdesigner.desktop
+
+rcdir = $(kde_datadir)/kformdesigner
+rc_DATA = kfd_mainwindow.rc
+
+
+# KFormDesigner KPart
+kde_module_LTLIBRARIES = libkformdesigner_part.la
+
+libkformdesigner_part_la_SOURCES = kfd_part.cpp
+libkformdesigner_part_la_LDFLAGS = -module $(KDE_PLUGIN) $(all_libraries) $(VER_INFO)
+libkformdesigner_part_la_LIBADD = $(top_builddir)/kexi/formeditor/libkformdesigner.la $(LIB_KFILE)
+
+# this is where the desktop file will go
+partdesktopdir = $(kde_servicesdir)
+partdesktop_DATA = kformdesigner_part.desktop
+
+# this is where the part's XML-GUI resource file goes
+partrcdir = $(kde_datadir)/kformdesigner_part
+partrc_DATA = kformdesigner_part.rc kformdesigner_part_shell.rc
+
+KDE_ICON = kformdesigner
diff --git a/kexi/formeditor/test/cr16-app-kformdesigner.png b/kexi/formeditor/test/cr16-app-kformdesigner.png
new file mode 100644
index 00000000..fee34b1a
--- /dev/null
+++ b/kexi/formeditor/test/cr16-app-kformdesigner.png
Binary files differ
diff --git a/kexi/formeditor/test/cr22-app-kformdesigner.png b/kexi/formeditor/test/cr22-app-kformdesigner.png
new file mode 100644
index 00000000..50f608cc
--- /dev/null
+++ b/kexi/formeditor/test/cr22-app-kformdesigner.png
Binary files differ
diff --git a/kexi/formeditor/test/cr32-app-kformdesigner.png b/kexi/formeditor/test/cr32-app-kformdesigner.png
new file mode 100644
index 00000000..e98d13d9
--- /dev/null
+++ b/kexi/formeditor/test/cr32-app-kformdesigner.png
Binary files differ
diff --git a/kexi/formeditor/test/kfd_mainwindow.cpp b/kexi/formeditor/test/kfd_mainwindow.cpp
new file mode 100644
index 00000000..e9d52e47
--- /dev/null
+++ b/kexi/formeditor/test/kfd_mainwindow.cpp
@@ -0,0 +1,88 @@
+/* This file is part of the KDE project
+ Copyright (C) 2004 Cedric Pasteur <cedric.pasteur@free.fr>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+*/
+#include <kaction.h>
+#include <kstdaction.h>
+#include <kurl.h>
+#include <kdebug.h>
+#include <klibloader.h>
+#include <kmessagebox.h>
+#include <klocale.h>
+#include <kapplication.h>
+
+#include "kfd_mainwindow.h"
+
+KFDMainWindow::KFDMainWindow()
+ : KParts::MainWindow()
+{
+ setXMLFile("kfd_mainwindow.rc");
+
+ setupActions();
+ //statusBar()->show();
+
+ KLibFactory *factory = KLibLoader::self()->factory("libkformdesigner_part");
+ if (factory)
+ {
+ QStringList list;
+ list << "shell" << "multipleMode";
+ m_part = static_cast<KParts::ReadWritePart *>( factory->create(this, "kformdesigner_part", "KParts::ReadWritePart", list) );
+
+ if(m_part)
+ {
+ setCentralWidget(m_part->widget());
+ createGUI(m_part);
+ }
+ }
+ else
+ {
+ KMessageBox::error(this, i18n("Could not find the KFormDesigner part. Please check your installation."));
+ kapp->quit();
+ return;
+ }
+
+ setAutoSaveSettings();
+}
+
+void
+KFDMainWindow::loadUIFile(const QString &filename)
+{
+ loadUIFile(KURL::fromPathOrURL(filename));
+}
+
+void
+KFDMainWindow::loadUIFile(const KURL &url)
+{
+ m_part->openURL(url);
+}
+
+void
+KFDMainWindow::setupActions()
+{
+ KStdAction::quit(kapp, SLOT(quit()), actionCollection());
+}
+
+bool
+KFDMainWindow::queryClose()
+{
+ if(!m_part)
+ return true;
+
+ return m_part->closeURL();
+}
+
+#include "kfd_mainwindow.moc"
diff --git a/kexi/formeditor/test/kfd_mainwindow.h b/kexi/formeditor/test/kfd_mainwindow.h
new file mode 100644
index 00000000..03892a1e
--- /dev/null
+++ b/kexi/formeditor/test/kfd_mainwindow.h
@@ -0,0 +1,46 @@
+/* This file is part of the KDE project
+ Copyright (C) 2004 Cedric Pasteur <cedric.pasteur@free.fr>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+*/
+
+#ifndef KFORMDESIGNER_MAINWINDOW_H
+#define KFORMDESIGNER_MAINWINDOW_H
+
+#include <kparts/mainwindow.h>
+
+class KFDMainWindow : public KParts::MainWindow
+{
+ Q_OBJECT
+
+ public:
+ KFDMainWindow();
+ ~KFDMainWindow() {;}
+
+ /** @todo change it to bool */
+ void loadUIFile(const QString &filename);
+ /** @todo change it to bool */
+ void loadUIFile(const KURL &url);
+ virtual bool queryClose();
+
+ private:
+ void setupActions();
+
+ private:
+ KParts::ReadWritePart *m_part;
+};
+
+#endif
diff --git a/kexi/formeditor/test/kfd_mainwindow.rc b/kexi/formeditor/test/kfd_mainwindow.rc
new file mode 100644
index 00000000..66f48600
--- /dev/null
+++ b/kexi/formeditor/test/kfd_mainwindow.rc
@@ -0,0 +1,26 @@
+<!DOCTYPE kpartgui SYSTEM "kpartgui.dtd">
+<kpartgui name="kfd_mainwindow" version="1">
+<MenuBar>
+ <Menu noMerge="1" name="file"><text>&amp;File</text>
+ <Merge/>
+ <Separator/>
+ <Action name="file_quit"/>
+ </Menu>
+ <Menu noMerge="1" name="edit"><text>&amp;Edit</text>
+ <Merge/>
+ </Menu>
+ <Menu noMerge="1" name="view"><text>&amp;View</text>
+ <Merge/>
+ </Menu>
+ <Menu noMerge="1" name="tools"><text>&amp;Tools</text>
+ <Merge/>
+ </Menu>
+ <Menu noMerge="1" name="widgets"><text>&amp;Widgets</text>
+ <Merge/>
+ </Menu>
+ <Menu noMerge="1" name="format"><text>&amp;Format</text>
+ <Merge/>
+ </Menu>
+ <Merge/>
+</MenuBar>
+</kpartgui> \ No newline at end of file
diff --git a/kexi/formeditor/test/kfd_part.cpp b/kexi/formeditor/test/kfd_part.cpp
new file mode 100644
index 00000000..48832be8
--- /dev/null
+++ b/kexi/formeditor/test/kfd_part.cpp
@@ -0,0 +1,729 @@
+/* This file is part of the KDE project
+ Copyright (C) 2004 Cedric Pasteur <cedric.pasteur@free.fr>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+*/
+
+#include <qworkspace.h>
+#include <qdockarea.h>
+#include <qdockwindow.h>
+#include <qhbox.h>
+#include <qpainter.h>
+#include <qevent.h>
+#include <qobjectlist.h>
+
+#include <kdeversion.h>
+#include <kaction.h>
+#include <kinstance.h>
+#include <klocale.h>
+#include <kaboutdata.h>
+#include <kdebug.h>
+#include <kstdaction.h>
+#include <kapplication.h>
+#include <kiconloader.h>
+#include <kfiledialog.h>
+#include <klibloader.h>
+#include <kmessagebox.h>
+
+#include "form.h"
+#include "formIO.h"
+#include "objecttree.h"
+#include "container.h"
+#include "formmanager.h"
+#include "objecttreeview.h"
+#include <koproperty/set.h>
+#include <koproperty/editor.h>
+
+#include "kfd_part.h"
+
+/*
+#define ENABLE_ACTION(name, enable)
+ if(actionCollection()->action( name ))
+ actionCollection()->action( name )->setEnabled( enable )
+*/
+
+class KFDPart_FormManager : public KFormDesigner::FormManager
+{
+ public:
+ /*! Constructs FormManager object.
+ See WidgetLibrary's constructor documentation for information about
+ \a supportedFactoryGroups parameter.
+ Using \a options you can control manager's behaviour, see \ref Options. */
+ KFDPart_FormManager(KFormDesignerPart *part, int options = 0, const char *name = 0)
+ : KFormDesigner::FormManager(part, options, name)
+ , m_part(part)
+ {
+ }
+
+ virtual KAction* action( const char* name)
+ {
+ return m_part->actionCollection()->action( name );
+ }
+
+ virtual void enableAction( const char* name, bool enable ) {
+ if(m_part->actionCollection()->action( name ))
+ m_part->actionCollection()->action( name )->setEnabled( enable );
+ }
+
+ KFormDesignerPart *m_part;
+};
+
+KInstance *KFDFactory::m_instance = 0L;
+
+KFDFactory::KFDFactory()
+{}
+
+KFDFactory::~KFDFactory()
+{
+ if (m_instance)
+ {
+ delete m_instance->aboutData();
+ delete m_instance;
+ }
+
+ m_instance = 0;
+}
+
+KParts::Part*
+KFDFactory::createPartObject( QWidget *parentWidget, const char *, QObject *, const char *name,
+ const char *classname, const QStringList &args)
+{
+ bool readOnly = (classname == "KParts::ReadOnlyPart");
+ KFormDesignerPart *part = new KFormDesignerPart(parentWidget, name, readOnly, args);
+ return part;
+}
+
+KInstance*
+KFDFactory::instance()
+{
+ if (!m_instance)
+ m_instance = new KInstance(aboutData());
+ return m_instance;
+}
+
+KAboutData*
+KFDFactory::aboutData()
+{
+ KAboutData *about = new KAboutData("kformdesigner_part", I18N_NOOP("Form Designer Part"), "0.3");
+ return about;
+}
+
+KFormDesigner::WidgetLibrary* KFormDesignerPart::static_formsLibrary = 0L;
+
+KFormDesignerPart::KFormDesignerPart(QWidget *parent, const char *name, bool readOnly, const QStringList &args)
+: KParts::ReadWritePart(parent, name), m_count(0)
+{
+ setInstance(KFDFactory::instance());
+ instance()->iconLoader()->addAppDir("kexi");
+ instance()->iconLoader()->addAppDir("kformdesigner");
+
+ setReadWrite(!readOnly);
+ m_uniqueFormMode = true;
+ m_openingFile = false;
+
+ if(!args.grep("multipleMode").isEmpty())
+ setUniqueFormMode(false);
+ m_inShell = (!args.grep("shell").isEmpty());
+
+ QHBox *container = new QHBox(parent, "kfd_container_widget");
+
+ m_workspace = new QWorkspace(container, "kfd_workspace");
+ m_workspace->show();
+
+ QStringList supportedFactoryGroups;
+/* @todo add configuration for supported factory groups */
+ static_formsLibrary = KFormDesigner::FormManager::createWidgetLibrary(
+ new KFDPart_FormManager(this, 0, "kfd_manager"), supportedFactoryGroups );
+
+ if(!readOnly)
+ {
+ QDockArea *dockArea = new QDockArea(Vertical, QDockArea::Reverse, container, "kfd_part_dockarea");
+
+ QDockWindow *dockTree = new QDockWindow(dockArea);
+ KFormDesigner::ObjectTreeView *view = new KFormDesigner::ObjectTreeView(dockTree);
+ dockTree->setWidget(view);
+ dockTree->setCaption(i18n("Objects"));
+ dockTree->setResizeEnabled(true);
+ dockTree->setFixedExtentWidth(256);
+
+ QDockWindow *dockEditor = new QDockWindow(dockArea);
+ m_editor = new KoProperty::Editor(dockEditor);
+ dockEditor->setWidget(m_editor);
+ dockEditor->setCaption(i18n("Properties"));
+ dockEditor->setResizeEnabled(true);
+
+ KFormDesigner::FormManager::self()->setEditor(m_editor);
+ KFormDesigner::FormManager::self()->setObjectTreeView(view);
+
+ setupActions();
+ setModified(false);
+
+ // action stuff
+// connect(m_manager, SIGNAL(widgetSelected(KFormDesigner::Form*, bool)), SLOT(slotWidgetSelected(KFormDesigner::Form*, bool)));
+// connect(m_manager, SIGNAL(formWidgetSelected(KFormDesigner::Form*)), SLOT(slotFormWidgetSelected(KFormDesigner::Form*)));
+// connect(m_manager, SIGNAL(noFormSelected()), SLOT(slotNoFormSelected()));
+ connect(KFormDesigner::FormManager::self(), SIGNAL(undoEnabled(bool, const QString&)), SLOT(setUndoEnabled(bool, const QString&)));
+ connect(KFormDesigner::FormManager::self(), SIGNAL(redoEnabled(bool, const QString&)), SLOT(setRedoEnabled(bool, const QString&)));
+ connect(KFormDesigner::FormManager::self(), SIGNAL(dirty(KFormDesigner::Form*, bool)), this, SLOT(slotFormModified(KFormDesigner::Form*, bool)));
+ }
+
+ container->show();
+ setWidget(container);
+ connect(m_workspace, SIGNAL(windowActivated(QWidget*)), KFormDesigner::FormManager::self(), SLOT(windowChanged(QWidget*)));
+ connect(KFormDesigner::FormManager::self(), SIGNAL(propertySetSwitched(KoProperty::Set*, bool, const QCString&)),
+ this, SLOT(slotPropertySetSwitched(KoProperty::Set*, bool, const QCString&)));
+
+// slotNoFormSelected();
+ KFormDesigner::FormManager::self()->emitNoFormSelected();
+}
+
+KFormDesignerPart::~KFormDesignerPart()
+{
+}
+
+KFormDesigner::WidgetLibrary* KFormDesignerPart::formsLibrary()
+{
+ return static_formsLibrary;
+}
+
+void
+KFormDesignerPart::setupActions()
+{
+ KStdAction::open(this, SLOT(open()), actionCollection());
+ KStdAction::openNew(this, SLOT(createBlankForm()), actionCollection());
+ KStdAction::save(this, SLOT(save()), actionCollection());
+ KStdAction::saveAs(this, SLOT(saveAs()), actionCollection());
+ KStdAction::cut(KFormDesigner::FormManager::self(), SLOT(cutWidget()), actionCollection());
+ KStdAction::copy(KFormDesigner::FormManager::self(), SLOT(copyWidget()), actionCollection());
+ KStdAction::paste(KFormDesigner::FormManager::self(), SLOT(pasteWidget()), actionCollection());
+ KStdAction::undo(KFormDesigner::FormManager::self(), SLOT(undo()), actionCollection());
+ KStdAction::redo(KFormDesigner::FormManager::self(), SLOT(redo()), actionCollection());
+ KStdAction::selectAll(KFormDesigner::FormManager::self(), SLOT(selectAll()), actionCollection());
+ new KAction(i18n("Clear Widget Contents"), "editclear", KShortcut(0), KFormDesigner::FormManager::self(), SLOT(clearWidgetContent()), actionCollection(), "clear_contents");
+ new KAction(i18n("Delete Widget"), "editdelete", KShortcut(0), KFormDesigner::FormManager::self(), SLOT(deleteWidget()), actionCollection(), "edit_delete");
+ new KAction(i18n("Preview Form"), "filequickprint", CTRL+Key_T, this, SLOT(slotPreviewForm()), actionCollection(), "preview_form");
+ new KAction(i18n("Edit Tab Order"), "tab_order", KShortcut(0), KFormDesigner::FormManager::self(), SLOT(editTabOrder()), actionCollection(), "taborder");
+ new KAction(i18n("Edit Pixmap Collection"), "icons", KShortcut(0), KFormDesigner::FormManager::self(), SLOT(editFormPixmapCollection()), actionCollection(), "pixmap_collection");
+ new KAction(i18n("Edit Form Connections"), "connections", KShortcut(0), KFormDesigner::FormManager::self(), SLOT(editConnections()), actionCollection(), "form_connections");
+
+ KActionMenu *layoutMenu = new KActionMenu(i18n("Group Widgets"), "", actionCollection(), "layout_menu");
+ layoutMenu->insert(new KAction(i18n("&Horizontally"), QString::null, KShortcut(0), KFormDesigner::FormManager::self(), SLOT(layoutHBox()), actionCollection(), "layout_hbox"));
+ layoutMenu->insert(new KAction(i18n("&Vertically"), QString::null, KShortcut(0), KFormDesigner::FormManager::self(), SLOT(layoutVBox()), actionCollection(), "layout_vbox"));
+ layoutMenu->insert(new KAction(i18n("In &Grid"), QString::null, KShortcut(0), KFormDesigner::FormManager::self(), SLOT(layoutGrid()), actionCollection(), "layout_grid"));
+ layoutMenu->insert(new KAction(i18n("By &Rows"), QString::null, KShortcut(0), KFormDesigner::FormManager::self(), SLOT(layoutHFlow()), actionCollection(), "layout_hflow"));
+ layoutMenu->insert(new KAction(i18n("By &Columns"), QString::null, KShortcut(0), KFormDesigner::FormManager::self(), SLOT(layoutVFlow()), actionCollection(), "layout_vflow"));
+ layoutMenu->insert(new KAction(i18n("Horizontally in &Splitter"), QString::null, KShortcut(0), KFormDesigner::FormManager::self(), SLOT(layoutHSplitter()), actionCollection(), "layout_hsplitter"));
+ layoutMenu->insert(new KAction(i18n("Verti&cally in Splitter"), QString::null, KShortcut(0), KFormDesigner::FormManager::self(), SLOT(layoutVSplitter()), actionCollection(), "layout_vsplitter"));
+ new KAction(i18n("&Ungroup Widgets"), QString::null, KShortcut(0), KFormDesigner::FormManager::self(), SLOT(breakLayout()), actionCollection(), "break_layout");
+
+/*
+ new KAction(i18n("Lay Out Widgets &Horizontally"), QString::null, KShortcut(0), KFormDesigner::FormManager::self(), SLOT(layoutHBox()), actionCollection(), "layout_hbox");
+ new KAction(i18n("Lay Out Widgets &Vertically"), QString::null, KShortcut(0), KFormDesigner::FormManager::self(), SLOT(layoutVBox()), actionCollection(), "layout_vbox");
+ new KAction(i18n("Lay Out Widgets in &Grid"), QString::null, KShortcut(0), KFormDesigner::FormManager::self(), SLOT(layoutGrid()), actionCollection(), "layout_grid");
+ new KAction(i18n("Lay Out Widgets H&orizontally in Splitter"), QString::null, KShortcut(0), KFormDesigner::FormManager::self(), SLOT(layoutHSplitter()), actionCollection(), "layout_hsplitter");
+ new KAction(i18n("Lay Out Widgets Verti&cally in Splitter"), QString::null, KShortcut(0), KFormDesigner::FormManager::self(), SLOT(layoutVSplitter()), actionCollection(), "layout_vsplitter");
+ new KAction(i18n("&Break Layout"), QString::null, KShortcut(0), KFormDesigner::FormManager::self(), SLOT(breakLayout()), actionCollection(), "break_layout");
+*/
+ new KAction(i18n("Bring Widget to Front"), "raise", KShortcut(0), KFormDesigner::FormManager::self(), SLOT(bringWidgetToFront()), actionCollection(), "format_raise");
+ new KAction(i18n("Send Widget to Back"), "lower", KShortcut(0), KFormDesigner::FormManager::self(), SLOT(sendWidgetToBack()), actionCollection(), "format_lower");
+
+ KActionMenu *alignMenu = new KActionMenu(i18n("Align Widgets' Positions"), "aopos2grid", actionCollection(), "align_menu");
+ alignMenu->insert( new KAction(i18n("To Left"), "aoleft", KShortcut(0), KFormDesigner::FormManager::self(), SLOT(alignWidgetsToLeft()), actionCollection(), "align_to_left") );
+ alignMenu->insert( new KAction(i18n("To Right"), "aoright", KShortcut(0), KFormDesigner::FormManager::self(), SLOT(alignWidgetsToRight()), actionCollection(), "align_to_right") );
+ alignMenu->insert( new KAction(i18n("To Top"), "aotop", KShortcut(0), KFormDesigner::FormManager::self(), SLOT(alignWidgetsToTop()), actionCollection(), "align_to_top") );
+ alignMenu->insert( new KAction(i18n("To Bottom"), "aobottom", KShortcut(0), KFormDesigner::FormManager::self(), SLOT(alignWidgetsToBottom()), actionCollection(), "align_to_bottom") );
+ alignMenu->insert( new KAction(i18n("To Grid"), "aopos2grid", KShortcut(0), KFormDesigner::FormManager::self(), SLOT(alignWidgetsToGrid()), actionCollection(), "align_to_grid") );
+
+ KActionMenu *sizeMenu = new KActionMenu(i18n("Adjust Widgets' Sizes"), "aogrid", actionCollection(), "adjust_size_menu");
+ sizeMenu->insert( new KAction(i18n("To Fit"), "aofit", KShortcut(0), KFormDesigner::FormManager::self(), SLOT(adjustWidgetSize()), actionCollection(), "adjust_to_fit") );
+ sizeMenu->insert( new KAction(i18n("To Grid"), "aogrid", KShortcut(0), KFormDesigner::FormManager::self(), SLOT(adjustSizeToGrid()), actionCollection(), "adjust_size_grid") );
+ sizeMenu->insert( new KAction(i18n("To Shortest"), "aoshortest", KShortcut(0), KFormDesigner::FormManager::self(), SLOT(adjustHeightToSmall()), actionCollection(), "adjust_height_small") );
+ sizeMenu->insert( new KAction(i18n("To Tallest"), "aotallest", KShortcut(0), KFormDesigner::FormManager::self(), SLOT(adjustHeightToBig()), actionCollection(), "adjust_height_big") );
+ sizeMenu->insert( new KAction(i18n("To Narrowest"), "aonarrowest", KShortcut(0), KFormDesigner::FormManager::self(), SLOT(adjustWidthToSmall()), actionCollection(), "adjust_width_small") );
+ sizeMenu->insert( new KAction(i18n("To Widest"), "aowidest", KShortcut(0), KFormDesigner::FormManager::self(), SLOT(adjustWidthToBig()), actionCollection(), "adjust_width_big") );
+
+ if(m_inShell)
+ setXMLFile("kformdesigner_part_shell.rc");
+ else
+ setXMLFile("kformdesigner_part.rc");
+ KFormDesigner::FormManager::self()->createActions(formsLibrary(), actionCollection(), this);
+}
+
+void
+KFormDesignerPart::createBlankForm()
+{
+ if(KFormDesigner::FormManager::self()->activeForm() && m_uniqueFormMode)
+ {
+ m_openingFile = true;
+ closeURL();
+ m_openingFile = false;
+ }
+
+ if(m_uniqueFormMode && KFormDesigner::FormManager::self()->activeForm()
+ && !KFormDesigner::FormManager::self()->activeForm()->isModified()
+ && KFormDesigner::FormManager::self()->activeForm()->filename().isNull())
+ return; // active form is already a blank one
+
+ QString n = i18n("Form") + QString::number(++m_count);
+ Form *form = new Form(formsLibrary(), n.latin1(),
+ false/*!designMode, we need to set it early enough*/);
+ FormWidgetBase *w = new FormWidgetBase(this, m_workspace, n.latin1());
+
+ w->setCaption(n);
+ w->setIcon(SmallIcon("form"));
+ w->resize(350, 300);
+ w->show();
+ w->setFocus();
+
+ form->createToplevel(w, w);
+ KFormDesigner::FormManager::self()->importForm(form);
+}
+
+void
+KFormDesignerPart::open()
+{
+ m_openingFile = true;
+ KURL url = KFileDialog::getOpenURL("::kformdesigner", i18n("*.ui|Qt Designer UI Files"), m_workspace->topLevelWidget());
+ if(!url.isEmpty())
+ ReadWritePart::openURL(url);
+ m_openingFile = false;
+}
+
+bool
+KFormDesignerPart::openFile()
+{
+ Form *form = new Form(formsLibrary());
+ FormWidgetBase *w = new FormWidgetBase(this, m_workspace);
+ form->createToplevel(w, w);
+
+ if(!KFormDesigner::FormIO::loadFormFromFile(form, w, m_file))
+ {
+ delete form;
+ delete w;
+ return false;
+ }
+
+ w->show();
+ KFormDesigner::FormManager::self()->importForm(form, !isReadWrite());
+ return true;
+}
+
+bool
+KFormDesignerPart::saveFile()
+{
+ KFormDesigner::FormIO::saveFormToFile(KFormDesigner::FormManager::self()->activeForm(), m_file);
+ return true;
+}
+
+void
+KFormDesignerPart::saveAs()
+{
+ KURL url = KFileDialog::getSaveURL("::kformdesigner", i18n("*.ui|Qt Designer UI Files"),
+ m_workspace->topLevelWidget());
+ if(url.isEmpty())
+ return;
+ else
+ ReadWritePart::saveAs(url);
+}
+
+bool
+KFormDesignerPart::closeForm(Form *form)
+{
+ int res = KMessageBox::questionYesNoCancel( m_workspace->topLevelWidget(),
+ i18n( "The form \"%1\" has been modified.\n"
+ "Do you want to save your changes or discard them?" ).arg( form->objectTree()->name() ),
+ i18n( "Close Form" ), KStdGuiItem::save(), KStdGuiItem::discard() );
+
+ if(res == KMessageBox::Yes)
+ save();
+
+ return (res != KMessageBox::Cancel);
+}
+
+bool
+KFormDesignerPart::closeForms()
+{
+ QWidgetList list = m_workspace->windowList(QWorkspace::CreationOrder);
+ for(QWidget *w = list.first(); w; w = list.next())
+ if(w->close() == false)
+ return false;
+
+ return true;
+}
+
+bool
+KFormDesignerPart::closeURL()
+{
+ if(!KFormDesigner::FormManager::self()->activeForm())
+ return true;
+
+ if(m_uniqueFormMode || !m_openingFile) {
+ if (!closeForms())
+ return false;
+ }
+
+ delete (KoProperty::Editor*)m_editor;
+ return true;
+}
+
+void
+KFormDesignerPart::slotFormModified(Form *, bool isDirty)
+{
+ setModified(isDirty);
+}
+
+void
+KFormDesignerPart::slotPreviewForm()
+{
+ if(!KFormDesigner::FormManager::self()->activeForm())
+ return;
+
+ FormWidgetBase *w = new FormWidgetBase(this, m_workspace);
+ KFormDesigner::FormManager::self()->previewForm(KFormDesigner::FormManager::self()->activeForm(), w);
+}
+
+#if 0
+
+void
+KFormDesignerPart::slotWidgetSelected(Form *form, bool multiple)
+{
+ enableFormActions();
+ // Enable edit actions
+ ENABLE_ACTION("edit_copy", true);
+ ENABLE_ACTION("edit_cut", true);
+ ENABLE_ACTION("edit_delete", true);
+ ENABLE_ACTION("clear_contents", true);
+
+ // 'Align Widgets' menu
+ ENABLE_ACTION("align_menu", multiple);
+ ENABLE_ACTION("align_to_left", multiple);
+ ENABLE_ACTION("align_to_right", multiple);
+ ENABLE_ACTION("align_to_top", multiple);
+ ENABLE_ACTION("align_to_bottom", multiple);
+
+ ENABLE_ACTION("adjust_size_menu", true);
+ ENABLE_ACTION("adjust_width_small", multiple);
+ ENABLE_ACTION("adjust_width_big", multiple);
+ ENABLE_ACTION("adjust_height_small", multiple);
+ ENABLE_ACTION("adjust_height_big", multiple);
+
+ ENABLE_ACTION("format_raise", true);
+ ENABLE_ACTION("format_lower", true);
+
+ // If the widgets selected is a container, we enable layout actions
+ bool containerSelected = false;
+ if(!multiple)
+ {
+ KFormDesigner::ObjectTreeItem *item = form->objectTree()->lookup( form->selectedWidgets()->first()->name() );
+ if(item && item->container())
+ containerSelected = true;
+ }
+ const bool twoSelected = form->selectedWidgets()->count()==2;
+ // Layout actions
+ ENABLE_ACTION("layout_menu", multiple || containerSelected);
+ ENABLE_ACTION("layout_hbox", multiple || containerSelected);
+ ENABLE_ACTION("layout_vbox", multiple || containerSelected);
+ ENABLE_ACTION("layout_grid", multiple || containerSelected);
+ ENABLE_ACTION("layout_hsplitter", twoSelected);
+ ENABLE_ACTION("layout_vsplitter", twoSelected);
+
+ KFormDesigner::Container *container = KFormDesigner::FormManager::self()->activeForm()->activeContainer();
+ ENABLE_ACTION("break_layout", (container->layoutType() != KFormDesigner::Container::NoLayout));
+}
+
+void
+KFormDesignerPart::slotFormWidgetSelected(Form *form)
+{
+ disableWidgetActions();
+ enableFormActions();
+
+ const bool twoSelected = form->selectedWidgets()->count()==2;
+ const bool hasChildren = !form->objectTree()->children()->isEmpty();
+
+ // Layout actions
+ ENABLE_ACTION("layout_menu", hasChildren);
+ ENABLE_ACTION("layout_hbox", hasChildren);
+ ENABLE_ACTION("layout_vbox", hasChildren);
+ ENABLE_ACTION("layout_grid", hasChildren);
+ ENABLE_ACTION("layout_hsplitter", twoSelected);
+ ENABLE_ACTION("layout_vsplitter", twoSelected);
+ ENABLE_ACTION("break_layout", (form->toplevelContainer()->layoutType() != KFormDesigner::Container::NoLayout));
+}
+
+void
+KFormDesignerPart::slotNoFormSelected()
+{
+ disableWidgetActions();
+
+ // Disable paste action
+ ENABLE_ACTION("edit_paste", false);
+
+ ENABLE_ACTION("edit_undo", false);
+ ENABLE_ACTION("edit_redo", false);
+
+ // Disable 'Tools' actions
+ ENABLE_ACTION("pixmap_collection", false);
+ ENABLE_ACTION("form_connections", false);
+ ENABLE_ACTION("taborder", false);
+ ENABLE_ACTION("change_style", KFormDesigner::FormManager::self()->activeForm());
+
+ // Disable items in 'File'
+ ENABLE_ACTION("file_save", false);
+ ENABLE_ACTION("file_save_as", false);
+ ENABLE_ACTION("preview_form", false);
+}
+
+void
+KFormDesignerPart::enableFormActions()
+{
+ // Enable 'Tools' actions
+ ENABLE_ACTION("pixmap_collection", true);
+ ENABLE_ACTION("form_connections", true);
+ ENABLE_ACTION("taborder", true);
+ ENABLE_ACTION("change_style", true);
+
+ // Enable items in 'File'
+ ENABLE_ACTION("file_save", true);
+ ENABLE_ACTION("file_save_as", true);
+ ENABLE_ACTION("preview_form", true);
+
+ ENABLE_ACTION("edit_paste", KFormDesigner::FormManager::self()->isPasteEnabled());
+ ENABLE_ACTION("edit_select_all", true);
+}
+
+void
+KFormDesignerPart::disableWidgetActions()
+{
+ // Disable edit actions
+ ENABLE_ACTION("edit_copy", false);
+ ENABLE_ACTION("edit_cut", false);
+ ENABLE_ACTION("edit_delete", false);
+ ENABLE_ACTION("clear_contents", false);
+
+ // Disable format functions
+ ENABLE_ACTION("align_menu", false);
+ ENABLE_ACTION("align_to_left", false);
+ ENABLE_ACTION("align_to_right", false);
+ ENABLE_ACTION("align_to_top", false);
+ ENABLE_ACTION("align_to_bottom", false);
+ ENABLE_ACTION("adjust_size_menu", false);
+ ENABLE_ACTION("format_raise", false);
+ ENABLE_ACTION("format_lower", false);
+
+ ENABLE_ACTION("layout_menu", false);
+ ENABLE_ACTION("layout_hbox", false);
+ ENABLE_ACTION("layout_vbox", false);
+ ENABLE_ACTION("layout_grid", false);
+ ENABLE_ACTION("layout_hsplitter", false);
+ ENABLE_ACTION("layout_vsplitter", false);
+ ENABLE_ACTION("break_layout", false);
+}
+#endif
+
+void
+KFormDesignerPart::setUndoEnabled(bool enabled, const QString &text)
+{
+ KAction *undoAction = actionCollection()->action("edit_undo");
+ if(undoAction)
+ {
+ if(!text.isNull())
+ undoAction->setText(text);
+ }
+}
+
+void
+KFormDesignerPart::setRedoEnabled(bool enabled, const QString &text)
+{
+ KAction *redoAction = actionCollection()->action("edit_redo");
+ if(redoAction)
+ {
+ if(!text.isNull())
+ redoAction->setText(text);
+ }
+}
+
+
+////// FormWidgetBase : helper widget to draw rects on top of widgets
+
+//repaint all children widgets
+static void repaintAll(QWidget *w)
+{
+ w->repaint();
+ QObjectList *list = w->queryList("QWidget");
+ QObjectListIt it(*list);
+ for (QObject *obj; (obj=it.current()); ++it ) {
+ static_cast<QWidget*>(obj)->repaint();
+ }
+ delete list;
+}
+
+void
+FormWidgetBase::drawRects(const QValueList<QRect> &list, int type)
+{
+ QPainter p;
+ p.begin(this, true);
+ bool unclipped = testWFlags( WPaintUnclipped );
+ setWFlags( WPaintUnclipped );
+
+ if (prev_rect.isValid()) {
+ //redraw prev. selection's rectangle
+ p.drawPixmap( QPoint(prev_rect.x()-2, prev_rect.y()-2), buffer, QRect(prev_rect.x()-2, prev_rect.y()-2, prev_rect.width()+4, prev_rect.height()+4));
+ }
+ p.setBrush(QBrush::NoBrush);
+ if(type == 1) // selection rect
+ p.setPen(QPen(white, 1, Qt::DotLine));
+ else if(type == 2) // insert rect
+ p.setPen(QPen(white, 2));
+ p.setRasterOp(XorROP);
+
+ prev_rect = QRect();
+ QValueList<QRect>::ConstIterator endIt = list.constEnd();
+ for(QValueList<QRect>::ConstIterator it = list.constBegin(); it != endIt; ++it) {
+ p.drawRect(*it);
+ prev_rect = prev_rect.unite(*it);
+ }
+
+ if (!unclipped)
+ clearWFlags( WPaintUnclipped );
+ p.end();
+}
+
+void
+FormWidgetBase::drawRect(const QRect& r, int type)
+{
+ QValueList<QRect> l;
+ l.append(r);
+ drawRects(l, type);
+}
+
+void
+FormWidgetBase::initBuffer()
+{
+ repaintAll(this);
+ buffer.resize( width(), height() );
+ buffer = QPixmap::grabWindow( winId() );
+ prev_rect = QRect();
+}
+
+void
+FormWidgetBase::clearForm()
+{
+ QPainter p;
+ p.begin(this, true);
+ bool unclipped = testWFlags( WPaintUnclipped );
+ setWFlags( WPaintUnclipped );
+
+ //redraw entire form surface
+ p.drawPixmap( QPoint(0,0), buffer, QRect(0,0,buffer.width(), buffer.height()) );
+
+ if (!unclipped)
+ clearWFlags( WPaintUnclipped );
+ p.end();
+
+ repaintAll(this);
+}
+
+void
+FormWidgetBase::highlightWidgets(QWidget *from, QWidget *to)//, const QPoint &point)
+{
+ QPoint fromPoint, toPoint;
+ if(from && from->parentWidget() && (from != this))
+ fromPoint = from->parentWidget()->mapTo(this, from->pos());
+ if(to && to->parentWidget() && (to != this))
+ toPoint = to->parentWidget()->mapTo(this, to->pos());
+
+ QPainter p;
+ p.begin(this, true);
+ bool unclipped = testWFlags( WPaintUnclipped );
+ setWFlags( WPaintUnclipped );
+
+ if (prev_rect.isValid()) {
+ //redraw prev. selection's rectangle
+ p.drawPixmap( QPoint(prev_rect.x(), prev_rect.y()), buffer, QRect(prev_rect.x(), prev_rect.y(), prev_rect.width(), prev_rect.height()));
+ }
+
+ p.setPen( QPen(Qt::red, 2) );
+
+ if(to)
+ {
+ QPixmap pix1 = QPixmap::grabWidget(from);
+ QPixmap pix2 = QPixmap::grabWidget(to);
+
+ if((from != this) && (to != this))
+ p.drawLine( from->parentWidget()->mapTo(this, from->geometry().center()), to->parentWidget()->mapTo(this, to->geometry().center()) );
+
+ p.drawPixmap(fromPoint.x(), fromPoint.y(), pix1);
+ p.drawPixmap(toPoint.x(), toPoint.y(), pix2);
+
+ if(to == this)
+ p.drawRoundRect(2, 2, width()-4, height()-4, 4, 4);
+ else
+ p.drawRoundRect(toPoint.x(), toPoint.y(), to->width(), to->height(), 5, 5);
+ }
+
+ if(from == this)
+ p.drawRoundRect(2, 2, width()-4, height()-4, 4, 4);
+ else
+ p.drawRoundRect(fromPoint.x(), fromPoint.y(), from->width(), from->height(), 5, 5);
+
+ if((to == this) || (from == this))
+ prev_rect = QRect(0, 0, buffer.width(), buffer.height());
+ else if(to)
+ {
+ prev_rect.setX( (fromPoint.x() < toPoint.x()) ? (fromPoint.x() - 5) : (toPoint.x() - 5) );
+ prev_rect.setY( (fromPoint.y() < toPoint.y()) ? (fromPoint.y() - 5) : (toPoint.y() - 5) );
+ prev_rect.setRight( (fromPoint.x() < toPoint.x()) ? (toPoint.x() + to->width() + 10) : (fromPoint.x() + from->width() + 10) );
+ prev_rect.setBottom( (fromPoint.y() < toPoint.y()) ? (toPoint.y() + to->height() + 10) : (fromPoint.y() + from->height() + 10) ) ;
+ }
+ else
+ prev_rect = QRect(fromPoint.x()- 5, fromPoint.y() -5, from->width() + 10, from->height() + 10);
+
+ if (!unclipped)
+ clearWFlags( WPaintUnclipped );
+ p.end();
+}
+
+void
+FormWidgetBase::closeEvent(QCloseEvent *ev)
+{
+ Form *form = KFormDesigner::FormManager::self()->formForWidget(this);
+ if(!form || !form->isModified() || !form->objectTree()) // == preview form
+ ev->accept();
+ else
+ {
+ bool close = m_part->closeForm(form);
+ if(close)
+ ev->accept();
+ else
+ ev->ignore();
+ }
+}
+
+void KFormDesignerPart::slotPropertySetSwitched(KoProperty::Set *set, bool forceReload,
+ const QCString& propertyToSelect)
+{
+ if (m_editor) {
+ if (propertyToSelect.isEmpty() && forceReload)
+ m_editor->changeSet(set, propertyToSelect);
+ else
+ m_editor->changeSet(set);
+ }
+}
+
+K_EXPORT_COMPONENT_FACTORY(libkformdesigner_part, KFDFactory)
+
+#include "kfd_part.moc"
+
diff --git a/kexi/formeditor/test/kfd_part.h b/kexi/formeditor/test/kfd_part.h
new file mode 100644
index 00000000..77b809ca
--- /dev/null
+++ b/kexi/formeditor/test/kfd_part.h
@@ -0,0 +1,142 @@
+/* This file is part of the KDE project
+ Copyright (C) 2004 Cedric Pasteur <cedric.pasteur@free.fr>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+*/
+
+#ifndef KFORMDESIGNER_PART_H
+#define KFORMDESIGNER_PART_H
+
+#include <qwidget.h>
+#include <qpixmap.h>
+
+#include <kparts/part.h>
+#include <kparts/factory.h>
+
+#include "form.h"
+
+class KAboutData;
+class KInstance;
+class QWorkspace;
+class QCloseEvent;
+
+using KFormDesigner::Form;
+
+class KFORMEDITOR_EXPORT KFDFactory : public KParts::Factory
+{
+ Q_OBJECT
+
+ public:
+ KFDFactory();
+ virtual ~KFDFactory();
+
+ virtual KParts::Part* createPartObject(QWidget *parentWidget=0, const char *widgetName=0, QObject *parent=0, const char *name=0,
+ const char *classname="KParts::Part", const QStringList &args=QStringList());
+
+ static KInstance *instance();
+ static KAboutData *aboutData();
+
+ private:
+ static KInstance *m_instance;
+};
+
+class KFORMEDITOR_EXPORT KFormDesignerPart: public KParts::ReadWritePart
+{
+ Q_OBJECT
+
+ public:
+ KFormDesignerPart(QWidget *parent, const char *name, bool readOnly=true, const QStringList &args=QStringList());
+ virtual ~KFormDesignerPart();
+
+ static KFormDesigner::WidgetLibrary* formsLibrary();
+
+// KFormDesigner::FormManager* manager() { return m_manager; }
+ void setUniqueFormMode(bool enable) { m_uniqueFormMode = enable; }
+
+ bool closeForm(Form *form);
+ bool closeForms();
+
+ virtual bool closeURL();
+
+ public slots:
+ /*! Creates a new blank Form. The new Form is shown and become the active Form. */
+ void createBlankForm();
+
+ /*! Loads a Form from a UI file. A "Open File" dialog is shown to select the file. The loaded Form is shown and becomes
+ the active Form. */
+ void open();
+
+ void slotPreviewForm();
+ void saveAs();
+ //void slotCreateFormSlot(KFormDesigner::Form *form, const QString &widget, const QString &signal);
+
+ protected slots:
+ void slotFormModified(KFormDesigner::Form *form, bool isDirty);
+//moved to manager void slotWidgetSelected(KFormDesigner::Form *form, bool multiple);
+//moved to manager void slotFormWidgetSelected(KFormDesigner::Form *form);
+//moved to manager void slotNoFormSelected();
+ void setUndoEnabled(bool enabled, const QString &text);
+ void setRedoEnabled(bool enabled, const QString &text);
+
+ /*! Shows a property set \a set in a Property Editor. */
+ void slotPropertySetSwitched(KoProperty::Set *set, bool forceReload = false,
+ const QCString& propertyToSelect = QCString());
+
+ protected:
+ virtual bool openFile();
+ virtual bool saveFile();
+ void disableWidgetActions();
+ void enableFormActions();
+ void setupActions();
+
+ private:
+ static KFormDesigner::WidgetLibrary* static_formsLibrary;
+// KFormDesigner::FormManager *m_manager;
+ QWorkspace *m_workspace;
+ QGuardedPtr<KoProperty::Editor> m_editor;
+ int m_count;
+ bool m_uniqueFormMode;
+ bool m_openingFile;
+ bool m_inShell;
+};
+
+//! Helper: this widget is used to create form's surface
+class KFORMEDITOR_EXPORT FormWidgetBase : public QWidget, public KFormDesigner::FormWidget
+{
+ Q_OBJECT
+
+ public:
+ FormWidgetBase(KFormDesignerPart *part, QWidget *parent = 0, const char *name = 0, int WFlags = WDestructiveClose)
+ : QWidget(parent, name, WFlags), m_part(part) {}
+ ~FormWidgetBase() {;}
+
+ void drawRect(const QRect& r, int type);
+ void drawRects(const QValueList<QRect> &list, int type);
+ void initBuffer();
+ void clearForm();
+ void highlightWidgets(QWidget *from, QWidget *to);//, const QPoint &p);
+
+ protected:
+ void closeEvent(QCloseEvent *ev);
+
+ private:
+ QPixmap buffer; //!< stores grabbed entire form's area for redraw
+ QRect prev_rect; //!< previously selected rectangle
+ KFormDesignerPart *m_part;
+};
+
+#endif
+
diff --git a/kexi/formeditor/test/kformdesigner.desktop b/kexi/formeditor/test/kformdesigner.desktop
new file mode 100644
index 00000000..4a018915
--- /dev/null
+++ b/kexi/formeditor/test/kformdesigner.desktop
@@ -0,0 +1,61 @@
+[Desktop Entry]
+Name=KFormDesigner
+Name[cs]=Návrhář formulářů
+Name[cy]=DylunyddKForm
+Name[fa]=طراح KForm
+Name[ne]=केडीई फाराम डिजाइनकर्ता
+Name[sv]=Kformdesigner
+Name[ta]=படிவம் வடிவமைப்பவர்
+Name[tg]=KДизайнгари шакл
+Name[tr]=KFormTasarımcısı
+Name[zh_CN]=KForm 设计器
+Exec=kformdesigner %i %m -caption "%c"
+Icon=kformdesigner
+Type=Application
+DocPath=kformdesigner/kformdesigner.html
+GenericName=Form Designer
+GenericName[bg]=Проектиране на форми
+GenericName[br]=Ergrafer ar paperenn-reol
+GenericName[ca]=Dissenyador de formulari
+GenericName[cy]=Dylunydd Ffurflenni
+GenericName[de]=Formular-Designer
+GenericName[el]=Σχεδιαστής φόρμας
+GenericName[eo]=Formulardesegnilo
+GenericName[es]=Diseñador de formularios
+GenericName[et]=Vormikujundaja
+GenericName[eu]=Formularioen diseinatzailea
+GenericName[fa]=طراح برگه
+GenericName[fi]=Lomakkeen suunnittleija
+GenericName[fr]=Concepteur d'interfaces graphiques
+GenericName[gl]=Deseño de Formularios
+GenericName[he]=מעצב טפסים
+GenericName[hr]=Dizajner obrazaca
+GenericName[hu]=Űrlaptervező
+GenericName[is]=Form hönnuður
+GenericName[it]=Progetto dei moduli
+GenericName[ja]=フォームデザイナー
+GenericName[km]=កម្មវិធី​រចនា​សំណុំបែបបទ
+GenericName[lv]=Formu veidotājs
+GenericName[ms]=Pereka Bentuk Borang
+GenericName[nb]=Skjemautforming
+GenericName[nds]=Kiekwark-Maker
+GenericName[ne]=फारम डिजाइनकर्ता
+GenericName[nn]=Skjemautforming
+GenericName[pl]=Projektant formularzy
+GenericName[pt]=Desenho de Formulários
+GenericName[pt_BR]=Desenhista de Formulário
+GenericName[ru]=Редактор форм
+GenericName[se]=Skovvehápmejeaddji
+GenericName[sl]=Oblikovalec obrazcev
+GenericName[sr]=Дизајнер форми
+GenericName[sr@Latn]=Dizajner formi
+GenericName[sv]=Formulärkonstruktion
+GenericName[uk]=Дизайнер форм
+GenericName[uz]=Shakl dizayneri
+GenericName[uz@cyrillic]=Шакл дизайнери
+GenericName[zh_CN]=表单设计器
+GenericName[zh_TW]=表單設計師
+MimeType=application/x-designer;
+Terminal=false
+Categories=Qt;KDE;Development;
+
diff --git a/kexi/formeditor/test/kformdesigner_part.desktop b/kexi/formeditor/test/kformdesigner_part.desktop
new file mode 100644
index 00000000..b0f38454
--- /dev/null
+++ b/kexi/formeditor/test/kformdesigner_part.desktop
@@ -0,0 +1,52 @@
+[Desktop Entry]
+Name=Form Designer
+Name[bg]=Проектиране на форми
+Name[br]=Ergrafer ar paperenn-reol
+Name[ca]=Dissenyador de formulari
+Name[cs]=Návrhář formulářů
+Name[cy]=Dylunydd Ffurflenni
+Name[de]=Formular-Designer
+Name[el]=Σχεδιαστής φόρμας
+Name[eo]=Formulardesegnilo
+Name[es]=Diseñador de formularios
+Name[et]=Vormikujundaja
+Name[eu]=Formularioen diseinatzailea
+Name[fa]=طراح برگه
+Name[fi]=Lomakkeen suunnittelija
+Name[fr]=Composeur d'interfaces graphiques
+Name[gl]=Deseño de Formularios
+Name[he]=מעצב טפסים
+Name[hr]=Dizajner obrazaca
+Name[hu]=Űrlaptervező
+Name[is]=Form hönnuður
+Name[it]=Progetto dei moduli
+Name[ja]=フォームデザイナー
+Name[km]=កម្មវិធី​រចនា​សំណុំបែបបទ
+Name[lt]=Formų kūrimo programa
+Name[lv]=Formu veidotājs
+Name[ms]=Pereka Bentuk Borang
+Name[nb]=Skjemautforming
+Name[nds]=Kiekwark-Maker
+Name[ne]=फारम डिजाइनकर्ता
+Name[nn]=Skjemautforming
+Name[pl]=Projektant formularzy
+Name[pt]=Desenho de Formulários
+Name[pt_BR]=Desenhista de Formulário
+Name[ru]=Редактор форм
+Name[se]=Skovvehápmejeaddji
+Name[sl]=Oblikovalec obrazcev
+Name[sr]=Дизајнер форми
+Name[sr@Latn]=Dizajner formi
+Name[sv]=Formulärkonstruktion
+Name[ta]=படிவ வடிவமைப்பாளர்
+Name[tg]=Дизайнгари шакл
+Name[tr]=FormTasarımcısı
+Name[uk]=Дизайнер форм
+Name[uz]=Shakl dizayneri
+Name[uz@cyrillic]=Шакл дизайнери
+Name[zh_CN]=表单设计器
+Name[zh_TW]=表單設計師
+MimeType=application/x-designer;
+ServiceTypes=KParts/ReadOnlyPart,KParts/ReadWritePart
+X-KDE-Library=libkformdesigner_part
+Type=Service
diff --git a/kexi/formeditor/test/kformdesigner_part.rc b/kexi/formeditor/test/kformdesigner_part.rc
new file mode 100644
index 00000000..03c25f19
--- /dev/null
+++ b/kexi/formeditor/test/kformdesigner_part.rc
@@ -0,0 +1,125 @@
+<!DOCTYPE kpartgui SYSTEM "kpartgui.dtd">
+<kpartgui name="kfd_part" version="2">
+
+<MenuBar>
+ <Menu name="edit" noMerge="1">
+ <Action name="edit_undo" group="edit_undo_merge"/>
+ <Action name="edit_redo" group="edit_undo_merge"/>
+ <Separator group="edit_undo_merge"/>
+ <Action name="edit_cut" group="edit_paste_merge"/>
+ <Action name="edit_copy" group="edit_paste_merge"/>
+ <Action name="edit_paste" group="edit_paste_merge"/>
+ <Action name="edit_delete" group="edit_paste_merge"/>
+ <Action name="clear_contents" group="edit_paste_merge"/>
+ <Action name="edit_select_all" group="edit_select_merge"/>
+ </Menu>
+ <Menu name="tools" noMerge="1">
+ <Merge/>
+ <Separator/>
+ <Action name="taborder"/>
+ <Action name="change_style"/>
+ <Action name="pixmap_collection"/>
+ <Action name="form_connections"/>
+ </Menu>
+ <Menu name="widgets" noMerge="1">
+ <text>&amp;Widgets</text>
+ <Merge/>
+ <Action name="pointer"/>
+ <Action name="drag_connection"/>
+ <Separator/>
+ <Action name="library_widget_SubForm"/>
+ <Action name="library_widget_QGroupBox"/>
+ <Action name="library_widget_KFDTabWidget"/>
+ <Action name="library_widget_QWidgetStack"/>
+ <Action name="library_widget_QFrame"/>
+ <Separator/>
+ <Action name="library_widget_KLineEdit"/>
+ <Action name="library_widget_QLabel"/>
+ <Action name="library_widget_KexiPictureLabel"/>
+ <Action name="library_widget_KPushButton"/>
+ <Action name="library_widget_QRadioButton"/>
+ <Action name="library_widget_QCheckBox"/>
+ <Action name="library_widget_KIntSpinBox"/>
+ <Action name="library_widget_KComboBox"/>
+ <Action name="library_widget_KListBox"/>
+ <Action name="library_widget_KTextEdit"/>
+ <Action name="library_widget_KListView"/>
+ <Action name="library_widget_QSlider"/>
+ <Action name="library_widget_KProgress"/>
+ <Action name="library_widget_KTimeWidget"/>
+ <Action name="library_widget_KDateWidget"/>
+ <Action name="library_widget_KDateTimeWidget"/>
+ <Action name="library_widget_Line"/>
+ <Action name="library_widget_Spring"/>
+ </Menu>
+ <Menu name="format" noMerge="1">
+ <text>&amp;Format</text>
+ <Action name="snap_to_grid"/>
+ <Separator/>
+ <Action name="layout_menu"/>
+ <Action name="break_layout"/>
+ <Separator/>
+ <Action name="formpart_break_layout"/>
+ <Action name="align_menu"/>
+ <Action name="adjust_size_menu"/>
+ <Separator/>
+ <Action name="format_raise"/>
+ <Action name="format_lower"/>
+ </Menu>
+</MenuBar>
+
+<ToolBar name="fileToolBar" noMerge="1"><text>Main Toolbar</text>
+ <Action name="preview_form"/>
+ <Separator/>
+ <Action name="edit_undo"/>
+ <Action name="edit_redo"/>
+ <Separator/>
+ <Action name="edit_cut"/>
+ <Action name="edit_copy"/>
+ <Action name="edit_paste"/>
+</ToolBar>
+<ToolBar name="containers" fullWidth="false" noMerge="1">
+ <text>Containers</text>
+ <Action name="library_widget_SubForm"/>
+ <Action name="library_widget_QGroupBox"/>
+ <Action name="library_widget_KFDTabWidget"/>
+ <Action name="library_widget_QWidgetStack"/>
+ <Action name="library_widget_QFrame"/>
+</ToolBar>
+<ToolBar name="widgets" fullWidth="false" noMerge="1">
+ <text>Widgets</text>
+ <Action name="pointer"/>
+ <Action name="drag_connection"/>
+ <Separator/>
+ <Action name="library_widget_KLineEdit"/>
+ <Action name="library_widget_QLabel"/>
+ <Action name="library_widget_KexiPictureLabel"/>
+ <Action name="library_widget_KPushButton"/>
+ <Action name="library_widget_QRadioButton"/>
+ <Action name="library_widget_QCheckBox"/>
+ <Action name="library_widget_KIntSpinBox"/>
+ <Action name="library_widget_KComboBox"/>
+ <Action name="library_widget_KListBox"/>
+ <Action name="library_widget_KTextEdit"/>
+ <Action name="library_widget_KListView"/>
+ <Action name="library_widget_QSlider"/>
+ <Action name="library_widget_KProgress"/>
+ <Action name="library_widget_KTimeWidget"/>
+ <Action name="library_widget_KDateWidget"/>
+ <Action name="library_widget_KDateTimeWidget"/>
+ <Action name="library_widget_Line"/>
+ <Action name="library_widget_Spring"/>
+ <ActionList name="undo_actions" />
+</ToolBar>
+<ToolBar name="tools" fullWidth="false" noMerge="1">
+<text>Tools Toolbar</text>
+ <Action name="pixmap_collection"/>
+ <!-- <Action name="change_style"/> !-->
+</ToolBar>
+<ToolBar name="format" fullWidth="false" noMerge="1">
+<text>Format Toolbar</text>
+ <Action name="align_menu"/>
+ <Action name="adjust_size_menu"/>
+</ToolBar>
+
+</kpartgui> \ No newline at end of file
diff --git a/kexi/formeditor/test/kformdesigner_part_shell.rc b/kexi/formeditor/test/kformdesigner_part_shell.rc
new file mode 100644
index 00000000..8163cab3
--- /dev/null
+++ b/kexi/formeditor/test/kformdesigner_part_shell.rc
@@ -0,0 +1,138 @@
+<!DOCTYPE kpartgui SYSTEM "kpartgui.dtd">
+<kpartgui name="kfd_part" version="2">
+
+<MenuBar>
+ <Menu name="file" noMerge="1">
+ <Action name="file_new"/>
+ <Action name="file_open"/>
+ <Separator />
+ <Action name="file_save"/>
+ <Action name="file_save_as"/>
+ <Separator/>
+ </Menu>
+ <Menu name="edit" noMerge="1">
+ <Action name="edit_undo" group="edit_undo_merge"/>
+ <Action name="edit_redo" group="edit_undo_merge"/>
+ <Separator group="edit_undo_merge"/>
+ <Action name="edit_cut" group="edit_paste_merge"/>
+ <Action name="edit_copy" group="edit_paste_merge"/>
+ <Action name="edit_paste" group="edit_paste_merge"/>
+ <Action name="edit_delete" group="edit_paste_merge"/>
+ <Action name="clear_contents" group="edit_paste_merge"/>
+ <Separator group="edit_select_merge"/>
+ <Action name="edit_select_all" group="edit_select_merge"/>
+ <Separator group="edit_paste_merge"/>
+ </Menu>
+ <Menu name="view" noMerge="1">
+ <Action name="preview_form"/>
+ </Menu>
+ <Menu name="tools" noMerge="1">
+ <Action name="taborder"/>
+ <Action name="change_style"/>
+ <Action name="pixmap_collection"/>
+ <Action name="form_connections"/>
+ </Menu>
+ <Menu name="widgets" noMerge="1">
+ <text>&amp;Widgets</text>
+ <Merge/>
+ <Action name="pointer"/>
+ <Action name="drag_connection"/>
+ <Separator/>
+ <Action name="library_widget_SubForm"/>
+ <Action name="library_widget_QGroupBox"/>
+ <Action name="library_widget_KFDTabWidget"/>
+ <Action name="library_widget_QWidgetStack"/>
+ <Action name="library_widget_QFrame"/>
+ <Separator/>
+ <Action name="library_widget_KLineEdit"/>
+ <Action name="library_widget_QLabel"/>
+ <Action name="library_widget_KexiPictureLabel"/>
+ <Action name="library_widget_KPushButton"/>
+ <Action name="library_widget_QRadioButton"/>
+ <Action name="library_widget_QCheckBox"/>
+ <Action name="library_widget_KIntSpinBox"/>
+ <Action name="library_widget_KComboBox"/>
+ <Action name="library_widget_KListBox"/>
+ <Action name="library_widget_KTextEdit"/>
+ <Action name="library_widget_KListView"/>
+ <Action name="library_widget_QSlider"/>
+ <Action name="library_widget_KProgress"/>
+ <Action name="library_widget_KTimeWidget"/>
+ <Action name="library_widget_KDateWidget"/>
+ <Action name="library_widget_KDateTimeWidget"/>
+ <Action name="library_widget_Line"/>
+ <Action name="library_widget_Spring"/>
+ </Menu>
+ <Menu name="format" noMerge="1">
+ <text>&amp;Format</text>
+ <Action name="snap_to_grid"/>
+ <Separator/>
+ <Action name="layout_menu"/>
+ <Action name="break_layout"/>
+ <Separator/>
+ <Action name="align_menu"/>
+ <Action name="adjust_size_menu"/>
+ <Separator/>
+ <Action name="format_raise"/>
+ <Action name="format_lower"/>
+ </Menu>
+</MenuBar>
+
+<ToolBar name="fileToolBar" noMerge="1"><text>Main Toolbar</text>
+ <Action name="file_new"/>
+ <Action name="file_open"/>
+ <Action name="file_save"/>
+ <Action name="preview_form"/>
+ <Separator/>
+ <Action name="edit_undo"/>
+ <Action name="edit_redo"/>
+ <Separator/>
+ <Action name="edit_cut"/>
+ <Action name="edit_copy"/>
+ <Action name="edit_paste"/>
+</ToolBar>
+<ToolBar name="containers" fullWidth="false" noMerge="1">
+ <text>Containers</text>
+ <Action name="library_widget_SubForm"/>
+ <Action name="library_widget_QGroupBox"/>
+ <Action name="library_widget_KFDTabWidget"/>
+ <Action name="library_widget_QWidgetStack"/>
+ <Action name="library_widget_QFrame"/>
+</ToolBar>
+<ToolBar name="widgets" fullWidth="false" noMerge="1">
+ <text>Widgets</text>
+ <Action name="pointer"/>
+ <Action name="drag_connection"/>
+ <Separator/>
+ <Action name="library_widget_KLineEdit"/>
+ <Action name="library_widget_QLabel"/>
+ <Action name="library_widget_KexiPictureLabel"/>
+ <Action name="library_widget_KPushButton"/>
+ <Action name="library_widget_QRadioButton"/>
+ <Action name="library_widget_QCheckBox"/>
+ <Action name="library_widget_KIntSpinBox"/>
+ <Action name="library_widget_KComboBox"/>
+ <Action name="library_widget_KListBox"/>
+ <Action name="library_widget_KTextEdit"/>
+ <Action name="library_widget_KListView"/>
+ <Action name="library_widget_QSlider"/>
+ <Action name="library_widget_KProgress"/>
+ <Action name="library_widget_KTimeWidget"/>
+ <Action name="library_widget_KDateWidget"/>
+ <Action name="library_widget_KDateTimeWidget"/>
+ <Action name="library_widget_Line"/>
+ <Action name="library_widget_Spring"/>
+ <ActionList name="undo_actions" />
+</ToolBar>
+<ToolBar name="tools" fullWidth="false" noMerge="1">
+<text>Tools Toolbar</text>
+ <Action name="pixmap_collection"/>
+ <!-- <Action name="change_style"/> !-->
+</ToolBar>
+<ToolBar name="format" fullWidth="false" noMerge="1">
+<text>Format Toolbar</text>
+ <Action name="align_menu"/>
+ <Action name="adjust_size_menu"/>
+</ToolBar>
+
+</kpartgui> \ No newline at end of file
diff --git a/kexi/formeditor/test/main.cpp b/kexi/formeditor/test/main.cpp
new file mode 100644
index 00000000..f4866f29
--- /dev/null
+++ b/kexi/formeditor/test/main.cpp
@@ -0,0 +1,81 @@
+/* This file is part of the KDE project
+ Copyright (C) 2004 Cedric Pasteur <cedric.pasteur@free.fr>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+*/
+#include "kfd_mainwindow.h"
+
+#include <kapplication.h>
+#include <kiconloader.h>
+#include <kaboutdata.h>
+#include <kcmdlineargs.h>
+#include <klocale.h>
+
+static const char *description =
+ I18N_NOOP("KFormDesigner");
+
+static const char *version = "0.3";
+
+static KCmdLineOptions options[] =
+{
+ { "+[URL]", I18N_NOOP( "Document to open" ), 0 },
+ KCmdLineLastOption
+};
+
+int main(int argc, char **argv)
+{
+ KAboutData about("kformdesigner", I18N_NOOP("KFormDesigner"), version, description,
+ KAboutData::License_LGPL, "(C) 2003-2005 Kexi Team", 0, 0);
+ about.addCredit( "Lucijan Busch", "Original author", 0, "lucijan@kde.org" );
+ about.addAuthor( "Cedric Pasteur", 0, "cedric.pasteur@free.fr");
+ about.addCredit( "Jarosław Staniek", "Win32 version, some icons, many fixes, ideas and bug reports", "js@iidea.pl", 0);
+ about.addCredit( "Kristof Borrey ", "Icons", 0, "kristof.borrey@skynet.be" );
+ KCmdLineArgs::init(argc, argv, &about);
+ KCmdLineArgs::addCmdLineOptions(options);
+ KApplication app;
+
+ KGlobal::iconLoader()->addAppDir("kexi");
+
+ KFDMainWindow *v = new KFDMainWindow();
+ if (!v->centralWidget()) { //KFD part could be not found
+ delete v;
+ return 1;
+ }
+ app.setMainWidget(v);
+ v->show();
+
+
+
+ // see if we are starting with session management
+ if (app.isRestored())
+ {
+ RESTORE(KFDMainWindow);
+ }
+ else
+ {
+ // no session.. just start up normally
+ KCmdLineArgs *args = KCmdLineArgs::parsedArgs();
+ if (args->count() >= 1)
+ {
+ for (int i = 0; i < args->count(); i++)
+ /** @todo report loading errors here */
+ v->loadUIFile(args->url(i));
+ }
+ args->clear();
+ }
+
+ return app.exec();
+}
diff --git a/kexi/formeditor/utils.cpp b/kexi/formeditor/utils.cpp
new file mode 100644
index 00000000..0c3acf59
--- /dev/null
+++ b/kexi/formeditor/utils.cpp
@@ -0,0 +1,184 @@
+/* This file is part of the KDE project
+ Copyright (C) 2004 Cedric Pasteur <cedric.pasteur@free.fr>
+ Copyright (C) 2007 Jaroslaw Staniek <js@iidea.pl>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+*/
+
+#include <qcursor.h>
+#include <qobjectlist.h>
+#include <qtabwidget.h>
+#include <qtabbar.h>
+
+#include <kdebug.h>
+#include <kexiutils/utils.h>
+
+#include "form.h"
+#include "objecttree.h"
+#include "utils.h"
+
+using namespace KFormDesigner;
+
+void
+KFormDesigner::removeChildrenFromList(WidgetList &list)
+{
+ for(WidgetListIterator it(list); it.current() != 0; ++it) {
+ QWidget *w = it.current();
+
+ // If any widget in the list is a child of this widget, we remove it from the list
+ for(WidgetListIterator it2(list); it2.current() != 0; ++it2) {
+ QWidget *widg = it2.current();
+ if((w != widg) && (w->child(widg->name())))
+ {
+ kdDebug() << "Removing the widget " << widg->name() << "which is a child of " << w->name() << endl;
+ list.remove(widg);
+ }
+ }
+ }
+}
+
+void
+KFormDesigner::installRecursiveEventFilter(QObject *object, QObject *container)
+{
+ if(!object || !container|| !object->isWidgetType())
+ return;
+
+ kdDebug() << "Installing event filter on widget: " << object->name() << " directed to " << container->name() << endl;
+ object->installEventFilter(container);
+ if(((QWidget*)object)->ownCursor())
+ ((QWidget*)object)->setCursor(QCursor(Qt::ArrowCursor));
+
+ if(!object->children())
+ return;
+
+ QObjectList list = *(object->children());
+ for(QObject *obj = list.first(); obj; obj = list.next())
+ installRecursiveEventFilter(obj, container);
+}
+
+void
+KFormDesigner::removeRecursiveEventFilter(QObject *object, QObject *container)
+{
+ object->removeEventFilter(container);
+ if(!object->isWidgetType())
+ return;
+ if(!object->children())
+ return;
+
+ QObjectList list = *(object->children());
+ for(QObject *obj = list.first(); obj; obj = list.next())
+ removeRecursiveEventFilter(obj, container);
+}
+
+void
+KFormDesigner::setRecursiveCursor(QWidget *w, Form *form)
+{
+ ObjectTreeItem *tree = form->objectTree()->lookup(w->name());
+ if(tree && ((tree->modifiedProperties()->contains("cursor")) || !tree->children()->isEmpty())
+ && !w->inherits("QLineEdit") && !w->inherits("QTextEdit")
+ ) //fix weird behaviour
+ return; // if the user has set a cursor for this widget or this is a container, don't change it
+
+ if(w->ownCursor())
+ w->setCursor(Qt::ArrowCursor);
+
+ QObjectList *l = w->queryList( "QWidget" );
+ for(QObject *o = l->first(); o; o = l->next())
+ ((QWidget*)o)->setCursor(Qt::ArrowCursor);
+ delete l;
+}
+
+QSize
+KFormDesigner::getSizeFromChildren(QWidget *w, const char *inheritClass)
+{
+ int tmpw = 0, tmph = 0;
+ QObjectList *list = w->queryList(inheritClass, 0, false, false);
+ for(QObject *o = list->first(); o; o = list->next()) {
+ QRect r = ((QWidget*)o)->geometry();
+ tmpw = QMAX(tmpw, r.right());
+ tmph = QMAX(tmph, r.bottom());
+ }
+
+ delete list;
+ return QSize(tmpw, tmph) + QSize(10, 10);
+}
+
+// -----------------
+
+HorWidgetList::HorWidgetList(QWidget *topLevelWidget)
+ : WidgetList()
+ , m_topLevelWidget(topLevelWidget)
+{
+}
+
+HorWidgetList::~HorWidgetList()
+{
+}
+
+int HorWidgetList::compareItems(QPtrCollection::Item item1, QPtrCollection::Item item2)
+{
+ QWidget *w1 = static_cast<QWidget*>(item1);
+ QWidget *w2 = static_cast<QWidget*>(item2);
+ return w1->mapTo(m_topLevelWidget, QPoint(0,0)).x() - w2->mapTo(m_topLevelWidget, QPoint(0,0)).x();
+}
+
+// -----------------
+
+VerWidgetList::VerWidgetList(QWidget *topLevelWidget)
+ : WidgetList()
+ , m_topLevelWidget(topLevelWidget)
+{
+}
+
+VerWidgetList::~VerWidgetList()
+{
+}
+
+int VerWidgetList::compareItems(QPtrCollection::Item item1, QPtrCollection::Item item2)
+{
+ QWidget *w1 = static_cast<QWidget*>(item1);
+ QWidget *w2 = static_cast<QWidget*>(item2);
+
+ int y1, y2;
+ QObject *page1 = 0;
+ TabWidget *tw1 = KFormDesigner::findParent<KFormDesigner::TabWidget>(w1, "KFormDesigner::TabWidget", page1);
+ if (tw1) // special case
+ y1 = w1->mapTo(m_topLevelWidget, QPoint(0,0)).y() + tw1->tabBarHeight() -2 -2;
+ else
+ y1 = w1->mapTo(m_topLevelWidget, QPoint(0,0)).y();
+
+ QObject *page2 = 0;
+ TabWidget *tw2 = KFormDesigner::findParent<KFormDesigner::TabWidget>(w2, "KFormDesigner::TabWidget", page2);
+ if (tw1 && tw2 && tw1 == tw2 && page1 != page2) {
+ // this sorts widgets by tabs there're put in
+ return tw1->indexOf(static_cast<QWidget*>(page1)) - tw2->indexOf(static_cast<QWidget*>(page2));
+ }
+
+ if (tw2) // special case
+ y2 = w2->mapTo(m_topLevelWidget, QPoint(0,0)).y() + tw2->tabBarHeight() -2 -2;
+ else
+ y2 = w2->mapTo(m_topLevelWidget, QPoint(0,0)).y();
+
+ kdDebug() << w1->name() << ": " << y1 << " "
+ << " | " << w2->name() << ": " << y2 << endl;
+
+
+ //kdDebug() << w1->name() << ": " << w1->mapTo(m_topLevelWidget, QPoint(0,0)) << " " << w1->y()
+ //<< " | " << w2->name() << ":" /*<< w2->mapFrom(m_topLevelWidget, QPoint(0,w2->y()))*/ << " " << w2->y() << endl;
+ return y1 - y2;
+}
+
+#include "utils.moc"
diff --git a/kexi/formeditor/utils.h b/kexi/formeditor/utils.h
new file mode 100644
index 00000000..d5384e45
--- /dev/null
+++ b/kexi/formeditor/utils.h
@@ -0,0 +1,113 @@
+/* This file is part of the KDE project
+ Copyright (C) 2004 Cedric Pasteur <cedric.pasteur@free.fr>
+ Copyright (C) 2007 Jaroslaw Staniek <js@iidea.pl>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+*/
+
+#ifndef FORMEDITORUTILS_H
+#define FORMEDITORUTILS_H
+
+#include <qptrlist.h>
+#include <qtabbar.h>
+#include <qtabwidget.h>
+
+//! @todo replace QTabWidget by KTabWidget after the bug with & is fixed:
+#define TabWidgetBase QTabWidget
+//#define USE_KTabWidget //todo: uncomment
+
+namespace KFormDesigner {
+
+class Form;
+
+/*! \return parent object of \a o that inherits \a className or NULL if no such parent
+ If the parent is found, \a prevPrev is set to a child of child of the parent,
+ what for TabWidget means the page widget. */
+template<class type>
+type* findParent(QObject* o, const char* className, QObject* &prevPrev)
+{
+ if (!o || !className || className[0]=='\0')
+ return 0;
+ QObject *prev = o;
+ while ( ((o=o->parent())) && !o->inherits(className) ) {
+ prevPrev = prev;
+ prev = o;
+ }
+ return static_cast<type*>(o);
+}
+
+//! A tab widget providing information about height of the tab bar.
+class KFORMEDITOR_EXPORT TabWidget : public TabWidgetBase
+{
+ Q_OBJECT
+ public:
+ TabWidget(QWidget *parent, const char *name)
+ : TabWidgetBase(parent, name) {}
+ virtual ~TabWidget() {}
+ int tabBarHeight() const { return tabBar()->height(); }
+};
+
+//! @short A list of widget pointers.
+typedef QPtrList<QWidget> WidgetList;
+
+//! @short An iterator for WidgetList.
+typedef QPtrListIterator<QWidget> WidgetListIterator;
+
+//! @short A helper for sorting widgets horizontally
+class HorWidgetList : public WidgetList
+{
+ public:
+ HorWidgetList(QWidget *topLevelWidget);
+ virtual ~HorWidgetList();
+ protected:
+ virtual int compareItems(QPtrCollection::Item item1, QPtrCollection::Item item2);
+ QWidget *m_topLevelWidget;
+};
+
+//! @short A helper for sorting widgets vertically
+class VerWidgetList : public WidgetList
+{
+ public:
+ VerWidgetList(QWidget *topLevelWidget);
+ virtual ~VerWidgetList();
+ protected:
+ virtual int compareItems(QPtrCollection::Item item1, QPtrCollection::Item item2);
+ QWidget *m_topLevelWidget;
+};
+
+/*! This function is used to remove all the child widgets from a list, and
+ keep only the "toplevel" ones. */
+KFORMEDITOR_EXPORT void removeChildrenFromList(WidgetList &list);
+
+/*! This helper function install an event filter on \a object and all of its
+ children, directed to \a container.
+ This is necessary to filter events for composed widgets. */
+KFORMEDITOR_EXPORT void installRecursiveEventFilter(QObject *object, QObject *container);
+
+/*! This helper function removes an event filter installed before
+ on \a object and all of its children.
+ This is necessary to filter events for composed widgets. */
+KFORMEDITOR_EXPORT void removeRecursiveEventFilter(QObject *object, QObject *container);
+
+KFORMEDITOR_EXPORT void setRecursiveCursor(QWidget *w, Form *form);
+
+/*! \return the size of \a w children. This can be used eg to get widget's sizeHint. */
+KFORMEDITOR_EXPORT QSize getSizeFromChildren(QWidget *widget, const char *inheritClass="QWidget");
+
+}
+
+#endif
+
diff --git a/kexi/formeditor/widgetfactory.cpp b/kexi/formeditor/widgetfactory.cpp
new file mode 100644
index 00000000..8122013c
--- /dev/null
+++ b/kexi/formeditor/widgetfactory.cpp
@@ -0,0 +1,725 @@
+/* This file is part of the KDE project
+ Copyright (C) 2003 Lucijan Busch <lucijan@gmx.at>
+ Copyright (C) 2004 Cedric Pasteur <cedric.pasteur@free.fr>
+ Copyright (C) 2004-2006 Jaroslaw Staniek <js@iidea.pl>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+*/
+
+#include "widgetfactory.h"
+
+#include <qcursor.h>
+#include <qobjectlist.h>
+#include <qdict.h>
+#include <qmetaobject.h>
+
+#include <kdebug.h>
+#include <klocale.h>
+//#ifdef KEXI_KTEXTEDIT
+#include <ktextedit.h>
+//#else
+#include <klineedit.h>
+//#endif
+#include <kdialogbase.h>
+#include <keditlistbox.h>
+#include <kxmlguiclient.h>
+#include <kactioncollection.h>
+
+#include "richtextdialog.h"
+#include "editlistviewdialog.h"
+#include "resizehandle.h"
+#include "formmanager.h"
+#include "form.h"
+#include "container.h"
+#include "objecttree.h"
+#include "widgetlibrary.h"
+#include "utils.h"
+#include "widgetpropertyset.h"
+#include "widgetwithsubpropertiesinterface.h"
+#include <koproperty/property.h>
+
+using namespace KFormDesigner;
+
+///// Widget Info //////////////////////////
+
+WidgetInfo::WidgetInfo(WidgetFactory *f)
+ : m_inheritedClass(0)
+ , m_overriddenAlternateNames(0)
+ , m_factory(f)
+ , m_propertiesWithDisabledAutoSync(0)
+ , m_customTypesForProperty(0)
+{
+}
+
+WidgetInfo::WidgetInfo(WidgetFactory *f, const char* parentFactoryName,
+ const char* inheritedClassName)
+ : m_parentFactoryName( QCString("kformdesigner_")+parentFactoryName )
+ , m_inheritedClassName(inheritedClassName)
+ , m_inheritedClass(0)
+ , m_overriddenAlternateNames(0)
+ , m_factory(f)
+ , m_propertiesWithDisabledAutoSync(0)
+ , m_customTypesForProperty(0)
+{
+ m_class = inheritedClassName;
+}
+
+WidgetInfo::~WidgetInfo()
+{
+ delete m_overriddenAlternateNames;
+ delete m_propertiesWithDisabledAutoSync;
+ delete m_customTypesForProperty;
+}
+
+void WidgetInfo::addAlternateClassName(const QCString& alternateName, bool override)
+{
+ m_alternateNames += alternateName;
+ if (override) {
+ if (!m_overriddenAlternateNames)
+ m_overriddenAlternateNames = new QAsciiDict<char>(101);
+ m_overriddenAlternateNames->insert(alternateName, (char*)1);
+ }
+ else {
+ if (m_overriddenAlternateNames)
+ m_overriddenAlternateNames->take(alternateName);
+ }
+}
+
+bool WidgetInfo::isOverriddenClassName(const QCString& alternateName) const
+{
+ return m_overriddenAlternateNames && (m_overriddenAlternateNames->find(alternateName) != 0);
+}
+
+void WidgetInfo::setAutoSyncForProperty(const char *propertyName, tristate flag)
+{
+ if (!m_propertiesWithDisabledAutoSync) {
+ if (~flag)
+ return;
+ m_propertiesWithDisabledAutoSync = new QAsciiDict<char>(101);
+ }
+
+ if (~flag) {
+ m_propertiesWithDisabledAutoSync->remove(propertyName);
+ }
+ else {
+ m_propertiesWithDisabledAutoSync->insert(propertyName, flag==true ? (char*)1 : (char*)2);
+ }
+}
+
+tristate WidgetInfo::autoSyncForProperty(const char *propertyName) const
+{
+ char* flag = m_propertiesWithDisabledAutoSync ? m_propertiesWithDisabledAutoSync->find(propertyName) : 0;
+ if (!flag)
+ return cancelled;
+ return flag==(char*)1 ? true : false;
+}
+
+void WidgetInfo::setCustomTypeForProperty(const char *propertyName, int type)
+{
+ if (!propertyName || type==KoProperty::Auto)
+ return;
+ if (!m_customTypesForProperty) {
+ m_customTypesForProperty = new QMap<QCString,int>();
+ }
+ m_customTypesForProperty->replace(propertyName, type);
+}
+
+int WidgetInfo::customTypeForProperty(const char *propertyName) const
+{
+ if (!m_customTypesForProperty || !m_customTypesForProperty->contains(propertyName))
+ return KoProperty::Auto;
+ return (*m_customTypesForProperty)[propertyName];
+}
+
+
+///// Widget Factory //////////////////////////
+
+WidgetFactory::WidgetFactory(QObject *parent, const char *name)
+ : QObject(parent, (const char*)(QCString("kformdesigner_")+name))
+{
+ m_showAdvancedProperties = true;
+ m_classesByName.setAutoDelete(true);
+ m_hiddenClasses = 0;
+ m_guiClient = 0;
+}
+
+WidgetFactory::~WidgetFactory()
+{
+ delete m_hiddenClasses;
+}
+
+void WidgetFactory::addClass(WidgetInfo *w)
+{
+ WidgetInfo *oldw = m_classesByName[w->className()];
+ if (oldw==w)
+ return;
+ if (oldw) {
+ kdWarning() << "WidgetFactory::addClass(): class with name '" << w->className()
+ << "' already exists for factory '" << name() << "'" << endl;
+ return;
+ }
+ m_classesByName.insert( w->className(), w );
+}
+
+void WidgetFactory::hideClass(const char *classname)
+{
+ if (!m_hiddenClasses)
+ m_hiddenClasses = new QAsciiDict<char>(101, false);
+ m_hiddenClasses->insert(classname, (char*)1);
+}
+
+void
+WidgetFactory::createEditor(const QCString &classname, const QString &text,
+ QWidget *w, Container *container, QRect geometry,
+ int align, bool useFrame, bool multiLine, BackgroundMode background)
+{
+//#ifdef KEXI_KTEXTEDIT
+ if (multiLine) {
+ KTextEdit *textedit = new KTextEdit(text, QString::null, w->parentWidget());
+ textedit->setTextFormat(Qt::PlainText);
+ textedit->setAlignment(align);
+ if (dynamic_cast<QTextEdit*>(w)) {
+ textedit->setWordWrap(dynamic_cast<QTextEdit*>(w)->wordWrap());
+ textedit->setWrapPolicy(dynamic_cast<QTextEdit*>(w)->wrapPolicy());
+ }
+ textedit->setPalette(w->palette());
+ textedit->setFont(w->font());
+ textedit->setResizePolicy(QScrollView::Manual);
+ textedit->setGeometry(geometry);
+ if(background == Qt::NoBackground)
+ textedit->setBackgroundMode(w->backgroundMode());
+ else
+ textedit->setBackgroundMode(background);
+// textedit->setPaletteBackgroundColor(textedit->colorGroup().color( QColorGroup::Base ));
+ textedit->setPaletteBackgroundColor(w->paletteBackgroundColor());
+ for(int i =0; i <= textedit->paragraphs(); i++)
+ textedit->setParagraphBackgroundColor(i, w->paletteBackgroundColor());
+ textedit->selectAll(true);
+ textedit->setColor(w->paletteForegroundColor());
+ textedit->selectAll(false);
+ textedit->moveCursor(QTextEdit::MoveEnd, false);
+ textedit->setParagraphBackgroundColor(0, w->paletteBackgroundColor());
+ textedit->setVScrollBarMode(QScrollView::AlwaysOff); //ok?
+ textedit->setHScrollBarMode(QScrollView::AlwaysOff); //ok?
+ textedit->installEventFilter(this);
+ textedit->setFrameShape(useFrame ? QFrame::LineEditPanel : QFrame::NoFrame);
+ textedit->setMargin(2); //to move away from resize handle
+ textedit->show();
+ textedit->setFocus();
+ textedit->selectAll();
+ setEditor(w, textedit);
+
+ connect(textedit, SIGNAL(textChanged()), this, SLOT(slotTextChanged()));
+ connect(w, SIGNAL(destroyed()), this, SLOT(widgetDestroyed()));
+ connect(textedit, SIGNAL(destroyed()), this, SLOT(editorDeleted()));
+//#else
+ }
+ else {
+ KLineEdit *editor = new KLineEdit(text, w->parentWidget());
+ editor->setAlignment(align);
+ editor->setPalette(w->palette());
+ editor->setFont(w->font());
+ editor->setGeometry(geometry);
+ if(background == Qt::NoBackground)
+ editor->setBackgroundMode(w->backgroundMode());
+ else
+ editor->setBackgroundMode(background);
+ editor->installEventFilter(this);
+ editor->setFrame(useFrame);
+ editor->setMargin(2); //to move away from resize handle
+ editor->show();
+ editor->setFocus();
+ editor->selectAll();
+ connect(editor, SIGNAL(textChanged(const QString&)), this, SLOT(changeTextInternal(const QString&)));
+ connect(w, SIGNAL(destroyed()), this, SLOT(widgetDestroyed()));
+ connect(editor, SIGNAL(destroyed()), this, SLOT(editorDeleted()));
+
+ setEditor(w, editor);
+// m_editor = editor;
+ }
+ //copy properties if available
+ WidgetWithSubpropertiesInterface* subpropIface = dynamic_cast<WidgetWithSubpropertiesInterface*>(w);
+ QWidget *subwidget = (subpropIface && subpropIface->subwidget()) ? subpropIface->subwidget() : w;
+ if (-1!=m_editor->metaObject()->findProperty("margin", true) && -1!=subwidget->metaObject()->findProperty("margin", true))
+ m_editor->setProperty("margin", subwidget->property("margin"));
+//#endif
+//js m_handles = new ResizeHandleSet(w, container->form(), true);
+ m_handles = container->form()->resizeHandlesForWidget(w);
+ if (m_handles) {
+ m_handles->setEditingMode(true);
+ m_handles->raise();
+ }
+
+ ObjectTreeItem *tree = container->form()->objectTree()->lookup(w->name());
+ if(!tree)
+ return;
+ tree->eventEater()->setContainer(this);
+
+ //m_widget = w;
+ setWidget(w, container);
+ m_editedWidgetClass = classname;
+ m_firstText = text;
+// m_container = container;
+
+ changeTextInternal(text); // to update size of the widget
+}
+
+void
+WidgetFactory::disableFilter(QWidget *w, Container *container)
+{
+ ObjectTreeItem *tree = container->form()->objectTree()->lookup(w->name());
+ if(!tree)
+ return;
+ tree->eventEater()->setContainer(this);
+
+ w->setFocus();
+//js m_handles = new ResizeHandleSet(w, container->form(), true);
+ m_handles = container->form()->resizeHandlesForWidget(w);
+ if (m_handles) {
+ m_handles->setEditingMode(true);
+ m_handles->raise();
+ }
+
+ //m_widget = w;
+ setWidget(w, container);
+// m_container = container;
+ setEditor(w, 0);
+// m_editor = 0;
+
+ // widget is disabled, so we re-enable it while editing
+ if(!tree->isEnabled()) {
+ QPalette p = w->palette();
+ QColorGroup cg = p.active();
+ p.setActive(p.disabled());
+ p.setDisabled(cg);
+ w->setPalette(p);
+ }
+
+ connect(w, SIGNAL(destroyed()), this, SLOT(widgetDestroyed()));
+}
+
+bool
+WidgetFactory::editList(QWidget *w, QStringList &list)
+{
+ KDialogBase dialog(w->topLevelWidget(), "stringlist_dialog", true, i18n("Edit List of Items"),
+ KDialogBase::Ok|KDialogBase::Cancel, KDialogBase::Ok, false);
+
+ KEditListBox *edit = new KEditListBox(i18n("Contents of %1").arg(w->name()), &dialog, "editlist");
+ dialog.setMainWidget(edit);
+ edit->insertStringList(list);
+// edit->show();
+
+ if(dialog.exec() == QDialog::Accepted)
+ {
+ list = edit->items();
+ return true;
+ }
+ return false;
+}
+
+bool
+WidgetFactory::editRichText(QWidget *w, QString &text)
+{
+ RichTextDialog dlg(w, text);
+ if(dlg.exec()== QDialog::Accepted)
+ {
+ text = dlg.text();
+ return true;
+ }
+ return false;
+}
+
+void
+WidgetFactory::editListView(QListView *listview)
+{
+ EditListViewDialog dlg(((QWidget*)listview)->topLevelWidget());
+ //dlg.exec(listview);
+}
+
+bool
+WidgetFactory::eventFilter(QObject *obj, QEvent *ev)
+{
+ if( ((ev->type() == QEvent::Resize) || (ev->type() == QEvent::Move) ) && (obj == m_widget) && editor(m_widget)) {
+ // resize widget using resize handles
+ QWidget *ed = editor(m_widget);
+ resizeEditor(ed, m_widget, m_widget->className());
+ }
+ else if((ev->type() == QEvent::Paint) && (obj == m_widget) && editor(m_widget)) {
+ // paint event for container edited (eg button group)
+ return m_container->eventFilter(obj, ev);
+ }
+ else if((ev->type() == QEvent::MouseButtonPress) && (obj == m_widget) && editor(m_widget)) {
+ // click outside editor --> cancel editing
+ Container *cont = m_container;
+ resetEditor();
+ return cont->eventFilter(obj, ev);
+ }
+
+ if(ev->type() == QEvent::FocusOut)
+ {
+ QWidget *w = editor(m_widget);
+ if (!w)
+ w = (QWidget *)m_widget;
+ if(obj != (QObject *)w)
+ return false;
+
+ QWidget *focus = w->topLevelWidget()->focusWidget();
+ if(focus && w != focus && !w->child(focus->name(), focus->className()))
+ resetEditor();
+ }
+ else if(ev->type() == QEvent::KeyPress)
+ {
+ QWidget *w = editor(m_widget);
+ if (!w)
+ w = (QWidget *)m_widget;
+ if(obj != (QObject *)w)
+ return false;
+
+ QKeyEvent *e = static_cast<QKeyEvent*>(ev);
+ if(((e->key() == Qt::Key_Return) || (e->key() == Qt::Key_Enter)) && (e->state() != AltButton))
+ resetEditor();
+ if(e->key() == Qt::Key_Escape)
+ {
+ setEditorText(m_firstText);
+ //changeText(m_firstText);
+ resetEditor();
+ }
+ }
+ else if(ev->type() == QEvent::ContextMenu) {
+ QWidget *w = editor(m_widget);
+ if (!w)
+ w = (QWidget *)m_widget;
+ if(obj != (QObject *)w)
+ return false;
+
+ return true;
+ }
+// if(obj == m_widget)
+// return m_container->eventFilter(obj, ev);
+// else
+ return false;
+}
+
+void
+WidgetFactory::resetEditor()
+{
+ if (m_container)
+ m_container->stopInlineEditing();
+
+ QWidget *ed = editor(m_widget);
+ if(m_widget)
+ {
+ ObjectTreeItem *tree = m_container ? m_container->form()->objectTree()->lookup(m_widget->name()) : 0;
+ if(!tree)
+ {
+ kdDebug() << "WidgetFactory::resetEditor() : error cannot found a tree item " << endl;
+ return;
+ }
+ tree->eventEater()->setContainer(m_container);
+ if(m_widget) {// && !ed)
+ setRecursiveCursor(m_widget, m_container->form());
+ if (m_widget->inherits("QLineEdit") || m_widget->inherits("QTextEdit")) { //fix weird behaviour
+ m_widget->unsetCursor();
+ m_widget->setCursor(Qt::ArrowCursor);
+ }
+ }
+
+ // disable again the widget
+ if(!ed && !tree->isEnabled()) {
+ QPalette p = m_widget->palette();
+ QColorGroup cg = p.active();
+ p.setActive(p.disabled());
+ p.setDisabled(cg);
+ m_widget->setPalette(p);
+ }
+ }
+ if(ed)
+ {
+ changeTextInternal(editorText());
+ disconnect(ed, 0, this, 0);
+ ed->deleteLater();
+ }
+
+ if(m_widget)
+ {
+ disconnect(m_widget, 0, this, 0);
+ m_widget->repaint();
+ }
+
+//js delete m_handles;
+ if (m_handles) {
+ m_handles->setEditingMode(false);
+ }
+ setEditor(m_widget, 0);
+// m_editor = 0;
+ setWidget(0, 0);
+ //m_widget = 0;
+ m_handles = 0;
+// m_container = 0;
+}
+
+void
+WidgetFactory::widgetDestroyed()
+{
+ if(m_editor)
+ {
+ m_editor->deleteLater();
+ m_editor = 0;
+ }
+
+//js delete m_handles;
+ if (m_handles) {
+ m_handles->setEditingMode(false);
+
+ }
+ m_widget = 0;
+ m_handles = 0;
+ m_container = 0;
+}
+
+void
+WidgetFactory::editorDeleted()
+{
+//js delete m_handles;
+ if (m_handles) {
+ m_handles->setEditingMode(false);
+ }
+ setEditor(m_widget, 0);
+ setWidget(0, 0);
+// m_widget = 0;
+ m_handles = 0;
+// m_container = 0;
+}
+
+void
+WidgetFactory::changeProperty(const char *name, const QVariant &value, Form *form)
+//WidgetFactory::changeProperty(const char *name, const QVariant &value, Container *container)
+{
+// if (!form->manager())
+// return;
+ if(form->selectedWidgets()->count() > 1)
+ { // If eg multiple labels are selected, we only want to change the text of one of them (the one the user cliked on)
+ if(m_widget)
+ m_widget->setProperty(name, value);
+ else
+ form->selectedWidgets()->first()->setProperty(name, value);
+ }
+ else
+ {
+ WidgetPropertySet *set = KFormDesigner::FormManager::self()->propertySet();
+ if(set->contains(name))
+ (*set)[name] = value;
+ }
+}
+
+/*
+void
+WidgetFactory::addPropertyDescription(Container *container, const char *prop, const QString &desc)
+{
+ WidgetPropertySet *buff = container->form()->manager()->buffer();
+ buff->addPropertyDescription(prop, desc);
+}
+
+void
+WidgetFactory::addValueDescription(Container *container, const char *value, const QString &desc)
+{
+ WidgetPropertySet *buff = container->form()->manager()->buffer();
+ buff->addValueDescription(value, desc);
+}*/
+
+bool
+WidgetFactory::isPropertyVisible(const QCString &classname, QWidget *w,
+ const QCString &property, bool multiple, bool isTopLevel)
+{
+ if (multiple)
+ {
+ return property=="font" || property=="paletteBackgroundColor" || property=="enabled"
+ || property=="paletteForegroundColor" || property=="cursor" || property=="paletteBackgroundPixmap";
+ }
+
+// if(d->properties.isEmpty() && !isTopLevel)
+// d->properties << "caption" << "icon" << "sizeIncrement" << "iconText";
+// if(! (d->properties.grep(property)).isEmpty() )
+// return false;
+
+ return isPropertyVisibleInternal(classname, w, property, isTopLevel);
+// return !multiple && isPropertyVisibleInternal(classname, w, property);
+}
+
+bool
+WidgetFactory::isPropertyVisibleInternal(const QCString &, QWidget *w,
+ const QCString &property, bool isTopLevel)
+{
+ Q_UNUSED( w );
+
+#ifdef KEXI_NO_CURSOR_PROPERTY
+//! @todo temporary unless cursor works properly in the Designer
+ if (property=="cursor")
+ return false;
+#endif
+
+ if (!isTopLevel
+ && (property=="caption" || property=="icon" || property=="sizeIncrement" || property=="iconText")) {
+ // don't show these properties for a non-toplevel widget
+ return false;
+ }
+ return true;
+}
+
+bool
+WidgetFactory::propertySetShouldBeReloadedAfterPropertyChange(const QCString& classname, QWidget *w,
+ const QCString& property)
+{
+ Q_UNUSED(classname);
+ Q_UNUSED(w);
+ Q_UNUSED(property);
+ return false;
+}
+
+void
+WidgetFactory::resizeEditor(QWidget *, QWidget *, const QCString&)
+{
+}
+
+void
+WidgetFactory::slotTextChanged()
+{
+ changeTextInternal(editorText());
+}
+
+bool
+WidgetFactory::clearWidgetContent(const QCString &, QWidget *)
+{
+ return false;
+}
+
+void
+WidgetFactory::changeTextInternal(const QString& text)
+{
+ if (changeText( text ))
+ return;
+ //try in inherited
+ if (!m_editedWidgetClass.isEmpty()) {
+ WidgetInfo *wi = m_classesByName[ m_editedWidgetClass ];
+ if (wi && wi->inheritedClass()) {
+// wi->inheritedClass()->factory()->m_container = m_container;
+ wi->inheritedClass()->factory()->changeText( text );
+ }
+ }
+}
+
+bool
+WidgetFactory::changeText(const QString& text)
+{
+ changeProperty( "text", text, m_container->form() );
+ return true;
+}
+
+bool
+WidgetFactory::readSpecialProperty(const QCString &, QDomElement &, QWidget *, ObjectTreeItem *)
+{
+ return false;
+}
+
+bool
+WidgetFactory::saveSpecialProperty(const QCString &, const QString &, const QVariant&, QWidget *, QDomElement &, QDomDocument &)
+{
+ return false;
+}
+
+bool WidgetFactory::inheritsFactories()
+{
+ for (QAsciiDictIterator<WidgetInfo> it(m_classesByName); it.current(); ++it) {
+ if (!it.current()->parentFactoryName().isEmpty())
+ return true;
+ }
+ return false;
+}
+
+QString WidgetFactory::editorText() const {
+ QWidget *ed = editor(m_widget);
+ return dynamic_cast<KTextEdit*>(ed) ? dynamic_cast<KTextEdit*>(ed)->text() : dynamic_cast<KLineEdit*>(ed)->text();
+}
+
+void WidgetFactory::setEditorText(const QString& text) {
+ QWidget *ed = editor(m_widget);
+ if (dynamic_cast<KTextEdit*>(ed))
+ dynamic_cast<KTextEdit*>(ed)->setText(text);
+ else
+ dynamic_cast<KLineEdit*>(ed)->setText(text);
+}
+
+void WidgetFactory::setEditor(QWidget *widget, QWidget *editor)
+{
+ if (!widget)
+ return;
+ WidgetInfo *winfo = m_classesByName[widget->className()];
+ if (!winfo || winfo->parentFactoryName().isEmpty()) {
+ m_editor = editor;
+ }
+ else {
+ WidgetFactory *f = m_library->factory(winfo->parentFactoryName());
+ if (f!=this)
+ f->setEditor(widget, editor);
+ m_editor = editor; //keep a copy
+ }
+}
+
+QWidget *WidgetFactory::editor(QWidget *widget) const
+{
+ if (!widget)
+ return 0;
+ WidgetInfo *winfo = m_classesByName[widget->className()];
+ if (!winfo || winfo->parentFactoryName().isEmpty()) {
+ return m_editor;
+ }
+ else {
+ WidgetFactory *f = m_library->factoryForClassName(widget->className());
+ if (f!=this)
+ return f->editor(widget);
+ return m_editor;
+ }
+}
+
+void WidgetFactory::setWidget(QWidget *widget, Container* container)
+{
+ WidgetInfo *winfo = widget ? m_classesByName[widget->className()] : 0;
+ if (winfo && !winfo->parentFactoryName().isEmpty()) {
+ WidgetFactory *f = m_library->factory(winfo->parentFactoryName());
+ if (f!=this)
+ f->setWidget(widget, container);
+ }
+ m_widget = widget; //keep a copy
+ m_container = container;
+}
+
+QWidget *WidgetFactory::widget() const
+{
+ return m_widget;
+}
+
+void WidgetFactory::setInternalProperty(const QCString& classname, const QCString& property,
+ const QString& value)
+{
+ m_internalProp[classname+":"+property]=value;
+}
+
+void WidgetFactory::setPropertyOptions( WidgetPropertySet& /*buf*/, const WidgetInfo& /*info*/, QWidget * /*w*/ )
+{
+ //nothing
+}
+
+#include "widgetfactory.moc"
diff --git a/kexi/formeditor/widgetfactory.desktop b/kexi/formeditor/widgetfactory.desktop
new file mode 100644
index 00000000..1bf68d9e
--- /dev/null
+++ b/kexi/formeditor/widgetfactory.desktop
@@ -0,0 +1,53 @@
+[Desktop Entry]
+Type=ServiceType
+X-KDE-ServiceType=KFormDesigner/WidgetFactory
+Comment=Widget Factory Base
+Comment[bg]=Създаване на графични обекти
+Comment[ca]=Factoria base d'estris
+Comment[cy]=Bâs Ffatri Celfigion
+Comment[de]=Basis für die Erstellung von Bedienelementen
+Comment[el]=Βάση μηχανής γραφικών συστατικών
+Comment[eo]=Fenestraĵfabrikbazo
+Comment[es]=Base de fábrica de elementos
+Comment[et]=Vidinate põhibaas
+Comment[eu]=Trepeten faktoriaren oinarria
+Comment[fa]=پایۀ کارخانۀ عنصر
+Comment[fi]=Käyttöliittymäelementtien pohja
+Comment[fr]=Base de création de widgets
+Comment[gl]=Fábrica de Elementos
+Comment[he]=בסיס למפעל פריטים
+Comment[hr]=Baza widget tvornice
+Comment[hu]=Widgetkészítő-alap
+Comment[is]=Hluta smiðjugrunnur
+Comment[it]=Base della fabbrica di oggetti
+Comment[ja]=ウィジェットファクトリーベース
+Comment[lv]=Logdaļas fabrikas bāze
+Comment[ms]=Pangkalan Kilang Widget
+Comment[nb]=Base for elementfabrikk
+Comment[nds]=Basis för't Opstellen vun Stüerelementen
+Comment[ne]=विजेट फ्याक्ट्री आधार
+Comment[nn]=Base for elementfabrikk
+Comment[pl]=Podstawowa fabryka kontrolek
+Comment[pt]=Fábrica de Elementos
+Comment[pt_BR]=Widget de Fábrica Base
+Comment[ru]=Базовое приложение, содержащее офисный элемент управления
+Comment[se]=Áhtafabrihka vuođđu
+Comment[sk]=Základ pre vytváracie rozhranie prvkov
+Comment[sl]=Tovarna gradnikov
+Comment[sr]=Основа фабрике контрола
+Comment[sr@Latn]=Osnova fabrike kontrola
+Comment[sv]=Bas för att skapa grafiska komponenter
+Comment[ta]= widget தொழிற்சாலை தளம்
+Comment[tg]=Гузориши база, ки таркиботи идораи офис дар дохил дорад
+Comment[uk]=База фабрики віджетів
+Comment[zh_CN]=基础组件工厂
+Comment[zh_TW]=視窗元件工廠基地
+
+[PropertyDef::X-KFormDesigner-FactoryGroup]
+Type=QString
+
+[PropertyDef::X-KFormDesigner-WidgetFactoryVersion]
+Type=int
+
+[PropertyDef::X-KFormDesigner-XMLGUIFileName]
+Type=QString
diff --git a/kexi/formeditor/widgetfactory.h b/kexi/formeditor/widgetfactory.h
new file mode 100644
index 00000000..43736ebc
--- /dev/null
+++ b/kexi/formeditor/widgetfactory.h
@@ -0,0 +1,518 @@
+/* This file is part of the KDE project
+ Copyright (C) 2003 Lucijan Busch <lucijan@gmx.at>
+ Copyright (C) 2004 Cedric Pasteur <cedric.pasteur@free.fr>
+ Copyright (C) 2004-2006 Jaroslaw Staniek <js@iidea.pl>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+*/
+
+#ifndef KFORMDESIGNERWIDGETFACTORY_H
+#define KFORMDESIGNERWIDGETFACTORY_H
+
+
+#include <qobject.h>
+#include <qguardedptr.h>
+#include <qpixmap.h>
+#include <qpopupmenu.h>
+#include <qasciidict.h>
+
+#include <kexiutils/tristate.h>
+
+// class QPixmap;
+template<class type> class QValueVector;
+template<class type> class QPtrList;
+template<class type> class QDict;
+class QWidget;
+class QDomElement;
+class QDomDocument;
+class QVariant;
+class QListView;
+class KActionCollection;
+class KTextEdit;
+class KLineEdit;
+class KXMLGUIClient;
+
+namespace KoProperty {
+ class Set;
+}
+
+namespace KFormDesigner {
+
+class WidgetFactory;
+class WidgetLibrary;
+class Container;
+class ResizeHandleSet;
+class ObjectTreeItem;
+class WidgetPropertySet;
+class Form;
+
+/**
+ * This class holds properties of widget classes provided by a factory.
+ */
+class KFORMEDITOR_EXPORT WidgetInfo
+{
+ public:
+ typedef QPtrList<WidgetInfo> List;
+ typedef QAsciiDict<WidgetInfo> Dict;
+
+ WidgetInfo(WidgetFactory *f);
+
+ WidgetInfo(WidgetFactory *f, const char* parentFactoryName, const char* inheritedClassName = 0);
+
+ virtual ~WidgetInfo();
+
+ //! \return a pixmap associated with the widget
+ QString pixmap() const { return m_pixmap; }
+
+ //! \return the class name of a widget e.g. 'QLineEdit'
+ QCString className() const { return m_class; }
+
+ /*! \return the name used to name widget, that will appear eg in scripts (must not contain spaces
+ nor non-latin1 characters) */
+ QString namePrefix() const { return m_prefixName; }
+
+ //! \return the real name e.g. 'Line Edit', showed eg in ObjectTreeView
+ QString name() const { return m_name; }
+
+ QString description() const { return m_desc; }
+ QString includeFileName() const { return m_include; }
+ QValueList<QCString> alternateClassNames() const { return m_alternateNames; }
+ QString savingName() const { return m_saveName; }
+ WidgetFactory *factory() const { return m_factory; }
+
+ void setPixmap(const QString &p) { m_pixmap = p; }
+ void setClassName(const QCString &s) { m_class = s; }
+ void setName(const QString &n) { m_name = n; }
+ void setNamePrefix(const QString &n) { m_prefixName = n; }
+ void setDescription(const QString &desc) { m_desc = desc;}
+
+ /*! Sets the C++ include file corresponding to this class,
+ that uic will need to add when creating the file. You don't have to set this for Qt std widgets.*/
+ void setIncludeFileName(const QString &name) { m_include = name;}
+
+ /*! Sets alternate names for this class.
+ If this name is found when loading a .ui file, the className() will be used instead.
+ It allows to support both KDE and Qt versions of widget, without duplicating code.
+ As a rule, className() should always return a class name which is inherited from
+ alternate class. For example KListView class has alternate QListView class.
+
+ \a override parameter overrides class name of a widget,
+ even if it was implemented in other factory.
+ By default it's set to false, what means that no other class is overridden
+ by this widget class if there is already a class implementing it
+ (no matter in which factory).
+ By forced overriding existing class with other - custom, user
+ will be able to see more or less properties and experience different behaviour.
+ For example, in Kexi application, KLineEdit class contains additional
+ "datasource" property for binding to database sources.
+ */
+ void addAlternateClassName(const QCString& alternateName, bool override = false);
+
+ /*! \return true is a class \a alternateName is defined as alternate name with
+ 'override' flag set to true, using addAlternateClassName().
+ If this flag is set to false (the default) or there's no such alternate class
+ name defined. */
+ bool isOverriddenClassName(const QCString& alternateName) const;
+
+ /*! Sets the name that will be written in the .ui file when saving.
+ This name must be one of alternate names (or loading will be impossible).
+
+ On form data saving to XML .ui format, saveName is used instead,
+ so .ui format is not broken and still usable with other software as Qt Designer.
+ Custom properties are saved as well with 'stdset' attribute set to 0. */
+ void setSavingName(const QString &saveName) { m_saveName = saveName; }
+
+ /*! Sets autoSync flag for property \a propertyName.
+ This allows to override autoSync flag for certain widget's property, because
+ e.g. KoProperty::Editor can have autoSync flag set to false or true, but
+ not all properties have to comply with that.
+ \a flag equal to cancelled value means there is no overriding (the default). */
+ void setAutoSyncForProperty(const char *propertyName, tristate flag);
+
+ /*! \return autoSync override value (true or false) for \a propertyName.
+ If cancelled value is returned, there is no overriding (the default). */
+ tristate autoSyncForProperty(const char *propertyName) const;
+
+ QCString parentFactoryName() const { return m_parentFactoryName; }
+
+ WidgetInfo* inheritedClass() const { return m_inheritedClass; }
+
+ /*! Sets custom type \a type for property \a propertyName.
+ This allows to override default type, especially when custom property
+ and custom property editor item has to be used. */
+ void setCustomTypeForProperty(const char *propertyName, int type);
+
+ /*! \return custom type for property \a propertyName. If no specific custom type has been assigned,
+ KoProperty::Auto is returned.
+ @see setCustomTypeForProperty() */
+ int customTypeForProperty(const char *propertyName) const;
+
+ protected:
+ QCString m_parentFactoryName, m_inheritedClassName; //!< Used for inheriting widgets between factories
+ WidgetInfo* m_inheritedClass;
+
+ private:
+ QString m_pixmap;
+ QCString m_class;
+ QString m_name;
+ QString m_prefixName;
+ QString m_desc;
+ QString m_include;
+ QValueList<QCString> m_alternateNames;
+ QAsciiDict<char> *m_overriddenAlternateNames;
+ QString m_saveName;
+ QGuardedPtr<WidgetFactory> m_factory;
+ QAsciiDict<char> *m_propertiesWithDisabledAutoSync;
+ QMap<QCString,int> *m_customTypesForProperty;
+
+ friend class WidgetLibrary;
+};
+
+//! The base class for all widget Factories
+/*! This is the class you need to inherit to create a new Factory. There are few
+ virtuals you need to implement, and some other functions
+ to implement if you want more features.\n \n
+
+ <b>Widget Creation</b>\n
+ To be able to create widgets, you need to implement the create() function, an classes(),
+ which should return all the widgets supported by this factory.\n \n
+
+ <b>GUI Integration</b>\n
+ The following functions allow you to customize even more the look-n-feel of your widgets inside KFormDesigner.
+ You can use createMenuActions() to add custom items in widget's context menu. The previewWidget()
+ is called when the Form gets in Preview mode, and you have a last opportunity to remove all editing-related
+ stuff (see eg \ref Spring class).\n
+ You can also choose which properties to show in the Property Editor.
+ By default, most all properties are shown (see implementation for details),
+ but you can hide some reimplementing isPropertyVisibleInternal() (don't forget to call superclass' method)
+ To add new properties, just define new Q_PROPERTY in widget class definition.\n \n
+
+ <b>Inline editing</b>\n
+ KFormDesigner allow you to edit the widget's contents inside Form, without using a dialog.
+ You can of course customize the behaviour of your widgets, using startEditing(). There are some editing
+ modes already implemented in WidgetFactroy, but you can create your own if you want:
+ \li Editing using a line edit (createEditor()): a line edit is created on top of widget,
+ where the user inputs text. As the text changes, changeText() is called
+ (where you should set your widget's text and resize widget to fit the text if needed) and resizeEditor()
+ to update editor's position when widget is moved/resized.\n
+ \li Editing by disabling event filter: if you call disableFilter(), the event filter
+ on the object is temporarily disabled, so the widget behaves as usual. This
+ can be used for more complex widgets, such as spinbox, date/time edit, etc.
+ \li Other modes: there are 3 other modes, to edit a string list: editList()
+ (for combo box, listbox), to edit rich text: editRichText() (for labels, etc.)
+ and to edit a listview: editListView(). \n \n
+
+ <b>Widget saving/loading</b>\n
+ You can also control how your widget are saved/loaded. You can choose which properties to save
+ (see autoSaveProperties()), and save/load custom properties, ie
+ properties that are not Q_PROPERTY but you want to save in the UI file. This is used eg to
+ save combo box or listview contents (see saveSpecialProperty() and
+ readSpecialProperty()). \n \n
+
+ <b>Special internal properties</b>\n
+ Use void setInternalProperty(const QCString& classname, const QCString& property, const QString& value);
+ to set values of special internal properties.
+ Currently these properties are used for customizing popup menu items used for orientation selection.
+ Customization for class ClassName should look like:
+ <code> void setInternalProperty("ClassName", "orientationSelectionPopup", "myicon"); </code>
+ Available internal properties:
+ * "orientationSelectionPopup" - set it to "1" if you want a given class to offer orientation selection,
+ so orientation selection popup will be displayed when needed.
+ * "orientationSelectionPopup:horizontalIcon" - sets a name of icon for "Horizontal" item
+ for objects of class 'ClassName'. Set this property only for classes supporting orientations.
+ * "orientationSelectionPopup:verticalIcon" - the same for "Vertical" item.
+ Set this property only for classes supporting orientations.
+ * "orientationSelectionPopup:horizontalText" - sets a i18n'd text for "Horizontal" item
+ for objects of class 'ClassName', e.g. i18n("Insert Horizontal Line").
+ Set this property only for classes supporting orientations.
+ * "orientationSelectionPopup:verticalText" - the same for "Vertical" item,
+ e.g. i18n("Insert Vertical Line"). Set this property only for classes supporting orientations.
+ * "dontStartEditingOnInserting" - if not empty, WidgetFactory::startEditing() will not be executed upon
+ widget inseting by a user.
+ * "forceShowAdvancedProperty:{propertyname}" - set it to "1" for "{propertyname}" advanced property
+ if you want to force it to be visible even if WidgetLibrary::setAdvancedPropertiesVisible(false)
+ has been called. For example, setting "forceShowAdvancedProperty:pixmap" to "1"
+ unhides "pixmap" property for a given class.
+
+ See StdWidgetFactory::StdWidgetFactory() for properties like
+ "Line:orientationSelectionPopup:horizontalIcon".
+
+ \n\n
+ See the standard factories in formeditor/factories for an example of factories,
+ and how to deal with complex widgets (eg tabwidget).
+ */
+class KFORMEDITOR_EXPORT WidgetFactory : public QObject
+{
+ Q_OBJECT
+ public:
+ //! Options used in createWidget()
+ enum CreateWidgetOptions {
+ AnyOrientation = 1, //!< any orientation hint
+ HorizontalOrientation = 2, //!< horizontal orientation hint
+ VerticalOrientation = 4, //!< vertical orientation hint
+ DesignViewMode = 8, //!< create widget in design view mode, otherwise preview mode
+ DefaultOptions = AnyOrientation | DesignViewMode
+ };
+
+ WidgetFactory(QObject *parent=0, const char *name=0);
+ virtual ~WidgetFactory();
+
+ /*! Adds a new class described by \a w. */
+ void addClass(WidgetInfo *w);
+
+ /*! This method allows to force a class \a classname to hidden.
+ It is useful if you do not want a class to be available
+ (e.g. because it is not implemented well yet for our purposes).
+ All widget libraries are affected by this setting. */
+ void hideClass(const char *classname);
+
+ /**
+ * \return all classes which are provided by this factory
+ */
+ const WidgetInfo::Dict classes() const { return m_classesByName; }
+
+ /**
+ * Creates a widget (and if needed a KFormDesigner::Container)
+ * \return the created widget
+ * \param classname the classname of the widget, which should get created
+ * \param parent the parent for the created widget
+ * \param name the name of the created widget
+ * \param container the toplevel Container (if a container should get created)
+ * \param options options for the created widget: orientation and view mode (see CreateWidgetOptions)
+ */
+ virtual QWidget* createWidget(const QCString &classname, QWidget *parent, const char *name,
+ KFormDesigner::Container *container,
+ int options = DefaultOptions) = 0;
+
+ /*! Creates custom actions. Reimplement this if you need to add some
+ actions coming from the factory. */
+ virtual void createCustomActions(KActionCollection *col) { Q_UNUSED(col); };
+
+ /*! This function can be used to add custom items in widget \a w context
+ menu \a menu. */
+ virtual bool createMenuActions(const QCString &classname, QWidget *w, QPopupMenu *menu,
+ KFormDesigner::Container *container)=0;
+
+ /*! Creates (if necessary) an editor to edit the contents of the widget directly in the Form
+ (eg creates a line edit to change the text of a label). \a classname is
+ the class the widget belongs to, \a w is the widget to edit
+ and \a container is the parent container of this widget (to access Form etc.).
+ */
+ virtual bool startEditing(const QCString &classname, QWidget *w, Container *container)=0;
+
+ /*! This function is called just before the Form is previewed. It allows widgets
+ to make changes before switching (ie for a Spring, hiding the cross) */
+ virtual bool previewWidget(const QCString &classname, QWidget *widget, Container *container)=0;
+
+ virtual bool clearWidgetContent(const QCString &classname, QWidget *w);
+
+ /*! This function is called when FormIO finds a property, at save time,
+ that it cannot handle (ie not a normal property).
+ This way you can save special properties, for example the contents of a listbox.
+ \sa readSpecialProperty()
+ */
+ virtual bool saveSpecialProperty(const QCString &classname, const QString &name,
+ const QVariant &value, QWidget *w,
+ QDomElement &parentNode, QDomDocument &parent);
+
+ /*! This function is called when FormIO finds a property or an unknown
+ element in a .ui file. You can this way load a special property, for
+ example the contents of a listbox.
+ \sa saveSpecialProperty()
+ */
+ virtual bool readSpecialProperty(const QCString &classname, QDomElement &node,
+ QWidget *w, ObjectTreeItem *item);
+
+ /*! This function is used to know whether the \a property for the widget \a w
+ should be shown or not in the PropertyEditor. If \a multiple is true,
+ then multiple widgets of the same class are selected, and you should
+ only show properties shared by widgets (eg font, color). By default,
+ all properties are shown if multiple == true, and none if multiple == false. */
+ bool isPropertyVisible(const QCString &classname, QWidget *w,
+ const QCString &property, bool multiple, bool isTopLevel);
+
+ /*! You need to return here a list of the properties that should automatically be saved
+ for a widget belonging to \a classname, and your custom properties (eg "text"
+ for label or button, "contents" for combobox...). */
+ virtual QValueList<QCString> autoSaveProperties(const QCString &classname)=0;
+
+ /*! \return The i18n'ed name of the property whose name is \a name,
+ that will be displayed in PropertyEditor. */
+ inline QString propertyDescForName(const QCString &name) { return m_propDesc[name]; };
+
+ /*! \return The i18n'ed name of the property's value whose name is \a name. */
+ inline QString propertyDescForValue(const QCString &name) { return m_propValDesc[name]; };
+
+ /*! This method is called after WidgetPropertySet was filled with properties
+ of a widget \a w, of class defined by \a info.
+ Default implementation does nothing.
+ Implement this if you need to set options for properties within the set \a buf. */
+ virtual void setPropertyOptions( WidgetPropertySet& buf, const WidgetInfo& info, QWidget *w );
+
+ /*! \return internal property \a property for a class \a classname.
+ Internal properties are not stored within objects, but can be just provided
+ to describe classes' details. */
+ inline QString internalProperty(const QCString& classname, const QCString& property) const {
+ return m_internalProp[classname+":"+property];
+ }
+
+ protected:
+ /*! This function is called when we want to know whether the property should be visible.
+ Implement it in the factory; don't forget to call implementation in the superclass.
+ Default implementation hides "caption", "icon", "sizeIncrement" and "iconText" properties. */
+ virtual bool isPropertyVisibleInternal(const QCString &classname, QWidget *w,
+ const QCString &property, bool isTopLevel);
+
+ /*! Sometimes property sets should be reloaded when a given property value changed.
+ Implement it in the factory. Default implementation always returns false. */
+ virtual bool propertySetShouldBeReloadedAfterPropertyChange(const QCString& classname, QWidget *w,
+ const QCString& property);
+
+ /*! This function creates a KLineEdit to input some text and edit a widget's contents.
+ This can be used in startEditing(). \a text is the text to display by default
+ in the line edit, \a w is the edited widget, \a geometry is the geometry the new line
+ edit should have, and \a align is Qt::AlignmentFlags of the new line edit. */
+ void createEditor(const QCString &classname, const QString &text,
+ QWidget *w, Container *container, QRect geometry,
+ int align, bool useFrame=false, bool multiLine = false,
+ BackgroundMode background = Qt::NoBackground);
+
+ /*! This function provides a simple editing mode : it justs disable event filtering
+ for the widget, and it install it again when
+ the widget loose focus or Enter is pressed.
+ */
+ void disableFilter(QWidget *w, Container *container);
+
+ /*! This function creates a little dialog (a KEditListBox) to modify the contents
+ of a list (of strings). It can be used to modify the contents
+ of a combo box for instance. The modified list is copied
+ into \a list when the user presses "Ok".*/
+ bool editList(QWidget *w, QStringList &list);
+
+ /*! This function creates a little editor to modify rich text. It supports alignment,
+ subscript and superscript and all basic formatting properties.
+ If the user presses "Ok", the edited text is put in \a text.
+ If he presses "Cancel", nothing happens. */
+ bool editRichText(QWidget *w, QString &text);
+
+ /*! This function creates a dialog to modify the contents of a ListView. You can modify both
+ columns and list items. The listview is automatically updated if the user presses "Ok".*/
+ void editListView(QListView *listview);
+
+ /*! This function destroys the editor when it loses focus or Enter is pressed. */
+ virtual bool eventFilter(QObject *obj, QEvent *ev);
+
+ /*! This function is used to modify a property of a widget (eg after editing it).
+ Please use it instead of w->setProperty() to allow sync inside PropertyEditor.
+ */
+ void changeProperty(const char *name, const QVariant &value, Form *form);
+
+ /*! This function is called when the widget is resized,
+ and the \a editor size needs to be updated. */
+ virtual void resizeEditor(QWidget *editor, QWidget *widget, const QCString &classname);
+
+// /*! Adds the i18n'ed description of a property, which will be shown in PropertyEditor. */
+// void addPropertyDescription(Container *container, const char *prop, const QString &desc);
+
+// /*! Adds the i18n'ed description of a property value, which will be shown in PropertyEditor. */
+// void addValueDescription(Container *container, const char *value, const QString &desc);
+
+ /*! \return true if at least one class defined by this factory inherits
+ a class from other factory. Used in WidgetLibrary::loadFactories()
+ to load factories in proper order. */
+ bool inheritsFactories();
+
+ public slots:
+
+ /*! @internal. This slot is called when the editor has lost focus or the user pressed Enter.
+ It destroys the editor or installs again the event filter on the widget. */
+ void resetEditor();
+
+ protected slots:
+ /*!
+ Default implementation changes "text" property.
+ You have to reimplement this function for editing inside the Form to work if your widget's
+ property you want to change isn't named "text".
+ This slot is called when the line edit text changes, and you have to make
+ it really change the good property of the widget using changeProperty() (text, or title, etc.).
+ */
+ virtual bool changeText(const QString &newText);
+
+ void changeTextInternal(const QString& text);
+
+ void slotTextChanged();
+
+ /*! This slot is called when the editor is destroyed.*/
+ void editorDeleted();
+ void widgetDestroyed();
+
+ protected:
+ QString editorText() const;
+ void setEditorText(const QString& text);
+ void setEditor(QWidget *widget, QWidget *editor);
+ QWidget *editor(QWidget *widget) const;
+ void setWidget(QWidget *widget, Container *container);
+ QWidget *widget() const;
+
+ /*! Assigns \a value for internal property \a property for a class \a classname.
+ Internal properties are not stored within objects, but can be provided
+ to describe classes' details. */
+ void setInternalProperty(const QCString& classname, const QCString& property, const QString& value);
+
+ WidgetLibrary *m_library;
+ QCString m_editedWidgetClass;
+//#ifdef KEXI_KTEXTEDIT
+// QGuardedPtr<KTextEdit> m_editor;
+//#else
+// QGuardedPtr<KLineEdit> m_editor;
+//#endif
+ QString m_firstText;
+ QGuardedPtr<ResizeHandleSet> m_handles;
+ QGuardedPtr<Container> m_container;
+// WidgetInfo::List m_classes;
+ WidgetInfo::Dict m_classesByName;
+ QAsciiDict<char>* m_hiddenClasses;
+
+ //! i18n stuff
+ QMap<QCString, QString> m_propDesc;
+ QMap<QCString, QString> m_propValDesc;
+ //! internal properties
+ QMap<QCString, QString> m_internalProp;
+
+ /*! flag useful to decide whether to hide some properties.
+ It's value is inherited from WidgetLibrary. */
+ bool m_showAdvancedProperties;
+
+ /*! Contains name of an XMLGUI file providing toolbar buttons
+ (and menu items in the future?) for the factory.
+ Can be empty, e.g. for the main factory which has XMLGUI defined in the shell window itself
+ (e.g. kexiformpartinstui.rc for Kexi Forms). This name is set in WidgetLibrary::loadFactories() */
+ QString m_xmlGUIFileName;
+
+ KXMLGUIClient *m_guiClient;
+
+ QGuardedPtr<QWidget> m_widget;
+ QGuardedPtr<QWidget> m_editor;
+
+ friend class WidgetLibrary;
+};
+
+//! macro to declare KFormDesigner-compatible widget factory as a KDE Component factory
+#define KFORMDESIGNER_WIDGET_FACTORY(factoryClassName, libraryName) \
+ K_EXPORT_COMPONENT_FACTORY(kformdesigner_ ## libraryName, KGenericFactory<factoryClassName>("kformdesigner_" # libraryName))
+
+}
+#endif
diff --git a/kexi/formeditor/widgetlibrary.cpp b/kexi/formeditor/widgetlibrary.cpp
new file mode 100644
index 00000000..1a198195
--- /dev/null
+++ b/kexi/formeditor/widgetlibrary.cpp
@@ -0,0 +1,769 @@
+/* This file is part of the KDE project
+ Copyright (C) 2003 Lucijan Busch <lucijan@gmx.at>
+ Copyright (C) 2004 Cedric Pasteur <cedric.pasteur@free.fr>
+ Copyright (C) 2004-2007 Jaroslaw Staniek <js@iidea.pl>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+*/
+
+#include <qdom.h>
+#include <qstrlist.h>
+
+#include <kdebug.h>
+#include <klocale.h>
+#include <klibloader.h>
+#include <kparts/componentfactory.h>
+#include <ktrader.h>
+#include <kiconloader.h>
+#include <kpopupmenu.h>
+
+#include "widgetfactory.h"
+#include "widgetlibrary.h"
+#include "libactionwidget.h"
+#include "container.h"
+#include "form.h"
+#include "formIO.h"
+
+namespace KFormDesigner {
+
+//! @internal
+class XMLGUIClient : public QObject, public KXMLGUIClient
+{
+ public:
+ XMLGUIClient(KXMLGUIClient* parent, const QString& xmlFileName)
+ : QObject(parent->actionCollection()), KXMLGUIClient(parent)
+ {
+ setXMLFile( xmlFileName, true /*merge*/ );
+ }
+};
+
+//! @internal
+class WidgetLibraryPrivate
+{
+ public:
+ WidgetLibraryPrivate()
+ : widgets(101)
+// , alternateWidgets(101)
+ , services(101, false)
+ , supportedFactoryGroups(17, false)
+ , factories(101, false)
+ , advancedProperties(1009, true)
+ , hiddenClasses(101, true)
+ , showAdvancedProperties(true)
+ , factoriesLoaded(false)
+ {
+ services.setAutoDelete(true);
+ advancedProperties.insert("autoMask", (char*)1);
+ advancedProperties.insert("baseSize", (char*)1);
+ advancedProperties.insert("mouseTracking", (char*)1);
+ advancedProperties.insert("acceptDrops", (char*)1);
+ advancedProperties.insert("cursorPosition", (char*)1);
+ advancedProperties.insert("contextMenuEnabled", (char*)1);
+ advancedProperties.insert("trapEnterKeyEvent", (char*)1);
+ advancedProperties.insert("dragEnabled", (char*)1);
+ advancedProperties.insert("enableSqueezedText", (char*)1);
+ advancedProperties.insert("sizeIncrement", (char*)1);
+/*! @todo: reenable */ advancedProperties.insert("palette", (char*)1);
+ advancedProperties.insert("backgroundOrigin", (char*)1);
+ advancedProperties.insert("backgroundMode", (char*)1);//this is rather useless
+ advancedProperties.insert("layout", (char*)1);// too large risk to break things
+ // by providing this in propeditor
+ advancedProperties.insert("minimumSize", (char*)1);
+ advancedProperties.insert("maximumSize", (char*)1);
+#ifdef KEXI_NO_UNFINISHED
+/*! @todo reenable */
+ advancedProperties.insert("paletteBackgroundPixmap", (char*)1);
+ advancedProperties.insert("icon", (char*)1);
+ advancedProperties.insert("pixmap", (char*)1);
+ advancedProperties.insert("accel", (char*)1);
+#endif
+ }
+ // dict which associates a class name with a Widget class
+ WidgetInfo::Dict widgets;//, alternateWidgets;
+ QAsciiDict<KService::Ptr> services;
+ QAsciiDict<char> supportedFactoryGroups;
+ QAsciiDict<WidgetFactory> factories;
+ QAsciiDict<char> advancedProperties;
+ QAsciiDict<char> hiddenClasses;
+ bool showAdvancedProperties : 1;
+ bool factoriesLoaded : 1;
+};
+}
+
+using namespace KFormDesigner;
+
+//-------------------------------------------
+
+WidgetLibrary::WidgetLibrary(QObject *parent, const QStringList& supportedFactoryGroups)
+ : QObject(parent)
+ , d(new WidgetLibraryPrivate())
+{
+ for (QStringList::ConstIterator it = supportedFactoryGroups.constBegin();
+ it!=supportedFactoryGroups.constEnd(); ++it)
+ {
+ d->supportedFactoryGroups.insert( (*it).lower().latin1(), (char*)1);
+ }
+ lookupFactories();
+}
+
+WidgetLibrary::~WidgetLibrary()
+{
+ delete d;
+}
+
+void
+WidgetLibrary::loadFactoryWidgets(WidgetFactory *f)
+{
+ const WidgetInfo::Dict widgets = f->classes();
+ WidgetInfo *w;
+ for(QAsciiDictIterator<WidgetInfo> it(widgets); (w = it.current()); ++it)
+ {
+ if (0 != d->hiddenClasses[ w->className() ])
+ continue; //this class is hidden
+ // check if we want to inherit a widget from a different factory
+ if (!w->m_parentFactoryName.isEmpty() && !w->m_inheritedClassName.isEmpty()) {
+ WidgetFactory *parentFactory = d->factories[w->m_parentFactoryName];
+ if (!parentFactory) {
+ kdWarning() << "WidgetLibrary::loadFactoryWidgets(): class '" << w->className()
+ << "' - no such parent factory '" << w->m_parentFactoryName << "'" << endl;
+ continue;
+ }
+ WidgetInfo* inheritedClass = parentFactory->m_classesByName[ w->m_inheritedClassName ];
+ if (!inheritedClass) {
+ kdWarning() << "WidgetLibrary::loadFactoryWidgets(): class '" << w->m_inheritedClassName
+ << "' - no such class to inherit in factory '" << w->m_parentFactoryName << "'" << endl;
+ continue;
+ }
+ //ok: inherit properties:
+ w->m_inheritedClass = inheritedClass;
+ if (w->pixmap().isEmpty())
+ w->setPixmap( inheritedClass->pixmap() );
+ //ok?
+ foreach (QValueList<QCString>::ConstIterator, it_alt, inheritedClass->m_alternateNames) {
+ w->addAlternateClassName( *it_alt, inheritedClass->isOverriddenClassName( *it_alt ) );
+ }
+ if (w->includeFileName().isEmpty())
+ w->setIncludeFileName( inheritedClass->includeFileName() );
+ if (w->name().isEmpty())
+ w->setName( inheritedClass->name() );
+ if (w->namePrefix().isEmpty())
+ w->setNamePrefix( inheritedClass->namePrefix() );
+ if (w->description().isEmpty())
+ w->setDescription( inheritedClass->description() );
+ }
+
+// kdDebug() << "WidgetLibrary::addFactory(): adding class " << w->className() << endl;
+ QValueList<QCString> l = w->alternateClassNames();
+ l.prepend( w->className() );
+ //d->widgets.insert(w->className(), w);
+// if(!w->alternateClassName().isEmpty()) {
+// QStringList l = QStringList::split("|", w->alternateClassName());
+ QValueList<QCString>::ConstIterator endIt = l.constEnd();
+ for(QValueList<QCString>::ConstIterator it = l.constBegin(); it != endIt; ++it) {
+ WidgetInfo *widgetForClass = d->widgets.find( *it );
+ if (!widgetForClass || (widgetForClass && !widgetForClass->isOverriddenClassName(*it))) {
+ //insert a widgetinfo, if:
+ //1) this class has no alternate class assigned yet, or
+ //2) this class has alternate class assigned but without 'override' flag
+ d->widgets.replace( *it, w);
+ }
+
+/* WidgetInfo *widgetForClass = d->alternateWidgets.find(*it);
+ if (!widgetForClass || (widgetForClass && !widgetForClass->isOverriddenClassName(*it))) {
+ //insert a widgetinfo, if:
+ //1) this class has no alternate class assigned yet, or
+ //2) this class has alternate class assigned but without 'override' flag
+ d->alternateWidgets.replace(*it, w);
+ }*/
+ }
+ }
+}
+
+void
+WidgetLibrary::lookupFactories()
+{
+ KTrader::OfferList tlist = KTrader::self()->query("KFormDesigner/WidgetFactory");
+ KTrader::OfferList::ConstIterator it, end( tlist.constEnd() );
+ for( it = tlist.constBegin(); it != end; ++it)
+ {
+ KService::Ptr ptr = (*it);
+ KService::Ptr* existingService = (d->services)[ptr->library().latin1()];
+ if (existingService) {
+ kdWarning() << "WidgetLibrary::lookupFactories(): factory '" << ptr->name()
+ << "' already found (library="<< (*existingService)->library()
+ <<")! skipping this one: library=" << ptr->library() << endl;
+ continue;
+ }
+ kdDebug() << "WidgetLibrary::lookupFactories(): found factory: " << ptr->name() << endl;
+
+ QCString groupName = ptr->property("X-KFormDesigner-FactoryGroup").toCString();
+ if (!groupName.isEmpty() && !d->supportedFactoryGroups[groupName]) {
+ kdDebug() << "WidgetLibrary::lookupFactories(): factory group '" << groupName
+ << "' is unsupported by this application (library=" << ptr->library() << ")"<< endl;
+ continue;
+ }
+ const uint factoryVersion = ptr->property("X-KFormDesigner-WidgetFactoryVersion").toUInt();
+ if (KFormDesigner::version()!=factoryVersion) {
+ kdWarning() << QString("WidgetLibrary::lookupFactories(): factory '%1'"
+ " has version '%2' but required Widget Factory version is '%3'\n"
+ " -- skipping this factory!").arg(ptr->library()).arg(factoryVersion)
+ .arg(KFormDesigner::version()) << endl;
+ continue;
+ }
+ d->services.insert(ptr->library().latin1(), new KService::Ptr( ptr ));
+ }
+}
+
+void
+WidgetLibrary::loadFactories()
+{
+ if (d->factoriesLoaded)
+ return;
+ d->factoriesLoaded = true;
+ for (QAsciiDictIterator<KService::Ptr> it(d->services); it.current(); ++it) {
+ WidgetFactory *f = KParts::ComponentFactory::createInstanceFromService<WidgetFactory>(
+ *it.current(), this, (*it.current())->library().latin1(), QStringList());
+ if (!f) {
+ kdWarning() << "WidgetLibrary::loadFactories(): creating factory failed! "
+ << (*it.current())->library() << endl;
+ continue;
+ }
+ f->m_library = this;
+ f->m_showAdvancedProperties = d->showAdvancedProperties; //inherit this flag from the library
+ f->m_xmlGUIFileName = (*it.current())->property("X-KFormDesigner-XMLGUIFileName").toString();
+ d->factories.insert( f->name(), f );
+
+ //collect information about classes to be hidden
+ if (f->m_hiddenClasses) {
+ for (QAsciiDictIterator<char> it2(*f->m_hiddenClasses); it2.current(); ++it2) {
+ d->hiddenClasses.replace( it2.currentKey(), (char*)1 );
+ }
+ }
+ }
+
+ //now we have factories instantiated: load widgets
+ QPtrList<WidgetFactory> loadLater;
+ for (QAsciiDictIterator<WidgetFactory> it(d->factories); it.current(); ++it) {
+ //ONE LEVEL, FLAT INHERITANCE, but works!
+ //if this factory inherits from something, load its witgets later
+//! @todo improve
+ if (it.current()->inheritsFactories())
+ loadLater.append( it.current() );
+ else
+ loadFactoryWidgets(it.current());
+ }
+ //load now the rest
+ for (QPtrListIterator<WidgetFactory> it(loadLater); it.current(); ++it) {
+ loadFactoryWidgets(it.current());
+ }
+}
+
+/* old
+QString
+WidgetLibrary::createXML()
+{
+ loadFactories();
+
+ QDomDocument doc("kpartgui");
+ QDomElement root = doc.createElement("kpartgui");
+
+ root.setAttribute("name", "kformdesigner");
+ root.setAttribute("version", "0.3");
+ doc.appendChild(root);
+
+ QDomElement toolbar = doc.createElement("ToolBar");
+ toolbar.setAttribute("name", "widgets");
+ root.appendChild(toolbar);
+
+ QDomElement texttb = doc.createElement("text");
+ toolbar.appendChild(texttb);
+ QDomText ttext = doc.createTextNode("Widgets");
+ texttb.appendChild(ttext);
+
+ QDomElement menubar = doc.createElement("MenuBar");
+ toolbar.setAttribute("name", "widgets");
+ root.appendChild(menubar);
+
+ QDomElement Mtextb = doc.createElement("text");
+ toolbar.appendChild(Mtextb);
+ QDomText Mtext = doc.createTextNode("Widgets");
+ Mtextb.appendChild(Mtext);
+ QDomElement menu = doc.createElement("Menu");
+ menu.setAttribute("name", "widgets");
+
+ QAsciiDictIterator<WidgetInfo> it(d->widgets);
+ int i = 0;
+ for(; it.current(); ++it)
+ {
+ QDomElement action = doc.createElement("Action");
+ action.setAttribute("name", "library_widget" + it.current()->className());
+ toolbar.appendChild(action);
+
+ i++;
+ }
+
+ return doc.toString();
+}*/
+
+ActionList
+WidgetLibrary::createWidgetActions(KXMLGUIClient* client, KActionCollection *parent,
+ QObject *receiver, const char *slot)
+{
+ loadFactories();
+
+ // init XML gui clients (custom factories have their own .rc files)
+ for (QAsciiDictIterator<WidgetFactory> it(d->factories); it.current(); ++it)
+ {
+ if (it.current()->m_xmlGUIFileName.isEmpty()) { // probably a built-in factory, with GUI file like kexiformpartinstui.rc
+ it.current()->m_guiClient = 0;
+ }
+ else { // a custom factory with its own .rc file
+ it.current()->m_guiClient = new XMLGUIClient(client, it.current()->m_xmlGUIFileName);
+ }
+ }
+
+ ActionList actions;
+ for (QAsciiDictIterator<WidgetInfo> it(d->widgets); it.current(); ++it)
+ {
+ LibActionWidget *a = new LibActionWidget(it.current(),
+ it.current()->factory()->m_guiClient
+ ? it.current()->factory()->m_guiClient->actionCollection() : parent);
+ connect(a, SIGNAL(prepareInsert(const QCString &)), receiver, slot);
+ actions.append(a);
+ }
+ return actions;
+}
+
+void
+WidgetLibrary::addCustomWidgetActions(KActionCollection *col)
+{
+ for (QAsciiDictIterator<WidgetFactory> it(d->factories); it.current(); ++it)
+ {
+ it.current()->createCustomActions(
+ it.current()->m_guiClient
+ ? it.current()->m_guiClient->actionCollection() : col);
+ }
+}
+
+QWidget*
+WidgetLibrary::createWidget(const QCString &classname, QWidget *parent, const char *name, Container *c,
+ int options)
+{
+ loadFactories();
+ WidgetInfo *wclass = d->widgets[classname];
+ if(!wclass)
+ return 0;
+
+ QWidget *widget = wclass->factory()->createWidget(wclass->className(), parent, name, c, options);
+ if (!widget) {
+ //try to instantiate from inherited class
+ if (wclass->inheritedClass())
+ widget = wclass->inheritedClass()->factory()->createWidget(
+ wclass->className(), parent, name, c, options);
+ if (!widget)
+ return 0;
+ }
+ widget->setAcceptDrops(true);
+ emit widgetCreated(widget);
+ return widget;
+}
+
+bool
+WidgetLibrary::createMenuActions(const QCString &c, QWidget *w, QPopupMenu *menu,
+ KFormDesigner::Container *container)
+{
+ loadFactories();
+ WidgetInfo *wclass = d->widgets[c];
+ if(!wclass)
+ return false;
+
+ wclass->factory()->m_widget = w;
+ wclass->factory()->m_container = container;
+ if (wclass->factory()->createMenuActions(c, w, menu, container))
+ return true;
+ //try from inherited class
+ if (wclass->inheritedClass())
+ return wclass->inheritedClass()->factory()
+ ->createMenuActions(wclass->className(), w, menu, container);
+ return false;
+}
+
+bool
+WidgetLibrary::startEditing(const QCString &classname, QWidget *w, Container *container)
+{
+ loadFactories();
+ WidgetInfo *wclass = d->widgets[classname];
+ if(!wclass)
+ return false;
+
+ if (wclass->factory()->startEditing(classname, w, container))
+ return true;
+ //try from inherited class
+ if (wclass->inheritedClass())
+ return wclass->inheritedClass()->factory()->startEditing(wclass->className(), w, container);
+ return false;
+}
+
+bool
+WidgetLibrary::previewWidget(const QCString &classname, QWidget *widget, Container *container)
+{
+ loadFactories();
+ WidgetInfo *wclass = d->widgets[classname];
+ if(!wclass)
+ return false;
+
+ if (wclass->factory()->previewWidget(classname, widget, container))
+ return true;
+ //try from inherited class
+ if (wclass->inheritedClass())
+ return wclass->inheritedClass()->factory()->previewWidget(wclass->className(), widget, container);
+ return false;
+}
+
+bool
+WidgetLibrary::clearWidgetContent(const QCString &classname, QWidget *w)
+{
+ loadFactories();
+ WidgetInfo *wclass = d->widgets[classname];
+ if(!wclass)
+ return false;
+
+ if (wclass->factory()->clearWidgetContent(classname, w))
+ return true;
+ //try from inherited class
+ if (wclass->inheritedClass())
+ return wclass->inheritedClass()->factory()->clearWidgetContent(wclass->className(), w);
+ return false;
+}
+
+QString
+WidgetLibrary::displayName(const QCString &classname)
+{
+ loadFactories();
+ WidgetInfo *wi = d->widgets.find(classname);
+ if(wi)
+ return wi->name();
+
+ return classname;
+}
+
+QString
+WidgetLibrary::savingName(const QCString &classname)
+{
+ loadFactories();
+ QString s;
+ WidgetInfo *wi = d->widgets.find(classname);
+ if(wi && !wi->savingName().isEmpty())
+ return wi->savingName();
+
+ return classname;
+}
+
+QString
+WidgetLibrary::namePrefix(const QCString &classname)
+{
+ loadFactories();
+ WidgetInfo *wi = d->widgets.find(classname);
+ if(wi)
+ return wi->namePrefix();
+
+ return classname;
+}
+
+QString
+WidgetLibrary::textForWidgetName(const QCString &name, const QCString &className)
+{
+ loadFactories();
+ WidgetInfo *widget = d->widgets[className];
+ if(!widget)
+ return QString::null;
+
+ QString newName = name;
+ newName.remove(widget->namePrefix());
+ newName = widget->name() + " " + newName;
+ return newName;
+}
+
+QCString
+WidgetLibrary::classNameForAlternate(const QCString &classname)
+{
+ loadFactories();
+ if(d->widgets.find(classname))
+ return classname;
+
+ WidgetInfo *wi = d->widgets[classname];
+ if (wi) {
+ return wi->className();
+ }
+
+ // widget not supported
+ return "CustomWidget";
+}
+
+QString
+WidgetLibrary::includeFileName(const QCString &classname)
+{
+ loadFactories();
+ WidgetInfo *wi = d->widgets.find(classname);
+ if(wi)
+ return wi->includeFileName();
+
+ return QString::null;
+}
+
+QString
+WidgetLibrary::iconName(const QCString &classname)
+{
+ loadFactories();
+ WidgetInfo *wi = d->widgets.find(classname);
+ if(wi)
+ return wi->pixmap();
+
+ return QString::fromLatin1("unknown_widget");
+}
+
+bool
+WidgetLibrary::saveSpecialProperty(const QCString &classname, const QString &name, const QVariant &value, QWidget *w, QDomElement &parentNode, QDomDocument &parent)
+{
+ loadFactories();
+ WidgetInfo *wi = d->widgets.find(classname);
+ if (!wi)
+ return false;
+
+ if (wi->factory()->saveSpecialProperty(classname, name, value, w, parentNode, parent))
+ return true;
+ //try from inherited class
+ if (wi->inheritedClass())
+ return wi->inheritedClass()->factory()->saveSpecialProperty(wi->className(), name, value, w, parentNode, parent);
+ return false;
+}
+
+bool
+WidgetLibrary::readSpecialProperty(const QCString &classname, QDomElement &node, QWidget *w, ObjectTreeItem *item)
+{
+ loadFactories();
+ WidgetInfo *wi = d->widgets.find(classname);
+ if (!wi)
+ return false;
+ if (wi->factory()->readSpecialProperty(classname, node, w, item))
+ return true;
+ //try from inherited class
+ if (wi->inheritedClass())
+ return wi->inheritedClass()->factory()->readSpecialProperty(wi->className(), node, w, item);
+ return false;
+}
+
+void WidgetLibrary::setAdvancedPropertiesVisible(bool set)
+{
+ d->showAdvancedProperties = set;
+}
+
+bool WidgetLibrary::advancedPropertiesVisible() const
+{
+ return d->showAdvancedProperties;
+}
+
+bool
+WidgetLibrary::isPropertyVisible(const QCString &classname, QWidget *w,
+ const QCString &property, bool multiple, bool isTopLevel)
+{
+ if (isTopLevel) {
+ // no focus policy for top-level form widget...
+ if (!d->showAdvancedProperties && property == "focusPolicy")
+ return false;
+ }
+
+ loadFactories();
+ WidgetInfo *wi = d->widgets.find(classname);
+ if (!wi)
+ return false;
+ if (!d->showAdvancedProperties && d->advancedProperties[ property ]) {
+ //this is advanced property, should we hide it?
+ if (wi->factory()->internalProperty(classname, "forceShowAdvancedProperty:"+property).isEmpty()
+ && (!wi->inheritedClass() || wi->inheritedClass()->factory()->internalProperty(classname, "forceShowAdvancedProperty:"+property).isEmpty()))
+ {
+ return false; //hide it
+ }
+ }
+
+ if (!wi->factory()->isPropertyVisible(classname, w, property, multiple, isTopLevel))
+ return false;
+ //try from inherited class
+ if (wi->inheritedClass()
+ && !wi->inheritedClass()->factory()->isPropertyVisible(wi->className(), w, property, multiple, isTopLevel))
+ return false;
+
+ return true;
+}
+
+QValueList<QCString>
+WidgetLibrary::autoSaveProperties(const QCString &classname)
+{
+ loadFactories();
+ WidgetInfo *wi = d->widgets.find(classname);
+ if(!wi)
+ return QValueList<QCString>();
+ QValueList<QCString> lst;
+ //prepend from inherited class
+ if (wi->inheritedClass())
+ lst = wi->inheritedClass()->factory()->autoSaveProperties(wi->className());
+ lst += wi->factory()->autoSaveProperties(classname);
+ return lst;
+}
+
+WidgetInfo*
+WidgetLibrary::widgetInfoForClassName(const char* classname)
+{
+ loadFactories();
+ return d->widgets.find(classname);
+}
+
+WidgetFactory*
+WidgetLibrary::factoryForClassName(const char* classname)
+{
+ WidgetInfo *wi = widgetInfoForClassName(classname);
+ return wi ? wi->factory() : 0;
+}
+
+QString WidgetLibrary::propertyDescForName(WidgetInfo *winfo, const QCString& propertyName)
+{
+ if (!winfo || !winfo->factory())
+ return QString::null;
+ QString desc( winfo->factory()->propertyDescForName(propertyName) );
+ if (!desc.isEmpty())
+ return desc;
+ if (winfo->m_parentFactoryName.isEmpty())
+ return QString::null;
+
+ //try in parent factory, if exists
+ WidgetFactory *parentFactory = d->factories[winfo->m_parentFactoryName];
+ if (!parentFactory)
+ return QString::null;
+
+ return parentFactory->propertyDescForName(propertyName);
+}
+
+QString WidgetLibrary::propertyDescForValue(WidgetInfo *winfo, const QCString& name)
+{
+ if (!winfo->factory())
+ return QString::null;
+ QString desc( winfo->factory()->propertyDescForValue(name) );
+ if (!desc.isEmpty())
+ return desc;
+ if (winfo->m_parentFactoryName.isEmpty())
+ return QString::null;
+
+ //try in parent factory, if exists
+ WidgetFactory *parentFactory = d->factories[winfo->m_parentFactoryName];
+ if (!parentFactory)
+ return QString::null;
+
+ return parentFactory->propertyDescForValue(name);
+}
+
+void WidgetLibrary::setPropertyOptions( WidgetPropertySet& buf, const WidgetInfo& winfo, QWidget* w )
+{
+ if (!winfo.factory())
+ return;
+ winfo.factory()->setPropertyOptions(buf, winfo, w);
+ if (winfo.m_parentFactoryName.isEmpty())
+ return;
+ WidgetFactory *parentFactory = d->factories[winfo.m_parentFactoryName];
+ if (!parentFactory)
+ return;
+ parentFactory->setPropertyOptions(buf, winfo, w);
+}
+
+WidgetFactory* WidgetLibrary::factory(const char* factoryName) const
+{
+ return d->factories[factoryName];
+}
+
+QString WidgetLibrary::internalProperty(const QCString& classname, const QCString& property)
+{
+ loadFactories();
+ WidgetInfo *wclass = d->widgets[classname];
+ if(!wclass)
+ return QString::null;
+ QString value( wclass->factory()->internalProperty(classname, property) );
+ if (value.isEmpty() && wclass->inheritedClass())
+ return wclass->inheritedClass()->factory()->internalProperty(classname, property);
+ return value;
+}
+
+WidgetFactory::CreateWidgetOptions WidgetLibrary::showOrientationSelectionPopup(
+ const QCString &classname, QWidget* parent, const QPoint& pos)
+{
+ loadFactories();
+ WidgetInfo *wclass = d->widgets[classname];
+ if(!wclass)
+ return WidgetFactory::AnyOrientation;
+
+ //get custom icons and strings
+ QPixmap iconHorizontal, iconVertical;
+ QString iconName( wclass->factory()->internalProperty(classname, "orientationSelectionPopup:horizontalIcon") );
+ if (iconName.isEmpty() && wclass->inheritedClass())
+ iconName = wclass->inheritedClass()->factory()->internalProperty(classname, "orientationSelectionPopup:horizontalIcon");
+ if (!iconName.isEmpty())
+ iconHorizontal = SmallIcon(iconName);
+
+ iconName = wclass->factory()->internalProperty(classname, "orientationSelectionPopup:verticalIcon");
+ if (iconName.isEmpty() && wclass->inheritedClass())
+ iconName = wclass->inheritedClass()->factory()->internalProperty(classname, "orientationSelectionPopup:verticalIcon");
+ if (!iconName.isEmpty())
+ iconVertical = SmallIcon(iconName);
+
+ QString textHorizontal = wclass->factory()->internalProperty(classname, "orientationSelectionPopup:horizontalText");
+ if (textHorizontal.isEmpty() && wclass->inheritedClass())
+ iconName = wclass->inheritedClass()->factory()->internalProperty(classname, "orientationSelectionPopup:horizontalText");
+ if (textHorizontal.isEmpty()) //default
+ textHorizontal = i18n("Insert Horizontal Widget", "Insert Horizontal");
+
+ QString textVertical = wclass->factory()->internalProperty(classname, "orientationSelectionPopup:verticalText");
+ if (textVertical.isEmpty() && wclass->inheritedClass())
+ iconName = wclass->inheritedClass()->factory()->internalProperty(classname, "orientationSelectionPopup:verticalText");
+ if (textVertical.isEmpty()) //default
+ textVertical = i18n("Insert Vertical Widget", "Insert Vertical");
+
+ KPopupMenu* popup = new KPopupMenu(parent, "orientationSelectionPopup");
+ popup->insertTitle(SmallIcon(wclass->pixmap()), i18n("Insert Widget: %1").arg(wclass->name()));
+ popup->insertItem(iconHorizontal, textHorizontal, 1);
+ popup->insertItem(iconVertical, textVertical, 2);
+ popup->insertSeparator();
+ popup->insertItem(SmallIcon("button_cancel"), i18n("Cancel"), 3);
+ WidgetFactory::CreateWidgetOptions result;
+ switch (popup->exec(pos)) {
+ case 1:
+ result = WidgetFactory::HorizontalOrientation; break;
+ case 2:
+ result = WidgetFactory::VerticalOrientation; break;
+ default:
+ result = WidgetFactory::AnyOrientation; //means "cancelled"
+ }
+ delete popup;
+ return result;
+}
+
+bool WidgetLibrary::propertySetShouldBeReloadedAfterPropertyChange(
+ const QCString& classname, QWidget *w, const QCString& property)
+{
+ WidgetInfo *winfo = widgetInfoForClassName(classname);
+ if (!winfo)
+ return false;
+ return winfo->factory()->propertySetShouldBeReloadedAfterPropertyChange(classname, w, property);
+}
+
+#include "widgetlibrary.moc"
diff --git a/kexi/formeditor/widgetlibrary.h b/kexi/formeditor/widgetlibrary.h
new file mode 100644
index 00000000..f4f8c1f3
--- /dev/null
+++ b/kexi/formeditor/widgetlibrary.h
@@ -0,0 +1,212 @@
+/* This file is part of the KDE project
+ Copyright (C) 2003 Lucijan Busch <lucijan@gmx.at>
+ Copyright (C) 2004 Cedric Pasteur <cedric.pasteur@free.fr>
+ Copyright (C) 2004-2007 Jaroslaw Staniek <js@iidea.pl>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+*/
+
+#ifndef KFORMDESIGNERWIDGETLIBRARY_H
+#define KFORMDESIGNERWIDGETLIBRARY_H
+
+#include <qobject.h>
+#include <qmap.h>
+#include <qdict.h>
+
+#include "widgetfactory.h"
+
+template<class type> class QPtrList;
+template<class type> class QValueVector;
+class KActionCollection;
+class KAction;
+class QWidget;
+class QPopupMenu;
+class QVariant;
+class QDomDocument;
+class QDomElement;
+
+namespace KFormDesigner {
+
+class Container;
+class ObjectTreeItem;
+class WidgetLibraryPrivate;
+class WidgetPropertySet;
+
+typedef QPtrList<KAction> ActionList;
+
+/**
+ * This class searches for factories and provides KActions for widget creation.
+ * Every widget can be located using this library.
+ * You call WidgetLibrary functions instead of calling directly factories.
+ * See WidgetFactory for a description of the functions.
+ */
+class KFORMEDITOR_EXPORT WidgetLibrary : public QObject
+{
+ Q_OBJECT
+
+ public:
+ /*! Constructs WidgetLibrary object.
+ In \a supportedFactoryGroups you can provide
+ factory group list to be supported. Factory groups are defined by
+ "X-KFormDesigner-FactoryGroup" field in every factory serviece's .desktop file.
+ By default (when supportedFactoryGroups is empty) only factories having empty
+ "X-KFormDesigner-FactoryGroup" field will be loaded.
+ Factory group names are case-insensitive. */
+ WidgetLibrary(QObject *parent=0, const QStringList& supportedFactoryGroups = QStringList());
+
+ virtual ~WidgetLibrary();
+
+ /**
+ * creates actions for widget creating
+ */
+ ActionList createWidgetActions(KXMLGUIClient* client, KActionCollection *parent,
+ QObject *receiver, const char *slot);
+
+ void addCustomWidgetActions(KActionCollection *col);
+
+//old /**
+//old * creates the XML for widget actions
+//old */
+//old QString createXML();
+
+ /**
+ * searches the right factory and creates a widget.
+ * \return the widget or 0 if something falid
+ */
+ QWidget *createWidget(const QCString &classname, QWidget *parent, const char *name, Container *c,
+ int options = WidgetFactory::DefaultOptions);
+
+ bool createMenuActions(const QCString &c, QWidget *w, QPopupMenu *menu,
+ KFormDesigner::Container *container);
+
+ /**
+ * Shows orientation selection popup.
+ * \return one of the following values:
+ * - WidgetFactory::AnyOrientation (means no selection has been made, i.e. it was cancelled)
+ * - WidgetFactory::HorizontalOrientation
+ * - WidgetFactory::VerticalOrientation
+ */
+ WidgetFactory::CreateWidgetOptions showOrientationSelectionPopup(
+ const QCString &classname, QWidget* parent, const QPoint& pos);
+
+ QString internalProperty(const QCString& classname, const QCString& property);
+
+ QString displayName(const QCString &classname);
+ QString namePrefix(const QCString &classname);
+ QString textForWidgetName(const QCString &name, const QCString &className);
+
+ /*! Checks if the \a classname is an alternate classname,
+ and returns the good classname.
+ If \a classname is not alternate, \a classname is returned. */
+ QCString classNameForAlternate(const QCString &classname);
+ QString iconName(const QCString &classname);
+ QString includeFileName(const QCString &classname);
+ QString savingName(const QCString &classname);
+
+ bool startEditing(const QCString &classname, QWidget *w, Container *container);
+ bool previewWidget(const QCString &classname, QWidget *widget, Container *container);
+ bool clearWidgetContent(const QCString &classname, QWidget *w);
+
+ bool saveSpecialProperty(const QCString &classname, const QString &name,
+ const QVariant &value, QWidget *w, QDomElement &parentNode, QDomDocument &parent);
+ bool readSpecialProperty(const QCString &classname, QDomElement &node, QWidget *w,
+ ObjectTreeItem *item);
+ bool isPropertyVisible(const QCString &classname, QWidget *w,
+ const QCString &property, bool multiple = false, bool isTopLevel = false);
+
+ QValueList<QCString> autoSaveProperties(const QCString &classname);
+
+ WidgetInfo* widgetInfoForClassName(const char* classname);
+
+ WidgetFactory* factoryForClassName(const char* className);
+
+ WidgetFactory* factory(const char* factoryName) const;
+
+ /*! \return true if advanced properties like "mouseTracking" should
+ be user-visible. True by default (in KFD), but Kexi set's this to false.
+ See WidgetLibraryPrivate class implementation for complete list
+ of advanced properties. */
+ bool advancedPropertiesVisible() const;
+
+ /*! Sets advanced properties to be visible or not. */
+ void setAdvancedPropertiesVisible(bool set);
+
+ /*! \return The i18n'ed name of the property \a propertyName
+ for a class described by \a winfo. The name can be displayed in
+ PropertyEditor. The name is retrieved from class' widget library.
+ If this library doesn't define description for such property,
+ and there is a parent library for \a winfo defined, parent library
+ is asked for returning description string.
+ Eventually, if even this failed, empty string is returned.
+ @see WidgetFactory::propertyDescForName() */
+ QString propertyDescForName(WidgetInfo *winfo, const QCString& propertyName);
+
+ /*! \return The i18n'ed name of the property's value whose name is \a name.
+ Works in the same way as propertyDescForName(): if actual library
+ does not define a description we are looking for, parent factory is asked
+ to return such description.
+ Eventually, if even this failed, empty string is returned.
+ @see WidgetFactory::propertyDescForValue() */
+ QString propertyDescForValue(WidgetInfo *winfo, const QCString& name);
+
+ /*! Used by WidgetPropertySet::setWidget() after creating properties. */
+ void setPropertyOptions( WidgetPropertySet &list, const WidgetInfo& winfo, QWidget* w );
+
+ /*! \return true if property sets should be reloaded for \a property property,
+ \a classname class and widget \a w when a given property value changed. */
+ bool propertySetShouldBeReloadedAfterPropertyChange(const QCString& classname, QWidget *w,
+ const QCString& property);
+
+ signals:
+ void prepareInsert(const QCString &c);
+
+ //! Received by KexiFormPart::slotWidgetCreatedByFormsLibrary() so we can add drag/drop
+ //! connection for the new widget
+ void widgetCreated(QWidget *widget);
+
+ protected:
+ /**
+ * Adds a factory to the library, creates actions for widgets in the added factory.
+ * This function is not called directly but by the factory locater.
+ */
+ void loadFactoryWidgets(WidgetFactory *f);
+
+#if 0 //UNIMPLEMENTED
+ /**
+ * you can restrict the loaded factories by setting the filter to a pattern
+ * like 'kexi|containers' in that case only factory containing 'kexi' or containers will be loaded.
+ * this is useful if you want to embedd formeditor and provide e.g. a LineEdit with special features
+ * but don't want to confuse the user... are you confused now?
+ * NB: not implemented yet
+ */
+ void setFilter(const QRegExp &expr);
+#endif
+
+ /**
+ * Lookups widget factories list (note that this function get called once in ctor)
+ */
+ void lookupFactories();
+
+ /**
+ * Loads widget factories found in lookupFactories(). This is called once.
+ */
+ void loadFactories();
+
+ WidgetLibraryPrivate *d;
+};
+
+}
+#endif
diff --git a/kexi/formeditor/widgetpropertyset.cpp b/kexi/formeditor/widgetpropertyset.cpp
new file mode 100644
index 00000000..497fb5e6
--- /dev/null
+++ b/kexi/formeditor/widgetpropertyset.cpp
@@ -0,0 +1,1120 @@
+/* This file is part of the KDE project
+ Copyright (C) 2004 Cedric Pasteur <cedric.pasteur@free.fr>
+ Copyright (C) 2004-2006 Jaroslaw Staniek <js@iidea.pl>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+*/
+#include "widgetpropertyset.h"
+
+#include <qstringlist.h>
+#include <qstrlist.h>
+#include <qmetaobject.h>
+#include <qvariant.h>
+#include <qevent.h>
+#include <qlayout.h>
+#include <qapplication.h>
+#include <qeventloop.h>
+
+#include <klocale.h>
+#include <kdebug.h>
+#include <kmessagebox.h>
+
+#include "objecttree.h"
+#include "form.h"
+#include "container.h"
+#include "formmanager.h"
+#include "widgetlibrary.h"
+#include "commands.h"
+#include "widgetwithsubpropertiesinterface.h"
+
+#include <kexiutils/utils.h>
+#include <kexiutils/identifier.h>
+
+using namespace KFormDesigner;
+
+namespace KFormDesigner {
+
+//! @internal
+typedef QValueList< QGuardedPtr<QWidget> > QGuardedWidgetList;
+
+//! @internal
+class WidgetPropertySetPrivate
+{
+ public:
+ WidgetPropertySetPrivate()
+ : lastCommand(0), lastGeoCommand(0),
+ isUndoing(false), slotPropertyChangedEnabled(true),
+ slotPropertyChanged_addCommandEnabled(true),
+ origActiveColors(0)
+ {}
+ ~WidgetPropertySetPrivate()
+ {
+ delete origActiveColors;
+ }
+
+ KoProperty::Set set;
+ // list of properties (not) to show in editor
+ QStringList properties;
+ // list of widgets
+ QGuardedWidgetList widgets;
+// FormManager *manager;
+
+ // used to update command's value when undoing
+ PropertyCommand *lastCommand;
+ GeometryPropertyCommand *lastGeoCommand;
+ bool isUndoing : 1;
+ bool slotPropertyChangedEnabled : 1;
+ bool slotPropertyChanged_addCommandEnabled : 1;
+
+ // helper to change color palette when switching 'enabled' property
+ QColorGroup* origActiveColors;
+
+ // i18n stuff
+ QMap<QCString, QString> propCaption;
+ QMap<QCString, QString> propValCaption;
+};
+}
+
+WidgetPropertySet::WidgetPropertySet(QObject *parent)
+ : QObject(parent, "kfd_widgetPropertySet")
+{
+ d = new WidgetPropertySetPrivate();
+// d->manager = manager;
+
+ connect(&d->set, SIGNAL(propertyChanged(KoProperty::Set&, KoProperty::Property&)),
+ this, SLOT(slotPropertyChanged(KoProperty::Set&, KoProperty::Property&)));
+ connect(&d->set, SIGNAL(propertyReset(KoProperty::Set&, KoProperty::Property&)),
+ this, SLOT(slotPropertyReset(KoProperty::Set&, KoProperty::Property&)));
+
+ initPropertiesDescription();
+}
+
+WidgetPropertySet::~WidgetPropertySet()
+{
+ delete d;
+}
+
+/*FormManager*
+WidgetPropertySet::manager()
+{
+ return d->manager;
+}*/
+
+KoProperty::Property&
+WidgetPropertySet::operator[](const QCString &name)
+{
+ return d->set[name];
+}
+
+KoProperty::Property&
+WidgetPropertySet::property(const QCString &name)
+{
+ return d->set[name];
+}
+
+bool
+WidgetPropertySet::contains(const QCString &property)
+{
+ return d->set.contains(property);
+}
+
+KoProperty::Set*
+WidgetPropertySet::set()
+{
+ return &(d->set);
+}
+
+void
+WidgetPropertySet::clearSet(bool dontSignalShowPropertySet)
+{
+ saveModifiedProperties();
+
+ if (!dontSignalShowPropertySet)
+ KFormDesigner::FormManager::self()->showPropertySet(0);
+ d->widgets.clear();
+ d->lastCommand = 0;
+ d->lastGeoCommand = 0;
+ d->properties.clear();
+ d->set.clear();
+
+ if(!d->widgets.isEmpty()) {
+ d->widgets.first()->removeEventFilter(this);
+ disconnect(d->widgets.first(), 0, this, 0);
+ }
+}
+
+void
+WidgetPropertySet::saveModifiedProperties()
+{
+ QWidget * w = d->widgets.first();
+ if(!w || d->widgets.count() > 1 || !KFormDesigner::FormManager::self()->activeForm() || !KFormDesigner::FormManager::self()->activeForm()->objectTree())
+ return;
+ ObjectTreeItem *tree = KFormDesigner::FormManager::self()->activeForm()->objectTree()->lookup(w->name());
+ if(!tree)
+ return;
+
+ for(KoProperty::Set::Iterator it(d->set); it.current(); ++it) {
+ if(it.current()->isModified())
+ tree->addModifiedProperty(it.current()->name(), it.current()->oldValue());
+ }
+}
+
+void
+WidgetPropertySet::setUndoing(bool isUndoing)
+{
+ d->isUndoing = isUndoing;
+}
+
+bool
+WidgetPropertySet::isUndoing()
+{
+ return d->isUndoing;
+}
+
+/////////////// Functions related to adding widgets /////////////////////////////////////
+
+void
+WidgetPropertySet::setSelectedWidget(QWidget *w, bool add, bool forceReload, bool moreWillBeSelected)
+{
+ if(!w) {
+ clearSet();
+ return;
+ }
+
+ // don't add a widget twice
+ if(!forceReload && d->widgets.contains(QGuardedPtr<QWidget>(w))) {
+ kdWarning() << "WidgetPropertySet::setSelectedWidget() Widget is already selected" << endl;
+ return;
+ }
+ // if our list is empty,don't use add parameter value
+ if(d->widgets.count() == 0)
+ add = false;
+
+ QCString prevProperty;
+ if(add)
+ addWidget(w);
+ else {
+ if (forceReload) {
+ KFormDesigner::FormManager::self()->showPropertySet(0, true/*force*/);
+ prevProperty = d->set.prevSelection();
+ }
+ clearSet(true); //clear but do not reload to avoid blinking
+ d->widgets.append(QGuardedPtr<QWidget>(w));
+ createPropertiesForWidget(w);
+
+ w->installEventFilter(this);
+ connect(w, SIGNAL(destroyed()), this, SLOT(slotWidgetDestroyed()));
+ }
+
+ if (!moreWillBeSelected)
+ KFormDesigner::FormManager::self()->showPropertySet(this, true/*force*/, prevProperty);
+}
+
+void
+WidgetPropertySet::addWidget(QWidget *w)
+{
+ d->widgets.append(QGuardedPtr<QWidget>(w));
+
+ // Reset some stuff
+ d->lastCommand = 0;
+ d->lastGeoCommand = 0;
+ d->properties.clear();
+
+ QCString classname;
+ if(d->widgets.first()->className() == w->className())
+ classname = d->widgets.first()->className();
+
+ // show only properties shared by widget (properties chosen by factory)
+ bool isTopLevel = KFormDesigner::FormManager::self()->isTopLevel(w);
+
+ //WidgetWithSubpropertiesInterface* subpropIface = dynamic_cast<WidgetWithSubpropertiesInterface*>(w);
+// QWidget *subwidget = isSubproperty ? subpropIface->subwidget() : w;
+
+ for(KoProperty::Set::Iterator it(d->set); it.current(); ++it) {
+ kdDebug() << it.currentKey() << endl;
+ if(!isPropertyVisible(it.currentKey(), isTopLevel, classname))
+ d->set[it.currentKey()].setVisible(false);
+ }
+
+ if (d->widgets.count()>=2) {
+ //second widget, update metainfo
+ d->set["this:className"].setValue("special:multiple");
+ d->set["this:classString"].setValue(
+ i18n("Multiple Widgets") + QString(" (%1)").arg(d->widgets.count()) );
+ d->set["this:iconName"].setValue("multiple_obj");
+ //name doesn't make sense for now
+ d->set["name"].setValue("");
+ }
+}
+
+void
+WidgetPropertySet::createPropertiesForWidget(QWidget *w)
+{
+ Form *form;
+ if (!KFormDesigner::FormManager::self()
+ || !(form = KFormDesigner::FormManager::self()->activeForm())
+ || !KFormDesigner::FormManager::self()->activeForm()->objectTree())
+ {
+ kdWarning() << "WidgetPropertySet::createPropertiesForWidget() no manager or active form!!!" << endl;
+ return;
+ }
+ ObjectTreeItem *tree = form->objectTree()->lookup(w->name());
+ if(!tree)
+ return;
+
+ const QVariantMap* modifiedProperties = tree->modifiedProperties();
+ QVariantMapConstIterator modifiedPropertiesIt;
+ bool isTopLevel = KFormDesigner::FormManager::self()->isTopLevel(w);
+// int count = 0;
+ KoProperty::Property *newProp = 0;
+ WidgetInfo *winfo = form->library()->widgetInfoForClassName(w->className());
+ if (!winfo) {
+ kdWarning() << "WidgetPropertySet::createPropertiesForWidget() no widget info for class "
+ << w->className() << endl;
+ return;
+ }
+
+ QStrList pList = w->metaObject()->propertyNames(true);
+ QStrListIterator it(pList);
+
+ // add subproperties if available
+ WidgetWithSubpropertiesInterface* subpropIface = dynamic_cast<WidgetWithSubpropertiesInterface*>(w);
+ QStrList tmpList; //used to allocate copy of names
+ if (subpropIface) {
+ QValueList<QCString> subproperies(
+ subpropIface->subproperies() );
+ foreach(QValueListConstIterator<QCString>, it, subproperies ) {
+ tmpList.append( *it );
+ pList.append( tmpList.last() );
+ kdDebug() << "Added subproperty: " << *it << endl;
+ }
+ }
+
+ // iterate over the property list, and create Property objects
+ for(; it.current() != 0; ++it) {
+ //kdDebug() << ">> " << it.current() << endl;
+ const QMetaProperty *subMeta = // special case - subproperty
+ subpropIface ? subpropIface->findMetaSubproperty(it.current()) : 0;
+ const QMetaProperty *meta = subMeta ? subMeta
+ : w->metaObject()->property( w->metaObject()->findProperty(*it, true), true);
+ if (!meta)
+ continue;
+ const char* propertyName = meta->name();
+ QWidget *subwidget = subMeta/*subpropIface*/ ? subpropIface->subwidget() : w;
+ WidgetInfo *subwinfo = form->library()->widgetInfoForClassName(subwidget->className());
+// kdDebug() << "$$$ " << subwidget->className() << endl;
+
+ if(subwinfo && meta->designable(subwidget) && !d->set.contains(propertyName)) {
+ //! \todo add another list for property description
+ QString desc( d->propCaption[meta->name()] );
+ //! \todo change i18n
+ if (desc.isEmpty()) //try to get property description from factory
+ desc = form->library()->propertyDescForName(subwinfo, propertyName);
+
+ modifiedPropertiesIt = modifiedProperties->find(propertyName);
+ const bool oldValueExists = modifiedPropertiesIt!=modifiedProperties->constEnd();
+
+ if(meta->isEnumType()) {
+ if(qstrcmp(propertyName, "alignment") == 0) {
+ createAlignProperty(meta, w, subwidget);
+ continue;
+ }
+
+ QStringList keys = QStringList::fromStrList( meta->enumKeys() );
+ newProp = new KoProperty::Property(propertyName, createValueList(subwinfo, keys),
+ /* assign current or older value */
+ meta->valueToKey(
+ oldValueExists ? modifiedPropertiesIt.data().toInt() : subwidget->property(propertyName).toInt() ),
+ desc, desc );
+ //now set current value, so the old one is stored as old
+ if (oldValueExists) {
+ newProp->setValue( meta->valueToKey( subwidget->property(propertyName).toInt() ) );
+ }
+ }
+ else {
+ newProp = new KoProperty::Property(propertyName,
+ /* assign current or older value */
+ oldValueExists ? modifiedPropertiesIt.data() : subwidget->property(propertyName),
+ desc, desc, subwinfo->customTypeForProperty(propertyName));
+ //now set current value, so the old one is stored as old
+ if (oldValueExists) {
+ newProp->setValue( subwidget->property(propertyName) );
+ }
+ }
+
+ d->set.addProperty(newProp);
+ if(!isPropertyVisible(propertyName, isTopLevel))
+ newProp->setVisible(false);
+ //! TMP
+ if(newProp->type() == 0) // invalid type == null pixmap ?
+ newProp->setType(KoProperty::Pixmap);
+ }
+
+// if(0==qstrcmp(propertyName, "name"))
+// (*this)["name"].setAutoSync(0); // name should be updated only when pressing Enter
+
+ // \todo js what does this mean? why do you use WidgetInfo and not WidgetLibrary
+ /*if (winfo) {
+ tristate autoSync = winfo->autoSyncForProperty( propertyName );
+ if (! ~autoSync)
+ d->set[propertyName].setAutoSync( autoSync );
+ }*/
+
+ // update the Property.oldValue() and isModified() using the value stored in the ObjectTreeItem
+ updatePropertyValue(tree, propertyName, meta);
+ }
+
+ (*this)["name"].setAutoSync(false); // name should be updated only when pressing Enter
+ (*this)["enabled"].setValue( QVariant(tree->isEnabled(), 3));
+
+ if (winfo) {
+ form->library()->setPropertyOptions(*this, *winfo, w);
+ d->set.addProperty( newProp = new KoProperty::Property("this:classString", winfo->name()) );
+ newProp->setVisible(false);
+ d->set.addProperty( newProp = new KoProperty::Property("this:iconName", winfo->pixmap()) );
+ newProp->setVisible(false);
+ }
+ d->set.addProperty( newProp = new KoProperty::Property("this:className", w->className()) );
+ newProp->setVisible(false);
+
+ /*! let's forget it for now, until we have new complete events editor
+ if (m_manager->lib()->advancedPropertiesVisible()) {
+ // add the signals property
+ QStrList strlist = w->metaObject()->signalNames(true);
+ QStrListIterator strIt(strlist);
+ QStringList list;
+ for(; strIt.current() != 0; ++strIt)
+ list.append(*strIt);
+ Property *prop = new Property("signals", i18n("Events")"",
+ new KexiProperty::ListData(list, descList(winfo, list)),
+ ));
+ }*/
+
+ if(KFormDesigner::FormManager::self()->activeForm() && tree->container()) // we are a container -> layout property
+ createLayoutProperty(tree);
+}
+
+void
+WidgetPropertySet::updatePropertyValue(ObjectTreeItem *tree, const char *property, const QMetaProperty *meta)
+{
+ const char *propertyName = meta ? meta->name() : property;
+ if (!d->set.contains(propertyName))
+ return;
+ KoProperty::Property p( d->set[propertyName] );
+
+//! \todo what about set properties, and lists properties
+ QMap<QString, QVariant>::ConstIterator it( tree->modifiedProperties()->find(propertyName) );
+ if (it != tree->modifiedProperties()->constEnd()) {
+ blockSignals(true);
+ if(meta && meta->isEnumType()) {
+ p.setValue( meta->valueToKey( it.data().toInt() ), false );
+ }
+ else {
+ p.setValue(it.data(), false );
+ }
+ p.setValue(p.value(), true);
+ blockSignals(false);
+ }
+}
+
+bool
+WidgetPropertySet::isPropertyVisible(const QCString &property, bool isTopLevel, const QCString &classname)
+{
+ const bool multiple = d->widgets.count() >= 2;
+ if(multiple && classname.isEmpty())
+ return false;
+/* moved to WidgetLibrary::isPropertyVisible()
+ if(d->widgets.count() < 2)
+ {
+ if(d->properties.isEmpty() && !isTopLevel)
+ d->properties << "caption" << "icon" << "sizeIncrement" << "iconText";
+ // don't show these properties for a non-toplevel widget
+
+ if(! (d->properties.grep(property)).isEmpty() )
+ return false;
+ }
+ else
+ {
+ if(classname.isEmpty())
+ return false;
+
+ if(d->properties.isEmpty()) {
+ d->properties << "font" << "paletteBackgroundColor" << "enabled" << "paletteForegroundColor"
+ << "cursor" << "paletteBackgroundPixmap";
+ } // properties always shown in multiple mode
+ if(! (d->properties.grep(property)).isEmpty() )
+ return true;
+ }
+*/
+
+// return KFormDesigner::FormManager::self()->lib()->isPropertyVisible(d->widgets.first()->className(), d->widgets.first(),
+ QWidget *w = d->widgets.first();
+ WidgetWithSubpropertiesInterface* subpropIface = dynamic_cast<WidgetWithSubpropertiesInterface*>(w);
+ QWidget *subwidget;
+ if (subpropIface && subpropIface->findMetaSubproperty(property)) // special case - subproperty
+ subwidget = subpropIface->subwidget();
+ else
+ subwidget = w;
+
+ return KFormDesigner::FormManager::self()->activeForm()->library()->isPropertyVisible(
+ subwidget->className(), subwidget, property, multiple, isTopLevel);
+}
+
+//////////////// Slots called when properties are modified ///////////////
+
+void
+WidgetPropertySet::slotPropertyChanged(KoProperty::Set& set, KoProperty::Property& p)
+{
+ Q_UNUSED( set );
+
+ if(!d->slotPropertyChangedEnabled || !KFormDesigner::FormManager::self() || !KFormDesigner::FormManager::self()->activeForm()
+ || ! KFormDesigner::FormManager::self()->activeForm()->objectTree())
+ return;
+
+ QCString property = p.name();
+ if (0==property.find("this:"))
+ return; //starts with magical prefix: it's a "meta" prop.
+
+ QVariant value = p.value();
+
+ // check if the name is valid (ie is correct identifier) and there is no name conflict
+ if(property == "name") {
+ if(d->widgets.count()!=1)
+ return;
+ if(!isNameValid(value.toString()))
+ return;
+ }
+ // a widget with a background pixmap should have its own origin
+ else if(property == "paletteBackgroundPixmap") {
+ d->set["backgroundOrigin"] = "WidgetOrigin";
+ //else if(property == "signals")
+ // return;
+ // special types of properties handled separately
+ } else if((property == "hAlign") || (property == "vAlign") || (property == "wordbreak")) {
+ saveAlignProperty(property);
+ return;
+ }
+ else if((property == "layout") || (property == "layoutMargin") || (property == "layoutSpacing")) {
+ saveLayoutProperty(property, value);
+ return;
+ }
+ // we cannot really disable the widget, we just change its color palette
+ else if(property == "enabled") {
+ saveEnabledProperty(value.toBool());
+ return;
+ }
+
+ // make sure we are not already undoing -> avoid recursion
+ if(d->isUndoing && !KFormDesigner::FormManager::self()->isRedoing())
+ return;
+
+ const bool alterLastCommand = d->lastCommand && d->lastCommand->property() == property;
+
+ if(d->widgets.count() == 1) // one widget selected
+ {
+ // If the last command is the same, we just change its value
+ if(alterLastCommand && !KFormDesigner::FormManager::self()->isRedoing())
+ d->lastCommand->setValue(value);
+ else {
+// if(m_widgets.first() && ((m_widgets.first() != m_manager->activeForm()->widget()) || (property != "geometry"))) {
+ if (d->slotPropertyChanged_addCommandEnabled && !KFormDesigner::FormManager::self()->isRedoing()) {
+ d->lastCommand = new PropertyCommand(this, d->widgets.first()->name(),
+ d->widgets.first()->property(property), value, property);
+ KFormDesigner::FormManager::self()->activeForm()->addCommand(d->lastCommand, false);
+ }
+
+ // If the property is changed, we add it in ObjectTreeItem modifProp
+ ObjectTreeItem *tree = KFormDesigner::FormManager::self()->activeForm()->objectTree()->lookup(d->widgets.first()->name());
+ if (tree && p.isModified())
+ tree->addModifiedProperty(property, d->widgets.first()->property(property));
+ }
+
+ if(property == "name")
+ emit widgetNameChanged(d->widgets.first()->name(), p.value().toCString());
+ d->widgets.first()->setProperty(property, value);
+ emitWidgetPropertyChanged(d->widgets.first(), property, value);
+ }
+ else
+ {
+ if(alterLastCommand && !KFormDesigner::FormManager::self()->isRedoing())
+ d->lastCommand->setValue(value);
+ else {
+ if (d->slotPropertyChanged_addCommandEnabled && !KFormDesigner::FormManager::self()->isRedoing()) {
+ // We store old values for each widget
+ QMap<QCString, QVariant> list;
+ // for(QWidget *w = d->widgets.first(); w; w = d->widgets.next())
+ foreach(QGuardedWidgetList::ConstIterator, it, d->widgets)
+ list.insert((*it)->name(), (*it)->property(property));
+
+ d->lastCommand = new PropertyCommand(this, list, value, property);
+ KFormDesigner::FormManager::self()->activeForm()->addCommand(d->lastCommand, false);
+ }
+ }
+
+// for(QWidget *w = d->widgets.first(); w; w = d->widgets.next())
+ foreach(QGuardedWidgetList::ConstIterator, it, d->widgets) {
+ if (!alterLastCommand) {
+ ObjectTreeItem *tree = KFormDesigner::FormManager::self()->activeForm()->objectTree()
+ ->lookup((*it)->name());
+ if(tree && p.isModified())
+ tree->addModifiedProperty(property, (*it)->property(property));
+ }
+ (*it)->setProperty(property, value);
+ emitWidgetPropertyChanged((*it), property, value);
+ }
+ }
+}
+
+void WidgetPropertySet::emitWidgetPropertyChanged(QWidget *w, const QCString& property, const QVariant& value)
+{
+ emit widgetPropertyChanged(w, property, value);
+
+ Form *form = KFormDesigner::FormManager::self()->activeForm();
+ if (form && form->library()->propertySetShouldBeReloadedAfterPropertyChange( w->className(), w, property)) {
+ //setSelectedWidget(0, false);
+ qApp->eventLoop()->processEvents(QEventLoop::AllEvents); //be sure events related to editors are consumed
+ setSelectedWidget(w, /*!add*/false, /*forceReload*/true);
+ qApp->eventLoop()->processEvents(QEventLoop::AllEvents); //be sure events related to editors are consumed
+ //KFormDesigner::FormManager::self()->showPropertySet(this, true/*forceReload*/);
+ }
+}
+
+void
+WidgetPropertySet::createPropertyCommandsInDesignMode(QWidget* widget,
+ const QMap<QCString, QVariant> &propValues, CommandGroup *group, bool addToActiveForm,
+ bool execFlagForSubCommands)
+{
+ if (!widget || propValues.isEmpty())
+ return;
+
+ //is this widget selected? (if so, use property system)
+ const bool widgetIsSelected = KFormDesigner::FormManager::self()->activeForm()->selectedWidget() == widget;
+
+ d->slotPropertyChanged_addCommandEnabled = false;
+ QMap<QCString, QVariant>::ConstIterator endIt = propValues.constEnd();
+// CommandGroup *group = new CommandGroup(commandName);
+ for(QMap<QCString, QVariant>::ConstIterator it = propValues.constBegin(); it != endIt; ++it)
+ {
+ if (!d->set.contains(it.key())) {
+ kdWarning() << "WidgetPropertySet::createPropertyCommandsInDesignMode(): \"" <<it.key()<<"\" property not found"<<endl;
+ continue;
+ }
+ PropertyCommand *subCommand = new PropertyCommand(this, widget->name(),
+ widget->property(it.key()), it.data(), it.key());
+ group->addCommand( subCommand, execFlagForSubCommands);
+ if (widgetIsSelected) {
+ d->set[it.key()].setValue(it.data());
+ }
+ else {
+ WidgetWithSubpropertiesInterface* subpropIface = dynamic_cast<WidgetWithSubpropertiesInterface*>(widget);
+ QWidget *subwidget = (subpropIface && subpropIface->subwidget()) ? subpropIface->subwidget() : widget;
+ if (-1 != subwidget->metaObject()->findProperty(it.key(), true) && subwidget->property(it.key())!=it.data()) {
+ ObjectTreeItem *tree = KFormDesigner::FormManager::self()->activeForm()->objectTree()->lookup(widget->name());
+ if (tree)
+ tree->addModifiedProperty(it.key(), subwidget->property(it.key()));
+ subwidget->setProperty(it.key(), it.data());
+ emit widgetPropertyChanged(widget, it.key(), it.data());
+ }
+ }
+ }
+ d->lastCommand = 0;
+ if (addToActiveForm)
+ KFormDesigner::FormManager::self()->activeForm()->addCommand(group, false/*no exec*/);
+ d->slotPropertyChanged_addCommandEnabled = true;
+// }
+}
+
+//! \todo make it support undo
+void
+WidgetPropertySet::saveEnabledProperty(bool value)
+{
+// for(QWidget *w = d->widgets.first(); w; w = d->widgets.next()) {
+ foreach(QGuardedWidgetList::ConstIterator, it, d->widgets) {
+ ObjectTreeItem *tree = KFormDesigner::FormManager::self()->activeForm()->objectTree()
+ ->lookup((*it)->name());
+ if(tree->isEnabled() == value)
+ continue;
+
+ QPalette p( (*it)->palette() );
+ if (!d->origActiveColors)
+ d->origActiveColors = new QColorGroup( p.active() );
+ if (value) {
+ if (d->origActiveColors)
+ p.setActive( *d->origActiveColors ); //revert
+ }
+ else {
+ QColorGroup cg = p.disabled();
+ //also make base color a bit disabled-like
+ cg.setColor(QColorGroup::Base, cg.color(QColorGroup::Background));
+ p.setActive(cg);
+ }
+ (*it)->setPalette(p);
+
+ tree->setEnabled(value);
+ emit widgetPropertyChanged((*it), "enabled", QVariant(value, 3));
+ }
+}
+
+bool
+WidgetPropertySet::isNameValid(const QString &name)
+{
+ //! \todo add to undo buffer
+ QWidget *w = d->widgets.first();
+ //also update widget's name in QObject member
+ if (!KexiUtils::isIdentifier(name)) {
+ KMessageBox::sorry(KFormDesigner::FormManager::self()->activeForm()->widget(),
+ i18n("Could not rename widget \"%1\" to \"%2\" because "
+ "\"%3\" is not a valid name (identifier) for a widget.\n")
+ .arg(w->name()).arg(name).arg(name));
+ d->slotPropertyChangedEnabled = false;
+ d->set["name"].resetValue();
+ d->slotPropertyChangedEnabled = true;
+ return false;
+ }
+
+ if (KFormDesigner::FormManager::self()->activeForm()->objectTree()->lookup(name)) {
+ KMessageBox::sorry( KFormDesigner::FormManager::self()->activeForm()->widget(),
+ i18n("Could not rename widget \"%1\" to \"%2\" "
+ "because a widget with the name \"%3\" already exists.\n")
+ .arg(w->name()).arg(name).arg(name));
+ d->slotPropertyChangedEnabled = false;
+ d->set["name"].resetValue();
+ d->slotPropertyChangedEnabled = true;
+ return false;
+ }
+
+ return true; //ie name is correct
+}
+
+void
+WidgetPropertySet::slotPropertyReset(KoProperty::Set& set, KoProperty::Property& property)
+{
+ Q_UNUSED( set );
+
+ if(d->widgets.count() < 2)
+ return;
+
+ // We use the old value in modifProp for each widget
+// for(QWidget *w = d->widgets.first(); w; w = d->widgets.next()) {
+ foreach(QGuardedWidgetList::ConstIterator, it, d->widgets) {
+ ObjectTreeItem *tree = KFormDesigner::FormManager::self()->activeForm()->objectTree()->lookup((*it)->name());
+ if(tree->modifiedProperties()->contains(property.name()))
+ (*it)->setProperty(property.name(), tree->modifiedProperties()->find(property.name()).data());
+ }
+}
+
+void
+WidgetPropertySet::slotWidgetDestroyed()
+{
+// if(d->widgets.contains(QGuardedPtr<const QWidget>( dynamic_cast<const QWidget*>(sender()) ))) {
+ //only clear this set if it contains the destroyed widget
+ foreach(QGuardedWidgetList::ConstIterator, it, d->widgets) {
+ if (dynamic_cast<const QWidget*>(sender()) == *it) {
+ clearSet();
+ break;
+ }
+ }
+}
+
+bool
+WidgetPropertySet::eventFilter(QObject *o, QEvent *ev)
+{
+ if(d->widgets.count() > 0 && o == d->widgets.first() && d->widgets.count() < 2)
+ {
+ if((ev->type() == QEvent::Resize) || (ev->type() == QEvent::Move)) {
+ if(!d->set.contains("geometry"))
+ return false;
+ if(d->set["geometry"].value() == o->property("geometry")) // to avoid infinite recursion
+ return false;
+
+ d->set["geometry"] = static_cast<QWidget*>(o)->geometry();
+ }
+ }
+ else if(d->widgets.count() > 1 && ev->type() == QEvent::Move) // the widget is being moved, we update the property
+ {
+ if(d->isUndoing)
+ return false;
+
+ if(d->lastGeoCommand)
+ d->lastGeoCommand->setPos(static_cast<QMoveEvent*>(ev)->pos());
+ else {
+ QStringList list;
+ foreach(QGuardedWidgetList::ConstIterator, it, d->widgets)
+ list.append((*it)->name());
+
+ d->lastGeoCommand = new GeometryPropertyCommand(this, list, static_cast<QMoveEvent*>(ev)->oldPos());
+ if (KFormDesigner::FormManager::self()->activeForm())
+ KFormDesigner::FormManager::self()->activeForm()->addCommand(d->lastGeoCommand, false);
+ }
+ }
+
+ return false;
+}
+
+// Alignment-related functions /////////////////////////////
+
+void
+WidgetPropertySet::createAlignProperty(const QMetaProperty *meta, QWidget *widget, QWidget *subwidget)
+{
+ if (!KFormDesigner::FormManager::self()->activeForm()
+|| !KFormDesigner::FormManager::self()->activeForm()->objectTree())
+ return;
+
+ QStringList list;
+ QString value;
+ const int alignment = subwidget->property("alignment").toInt();
+ const QStringList keys( QStringList::fromStrList( meta->valueToKeys(alignment) ) );
+
+ QStrList *enumKeys = new QStrList(meta->enumKeys());
+ const QStringList possibleValues( QStringList::fromStrList(*enumKeys) );
+ delete enumKeys;
+
+ ObjectTreeItem *tree = KFormDesigner::FormManager::self()->activeForm()->objectTree()->lookup(widget->name());
+ bool isTopLevel = KFormDesigner::FormManager::self()->isTopLevel(widget);
+
+ if(possibleValues.find("AlignHCenter")!=possibleValues.constEnd()) {
+ // Create the horizontal alignment property
+ if(keys.find("AlignHCenter")!=keys.constEnd() || keys.find("AlignCenter")!=keys.constEnd())
+ value = "AlignHCenter";
+ else if(keys.find("AlignRight")!=keys.constEnd())
+ value = "AlignRight";
+ else if(keys.find("AlignLeft")!=keys.constEnd())
+ value = "AlignLeft";
+ else if(keys.find("AlignJustify")!=keys.constEnd())
+ value = "AlignJustify";
+ else
+ value = "AlignAuto";
+
+ list << "AlignAuto" << "AlignLeft" << "AlignRight" << "AlignHCenter" << "AlignJustify";
+ KoProperty::Property *p = new KoProperty::Property("hAlign", createValueList(0, list), value,
+ i18n("Translators: please keep this string short (less than 20 chars)", "Hor. Alignment"),
+ i18n("Horizontal Alignment"));
+ d->set.addProperty(p);
+ if(!isPropertyVisible(p->name(), isTopLevel)) {
+ p->setVisible(false);
+ }
+ updatePropertyValue(tree, "hAlign");
+ list.clear();
+ }
+
+ if(possibleValues.find("AlignTop")!=possibleValues.constEnd())
+ {
+ // Create the ver alignment property
+ if(keys.find("AlignTop")!=keys.constEnd())
+ value = "AlignTop";
+ else if(keys.find("AlignBottom")!=keys.constEnd())
+ value = "AlignBottom";
+ else
+ value = "AlignVCenter";
+
+ list << "AlignTop" << "AlignVCenter" << "AlignBottom";
+ KoProperty::Property *p = new KoProperty::Property("vAlign", createValueList(0, list), value,
+ i18n("Translators: please keep this string short (less than 20 chars)", "Ver. Alignment"),
+ i18n("Vertical Alignment"));
+ d->set.addProperty(p);
+ if(!isPropertyVisible(p->name(), isTopLevel)) {
+ p->setVisible(false);
+ }
+ updatePropertyValue(tree, "vAlign");
+ }
+
+ if(possibleValues.find("WordBreak")!=possibleValues.constEnd()
+// && isPropertyVisible("wordbreak", false, subwidget->className())
+// && !subWidget->inherits("QLineEdit") /* QLineEdit doesn't support 'word break' is this generic enough?*/
+ ) {
+ // Create the wordbreak property
+ KoProperty::Property *p = new KoProperty::Property("wordbreak",
+ QVariant(alignment & Qt::WordBreak, 3), i18n("Word Break"), i18n("Word Break") );
+ d->set.addProperty(p);
+ updatePropertyValue(tree, "wordbreak");
+ if (!KFormDesigner::FormManager::self()->activeForm()->library()->isPropertyVisible(
+ subwidget->className(), subwidget, p->name(), false/*multiple*/, isTopLevel))
+ {
+ p->setVisible(false);
+ }
+ }
+}
+
+void
+WidgetPropertySet::saveAlignProperty(const QString &property)
+{
+ if (!KFormDesigner::FormManager::self()->activeForm())
+ return;
+
+ QStrList list;
+ if( d->set.contains("hAlign") )
+ list.append( d->set["hAlign"].value().toCString() );
+ if( d->set.contains("vAlign") )
+ list.append( d->set["vAlign"].value().toCString() );
+ if( d->set.contains("wordbreak") && d->set["wordbreak"].value().toBool() )
+ list.append("WordBreak");
+
+ WidgetWithSubpropertiesInterface* subpropIface = dynamic_cast<WidgetWithSubpropertiesInterface*>(
+ (QWidget*)d->widgets.first() );
+ QWidget *subwidget = (subpropIface && subpropIface->subwidget()) ? subpropIface->subwidget() : (QWidget*)d->widgets.first();
+ int count = subwidget->metaObject()->findProperty("alignment", true);
+ const QMetaProperty *meta = subwidget->metaObject()->property(count, true);
+ subwidget->setProperty("alignment", meta->keysToValue(list));
+
+ ObjectTreeItem *tree = KFormDesigner::FormManager::self()->activeForm()->objectTree()->lookup(
+ d->widgets.first()->name() );
+ if(tree && d->set[property.latin1()].isModified())
+ tree->addModifiedProperty(property.latin1(), d->set[property.latin1()].oldValue());
+
+ if(d->isUndoing)
+ return;
+
+ if(d->lastCommand && d->lastCommand->property() == "alignment")
+ d->lastCommand->setValue(meta->keysToValue(list));
+ else {
+ d->lastCommand = new PropertyCommand(this, d->widgets.first()->name(),
+ subwidget->property("alignment"), meta->keysToValue(list), "alignment");
+ KFormDesigner::FormManager::self()->activeForm()->addCommand(d->lastCommand, false);
+ }
+}
+
+// Layout-related functions //////////////////////////
+
+void
+WidgetPropertySet::createLayoutProperty(ObjectTreeItem *item)
+{
+ Container *container = item->container();
+ if (!container || !KFormDesigner::FormManager::self()->activeForm() ||
+ !KFormDesigner::FormManager::self()->activeForm()->objectTree() || !container->widget())
+ return;
+ // special containers have no 'layout' property, as it should not be changed
+ QCString className = container->widget()->className();
+ if((className == "HBox") || (className == "VBox") || (className == "Grid"))
+ return;
+
+ QStringList list;
+ QString value = Container::layoutTypeToString(container->layoutType());
+
+ list << "NoLayout" << "HBox" << "VBox" << "Grid" << "HFlow" << "VFlow";
+
+ KoProperty::Property *p = new KoProperty::Property("layout", createValueList(0, list), value,
+ i18n("Container's Layout"), i18n("Container's Layout"));
+ p->setVisible( container->form()->library()->advancedPropertiesVisible() );
+ d->set.addProperty(p);
+
+ updatePropertyValue(item, "layout");
+
+ p = new KoProperty::Property("layoutMargin", container->layoutMargin(), i18n("Layout Margin"), i18n("Layout Margin"));
+ d->set.addProperty(p);
+ updatePropertyValue(item, "layoutMargin");
+ if(container->layoutType() == Container::NoLayout)
+ p->setVisible(false);
+
+ p = new KoProperty::Property("layoutSpacing", container->layoutSpacing(),
+ i18n("Layout Spacing"), i18n("Layout Spacing"));
+ d->set.addProperty(p);
+ updatePropertyValue(item, "layoutSpacing");
+ if(container->layoutType() == Container::NoLayout)
+ p->setVisible(false);
+
+}
+
+void
+WidgetPropertySet::saveLayoutProperty(const QString &prop, const QVariant &value)
+{
+ Container *container=0;
+ if(!KFormDesigner::FormManager::self()->activeForm() || !KFormDesigner::FormManager::self()->activeForm()->objectTree())
+ return;
+ ObjectTreeItem *item = KFormDesigner::FormManager::self()->activeForm()->objectTree()->lookup(d->widgets.first()->name());
+ if(!item)
+ return;
+ container = item->container();
+
+ if(prop == "layout") {
+ Container::LayoutType type = Container::stringToLayoutType(value.toString());
+
+ if(d->lastCommand && d->lastCommand->property() == "layout" && !d->isUndoing)
+ d->lastCommand->setValue(value);
+ else if(!d->isUndoing) {
+ d->lastCommand = new LayoutPropertyCommand(this, d->widgets.first()->name(),
+ d->set["layout"].oldValue(), value);
+ KFormDesigner::FormManager::self()->activeForm()->addCommand(d->lastCommand, false);
+ }
+
+ container->setLayout(type);
+ bool show = (type != Container::NoLayout);
+ if(show != d->set["layoutMargin"].isVisible()) {
+ d->set["layoutMargin"].setVisible(show);
+ d->set["layoutSpacing"].setVisible(show);
+ KFormDesigner::FormManager::self()->showPropertySet(this, true/*force*/);
+ }
+ return;
+ }
+
+ if(prop == "layoutMargin" && container->layout()) {
+ container->setLayoutMargin(value.toInt());
+ container->layout()->setMargin(value.toInt());
+ }
+ else if(prop == "layoutSpacing" && container->layout()) {
+ container->setLayoutSpacing(value.toInt());
+ container->layout()->setSpacing(value.toInt());
+ }
+
+ ObjectTreeItem *tree = KFormDesigner::FormManager::self()->activeForm()->objectTree()->lookup(d->widgets.first()->name());
+ if(tree && d->set[ prop.latin1() ].isModified())
+ tree->addModifiedProperty(prop.latin1(), d->set[prop.latin1()].oldValue());
+
+ if(d->isUndoing)
+ return;
+
+ if(d->lastCommand && (QString(d->lastCommand->property()) == prop))
+ d->lastCommand->setValue(value);
+ else {
+ d->lastCommand = new PropertyCommand(this, d->widgets.first()->name(),
+ d->set[ prop.latin1() ].oldValue(), value, prop.latin1());
+ KFormDesigner::FormManager::self()->activeForm()->addCommand(d->lastCommand, false);
+ }
+}
+
+
+
+////////////////////////////////////////// i18n related functions ////////
+
+void
+WidgetPropertySet::initPropertiesDescription()
+{
+//! \todo perhaps a few of them shouldn't be translated within KFD mode,
+//! to be more Qt Designer friendly?
+ d->propCaption["name"] = i18n("Name");
+ d->propCaption["caption"] = i18n("Caption");
+ d->propCaption["text"] = i18n("Text");
+ d->propCaption["paletteBackgroundPixmap"] = i18n("Background Pixmap");
+ d->propCaption["enabled"] = i18n("Enabled");
+ d->propCaption["geometry"] = i18n("Geometry");
+ d->propCaption["sizePolicy"] = i18n("Size Policy");
+ d->propCaption["minimumSize"] = i18n("Minimum Size");
+ d->propCaption["maximumSize"] = i18n("Maximum Size");
+ d->propCaption["font"] = i18n("Font");
+ d->propCaption["cursor"] = i18n("Cursor");
+ d->propCaption["paletteForegroundColor"] = i18n("Foreground Color");
+ d->propCaption["paletteBackgroundColor"] = i18n("Background Color");
+ d->propCaption["focusPolicy"] = i18n("Focus Policy");
+ d->propCaption["margin"] = i18n("Margin");
+ d->propCaption["readOnly"] = i18n("Read Only");
+ //any QFrame
+ d->propCaption["frame"] = i18n("Frame");
+ d->propCaption["lineWidth"] = i18n("Frame Width");
+ d->propCaption["midLineWidth"] = i18n("Mid Frame Width");
+ d->propCaption["frameShape"] = i18n("Frame Shape");
+ d->propCaption["frameShadow"] = i18n("Frame Shadow");
+ //any QScrollbar
+ d->propCaption["vScrollBarMode"] = i18n("Vertical ScrollBar");
+ d->propCaption["hScrollBarMode"] = i18n("Horizontal ScrollBar");
+
+ d->propValCaption["NoBackground"] = i18n("No Background");
+ d->propValCaption["PaletteForeground"] = i18n("Palette Foreground");
+ d->propValCaption["AutoText"] = i18n("Auto (HINT: for AutoText)", "Auto");
+
+ d->propValCaption["AlignAuto"] = i18n("Auto (HINT: for Align)", "Auto");
+ d->propValCaption["AlignLeft"] = i18n("Left (HINT: for Align)", "Left");
+ d->propValCaption["AlignRight"] = i18n("Right (HINT: for Align)", "Right");
+ d->propValCaption["AlignHCenter"] = i18n("Center (HINT: for Align)", "Center");
+ d->propValCaption["AlignJustify"] = i18n("Justify (HINT: for Align)", "Justify");
+ d->propValCaption["AlignVCenter"] = i18n("Center (HINT: for Align)", "Center");
+ d->propValCaption["AlignTop"] = i18n("Top (HINT: for Align)", "Top");
+ d->propValCaption["AlignBottom"] = i18n("Bottom (HINT: for Align)", "Bottom");
+
+ d->propValCaption["NoFrame"] = i18n("No Frame (HINT: for Frame Shape)", "No Frame");
+ d->propValCaption["Box"] = i18n("Box (HINT: for Frame Shape)", "Box");
+ d->propValCaption["Panel"] = i18n("Panel (HINT: for Frame Shape)", "Panel");
+ d->propValCaption["WinPanel"] = i18n("Windows Panel (HINT: for Frame Shape)", "Windows Panel");
+ d->propValCaption["HLine"] = i18n("Horiz. Line (HINT: for Frame Shape)", "Horiz. Line");
+ d->propValCaption["VLine"] = i18n("Vertical Line (HINT: for Frame Shape)", "Vertical Line");
+ d->propValCaption["StyledPanel"] = i18n("Styled (HINT: for Frame Shape)", "Styled");
+ d->propValCaption["PopupPanel"] = i18n("Popup (HINT: for Frame Shape)", "Popup");
+ d->propValCaption["MenuBarPanel"] = i18n("Menu Bar (HINT: for Frame Shape)", "Menu Bar");
+ d->propValCaption["ToolBarPanel"] = i18n("Toolbar (HINT: for Frame Shape)", "Toolbar");
+ d->propValCaption["LineEditPanel"] = i18n("Text Box (HINT: for Frame Shape)", "Text Box");
+ d->propValCaption["TabWidgetPanel"] = i18n("Tab Widget (HINT: for Frame Shape)", "Tab Widget");
+ d->propValCaption["GroupBoxPanel"] = i18n("Group Box (HINT: for Frame Shape)", "Group Box");
+
+ d->propValCaption["Plain"] = i18n("Plain (HINT: for Frame Shadow)", "Plain");
+ d->propValCaption["Raised"] = i18n("Raised (HINT: for Frame Shadow)", "Raised");
+ d->propValCaption["Sunken"] = i18n("Sunken (HINT: for Frame Shadow)", "Sunken");
+ d->propValCaption["MShadow"] = i18n("for Frame Shadow", "Internal");
+
+ d->propValCaption["NoFocus"] = i18n("No Focus (HINT: for Focus)", "No Focus");
+ d->propValCaption["TabFocus"] = i18n("Tab (HINT: for Focus)", "Tab");
+ d->propValCaption["ClickFocus"] = i18n("Click (HINT: for Focus)", "Click");
+ d->propValCaption["StrongFocus"] = i18n("Tab/Click (HINT: for Focus)", "Tab/Click");
+ d->propValCaption["WheelFocus"] = i18n("Tab/Click/MouseWheel (HINT: for Focus)", "Tab/Click/MouseWheel");
+
+ d->propValCaption["Auto"] = i18n("Auto");
+ d->propValCaption["AlwaysOff"] = i18n("Always Off");
+ d->propValCaption["AlwaysOn"] = i18n("Always On");
+
+ //orientation
+ d->propValCaption["Horizontal"] = i18n("Horizontal");
+ d->propValCaption["Vertical"] = i18n("Vertical");
+}
+
+QString
+WidgetPropertySet::propertyCaption(const QCString &name)
+{
+ return d->propCaption[name];
+}
+
+QString
+WidgetPropertySet::valueCaption(const QCString &name)
+{
+ return d->propValCaption[name];
+}
+
+KoProperty::Property::ListData*
+WidgetPropertySet::createValueList(WidgetInfo *winfo, const QStringList &list)
+{
+// QMap <QString, QVariant> map;
+ QStringList names;
+ QStringList::ConstIterator endIt = list.end();
+ for(QStringList::ConstIterator it = list.begin(); it != endIt; ++it) {
+ QString n( d->propValCaption[ (*it).latin1() ] );
+ if (n.isEmpty()) { //try within factory and (maybe) parent factory
+ if (winfo)
+ n = KFormDesigner::FormManager::self()->activeForm()->library()->propertyDescForValue( winfo, (*it).latin1() );
+ if (n.isEmpty())
+ names.append( *it ); //untranslated
+// map.insert(*it, (*it).latin1()); //untranslated
+ else
+ names.append( n );
+// map.insert(*it, n);
+ }
+ else
+ names.append( n );
+// map.insert(*it, n);
+ }
+ return new KoProperty::Property::ListData(list, names);
+}
+
+void
+WidgetPropertySet::addPropertyCaption(const QCString &property, const QString &caption)
+{
+ if(!d->propCaption.contains(property))
+ d->propCaption[property] = caption;
+}
+
+void
+WidgetPropertySet::addValueCaption(const QCString &value, const QString &caption)
+{
+ if(!d->propValCaption.contains(value))
+ d->propValCaption[value] = caption;
+}
+
+#include "widgetpropertyset.moc"
diff --git a/kexi/formeditor/widgetpropertyset.h b/kexi/formeditor/widgetpropertyset.h
new file mode 100644
index 00000000..71e7b225
--- /dev/null
+++ b/kexi/formeditor/widgetpropertyset.h
@@ -0,0 +1,206 @@
+/* This file is part of the KDE project
+ Copyright (C) 2004 Cedric Pasteur <cedric.pasteur@free.fr>
+ Copyright (C) 2004-2006 Jaroslaw Staniek <js@iidea.pl>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+*/
+
+#ifndef KFD_WIDGETPROPERTYSET_H
+#define KFD_WIDGETPROPERTYSET_H
+
+#include <qobject.h>
+#include <qstrlist.h>
+
+#include <koproperty/set.h>
+#include <koproperty/property.h>
+
+class QMetaObject;
+class QWidget;
+
+namespace KFormDesigner {
+
+class FormManager;
+class ObjectTreeItem;
+class WidgetPropertySetPrivate;
+class WidgetInfo;
+class CommandGroup;
+
+class KFORMEDITOR_EXPORT WidgetPropertySet : public QObject
+{
+ Q_OBJECT
+
+ public:
+ WidgetPropertySet(QObject *parent);
+ ~WidgetPropertySet();
+
+// FormManager* manager();
+
+ KoProperty::Property& operator[](const QCString &name);
+
+ KoProperty::Property& property(const QCString &name);
+
+ bool contains(const QCString &property);
+
+ /*! i18n function used by factories to add new property caption.
+ Should be called on Factory creation. */
+ void addPropertyCaption(const QCString &property, const QString &caption);
+
+ void addValueCaption(const QCString &value, const QString &caption);
+
+ public slots:
+ /*! Sets the widget which properties are shown in the property editor.
+ If \a add is true, the list switch to multiple widget mode
+ (only common properties are shown). Should be directly
+ connected to Form::widgetSelected() signal.
+ If \a forceReload is true, the the properties will be redisplayed in the property editor
+ even if these were already displayed.
+ If \a showPropertySet is true (the default), property editor will be updated for the current selection.
+ This flag is set to false when we're selecting multiple widgets. */
+ void setSelectedWidget(QWidget *w, bool add = false, bool forceReload = false,
+ bool moreWillBeSelected = false);
+
+ void setSelectedWidgetWithoutReload(QWidget *w, bool add = false, bool moreWillBeSelected = false) {
+ setSelectedWidget(w, add, false, moreWillBeSelected);
+ }
+
+ /*! This function is called every time a property is modifed. It also takes
+ care of saving set and enum properties. */
+ void slotPropertyChanged(KoProperty::Set& set, KoProperty::Property& property);
+
+ /*! This slot is called when a property is reset using the "reload" button in PropertyEditor. */
+ void slotPropertyReset(KoProperty::Set& set, KoProperty::Property& property);
+
+ /*! This slot is called when the watched widget is destroyed. Resets the buffer.*/
+ void slotWidgetDestroyed();
+
+// void setPropertyValueInDesignMode(QWidget* widget, const QMap<QCString, QVariant> &propValues,
+ void createPropertyCommandsInDesignMode(QWidget* widget, const QMap<QCString,
+ QVariant> &propValues, CommandGroup *group, bool addToActiveForm = true,
+ bool execFlagForSubCommands = false);
+
+ signals:
+ /*! This signal is emitted when a property was changed.
+ \a widg is the widget concerned, \a property
+ is the name of the modified property, and \a v is the new value of this property. */
+ void widgetPropertyChanged(QWidget *w, const QCString &property, const QVariant &v);
+
+ /*! This signal is emitted when the name of the widget is modified.
+ \a oldname is the name of the widget before the
+ change, \a newname is the name after renaming. */
+ void widgetNameChanged(const QCString &oldname, const QCString &newname);
+
+ protected:
+ /*! Adds the widget in d->widgets, and updates property visibilty. */
+ void addWidget(QWidget *w);
+
+ /*! Fills the list with properties related to the widget \a w. Also updates
+ properties old value and changed state. */
+ void createPropertiesForWidget(QWidget *w);
+
+ /*! Creates a map property description->prop. value from
+ the list of keys \a list. */
+ KoProperty::Property::ListData* createValueList(WidgetInfo *winfo, const QStringList &list);
+
+ /*! Changes \a property old value and changed state, using the value
+ stored in \a tree. Optional \a meta can be specified if you need to handle enum values. */
+ void updatePropertyValue(ObjectTreeItem *tree, const char *property, const QMetaProperty *meta = 0);
+
+ /*! \return the property list hold by this object. Do not modify the list,
+ just use this method to change Editor's list. */
+ KoProperty::Set* set();
+
+ /*! Clears the set, and reset all members. */
+ void clearSet(bool dontSignalShowPropertySet = false);
+
+ /*! Saves old values of modified properties in ObjectTreeItem, so
+ that we can restore them later.*/
+ void saveModifiedProperties();
+
+ /*! Checks if the name entered by user is valid, ie that it is
+ a valid identifier, and that there is no name conflict. */
+ bool isNameValid(const QString &name);
+
+ /*! Saves 'enabled' property, and takes care of updating widget's palette. */
+ void saveEnabledProperty(bool value);
+
+ /*! This function filters the event of the selected widget to
+ automatically updates the "geometry" property
+ when the widget is moved or resized in the Form. */
+ bool eventFilter(QObject *o, QEvent *ev);
+
+ /*! Changes undoing state of the list. Used by Undo command to
+ prevent recursion. */
+ void setUndoing(bool isUndoing);
+
+ bool isUndoing();
+
+ /*! This function is used to filter the properties to be shown
+ (ie not show "caption" if the widget isn't toplevel).
+ \return true if the property should be shown. False otherwise.*/
+ bool isPropertyVisible(const QCString &property, bool isTopLevel,
+ const QCString &classname=QCString());
+
+ // Following functions are used to create special types of properties, different
+ // from Q_PROPERTY
+
+ /*! Creates the properties related to alignment (ie hAlign, vAlign and WordBreak) for
+ the QWidget \a widget. \a subwidget is the same as \a widget if the widget itself handles
+ the property and it's a child widget if the child handles the property.
+ For example, the second case is true for KexiDBAutoField.
+ \a meta is the QMetaProperty for "alignment" property" of subwidget. */
+ void createAlignProperty(const QMetaProperty *meta, QWidget *widget, QWidget *subwidget);
+
+ /*! Saves the properties related to alignment (ie hAlign, vAlign and WordBreak)
+ and modifies the "alignment" property of the widget.*/
+ void saveAlignProperty(const QString &property);
+
+ /*! Creates the "layout" property, for the Container representing \a item. */
+ void createLayoutProperty(ObjectTreeItem *item);
+
+ /*! Saves the "layout" property and changes the Container 's layout (
+ using Container::setLayout() ).*/
+ void saveLayoutProperty(const QString &property, const QVariant &value);
+
+ // Some i18n functions
+ //! Adds translations for general properties, by adding items in d->propDesc
+ void initPropertiesDescription();
+
+ /*! \return The i18n'ed name of the property whose name is \a name, that will be
+ displayed in PropertyEditor. */
+ QString propertyCaption(const QCString &name);
+
+ /*! \return The i18n'ed name of the property's value whose name is \a name. */
+ QString valueCaption(const QCString &name);
+
+ /*! \return The i18n'ed list of values, that will be shown by Property
+ Editor (using descFromValue()).*/
+ //QStringList captionForList(const QStringList &list);
+
+ //! Helper
+ void emitWidgetPropertyChanged(QWidget *w, const QCString& property, const QVariant& value);
+
+ private:
+ WidgetPropertySetPrivate *d;
+
+ friend class FormManager;
+ friend class PropertyCommand;
+ friend class LayoutPropertyCommand;
+ friend class GeometryPropertyCommand;
+};
+
+}
+
+#endif
diff --git a/kexi/formeditor/widgetwithsubpropertiesinterface.cpp b/kexi/formeditor/widgetwithsubpropertiesinterface.cpp
new file mode 100644
index 00000000..812379e1
--- /dev/null
+++ b/kexi/formeditor/widgetwithsubpropertiesinterface.cpp
@@ -0,0 +1,98 @@
+/* This file is part of the KDE project
+ Copyright (C) 2006 Jaroslaw Staniek <js@iidea.pl>
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this program; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "widgetwithsubpropertiesinterface.h"
+
+#include <qmetaobject.h>
+#include <qasciidict.h>
+
+#include <kdebug.h>
+
+using namespace KFormDesigner;
+
+WidgetWithSubpropertiesInterface::WidgetWithSubpropertiesInterface()
+{
+}
+
+WidgetWithSubpropertiesInterface::~WidgetWithSubpropertiesInterface()
+{
+}
+
+void WidgetWithSubpropertiesInterface::setSubwidget(QWidget *widget)
+{
+ m_subwidget = widget;
+ m_subproperies.clear();
+ QAsciiDict<char> addedSubproperies(1024);
+ if (m_subwidget) {
+ //remember properties in the subwidget that are not present in the parent
+ for( QMetaObject *metaObject = m_subwidget->metaObject(); metaObject; metaObject = metaObject->superClass()) {
+ const int numProperties = metaObject->numProperties();
+ for (int i = 0; i < numProperties; i++) {
+ const char *propertyName = metaObject->property( i )->name();
+ if (dynamic_cast<QObject*>(this)->metaObject()->findProperty( propertyName, true )==-1
+ && !addedSubproperies.find( propertyName ) )
+ {
+ m_subproperies.append( propertyName );
+ addedSubproperies.insert( propertyName, (char*)1 );
+ kdDebug() << propertyName << endl;
+ }
+ }
+ }
+ qHeapSort( m_subproperies );
+ }
+}
+
+QWidget* WidgetWithSubpropertiesInterface::subwidget() const
+{
+ return m_subwidget;
+}
+
+QValueList<QCString> WidgetWithSubpropertiesInterface::subproperies() const
+{
+ return m_subproperies;
+}
+
+const QMetaProperty *WidgetWithSubpropertiesInterface::findMetaSubproperty(const char * name) const
+{
+ if (!m_subwidget || m_subproperies.find(name) == m_subproperies.constEnd()) {
+ return 0;
+ }
+ const int index = m_subwidget->metaObject()->findProperty( name, true );
+ if (index==-1)
+ return 0;
+ return m_subwidget->metaObject()->property( index, true );
+}
+
+QVariant WidgetWithSubpropertiesInterface::subproperty( const char * name, bool &ok ) const
+{
+ if (!m_subwidget || m_subproperies.find(name) == m_subproperies.constEnd()) {
+ ok = false;
+ return QVariant();
+ }
+ ok = true;
+ return m_subwidget->property( name );
+}
+
+bool WidgetWithSubpropertiesInterface::setSubproperty( const char * name, const QVariant & value )
+{
+ if (!m_subwidget || m_subproperies.find(name) == m_subproperies.end()) {
+ return false;
+ }
+ return m_subwidget->setProperty( name, value );
+}
diff --git a/kexi/formeditor/widgetwithsubpropertiesinterface.h b/kexi/formeditor/widgetwithsubpropertiesinterface.h
new file mode 100644
index 00000000..878fefca
--- /dev/null
+++ b/kexi/formeditor/widgetwithsubpropertiesinterface.h
@@ -0,0 +1,72 @@
+/* This file is part of the KDE project
+ Copyright (C) 2006 Jaroslaw Staniek <js@iidea.pl>
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this program; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef WIDGETWITHSUBPROPERTIESINTERFACE_H
+#define WIDGETWITHSUBPROPERTIESINTERFACE_H
+
+#include <qcstring.h>
+#include <qvaluelist.h>
+#include <qwidget.h>
+#include <qguardedptr.h>
+#include <qvariant.h>
+
+namespace KFormDesigner {
+
+//! An interface for declaring form widgets to have subproperties.
+/*! Currently used in KexiDBAutoField to allow editing specific properties
+ of its internal editor. For example, if the autofield is of type Image Box,
+ the Image Box widget has some specific properties like "lineWidth".
+ Such properties are provided by the parent KexiDBAutoField object as subproperties. */
+class KFORMEDITOR_EXPORT WidgetWithSubpropertiesInterface
+{
+ public:
+ WidgetWithSubpropertiesInterface();
+ virtual ~WidgetWithSubpropertiesInterface();
+
+ //! Sets \a widget subwidget handling subproperties. Setting 0 clears subwidget.
+//! @todo maybe someone wants to add more than one widget here?
+ void setSubwidget(QWidget *widget);
+
+ //! \return the assigned subwidget.
+ QWidget* subwidget() const;
+
+ //! \return a list of subproperties available for this widget.
+ //! This is achieved by only listing those properties that are available in the
+ QValueList<QCString> subproperies() const;
+
+ //! \return a meta property for a widget's subproperty or 0 if there
+ //! is no such subproperty.
+ const QMetaProperty *findMetaSubproperty(const char * name) const;
+
+ //! \return a value of widget's subproperty. \a ok is set to true on success
+ //! and to false on failure.
+ QVariant subproperty( const char * name, bool &ok ) const;
+
+ //! Sets a subproperty value \a value for a subproperty \a name
+ //! \return true on successful setting and false when there
+ //! is no such a subproperty in the subwidget or QObject::setProperty() failed.
+ bool setSubproperty( const char * name, const QVariant & value );
+
+ protected:
+ QGuardedPtr<QWidget> m_subwidget;
+ QValueList<QCString> m_subproperies;
+};
+}
+
+#endif