00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021 #include "kexiblobtableedit.h"
00022
00023 #include <stdlib.h>
00024
00025 #include <qdatastream.h>
00026 #include <qfile.h>
00027 #include <qpopupmenu.h>
00028 #include <qtextedit.h>
00029 #include <qlayout.h>
00030 #include <qstatusbar.h>
00031 #include <qlabel.h>
00032 #include <qpixmap.h>
00033 #include <qimage.h>
00034 #include <qpainter.h>
00035 #include <qtooltip.h>
00036 #include <qapplication.h>
00037 #include <qclipboard.h>
00038 #include <qbuffer.h>
00039
00040 #include <kdebug.h>
00041 #include <ktempfile.h>
00042 #include <kmimetype.h>
00043 #include <kmimemagic.h>
00044 #include <kuserprofile.h>
00045 #include <kservice.h>
00046 #include <kprocess.h>
00047 #include <kopenwith.h>
00048 #include <kurl.h>
00049 #include <karrowbutton.h>
00050 #include <klocale.h>
00051 #include <kfiledialog.h>
00052 #include <kio/job.h>
00053 #include <kglobal.h>
00054 #include <kiconloader.h>
00055 #include <kpopupmenu.h>
00056 #include <kstdaccel.h>
00057
00058 #include <kexiutils/utils.h>
00059 #include <widget/utils/kexidropdownbutton.h>
00060 #include <widget/utils/kexicontextmenuutils.h>
00061
00063 class KexiBlobTableEdit::Private
00064 {
00065 public:
00066 Private()
00067 : popup(0)
00068 , readOnly(false)
00069 , setValueInternalEnabled(true)
00070 {
00071 }
00072
00073 QByteArray value;
00074 KexiDropDownButton *button;
00075 QSize totalSize;
00076 KexiImageContextMenu *popup;
00077 bool readOnly : 1;
00078 bool setValueInternalEnabled : 1;
00079 };
00080
00081
00082
00083 KexiBlobTableEdit::KexiBlobTableEdit(KexiTableViewColumn &column, QWidget *parent)
00084 : KexiTableEdit(column, parent)
00085 , d ( new Private() )
00086 {
00087 setName("KexiBlobTableEdit");
00088
00089
00090 m_hasFocusableWidget = false;
00091 d->button = new KexiDropDownButton( parentWidget() );
00092 d->button->hide();
00093 QToolTip::add(d->button, i18n("Click to show available actions for this cell"));
00094
00095 d->popup = new KexiImageContextMenu(this);
00096 d->popup->installEventFilter(this);
00097 if (column.columnInfo)
00098 KexiImageContextMenu::updateTitle( d->popup, column.columnInfo->captionOrAliasOrName(),
00100 "pixmaplabel" );
00101 d->button->setPopup( d->popup );
00102
00103
00104
00105
00106 connect(d->popup, SIGNAL(updateActionsAvailabilityRequested(bool&, bool&)),
00107 this, SLOT(slotUpdateActionsAvailabilityRequested(bool&, bool&)));
00108
00109 connect(d->popup, SIGNAL(insertFromFileRequested(const KURL&)),
00110 this, SLOT(handleInsertFromFileAction(const KURL&)));
00111 connect(d->popup, SIGNAL(saveAsRequested(const QString&)),
00112 this, SLOT(handleSaveAsAction(const QString&)));
00113 connect(d->popup, SIGNAL(cutRequested()),
00114 this, SLOT(handleCutAction()));
00115 connect(d->popup, SIGNAL(copyRequested()),
00116 this, SLOT(handleCopyAction()));
00117 connect(d->popup, SIGNAL(pasteRequested()),
00118 this, SLOT(handlePasteAction()));
00119 connect(d->popup, SIGNAL(clearRequested()),
00120 this, SLOT(clear()));
00121 connect(d->popup, SIGNAL(showPropertiesRequested()),
00122 this, SLOT(handleShowPropertiesAction()));
00123 }
00124
00125 KexiBlobTableEdit::~KexiBlobTableEdit()
00126 {
00127 delete d;
00128 #if 0
00129 kdDebug() << "KexiBlobTableEdit: Cleaning up..." << endl;
00130 if (m_tempFile) {
00131 m_tempFile->unlink();
00132
00133 }
00134 delete m_proc;
00135 m_proc = 0;
00136 kdDebug() << "KexiBlobTableEdit: Ready." << endl;
00137 #endif
00138 }
00139
00141 void KexiBlobTableEdit::setValueInternal(const QVariant& add, bool removeOld)
00142 {
00143 if (!d->setValueInternalEnabled)
00144 return;
00145 if (removeOld)
00146 d->value = add.toByteArray();
00147 else
00148 d->value = m_origValue.toByteArray();
00149
00150 #if 0 //todo?
00151 QByteArray val = m_origValue.toByteArray();
00152 kdDebug() << "KexiBlobTableEdit: Size of BLOB: " << val.size() << endl;
00153 m_tempFile = new KTempFile();
00154 m_tempFile->setAutoDelete(true);
00155 kdDebug() << "KexiBlobTableEdit: Creating temporary file: " << m_tempFile->name() << endl;
00156 m_tempFile->dataStream()->writeRawBytes(val.data(), val.size());
00157 m_tempFile->close();
00158 delete m_tempFile;
00159 m_tempFile = 0;
00160
00161 KMimeMagicResult* mmr = KMimeMagic::self()->findFileType(m_tempFile->name());
00162 kdDebug() << "KexiBlobTableEdit: Mimetype = " << mmr->mimeType() << endl;
00163
00164 setViewWidget( new QWidget(this) );
00165 #endif
00166 }
00167
00168 bool KexiBlobTableEdit::valueIsNull()
00169 {
00170
00171 d->value.size();
00172 return d->value.isEmpty();
00173 }
00174
00175 bool KexiBlobTableEdit::valueIsEmpty()
00176 {
00177
00178 return d->value.isEmpty();
00179 }
00180
00181 QVariant
00182 KexiBlobTableEdit::value()
00183 {
00184 return d->value;
00185 #if 0
00186
00187
00188
00189 if(m_content && m_content->isModified())
00190 {
00191 return QVariant(m_content->text());
00192 }
00193 QByteArray value;
00194 QFile f( m_tempFile->name() );
00195 f.open(IO_ReadOnly);
00196 QDataStream stream(&f);
00197 char* data = (char*) malloc(f.size());
00198 value.resize(f.size());
00199 stream.readRawBytes(data, f.size());
00200 value.duplicate(data, f.size());
00201 free(data);
00202 kdDebug() << "KexiBlobTableEdit: Size of BLOB: " << value.size() << endl;
00203 return QVariant(value);
00204 #endif
00205 }
00206
00207 void KexiBlobTableEdit::paintFocusBorders( QPainter *p, QVariant &, int x, int y, int w, int h )
00208 {
00209
00210 if (!d->readOnly && w > d->button->width())
00211 w -= d->button->width();
00212 p->drawRect(x, y, w, h);
00213 }
00214
00215 void
00216 KexiBlobTableEdit::setupContents( QPainter *p, bool focused, const QVariant& val,
00217 QString &txt, int &align, int &x, int &y_offset, int &w, int &h )
00218 {
00219 Q_UNUSED(focused);
00220 Q_UNUSED(txt);
00221 Q_UNUSED(align);
00222
00224 QPixmap pixmap;
00225 x = 0;
00226 w -= 1;
00227 h -= 1;
00228 if (p && val.canCast(QVariant::ByteArray) && pixmap.loadFromData(val.toByteArray())) {
00229 KexiUtils::drawPixmap( *p, 0, QRect(x, y_offset, w, h),
00230 pixmap, Qt::AlignCenter, true, true);
00231 }
00232 }
00233
00234 bool KexiBlobTableEdit::cursorAtStart()
00235 {
00236 return true;
00237 }
00238
00239 bool KexiBlobTableEdit::cursorAtEnd()
00240 {
00241 return true;
00242 }
00243
00244 void KexiBlobTableEdit::handleInsertFromFileAction(const KURL& url)
00245 {
00246 if (isReadOnly())
00247 return;
00248
00249 QString fileName( url.isLocalFile() ? url.path() : url.prettyURL() );
00250
00252 QFile f(fileName);
00253 if (!f.open(IO_ReadOnly)) {
00255 return;
00256 }
00257 QByteArray ba = f.readAll();
00258 if (f.status()!=IO_Ok) {
00260 f.close();
00261 return;
00262 }
00263 f.close();
00264
00265 setValueInternal( ba, true );
00266 signalEditRequested();
00267
00268 }
00269
00270 void KexiBlobTableEdit::handleAboutToSaveAsAction(QString& origFilename, QString& fileExtension, bool& dataIsEmpty)
00271 {
00272 Q_UNUSED(origFilename);
00273 Q_UNUSED(fileExtension);
00274 dataIsEmpty = valueIsEmpty();
00276 }
00277
00278 void KexiBlobTableEdit::handleSaveAsAction(const QString& fileName)
00279 {
00280 QFile f(fileName);
00281 if (!f.open(IO_WriteOnly)) {
00283 return;
00284 }
00285 f.writeBlock( d->value );
00286 if (f.status()!=IO_Ok) {
00288 f.close();
00289 return;
00290 }
00291 f.close();
00292 }
00293
00294 void KexiBlobTableEdit::handleCutAction()
00295 {
00296 if (isReadOnly())
00297 return;
00298 handleCopyAction();
00299 clear();
00300 }
00301
00302 void KexiBlobTableEdit::handleCopyAction()
00303 {
00304 executeCopyAction(d->value);
00305 }
00306
00307 void KexiBlobTableEdit::executeCopyAction(const QByteArray& data)
00308 {
00309 QPixmap pixmap;
00310 if (!pixmap.loadFromData(data))
00311 return;
00312 qApp->clipboard()->setPixmap(pixmap, QClipboard::Clipboard);
00313 }
00314
00315 void KexiBlobTableEdit::handlePasteAction()
00316 {
00317 if (isReadOnly())
00318 return;
00319 QPixmap pm( qApp->clipboard()->pixmap(QClipboard::Clipboard) );
00320 QByteArray ba;
00321 QBuffer buffer( ba );
00322 buffer.open( IO_WriteOnly );
00323 if (pm.save( &buffer, "PNG" )) {
00324 setValueInternal( ba, true );
00325 }
00326 else {
00327 setValueInternal( QByteArray(), true );
00328 }
00329 signalEditRequested();
00330
00331 repaintRelatedCell();
00332 }
00333
00334 void KexiBlobTableEdit::clear()
00335 {
00336 setValueInternal( QByteArray(), true );
00337 signalEditRequested();
00338
00339 repaintRelatedCell();
00340 }
00341
00342 void KexiBlobTableEdit::handleShowPropertiesAction()
00343 {
00345 }
00346
00347 void KexiBlobTableEdit::showFocus( const QRect& r, bool readOnly )
00348 {
00349 d->readOnly = readOnly;
00350
00351 updateFocus( r );
00352
00353 if (d->readOnly)
00354 d->button->hide();
00355 else
00356 d->button->show();
00357 }
00358
00359 void KexiBlobTableEdit::resize(int w, int h)
00360 {
00361 d->totalSize = QSize(w,h);
00362 const int addWidth = d->readOnly ? 0 : d->button->width();
00363 QWidget::resize(w - addWidth, h);
00364 if (!d->readOnly)
00365 d->button->resize( h, h );
00366 m_rightMarginWhenFocused = m_rightMargin + addWidth;
00367 QRect r( pos().x(), pos().y(), w+1, h+1 );
00368 r.moveBy(m_scrollView->contentsX(),m_scrollView->contentsY());
00369 updateFocus( r );
00370
00371
00372
00373 }
00374
00375 void KexiBlobTableEdit::updateFocus( const QRect& r )
00376 {
00377 if (!d->readOnly) {
00378 if (d->button->width() > r.width())
00379 moveChild(d->button, r.right() + 1, r.top());
00380 else
00381 moveChild(d->button, r.right() - d->button->width(), r.top() );
00382 }
00383 }
00384
00385 void KexiBlobTableEdit::hideFocus()
00386 {
00387 d->button->hide();
00388 }
00389
00390 QSize KexiBlobTableEdit::totalSize() const
00391 {
00392 return d->totalSize;
00393 }
00394
00395 void KexiBlobTableEdit::slotUpdateActionsAvailabilityRequested(bool& valueIsNull, bool& valueIsReadOnly)
00396 {
00397 emit editRequested();
00398 valueIsNull = this->valueIsNull();
00399 valueIsReadOnly = d->readOnly || isReadOnly();
00400 }
00401
00402 void KexiBlobTableEdit::signalEditRequested()
00403 {
00404 d->setValueInternalEnabled = false;
00405 emit editRequested();
00406 d->setValueInternalEnabled = true;
00407 }
00408
00409 bool KexiBlobTableEdit::handleKeyPress( QKeyEvent* ke, bool editorActive )
00410 {
00411 Q_UNUSED(editorActive);
00412
00413 const int k = ke->key();
00414 KKey kkey(ke);
00415 if (!d->readOnly) {
00416 if ((ke->state()==Qt::NoButton && k==Qt::Key_F4)
00417 || (ke->state()==Qt::AltButton && k==Qt::Key_Down)) {
00418 d->button->animateClick();
00419 QMouseEvent me( QEvent::MouseButtonPress, QPoint(2,2), Qt::LeftButton, Qt::NoButton );
00420 QApplication::sendEvent( d->button, &me );
00421 }
00422 else if ((ke->state()==NoButton && (k==Qt::Key_F2 || k==Qt::Key_Space || k==Qt::Key_Enter || k==Qt::Key_Return))) {
00423 d->popup->insertFromFile();
00424 }
00425 else
00426 return false;
00427 }
00428 else
00429 return false;
00430 return true;
00431 }
00432
00433 bool KexiBlobTableEdit::handleDoubleClick()
00434 {
00435 d->popup->insertFromFile();
00436 return true;
00437 }
00438
00439 void KexiBlobTableEdit::handleCopyAction(const QVariant& value, const QVariant& visibleValue)
00440 {
00441 Q_UNUSED(visibleValue);
00442 executeCopyAction(value.toByteArray());
00443 }
00444
00445 void KexiBlobTableEdit::handleAction(const QString& actionName)
00446 {
00447 if (actionName=="edit_paste") {
00448 d->popup->paste();
00449 }
00450 else if (actionName=="edit_cut") {
00451 emit editRequested();
00452 d->popup->cut();
00453 }
00454 }
00455
00456 bool KexiBlobTableEdit::eventFilter( QObject *o, QEvent *e )
00457 {
00458 if (o == d->popup && e->type()==QEvent::KeyPress) {
00459 QKeyEvent* ke = static_cast<QKeyEvent*>(e);
00460 const int state = ke->state();
00461 const int k = ke->key();
00462 if ( (state==Qt::NoButton && (k==Qt::Key_Tab || k==Qt::Key_Left || k==Qt::Key_Right))
00463 || (state==Qt::ShiftButton && k==Qt::Key_Backtab)
00464 )
00465 {
00466 d->popup->hide();
00467 QApplication::sendEvent( this, ke );
00468 return true;
00469 }
00470 }
00471 return false;
00472 }
00473
00474 KEXI_CELLEDITOR_FACTORY_ITEM_IMPL(KexiBlobEditorFactoryItem, KexiBlobTableEdit)
00475
00476
00477
00478
00479
00480 class KexiKIconTableEdit::Private
00481 {
00482 public:
00483 Private()
00484 : pixmapCache(17, 17, false)
00485 {
00486 }
00488 QVariant currentValue;
00489
00490 QCache<QPixmap> pixmapCache;
00491 };
00492
00493 KexiKIconTableEdit::KexiKIconTableEdit(KexiTableViewColumn &column, QWidget *parent)
00494 : KexiTableEdit(column, parent)
00495 , d( new Private() )
00496 {
00497 setName("KexiKIconTableEdit");
00498 init();
00499 }
00500
00501 KexiKIconTableEdit::~KexiKIconTableEdit()
00502 {
00503 delete d;
00504 }
00505
00506 void KexiKIconTableEdit::init()
00507 {
00508 m_hasFocusableWidget = false;
00509 d->pixmapCache.setAutoDelete(true);
00510 }
00511
00512 void KexiKIconTableEdit::setValueInternal(const QVariant& , bool )
00513 {
00514 d->currentValue = m_origValue;
00515 }
00516
00517 bool KexiKIconTableEdit::valueIsNull()
00518 {
00519 return d->currentValue.isNull();
00520 }
00521
00522 bool KexiKIconTableEdit::valueIsEmpty()
00523 {
00524 return d->currentValue.isNull();
00525 }
00526
00527 QVariant KexiKIconTableEdit::value()
00528 {
00529 return d->currentValue;
00530 }
00531
00532 void KexiKIconTableEdit::clear()
00533 {
00534 d->currentValue = QVariant();
00535 }
00536
00537 bool KexiKIconTableEdit::cursorAtStart()
00538 {
00539 return true;
00540 }
00541
00542 bool KexiKIconTableEdit::cursorAtEnd()
00543 {
00544 return true;
00545 }
00546
00547 void KexiKIconTableEdit::setupContents( QPainter *p, bool , const QVariant& val,
00548 QString &, int &, int &, int &y_offset, int &w, int &h )
00549 {
00550 Q_UNUSED( y_offset );
00551
00552 #if 0
00553 #ifdef Q_WS_WIN
00554 y_offset = -1;
00555 #else
00556 y_offset = 0;
00557 #endif
00558 int s = QMAX(h - 5, 12);
00559 s = QMIN( h-3, s );
00560 s = QMIN( w-3, s );
00561 QRect r( QMAX( w/2 - s/2, 0 ) , h/2 - s/2 , s, s);
00562 p->setPen(QPen(colorGroup().text(), 1));
00563 p->drawRect(r);
00564 if (val.asBool()) {
00565 p->drawLine(r.x(), r.y(), r.right(), r.bottom());
00566 p->drawLine(r.x(), r.bottom(), r.right(), r.y());
00567 }
00568 #endif
00569
00570 QString key = val.toString();
00571 QPixmap *pix = 0;
00572 if (!key.isEmpty() && !(pix = d->pixmapCache[ key ])) {
00573
00574 QPixmap pm = KGlobal::iconLoader()->loadIcon( key, KIcon::Small,
00575 0, KIcon::DefaultState, 0L, true );
00576 if (!pm.isNull()) {
00577 pix = new QPixmap(pm);
00578 d->pixmapCache.insert(key, pix);
00579 }
00580 }
00581
00582 if (p && pix) {
00583 p->drawPixmap( (w-pix->width())/2, (h-pix->height())/2, *pix );
00584 }
00585 }
00586
00587 void KexiKIconTableEdit::handleCopyAction(const QVariant& value, const QVariant& visibleValue)
00588 {
00589 Q_UNUSED(value);
00590 Q_UNUSED(visibleValue);
00591 }
00592
00593 KEXI_CELLEDITOR_FACTORY_ITEM_IMPL(KexiKIconTableEditorFactoryItem, KexiKIconTableEdit)
00594
00595 #include "kexiblobtableedit.moc"