diff --git a/src/widget/KexiNameWidget.cpp b/src/widget/KexiNameWidget.cpp index 0e9199137..116c8e621 100644 --- a/src/widget/KexiNameWidget.cpp +++ b/src/widget/KexiNameWidget.cpp @@ -1,309 +1,308 @@ /* This file is part of the KDE project Copyright (C) 2004 Jarosław Staniek 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 "KexiNameWidget.h" #include #include #include #include #include #include #include #include class Q_DECL_HIDDEN KexiNameWidget::Private { public: Private() {} QLabel* lbl_message; QLabel* lbl_caption; QLabel* lbl_name; QLineEdit* le_caption; QLineEdit* le_name; QGridLayout* lyr; KDbMultiValidator *validator; QString nameWarning, captionWarning; QString originalNameText; bool le_name_txtchanged_disable; bool le_name_autofill; bool caption_required; }; KexiNameWidget::KexiNameWidget(const QString& message, QWidget* parent) : QWidget(parent) , d(new Private) { init(message, QString(), QString(), QString(), QString()); } KexiNameWidget::KexiNameWidget(const QString& message, const QString& nameLabel, const QString& nameText, const QString& captionLabel, const QString& captionText, QWidget * parent) : QWidget(parent) , d(new Private) { init(message, nameLabel, nameText, captionLabel, captionText); } void KexiNameWidget::init( const QString& message, const QString& nameLabel, const QString& nameText, const QString& captionLabel, const QString& captionText) { Q_UNUSED(captionText); setObjectName("KexiNameWidget"); d->le_name_txtchanged_disable = false; d->le_name_autofill = true; d->caption_required = false; d->lyr = new QGridLayout(this); d->lbl_message = new QLabel(this); setMessageText(message); d->lbl_message->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed); d->lbl_message->setAlignment(Qt::AlignTop|Qt::AlignLeft); d->lbl_message->setWordWrap(true); d->lbl_message->setTextInteractionFlags(Qt::TextBrowserInteraction); d->lyr->addWidget(d->lbl_message, 0, 0, 1, 2); d->lbl_caption = new QLabel(captionLabel.isEmpty() ? xi18n("Caption:") : captionLabel, this); d->lbl_caption->setAlignment(Qt::AlignVCenter|Qt::AlignRight); d->lyr->addWidget(d->lbl_caption, 1, 0); d->lbl_name = new QLabel(nameLabel.isEmpty() ? xi18n("Name:") : nameLabel, this); d->lbl_name->setAlignment(Qt::AlignVCenter|Qt::AlignRight); d->lyr->addWidget(d->lbl_name, 2, 0); d->le_caption = new QLineEdit(this); setCaptionText(nameText); QSizePolicy le_captionSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed); le_captionSizePolicy.setHorizontalStretch(1); d->le_caption->setSizePolicy(le_captionSizePolicy); d->le_caption->setClearButtonEnabled(true); d->lyr->addWidget(d->le_caption, 1, 1); d->le_name = new QLineEdit(this); setNameText(nameText); - QSizePolicy le_nameSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed); le_captionSizePolicy.setHorizontalStretch(1); d->le_name->setSizePolicy(le_captionSizePolicy); d->le_name->setClearButtonEnabled(true); KDbIdentifierValidator *idValidator = new KDbIdentifierValidator(0); idValidator->setLowerCaseForced(true); d->le_name->setValidator(d->validator = new KDbMultiValidator(idValidator, this)); d->lyr->addWidget(d->le_name, 2, 1); setFocusProxy(d->le_caption); resize(QSize(342, 123).expandedTo(minimumSizeHint())); d->nameWarning = xi18n("Please enter the name."); d->captionWarning = xi18n("Please enter the caption."); connect(d->le_caption, SIGNAL(textChanged(QString)), this, SLOT(slotCaptionTextChanged(QString))); connect(d->le_name, SIGNAL(textChanged(QString)), this, SLOT(slotNameTextChanged(QString))); connect(d->le_caption, SIGNAL(returnPressed()), this, SIGNAL(returnPressed())); connect(d->le_name, SIGNAL(returnPressed()), this, SIGNAL(returnPressed())); } KexiNameWidget::~KexiNameWidget() { delete d; } QLabel* KexiNameWidget::captionLabel() const { return d->lbl_caption; } QLabel* KexiNameWidget::nameLabel() const { return d->lbl_name; } QLineEdit* KexiNameWidget::captionLineEdit() const { return d->le_caption; } QLineEdit* KexiNameWidget::nameLineEdit() const { return d->le_name; } QLabel* KexiNameWidget::messageLabel() const { return d->lbl_message; } QString KexiNameWidget::messageText() const { return d->lbl_message->text(); } void KexiNameWidget::slotCaptionTextChanged(const QString &capt) { emit textChanged(); if (d->le_name->text().isEmpty()) d->le_name_autofill = true; if (d->le_name_autofill) { d->le_name_txtchanged_disable = true; d->le_name->setText(KDb::stringToIdentifier(capt).toLower()); d->le_name_txtchanged_disable = false; } } void KexiNameWidget::slotNameTextChanged(const QString &) { emit textChanged(); if (d->le_name_txtchanged_disable) return; d->le_name_autofill = false; } void KexiNameWidget::clear() { d->le_name->clear(); d->le_caption->clear(); } bool KexiNameWidget::empty() const { return d->le_name->text().isEmpty() || d->le_caption->text().trimmed().isEmpty(); } void KexiNameWidget::setNameRequired(bool set) { d->validator->setAcceptsEmptyValue(!set); } bool KexiNameWidget::isCaptionRequired() const { return d->caption_required; } void KexiNameWidget::setCaptionRequired(bool set) { d->caption_required = set; } bool KexiNameWidget::isNameRequired() const { return !d->validator->acceptsEmptyValue(); } void KexiNameWidget::setCaptionText(const QString& capt) { d->le_caption->setText(capt); d->le_name_autofill = true; } void KexiNameWidget::setNameText(const QString& name) { d->le_name->setText(name); d->originalNameText = name; d->le_name_autofill = true; } void KexiNameWidget::setWarningForName(const QString& txt) { d->nameWarning = txt; } void KexiNameWidget::setWarningForCaption(const QString& txt) { d->captionWarning = txt; } void KexiNameWidget::setMessageText(const QString& msg) { if (msg.trimmed().isEmpty()) { d->lbl_message->setText(QString()); d->lbl_message->hide(); } else { d->lbl_message->setText(msg.trimmed() + "
"); d->lbl_message->show(); } messageChanged(); } QString KexiNameWidget::captionText() const { return d->le_caption->text().trimmed(); } QString KexiNameWidget::nameText() const { return d->le_name->text().trimmed(); } QString KexiNameWidget::originalNameText() const { return d->originalNameText; } bool KexiNameWidget::checkValidity() { if (isNameRequired() && d->le_name->text().trimmed().isEmpty()) { KMessageBox::sorry(0, d->nameWarning); d->le_name->setFocus(); return false; } if (isCaptionRequired() && d->le_caption->text().trimmed().isEmpty()) { KMessageBox::sorry(0, d->captionWarning); d->le_caption->setFocus(); return false; } QString dummy, message, details; if (d->validator->check(dummy, d->le_name->text(), &message, &details) == KDbValidator::Error) { KMessageBox::detailedSorry(0, message, details); d->le_name->setFocus(); return false; } return true; } KDbValidator *KexiNameWidget::nameValidator() const { return d->validator; } void KexiNameWidget::addNameSubvalidator(KDbValidator* validator, bool owned) { d->validator->addSubvalidator(validator, owned); } diff --git a/src/widget/tableview/kexiblobtableedit.cpp b/src/widget/tableview/kexiblobtableedit.cpp index d14483c16..d24c44a7a 100644 --- a/src/widget/tableview/kexiblobtableedit.cpp +++ b/src/widget/tableview/kexiblobtableedit.cpp @@ -1,603 +1,602 @@ /* This file is part of the KDE project Copyright (C) 2002 Peter Simonsson Copyright (C) 2004, 2006 Jarosław Staniek 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 "kexiblobtableedit.h" #include "KexiTableScrollArea.h" #include "KexiTableScrollAreaWidget.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include struct PixmapAndPos { QPixmap pixmap; QPoint pos; }; //! @internal class Q_DECL_HIDDEN KexiBlobTableEdit::Private { public: Private() : menu(0) , readOnly(false) , setValueInternalEnabled(true) { } QByteArray value; KexiDropDownButton *button; QSize totalSize; KexiImageContextMenu *menu; bool readOnly; //!< cached for slotUpdateActionsAvailabilityRequested() bool setValueInternalEnabled; //!< used to disable KexiBlobTableEdit::setValueInternal() QCache cachedPixmaps; }; //====================================================== KexiBlobTableEdit::KexiBlobTableEdit(KDbTableViewColumn *column, QWidget *parent) : KexiTableEdit(column, parent) , d(new Private()) { KexiDataItemInterface::setHasFocusableWidget(false); d->button = new KexiDropDownButton(parentWidget() /*usually a viewport*/); d->button->hide(); d->button->setToolTip(xi18n("Click to show available actions for this cell")); d->menu = new KexiImageContextMenu(this); d->menu->installEventFilter(this); if (column->columnInfo()) KexiImageContextMenu::updateTitle(d->menu, column->columnInfo()->captionOrAliasOrName(), //! @todo pixmaplabel icon is hardcoded... KexiIconName("imagebox")); d->button->setMenu(d->menu); connect(d->menu, SIGNAL(updateActionsAvailabilityRequested(bool*,bool*)), this, SLOT(slotUpdateActionsAvailabilityRequested(bool*,bool*))); connect(d->menu, SIGNAL(insertFromFileRequested(QUrl)), this, SLOT(handleInsertFromFileAction(QUrl))); connect(d->menu, SIGNAL(saveAsRequested(QString)), this, SLOT(handleSaveAsAction(QString))); connect(d->menu, SIGNAL(cutRequested()), this, SLOT(handleCutAction())); connect(d->menu, SIGNAL(copyRequested()), this, SLOT(handleCopyAction())); connect(d->menu, SIGNAL(pasteRequested()), this, SLOT(handlePasteAction())); connect(d->menu, SIGNAL(clearRequested()), this, SLOT(clear())); connect(d->menu, SIGNAL(showPropertiesRequested()), this, SLOT(handleShowPropertiesAction())); } KexiBlobTableEdit::~KexiBlobTableEdit() { delete d; #if 0 qDebug() << "Cleaning up..."; if (m_tempFile) { m_tempFile->unlink(); //! @todo } delete m_proc; m_proc = 0; qDebug() << "Ready."; #endif } //! initializes this editor with \a add value void KexiBlobTableEdit::setValueInternal(const QVariant& add, bool removeOld) { if (!d->setValueInternalEnabled) return; if (removeOld) d->value = add.toByteArray(); else //do not add "m_origValue" to "add" as this is QByteArray d->value = KexiDataItemInterface::originalValue().toByteArray(); //! @todo #if 0 //todo? QByteArray val = m_origValue.toByteArray(); qDebug() << "Size of BLOB:" << val.size(); m_tempFile = new QTemporaryFile(); m_tempFile->open(); qDebug() << "Creating temporary file:" << m_tempFile->fileName(); QDataStream stream(m_tempFile); stream->writeRawBytes(val.data(), val.size()); delete m_tempFile; m_tempFile = 0; KMimeMagicResult* mmr = KMimeMagic::self()->findFileType(m_tempFile->fileName()); qDebug() << "Mimetype=" << mmr->mimeType(); setViewWidget(new QWidget(this)); #endif } bool KexiBlobTableEdit::valueIsNull() { //! @todo return d->value.isEmpty(); } bool KexiBlobTableEdit::valueIsEmpty() { //! @todo return d->value.isEmpty(); } QVariant KexiBlobTableEdit::value() { return d->value; //! @todo #if 0 if (m_content && m_content->isModified()) { return QVariant(m_content->text()); } QByteArray value; QFile f(m_tempFile->fileName()); f.open(QIODevice::ReadOnly); QDataStream stream(&f); char* data = (char*) malloc(f.size()); value.resize(f.size()); stream.readRawBytes(data, f.size()); value.duplicate(data, f.size()); free(data); qDebug() << "Size of BLOB:" << value.size(); return QVariant(value); #endif } void KexiBlobTableEdit::paintFocusBorders(QPainter *p, QVariant &, int x, int y, int w, int h) { p->drawRect(x, y, w, h); } void KexiBlobTableEdit::setupContents(QPainter *p, bool focused, const QVariant& val, QString &txt, int &align, int &x, int &y_offset, int &w, int &h) { Q_UNUSED(focused); Q_UNUSED(txt); Q_UNUSED(align); - QPoint pos; PixmapAndPos *pp = 0; x = 0; w -= 1; //a place for border h -= 1; //a place for border if (p) { const QByteArray array(val.toByteArray()); //! @todo optimize: keep this checksum in context of data //! @todo optimize: for now 100 items are cached; set proper cache size, e.g. based on the number of blob items visible on screen // the key is unique for this tuple: (checksum, w, h) qulonglong sum((((qulonglong(qChecksum(array.constData(), array.length())) << 32) + w) << 16) + h); pp = d->cachedPixmaps.object(sum); bool insertToCache = false; if (!pp) { QPixmap pixmap; if (val.canConvert(QVariant::ByteArray) && KexiUtils::loadPixmapFromData(&pixmap, val.toByteArray())) { #if 0 KexiUtils::drawPixmap(*p, QMargins()/*lineWidth*/, QRect(x, y_offset, w, h), pixmap, Qt::AlignCenter, true/*scaledContents*/, true/*keepAspectRatio*/); #endif QPoint pos; pixmap = KexiUtils::scaledPixmap(QMargins()/*lineWidth*/, QRect(x, y_offset, w, h), pixmap, &pos, Qt::AlignCenter, true/*scaledContents*/, true/*keepAspectRatio*/, Qt::SmoothTransformation); if (!pixmap.isNull()) { pp = new PixmapAndPos; pp->pixmap = pixmap; pp->pos = pos; insertToCache = true; } } } if (pp) { p->drawPixmap(pp->pos, pp->pixmap); } if (insertToCache) { // Do that afterwards because in theory QCache can delete pp immediately (COVERITY CID #1354236) //! @todo use cost other than 1 d->cachedPixmaps.insert(sum, pp); } } } bool KexiBlobTableEdit::cursorAtStart() { return true; } bool KexiBlobTableEdit::cursorAtEnd() { return true; } void KexiBlobTableEdit::handleInsertFromFileAction(const QUrl &url) { if (isReadOnly()) return; QString fileName(url.isLocalFile() ? url.toLocalFile() : url.toDisplayString()); //! @todo download the file if remote, then set fileName properly QFile f(fileName); if (!f.open(QIODevice::ReadOnly)) { //! @todo err msg return; } QByteArray ba = f.readAll(); if (f.error() != QFile::NoError) { //! @todo err msg f.close(); return; } f.close(); setValueInternal(ba, true); signalEditRequested(); //emit acceptRequested(); } void KexiBlobTableEdit::handleAboutToSaveAsAction(QString *origFilename, QString *mimeType, bool *dataIsEmpty) { Q_ASSERT(origFilename); Q_ASSERT(mimeType); Q_ASSERT(dataIsEmpty); Q_UNUSED(origFilename); Q_UNUSED(mimeType); *dataIsEmpty = valueIsEmpty(); //! @todo no fname stored for now } void KexiBlobTableEdit::handleSaveAsAction(const QString& fileName) { QFile f(fileName); if (!f.open(QIODevice::WriteOnly)) { //! @todo err msg return; } f.write(d->value); if (f.error() != QFile::NoError) { //! @todo err msg f.close(); return; } f.close(); } void KexiBlobTableEdit::handleCutAction() { if (isReadOnly()) return; handleCopyAction(); clear(); } void KexiBlobTableEdit::handleCopyAction() { executeCopyAction(d->value); } void KexiBlobTableEdit::executeCopyAction(const QByteArray& data) { QPixmap pixmap; if (!KexiUtils::loadPixmapFromData(&pixmap, data)) { return; } qApp->clipboard()->setPixmap(pixmap, QClipboard::Clipboard); } void KexiBlobTableEdit::handlePasteAction() { if (isReadOnly()) return; QPixmap pm(qApp->clipboard()->pixmap(QClipboard::Clipboard)); QByteArray ba; QBuffer buffer(&ba); buffer.open(QIODevice::WriteOnly); if (pm.save(&buffer, "PNG")) { // write pixmap into ba in PNG format setValueInternal(ba, true); } else { setValueInternal(QByteArray(), true); } signalEditRequested(); repaintRelatedCell(); } void KexiBlobTableEdit::clear() { setValueInternal(QByteArray(), true); signalEditRequested(); //emit acceptRequested(); repaintRelatedCell(); } void KexiBlobTableEdit::handleShowPropertiesAction() { //! @todo } void KexiBlobTableEdit::showFocus(const QRect& r, bool readOnly) { d->readOnly = readOnly; //cache for slotUpdateActionsAvailabilityRequested() updateFocus(r); if (d->readOnly) d->button->hide(); else d->button->show(); } void KexiBlobTableEdit::resize(int w, int h) { d->totalSize = QSize(w, h); const int addWidth = d->readOnly ? 0 : d->button->width(); QWidget::resize(w - addWidth, h); if (!d->readOnly) d->button->resize(h, h); m_rightMarginWhenFocused = m_rightMargin + addWidth; QRect r(pos().x(), pos().y(), w + 1, h + 1); r.translate(qobject_cast(parentWidget())->scrollArea->horizontalScrollBar()->value(), qobject_cast(parentWidget())->scrollArea->verticalScrollBar()->value()); updateFocus(r); /*! @todo if (d->menu) { d->menu->updateSize(); }*/ } void KexiBlobTableEdit::updateFocus(const QRect& r) { if (!d->readOnly) { if (d->button->width() > r.width()) moveChild(d->button, r.right() + 1, r.top()); else moveChild(d->button, r.right() - d->button->width(), r.top()); } } void KexiBlobTableEdit::hideFocus() { d->button->hide(); } QSize KexiBlobTableEdit::totalSize() const { return d->totalSize; } void KexiBlobTableEdit::slotUpdateActionsAvailabilityRequested(bool *valueIsNull, bool *valueIsReadOnly) { Q_ASSERT(valueIsNull); Q_ASSERT(valueIsReadOnly); emit editRequested(); *valueIsNull = this->valueIsNull(); *valueIsReadOnly = d->readOnly || isReadOnly(); } void KexiBlobTableEdit::signalEditRequested() { d->setValueInternalEnabled = false; emit editRequested(); d->setValueInternalEnabled = true; } bool KexiBlobTableEdit::handleKeyPress(QKeyEvent* ke, bool editorActive) { Q_UNUSED(editorActive); const int k = ke->key(); if (!d->readOnly) { if ((ke->modifiers() == Qt::NoButton && k == Qt::Key_F4) || (ke->modifiers() == Qt::AltModifier && k == Qt::Key_Down)) { d->button->animateClick(); QMouseEvent me(QEvent::MouseButtonPress, QPoint(2, 2), Qt::LeftButton, Qt::NoButton, Qt::NoModifier); QApplication::sendEvent(d->button, &me); } else if (ke->modifiers() == Qt::NoModifier && (k == Qt::Key_F2 || k == Qt::Key_Space || k == Qt::Key_Enter || k == Qt::Key_Return)) { d->menu->insertFromFile(); } else return false; } else return false; return true; } bool KexiBlobTableEdit::handleDoubleClick() { d->menu->insertFromFile(); return true; } void KexiBlobTableEdit::handleCopyAction(const QVariant& value, const QVariant& visibleValue) { Q_UNUSED(visibleValue); executeCopyAction(value.toByteArray()); } void KexiBlobTableEdit::handleAction(const QString& actionName) { if (actionName == "edit_paste") { d->menu->paste(); } else if (actionName == "edit_cut") { emit editRequested(); d->menu->cut(); } } bool KexiBlobTableEdit::eventFilter(QObject *o, QEvent *e) { if (o == d->menu && e->type() == QEvent::KeyPress) { QKeyEvent* ke = static_cast(e); const Qt::KeyboardModifiers mods = ke->modifiers(); const int k = ke->key(); if ((mods == Qt::NoModifier && (k == Qt::Key_Tab || k == Qt::Key_Left || k == Qt::Key_Right)) || (mods == Qt::ShiftModifier && k == Qt::Key_Backtab) ) { d->menu->hide(); QApplication::sendEvent(this, ke); //re-send to move cursor return true; } } return false; } KEXI_CELLEDITOR_FACTORY_ITEM_IMPL(KexiBlobEditorFactoryItem, KexiBlobTableEdit) //======================= // KexiKIconTableEdit class is temporarily here: //! @internal class Q_DECL_HIDDEN KexiKIconTableEdit::Private { public: Private() : pixmapCache(17) { } //! We've no editor widget that would store current value, so we do this here QVariant currentValue; QCache pixmapCache; }; KexiKIconTableEdit::KexiKIconTableEdit(KDbTableViewColumn *column, QWidget *parent) : KexiTableEdit(column, parent) , d(new Private()) { init(); } KexiKIconTableEdit::~KexiKIconTableEdit() { delete d; } void KexiKIconTableEdit::init() { KexiDataItemInterface::setHasFocusableWidget(false); } void KexiKIconTableEdit::setValueInternal(const QVariant& /*add*/, bool /*removeOld*/) { d->currentValue = KexiDataItemInterface::originalValue(); } bool KexiKIconTableEdit::valueIsNull() { return d->currentValue.isNull(); } bool KexiKIconTableEdit::valueIsEmpty() { return d->currentValue.isNull(); } QVariant KexiKIconTableEdit::value() { return d->currentValue; } void KexiKIconTableEdit::clear() { d->currentValue = QVariant(); } bool KexiKIconTableEdit::cursorAtStart() { return true; } bool KexiKIconTableEdit::cursorAtEnd() { return true; } void KexiKIconTableEdit::setupContents(QPainter *p, bool /*focused*/, const QVariant& val, QString &/*txt*/, int &/*align*/, int &/*x*/, int &y_offset, int &w, int &h) { Q_UNUSED(y_offset); #if 0 #ifdef Q_OS_WIN y_offset = -1; #else y_offset = 0; #endif int s = qMax(h - 5, 12); s = qMin(h - 3, s); s = qMin(w - 3, s);//avoid too large box QRect r(qMax(w / 2 - s / 2, 0) , h / 2 - s / 2 /*- 1*/, s, s); p->setPen(QPen(colorGroup().text(), 1)); p->drawRect(r); if (val.asBool()) { p->drawLine(r.x(), r.y(), r.right(), r.bottom()); p->drawLine(r.x(), r.bottom(), r.right(), r.y()); } #endif QString key(val.toString()); QPixmap pm; if (!key.isEmpty()) { QPixmap *cached = d->pixmapCache[ key ]; if (cached) pm = *cached; if (pm.isNull()) { //cache pixmap pm = QIcon::fromTheme(key).pixmap(IconSize(KIconLoader::Small)); if (!pm.isNull()) d->pixmapCache.insert(key, new QPixmap(pm)); } } if (p && !pm.isNull()) p->drawPixmap((w - pm.width()) / 2, (h - pm.height()) / 2, pm); } void KexiKIconTableEdit::handleCopyAction(const QVariant& value, const QVariant& visibleValue) { Q_UNUSED(value); Q_UNUSED(visibleValue); } KEXI_CELLEDITOR_FACTORY_ITEM_IMPL(KexiKIconTableEditorFactoryItem, KexiKIconTableEdit)