diff options
Diffstat (limited to 'kexi/widget/utils')
26 files changed, 4135 insertions, 0 deletions
diff --git a/kexi/widget/utils/Makefile.am b/kexi/widget/utils/Makefile.am new file mode 100644 index 000000000..5d210f1aa --- /dev/null +++ b/kexi/widget/utils/Makefile.am @@ -0,0 +1,19 @@ +include $(top_srcdir)/kexi/Makefile.global + +lib_LTLIBRARIES = libkexiguiutils.la +libkexiguiutils_la_SOURCES = kexisharedactionclient.cpp kexirecordnavigator.cpp \ + kexigradientwidget.cpp kexirecordmarker.cpp kexidisplayutils.cpp \ + kexiflowlayout.cpp kexidatetimeformatter.cpp kexitooltip.cpp kexiarrowtip.cpp \ + kexidropdownbutton.cpp kexicomboboxdropdownbutton.cpp kexicontextmenuutils.cpp + +libkexiguiutils_la_LDFLAGS = $(all_libraries) $(VER_INFO) -Wnounresolved +libkexiguiutils_la_LIBADD = $(LIB_KDEUI) + +SUBDIRS = . + +# set the include path for X, qt and KDE - all_includes must remain last! +INCLUDES = -I$(top_srcdir)/kexi -I$(top_srcdir)/kexi/widget/utils $(all_includes) + +METASOURCES = AUTO + +noinst_HEADERS = kexigradientwidget.h diff --git a/kexi/widget/utils/kexiarrowtip.cpp b/kexi/widget/utils/kexiarrowtip.cpp new file mode 100644 index 000000000..cdffcb023 --- /dev/null +++ b/kexi/widget/utils/kexiarrowtip.cpp @@ -0,0 +1,164 @@ +/* This file is part of the KDE project + Copyright (C) 2006 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 "kexiarrowtip.h" + +#include <qpixmap.h> +#include <qbitmap.h> +#include <qpainter.h> +#include <qimage.h> +#include <qtooltip.h> +#include <qfont.h> +#include <qfontmetrics.h> +#include <qtimer.h> + +#include <kexiutils/utils.h> + +KexiArrowTip::KexiArrowTip(const QString& text, QWidget* parent) + : KexiToolTip(text, parent) + , m_opacity(0.0) +{ + QPalette pal( palette() ); + QColorGroup cg(pal.active()); + cg.setColor(QColorGroup::Foreground, Qt::red); + pal.setActive(cg); + setPalette(pal); + + QFontMetrics fm(font()); + QSize sz(fm.boundingRect(m_value.toString()).size()); + sz += QSize(14, 10); //+margins + m_arrowHeight = sz.height()/2; + sz += QSize(0, m_arrowHeight); //+arrow height + resize(sz); + + setAutoMask( false ); + + //generate mask + QPixmap maskPm(size()); + maskPm.fill( black ); + QPainter maskPainter(&maskPm); + drawFrame(maskPainter); + QImage maskImg( maskPm.convertToImage() ); + QBitmap bm; + bm = maskImg.createHeuristicMask(); + setMask( bm ); +} + +KexiArrowTip::~KexiArrowTip() +{ +} + +void KexiArrowTip::show() +{ + if (isVisible()) + return; + + m_opacity = 0.0; + setWindowOpacity(0.0); + KexiToolTip::show(); + increaseOpacity(); +} + +void KexiArrowTip::hide() +{ + if (!isVisible()) + return; + + decreaseOpacity(); +} + +void KexiArrowTip::increaseOpacity() +{ + m_opacity += 0.10; + setWindowOpacity(m_opacity); + if (m_opacity < 1.0) + QTimer::singleShot(25, this, SLOT(increaseOpacity())); +} + +void KexiArrowTip::decreaseOpacity() +{ + if (m_opacity<=0.0) { + KexiToolTip::close(); + m_opacity = 0.0; + return; + } + m_opacity -= 0.10; + setWindowOpacity(m_opacity); + QTimer::singleShot(25, this, SLOT(decreaseOpacity())); +} + +bool KexiArrowTip::close ( bool alsoDelete ) +{ + if (!isVisible()) { + return KexiToolTip::close(alsoDelete); + } + if (m_opacity>0.0) + decreaseOpacity(); + else + return KexiToolTip::close(alsoDelete); + return m_opacity<=0.0; +} + +void KexiArrowTip::drawContents(QPainter& p) +{ + p.setPen( QPen(palette().active().foreground(), 1) ); + p.drawText(QRect(0,m_arrowHeight,width(),height()-m_arrowHeight), + Qt::AlignCenter, m_value.toString()); +} + +void KexiArrowTip::drawFrame(QPainter& p) +{ + QPen pen(palette().active().foreground(), 1, Qt::SolidLine, Qt::SquareCap, Qt::MiterJoin); + p.setPen( pen ); + /* + /\ + +- -----+ + | text | + +--------+ + */ + //1st line + const int arrowOffset = 5; //5 pixels to right + QPointArray pa(8); + pa.setPoint(0, 0, m_arrowHeight-1); + pa.setPoint(1, 0, height()-1); + pa.setPoint(2, width()-1, height()-1); + pa.setPoint(3, width()-1, m_arrowHeight-1); + pa.setPoint(4, arrowOffset+m_arrowHeight+m_arrowHeight-2, m_arrowHeight-1); + pa.setPoint(5, arrowOffset+m_arrowHeight-1, 0); + pa.setPoint(6, arrowOffset, m_arrowHeight-1); + pa.setPoint(7, 0, m_arrowHeight-1); + p.drawPolyline(pa); + //-2nd, internal line + pa.resize(12); + pa.setPoint(0, 1, m_arrowHeight); + pa.setPoint(1, 1, height()-2); + pa.setPoint(2, width()-2, height()-2); + pa.setPoint(3, width()-2, m_arrowHeight); + pa.setPoint(4, arrowOffset+m_arrowHeight+m_arrowHeight-2, m_arrowHeight); + pa.setPoint(5, arrowOffset+m_arrowHeight-1, 1); + pa.setPoint(6, arrowOffset, m_arrowHeight); + pa.setPoint(7, 0, m_arrowHeight); + pa.setPoint(8, arrowOffset+1, m_arrowHeight); + pa.setPoint(9, arrowOffset+m_arrowHeight-1, 2); + pa.setPoint(10, arrowOffset+m_arrowHeight+m_arrowHeight-3, m_arrowHeight); + pa.setPoint(11, width()-2, m_arrowHeight); + p.drawPolyline(pa); +} + +#include "kexiarrowtip.moc" diff --git a/kexi/widget/utils/kexiarrowtip.h b/kexi/widget/utils/kexiarrowtip.h new file mode 100644 index 000000000..d6de61868 --- /dev/null +++ b/kexi/widget/utils/kexiarrowtip.h @@ -0,0 +1,56 @@ +/* This file is part of the KDE project + Copyright (C) 2006 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. +*/ + +#ifndef KEXIARROWTIP_H +#define KEXIARROWTIP_H + +#include "kexitooltip.h" + +//! \brief A tooltip-like widget with additional arrow +/*! The widget also suppors fade in and fade out effect, + if the underlying display system supports this. +*/ +class KEXIGUIUTILS_EXPORT KexiArrowTip : public KexiToolTip +{ + Q_OBJECT + public: + KexiArrowTip(const QString& text, QWidget* parent); + virtual ~KexiArrowTip(); + + inline QString text() const { return m_value.toString(); } + virtual bool close() { return close(false); } + virtual bool close( bool alsoDelete ); + + public slots: + virtual void show(); + virtual void hide(); + + protected slots: + void increaseOpacity(); + void decreaseOpacity(); + + protected: + virtual void drawFrame(QPainter& p); + virtual void drawContents(QPainter& p); + + int m_arrowHeight; + double m_opacity; +}; + +#endif diff --git a/kexi/widget/utils/kexicomboboxdropdownbutton.cpp b/kexi/widget/utils/kexicomboboxdropdownbutton.cpp new file mode 100644 index 000000000..407bc6fe5 --- /dev/null +++ b/kexi/widget/utils/kexicomboboxdropdownbutton.cpp @@ -0,0 +1,87 @@ +/* This file is part of the KDE project + Copyright (C) 2006 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 "kexicomboboxdropdownbutton.h" + +#include <kpopupmenu.h> +#include <kdebug.h> +#include <kcombobox.h> + +#include <qstyle.h> +#include <qapplication.h> + +KexiComboBoxDropDownButton::KexiComboBoxDropDownButton( QWidget *parent ) + : KPushButton(parent) +{ + m_paintedCombo = new KComboBox(this); + m_paintedCombo->hide(); + m_paintedCombo->setEditable(true); + + setToggleButton(true); + styleChange(style()); + m_paintedCombo->move(0,0); + m_paintedCombo->setFixedSize(size()); +} + +KexiComboBoxDropDownButton::~KexiComboBoxDropDownButton() +{ +} + +void KexiComboBoxDropDownButton::drawButton(QPainter *p) +{ + int flags = QStyle::Style_Enabled | QStyle::Style_HasFocus; + if (isDown()) + flags |= QStyle::Style_Down; + + KPushButton::drawButton(p); + + QRect r = rect(); + r.setHeight(r.height()+m_fixForHeight); + if (m_drawComplexControl) { + if (m_fixForHeight>0 && m_paintedCombo->size()!=size()) { + m_paintedCombo->move(0,0); + m_paintedCombo->setFixedSize(size()+QSize(0, m_fixForHeight)); //last chance to fix size + } + style().drawComplexControl( QStyle::CC_ComboBox, p, + m_fixForHeight>0 ? (const QWidget*)m_paintedCombo : this, r, colorGroup(), + flags, (uint)(QStyle::SC_ComboBoxArrow), QStyle::SC_None ); + } + else { + r.setWidth(r.width()+2); + style().drawPrimitive( QStyle::PE_ArrowDown, p, r, colorGroup(), flags); + } +} + +void KexiComboBoxDropDownButton::styleChange( QStyle & oldStyle ) +{ + //<hack> + if (qstricmp(style().name(),"thinkeramik")==0) { + m_fixForHeight = 3; + } + else + m_fixForHeight = 0; + //</hack> + m_drawComplexControl = + (style().inherits("KStyle") && qstricmp(style().name(),"qtcurve")!=0) + || qstricmp(style().name(),"platinum")==0; + if (m_fixForHeight==0) + setFixedWidth( style().querySubControlMetrics( QStyle::CC_ComboBox, + (const QWidget*)m_paintedCombo, QStyle::SC_ComboBoxArrow ).width() +1 ); + KPushButton::styleChange(oldStyle); +} diff --git a/kexi/widget/utils/kexicomboboxdropdownbutton.h b/kexi/widget/utils/kexicomboboxdropdownbutton.h new file mode 100644 index 000000000..da53a7e2e --- /dev/null +++ b/kexi/widget/utils/kexicomboboxdropdownbutton.h @@ -0,0 +1,49 @@ +/* This file is part of the KDE project + Copyright (C) 2006 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. +*/ + +#ifndef KexiComboBoxDropDownButton_H +#define KexiComboBoxDropDownButton_H + +#include <kpushbutton.h> + +class KComboBox; + +//! @short A drop-down button for combo box widgets +/*! Used in KexiComboBoxTableEdit. +*/ +class KEXIGUIUTILS_EXPORT KexiComboBoxDropDownButton : public KPushButton +{ + public: + KexiComboBoxDropDownButton( QWidget *parent ); + virtual ~KexiComboBoxDropDownButton(); + + protected: + /*! Reimplemented after @ref KPushButton to draw drop-down arrow. */ + virtual void drawButton(QPainter *p); + + /*! Reimplemented after @ref KPushButton to adapt size to style changes. */ + virtual void styleChange( QStyle & oldStyle ); + + int m_fixForHeight; + bool m_drawComplexControl : 1; + KComboBox *m_paintedCombo; //!< fake combo used only to pass it as 'this' for QStyle + //!< (because styles use \<static_cast\>) +}; + +#endif diff --git a/kexi/widget/utils/kexicontextmenuutils.cpp b/kexi/widget/utils/kexicontextmenuutils.cpp new file mode 100644 index 000000000..727cef6f0 --- /dev/null +++ b/kexi/widget/utils/kexicontextmenuutils.cpp @@ -0,0 +1,283 @@ +/* This file is part of the KDE project + Copyright (C) 2006-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 "kexicontextmenuutils.h" + +#include <kactioncollection.h> +#include <klocale.h> +#include <kiconloader.h> +#include <kfiledialog.h> +#include <kimageio.h> +#include <kdebug.h> +#include <kmessagebox.h> + +#include <qfiledialog.h> +#include <qapplication.h> + +#ifdef Q_WS_WIN +#include <win32_utils.h> +#include <krecentdirs.h> +#endif + +//! @internal +class KexiImageContextMenu::Private +{ +public: + Private(QWidget *parent) + : actionCollection(parent) + { + } + + KActionCollection actionCollection; + KAction *insertFromFileAction, *saveAsAction, *cutAction, *copyAction, *pasteAction, + *deleteAction +#ifdef KEXI_NO_UNFINISHED + , *propertiesAction +#endif + ; +}; + +//------------ + +KexiImageContextMenu::KexiImageContextMenu(QWidget* parent) + : KPopupMenu(parent) + , d( new Private(this) ) +{ + setName("KexiImageContextMenu"); + insertTitle(QString::null); + + d->insertFromFileAction = new KAction(i18n("Insert From &File..."), SmallIconSet("fileopen"), 0, + this, SLOT(insertFromFile()), &d->actionCollection, "insert"); + d->insertFromFileAction->plug(this); + d->saveAsAction = KStdAction::saveAs(this, SLOT(saveAs()), &d->actionCollection); +// d->saveAsAction->setText(i18n("&Save &As...")); + d->saveAsAction->plug(this); + insertSeparator(); + d->cutAction = KStdAction::cut(this, SLOT(cut()), &d->actionCollection); + d->cutAction->plug(this); + d->copyAction = KStdAction::copy(this, SLOT(copy()), &d->actionCollection); + d->copyAction->plug(this); + d->pasteAction = KStdAction::paste(this, SLOT(paste()), &d->actionCollection); + d->pasteAction->plug(this); + d->deleteAction = new KAction(i18n("&Clear"), SmallIconSet("editdelete"), 0, + this, SLOT(clear()), &d->actionCollection, "delete"); + d->deleteAction->plug(this); +#ifdef KEXI_NO_UNFINISHED + d->propertiesAction = 0; +#else + insertSeparator(); + d->propertiesAction = new KAction(i18n("Properties"), 0, 0, + this, SLOT(showProperties()), &d->actionCollection, "properties"); + d->propertiesAction->plug(this); +#endif + connect(this, SIGNAL(aboutToShow()), this, SLOT(updateActionsAvailability())); +} + +KexiImageContextMenu::~KexiImageContextMenu() +{ + delete d; +} + +void KexiImageContextMenu::insertFromFile() +{ +// QWidget *focusWidget = qApp->focusWidget(); +#ifdef Q_WS_WIN + QString recentDir; + QString fileName = QFileDialog::getOpenFileName( + KFileDialog::getStartURL(":LastVisitedImagePath", recentDir).path(), + convertKFileDialogFilterToQFileDialogFilter(KImageIO::pattern(KImageIO::Reading)), + this, 0, i18n("Insert Image From File")); + KURL url; + if (!fileName.isEmpty()) + url.setPath( fileName ); +#else + KURL url( KFileDialog::getImageOpenURL( + ":LastVisitedImagePath", this, i18n("Insert Image From File")) ); +// QString fileName = url.isLocalFile() ? url.path() : url.prettyURL(); + + //! @todo download the file if remote, then set fileName properly +#endif + if (!url.isValid()) { + //focus the app again because to avoid annoying the user with unfocused main window + if (qApp->mainWidget()) { + //focusWidget->raise(); + //focusWidget->setFocus(); + qApp->mainWidget()->raise(); + } + return; + } + kexipluginsdbg << "fname=" << url.prettyURL() << endl; + +#ifdef Q_WS_WIN + //save last visited path +// KURL url(fileName); + if (url.isLocalFile()) + KRecentDirs::add(":LastVisitedImagePath", url.directory()); +#endif + + emit insertFromFileRequested(url); + if (qApp->mainWidget()) { +// focusWidget->raise(); +// focusWidget->setFocus(); + qApp->mainWidget()->raise(); + } +} + +void KexiImageContextMenu::saveAs() +{ + QString origFilename, fileExtension; + bool dataIsEmpty = false; + emit aboutToSaveAsRequested(origFilename, fileExtension, dataIsEmpty); + + if (dataIsEmpty) { + kdWarning() << "KexiImageContextMenu::saveAs(): no data!" << endl; + return; + } + if (!origFilename.isEmpty()) + origFilename = QString("/") + origFilename; + + if (fileExtension.isEmpty()) { + // PNG data is the default + fileExtension = "png"; + } + +#ifdef Q_WS_WIN + QString recentDir; + QString fileName = QFileDialog::getSaveFileName( + KFileDialog::getStartURL(":LastVisitedImagePath", recentDir).path() + origFilename, + convertKFileDialogFilterToQFileDialogFilter(KImageIO::pattern(KImageIO::Writing)), + this, 0, i18n("Save Image to File")); +#else + //! @todo add originalFileName! (requires access to KRecentDirs) + QString fileName = KFileDialog::getSaveFileName( + ":LastVisitedImagePath", KImageIO::pattern(KImageIO::Writing), this, i18n("Save Image to File")); +#endif + if (fileName.isEmpty()) + return; + + if (QFileInfo(fileName).extension().isEmpty()) + fileName += (QString(".")+fileExtension); + kdDebug() << fileName << endl; + KURL url; + url.setPath( fileName ); + +#ifdef Q_WS_WIN + //save last visited path + if (url.isLocalFile()) + KRecentDirs::add(":LastVisitedImagePath", url.directory()); +#endif + + QFile f(fileName); + if (f.exists() && KMessageBox::Yes != KMessageBox::warningYesNo(this, + "<qt>"+i18n("File \"%1\" already exists." + "<p>Do you want to replace it with a new one?") + .arg(QDir::convertSeparators(fileName))+"</qt>",0, + KGuiItem(i18n("&Replace")), KGuiItem(i18n("&Don't Replace")))) + { + return; + } + +//! @todo use KURL? + emit saveAsRequested(fileName); +} + +void KexiImageContextMenu::cut() +{ + emit cutRequested(); +} + +void KexiImageContextMenu::copy() +{ + emit copyRequested(); +} + +void KexiImageContextMenu::paste() +{ + emit pasteRequested(); +} + +void KexiImageContextMenu::clear() +{ + emit clearRequested(); +} + +void KexiImageContextMenu::showProperties() +{ + emit showPropertiesRequested(); +} + +void KexiImageContextMenu::updateActionsAvailability() +{ + bool valueIsNull = true; + bool valueIsReadOnly = true; + emit updateActionsAvailabilityRequested(valueIsNull, valueIsReadOnly); + + d->insertFromFileAction->setEnabled( !valueIsReadOnly ); + d->saveAsAction->setEnabled( !valueIsNull ); + d->cutAction->setEnabled( !valueIsNull && !valueIsReadOnly ); + d->copyAction->setEnabled( !valueIsNull ); + d->pasteAction->setEnabled( !valueIsReadOnly ); + d->deleteAction->setEnabled( !valueIsNull && !valueIsReadOnly ); + if (d->propertiesAction) + d->propertiesAction->setEnabled( !valueIsNull ); +} + +KActionCollection* KexiImageContextMenu::actionCollection() const +{ + return &d->actionCollection; +} + +//static +bool KexiImageContextMenu::updateTitle(QPopupMenu *menu, const QString& title, const QString& iconName) +{ + return KexiContextMenuUtils::updateTitle(menu, title, i18n("Image"), iconName); +} + +// ------------------------------------------- + +//static +bool KexiContextMenuUtils::updateTitle(QPopupMenu *menu, const QString& objectName, + const QString& objectTypeName, const QString& iconName) +{ + if (!menu || objectName.isEmpty() || objectTypeName.isEmpty()) + return false; + const int id = menu->idAt(0); + QMenuItem *item = menu->findItem(id); + if (!item) + return false; + KPopupTitle *title = dynamic_cast<KPopupTitle *>(item->widget()); + if (!title) + return false; + +/*! @todo look at makeFirstCharacterUpperCaseInCaptions setting [bool] + (see doc/dev/settings.txt) */ + QString realTitle( i18n("Object name : Object type", "%1 : %2") + .arg( objectName[0].upper() + objectName.mid(1) ) + .arg( objectTypeName )); + + if (iconName.isEmpty()) + title->setTitle(realTitle); + else { + QPixmap pixmap(SmallIcon( iconName )); + title->setTitle(realTitle, &pixmap); + } + return true; +} + +#include "kexicontextmenuutils.moc" diff --git a/kexi/widget/utils/kexicontextmenuutils.h b/kexi/widget/utils/kexicontextmenuutils.h new file mode 100644 index 000000000..95258e964 --- /dev/null +++ b/kexi/widget/utils/kexicontextmenuutils.h @@ -0,0 +1,112 @@ +/* This file is part of the KDE project + Copyright (C) 2006-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. +*/ + +#ifndef KexiContextMenuUtils_H +#define KexiContextMenuUtils_H + +#include <kexidb/queryschema.h> +#include <kpopupmenu.h> +#include <kurl.h> + +class KActionCollection; +class KexiDataItemInterface; + +//! @short A set of helpers for updating popup menu titles +/*! The functions set meaningful titles like "Emploee : Image". +*/ +class KEXIGUIUTILS_EXPORT KexiContextMenuUtils +{ + public: + /*! Updates title for context menu. + \return true if the title has been updated. */ + static bool updateTitle(QPopupMenu *menu, const QString& objectName, + const QString& objectTypeName, const QString& iconName); +}; + +//! @short A context menu used for images within form and table views +/*! Used in KexiDBImageBox and KexiBlobTableEdit. + Contains actions like insert, save, copy, paste, clear. + + Signals like insertFromFileRequested() are all connected to + handlers in KexiDBImageBox and KexiBlobTableEdit so these objects can + respond on requests for data handling. +*/ +class KEXIGUIUTILS_EXPORT KexiImageContextMenu : public KPopupMenu +{ + Q_OBJECT + + public: + KexiImageContextMenu(QWidget *parent); + virtual ~KexiImageContextMenu(); + + KActionCollection* actionCollection() const; + + /*! Updates title for context menu. + Used in KexiDBWidgetContextMenuExtender::createTitle(QPopupMenu *menu) and KexiDBImageBox. + \return true if the title has been updated. */ + static bool updateTitle(QPopupMenu *menu, const QString& title, const QString& iconName = QString::null); + + public slots: + void updateActionsAvailability(); + + virtual void insertFromFile(); + virtual void saveAs(); + virtual void cut(); + virtual void copy(); + virtual void paste(); + virtual void clear(); + virtual void showProperties(); + + signals: + //! Emitted when actions availability should be performed. Just connect this signal + //! to a slot and set \a valueIsNull and \a valueIsReadOnly. + void updateActionsAvailabilityRequested(bool& valueIsNull, bool& valueIsReadOnly); + + /*! Emitted before "insertFromFile" action was requested. */ + void insertFromFileRequested(const KURL &url); + + /*! Emitted before "saveAs" action was requested. + You should fill \a origFilename, \a fileExtension and \a dataIsEmpty values. + If \a dataIsEmpty is false, saving will be cancelled. */ + void aboutToSaveAsRequested(QString& origFilename, QString& fileExtension, bool& dataIsEmpty); + + //! Emitted when "saveAs" action was requested + void saveAsRequested(const QString& fileName); + + //! Emitted when "cut" action was requested + void cutRequested(); + + //! Emitted when "copy" action was requested + void copyRequested(); + + //! Emitted when "paste" action was requested + void pasteRequested(); + + //! Emitted when "clear" action was requested + void clearRequested(); + + //! Emitted when "showProperties" action was requested + void showPropertiesRequested(); + + protected: + class Private; + Private *d; +}; + +#endif diff --git a/kexi/widget/utils/kexidatetimeformatter.cpp b/kexi/widget/utils/kexidatetimeformatter.cpp new file mode 100644 index 000000000..d8f642ca0 --- /dev/null +++ b/kexi/widget/utils/kexidatetimeformatter.cpp @@ -0,0 +1,367 @@ +/* This file is part of the KDE project + Copyright (C) 2006 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 "kexidatetimeformatter.h" + +#include <kdebug.h> +#include <klocale.h> +#include <kglobal.h> +#include <kdatepicker.h> +#include <kdatetbl.h> +#include <klineedit.h> +#include <kpopupmenu.h> +#include <kdatewidget.h> + +KexiDateFormatter::KexiDateFormatter() +{ + // use "short date" format system settings +//! @todo allow to override the format using column property and/or global app settings + QString df( KGlobal::locale()->dateFormatShort() ); + if (df.length()>2) + m_separator = df.mid(2,1); + else + m_separator = "-"; + const int separatorLen = m_separator.length(); + QString yearMask("9999"); + QString yearDateFormat("yyyy"), + monthDateFormat("MM"), + dayDateFormat("dd"); //for setting up m_dateFormat + bool ok = df.length()>=8; + int yearpos, monthpos, daypos; //result of df.find() + if (ok) {//look at % variables +//! @todo more variables are possible here, see void KLocale::setDateFormatShort() docs +//! http://developer.kde.org/documentation/library/3.5-api/kdelibs-apidocs/kdecore/html/classKLocale.html#a59 + yearpos = df.find("%y", 0, false); //&y or %y + m_longYear = !(yearpos>=0 && df.mid(yearpos+1, 1)=="y"); + if (!m_longYear) { + yearMask = "99"; + yearDateFormat = "yy"; + } + monthpos = df.find("%m", 0, true); //%m or %n + m_monthWithLeadingZero = true; + if (monthpos<0) { + monthpos = df.find("%n", 0, false); + m_monthWithLeadingZero = false; + monthDateFormat = "M"; + } + daypos = df.find("%d", 0, true);//%d or %e + m_dayWithLeadingZero = true; + if (daypos<0) { + daypos = df.find("%e", 0, false); + m_dayWithLeadingZero = false; + dayDateFormat = "d"; + } + ok = (yearpos>=0 && monthpos>=0 && daypos>=0); + } + m_order = QDateEdit::YMD; //default + if (ok) { + if (yearpos<monthpos && monthpos<daypos) { + //will be set in "default: YMD" + } + else if (yearpos<daypos && daypos<monthpos) { + m_order = QDateEdit::YDM; +//! @todo use QRegExp (to replace %Y by %1, etc.) instead of hardcoded "%1%299%399" +//! because df may contain also other characters + m_inputMask = QString("%1%299%399").arg(yearMask).arg(m_separator).arg(m_separator); + m_qtFormat = yearDateFormat+m_separator+dayDateFormat+m_separator+monthDateFormat; + m_yearpos = 0; + m_daypos = yearMask.length()+separatorLen; + m_monthpos = m_daypos+2+separatorLen; + } + else if (daypos<monthpos && monthpos<yearpos) { + m_order = QDateEdit::DMY; + m_inputMask = QString("99%199%2%3").arg(m_separator).arg(m_separator).arg(yearMask); + m_qtFormat = dayDateFormat+m_separator+monthDateFormat+m_separator+yearDateFormat; + m_daypos = 0; + m_monthpos = 2+separatorLen; + m_yearpos = m_monthpos+2+separatorLen; + } + else if (monthpos<daypos && daypos<yearpos) { + m_order = QDateEdit::MDY; + m_inputMask = QString("99%199%2%3").arg(m_separator).arg(m_separator).arg(yearMask); + m_qtFormat = monthDateFormat+m_separator+dayDateFormat+m_separator+yearDateFormat; + m_monthpos = 0; + m_daypos = 2+separatorLen; + m_yearpos = m_daypos+2+separatorLen; + } + else + ok = false; + } + if (!ok || m_order == QDateEdit::YMD) {//default: YMD + m_inputMask = QString("%1%299%399").arg(yearMask).arg(m_separator).arg(m_separator); + m_qtFormat = yearDateFormat+m_separator+monthDateFormat+m_separator+dayDateFormat; + m_yearpos = 0; + m_monthpos = yearMask.length()+separatorLen; + m_daypos = m_monthpos+2+separatorLen; + } + m_inputMask += ";_"; +} + +KexiDateFormatter::~KexiDateFormatter() +{ +} + +QDate KexiDateFormatter::stringToDate( const QString& str ) const +{ + bool ok = true; + int year = str.mid(m_yearpos, m_longYear ? 4 : 2).toInt(&ok); + if (!ok) + return QDate(); + if (year < 30) {//2000..2029 + year = 2000 + year; + } + else if (year < 100) {//1930..1999 + year = 1900 + year; + } + + int month = str.mid(m_monthpos, 2).toInt(&ok); + if (!ok) + return QDate(); + + int day = str.mid(m_daypos, 2).toInt(&ok); + if (!ok) + return QDate(); + + QDate date(year, month, day); + if (!date.isValid()) + return QDate(); + return date; +} + +QVariant KexiDateFormatter::stringToVariant( const QString& str ) const +{ + if (isEmpty(str)) + return QVariant(); + const QDate date( stringToDate( str ) ); + if (date.isValid()) + return date; + return QVariant(); +} + +bool KexiDateFormatter::isEmpty( const QString& str ) const +{ + QString s(str); + return s.replace(m_separator,"").stripWhiteSpace().isEmpty(); +} + +QString KexiDateFormatter::dateToString( const QDate& date ) const +{ + return date.toString(m_qtFormat); +} + +//------------------------------------------------ + +KexiTimeFormatter::KexiTimeFormatter() +: m_hmsRegExp( new QRegExp("(\\d*):(\\d*):(\\d*).*( am| pm){,1}", false/*!CS*/) ) + , m_hmRegExp( new QRegExp("(\\d*):(\\d*).*( am| pm){,1}", false/*!CS*/) ) +{ + QString tf( KGlobal::locale()->timeFormat() ); + //m_hourpos, m_minpos, m_secpos; are result of tf.find() + QString hourVariable, minVariable, secVariable; + + //detect position of HOUR section: find %H or %k or %I or %l + m_24h = true; + m_hoursWithLeadingZero = true; + m_hourpos = tf.find("%H", 0, true); + if (m_hourpos>=0) { + m_24h = true; + m_hoursWithLeadingZero = true; + } + else { + m_hourpos = tf.find("%k", 0, true); + if (m_hourpos>=0) { + m_24h = true; + m_hoursWithLeadingZero = false; + } + else { + m_hourpos = tf.find("%I", 0, true); + if (m_hourpos>=0) { + m_24h = false; + m_hoursWithLeadingZero = true; + } + else { + m_hourpos = tf.find("%l", 0, true); + if (m_hourpos>=0) { + m_24h = false; + m_hoursWithLeadingZero = false; + } + } + } + } + m_minpos = tf.find("%M", 0, true); + m_secpos = tf.find("%S", 0, true); //can be -1 + m_ampmpos = tf.find("%p", 0, true); //can be -1 + + if (m_hourpos<0 || m_minpos<0) { + //set default: hr and min are needed, sec are optional + tf = "%H:%M:%S"; + m_24h = true; + m_hoursWithLeadingZero = false; + m_hourpos = 0; + m_minpos = 3; + m_secpos = m_minpos + 3; + m_ampmpos = -1; + } + hourVariable = tf.mid(m_hourpos, 2); + + m_inputMask = tf; +// m_inputMask.replace( hourVariable, "00" ); +// m_inputMask.replace( "%M", "00" ); +// m_inputMask.replace( "%S", "00" ); //optional + m_inputMask.replace( hourVariable, "99" ); + m_inputMask.replace( "%M", "99" ); + m_inputMask.replace( "%S", "00" ); //optional + m_inputMask.replace( "%p", "AA" ); //am or pm + m_inputMask += ";_"; + + m_outputFormat = tf; +} + +KexiTimeFormatter::~KexiTimeFormatter() +{ + delete m_hmsRegExp; + delete m_hmRegExp; +} + +QTime KexiTimeFormatter::stringToTime( const QString& str ) const +{ + int hour, min, sec; + bool pm = false; + + bool tryWithoutSeconds = true; + if (m_secpos>=0) { + if (-1 != m_hmsRegExp->search(str)) { + hour = m_hmsRegExp->cap(1).toInt(); + min = m_hmsRegExp->cap(2).toInt(); + sec = m_hmsRegExp->cap(3).toInt(); + if (m_ampmpos >= 0 && m_hmsRegExp->numCaptures()>3) + pm = m_hmsRegExp->cap(4).stripWhiteSpace().lower()=="pm"; + tryWithoutSeconds = false; + } + } + if (tryWithoutSeconds) { + if (-1 == m_hmRegExp->search(str)) + return QTime(99,0,0); + hour = m_hmRegExp->cap(1).toInt(); + min = m_hmRegExp->cap(2).toInt(); + sec = 0; + if (m_ampmpos >= 0 && m_hmRegExp->numCaptures()>2) + pm = m_hmsRegExp->cap(4).lower()=="pm"; + } + + if (pm && hour < 12) + hour += 12; //PM + return QTime(hour, min, sec); +} + +QVariant KexiTimeFormatter::stringToVariant( const QString& str ) +{ + if (isEmpty( str )) + return QVariant(); + const QTime time( stringToTime( str ) ); + if (time.isValid()) + return time; + return QVariant(); +} + +bool KexiTimeFormatter::isEmpty( const QString& str ) const +{ + QString s(str); + return s.replace(':',"").stripWhiteSpace().isEmpty(); +} + +QString KexiTimeFormatter::timeToString( const QTime& time ) const +{ + if (!time.isValid()) + return QString::null; + + QString s(m_outputFormat); + if (m_24h) { + if (m_hoursWithLeadingZero) + s.replace( "%H", QString::fromLatin1(time.hour()<10 ? "0" : "") + QString::number(time.hour()) ); + else + s.replace( "%k", QString::number(time.hour()) ); + } + else { + int time12 = (time.hour()>12) ? (time.hour()-12) : time.hour(); + if (m_hoursWithLeadingZero) + s.replace( "%I", QString::fromLatin1(time12<10 ? "0" : "") + QString::number(time12) ); + else + s.replace( "%l", QString::number(time12) ); + } + s.replace( "%M", QString::fromLatin1(time.minute()<10 ? "0" : "") + QString::number(time.minute()) ); + if (m_secpos>=0) + s.replace( "%S", QString::fromLatin1(time.second()<10 ? "0" : "") + QString::number(time.second()) ); + if (m_ampmpos>=0) + s.replace( "%p", KGlobal::locale()->translate( time.hour()>=12 ? "pm" : "am") ); + return s; +} + +//------------------------------------------------ + +QString dateTimeInputMask(const KexiDateFormatter& dateFormatter, const KexiTimeFormatter& timeFormatter) +{ + QString mask(dateFormatter.inputMask()); + mask.truncate(dateFormatter.inputMask().length()-2); + return mask + " " + timeFormatter.inputMask(); +} + +QDateTime stringToDateTime( + const KexiDateFormatter& dateFormatter, const KexiTimeFormatter& timeFormatter, const QString& str) +{ + QString s( str.stripWhiteSpace() ); + const int timepos = s.find(" "); + const bool emptyTime = timepos >= 0 && timeFormatter.isEmpty(s.mid(timepos+1)); //.replace(':',"").stripWhiteSpace().isEmpty(); + if (emptyTime) + s = s.left(timepos); + if (timepos>0 && !emptyTime) { + return QDateTime( + dateFormatter.stringToDate( s.left(timepos) ), + timeFormatter.stringToTime( s.mid(timepos+1) ) + ); + } + else { + return QDateTime( + dateFormatter.stringToDate( s ), + QTime(0,0,0) + ); + } +} + +bool dateTimeIsEmpty( const KexiDateFormatter& dateFormatter, const KexiTimeFormatter& timeFormatter, + const QString& str ) +{ + int timepos = str.find(" "); + const bool emptyTime = timepos >= 0 && timeFormatter.isEmpty(str.mid(timepos+1)); //s.mid(timepos+1).replace(':',"").stripWhiteSpace().isEmpty(); + return (timepos >= 0 && dateFormatter.isEmpty(str.left(timepos)) //s.left(timepos).replace(m_dateFormatter.separator(), "").stripWhiteSpace().isEmpty() + && emptyTime); +} + +bool dateTimeIsValid( const KexiDateFormatter& dateFormatter, + const KexiTimeFormatter& timeFormatter, const QString& str ) +{ + int timepos = str.find(" "); + const bool emptyTime = timepos >= 0 && timeFormatter.isEmpty(str.mid(timepos+1)); //s.mid(timepos+1).replace(':',"").stripWhiteSpace().isEmpty(); + if (timepos >= 0 && dateFormatter.isEmpty(str.left(timepos)) // s.left(timepos).replace(m_dateFormatter.separator(), "").stripWhiteSpace().isEmpty() + && emptyTime) + //empty date/time is valid + return true; + return timepos>=0 && dateFormatter.stringToDate( str.left(timepos) ).isValid() + && (emptyTime /*date without time is also valid*/ || timeFormatter.stringToTime( str.mid(timepos+1) ).isValid()); +} diff --git a/kexi/widget/utils/kexidatetimeformatter.h b/kexi/widget/utils/kexidatetimeformatter.h new file mode 100644 index 000000000..252bc535e --- /dev/null +++ b/kexi/widget/utils/kexidatetimeformatter.h @@ -0,0 +1,165 @@ +/* This file is part of the KDE project + Copyright (C) 2006 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. +*/ + +#ifndef KEXIDATETIMEFORMATTER_H +#define KEXIDATETIMEFORMATTER_H + +#include <qdatetimeedit.h> +#include <qregexp.h> + +//! @short Date formatter used by KexiDateTableEdit and KexiDateTimeTableEdit +class KEXIGUIUTILS_EXPORT KexiDateFormatter +{ + public: + //! Creates new formatter with KDE setting for "short date" + KexiDateFormatter(); + + //! Creates new formatter with given settings +//! @todo KexiDateFormatter(... settings ...); + + ~KexiDateFormatter(); + + //! Converts string \a str to date using predefined settings. + //! \return invalid date if the conversion is impossible + QDate stringToDate( const QString& str ) const; + + /*! Converts string \a str to date using predefined settings + and returns QVariant containing the date value. + This method does the same as stringToDate() but if \a string + contains invalid date representation, e.g. contains only spaces + and separators, null QVariant() is returned. */ + QVariant stringToVariant( const QString& str ) const; + + //! Converts \a date to string using predefined settings. + //! \return null string if \a date is invalid + QString dateToString( const QDate& date ) const; + + //! \return Input mask generated using the formatter settings. + //! Can be used in QLineEdit::setInputMask(). + QString inputMask() const { return m_inputMask; } + + //! \return separator for this date format, a single character like "-" or "/" + QString separator() const { return m_separator; } + + //! \return true if \a str contains only spaces + //! and separators according to the date format. + bool isEmpty( const QString& str ) const; + + protected: + //! Input mask generated using the formatter settings. Can be used in QLineEdit::setInputMask(). + QString m_inputMask; + + //! Order of date sections + QDateEdit::Order m_order; + + //! 4 or 2 digits + bool m_longYear; + + bool m_monthWithLeadingZero, m_dayWithLeadingZero; + + //! Date format used in dateToString() + QString m_qtFormat; + + //! Used in stringToDate() to convert string back to QDate + int m_yearpos, m_monthpos, m_daypos; + + QString m_separator; +}; + +/*! @short Time formatter used by KexiTimeTableEdit and KexiDateTimeTableEdit + Following time formats are allowed: HH:MM:SS (24h), HH:MM (24h), HH:MM AM/PM (12h) + Separator MUST be ":" */ +class KEXIGUIUTILS_EXPORT KexiTimeFormatter +{ + public: + //! Creates new formatter with KDE setting for time + KexiTimeFormatter(); + + //! Creates new formatter with given settings +//! @todo KexiDateFormatter(... settings ...); + + ~KexiTimeFormatter(); + + //! converts string \a str to time using predefined settings + //! \return invalid time if the conversion is impossible + QTime stringToTime( const QString& str ) const; + + /*! Converts string \a str to time using predefined settings + and returns QVariant containing the time value. + This method does the same as stringToTime() but if \a string + contains invalid time representation, e.g. contains only spaces + and separators, null QVariant() is returned. */ + QVariant stringToVariant( const QString& str ); + + //! converts \a time to string using predefined settings + //! \return null string if \a time is invalid + QString timeToString( const QTime& time ) const; + + //! \return Input mask generated using the formatter settings. + //! Can be used in QLineEdit::setInputMask(). + QString inputMask() const { return m_inputMask; } + + //! \return true if \a str contains only spaces + //! and separators according to the time format. + bool isEmpty( const QString& str ) const; + + protected: + //! Input mask generated using the formatter settings. Can be used in QLineEdit::setInputMask(). + QString m_inputMask; + +// //! Order of date sections +// QDateEdit::Order m_order; + + //! 12 or 12h + bool m_24h; + + bool m_hoursWithLeadingZero; + + //! Time format used in timeToString(). Notation from KLocale::setTimeFormat() is used. + QString m_outputFormat; + + //! Used in stringToTime() to convert string back to QTime + int m_hourpos, m_minpos, m_secpos, m_ampmpos; + + QRegExp *m_hmsRegExp, *m_hmRegExp; +}; + +//! \return a date/time input mask using date and time formatter. +//! Date is separated from time by one space character. +KEXIGUIUTILS_EXPORT QString dateTimeInputMask( + const KexiDateFormatter& dateFormatter, const KexiTimeFormatter& timeFormatter); + +/*! \return a QDateTime value converted from string using \a dateFormatter and \a timeFormatter. + A single space between date and time is assumed. + Invalid value is returned when \a str contains no valid date or \a str contains invalid time. + Value with time equal 00:00:00 is returned if \a str contains empty time part. */ +KEXIGUIUTILS_EXPORT QDateTime stringToDateTime( + const KexiDateFormatter& dateFormatter, const KexiTimeFormatter& timeFormatter, const QString& str); + +/*! \return true if \a str contains only spaces and separators according to formats provided by + \a dateFormatter and \a timeFormatter. */ +KEXIGUIUTILS_EXPORT bool dateTimeIsEmpty( const KexiDateFormatter& dateFormatter, + const KexiTimeFormatter& timeFormatter, const QString& str ); + +/*! \return true if \a str gives valid date/time value according to formats provided by + \a dateFormatter and \a timeFormatter. */ +KEXIGUIUTILS_EXPORT bool dateTimeIsValid( const KexiDateFormatter& dateFormatter, + const KexiTimeFormatter& timeFormatter, const QString& str ); + +#endif diff --git a/kexi/widget/utils/kexidisplayutils.cpp b/kexi/widget/utils/kexidisplayutils.cpp new file mode 100644 index 000000000..c7d238b1d --- /dev/null +++ b/kexi/widget/utils/kexidisplayutils.cpp @@ -0,0 +1,172 @@ +/* This file is part of the KDE project + Copyright (C) 2005-2006 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 "kexidisplayutils.h" + +#include <qpixmap.h> +#include <qpainter.h> +#include <qimage.h> +#include <qwidget.h> + +#include <klocale.h> +#include <kstaticdeleter.h> + +// a color for displaying default values or autonumbers +#define SPECIAL_TEXT_COLOR Qt::blue + +static KStaticDeleter<QPixmap> KexiDisplayUtils_autonum_deleter; +QPixmap* KexiDisplayUtils_autonum = 0; + +static const unsigned int autonumber_png_len = 245; +static const unsigned char autonumber_png_data[] = { + 0x89,0x50,0x4e,0x47,0x0d,0x0a,0x1a,0x0a,0x00,0x00,0x00,0x0d,0x49,0x48, + 0x44,0x52,0x00,0x00,0x00,0x0b,0x00,0x00,0x00,0x0d,0x08,0x06,0x00,0x00, + 0x00,0x7f,0xf5,0x94,0x3b,0x00,0x00,0x00,0x06,0x62,0x4b,0x47,0x44,0x00, + 0xff,0x00,0xff,0x00,0xff,0xa0,0xbd,0xa7,0x93,0x00,0x00,0x00,0x09,0x70, + 0x48,0x59,0x73,0x00,0x00,0x0b,0x11,0x00,0x00,0x0b,0x11,0x01,0x7f,0x64, + 0x5f,0x91,0x00,0x00,0x00,0x07,0x74,0x49,0x4d,0x45,0x07,0xd4,0x08,0x14, + 0x0c,0x09,0x11,0x18,0x18,0x1d,0x4f,0x00,0x00,0x00,0x82,0x49,0x44,0x41, + 0x54,0x78,0x9c,0x8d,0x91,0x41,0x0e,0x03,0x31,0x08,0x03,0x87,0xbe,0x2e, + 0x1c,0xb3,0xff,0xbf,0xf6,0x1d,0xee,0x81,0xa0,0x05,0xaa,0x55,0x6b,0x29, + 0x92,0x03,0x06,0x59,0x06,0x49,0x48,0x02,0xa4,0xe4,0xf1,0x5f,0x1b,0xa4, + 0x78,0x6b,0xc3,0xc2,0x24,0x61,0x86,0x00,0x24,0x8c,0x83,0x53,0x33,0xe9, + 0xe6,0xaf,0x29,0x4a,0x48,0x29,0xf4,0x0d,0xbc,0xc1,0xe1,0xc9,0x46,0xb5, + 0x72,0xfa,0xcf,0xe2,0x2a,0x4c,0x71,0xf3,0x5c,0x2d,0xd5,0x5a,0xc0,0xcd, + 0x62,0xea,0x6f,0xf4,0x88,0x86,0x95,0xf0,0x4a,0xf2,0xee,0x6b,0xf8,0x1e, + 0x03,0x55,0xf8,0x73,0xf3,0x28,0x7e,0x6d,0x6e,0x69,0xc4,0xc6,0xfb,0x52, + 0x23,0x8d,0x3c,0x56,0x5e,0xd0,0x2f,0x40,0xd1,0xf4,0x6b,0xc4,0xd5,0xf8, + 0x07,0x69,0x14,0xc6,0x69,0x9a,0x12,0x79,0x9a,0x00,0x00,0x00,0x00,0x49, + 0x45,0x4e,0x44,0xae,0x42,0x60,0x82 +}; + +/* Generated by qembed */ +#include <qcstring.h> +#include <qdict.h> +static struct Embed { + unsigned int size; + const unsigned char *data; + const char *name; +} embed_vec[] = { + { 245, autonumber_png_data, "autonumber.png" }, + { 0, 0, 0 } +}; + +QPixmap* getPix(int id) +{ +// QByteArray ba; +// ba.setRawData( (char*)embed_vec[id].data, embed_vec[id].size ); + QPixmap *pix = new QPixmap(); + pix->loadFromData( embed_vec[id].data, embed_vec[id].size ); + return pix; +} + +static void initDisplayUtilsImages() +{ + if (!KexiDisplayUtils_autonum) { +/*! @warning not reentrant! */ + KexiDisplayUtils_autonum_deleter.setObject( KexiDisplayUtils_autonum, getPix(0) ); + } +} + +//----------------- + +KexiDisplayUtils::DisplayParameters::DisplayParameters() +{ +} + +KexiDisplayUtils::DisplayParameters::DisplayParameters(QWidget *w) +{ + textColor = w->palette().active().foreground(); + selectedTextColor = w->palette().active().highlightedText(); + font = w->font(); +} + +void KexiDisplayUtils::initDisplayForAutonumberSign(DisplayParameters& par, QWidget *widget) +{ + initDisplayUtilsImages(); + + par.textColor = SPECIAL_TEXT_COLOR; + par.selectedTextColor = SPECIAL_TEXT_COLOR; //hmm, unused anyway + par.font = widget->font(); + par.font.setItalic(true); + QFontMetrics fm(par.font); + par.textWidth = fm.width(i18n("(autonumber)")); + par.textHeight = fm.height(); +} + +void KexiDisplayUtils::initDisplayForDefaultValue(DisplayParameters& par, QWidget *widget) +{ + par.textColor = SPECIAL_TEXT_COLOR; + par.selectedTextColor = widget->palette().active().highlightedText(); + par.font = widget->font(); + par.font.setItalic(true); +} + +void KexiDisplayUtils::paintAutonumberSign(const DisplayParameters& par, QPainter* painter, + int x, int y, int width, int height, int align, bool overrideColor) +{ + painter->save(); + + painter->setFont(par.font); + if (!overrideColor) + painter->setPen(par.textColor); + +// int text_x = x; + if (!(align & Qt::AlignVertical_Mask)) + align |= Qt::AlignVCenter; + if (!(align & Qt::AlignHorizontal_Mask)) + align |= Qt::AlignLeft; + + int y_pixmap_pos = 0; + if (align & Qt::AlignVCenter) { + y_pixmap_pos = QMAX(0, y+1 + (height - KexiDisplayUtils_autonum->height())/2); + } + else if (align & Qt::AlignTop) { + y_pixmap_pos = y + QMAX(0, (par.textHeight - KexiDisplayUtils_autonum->height())/2); + } + else if (align & Qt::AlignBottom) { + y_pixmap_pos = y+1 + height - KexiDisplayUtils_autonum->height() + - QMAX(0, (par.textHeight - KexiDisplayUtils_autonum->height())/2); + } + + if (align & (Qt::AlignLeft | Qt::AlignJustify)) { +// text_x = x + KexiDisplayUtils_autonum->width() + 2; + if (!overrideColor) { + painter->drawPixmap( x, y_pixmap_pos, *KexiDisplayUtils_autonum ); + x += (KexiDisplayUtils_autonum->width() + 4); + } + } + else if (align & Qt::AlignRight) { + if (!overrideColor) { + painter->drawPixmap( x + width - par.textWidth - KexiDisplayUtils_autonum->width() - 4, + y_pixmap_pos, *KexiDisplayUtils_autonum ); + } + } + else if (align & Qt::AlignCenter) { + //! @todo + if (!overrideColor) + painter->drawPixmap( x + (width - par.textWidth)/2 - KexiDisplayUtils_autonum->width() - 4, + y_pixmap_pos, *KexiDisplayUtils_autonum ); + } + + painter->drawText(x, y, width, height, align, i18n("(autonumber)")); + + painter->restore(); +} + diff --git a/kexi/widget/utils/kexidisplayutils.h b/kexi/widget/utils/kexidisplayutils.h new file mode 100644 index 000000000..8790b662b --- /dev/null +++ b/kexi/widget/utils/kexidisplayutils.h @@ -0,0 +1,57 @@ +/* This file is part of the KDE project + Copyright (C) 2005-2006 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. +*/ + +#ifndef KEXIDISPUTILS_H +#define KEXIDISPUTILS_H + +#include <qfont.h> +#include <qcolor.h> +class QWidget; + +//! \brief A set of utilities related to displaying common elements in Kexi, like e.g. (autonumber) sign +class KEXIGUIUTILS_EXPORT KexiDisplayUtils +{ + public: + //! Stores set of display parameters used in utility functions + class KEXIGUIUTILS_EXPORT DisplayParameters + { + public: + //! Creates uninitialized parameters + DisplayParameters(); + + //! Copies properties from \a w. + DisplayParameters(QWidget *w); + + QColor textColor, selectedTextColor; + QFont font; + int textWidth, textHeight; //!< used for "(autonumber)" text only + }; + + //! Initializes display parameters for autonumber sign + static void initDisplayForAutonumberSign(DisplayParameters& par, QWidget *widget); + + //! Paints autonumber sign using \a par parameters + static void paintAutonumberSign(const DisplayParameters& par, QPainter* painter, + int x, int y, int width, int height, int align, bool overrideColor = false); + + //! Initializes display parameters for default value + static void initDisplayForDefaultValue(DisplayParameters& par, QWidget *widget); +}; + +#endif diff --git a/kexi/widget/utils/kexidropdownbutton.cpp b/kexi/widget/utils/kexidropdownbutton.cpp new file mode 100644 index 000000000..a17e5cfb1 --- /dev/null +++ b/kexi/widget/utils/kexidropdownbutton.cpp @@ -0,0 +1,82 @@ +/* This file is part of the KDE project + Copyright (C) 2006 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 "kexidropdownbutton.h" + +#include <kpopupmenu.h> +#include <kdebug.h> + +#include <qstyle.h> +#include <qapplication.h> + +KexiDropDownButton::KexiDropDownButton(QWidget *parent) + : QToolButton(parent, "KexiDBImageBox::Button") +{ + setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Expanding); +//! @todo get this from a KStyle +// setFixedWidth(QMAX(18, qApp->globalStrut().width())); + int fixedWidth; + //hack + if (qstricmp(style().name(),"thinkeramik")==0) + fixedWidth = 18; //typical width as in "windows" style + else + fixedWidth = style().querySubControlMetrics( QStyle::CC_ComboBox, + this, QStyle::SC_ComboBoxArrow ).width(); + setFixedWidth( fixedWidth ); + setPopupDelay(10/*ms*/); +} + +KexiDropDownButton::~KexiDropDownButton() +{ +} + +void KexiDropDownButton::drawButton( QPainter *p ) +{ + QToolButton::drawButton(p); + QStyle::SFlags arrowFlags = QStyle::Style_Default; + if (isDown() || state()==On) + arrowFlags |= QStyle::Style_Down; + if (isEnabled()) + arrowFlags |= QStyle::Style_Enabled; + style().drawPrimitive(QStyle::PE_ArrowDown, p, + QRect((width()-7)/2, height()-9, 7, 7), colorGroup(), + arrowFlags, QStyleOption() ); +} + +QSize KexiDropDownButton::sizeHint () const +{ + return QSize( fontMetrics().maxWidth() + 2*2, fontMetrics().height()*2 + 2*2 ); +} + +void KexiDropDownButton::keyPressEvent( QKeyEvent * e ) +{ + const int k = e->key(); + const bool dropDown = (e->state() == Qt::NoButton && (k==Qt::Key_Space || k==Qt::Key_Enter || k==Qt::Key_Return || k==Qt::Key_F2 || k==Qt::Key_F4)) + || (e->state() == Qt::AltButton && k==Qt::Key_Down); + if (dropDown) { + e->accept(); + animateClick(); + QMouseEvent me( QEvent::MouseButtonPress, QPoint(2,2), Qt::LeftButton, Qt::NoButton ); + QApplication::sendEvent( this, &me ); + return; + } + QToolButton::keyPressEvent(e); +} + +#include "kexidropdownbutton.moc" diff --git a/kexi/widget/utils/kexidropdownbutton.h b/kexi/widget/utils/kexidropdownbutton.h new file mode 100644 index 000000000..fccbd409a --- /dev/null +++ b/kexi/widget/utils/kexidropdownbutton.h @@ -0,0 +1,45 @@ +/* This file is part of the KDE project + Copyright (C) 2006 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. +*/ + +#ifndef KexiDropDownButton_H +#define KexiDropDownButton_H + +#include <qtoolbutton.h> +#include <qguardedptr.h> + +//! @short A button for drop-down "Image" menu +/*! Used in KexiDBImageBox and KexiBlobTableEdit. + Additionally, the button reacts on pressing space, return, enter, + F2, F4 and alt+down buttons. */ +class KEXIGUIUTILS_EXPORT KexiDropDownButton : public QToolButton +{ + Q_OBJECT + + public: + KexiDropDownButton(QWidget *parent); + virtual ~KexiDropDownButton(); + + virtual void drawButton( QPainter *p ); + + virtual QSize sizeHint () const; + + virtual void keyPressEvent ( QKeyEvent * e ); +}; + +#endif diff --git a/kexi/widget/utils/kexiflowlayout.cpp b/kexi/widget/utils/kexiflowlayout.cpp new file mode 100644 index 000000000..b8a8601e1 --- /dev/null +++ b/kexi/widget/utils/kexiflowlayout.cpp @@ -0,0 +1,452 @@ +/* This file is part of the KDE project + Copyright (C) 2005 Cedric Pasteur <cedric.pasteur@free.fr> + + This library 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 library 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 library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + +#include "kexiflowlayout.h" + +#include <kdebug.h> + +/// Iterator class + +class KexiFlowLayoutIterator : public QGLayoutIterator +{ + public: + KexiFlowLayoutIterator( QPtrList<QLayoutItem> *list ) + : m_idx(0), m_list( list ) + {} + uint count() const; + QLayoutItem *current(); + QLayoutItem *next(); + QLayoutItem *takeCurrent(); + + private: + int m_idx; + QPtrList<QLayoutItem> *m_list; +}; + +uint +KexiFlowLayoutIterator::count() const +{ + return m_list->count(); +} + +QLayoutItem * +KexiFlowLayoutIterator::current() +{ + return (m_idx < (int)count()) ? m_list->at(m_idx) : 0; +} + +QLayoutItem * +KexiFlowLayoutIterator::next() +{ + m_idx++; + return current(); +} + +QLayoutItem * +KexiFlowLayoutIterator::takeCurrent() +{ + return (m_idx < (int)count()) ? m_list->take(m_idx) : 0; +} + +//// The layout itself + +KexiFlowLayout::KexiFlowLayout(QWidget *parent, int border, int space, const char *name) + : QLayout(parent, border, space, name) +{ + m_orientation = Horizontal; + m_justify = false; + m_cached_width = 0; +} + +KexiFlowLayout::KexiFlowLayout(QLayout* parent, int space, const char *name) + : QLayout( parent, space, name ) +{ + m_orientation = Horizontal; + m_justify = false; + m_cached_width = 0; +} + +KexiFlowLayout::KexiFlowLayout(int space, const char *name) + : QLayout(space, name) + { + m_orientation = Horizontal; + m_justify = false; + m_cached_width = 0; + } + +KexiFlowLayout::~KexiFlowLayout() +{ + deleteAllItems(); +} + +void +KexiFlowLayout::addItem(QLayoutItem *item) +{ + m_list.append(item); +} + +void +KexiFlowLayout::addSpacing(int size) +{ + if (m_orientation == Horizontal) + addItem( new QSpacerItem( size, 0, QSizePolicy::Fixed, QSizePolicy::Minimum ) ); + else + addItem( new QSpacerItem( 0, size, QSizePolicy::Minimum, QSizePolicy::Fixed ) ); +} + +QLayoutIterator +KexiFlowLayout::iterator() +{ + return QLayoutIterator( new KexiFlowLayoutIterator(&m_list) ); +} + +QPtrList<QWidget>* +KexiFlowLayout::widgetList() const +{ + QPtrList<QWidget> *list = new QPtrList<QWidget>(); + for (QPtrListIterator<QLayoutItem> it(m_list); it.current(); ++it) { + if(it.current()->widget()) + list->append(it.current()->widget()); + } + return list; +} + +void +KexiFlowLayout::invalidate() +{ + QLayout::invalidate(); + m_cached_sizeHint = QSize(); + m_cached_minSize = QSize(); + m_cached_width = 0; +} + +bool +KexiFlowLayout::isEmpty() +{ + return m_list.isEmpty(); +} + +bool +KexiFlowLayout::hasHeightForWidth() const +{ + return (m_orientation == Horizontal); +} + +int +KexiFlowLayout::heightForWidth(int w) const +{ + if(m_cached_width != w) { + // workaround to allow this method to stay 'const' + KexiFlowLayout *mthis = (KexiFlowLayout*)this; + int h = mthis->simulateLayout( QRect(0,0,w,0) ); + mthis->m_cached_hfw = h; + mthis->m_cached_width = w; + return h; + } + return m_cached_hfw; +} + +QSize +KexiFlowLayout::sizeHint() const +{ + if(m_cached_sizeHint.isEmpty()) { + KexiFlowLayout *mthis = (KexiFlowLayout*)this; + QRect r = QRect(0, 0, 2000, 2000); + mthis->simulateLayout(r); + } + return m_cached_sizeHint; +} + +QSize +KexiFlowLayout::minimumSize() const +{ +//js: do we really need to simulate layout here? +// I commented this out because it was impossible to stretch layout conveniently. +// Now, minimum size is computed automatically based on item's minimumSize... +#if 0 + if(m_cached_minSize.isEmpty()) { + KexiFlowLayout *mthis = (KexiFlowLayout*)this; + QRect r = QRect(0, 0, 2000, 2000); + mthis->simulateLayout(r); + } +#endif + return m_cached_minSize; +} + +QSizePolicy::ExpandData +KexiFlowLayout::expanding() const +{ + if(m_orientation == Vertical) + return QSizePolicy::Vertically; + else + return QSizePolicy::Horizontally; +} + +void +KexiFlowLayout::setGeometry(const QRect &r) +{ + QLayout::setGeometry(r); + if(m_orientation == Horizontal) + doHorizontalLayout(r); + else + doVerticalLayout(r); +} + +int +KexiFlowLayout::simulateLayout(const QRect &r) +{ + if(m_orientation == Horizontal) + return doHorizontalLayout(r, true); + else + return doVerticalLayout(r, true); +} + +int +KexiFlowLayout::doHorizontalLayout(const QRect &r, bool testOnly) +{ + int x = r.x(); + int y = r.y(); + int h = 0; // height of this line + int availableSpace = r.width() + spacing(); + int expandingWidgets=0; // number of widgets in the line with QSizePolicy == Expanding + QPtrListIterator<QLayoutItem> it(m_list); + QPtrList<QLayoutItem> currentLine; + QLayoutItem *o; + QSize minSize, sizeHint(20, 20); + int minSizeHeight = 0 - spacing(); + + while ( (o = it.current()) != 0 ) { + if(o->isEmpty()) { /// do not consider hidden widgets + ++it; + continue; + } + +// kdDebug() << "- doHorizontalLayout(): " << o->widget()->className() << " " << o->widget()->name() << endl; + QSize oSizeHint = o->sizeHint(); // we cache these ones because it can take a while to get it (eg for child layouts) + if ((x + oSizeHint.width()) > r.right() && h > 0) { + // do the layout of current line + QPtrListIterator<QLayoutItem> it2(currentLine); + QLayoutItem *item; + int wx = r.x(); + int sizeHintWidth = 0 -spacing(), minSizeWidth=0 - spacing(), lineMinHeight=0; + while( (item = it2.current()) != 0 ) { + QSize itemSizeHint = item->sizeHint(); // we cache these ones because it can take + QSize itemMinSize = item->minimumSize(); // a while to get them + QSize s; + if(m_justify) { + if(expandingWidgets != 0) { + if(item->expanding() == QSizePolicy::Horizontally || item->expanding() == QSizePolicy::BothDirections) + s = QSize( QMIN(itemSizeHint.width() + availableSpace / expandingWidgets + , r.width()), itemSizeHint.height() ); + else + s = QSize( QMIN(itemSizeHint.width(), r.width()), itemSizeHint.height() ); + } + else + s = QSize( QMIN(itemSizeHint.width() + availableSpace / (int)currentLine.count() + , r.width()), itemSizeHint.height() ); + } + else + s = QSize ( QMIN(itemSizeHint.width(), r.width()), itemSizeHint.height() ); + if(!testOnly) + item->setGeometry( QRect(QPoint(wx, y), s) ); + wx = wx + s.width() + spacing(); + minSizeWidth = minSizeWidth + spacing() + itemMinSize.width(); + sizeHintWidth = sizeHintWidth + spacing() + itemSizeHint.width(); + lineMinHeight = QMAX( lineMinHeight, itemMinSize.height() ); + ++it2; + } + sizeHint = sizeHint.expandedTo( QSize(sizeHintWidth, 0) ); + minSize = minSize.expandedTo( QSize(minSizeWidth, 0) ); + minSizeHeight = minSizeHeight + spacing() + lineMinHeight; + // start a new line + y = y + spacing() + h; + h = 0; + x = r.x(); + currentLine.clear(); + expandingWidgets = 0; + availableSpace = r.width() + spacing(); + } + + x = x + spacing() + oSizeHint.width(); + h = QMAX( h, oSizeHint.height() ); + currentLine.append(o); + if(o->expanding() == QSizePolicy::Horizontally || o->expanding() == QSizePolicy::BothDirections) + ++expandingWidgets; + availableSpace = QMAX(0, availableSpace - spacing() - oSizeHint.width()); + ++it; + } + + // don't forget to layout the last line + QPtrListIterator<QLayoutItem> it2(currentLine); + QLayoutItem *item; + int wx = r.x(); + int sizeHintWidth = 0 -spacing(), minSizeWidth=0 - spacing(), lineMinHeight=0; + while( (item = it2.current()) != 0 ) { + QSize itemSizeHint = item->sizeHint(); // we cache these ones because it can take + QSize itemMinSize = item->minimumSize(); // a while to get them + QSize s; + if(m_justify) { + if(expandingWidgets != 0) { + if(item->expanding() == QSizePolicy::Horizontally || item->expanding() == QSizePolicy::BothDirections) + s = QSize( QMIN(itemSizeHint.width() + availableSpace / expandingWidgets + , r.width()), itemSizeHint.height() ); + else + s = QSize( QMIN(itemSizeHint.width(), r.width()), itemSizeHint.height() ); + } + else + s = QSize( QMIN(itemSizeHint.width() + availableSpace / (int)currentLine.count() + , r.width()), itemSizeHint.height() ); + } + else + s = QSize ( QMIN(itemSizeHint.width(), r.width()), itemSizeHint.height() ); + if(!testOnly) + item->setGeometry( QRect(QPoint(wx, y), s) ); + wx = wx + s.width() + spacing(); + minSizeWidth = minSizeWidth + spacing() + itemMinSize.width(); + sizeHintWidth = sizeHintWidth + spacing() + itemSizeHint.width(); + lineMinHeight = QMAX( lineMinHeight, itemMinSize.height() ); + ++it2; + } + sizeHint = sizeHint.expandedTo( QSize(sizeHintWidth, y + spacing() + h) ); + minSizeHeight = minSizeHeight + spacing() + lineMinHeight; + minSize = minSize.expandedTo( QSize(minSizeWidth, minSizeHeight) ); + + // store sizeHint() and minimumSize() + m_cached_sizeHint = sizeHint + QSize(2* margin(), 2*margin()); + m_cached_minSize = minSize + QSize(2* margin() , 2*margin()); + // return our height + return y + h - r.y(); +} + +int +KexiFlowLayout::doVerticalLayout(const QRect &r, bool testOnly) +{ + int x = r.x(); + int y = r.y(); + int w = 0; // width of this line + int availableSpace = r.height() + spacing(); + int expandingWidgets=0; // number of widgets in the line with QSizePolicy == Expanding + QPtrListIterator<QLayoutItem> it(m_list); + QPtrList<QLayoutItem> currentLine; + QLayoutItem *o; + QSize minSize, sizeHint(20, 20); + int minSizeWidth = 0 - spacing(); + + while ( (o = it.current()) != 0 ) { + if(o->isEmpty()) { /// do not consider hidden widgets + ++it; + continue; + } + + QSize oSizeHint = o->sizeHint(); // we cache these ones because it can take a while to get it (eg for child layouts) + if (y + oSizeHint.height() > r.bottom() && w > 0) { + // do the layout of current line + QPtrListIterator<QLayoutItem> it2(currentLine); + QLayoutItem *item; + int wy = r.y(); + int sizeHintHeight = 0 - spacing(), minSizeHeight = 0 - spacing(), colMinWidth=0; + while( (item = it2.current()) != 0 ) { + QSize itemSizeHint = item->sizeHint(); // we cache these ones because it can take + QSize itemMinSize = item->minimumSize(); // a while to get them + QSize s; + if(m_justify) { + if(expandingWidgets != 0) { + if(item->expanding() == QSizePolicy::Vertically || item->expanding() == QSizePolicy::BothDirections) + s = QSize( itemSizeHint.width(), QMIN(itemSizeHint.height() + availableSpace / expandingWidgets + , r.height()) ); + else + s = QSize( itemSizeHint.width(), QMIN(itemSizeHint.height(), r.height()) ); + } + else + s = QSize( itemSizeHint.width(), QMIN(itemSizeHint.height() + availableSpace / (int)currentLine.count() + , r.height()) ); + } + else + s = QSize ( itemSizeHint.width(), QMIN(itemSizeHint.height(), r.height()) ); + if(!testOnly) + item->setGeometry( QRect(QPoint(x, wy), s) ); + wy = wy + s.height() + spacing(); + minSizeHeight = minSizeHeight + spacing() + itemMinSize.height(); + sizeHintHeight = sizeHintHeight + spacing() + itemSizeHint.height(); + colMinWidth = QMAX( colMinWidth, itemMinSize.width() ); + ++it2; + } + sizeHint = sizeHint.expandedTo( QSize(0, sizeHintHeight) ); + minSize = minSize.expandedTo( QSize(0, minSizeHeight) ); + minSizeWidth = minSizeWidth + spacing() + colMinWidth; + // start a new column + x = x + spacing() + w; + w = 0; + y = r.y(); + currentLine.clear(); + expandingWidgets = 0; + availableSpace = r.height() + spacing(); + } + + y = y + spacing() + oSizeHint.height(); + w = QMAX( w, oSizeHint.width() ); + currentLine.append(o); + if(o->expanding() == QSizePolicy::Vertically || o->expanding() == QSizePolicy::BothDirections) + ++expandingWidgets; + availableSpace = QMAX(0, availableSpace - spacing() - oSizeHint.height()); + ++it; + } + + // don't forget to layout the last line + QPtrListIterator<QLayoutItem> it2(currentLine); + QLayoutItem *item; + int wy = r.y(); + int sizeHintHeight = 0 - spacing(), minSizeHeight = 0 - spacing(), colMinWidth=0; + while( (item = it2.current()) != 0 ) { + QSize itemSizeHint = item->sizeHint(); // we cache these ones because it can take + QSize itemMinSize = item->minimumSize(); // a while to get them + QSize s; + if(m_justify) { + if(expandingWidgets != 0) { + if(item->expanding() == QSizePolicy::Vertically || item->expanding() == QSizePolicy::BothDirections) + s = QSize( itemSizeHint.width(), QMIN(itemSizeHint.height() + availableSpace / expandingWidgets + , r.height()) ); + else + s = QSize( itemSizeHint.width(), QMIN(itemSizeHint.height(), r.height()) ); + } + else + s = QSize( itemSizeHint.width(), QMIN(itemSizeHint.height() + availableSpace / (int)currentLine.count() + , r.height()) ); + } + else + s = QSize ( itemSizeHint.width(), QMIN(itemSizeHint.height(), r.height()) ); + if(!testOnly) + item->setGeometry( QRect(QPoint(x, wy), s) ); + wy = wy + s.height() + spacing(); + minSizeHeight = minSizeHeight + spacing() + itemMinSize.height(); + sizeHintHeight = sizeHintHeight + spacing() + itemSizeHint.height(); + colMinWidth = QMAX( colMinWidth, itemMinSize.width() ); + ++it2; + } + sizeHint = sizeHint.expandedTo( QSize( x + spacing() + w, sizeHintHeight) ); + minSizeWidth = minSizeWidth + spacing() + colMinWidth; + minSize = minSize.expandedTo( QSize(minSizeWidth, minSizeHeight) ); + + // store sizeHint() and minimumSize() + m_cached_sizeHint = sizeHint + QSize(2* margin(), 2*margin()); + m_cached_minSize = minSize + QSize(2* margin(), 2*margin()); + // return our width + return x + w - r.x(); +} + diff --git a/kexi/widget/utils/kexiflowlayout.h b/kexi/widget/utils/kexiflowlayout.h new file mode 100644 index 000000000..173ddad57 --- /dev/null +++ b/kexi/widget/utils/kexiflowlayout.h @@ -0,0 +1,79 @@ +/* This file is part of the KDE project + Copyright (C) 2005 Cedric Pasteur <cedric.pasteur@free.fr> + + This library 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 library 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 library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + +#ifndef KEXIFLOWLAYOUT_H +#define KEXIFLOWLAYOUT_H + +#include <qlayout.h> +#include <qptrlist.h> + +//! @short a special "flow" layout +class KEXIGUIUTILS_EXPORT KexiFlowLayout : public QLayout +{ + public: + KexiFlowLayout(QWidget *parent, int border=0, int space=-1, const char *name=0); + KexiFlowLayout(QLayout* parent, int space=-1, const char *name=0); + KexiFlowLayout(int space=-1, const char *name=0); + + ~KexiFlowLayout(); + + /*! \return the widgets in the order of the layout, + ie as it is stored in m_list. You must delete the list after using it. */ + QPtrList<QWidget>* widgetList() const; + + /*! Sets layout's orientation to \a orientation. Default orientation is Vertical. */ + void setOrientation(Orientation orientation) { m_orientation = orientation; } + + /*! \return layout's orientation. */ + Qt::Orientation orientation() const { return m_orientation; } + + void setJustified(bool justify) { m_justify = justify; } + bool isJustified() const { return m_justify; } + + virtual void addItem(QLayoutItem *item); + virtual void addSpacing(int size); + virtual QLayoutIterator iterator(); + virtual void invalidate(); + + virtual bool hasHeightForWidth() const; + virtual int heightForWidth(int width) const; + virtual QSize sizeHint() const; + virtual QSize minimumSize() const; + virtual QSizePolicy::ExpandData expanding() const; + + virtual bool isEmpty(); + + protected: + virtual void setGeometry(const QRect&); + int simulateLayout(const QRect &r); + int doHorizontalLayout(const QRect&, bool testonly = false); + int doVerticalLayout(const QRect&, bool testonly = false); + + private: + QPtrList<QLayoutItem> m_list; + int m_cached_width; + int m_cached_hfw; + bool m_justify; + Orientation m_orientation; + QSize m_cached_sizeHint; + QSize m_cached_minSize; +}; + +#endif + diff --git a/kexi/widget/utils/kexigradientwidget.cpp b/kexi/widget/utils/kexigradientwidget.cpp new file mode 100644 index 000000000..0411318de --- /dev/null +++ b/kexi/widget/utils/kexigradientwidget.cpp @@ -0,0 +1,358 @@ +/* This file is part of the KDE project + Copyright (C) 2005 Christian Nitschkowski <segfault_ii@web.de> + + 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 <qapplication.h> +#include <qbitmap.h> +#include <qimage.h> +#include <qobjectlist.h> +#include <qpainter.h> +#include <qstyle.h> + +#include <kimageeffect.h> +#include <kpixmap.h> + +#include "kexigradientwidget.h" + +KexiGradientWidget::KexiGradientWidget( QWidget *parent, const char *name, WFlags f ) + : QWidget( parent, name, f ), p_displayMode( NoGradient ), + p_gradientType( VerticalGradient ), + p_color1( Qt::white ), p_color2( Qt::blue ), p_currentChild( 0 ), + p_opacity( 0.5 ), p_cacheDirty( true ) +{ + p_customBackgroundWidgets.setAutoDelete( false ); + p_knownWidgets.setAutoDelete( false ); + + p_backgroundColor = QWidget::paletteBackgroundColor(); + + connect ( &p_rebuildDelayTimer, SIGNAL( timeout() ), this, SLOT( setCacheDirty() ) ); + + installEventFilter( this ); +} + +KexiGradientWidget::~KexiGradientWidget() +{ +} + +bool KexiGradientWidget::isValidChildWidget( QObject* child ) { + const QWidget* wgt = dynamic_cast<QWidget*>( child ); + + if ( wgt == 0L ) + return false; + + if ( wgt->inherits( "QScrollView" ) ) + return false; + if ( wgt->inherits( "QComboBox" ) ) + return false; + if ( wgt->inherits( "QLineEdit" ) ) + return false; + if ( wgt->inherits( "KexiDBForm" ) ) + return false; + + return true; +} + +void KexiGradientWidget::buildChildrenList( WidgetList& list, QWidget* p ) { + QObjectList* objects = p->queryList( "QWidget", 0, false, false ); + + for ( QObjectList::Iterator it = objects->begin(); it != objects->end(); ++it ) { + if ( isValidChildWidget( ( *it ) ) == false ) + continue; + list.append( dynamic_cast<QWidget*>( ( *it ) ) ); + buildChildrenList( list, dynamic_cast<QWidget*>( ( *it ) ) ); + } + + delete objects; +} + +void KexiGradientWidget::rebuildCache( void ) { + WidgetList childWidgetList; + buildChildrenList( childWidgetList, this ); + + /** + Disable the effect and behave like a normal QWidget. + */ + if ( p_displayMode == NoGradient ) { +// if ( p_backgroundPixmap.isNull() ) { + //unsetPalette(); + //} else { + QWidget::setPaletteBackgroundPixmap( p_backgroundPixmap ); + //} + QWidget::setPaletteBackgroundColor( p_backgroundColor ); + + for ( WidgetList::Iterator it = childWidgetList.begin(); + it != childWidgetList.end(); ++it ) { + + if ( p_customBackgroundWidgets.contains( ( *it ) ) == false ) { + ( *it )->unsetPalette(); + } + } + /** + The cache is now in a current state. + */ + p_cacheDirty = false; + return; + } + + KPixmap tempPixmap; + QImage gradientImage; + QImage bgImage; + + /** + Draw the gradient + */ + gradientImage = KImageEffect::gradient( size(), p_color1, p_color2, + (KImageEffect::GradientType)p_gradientType ); + + /** + Draw the widget-background in a pixmap and fade it with the gradient. + */ + if ( p_displayMode == FadedGradient ) { + tempPixmap.resize( size() ); + QPainter p( &tempPixmap, this ); + + if ( p_backgroundPixmap.isNull() ) { + /* + Need to unset the palette, otherwise the old gradient + will be used as a background, not the widget's default bg. + */ + unsetPalette(); + p.fillRect( 0, 0, width(), height(), palette().brush( + isEnabled() ? QPalette::Active : QPalette::Disabled, + QColorGroup::Background ) ); + } else { + p.drawTiledPixmap( 0, 0, width(), height(), p_backgroundPixmap ); + } + + p.end(); + + bgImage = tempPixmap; + + KImageEffect::blend( gradientImage, bgImage, (float)p_opacity ); + + tempPixmap.convertFromImage( bgImage ); + } else if ( p_displayMode == SimpleGradient ) { + /** + Use the gradient as the final background-pixmap + if displaymode is set to SimpleGradient. + */ + tempPixmap.convertFromImage( gradientImage ); + } + + /** + All children need to have our background set. + */ + KPixmap partPixmap; + QRect area; + QWidget* childWidget = 0; + const QPoint topLeft( 0, 0 ); + + for ( WidgetList::Iterator it = childWidgetList.begin(); + it != childWidgetList.end(); ++it ) { + + childWidget = ( *it ); + + /** + Exclude widgets with a custom palette. + */ + if ( p_customBackgroundWidgets.contains( childWidget ) ) { + continue; + } + + partPixmap.resize( childWidget->size() ); + /** + Get the part of the tempPixmap that is + under the current child-widget. + */ + if ( childWidget->parent() == this ) { + area = childWidget->geometry(); + } else { + area.setTopLeft( childWidget->mapTo( this, + childWidget->clipRegion().boundingRect().topLeft() ) ); + area.setSize( childWidget->size() ); + } + bitBlt( &partPixmap, topLeft, &tempPixmap, area ); + + p_currentChild = childWidget; + childWidget->setPaletteBackgroundPixmap( partPixmap ); + } + + QWidget::setPaletteBackgroundPixmap( tempPixmap ); + /** + Unset the dirty-flag at the end of the method. + QWidget::setPaletteBackgroundPixmap() causes this + to get set to true again, so set it to false + right after setting the pixmap. + */ + p_cacheDirty = false; +} + +void KexiGradientWidget::paintEvent( QPaintEvent* e ) { + /** + Rebuild the background-pixmap if necessary. + */ + if ( p_cacheDirty == true ) { + rebuildCache(); + } + + /** + Draw the widget as usual + */ + QWidget::paintEvent( e ); +} + +bool KexiGradientWidget::eventFilter( QObject* object, QEvent* event ) { + QWidget* child = dynamic_cast<QWidget*>( object ); + + /** + Manage list of child-widgets. + */ + if ( object == this ) { + if ( event->type() == QEvent::ChildInserted ) { + child = dynamic_cast<QWidget*>( dynamic_cast<QChildEvent*>( event )->child() ); + if ( isValidChildWidget( child ) == false ) { + return false; + } + /** + Add the new child-widget to our list of known widgets. + */ + p_knownWidgets.append( child ); + /** + ... and install 'this' as the child's event-filter. + */ + child->installEventFilter( this ); + } else if ( event->type() == QEvent::ChildRemoved ) { + /** + Remove the child-widget from the list of known widgets. + */ + p_knownWidgets.remove( dynamic_cast<QWidget*>( dynamic_cast<QChildEvent*>( event )->child() ) ); + } + return false; + } + + /** + Manage custombackground-list. + */ + if ( event->type() == QEvent::PaletteChange ) { + /** + p_currentChild will be == 0L, when the user + sets it's palette manually. + In this case, it has to be added to the customBackground-list. + */ + if ( p_currentChild == 0L && child != 0L ) { + if ( p_customBackgroundWidgets.contains( child ) == false ) { + p_customBackgroundWidgets.append( child ); + return false; + } + } + /** + Check if the widget whose PaletteChange-event we handle + isn't the widget we set the background in rebuildCache(). + */ + if ( child != p_currentChild && child != 0L ) { + /** + Add the new child to the list of widgets, we don't set + the background ourselves if it isn't in the list. + */ + if ( p_customBackgroundWidgets.contains( child ) == false ) { + if ( child->paletteBackgroundPixmap() != 0L ) { + p_customBackgroundWidgets.append( child ); + } + } else { + /** + If the palette is now the default-palette again, + remove it from the "don't set background in rebuildCache()"-list + and rebuild the cache, so it again will get the gradient background. + */ + if ( child->paletteBackgroundPixmap() == 0L ) { + p_customBackgroundWidgets.remove( child ); + if ( p_displayMode != NoGradient ) { + p_cacheDirty = true; + } + } + } + } + p_currentChild = 0; + } + + if ( event->type() == QEvent::Move ) { + if ( p_customBackgroundWidgets.contains( child ) == false ) { + updateChildBackground( child ); + } + } + return false; +} + +void KexiGradientWidget::updateChildBackground( QWidget* childWidget ) +{ + KPixmap partPixmap; + KPixmap bgPixmap; + QRect area; + const QPoint topLeft( 0, 0 ); + + bgPixmap = paletteBackgroundPixmap() ? (*paletteBackgroundPixmap()) : QPixmap(); + if ( bgPixmap.isNull() ) + return; + + /** + Exclude widgtes that don't have a parent. + This happens when children are removed + which are in the knownWidgets-list. + */ + if ( childWidget->parent() == 0L ) + return; + + /** + Exclude widgets with a custom palette. + */ + if ( p_customBackgroundWidgets.contains( childWidget ) ) { + return; + } + + partPixmap.resize( childWidget->size() ); + /** + Get the part of the tempPixmap that is + under the current child-widget. + */ + if ( childWidget->parent() == this ) { + area = childWidget->geometry(); + } else { + area.setTopLeft( childWidget->mapTo( this, + childWidget->clipRegion().boundingRect().topLeft() ) ); + area.setSize( childWidget->size() ); + } + bitBlt( &partPixmap, topLeft, &bgPixmap, area ); + + p_currentChild = childWidget; + childWidget->setPaletteBackgroundPixmap( partPixmap ); +} + +void KexiGradientWidget::setPaletteBackgroundColor( const QColor& color ) +{ + p_backgroundColor = color; + if ( p_displayMode == NoGradient ) { + QWidget::setPaletteBackgroundColor( p_backgroundColor ); + } +} + +const QColor& KexiGradientWidget::paletteBackgroundColor() const +{ + return p_backgroundColor; +} + +#include "kexigradientwidget.moc" diff --git a/kexi/widget/utils/kexigradientwidget.h b/kexi/widget/utils/kexigradientwidget.h new file mode 100644 index 000000000..0032e7b10 --- /dev/null +++ b/kexi/widget/utils/kexigradientwidget.h @@ -0,0 +1,247 @@ +/* This file is part of the KDE project + Copyright (C) 2005 Christian Nitschkowski <segfault_ii@web.de> + + 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. +*/ + +#ifndef KEXIGRADIENTWIDGET_H +#define KEXIGRADIENTWIDGET_H + +#include <qtimer.h> +#include <qwidget.h> + +#include <kimageeffect.h> +#include <kpixmap.h> + +#define REBUILD_DELAY 100 + +//! @short A simple widget that can use different types of gradients as the background. +/*! + @author Christian Nitschkowski +*/ +class KEXIGUIUTILS_EXPORT KexiGradientWidget : public QWidget { + typedef QPtrList<QWidget> WidgetList; + + Q_OBJECT + Q_PROPERTY(DisplayMode displayMode READ displayMode WRITE setDisplayMode DESIGNABLE true) + Q_PROPERTY(GradientType gradientType READ gradientType WRITE setGradientType DESIGNABLE true) + Q_PROPERTY(QColor gradientColor1 READ gradientColor1 WRITE setGradientColor1 DESIGNABLE true) + Q_PROPERTY(QColor gradientColor2 READ gradientColor2 WRITE setGradientColor2 DESIGNABLE true) + Q_PROPERTY(double blendOpacity READ blendOpacity WRITE setBlendOpacity DESIGNABLE true) + Q_ENUMS( DisplayMode GradientType ) + + public: + /*! + Modes for displaying the gradient. + */ + enum DisplayMode { + NoGradient, //!< No gradient at all. Will behave just like a QWidget + FadedGradient, //!< Gradient will be faded with the widgets background + SimpleGradient //!< Gradient will replace the usual widget background + }; + + /*! + Gradient type specification. + See GradientType for more details (part of the KDEFX library) + */ + enum GradientType { + VerticalGradient = KImageEffect::VerticalGradient, + HorizontalGradient = KImageEffect::HorizontalGradient, + DiagonalGradient = KImageEffect::DiagonalGradient, + CrossDiagonalGradient = KImageEffect::CrossDiagonalGradient, + PyramidGradient = KImageEffect::PyramidGradient, + RectangleGradient = KImageEffect::RectangleGradient, + PipeCrossGradient = KImageEffect::PipeCrossGradient, + EllipticGradient = KImageEffect::EllipticGradient + }; + + KexiGradientWidget( QWidget *parent = 0, const char *name = 0, WFlags f = 0 ); + + virtual ~KexiGradientWidget(); + + virtual void setPaletteBackgroundPixmap( const QPixmap& pixmap ) { + p_backgroundPixmap = pixmap; + p_rebuildDelayTimer.start( REBUILD_DELAY, true ); + } + + virtual const QColor& paletteBackgroundColor() const; + + /*! + Set the displaymode \a mode. + The widget will be updated automatically. + */ + void setDisplayMode( DisplayMode mode ) { + p_displayMode = mode; + p_cacheDirty = true; + update(); + } + + /*! + Get the current displaymode. + */ + DisplayMode displayMode() const { + return p_displayMode; + } + + /*! + Set the gradient-type. + */ + void setGradientType( GradientType type ) { + p_gradientType = type; + p_cacheDirty = true; + update(); + } + + /*! + Get the current gradient-type. + */ + GradientType gradientType() const { + return p_gradientType; + } + + /*! Set color #1 for the gradient-effect. + \a color is the new color. */ + void setGradientColor1( const QColor& color ) { + p_color1 = color; + p_cacheDirty = true; + } + + /*! Set color #2 for the gradient-effect. + \a color is the new color. */ + void setGradientColor2( const QColor& color ) { + p_color2 = color; + p_cacheDirty = true; + } + + /*! + Set both colors for the gradient. + \a color1 is the first color, + \a color2 the second. + */ + void setGradientColors( const QColor& color1, const QColor& color2 ) { + p_color1 = color1; + p_color2 = color2; + p_cacheDirty = true; + } + + /*! \return the color #1 used for the gradient. */ + QColor gradientColor1() const { return p_color1; } + + /*! \return the color #2 used for the gradient. */ + QColor gradientColor2() const { return p_color2; } + + /*! + Sets the opacity of the gradient when fading with background. + \a opacity has to be between 0.0 and 1.0. + */ + void setBlendOpacity( double opacity ) { + p_opacity = opacity; + p_cacheDirty = true; + } + + double blendOpacity() const { return p_opacity; } + + public slots: + virtual void setPaletteBackgroundColor( const QColor& color ); + + protected: + virtual bool eventFilter( QObject* object, QEvent* event ); + virtual void enabledChange( bool enabled ) { + p_cacheDirty = true; + QWidget::enabledChange( enabled ); + } + + virtual void paletteChange( const QPalette& pal ) { + p_cacheDirty = true; + QWidget::paletteChange( pal ); + } + + virtual void paintEvent( QPaintEvent* e ); + + virtual void resizeEvent( QResizeEvent* e ) { + p_rebuildDelayTimer.start( REBUILD_DELAY, true ); + QWidget::resizeEvent( e ); + } + + virtual void styleChange( QStyle& style ) { + p_cacheDirty = true; + QWidget::styleChange( style ); + } + + private: + /*! + Builds a list of children of \a p. + Only widgets that work correctly with KexiGradientWidget + will be in this list. + The results will be stored in \a list. + The method recursively calls itself until all children of \a p + have been found and stored in the list. + */ + static void buildChildrenList( WidgetList& list, QWidget* p ); + /*! + \a return if the \a child is a widget that should + get a background set. + */ + static bool isValidChildWidget( QObject* child ); + + /*! + Rebuilds the cache completely. + This is done automatically if necessary. + */ + void rebuildCache(); + + /*! + Sets the background of \a childWidget. + This is necessary when the child has been moved. + For performance-reasons this is used only for Move-events. + The same code is used for PaletteChange-events, but in a + different location. + */ + void updateChildBackground( QWidget* childWidget ); + + private: + WidgetList p_knownWidgets; + WidgetList p_customBackgroundWidgets; + DisplayMode p_displayMode; + GradientType p_gradientType; + KPixmap p_backgroundPixmap; + QColor p_color1; + QColor p_color2; + QTimer p_rebuildDelayTimer; + QWidget* p_currentChild; + double p_opacity; + bool p_cacheDirty; + + QColor p_backgroundColor; + + public slots: + /*! + The cache needs to be rebuild once the widget + is set up completely. + */ + virtual void polish() { + QWidget::polish(); + rebuildCache(); + } + + private slots: + void setCacheDirty() { + rebuildCache(); + } + + }; + +#endif diff --git a/kexi/widget/utils/kexirecordmarker.cpp b/kexi/widget/utils/kexirecordmarker.cpp new file mode 100644 index 000000000..d434fcaf6 --- /dev/null +++ b/kexi/widget/utils/kexirecordmarker.cpp @@ -0,0 +1,307 @@ +/* This file is part of the KDE project + Copyright (C) 2002 Lucijan Busch <lucijan@gmx.at> + Copyright (C) 2002 Till Busch <till@bux.at> + Copyright (C) 2002 Daniel Molkentin <molkentin@kde.org> + Copyright (C) 2003-2006 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 "kexirecordmarker.h" + +#include <qcolor.h> +#include <qstyle.h> +#include <qpixmap.h> +#include <qpainter.h> +#include <qimage.h> +#include <qapplication.h> + +#include <kdebug.h> +#include <kstaticdeleter.h> + +#include <kexiutils/utils.h> + +static KStaticDeleter<QImage> KexiRecordMarker_pen_deleter, KexiRecordMarker_plus_deleter; +QImage* KexiRecordMarker_pen = 0, *KexiRecordMarker_plus = 0; + +static const unsigned char img_pen_data[] = { + 0x00,0x00,0x03,0x30,0x78,0x9c,0xfb,0xff,0xff,0x3f,0xc3,0x7f,0x32,0x30, + 0x10,0x80,0x88,0xff,0xe4,0xe8,0x85,0xe9,0xc7,0xc6,0x26,0x55,0x3f,0x3a, + 0x4d,0x8e,0x7e,0x72,0xfc,0x32,0xd2,0xf5,0xa3,0xeb,0xa5,0xb5,0x7e,0x5c, + 0xe9,0x85,0x54,0xfb,0xb1,0xa5,0x1b,0x52,0xdc,0x0e,0x00,0xf2,0xea,0x0a, + 0x13 +}; +static const unsigned char img_plus_data[] = { + 0x00,0x00,0x01,0x90,0x78,0x9c,0xfb,0xff,0xff,0x3f,0xc3,0x7f,0x28,0x86, + 0x82,0xff,0x50,0x0c,0x17,0x47,0xc7,0xd4,0x50,0x87,0x05,0xc0,0xd5,0xe1, + 0x10,0xa7,0x16,0x26,0xca,0x5e,0x7c,0xfe,0x20,0x47,0x1d,0xb2,0x5a,0x5c, + 0xea,0x40,0x72,0x00,0x03,0x6e,0x74,0x8c +}; + +static struct EmbedImage { + int width, height, depth; + const unsigned char *data; + ulong compressed; + int numColors; + const QRgb *colorTable; + bool alpha; + const char *name; +} embed_image[] = { + { 17, 12, 32, (const unsigned char*)img_pen_data, 57, 0, 0, true, "tableview_pen.png" }, + { 10, 10, 32, (const unsigned char*)img_pen_data, 50, 0, 0, true, "tableview_plus.png" } +}; + +QImage* getImg(const unsigned char* data, int id) +{ + QByteArray baunzip; + baunzip = qUncompress( data, embed_image[id].compressed ); + QImage *img = new QImage( QImage((uchar*)baunzip.data(), + embed_image[id].width, embed_image[id].height, + embed_image[id].depth, (QRgb*)embed_image[id].colorTable, + embed_image[id].numColors, QImage::BigEndian + ).copy() ); + if ( embed_image[id].alpha ) + img->setAlphaBuffer(true); + return img; +} + +static void initRecordMarkerImages() +{ + if (!KexiRecordMarker_pen) { +/*! @warning not reentrant! */ + KexiRecordMarker_pen_deleter.setObject( KexiRecordMarker_pen, getImg(img_pen_data, 0) ); + KexiRecordMarker_plus_deleter.setObject( KexiRecordMarker_plus, getImg(img_plus_data, 1) ); + } +} + +//---------------------------------------------------------------- + +//! @internal +class KexiRecordMarker::Private +{ +public: + Private() + : rowHeight(1) + , offset(0) + , currentRow(-1) + , highlightedRow(-1) + , editRow(-1) + , rows(0) + , selectionBackgroundColor(qApp->palette().active().highlight()) + , showInsertRow(true) + { + } + int rowHeight; + int offset; + int currentRow; + int highlightedRow; + int editRow; + int rows; + QColor selectionBackgroundColor; + bool showInsertRow : 1; +}; + +//---------------------------------------------------------------- + +KexiRecordMarker::KexiRecordMarker(QWidget *parent, const char* name) + : QWidget(parent, name) + , d( new Private() ) +{ + initRecordMarkerImages(); +} + +KexiRecordMarker::~KexiRecordMarker() +{ + delete d; +} + +QImage* KexiRecordMarker::penImage() +{ + initRecordMarkerImages(); + return KexiRecordMarker_pen; +} + +QImage* KexiRecordMarker::plusImage() +{ + initRecordMarkerImages(); + return KexiRecordMarker_plus; +} + +void KexiRecordMarker::addLabel(bool upd) +{ + d->rows++; + if (upd) + update(); +} + +void KexiRecordMarker::removeLabel(bool upd) +{ + if (d->rows > 0) { + d->rows--; + if (upd) + update(); + } +} + +void KexiRecordMarker::addLabels(int num, bool upd) +{ + d->rows += num; + if (upd) + update(); +} + +void KexiRecordMarker::clear(bool upd) +{ + d->rows=0; + if (upd) + update(); +} + +int KexiRecordMarker::rows() const +{ + if (d->showInsertRow) + return d->rows +1; + else + return d->rows; +} + +void KexiRecordMarker::paintEvent(QPaintEvent *e) +{ + QPainter p(this); + QRect r(e->rect()); + + int first = (r.top() + d->offset) / d->rowHeight; + int last = (r.bottom() + d->offset) / d->rowHeight; + if(last > (d->rows-1+(d->showInsertRow?1:0))) + last = d->rows-1+(d->showInsertRow?1:0); + + QColorGroup selectedColorGroup(colorGroup()); + selectedColorGroup.setColor( QColorGroup::Button, + KexiUtils::blendedColors( selectedColorGroup.color(QColorGroup::Background), + d->selectionBackgroundColor, 2, 1) ); + selectedColorGroup.setColor( QColorGroup::Background, + selectedColorGroup.color(QColorGroup::Button) ); //set background color as well (e.g. for thinkeramik) + QColorGroup highlightedColorGroup(colorGroup()); + highlightedColorGroup.setColor( QColorGroup::Button, + KexiUtils::blendedColors( highlightedColorGroup.color(QColorGroup::Background), + d->selectionBackgroundColor, 4, 1) ); + highlightedColorGroup.setColor( QColorGroup::Background, + highlightedColorGroup.color(QColorGroup::Button) ); //set background color as well (e.g. for thinkeramik) + for(int i=first; i <= last; i++) + { + int y = ((d->rowHeight * i)-d->offset); + QRect r(0, y, width(), d->rowHeight); + p.drawRect(r); + style().drawPrimitive( QStyle::PE_HeaderSection, &p, r, + (d->currentRow == i) ? selectedColorGroup : (d->highlightedRow == i ? highlightedColorGroup : colorGroup()), + QStyle::Style_Raised | (isEnabled() ? QStyle::Style_Enabled : 0)); + } + if (d->editRow!=-1 && d->editRow >= first && d->editRow <= (last/*+1 for insert row*/)) { + //show pen when editing + int ofs = d->rowHeight / 4; + int pos = ((d->rowHeight*(d->currentRow>=0?d->currentRow:0))-d->offset)-ofs/2+1; + p.drawImage((d->rowHeight-KexiRecordMarker_pen->width())/2, + (d->rowHeight-KexiRecordMarker_pen->height())/2+pos,*KexiRecordMarker_pen); + } + else if (d->currentRow >= first && d->currentRow <= last + && (!d->showInsertRow || (d->showInsertRow && d->currentRow < last)))/*don't display marker for 'insert' row*/ + { + //show marker + p.setBrush(colorGroup().foreground()); + p.setPen(QPen(Qt::NoPen)); + QPointArray points(3); + int ofs = d->rowHeight / 4; + int ofs2 = (width() - ofs) / 2 -1; + int pos = ((d->rowHeight*d->currentRow)-d->offset)-ofs/2+2; + points.putPoints(0, 3, ofs2, pos+ofs, ofs2 + ofs, pos+ofs*2, + ofs2,pos+ofs*3); + p.drawPolygon(points); +// kdDebug() <<"KexiRecordMarker::paintEvent(): POLYGON" << endl; +/* int half = d->rowHeight / 2; + points.setPoints(3, 2, pos + 2, width() - 5, pos + half, 2, pos + (2 * half) - 2);*/ + } + if (d->showInsertRow && d->editRow < last + && last == (d->rows-1+(d->showInsertRow?1:0)) ) { + //show plus sign + int pos = ((d->rowHeight*last)-d->offset)+(d->rowHeight-KexiRecordMarker_plus->height())/2; +// p.drawImage((width()-d->plusImg.width())/2-1, pos, d->plusImg); + p.drawImage((width()-KexiRecordMarker_plus->width())/2, pos, *KexiRecordMarker_plus); + } +} + +void KexiRecordMarker::setCurrentRow(int row) +{ + if (row == d->currentRow) + return; + int oldRow = d->currentRow; + d->currentRow=row; + + if (oldRow != -1) + update(0,(d->rowHeight*(oldRow))-d->offset-1, width()+2, d->rowHeight+2); + if (d->currentRow != -1) + update(0,(d->rowHeight*d->currentRow)-d->offset-1, width()+2, d->rowHeight+2); +} + +void KexiRecordMarker::setHighlightedRow(int row) +{ + if (row == d->highlightedRow) + return; + int oldRow = d->highlightedRow; + d->highlightedRow = row; + + if (oldRow != -1) + update(0,(d->rowHeight*(oldRow))-d->offset-1, width()+2, d->rowHeight+2); + if (d->currentRow != -1) + update(0,(d->rowHeight*d->highlightedRow)-d->offset-1, width()+2, d->rowHeight+2); +} + +void KexiRecordMarker::setOffset(int offset) +{ + int oldOff = d->offset; + d->offset = offset; + scroll(0,oldOff-offset); +} + +void KexiRecordMarker::setCellHeight(int cellHeight) +{ + d->rowHeight = cellHeight; +} + +void KexiRecordMarker::setEditRow(int row) +{ + d->editRow = row; +//TODO: update only needed area! + update(); +} + +void KexiRecordMarker::showInsertRow(bool show) +{ + d->showInsertRow = show; +//TODO: update only needed area! + update(); +} + +void KexiRecordMarker::setSelectionBackgroundColor(const QColor &color) +{ + d->selectionBackgroundColor = color; +} + +QColor KexiRecordMarker::selectionBackgroundColor() const +{ + return d->selectionBackgroundColor; +} + +#include "kexirecordmarker.moc" diff --git a/kexi/widget/utils/kexirecordmarker.h b/kexi/widget/utils/kexirecordmarker.h new file mode 100644 index 000000000..1408f83b9 --- /dev/null +++ b/kexi/widget/utils/kexirecordmarker.h @@ -0,0 +1,72 @@ +/* This file is part of the KDE project + Copyright (C) 2002 Lucijan Busch <lucijan@gmx.at> + Copyright (C) 2002 Till Busch <till@bux.at> + Copyright (C) 2002 Daniel Molkentin <molkentin@kde.org> + Copyright (C) 2003-2006 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. +*/ + +#ifndef KEXIRECORDMARKER_H +#define KEXIRECORDMARKER_H + +#include <qwidget.h> + +class QImage; + +//! \brief Record marker, usually displayed at the left side of a table view or a continuous form. +class KEXIGUIUTILS_EXPORT KexiRecordMarker : public QWidget +{ + Q_OBJECT + + public: + KexiRecordMarker(QWidget *parent, const char* name = 0); + ~KexiRecordMarker(); + + int rows() const; + + static QImage* penImage(); + static QImage* plusImage(); + + public slots: + void setOffset(int offset); + void setCellHeight(int cellHeight); + void setCurrentRow(int row); + void setHighlightedRow(int row); + + /*! Sets 'edit row' flag for \a row. Use row==-1 if you want to switch the flag off. */ + void setEditRow(int row); + void showInsertRow(bool show); + + QColor selectionBackgroundColor() const; + void setSelectionBackgroundColor(const QColor &color); + + void addLabel(bool upd=true); + void removeLabel(bool upd=true); + + /*! Adds \a num labels */ + void addLabels(int num, bool upd=true); + + void clear(bool upd=true); + + protected: + virtual void paintEvent(QPaintEvent *e); + + class Private; + Private * const d; +}; + +#endif diff --git a/kexi/widget/utils/kexirecordnavigator.cpp b/kexi/widget/utils/kexirecordnavigator.cpp new file mode 100644 index 000000000..f0dff0878 --- /dev/null +++ b/kexi/widget/utils/kexirecordnavigator.cpp @@ -0,0 +1,511 @@ +/* This file is part of the KDE project + Copyright (C) 2004 Lucijan Busch <lucijan@kde.org> + Copyright (C) 2003-2004 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 <qtoolbutton.h> +#include <qlayout.h> +#include <qlabel.h> +#include <qvalidator.h> +#include <qtooltip.h> +#include <qscrollview.h> + +#include <klocale.h> +#include <kiconloader.h> +#include <klineedit.h> +#include <kguiitem.h> +#include <kstaticdeleter.h> + +#include "kexirecordnavigator.h" +#include "kexirecordmarker.h" + +//! @internal +class KexiRecordNavigatorPrivate +{ + public: + KexiRecordNavigatorPrivate() + : handler(0) + , editingIndicatorLabel(0) + , editingIndicatorEnabled(false) + , editingIndicatorVisible(false) + { + } + KexiRecordNavigatorHandler *handler; + QHBoxLayout *lyr; + + QLabel *editingIndicatorLabel; + bool editingIndicatorEnabled : 1; + bool editingIndicatorVisible : 1; +}; + +//-------------------------------------------------- + +KexiRecordNavigatorHandler::KexiRecordNavigatorHandler() +{ +} + +KexiRecordNavigatorHandler::~KexiRecordNavigatorHandler() +{ +} + +//-------------------------------------------------- + +KexiRecordNavigator::KexiRecordNavigator(QWidget *parent, int leftMargin, const char *name) + : QFrame(parent, name) + , m_view(0) + , m_isInsertingEnabled(true) + , d( new KexiRecordNavigatorPrivate() ) +{ + if (parent->inherits("QScrollView")) + setParentView( dynamic_cast<QScrollView*>(parent) ); + setFrameStyle(QFrame::NoFrame); + d->lyr = new QHBoxLayout(this,0,0,"nav_lyr"); + + m_textLabel = new QLabel(this); + d->lyr->addWidget( m_textLabel ); + setLabelText(i18n("Row:")); + + int bw = 6+SmallIcon("navigator_first").width(); //QMIN( horizontalScrollBar()->height(), 20); + QFont f = font(); + f.setPixelSize((bw > 12) ? 12 : bw); + QFontMetrics fm(f); + m_nav1DigitWidth = fm.width("8"); + + d->lyr->addWidget( m_navBtnFirst = new QToolButton(this) ); + m_navBtnFirst->setFixedWidth(bw); + m_navBtnFirst->setFocusPolicy(NoFocus); + m_navBtnFirst->setIconSet( SmallIconSet("navigator_first") ); + QToolTip::add(m_navBtnFirst, i18n("First row")); + + d->lyr->addWidget( m_navBtnPrev = new QToolButton(this) ); + m_navBtnPrev->setFixedWidth(bw); + m_navBtnPrev->setFocusPolicy(NoFocus); + m_navBtnPrev->setIconSet( SmallIconSet("navigator_prev") ); + m_navBtnPrev->setAutoRepeat(true); + QToolTip::add(m_navBtnPrev, i18n("Previous row")); + + d->lyr->addSpacing( 6 ); + + d->lyr->addWidget( m_navRecordNumber = new KLineEdit(this) ); + m_navRecordNumber->setAlignment(AlignRight | AlignVCenter); + m_navRecordNumber->setFocusPolicy(ClickFocus); + m_navRecordNumber->installEventFilter(this); +// m_navRowNumber->setFixedWidth(fw); + m_navRecordNumberValidator = new QIntValidator(1, INT_MAX, this); + m_navRecordNumber->setValidator(m_navRecordNumberValidator); + m_navRecordNumber->installEventFilter(this); + QToolTip::add(m_navRecordNumber, i18n("Current row number")); + + KLineEdit *lbl_of = new KLineEdit(i18n("of"), this); + lbl_of->setSizePolicy(QSizePolicy::Fixed,QSizePolicy::Preferred); + lbl_of->setMaximumWidth(fm.width(lbl_of->text())+8); + lbl_of->setReadOnly(true); + lbl_of->setLineWidth(0); + lbl_of->setFocusPolicy(NoFocus); + lbl_of->setAlignment(AlignCenter); + d->lyr->addWidget( lbl_of ); + + d->lyr->addWidget( m_navRecordCount = new KLineEdit(this) ); + m_navRecordCount->setSizePolicy(QSizePolicy::Fixed,QSizePolicy::Preferred); + m_navRecordCount->setReadOnly(true); + m_navRecordCount->setLineWidth(0); + m_navRecordCount->setFocusPolicy(NoFocus); + m_navRecordCount->setAlignment(AlignLeft | AlignVCenter); + QToolTip::add(m_navRecordCount, i18n("Number of rows")); + + lbl_of->setFont(f); + m_navRecordNumber->setFont(f); + m_navRecordCount->setFont(f); + setFont(f); + + d->lyr->addWidget( m_navBtnNext = new QToolButton(this) ); + m_navBtnNext->setFixedWidth(bw); + m_navBtnNext->setFocusPolicy(NoFocus); + m_navBtnNext->setIconSet( SmallIconSet("navigator_next") ); + m_navBtnNext->setAutoRepeat(true); + QToolTip::add(m_navBtnNext, i18n("Next row")); + + d->lyr->addWidget( m_navBtnLast = new QToolButton(this) ); + m_navBtnLast->setFixedWidth(bw); + m_navBtnLast->setFocusPolicy(NoFocus); + m_navBtnLast->setIconSet( SmallIconSet("navigator_last") ); + QToolTip::add(m_navBtnLast, i18n("Last row")); + + d->lyr->addSpacing( 6 ); + d->lyr->addWidget( m_navBtnNew = new QToolButton(this) ); + m_navBtnNew->setFixedWidth(bw); + m_navBtnNew->setFocusPolicy(NoFocus); + m_navBtnNew->setIconSet( SmallIconSet("navigator_new") ); + QToolTip::add(m_navBtnNew, i18n("New row")); + m_navBtnNext->setEnabled(isInsertingEnabled()); + + d->lyr->addSpacing( 6 ); + d->lyr->addStretch(10); + + connect(m_navBtnPrev,SIGNAL(clicked()),this,SLOT(slotPrevButtonClicked())); + connect(m_navBtnNext,SIGNAL(clicked()),this,SLOT(slotNextButtonClicked())); + connect(m_navBtnLast,SIGNAL(clicked()),this,SLOT(slotLastButtonClicked())); + connect(m_navBtnFirst,SIGNAL(clicked()),this,SLOT(slotFirstButtonClicked())); + connect(m_navBtnNew,SIGNAL(clicked()),this,SLOT(slotNewButtonClicked())); + + setRecordCount(0); + setCurrentRecordNumber(0); + + updateGeometry(leftMargin); +} + +KexiRecordNavigator::~KexiRecordNavigator() +{ + delete d; +} + +void KexiRecordNavigator::setInsertingEnabled(bool set) +{ + if (m_isInsertingEnabled==set) + return; + m_isInsertingEnabled = set; + if (isEnabled()) + m_navBtnNew->setEnabled( m_isInsertingEnabled ); +} + +void KexiRecordNavigator::setEnabled( bool set ) +{ + QFrame::setEnabled(set); + if (set && !m_isInsertingEnabled) + m_navBtnNew->setEnabled( false ); +} + +bool KexiRecordNavigator::eventFilter( QObject *o, QEvent *e ) +{ + if (o==m_navRecordNumber) { + bool recordEntered = false; + bool ret; + if (e->type()==QEvent::KeyPress) { + QKeyEvent *ke = static_cast<QKeyEvent*>(e); + switch (ke->key()) { + case Qt::Key_Escape: { + ke->accept(); + m_navRecordNumber->undo(); + if (m_view) + m_view->setFocus(); + return true; + } + case Qt::Key_Enter: + case Qt::Key_Return: + case Qt::Key_Tab: + case Qt::Key_BackTab: + { + recordEntered=true; + ke->accept(); //to avoid pressing Enter later + ret = true; + } + default:; + } + } + else if (e->type()==QEvent::FocusOut) { + if (static_cast<QFocusEvent*>(e)->reason()!=QFocusEvent::Tab + && static_cast<QFocusEvent*>(e)->reason()!=QFocusEvent::Backtab + && static_cast<QFocusEvent*>(e)->reason()!=QFocusEvent::Other) + recordEntered=true; + ret = false; + } + + if (recordEntered) { + bool ok=true; + uint r = m_navRecordNumber->text().toUInt(&ok); + if (!ok || r<1) + r = (recordCount()>0)?1:0; + if (m_view && (hasFocus() || e->type()==QEvent::KeyPress)) + m_view->setFocus(); + setCurrentRecordNumber(r); + emit recordNumberEntered(r); + if (d->handler) + d->handler->moveToRecordRequested(r-1); + return ret; + } + } +/* + bool ok=true; + int r = text.toInt(&ok); + if (!ok || r<1) + r = 1; + emit recordNumberEntered(r);*/ + return false; +} + +void KexiRecordNavigator::setCurrentRecordNumber(uint r) +{ + uint recCnt = recordCount(); + if (r>(recCnt+(m_isInsertingEnabled?1:0))) + r = recCnt+(m_isInsertingEnabled?1:0); + QString n; + if (r>0) + n = QString::number(r); + else + n = " "; +// if (d->navRecordNumber->text().length() != n.length()) {//resize +// d->navRecordNumber->setFixedWidth( +// d->nav1DigitWidth*QMAX( QMAX(n.length(),2)+1,d->navRecordCount->text().length()+1)+6 +// ); +// } + + m_navRecordNumber->setText(n); + m_navRecordCount->deselect(); + updateButtons(recCnt); +} + +void KexiRecordNavigator::updateButtons(uint recCnt) +{ + const uint r = currentRecordNumber(); + if (isEnabled()) { + m_navBtnPrev->setEnabled(r > 1); + m_navBtnFirst->setEnabled(r > 1); + m_navBtnNext->setEnabled(r > 0 + && r < (recCnt +(m_isInsertingEnabled?(1+d->editingIndicatorVisible/*if we're editing, next btn is avail.*/):0) ) ); + m_navBtnLast->setEnabled(r!=(recCnt+(m_isInsertingEnabled?1:0)) && (m_isInsertingEnabled || recCnt>0)); + } +} + +void KexiRecordNavigator::setRecordCount(uint count) +{ + const QString & n = QString::number(count); + if (m_isInsertingEnabled && currentRecordNumber()==0) { + setCurrentRecordNumber(1); + } + if (m_navRecordCount->text().length() != n.length()) {//resize + m_navRecordCount->setFixedWidth(m_nav1DigitWidth*n.length()+6); + + if (m_view && m_view->horizontalScrollBar()->isVisible()) { + //+width of the delta + resize(width()+(n.length()-m_navRecordCount->text().length())*m_nav1DigitWidth, height()); +// horizontalScrollBar()->move(d->navPanel->x()+d->navPanel->width()+20,horizontalScrollBar()->y()); + } + } + //update row number widget's width + const int w = m_nav1DigitWidth*QMAX( QMAX(n.length(),2)+1,m_navRecordNumber->text().length()+1)+6; + if (m_navRecordNumber->width()!=w) //resize + m_navRecordNumber->setFixedWidth(w); + + m_navRecordCount->setText(n); + m_navRecordCount->deselect(); + if (m_view) + m_view->updateScrollBars(); + updateButtons(recordCount()); +} + +uint KexiRecordNavigator::currentRecordNumber() const +{ + bool ok=true; + int r = m_navRecordNumber->text().toInt(&ok); + if (!ok || r<1) + r = 0; + return r; +} + +uint KexiRecordNavigator::recordCount() const +{ + bool ok=true; + int r = m_navRecordCount->text().toInt(&ok); + if (!ok || r<1) + r = 0; + return r; +} + +void KexiRecordNavigator::setParentView(QScrollView *view) +{ + m_view = view; +} + +void KexiRecordNavigator::updateGeometry(int leftMargin) +{ + QFrame::updateGeometry(); + if (m_view) { + int navWidth; + if (m_view->horizontalScrollBar()->isVisible()) { + navWidth = sizeHint().width(); + } + else { + navWidth = leftMargin + m_view->clipper()->width(); + } + + setGeometry( + m_view->frameWidth(), + m_view->height() - m_view->horizontalScrollBar()->sizeHint().height()-m_view->frameWidth(), + navWidth, + m_view->horizontalScrollBar()->sizeHint().height() + ); + + m_view->updateScrollBars(); + } +} + +void KexiRecordNavigator::setHBarGeometry( QScrollBar & hbar, int x, int y, int w, int h ) +{ + hbar.setGeometry( x + width(), y, w - width(), h ); +} + +void KexiRecordNavigator::setLabelText(const QString& text) +{ + m_textLabel->setText(text.isEmpty() ? QString::null : (QString::fromLatin1(" ")+text+" ")); +} + +void KexiRecordNavigator::setInsertingButtonVisible(bool set) +{ + if (set) + m_navBtnNew->show(); + else + m_navBtnNew->hide(); +} + +void KexiRecordNavigator::slotPrevButtonClicked() +{ + emit prevButtonClicked(); + if (d->handler) + d->handler->moveToPreviousRecordRequested(); +} + +void KexiRecordNavigator::slotNextButtonClicked() +{ + emit nextButtonClicked(); + if (d->handler) + d->handler->moveToNextRecordRequested(); +} + +void KexiRecordNavigator::slotLastButtonClicked() +{ + emit lastButtonClicked(); + if (d->handler) + d->handler->moveToLastRecordRequested(); +} + +void KexiRecordNavigator::slotFirstButtonClicked() +{ + emit firstButtonClicked(); + if (d->handler) + d->handler->moveToFirstRecordRequested(); +} + +void KexiRecordNavigator::slotNewButtonClicked() +{ + emit newButtonClicked(); + if (d->handler) + d->handler->addNewRecordRequested(); +} + + +void KexiRecordNavigator::setRecordHandler(KexiRecordNavigatorHandler *handler) +{ + d->handler = handler; +} + +bool KexiRecordNavigator::editingIndicatorVisible() const +{ + return d->editingIndicatorVisible; +} + +bool KexiRecordNavigator::editingIndicatorEnabled() const +{ + return d->editingIndicatorEnabled; +} + +void KexiRecordNavigator::setEditingIndicatorEnabled(bool set) +{ + d->editingIndicatorEnabled = set; + if (d->editingIndicatorEnabled) { + if (!d->editingIndicatorLabel) { + d->editingIndicatorLabel = new QLabel(this); + d->editingIndicatorLabel->setAlignment(Qt::AlignCenter); + QPixmap pix; + pix.convertFromImage( *KexiRecordMarker::penImage() ); + d->editingIndicatorLabel->setFixedWidth( pix.width() + 2*2 ); + d->lyr->insertWidget( 0, d->editingIndicatorLabel ); + } + d->editingIndicatorLabel->show(); + } + else { + if (d->editingIndicatorLabel) { + d->editingIndicatorLabel->hide(); + } + } +} + +void KexiRecordNavigator::showEditingIndicator(bool show) +{ + d->editingIndicatorVisible = show; + updateButtons(recordCount()); //this will refresh 'next btn' + if (!d->editingIndicatorEnabled) + return; + if (d->editingIndicatorVisible) { + QPixmap pix; + pix.convertFromImage( *KexiRecordMarker::penImage() ); + d->editingIndicatorLabel->setPixmap( pix ); + QToolTip::add( d->editingIndicatorLabel, i18n("Editing indicator") ); + } + else { + d->editingIndicatorLabel->setPixmap( QPixmap() ); + QToolTip::remove( d->editingIndicatorLabel ); + } +} + +//------------------------------------------------ + +//! @internal +class KexiRecordNavigatorActionsInternal { + public: + KexiRecordNavigatorActionsInternal() + : moveToFirstRecord(i18n("First row"), "navigator_first", i18n("Go to first row")) + , moveToPreviousRecord(i18n("Previous row"), "navigator_prev", i18n("Go to previous row")) + , moveToNextRecord(i18n("Next row"), "navigator_next", i18n("Go to next row")) + , moveToLastRecord(i18n("Last row"), "navigator_last", i18n("Go to last row")) + , moveToNewRecord(i18n("New row"), "navigator_new", i18n("Go to new row")) + { + } + static void init(); + KGuiItem moveToFirstRecord; + KGuiItem moveToPreviousRecord; + KGuiItem moveToNextRecord; + KGuiItem moveToLastRecord; + KGuiItem moveToNewRecord; +}; + +static KStaticDeleter<KexiRecordNavigatorActionsInternal> KexiRecordNavigatorActions_deleter; +KexiRecordNavigatorActionsInternal* KexiRecordNavigatorActions_internal = 0; + +void KexiRecordNavigatorActionsInternal::init() +{ + if (!KexiRecordNavigatorActions_internal) + KexiRecordNavigatorActions_deleter.setObject(KexiRecordNavigatorActions_internal, + new KexiRecordNavigatorActionsInternal()); +} + +const KGuiItem& KexiRecordNavigator::Actions::moveToFirstRecord() +{ KexiRecordNavigatorActionsInternal::init(); return KexiRecordNavigatorActions_internal->moveToFirstRecord; } + +const KGuiItem& KexiRecordNavigator::Actions::moveToPreviousRecord() +{ KexiRecordNavigatorActionsInternal::init(); return KexiRecordNavigatorActions_internal->moveToPreviousRecord; } + +const KGuiItem& KexiRecordNavigator::Actions::moveToNextRecord() +{ KexiRecordNavigatorActionsInternal::init(); return KexiRecordNavigatorActions_internal->moveToNextRecord; } + +const KGuiItem& KexiRecordNavigator::Actions::moveToLastRecord() +{ KexiRecordNavigatorActionsInternal::init(); return KexiRecordNavigatorActions_internal->moveToLastRecord; } + +const KGuiItem& KexiRecordNavigator::Actions::moveToNewRecord() +{ KexiRecordNavigatorActionsInternal::init(); return KexiRecordNavigatorActions_internal->moveToNewRecord; } + +#include "kexirecordnavigator.moc" diff --git a/kexi/widget/utils/kexirecordnavigator.h b/kexi/widget/utils/kexirecordnavigator.h new file mode 100644 index 000000000..674746e22 --- /dev/null +++ b/kexi/widget/utils/kexirecordnavigator.h @@ -0,0 +1,190 @@ +/* This file is part of the KDE project + Copyright (C) 2004 Lucijan Busch <lucijan@kde.org> + Copyright (C) 2003-2004 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. +*/ + +#ifndef KEXIRECORDNAVIGATOR_H +#define KEXIRECORDNAVIGATOR_H + +#include <qframe.h> +#include <kexi_export.h> + +class QToolButton; +class QIntValidator; +class QScrollView; +class QScrollBar; +class QLabel; +class KLineEdit; +class KGuiItem; +class KexiRecordNavigatorPrivate; + +//! \brief KexiRecordNavigatorHandler interface handles requests generated by KexiRecordNavigator +class KEXIGUIUTILS_EXPORT KexiRecordNavigatorHandler +{ + public: + KexiRecordNavigatorHandler(); + virtual ~KexiRecordNavigatorHandler(); + + //! Moving to record \a r is requested. Records are counted from 0. + virtual void moveToRecordRequested(uint r) = 0; + virtual void moveToLastRecordRequested() = 0; + virtual void moveToPreviousRecordRequested() = 0; + virtual void moveToNextRecordRequested() = 0; + virtual void moveToFirstRecordRequested() = 0; + virtual void addNewRecordRequested() = 0; +}; + + +//! \brief KexiRecordNavigator class provides a record navigator. +/*! Record navigator is usually used for data tables (e.g. KexiTableView) + or data-aware forms. + + You can plug KexiRecordNavigator object to your data-aware object in two ways: + 1) By connectiong to slots prevButtonClicked(), etc. + 2) A bit cleaner way: by inheriting from KexiRecordNavigatorHandler interface + in your data-aware class and implementing all it's prototype methods like + moveToRecordRequested(), and then caling setRecordHandler() on navigator's object. + Note that using this way, you can allow to exist more than one navigator widget + connected with your data-aware object (don't matter if this is sane). + */ +class KEXIGUIUTILS_EXPORT KexiRecordNavigator : public QFrame +{ + Q_OBJECT + + public: + KexiRecordNavigator(QWidget *parent, int leftMargin = 0, const char *name=0); + virtual ~KexiRecordNavigator(); + + void setParentView(QScrollView *view); + + /*! Sets record navigator handler. This allows to react + on actions performed within navigator and vice versa. */ + void setRecordHandler(KexiRecordNavigatorHandler *handler); + + /*! \return true if data inserting is enabled (the default). */ + inline bool isInsertingEnabled() const { return m_isInsertingEnabled; } + + /*! \return current record number displayed for this navigator. + can return 0, if the 'text box's content is cleared. */ + uint currentRecordNumber() const; + + /*! \return record count displayed for this navigator. */ + uint recordCount() const; + + /*! Sets horizontal bar's \a hbar (at the bottom) geometry so this record navigator + is properly positioned together with horizontal scroll bar. This method is used + in QScrollView::setHBarGeometry() implementations: + see KexiTableView::setHBarGeometry() and KexiFormScrollView::setHBarGeometry() + for usage examples. */ + void setHBarGeometry( QScrollBar & hbar, int x, int y, int w, int h ); + + /*! @internal used for keyboard handling. */ + virtual bool eventFilter( QObject *o, QEvent *e ); + + /*! \return true if "editing" indicator is visible for this navigator. + @see showEditingIndicator() */ + bool editingIndicatorVisible() const; + + /*! \return true if "editing" indicator is enabled for this navigator. + Only meaningful if setEditingIndicatorEnabled(true) is called. */ + bool editingIndicatorEnabled() const; + + //! @short A set of GUI items usable for displaying related actions. + /*! For instance, the items are used by Kexi main window to create shared actions. */ + class KEXIGUIUTILS_EXPORT Actions { + public: + static const KGuiItem& moveToFirstRecord(); + static const KGuiItem& moveToPreviousRecord(); + static const KGuiItem& moveToNextRecord(); + static const KGuiItem& moveToLastRecord(); + static const KGuiItem& moveToNewRecord(); + }; + + public slots: + /*! Sets insertingEnabled flag. If true, "+" button will be enabled. */ + void setInsertingEnabled(bool set); + + /*! Sets visibility of "inserting" button. */ + void setInsertingButtonVisible(bool set); + + /*! Sets visibility of the place where "editing" indicator will be displayed. + "editing" indicator will display KexiRecordMarker::penImage() image when + setEditingIndicatorVisible() is called. + This method is currently used e.g. within standard kexi forms + (see KexiFormScrollView class). */ + void setEditingIndicatorEnabled(bool set); + + /*! Shows or hides "editing" indicator. */ + void showEditingIndicator(bool show); + + virtual void setEnabled(bool set); + + /*! Sets current record number for this navigator, + i.e. a value that will be displayed in the 'record number' text box. + This can also affect button's enabling and disabling. + If @p r is 0, 'record number' text box's content is cleared. */ + void setCurrentRecordNumber(uint r); + + /*! Sets record count for this navigator. + This can also affect button's enabling and disabling. + By default count is 0. */ + void setRecordCount(uint count); + + void updateGeometry(int leftMargin); + + /*! Sets label text at the left of the for record navigator's button. + By default this label contains translated "Row:" text. */ + void setLabelText(const QString& text); + + signals: + void prevButtonClicked(); + void nextButtonClicked(); + void lastButtonClicked(); + void firstButtonClicked(); + void newButtonClicked(); + void recordNumberEntered( uint r ); + + protected slots: + void slotPrevButtonClicked(); + void slotNextButtonClicked(); + void slotLastButtonClicked(); + void slotFirstButtonClicked(); + void slotNewButtonClicked(); + //void slotRecordNumberReturnPressed(const QString& text); + + protected: + void updateButtons(uint recCnt); + + QLabel *m_textLabel; + QToolButton *m_navBtnFirst; + QToolButton *m_navBtnPrev; + QToolButton *m_navBtnNext; + QToolButton *m_navBtnLast; + QToolButton *m_navBtnNew; + KLineEdit *m_navRecordNumber; + QIntValidator *m_navRecordNumberValidator; + KLineEdit *m_navRecordCount; //!< readonly counter + uint m_nav1DigitWidth; +// uint m_recordCount; + QScrollView *m_view; + bool m_isInsertingEnabled : 1; + + KexiRecordNavigatorPrivate *d; +}; + +#endif diff --git a/kexi/widget/utils/kexisharedactionclient.cpp b/kexi/widget/utils/kexisharedactionclient.cpp new file mode 100644 index 000000000..4dbd9299d --- /dev/null +++ b/kexi/widget/utils/kexisharedactionclient.cpp @@ -0,0 +1,39 @@ +/* This file is part of the KDE project + Copyright (C) 2005 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 "kexisharedactionclient.h" + +#include <kaction.h> + +KexiSharedActionClient::KexiSharedActionClient() + : m_sharedActions(101, false) +{ +} + +KexiSharedActionClient::~KexiSharedActionClient() +{ +} + +void KexiSharedActionClient::plugSharedAction(KAction* a) +{ + if (!a) + return; + m_sharedActions.insert(a->name(), a); +} + diff --git a/kexi/widget/utils/kexisharedactionclient.h b/kexi/widget/utils/kexisharedactionclient.h new file mode 100644 index 000000000..80181bc7e --- /dev/null +++ b/kexi/widget/utils/kexisharedactionclient.h @@ -0,0 +1,49 @@ +/* This file is part of the KDE project + Copyright (C) 2005 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. +*/ + +#ifndef KEXISHAREDACTIONCLIENT_H +#define KEXISHAREDACTIONCLIENT_H + +#include <qasciidict.h> + +class KAction; +#include <kexi_export.h> + +//! The KexiSharedActionClient is an interface using application-wide (shared) actions. +/** See KexiTableView and KexiFormScrollView for example usage. +*/ +class KEXIGUIUTILS_EXPORT KexiSharedActionClient +{ + public: + KexiSharedActionClient(); + virtual ~KexiSharedActionClient(); + + /*! Plugs action \a a for a widget. The action will be later looked up (by name) + on key press event, to get proper shortcut. If found, we know that the action is already + performed at main window's level, so we should give up. Otherwise - default shortcut + will be used (example: Shift+Enter key for "data_save_row" action). \sa KexiTableView::shortCutPressed() + */ + void plugSharedAction(KAction* a); + + protected: + //! Actions pluged for this widget using plugSharedAction(), available by name. + QAsciiDict<KAction> m_sharedActions; +}; + +#endif diff --git a/kexi/widget/utils/kexitooltip.cpp b/kexi/widget/utils/kexitooltip.cpp new file mode 100644 index 000000000..69a8b583c --- /dev/null +++ b/kexi/widget/utils/kexitooltip.cpp @@ -0,0 +1,76 @@ +/* This file is part of the KDE project + Copyright (C) 2006 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 "kexitooltip.h" + +#include <qpixmap.h> +#include <qbitmap.h> +#include <qpainter.h> +#include <qimage.h> +#include <qtooltip.h> +#include <qfont.h> +#include <qfontmetrics.h> +#include <qtimer.h> + + +KexiToolTip::KexiToolTip(const QVariant& value, QWidget* parent) + : QWidget(parent, "KexiToolTip", Qt::WStyle_Customize | Qt::WType_Popup | Qt::WStyle_NoBorder + | Qt::WX11BypassWM | Qt::WDestructiveClose) + , m_value(value) +{ + setPalette( QToolTip::palette() ); + setFocusPolicy(QWidget::NoFocus); +} + +KexiToolTip::~KexiToolTip() +{ +} + +QSize KexiToolTip::sizeHint() const +{ + QSize sz(fontMetrics().boundingRect(m_value.toString()).size()); + return sz; +} + +void KexiToolTip::show() +{ + updateGeometry(); + QWidget::show(); +} + +void KexiToolTip::paintEvent( QPaintEvent *pev ) +{ + QWidget::paintEvent(pev); + QPainter p(this); + drawFrame(p); + drawContents(p); +} + +void KexiToolTip::drawFrame(QPainter& p) +{ + p.setPen( QPen(palette().active().foreground(), 1) ); + p.drawRect(rect()); +} + +void KexiToolTip::drawContents(QPainter& p) +{ + p.drawText(rect(), Qt::AlignCenter, m_value.toString()); +} + +#include "kexitooltip.moc" diff --git a/kexi/widget/utils/kexitooltip.h b/kexi/widget/utils/kexitooltip.h new file mode 100644 index 000000000..cbb0931f4 --- /dev/null +++ b/kexi/widget/utils/kexitooltip.h @@ -0,0 +1,47 @@ +/* This file is part of the KDE project + Copyright (C) 2006 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. +*/ + +#ifndef KEXITOOLTIP_H +#define KEXITOOLTIP_H + +#include <qwidget.h> +#include <qvariant.h> + +//! \brief A tooltip that can display rich content +class KEXIGUIUTILS_EXPORT KexiToolTip : public QWidget +{ + Q_OBJECT + public: + KexiToolTip(const QVariant& value, QWidget* parent); + virtual ~KexiToolTip(); + + virtual QSize sizeHint() const; + + public slots: + virtual void show(); + + protected: + virtual void paintEvent( QPaintEvent *pev ); + virtual void drawFrame(QPainter& p); + virtual void drawContents(QPainter& p); + + QVariant m_value; +}; + +#endif diff --git a/kexi/widget/utils/klistviewitemtemplate.h b/kexi/widget/utils/klistviewitemtemplate.h new file mode 100644 index 000000000..1c89f96c3 --- /dev/null +++ b/kexi/widget/utils/klistviewitemtemplate.h @@ -0,0 +1,50 @@ +/* This file is part of the KDE project + Copyright (C) 2005 Jaroslaw Staniek <js@iidea.pl> + + This library 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 library 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 library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + +#ifndef KLISTVIEWITEMTEMPLATE_H +#define KLISTVIEWITEMTEMPLATE_H + +#include <klistview.h> + +//! QListViewItem class with ability for storing additional data member +template<class type> +class KListViewItemTemplate : public KListViewItem +{ + public: + KListViewItemTemplate(type _data, QListView *parent) + : KListViewItem(parent), data(_data) {} + KListViewItemTemplate(type _data, QListViewItem *parent) + : KListViewItem(parent), data(_data) {} + KListViewItemTemplate(type _data, QListView *parent, QListViewItem *after) + : KListViewItem(parent, after), data(_data) {} + KListViewItemTemplate(type _data, QListViewItem *parent, QListViewItem *after) + : KListViewItem(parent, after), data(_data) {} + KListViewItemTemplate(type _data, QListView *parent, QString label1, QString label2=QString::null, QString label3=QString::null, QString label4=QString::null, QString label5=QString::null, QString label6=QString::null, QString label7=QString::null, QString label8=QString::null) + : KListViewItem(parent, label1, label2, label3, label4, label5, label6, label7, label8), data(_data) {} + KListViewItemTemplate(type _data, QListViewItem *parent, QString label1, QString label2=QString::null, QString label3=QString::null, QString label4=QString::null, QString label5=QString::null, QString label6=QString::null, QString label7=QString::null, QString label8=QString::null) + : KListViewItem(parent, label1, label2, label3, label4, label5, label6, label7, label8), data(_data) {} + KListViewItemTemplate(type _data, QListView *parent, QListViewItem *after, QString label1, QString label2=QString::null, QString label3=QString::null, QString label4=QString::null, QString label5=QString::null, QString label6=QString::null, QString label7=QString::null, QString label8=QString::null) + : KListViewItem(parent, after, label1, label2, label3, label4, label5, label6, label7, label8), data(_data) {} + KListViewItemTemplate(type _data, QListViewItem *parent, QListViewItem *after, QString label1, QString label2=QString::null, QString label3=QString::null, QString label4=QString::null, QString label5=QString::null, QString label6=QString::null, QString label7=QString::null, QString label8=QString::null) + : KListViewItem(parent, after, label1, label2, label3, label4, label5, label6, label7, label8), data(_data) {} + + type data; +}; + +#endif |
