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