/* This file is part of the KDE project Copyright (C) 2005 Cedric Pasteur Copyright (C) 2004-2007 Jaroslaw 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 "kexidbimagebox.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef TQ_WS_WIN #include #include #endif #include "kexidbutils.h" #include "../kexiformpart.h" static KStaticDeleter KexiDBImageBox_pmDeleter; static TQPixmap* KexiDBImageBox_pm = 0; static KStaticDeleter KexiDBImageBox_pmSmallDeleter; static TQPixmap* KexiDBImageBox_pmSmall = 0; KexiDBImageBox::KexiDBImageBox( bool designMode, TQWidget *parent, const char *name ) : KexiFrame( parent, name, TQt::WNoAutoErase ) , KexiFormDataItemInterface() , m_alignment(TQt::AlignAuto|TQt::AlignTop) , m_designMode(designMode) , m_readOnly(false) , m_scaledContents(false) , m_keepAspectRatio(true) , m_insideSetData(false) , m_setFocusOnButtonAfterClosingPopup(false) , m_lineWidthChanged(false) , m_paintEventEnabled(true) , m_dropDownButtonVisible(true) , m_insideSetPalette(false) { installEventFilter(this); setSizePolicy(TQSizePolicy::Expanding, TQSizePolicy::Preferred); //setup popup menu m_popupMenu = new KexiImageContextMenu(this); m_popupMenu->installEventFilter(this); if (m_designMode) { m_chooser = 0; } else { m_chooser = new KexiDropDownButton(this); m_chooser->setFocusPolicy(TQWidget::StrongFocus); m_chooser->setPopup(m_popupMenu); setFocusProxy(m_chooser); m_chooser->installEventFilter(this); // m_chooser->setPalette(tqApp->palette()); // hlyr->addWidget(m_chooser); } setBackgroundMode(TQt::NoBackground); setFrameShape(TQFrame::Box); setFrameShadow(TQFrame::Plain); setFrameColor(TQt::black); m_paletteBackgroundColorChanged = false; //set this here, not before connect(m_popupMenu, TQT_SIGNAL(updateActionsAvailabilityRequested(bool&, bool&)), this, TQT_SLOT(slotUpdateActionsAvailabilityRequested(bool&, bool&))); connect(m_popupMenu, TQT_SIGNAL(insertFromFileRequested(const KURL&)), this, TQT_SLOT(handleInsertFromFileAction(const KURL&))); connect(m_popupMenu, TQT_SIGNAL(saveAsRequested(const TQString&)), this, TQT_SLOT(handleSaveAsAction(const TQString&))); connect(m_popupMenu, TQT_SIGNAL(cutRequested()), this, TQT_SLOT(handleCutAction())); connect(m_popupMenu, TQT_SIGNAL(copyRequested()), this, TQT_SLOT(handleCopyAction())); connect(m_popupMenu, TQT_SIGNAL(pasteRequested()), this, TQT_SLOT(handlePasteAction())); connect(m_popupMenu, TQT_SIGNAL(clearRequested()), this, TQT_SLOT(clear())); connect(m_popupMenu, TQT_SIGNAL(showPropertiesRequested()), this, TQT_SLOT(handleShowPropertiesAction())); // connect(m_popupMenu, TQT_SIGNAL(aboutToHide()), this, TQT_SLOT(slotAboutToHidePopupMenu())); // if (m_chooser) { //we couldn't use m_chooser->setPopup() because of drawing problems // connect(m_chooser, TQT_SIGNAL(pressed()), this, TQT_SLOT(slotChooserPressed())); // connect(m_chooser, TQT_SIGNAL(released()), this, TQT_SLOT(slotChooserReleased())); // connect(m_chooser, TQT_SIGNAL(toggled(bool)), this, TQT_SLOT(slotToggled(bool))); // } setDataSource( TQString() ); //to initialize popup menu and actions availability } KexiDBImageBox::~KexiDBImageBox() { } KexiImageContextMenu* KexiDBImageBox::contextMenu() const { return m_popupMenu; } TQVariant KexiDBImageBox::value() { if (dataSource().isEmpty()) { //not db-aware return TQVariant(); } //db-aware mode return m_value; //todo //return TQVariant(); //todo } void KexiDBImageBox::setValueInternal( const TQVariant& add, bool removeOld, bool loadPixmap ) { if (isReadOnly()) return; m_popupMenu->hide(); if (removeOld) m_value = add.toByteArray(); else //do not add "m_origValue" to "add" as this is TQByteArray m_value = m_origValue.toByteArray(); bool ok = !m_value.isEmpty(); if (ok) { ///unused (m_valueMimeType is not available unless the px is inserted) TQString type( KImageIO::typeForMime(m_valueMimeType) ); ///ok = KImageIO::canRead( type ); ok = loadPixmap ? m_pixmap.loadFromData(m_value) : true; //, type.latin1()); if (!ok) { //! @todo inform about error? } } if (!ok) { m_valueMimeType = TQString(); m_pixmap = TQPixmap(); } repaint(); } void KexiDBImageBox::setInvalidState( const TQString& displayText ) { Q_UNUSED( displayText ); // m_pixmapLabel->setPixmap(TQPixmap()); if (!dataSource().isEmpty()) { m_value = TQByteArray(); } // m_pixmap = TQPixmap(); // m_originalFileName = TQString(); //! @todo m_pixmapLabel->setText( displayText ); if (m_chooser) m_chooser->hide(); setReadOnly(true); } bool KexiDBImageBox::valueIsNull() { return m_value.isEmpty(); // return !m_pixmapLabel->pixmap() || m_pixmapLabel->pixmap()->isNull(); } bool KexiDBImageBox::valueIsEmpty() { return false; } bool KexiDBImageBox::isReadOnly() const { return m_readOnly; } void KexiDBImageBox::setReadOnly(bool set) { m_readOnly = set; } TQPixmap KexiDBImageBox::pixmap() const { if (dataSource().isEmpty()) { //not db-aware return m_data.pixmap(); } //db-aware mode return m_pixmap; } uint KexiDBImageBox::pixmapId() const { if (dataSource().isEmpty()) {// && !m_data.stored()) { //not db-aware return m_data.id(); } return 0; } void KexiDBImageBox::setPixmapId(uint id) { if (m_insideSetData) //avoid recursion return; setData(KexiBLOBBuffer::self()->objectForId( id, /*unstored*/false )); repaint(); } uint KexiDBImageBox::storedPixmapId() const { if (dataSource().isEmpty() && m_data.stored()) { //not db-aware return m_data.id(); } return 0; } void KexiDBImageBox::setStoredPixmapId(uint id) { setData(KexiBLOBBuffer::self()->objectForId( id, /*stored*/true )); repaint(); } bool KexiDBImageBox::hasScaledContents() const { return m_scaledContents; // return m_pixmapLabel->hasScaledContents(); } /*void KexiDBImageBox::setPixmap(const TQByteArray& pixmap) { setValueInternal(pixmap, true); // setBackgroundMode(pixmap.isNull() ? TQt::NoBackground : TQt::PaletteBackground); }*/ void KexiDBImageBox::setScaledContents(bool set) { //todo m_pixmapLabel->setScaledContents(set); m_scaledContents = set; repaint(); } void KexiDBImageBox::setKeepAspectRatio(bool set) { m_keepAspectRatio = set; if (m_scaledContents) repaint(); } TQWidget* KexiDBImageBox::widget() { //! @todo // return m_pixmapLabel; return this; } bool KexiDBImageBox::cursorAtStart() { return true; } bool KexiDBImageBox::cursorAtEnd() { return true; } TQByteArray KexiDBImageBox::data() const { if (dataSource().isEmpty()) { //static mode return m_data.data(); } else { //db-aware mode return m_value; } } void KexiDBImageBox::insertFromFile() { m_popupMenu->insertFromFile(); } void KexiDBImageBox::handleInsertFromFileAction(const KURL& url) { if (!dataSource().isEmpty() && isReadOnly()) return; if (dataSource().isEmpty()) { //static mode KexiBLOBBuffer::Handle h = KexiBLOBBuffer::self()->insertPixmap( url ); if (!h) return; setData(h); repaint(); } else { //db-aware TQString fileName( url.isLocalFile() ? url.path() : url.prettyURL() ); //! @todo download the file if remote, then set fileName properly TQFile f(fileName); if (!f.open(IO_ReadOnly)) { //! @todo err msg return; } TQByteArray ba = f.readAll(); if (f.status()!=IO_Ok) { //! @todo err msg f.close(); return; } m_valueMimeType = KImageIO::mimeType( fileName ); setValueInternal( ba, true ); } //! @todo emit signal for setting "dirty" flag within the design if (!dataSource().isEmpty()) { signalValueChanged(); } } void KexiDBImageBox::handleAboutToSaveAsAction(TQString& origFilename, TQString& fileExtension, bool& dataIsEmpty) { if (data().isEmpty()) { kdWarning() << "KexiDBImageBox::handleAboutToSaveAs(): no pixmap!" << endl; dataIsEmpty = false; return; } if (dataSource().isEmpty()) { //for static images filename and mimetype can be available origFilename = m_data.originalFileName(); if (!origFilename.isEmpty()) origFilename = TQString("/") + origFilename; if (!m_data.mimeType().isEmpty()) fileExtension = KImageIO::typeForMime(m_data.mimeType()).lower(); } } void KexiDBImageBox::handleSaveAsAction(const TQString& fileName) { TQFile f(fileName); if (!f.open(IO_WriteOnly)) { //! @todo err msg return; } f.writeBlock( data() ); if (f.status()!=IO_Ok) { //! @todo err msg f.close(); return; } f.close(); } void KexiDBImageBox::handleCutAction() { if (!dataSource().isEmpty() && isReadOnly()) return; handleCopyAction(); clear(); } void KexiDBImageBox::handleCopyAction() { tqApp->clipboard()->setPixmap(pixmap(), TQClipboard::Clipboard); } void KexiDBImageBox::handlePasteAction() { if (isReadOnly() || (!m_designMode && !hasFocus())) return; TQPixmap pm( tqApp->clipboard()->pixmap(TQClipboard::Clipboard) ); // if (!pm.isNull()) // setValueInternal(pm, true); if (dataSource().isEmpty()) { //static mode setData(KexiBLOBBuffer::self()->insertPixmap( pm )); } else { //db-aware mode m_pixmap = pm; TQByteArray ba; TQBuffer buffer( ba ); buffer.open( IO_WriteOnly ); if (m_pixmap.save( &buffer, "PNG" )) {// write pixmap into ba in PNG format setValueInternal( ba, true, false/* !loadPixmap */ ); } else { setValueInternal( TQByteArray(), true ); } } repaint(); if (!dataSource().isEmpty()) { // emit pixmapChanged(); signalValueChanged(); } } void KexiDBImageBox::clear() { if (dataSource().isEmpty()) { //static mode setData(KexiBLOBBuffer::Handle()); } else { if (isReadOnly()) return; //db-aware mode setValueInternal(TQByteArray(), true); //m_pixmap = TQPixmap(); } // m_originalFileName = TQString(); //! @todo emit signal for setting "dirty" flag within the design // m_pixmap = TQPixmap(); //will be loaded on demand repaint(); if (!dataSource().isEmpty()) { // emit pixmapChanged();//valueChanged(data()); signalValueChanged(); } } void KexiDBImageBox::handleShowPropertiesAction() { //! @todo } void KexiDBImageBox::slotUpdateActionsAvailabilityRequested(bool& valueIsNull, bool& valueIsReadOnly) { valueIsNull = !( (dataSource().isEmpty() && !pixmap().isNull()) /*static pixmap available*/ || (!dataSource().isEmpty() && !this->valueIsNull()) /*db-aware pixmap available*/ ); // read-only if static pixmap or db-aware pixmap for read-only widget: valueIsReadOnly = !m_designMode && dataSource().isEmpty() || !dataSource().isEmpty() && isReadOnly() || m_designMode && !dataSource().isEmpty(); } /* void KexiDBImageBox::slotAboutToHidePopupMenu() { // kexipluginsdbg << "##### slotAboutToHidePopupMenu() " << endl; m_clickTimer.start(50, true); if (m_chooser && m_chooser->isOn()) { m_chooser->toggle(); if (m_setFocusOnButtonAfterClosingPopup) { m_setFocusOnButtonAfterClosingPopup = false; m_chooser->setFocus(); } } }*/ void KexiDBImageBox::contextMenuEvent( TQContextMenuEvent * e ) { if (popupMenuAvailable()) m_popupMenu->exec( e->globalPos(), -1 ); } /*void KexiDBImageBox::slotChooserPressed() { // if (!m_clickTimer.isActive()) // return; // m_chooser->setDown( false ); } void KexiDBImageBox::slotChooserReleased() { } void KexiDBImageBox::slotToggled(bool on) { return; // kexipluginsdbg << "##### slotToggled() " << on << endl; if (m_clickTimer.isActive() || !on) { m_chooser->disableMousePress = true; return; } m_chooser->disableMousePress = false; TQRect screen = tqApp->desktop()->availableGeometry( m_chooser ); TQPoint p; if ( TQApplication::reverseLayout() ) { if ( (mapToGlobal( m_chooser->rect().bottomLeft() ).y() + m_popupMenu->sizeHint().height()) <= screen.height() ) p = m_chooser->mapToGlobal( m_chooser->rect().bottomRight() ); else p = m_chooser->mapToGlobal( m_chooser->rect().topRight() - TQPoint( 0, m_popupMenu->sizeHint().height() ) ); p.rx() -= m_popupMenu->sizeHint().width(); } else { if ( (m_chooser->mapToGlobal( m_chooser->rect().bottomLeft() ).y() + m_popupMenu->sizeHint().height()) <= screen.height() ) p = m_chooser->mapToGlobal( m_chooser->rect().bottomLeft() ); else p = m_chooser->mapToGlobal( m_chooser->rect().topLeft() - TQPoint( 0, m_popupMenu->sizeHint().height() ) ); } if (!m_popupMenu->isVisible() && on) { m_popupMenu->exec( p, -1 ); m_popupMenu->setFocus(); } //m_chooser->setDown( false ); }*/ void KexiDBImageBox::updateActionStrings() { if (!m_popupMenu) return; if (m_designMode) { /* TQString titleString( i18n("Image Box") ); if (!dataSource().isEmpty()) titleString.prepend(dataSource() + " : "); m_popupMenu->changeTitle(m_popupMenu->idAt(0), m_popupMenu->titlePixmap(m_popupMenu->idAt(0)), titleString);*/ } else { //update title in data view mode, based on the data source if (columnInfo()) { KexiImageContextMenu::updateTitle( m_popupMenu, columnInfo()->captionOrAliasOrName(), KexiFormPart::library()->iconName(className()) ); } } if (m_chooser) { if (popupMenuAvailable() && dataSource().isEmpty()) { //this may work in the future (see @todo below) TQToolTip::add(m_chooser, i18n("Click to show actions for this image box")); } else { TQString beautifiedImageBoxName; if (m_designMode) { beautifiedImageBoxName = dataSource(); } else { beautifiedImageBoxName = columnInfo() ? columnInfo()->captionOrAliasOrName() : TQString(); /*! @todo look at makeFirstCharacterUpperCaseInCaptions setting [bool] (see doc/dev/settings.txt) */ beautifiedImageBoxName = beautifiedImageBoxName[0].upper() + beautifiedImageBoxName.mid(1); } TQToolTip::add(m_chooser, i18n("Click to show actions for \"%1\" image box").arg(beautifiedImageBoxName)); } } } bool KexiDBImageBox::popupMenuAvailable() { /*! @todo add kexi-global setting which anyway, allows to show this button (read-only actions like copy/save as/print can be available) */ //chooser button can be only visible when data source is specified return !dataSource().isEmpty(); } void KexiDBImageBox::setDataSource( const TQString &ds ) { KexiFormDataItemInterface::setDataSource( ds ); setData(KexiBLOBBuffer::Handle()); updateActionStrings(); KexiFrame::setFocusPolicy( focusPolicy() ); //set modified policy if (m_chooser) { m_chooser->setEnabled(popupMenuAvailable()); if (m_dropDownButtonVisible && popupMenuAvailable()) { m_chooser->show(); } else { m_chooser->hide(); } } // update some properties s not changed by user //! @todo get default line width from global style settings if (!m_lineWidthChanged) { KexiFrame::setLineWidth( ds.isEmpty() ? 0 : 1 ); } if (!m_paletteBackgroundColorChanged && parentWidget()) { KexiFrame::setPaletteBackgroundColor( dataSource().isEmpty() ? parentWidget()->paletteBackgroundColor() : palette().active().base() ); } } TQSize KexiDBImageBox::sizeHint() const { if (pixmap().isNull()) return TQSize(80, 80); return pixmap().size(); } int KexiDBImageBox::realLineWidth() const { if (frameShape()==TQFrame::Box && (frameShadow()==TQFrame::Sunken || frameShadow()==TQFrame::Raised)) return 2 * lineWidth(); else return lineWidth(); } void KexiDBImageBox::paintEvent( TQPaintEvent *pe ) { if (!m_paintEventEnabled) return; TQPainter p(this); p.setClipRect(pe->rect()); const int m = realLineWidth() + margin(); TQColor bg(eraseColor()); if (m_designMode && pixmap().isNull()) { TQPixmap pm(size()-TQSize(m, m)); TQPainter p2; p2.begin(TQT_TQPAINTDEVICE(&pm), this); p2.fillRect(0,0,width(),height(), bg); updatePixmap(); TQPixmap *imagBoxPm; const bool tooLarge = (height()-m-m) <= KexiDBImageBox_pm->height(); if (tooLarge || (width()-m-m) <= KexiDBImageBox_pm->width()) imagBoxPm = KexiDBImageBox_pmSmall; else imagBoxPm = KexiDBImageBox_pm; TQImage img(imagBoxPm->convertToImage()); img = KImageEffect::flatten(img, bg.dark(150), tqGray( bg.rgb() ) <= 20 ? TQColor(TQt::gray).dark(150) : bg.light(105)); TQPixmap converted; converted.convertFromImage(img); // if (tooLarge) // p2.drawPixmap(2, 2, converted); // else p2.drawPixmap(2, height()-m-m-imagBoxPm->height()-2, converted); TQFont f(tqApp->font()); p2.setFont(f); p2.setPen( KexiUtils::contrastColor( bg ) ); p2.drawText(pm.rect(), TQt::AlignCenter, dataSource().isEmpty() ? TQString::fromLatin1(name())+"\n"+i18n("Unbound Image Box", "(unbound)") //i18n("No Image") : dataSource()); p2.end(); bitBlt(this, m, m, &pm); } else { TQSize internalSize(size()); if (m_chooser && m_dropDownButtonVisible && !dataSource().isEmpty()) internalSize.setWidth( internalSize.width() - m_chooser->width() ); //clearing needed here because we may need to draw a pixmap with transparency p.fillRect(0,0,width(),height(), bg); KexiUtils::drawPixmap( p, m, TQRect(TQPoint(0,0), internalSize), pixmap(), m_alignment, m_scaledContents, m_keepAspectRatio ); } KexiFrame::drawFrame( &p ); // if the widget is focused, draw focus indicator rect _if_ there is no chooser button if (!m_designMode && !dataSource().isEmpty() && hasFocus() && (!m_chooser || !m_chooser->isVisible())) { style().tqdrawPrimitive( TQStyle::PE_FocusRect, &p, style().subRect(TQStyle::SR_PushButtonContents, this), palette().active() ); } } /* virtual void KexiDBImageBox::paletteChange ( const TQPalette & oldPalette ) { TQFrame::paletteChange(oldPalette); if (oldPalette.active().background()!=palette().active().background()) { delete KexiDBImageBox_pm; KexiDBImageBox_pm = 0; repaint(); } }*/ void KexiDBImageBox::updatePixmap() { if (! (m_designMode && pixmap().isNull()) ) return; if (!KexiDBImageBox_pm) { TQString fname( locate("data", TQString("kexi/pics/imagebox.png")) ); KexiDBImageBox_pmDeleter.setObject( KexiDBImageBox_pm, new TQPixmap(fname, "PNG") ); TQImage img(KexiDBImageBox_pm->convertToImage()); KexiDBImageBox_pmSmallDeleter.setObject( KexiDBImageBox_pmSmall, new TQPixmap( img.smoothScale(img.width()/2, img.height()/2, TQImage::ScaleMin) ) ); } } void KexiDBImageBox::setAlignment(int alignment) { m_alignment = alignment; if (!m_scaledContents || m_keepAspectRatio) repaint(); } void KexiDBImageBox::setData(const KexiBLOBBuffer::Handle& handle) { if (m_insideSetData) //avoid recursion return; m_insideSetData = true; m_data = handle; emit idChanged(handle.id()); m_insideSetData = false; update(); } void KexiDBImageBox::resizeEvent( TQResizeEvent * e ) { KexiFrame::resizeEvent(e); if (m_chooser) { TQSize s( m_chooser->sizeHint() ); TQSize margin( realLineWidth(), realLineWidth() ); s.setHeight( height() - 2*margin.height() ); s = s.boundedTo( size()-2*margin ); m_chooser->resize( s ); m_chooser->move( TQRect(TQPoint(0,0), e->size() - m_chooser->size() - margin + TQSize(1,1)).bottomRight() ); } } /* bool KexiDBImageBox::setProperty( const char * name, const TQVariant & value ) { const bool ret = TQLabel::setProperty(name, value); if (p_shadowEnabled) { if (0==qstrcmp("indent", name) || 0==qstrcmp("font", name) || 0==qstrcmp("margin", name) || 0==qstrcmp("frameShadow", name) || 0==qstrcmp("frameShape", name) || 0==qstrcmp("frameStyle", name) || 0==qstrcmp("midLineWidth", name) || 0==qstrcmp("lineWidth", name)) { p_privateLabel->setProperty(name, value); updatePixmap(); } } return ret; } */ void KexiDBImageBox::setColumnInfo(KexiDB::QueryColumnInfo* cinfo) { KexiFormDataItemInterface::setColumnInfo(cinfo); //updating strings and title is needed updateActionStrings(); } bool KexiDBImageBox::keyPressed(TQKeyEvent *ke) { // Esc key should close the popup if (ke->state() == TQt::NoButton && ke->key() == TQt::Key_Escape) { if (m_popupMenu->isVisible()) { m_setFocusOnButtonAfterClosingPopup = true; return true; } } // else if (ke->state() == TQt::ControlButton && TDEStdAccel::shortcut(TDEStdAccel::Copy).keyCodeTQt() == (ke->key()|TQt::CTRL)) { // } return false; } void KexiDBImageBox::setLineWidth( int width ) { m_lineWidthChanged = true; KexiFrame::setLineWidth(width); } void KexiDBImageBox::setPalette( const TQPalette &pal ) { KexiFrame::setPalette(pal); if (m_insideSetPalette) return; m_insideSetPalette = true; setPaletteBackgroundColor(pal.active().base()); setPaletteForegroundColor(pal.active().foreground()); m_insideSetPalette = false; } void KexiDBImageBox::setPaletteBackgroundColor( const TQColor & color ) { kexipluginsdbg << "KexiDBImageBox::setPaletteBackgroundColor(): " << TQString(color.name()) << endl; m_paletteBackgroundColorChanged = true; KexiFrame::setPaletteBackgroundColor(color); if (m_chooser) m_chooser->setPalette( tqApp->palette() ); } bool KexiDBImageBox::dropDownButtonVisible() const { return m_dropDownButtonVisible; } void KexiDBImageBox::setDropDownButtonVisible( bool set ) { //! @todo use global default setting for this property if (m_dropDownButtonVisible == set) return; m_dropDownButtonVisible = set; if (m_chooser) { if (m_dropDownButtonVisible) m_chooser->show(); else m_chooser->hide(); } } bool KexiDBImageBox::subwidgetStretchRequired(KexiDBAutoField* autoField) const { Q_UNUSED(autoField); return true; } bool KexiDBImageBox::eventFilter( TQObject * watched, TQEvent * e ) { if (watched==this || watched==m_chooser) { //we're watching chooser as well because it's a focus proxy even if invisible if (e->type()==TQEvent::FocusIn || e->type()==TQEvent::FocusOut || e->type()==TQEvent::MouseButtonPress) { update(); //to repaint focus rect } } // hide popup menu as soon as it loses focus if (watched==m_popupMenu && e->type()==TQEvent::FocusOut) { m_popupMenu->hide(); } return KexiFrame::eventFilter(watched, e); } TQWidget::FocusPolicy KexiDBImageBox::focusPolicy() const { if (dataSource().isEmpty()) return TQWidget::NoFocus; return m_focusPolicyInternal; } TQWidget::FocusPolicy KexiDBImageBox::focusPolicyInternal() const { return m_focusPolicyInternal; } void KexiDBImageBox::setFocusPolicy( TQWidget::FocusPolicy policy ) { m_focusPolicyInternal = policy; KexiFrame::setFocusPolicy( focusPolicy() ); //set modified policy } #include "kexidbimagebox.moc"