kexi

kexiblobtableedit.cpp

00001 /* This file is part of the KDE project
00002    Copyright (C) 2002 Peter Simonsson <psn@linux.se>
00003    Copyright (C) 2004, 2006 Jaroslaw Staniek <js@iidea.pl>
00004 
00005    This program is free software; you can redistribute it and/or
00006    modify it under the terms of the GNU Library General Public
00007    License as published by the Free Software Foundation; either
00008    version 2 of the License, or (at your option) any later version.
00009 
00010    This program is distributed in the hope that it will be useful,
00011    but WITHOUT ANY WARRANTY; without even the implied warranty of
00012    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013    Library General Public License for more details.
00014 
00015    You should have received a copy of the GNU Library General Public License
00016    along with this program; see the file COPYING.  If not, write to
00017    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00018  * Boston, MA 02110-1301, USA.
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 //  m_proc = 0;
00089 //  m_content = 0;
00090     m_hasFocusableWidget = false;
00091     d->button = new KexiDropDownButton( parentWidget() /*usually a viewport*/ );
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     //force edit requested to start editing... (this will call slotUpdateActionsAvailabilityRequested())
00104     //connect(d->popup, SIGNAL(aboutToShow()), this, SIGNAL(editRequested()));
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         //todo
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 //do not add "m_origValue" to "add" as this is QByteArray
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 //TODO
00171     d->value.size();
00172     return d->value.isEmpty();
00173 }
00174 
00175 bool KexiBlobTableEdit::valueIsEmpty()
00176 {
00177 //TODO
00178     return d->value.isEmpty();
00179 }
00180 
00181 QVariant
00182 KexiBlobTableEdit::value()
00183 {
00184     return d->value;
00185 #if 0
00186     //todo
00187 //  ok = true;
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 //  d->currentEditorWidth = w;
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; //a place for border
00227     h -= 1; //a place for border
00228     if (p && val.canCast(QVariant::ByteArray) && pixmap.loadFromData(val.toByteArray())) {
00229         KexiUtils::drawPixmap( *p, 0/*lineWidth*/, QRect(x, y_offset, w, h), 
00230             pixmap, Qt::AlignCenter, true/*scaledContents*/, true/*keepAspectRatio*/);
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 //  m_valueMimeType = KImageIO::mimeType( fileName ); 
00265     setValueInternal( ba, true );
00266     signalEditRequested();
00267     //emit acceptRequested();
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" )) {// write pixmap into ba in PNG format
00324         setValueInternal( ba, true );
00325     }
00326     else {
00327         setValueInternal( QByteArray(), true );
00328     }
00329     signalEditRequested();
00330     //emit acceptRequested();
00331     repaintRelatedCell();
00332 }
00333 
00334 void KexiBlobTableEdit::clear()
00335 {
00336     setValueInternal( QByteArray(), true );
00337     signalEditRequested();
00338     //emit acceptRequested();
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; //cache for slotUpdateActionsAvailabilityRequested() 
00350 //  d->button->move( pos().x()+ width(), pos().y() );
00351     updateFocus( r );
00352 //  d->button->setEnabled(!readOnly);
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 //todo  if (d->popup) {
00371 //todo      d->popup->updateSize();
00372 //todo  }
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 ); //re-send to move cursor
00468             return true;
00469         }
00470     }
00471     return false;
00472 }
00473 
00474 KEXI_CELLEDITOR_FACTORY_ITEM_IMPL(KexiBlobEditorFactoryItem, KexiBlobTableEdit)
00475 
00476 //=======================
00477 // KexiKIconTableEdit class is temporarily here:
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& /*add*/, bool /*removeOld*/)
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 /*focused*/, const QVariant& val, 
00548     QString &/*txt*/, int &/*align*/, int &/*x*/, 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 );//avoid too large box
00561     QRect r( QMAX( w/2 - s/2, 0 ) , h/2 - s/2 /*- 1*/, 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         //cache pixmap
00574         QPixmap pm = KGlobal::iconLoader()->loadIcon( key, KIcon::Small, 
00575             0, KIcon::DefaultState, 0L, true/*canReturnNull*/ );
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"
KDE Home | KDE Accessibility Home | Description of Access Keys