kexi

keximacrodesignview.cpp
1/* This file is part of the KDE project
2 Copyright (C) 2006 Sebastian Sauer <mail@dipe.org>
3
4 This library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Library General Public
6 License as published by the Free Software Foundation; either
7 version 2 of the License, or (at your option) any later version.
8 This library is distributed in the hope that it will be useful,
9 but WITHOUT ANY WARRANTY; without even the implied warranty of
10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 Library General Public License for more details.
12 You should have received a copy of the GNU Library General Public License
13 along with this library; see the file COPYING.LIB. If not, write to
14 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
15 Boston, MA 02110-1301, USA.
16*/
17
18#include "keximacrodesignview.h"
19#include "keximacroproperty.h"
20
21#include <tqtimer.h>
22#include <tqdom.h>
23#include <kdebug.h>
24
25#include <kexidialogbase.h>
26#include <kexidb/connection.h>
27#include <kexidb/error.h>
28
29#include <core/kexi.h>
30#include <core/kexiproject.h>
31#include <core/kexipartmanager.h>
32#include <core/kexipartinfo.h>
33
34#include <widget/kexidatatable.h>
35#include <widget/tableview/kexitableview.h>
36#include <widget/tableview/kexitableviewdata.h>
37#include <widget/tableview/kexitableitem.h>
38#include <widget/tableview/kexidataawarepropertyset.h>
39
40#include <koproperty/set.h>
41#include <koproperty/property.h>
42
43#include "../lib/macro.h"
44#include "../lib/macroitem.h"
45#include "../lib/xmlhandler.h"
46
48#define COLUMN_ID_ACTION 0
49#define COLUMN_ID_COMMENT 1
50
55class KexiMacroDesignView::Private
56{
57 public:
58
63 KexiDataTable* datatable;
64
68 KexiTableView* tableview;
69
74 KexiTableViewData* tabledata;
75
80 KexiDataAwarePropertySet* propertyset;
81
83 bool reloadsProperties;
85 bool updatesProperties;
86
93 Private()
94 : propertyset(0)
95 , reloadsProperties(false)
96 , updatesProperties(false)
97 {
98 }
99
103 ~Private()
104 {
105 delete propertyset;
106 }
107
108};
109
111 : KexiMacroView(mainwin, parent, macro, "KexiMacroDesignView")
112 , d( new Private() )
113{
114 // The table's data-model.
115 d->tabledata = new KexiTableViewData();
116 d->tabledata->setSorting(-1); // disable sorting
117
118 // Add the "Action" column.
120 "action", // name/identifier
121 KexiDB::Field::Enum, // fieldtype
122 KexiDB::Field::NoConstraints, // constraints
123 KexiDB::Field::NoOptions, // options
124 0, // length
125 0, // precision
126 TQVariant(), // default value
127 i18n("Action"), // caption
128 TQString(), // description
129 0 // width
130 );
131 d->tabledata->addColumn(actioncol);
132
133 TQValueVector<TQString> items;
134 items.append(""); // empty means no action
135
136 // Append the list of actions provided by Kexi.
137 TQStringList actionnames = KoMacro::Manager::self()->actionNames();
138 TQStringList::ConstIterator it, end( actionnames.constEnd() );
139 for( it = actionnames.constBegin(); it != end; ++it) {
140 TDESharedPtr<KoMacro::Action> action = KoMacro::Manager::self()->action(*it);
141 items.append( action->text() );
142 }
143
144 actioncol->field()->setEnumHints(items);
145
146 // Add the "Comment" column.
147 d->tabledata->addColumn( new KexiTableViewColumn(
148 "comment", // name/identifier
149 KexiDB::Field::Text, // fieldtype
150 KexiDB::Field::NoConstraints, // constraints
151 KexiDB::Field::NoOptions, // options
152 0, // length
153 0, // precision
154 TQVariant(), // default value
155 i18n("Comment"), // caption
156 TQString(), // description
157 0 // width
158 ) );
159
160 // Create the tableview.
161 TQHBoxLayout* layout = new TQHBoxLayout(this);
162 d->datatable = new KexiDataTable(mainWin(), this, "Macro KexiDataTable", false /*not db aware*/);
163 layout->addWidget(d->datatable);
164 d->tableview = d->datatable->tableView();
165 d->tableview->setSpreadSheetMode();
166 d->tableview->setColumnStretchEnabled( true, COLUMN_ID_COMMENT ); //last column occupies the rest of the area
167
168 // We need to register our KexiMacroPropertyFactory to use our own
169 // KoProperty::Property implementation.
171
172 // Create the propertyset.
173 d->propertyset = new KexiDataAwarePropertySet(this, d->tableview);
174
175 // Connect signals the KexiDataTable provides to local slots.
176 connect(d->tabledata, TQ_SIGNAL(aboutToChangeCell(KexiTableItem*,int,TQVariant&,KexiDB::ResultInfo*)),
177 this, TQ_SLOT(beforeCellChanged(KexiTableItem*,int,TQVariant&,KexiDB::ResultInfo*)));
178 connect(d->tabledata, TQ_SIGNAL(rowUpdated(KexiTableItem*)),
179 this, TQ_SLOT(rowUpdated(KexiTableItem*)));
180 connect(d->tabledata, TQ_SIGNAL(rowInserted(KexiTableItem*,uint,bool)),
181 this, TQ_SLOT(rowInserted(KexiTableItem*,uint,bool)));
182 connect(d->tabledata, TQ_SIGNAL(rowDeleted()),
183 this, TQ_SLOT(rowDeleted()));
184
185 // Everything is ready. So, update the data now.
186 updateData();
187 setDirty(false);
188}
189
194
195void KexiMacroDesignView::updateData()
196{
197 kdDebug() << "KexiMacroDesignView::updateData()" << endl;
198
199 // Remove previous content of tabledata.
200 d->tabledata->deleteAllRows();
201 // Remove old property sets.
202 d->propertyset->clear();
203
204 // Add some empty rows
205 for (int i=0; i<50; i++) {
206 d->tabledata->append( d->tabledata->createItem() );
207 }
208
209 // Set the MacroItem's
210 TQStringList actionnames = KoMacro::Manager::self()->actionNames();
211 KoMacro::MacroItem::List macroitems = macro()->items();
212 KoMacro::MacroItem::List::ConstIterator it(macroitems.constBegin()), end(macroitems.constEnd());
213 for(uint idx = 0; it != end; ++it, idx++) {
214 KexiTableItem* tableitem = d->tabledata->at(idx);
215 if(! tableitem) {
216 // If there exists no such item, add it.
217 tableitem = d->tabledata->createItem();
218 d->tabledata->append(tableitem);
219 }
220 // Set the action-column.
221 TDESharedPtr<KoMacro::Action> action = (*it)->action();
222 if(action.data()) {
223 int i = actionnames.findIndex( action->name() );
224 if(i >= 0) {
225 tableitem->at(COLUMN_ID_ACTION) = i + 1;
226 //setAction(tableitem, action->name());
227 }
228 }
229 // Set the comment-column.
230 tableitem->at(COLUMN_ID_COMMENT) = (*it)->comment();
231 }
232
233 // set data for our spreadsheet: this will clear our sets
234 d->tableview->setData(d->tabledata);
235
236 // Add the property sets.
237 it = macroitems.constBegin();
238 for(uint idx = 0; it != end; ++it, idx++) {
239 updateProperties(idx, 0, *it);
240 }
241
242 // work around a bug in the KexiTableView where we lose the stretch-setting...
243 d->tableview->setColumnStretchEnabled( true, COLUMN_ID_COMMENT ); //last column occupies the rest of the area
244
246}
247
249{
251 return false;
252 }
253 updateData(); // update the tableview's data.
254 return true;
255}
256
258{
259 return d->propertyset->currentPropertySet();
260}
261
262void KexiMacroDesignView::beforeCellChanged(KexiTableItem* item, int colnum, TQVariant& newvalue, KexiDB::ResultInfo* result)
263{
264 Q_UNUSED(result);
265 kdDebug() << "KexiMacroDesignView::beforeCellChanged() colnum=" << colnum << " newvalue=" << newvalue.toString() << endl;
266
267 int rowindex = d->tabledata->findRef(item);
268 if(rowindex < 0) {
269 kdWarning() << "KexiMacroDesignView::beforeCellChanged() No such item" << endl;
270 return;
271 }
272
273 // If the rowindex doesn't exists yet, we need to append new
274 // items till we are able to access the item we like to use.
275 for(int i = macro()->items().count(); i <= rowindex; i++) {
276 macro()->addItem( TDESharedPtr<KoMacro::MacroItem>( new KoMacro::MacroItem() ) );
277 }
278
279 // Get the matching MacroItem.
280 TDESharedPtr<KoMacro::MacroItem> macroitem = macro()->items()[rowindex];
281 if(! macroitem.data()) {
282 kdWarning() << "KexiMacroDesignView::beforeCellChanged() Invalid item for rowindex=" << rowindex << endl;
283 return;
284 }
285
286 // Handle the column that should be changed
287 switch(colnum) {
288 case COLUMN_ID_ACTION: { // The "Action" column
289 TQString actionname;
290 bool ok;
291 int selectedindex = newvalue.toInt(&ok);
292 if(ok && selectedindex > 0) {
293 TQStringList actionnames = KoMacro::Manager::self()->actionNames();
294 actionname = actionnames[ selectedindex - 1 ]; // first item is empty
295 }
296 TDESharedPtr<KoMacro::Action> action = KoMacro::Manager::self()->action(actionname);
297 macroitem->setAction(action);
298 updateProperties(d->propertyset->currentRow(), d->propertyset->currentPropertySet(), macroitem);
300 } break;
301 case COLUMN_ID_COMMENT: { // The "Comment" column
302 macroitem->setComment( newvalue.toString() );
303 } break;
304 default:
305 kdWarning() << "KexiMacroDesignView::beforeCellChanged() No such column number " << colnum << endl;
306 return;
307 }
308
309 setDirty();
310}
311
312void KexiMacroDesignView::rowUpdated(KexiTableItem* item)
313{
314 int rowindex = d->tabledata->findRef(item);
315 kdDebug() << "KexiMacroDesignView::rowUpdated() rowindex=" << rowindex << endl;
316 //propertySetSwitched();
317 //propertySetReloaded(true);
318 //setDirty();
319}
320
321void KexiMacroDesignView::rowInserted(KexiTableItem*, uint row, bool)
322{
323 kdDebug() << "KexiMacroDesignView::rowInserted() rowindex=" << row << endl;
324 KoMacro::MacroItem::List& macroitems = macro()->items();
325
326 if(row < macroitems.count()) {
327 // If a new item was inserted, we need to insert a new item to our
328 // list of MacroItems too. If the new item was appended, we don't
329 // need to do anything yet cause the new item will be handled on
330 // beforeCellChanged() anyway.
331 kdDebug() << "KexiMacroDesignView::rowInserted() Inserting new MacroItem" << endl;
332 TDESharedPtr<KoMacro::MacroItem> macroitem = TDESharedPtr<KoMacro::MacroItem>( new KoMacro::MacroItem() );
333 KoMacro::MacroItem::List::Iterator it = macroitems.at(row);
334 macroitems.insert(it, macroitem);
335 }
336}
337
338void KexiMacroDesignView::rowDeleted()
339{
340 int rowindex = d->propertyset->currentRow();
341 if(rowindex < 0) {
342 kdWarning() << "KexiMacroDesignView::rowDeleted() No such item" << endl;
343 return;
344 }
345 kdDebug() << "KexiMacroDesignView::rowDeleted() rowindex=" << rowindex << endl;
346 KoMacro::MacroItem::List& macroitems = macro()->items();
347 macroitems.remove( macroitems.at(rowindex) );
348}
349
350bool KexiMacroDesignView::updateSet(KoProperty::Set* set, TDESharedPtr<KoMacro::MacroItem> macroitem, const TQString& variablename)
351{
352 kdDebug() << "KexiMacroDesignView::updateSet() variablename=" << variablename << endl;
353 KoProperty::Property* property = KexiMacroProperty::createProperty(macroitem, variablename);
354 if(! property)
355 return false;
356 set->addProperty(property);
357 return true;
358}
359
360void KexiMacroDesignView::updateProperties(int row, KoProperty::Set* set, TDESharedPtr<KoMacro::MacroItem> macroitem)
361{
362 kdDebug() << "KexiMacroDesignView::updateProperties() row=" << row << endl;
363
364 if(row < 0 || d->updatesProperties) {
365 return; // ignore invalid rows and avoid infinite recursion.
366 }
367
368 TDESharedPtr<KoMacro::Action> action = macroitem->action();
369 if(! action.data()) {
370 // don't display a propertyset if there is no action defined.
371 d->propertyset->remove(row);
372 return; // job done.
373 }
374
375 d->updatesProperties = true;
376
377 if(set) {
378 // we need to clear old data before adding the new content.
379 set->clear();
380 }
381 else {
382 // if there exists no such propertyset yet, create one.
383 set = new KoProperty::Set(d->propertyset, action->name());
384 d->propertyset->insert(row, set, true);
385 connect(set, TQ_SIGNAL(propertyChanged(KoProperty::Set&, KoProperty::Property&)),
386 this, TQ_SLOT(propertyChanged(KoProperty::Set&, KoProperty::Property&)));
387 }
388
389 // The caption.
390 KoProperty::Property* prop = new KoProperty::Property("this:classString", action->text());
391 prop->setVisible(false);
392 set->addProperty(prop);
393
394 // Display the list of variables.
395 TQStringList varnames = action->variableNames();
396 for(TQStringList::Iterator it = varnames.begin(); it != varnames.end(); ++it) {
397 if(updateSet(set, macroitem, *it)) {
398 TDESharedPtr<KoMacro::Variable> variable = macroitem->variable(*it, true);
399 kdDebug()<<"KexiMacroDesignView::updateProperties() name=" << *it << " variable=" << variable->variant().toString() << endl;
400#if 0
401 macroitem->setVariable(*it, variable);
402#endif
403 }
404 }
405
406 d->updatesProperties = false;
407}
408
409void KexiMacroDesignView::propertyChanged(KoProperty::Set& set, KoProperty::Property& property)
410{
411 Q_UNUSED(set);
412 kdDebug() << "!!!!! KexiMacroDesignView::propertyChanged() propertyname=" << property.name() << endl;
413 setDirty();
414
415 /*
416 if(d->reloadsProperties) // be sure to don't update properties if we are still on reloading.
417 return;
418 d->reloadsProperties = true;
419
420 const int row = d->propertyset->currentRow();
421 const TQCString name = property.name();
422 kdDebug() << "KexiMacroDesignView::propertyChanged() name=" << name << " row=" << row << endl;
423
424 //TODO reload is only needed if something changed!
425 bool dirty = true; bool reload = true;//dirtyvarnames.count()>0;
426
427 if(dirty || reload) { // Only reload properties if it's really needed.
428 setDirty();
429 if(reload) {
430 // The MacroItem which should be changed.
431 TDESharedPtr<KoMacro::MacroItem> macroitem = macro()->items()[row];
432 // Update the properties.
433 updateProperties(row, &set, macroitem);
434 }
435 // It's needed to call the reload delayed cause in KoProperty::Editor
436 // TQTimer::singleShot(10, this, TQ_SLOT(selectItemLater())); may lead
437 // to crashes if we are to fast.
438 TQTimer::singleShot(50, this, TQ_SLOT(reloadPropertyLater()));
439 }
440
441 d->reloadsProperties = false;
442 */
443
444 /*
445 TQStringList dirtyvarnames = macroitem->setVariable(name, TDESharedPtr<KoMacro::Variable>(pv));
446 bool dirty = false;
447 bool reload = false;
448 for(TQStringList::Iterator it = dirtyvarnames.begin(); it != dirtyvarnames.end(); ++it) {
449 TDESharedPtr<KoMacro::Variable> variable = macroitem->variable(*it);
450 if(! variable.data()) {
451 kdDebug() << "KexiMacroDesignView::propertyChanged() name=" << name << " it=" << *it << " skipped cause such a variable is not known." << endl;
452 continue;
453 }
454
455 if(! set.contains( (*it).latin1() )) {
456 // If there exist no such property yet, we need to add it.
457 if(updateSet(&set, macroitem, *it))
458 reload = true; // we like to reload the whole set
459 continue;
460 }
461
462 kdDebug() << "KexiMacroDesignView::propertyChanged() set existing property=" << *it << endl;
463 KoProperty::Property& p = set.property((*it).latin1());
464 KoMacro::Variable::List children = variable->children();
465 if(children.count() > 0) {
466 TQStringList keys, names;
467 KoMacro::Variable::List::Iterator childit(children.begin()), childend(children.end());
468 for(; childit != childend; ++childit) {
469 const TQString s = (*childit)->variant().toString();
470 keys << s;
471 names << s;
472 }
473 p.setListData( new KoProperty::Property::ListData(keys, names) );
474 }
475 p.setValue(variable->variant());
476 dirty = true;
477 }
478
479 // If there are expired aka not any longer needed properties around, we
480 // need to reload the whole set.
481 for(KoProperty::Set::Iterator setit = set; setit.current(); ++setit) {
482 if(setit.currentKey() == name) continue; // don't remove ourself
483 if(setit.currentKey().left(5) == TQCString("this:")) continue; // don't remove internal properties
484 if(setit.currentKey() == TQCString("newrow")) continue; // also an internal used property
485 if(action.data() && action->hasVariable(setit.currentKey())) continue; // the property is still valid
486 reload = true; // we like to reload the whole set
487 }
488 */
489}
490
491void KexiMacroDesignView::reloadPropertyLater()
492{
494}
495
496#include "keximacrodesignview.moc"
497
void setEnumHints(const TQValueVector< TQString > &l)
Definition field.h:544
Provides a data-driven (record-based) tabular view.
virtual ~KexiMacroDesignView()
Destructor.
virtual KoProperty::Set * propertySet()
KexiMacroDesignView(KexiMainWindow *mainwin, TQWidget *parent, ::KoMacro::Macro *const macro)
Constructor.
virtual bool loadData()
Load the data from XML source and fill the internally used KoMacro::Macro instance.
static void initFactory()
Initializes this factory.
static KoProperty::Property * createProperty(TDESharedPtr< KoMacro::MacroItem > macroitem, const TQString &name)
Factory function to create a new KoProperty::Property instance that will use a KexiMacroProperty as c...
TDESharedPtr< KoMacro::Macro > macro() const
KexiMacroView(KexiMainWindow *mainwin, TQWidget *parent, ::KoMacro::Macro *const macro, const char *name=0)
Constructor.
virtual bool loadData()
Load the data from XML source and fill the internally used KoMacro::Macro instance.
Kexi's main window interface This interface is implemented by KexiMainWindowImpl class.
KexiDB::Field * field() const
virtual bool deleteAllRows(bool repaint=false)
void propertySetReloaded(bool preservePrevSelection=false, const TQCString &propertyToSelect=TQCString())
KexiMainWindow * mainWin() const
TQValueList< TDESharedPtr< MacroItem > > List
A list of MacroItem instances.
Definition macroitem.h:54
The Macro class implements all the action-handling.
Definition macro.h:45
static Manager * self()
Definition manager.cpp:76
TDESharedPtr< Action > action(const TQString &name) const
Definition manager.cpp:132
TQStringList actionNames() const
Definition manager.cpp:142