You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
koffice/kexi/formeditor/connectiondialog.cpp

421 lines
12 KiB

/* This file is part of the KDE project
Copyright (C) 2004 Cedric Pasteur <cedric.pasteur@free.fr>
Copyright (C) 2004 Jaroslaw Staniek <js@iidea.pl>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public License
along with this library; see the file COPYING.LIB. If not, write to
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#include <tqlayout.h>
#include <tqhbox.h>
#include <tqlabel.h>
#include <tqregexp.h>
#include <tqmetaobject.h>
#include <tqstrlist.h>
#include <kpushbutton.h>
#include <kiconloader.h>
#include <tdemessagebox.h>
#include <kdebug.h>
#include <tdelocale.h>
#include "kexitableview.h"
#include "kexitableviewdata.h"
#include "events.h"
#include "form.h"
#include "formmanager.h"
#include "objecttree.h"
#include "connectiondialog.h"
namespace KFormDesigner {
/////////////////////////////////////////////////////////////////////////////////
///////////// The dialog to edit or add/remove connections //////////////////////
/////////////////////////////////////////////////////////////////////////////////
ConnectionDialog::ConnectionDialog(TQWidget *parent)
: KDialogBase(parent, "connections_dialog", true, i18n("Edit Form Connections"),
Ok|Cancel|Details, Ok, false)
, m_buffer(0)
{
TQFrame *frame = makeMainWidget();
TQHBoxLayout *layout = new TQHBoxLayout(frame, 0, 6);
// Setup the details widget /////////
TQHBox *details = new TQHBox(frame);
setDetailsWidget(details);
setDetails(true);
m_pixmapLabel = new TQLabel(details);
m_pixmapLabel->setFixedWidth( int(IconSize(TDEIcon::Desktop) * 1.5) );
m_pixmapLabel->setAlignment(AlignHCenter | AlignTop);
m_textLabel = new TQLabel(details);
m_textLabel->setAlignment(AlignLeft | AlignTop);
//setStatusOk();
// And the KexiTableView ////////
m_data = new KexiTableViewData();
m_table = new KexiTableView(0, frame, "connections_tableview");
m_table->setSpreadSheetMode();
m_table->setInsertingEnabled(true);
initTable();
m_table->setData(m_data, false);
m_table->adjustColumnWidthToContents(0);
layout->addWidget(m_table);
//// Setup the icon toolbar /////////////////
TQVBoxLayout *vlayout = new TQVBoxLayout(layout, 3);
KPushButton *newItem = new KPushButton(SmallIconSet("document-new"), i18n("&New Connection"), frame);
vlayout->addWidget(newItem);
m_buttons.insert(BAdd, newItem);
connect(newItem, TQT_SIGNAL(clicked()), this, TQT_SLOT(newItem()));
KPushButton *delItem = new KPushButton(SmallIconSet("edit-delete"), i18n("&Remove Connection"), frame);
vlayout->addWidget(delItem);
m_buttons.insert(BRemove, delItem);
connect(delItem, TQT_SIGNAL(clicked()), this, TQT_SLOT(removeItem()));
vlayout->addStretch();
setInitialSize(TQSize(600, 300));
//setWFlags(WDestructiveClose);
connect(m_table,TQT_SIGNAL(cellSelected(int, int)), this, TQT_SLOT(slotCellSelected(int, int)));
connect(m_table->KexiDataAwareObjectInterface::data(), TQT_SIGNAL(rowInserted(KexiTableItem*,bool)), this, TQT_SLOT(slotRowInserted(KexiTableItem*,bool)));
this->newItem();
}
void
ConnectionDialog::initTable()
{
KexiTableViewColumn *col0 = new KexiTableViewColumn(i18n("OK?"), KexiDB::Field::Text);
col0->field()->setSubType("TDEIcon");
col0->setReadOnly(true);
col0->field()->setDescription(i18n("Connection correctness"));
m_data->addColumn(col0);
KexiTableViewColumn *col1 = new KexiTableViewColumn(i18n("Sender"), KexiDB::Field::Enum);
m_widgetsColumnData = new KexiTableViewData(KexiDB::Field::Text, KexiDB::Field::Text);
col1->setRelatedData( m_widgetsColumnData );
m_data->addColumn(col1);
KexiTableViewColumn *col2 = new KexiTableViewColumn(i18n("Signal"), KexiDB::Field::Enum);
m_signalsColumnData = new KexiTableViewData(KexiDB::Field::Text, KexiDB::Field::Text);
col2->setRelatedData( m_signalsColumnData );
m_data->addColumn(col2);
KexiTableViewColumn *col3 = new KexiTableViewColumn(i18n("Receiver"), KexiDB::Field::Enum);
col3->setRelatedData( m_widgetsColumnData );
m_data->addColumn(col3);
KexiTableViewColumn *col4 = new KexiTableViewColumn(i18n("Slot"), KexiDB::Field::Enum);
m_slotsColumnData = new KexiTableViewData(KexiDB::Field::Text, KexiDB::Field::Text);
col4->setRelatedData( m_slotsColumnData );
m_data->addColumn(col4);
TQValueList<int> c;
c << 2 << 4;
m_table->maximizeColumnsWidth(c);
m_table->setColumnStretchEnabled( true, 4 );
connect(m_data, TQT_SIGNAL(aboutToChangeCell(KexiTableItem*, int, TQVariant&, KexiDB::ResultInfo*)),
this,TQT_SLOT(slotCellChanged(KexiTableItem*, int, TQVariant, KexiDB::ResultInfo*)));
connect(m_data, TQT_SIGNAL(rowUpdated(KexiTableItem*)), this, TQT_SLOT(checkConnection(KexiTableItem *)));
connect(m_table, TQT_SIGNAL(itemSelected(KexiTableItem *)), this, TQT_SLOT(checkConnection(KexiTableItem *)));
}
void
ConnectionDialog::exec(Form *form)
{
m_form = form;
updateTableData();
KDialogBase::exec();
}
void ConnectionDialog::slotCellSelected(int col, int row)
{
m_buttons[BRemove]->setEnabled( row < m_table->rows() );
KexiTableItem *item = m_table->itemAt(row);
if (!item)
return;
if(col == 2) // signal col
updateSignalList(item);
else if(col == 4) // slot col
updateSlotList(item);
}
void ConnectionDialog::slotRowInserted(KexiTableItem* item,bool)
{
m_buffer->append(new Connection());
checkConnection( item );
}
void
ConnectionDialog::slotOk()
{
// First we update our buffer contents
for(int i=0; i < m_table->rows(); i++)
{
KexiTableItem *item = m_table->itemAt(i);
Connection *c = m_buffer->at(i);
c->setSender( (*item)[1].toString() );
c->setSignal( (*item)[2].toString() );
c->setReceiver( (*item)[3].toString() );
c->setSlot( (*item)[4].toString() );
}
// then me make it replace form's current one
delete m_form->connectionBuffer();
m_form->setConnectionBuffer(m_buffer);
TQDialog::accept();
}
void
ConnectionDialog::updateTableData()
{
// First we update the columns data
ObjectTreeDict *dict = new ObjectTreeDict( *(m_form->objectTree()->dict()) );
ObjectTreeDictIterator it(*dict);
for(; it.current(); ++it)
{
KexiTableItem *item = m_widgetsColumnData->createItem(); //new KexiTableItem(2);
(*item)[0] = it.current()->name();
(*item)[1] = (*item)[0];
m_widgetsColumnData->append(item);
}
delete dict;
// Then we fill the columns with the form connections
for(Connection *c = m_form->connectionBuffer()->first(); c ; c = m_form->connectionBuffer()->next())
{
KexiTableItem *item = m_table->KexiDataAwareObjectInterface::data()->createItem(); //new KexiTableItem(5);
(*item)[1] = c->sender();
(*item)[2] = c->signal();
(*item)[3] = c->receiver();
(*item)[4] = c->slot();
m_table->insertItem(item, m_table->rows());
}
m_buffer = new ConnectionBuffer(*(m_form->connectionBuffer()));
}
void
ConnectionDialog::setStatusOk(KexiTableItem *item)
{
m_pixmapLabel->setPixmap( DesktopIcon("button_ok") );
m_textLabel->setText("<qt><h2>The connection is OK.</h2></qt>");
if (!item)
item = m_table->selectedItem();
if (m_table->currentRow() >= m_table->rows())
item = 0;
if (item)
(*item)[0] = "button_ok";
else {
m_pixmapLabel->setPixmap( TQPixmap() );
m_textLabel->setText(TQString());
}
}
void
ConnectionDialog::setStatusError(const TQString &msg, KexiTableItem *item)
{
m_pixmapLabel->setPixmap( DesktopIcon("button_cancel") );
m_textLabel->setText("<qt><h2>The connection is invalid.</h2></qt>" + msg);
if (!item)
item = m_table->selectedItem();
if (m_table->currentRow() >= m_table->rows())
item = 0;
if (item)
(*item)[0] = "button_cancel";
else {
m_pixmapLabel->setPixmap( TQPixmap() );
m_textLabel->setText(TQString());
}
}
void
ConnectionDialog::slotCellChanged(KexiTableItem *item, int col, TQVariant&, KexiDB::ResultInfo*)
{
switch(col)
{
// sender changed, we clear siganl and slot
case 1:
(*item)[2] = TQString("");
// signal or receiver changed, we clear the slot cell
case 2:
case 3:
{
(*item)[4] = TQString("");
break;
}
default:
break;
}
}
void
ConnectionDialog::updateSlotList(KexiTableItem *item)
{
m_slotsColumnData->deleteAllRows();
TQString widget = (*item)[1].toString();
TQString signal = (*item)[2].toString();
if((widget.isEmpty()) || signal.isEmpty())
return;
ObjectTreeItem *tree = m_form->objectTree()->lookup(widget);
if(!tree || !tree->widget())
return;
TQString signalArg(signal);
signalArg = signalArg.remove( TQRegExp(".*[(]|[)]") );
TQStrList slotList = tree->widget()->metaObject()->slotNames(true);
TQStrListIterator it(slotList);
for(; it.current() != 0; ++it)
{
// we add the slot only if it is compatible with the signal
TQString slotArg(*it);
slotArg = slotArg.remove( TQRegExp(".*[(]|[)]") );
if(!signalArg.startsWith(slotArg, true) && (!signal.isEmpty())) // args not compatible
continue;
KexiTableItem *item = m_slotsColumnData->createItem(); //new KexiTableItem(2);
(*item)[0] = TQString(*it);
(*item)[1] = (*item)[0];
m_slotsColumnData->append(item);
}
}
void
ConnectionDialog::updateSignalList(KexiTableItem *item)
{
ObjectTreeItem *tree = m_form->objectTree()->lookup((*item)[1].toString());
if(!tree || !tree->widget())
return;
m_signalsColumnData->deleteAllRows();
TQStrList signalList = tree->widget()->metaObject()->signalNames(true);
TQStrListIterator it(signalList);
for(; it.current() != 0; ++it)
{
KexiTableItem *item = m_signalsColumnData->createItem(); //new KexiTableItem(2);
(*item)[0] = TQString(*it);
(*item)[1] = (*item)[0];
m_signalsColumnData->append(item);
}
}
void
ConnectionDialog::checkConnection(KexiTableItem *item)
{
// First we check if one column is empty
for(int i = 1; i < 5; i++)
{
if( !item || (*item)[i].toString().isEmpty())
{
setStatusError( i18n("<qt>You have not selected item: <b>%1</b>.</qt>").arg(m_data->column(i)->captionAliasOrName()),
item);
return;
}
}
// Then we check if signal/slot args are compatible
TQString signal = (*item)[2].toString();
signal = signal.remove( TQRegExp(".*[(]|[)]") ); // just keep the args list
TQString slot = (*item)[4].toString();
slot = slot.remove( TQRegExp(".*[(]|[)]") );
if(!signal.startsWith(slot, true))
{
setStatusError( i18n("The signal/slot arguments are not compatible."), item);
return;
}
setStatusOk(item);
}
void
ConnectionDialog::newItem()
{
m_table->acceptRowEdit();
m_table->setCursorPosition(m_table->rows(), 1);
}
void
ConnectionDialog::newItemByDragnDrop()
{
KFormDesigner::FormManager::self()->startCreatingConnection();
connect(KFormDesigner::FormManager::self(), TQT_SIGNAL(connectionAborted(KFormDesigner::Form*)), this, TQT_SLOT(slotConnectionAborted(KFormDesigner::Form*)));
connect(KFormDesigner::FormManager::self(), TQT_SIGNAL(connectionCreated(KFormDesigner::Form*, Connection&)), this, TQT_SLOT(slotConnectionCreated(KFormDesigner::Form*, Connection&)) );
hide();
}
void
ConnectionDialog::slotConnectionCreated(KFormDesigner::Form *form, Connection &connection)
{
show();
if(form != m_form)
return;
Connection *c = new Connection(connection);
KexiTableItem *item = m_table->KexiDataAwareObjectInterface::data()->createItem(); //new KexiTableItem(5);
(*item)[1] = c->sender();
(*item)[2] = c->signal();
(*item)[3] = c->receiver();
(*item)[4] = c->slot();
m_table->insertItem(item, m_table->rows());
m_buffer->append(c);
}
void
ConnectionDialog::slotConnectionAborted(KFormDesigner::Form *form)
{
show();
if(form != m_form)
return;
newItem();
}
void
ConnectionDialog::removeItem()
{
if(m_table->currentRow() == -1 || m_table->currentRow()>=m_table->rows())
return;
int confirm = KMessageBox::warningContinueCancel(parentWidget(),
TQString("<qt>")+i18n("Do you want to delete this connection ?")+"</qt>", TQString(), KGuiItem(i18n("&Delete Connection")),
"dontAskBeforeDeleteConnection"/*config entry*/);
if(confirm == KMessageBox::Cancel)
return;
m_buffer->remove(m_table->currentRow());
m_table->deleteItem(m_table->selectedItem());
}
}
#include "connectiondialog.moc"