00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021 #include "kexidbimagebox.h"
00022
00023 #include <qapplication.h>
00024 #include <qpixmap.h>
00025 #include <qstyle.h>
00026 #include <qclipboard.h>
00027 #include <qtooltip.h>
00028 #include <qimage.h>
00029 #include <qbuffer.h>
00030 #include <qfiledialog.h>
00031 #include <qpainter.h>
00032
00033 #include <kdebug.h>
00034 #include <kpopupmenu.h>
00035 #include <klocale.h>
00036 #include <kiconloader.h>
00037 #include <kfiledialog.h>
00038 #include <kimageio.h>
00039 #include <kstandarddirs.h>
00040 #include <kstaticdeleter.h>
00041 #include <kimageeffect.h>
00042 #include <kstdaccel.h>
00043 #include <kmessagebox.h>
00044 #include <kguiitem.h>
00045
00046 #include <widget/utils/kexidropdownbutton.h>
00047 #include <kexiutils/utils.h>
00048 #include <kexidb/field.h>
00049 #include <kexidb/queryschema.h>
00050 #include <formeditor/widgetlibrary.h>
00051
00052 #ifdef Q_WS_WIN
00053 #include <win32_utils.h>
00054 #include <krecentdirs.h>
00055 #endif
00056
00057 #include "kexidbutils.h"
00058 #include "../kexiformpart.h"
00059
00060 static KStaticDeleter<QPixmap> KexiDBImageBox_pmDeleter;
00061 static QPixmap* KexiDBImageBox_pm = 0;
00062
00063 KexiDBImageBox::KexiDBImageBox( bool designMode, QWidget *parent, const char *name )
00064 : KexiFrame( parent, name, Qt::WNoAutoErase )
00065 , KexiFormDataItemInterface()
00066 , m_alignment(Qt::AlignAuto|Qt::AlignTop)
00067 , m_designMode(designMode)
00068 , m_readOnly(false)
00069 , m_scaledContents(false)
00070 , m_keepAspectRatio(true)
00071 , m_insideSetData(false)
00072 , m_setFocusOnButtonAfterClosingPopup(false)
00073 , m_lineWidthChanged(false)
00074 , m_paintEventEnabled(true)
00075 , m_dropDownButtonVisible(true)
00076 , m_insideSetPalette(false)
00077 {
00078 installEventFilter(this);
00079 setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
00080
00081
00082 m_popupMenu = new KexiImageContextMenu(this);
00083
00084 if (m_designMode) {
00085 m_chooser = 0;
00086 }
00087 else {
00088 m_chooser = new KexiDropDownButton(this);
00089 m_chooser->setFocusPolicy(StrongFocus);
00090 m_chooser->setPopup(m_popupMenu);
00091 setFocusProxy(m_chooser);
00092 m_chooser->installEventFilter(this);
00093
00094
00095 }
00096
00097 setBackgroundMode(Qt::NoBackground);
00098 setFrameShape(QFrame::Box);
00099 setFrameShadow(QFrame::Plain);
00100 setFrameColor(Qt::black);
00101
00102 m_paletteBackgroundColorChanged = false;
00103
00104 connect(m_popupMenu, SIGNAL(updateActionsAvailabilityRequested(bool&, bool&)),
00105 this, SLOT(slotUpdateActionsAvailabilityRequested(bool&, bool&)));
00106 connect(m_popupMenu, SIGNAL(insertFromFileRequested(const KURL&)),
00107 this, SLOT(handleInsertFromFileAction(const KURL&)));
00108 connect(m_popupMenu, SIGNAL(saveAsRequested(const QString&)),
00109 this, SLOT(handleSaveAsAction(const QString&)));
00110 connect(m_popupMenu, SIGNAL(cutRequested()),
00111 this, SLOT(handleCutAction()));
00112 connect(m_popupMenu, SIGNAL(copyRequested()),
00113 this, SLOT(handleCopyAction()));
00114 connect(m_popupMenu, SIGNAL(pasteRequested()),
00115 this, SLOT(handlePasteAction()));
00116 connect(m_popupMenu, SIGNAL(clearRequested()),
00117 this, SLOT(clear()));
00118 connect(m_popupMenu, SIGNAL(showPropertiesRequested()),
00119 this, SLOT(handleShowPropertiesAction()));
00120
00121
00122
00123
00124
00125
00126
00127
00128
00129 setDataSource( QString::null );
00130 }
00131
00132 KexiDBImageBox::~KexiDBImageBox()
00133 {
00134 }
00135
00136 KexiImageContextMenu* KexiDBImageBox::contextMenu() const
00137 {
00138 return m_popupMenu;
00139 }
00140
00141 QVariant KexiDBImageBox::value()
00142 {
00143 if (dataSource().isEmpty()) {
00144
00145 return QVariant();
00146 }
00147
00148 return m_value;
00149
00150 }
00151
00152 void KexiDBImageBox::setValueInternal( const QVariant& add, bool removeOld, bool loadPixmap )
00153 {
00154 if (isReadOnly())
00155 return;
00156
00157 if (removeOld)
00158 m_value = add.toByteArray();
00159 else
00160 m_value = m_origValue.toByteArray();
00161 bool ok = !m_value.isEmpty();
00162 if (ok) {
00165 ok = loadPixmap ? m_pixmap.loadFromData(m_value) : true;
00166 if (!ok) {
00168 }
00169 }
00170 if (!ok) {
00171 m_valueMimeType = QString::null;
00172 m_pixmap = QPixmap();
00173 }
00174 repaint();
00175
00176
00177 }
00178
00179 void KexiDBImageBox::setInvalidState( const QString& displayText )
00180 {
00181 Q_UNUSED( displayText );
00182
00183
00184 if (!dataSource().isEmpty()) {
00185 m_value = QByteArray();
00186 }
00187
00188
00189
00191
00192 if (m_chooser)
00193 m_chooser->hide();
00194 setReadOnly(true);
00195 }
00196
00197 bool KexiDBImageBox::valueIsNull()
00198 {
00199 return m_value.isEmpty();
00200
00201 }
00202
00203 bool KexiDBImageBox::valueIsEmpty()
00204 {
00205 return false;
00206 }
00207
00208 bool KexiDBImageBox::isReadOnly() const
00209 {
00210 return m_readOnly;
00211 }
00212
00213 void KexiDBImageBox::setReadOnly(bool set)
00214 {
00215 m_readOnly = set;
00216 }
00217
00218 QPixmap KexiDBImageBox::pixmap() const
00219 {
00220 if (dataSource().isEmpty()) {
00221
00222 return m_data.pixmap();
00223 }
00224
00225 return m_pixmap;
00226 }
00227
00228 uint KexiDBImageBox::pixmapId() const
00229 {
00230 if (dataSource().isEmpty()) {
00231
00232 return m_data.id();
00233 }
00234 return 0;
00235 }
00236
00237 void KexiDBImageBox::setPixmapId(uint id)
00238 {
00239 if (m_insideSetData)
00240 return;
00241 setData(KexiBLOBBuffer::self()->objectForId( id, false ));
00242 repaint();
00243 }
00244
00245 uint KexiDBImageBox::storedPixmapId() const
00246 {
00247 if (dataSource().isEmpty() && m_data.stored()) {
00248
00249 return m_data.id();
00250 }
00251 return 0;
00252 }
00253
00254 void KexiDBImageBox::setStoredPixmapId(uint id)
00255 {
00256 setData(KexiBLOBBuffer::self()->objectForId( id, true ));
00257 repaint();
00258 }
00259
00260 bool KexiDBImageBox::hasScaledContents() const
00261 {
00262 return m_scaledContents;
00263
00264 }
00265
00266
00267
00268
00269
00270
00271
00272 void KexiDBImageBox::setScaledContents(bool set)
00273 {
00274
00275 m_scaledContents = set;
00276 repaint();
00277 }
00278
00279 void KexiDBImageBox::setKeepAspectRatio(bool set)
00280 {
00281 m_keepAspectRatio = set;
00282 if (m_scaledContents)
00283 repaint();
00284 }
00285
00286 QWidget* KexiDBImageBox::widget()
00287 {
00289
00290 return this;
00291 }
00292
00293 bool KexiDBImageBox::cursorAtStart()
00294 {
00295 return true;
00296 }
00297
00298 bool KexiDBImageBox::cursorAtEnd()
00299 {
00300 return true;
00301 }
00302
00303 QByteArray KexiDBImageBox::data() const
00304 {
00305 if (dataSource().isEmpty()) {
00306
00307 return m_data.data();
00308 }
00309 else {
00310
00311 return m_value;
00312 }
00313 }
00314
00315 void KexiDBImageBox::insertFromFile()
00316 {
00317 m_popupMenu->insertFromFile();
00318 }
00319
00320 void KexiDBImageBox::handleInsertFromFileAction(const KURL& url)
00321 {
00322 if (!dataSource().isEmpty() && isReadOnly())
00323 return;
00324
00325 if (dataSource().isEmpty()) {
00326
00327 KexiBLOBBuffer::Handle h = KexiBLOBBuffer::self()->insertPixmap( url );
00328 if (!h)
00329 return;
00330 setData(h);
00331 repaint();
00332 }
00333 else {
00334
00335 QString fileName( url.isLocalFile() ? url.path() : url.prettyURL() );
00336
00338 QFile f(fileName);
00339 if (!f.open(IO_ReadOnly)) {
00341 return;
00342 }
00343 QByteArray ba = f.readAll();
00344 if (f.status()!=IO_Ok) {
00346 f.close();
00347 return;
00348 }
00349 m_valueMimeType = KImageIO::mimeType( fileName );
00350 setValueInternal( ba, true );
00351 }
00352
00354 if (!dataSource().isEmpty()) {
00355 signalValueChanged();
00356 }
00357 }
00358
00359 void KexiDBImageBox::handleAboutToSaveAsAction(QString& origFilename, QString& fileExtension, bool& dataIsEmpty)
00360 {
00361 if (data().isEmpty()) {
00362 kdWarning() << "KexiDBImageBox::handleAboutToSaveAs(): no pixmap!" << endl;
00363 dataIsEmpty = false;
00364 return;
00365 }
00366 if (dataSource().isEmpty()) {
00367 origFilename = m_data.originalFileName();
00368 if (!origFilename.isEmpty())
00369 origFilename = QString("/") + origFilename;
00370 if (!m_data.mimeType().isEmpty())
00371 fileExtension = KImageIO::typeForMime(m_data.mimeType()).lower();
00372 }
00373 }
00374
00375 void KexiDBImageBox::handleSaveAsAction(const QString& fileName)
00376 {
00377 QFile f(fileName);
00378 if (!f.open(IO_WriteOnly)) {
00380 return;
00381 }
00382 f.writeBlock( data() );
00383 if (f.status()!=IO_Ok) {
00385 f.close();
00386 return;
00387 }
00388 f.close();
00389 }
00390
00391 void KexiDBImageBox::handleCutAction()
00392 {
00393 if (!dataSource().isEmpty() && isReadOnly())
00394 return;
00395 handleCopyAction();
00396 clear();
00397 }
00398
00399 void KexiDBImageBox::handleCopyAction()
00400 {
00401 qApp->clipboard()->setPixmap(pixmap(), QClipboard::Clipboard);
00402 }
00403
00404 void KexiDBImageBox::handlePasteAction()
00405 {
00406 if (isReadOnly() || (!m_designMode && !hasFocus()))
00407 return;
00408 QPixmap pm( qApp->clipboard()->pixmap(QClipboard::Clipboard) );
00409
00410
00411 if (dataSource().isEmpty()) {
00412
00413 setData(KexiBLOBBuffer::self()->insertPixmap( pm ));
00414 }
00415 else {
00416
00417 m_pixmap = pm;
00418 QByteArray ba;
00419 QBuffer buffer( ba );
00420 buffer.open( IO_WriteOnly );
00421 if (m_pixmap.save( &buffer, "PNG" )) {
00422 setValueInternal( ba, true, false );
00423 }
00424 else {
00425 setValueInternal( QByteArray(), true );
00426 }
00427 }
00428
00429 repaint();
00430 if (!dataSource().isEmpty()) {
00431
00432 signalValueChanged();
00433 }
00434 }
00435
00436 void KexiDBImageBox::clear()
00437 {
00438 if (dataSource().isEmpty()) {
00439
00440 setData(KexiBLOBBuffer::Handle());
00441 }
00442 else {
00443 if (isReadOnly())
00444 return;
00445
00446 setValueInternal(QByteArray(), true);
00447
00448 }
00449
00450
00451
00453
00454
00455 repaint();
00456 if (!dataSource().isEmpty()) {
00457
00458 signalValueChanged();
00459 }
00460 }
00461
00462 void KexiDBImageBox::handleShowPropertiesAction()
00463 {
00465 }
00466
00467 void KexiDBImageBox::slotUpdateActionsAvailabilityRequested(bool& valueIsNull, bool& valueIsReadOnly)
00468 {
00469 valueIsNull = !(
00470 (dataSource().isEmpty() && !pixmap().isNull())
00471 || (!dataSource().isEmpty() && !this->valueIsNull())
00472 );
00473
00474 valueIsReadOnly = !m_designMode && dataSource().isEmpty() || !dataSource().isEmpty() && isReadOnly()
00475 || m_designMode && !dataSource().isEmpty();
00476 }
00477
00478
00479
00480
00481
00482
00483
00484
00485
00486
00487
00488
00489
00490
00491
00492 void KexiDBImageBox::contextMenuEvent( QContextMenuEvent * e )
00493 {
00494 if (popupMenuAvailable())
00495 m_popupMenu->exec( e->globalPos(), -1 );
00496 }
00497
00498
00499
00500
00501
00502
00503
00504
00505
00506
00507
00508
00509
00510
00511
00512
00513
00514
00515
00516
00517
00518
00519
00520
00521
00522
00523
00524
00525
00526
00527
00528
00529
00530
00531
00532
00533
00534
00535
00536
00537
00538
00539
00540
00541 void KexiDBImageBox::updateActionStrings()
00542 {
00543 if (!m_popupMenu)
00544 return;
00545 if (m_designMode) {
00546
00547
00548
00549
00550 }
00551 else {
00552
00553 if (columnInfo()) {
00554 KexiImageContextMenu::updateTitle( m_popupMenu, columnInfo()->captionOrAliasOrName(),
00555 KexiFormPart::library()->iconName(className()) );
00556 }
00557 }
00558
00559 if (m_chooser) {
00560 if (popupMenuAvailable() && dataSource().isEmpty()) {
00561 QToolTip::add(m_chooser, i18n("Click to show actions for this image box"));
00562 } else {
00563 QString beautifiedImageBoxName;
00564 if (m_designMode) {
00565 beautifiedImageBoxName = dataSource();
00566 }
00567 else {
00568 beautifiedImageBoxName = columnInfo() ? columnInfo()->captionOrAliasOrName() : QString::null;
00571 beautifiedImageBoxName = beautifiedImageBoxName[0].upper() + beautifiedImageBoxName.mid(1);
00572 }
00573 QToolTip::add(m_chooser, i18n("Click to show actions for \"%1\" image box").arg(beautifiedImageBoxName));
00574 }
00575 }
00576 }
00577
00578 bool KexiDBImageBox::popupMenuAvailable()
00579 {
00582
00583 return !dataSource().isEmpty();
00584 }
00585
00586 void KexiDBImageBox::setDataSource( const QString &ds )
00587 {
00588 KexiFormDataItemInterface::setDataSource( ds );
00589 setData(KexiBLOBBuffer::Handle());
00590 updateActionStrings();
00591 KexiFrame::setFocusPolicy( focusPolicy() );
00592
00593 if (m_chooser) {
00594 m_chooser->setEnabled(popupMenuAvailable());
00595 if (m_dropDownButtonVisible && popupMenuAvailable()) {
00596 m_chooser->show();
00597 }
00598 else {
00599 m_chooser->hide();
00600 }
00601 }
00602
00603
00605 if (!m_lineWidthChanged) {
00606 KexiFrame::setLineWidth( ds.isEmpty() ? 0 : 1 );
00607 }
00608 if (!m_paletteBackgroundColorChanged && parentWidget()) {
00609 KexiFrame::setPaletteBackgroundColor(
00610 dataSource().isEmpty() ? parentWidget()->paletteBackgroundColor() : palette().active().base() );
00611 }
00612 }
00613
00614 QSize KexiDBImageBox::sizeHint() const
00615 {
00616 if (pixmap().isNull())
00617 return QSize(80, 80);
00618 return pixmap().size();
00619 }
00620
00621 int KexiDBImageBox::realLineWidth() const
00622 {
00623 if (frameShape()==QFrame::Box && (frameShadow()==QFrame::Sunken || frameShadow()==QFrame::Raised))
00624 return 2 * lineWidth();
00625 else
00626 return lineWidth();
00627 }
00628
00629 void KexiDBImageBox::paintEvent( QPaintEvent *pe )
00630 {
00631 if (!m_paintEventEnabled)
00632 return;
00633 QPainter p(this);
00634 p.setClipRect(pe->rect());
00635 const int m = realLineWidth();
00636 QColor bg(eraseColor());
00637 if (m_designMode && pixmap().isNull()) {
00638 QPixmap pm(size()-QSize(m, m));
00639 QPainter p2;
00640 p2.begin(&pm, this);
00641 p2.fillRect(0,0,width(),height(), bg);
00642
00643 updatePixmap();
00644 QImage img(KexiDBImageBox_pm->convertToImage());
00645 img = KImageEffect::flatten(img, bg.dark(150),
00646 qGray( bg.rgb() ) <= 20 ? QColor(Qt::gray).dark(150) : bg.light(105));
00647
00648 QPixmap converted;
00649 converted.convertFromImage(img);
00650 p2.drawPixmap(2, height()-m-m-KexiDBImageBox_pm->height()-2, converted);
00651 QFont f(qApp->font());
00652 p2.setFont(f);
00653 p2.setPen( KexiUtils::contrastColor( bg ) );
00654 ;
00655
00656 p2.drawText(pm.rect(), Qt::AlignCenter|Qt::WordBreak,
00657 dataSource().isEmpty()
00658 ? QString::fromLatin1(name())+"\n"+i18n("Unbound Image Box", "(unbound)")
00659 : dataSource());
00660 p2.end();
00661 bitBlt(this, m, m, &pm);
00662 }
00663 else {
00664 QSize internalSize(size());
00665 if (m_chooser && m_dropDownButtonVisible && !dataSource().isEmpty())
00666 internalSize.setWidth( internalSize.width() - m_chooser->width() );
00667
00668
00669 p.fillRect(0,0,width(),height(), bg);
00670
00671 KexiUtils::drawPixmap( p, m, QRect(QPoint(0,0), internalSize), pixmap(), m_alignment,
00672 m_scaledContents, m_keepAspectRatio );
00673 }
00674 KexiFrame::drawFrame( &p );
00675
00676
00677 if (!m_designMode && !dataSource().isEmpty() && hasFocus() && (!m_chooser || !m_chooser->isVisible())) {
00678 style().drawPrimitive(
00679 QStyle::PE_FocusRect, &p, style().subRect(QStyle::SR_PushButtonContents, this),
00680 palette().active() );
00681 }
00682 }
00683
00684
00685
00686
00687
00688
00689
00690
00691
00692
00693
00694 void KexiDBImageBox::updatePixmap() {
00695 if (! (m_designMode && pixmap().isNull()) )
00696 return;
00697
00698
00699
00700
00701
00702
00703
00704
00705
00706
00707 if (!KexiDBImageBox_pm) {
00708 QString fname( locate("data", QString("kexi/pics/imagebox.png")) );
00709 KexiDBImageBox_pmDeleter.setObject( KexiDBImageBox_pm, new QPixmap(fname, "PNG") );
00710 }
00711 }
00712
00713 void KexiDBImageBox::setAlignment(int alignment)
00714 {
00715 m_alignment = alignment;
00716 if (!m_scaledContents || m_keepAspectRatio)
00717 repaint();
00718 }
00719
00720 void KexiDBImageBox::setData(const KexiBLOBBuffer::Handle& handle)
00721 {
00722 if (m_insideSetData)
00723 return;
00724 m_insideSetData = true;
00725 m_data = handle;
00726 emit idChanged(handle.id());
00727 m_insideSetData = false;
00728 update();
00729 }
00730
00731 void KexiDBImageBox::resizeEvent( QResizeEvent * e )
00732 {
00733 KexiFrame::resizeEvent(e);
00734 if (m_chooser) {
00735 QSize s( m_chooser->sizeHint() );
00736 QSize margin( realLineWidth(), realLineWidth() );
00737 s.setHeight( height() - 2*margin.height() );
00738 s = s.boundedTo( size()-2*margin );
00739 m_chooser->resize( s );
00740 m_chooser->move( QRect(QPoint(0,0), e->size() - m_chooser->size() - margin + QSize(1,1)).bottomRight() );
00741 }
00742 }
00743
00744
00745
00746
00747
00748
00749
00750
00751
00752
00753
00754
00755
00756
00757
00758
00759
00760
00761 void KexiDBImageBox::setColumnInfo(KexiDB::QueryColumnInfo* cinfo)
00762 {
00763 KexiFormDataItemInterface::setColumnInfo(cinfo);
00764
00765 updateActionStrings();
00766 }
00767
00768 bool KexiDBImageBox::keyPressed(QKeyEvent *ke)
00769 {
00770
00771 if (ke->state() == Qt::NoButton && ke->key() == Qt::Key_Escape) {
00772 if (m_popupMenu->isVisible()) {
00773 m_setFocusOnButtonAfterClosingPopup = true;
00774 return true;
00775 }
00776 }
00777
00778
00779 return false;
00780 }
00781
00782 void KexiDBImageBox::setLineWidth( int width )
00783 {
00784 m_lineWidthChanged = true;
00785 KexiFrame::setLineWidth(width);
00786 }
00787
00788 void KexiDBImageBox::setPalette( const QPalette &pal )
00789 {
00790 KexiFrame::setPalette(pal);
00791 if (m_insideSetPalette)
00792 return;
00793 m_insideSetPalette = true;
00794 setPaletteBackgroundColor(pal.active().base());
00795 setPaletteForegroundColor(pal.active().foreground());
00796 m_insideSetPalette = false;
00797 }
00798
00799 void KexiDBImageBox::setPaletteBackgroundColor( const QColor & color )
00800 {
00801 kexipluginsdbg << "KexiDBImageBox::setPaletteBackgroundColor(): " << color.name() << endl;
00802 m_paletteBackgroundColorChanged = true;
00803 KexiFrame::setPaletteBackgroundColor(color);
00804 if (m_chooser)
00805 m_chooser->setPalette( qApp->palette() );
00806 }
00807
00808 bool KexiDBImageBox::dropDownButtonVisible() const
00809 {
00810 return m_dropDownButtonVisible;
00811 }
00812
00813 void KexiDBImageBox::setDropDownButtonVisible( bool set )
00814 {
00816 if (m_dropDownButtonVisible == set)
00817 return;
00818 m_dropDownButtonVisible = set;
00819 if (m_chooser) {
00820 if (m_dropDownButtonVisible)
00821 m_chooser->show();
00822 else
00823 m_chooser->hide();
00824 }
00825 }
00826
00827 bool KexiDBImageBox::subwidgetStretchRequired(KexiDBAutoField* autoField) const
00828 {
00829 Q_UNUSED(autoField);
00830 return true;
00831 }
00832
00833 bool KexiDBImageBox::eventFilter( QObject * watched, QEvent * e )
00834 {
00835 if (watched==this || watched==m_chooser) {
00836 if (e->type()==QEvent::FocusIn || e->type()==QEvent::FocusOut || e->type()==QEvent::MouseButtonPress) {
00837 update();
00838 }
00839 }
00840 return KexiFrame::eventFilter(watched, e);
00841 }
00842
00843 QWidget::FocusPolicy KexiDBImageBox::focusPolicy() const
00844 {
00845 if (dataSource().isEmpty())
00846 return NoFocus;
00847 return m_focusPolicyInternal;
00848 }
00849
00850 QWidget::FocusPolicy KexiDBImageBox::focusPolicyInternal() const
00851 {
00852 return m_focusPolicyInternal;
00853 }
00854
00855 void KexiDBImageBox::setFocusPolicy( FocusPolicy policy )
00856 {
00857 m_focusPolicyInternal = policy;
00858 KexiFrame::setFocusPolicy( focusPolicy() );
00859 }
00860
00861 #include "kexidbimagebox.moc"