|
|
|
/* This file is part of the KDE project
|
|
|
|
Copyright (C) 2005 Cedric Pasteur <cedric.pasteur@free.fr>
|
|
|
|
Copyright (C) 2004-2007 Jaroslaw Staniek <js@iidea.pl>
|
|
|
|
|
|
|
|
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 <tqapplication.h>
|
|
|
|
#include <tqpixmap.h>
|
|
|
|
#include <tqstyle.h>
|
|
|
|
#include <tqclipboard.h>
|
|
|
|
#include <tqtooltip.h>
|
|
|
|
#include <tqimage.h>
|
|
|
|
#include <tqbuffer.h>
|
|
|
|
#include <tqfiledialog.h>
|
|
|
|
#include <tqpainter.h>
|
|
|
|
|
|
|
|
#include <kdebug.h>
|
|
|
|
#include <tdepopupmenu.h>
|
|
|
|
#include <tdelocale.h>
|
|
|
|
#include <kiconloader.h>
|
|
|
|
#include <tdefiledialog.h>
|
|
|
|
#include <kimageio.h>
|
|
|
|
#include <kstandarddirs.h>
|
|
|
|
#include <kstaticdeleter.h>
|
|
|
|
#include <kimageeffect.h>
|
|
|
|
#include <tdestdaccel.h>
|
|
|
|
#include <tdemessagebox.h>
|
|
|
|
#include <kguiitem.h>
|
|
|
|
|
|
|
|
#include <widget/utils/kexidropdownbutton.h>
|
|
|
|
#include <widget/utils/kexicontextmenuutils.h>
|
|
|
|
#include <kexiutils/utils.h>
|
|
|
|
#include <kexidb/field.h>
|
|
|
|
#include <kexidb/utils.h>
|
|
|
|
#include <kexidb/queryschema.h>
|
|
|
|
#include <formeditor/widgetlibrary.h>
|
|
|
|
|
|
|
|
#ifdef TQ_WS_WIN
|
|
|
|
#include <win32_utils.h>
|
|
|
|
#include <tderecentdirs.h>
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#include "kexidbutils.h"
|
|
|
|
#include "../kexiformpart.h"
|
|
|
|
|
|
|
|
static KStaticDeleter<TQPixmap> KexiDBImageBox_pmDeleter;
|
|
|
|
static TQPixmap* KexiDBImageBox_pm = 0;
|
|
|
|
static KStaticDeleter<TQPixmap> 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, TQ_SIGNAL(updateActionsAvailabilityRequested(bool&, bool&)),
|
|
|
|
this, TQ_SLOT(slotUpdateActionsAvailabilityRequested(bool&, bool&)));
|
|
|
|
connect(m_popupMenu, TQ_SIGNAL(insertFromFileRequested(const KURL&)),
|
|
|
|
this, TQ_SLOT(handleInsertFromFileAction(const KURL&)));
|
|
|
|
connect(m_popupMenu, TQ_SIGNAL(saveAsRequested(const TQString&)),
|
|
|
|
this, TQ_SLOT(handleSaveAsAction(const TQString&)));
|
|
|
|
connect(m_popupMenu, TQ_SIGNAL(cutRequested()),
|
|
|
|
this, TQ_SLOT(handleCutAction()));
|
|
|
|
connect(m_popupMenu, TQ_SIGNAL(copyRequested()),
|
|
|
|
this, TQ_SLOT(handleCopyAction()));
|
|
|
|
connect(m_popupMenu, TQ_SIGNAL(pasteRequested()),
|
|
|
|
this, TQ_SLOT(handlePasteAction()));
|
|
|
|
connect(m_popupMenu, TQ_SIGNAL(clearRequested()),
|
|
|
|
this, TQ_SLOT(clear()));
|
|
|
|
connect(m_popupMenu, TQ_SIGNAL(showPropertiesRequested()),
|
|
|
|
this, TQ_SLOT(handleShowPropertiesAction()));
|
|
|
|
|
|
|
|
// connect(m_popupMenu, TQ_SIGNAL(aboutToHide()), this, TQ_SLOT(slotAboutToHidePopupMenu()));
|
|
|
|
// if (m_chooser) {
|
|
|
|
//we couldn't use m_chooser->setPopup() because of drawing problems
|
|
|
|
// connect(m_chooser, TQ_SIGNAL(pressed()), this, TQ_SLOT(slotChooserPressed()));
|
|
|
|
// connect(m_chooser, TQ_SIGNAL(released()), this, TQ_SLOT(slotChooserReleased()));
|
|
|
|
// connect(m_chooser, TQ_SIGNAL(toggled(bool)), this, TQ_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(&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().drawPrimitive(
|
|
|
|
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"
|