File indexing completed on 2024-05-12 16:39:44
0001 /* This file is part of the KDE project 0002 Copyright (C) 2004 Cedric Pasteur <cedric.pasteur@free.fr> 0003 Copyright (C) 2004-2009 Jarosław Staniek <staniek@kde.org> 0004 0005 This library is free software; you can redistribute it and/or 0006 modify it under the terms of the GNU Library General Public 0007 License as published by the Free Software Foundation; either 0008 version 2 of the License, or (at your option) any later version. 0009 0010 This library is distributed in the hope that it will be useful, 0011 but WITHOUT ANY WARRANTY; without even the implied warranty of 0012 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 0013 Library General Public License for more details. 0014 0015 You should have received a copy of the GNU Library General Public License 0016 along with this library; see the file COPYING.LIB. If not, write to 0017 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 0018 * Boston, MA 02110-1301, USA. 0019 */ 0020 0021 #include "connectiondialog.h" 0022 #include <KexiIcon.h> 0023 #include "kexitableview.h" 0024 #include "events.h" 0025 #include "form.h" 0026 #include "objecttree.h" 0027 0028 #include <KDbTableViewData> 0029 0030 #include <KMessageBox> 0031 #include <KLocalizedString> 0032 0033 #include <QLabel> 0034 #include <QRegularExpression> 0035 #include <QPushButton> 0036 0037 using namespace KFormDesigner; 0038 0039 class Q_DECL_HIDDEN ConnectionDialog::Private 0040 { 0041 public: 0042 explicit Private(Form *f); 0043 ~Private(); 0044 0045 Form *form; 0046 ConnectionBuffer *buffer; 0047 KexiTableView *table; 0048 KDbTableViewData *data; 0049 KDbTableViewData *widgetsColumnData, 0050 *slotsColumnData, *signalsColumnData; 0051 QLabel *pixmapLabel, *textLabel; 0052 QPushButton *addButton, *removeButton; 0053 }; 0054 0055 ConnectionDialog::Private::Private(Form *f) 0056 :form(f), buffer(0) 0057 { 0058 0059 } 0060 0061 ConnectionDialog::Private::~Private() 0062 { 0063 0064 } 0065 0066 ///////////////////////////////////////////////////////////////////////////////// 0067 ///////////// The dialog to edit or add/remove connections ////////////////////// 0068 ///////////////////////////////////////////////////////////////////////////////// 0069 ConnectionDialog::ConnectionDialog(Form *form, QWidget *parent) 0070 : KDialog(parent) 0071 , d(new Private(form)) 0072 { 0073 setObjectName("connections_dialog"); 0074 setModal(true); 0075 setWindowTitle(xi18nc("@title:window", "Edit Form Connections")); 0076 setButtons(KDialog::Ok | KDialog::Cancel | KDialog::Details); 0077 setDefaultButton(KDialog::Ok); 0078 0079 QFrame *frame = new QFrame(this); 0080 setMainWidget(frame); 0081 QHBoxLayout *layout = new QHBoxLayout(frame); 0082 0083 // Setup the details widget ///////// 0084 QWidget *details = new QWidget(frame); 0085 layout->addWidget(details); 0086 QHBoxLayout *detailsLyr = new QHBoxLayout(details); 0087 setDetailsWidget(details); 0088 setDetailsWidgetVisible(true); 0089 0090 d->pixmapLabel = new QLabel(details); 0091 detailsLyr->addWidget(d->pixmapLabel); 0092 d->pixmapLabel->setFixedWidth(int(KIconLoader::global()->currentSize(KIconLoader::Desktop) * 1.5)); 0093 d->pixmapLabel->setAlignment(Qt::AlignHCenter | Qt::AlignTop); 0094 0095 d->textLabel = new QLabel(details); 0096 detailsLyr->addWidget(d->textLabel); 0097 d->textLabel->setAlignment(Qt::AlignLeft | Qt::AlignTop); 0098 //setStatusOk(); 0099 0100 // And the KexiTableView //////// 0101 d->data = new KDbTableViewData(); 0102 d->table = new KexiTableView(0, frame, "connections_tableview"); 0103 d->table->setSpreadSheetMode(true); 0104 d->table->setInsertingEnabled(true); 0105 initTable(); 0106 d->table->setData(d->data, false); 0107 d->table->adjustColumnWidthToContents(0); 0108 layout->addWidget(d->table); 0109 0110 connect(d->table, SIGNAL(cellSelected(int,int)), 0111 this, SLOT(slotCellSelected(int,int))); 0112 connect(d->table->data(), SIGNAL(recordInserted(KDbRecordData*,bool)), 0113 this, SLOT(slotRecordInserted(KDbRecordData*,bool))); 0114 0115 //// Setup the icon toolbar ///////////////// 0116 QVBoxLayout *vlayout = new QVBoxLayout(layout); 0117 d->addButton = new QPushButton(koIcon("document-new"), xi18n("&New Connection"), frame); 0118 vlayout->addWidget(d->addButton); 0119 connect(d->addButton, SIGNAL(clicked()), this, SLOT(newItem())); 0120 0121 d->removeButton = new QPushButton(KStandardGuiItem::del().icon(), xi18n("&Delete Connection"), frame); 0122 vlayout->addWidget(d->removeButton); 0123 connect(d->removeButton, SIGNAL(clicked()), this, SLOT(removeItem())); 0124 0125 vlayout->addStretch(); 0126 0127 setInitialSize(QSize(600, 300)); 0128 //setWFlags(WDestructiveClose); 0129 0130 this->newItem(); 0131 } 0132 0133 ConnectionDialog::~ConnectionDialog() 0134 { 0135 delete d; 0136 } 0137 0138 void 0139 ConnectionDialog::initTable() 0140 { 0141 KDbTableViewColumn *col0 = new KDbTableViewColumn(xi18n("OK?"), KDbField::Text); 0142 col0->field()->setSubType("QIcon"); 0143 col0->setReadOnly(true); 0144 col0->field()->setDescription(xi18n("Connection correctness")); 0145 d->data->addColumn(col0); 0146 0147 KDbTableViewColumn *col1 = new KDbTableViewColumn(xi18n("Sender"), KDbField::Enum); 0148 d->widgetsColumnData = new KDbTableViewData(KDbField::Text, KDbField::Text); 0149 col1->setRelatedData(d->widgetsColumnData); 0150 d->data->addColumn(col1); 0151 0152 KDbTableViewColumn *col2 = new KDbTableViewColumn(xi18n("Signal"), KDbField::Enum); 0153 d->signalsColumnData = new KDbTableViewData(KDbField::Text, KDbField::Text); 0154 col2->setRelatedData(d->signalsColumnData); 0155 d->data->addColumn(col2); 0156 0157 KDbTableViewColumn *col3 = new KDbTableViewColumn(xi18n("Receiver"), KDbField::Enum); 0158 col3->setRelatedData(d->widgetsColumnData); 0159 d->data->addColumn(col3); 0160 0161 KDbTableViewColumn *col4 = new KDbTableViewColumn(xi18n("Slot"), KDbField::Enum); 0162 d->slotsColumnData = new KDbTableViewData(KDbField::Text, KDbField::Text); 0163 col4->setRelatedData(d->slotsColumnData); 0164 d->data->addColumn(col4); 0165 0166 QList<int> c; 0167 c << 2 << 4; 0168 d->table->maximizeColumnsWidth(c); 0169 d->table->setColumnResizeEnabled(4, true); 0170 0171 connect(d->data, SIGNAL(aboutToChangeCell(KDbRecordData*,int,QVariant*,KDbResultInfo*)), 0172 this, SLOT(slotCellChanged(KDbRecordData*,int,QVariant*,KDbResultInfo*))); 0173 connect(d->data, SIGNAL(recordUpdated(KDbRecordData*)), this, SLOT(checkConnection(KDbRecordData*))); 0174 connect(d->table, SIGNAL(itemSelected(KDbRecordData*)), this, SLOT(checkConnection(KDbRecordData*))); 0175 } 0176 0177 void ConnectionDialog::exec() 0178 { 0179 updateTableData(); 0180 KDialog::exec(); 0181 } 0182 0183 void ConnectionDialog::slotCellSelected(int row, int col) 0184 { 0185 d->removeButton->setEnabled(row < d->table->rows()); 0186 KDbRecordData *data = d->table->itemAt(row); 0187 if (!data) 0188 return; 0189 if (col == 2) // signal col 0190 updateSignalList(data); 0191 else if (col == 4) // slot col 0192 updateSlotList(data); 0193 } 0194 0195 void ConnectionDialog::slotRecordInserted(KDbRecordData* item, bool) 0196 { 0197 d->buffer->append(new Connection()); 0198 checkConnection(item); 0199 } 0200 0201 void 0202 ConnectionDialog::slotOk() 0203 { 0204 // First we update our buffer contents 0205 for (int i = 0; i < d->table->rows(); i++) { 0206 KDbRecordData *data = d->table->itemAt(i); 0207 Connection *c = d->buffer->at(i); 0208 0209 c->setSender((*data)[1].toString()); 0210 c->setSignal((*data)[2].toString()); 0211 c->setReceiver((*data)[3].toString()); 0212 c->setSlot((*data)[4].toString()); 0213 } 0214 0215 // then me make it replace form's current one 0216 d->form->setConnectionBuffer(d->buffer); 0217 0218 QDialog::accept(); 0219 } 0220 0221 void 0222 ConnectionDialog::updateTableData() 0223 { 0224 // First we update the columns data 0225 foreach (ObjectTreeItem *item, *d->form->objectTree()->hash()) { 0226 KDbRecordData *data = d->widgetsColumnData->createItem(); 0227 (*data)[0] = item->name(); 0228 (*data)[1] = (*data)[0]; 0229 d->widgetsColumnData->append(data); 0230 } 0231 0232 // Then we fill the columns with the form connections 0233 foreach (Connection *c, *d->form->connectionBuffer()) { 0234 KDbRecordData *newData = d->table->data()->createItem(); 0235 (*newData )[1] = c->sender(); 0236 (*newData )[2] = c->signal(); 0237 (*newData )[3] = c->receiver(); 0238 (*newData )[4] = c->slot(); 0239 d->table->insertItem(newData , d->table->rows()); 0240 } 0241 0242 d->buffer = new ConnectionBuffer(*(d->form->connectionBuffer())); 0243 } 0244 0245 void 0246 ConnectionDialog::setStatusOk(KDbRecordData *data) 0247 { 0248 d->pixmapLabel->setPixmap(koDesktopIcon("dialog-ok")); 0249 d->textLabel->setText(QString("<qt><h2>%1</h2></qt>").arg(xi18n("The connection is OK."))); 0250 0251 if (!data) 0252 data = d->table->selectedItem(); 0253 if (d->table->currentRow() >= d->table->rows()) 0254 data = 0; 0255 0256 if (data) 0257 (*data)[0] = "dialog-ok"; 0258 else { 0259 d->pixmapLabel->setPixmap(QPixmap()); 0260 d->textLabel->setText(QString()); 0261 } 0262 } 0263 0264 void 0265 ConnectionDialog::setStatusError(const QString &msg, KDbRecordData *data) 0266 { 0267 d->pixmapLabel->setPixmap(koDesktopIcon("dialog-cancel")); 0268 d->textLabel->setText(QString("<qt><h2>%1</h2></qt>").arg(xi18n("The connection is invalid.")) + msg); 0269 0270 if (!data) 0271 data = d->table->selectedItem(); 0272 if (d->table->currentRow() >= d->table->rows()) 0273 data = 0; 0274 0275 if (data) 0276 (*data)[0] = "dialog-cancel"; 0277 else { 0278 d->pixmapLabel->setPixmap(QPixmap()); 0279 d->textLabel->setText(QString()); 0280 } 0281 } 0282 0283 void 0284 ConnectionDialog::slotCellChanged(KDbRecordData *data, int col, QVariant*, KDbResultInfo*) 0285 { 0286 switch (col) { 0287 // sender changed, we clear siganl and slot 0288 case 1: 0289 (*data)[2] = QString(""); 0290 // signal or receiver changed, we clear the slot cell 0291 case 2: 0292 case 3: { 0293 (*data)[4] = QString(""); 0294 break; 0295 } 0296 default: 0297 break; 0298 } 0299 } 0300 0301 void 0302 ConnectionDialog::updateSlotList(KDbRecordData *data) 0303 { 0304 d->slotsColumnData->deleteAllRecords(); 0305 QString widget = (*data)[1].toString(); 0306 QString signal = (*data)[2].toString(); 0307 0308 if ((widget.isEmpty()) || signal.isEmpty()) 0309 return; 0310 ObjectTreeItem *tree = d->form->objectTree()->lookup(widget); 0311 if (!tree || !tree->widget()) 0312 return; 0313 0314 QString signalArg(signal); 0315 signalArg.remove(QRegularExpression(".*[(]|[)]")); 0316 0317 const QList<QMetaMethod> list( 0318 KexiUtils::methodsForMetaObjectWithParents(tree->widget()->metaObject(), 0319 QMetaMethod::Slot, QMetaMethod::Public)); 0320 foreach(const QMetaMethod &method, list) { 0321 // we add the slot only if it is compatible with the signal 0322 QString slotArg(method.signature()); 0323 slotArg.remove(QRegularExpression(".*[(]|[)]")); 0324 if (!signalArg.startsWith(slotArg, Qt::CaseSensitive) && (!signal.isEmpty())) // args not compatible 0325 continue; 0326 0327 KDbRecordData *newData = d->slotsColumnData->createItem(); 0328 (*newData)[0] = QString::fromLatin1(method.signature()); 0329 (*newData)[1] = (*newData)[0]; 0330 d->slotsColumnData->append(newData); 0331 } 0332 } 0333 0334 void 0335 ConnectionDialog::updateSignalList(KDbRecordData *data) 0336 { 0337 ObjectTreeItem *tree = d->form->objectTree()->lookup((*data)[1].toString()); 0338 if (!tree || !tree->widget()) 0339 return; 0340 0341 d->signalsColumnData->deleteAllRecords(); 0342 const QList<QMetaMethod> list( 0343 KexiUtils::methodsForMetaObjectWithParents(tree->widget()->metaObject(), 0344 QMetaMethod::Signal, QMetaMethod::Public)); 0345 foreach(const QMetaMethod &method, list) { 0346 KDbRecordData *newData = d->signalsColumnData->createItem(); 0347 (*newData )[0] = QString::fromLatin1(method.signature()); 0348 (*newData )[1] = (*newData )[0]; 0349 d->signalsColumnData->append(newData ); 0350 } 0351 } 0352 0353 void 0354 ConnectionDialog::checkConnection(KDbRecordData *data) 0355 { 0356 // First we check if one column is empty 0357 for (int i = 1; i < 5; i++) { 0358 if (!data || (*data)[i].toString().isEmpty()) { 0359 setStatusError(xi18n("You have not selected item: <resource>%1</resource>.", 0360 d->data->column(i)->captionAliasOrName()), data); 0361 return; 0362 } 0363 } 0364 0365 // Then we check if signal/slot args are compatible 0366 QString signal = (*data)[2].toString(); 0367 signal.remove(QRegularExpression(".*[(]|[)]")); // just keep the args list 0368 QString slot = (*data)[4].toString(); 0369 slot.remove(QRegularExpression(".*[(]|[)]")); 0370 0371 if (!signal.startsWith(slot, Qt::CaseSensitive)) { 0372 setStatusError(xi18n("The signal/slot arguments are not compatible."), data); 0373 return; 0374 } 0375 0376 setStatusOk(data); 0377 } 0378 0379 void 0380 ConnectionDialog::newItem() 0381 { 0382 d->table->acceptRecordEditing(); 0383 d->table->setCursorPosition(d->table->rows(), 1); 0384 } 0385 0386 void 0387 ConnectionDialog::newItemByDragnDrop() 0388 { 0389 d->form->enterConnectingState(); 0390 connect(d->form, SIGNAL(connectionAborted(KFormDesigner::Form*)), 0391 this, SLOT(slotConnectionAborted(KFormDesigner::Form*))); 0392 connect(d->form, SIGNAL(connectionCreated(KFormDesigner::Form*,Connection&)), 0393 this, SLOT(slotConnectionCreated(KFormDesigner::Form*,Connection&))); 0394 0395 hide(); 0396 } 0397 0398 void 0399 ConnectionDialog::slotConnectionCreated(KFormDesigner::Form *form, Connection &connection) 0400 { 0401 show(); 0402 if (form != d->form) 0403 return; 0404 0405 Connection *c = new Connection(connection); 0406 KDbRecordData *newData = d->table->data()->createItem(); 0407 (*newData)[1] = c->sender(); 0408 (*newData)[2] = c->signal(); 0409 (*newData)[3] = c->receiver(); 0410 (*newData)[4] = c->slot(); 0411 d->table->insertItem(newData, d->table->rows()); 0412 d->buffer->append(c); 0413 } 0414 0415 void 0416 ConnectionDialog::slotConnectionAborted(KFormDesigner::Form *form) 0417 { 0418 show(); 0419 if (form != d->form) 0420 return; 0421 0422 newItem(); 0423 } 0424 0425 void 0426 ConnectionDialog::removeItem() 0427 { 0428 if (d->table->currentRow() == -1 || d->table->currentRow() >= d->table->rows()) 0429 return; 0430 0431 if (KMessageBox::Yes != KMessageBox::questionYesNo(parentWidget(), 0432 xi18n("Do you want to delete this connection?"), 0433 QString(), 0434 KGuiItem(xi18nc("@action:button", "&Delete Connection")), 0435 KStandardGuiItem::no(), 0436 "AskBeforeDeleteConnection"/*config entry*/, 0437 KMessageBox::Notify | KMessageBox::Dangerous)) 0438 { 0439 return; 0440 } 0441 d->buffer->removeAt(d->table->currentRow()); 0442 d->table->deleteItem(d->table->selectedItem()); 0443 } 0444 0445 //! @todo KEXI3 noi18n # added to disable message extraction in Messages.sh