connectiondialog.cpp
1/* This file is part of the KDE project
2 Copyright (C) 2004 Cedric Pasteur <cedric.pasteur@free.fr>
3 Copyright (C) 2004 Jaroslaw Staniek <js@iidea.pl>
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Library General Public
7 License as published by the Free Software Foundation; either
8 version 2 of the License, or (at your option) any later version.
9
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Library General Public License for more details.
14
15 You should have received a copy of the GNU Library General Public License
16 along with this library; see the file COPYING.LIB. If not, write to
17 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 * Boston, MA 02110-1301, USA.
19*/
20
21#include <tqlayout.h>
22#include <tqhbox.h>
23#include <tqlabel.h>
24#include <tqregexp.h>
25#include <tqmetaobject.h>
26#include <tqstrlist.h>
27
28#include <kpushbutton.h>
29#include <kiconloader.h>
30#include <tdemessagebox.h>
31#include <kdebug.h>
32#include <tdelocale.h>
33
34#include "kexitableview.h"
35#include "kexitableviewdata.h"
36#include "events.h"
37#include "form.h"
38#include "formmanager.h"
39#include "objecttree.h"
40
41#include "connectiondialog.h"
42
43namespace KFormDesigner {
44
48ConnectionDialog::ConnectionDialog(TQWidget *parent)
49: KDialogBase(parent, "connections_dialog", true, i18n("Edit Form Connections"),
50 Ok|Cancel|Details, Ok, false)
51, m_buffer(0)
52{
53 TQFrame *frame = makeMainWidget();
54 TQHBoxLayout *layout = new TQHBoxLayout(frame, 0, 6);
55
56 // Setup the details widget /////////
57 TQHBox *details = new TQHBox(frame);
58 setDetailsWidget(details);
59 setDetails(true);
60
61 m_pixmapLabel = new TQLabel(details);
62 m_pixmapLabel->setFixedWidth( int(IconSize(TDEIcon::Desktop) * 1.5) );
63 m_pixmapLabel->setAlignment(AlignHCenter | AlignTop);
64
65 m_textLabel = new TQLabel(details);
66 m_textLabel->setAlignment(AlignLeft | AlignTop);
67 //setStatusOk();
68
69 // And the KexiTableView ////////
70 m_data = new KexiTableViewData();
71 m_table = new KexiTableView(0, frame, "connections_tableview");
72 m_table->setSpreadSheetMode();
73 m_table->setInsertingEnabled(true);
74 initTable();
75 m_table->setData(m_data, false);
76 m_table->adjustColumnWidthToContents(0);
77 layout->addWidget(m_table);
78
80 TQVBoxLayout *vlayout = new TQVBoxLayout(layout, 3);
81 KPushButton *newItem = new KPushButton(SmallIconSet("document-new"), i18n("&New Connection"), frame);
82 vlayout->addWidget(newItem);
83 m_buttons.insert(BAdd, newItem);
84 connect(newItem, TQ_SIGNAL(clicked()), this, TQ_SLOT(newItem()));
85
86 KPushButton *delItem = new KPushButton(SmallIconSet("edit-delete"), i18n("&Remove Connection"), frame);
87 vlayout->addWidget(delItem);
88 m_buttons.insert(BRemove, delItem);
89 connect(delItem, TQ_SIGNAL(clicked()), this, TQ_SLOT(removeItem()));
90
91 vlayout->addStretch();
92
93 setInitialSize(TQSize(600, 300));
94 //setWFlags(WDestructiveClose);
95
96 connect(m_table,TQ_SIGNAL(cellSelected(int, int)), this, TQ_SLOT(slotCellSelected(int, int)));
97 connect(m_table->KexiDataAwareObjectInterface::data(), TQ_SIGNAL(rowInserted(KexiTableItem*,bool)), this, TQ_SLOT(slotRowInserted(KexiTableItem*,bool)));
98 this->newItem();
99}
100
101void
102ConnectionDialog::initTable()
103{
105 col0->field()->setSubType("TDEIcon");
106 col0->setReadOnly(true);
107 col0->field()->setDescription(i18n("Connection correctness"));
108 m_data->addColumn(col0);
109
112 col1->setRelatedData( m_widgetsColumnData );
113 m_data->addColumn(col1);
114
117 col2->setRelatedData( m_signalsColumnData );
118 m_data->addColumn(col2);
119
120 KexiTableViewColumn *col3 = new KexiTableViewColumn(i18n("Receiver"), KexiDB::Field::Enum);
121 col3->setRelatedData( m_widgetsColumnData );
122 m_data->addColumn(col3);
123
126 col4->setRelatedData( m_slotsColumnData );
127 m_data->addColumn(col4);
128
129 TQValueList<int> c;
130 c << 2 << 4;
131 m_table->maximizeColumnsWidth(c);
132 m_table->setColumnStretchEnabled( true, 4 );
133
134 connect(m_data, TQ_SIGNAL(aboutToChangeCell(KexiTableItem*, int, TQVariant&, KexiDB::ResultInfo*)),
135 this,TQ_SLOT(slotCellChanged(KexiTableItem*, int, TQVariant, KexiDB::ResultInfo*)));
136 connect(m_data, TQ_SIGNAL(rowUpdated(KexiTableItem*)), this, TQ_SLOT(checkConnection(KexiTableItem *)));
137 connect(m_table, TQ_SIGNAL(itemSelected(KexiTableItem *)), this, TQ_SLOT(checkConnection(KexiTableItem *)));
138}
139
140void
141ConnectionDialog::exec(Form *form)
142{
143 m_form = form;
144 updateTableData();
145
146 KDialogBase::exec();
147}
148
149void ConnectionDialog::slotCellSelected(int col, int row)
150{
151 m_buttons[BRemove]->setEnabled( row < m_table->rows() );
152 KexiTableItem *item = m_table->itemAt(row);
153 if (!item)
154 return;
155 if(col == 2) // signal col
156 updateSignalList(item);
157 else if(col == 4) // slot col
158 updateSlotList(item);
159}
160
161void ConnectionDialog::slotRowInserted(KexiTableItem* item,bool)
162{
163 m_buffer->append(new Connection());
164 checkConnection( item );
165}
166
167void
168ConnectionDialog::slotOk()
169{
170 // First we update our buffer contents
171 for(int i=0; i < m_table->rows(); i++)
172 {
173 KexiTableItem *item = m_table->itemAt(i);
174 Connection *c = m_buffer->at(i);
175
176 c->setSender( (*item)[1].toString() );
177 c->setSignal( (*item)[2].toString() );
178 c->setReceiver( (*item)[3].toString() );
179 c->setSlot( (*item)[4].toString() );
180 }
181
182 // then me make it replace form's current one
183 delete m_form->connectionBuffer();
184 m_form->setConnectionBuffer(m_buffer);
185
186 TQDialog::accept();
187}
188
189void
190ConnectionDialog::updateTableData()
191{
192 // First we update the columns data
193 ObjectTreeDict *dict = new ObjectTreeDict( *(m_form->objectTree()->dict()) );
194 ObjectTreeDictIterator it(*dict);
195 for(; it.current(); ++it)
196 {
197 KexiTableItem *item = m_widgetsColumnData->createItem(); //new KexiTableItem(2);
198 (*item)[0] = it.current()->name();
199 (*item)[1] = (*item)[0];
200 m_widgetsColumnData->append(item);
201 }
202 delete dict;
203
204 // Then we fill the columns with the form connections
205 for(Connection *c = m_form->connectionBuffer()->first(); c ; c = m_form->connectionBuffer()->next())
206 {
207 KexiTableItem *item = m_table->KexiDataAwareObjectInterface::data()->createItem(); //new KexiTableItem(5);
208 (*item)[1] = c->sender();
209 (*item)[2] = c->signal();
210 (*item)[3] = c->receiver();
211 (*item)[4] = c->slot();
212 m_table->insertItem(item, m_table->rows());
213 }
214
215 m_buffer = new ConnectionBuffer(*(m_form->connectionBuffer()));
216}
217
218void
219ConnectionDialog::setStatusOk(KexiTableItem *item)
220{
221 m_pixmapLabel->setPixmap( DesktopIcon("button_ok") );
222 m_textLabel->setText("<qt><h2>The connection is OK.</h2></qt>");
223
224 if (!item)
225 item = m_table->selectedItem();
226 if (m_table->currentRow() >= m_table->rows())
227 item = 0;
228
229 if (item)
230 (*item)[0] = "button_ok";
231 else {
232 m_pixmapLabel->setPixmap( TQPixmap() );
233 m_textLabel->setText(TQString());
234 }
235}
236
237void
238ConnectionDialog::setStatusError(const TQString &msg, KexiTableItem *item)
239{
240 m_pixmapLabel->setPixmap( DesktopIcon("button_cancel") );
241 m_textLabel->setText("<qt><h2>The connection is invalid.</h2></qt>" + msg);
242
243 if (!item)
244 item = m_table->selectedItem();
245 if (m_table->currentRow() >= m_table->rows())
246 item = 0;
247
248 if (item)
249 (*item)[0] = "button_cancel";
250 else {
251 m_pixmapLabel->setPixmap( TQPixmap() );
252 m_textLabel->setText(TQString());
253 }
254}
255
256void
257ConnectionDialog::slotCellChanged(KexiTableItem *item, int col, TQVariant&, KexiDB::ResultInfo*)
258{
259 switch(col)
260 {
261 // sender changed, we clear siganl and slot
262 case 1:
263 (*item)[2] = TQString("");
264 // signal or receiver changed, we clear the slot cell
265 case 2:
266 case 3:
267 {
268 (*item)[4] = TQString("");
269 break;
270 }
271 default:
272 break;
273 }
274}
275
276void
277ConnectionDialog::updateSlotList(KexiTableItem *item)
278{
279 m_slotsColumnData->deleteAllRows();
280 TQString widget = (*item)[1].toString();
281 TQString signal = (*item)[2].toString();
282
283 if((widget.isEmpty()) || signal.isEmpty())
284 return;
285 ObjectTreeItem *tree = m_form->objectTree()->lookup(widget);
286 if(!tree || !tree->widget())
287 return;
288
289 TQString signalArg(signal);
290 signalArg = signalArg.remove( TQRegExp(".*[(]|[)]") );
291
292 TQStrList slotList = tree->widget()->metaObject()->slotNames(true);
293 TQStrListIterator it(slotList);
294 for(; it.current() != 0; ++it)
295 {
296 // we add the slot only if it is compatible with the signal
297 TQString slotArg(*it);
298 slotArg = slotArg.remove( TQRegExp(".*[(]|[)]") );
299
300 if(!signalArg.startsWith(slotArg, true) && (!signal.isEmpty())) // args not compatible
301 continue;
302
303 KexiTableItem *item = m_slotsColumnData->createItem(); //new KexiTableItem(2);
304 (*item)[0] = TQString(*it);
305 (*item)[1] = (*item)[0];
306 m_slotsColumnData->append(item);
307 }
308}
309
310void
311ConnectionDialog::updateSignalList(KexiTableItem *item)
312{
313 ObjectTreeItem *tree = m_form->objectTree()->lookup((*item)[1].toString());
314 if(!tree || !tree->widget())
315 return;
316
317 m_signalsColumnData->deleteAllRows();
318 TQStrList signalList = tree->widget()->metaObject()->signalNames(true);
319 TQStrListIterator it(signalList);
320 for(; it.current() != 0; ++it)
321 {
322 KexiTableItem *item = m_signalsColumnData->createItem(); //new KexiTableItem(2);
323 (*item)[0] = TQString(*it);
324 (*item)[1] = (*item)[0];
325 m_signalsColumnData->append(item);
326 }
327}
328
329void
330ConnectionDialog::checkConnection(KexiTableItem *item)
331{
332 // First we check if one column is empty
333 for(int i = 1; i < 5; i++)
334 {
335 if( !item || (*item)[i].toString().isEmpty())
336 {
337 setStatusError( i18n("<qt>You have not selected item: <b>%1</b>.</qt>").arg(m_data->column(i)->captionAliasOrName()),
338 item);
339 return;
340 }
341 }
342
343 // Then we check if signal/slot args are compatible
344 TQString signal = (*item)[2].toString();
345 signal = signal.remove( TQRegExp(".*[(]|[)]") ); // just keep the args list
346 TQString slot = (*item)[4].toString();
347 slot = slot.remove( TQRegExp(".*[(]|[)]") );
348
349 if(!signal.startsWith(slot, true))
350 {
351 setStatusError( i18n("The signal/slot arguments are not compatible."), item);
352 return;
353 }
354
355 setStatusOk(item);
356}
357
358void
359ConnectionDialog::newItem()
360{
361 m_table->acceptRowEdit();
362 m_table->setCursorPosition(m_table->rows(), 1);
363}
364
365void
366ConnectionDialog::newItemByDragnDrop()
367{
369 connect(KFormDesigner::FormManager::self(), TQ_SIGNAL(connectionAborted(KFormDesigner::Form*)), this, TQ_SLOT(slotConnectionAborted(KFormDesigner::Form*)));
370 connect(KFormDesigner::FormManager::self(), TQ_SIGNAL(connectionCreated(KFormDesigner::Form*, Connection&)), this, TQ_SLOT(slotConnectionCreated(KFormDesigner::Form*, Connection&)) );
371
372 hide();
373}
374
375void
376ConnectionDialog::slotConnectionCreated(KFormDesigner::Form *form, Connection &connection)
377{
378 show();
379 if(form != m_form)
380 return;
381
382 Connection *c = new Connection(connection);
383 KexiTableItem *item = m_table->KexiDataAwareObjectInterface::data()->createItem(); //new KexiTableItem(5);
384 (*item)[1] = c->sender();
385 (*item)[2] = c->signal();
386 (*item)[3] = c->receiver();
387 (*item)[4] = c->slot();
388 m_table->insertItem(item, m_table->rows());
389 m_buffer->append(c);
390}
391
392void
393ConnectionDialog::slotConnectionAborted(KFormDesigner::Form *form)
394{
395 show();
396 if(form != m_form)
397 return;
398
399 newItem();
400}
401
402void
403ConnectionDialog::removeItem()
404{
405 if(m_table->currentRow() == -1 || m_table->currentRow()>=m_table->rows())
406 return;
407
408 int confirm = KMessageBox::warningContinueCancel(parentWidget(),
409 TQString("<qt>")+i18n("Do you want to delete this connection ?")+"</qt>", TQString(), KGuiItem(i18n("&Delete Connection")),
410 "dontAskBeforeDeleteConnection"/*config entry*/);
411 if(confirm == KMessageBox::Cancel)
412 return;
413
414 m_buffer->remove(m_table->currentRow());
415 m_table->deleteItem(m_table->selectedItem());
416}
417
418}
419
420#include "connectiondialog.moc"
static FormManager * self()
Access to FormManager singleton.
void startCreatingConnection()
Enter the Connection creation mode.
A simple class representing a form.
Definition form.h:136
An item representing a widget Holds the properties of a widget (classname, name, parent,...
Definition objecttree.h:59
void setDescription(const TQString &description)
Definition field.h:496
void setSubType(const TQString &subType)
Definition field.h:322
KexiDB::Field * field() const
void setReadOnly(bool ro)
forces readOnly flag to be set to ro
void setRelatedData(KexiTableViewData *data)
KexiTableView class provides a widget for displaying data in a tabular view.
TQDictIterator< ObjectTreeItem > ObjectTreeDictIterator
An iterator for ObjectTreeDict.
Definition objecttree.h:51
type * findParent(TQObject *o, const char *className, TQObject *&prevPrev)
TQDict< ObjectTreeItem > ObjectTreeDict
A TQString-based disctionary of ObjectTreeItem pointers.
Definition objecttree.h:48