diff options
Diffstat (limited to 'kexi/plugins/macros/kexipart')
-rw-r--r-- | kexi/plugins/macros/kexipart/Makefile.am | 32 | ||||
-rw-r--r-- | kexi/plugins/macros/kexipart/keximacrodesignview.cpp | 497 | ||||
-rw-r--r-- | kexi/plugins/macros/kexipart/keximacrodesignview.h | 129 | ||||
-rw-r--r-- | kexi/plugins/macros/kexipart/keximacroerror.cpp | 130 | ||||
-rw-r--r-- | kexi/plugins/macros/kexipart/keximacroerror.h | 89 | ||||
-rw-r--r-- | kexi/plugins/macros/kexipart/keximacroerrorbase.ui | 213 | ||||
-rw-r--r-- | kexi/plugins/macros/kexipart/keximacrohandler.desktop | 81 | ||||
-rw-r--r-- | kexi/plugins/macros/kexipart/keximacropart.cpp | 172 | ||||
-rw-r--r-- | kexi/plugins/macros/kexipart/keximacropart.h | 95 | ||||
-rw-r--r-- | kexi/plugins/macros/kexipart/keximacroproperty.cpp | 626 | ||||
-rw-r--r-- | kexi/plugins/macros/kexipart/keximacroproperty.h | 186 | ||||
-rw-r--r-- | kexi/plugins/macros/kexipart/keximacrotextview.cpp | 90 | ||||
-rw-r--r-- | kexi/plugins/macros/kexipart/keximacrotextview.h | 77 | ||||
-rw-r--r-- | kexi/plugins/macros/kexipart/keximacroview.cpp | 175 | ||||
-rw-r--r-- | kexi/plugins/macros/kexipart/keximacroview.h | 140 |
15 files changed, 2732 insertions, 0 deletions
diff --git a/kexi/plugins/macros/kexipart/Makefile.am b/kexi/plugins/macros/kexipart/Makefile.am new file mode 100644 index 00000000..51cff0ea --- /dev/null +++ b/kexi/plugins/macros/kexipart/Makefile.am @@ -0,0 +1,32 @@ +include $(top_srcdir)/kexi/Makefile.global + +kde_module_LTLIBRARIES = kexihandler_macro.la + +kexihandler_macro_la_SOURCES = \ + keximacropart.cpp keximacroview.cpp keximacroproperty.cpp keximacrodesignview.cpp keximacrotextview.cpp keximacroerrorbase.ui keximacroerror.cpp + +kexihandler_macro_la_LDFLAGS = \ + $(KDE_PLUGIN) -module -no-undefined -Wnounresolved $(all_libraries) $(VER_INFO) + +kexihandler_macro_la_LIBADD = \ + ../kexiactions/libkeximacroactions.la \ + $(top_builddir)/kexi/core/libkexicore.la \ + $(top_builddir)/kexi/widget/libkexiextendedwidgets.la \ + $(top_builddir)/lib/koproperty/libkoproperty.la + +INCLUDES = \ + -I$(top_srcdir)/lib \ + -I$(top_srcdir)/lib/kofficecore/ \ + -I$(top_srcdir)/kexi/core \ + -I$(top_srcdir)/kexi \ + -I$(top_srcdir)/kexi/widget \ + $(all_includes) + +servicesdir=$(kde_servicesdir)/kexi +services_DATA=keximacrohandler.desktop + +SUBDIRS = . +METASOURCES = AUTO + +noinst_HEADERS = \ + keximacropart.h keximacroview.h keximacrodesignview.h keximacrotextview.h keximacroerror.h diff --git a/kexi/plugins/macros/kexipart/keximacrodesignview.cpp b/kexi/plugins/macros/kexipart/keximacrodesignview.cpp new file mode 100644 index 00000000..030be0cb --- /dev/null +++ b/kexi/plugins/macros/kexipart/keximacrodesignview.cpp @@ -0,0 +1,497 @@ +/* This file is part of the KDE project + Copyright (C) 2006 Sebastian Sauer <[email protected]> + + 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 "keximacrodesignview.h" +#include "keximacroproperty.h" + +#include <qtimer.h> +#include <qdom.h> +#include <kdebug.h> + +#include <kexidialogbase.h> +#include <kexidb/connection.h> +#include <kexidb/error.h> + +#include <core/kexi.h> +#include <core/kexiproject.h> +#include <core/kexipartmanager.h> +#include <core/kexipartinfo.h> + +#include <widget/kexidatatable.h> +#include <widget/tableview/kexitableview.h> +#include <widget/tableview/kexitableviewdata.h> +#include <widget/tableview/kexitableitem.h> +#include <widget/tableview/kexidataawarepropertyset.h> + +#include <koproperty/set.h> +#include <koproperty/property.h> + +#include "../lib/macro.h" +#include "../lib/macroitem.h" +#include "../lib/xmlhandler.h" + +/// constants used to name columns instead of hardcoding indices +#define COLUMN_ID_ACTION 0 +#define COLUMN_ID_COMMENT 1 + +/** +* \internal d-pointer class to be more flexible on future extension of the +* functionality without to much risk to break the binary compatibility. +*/ +class KexiMacroDesignView::Private +{ + public: + + /** + * The view used to display the actions + * a \a Macro has. + */ + KexiDataTable* datatable; + + /** + * For convenience. The table view ( datatable->tableView() ). + */ + KexiTableView* tableview; + + /** + * The \a KexiTableViewData data-model for the + * \a KexiTableView above. + */ + KexiTableViewData* tabledata; + + /** + * The \a KexiDataAwarePropertySet is used to display + * properties an action provides in the propertyview. + */ + KexiDataAwarePropertySet* propertyset; + + /// Boolean flag to avoid infinite recursion. + bool reloadsProperties; + /// Boolean flag to avoid infinite recursion. + bool updatesProperties; + + /** + * Constructor. + * + * \param m The passed \a KoMacro::Manager instance our + * \a manager points to. + */ + Private() + : propertyset(0) + , reloadsProperties(false) + , updatesProperties(false) + { + } + + /** + * Destructor. + */ + ~Private() + { + delete propertyset; + } + +}; + +KexiMacroDesignView::KexiMacroDesignView(KexiMainWindow *mainwin, QWidget *parent, ::KoMacro::Macro* const macro) + : KexiMacroView(mainwin, parent, macro, "KexiMacroDesignView") + , d( new Private() ) +{ + // The table's data-model. + d->tabledata = new KexiTableViewData(); + d->tabledata->setSorting(-1); // disable sorting + + // Add the "Action" column. + KexiTableViewColumn* actioncol = new KexiTableViewColumn( + "action", // name/identifier + KexiDB::Field::Enum, // fieldtype + KexiDB::Field::NoConstraints, // constraints + KexiDB::Field::NoOptions, // options + 0, // length + 0, // precision + QVariant(), // default value + i18n("Action"), // caption + QString::null, // description + 0 // width + ); + d->tabledata->addColumn(actioncol); + + QValueVector<QString> items; + items.append(""); // empty means no action + + // Append the list of actions provided by Kexi. + QStringList actionnames = KoMacro::Manager::self()->actionNames(); + QStringList::ConstIterator it, end( actionnames.constEnd() ); + for( it = actionnames.constBegin(); it != end; ++it) { + KSharedPtr<KoMacro::Action> action = KoMacro::Manager::self()->action(*it); + items.append( action->text() ); + } + + actioncol->field()->setEnumHints(items); + + // Add the "Comment" column. + d->tabledata->addColumn( new KexiTableViewColumn( + "comment", // name/identifier + KexiDB::Field::Text, // fieldtype + KexiDB::Field::NoConstraints, // constraints + KexiDB::Field::NoOptions, // options + 0, // length + 0, // precision + QVariant(), // default value + i18n("Comment"), // caption + QString::null, // description + 0 // width + ) ); + + // Create the tableview. + QHBoxLayout* layout = new QHBoxLayout(this); + d->datatable = new KexiDataTable(mainWin(), this, "Macro KexiDataTable", false /*not db aware*/); + layout->addWidget(d->datatable); + d->tableview = d->datatable->tableView(); + d->tableview->setSpreadSheetMode(); + d->tableview->setColumnStretchEnabled( true, COLUMN_ID_COMMENT ); //last column occupies the rest of the area + + // We need to register our KexiMacroPropertyFactory to use our own + // KoProperty::Property implementation. + KexiMacroPropertyFactory::initFactory(); + + // Create the propertyset. + d->propertyset = new KexiDataAwarePropertySet(this, d->tableview); + + // Connect signals the KexiDataTable provides to local slots. + connect(d->tabledata, SIGNAL(aboutToChangeCell(KexiTableItem*,int,QVariant&,KexiDB::ResultInfo*)), + this, SLOT(beforeCellChanged(KexiTableItem*,int,QVariant&,KexiDB::ResultInfo*))); + connect(d->tabledata, SIGNAL(rowUpdated(KexiTableItem*)), + this, SLOT(rowUpdated(KexiTableItem*))); + connect(d->tabledata, SIGNAL(rowInserted(KexiTableItem*,uint,bool)), + this, SLOT(rowInserted(KexiTableItem*,uint,bool))); + connect(d->tabledata, SIGNAL(rowDeleted()), + this, SLOT(rowDeleted())); + + // Everything is ready. So, update the data now. + updateData(); + setDirty(false); +} + +KexiMacroDesignView::~KexiMacroDesignView() +{ + delete d; +} + +void KexiMacroDesignView::updateData() +{ + kdDebug() << "KexiMacroDesignView::updateData()" << endl; + + // Remove previous content of tabledata. + d->tabledata->deleteAllRows(); + // Remove old property sets. + d->propertyset->clear(); + + // Add some empty rows + for (int i=0; i<50; i++) { + d->tabledata->append( d->tabledata->createItem() ); + } + + // Set the MacroItem's + QStringList actionnames = KoMacro::Manager::self()->actionNames(); + KoMacro::MacroItem::List macroitems = macro()->items(); + KoMacro::MacroItem::List::ConstIterator it(macroitems.constBegin()), end(macroitems.constEnd()); + for(uint idx = 0; it != end; ++it, idx++) { + KexiTableItem* tableitem = d->tabledata->at(idx); + if(! tableitem) { + // If there exists no such item, add it. + tableitem = d->tabledata->createItem(); + d->tabledata->append(tableitem); + } + // Set the action-column. + KSharedPtr<KoMacro::Action> action = (*it)->action(); + if(action.data()) { + int i = actionnames.findIndex( action->name() ); + if(i >= 0) { + tableitem->at(COLUMN_ID_ACTION) = i + 1; + //setAction(tableitem, action->name()); + } + } + // Set the comment-column. + tableitem->at(COLUMN_ID_COMMENT) = (*it)->comment(); + } + + // set data for our spreadsheet: this will clear our sets + d->tableview->setData(d->tabledata); + + // Add the property sets. + it = macroitems.constBegin(); + for(uint idx = 0; it != end; ++it, idx++) { + updateProperties(idx, 0, *it); + } + + // work around a bug in the KexiTableView where we lose the stretch-setting... + d->tableview->setColumnStretchEnabled( true, COLUMN_ID_COMMENT ); //last column occupies the rest of the area + + propertySetReloaded(true); +} + +bool KexiMacroDesignView::loadData() +{ + if(! KexiMacroView::loadData()) { + return false; + } + updateData(); // update the tableview's data. + return true; +} + +KoProperty::Set* KexiMacroDesignView::propertySet() +{ + return d->propertyset->currentPropertySet(); +} + +void KexiMacroDesignView::beforeCellChanged(KexiTableItem* item, int colnum, QVariant& newvalue, KexiDB::ResultInfo* result) +{ + Q_UNUSED(result); + kdDebug() << "KexiMacroDesignView::beforeCellChanged() colnum=" << colnum << " newvalue=" << newvalue.toString() << endl; + + int rowindex = d->tabledata->findRef(item); + if(rowindex < 0) { + kdWarning() << "KexiMacroDesignView::beforeCellChanged() No such item" << endl; + return; + } + + // If the rowindex doesn't exists yet, we need to append new + // items till we are able to access the item we like to use. + for(int i = macro()->items().count(); i <= rowindex; i++) { + macro()->addItem( KSharedPtr<KoMacro::MacroItem>( new KoMacro::MacroItem() ) ); + } + + // Get the matching MacroItem. + KSharedPtr<KoMacro::MacroItem> macroitem = macro()->items()[rowindex]; + if(! macroitem.data()) { + kdWarning() << "KexiMacroDesignView::beforeCellChanged() Invalid item for rowindex=" << rowindex << endl; + return; + } + + // Handle the column that should be changed + switch(colnum) { + case COLUMN_ID_ACTION: { // The "Action" column + QString actionname; + bool ok; + int selectedindex = newvalue.toInt(&ok); + if(ok && selectedindex > 0) { + QStringList actionnames = KoMacro::Manager::self()->actionNames(); + actionname = actionnames[ selectedindex - 1 ]; // first item is empty + } + KSharedPtr<KoMacro::Action> action = KoMacro::Manager::self()->action(actionname); + macroitem->setAction(action); + updateProperties(d->propertyset->currentRow(), d->propertyset->currentPropertySet(), macroitem); + propertySetReloaded(true); + } break; + case COLUMN_ID_COMMENT: { // The "Comment" column + macroitem->setComment( newvalue.toString() ); + } break; + default: + kdWarning() << "KexiMacroDesignView::beforeCellChanged() No such column number " << colnum << endl; + return; + } + + setDirty(); +} + +void KexiMacroDesignView::rowUpdated(KexiTableItem* item) +{ + int rowindex = d->tabledata->findRef(item); + kdDebug() << "KexiMacroDesignView::rowUpdated() rowindex=" << rowindex << endl; + //propertySetSwitched(); + //propertySetReloaded(true); + //setDirty(); +} + +void KexiMacroDesignView::rowInserted(KexiTableItem*, uint row, bool) +{ + kdDebug() << "KexiMacroDesignView::rowInserted() rowindex=" << row << endl; + KoMacro::MacroItem::List& macroitems = macro()->items(); + + if(row < macroitems.count()) { + // If a new item was inserted, we need to insert a new item to our + // list of MacroItems too. If the new item was appended, we don't + // need to do anything yet cause the new item will be handled on + // beforeCellChanged() anyway. + kdDebug() << "KexiMacroDesignView::rowInserted() Inserting new MacroItem" << endl; + KSharedPtr<KoMacro::MacroItem> macroitem = KSharedPtr<KoMacro::MacroItem>( new KoMacro::MacroItem() ); + KoMacro::MacroItem::List::Iterator it = macroitems.at(row); + macroitems.insert(it, macroitem); + } +} + +void KexiMacroDesignView::rowDeleted() +{ + int rowindex = d->propertyset->currentRow(); + if(rowindex < 0) { + kdWarning() << "KexiMacroDesignView::rowDeleted() No such item" << endl; + return; + } + kdDebug() << "KexiMacroDesignView::rowDeleted() rowindex=" << rowindex << endl; + KoMacro::MacroItem::List& macroitems = macro()->items(); + macroitems.remove( macroitems.at(rowindex) ); +} + +bool KexiMacroDesignView::updateSet(KoProperty::Set* set, KSharedPtr<KoMacro::MacroItem> macroitem, const QString& variablename) +{ + kdDebug() << "KexiMacroDesignView::updateSet() variablename=" << variablename << endl; + KoProperty::Property* property = KexiMacroProperty::createProperty(macroitem, variablename); + if(! property) + return false; + set->addProperty(property); + return true; +} + +void KexiMacroDesignView::updateProperties(int row, KoProperty::Set* set, KSharedPtr<KoMacro::MacroItem> macroitem) +{ + kdDebug() << "KexiMacroDesignView::updateProperties() row=" << row << endl; + + if(row < 0 || d->updatesProperties) { + return; // ignore invalid rows and avoid infinite recursion. + } + + KSharedPtr<KoMacro::Action> action = macroitem->action(); + if(! action.data()) { + // don't display a propertyset if there is no action defined. + d->propertyset->remove(row); + return; // job done. + } + + d->updatesProperties = true; + + if(set) { + // we need to clear old data before adding the new content. + set->clear(); + } + else { + // if there exists no such propertyset yet, create one. + set = new KoProperty::Set(d->propertyset, action->name()); + d->propertyset->insert(row, set, true); + connect(set, SIGNAL(propertyChanged(KoProperty::Set&, KoProperty::Property&)), + this, SLOT(propertyChanged(KoProperty::Set&, KoProperty::Property&))); + } + + // The caption. + KoProperty::Property* prop = new KoProperty::Property("this:classString", action->text()); + prop->setVisible(false); + set->addProperty(prop); + + // Display the list of variables. + QStringList varnames = action->variableNames(); + for(QStringList::Iterator it = varnames.begin(); it != varnames.end(); ++it) { + if(updateSet(set, macroitem, *it)) { + KSharedPtr<KoMacro::Variable> variable = macroitem->variable(*it, true); + kdDebug()<<"KexiMacroDesignView::updateProperties() name=" << *it << " variable=" << variable->variant().toString() << endl; +#if 0 + macroitem->setVariable(*it, variable); +#endif + } + } + + d->updatesProperties = false; +} + +void KexiMacroDesignView::propertyChanged(KoProperty::Set& set, KoProperty::Property& property) +{ + Q_UNUSED(set); + kdDebug() << "!!!!! KexiMacroDesignView::propertyChanged() propertyname=" << property.name() << endl; + setDirty(); + + /* + if(d->reloadsProperties) // be sure to don't update properties if we are still on reloading. + return; + d->reloadsProperties = true; + + const int row = d->propertyset->currentRow(); + const QCString name = property.name(); + kdDebug() << "KexiMacroDesignView::propertyChanged() name=" << name << " row=" << row << endl; + + //TODO reload is only needed if something changed! + bool dirty = true; bool reload = true;//dirtyvarnames.count()>0; + + if(dirty || reload) { // Only reload properties if it's really needed. + setDirty(); + if(reload) { + // The MacroItem which should be changed. + KSharedPtr<KoMacro::MacroItem> macroitem = macro()->items()[row]; + // Update the properties. + updateProperties(row, &set, macroitem); + } + // It's needed to call the reload delayed cause in KoProperty::Editor + // QTimer::singleShot(10, this, SLOT(selectItemLater())); may lead + // to crashes if we are to fast. + QTimer::singleShot(50, this, SLOT(reloadPropertyLater())); + } + + d->reloadsProperties = false; + */ + + /* + QStringList dirtyvarnames = macroitem->setVariable(name, KSharedPtr<KoMacro::Variable>(pv)); + bool dirty = false; + bool reload = false; + for(QStringList::Iterator it = dirtyvarnames.begin(); it != dirtyvarnames.end(); ++it) { + KSharedPtr<KoMacro::Variable> variable = macroitem->variable(*it); + if(! variable.data()) { + kdDebug() << "KexiMacroDesignView::propertyChanged() name=" << name << " it=" << *it << " skipped cause such a variable is not known." << endl; + continue; + } + + if(! set.contains( (*it).latin1() )) { + // If there exist no such property yet, we need to add it. + if(updateSet(&set, macroitem, *it)) + reload = true; // we like to reload the whole set + continue; + } + + kdDebug() << "KexiMacroDesignView::propertyChanged() set existing property=" << *it << endl; + KoProperty::Property& p = set.property((*it).latin1()); + KoMacro::Variable::List children = variable->children(); + if(children.count() > 0) { + QStringList keys, names; + KoMacro::Variable::List::Iterator childit(children.begin()), childend(children.end()); + for(; childit != childend; ++childit) { + const QString s = (*childit)->variant().toString(); + keys << s; + names << s; + } + p.setListData( new KoProperty::Property::ListData(keys, names) ); + } + p.setValue(variable->variant()); + dirty = true; + } + + // If there are expired aka not any longer needed properties around, we + // need to reload the whole set. + for(KoProperty::Set::Iterator setit = set; setit.current(); ++setit) { + if(setit.currentKey() == name) continue; // don't remove ourself + if(setit.currentKey().left(5) == QCString("this:")) continue; // don't remove internal properties + if(setit.currentKey() == QCString("newrow")) continue; // also an internal used property + if(action.data() && action->hasVariable(setit.currentKey())) continue; // the property is still valid + reload = true; // we like to reload the whole set + } + */ +} + +void KexiMacroDesignView::reloadPropertyLater() +{ + propertySetReloaded(true); +} + +#include "keximacrodesignview.moc" + diff --git a/kexi/plugins/macros/kexipart/keximacrodesignview.h b/kexi/plugins/macros/kexipart/keximacrodesignview.h new file mode 100644 index 00000000..c3eca2d2 --- /dev/null +++ b/kexi/plugins/macros/kexipart/keximacrodesignview.h @@ -0,0 +1,129 @@ +/* This file is part of the KDE project + Copyright (C) 2006 Sebastian Sauer <[email protected]> + + 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 KEXIMACRODESIGNVIEW_H +#define KEXIMACRODESIGNVIEW_H + +#include "keximacroview.h" + +// Forward declarations. +namespace KoMacro { + class Action; + class Macro; + class MacroItem; +} +namespace KoProperty { + class Property; +} +namespace KexiDB { + class ResultInfo; +} +class KexiTableItem; + +/** + * The KexiScriptDesignView implements \a KexiMacroView to provide + * a GUI-Editor to edit a Macro. + */ +class KexiMacroDesignView : public KexiMacroView +{ + Q_OBJECT + public: + + /** + * Constructor. + * + * \param mainwin The \a KexiMainWindow instance this \a KexiViewBase + * belongs to. + * \param parent The parent widget this widget should be displayed in. + * \param macro The \a KoMacro::Macro instance this view is for. + */ + KexiMacroDesignView(KexiMainWindow *mainwin, QWidget *parent, ::KoMacro::Macro* const macro); + + /** + * Destructor. + */ + virtual ~KexiMacroDesignView(); + + /** + * Load the data from XML source and fill the internally + * used \a KoMacro::Macro instance. + */ + virtual bool loadData(); + + /** + * \return the \a KoProperty::Set properties this view provides. + */ + virtual KoProperty::Set* propertySet(); + + private slots: + + /** + * Called before a cell changed in the internaly used + * \a KexiTableView . + */ + void beforeCellChanged(KexiTableItem*, int, QVariant&, KexiDB::ResultInfo*); + + /** + * Called if the passed \p item got updated. + */ + void rowUpdated(KexiTableItem* item); + + /** + * Called if a row got deleted. + */ + void rowDeleted(); + + /** + * Called if a row got inserted. + */ + void rowInserted(KexiTableItem* item, uint row, bool repaint); + + /** + * Called if a property in the \a KoProperty got changed. + */ + void propertyChanged(KoProperty::Set&, KoProperty::Property&); + + /** + * Reloads the propertyset delayed. + */ + void reloadPropertyLater(); + + private: + /// \internal d-pointer class. + class Private; + /// \internal d-pointer instance. + Private* const d; + + /** + * Update the table's data. + */ + void updateData(); + + /** + * Update the \a KoProperty::Set set with the passed \a KoMacro::MacroItem + * \p item and the variablename \p variablename . + */ + bool updateSet(KoProperty::Set* set, KSharedPtr<KoMacro::MacroItem> item, const QString& variablename); + + /** + * Update the properties of the \a KoProperty::Set \p set at + * row-number \p row with the \a KoMacro::MacroItem \p macroitem . + */ + void updateProperties(int row, KoProperty::Set* set, KSharedPtr<KoMacro::MacroItem> macroitem); +}; + +#endif diff --git a/kexi/plugins/macros/kexipart/keximacroerror.cpp b/kexi/plugins/macros/kexipart/keximacroerror.cpp new file mode 100644 index 00000000..15f4df3f --- /dev/null +++ b/kexi/plugins/macros/kexipart/keximacroerror.cpp @@ -0,0 +1,130 @@ +/*************************************************************************** + * This file is part of the KDE project + * copyright (C) 2006 by Tobi Krebs ([email protected]) + * copyright (C) 2006 by Bernd Steindorff ([email protected]) + * copyright (C) 2006 by Sascha Kupper ([email protected]) + * copyright (C) 2006 by Sebastian Sauer ([email protected]) + * + * 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 "keximacroerror.h" + +#include <core/kexiproject.h> +#include <core/keximainwindow.h> + +#include <qtimer.h> + +/** +* \internal d-pointer class to be more flexible on future extension of the +* functionality without to much risk to break the binary compatibility. +*/ +class KexiMacroError::Private +{ + public: + KexiMainWindow* const mainwin; + KSharedPtr<KoMacro::Context> context; + + Private(KexiMainWindow* const m, KoMacro::Context* const c) + : mainwin(m) + , context(c) + { + } +}; + +KexiMacroError::KexiMacroError(KexiMainWindow* mainwin, KSharedPtr<KoMacro::Context> context) + : KexiMacroErrorBase(mainwin, "KexiMacroError" , /*WFlags*/ Qt::WDestructiveClose) + , d(new Private(mainwin, context)) +{ + //setText(i18n("Execution failed")); //caption + //errortext, errorlist, continuebtn,cancelbtn, designerbtn + + KoMacro::Exception* exception = context->exception(); + + iconlbl->setPixmap(KGlobal::instance()->iconLoader()->loadIcon("messagebox_critical", KIcon::Small, 32)); + errorlbl->setText(i18n("<qt>Failed to execute the macro \"%1\".<br>%2</qt>").arg( context->macro()->name() ).arg( exception->errorMessage() )); + + int i = 1; + KoMacro::MacroItem::List items = context->macro()->items(); + for (KoMacro::MacroItem::List::ConstIterator mit = items.begin(); mit != items.end(); mit++) + { + KListViewItem* listviewitem = new KListViewItem(errorlist); + listviewitem->setText(0,QString("%1").arg(i++)); + listviewitem->setText(1,i18n("Action")); + KSharedPtr<KoMacro::MacroItem> macroitem = *mit; + + if (macroitem != 0 && macroitem->action() != 0) + { + listviewitem->setText(2,macroitem->action()->name()); + } + + if(macroitem == context->macroItem()) + { + listviewitem->setOpen(true); + listviewitem->setSelected(true); + errorlist->setSelected(listviewitem, true); + errorlist->ensureItemVisible(listviewitem); + } + + KoMacro::Variable::Map variables = macroitem->variables(); + KoMacro::Variable::Map::ConstIterator vit; + for ( vit = variables.begin(); vit != variables.end(); ++vit ) { + KListViewItem* child = new KListViewItem(listviewitem); + child->setText(1,vit.key()); + child->setText(2,vit.data()->toString()); + } + } + + connect(designerbtn, SIGNAL(clicked()), this, SLOT(designbtnClicked())); + connect(continuebtn, SIGNAL(clicked()), this, SLOT(continuebtnClicked())); +} + +KexiMacroError::~KexiMacroError() +{ + delete d; +} + +void KexiMacroError::designbtnClicked() +{ + if(! d->mainwin->project()) { + kdWarning() << QString("KexiMacroError::designbtnClicked(): No project open.") << endl; + return; + } + + // We need to determinate the KexiPart::Item which should be opened. + KSharedPtr<KoMacro::Macro> macro = d->context->macro(); + const QString name = macro->name(); + KexiPart::Item* item = d->mainwin->project()->itemForMimeType("kexi/macro", name); + if(! item) { + kdWarning() << QString("KexiMacroError::designbtnClicked(): No such macro \"%1\"").arg(name) << endl; + return; + } + + // Try to open the KexiPart::Item now. + bool openingCancelled; + if(! d->mainwin->openObject(item, Kexi::DesignViewMode, openingCancelled)) { + if(! openingCancelled) { + kdWarning() << QString("KexiMacroError::designbtnClicked(): Open macro \"%1\" in designview failed.").arg(name) << endl; + return; + } + } + + close(); +} + +void KexiMacroError::continuebtnClicked() +{ + QTimer::singleShot(200, d->context, SLOT(activateNext())); + close(); +} diff --git a/kexi/plugins/macros/kexipart/keximacroerror.h b/kexi/plugins/macros/kexipart/keximacroerror.h new file mode 100644 index 00000000..641859b7 --- /dev/null +++ b/kexi/plugins/macros/kexipart/keximacroerror.h @@ -0,0 +1,89 @@ +/*************************************************************************** + * This file is part of the KDE project + * copyright (C) 2006 by Tobi Krebs ([email protected]) + * copyright (C) 2006 by Bernd Steindorff ([email protected]) + * copyright (C) 2006 by Sascha Kupper ([email protected]) + * copyright (C) 2006 by Sebastian Sauer ([email protected]) + * + * 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 KEXIMACROERROR_H +#define KEXIMACROERROR_H + +#include <qwidget.h> +#include <qlabel.h> +#include <qpushbutton.h> + +#include <klistview.h> +#include <klocale.h> +#include <kiconloader.h> +#include <kglobal.h> +#include <kdebug.h> + +#include "../lib/context.h" +#include "../lib/exception.h" +#include "../lib/macro.h" +#include "../lib/macroitem.h" + +#include "keximacroerrorbase.h" + +// Forward-declarations. +class KexiMainWindow; + +/** +* An error dialog used to displayed more detailed informations about +* a @a KoMacro::Exception that got thrown within a @a KoMacro::Context +* during execution. +*/ +class KexiMacroError : public KexiMacroErrorBase +{ + Q_OBJECT + + public: + + /** + * Constructor. + * + * @param mainwin The parent @a KexiMainWindow instance. + * @param context The @a KoMacro::Context where the error happened. + */ + KexiMacroError(KexiMainWindow* mainwin, KSharedPtr<KoMacro::Context> context); + + /** + * Destructor. + */ + virtual ~KexiMacroError(); + + private slots: + + /** + * Called if the "Open Macrodesigner"-Button is clicked. + */ + void designbtnClicked(); + + /** + * Called if the "continue"-Button is clicked. + */ + void continuebtnClicked(); + + private: + /// \internal d-pointer class. + class Private; + /// \internal d-pointer instance. + Private* const d; + +}; + +#endif diff --git a/kexi/plugins/macros/kexipart/keximacroerrorbase.ui b/kexi/plugins/macros/kexipart/keximacroerrorbase.ui new file mode 100644 index 00000000..74e47cfc --- /dev/null +++ b/kexi/plugins/macros/kexipart/keximacroerrorbase.ui @@ -0,0 +1,213 @@ +<!DOCTYPE UI><UI version="3.3" stdsetdef="1"> +<class>KexiMacroErrorBase</class> +<widget class="QDialog"> + <property name="name"> + <cstring>KexiMacroErrorBase</cstring> + </property> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>492</width> + <height>424</height> + </rect> + </property> + <property name="caption"> + <string>Error</string> + </property> + <property name="sizeGripEnabled"> + <bool>true</bool> + </property> + <property name="modal"> + <bool>true</bool> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>layout4</cstring> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>layout8</cstring> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLabel"> + <property name="name"> + <cstring>iconlbl</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>0</hsizetype> + <vsizetype>0</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="minimumSize"> + <size> + <width>48</width> + <height>48</height> + </size> + </property> + <property name="frameShape"> + <enum>NoFrame</enum> + </property> + <property name="text"> + <string></string> + </property> + <property name="alignment"> + <set>AlignVCenter|AlignLeft</set> + </property> + </widget> + <widget class="QLabel"> + <property name="name"> + <cstring>errorlbl</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>5</hsizetype> + <vsizetype>1</vsizetype> + <horstretch>1</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="frameShape"> + <enum>NoFrame</enum> + </property> + <property name="text"> + <string></string> + </property> + <property name="alignment"> + <set>WordBreak|AlignVCenter</set> + </property> + </widget> + </hbox> + </widget> + <widget class="KListView"> + <column> + <property name="text"> + <string>No</string> + </property> + <property name="clickable"> + <bool>false</bool> + </property> + <property name="resizable"> + <bool>true</bool> + </property> + </column> + <column> + <property name="text"> + <string>Name</string> + </property> + <property name="clickable"> + <bool>false</bool> + </property> + <property name="resizable"> + <bool>true</bool> + </property> + </column> + <column> + <property name="text"> + <string>Value</string> + </property> + <property name="clickable"> + <bool>false</bool> + </property> + <property name="resizable"> + <bool>true</bool> + </property> + </column> + <property name="name"> + <cstring>errorlist</cstring> + </property> + <property name="allColumnsShowFocus"> + <bool>true</bool> + </property> + <property name="rootIsDecorated"> + <bool>true</bool> + </property> + <property name="resizeMode"> + <enum>LastColumn</enum> + </property> + <property name="fullWidth"> + <bool>true</bool> + </property> + <property name="itemsMovable"> + <bool>false</bool> + </property> + <property name="autoOpen"> + <bool>false</bool> + </property> + <property name="tooltipColumn"> + <number>1</number> + </property> + </widget> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>layout1</cstring> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QPushButton"> + <property name="name"> + <cstring>designerbtn</cstring> + </property> + <property name="text"> + <string>Open in design view</string> + </property> + <property name="accel"> + <string></string> + </property> + <property name="autoDefault"> + <bool>true</bool> + </property> + </widget> + <widget class="QPushButton"> + <property name="name"> + <cstring>continuebtn</cstring> + </property> + <property name="text"> + <string>Continue</string> + </property> + </widget> + <widget class="QPushButton"> + <property name="name"> + <cstring>cancelbtn</cstring> + </property> + <property name="text"> + <string>Abort</string> + </property> + </widget> + </hbox> + </widget> + </vbox> + </widget> + </vbox> +</widget> +<customwidgets> +</customwidgets> +<connections> + <connection> + <sender>cancelbtn</sender> + <signal>clicked()</signal> + <receiver>KexiMacroErrorBase</receiver> + <slot>close()</slot> + </connection> +</connections> +<layoutdefaults spacing="6" margin="11"/> +<includehints> + <includehint>klistview.h</includehint> +</includehints> +</UI> diff --git a/kexi/plugins/macros/kexipart/keximacrohandler.desktop b/kexi/plugins/macros/kexipart/keximacrohandler.desktop new file mode 100644 index 00000000..c08a7b2a --- /dev/null +++ b/kexi/plugins/macros/kexipart/keximacrohandler.desktop @@ -0,0 +1,81 @@ +[Desktop Entry] +Type=Service +ServiceTypes=Kexi/Handler + +GenericName=Macros +GenericName[bg]=Макроси +GenericName[br]=Makroù +GenericName[da]=Makroer +GenericName[de]=Makros +GenericName[el]=Μακροεντολές +GenericName[eo]=Makrooj +GenericName[et]=Makrod +GenericName[fa]=کلاندستورها +GenericName[fy]=Macro's +GenericName[ga]=Macraí +GenericName[hr]=Makroi +GenericName[hu]=Makrók +GenericName[it]=Macro +GenericName[ja]=マクロ +GenericName[km]=ម៉ាក្រូ +GenericName[lv]=Makross +GenericName[nb]=Makroer +GenericName[nds]=Makros +GenericName[ne]=म्याक्रोस +GenericName[nl]=Macro's +GenericName[pl]=Makra +GenericName[ru]=Макросы +GenericName[se]=Makroat +GenericName[sk]=Makrá +GenericName[sl]=Makri +GenericName[sr]=Макрои +GenericName[sr@Latn]=Makroi +GenericName[sv]=Makron +GenericName[uk]=Макроси +GenericName[uz]=Makros +GenericName[uz@cyrillic]=Макрос +GenericName[zh_TW]=巨集 + +Name=Macros +Name[bg]=Макроси +Name[br]=Makroù +Name[da]=Makroer +Name[de]=Makros +Name[el]=Μακροεντολές +Name[eo]=Makrooj +Name[et]=Makrod +Name[fa]=کلاندستورها +Name[fy]=Macro's +Name[ga]=Macraí +Name[hr]=Makroi +Name[hu]=Makrók +Name[it]=Macro +Name[ja]=マクロ +Name[km]=ម៉ាក្រូ +Name[lv]=Makross +Name[nb]=Makroer +Name[nds]=Makros +Name[ne]=म्याक्रोस +Name[nl]=Macro's +Name[pl]=Makra +Name[ru]=Макросы +Name[se]=Makroat +Name[sk]=Makrá +Name[sl]=Makri +Name[sr]=Макрои +Name[sr@Latn]=Makroi +Name[sv]=Makron +Name[uk]=Макроси +Name[uz]=Makros +Name[uz@cyrillic]=Макрос +Name[zh_TW]=巨集 + +X-KDE-Library=kexihandler_macro +X-KDE-ParentApp=kexi +X-Kexi-PartVersion=2 +X-Kexi-TypeName=macro +X-Kexi-TypeMime=kexi/macro +X-Kexi-ItemIcon=macro +X-Kexi-SupportsDataExport=false +X-Kexi-SupportsPrinting=false +X-Kexi-SupportsExecution=true diff --git a/kexi/plugins/macros/kexipart/keximacropart.cpp b/kexi/plugins/macros/kexipart/keximacropart.cpp new file mode 100644 index 00000000..c4f020e4 --- /dev/null +++ b/kexi/plugins/macros/kexipart/keximacropart.cpp @@ -0,0 +1,172 @@ +/* This file is part of the KDE project + Copyright (C) 2006 Sebastian Sauer <[email protected]> + + 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 "keximacropart.h" + +#include "keximacroview.h" +#include "keximacrodesignview.h" +#include "keximacrotextview.h" + +//#include "kexiviewbase.h" +//#include "keximainwindow.h" +//#include "kexiproject.h" + +#include <qdom.h> +#include <qstringlist.h> +#include <kgenericfactory.h> +#include <kexipartitem.h> +//#include <kxmlguiclient.h> +//#include <kexidialogbase.h> +//#include <kconfig.h> +//#include <kdebug.h> + +#include "../lib/manager.h" +#include "../lib/macro.h" +#include "../lib/macroitem.h" +#include "../lib/action.h" + +#include "../kexiactions/openaction.h" +#include "../kexiactions/executeaction.h" +#include "../kexiactions/navigateaction.h" +#include "../kexiactions/messageaction.h" +#include "../kexiactions/datatableaction.h" + +/** +* \internal d-pointer class to be more flexible on future extension of the +* functionality without to much risk to break the binary compatibility. +*/ +class KexiMacroPart::Private +{ + public: +}; + +KexiMacroPart::KexiMacroPart(QObject *parent, const char *name, const QStringList &l) + : KexiPart::Part(parent, name, l) + , d( new Private() ) +{ + //kdDebug() << "KexiMacroPart::KexiMacroPart() Ctor" << endl; + + //registered ID + m_registeredPartID = (int)KexiPart::MacroObjectType; + + //name of the instance. + m_names["instanceName"] + = i18n("Translate this word using only lowercase alphanumeric characters (a..z, 0..9). " + "Use '_' character instead of spaces. First character should be a..z character. " + "If you cannot use latin characters in your language, use english word.", + "macro"); + + //describing caption + m_names["instanceCaption"] = i18n("Macro"); + + //supported viewmodes + m_supportedViewModes = Kexi::DesignViewMode | Kexi::TextViewMode; +} + +KexiMacroPart::~KexiMacroPart() +{ + //kdDebug() << "KexiMacroPart::~KexiMacroPart() Dtor" << endl; + delete d; +} + +bool KexiMacroPart::execute(KexiPart::Item* item, QObject* sender) +{ + KexiDialogBase* dialog = new KexiDialogBase(m_mainWin); + dialog->setId( item->identifier() ); + KexiMacroView* view = dynamic_cast<KexiMacroView*>( createView(dialog, dialog, *item, Kexi::DataViewMode) ); + if(! view) { + kdWarning() << "KexiMacroPart::execute() Failed to create a view." << endl; + return false; + } + + if(! view->macro().data()) { + kdWarning() << "KexiMacroPart::execute() No such item " << item->name() << endl; + return false; + } + + kdDebug() << "KexiMacroPart::execute() itemname=" << item->name() << endl; + view->loadData(); + view->execute(sender); + view->deleteLater(); + return true; +} + +void KexiMacroPart::initPartActions() +{ + //kdDebug() << "KexiMacroPart::initPartActions()" << endl; + + KoMacro::Manager::init(m_mainWin); + new KexiMacro::OpenAction; + new KexiMacro::ExecuteAction; + new KexiMacro::DataTableAction; + new KexiMacro::NavigateAction; + new KexiMacro::MessageAction; +} + +void KexiMacroPart::initInstanceActions() +{ + //kdDebug() << "KexiMacroPart::initInstanceActions()" << endl; + //createSharedAction(Kexi::DesignViewMode, i18n("Execute Macro"), "exec", 0, "data_execute"); +} + +KexiViewBase* KexiMacroPart::createView(QWidget* parent, KexiDialogBase* dialog, KexiPart::Item& item, int viewMode, QMap<QString,QString>*) +{ + const QString itemname = item.name(); + //kdDebug() << "KexiMacroPart::createView() itemname=" << itemname << endl; + + if(! itemname.isNull()) { + KSharedPtr<KoMacro::Macro> macro = ::KoMacro::Manager::self()->getMacro(itemname); + if(! macro) { + // If we don't have a macro with that name yet, create one. + macro = ::KoMacro::Manager::self()->createMacro(itemname); + // and remember the new macro for later usage. + ::KoMacro::Manager::self()->addMacro(itemname, macro); + } + + KexiMainWindow *win = dialog->mainWin(); + if(win && win->project() && win->project()->dbConnection()) { + if(viewMode == Kexi::DesignViewMode) { + return new KexiMacroDesignView(win, parent, macro); + } + if(viewMode == Kexi::TextViewMode) { + return new KexiMacroTextView(win, parent, macro); + } + if(viewMode == Kexi::DataViewMode) { + // Called if the macro should be executed. + return new KexiMacroView(win, parent, macro); + } + } + } + + //kdDebug() << "KexiMacroPart::createView() No view available." << endl; + return 0; +} + +QString KexiMacroPart::i18nMessage(const QCString& englishMessage) const +{ + if(englishMessage=="Design of object \"%1\" has been modified.") { + return i18n("Design of macro \"%1\" has been modified."); + } + if(englishMessage=="Object \"%1\" already exists.") { + return i18n("Macro \"%1\" already exists."); + } + return englishMessage; +} + +K_EXPORT_COMPONENT_FACTORY( kexihandler_macro, KGenericFactory<KexiMacroPart>("kexihandler_macro") ) + +#include "keximacropart.moc" diff --git a/kexi/plugins/macros/kexipart/keximacropart.h b/kexi/plugins/macros/kexipart/keximacropart.h new file mode 100644 index 00000000..8d2d7af2 --- /dev/null +++ b/kexi/plugins/macros/kexipart/keximacropart.h @@ -0,0 +1,95 @@ +/* This file is part of the KDE project + Copyright (C) 2006 Sebastian Sauer <[email protected]> + + 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 KEXIMACROPART_H +#define KEXIMACROPART_H + +//#include <qcstring.h> + +#include <kexi.h> +#include <kexipart.h> +#include <kexidialogbase.h> + +/** + * Kexi Macro Plugin. + */ +class KexiMacroPart : public KexiPart::Part +{ + Q_OBJECT + + public: + + /** + * Constructor. + * + * \param parent The parent QObject this part is child of. + * \param name The name this part has. + * \param args Optional list of arguments passed to this part. + */ + KexiMacroPart(QObject *parent, const char *name, const QStringList& args); + + /** + * Destructor. + */ + virtual ~KexiMacroPart(); + + /** + * Implementation of the KexiPart::Part::action method used to + * provide scripts as KAction's to the outside world. + */ + virtual bool execute(KexiPart::Item* item, QObject* sender = 0); + + /** + * \return the i18n message for the passed \p englishMessage string. + */ + virtual QString i18nMessage(const QCString& englishMessage) const; + + protected: + + /** + * Create a new view. + * + * \param parent The parent QWidget the new view is displayed in. + * \param dialog The \a KexiDialogBase the view is child of. + * \param item The \a KexiPart::Item this view is for. + * \param viewMode The viewmode we like to have a view for. + */ + virtual KexiViewBase* createView(QWidget *parent, + KexiDialogBase* dialog, + KexiPart::Item& item, + int viewMode = Kexi::DesignViewMode, + QMap<QString,QString>* staticObjectArgs = 0); + + /** + * Initialize the part's actions. + */ + virtual void initPartActions(); + + /** + * Initialize the instance actions. + */ + virtual void initInstanceActions(); + + private: + /// \internal d-pointer class. + class Private; + /// \internal d-pointer instance. + Private* const d; +}; + +#endif + diff --git a/kexi/plugins/macros/kexipart/keximacroproperty.cpp b/kexi/plugins/macros/kexipart/keximacroproperty.cpp new file mode 100644 index 00000000..2fdafd28 --- /dev/null +++ b/kexi/plugins/macros/kexipart/keximacroproperty.cpp @@ -0,0 +1,626 @@ +/* This file is part of the KDE project + Copyright (C) 2006 Sebastian Sauer <[email protected]> + + 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 "keximacroproperty.h" + +#include <qlayout.h> +#include <qlineedit.h> +#include <qlistbox.h> +#include <qpainter.h> + +#include <kcombobox.h> +#include <kpushbutton.h> +#include <klocale.h> +#include <kiconloader.h> +#include <kdebug.h> + +#include "../lib/variable.h" +#include "../lib/macroitem.h" + +#define KEXIMACRO_PROPERTYEDITORTYPE 5682 + +/************************************************************* + * KexiMacroProperty + */ + +/** +* @internal d-pointer class to be more flexible on future extension of the +* functionality without to much risk to break the binary compatibility. +*/ +class KexiMacroProperty::Private +{ + public: + /** The @a KoMacro::MacroItem the custom property uses + internal. Together with the name we are able to identify + the used variable at runtime. */ + KSharedPtr<KoMacro::MacroItem> macroitem; + /** The name the variable @a KoMacro::Variable is known + as in the @a KoMacro::MacroItem defined above. */ + QString name; +}; + +KexiMacroProperty::KexiMacroProperty(KoProperty::Property* parent, KSharedPtr<KoMacro::MacroItem> macroitem, const QString& name) + : KoProperty::CustomProperty(parent) + , d( new Private() ) +{ + d->macroitem = macroitem; + d->name = name; + init(); +} + +KexiMacroProperty::~KexiMacroProperty() +{ + delete d; +} + +void KexiMacroProperty::init() +{ + Q_ASSERT( d->macroitem != 0 ); + //kdDebug() << "--------- KexiMacroProperty::set() macroitem=" << d->macroitem->name() << " name=" << d->name << endl; + + KSharedPtr<KoMacro::Action> action = d->macroitem->action(); + KSharedPtr<KoMacro::Variable> actionvariable = action->variable(d->name); + if(! actionvariable.data()) { + kdDebug() << "KexiMacroProperty::createProperty() Skipped cause there exists no such action=" << d->name << endl; + return; + } + + KSharedPtr<KoMacro::Variable> variable = d->macroitem->variable(d->name, true/*checkaction*/); + if(! variable.data()) { + kdDebug() << "KexiMacroProperty::createProperty() Skipped cause there exists no such variable=" << d->name << endl; + return; + } + + //TESTCASE!!!!!!!!!!!!!!!!!!!!!! + //if(! variable->isEnabled()) qFatal( QString("############## VARIABLE=%1").arg(variable->name()).latin1() ); + + Q_ASSERT(! d->name.isNull()); + m_property->setName( d->name.latin1() ); + m_property->setCaption( actionvariable->text() ); + m_property->setDescription( action->comment() ); + m_property->setValue( variable->variant(), true ); + m_property->setType( KEXIMACRO_PROPERTYEDITORTYPE ); // use our own propertytype +} + +KoProperty::Property* KexiMacroProperty::parentProperty() const +{ + return m_property; +} + +void KexiMacroProperty::setValue(const QVariant &value, bool rememberOldValue) +{ + Q_UNUSED(rememberOldValue); + kdDebug()<<"KexiMacroProperty::setValue name="<<d->name<<" value="<<value<<" rememberOldValue="<<rememberOldValue<<endl; + if(! d->macroitem->setVariant(d->name, value)) { // takes care of the type-conversation + kdDebug()<<"KexiMacroProperty::setValue Update failed !!!"<<endl; + return; + } + + // m_property->setValue() does check if the value changed by using + // this-value() and cause we already set it above, m_property->setValue() + // will be aborted. Well, we don't touch the properties value and handle + // it all via our CustomProperty class anyway. So, just ignore the property. + //m_property->setValue(this->value(), rememberOldValue, false/*useCustomProperty*/); + + emit valueChanged(); +} + +QVariant KexiMacroProperty::value() const +{ + KSharedPtr<KoMacro::Variable> variable = d->macroitem->variable(d->name, true); + Q_ASSERT( variable.data() != 0 ); + return variable.data() ? variable->variant() : QVariant(); +} + +bool KexiMacroProperty::handleValue() const +{ + return true; // we handle getting and setting of values and don't need KoProperty::Property for it. +} + +KSharedPtr<KoMacro::MacroItem> KexiMacroProperty::macroItem() const +{ + return d->macroitem; +} + +QString KexiMacroProperty::name() const +{ + return d->name; +} + +KSharedPtr<KoMacro::Variable> KexiMacroProperty::variable() const +{ + return d->macroitem->variable(d->name, true/*checkaction*/); +} + +KoProperty::Property* KexiMacroProperty::createProperty(KSharedPtr<KoMacro::MacroItem> macroitem, const QString& name) +{ + KoProperty::Property* property = new KoProperty::Property(); + KexiMacroProperty* customproperty = new KexiMacroProperty(property, macroitem, name); + if(! customproperty->variable().data()) { + kdWarning() << "KexiMacroProperty::createProperty() No such variable" << endl; + delete customproperty; customproperty = 0; + delete property; property = 0; + return 0; + } + property->setCustomProperty(customproperty); + return property; +} + +/************************************************************* + * KexiMacroPropertyFactory + */ + +KexiMacroPropertyFactory::KexiMacroPropertyFactory(QObject* parent) + : KoProperty::CustomPropertyFactory(parent) +{ +} + +KexiMacroPropertyFactory::~KexiMacroPropertyFactory() +{ +} + +KoProperty::CustomProperty* KexiMacroPropertyFactory::createCustomProperty(KoProperty::Property* parent) +{ + kdDebug()<<"KexiMacroPropertyFactory::createCustomProperty parent="<<parent->name()<<endl; + + KoProperty::CustomProperty* customproperty = parent->customProperty(); + KexiMacroProperty* parentcustomproperty = dynamic_cast<KexiMacroProperty*>(customproperty); + if(! parentcustomproperty) { + kdWarning() << "KexiMacroPropertyFactory::createCustomProperty() parent=" << parent->name() << " has an invalid customproperty." << endl; + return 0; + } + + KSharedPtr<KoMacro::MacroItem> macroitem = parentcustomproperty->macroItem(); + Q_ASSERT( macroitem.data() != 0 ); + const QString name = parentcustomproperty->name(); + Q_ASSERT(! name.isEmpty()); + + KexiMacroProperty* macroproperty = new KexiMacroProperty(parent, macroitem, name); + if(! macroproperty->variable().data()) { + delete macroproperty; macroproperty = 0; + return 0; + } + + return macroproperty; +} + +KoProperty::Widget* KexiMacroPropertyFactory::createCustomWidget(KoProperty::Property* property) +{ + kdDebug()<<"KexiMacroPropertyFactory::createCustomWidget property="<<property->name()<<endl; + return new KexiMacroPropertyWidget(property); +} + +void KexiMacroPropertyFactory::initFactory() +{ + CustomPropertyFactory* factory = KoProperty::FactoryManager::self()->factoryForEditorType(KEXIMACRO_PROPERTYEDITORTYPE); + if(! factory) { + factory = new KexiMacroPropertyFactory( KoProperty::FactoryManager::self() ); + KoProperty::FactoryManager::self()->registerFactoryForEditor(KEXIMACRO_PROPERTYEDITORTYPE, factory); + } +} + +/************************************************************* + * KexiMacroPropertyWidget + */ + +/** +* @internal implementation of a QListBoxItem to display the items of the +* combobox used within @a KexiMacroPropertyWidget to handle variables +* within a @a ListBox instance. +*/ +class ListBoxItem : public QListBoxText +{ + public: + ListBoxItem(QListBox* listbox) + : QListBoxText(listbox), m_enabled(true) {} + ListBoxItem(QListBox* listbox, const QString& text, QListBoxItem* after) + : QListBoxText(listbox, text, after), m_enabled(true) {} + virtual ~ListBoxItem() {} + void setEnabled(bool enabled) { m_enabled = enabled; } + virtual int width(const QListBox* lb) const { + Q_ASSERT( dynamic_cast<KComboBox*>( lb->parent() ) ); + return static_cast<KComboBox*>( lb->parent() )->lineEdit()->width() + 2; + } + virtual int height(const QListBox* lb) const { + Q_ASSERT( dynamic_cast<KComboBox*>( lb->parent() ) ); + return m_enabled ? static_cast<KComboBox*>( lb->parent() )->height() + 2 : 0; + } + private: + bool m_enabled; +}; + +/** +* @internal implementation of a @a ListBoxItem to provide an editable +* @a KoProperty::Widget as QListBoxItem in a @a ListBox instance. +*/ +class EditListBoxItem : public ListBoxItem +{ + public: + + EditListBoxItem(QListBox* listbox, KexiMacroProperty* macroproperty) + : ListBoxItem(listbox) + , m_macroproperty(macroproperty) + , m_prop(0) + , m_widget(0) + { + init(); + } + + virtual ~EditListBoxItem() { + delete m_widget; + delete m_prop; + } + + virtual QString text() const { + KSharedPtr<KoMacro::Variable> variable = m_macroproperty->variable(); + Q_ASSERT( variable.data() ); + //kdDebug()<<"EditListBoxItem::text() text="<<variable->toString()<<endl; + Q_ASSERT( variable->toString() != QString::null ); + return variable->toString(); + } + + KoProperty::Widget* widget() const { return m_widget; } + KSharedPtr<KoMacro::MacroItem> macroItem() const { return m_macroproperty->macroItem(); } + KSharedPtr<KoMacro::Variable> variable() const { return m_macroproperty->variable(); } + KSharedPtr<KoMacro::Action> action() const { return m_macroproperty->macroItem()->action(); } + + protected: + virtual void paint(QPainter* p) { + if(! m_widget) return; + Q_ASSERT( dynamic_cast<KComboBox*>( listBox()->parent() ) ); + const int w = width(listBox()); + const int h = height(listBox()); + m_widget->setFixedSize(w - 2, h - 2); + p->drawPixmap(0, 0, QPixmap::grabWidget(m_widget), 1, 1, w - 1, h - 1); + } + + private: + void init() { + KSharedPtr<KoMacro::MacroItem> macroitem = m_macroproperty->macroItem(); + Q_ASSERT( macroitem.data() ); + KSharedPtr<KoMacro::Action> action = m_macroproperty->macroItem()->action(); + if(! action.data()) { + kdWarning() << "EditListBoxItem::EditListBoxItem() Skipped cause there exists no action for macroproperty=" << m_macroproperty->name() << endl; + return; + } + KoProperty::Property* parentproperty = m_macroproperty->parentProperty(); + if(! parentproperty) { + kdWarning() << "EditListBoxItem::EditListBoxItem() No parentproperty defined" << endl; + return; + } + KSharedPtr<KoMacro::Variable> variable = m_macroproperty->variable(); + if(! variable.data()) { + kdWarning() << "EditListBoxItem::EditListBoxItem() No variable defined for property=" << parentproperty->name() << endl; + return; + } + + QVariant variant = variable->variant(); + + KSharedPtr<KoMacro::Variable> actionvariable = action->variable(m_macroproperty->name()); + if(actionvariable.data()) { + QVariant actionvariant = actionvariable->variant(); + Q_ASSERT( ! actionvariant.isNull() ); + Q_ASSERT( variant.canCast(actionvariant.type()) ); + variant.cast( actionvariant.type() ); //preserve type. + } + + int type = KoProperty::Auto; + switch(variant.type()) { + case QVariant::UInt: + case QVariant::Int: { + type = KoProperty::Integer; + } break; + case QVariant::CString: + case QVariant::String: { + type = KoProperty::String; + } break; + default: { + kdWarning() << "EditListBoxItem::EditListBoxItem() name=" << variable->name() << " type=" << QVariant::typeToName(variant.type()) << endl; + } break; + } + + QString name = variable->name(); + Q_ASSERT(! name.isNull()); + //if(name.isNull()) name = "aaaaaaaaaaaaaaaaa";//TESTCASE + m_prop = new KoProperty::Property( + name.latin1(), // name + variant, // value + variable->text(), // caption + QString::null, // description + type, // type + 0 //parentproperty // parent + ); + + m_widget = KoProperty::FactoryManager::self()->createWidgetForProperty(m_prop); + Q_ASSERT( m_widget != 0 ); + //m_widget->reparent(listBox()->viewport(), 0, QPoint(0,0)); + m_widget->reparent(listBox(), 0, QPoint(1,1)); + //layout->addWidget(m_widget, 1); + m_widget->setMinimumHeight(5); + m_widget->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); + } + + private: + KexiMacroProperty* m_macroproperty; + KoProperty::Property* m_prop; + KoProperty::Widget* m_widget; +}; + +/** +* @internal implementation of a @a QListBox for the combobox used within +* @a KexiMacroPropertyWidget to handle different variable-states. +*/ +class ListBox : public QListBox +{ + public: + ListBox(KComboBox* parent, KexiMacroProperty* macroproperty) + : QListBox(parent) + , m_macroproperty(macroproperty) + , m_edititem(0) + { + viewport()->setBackgroundMode(PaletteBackground); + setVariableHeight(true); + update(); + } + + virtual ~ListBox() {} + + void update() { + m_items.clear(); + delete m_edititem; + m_edititem = 0; + clear(); + + m_edititem = new EditListBoxItem(this, m_macroproperty); + Q_ASSERT( m_edititem->widget() != 0 ); + + const QString name = m_macroproperty->name(); + KoMacro::Variable::List children; + { + KoMacro::Variable::List actionchildren; + + KSharedPtr<KoMacro::Variable> itemvar = m_macroproperty->macroItem()->variable(name,false); + //kdDebug() << "KexiMacroProperty::ListBox::update() itemvar="<<(itemvar.data() ? "name:"+itemvar->name()+" value:"+itemvar->toString() : "NULL")<<endl; + if(itemvar.data()) + actionchildren = itemvar->children(); + + KSharedPtr<KoMacro::Action> action = m_edititem->action(); + KSharedPtr<KoMacro::Variable> actionvar = action.data() ? action->variable(name) : KSharedPtr<KoMacro::Variable>(); + //kdDebug() << "KexiMacroProperty::ListBox::update() actionvar="<<(actionvar.data() ? "name:"+actionvar->name()+" value:"+actionvar->toString() : "NULL")<<endl; + if(actionvar.data()) + actionchildren += actionvar->children(); + + KoMacro::Variable::List::ConstIterator it(actionchildren.constBegin()), end(actionchildren.constEnd()); + for(; it != end; ++it) { + if(name == (*it)->name()) { + KoMacro::Variable::List list = (*it)->children(); + KoMacro::Variable::List::ConstIterator listit(list.constBegin()), listend(list.constEnd()); + for(; listit != listend; ++listit) + children.append( *listit ); + } + } + + if(children.count() <= 0) + children = actionchildren; + } + + /* + kdDebug() << "KexiMacroProperty::ListBox::update() name="<<name<<" childcount="<<children.count()<<endl; + KoMacro::Variable::List::ConstIterator listit(children.constBegin()), listend(children.constEnd()); + for(; listit != listend; ++listit) { + kdDebug()<<" child name="<<(*listit)->name()<<" value="<<(*listit)->toString()<<" childcount="<<(*listit)->children().count()<<endl; + } + */ + + if(children.count() > 0) { + KoMacro::Variable::List::Iterator childit(children.begin()), childend(children.end()); + for(; childit != childend; ++childit) { + const QString n = (*childit)->name(); + //if(! n.startsWith("@")) continue; + const QVariant v = (*childit)->variant(); + + //kdDebug() << " child name=" << n << " value=" << v << endl; + switch( v.type() ) { + /* case QVariant::Map: { + const QMap<QString,QVariant> map = v.toMap(); + for(QMap<QString,QVariant>::ConstIterator it = map.constBegin(); it != map.constEnd(); ++it) + m_items.append(it.key()); + } break; */ + case QVariant::List: { + const QValueList<QVariant> list = v.toList(); + for(QValueList<QVariant>::ConstIterator it = list.constBegin(); it != list.constEnd(); ++it) { + const QString s = (*it).toString().stripWhiteSpace(); + if(! s.isEmpty()) + m_items.append(s); + } + } break; + case QVariant::StringList: { + const QStringList list = v.toStringList(); + for(QStringList::ConstIterator it = list.constBegin(); it != list.constEnd(); ++it) + if(! (*it).isEmpty()) + m_items.append(*it); + } break; + default: { + const QString s = v.toString().stripWhiteSpace(); + if(! s.isEmpty()) + m_items.append(s); + } break; + } + } + } + + QListBoxItem* item = m_edititem; + const uint count = m_items.count(); + for(uint i = 0; i < count; i++) + item = new ListBoxItem(this, m_items[i], item); + } + + EditListBoxItem* editItem() const { return m_edititem; } + QStringList items() const { return m_items; } + + virtual void hide () { + QListBox::hide(); + for(uint i = 0; i < count(); i++) + static_cast<ListBoxItem*>( item(i) )->setEnabled(false); + } + virtual void show() { + update(); + adjustSize(); + QListBox::show(); + } + + private: + KexiMacroProperty* m_macroproperty; + EditListBoxItem* m_edititem; + QStringList m_items; +}; + +/** +* @internal d-pointer class to be more flexible on future extension of the +* functionality without to much risk to break the binary compatibility. +*/ +class KexiMacroPropertyWidget::Private +{ + public: + KexiMacroProperty* macroproperty; + KComboBox* combobox; + ListBox* listbox; +}; + +KexiMacroPropertyWidget::KexiMacroPropertyWidget(KoProperty::Property* property, QWidget* parent) + : KoProperty::Widget(property, parent) + , d( new Private() ) +{ + kdDebug() << "KexiMacroPropertyWidget::KexiMacroPropertyWidget() Ctor" << endl; + + QHBoxLayout* layout = new QHBoxLayout(this, 0, 0); + + d->macroproperty = dynamic_cast<KexiMacroProperty*>( property->customProperty() ); + if(! d->macroproperty) { + kdWarning() << "KexiMacroPropertyWidget::KexiMacroPropertyWidget() Missing macroproperty for property=" << property->name() << endl; + return; + } + + d->combobox = new KComboBox(this); + layout->addWidget(d->combobox); + d->listbox = new ListBox(d->combobox, d->macroproperty); + d->combobox->setEditable(true); + d->combobox->setListBox(d->listbox); + d->combobox->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); + d->combobox->setMinimumHeight(5); + d->combobox->setInsertionPolicy(QComboBox::NoInsertion); + d->combobox->setMinimumSize(10, 0); // to allow the combo to be resized to a small size + d->combobox->setAutoCompletion(false); + d->combobox->setContextMenuEnabled(false); + + QVariant value = d->macroproperty->value(); + int index = d->listbox->items().findIndex( value.toString() ); + if(index >= 0) { + d->combobox->setCurrentItem(index + 1); + d->listbox->setCurrentItem(index + 1); + } + else { + Q_ASSERT( d->listbox->editItem()->widget() != 0 ); + d->listbox->editItem()->widget()->setValue( d->macroproperty->value(), true ); + //d->combobox->setCurrentItem(0); + } + kdDebug() << ">>> KexiMacroPropertyWidget::KexiMacroPropertyWidget() CurrentItem=" << d->combobox->currentItem() << endl; + + d->combobox->setFocusProxy( d->listbox->editItem()->widget() ); + setFocusWidget( d->combobox->lineEdit() ); + + connect(d->combobox, SIGNAL(textChanged(const QString&)), + this, SLOT(slotComboBoxChanged())); + connect(d->combobox, SIGNAL(activated(int)), + this, SLOT(slotComboBoxActivated())); + connect(d->listbox->editItem()->widget(), SIGNAL(valueChanged(Widget*)), + this, SLOT(slotWidgetValueChanged())); + connect(d->macroproperty, SIGNAL(valueChanged()), + this, SLOT(slotPropertyValueChanged())); +} + +KexiMacroPropertyWidget::~KexiMacroPropertyWidget() +{ + kdDebug() << "KexiMacroPropertyWidget::~KexiMacroPropertyWidget() Dtor" << endl; + delete d; +} + +QVariant KexiMacroPropertyWidget::value() const +{ + kdDebug()<<"KexiMacroPropertyWidget::value() value="<<d->macroproperty->value()<<endl; + return d->macroproperty->value(); + /* QVariant value = d->combobox->currentText(); + value.cast( d->macroproperty->value().type() ); + return value; */ +} + +void KexiMacroPropertyWidget::setValue(const QVariant& value, bool emitChange) +{ + kdDebug()<<"KexiMacroPropertyWidget::setValue() value="<<value<<" emitChange="<<emitChange<<endl; + + if(! emitChange) + d->combobox->blockSignals(true); + + const QString s = value.toString(); + d->combobox->setCurrentText( s.isNull() ? "" : s ); + + if(emitChange) + emit valueChanged(this); + else + d->combobox->blockSignals(false); +} + +void KexiMacroPropertyWidget::setReadOnlyInternal(bool readOnly) +{ + Q_UNUSED(readOnly); + //kdDebug()<<"KexiMacroPropertyWidget::setReadOnlyInternal() readOnly="<<readOnly<<endl; +} + +void KexiMacroPropertyWidget::slotComboBoxChanged() +{ + kdDebug()<<"KexiMacroPropertyWidget::slotComboBoxChanged()"<<endl; + const QVariant v = d->combobox->currentText(); + d->macroproperty->setValue(v, true); + //emit valueChanged(this); +} + +void KexiMacroPropertyWidget::slotComboBoxActivated() +{ + Q_ASSERT( d->listbox->editItem()->widget() ); + const int index = d->combobox->currentItem(); + QString text = (index == 0) + ? d->listbox->editItem()->widget()->value().toString() + : d->combobox->text(index); + kdDebug()<<"KexiMacroPropertyWidget::slotComboBoxActivated() index="<<index<<" text="<<text<<endl; + d->combobox->setCurrentText(text); + slotWidgetValueChanged(); +} + +void KexiMacroPropertyWidget::slotWidgetValueChanged() +{ + d->macroproperty->emitPropertyChanged(); +} + +void KexiMacroPropertyWidget::slotPropertyValueChanged() +{ + Q_ASSERT( d->listbox->editItem()->widget() ); + const QVariant v = d->macroproperty->value(); + kdDebug()<<"KexiMacroPropertyWidget::slotPropertyValueChanged() value="<<v<<endl; + d->listbox->editItem()->widget()->setValue(v, true); +} + +#include "keximacroproperty.moc" diff --git a/kexi/plugins/macros/kexipart/keximacroproperty.h b/kexi/plugins/macros/kexipart/keximacroproperty.h new file mode 100644 index 00000000..19f7b7ac --- /dev/null +++ b/kexi/plugins/macros/kexipart/keximacroproperty.h @@ -0,0 +1,186 @@ +/* This file is part of the KDE project + Copyright (C) 2006 Sebastian Sauer <[email protected]> + + 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 KEXIMACROPROPERTY_H +#define KEXIMACROPROPERTY_H + +#include <ksharedptr.h> +#include <koproperty/property.h> +#include <koproperty/factory.h> +#include <koproperty/customproperty.h> +#include <koproperty/widget.h> + +namespace KoMacro { + class Variable; + class MacroItem; +} + +class KexiMacroPropertyWidget; + +/** +* Implementation of a @a KoProperty::CustomProperty to have +* more control about the handling of our macro-properties. +*/ +class KexiMacroProperty + : public QObject + , public KoProperty::CustomProperty +{ + Q_OBJECT + + friend class KexiMacroPropertyWidget; + + public: + + /** Constructor. */ + explicit KexiMacroProperty(KoProperty::Property* parent, KSharedPtr<KoMacro::MacroItem> macroitem, const QString& name); + /** Destructor. */ + virtual ~KexiMacroProperty(); + + /** @return the parent @a KoProperty::Property instance. */ + KoProperty::Property* parentProperty() const; + + /** This function is called by @ref KoProperty::Property::setValue() + when a custom property is set. + You don't have to modify the property value, it is done by Property class. + You just have to update child or parent properties value (m_property->parent()->setValue()). + Note that, when calling Property::setValue, you <b>need</b> to set + useCustomProperty (3rd parameter) to false, or there will be infinite recursion. */ + virtual void setValue(const QVariant &value, bool rememberOldValue); + + /** This function is called by @ref KoProperty::Property::value() + when a custom property is set and @ref handleValue() is true. + You should return property's value, taken from parent's value.*/ + virtual QVariant value() const; + + /** Tells whether CustomProperty should be used to get the property's value. + You should return true for child properties, and false for others. */ + virtual bool handleValue() const; + + /** \return the \a KoMacro::MacroItem this custom property has or + NULL if there was no item provided. */ + KSharedPtr<KoMacro::MacroItem> macroItem() const; + + /** \return the name the property has in the \a KoMacro::MacroItem + above. Is QString::null if there was no item provided. */ + QString name() const; + + /** \return the \a KoMacro::Variable which has the name @a name() + in the item @a macroItem() . If such a variable doesn't exists NULL + is returned. */ + KSharedPtr<KoMacro::Variable> variable() const; + + /** Factory function to create a new @a KoProperty::Property instance + that will use a @a KexiMacroProperty as container. */ + static KoProperty::Property* createProperty(KSharedPtr<KoMacro::MacroItem> macroitem, const QString& name); + + signals: + + /** Emitted if @a setValue was called and the value changed. */ + void valueChanged(); + + private: + /** \internal d-pointer class. */ + class Private; + /** \internal d-pointer instance. */ + Private* const d; + /** \internal initializer method. */ + inline void init(); +}; + +/** +* Implementation of a @a KoProperty::CustomPropertyFactory to handle +* creation of @a KexiMacroProperty and @a KexiMacroPropertyWidget +* instances for our macro-properties. +*/ +class KexiMacroPropertyFactory : public KoProperty::CustomPropertyFactory +{ + public: + /** Constructor. */ + explicit KexiMacroPropertyFactory(QObject* parent); + /** Destructor. */ + virtual ~KexiMacroPropertyFactory(); + + /** @return a new instance of custom property for @p parent. + Implement this for property types you want to support. + Use parent->type() to get type of the property. */ + virtual KoProperty::CustomProperty* createCustomProperty(KoProperty::Property* parent); + + /** @return a new instance of custom property for @p property. + Implement this for property editor types you want to support. + Use parent->type() to get type of the property. */ + virtual KoProperty::Widget* createCustomWidget(KoProperty::Property* property); + + /** Initializes this factory. The factory may register itself at + the @a KoProperty::FactoryManager if not alreadydone before. This + function should be called from within the @a KexiMacroDesignView + before the functionality provided with @a KexiMacroProperty and + @a KexiMacroPropertyWidget got used. */ + static void initFactory(); +}; + +/** + * Implementation of a @a KoProperty::Widget used to display and + * edit a @a KexiMacroProperty . + */ +class KexiMacroPropertyWidget : public KoProperty::Widget +{ + Q_OBJECT + + public: + /** Constructor. */ + explicit KexiMacroPropertyWidget(KoProperty::Property* property, QWidget* parent = 0); + /** Destructor. */ + virtual ~KexiMacroPropertyWidget(); + + /** @return the value this widget has. */ + virtual QVariant value() const; + + /** Set the value @p value this widget has. If @p emitChange is true, + the @p KoProperty::Widget::valueChanged signal will be emitted. */ + virtual void setValue(const QVariant& value, bool emitChange=true); + + //virtual void drawViewer(QPainter *p, const QColorGroup &cg, const QRect &r, const QVariant &value); + + protected: + + /** Called if the value should be read only. */ + virtual void setReadOnlyInternal(bool readOnly); + + private slots: + + /** Called if the text in the KComboBox changed. */ + void slotComboBoxChanged(); + + /** Called if an item in the QListBox of the KComboBox got activated. */ + void slotComboBoxActivated(); + + /** Called if the @a KoProperty::Widget of the EditListBoxItem got changed. */ + void slotWidgetValueChanged(); + + /** Called if the value of a @a KexiMacroProperty changed to update + the widget and the displayed content. */ + void slotPropertyValueChanged(); + + private: + /** \internal d-pointer class. */ + class Private; + /** \internal d-pointer instance. */ + Private* const d; +}; + +#endif + diff --git a/kexi/plugins/macros/kexipart/keximacrotextview.cpp b/kexi/plugins/macros/kexipart/keximacrotextview.cpp new file mode 100644 index 00000000..95c94a47 --- /dev/null +++ b/kexi/plugins/macros/kexipart/keximacrotextview.cpp @@ -0,0 +1,90 @@ +/* This file is part of the KDE project + Copyright (C) 2006 Sebastian Sauer <[email protected]> + + 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 "keximacrotextview.h" + +#include <ktextedit.h> +#include <kdebug.h> + +#include <kexidialogbase.h> +#include <kexidb/connection.h> + +#include "../lib/macro.h" +#include "../lib/xmlhandler.h" + +/** +* \internal d-pointer class to be more flexible on future extension of the +* functionality without to much risk to break the binary compatibility. +*/ +class KexiMacroTextView::Private +{ + public: + + /** + * The Editor used to display and edit the XML text. + */ + KTextEdit* editor; + +}; + +KexiMacroTextView::KexiMacroTextView(KexiMainWindow *mainwin, QWidget *parent, ::KoMacro::Macro* const macro) + : KexiMacroView(mainwin, parent, macro, "KexiMacroTextView") + , d( new Private() ) +{ + QHBoxLayout* layout = new QHBoxLayout(this); + d->editor = new KTextEdit(this); + d->editor->setTextFormat(Qt::PlainText); + d->editor->setWordWrap(QTextEdit::NoWrap); + layout->addWidget(d->editor); + + connect(d->editor, SIGNAL(textChanged()), this, SLOT(editorChanged())); +} + +KexiMacroTextView::~KexiMacroTextView() +{ + delete d; +} + +void KexiMacroTextView::editorChanged() +{ + setDirty(true); +} + +bool KexiMacroTextView::loadData() +{ + QString data; + if(! loadDataBlock(data)) { + kexipluginsdbg << "KexiMacroTextView::loadData(): no DataBlock" << endl; + return false; + } + + kdDebug() << QString("KexiMacroTextView::loadData()\n%1").arg(data) << endl; + //d->editor->blockSignals(true); + d->editor->setText(data); + //d->editor->blockSignals(false); + setDirty(false); + return true; +} + +tristate KexiMacroTextView::storeData(bool /*dontAsk*/) +{ + kexipluginsdbg << QString("KexiMacroTextView::storeData() %1 [%2]\n%3").arg(parentDialog()->partItem()->name()).arg(parentDialog()->id()).arg(d->editor->text()) << endl; + return storeDataBlock( d->editor->text() ); +} + +#include "keximacrotextview.moc" + diff --git a/kexi/plugins/macros/kexipart/keximacrotextview.h b/kexi/plugins/macros/kexipart/keximacrotextview.h new file mode 100644 index 00000000..66a2229c --- /dev/null +++ b/kexi/plugins/macros/kexipart/keximacrotextview.h @@ -0,0 +1,77 @@ +/* This file is part of the KDE project + Copyright (C) 2006 Sebastian Sauer <[email protected]> + + 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 KEXIMACROTEXTVIEW_H +#define KEXIMACROTEXTVIEW_H + +#include "keximacroview.h" + +// Forward declaration. +namespace KoMacro { + class Macro; +} + +/** + * The KexiMacroTextView implements \a KexiMacroView to provide + * a simple texteditor to edit the XML document of a Macro. + */ +class KexiMacroTextView : public KexiMacroView +{ + Q_OBJECT + public: + + /** + * Constructor. + * + * \param mainwin The \a KexiMainWindow instance this \a KexiViewBase + * belongs to. + * \param parent The parent widget this widget should be displayed in. + * \param macro The \a KoMacro::Macro instance this view is for. + */ + KexiMacroTextView(KexiMainWindow *mainwin, QWidget *parent, ::KoMacro::Macro* const macro); + + /** + * Destructor. + */ + virtual ~KexiMacroTextView(); + + /** + * Load the data and display it in the editor. + */ + virtual bool loadData(); + + /** + * Try to store the modified data in the already opened and + * currently used \a KexiDB::SchemaData instance. + */ + virtual tristate storeData(bool dontAsk = false); + + private slots: + + /** + * This slot got called if the text of the editor changed. + */ + void editorChanged(); + + private: + /// \internal d-pointer class. + class Private; + /// \internal d-pointer instance. + Private* const d; +}; + +#endif diff --git a/kexi/plugins/macros/kexipart/keximacroview.cpp b/kexi/plugins/macros/kexipart/keximacroview.cpp new file mode 100644 index 00000000..35200829 --- /dev/null +++ b/kexi/plugins/macros/kexipart/keximacroview.cpp @@ -0,0 +1,175 @@ +/* This file is part of the KDE project + Copyright (C) 2006 Sebastian Sauer <[email protected]> + + 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 "keximacroview.h" + +#include <qdom.h> +#include <kdebug.h> + +#include <kexidialogbase.h> +#include <kexidb/connection.h> +#include <kexidb/error.h> + +#include <core/kexi.h> +#include <core/kexiproject.h> +#include <core/kexipartmanager.h> +#include <core/kexipartinfo.h> + +#include "../lib/macro.h" +#include "../lib/xmlhandler.h" +#include "../lib/exception.h" + +#include "keximacroerror.h" + +/** +* \internal d-pointer class to be more flexible on future extension of the +* functionality without to much risk to break the binary compatibility. +*/ +class KexiMacroView::Private +{ + public: + + /** + * The \a KoMacro::Manager instance used to access the + * Macro Framework. + */ + KSharedPtr<KoMacro::Macro> macro; + + /** + * Constructor. + * + * \param m The passed \a KoMacro::Manager instance our + * \a manager points to. + */ + Private(KoMacro::Macro* const m) + : macro(m) + { + } + +}; + +KexiMacroView::KexiMacroView(KexiMainWindow *mainwin, QWidget *parent, KoMacro::Macro* const macro, const char* name) + : KexiViewBase(mainwin, parent, (name ? name : "KexiMacroView")) + , d( new Private(macro) ) +{ + //kdDebug() << "KexiMacroView::KexiMacroView() Ctor" << endl; + plugSharedAction( "data_execute", this, SLOT(execute()) ); +} + +KexiMacroView::~KexiMacroView() +{ + //kdDebug() << "KexiMacroView::~KexiMacroView() Dtor" << endl; + delete d; +} + +KSharedPtr<KoMacro::Macro> KexiMacroView::macro() const +{ + return d->macro; +} + +tristate KexiMacroView::beforeSwitchTo(int mode, bool& dontstore) +{ + kexipluginsdbg << "KexiMacroView::beforeSwitchTo mode=" << mode << " dontstore=" << dontstore << endl; + return true; +} + +tristate KexiMacroView::afterSwitchFrom(int mode) +{ + kexipluginsdbg << "KexiMacroView::afterSwitchFrom mode=" << mode << endl; + loadData(); // reload the data + return true; +} + +bool KexiMacroView::loadData() +{ + d->macro->clearItems(); + + QString data; + if(! loadDataBlock(data)) { + kexipluginsdbg << "KexiMacroView::loadData(): no DataBlock" << endl; + return false; + } + + QString errmsg; + int errline, errcol; + + QDomDocument domdoc; + bool parsed = domdoc.setContent(data, false, &errmsg, &errline, &errcol); + + if(! parsed) { + kexipluginsdbg << "KexiMacroView::loadData() XML parsing error line: " << errline << " col: " << errcol << " message: " << errmsg << endl; + return false; + } + + kexipluginsdbg << QString("KexiMacroView::loadData()\n%1").arg(domdoc.toString()) << endl; + QDomElement macroelem = domdoc.namedItem("macro").toElement(); + if(macroelem.isNull()) { + kexipluginsdbg << "KexiMacroView::loadData() Macro domelement is null" << endl; + return false; + } + + //kexipluginsdbg << "KexiMacroView::loadData()" << endl; + return d->macro->parseXML(macroelem); +} + +KexiDB::SchemaData* KexiMacroView::storeNewData(const KexiDB::SchemaData& sdata, bool &cancel) +{ + KexiDB::SchemaData *schema = KexiViewBase::storeNewData(sdata, cancel); + kexipluginsdbg << "KexiMacroView::storeNewData() new id:" << schema->id() << endl; + + if(!schema || cancel) { + delete schema; + return 0; + } + + if(! storeData()) { + kexipluginsdbg << "KexiMacroView::storeNewData() Failed to store the data." << endl; + //failure: remove object's schema data to avoid garbage + KexiDB::Connection *conn = parentDialog()->mainWin()->project()->dbConnection(); + conn->removeObject( schema->id() ); + delete schema; + return 0; + } + + return schema; +} + +tristate KexiMacroView::storeData(bool /*dontAsk*/) +{ + QDomDocument domdoc("macros"); + QDomElement macroelem = d->macro->toXML(); + domdoc.appendChild(macroelem); + const QString xml = domdoc.toString(2); + const QString name = QString("%1 [%2]").arg(parentDialog()->partItem()->name()).arg(parentDialog()->id()); + kexipluginsdbg << QString("KexiMacroView::storeData %1\n%2").arg(name).arg(xml) << endl; + return storeDataBlock(xml); +} + +void KexiMacroView::execute(QObject* sender) +{ + KSharedPtr<KoMacro::Context> context = d->macro->execute(sender); + if(context->hadException()) { + KexiMacroError* error = new KexiMacroError( + mainWin(), // The parent KexiMainWindow + context // The KoMacro::Context where the error occured. + ); + error->exec(); + } +} + +#include "keximacroview.moc" + diff --git a/kexi/plugins/macros/kexipart/keximacroview.h b/kexi/plugins/macros/kexipart/keximacroview.h new file mode 100644 index 00000000..beed842e --- /dev/null +++ b/kexi/plugins/macros/kexipart/keximacroview.h @@ -0,0 +1,140 @@ +/* This file is part of the KDE project + Copyright (C) 2006 Sebastian Sauer <[email protected]> + + 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 KEXIMACROVIEW_H +#define KEXIMACROVIEW_H + +#include <kexiviewbase.h> + +// Forward declarations. +namespace KoMacro { + class Macro; +} +namespace KoProperty { + class Property; +} +namespace KexiDB { + class ResultInfo; +} +class KexiTableItem; + +/** + * The KexiMacroView implements \a KexiViewBase to provide + * a base KexiView instance for Macros. + * + * The \a KexiMacroDesignView and the \a KexiMacroTextView + * are inherited from this class. + */ +class KexiMacroView : public KexiViewBase +{ + Q_OBJECT + public: + + /** + * Constructor. + * + * \param mainwin The \a KexiMainWindow instance this \a KexiViewBase + * belongs to. + * \param parent The parent widget this widget should be displayed in. + * \param macro The \a KoMacro::Macro instance this view is for. + */ + KexiMacroView(KexiMainWindow *mainwin, QWidget *parent, ::KoMacro::Macro* const macro, const char* name = 0); + + /** + * Destructor. + */ + virtual ~KexiMacroView(); + + /** + * \return the Macro instance. + */ + KSharedPtr<KoMacro::Macro> macro() const; + + /** + * Load the data from XML source and fill the internally + * used \a KoMacro::Macro instance. + */ + virtual bool loadData(); + + /** + * Try to call \a storeData with new data we like to store. On + * success the matching \a KexiDB::SchemaData is returned. + * + * \param sdata The source \a KexiDB::SchemaData instance. + * \param cancel Cancel on failure and don't try to clean + * possible temporary created data up. + * \return The matching \a KexiDB::SchemaData instance or NULL + * if storing failed. + */ + virtual KexiDB::SchemaData* storeNewData(const KexiDB::SchemaData& sdata, bool &cancel); + + /** + * Try to store the modified data in the already opened and + * currently used \a KexiDB::SchemaData instance. + */ + virtual tristate storeData(bool dontAsk = false); + + public slots: + + /** + * This slot will be invoked if Kexi's menuitem Data=>Execute + * got activated and will execute the Macro. + */ + void execute(QObject* sender = 0); + + protected: + + /** + * Called by \a KexiDialogBase::switchToViewMode() right before dialog + * is switched to new mode. + * + * \param mode The viewmode to which should be switched. This + * could be either Kexi::DataViewMode, Kexi::DesignViewMode + * or Kexi::TextViewMode. + * \param donstore This call-by-reference boolean value defines + * if \a storeData should be called for the old but still + * selected viewmode. Set \a dontstore to true (it's false + * by default) if you want to avoid data storing. + * \return true if you accept or false if a error occupied and view + * shouldn't change. If there is no error but switching + * should be just cancelled (probably after showing some + * info messages), you need to return cancelled. + */ + virtual tristate beforeSwitchTo(int mode, bool& dontstore); + + /** + * Called by \a KexiDialogBase::switchToViewMode() right after dialog + * is switched to new mode. + * + * \param mode The viewmode to which we switched. This could + * be either Kexi::DataViewMode, Kexi::DesignViewMode + * or Kexi::TextViewMode. + * \return true if you accept or false if a error occupied and view + * shouldn't change. If there is no error but switching + * should be just cancelled (probably after showing + * some info messages), you need to return cancelled. + */ + virtual tristate afterSwitchFrom(int mode); + + private: + /// \internal d-pointer class. + class Private; + /// \internal d-pointer instance. + Private* const d; +}; + +#endif |