diff options
author | axis <qt-info@nokia.com> | 2009-04-24 11:34:15 (GMT) |
---|---|---|
committer | axis <qt-info@nokia.com> | 2009-04-24 11:34:15 (GMT) |
commit | 8f427b2b914d5b575a4a7c0ed65d2fb8f45acc76 (patch) | |
tree | a17e1a767a89542ab59907462206d7dcf2e504b2 /tools/shared | |
download | Qt-8f427b2b914d5b575a4a7c0ed65d2fb8f45acc76.zip Qt-8f427b2b914d5b575a4a7c0ed65d2fb8f45acc76.tar.gz Qt-8f427b2b914d5b575a4a7c0ed65d2fb8f45acc76.tar.bz2 |
Long live Qt for S60!
Diffstat (limited to 'tools/shared')
115 files changed, 32739 insertions, 0 deletions
diff --git a/tools/shared/deviceskin/deviceskin.cpp b/tools/shared/deviceskin/deviceskin.cpp new file mode 100644 index 0000000..3301d24 --- /dev/null +++ b/tools/shared/deviceskin/deviceskin.cpp @@ -0,0 +1,857 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the tools applications of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "deviceskin.h" + +#include <QtCore/qnamespace.h> +#include <QtGui/QApplication> +#include <QtGui/QBitmap> +#include <QtGui/QPixmap> +#include <QtGui/QPainter> +#include <QtCore/QTextStream> +#include <QtCore/QFile> +#include <QtCore/QFileInfo> +#include <QtGui/QImage> +#include <QtCore/QTimer> +#include <QtCore/QDir> +#include <QtCore/QRegExp> +#include <QtGui/QMouseEvent> +#include <QtCore/QDebug> + +#ifdef TEST_SKIN +# include <QtGui/QMainWindow> +# include <QtGui/QDialog> +# include <QtGui/QDialogButtonBox> +# include <QtGui/QHBoxLayout> +#endif + +QT_BEGIN_NAMESPACE + +namespace { + enum { joydistance = 10, key_repeat_period = 50, key_repeat_delay = 500 }; + enum { debugDeviceSkin = 0 }; +} + +static void parseRect(const QString &value, QRect *rect) { + const QStringList l = value.split(QLatin1Char(' ')); + rect->setRect(l[0].toInt(), l[1].toInt(), l[2].toInt(), l[3].toInt()); +} + +static QString msgImageNotLoaded(const QString &f) { + return DeviceSkin::tr("The image file '%1' could not be loaded.").arg(f); +} + +// ------------ DeviceSkinButtonArea +DeviceSkinButtonArea::DeviceSkinButtonArea() : + keyCode(0), + activeWhenClosed(0) +{ +} + +QDebug &operator<<(QDebug &str, const DeviceSkinButtonArea &a) +{ + + str << "Area: " << a.name << " keyCode=" << a.keyCode << " area=" << a.area + << " text=" << a.text << " activeWhenClosed=" << a.activeWhenClosed; + return str; +} + +// ------------ DeviceSkinParameters + +QDebug operator<<(QDebug str, const DeviceSkinParameters &p) +{ + str << "Images " << p.skinImageUpFileName << ',' + << p.skinImageDownFileName<< ',' << p.skinImageClosedFileName + << ',' << p.skinCursorFileName <<"\nScreen: " << p.screenRect + << " back: " << p.backScreenRect << " closed: " << p.closedScreenRect + << " cursor: " << p.cursorHot << " Prefix: " << p.prefix + << " Joystick: " << p.joystick << " MouseHover" << p.hasMouseHover; + const int numAreas = p.buttonAreas.size(); + for (int i = 0; i < numAreas; i++) + str << p.buttonAreas[i]; + return str; +} + +QSize DeviceSkinParameters::secondaryScreenSize() const +{ + return backScreenRect.isNull() ? closedScreenRect .size(): backScreenRect.size(); +} + +bool DeviceSkinParameters::hasSecondaryScreen() const +{ + return secondaryScreenSize() != QSize(0, 0); +} + +bool DeviceSkinParameters::read(const QString &skinDirectory, ReadMode rm, QString *errorMessage) +{ + // Figure out the name. remove ending '/' if present + QString skinFile = skinDirectory; + if (skinFile.endsWith(QLatin1Char('/'))) + skinFile.truncate(skinFile.length() - 1); + + QFileInfo fi(skinFile); + QString fn; + if ( fi.isDir() ) { + prefix = skinFile; + prefix += QLatin1Char('/'); + fn = prefix; + fn += fi.baseName(); + fn += QLatin1String(".skin"); + } else if (fi.isFile()){ + fn = skinFile; + prefix = fi.path(); + prefix += QLatin1Char('/'); + } else { + *errorMessage = DeviceSkin::tr("The skin directory '%1' does not contain a configuration file.").arg(skinDirectory); + return false; + } + QFile f(fn); + if (!f.open(QIODevice::ReadOnly )) { + *errorMessage = DeviceSkin::tr("The skin configuration file '%1' could not be opened.").arg(fn); + return false; + } + QTextStream ts(&f); + const bool rc = read(ts, rm, errorMessage); + if (!rc) + *errorMessage = DeviceSkin::tr("The skin configuration file '%1' could not be read: %2").arg(fn).arg(*errorMessage); + return rc; +} +bool DeviceSkinParameters::read(QTextStream &ts, ReadMode rm, QString *errorMessage) +{ + QStringList closedAreas; + QStringList toggleAreas; + QStringList toggleActiveAreas; + int nareas = 0; + screenDepth = 0; + QString mark; + ts >> mark; + hasMouseHover = true; // historical default + if ( mark == QLatin1String("[SkinFile]") ) { + const QString UpKey = QLatin1String("Up"); + const QString DownKey = QLatin1String("Down"); + const QString ClosedKey = QLatin1String("Closed"); + const QString ClosedAreasKey = QLatin1String("ClosedAreas"); + const QString ScreenKey = QLatin1String("Screen"); + const QString ScreenDepthKey = QLatin1String("ScreenDepth"); + const QString BackScreenKey = QLatin1String("BackScreen"); + const QString ClosedScreenKey = QLatin1String("ClosedScreen"); + const QString CursorKey = QLatin1String("Cursor"); + const QString AreasKey = QLatin1String("Areas"); + const QString ToggleAreasKey = QLatin1String("ToggleAreas"); + const QString ToggleActiveAreasKey = QLatin1String("ToggleActiveAreas"); + const QString HasMouseHoverKey = QLatin1String("HasMouseHover"); + // New + while (!nareas) { + QString line = ts.readLine(); + if ( line.isNull() ) + break; + if ( line[0] != QLatin1Char('#') && !line.isEmpty() ) { + int eq = line.indexOf(QLatin1Char('=')); + if ( eq >= 0 ) { + const QString key = line.left(eq); + eq++; + while (eq<line.length()-1 && line[eq].isSpace()) + eq++; + const QString value = line.mid(eq); + if ( key == UpKey ) { + skinImageUpFileName = value; + } else if ( key == DownKey ) { + skinImageDownFileName = value; + } else if ( key == ClosedKey ) { + skinImageClosedFileName = value; + } else if ( key == ClosedAreasKey ) { + closedAreas = value.split(QLatin1Char(' ')); + } else if ( key == ScreenKey ) { + parseRect( value, &screenRect); + } else if ( key == ScreenDepthKey ) { + screenDepth = value.toInt(); + } else if ( key == BackScreenKey ) { + parseRect(value, &backScreenRect); + } else if ( key == ClosedScreenKey ) { + parseRect( value, &closedScreenRect ); + } else if ( key == CursorKey ) { + QStringList l = value.split(QLatin1Char(' ')); + skinCursorFileName = l[0]; + cursorHot = QPoint(l[1].toInt(),l[2].toInt()); + } else if ( key == AreasKey ) { + nareas = value.toInt(); + } else if ( key == ToggleAreasKey ) { + toggleAreas = value.split(QLatin1Char(' ')); + } else if ( key == ToggleActiveAreasKey ) { + toggleActiveAreas = value.split(QLatin1Char(' ')); + } else if ( key == HasMouseHoverKey ) { + hasMouseHover = value == QLatin1String("true") || value == QLatin1String("1"); + } + } else { + *errorMessage = DeviceSkin::tr("Syntax error: %1").arg(line); + return false; + } + } + } + } else { + // Old + skinImageUpFileName = mark; + QString s; + int x,y,w,h,na; + ts >> s >> x >> y >> w >> h >> na; + skinImageDownFileName = s; + screenRect.setRect(x, y, w, h); + nareas = na; + } + // Done for short mode + if (rm == ReadSizeOnly) + return true; + // verify skin files exist + skinImageUpFileName.insert(0, prefix); + if (!QFile(skinImageUpFileName).exists()) { + *errorMessage = DeviceSkin::tr("The skin \"up\" image file '%1' does not exist.").arg(skinImageUpFileName); + return false; + } + if (!skinImageUp.load(skinImageUpFileName)) { + *errorMessage = msgImageNotLoaded(skinImageUpFileName); + return false; + } + + skinImageDownFileName.insert(0, prefix); + if (!QFile(skinImageDownFileName).exists()) { + *errorMessage = DeviceSkin::tr("The skin \"down\" image file '%1' does not exist.").arg(skinImageDownFileName); + return false; + } + if (!skinImageDown.load(skinImageDownFileName)) { + *errorMessage = msgImageNotLoaded(skinImageDownFileName); + return false; + } + + if (!skinImageClosedFileName.isEmpty()) { + skinImageClosedFileName.insert(0, prefix); + if (!QFile(skinImageClosedFileName).exists()) { + *errorMessage = DeviceSkin::tr("The skin \"closed\" image file '%1' does not exist.").arg(skinImageClosedFileName); + return false; + } + if (!skinImageClosed.load(skinImageClosedFileName)) { + *errorMessage = msgImageNotLoaded(skinImageClosedFileName); + return false; + } + } + + if (!skinCursorFileName.isEmpty()) { + skinCursorFileName.insert(0, prefix); + if (!QFile(skinCursorFileName).exists()) { + *errorMessage = DeviceSkin::tr("The skin cursor image file '%1' does not exist.").arg(skinCursorFileName); + return false; + } + if (!skinCursor.load(skinCursorFileName)) { + *errorMessage = msgImageNotLoaded(skinCursorFileName); + return false; + } + } + + // read areas + if (!nareas) + return true; + buttonAreas.reserve(nareas); + + int i = 0; + ts.readLine(); // eol + joystick = -1; + const QString Joystick = QLatin1String("Joystick"); + while (i < nareas && !ts.atEnd() ) { + buttonAreas.push_back(DeviceSkinButtonArea()); + DeviceSkinButtonArea &area = buttonAreas.back(); + const QString line = ts.readLine(); + if ( !line.isEmpty() && line[0] != QLatin1Char('#') ) { + const QStringList tok = line.split(QRegExp(QLatin1String("[ \t][ \t]*"))); + if ( tok.count()<6 ) { + *errorMessage = DeviceSkin::tr("Syntax error in area definition: %1").arg(line); + return false; + } else { + area.name = tok[0]; + QString k = tok[1]; + if ( k.left(2).toLower() == QLatin1String("0x")) { + area.keyCode = k.mid(2).toInt(0,16); + } else { + area.keyCode = k.toInt(); + } + + int p=0; + for (int j=2; j < tok.count() - 1; ) { + const int x = tok[j++].toInt(); + const int y = tok[j++].toInt(); + area.area.putPoints(p++,1,x,y); + } + + const QChar doubleQuote = QLatin1Char('"'); + if ( area.name[0] == doubleQuote && area.name.endsWith(doubleQuote)) { + area.name.truncate(area.name.size() - 1); + area.name.remove(0, 1); + } + if ( area.name.length() == 1 ) + area.text = area.name; + if ( area.name == Joystick) + joystick = i; + area.activeWhenClosed = closedAreas.contains(area.name) + || area.keyCode == Qt::Key_Flip; // must be to work + area.toggleArea = toggleAreas.contains(area.name); + area.toggleActiveArea = toggleActiveAreas.contains(area.name); + if ( area.toggleArea ) + toggleAreaList += i; + i++; + } + } + } + if (i != nareas) { + qWarning() << DeviceSkin::tr("Mismatch in number of areas, expected %1, got %2.") + .arg(nareas).arg(i); + } + if (debugDeviceSkin) + qDebug() << *this; + return true; +} + +// --------- CursorWindow declaration + +namespace qvfb_internal { + +class CursorWindow : public QWidget +{ +public: + explicit CursorWindow(const QImage &cursor, QPoint hot, QWidget *sk); + + void setView(QWidget*); + void setPos(QPoint); + bool handleMouseEvent(QEvent *ev); + +protected: + bool event( QEvent *); + bool eventFilter( QObject*, QEvent *); + +private: + QWidget *mouseRecipient; + QWidget *m_view; + QWidget *skin; + QPoint hotspot; +}; +} + +// --------- Skin + +DeviceSkin::DeviceSkin(const DeviceSkinParameters ¶meters, QWidget *p ) : + QWidget(p), + m_parameters(parameters), + buttonRegions(parameters.buttonAreas.size(), QRegion()), + parent(p), + m_view(0), + m_secondaryView(0), + buttonPressed(false), + buttonIndex(0), + cursorw(0), + joydown(0), + t_skinkey(new QTimer(this)), + t_parentmove(new QTimer(this)), + flipped_open(true) +{ + Q_ASSERT(p); + setMouseTracking(true); + setAttribute(Qt::WA_NoSystemBackground); + + setZoom(1.0); + connect( t_skinkey, SIGNAL(timeout()), this, SLOT(skinKeyRepeat()) ); + t_parentmove->setSingleShot( true ); + connect( t_parentmove, SIGNAL(timeout()), this, SLOT(moveParent()) ); +} + +void DeviceSkin::skinKeyRepeat() +{ + if ( m_view ) { + const DeviceSkinButtonArea &area = m_parameters.buttonAreas[buttonIndex]; + emit skinKeyReleaseEvent( area.keyCode,area.text, true ); + emit skinKeyPressEvent( area.keyCode, area.text, true ); + t_skinkey->start(key_repeat_period); + } +} + +void DeviceSkin::calcRegions() +{ + const int numAreas = m_parameters.buttonAreas.size(); + for (int i=0; i<numAreas; i++) { + QPolygon xa(m_parameters.buttonAreas[i].area.count()); + int n = m_parameters.buttonAreas[i].area.count(); + for (int p=0; p<n; p++) { + xa.setPoint(p,transform.map(m_parameters.buttonAreas[i].area[p])); + } + if ( n == 2 ) { + buttonRegions[i] = QRegion(xa.boundingRect()); + } else { + buttonRegions[i] = QRegion(xa); + } + } +} + +void DeviceSkin::loadImages() +{ + QImage iup = m_parameters.skinImageUp; + QImage idown = m_parameters.skinImageDown; + + QImage iclosed; + const bool hasClosedImage = !m_parameters.skinImageClosed.isNull(); + + if (hasClosedImage) + iclosed = m_parameters.skinImageClosed; + QImage icurs; + const bool hasCursorImage = !m_parameters.skinCursor.isNull(); + if (hasCursorImage) + icurs = m_parameters.skinCursor; + + if (!transform.isIdentity()) { + iup = iup.transformed(transform, Qt::SmoothTransformation); + idown = idown.transformed(transform, Qt::SmoothTransformation); + if (hasClosedImage) + iclosed = iclosed.transformed(transform, Qt::SmoothTransformation); + if (hasCursorImage) + icurs = icurs.transformed(transform, Qt::SmoothTransformation); + } + const Qt::ImageConversionFlags conv = Qt::ThresholdAlphaDither|Qt::AvoidDither; + skinImageUp = QPixmap::fromImage(iup); + skinImageDown = QPixmap::fromImage(idown, conv); + if (hasClosedImage) + skinImageClosed = QPixmap::fromImage(iclosed, conv); + if (hasCursorImage) + skinCursor = QPixmap::fromImage(icurs, conv); + + setFixedSize( skinImageUp.size() ); + if (!skinImageUp.mask()) + skinImageUp.setMask(skinImageUp.createHeuristicMask()); + if (!skinImageClosed.mask()) + skinImageClosed.setMask(skinImageClosed.createHeuristicMask()); + + QWidget* parent = parentWidget(); + parent->setMask( skinImageUp.mask() ); + parent->setFixedSize( skinImageUp.size() ); + + delete cursorw; + cursorw = 0; + if (hasCursorImage) { + cursorw = new qvfb_internal::CursorWindow(m_parameters.skinCursor, m_parameters.cursorHot, this); + if ( m_view ) + cursorw->setView(m_view); + } +} + +DeviceSkin::~DeviceSkin( ) +{ + delete cursorw; +} + +void DeviceSkin::setTransform( const QMatrix& wm ) +{ + transform = QImage::trueMatrix(wm,m_parameters.skinImageUp.width(),m_parameters.skinImageUp.height()); + calcRegions(); + loadImages(); + if ( m_view ) { + QPoint p = transform.map(QPolygon(m_parameters.screenRect)).boundingRect().topLeft(); + m_view->move(p); + } + updateSecondaryScreen(); +} + +void DeviceSkin::setZoom( double z ) +{ + setTransform(QMatrix().scale(z,z)); +} + +void DeviceSkin::updateSecondaryScreen() +{ + if (!m_secondaryView) + return; + if (flipped_open) { + if (m_parameters.backScreenRect.isNull()) { + m_secondaryView->hide(); + } else { + m_secondaryView->move(transform.map(QPolygon(m_parameters.backScreenRect)).boundingRect().topLeft()); + m_secondaryView->show(); + } + } else { + if (m_parameters.closedScreenRect.isNull()) { + m_secondaryView->hide(); + } else { + m_secondaryView->move(transform.map(QPolygon(m_parameters.closedScreenRect)).boundingRect().topLeft()); + m_secondaryView->show(); + } + } +} + +void DeviceSkin::setView( QWidget *v ) +{ + m_view = v; + m_view->setFocus(); + m_view->move(transform.map(QPolygon(m_parameters.screenRect)).boundingRect().topLeft()); + if ( cursorw ) + cursorw->setView(v); +} + +void DeviceSkin::setSecondaryView( QWidget *v ) +{ + m_secondaryView = v; + updateSecondaryScreen(); +} + +void DeviceSkin::paintEvent( QPaintEvent *) +{ + QPainter p( this ); + if ( flipped_open ) { + p.drawPixmap( 0, 0, skinImageUp ); + } else { + p.drawPixmap( 0, 0, skinImageClosed ); + } + QList<int> toDraw; + if ( buttonPressed == true ) { + toDraw += buttonIndex; + } + foreach (int toggle, m_parameters.toggleAreaList) { + const DeviceSkinButtonArea &ba = m_parameters.buttonAreas[toggle]; + if ( flipped_open || ba.activeWhenClosed ) { + if ( ba.toggleArea && ba.toggleActiveArea ) + toDraw += toggle; + } + } + foreach (int button, toDraw ) { + const DeviceSkinButtonArea &ba = m_parameters.buttonAreas[button]; + const QRect r = buttonRegions[button].boundingRect(); + if ( ba.area.count() > 2 ) + p.setClipRegion(buttonRegions[button]); + p.drawPixmap( r.topLeft(), skinImageDown, r); + } +} + +void DeviceSkin::mousePressEvent( QMouseEvent *e ) +{ + if (e->button() == Qt::RightButton) { + emit popupMenu(); + } else { + buttonPressed = false; + + onjoyrelease = -1; + const int numAreas = m_parameters.buttonAreas.size(); + for (int i = 0; i < numAreas ; i++) { + const DeviceSkinButtonArea &ba = m_parameters.buttonAreas[i]; + if ( buttonRegions[i].contains( e->pos() ) ) { + if ( flipped_open || ba.activeWhenClosed ) { + if ( m_parameters.joystick == i ) { + joydown = true; + } else { + if ( joydown ) + onjoyrelease = i; + else + startPress(i); + break; + if (debugDeviceSkin)// Debug message to be sure we are clicking the right areas + qDebug()<< m_parameters.buttonAreas[i].name << " clicked"; + } + } + } + } + clickPos = e->pos(); +// This is handy for finding the areas to define rectangles for new skins + if (debugDeviceSkin) + qDebug()<< "Clicked in " << e->pos().x() << ',' << e->pos().y(); + clickPos = e->pos(); + } +} + +void DeviceSkin::flip(bool open) +{ + if ( flipped_open == open ) + return; + if ( open ) { + parent->setMask( skinImageUp.mask() ); + emit skinKeyReleaseEvent( Qt::Key(Qt::Key_Flip), QString(), false); + } else { + parent->setMask( skinImageClosed.mask() ); + emit skinKeyPressEvent( Qt::Key(Qt::Key_Flip), QString(), false); + } + flipped_open = open; + updateSecondaryScreen(); + repaint(); +} + +void DeviceSkin::startPress(int i) +{ + buttonPressed = true; + buttonIndex = i; + if (m_view) { + const DeviceSkinButtonArea &ba = m_parameters.buttonAreas[buttonIndex]; + if ( ba.keyCode == Qt::Key_Flip ) { + flip(!flipped_open); + } else if ( ba.toggleArea ) { + bool active = !ba.toggleActiveArea; + const_cast<DeviceSkinButtonArea &>(ba).toggleActiveArea = active; + if ( active ) + emit skinKeyPressEvent( ba.keyCode, ba.text, false); + else + emit skinKeyReleaseEvent( ba.keyCode, ba.text, false); + } else { + emit skinKeyPressEvent( ba.keyCode, ba.text, false); + t_skinkey->start(key_repeat_delay); + } + repaint( buttonRegions[buttonIndex].boundingRect() ); + } +} + +void DeviceSkin::endPress() +{ + const DeviceSkinButtonArea &ba = m_parameters.buttonAreas[buttonIndex]; + if (m_view && ba.keyCode != Qt::Key_Flip && !ba.toggleArea ) + emit skinKeyReleaseEvent(ba.keyCode, ba.text, false ); + t_skinkey->stop(); + buttonPressed = false; + repaint( buttonRegions[buttonIndex].boundingRect() ); +} + +void DeviceSkin::mouseMoveEvent( QMouseEvent *e ) +{ + if ( e->buttons() & Qt::LeftButton ) { + const int joystick = m_parameters.joystick; + QPoint newpos = e->globalPos() - clickPos; + if ( joydown ) { + int k1=0, k2=0; + if ( newpos.x() < -joydistance ) { + k1 = joystick+1; + } else if ( newpos.x() > +joydistance ) { + k1 = joystick+3; + } + if ( newpos.y() < -joydistance ) { + k2 = joystick+2; + } else if ( newpos.y() > +joydistance ) { + k2 = joystick+4; + } + if ( k1 || k2 ) { + if ( !buttonPressed ) { + onjoyrelease = -1; + if ( k1 && k2 ) { + startPress(k2); + endPress(); + } + startPress(k1 ? k1 : k2); + } + } else if ( buttonPressed ) { + endPress(); + } + } else if ( buttonPressed == false ) { + parentpos = newpos; + if ( !t_parentmove->isActive() ) + t_parentmove->start(50); + } + } + if ( cursorw ) + cursorw->setPos(e->globalPos()); +} + +void DeviceSkin::moveParent() +{ + parent->move( parentpos ); +} + +void DeviceSkin::mouseReleaseEvent( QMouseEvent * ) +{ + if ( buttonPressed ) + endPress(); + if ( joydown ) { + joydown = false; + if ( onjoyrelease >= 0 ) { + startPress(onjoyrelease); + endPress(); + } + } +} + +bool DeviceSkin::hasCursor() const +{ + return !skinCursor.isNull(); +} + +// ------------------ CursorWindow implementation + +namespace qvfb_internal { + +bool CursorWindow::eventFilter( QObject *, QEvent *ev) +{ + handleMouseEvent(ev); + return false; +} + +bool CursorWindow::event( QEvent *ev ) +{ + if (handleMouseEvent(ev)) + return true; + return QWidget::event(ev); +} + +bool CursorWindow::handleMouseEvent(QEvent *ev) +{ + bool handledEvent = false; + static int inhere=0; + if ( !inhere ) { + inhere++; + if ( m_view ) { + if ( ev->type() >= QEvent::MouseButtonPress && ev->type() <= QEvent::MouseMove ) { + QMouseEvent *e = (QMouseEvent*)ev; + QPoint gp = e->globalPos(); + QPoint vp = m_view->mapFromGlobal(gp); + QPoint sp = skin->mapFromGlobal(gp); + if ( e->type() == QEvent::MouseButtonPress || e->type() == QEvent::MouseButtonDblClick ) { + if ( m_view->rect().contains(vp) ) + mouseRecipient = m_view; + else if ( skin->parentWidget()->geometry().contains(gp) ) + mouseRecipient = skin; + else + mouseRecipient = 0; + } + if ( mouseRecipient ) { + setPos(gp); + QMouseEvent me(e->type(),mouseRecipient==skin ? sp : vp,gp,e->button(),e->buttons(),e->modifiers()); + QApplication::sendEvent(mouseRecipient, &me); + } else if ( !skin->parentWidget()->geometry().contains(gp) ) { + hide(); + } else { + setPos(gp); + } + if ( e->type() == QEvent::MouseButtonRelease ) + mouseRecipient = 0; + handledEvent = true; + } + } + inhere--; + } + return handledEvent; +} + +void CursorWindow::setView(QWidget* v) +{ + if ( m_view ) { + m_view->removeEventFilter(this); + m_view->removeEventFilter(this); + } + m_view = v; + m_view->installEventFilter(this); + m_view->installEventFilter(this); + mouseRecipient = 0; +} + +CursorWindow::CursorWindow(const QImage &img, QPoint hot, QWidget* sk) + :QWidget(0), + m_view(0), skin(sk), + hotspot(hot) +{ + setWindowFlags( Qt::FramelessWindowHint ); + mouseRecipient = 0; + setMouseTracking(true); +#ifndef QT_NO_CURSOR + setCursor(Qt::BlankCursor); +#endif + QPixmap p; + p = QPixmap::fromImage(img); + if (!p.mask()) { + if ( img.hasAlphaChannel() ) { + QBitmap bm; + bm = QPixmap::fromImage(img.createAlphaMask()); + p.setMask( bm ); + } else { + QBitmap bm; + bm = QPixmap::fromImage(img.createHeuristicMask()); + p.setMask( bm ); + } + } + QPalette palette; + palette.setBrush(backgroundRole(), QBrush(p)); + setPalette(palette); + setFixedSize( p.size() ); + if ( !p.mask().isNull() ) + setMask( p.mask() ); +} + +void CursorWindow::setPos(QPoint p) +{ + move(p-hotspot); + show(); + raise(); +} +} + +#ifdef TEST_SKIN + +int main(int argc,char *argv[]) +{ + if (argc < 1) + return 1; + const QString skinFile = QString::fromUtf8(argv[1]); + QApplication app(argc,argv); + QMainWindow mw; + + DeviceSkinParameters params; + QString errorMessage; + if (!params.read(skinFile, DeviceSkinParameters::ReadAll, &errorMessage)) { + qWarning() << errorMessage; + return 1; + } + DeviceSkin ds(params, &mw); + // View Dialog + QDialog *dialog = new QDialog(); + QHBoxLayout *dialogLayout = new QHBoxLayout(); + dialog->setLayout(dialogLayout); + QDialogButtonBox *dialogButtonBox = new QDialogButtonBox(QDialogButtonBox::Ok|QDialogButtonBox::Cancel); + QObject::connect(dialogButtonBox, SIGNAL(rejected()), dialog, SLOT(reject())); + QObject::connect(dialogButtonBox, SIGNAL(accepted()), dialog, SLOT(accept())); + dialogLayout->addWidget(dialogButtonBox); + dialog->setFixedSize(params.screenSize()); + dialog->setParent(&ds, Qt::SubWindow); + dialog->setAutoFillBackground(true); + ds.setView(dialog); + + QObject::connect(&ds, SIGNAL(popupMenu()), &mw, SLOT(close())); + QObject::connect(&ds, SIGNAL(skinKeyPressEvent(int,QString,bool)), &mw, SLOT(close())); + mw.show(); + return app.exec(); +} + +#endif + +QT_END_NAMESPACE + diff --git a/tools/shared/deviceskin/deviceskin.h b/tools/shared/deviceskin/deviceskin.h new file mode 100644 index 0000000..8f3fefd --- /dev/null +++ b/tools/shared/deviceskin/deviceskin.h @@ -0,0 +1,174 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the tools applications of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef SKIN_H +#define SKIN_H + +#include <QtGui/QWidget> +#include <QtGui/QPolygon> +#include <QtGui/QRegion> +#include <QtGui/QPixmap> +#include <QtCore/QVector> + +QT_BEGIN_NAMESPACE + +namespace qvfb_internal { + class CursorWindow; +} + +class QTextStream; + +// ------- Button Area +struct DeviceSkinButtonArea { + DeviceSkinButtonArea(); + QString name; + int keyCode; + QPolygon area; + QString text; + bool activeWhenClosed; + bool toggleArea; + bool toggleActiveArea; +}; + +// -------- Parameters +struct DeviceSkinParameters { + enum ReadMode { ReadAll, ReadSizeOnly }; + bool read(const QString &skinDirectory, ReadMode rm, QString *errorMessage); + bool read(QTextStream &ts, ReadMode rm, QString *errorMessage); + + QSize screenSize() const { return screenRect.size(); } + QSize secondaryScreenSize() const; + bool hasSecondaryScreen() const; + + QString skinImageUpFileName; + QString skinImageDownFileName; + QString skinImageClosedFileName; + QString skinCursorFileName; + + QImage skinImageUp; + QImage skinImageDown; + QImage skinImageClosed; + QImage skinCursor; + + QRect screenRect; + QRect backScreenRect; + QRect closedScreenRect; + int screenDepth; + QPoint cursorHot; + QVector<DeviceSkinButtonArea> buttonAreas; + QList<int> toggleAreaList; + + int joystick; + QString prefix; + bool hasMouseHover; +}; + +// --------- Skin Widget +class DeviceSkin : public QWidget +{ + Q_OBJECT +public: + explicit DeviceSkin(const DeviceSkinParameters ¶meters, QWidget *p ); + ~DeviceSkin( ); + + QWidget *view() const { return m_view; } + void setView( QWidget *v ); + + QWidget *secondaryView() const { return m_secondaryView; } + void setSecondaryView( QWidget *v ); + + void setZoom( double ); + void setTransform( const QMatrix& ); + + bool hasCursor() const; + + QString prefix() const {return m_parameters.prefix;} + +signals: + void popupMenu(); + void skinKeyPressEvent(int code, const QString& text, bool autorep); + void skinKeyReleaseEvent(int code, const QString& text, bool autorep); + +protected slots: + void skinKeyRepeat(); + void moveParent(); + +protected: + virtual void paintEvent( QPaintEvent * ); + virtual void mousePressEvent( QMouseEvent *e ); + virtual void mouseMoveEvent( QMouseEvent *e ); + virtual void mouseReleaseEvent( QMouseEvent * ); + +private: + void calcRegions(); + void flip(bool open); + void updateSecondaryScreen(); + void loadImages(); + void startPress(int); + void endPress(); + + const DeviceSkinParameters m_parameters; + QVector<QRegion> buttonRegions; + QPixmap skinImageUp; + QPixmap skinImageDown; + QPixmap skinImageClosed; + QPixmap skinCursor; + QWidget *parent; + QWidget *m_view; + QWidget *m_secondaryView; + QPoint parentpos; + QPoint clickPos; + bool buttonPressed; + int buttonIndex; + QMatrix transform; + qvfb_internal::CursorWindow *cursorw; + + bool joydown; + QTimer *t_skinkey; + QTimer *t_parentmove; + int onjoyrelease; + + bool flipped_open; +}; + +QT_END_NAMESPACE + +#endif diff --git a/tools/shared/deviceskin/deviceskin.pri b/tools/shared/deviceskin/deviceskin.pri new file mode 100644 index 0000000..e4c9ef7 --- /dev/null +++ b/tools/shared/deviceskin/deviceskin.pri @@ -0,0 +1,3 @@ +INCLUDEPATH += $$PWD +HEADERS += $$PWD/deviceskin.h +SOURCES += $$PWD/deviceskin.cpp diff --git a/tools/shared/findwidget/abstractfindwidget.cpp b/tools/shared/findwidget/abstractfindwidget.cpp new file mode 100644 index 0000000..e52722c --- /dev/null +++ b/tools/shared/findwidget/abstractfindwidget.cpp @@ -0,0 +1,295 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the tools applications of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/*! \class AbstractFindWidget + + \brief A search bar that is commonly added below a searchable widget. + + \internal + + This widget implements a search bar which becomes visible when the user + wants to start searching. It is a modern replacement for the commonly used + search dialog. It is usually placed below the target widget using a QVBoxLayout. + + The search is incremental and can be set to case sensitive or whole words + using buttons available on the search bar. + */ + +#include "abstractfindwidget.h" + +#include <QtCore/QEvent> +#include <QtCore/QFile> +#include <QtCore/QTimer> + +#include <QtGui/QCheckBox> +#include <QtGui/QKeyEvent> +#include <QtGui/QLabel> +#include <QtGui/QLayout> +#include <QtGui/QLineEdit> +#include <QtGui/QSpacerItem> +#include <QtGui/QToolButton> + +QT_BEGIN_NAMESPACE + +static QIcon createIconSet(const QString &name) +{ + QStringList candidates = QStringList() + << (QString::fromUtf8(":/trolltech/shared/images/") + name) +#ifdef Q_WS_MAC + << (QString::fromUtf8(":/trolltech/shared/images/mac/") + name); +#else + << (QString::fromUtf8(":/trolltech/shared/images/win/") + name); +#endif + + foreach (const QString &f, candidates) { + if (QFile::exists(f)) + return QIcon(f); + } + + return QIcon(); +} + +/*! + Constructs an AbstractFindWidget. + + \a flags can change the layout and turn off certain features. + \a parent is passed to the QWidget constructor. + */ +AbstractFindWidget::AbstractFindWidget(FindFlags flags, QWidget *parent) + : QWidget(parent) +{ + QBoxLayout *topLayOut; + QBoxLayout *layOut; + if (flags & NarrowLayout) { + topLayOut = new QVBoxLayout(this); + layOut = new QHBoxLayout; + topLayOut->addLayout(layOut); + } else { + topLayOut = layOut = new QHBoxLayout(this); + } +#ifndef Q_OS_MAC + topLayOut->setSpacing(6); + topLayOut->setMargin(0); +#endif + + m_toolClose = new QToolButton(this); + m_toolClose->setIcon(createIconSet(QLatin1String("closetab.png"))); + m_toolClose->setAutoRaise(true); + layOut->addWidget(m_toolClose); + connect(m_toolClose, SIGNAL(clicked()), SLOT(deactivate())); + + m_editFind = new QLineEdit(this); + layOut->addWidget(m_editFind); + connect(m_editFind, SIGNAL(returnPressed()), SLOT(findNext())); + connect(m_editFind, SIGNAL(textChanged(QString)), SLOT(findCurrentText())); + connect(m_editFind, SIGNAL(textChanged(QString)), SLOT(updateButtons())); + + m_toolPrevious = new QToolButton(this); + m_toolPrevious->setAutoRaise(true); + m_toolPrevious->setText(tr("&Previous")); + m_toolPrevious->setToolButtonStyle(Qt::ToolButtonTextBesideIcon); + m_toolPrevious->setIcon(createIconSet(QLatin1String("previous.png"))); + layOut->addWidget(m_toolPrevious); + connect(m_toolPrevious, SIGNAL(clicked()), SLOT(findPrevious())); + + m_toolNext = new QToolButton(this); + m_toolNext->setAutoRaise(true); + m_toolNext->setText(tr("&Next")); + m_toolNext->setToolButtonStyle(Qt::ToolButtonTextBesideIcon); + m_toolNext->setIcon(createIconSet(QLatin1String("next.png"))); + layOut->addWidget(m_toolNext); + connect(m_toolNext, SIGNAL(clicked()), SLOT(findNext())); + + if (flags & NarrowLayout) { + QSizePolicy sp(QSizePolicy::Preferred, QSizePolicy::Fixed); + m_toolPrevious->setSizePolicy(sp); + m_toolPrevious->setMinimumWidth(m_toolPrevious->minimumSizeHint().height()); + m_toolNext->setSizePolicy(sp); + m_toolNext->setMinimumWidth(m_toolNext->minimumSizeHint().height()); + + QSpacerItem *spacerItem = + new QSpacerItem(1, 1, QSizePolicy::Expanding, QSizePolicy::Minimum); + layOut->addItem(spacerItem); + + layOut = new QHBoxLayout; + topLayOut->addLayout(layOut); + } else { + m_editFind->setMinimumWidth(150); + } + + if (!(flags & NoCaseSensitive)) { + m_checkCase = new QCheckBox(tr("&Case sensitive"), this); + layOut->addWidget(m_checkCase); + connect(m_checkCase, SIGNAL(toggled(bool)), SLOT(findCurrentText())); + } else { + m_checkCase = 0; + } + + if (!(flags & NoWholeWords)) { + m_checkWholeWords = new QCheckBox(tr("Whole &words"), this); + layOut->addWidget(m_checkWholeWords); + connect(m_checkWholeWords, SIGNAL(toggled(bool)), SLOT(findCurrentText())); + } else { + m_checkWholeWords = 0; + } + + m_labelWrapped = new QLabel(this); + m_labelWrapped->setTextFormat(Qt::RichText); + m_labelWrapped->setAlignment( + Qt::AlignLeading | Qt::AlignLeft | Qt::AlignVCenter); + m_labelWrapped->setText( + tr("<img src=\":/trolltech/shared/images/wrap.png\">" + " Search wrapped")); + m_labelWrapped->hide(); + layOut->addWidget(m_labelWrapped); + + QSpacerItem *spacerItem = + new QSpacerItem(1, 1, QSizePolicy::Expanding, QSizePolicy::Minimum); + layOut->addItem(spacerItem); + + setMinimumWidth(minimumSizeHint().width()); + + updateButtons(); + hide(); +} + +/*! + Destroys the AbstractFindWidget. + */ +AbstractFindWidget::~AbstractFindWidget() +{ +} + +/*! + Returns the icon set to be used for the action that initiates a search. + */ +QIcon AbstractFindWidget::findIconSet() +{ + return createIconSet(QLatin1String("searchfind.png")); +} + +/*! + Activates the find widget, making it visible and having focus on its input + field. + */ +void AbstractFindWidget::activate() +{ + show(); + m_editFind->selectAll(); + m_editFind->setFocus(Qt::ShortcutFocusReason); +} + +/*! + Deactivates the find widget, making it invisible and handing focus to any + associated QTextEdit. + */ +void AbstractFindWidget::deactivate() +{ + hide(); +} + +void AbstractFindWidget::findNext() +{ + findInternal(m_editFind->text(), true, false); +} + +void AbstractFindWidget::findPrevious() +{ + findInternal(m_editFind->text(), true, true); +} + +void AbstractFindWidget::findCurrentText() +{ + findInternal(m_editFind->text(), false, false); +} + +void AbstractFindWidget::keyPressEvent(QKeyEvent *event) +{ + if (event->key() == Qt::Key_Escape) { + deactivate(); + return; + } + + QWidget::keyPressEvent(event); +} + +void AbstractFindWidget::updateButtons() +{ + const bool en = !m_editFind->text().isEmpty(); + m_toolPrevious->setEnabled(en); + m_toolNext->setEnabled(en); +} + +void AbstractFindWidget::findInternal(const QString &ttf, bool skipCurrent, bool backward) +{ + bool found = false; + bool wrapped = false; + find(ttf, skipCurrent, backward, &found, &wrapped); + QPalette p; + p.setColor(QPalette::Active, QPalette::Base, found ? Qt::white : QColor(255, 102, 102)); + m_editFind->setPalette(p); + m_labelWrapped->setVisible(wrapped); +} + +bool AbstractFindWidget::caseSensitive() const +{ + return m_checkCase && m_checkCase->isChecked(); +} + +bool AbstractFindWidget::wholeWords() const +{ + return m_checkWholeWords && m_checkWholeWords->isChecked(); +} + +bool AbstractFindWidget::eventFilter(QObject *object, QEvent *e) +{ + if (isVisible() && e->type() == QEvent::KeyPress) { + QKeyEvent *ke = static_cast<QKeyEvent*>(e); + if (ke->key() == Qt::Key_Escape) { + hide(); + return true; + } + } + + return QWidget::eventFilter(object, e); +} + +QT_END_NAMESPACE diff --git a/tools/shared/findwidget/abstractfindwidget.h b/tools/shared/findwidget/abstractfindwidget.h new file mode 100644 index 0000000..fe0c932 --- /dev/null +++ b/tools/shared/findwidget/abstractfindwidget.h @@ -0,0 +1,115 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the tools applications of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef ABSTRACTFINDWIDGET_H +#define ABSTRACTFINDWIDGET_H + +#include <QtGui/QIcon> +#include <QtGui/QWidget> + +QT_BEGIN_NAMESPACE + +class QCheckBox; +class QEvent; +class QKeyEvent; +class QLabel; +class QLineEdit; +class QObject; +class QToolButton; + +class AbstractFindWidget : public QWidget +{ + Q_OBJECT + +public: + enum FindFlag { + /// Use a layout that is roughly half as wide and twice as high as the regular one. + NarrowLayout = 1, + /// Do not show the "Whole words" checkbox. + NoWholeWords = 2, + /// Do not show the "Case sensitive" checkbox. + NoCaseSensitive = 4 + }; + Q_DECLARE_FLAGS(FindFlags, FindFlag) + + AbstractFindWidget(FindFlags flags = FindFlags(), QWidget *parent = 0); + virtual ~AbstractFindWidget(); + + bool eventFilter(QObject *object, QEvent *e); + + static QIcon findIconSet(); + +public slots: + void activate(); + virtual void deactivate(); + void findNext(); + void findPrevious(); + void findCurrentText(); + +protected: + void keyPressEvent(QKeyEvent *event); + +private slots: + void updateButtons(); + +protected: + virtual void find(const QString &textToFind, bool skipCurrent, bool backward, bool *found, bool *wrapped) = 0; + + bool caseSensitive() const; + bool wholeWords() const; + +private: + void findInternal(const QString &textToFind, bool skipCurrent, bool backward); + + QLineEdit *m_editFind; + QLabel *m_labelWrapped; + QToolButton *m_toolNext; + QToolButton *m_toolClose; + QToolButton *m_toolPrevious; + QCheckBox *m_checkCase; + QCheckBox *m_checkWholeWords; +}; + +Q_DECLARE_OPERATORS_FOR_FLAGS(AbstractFindWidget::FindFlags) + +QT_END_NAMESPACE + +#endif // ABSTRACTFINDWIDGET_H diff --git a/tools/shared/findwidget/findwidget.pri b/tools/shared/findwidget/findwidget.pri new file mode 100644 index 0000000..6e0f58a --- /dev/null +++ b/tools/shared/findwidget/findwidget.pri @@ -0,0 +1,4 @@ +INCLUDEPATH += $$PWD +HEADERS += $$PWD/abstractfindwidget.h $$PWD/texteditfindwidget.h $$PWD/itemviewfindwidget.h +SOURCES += $$PWD/abstractfindwidget.cpp $$PWD/texteditfindwidget.cpp $$PWD/itemviewfindwidget.cpp +RESOURCES += $$PWD/findwidget.qrc diff --git a/tools/shared/findwidget/findwidget.qrc b/tools/shared/findwidget/findwidget.qrc new file mode 100644 index 0000000..1d45b25 --- /dev/null +++ b/tools/shared/findwidget/findwidget.qrc @@ -0,0 +1,14 @@ +<RCC> + <qresource prefix="/trolltech/shared"> + <file>images/mac/closetab.png</file> + <file>images/mac/next.png</file> + <file>images/mac/previous.png</file> + <file>images/mac/searchfind.png</file> + <file>images/win/closetab.png</file> + <file>images/win/next.png</file> + <file>images/win/previous.png</file> + <file>images/win/searchfind.png</file> + <file>images/wrap.png</file> + </qresource> +</RCC> + diff --git a/tools/shared/findwidget/images/mac/closetab.png b/tools/shared/findwidget/images/mac/closetab.png Binary files differnew file mode 100644 index 0000000..ab9d669 --- /dev/null +++ b/tools/shared/findwidget/images/mac/closetab.png diff --git a/tools/shared/findwidget/images/mac/next.png b/tools/shared/findwidget/images/mac/next.png Binary files differnew file mode 100644 index 0000000..a585cab --- /dev/null +++ b/tools/shared/findwidget/images/mac/next.png diff --git a/tools/shared/findwidget/images/mac/previous.png b/tools/shared/findwidget/images/mac/previous.png Binary files differnew file mode 100644 index 0000000..612fb34 --- /dev/null +++ b/tools/shared/findwidget/images/mac/previous.png diff --git a/tools/shared/findwidget/images/mac/searchfind.png b/tools/shared/findwidget/images/mac/searchfind.png Binary files differnew file mode 100644 index 0000000..3561745 --- /dev/null +++ b/tools/shared/findwidget/images/mac/searchfind.png diff --git a/tools/shared/findwidget/images/win/closetab.png b/tools/shared/findwidget/images/win/closetab.png Binary files differnew file mode 100644 index 0000000..ef9e020 --- /dev/null +++ b/tools/shared/findwidget/images/win/closetab.png diff --git a/tools/shared/findwidget/images/win/next.png b/tools/shared/findwidget/images/win/next.png Binary files differnew file mode 100644 index 0000000..8df4127 --- /dev/null +++ b/tools/shared/findwidget/images/win/next.png diff --git a/tools/shared/findwidget/images/win/previous.png b/tools/shared/findwidget/images/win/previous.png Binary files differnew file mode 100644 index 0000000..0780bc2 --- /dev/null +++ b/tools/shared/findwidget/images/win/previous.png diff --git a/tools/shared/findwidget/images/win/searchfind.png b/tools/shared/findwidget/images/win/searchfind.png Binary files differnew file mode 100644 index 0000000..6ea35e9 --- /dev/null +++ b/tools/shared/findwidget/images/win/searchfind.png diff --git a/tools/shared/findwidget/images/wrap.png b/tools/shared/findwidget/images/wrap.png Binary files differnew file mode 100644 index 0000000..90f18d9 --- /dev/null +++ b/tools/shared/findwidget/images/wrap.png diff --git a/tools/shared/findwidget/itemviewfindwidget.cpp b/tools/shared/findwidget/itemviewfindwidget.cpp new file mode 100644 index 0000000..e1f8468 --- /dev/null +++ b/tools/shared/findwidget/itemviewfindwidget.cpp @@ -0,0 +1,317 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the tools applications of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/*! \class ItemViewFindWidget + + \brief A search bar that is commonly added below the searchable item view. + + \internal + + This widget implements a search bar which becomes visible when the user + wants to start searching. It is a modern replacement for the commonly used + search dialog. It is usually placed below a QAbstractItemView using a QVBoxLayout. + + The QAbstractItemView instance will need to be associated with this class using + setItemView(). + + The search is incremental and can be set to case sensitive or whole words + using buttons available on the search bar. + + The item traversal order should fit QTreeView, QTableView and QListView alike. + More complex tree structures will work as well, assuming the branch structure + is painted left to the items, without crossing lines. + + \sa QAbstractItemView + */ + +#include "itemviewfindwidget.h" + +#include <QtGui/QAbstractItemView> +#include <QtGui/QCheckBox> +#include <QtGui/QTreeView> + +QT_BEGIN_NAMESPACE + +/*! + Constructs a ItemViewFindWidget. + + \a flags is passed to the AbstractFindWidget constructor. + \a parent is passed to the QWidget constructor. + */ +ItemViewFindWidget::ItemViewFindWidget(FindFlags flags, QWidget *parent) + : AbstractFindWidget(flags, parent) + , m_itemView(0) +{ +} + +/*! + Associates a QAbstractItemView with this find widget. Searches done using this find + widget will then apply to the given QAbstractItemView. + + An event filter is set on the QAbstractItemView which intercepts the ESC key while + the find widget is active, and uses it to deactivate the find widget. + + If the find widget is already associated with a QAbstractItemView, the event filter + is removed from this QAbstractItemView first. + + \a itemView may be NULL. + */ +void ItemViewFindWidget::setItemView(QAbstractItemView *itemView) +{ + if (m_itemView) + m_itemView->removeEventFilter(this); + + m_itemView = itemView; + + if (m_itemView) + m_itemView->installEventFilter(this); +} + +/*! + \reimp + */ +void ItemViewFindWidget::deactivate() +{ + if (m_itemView) + m_itemView->setFocus(); + + AbstractFindWidget::deactivate(); +} + +// Sorting is needed to find the start/end of the selection. +// This is utter black magic. And it is damn slow. +static bool indexLessThan(const QModelIndex &a, const QModelIndex &b) +{ + // First determine the nesting of each index in the tree. + QModelIndex aa = a; + int aDepth = 0; + while (aa.parent() != QModelIndex()) { + // As a side effect, check if one of the items is the parent of the other. + // Children are always displayed below their parents, so sort them further down. + if (aa.parent() == b) + return true; + aa = aa.parent(); + aDepth++; + } + QModelIndex ba = b; + int bDepth = 0; + while (ba.parent() != QModelIndex()) { + if (ba.parent() == a) + return false; + ba = ba.parent(); + bDepth++; + } + // Now find indices at comparable depth. + for (aa = a; aDepth > bDepth; aDepth--) + aa = aa.parent(); + for (ba = b; aDepth < bDepth; bDepth--) + ba = ba.parent(); + // If they have the same parent, sort them within a top-to-bottom, left-to-right rectangle. + if (aa.parent() == ba.parent()) { + if (aa.row() < ba.row()) + return true; + if (aa.row() > ba.row()) + return false; + return aa.column() < ba.column(); + } + // Now try to find indices that have the same grandparent. This ends latest at the root node. + while (aa.parent().parent() != ba.parent().parent()) { + aa = aa.parent(); + ba = ba.parent(); + } + // A bigger row is always displayed further down. + if (aa.parent().row() < ba.parent().row()) + return true; + if (aa.parent().row() > ba.parent().row()) + return false; + // Here's the trick: a child spawned from a bigger column is displayed further *up*. + // That's because the tree lines are on the left and are supposed not to cross each other. + // This case is mostly academical, as "all" models spawn children from the first column. + return aa.parent().column() > ba.parent().column(); +} + +/*! + \reimp + */ +void ItemViewFindWidget::find(const QString &ttf, bool skipCurrent, bool backward, bool *found, bool *wrapped) +{ + if (!m_itemView || !m_itemView->model()->hasChildren()) + return; + + QModelIndex idx; + if (skipCurrent && m_itemView->selectionModel()->hasSelection()) { + QModelIndexList il = m_itemView->selectionModel()->selectedIndexes(); + qSort(il.begin(), il.end(), indexLessThan); + idx = backward ? il.first() : il.last(); + } else { + idx = m_itemView->currentIndex(); + } + + *found = true; + QModelIndex newIdx = idx; + + if (!ttf.isEmpty()) { + if (newIdx.isValid()) { + int column = newIdx.column(); + if (skipCurrent) + if (QTreeView *tv = qobject_cast<QTreeView *>(m_itemView)) + if (tv->allColumnsShowFocus()) + column = backward ? 0 : m_itemView->model()->columnCount(newIdx.parent()) - 1; + newIdx = findHelper(ttf, skipCurrent, backward, + newIdx.parent(), newIdx.row(), column); + } + if (!newIdx.isValid()) { + int row = backward ? m_itemView->model()->rowCount() : 0; + int column = backward ? 0 : -1; + newIdx = findHelper(ttf, true, backward, m_itemView->rootIndex(), row, column); + if (!newIdx.isValid()) { + *found = false; + newIdx = idx; + } else { + *wrapped = true; + } + } + } + + if (!isVisible()) + show(); + + m_itemView->setCurrentIndex(newIdx); +} + +// You are not expected to understand the following two functions. +// The traversal order is described in the indexLessThan() comments above. + +static inline bool skipForward(const QAbstractItemModel *model, QModelIndex &parent, int &row, int &column) +{ + forever { + column++; + if (column < model->columnCount(parent)) + return true; + forever { + while (--column >= 0) { + QModelIndex nIdx = model->index(row, column, parent); + if (nIdx.isValid()) { + if (model->hasChildren(nIdx)) { + row = 0; + column = 0; + parent = nIdx; + return true; + } + } + } + if (++row < model->rowCount(parent)) + break; + if (!parent.isValid()) + return false; + row = parent.row(); + column = parent.column(); + parent = parent.parent(); + } + } +} + +static inline bool skipBackward(const QAbstractItemModel *model, QModelIndex &parent, int &row, int &column) +{ + column--; + if (column == -1) { + if (--row < 0) { + if (!parent.isValid()) + return false; + row = parent.row(); + column = parent.column(); + parent = parent.parent(); + } + while (++column < model->columnCount(parent)) { + QModelIndex nIdx = model->index(row, column, parent); + if (nIdx.isValid()) { + if (model->hasChildren(nIdx)) { + row = model->rowCount(nIdx) - 1; + column = -1; + parent = nIdx; + } + } + } + column--; + } + return true; +} + +// QAbstractItemModel::match() does not support backwards searching. Still using it would +// be just a bit inefficient (not much worse than when no match is found). +// The bigger problem is that QAbstractItemView does not provide a method to sort a +// set of indices in traversal order (to find the start and end of the selection). +// Consequently, we do everything by ourselves to be consistent. Of course, this puts +// constraints on the allowable visualizations. +QModelIndex ItemViewFindWidget::findHelper(const QString &textToFind, bool skipCurrent, bool backward, + QModelIndex parent, int row, int column) +{ + const QAbstractItemModel *model = m_itemView->model(); + forever { + if (skipCurrent) { + if (backward) { + if (!skipBackward(model, parent, row, column)) + return QModelIndex(); + } else { + if (!skipForward(model, parent, row, column)) + return QModelIndex(); + } + } + + QModelIndex idx = model->index(row, column, parent); + if (idx.isValid()) { + Qt::CaseSensitivity cs = caseSensitive() ? Qt::CaseSensitive : Qt::CaseInsensitive; + + if (wholeWords()) { + QString rx = QLatin1String("\\b") + QRegExp::escape(textToFind) + QLatin1String("\\b"); + if (idx.data().toString().indexOf(QRegExp(rx, cs)) >= 0) + return idx; + } else { + if (idx.data().toString().indexOf(textToFind, 0, cs) >= 0) + return idx; + } + } + + skipCurrent = true; + } +} + +QT_END_NAMESPACE diff --git a/tools/shared/findwidget/itemviewfindwidget.h b/tools/shared/findwidget/itemviewfindwidget.h new file mode 100644 index 0000000..71bb8f6 --- /dev/null +++ b/tools/shared/findwidget/itemviewfindwidget.h @@ -0,0 +1,78 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the tools applications of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef ITEMVIEWFINDWIDGET_H +#define ITEMVIEWFINDWIDGET_H + +#include "abstractfindwidget.h" + +#include <QModelIndex> + +QT_BEGIN_NAMESPACE + +class QAbstractItemView; + +class ItemViewFindWidget : public AbstractFindWidget +{ + Q_OBJECT + +public: + ItemViewFindWidget(FindFlags flags = FindFlags(), QWidget *parent = 0); + + QAbstractItemView *itemView() const + { return m_itemView; } + + void setItemView(QAbstractItemView *itemView); + +protected: + virtual void deactivate(); + virtual void find(const QString &textToFind, bool skipCurrent, bool backward, bool *found, bool *wrapped); + +private: + QModelIndex findHelper(const QString &textToFind, bool skipCurrent, bool backward, + QModelIndex parent, int row, int column); + + QAbstractItemView *m_itemView; +}; + +QT_END_NAMESPACE + +#endif // ITEMVIEWFINDWIDGET_H diff --git a/tools/shared/findwidget/texteditfindwidget.cpp b/tools/shared/findwidget/texteditfindwidget.cpp new file mode 100644 index 0000000..73100f5 --- /dev/null +++ b/tools/shared/findwidget/texteditfindwidget.cpp @@ -0,0 +1,169 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the tools applications of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/*! \class TextEditFindWidget + + \brief A search bar that is commonly added below the searchable text. + + \internal + + This widget implements a search bar which becomes visible when the user + wants to start searching. It is a modern replacement for the commonly used + search dialog. It is usually placed below a QTextEdit using a QVBoxLayout. + + The QTextEdit instance will need to be associated with this class using + setTextEdit(). + + The search is incremental and can be set to case sensitive or whole words + using buttons available on the search bar. + + \sa QTextEdit + */ + +#include "texteditfindwidget.h" + +#include <QtGui/QCheckBox> +#include <QtGui/QTextCursor> +#include <QtGui/QTextEdit> + +QT_BEGIN_NAMESPACE + +/*! + Constructs a TextEditFindWidget. + + \a flags is passed to the AbstractFindWidget constructor. + \a parent is passed to the QWidget constructor. + */ +TextEditFindWidget::TextEditFindWidget(FindFlags flags, QWidget *parent) + : AbstractFindWidget(flags, parent) + , m_textEdit(0) +{ +} + +/*! + Associates a QTextEdit with this find widget. Searches done using this find + widget will then apply to the given QTextEdit. + + An event filter is set on the QTextEdit which intercepts the ESC key while + the find widget is active, and uses it to deactivate the find widget. + + If the find widget is already associated with a QTextEdit, the event filter + is removed from this QTextEdit first. + + \a textEdit may be NULL. + */ +void TextEditFindWidget::setTextEdit(QTextEdit *textEdit) +{ + if (m_textEdit) + m_textEdit->removeEventFilter(this); + + m_textEdit = textEdit; + + if (m_textEdit) + m_textEdit->installEventFilter(this); +} + +/*! + \reimp + */ +void TextEditFindWidget::deactivate() +{ + // Pass focus to the text edit + if (m_textEdit) + m_textEdit->setFocus(); + + AbstractFindWidget::deactivate(); +} + +/*! + \reimp + */ +void TextEditFindWidget::find(const QString &ttf, bool skipCurrent, bool backward, bool *found, bool *wrapped) +{ + if (!m_textEdit) + return; + + QTextCursor cursor = m_textEdit->textCursor(); + QTextDocument *doc = m_textEdit->document(); + + if (!doc || cursor.isNull()) + return; + + if (cursor.hasSelection()) + cursor.setPosition((skipCurrent && !backward) ? cursor.position() : cursor.anchor()); + + *found = true; + QTextCursor newCursor = cursor; + + if (!ttf.isEmpty()) { + QTextDocument::FindFlags options; + + if (backward) + options |= QTextDocument::FindBackward; + + if (caseSensitive()) + options |= QTextDocument::FindCaseSensitively; + + if (wholeWords()) + options |= QTextDocument::FindWholeWords; + + newCursor = doc->find(ttf, cursor, options); + if (newCursor.isNull()) { + QTextCursor ac(doc); + ac.movePosition(options & QTextDocument::FindBackward + ? QTextCursor::End : QTextCursor::Start); + newCursor = doc->find(ttf, ac, options); + if (newCursor.isNull()) { + *found = false; + newCursor = cursor; + } else { + *wrapped = true; + } + } + } + + if (!isVisible()) + show(); + + m_textEdit->setTextCursor(newCursor); +} + +QT_END_NAMESPACE diff --git a/tools/shared/findwidget/texteditfindwidget.h b/tools/shared/findwidget/texteditfindwidget.h new file mode 100644 index 0000000..4074ff0 --- /dev/null +++ b/tools/shared/findwidget/texteditfindwidget.h @@ -0,0 +1,73 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the tools applications of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef TEXTEDITFINDWIDGET_H +#define TEXTEDITFINDWIDGET_H + +#include "abstractfindwidget.h" + +QT_BEGIN_NAMESPACE + +class QTextEdit; + +class TextEditFindWidget : public AbstractFindWidget +{ + Q_OBJECT + +public: + TextEditFindWidget(FindFlags flags = FindFlags(), QWidget *parent = 0); + + QTextEdit *textEdit() const + { return m_textEdit; } + + void setTextEdit(QTextEdit *textEdit); + +protected: + virtual void deactivate(); + virtual void find(const QString &textToFind, bool skipCurrent, bool backward, bool *found, bool *wrapped); + +private: + QTextEdit *m_textEdit; +}; + +QT_END_NAMESPACE + +#endif // TEXTEDITFINDWIDGET_H diff --git a/tools/shared/fontpanel/fontpanel.cpp b/tools/shared/fontpanel/fontpanel.cpp new file mode 100644 index 0000000..4545baa --- /dev/null +++ b/tools/shared/fontpanel/fontpanel.cpp @@ -0,0 +1,304 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the tools applications of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "fontpanel.h" + +#include <QtGui/QLabel> +#include <QtGui/QComboBox> +#include <QtGui/QFormLayout> +#include <QtGui/QSpacerItem> +#include <QtGui/QFontComboBox> +#include <QtCore/QTimer> +#include <QtGui/QLineEdit> + +QT_BEGIN_NAMESPACE + +FontPanel::FontPanel(QWidget *parentWidget) : + QGroupBox(parentWidget), + m_previewLineEdit(new QLineEdit), + m_writingSystemComboBox(new QComboBox), + m_familyComboBox(new QFontComboBox), + m_styleComboBox(new QComboBox), + m_pointSizeComboBox(new QComboBox), + m_previewFontUpdateTimer(0) +{ + setTitle(tr("Font")); + + QFormLayout *formLayout = new QFormLayout(this); + // writing systems + m_writingSystemComboBox->setEditable(false); + + QList<QFontDatabase::WritingSystem> writingSystems = m_fontDatabase.writingSystems(); + writingSystems.push_front(QFontDatabase::Any); + foreach (QFontDatabase::WritingSystem ws, writingSystems) + m_writingSystemComboBox->addItem(QFontDatabase::writingSystemName(ws), QVariant(ws)); + connect(m_writingSystemComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(slotWritingSystemChanged(int))); + formLayout->addRow(tr("&Writing system"), m_writingSystemComboBox); + + connect(m_familyComboBox, SIGNAL( currentFontChanged(QFont)), this, SLOT(slotFamilyChanged(QFont))); + formLayout->addRow(tr("&Family"), m_familyComboBox); + + m_styleComboBox->setEditable(false); + connect(m_styleComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(slotStyleChanged(int))); + formLayout->addRow(tr("&Style"), m_styleComboBox); + + m_pointSizeComboBox->setEditable(false); + connect(m_pointSizeComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(slotPointSizeChanged(int))); + formLayout->addRow(tr("&Point size"), m_pointSizeComboBox); + + m_previewLineEdit->setReadOnly(true); + formLayout->addRow(m_previewLineEdit); + + setWritingSystem(QFontDatabase::Any); +} + +QFont FontPanel::selectedFont() const +{ + QFont rc = m_familyComboBox->currentFont(); + const QString family = rc.family(); + rc.setPointSize(pointSize()); + const QString styleDescription = styleString(); + rc.setItalic(m_fontDatabase.italic(family, styleDescription)); + + rc.setBold(m_fontDatabase.bold(family, styleDescription)); + + // Weight < 0 asserts... + const int weight = m_fontDatabase.weight(family, styleDescription); + if (weight >= 0) + rc.setWeight(weight); + return rc; +} + +void FontPanel::setSelectedFont(const QFont &f) +{ + m_familyComboBox->setCurrentFont(f); + if (m_familyComboBox->currentIndex() < 0) { + // family not in writing system - find the corresponding one? + QList<QFontDatabase::WritingSystem> familyWritingSystems = m_fontDatabase.writingSystems(f.family()); + if (familyWritingSystems.empty()) + return; + + setWritingSystem(familyWritingSystems.front()); + m_familyComboBox->setCurrentFont(f); + } + + updateFamily(family()); + + const int pointSizeIndex = closestPointSizeIndex(f.pointSize()); + m_pointSizeComboBox->setCurrentIndex( pointSizeIndex); + + const QString styleString = m_fontDatabase.styleString(f); + const int styleIndex = m_styleComboBox->findText(styleString); + m_styleComboBox->setCurrentIndex(styleIndex); + slotUpdatePreviewFont(); +} + + +QFontDatabase::WritingSystem FontPanel::writingSystem() const +{ + const int currentIndex = m_writingSystemComboBox->currentIndex(); + if ( currentIndex == -1) + return QFontDatabase::Latin; + return static_cast<QFontDatabase::WritingSystem>(m_writingSystemComboBox->itemData(currentIndex).toInt()); +} + +QString FontPanel::family() const +{ + const int currentIndex = m_familyComboBox->currentIndex(); + return currentIndex != -1 ? m_familyComboBox->currentFont().family() : QString(); +} + +int FontPanel::pointSize() const +{ + const int currentIndex = m_pointSizeComboBox->currentIndex(); + return currentIndex != -1 ? m_pointSizeComboBox->itemData(currentIndex).toInt() : 9; +} + +QString FontPanel::styleString() const +{ + const int currentIndex = m_styleComboBox->currentIndex(); + return currentIndex != -1 ? m_styleComboBox->itemText(currentIndex) : QString(); +} + +void FontPanel::setWritingSystem(QFontDatabase::WritingSystem ws) +{ + m_writingSystemComboBox->setCurrentIndex(m_writingSystemComboBox->findData(QVariant(ws))); + updateWritingSystem(ws); +} + + +void FontPanel::slotWritingSystemChanged(int) +{ + updateWritingSystem(writingSystem()); + delayedPreviewFontUpdate(); +} + +void FontPanel::slotFamilyChanged(const QFont &) +{ + updateFamily(family()); + delayedPreviewFontUpdate(); +} + +void FontPanel::slotStyleChanged(int) +{ + updatePointSizes(family(), styleString()); + delayedPreviewFontUpdate(); +} + +void FontPanel::slotPointSizeChanged(int) +{ + delayedPreviewFontUpdate(); +} + +void FontPanel::updateWritingSystem(QFontDatabase::WritingSystem ws) +{ + + m_previewLineEdit->setText(QFontDatabase::writingSystemSample(ws)); + m_familyComboBox->setWritingSystem (ws); + // Current font not in WS ... set index 0. + if (m_familyComboBox->currentIndex() < 0) { + m_familyComboBox->setCurrentIndex(0); + updateFamily(family()); + } +} + +void FontPanel::updateFamily(const QString &family) +{ + // Update styles and trigger update of point sizes. + // Try to maintain selection or select normal + const QString oldStyleString = styleString(); + + const QStringList styles = m_fontDatabase.styles(family); + const bool hasStyles = !styles.empty(); + + m_styleComboBox->setCurrentIndex(-1); + m_styleComboBox->clear(); + m_styleComboBox->setEnabled(hasStyles); + + int normalIndex = -1; + const QString normalStyle = QLatin1String("Normal"); + + if (hasStyles) { + foreach (QString style, styles) { + // try to maintain selection or select 'normal' preferably + const int newIndex = m_styleComboBox->count(); + m_styleComboBox->addItem(style); + if (oldStyleString == style) { + m_styleComboBox->setCurrentIndex(newIndex); + } else { + if (oldStyleString == normalStyle) + normalIndex = newIndex; + } + } + if (m_styleComboBox->currentIndex() == -1 && normalIndex != -1) + m_styleComboBox->setCurrentIndex(normalIndex); + } + updatePointSizes(family, styleString()); +} + +int FontPanel::closestPointSizeIndex(int desiredPointSize) const +{ + // try to maintain selection or select closest. + int closestIndex = -1; + int closestAbsError = 0xFFFF; + + const int pointSizeCount = m_pointSizeComboBox->count(); + for (int i = 0; i < pointSizeCount; i++) { + const int itemPointSize = m_pointSizeComboBox->itemData(i).toInt(); + const int absError = qAbs(desiredPointSize - itemPointSize); + if (absError < closestAbsError) { + closestIndex = i; + closestAbsError = absError; + if (closestAbsError == 0) + break; + } else { // past optimum + if (absError > closestAbsError) { + break; + } + } + } + return closestIndex; +} + + +void FontPanel::updatePointSizes(const QString &family, const QString &styleString) +{ + const int oldPointSize = pointSize(); + + QList<int> pointSizes = m_fontDatabase.pointSizes(family, styleString); + if (pointSizes.empty()) + pointSizes = QFontDatabase::standardSizes(); + + const bool hasSizes = !pointSizes.empty(); + m_pointSizeComboBox->clear(); + m_pointSizeComboBox->setEnabled(hasSizes); + m_pointSizeComboBox->setCurrentIndex(-1); + + // try to maintain selection or select closest. + if (hasSizes) { + QString n; + foreach (int pointSize, pointSizes) + m_pointSizeComboBox->addItem(n.setNum(pointSize), QVariant(pointSize)); + const int closestIndex = closestPointSizeIndex(oldPointSize); + if (closestIndex != -1) + m_pointSizeComboBox->setCurrentIndex(closestIndex); + } +} + +void FontPanel::slotUpdatePreviewFont() +{ + m_previewLineEdit->setFont(selectedFont()); +} + +void FontPanel::delayedPreviewFontUpdate() +{ + if (!m_previewFontUpdateTimer) { + m_previewFontUpdateTimer = new QTimer(this); + connect(m_previewFontUpdateTimer, SIGNAL(timeout()), this, SLOT(slotUpdatePreviewFont())); + m_previewFontUpdateTimer->setInterval(0); + m_previewFontUpdateTimer->setSingleShot(true); + } + if (m_previewFontUpdateTimer->isActive()) + return; + m_previewFontUpdateTimer->start(); +} + +QT_END_NAMESPACE diff --git a/tools/shared/fontpanel/fontpanel.h b/tools/shared/fontpanel/fontpanel.h new file mode 100644 index 0000000..0f542c6 --- /dev/null +++ b/tools/shared/fontpanel/fontpanel.h @@ -0,0 +1,108 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the tools applications of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of the Qt tools. This header +// file may change from version to version without notice, or even be removed. +// +// We mean it. +// + +#ifndef FONTPANEL_H +#define FONTPANEL_H + +#include <QtGui/QGroupBox> +#include <QtGui/QFont> +#include <QtGui/QFontDatabase> + +QT_BEGIN_NAMESPACE + +class QComboBox; +class QFontComboBox; +class QTimer; +class QLineEdit; + +class FontPanel: public QGroupBox +{ + Q_OBJECT +public: + FontPanel(QWidget *parentWidget = 0); + + QFont selectedFont() const; + void setSelectedFont(const QFont &); + + QFontDatabase::WritingSystem writingSystem() const; + void setWritingSystem(QFontDatabase::WritingSystem ws); + +private slots: + void slotWritingSystemChanged(int); + void slotFamilyChanged(const QFont &); + void slotStyleChanged(int); + void slotPointSizeChanged(int); + void slotUpdatePreviewFont(); + +private: + QString family() const; + QString styleString() const; + int pointSize() const; + int closestPointSizeIndex(int ps) const; + + void updateWritingSystem(QFontDatabase::WritingSystem ws); + void updateFamily(const QString &family); + void updatePointSizes(const QString &family, const QString &style); + void delayedPreviewFontUpdate(); + + QFontDatabase m_fontDatabase; + QLineEdit *m_previewLineEdit; + QComboBox *m_writingSystemComboBox; + QFontComboBox* m_familyComboBox; + QComboBox *m_styleComboBox; + QComboBox *m_pointSizeComboBox; + QTimer *m_previewFontUpdateTimer; +}; + +QT_END_NAMESPACE + +#endif // FONTPANEL_H diff --git a/tools/shared/fontpanel/fontpanel.pri b/tools/shared/fontpanel/fontpanel.pri new file mode 100644 index 0000000..9504853 --- /dev/null +++ b/tools/shared/fontpanel/fontpanel.pri @@ -0,0 +1,3 @@ +INCLUDEPATH += $$PWD +HEADERS += $$PWD/fontpanel.h +SOURCES += $$PWD/fontpanel.cpp diff --git a/tools/shared/qtgradienteditor/images/down.png b/tools/shared/qtgradienteditor/images/down.png Binary files differnew file mode 100644 index 0000000..29d1d44 --- /dev/null +++ b/tools/shared/qtgradienteditor/images/down.png diff --git a/tools/shared/qtgradienteditor/images/edit.png b/tools/shared/qtgradienteditor/images/edit.png Binary files differnew file mode 100644 index 0000000..4231bd9 --- /dev/null +++ b/tools/shared/qtgradienteditor/images/edit.png diff --git a/tools/shared/qtgradienteditor/images/editdelete.png b/tools/shared/qtgradienteditor/images/editdelete.png Binary files differnew file mode 100644 index 0000000..df2a147 --- /dev/null +++ b/tools/shared/qtgradienteditor/images/editdelete.png diff --git a/tools/shared/qtgradienteditor/images/minus.png b/tools/shared/qtgradienteditor/images/minus.png Binary files differnew file mode 100644 index 0000000..d6f233d --- /dev/null +++ b/tools/shared/qtgradienteditor/images/minus.png diff --git a/tools/shared/qtgradienteditor/images/plus.png b/tools/shared/qtgradienteditor/images/plus.png Binary files differnew file mode 100644 index 0000000..40df113 --- /dev/null +++ b/tools/shared/qtgradienteditor/images/plus.png diff --git a/tools/shared/qtgradienteditor/images/spreadpad.png b/tools/shared/qtgradienteditor/images/spreadpad.png Binary files differnew file mode 100644 index 0000000..104c0a2 --- /dev/null +++ b/tools/shared/qtgradienteditor/images/spreadpad.png diff --git a/tools/shared/qtgradienteditor/images/spreadreflect.png b/tools/shared/qtgradienteditor/images/spreadreflect.png Binary files differnew file mode 100644 index 0000000..17b82b7 --- /dev/null +++ b/tools/shared/qtgradienteditor/images/spreadreflect.png diff --git a/tools/shared/qtgradienteditor/images/spreadrepeat.png b/tools/shared/qtgradienteditor/images/spreadrepeat.png Binary files differnew file mode 100644 index 0000000..7aea898 --- /dev/null +++ b/tools/shared/qtgradienteditor/images/spreadrepeat.png diff --git a/tools/shared/qtgradienteditor/images/typeconical.png b/tools/shared/qtgradienteditor/images/typeconical.png Binary files differnew file mode 100644 index 0000000..5479811 --- /dev/null +++ b/tools/shared/qtgradienteditor/images/typeconical.png diff --git a/tools/shared/qtgradienteditor/images/typelinear.png b/tools/shared/qtgradienteditor/images/typelinear.png Binary files differnew file mode 100644 index 0000000..dbd8a1f --- /dev/null +++ b/tools/shared/qtgradienteditor/images/typelinear.png diff --git a/tools/shared/qtgradienteditor/images/typeradial.png b/tools/shared/qtgradienteditor/images/typeradial.png Binary files differnew file mode 100644 index 0000000..dc5888d --- /dev/null +++ b/tools/shared/qtgradienteditor/images/typeradial.png diff --git a/tools/shared/qtgradienteditor/images/up.png b/tools/shared/qtgradienteditor/images/up.png Binary files differnew file mode 100644 index 0000000..e437312 --- /dev/null +++ b/tools/shared/qtgradienteditor/images/up.png diff --git a/tools/shared/qtgradienteditor/images/zoomin.png b/tools/shared/qtgradienteditor/images/zoomin.png Binary files differnew file mode 100644 index 0000000..2e586fc --- /dev/null +++ b/tools/shared/qtgradienteditor/images/zoomin.png diff --git a/tools/shared/qtgradienteditor/images/zoomout.png b/tools/shared/qtgradienteditor/images/zoomout.png Binary files differnew file mode 100644 index 0000000..a736d39 --- /dev/null +++ b/tools/shared/qtgradienteditor/images/zoomout.png diff --git a/tools/shared/qtgradienteditor/qtcolorbutton.cpp b/tools/shared/qtgradienteditor/qtcolorbutton.cpp new file mode 100644 index 0000000..6926f60 --- /dev/null +++ b/tools/shared/qtgradienteditor/qtcolorbutton.cpp @@ -0,0 +1,278 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the tools applications of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qtcolorbutton.h" +#include <QtGui/QColorDialog> +#include <QtGui/QPainter> +#include <QtCore/QMimeData> +#include <QtGui/QDragEnterEvent> +#include <QtGui/QApplication> + +QT_BEGIN_NAMESPACE + +class QtColorButtonPrivate +{ + QtColorButton *q_ptr; + Q_DECLARE_PUBLIC(QtColorButton) +public: + QColor m_color; +#ifndef QT_NO_DRAGANDDROP + QColor m_dragColor; + QPoint m_dragStart; + bool m_dragging; +#endif + bool m_backgroundCheckered; + + void slotEditColor(); + QColor shownColor() const; + QPixmap generatePixmap() const; +}; + +void QtColorButtonPrivate::slotEditColor() +{ + bool ok; + const QRgb rgba = QColorDialog::getRgba(m_color.rgba(), &ok, q_ptr); + if (!ok) + return; + const QColor c = QColor::fromRgba(rgba); + if (c == q_ptr->color()) + return; + q_ptr->setColor(c); + emit q_ptr->colorChanged(m_color); +} + +QColor QtColorButtonPrivate::shownColor() const +{ +#ifndef QT_NO_DRAGANDDROP + if (m_dragging) + return m_dragColor; +#endif + return m_color; +} + +QPixmap QtColorButtonPrivate::generatePixmap() const +{ + QPixmap pix(24, 24); + + int pixSize = 20; + QBrush br(shownColor()); + + QPixmap pm(2 * pixSize, 2 * pixSize); + QPainter pmp(&pm); + pmp.fillRect(0, 0, pixSize, pixSize, Qt::lightGray); + pmp.fillRect(pixSize, pixSize, pixSize, pixSize, Qt::lightGray); + pmp.fillRect(0, pixSize, pixSize, pixSize, Qt::darkGray); + pmp.fillRect(pixSize, 0, pixSize, pixSize, Qt::darkGray); + pmp.fillRect(0, 0, 2 * pixSize, 2 * pixSize, shownColor()); + br = QBrush(pm); + + QPainter p(&pix); + int corr = 1; + QRect r = pix.rect().adjusted(corr, corr, -corr, -corr); + p.setBrushOrigin((r.width() % pixSize + pixSize) / 2 + corr, (r.height() % pixSize + pixSize) / 2 + corr); + p.fillRect(r, br); + + p.fillRect(r.width() / 4 + corr, r.height() / 4 + corr, + r.width() / 2, r.height() / 2, + QColor(shownColor().rgb())); + p.drawRect(pix.rect().adjusted(0, 0, -1, -1)); + + return pix; +} + +/////////////// + +QtColorButton::QtColorButton(QWidget *parent) + : QToolButton(parent) +{ + d_ptr = new QtColorButtonPrivate; + d_ptr->q_ptr = this; + d_ptr->m_dragging = false; + d_ptr->m_backgroundCheckered = true; + + setAcceptDrops(true); + + connect(this, SIGNAL(clicked()), this, SLOT(slotEditColor())); + setSizePolicy(QSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred)); +} + +QtColorButton::~QtColorButton() +{ + delete d_ptr; +} + +void QtColorButton::setColor(const QColor &color) +{ + if (d_ptr->m_color == color) + return; + d_ptr->m_color = color; + update(); +} + +QColor QtColorButton::color() const +{ + return d_ptr->m_color; +} + +void QtColorButton::setBackgroundCheckered(bool checkered) +{ + if (d_ptr->m_backgroundCheckered == checkered) + return; + d_ptr->m_backgroundCheckered = checkered; + update(); +} + +bool QtColorButton::isBackgroundCheckered() const +{ + return d_ptr->m_backgroundCheckered; +} + +void QtColorButton::paintEvent(QPaintEvent *event) +{ + QToolButton::paintEvent(event); + if (!isEnabled()) + return; + + const int pixSize = 10; + QBrush br(d_ptr->shownColor()); + if (d_ptr->m_backgroundCheckered) { + QPixmap pm(2 * pixSize, 2 * pixSize); + QPainter pmp(&pm); + pmp.fillRect(0, 0, pixSize, pixSize, Qt::white); + pmp.fillRect(pixSize, pixSize, pixSize, pixSize, Qt::white); + pmp.fillRect(0, pixSize, pixSize, pixSize, Qt::black); + pmp.fillRect(pixSize, 0, pixSize, pixSize, Qt::black); + pmp.fillRect(0, 0, 2 * pixSize, 2 * pixSize, d_ptr->shownColor()); + br = QBrush(pm); + } + + QPainter p(this); + const int corr = 4; + QRect r = rect().adjusted(corr, corr, -corr, -corr); + p.setBrushOrigin((r.width() % pixSize + pixSize) / 2 + corr, (r.height() % pixSize + pixSize) / 2 + corr); + p.fillRect(r, br); + + //const int adjX = qRound(r.width() / 4.0); + //const int adjY = qRound(r.height() / 4.0); + //p.fillRect(r.adjusted(adjX, adjY, -adjX, -adjY), + // QColor(d_ptr->shownColor().rgb())); + /* + p.fillRect(r.adjusted(0, r.height() * 3 / 4, 0, 0), + QColor(d_ptr->shownColor().rgb())); + p.fillRect(r.adjusted(0, 0, 0, -r.height() * 3 / 4), + QColor(d_ptr->shownColor().rgb())); + */ + /* + const QColor frameColor0(0, 0, 0, qRound(0.2 * (0xFF - d_ptr->shownColor().alpha()))); + p.setPen(frameColor0); + p.drawRect(r.adjusted(adjX, adjY, -adjX - 1, -adjY - 1)); + */ + + const QColor frameColor1(0, 0, 0, 26); + p.setPen(frameColor1); + p.drawRect(r.adjusted(1, 1, -2, -2)); + const QColor frameColor2(0, 0, 0, 51); + p.setPen(frameColor2); + p.drawRect(r.adjusted(0, 0, -1, -1)); +} + +void QtColorButton::mousePressEvent(QMouseEvent *event) +{ +#ifndef QT_NO_DRAGANDDROP + if (event->button() == Qt::LeftButton) + d_ptr->m_dragStart = event->pos(); +#endif + QToolButton::mousePressEvent(event); +} + +void QtColorButton::mouseMoveEvent(QMouseEvent *event) +{ +#ifndef QT_NO_DRAGANDDROP + if (event->buttons() & Qt::LeftButton && + (d_ptr->m_dragStart - event->pos()).manhattanLength() > QApplication::startDragDistance()) { + QMimeData *mime = new QMimeData; + mime->setColorData(color()); + QDrag *drg = new QDrag(this); + drg->setMimeData(mime); + drg->setPixmap(d_ptr->generatePixmap()); + setDown(false); + event->accept(); + drg->start(); + return; + } +#endif + QToolButton::mouseMoveEvent(event); +} + +#ifndef QT_NO_DRAGANDDROP +void QtColorButton::dragEnterEvent(QDragEnterEvent *event) +{ + const QMimeData *mime = event->mimeData(); + if (!mime->hasColor()) + return; + + event->accept(); + d_ptr->m_dragColor = qvariant_cast<QColor>(mime->colorData()); + d_ptr->m_dragging = true; + update(); +} + +void QtColorButton::dragLeaveEvent(QDragLeaveEvent *event) +{ + event->accept(); + d_ptr->m_dragging = false; + update(); +} + +void QtColorButton::dropEvent(QDropEvent *event) +{ + event->accept(); + d_ptr->m_dragging = false; + if (d_ptr->m_dragColor == color()) + return; + setColor(d_ptr->m_dragColor); + emit colorChanged(color()); +} +#endif + +QT_END_NAMESPACE + +#include "moc_qtcolorbutton.cpp" diff --git a/tools/shared/qtgradienteditor/qtcolorbutton.h b/tools/shared/qtgradienteditor/qtcolorbutton.h new file mode 100644 index 0000000..fb91452 --- /dev/null +++ b/tools/shared/qtgradienteditor/qtcolorbutton.h @@ -0,0 +1,86 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the tools applications of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QTCOLORBUTTON_H +#define QTCOLORBUTTON_H + +#include <QtGui/QToolButton> + +QT_BEGIN_NAMESPACE + +class QtColorButton : public QToolButton +{ + Q_OBJECT + Q_PROPERTY(bool backgroundCheckered READ isBackgroundCheckered WRITE setBackgroundCheckered) +public: + QtColorButton(QWidget *parent = 0); + ~QtColorButton(); + + bool isBackgroundCheckered() const; + void setBackgroundCheckered(bool checkered); + + QColor color() const; + +public slots: + + void setColor(const QColor &color); + +signals: + void colorChanged(const QColor &color); +protected: + void paintEvent(QPaintEvent *event); + void mousePressEvent(QMouseEvent *event); + void mouseMoveEvent(QMouseEvent *event); +#ifndef QT_NO_DRAGANDDROP + void dragEnterEvent(QDragEnterEvent *event); + void dragLeaveEvent(QDragLeaveEvent *event); + void dropEvent(QDropEvent *event); +#endif +private: + class QtColorButtonPrivate *d_ptr; + Q_DECLARE_PRIVATE(QtColorButton) + Q_DISABLE_COPY(QtColorButton) + Q_PRIVATE_SLOT(d_func(), void slotEditColor()) +}; + +QT_END_NAMESPACE + +#endif diff --git a/tools/shared/qtgradienteditor/qtcolorbutton.pri b/tools/shared/qtgradienteditor/qtcolorbutton.pri new file mode 100644 index 0000000..0e41068 --- /dev/null +++ b/tools/shared/qtgradienteditor/qtcolorbutton.pri @@ -0,0 +1,4 @@ +INCLUDEPATH += $$PWD +DEPENDPATH += $$PWD +SOURCES += $$PWD/qtcolorbutton.cpp +HEADERS += $$PWD/qtcolorbutton.h diff --git a/tools/shared/qtgradienteditor/qtcolorline.cpp b/tools/shared/qtgradienteditor/qtcolorline.cpp new file mode 100644 index 0000000..337726c --- /dev/null +++ b/tools/shared/qtgradienteditor/qtcolorline.cpp @@ -0,0 +1,1124 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the tools applications of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qtcolorline.h" +#include "qdrawutil.h" + +#include <QtGui/QPainter> +#include <QtGui/QPaintEvent> +#include <QtGui/QStyleOption> + +QT_BEGIN_NAMESPACE + +class QtColorLinePrivate +{ + QtColorLine *q_ptr; + Q_DECLARE_PUBLIC(QtColorLine) +public: + QtColorLinePrivate(); + + QColor color() const; + void setColor(const QColor &color); + + QtColorLine::ColorComponent colorComponent() const; + void setColorComponent(QtColorLine::ColorComponent component); + + void setIndicatorSize(int size); + int indicatorSize() const; + + void setIndicatorSpace(int space); + int indicatorSpace() const; + + void setFlip(bool flip); + bool flip() const; + + void setBackgroundCheckered(bool checkered); + bool isBackgroundCheckered() const; + + void setOrientation(Qt::Orientation orientation); + Qt::Orientation orientation() const; + + void resizeEvent(QResizeEvent *event); + void paintEvent(QPaintEvent *event); + void mousePressEvent(QMouseEvent *event); + void mouseMoveEvent(QMouseEvent *event); + void mouseReleaseEvent(QMouseEvent *event); + void mouseDoubleClickEvent(QMouseEvent *event); +private: + void checkColor(); + bool isMainPixmapValid() const; + void validate(); + void recreateMainPixmap(); + QSize pixmapSizeFromGeometrySize(const QSize &geometrySize) const; + QPixmap gradientPixmap(int size, Qt::Orientation orientation, const QColor &begin, const QColor &end, bool flipped = false) const; + QPixmap gradientPixmap(Qt::Orientation orientation, const QColor &begin, const QColor &end, bool flipped = false) const; + QPixmap hueGradientPixmap(int size, Qt::Orientation orientation, bool flipped = false, + int saturation = 0xFF, int value = 0xFF, int alpha = 0xFF) const; + QPixmap hueGradientPixmap(Qt::Orientation orientation, bool flipped = false, + int saturation = 0xFF, int value = 0xFF, int alpha = 0xFF) const; + + QVector<QRect> rects(const QPointF &point) const; + + QColor colorFromPoint(const QPointF &point) const; + QPointF pointFromColor(const QColor &color) const; + + QColor m_color; + QtColorLine::ColorComponent m_component; + bool m_flipped; + bool m_backgroundCheckered; + Qt::Orientation m_orientation; + bool m_dragging; + bool m_combiningAlpha; + int m_indicatorSize; + int m_indicatorSpace; + QPointF m_point; + QPoint m_clickOffset; + + QPixmap m_mainPixmap; + QPixmap m_alphalessPixmap; + QPixmap m_semiAlphaPixmap; + QSize m_pixmapSize; + + struct PixData { + QSize size; + QColor color; + QtColorLine::ColorComponent component; + bool flipped; + Qt::Orientation orientation; + }; + + PixData m_lastValidMainPixmapData; +}; + +QtColorLinePrivate::QtColorLinePrivate() + : m_color(Qt::black), m_component(QtColorLine::Value), + m_flipped(false), m_backgroundCheckered(true), m_orientation(Qt::Horizontal), m_dragging(false), m_combiningAlpha(false) +{ + m_indicatorSize = 22; + m_indicatorSpace = 0; + m_pixmapSize = QSize(0, 0); + m_point = pointFromColor(m_color); +} + +void QtColorLinePrivate::setColor(const QColor &color) +{ + if (m_color == color) + return; + if (!color.isValid()) + return; + if (m_dragging) // Warning perhaps here, recursive call + return; + m_color = color; + checkColor(); + QColor c = colorFromPoint(m_point); + m_point = pointFromColor(m_color); + q_ptr->update(); +} + +QColor QtColorLinePrivate::color() const +{ + return m_color; +} + +void QtColorLinePrivate::setColorComponent(QtColorLine::ColorComponent component) +{ + if (m_component == component) + return; + if (m_dragging) // Warning perhaps here, recursive call + return; + m_component = component; + checkColor(); + m_point = pointFromColor(m_color); + q_ptr->update(); +} + +QtColorLine::ColorComponent QtColorLinePrivate::colorComponent() const +{ + return m_component; +} + +void QtColorLinePrivate::setIndicatorSize(int size) +{ + if (size <= 0) + return; + if (m_dragging) // Warning perhaps here, recursive call + return; + if (m_indicatorSize == size) + return; + m_indicatorSize = size; + m_pixmapSize = pixmapSizeFromGeometrySize(q_ptr->contentsRect().size()); + q_ptr->update(); + q_ptr->updateGeometry(); +} + +int QtColorLinePrivate::indicatorSize() const +{ + return m_indicatorSize; +} + +void QtColorLinePrivate::setIndicatorSpace(int space) +{ + if (space < 0) + return; + if (m_dragging) // Warning perhaps here, recursive call + return; + if (m_indicatorSpace == space) + return; + m_indicatorSpace = space; + m_pixmapSize = pixmapSizeFromGeometrySize(q_ptr->contentsRect().size()); + q_ptr->update(); +} + +int QtColorLinePrivate::indicatorSpace() const +{ + return m_indicatorSpace; +} + +void QtColorLinePrivate::setFlip(bool flip) +{ + if (m_dragging) // Warning perhaps here, recursive call + return; + if (m_flipped == flip) + return; + m_flipped = flip; + m_point = pointFromColor(m_color); + q_ptr->update(); +} + +bool QtColorLinePrivate::flip() const +{ + return m_flipped; +} + +void QtColorLinePrivate::setBackgroundCheckered(bool checkered) +{ + if (m_backgroundCheckered == checkered) + return; + m_backgroundCheckered = checkered; + q_ptr->update(); +} + +bool QtColorLinePrivate::isBackgroundCheckered() const +{ + return m_backgroundCheckered; +} + +void QtColorLinePrivate::setOrientation(Qt::Orientation orientation) +{ + if (m_dragging) // Warning perhaps here, recursive call + return; + if (m_orientation == orientation) + return; + + m_orientation = orientation; + if (!q_ptr->testAttribute(Qt::WA_WState_OwnSizePolicy)) { + QSizePolicy sp = q_ptr->sizePolicy(); + sp.transpose(); + q_ptr->setSizePolicy(sp); + q_ptr->setAttribute(Qt::WA_WState_OwnSizePolicy, false); + } + m_point = pointFromColor(m_color); + q_ptr->update(); + q_ptr->updateGeometry(); +} + +Qt::Orientation QtColorLinePrivate::orientation() const +{ + return m_orientation; +} + +void QtColorLinePrivate::checkColor() +{ + switch (m_component) { + case QtColorLine::Red: + case QtColorLine::Green: + case QtColorLine::Blue: + if (m_color.spec() != QColor::Rgb) + m_color = m_color.toRgb(); + break; + case QtColorLine::Hue: + case QtColorLine::Saturation: + case QtColorLine::Value: + if (m_color.spec() != QColor::Hsv) + m_color = m_color.toHsv(); + break; + default: + break; + } + if (m_color.spec() == QColor::Hsv) { + if (m_color.hue() == 360 || m_color.hue() == -1) { + m_color.setHsvF(0.0, m_color.saturationF(), m_color.valueF(), m_color.alphaF()); + } + } +} + +bool QtColorLinePrivate::isMainPixmapValid() const +{ + if (m_mainPixmap.isNull()) { + if (m_pixmapSize.isEmpty()) + return true; + else + return false; + } + if (m_lastValidMainPixmapData.component != m_component) + return false; + if (m_lastValidMainPixmapData.size != m_pixmapSize) + return false; + if (m_lastValidMainPixmapData.flipped != m_flipped) + return false; + if (m_lastValidMainPixmapData.orientation != m_orientation) + return false; + if (m_lastValidMainPixmapData.color == m_color) + return true; + switch (m_component) { + case QtColorLine::Red: + if (m_color.green() == m_lastValidMainPixmapData.color.green() && + m_color.blue() == m_lastValidMainPixmapData.color.blue() && + (!m_combiningAlpha || m_color.alpha() == m_lastValidMainPixmapData.color.alpha())) + return true; + break; + case QtColorLine::Green: + if (m_color.red() == m_lastValidMainPixmapData.color.red() && + m_color.blue() == m_lastValidMainPixmapData.color.blue() && + (!m_combiningAlpha || m_color.alpha() == m_lastValidMainPixmapData.color.alpha())) + return true; + break; + case QtColorLine::Blue: + if (m_color.red() == m_lastValidMainPixmapData.color.red() && + m_color.green() == m_lastValidMainPixmapData.color.green() && + (!m_combiningAlpha || m_color.alpha() == m_lastValidMainPixmapData.color.alpha())) + return true; + break; + case QtColorLine::Hue: + if (m_color.saturation() == m_lastValidMainPixmapData.color.saturation() && + m_color.value() == m_lastValidMainPixmapData.color.value() && + (!m_combiningAlpha || m_color.alpha() == m_lastValidMainPixmapData.color.alpha())) + return true; + break; + case QtColorLine::Saturation: + if (m_color.hue() == m_lastValidMainPixmapData.color.hue() && + m_color.value() == m_lastValidMainPixmapData.color.value() && + (!m_combiningAlpha || m_color.alpha() == m_lastValidMainPixmapData.color.alpha())) + return true; + break; + case QtColorLine::Value: + if (m_color.hue() == m_lastValidMainPixmapData.color.hue() && + m_color.saturation() == m_lastValidMainPixmapData.color.saturation() && + (!m_combiningAlpha || m_color.alpha() == m_lastValidMainPixmapData.color.alpha())) + return true; + break; + case QtColorLine::Alpha: + if (m_color.hue() == m_lastValidMainPixmapData.color.hue() && + m_color.saturation() == m_lastValidMainPixmapData.color.saturation() && + m_color.value() == m_lastValidMainPixmapData.color.value()) + return true; + } + return false; +} + +void QtColorLinePrivate::validate() +{ + if (isMainPixmapValid()) + return; + + recreateMainPixmap(); +} + +QPixmap QtColorLinePrivate::gradientPixmap(Qt::Orientation orientation, const QColor &begin, const QColor &end, bool flipped) const +{ + int size = m_pixmapSize.width(); + if (orientation == Qt::Vertical) + size = m_pixmapSize.height(); + return gradientPixmap(size, orientation, begin, end, flipped); +} + +QPixmap QtColorLinePrivate::gradientPixmap(int size, Qt::Orientation orientation, + const QColor &begin, const QColor &end, bool flipped) const +{ + int gradW = size; + int gradH = size; + int w = size; + int h = size; + if (orientation == Qt::Horizontal) { + gradH = 0; + h = 1; + } else { + gradW = 0; + w = 1; + } + QColor c1 = begin; + QColor c2 = end; + if (flipped) { + c1 = end; + c2 = begin; + } + QLinearGradient lg(0, 0, gradW, gradH); + lg.setColorAt(0, c1); + lg.setColorAt(1, c2); + QImage img(w, h, QImage::Format_ARGB32); + QPainter p(&img); + p.setCompositionMode(QPainter::CompositionMode_Source); + p.fillRect(QRect(0, 0, w, h), lg); + return QPixmap::fromImage(img); +} + +QPixmap QtColorLinePrivate::hueGradientPixmap(Qt::Orientation orientation, bool flipped, + int saturation, int value, int alpha) const +{ + int size = m_pixmapSize.width(); + if (orientation == Qt::Vertical) + size = m_pixmapSize.height(); + return hueGradientPixmap(size, orientation, flipped, saturation, value, alpha); +} + +QPixmap QtColorLinePrivate::hueGradientPixmap(int size, Qt::Orientation orientation, bool flipped, + int saturation, int value, int alpha) const +{ + int gradW = size + 1; + int gradH = size + 1; + int w = size; + int h = size; + if (orientation == Qt::Horizontal) { + gradH = 0; + h = 1; + } else { + gradW = 0; + w = 1; + } + QList<QColor> colorList; + colorList << QColor::fromHsv(0, saturation, value, alpha); + colorList << QColor::fromHsv(60, saturation, value, alpha); + colorList << QColor::fromHsv(120, saturation, value, alpha); + colorList << QColor::fromHsv(180, saturation, value, alpha); + colorList << QColor::fromHsv(240, saturation, value, alpha); + colorList << QColor::fromHsv(300, saturation, value, alpha); + colorList << QColor::fromHsv(0, saturation, value, alpha); + QLinearGradient lg(0, 0, gradW, gradH); + for (int i = 0; i <= 6; i++) + lg.setColorAt((double)i / 6.0, flipped ? colorList.at(6 - i) : colorList.at(i)); + QImage img(w, h, QImage::Format_ARGB32); + QPainter p(&img); + p.setCompositionMode(QPainter::CompositionMode_Source); + p.fillRect(QRect(0, 0, w, h), lg); + return QPixmap::fromImage(img); +} + +void QtColorLinePrivate::recreateMainPixmap() +{ + m_lastValidMainPixmapData.size = m_pixmapSize; + m_lastValidMainPixmapData.component = m_component; + m_lastValidMainPixmapData.color = m_color; + m_lastValidMainPixmapData.flipped = m_flipped; + m_lastValidMainPixmapData.orientation = m_orientation; + + if (m_pixmapSize.isEmpty()) { + m_mainPixmap = QPixmap(); + m_alphalessPixmap = QPixmap(); + m_semiAlphaPixmap = QPixmap(); + return; + } + + if (m_mainPixmap.size() != m_pixmapSize) { + m_mainPixmap = QPixmap(m_pixmapSize); + m_alphalessPixmap = QPixmap(m_pixmapSize); + m_semiAlphaPixmap = QPixmap(m_pixmapSize); + } + + Qt::Orientation orient = m_orientation; + const bool flip = m_flipped; + + const int r = m_color.red(); + const int g = m_color.green(); + const int b = m_color.blue(); + const int h = m_color.hue(); + const int s = m_color.saturation(); + const int v = m_color.value(); + const int a = m_color.alpha(); + const double coef = 0.5; + const int semi = qRound(a * coef + 0xFF * (1.0 - coef)); + + if (m_component == QtColorLine::Hue) { + m_alphalessPixmap = hueGradientPixmap(orient, flip, s, v, 0xFF); + if (m_combiningAlpha) { + m_mainPixmap = hueGradientPixmap(orient, flip, s, v, a); + m_semiAlphaPixmap = hueGradientPixmap(orient, flip, s, v, semi); + } + } else if (m_component == QtColorLine::Saturation) { + m_alphalessPixmap = gradientPixmap(orient, QColor::fromHsv(h, 0, v, 0xFF), QColor::fromHsv(h, 0xFF, v, 0xFF), flip); + if (m_combiningAlpha) { + m_mainPixmap = gradientPixmap(orient, QColor::fromHsv(h, 0, v, a), QColor::fromHsv(h, 0xFF, v, a), flip); + m_semiAlphaPixmap = gradientPixmap(orient, QColor::fromHsv(h, 0, v, semi), QColor::fromHsv(h, 0xFF, v, semi), flip); + } + } else if (m_component == QtColorLine::Value) { + m_alphalessPixmap = gradientPixmap(orient, QColor::fromRgb(0, 0, 0, 0xFF), QColor::fromHsv(h, s, 0xFF, 0xFF), flip); + if (m_combiningAlpha) { + m_mainPixmap = gradientPixmap(orient, QColor::fromRgb(0, 0, 0, a), QColor::fromHsv(h, s, 0xFF, a), flip); + m_semiAlphaPixmap = gradientPixmap(orient, QColor::fromRgb(0, 0, 0, semi), QColor::fromHsv(h, s, 0xFF, semi), flip); + } + } else if (m_component == QtColorLine::Red) { + m_alphalessPixmap = gradientPixmap(orient, QColor::fromRgb(0, g, b, 0xFF), QColor::fromRgb(0xFF, g, b, 0xFF), flip); + if (m_combiningAlpha) { + m_mainPixmap = gradientPixmap(orient, QColor::fromRgb(0, g, b, a), QColor::fromRgb(0xFF, g, b, a), flip); + m_semiAlphaPixmap = gradientPixmap(orient, QColor::fromRgb(0, g, b, semi), QColor::fromRgb(0xFF, g, b, semi), flip); + } + } else if (m_component == QtColorLine::Green) { + m_alphalessPixmap = gradientPixmap(orient, QColor::fromRgb(r, 0, b, 0xFF), QColor::fromRgb(r, 0xFF, b, 0xFF), flip); + if (m_combiningAlpha) { + m_mainPixmap = gradientPixmap(orient, QColor::fromRgb(r, 0, b, a), QColor::fromRgb(r, 0xFF, b, a), flip); + m_semiAlphaPixmap = gradientPixmap(orient, QColor::fromRgb(r, 0, b, semi), QColor::fromRgb(r, 0xFF, b, semi), flip); + } + } else if (m_component == QtColorLine::Blue) { + m_alphalessPixmap = gradientPixmap(orient, QColor::fromRgb(r, g, 0, 0xFF), QColor::fromRgb(r, g, 0xFF, 0xFF), flip); + if (m_combiningAlpha) { + m_mainPixmap = gradientPixmap(orient, QColor::fromRgb(r, g, 0, a), QColor::fromRgb(r, g, 0xFF, a), flip); + m_semiAlphaPixmap = gradientPixmap(orient, QColor::fromRgb(r, g, 0, semi), QColor::fromRgb(r, g, 0xFF, semi), flip); + } + } else if (m_component == QtColorLine::Alpha) { + m_mainPixmap = gradientPixmap(orient, QColor::fromRgb(r, g, b, 0), QColor::fromRgb(r, g, b, 0xFF), flip); + +// m_alphalessPixmap = gradientPixmap(orient, QColor::fromRgb(r, g, b, 0xFF), QColor::fromRgb(r, g, b, 0xFF), flip); +// m_semiAlphaPixmap = gradientPixmap(orient, QColor::fromRgb(r, g, b, semi), QColor::fromRgb(r, g, b, semi), flip); + } + if (!m_combiningAlpha && m_component != QtColorLine::Alpha) + m_mainPixmap = m_alphalessPixmap; +} + +QSize QtColorLinePrivate::pixmapSizeFromGeometrySize( + const QSize &geometrySize) const +{ + QSize size(m_indicatorSize + 2 * m_indicatorSpace - 1, + m_indicatorSize + 2 * m_indicatorSpace - 1); + if (m_orientation == Qt::Horizontal) + size.setHeight(0); + else + size.setWidth(0); + return geometrySize - size; +} + +QColor QtColorLinePrivate::colorFromPoint(const QPointF &point) const +{ + QPointF p = point; + if (p.x() < 0) + p.setX(0.0); + else if (p.x() > 1) + p.setX(1.0); + if (p.y() < 0) + p.setY(0.0); + else if (p.y() > 1) + p.setY(1.0); + + double pos = p.x(); + if (m_orientation == Qt::Vertical) + pos = p.y(); + if (m_flipped) + pos = 1.0 - pos; + QColor c; + qreal hue; + switch (m_component) { + case QtColorLine::Red: + c.setRgbF(pos, m_color.greenF(), m_color.blueF(), m_color.alphaF()); + break; + case QtColorLine::Green: + c.setRgbF(m_color.redF(), pos, m_color.blueF(), m_color.alphaF()); + break; + case QtColorLine::Blue: + c.setRgbF(m_color.redF(), m_color.greenF(), pos, m_color.alphaF()); + break; + case QtColorLine::Hue: + hue = pos; + hue *= 35999.0 / 36000.0; + c.setHsvF(hue, m_color.saturationF(), m_color.valueF(), m_color.alphaF()); + break; + case QtColorLine::Saturation: + c.setHsvF(m_color.hueF(), pos, m_color.valueF(), m_color.alphaF()); + break; + case QtColorLine::Value: + c.setHsvF(m_color.hueF(), m_color.saturationF(), pos, m_color.alphaF()); + break; + case QtColorLine::Alpha: + c.setHsvF(m_color.hueF(), m_color.saturationF(), m_color.valueF(), pos); + break; + } + return c; +} + +QPointF QtColorLinePrivate::pointFromColor(const QColor &color) const +{ + qreal hue = color.hueF(); + if (color.hue() == 360) + hue = 0.0; + else + hue *= 36000.0 / 35999.0; + + double pos = 0.0; + switch (m_component) { + case QtColorLine::Red: + pos = color.redF(); + break; + case QtColorLine::Green: + pos = color.greenF(); + break; + case QtColorLine::Blue: + pos = color.blueF(); + break; + case QtColorLine::Hue: + pos = hue; + break; + case QtColorLine::Saturation: + pos = color.saturationF(); + break; + case QtColorLine::Value: + pos = color.valueF(); + break; + case QtColorLine::Alpha: + pos = color.alphaF(); + break; + } + if (m_flipped) + pos = 1.0 - pos; + QPointF p(pos, pos); + if (m_orientation == Qt::Horizontal) + p.setY(0); + else + p.setX(0); + return p; +} + +QVector<QRect> QtColorLinePrivate::rects(const QPointF &point) const +{ + QRect r = q_ptr->geometry(); + r.moveTo(0, 0); + + int x1 = (int)((r.width() - m_indicatorSize - 2 * m_indicatorSpace) * point.x() + 0.5); + int x2 = x1 + m_indicatorSize + 2 * m_indicatorSpace; + int y1 = (int)((r.height() - m_indicatorSize - 2 * m_indicatorSpace) * point.y() + 0.5); + int y2 = y1 + m_indicatorSize + 2 * m_indicatorSpace; + + QVector<QRect> rects; + if (m_orientation == Qt::Horizontal) { + // r0 r1 r2 + QRect r0(0, 0, x1, r.height()); + QRect r1(x1 + m_indicatorSpace, 0, m_indicatorSize, r.height()); + QRect r2(x2, 0, r.width() - x2, r.height()); + + rects << r0 << r1 << r2; + } else { + // r0 + // r1 + // r2 + QRect r0(0, 0, r.width(), y1); + QRect r1(0, y1 + m_indicatorSpace, r.width(), m_indicatorSize); + QRect r2(0, y2, r.width(), r.height() - y2); + + rects << r0 << r1 << r2; + } + return rects; +} + +void QtColorLinePrivate::resizeEvent(QResizeEvent *event) +{ + m_pixmapSize = pixmapSizeFromGeometrySize(event->size()); +} + +void QtColorLinePrivate::paintEvent(QPaintEvent *) +{ + QRect rect = q_ptr->rect(); + + QVector<QRect> r = rects(m_point); + + QColor cBack = q_ptr->palette().color(QPalette::Active, QPalette::Window); + QColor c = colorFromPoint(m_point); + if (!m_combiningAlpha && m_component != QtColorLine::Alpha) + c.setAlpha(0xFF); + + QPainter p(q_ptr); + if (q_ptr->isEnabled()) { + if (m_backgroundCheckered) { + int pixSize = 20; + QPixmap pm(2 * pixSize, 2 * pixSize); + QPainter pmp(&pm); + pmp.fillRect(0, 0, pixSize, pixSize, Qt::white); + pmp.fillRect(pixSize, pixSize, pixSize, pixSize, Qt::white); + pmp.fillRect(0, pixSize, pixSize, pixSize, Qt::black); + pmp.fillRect(pixSize, 0, pixSize, pixSize, Qt::black); + pmp.end(); + + p.setBrushOrigin((rect.width() % pixSize + pixSize) / 2, (rect.height() % pixSize + pixSize) / 2); + p.setClipRect(r[1].adjusted(4, 4, -4, -4)); + p.setClipRect(QRect(rect.topLeft(), QPoint(r[1].left() + 0, rect.bottom())), Qt::UniteClip); + p.setClipRect(QRect(QPoint(r[1].right() - 0, rect.top()), rect.bottomRight()), Qt::UniteClip); + p.setClipRect(QRect(rect.topLeft(), QPoint(rect.right(), r[1].top() + 0)), Qt::UniteClip); + p.setClipRect(QRect(QPoint(rect.left(), r[1].bottom() - 0), rect.bottomRight()), Qt::UniteClip); + /* + p.setClipRect(r[1].adjusted(3, 3, -3, -3)); + p.setClipRect(QRect(rect.topLeft(), QPoint(r[1].left() + 1, rect.bottom())), Qt::UniteClip); + p.setClipRect(QRect(QPoint(r[1].right() - 1, rect.top()), rect.bottomRight()), Qt::UniteClip); + p.setClipRect(QRect(rect.topLeft(), QPoint(rect.right(), r[1].top() + 1)), Qt::UniteClip); + p.setClipRect(QRect(QPoint(rect.left(), r[1].bottom() - 1), rect.bottomRight()), Qt::UniteClip); + */ + p.fillRect(rect, pm); + p.setBrushOrigin(0, 0); + p.setClipping(false); + } + + validate(); + + QSize fieldSize = pixmapSizeFromGeometrySize(q_ptr->geometry().size()); + + QPoint posOnField = r[1].topLeft() - QPoint(m_indicatorSpace, m_indicatorSpace); + int x = posOnField.x(); + int y = posOnField.y(); + int w = fieldSize.width(); + int h = fieldSize.height(); + + QRect r0, r2; + if (m_orientation == Qt::Horizontal) { + r0 = QRect(0, 0, x, m_pixmapSize.height()); + r2 = QRect(x + 1, 0, w - x - 1, m_pixmapSize.height()); + } else { + r0 = QRect(0, 0, m_pixmapSize.width(), y); + r2 = QRect(0, y + 1, m_pixmapSize.width(), h - y - 1); + } + + p.setBrush(m_mainPixmap); + p.setPen(Qt::NoPen); + if (r[0].isValid()) { + p.drawRect(r[0]); + } + if (r[2].isValid()) { + p.setBrushOrigin(r[2].topLeft() - r2.topLeft()); + p.drawRect(r[2]); + } + if (m_indicatorSpace) { + p.setBrush(c); + if (m_orientation == Qt::Horizontal) { + p.drawRect(r[1].adjusted(-m_indicatorSpace, 0, -r[1].width(), 0)); + p.drawRect(r[1].adjusted(r[1].width(), 0, m_indicatorSpace, 0)); + } else { + p.drawRect(r[1].adjusted(0, -m_indicatorSpace, 0, -r[1].height())); + p.drawRect(r[1].adjusted(0, r[1].height(), 0, m_indicatorSpace)); + } + } + + QPen pen(c); + p.setPen(pen); + p.setBrush(Qt::NoBrush); + if (r[1].isValid()) { + p.drawRect(r[1].adjusted(0, 0, -1, -1)); + // p.drawRect(r[1].adjusted(1, 1, -2, -2)); + } + double coef = 9.0 / 10; + p.setPen(Qt::NoPen); + if (m_component != QtColorLine::Alpha && m_combiningAlpha) { + p.setBrush(m_alphalessPixmap); + if (r[0].isValid()) { + p.setBrushOrigin(QPoint(0, 0)); + QRect thinRect1 = r[0]; + QRect thinRect2 = r[0]; + QRect thinRect = r[0]; + if (m_orientation == Qt::Horizontal) { + thinRect1.adjust(0, qRound(thinRect1.height() * coef), 0, 0); + thinRect2.adjust(0, 0, 0, -qRound(thinRect2.height() * coef)); + thinRect.adjust(0, qRound(thinRect.height() * coef), 0, -qRound(thinRect.height() * coef)); + } else { + thinRect1.adjust(qRound(thinRect1.width() * coef), 0, 0, 0); + thinRect2.adjust(0, 0, -qRound(thinRect2.width() * coef), 0); + thinRect.adjust(qRound(thinRect.width() * coef), 0, -qRound(thinRect.width() * coef), 0); + } + p.drawRect(thinRect1); + p.drawRect(thinRect2); + //p.drawRect(thinRect); + } + if (r[2].isValid()) { + p.setBrushOrigin(r[2].topLeft() - r2.topLeft()); + QRect thinRect1 = r[2]; + QRect thinRect2 = r[2]; + QRect thinRect = r[2]; + if (m_orientation == Qt::Horizontal) { + thinRect1.adjust(0, qRound(thinRect1.height() * coef), 0, 0); + thinRect2.adjust(0, 0, 0, -qRound(thinRect2.height() * coef)); + thinRect.adjust(0, qRound(thinRect.height() * coef), 0, -qRound(thinRect.height() * coef)); + } else { + thinRect1.adjust(qRound(thinRect1.width() * coef), 0, 0, 0); + thinRect2.adjust(0, 0, -qRound(thinRect2.width() * coef), 0); + thinRect.adjust(qRound(thinRect.width() * coef), 0, -qRound(thinRect.width() * coef), 0); + } + p.drawRect(thinRect1); + p.drawRect(thinRect2); + //p.drawRect(thinRect); + } + /* + +*/ + + + + + + p.setPen(Qt::NoPen); + + p.setBrush(m_semiAlphaPixmap); + if (r[0].isValid()) { + p.setBrushOrigin(QPoint(0, 0)); + QRect thinRect1 = r[0]; + QRect thinRect2 = r[0]; + QRect thinRect = r[0]; + if (m_orientation == Qt::Horizontal) { + thinRect1.adjust(0, qRound(thinRect1.height() * coef) - 1, 0, 0); + thinRect1.setBottom(thinRect1.top()); + thinRect2.adjust(0, 0, 0, -qRound(thinRect2.height() * coef) + 1); + thinRect2.setTop(thinRect2.bottom()); + thinRect.adjust(0, qRound(thinRect.height() * coef), 0, -qRound(thinRect.height() * coef)); + } else { + thinRect1.adjust(qRound(thinRect1.width() * coef) - 1, 0, 0, 0); + thinRect1.setRight(thinRect1.left()); + thinRect2.adjust(0, 0, -qRound(thinRect2.width() * coef) + 1, 0); + thinRect2.setLeft(thinRect2.right()); + thinRect.adjust(qRound(thinRect.width() * coef), 0, -qRound(thinRect.width() * coef), 0); + } + p.drawRect(thinRect1); + p.drawRect(thinRect2); + //p.drawRect(thinRect); + } + if (r[2].isValid()) { + p.setBrushOrigin(r[2].topLeft() - r2.topLeft()); + QRect thinRect1 = r[2]; + QRect thinRect2 = r[2]; + QRect thinRect = r[2]; + if (m_orientation == Qt::Horizontal) { + thinRect1.adjust(0, qRound(thinRect1.height() * coef) - 1, 0, 0); + thinRect1.setBottom(thinRect1.top()); + thinRect2.adjust(0, 0, 0, -qRound(thinRect2.height() * coef) + 1); + thinRect2.setTop(thinRect2.bottom()); + thinRect.adjust(0, qRound(thinRect.height() * coef), 0, -qRound(thinRect.height() * coef)); + } else { + thinRect1.adjust(qRound(thinRect1.width() * coef) - 1, 0, 0, 0); + thinRect1.setRight(thinRect1.left()); + thinRect2.adjust(0, 0, -qRound(thinRect2.width() * coef) + 1, 0); + thinRect2.setLeft(thinRect2.right()); + thinRect.adjust(qRound(thinRect.width() * coef), 0, -qRound(thinRect.width() * coef), 0); + } + p.drawRect(thinRect1); + p.drawRect(thinRect2); + //p.drawRect(thinRect); + } + p.setBrush(m_alphalessPixmap); + if (m_orientation == Qt::Horizontal) { + p.setClipRect(r[1].adjusted(0, qRound(r[1].height() * coef), 0, 0)); + p.setClipRect(r[1].adjusted(0, 0, 0, -qRound(r[1].height() * coef)), Qt::UniteClip); + } else { + p.setClipRect(r[1].adjusted(qRound(r[1].width() * coef), 0, 0, 0)); + p.setClipRect(r[1].adjusted(0, 0, -qRound(r[1].width() * coef), 0), Qt::UniteClip); + } + p.setBrush(Qt::NoBrush); + p.setPen(QPen(QColor(c.rgb()))); + + p.drawRect(r[1].adjusted(0, 0, -1, -1)); + // p.drawRect(r[1].adjusted(1, 1, -2, -2)); +/* + p.setBrush(m_semiAlphaPixmap); + if (m_orientation == Qt::Horizontal) { + QRect top = r[1].adjusted(0, 0, 0, -qRound(r[1].height() * coef) + 1); + top.setTop(top.bottom()); + QRect bottom = r[1].adjusted(0, qRound(r[1].height() * coef) - 1, 0, 0); + top.setBottom(bottom.top()); + p.setClipRect(top); + p.setClipRect(bottom, Qt::UniteClip); + } else { + + } + QColor semiColor(c.rgb()); + semiColor.setAlpha((c.alpha() + 0xFF) / 2); + p.setPen(QPen(semiColor)); + p.drawRect(r[1].adjusted(0, 0, -1, -1)); + // p.drawRect(r[1].adjusted(1, 1, -2, -2)); +*/ + p.setClipping(false); + } + } + + p.setBrush(Qt::NoBrush); + int lw = 4; + //int br = 1; + int br = 0; + r[1].adjust(br, br, -br, -br); + if (r[1].adjusted(lw, lw, -lw, -lw).isValid()) { + QStyleOptionFrame opt; + opt.init(q_ptr); + opt.rect = r[1]; + opt.lineWidth = 2; + opt.midLineWidth = 1; + if (m_dragging) + opt.state |= QStyle::State_Sunken; + else + opt.state |= QStyle::State_Raised; + q_ptr->style()->drawPrimitive(QStyle::PE_Frame, &opt, &p, q_ptr); + QRect colorRect = r[1].adjusted(lw, lw, -lw, -lw); + if (q_ptr->isEnabled()) { + p.fillRect(colorRect, c); + const QColor frameColor(0, 0, 0, 38); + p.setPen(frameColor); + p.drawRect(colorRect.adjusted(0, 0, -1, -1)); + /* + p.fillRect(colorRect.width() / 4 + colorRect.left(), + colorRect.height() / 4 + colorRect.top(), + colorRect.width() / 2, + colorRect.height() / 2, + QColor(c.rgb())); + */ + /* + if (m_component != QtColorLine::Alpha) { + p.fillRect(colorRect.adjusted(0, colorRect.height() * 4 / 5, 0, 0), QColor(c.rgb())); + p.fillRect(colorRect.adjusted(0, 0, 0, -colorRect.height() * 4 / 5), QColor(c.rgb())); + } + */ + } + } +} + +void QtColorLinePrivate::mousePressEvent(QMouseEvent *event) +{ + if (event->button() != Qt::LeftButton) + return; + + QVector<QRect> r = rects(m_point); + QPoint clickPos = event->pos(); + + QSize fieldSize = q_ptr->geometry().size() - + QSize(m_indicatorSize + 2 * m_indicatorSpace - 1, m_indicatorSize + 2 * m_indicatorSpace - 1); + QPoint posOnField = r[1].topLeft() - QPoint(m_indicatorSpace, m_indicatorSpace); + m_clickOffset = posOnField - clickPos; + + if (!r[1].contains(clickPos)) + return; + m_dragging = true; + q_ptr->update(); +} + +void QtColorLinePrivate::mouseMoveEvent(QMouseEvent *event) +{ + if (!m_dragging) + return; + QPoint newPos = event->pos(); + + QSize fieldSize = q_ptr->geometry().size() - + QSize(m_indicatorSize + 2 * m_indicatorSpace - 1, m_indicatorSize + 2 * m_indicatorSpace - 1); + QPoint newPosOnField = newPos + m_clickOffset; + if (newPosOnField.x() < 0) + newPosOnField.setX(0); + else if (newPosOnField.x() > fieldSize.width()) + newPosOnField.setX(fieldSize.width()); + if (newPosOnField.y() < 0) + newPosOnField.setY(0); + else if (newPosOnField.y() > fieldSize.height()) + newPosOnField.setY(fieldSize.height()); + + double x = (double)newPosOnField.x() / fieldSize.width(); + double y = (double)newPosOnField.y() / fieldSize.height(); + m_point = QPointF(x, y); + QColor color = colorFromPoint(m_point); + if (m_color == color) + return; + m_color = color; + emit q_ptr->colorChanged(color); // maybe before internal set, 1 line above + q_ptr->update(); +} + +void QtColorLinePrivate::mouseReleaseEvent(QMouseEvent *event) +{ + if (event->button() != Qt::LeftButton) + return; + m_dragging = false; + q_ptr->update(); +} + +void QtColorLinePrivate::mouseDoubleClickEvent(QMouseEvent *event) +{ + if (event->button() != Qt::LeftButton) + return; + + QVector<QRect> r = rects(m_point); + QPoint clickPos = event->pos(); + if (!r[0].contains(clickPos) && !r[2].contains(clickPos)) + return; + QPoint newPosOnField = clickPos; + if (r[2].contains(clickPos)) + newPosOnField -= QPoint(m_indicatorSize + 2 * m_indicatorSpace - 2, m_indicatorSize + 2 * m_indicatorSpace - 2); + QSize fieldSize = q_ptr->geometry().size() - + QSize(m_indicatorSize + 2 * m_indicatorSpace - 1, m_indicatorSize + 2 * m_indicatorSpace - 1); + + double x = (double)newPosOnField.x() / fieldSize.width(); + double y = (double)newPosOnField.y() / fieldSize.height(); + m_point = QPointF(x, y); + QColor color = colorFromPoint(m_point); + if (m_color == color) + return; + m_color = color; + emit q_ptr->colorChanged(color); // maybe before internal set, 1 line above + q_ptr->update(); +} + +//////////////////////////////////////////////////// + +QtColorLine::QtColorLine(QWidget *parent) + : QWidget(parent) +{ + d_ptr = new QtColorLinePrivate; + d_ptr->q_ptr = this; + + setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed)); +} + +QtColorLine::~QtColorLine() +{ + delete d_ptr; +} + +QSize QtColorLine::minimumSizeHint() const +{ + return QSize(d_ptr->m_indicatorSize, d_ptr->m_indicatorSize); +} + +QSize QtColorLine::sizeHint() const +{ + return QSize(d_ptr->m_indicatorSize, d_ptr->m_indicatorSize); +} + +void QtColorLine::setColor(const QColor &color) +{ + d_ptr->setColor(color); +} + +QColor QtColorLine::color() const +{ + return d_ptr->color(); +} + +void QtColorLine::setColorComponent(QtColorLine::ColorComponent component) +{ + d_ptr->setColorComponent(component); +} + +QtColorLine::ColorComponent QtColorLine::colorComponent() const +{ + return d_ptr->colorComponent(); +} + +void QtColorLine::setIndicatorSize(int size) +{ + d_ptr->setIndicatorSize(size); +} + +int QtColorLine::indicatorSize() const +{ + return d_ptr->indicatorSize(); +} + +void QtColorLine::setIndicatorSpace(int space) +{ + d_ptr->setIndicatorSpace(space); +} + +int QtColorLine::indicatorSpace() const +{ + return d_ptr->indicatorSpace(); +} + +void QtColorLine::setFlip(bool flip) +{ + d_ptr->setFlip(flip); +} + +bool QtColorLine::flip() const +{ + return d_ptr->flip(); +} + +void QtColorLine::setBackgroundCheckered(bool checkered) +{ + d_ptr->setBackgroundCheckered(checkered); +} + +bool QtColorLine::isBackgroundCheckered() const +{ + return d_ptr->isBackgroundCheckered(); +} + +void QtColorLine::setOrientation(Qt::Orientation orientation) +{ + d_ptr->setOrientation(orientation); +} + +Qt::Orientation QtColorLine::orientation() const +{ + return d_ptr->orientation(); +} +void QtColorLine::resizeEvent(QResizeEvent *event) +{ + d_ptr->resizeEvent(event); +} + +void QtColorLine::paintEvent(QPaintEvent *event) +{ + d_ptr->paintEvent(event); +} + +void QtColorLine::mousePressEvent(QMouseEvent *event) +{ + d_ptr->mousePressEvent(event); +} + +void QtColorLine::mouseMoveEvent(QMouseEvent *event) +{ + d_ptr->mouseMoveEvent(event); +} + +void QtColorLine::mouseReleaseEvent(QMouseEvent *event) +{ + d_ptr->mouseReleaseEvent(event); +} + +void QtColorLine::mouseDoubleClickEvent(QMouseEvent *event) +{ + d_ptr->mouseDoubleClickEvent(event); +} + +QT_END_NAMESPACE diff --git a/tools/shared/qtgradienteditor/qtcolorline.h b/tools/shared/qtgradienteditor/qtcolorline.h new file mode 100644 index 0000000..d5535b1 --- /dev/null +++ b/tools/shared/qtgradienteditor/qtcolorline.h @@ -0,0 +1,124 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the tools applications of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QTCOLORLINE_H +#define QTCOLORLINE_H + +#include <QtGui/QWidget> + +QT_BEGIN_NAMESPACE + +class QtColorLine : public QWidget +{ + Q_OBJECT + Q_PROPERTY(QColor color READ color WRITE setColor) + Q_PROPERTY(int indicatorSpace READ indicatorSpace WRITE setIndicatorSpace) + Q_PROPERTY(int indicatorSize READ indicatorSize WRITE setIndicatorSize) + Q_PROPERTY(bool flip READ flip WRITE setFlip) + Q_PROPERTY(bool backgroundCheckered READ isBackgroundCheckered WRITE setBackgroundCheckered) + Q_PROPERTY(ColorComponent colorComponent READ colorComponent WRITE setColorComponent) + Q_PROPERTY(Qt::Orientation orientation READ orientation WRITE setOrientation) + Q_ENUMS(ColorComponent) +public: + + enum ColorComponent { + Red, + Green, + Blue, + Hue, + Saturation, + Value, + Alpha + }; + + QSize minimumSizeHint() const; + QSize sizeHint() const; + + QtColorLine(QWidget *parent = 0); + ~QtColorLine(); + + QColor color() const; + + void setIndicatorSize(int size); + int indicatorSize() const; + + void setIndicatorSpace(int space); + int indicatorSpace() const; + + void setFlip(bool flip); + bool flip() const; + + bool isBackgroundCheckered() const; + void setBackgroundCheckered(bool checkered); + + void setOrientation(Qt::Orientation orientation); + Qt::Orientation orientation() const; + + void setColorComponent(ColorComponent component); + ColorComponent colorComponent() const; + +public slots: + + void setColor(const QColor &color); + +signals: + + void colorChanged(const QColor &color); + +protected: + + void resizeEvent(QResizeEvent *event); + void paintEvent(QPaintEvent *event); + void mousePressEvent(QMouseEvent *event); + void mouseMoveEvent(QMouseEvent *event); + void mouseReleaseEvent(QMouseEvent *event); + void mouseDoubleClickEvent(QMouseEvent *event); + +private: + + class QtColorLinePrivate *d_ptr; + Q_DECLARE_PRIVATE(QtColorLine) + Q_DISABLE_COPY(QtColorLine) +}; + +QT_END_NAMESPACE + +#endif diff --git a/tools/shared/qtgradienteditor/qtgradientdialog.cpp b/tools/shared/qtgradienteditor/qtgradientdialog.cpp new file mode 100644 index 0000000..032cb16 --- /dev/null +++ b/tools/shared/qtgradienteditor/qtgradientdialog.cpp @@ -0,0 +1,359 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the tools applications of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/* +TRANSLATOR qdesigner_internal::QtGradientDialog +*/ + +#include "qtgradientdialog.h" +#include "ui_qtgradientdialog.h" +#include <QtGui/QPushButton> + +QT_BEGIN_NAMESPACE + +class QtGradientDialogPrivate +{ + QtGradientDialog *q_ptr; + Q_DECLARE_PUBLIC(QtGradientDialog) +public: + + void slotAboutToShowDetails(bool details, int extensionWidthHint); + + Ui::QtGradientDialog m_ui; +}; + +void QtGradientDialogPrivate::slotAboutToShowDetails(bool details, int extensionWidthHint) +{ + if (details) { + q_ptr->resize(q_ptr->size() + QSize(extensionWidthHint, 0)); + } else { + q_ptr->setMinimumSize(1, 1); + q_ptr->resize(q_ptr->size() - QSize(extensionWidthHint, 0)); + q_ptr->setMinimumSize(0, 0); + } +} + +/*! + \class QtGradientDialog + + \brief The QtGradientDialog class provides a dialog for specifying gradients. + + The gradient dialog's function is to allow users to edit gradients. + For example, you might use this in a drawing program to allow the user to set the brush gradient. + + \table + \row + \o \inlineimage qtgradientdialog.png + \o \inlineimage qtgradientdialogextension.png + \header + \o Details extension hidden + \o Details extension visible + \endtable + + Starting from the top of the dialog there are several buttons: + + \image qtgradientdialogtopbuttons.png + + The first three buttons allow for changing a type of the gradient (QGradient::Type), while the second three allow for + changing spread of the gradient (QGradient::Spread). The last button shows or hides the details extension of the dialog. + Conceptually the default view with hidden details provides the full functional control over gradient editing. + The additional extension with details allows to set gradient's parameters more precisely. The visibility + of extension can be controlled by detailsVisible property. Moreover, if you don't want the user to + switch on or off the visibility of extension you can set the detailsButtonVisible property to false. + + Below top buttons there is an area where edited gradient is interactively previewed. + In addition the user can edit gradient type's specific parameters directly in this area by dragging + appropriate handles. + + \table + \row + \o \inlineimage qtgradientdialoglineareditor.png + \o \inlineimage qtgradientdialogradialeditor.png + \o \inlineimage qtgradientdialogconicaleditor.png + \header + \o Editing linear type + \o Editing radial type + \o Editing conical type + \row + \o The user can change the start and final point positions by dragging the circular handles. + \o The user can change the center and focal point positions by dragging the circular handles + and can change the gradient's radius by dragging horizontal or vertical line. + \o The user can change the center point by dragging the circular handle + and can change the gradient's angle by dragging the big wheel. + \endtable + + In the middle of the dialog there is an area where the user can edit gradient stops. + + \table + \row + \o \inlineimage qtgradientdialogstops.png + \o \inlineimage qtgradientdialogstopszoomed.png + \endtable + + The top part of this area contains stop handles, and bottom part shows the preview of gradient stops path. + In order to create a new gradient stop double click inside the view over the desired position. + If you double click on existing stop handle in the top part of the view, clicked handle will be duplicated + (duplicate will contain the same color). + The stop can be activated by clicking on its handle. You can activate previous or next stop by pressing + left or right key respectively. To jump to the first or last stop press home or end key respectively. + The gradient stops editor supports multiselection. + Clicking a handle holding the shift modifier key down will select a range of stops between + the active stop and clicked one. Clicking a handle holding control modifier key down will remove from or + add to selection the clicked stop depending if it was or wasn't already selected respectively. + Multiselection can also be created using rubberband (by pressing the left mouse button outside + of any handle and dragging). + Sometimes it's hard to select a stop because its handle can be partially covered by other handle. + In that case the user can zoom in the view by spinning mouse wheel. + The selected stop handles can be moved by drag & drop. In order to remove selected stops press delete key. + For convenience context menu is provided with the following actions: + + \list + \o New Stop - creates a new gradient stop + \o Delete - removes the active and all selected stops + \o Flip All - mirrors all stops + \o Select All - selects all stops + \o Zoom In - zooms in + \o Zoom Out - zooms out + \o Zoom All - goes back to original 100% zoom + \endlist + + The bottom part of the QtGradientDialog contains a set of widgets allowing to control the color of + the active and selected stops. + + \table + \row + \o \inlineimage qtgradientdialogcolorhsv.png + \o \inlineimage qtgradientdialogcolorrgb.png + \endtable + + + The color button shows the color of the active gradient stop. It also allows for choosing + a color from standard color dialog and applying it to the + active stop and all selected stops. It's also possible to drag a color directly from the color button + and to drop it in gradient stops editor at desired position (it will create new stop with dragged color) + or at desired stop handle (it will change the color of that handle). + + To the right of color button there is a set of 2 radio buttons which allows to switch between + HVS and RGB color spec. + + Finally there are 4 color sliders working either in HSVA (hue saturation value alpha) or + RGBA (red green blue alpha) mode, depending on which radio button is chosen. The radio buttons + can be controlled programatically by spec() and setSpec() methods. The sliders show the + color of the active stop. By double clicking inside color slider you can set directly the desired color. + Changes of slider's are applied to stop selection in the way that the color + component being changed is applied to stops in selection only, while other components + remain unchanged in selected stops (e.g. when the user is changing the saturation, + new saturation is applied to selected stops preventing original hue, value and alpha in multiselection). + + The convenient static functions getGradient() provide modal gradient dialogs, e.g.: + + \snippet doc/src/snippets/code/tools_shared_qtgradienteditor_qtgradientdialog.cpp 0 + + In order to have more control over the properties of QtGradientDialog use + standard QDialog::exec() method: + + \snippet doc/src/snippets/code/tools_shared_qtgradienteditor_qtgradientdialog.cpp 1 + + \sa {Gradient View Example} +*/ + +/*! + Constructs a gradient dialog with \a parent as parent widget. +*/ + +QtGradientDialog::QtGradientDialog(QWidget *parent) + : QDialog(parent) +{ +// setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint); + d_ptr = new QtGradientDialogPrivate(); + d_ptr->q_ptr = this; + d_ptr->m_ui.setupUi(this); + QPushButton *button = d_ptr->m_ui.buttonBox->button(QDialogButtonBox::Ok); + if (button) + button->setAutoDefault(false); + button = d_ptr->m_ui.buttonBox->button(QDialogButtonBox::Cancel); + if (button) + button->setAutoDefault(false); + connect(d_ptr->m_ui.gradientEditor, SIGNAL(aboutToShowDetails(bool, int)), + this, SLOT(slotAboutToShowDetails(bool, int))); +} + +/*! + Destroys the gradient dialog +*/ + +QtGradientDialog::~QtGradientDialog() +{ + delete d_ptr; +} + +/*! + \property QtGradientDialog::gradient + \brief the gradient of the dialog +*/ +void QtGradientDialog::setGradient(const QGradient &gradient) +{ + d_ptr->m_ui.gradientEditor->setGradient(gradient); +} + +QGradient QtGradientDialog::gradient() const +{ + return d_ptr->m_ui.gradientEditor->gradient(); +} + +/*! + \property QtGradientDialog::backgroundCheckered + \brief whether the background of widgets able to show the colors with alpha channel is checkered. + + \table + \row + \o \inlineimage qtgradientdialogbackgroundcheckered.png + \o \inlineimage qtgradientdialogbackgroundtransparent.png + \row + \o \snippet doc/src/snippets/code/tools_shared_qtgradienteditor_qtgradientdialog.cpp 2 + \o \snippet doc/src/snippets/code/tools_shared_qtgradienteditor_qtgradientdialog.cpp 3 + \endtable + + When this property is set to true (the default) widgets inside gradient dialog like color button, + color sliders, gradient stops editor and gradient editor will show checkered background + in case of transparent colors. Otherwise the background of these widgets is transparent. +*/ + +bool QtGradientDialog::isBackgroundCheckered() const +{ + return d_ptr->m_ui.gradientEditor->isBackgroundCheckered(); +} + +void QtGradientDialog::setBackgroundCheckered(bool checkered) +{ + d_ptr->m_ui.gradientEditor->setBackgroundCheckered(checkered); +} + +/*! + \property QtGradientDialog::detailsVisible + \brief whether details extension is visible. + + When this property is set to true the details extension is visible. By default + this property is set to false and the details extension is hidden. + + \sa detailsButtonVisible +*/ +bool QtGradientDialog::detailsVisible() const +{ + return d_ptr->m_ui.gradientEditor->detailsVisible(); +} + +void QtGradientDialog::setDetailsVisible(bool visible) +{ + d_ptr->m_ui.gradientEditor->setDetailsVisible(visible); +} + +/*! + \property QtGradientDialog::detailsButtonVisible + \brief whether the details button allowing for showing and hiding details extension is visible. + + When this property is set to true (the default) the details button is visible and the user + can show and hide details extension interactively. Otherwise the button is hidden and the details + extension is always visible or hidded depending on the value of detailsVisible property. + + \sa detailsVisible +*/ +bool QtGradientDialog::isDetailsButtonVisible() const +{ + return d_ptr->m_ui.gradientEditor->isDetailsButtonVisible(); +} + +void QtGradientDialog::setDetailsButtonVisible(bool visible) +{ + d_ptr->m_ui.gradientEditor->setDetailsButtonVisible(visible); +} + +/*! + Returns the current QColor::Spec used for the color sliders in the dialog. +*/ +QColor::Spec QtGradientDialog::spec() const +{ + return d_ptr->m_ui.gradientEditor->spec(); +} + +/*! + Sets the current QColor::Spec to \a spec used for the color sliders in the dialog. +*/ +void QtGradientDialog::setSpec(QColor::Spec spec) +{ + d_ptr->m_ui.gradientEditor->setSpec(spec); +} + +/*! + Executes a modal gradient dialog, lets the user to specify a gradient, and returns that gradient. + + If the user clicks \gui OK, the gradient specified by the user is returned. If the user clicks \gui Cancel, the \a initial gradient is returned. + + The dialog is constructed with the given \a parent. \a caption is shown as the window title of the dialog and + \a initial is the initial gradient shown in the dialog. If the \a ok parameter is not-null, + the value it refers to is set to true if the user clicks \gui OK, and set to false if the user clicks \gui Cancel. +*/ +QGradient QtGradientDialog::getGradient(bool *ok, const QGradient &initial, QWidget *parent, const QString &caption) +{ + QtGradientDialog dlg(parent); + if (!caption.isEmpty()) + dlg.setWindowTitle(caption); + dlg.setGradient(initial); + const int res = dlg.exec(); + if (ok) { + *ok = (res == QDialog::Accepted) ? true : false; + } + if (res == QDialog::Accepted) + return dlg.gradient(); + return initial; +} + +/*! + This method calls getGradient(ok, QLinearGradient(), parent, caption). +*/ +QGradient QtGradientDialog::getGradient(bool *ok, QWidget *parent, const QString &caption) +{ + return getGradient(ok, QLinearGradient(), parent, caption); +} + +QT_END_NAMESPACE + +#include "moc_qtgradientdialog.cpp" diff --git a/tools/shared/qtgradienteditor/qtgradientdialog.h b/tools/shared/qtgradienteditor/qtgradientdialog.h new file mode 100644 index 0000000..d3bafc9 --- /dev/null +++ b/tools/shared/qtgradienteditor/qtgradientdialog.h @@ -0,0 +1,87 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the tools applications of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QTGRADIENTDIALOG_H +#define QTGRADIENTDIALOG_H + +#include <QtGui/QDialog> + +QT_BEGIN_NAMESPACE + +class QtGradientDialog : public QDialog +{ + Q_OBJECT + Q_PROPERTY(QGradient gradient READ gradient WRITE setGradient) + Q_PROPERTY(bool backgroundCheckered READ isBackgroundCheckered WRITE setBackgroundCheckered) + Q_PROPERTY(bool detailsVisible READ detailsVisible WRITE setDetailsVisible) + Q_PROPERTY(bool detailsButtonVisible READ isDetailsButtonVisible WRITE setDetailsButtonVisible) +public: + QtGradientDialog(QWidget *parent = 0); + ~QtGradientDialog(); + + void setGradient(const QGradient &gradient); + QGradient gradient() const; + + bool isBackgroundCheckered() const; + void setBackgroundCheckered(bool checkered); + + bool detailsVisible() const; + void setDetailsVisible(bool visible); + + bool isDetailsButtonVisible() const; + void setDetailsButtonVisible(bool visible); + + QColor::Spec spec() const; + void setSpec(QColor::Spec spec); + + static QGradient getGradient(bool *ok, const QGradient &initial, QWidget *parent = 0, const QString &caption = QString()); + static QGradient getGradient(bool *ok, QWidget *parent = 0, const QString &caption = QString()); + +private: + class QtGradientDialogPrivate *d_ptr; + Q_DECLARE_PRIVATE(QtGradientDialog) + Q_DISABLE_COPY(QtGradientDialog) + Q_PRIVATE_SLOT(d_func(), void slotAboutToShowDetails(bool details, int extensionWidthHint)) +}; + +QT_END_NAMESPACE + +#endif diff --git a/tools/shared/qtgradienteditor/qtgradientdialog.ui b/tools/shared/qtgradienteditor/qtgradientdialog.ui new file mode 100644 index 0000000..0b3db0b --- /dev/null +++ b/tools/shared/qtgradienteditor/qtgradientdialog.ui @@ -0,0 +1,121 @@ +<ui version="4.0" > + <comment>********************************************************************* +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the tools applications of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +*********************************************************************</comment> + <class>QtGradientDialog</class> + <widget class="QDialog" name="QtGradientDialog" > + <property name="geometry" > + <rect> + <x>0</x> + <y>0</y> + <width>178</width> + <height>81</height> + </rect> + </property> + <property name="windowTitle" > + <string>Edit Gradient</string> + </property> + <layout class="QVBoxLayout" > + <item> + <widget class="QtGradientEditor" name="gradientEditor" > + <property name="sizePolicy" > + <sizepolicy vsizetype="MinimumExpanding" hsizetype="MinimumExpanding" > + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + </widget> + </item> + <item> + <widget class="QDialogButtonBox" name="buttonBox" > + <property name="orientation" > + <enum>Qt::Horizontal</enum> + </property> + <property name="standardButtons" > + <set>QDialogButtonBox::Cancel|QDialogButtonBox::NoButton|QDialogButtonBox::Ok</set> + </property> + </widget> + </item> + </layout> + </widget> + <customwidgets> + <customwidget> + <class>QtGradientEditor</class> + <extends>QFrame</extends> + <header>qtgradienteditor.h</header> + <container>1</container> + </customwidget> + </customwidgets> + <resources/> + <connections> + <connection> + <sender>buttonBox</sender> + <signal>accepted()</signal> + <receiver>QtGradientDialog</receiver> + <slot>accept()</slot> + <hints> + <hint type="sourcelabel" > + <x>72</x> + <y>224</y> + </hint> + <hint type="destinationlabel" > + <x>21</x> + <y>243</y> + </hint> + </hints> + </connection> + <connection> + <sender>buttonBox</sender> + <signal>rejected()</signal> + <receiver>QtGradientDialog</receiver> + <slot>reject()</slot> + <hints> + <hint type="sourcelabel" > + <x>168</x> + <y>233</y> + </hint> + <hint type="destinationlabel" > + <x>152</x> + <y>251</y> + </hint> + </hints> + </connection> + </connections> +</ui> diff --git a/tools/shared/qtgradienteditor/qtgradienteditor.cpp b/tools/shared/qtgradienteditor/qtgradienteditor.cpp new file mode 100644 index 0000000..9eca9d8 --- /dev/null +++ b/tools/shared/qtgradienteditor/qtgradienteditor.cpp @@ -0,0 +1,958 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the tools applications of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/* +TRANSLATOR qdesigner_internal::QtGradientEditor +*/ + +#include "qtgradienteditor.h" +#include "qtgradientstopscontroller.h" +#include "ui_qtgradienteditor.h" + +QT_BEGIN_NAMESPACE + +class QtGradientEditorPrivate +{ + QtGradientEditor *q_ptr; + Q_DECLARE_PUBLIC(QtGradientEditor) +public: + QtGradientEditorPrivate() : m_gradient(QLinearGradient()) {} + + void slotGradientStopsChanged(const QGradientStops &stops); + void slotTypeChanged(int type); + void slotSpreadChanged(int spread); + void slotStartLinearXChanged(double value); + void slotStartLinearYChanged(double value); + void slotEndLinearXChanged(double value); + void slotEndLinearYChanged(double value); + void slotCentralRadialXChanged(double value); + void slotCentralRadialYChanged(double value); + void slotFocalRadialXChanged(double value); + void slotFocalRadialYChanged(double value); + void slotRadiusRadialChanged(double value); + void slotCentralConicalXChanged(double value); + void slotCentralConicalYChanged(double value); + void slotAngleConicalChanged(double value); + + void slotDetailsChanged(bool details); + + void startLinearChanged(const QPointF &point); + void endLinearChanged(const QPointF &point); + void centralRadialChanged(const QPointF &point); + void focalRadialChanged(const QPointF &point); + void radiusRadialChanged(qreal radius); + void centralConicalChanged(const QPointF &point); + void angleConicalChanged(qreal angle); + + void setStartLinear(const QPointF &point); + void setEndLinear(const QPointF &point); + void setCentralRadial(const QPointF &point); + void setFocalRadial(const QPointF &point); + void setRadiusRadial(qreal radius); + void setCentralConical(const QPointF &point); + void setAngleConical(qreal angle); + + void setType(QGradient::Type type); + void showDetails(bool details); + + void setSpinBox(QDoubleSpinBox *spinBox, const char *slot, double max = 1.0, double step = 0.01, int decimals = 3); + void reset(); + void setLayout(bool details); + void layoutDetails(bool details); + bool row4Visible() const; + bool row5Visible() const; + int extensionWidthHint() const; + + void setCombos(bool combos); + + QGradient gradient() const; + void updateGradient(bool emitSignal); + + Ui::QtGradientEditor m_ui; + QtGradientStopsController *m_gradientStopsController; + + QDoubleSpinBox *startLinearXSpinBox; + QDoubleSpinBox *startLinearYSpinBox; + QDoubleSpinBox *endLinearXSpinBox; + QDoubleSpinBox *endLinearYSpinBox; + QDoubleSpinBox *centralRadialXSpinBox; + QDoubleSpinBox *centralRadialYSpinBox; + QDoubleSpinBox *focalRadialXSpinBox; + QDoubleSpinBox *focalRadialYSpinBox; + QDoubleSpinBox *radiusRadialSpinBox; + QDoubleSpinBox *centralConicalXSpinBox; + QDoubleSpinBox *centralConicalYSpinBox; + QDoubleSpinBox *angleConicalSpinBox; + + QButtonGroup *m_typeGroup; + QButtonGroup *m_spreadGroup; + + QGradient::Type m_type; + + QGridLayout *m_gridLayout; + QWidget *m_hiddenWidget; + QGridLayout *m_hiddenLayout; + bool m_details; + bool m_detailsButtonVisible; + bool m_backgroundCheckered; + + QGradient m_gradient; + + bool m_combos; +}; + +QGradient QtGradientEditorPrivate::gradient() const +{ + QGradient *gradient = 0; + switch (m_ui.gradientWidget->gradientType()) { + case QGradient::LinearGradient: + gradient = new QLinearGradient(m_ui.gradientWidget->startLinear(), + m_ui.gradientWidget->endLinear()); + break; + case QGradient::RadialGradient: + gradient = new QRadialGradient(m_ui.gradientWidget->centralRadial(), + m_ui.gradientWidget->radiusRadial(), + m_ui.gradientWidget->focalRadial()); + break; + case QGradient::ConicalGradient: + gradient = new QConicalGradient(m_ui.gradientWidget->centralConical(), + m_ui.gradientWidget->angleConical()); + break; + default: + break; + } + if (!gradient) + return QGradient(); + gradient->setStops(m_ui.gradientWidget->gradientStops()); + gradient->setSpread(m_ui.gradientWidget->gradientSpread()); + gradient->setCoordinateMode(QGradient::StretchToDeviceMode); + QGradient gr = *gradient; + delete gradient; + return gr; +} + +void QtGradientEditorPrivate::updateGradient(bool emitSignal) +{ + QGradient grad = gradient(); + if (m_gradient == grad) + return; + + m_gradient = grad; + if (emitSignal) + emit q_ptr->gradientChanged(m_gradient); +} + +void QtGradientEditorPrivate::setCombos(bool combos) +{ + if (m_combos == combos) + return; + + m_combos = combos; + m_ui.linearButton->setVisible(!m_combos); + m_ui.radialButton->setVisible(!m_combos); + m_ui.conicalButton->setVisible(!m_combos); + m_ui.padButton->setVisible(!m_combos); + m_ui.repeatButton->setVisible(!m_combos); + m_ui.reflectButton->setVisible(!m_combos); + m_ui.typeComboBox->setVisible(m_combos); + m_ui.spreadComboBox->setVisible(m_combos); +} + +void QtGradientEditorPrivate::setLayout(bool details) +{ + QHBoxLayout *hboxLayout = new QHBoxLayout(); + hboxLayout->setObjectName(QString::fromUtf8("hboxLayout")); + hboxLayout->addWidget(m_ui.typeComboBox); + hboxLayout->addWidget(m_ui.spreadComboBox); + QHBoxLayout *typeLayout = new QHBoxLayout(); + typeLayout->setSpacing(0); + typeLayout->addWidget(m_ui.linearButton); + typeLayout->addWidget(m_ui.radialButton); + typeLayout->addWidget(m_ui.conicalButton); + hboxLayout->addLayout(typeLayout); + QHBoxLayout *spreadLayout = new QHBoxLayout(); + spreadLayout->setSpacing(0); + spreadLayout->addWidget(m_ui.padButton); + spreadLayout->addWidget(m_ui.repeatButton); + spreadLayout->addWidget(m_ui.reflectButton); + hboxLayout->addLayout(spreadLayout); + hboxLayout->addItem(new QSpacerItem(0, 0, QSizePolicy::Expanding, QSizePolicy::Minimum)); + hboxLayout->addWidget(m_ui.detailsButton); + m_gridLayout->addLayout(hboxLayout, 0, 0, 1, 2); + int span = 1; + if (details) + span = 7; + m_gridLayout->addWidget(m_ui.frame, 1, 0, span, 2); + int row = 2; + if (details) { + row = 8; + span = 4; + } + m_gridLayout->addWidget(m_ui.gradientStopsWidget, row, 0, span, 2); + QHBoxLayout *hboxLayout1 = new QHBoxLayout(); + hboxLayout1->setObjectName(QString::fromUtf8("hboxLayout1")); + hboxLayout1->addWidget(m_ui.colorLabel); + hboxLayout1->addWidget(m_ui.colorButton); + hboxLayout1->addWidget(m_ui.hsvRadioButton); + hboxLayout1->addWidget(m_ui.rgbRadioButton); + hboxLayout1->addItem(new QSpacerItem(16, 23, QSizePolicy::Expanding, QSizePolicy::Minimum)); + int addRow = 0; + if (details) + addRow = 9; + m_gridLayout->addLayout(hboxLayout1, 3 + addRow, 0, 1, 2); + m_gridLayout->addWidget(m_ui.hLabel, 4 + addRow, 0, 1, 1); + m_gridLayout->addWidget(m_ui.frame_2, 4 + addRow, 1, 1, 1); + m_gridLayout->addWidget(m_ui.sLabel, 5 + addRow, 0, 1, 1); + m_gridLayout->addWidget(m_ui.frame_5, 5 + addRow, 1, 1, 1); + m_gridLayout->addWidget(m_ui.vLabel, 6 + addRow, 0, 1, 1); + m_gridLayout->addWidget(m_ui.frame_3, 6 + addRow, 1, 1, 1); + m_gridLayout->addWidget(m_ui.aLabel, 7 + addRow, 0, 1, 1); + m_gridLayout->addWidget(m_ui.frame_4, 7 + addRow, 1, 1, 1); + + if (details) { + layoutDetails(details); + } +} + +void QtGradientEditorPrivate::layoutDetails(bool details) +{ + QGridLayout *gridLayout = m_gridLayout; + int col = 2; + if (!details) { + col = 0; + if (!m_hiddenWidget) { + m_hiddenWidget = new QWidget(); + m_hiddenLayout = new QGridLayout(m_hiddenWidget); + m_hiddenLayout->setContentsMargins(0, 0, 0, 0); + m_hiddenLayout->setSizeConstraint(QLayout::SetFixedSize); + } + gridLayout = m_hiddenLayout; + } + gridLayout->addWidget(m_ui.label1, 1, col + 0, 1, 1); + gridLayout->addWidget(m_ui.spinBox1, 1, col + 1, 1, 1); + gridLayout->addWidget(m_ui.label2, 2, col + 0, 1, 1); + gridLayout->addWidget(m_ui.spinBox2, 2, col + 1, 1, 1); + gridLayout->addWidget(m_ui.label3, 3, col + 0, 1, 1); + gridLayout->addWidget(m_ui.spinBox3, 3, col + 1, 1, 1); + gridLayout->addWidget(m_ui.label4, 4, col + 0, 1, 1); + gridLayout->addWidget(m_ui.spinBox4, 4, col + 1, 1, 1); + gridLayout->addWidget(m_ui.label5, 5, col + 0, 1, 1); + gridLayout->addWidget(m_ui.spinBox5, 5, col + 1, 1, 1); + gridLayout->addItem(new QSpacerItem(0, 0, QSizePolicy::Minimum, QSizePolicy::Expanding), 6, col + 0, 1, 1); + gridLayout->addWidget(m_ui.line1Widget, 7, col + 0, 1, 2); + gridLayout->addWidget(m_ui.zoomLabel, 8, col + 0, 1, 1); + gridLayout->addWidget(m_ui.zoomWidget, 8, col + 1, 1, 1); + gridLayout->addWidget(m_ui.zoomButtonsWidget, 9, col + 0, 1, 1); + gridLayout->addWidget(m_ui.zoomAllButton, 9, col + 1, 1, 1); + gridLayout->addItem(new QSpacerItem(0, 0, QSizePolicy::Minimum, QSizePolicy::Preferred), 10, col + 0, 1, 1); + gridLayout->addWidget(m_ui.line2Widget, 11, col + 0, 1, 2); + gridLayout->addWidget(m_ui.positionLabel, 12, col + 0, 1, 1); + gridLayout->addWidget(m_ui.positionWidget, 12, col + 1, 1, 1); + gridLayout->addWidget(m_ui.hueLabel, 13, col + 0, 1, 1); + gridLayout->addWidget(m_ui.hueWidget, 13, col + 1, 1, 1); + gridLayout->addWidget(m_ui.saturationLabel, 14, col + 0, 1, 1); + gridLayout->addWidget(m_ui.saturationWidget, 14, col + 1, 1, 1); + gridLayout->addWidget(m_ui.valueLabel, 15, col + 0, 1, 1); + gridLayout->addWidget(m_ui.valueWidget, 15, col + 1, 1, 1); + gridLayout->addWidget(m_ui.alphaLabel, 16, col + 0, 1, 1); + gridLayout->addWidget(m_ui.alphaWidget, 16, col + 1, 1, 1); + + if (details) { + if (m_hiddenLayout) { + delete m_hiddenLayout; + m_hiddenLayout = 0; + } + if (m_hiddenWidget) { + delete m_hiddenWidget; + m_hiddenWidget = 0; + } + } +} + +int QtGradientEditorPrivate::extensionWidthHint() const +{ + if (m_details) + return q_ptr->size().width() - m_ui.gradientStopsWidget->size().width(); + + const int space = m_ui.spinBox1->geometry().left() - m_ui.label1->geometry().right(); + + return m_hiddenLayout->minimumSize().width() + space; +} + +void QtGradientEditorPrivate::slotDetailsChanged(bool details) +{ + showDetails(details); +} + +bool QtGradientEditorPrivate::row4Visible() const +{ + if (m_type == QGradient::ConicalGradient) + return false; + return true; +} + +bool QtGradientEditorPrivate::row5Visible() const +{ + if (m_type == QGradient::RadialGradient) + return true; + return false; +} + +void QtGradientEditorPrivate::showDetails(bool details) +{ + if (m_details == details) + return; + + bool blocked = m_ui.detailsButton->signalsBlocked(); + m_ui.detailsButton->blockSignals(true); + m_ui.detailsButton->setChecked(details); + m_ui.detailsButton->blockSignals(blocked); + + bool updates = q_ptr->updatesEnabled(); + q_ptr->setUpdatesEnabled(false); + + if (m_gridLayout) { + m_gridLayout->setEnabled(false); + delete m_gridLayout; + m_gridLayout = 0; + } + + if (!details) { + layoutDetails(details); + } + + emit q_ptr->aboutToShowDetails(details, extensionWidthHint()); + m_details = details; + + m_gridLayout = new QGridLayout(q_ptr); + m_gridLayout->setEnabled(false); + m_gridLayout->setObjectName(QString::fromUtf8("gridLayout")); + m_gridLayout->setContentsMargins(0, 0, 0, 0); + + m_ui.label4->setVisible(row4Visible()); + m_ui.label5->setVisible(row5Visible()); + m_ui.spinBox4->setVisible(row4Visible()); + m_ui.spinBox5->setVisible(row5Visible()); + + setLayout(details); + m_gridLayout->setEnabled(true); + + q_ptr->setUpdatesEnabled(updates); + q_ptr->update(); +} + +void QtGradientEditorPrivate::setSpinBox(QDoubleSpinBox *spinBox, const char *slot, double max, double step, int decimals) +{ + bool blocked = spinBox->signalsBlocked(); + spinBox->blockSignals(true); + spinBox->setDecimals(decimals); + spinBox->setMaximum(max); + spinBox->setSingleStep(step); + spinBox->blockSignals(blocked); + QObject::connect(spinBox, SIGNAL(valueChanged(double)), q_ptr, slot); +} + +void QtGradientEditorPrivate::reset() +{ + startLinearXSpinBox = 0; + startLinearYSpinBox = 0; + endLinearXSpinBox = 0; + endLinearYSpinBox = 0; + centralRadialXSpinBox = 0; + centralRadialYSpinBox = 0; + focalRadialXSpinBox = 0; + focalRadialYSpinBox = 0; + radiusRadialSpinBox = 0; + centralConicalXSpinBox = 0; + centralConicalYSpinBox = 0; + angleConicalSpinBox = 0; +} + +void QtGradientEditorPrivate::setType(QGradient::Type type) +{ + if (m_type == type) + return; + + m_type = type; + m_ui.spinBox1->disconnect(SIGNAL(valueChanged(double))); + m_ui.spinBox2->disconnect(SIGNAL(valueChanged(double))); + m_ui.spinBox3->disconnect(SIGNAL(valueChanged(double))); + m_ui.spinBox4->disconnect(SIGNAL(valueChanged(double))); + m_ui.spinBox5->disconnect(SIGNAL(valueChanged(double))); + + reset(); + + bool ena = true; + + if (m_gridLayout) { + ena = m_gridLayout->isEnabled(); + m_gridLayout->setEnabled(false); + } + + bool spreadEnabled = true; + + if (type == QGradient::LinearGradient) { + startLinearXSpinBox = m_ui.spinBox1; + setSpinBox(startLinearXSpinBox, SLOT(slotStartLinearXChanged(double))); + m_ui.label1->setText(QApplication::translate("QtGradientEditor", "Start X", 0, QApplication::UnicodeUTF8)); + + startLinearYSpinBox = m_ui.spinBox2; + setSpinBox(startLinearYSpinBox, SLOT(slotStartLinearYChanged(double))); + m_ui.label2->setText(QApplication::translate("QtGradientEditor", "Start Y", 0, QApplication::UnicodeUTF8)); + + endLinearXSpinBox = m_ui.spinBox3; + setSpinBox(endLinearXSpinBox, SLOT(slotEndLinearXChanged(double))); + m_ui.label3->setText(QApplication::translate("QtGradientEditor", "Final X", 0, QApplication::UnicodeUTF8)); + + endLinearYSpinBox = m_ui.spinBox4; + setSpinBox(endLinearYSpinBox, SLOT(slotEndLinearYChanged(double))); + m_ui.label4->setText(QApplication::translate("QtGradientEditor", "Final Y", 0, QApplication::UnicodeUTF8)); + + setStartLinear(m_ui.gradientWidget->startLinear()); + setEndLinear(m_ui.gradientWidget->endLinear()); + } else if (type == QGradient::RadialGradient) { + centralRadialXSpinBox = m_ui.spinBox1; + setSpinBox(centralRadialXSpinBox, SLOT(slotCentralRadialXChanged(double))); + m_ui.label1->setText(QApplication::translate("QtGradientEditor", "Central X", 0, QApplication::UnicodeUTF8)); + + centralRadialYSpinBox = m_ui.spinBox2; + setSpinBox(centralRadialYSpinBox, SLOT(slotCentralRadialYChanged(double))); + m_ui.label2->setText(QApplication::translate("QtGradientEditor", "Central Y", 0, QApplication::UnicodeUTF8)); + + focalRadialXSpinBox = m_ui.spinBox3; + setSpinBox(focalRadialXSpinBox, SLOT(slotFocalRadialXChanged(double))); + m_ui.label3->setText(QApplication::translate("QtGradientEditor", "Focal X", 0, QApplication::UnicodeUTF8)); + + focalRadialYSpinBox = m_ui.spinBox4; + setSpinBox(focalRadialYSpinBox, SLOT(slotFocalRadialYChanged(double))); + m_ui.label4->setText(QApplication::translate("QtGradientEditor", "Focal Y", 0, QApplication::UnicodeUTF8)); + + radiusRadialSpinBox = m_ui.spinBox5; + setSpinBox(radiusRadialSpinBox, SLOT(slotRadiusRadialChanged(double)), 2.0); + m_ui.label5->setText(QApplication::translate("QtGradientEditor", "Radius", 0, QApplication::UnicodeUTF8)); + + setCentralRadial(m_ui.gradientWidget->centralRadial()); + setFocalRadial(m_ui.gradientWidget->focalRadial()); + setRadiusRadial(m_ui.gradientWidget->radiusRadial()); + } else if (type == QGradient::ConicalGradient) { + centralConicalXSpinBox = m_ui.spinBox1; + setSpinBox(centralConicalXSpinBox, SLOT(slotCentralConicalXChanged(double))); + m_ui.label1->setText(QApplication::translate("QtGradientEditor", "Central X", 0, QApplication::UnicodeUTF8)); + + centralConicalYSpinBox = m_ui.spinBox2; + setSpinBox(centralConicalYSpinBox, SLOT(slotCentralConicalYChanged(double))); + m_ui.label2->setText(QApplication::translate("QtGradientEditor", "Central Y", 0, QApplication::UnicodeUTF8)); + + angleConicalSpinBox = m_ui.spinBox3; + setSpinBox(angleConicalSpinBox, SLOT(slotAngleConicalChanged(double)), 360.0, 1.0, 1); + m_ui.label3->setText(QApplication::translate("QtGradientEditor", "Angle", 0, QApplication::UnicodeUTF8)); + + setCentralConical(m_ui.gradientWidget->centralConical()); + setAngleConical(m_ui.gradientWidget->angleConical()); + + spreadEnabled = false; + } + m_ui.spreadComboBox->setEnabled(spreadEnabled); + m_ui.padButton->setEnabled(spreadEnabled); + m_ui.repeatButton->setEnabled(spreadEnabled); + m_ui.reflectButton->setEnabled(spreadEnabled); + + m_ui.label4->setVisible(row4Visible()); + m_ui.spinBox4->setVisible(row4Visible()); + m_ui.label5->setVisible(row5Visible()); + m_ui.spinBox5->setVisible(row5Visible()); + + if (m_gridLayout) { + m_gridLayout->setEnabled(ena); + } +} + +void QtGradientEditorPrivate::slotGradientStopsChanged(const QGradientStops &stops) +{ + m_ui.gradientWidget->setGradientStops(stops); + updateGradient(true); +} + +void QtGradientEditorPrivate::slotTypeChanged(int idx) +{ + QGradient::Type type = QGradient::NoGradient; + if (idx == 0) + type = QGradient::LinearGradient; + else if (idx == 1) + type = QGradient::RadialGradient; + else if (idx == 2) + type = QGradient::ConicalGradient; + setType(type); + m_ui.typeComboBox->setCurrentIndex(idx); + m_typeGroup->button(idx)->setChecked(true); + m_ui.gradientWidget->setGradientType(type); + updateGradient(true); +} + +void QtGradientEditorPrivate::slotSpreadChanged(int spread) +{ + if (spread == 0) { + m_ui.gradientWidget->setGradientSpread(QGradient::PadSpread); + } else if (spread == 1) { + m_ui.gradientWidget->setGradientSpread(QGradient::RepeatSpread); + } else if (spread == 2) { + m_ui.gradientWidget->setGradientSpread(QGradient::ReflectSpread); + } + m_ui.spreadComboBox->setCurrentIndex(spread); + updateGradient(true); +} + +void QtGradientEditorPrivate::slotStartLinearXChanged(double value) +{ + QPointF point = m_ui.gradientWidget->startLinear(); + point.setX(value); + m_ui.gradientWidget->setStartLinear(point); + updateGradient(true); +} + +void QtGradientEditorPrivate::slotStartLinearYChanged(double value) +{ + QPointF point = m_ui.gradientWidget->startLinear(); + point.setY(value); + m_ui.gradientWidget->setStartLinear(point); + updateGradient(true); +} + +void QtGradientEditorPrivate::slotEndLinearXChanged(double value) +{ + QPointF point = m_ui.gradientWidget->endLinear(); + point.setX(value); + m_ui.gradientWidget->setEndLinear(point); + updateGradient(true); +} + +void QtGradientEditorPrivate::slotEndLinearYChanged(double value) +{ + QPointF point = m_ui.gradientWidget->endLinear(); + point.setY(value); + m_ui.gradientWidget->setEndLinear(point); + updateGradient(true); +} + +void QtGradientEditorPrivate::slotCentralRadialXChanged(double value) +{ + QPointF point = m_ui.gradientWidget->centralRadial(); + point.setX(value); + m_ui.gradientWidget->setCentralRadial(point); + updateGradient(true); +} + +void QtGradientEditorPrivate::slotCentralRadialYChanged(double value) +{ + QPointF point = m_ui.gradientWidget->centralRadial(); + point.setY(value); + m_ui.gradientWidget->setCentralRadial(point); + updateGradient(true); +} + +void QtGradientEditorPrivate::slotFocalRadialXChanged(double value) +{ + QPointF point = m_ui.gradientWidget->focalRadial(); + point.setX(value); + m_ui.gradientWidget->setFocalRadial(point); + updateGradient(true); +} + +void QtGradientEditorPrivate::slotFocalRadialYChanged(double value) +{ + QPointF point = m_ui.gradientWidget->focalRadial(); + point.setY(value); + m_ui.gradientWidget->setFocalRadial(point); + updateGradient(true); +} + +void QtGradientEditorPrivate::slotRadiusRadialChanged(double value) +{ + m_ui.gradientWidget->setRadiusRadial(value); + updateGradient(true); +} + +void QtGradientEditorPrivate::slotCentralConicalXChanged(double value) +{ + QPointF point = m_ui.gradientWidget->centralConical(); + point.setX(value); + m_ui.gradientWidget->setCentralConical(point); + updateGradient(true); +} + +void QtGradientEditorPrivate::slotCentralConicalYChanged(double value) +{ + QPointF point = m_ui.gradientWidget->centralConical(); + point.setY(value); + m_ui.gradientWidget->setCentralConical(point); + updateGradient(true); +} + +void QtGradientEditorPrivate::slotAngleConicalChanged(double value) +{ + m_ui.gradientWidget->setAngleConical(value); + updateGradient(true); +} + +void QtGradientEditorPrivate::startLinearChanged(const QPointF &point) +{ + setStartLinear(point); + updateGradient(true); +} + +void QtGradientEditorPrivate::endLinearChanged(const QPointF &point) +{ + setEndLinear(point); + updateGradient(true); +} + +void QtGradientEditorPrivate::centralRadialChanged(const QPointF &point) +{ + setCentralRadial(point); + updateGradient(true); +} + +void QtGradientEditorPrivate::focalRadialChanged(const QPointF &point) +{ + setFocalRadial(point); + updateGradient(true); +} + +void QtGradientEditorPrivate::radiusRadialChanged(qreal radius) +{ + setRadiusRadial(radius); + updateGradient(true); +} + +void QtGradientEditorPrivate::centralConicalChanged(const QPointF &point) +{ + setCentralConical(point); + updateGradient(true); +} + +void QtGradientEditorPrivate::angleConicalChanged(qreal angle) +{ + setAngleConical(angle); + updateGradient(true); +} + +void QtGradientEditorPrivate::setStartLinear(const QPointF &point) +{ + if (startLinearXSpinBox) + startLinearXSpinBox->setValue(point.x()); + if (startLinearYSpinBox) + startLinearYSpinBox->setValue(point.y()); +} + +void QtGradientEditorPrivate::setEndLinear(const QPointF &point) +{ + if (endLinearXSpinBox) + endLinearXSpinBox->setValue(point.x()); + if (endLinearYSpinBox) + endLinearYSpinBox->setValue(point.y()); +} + +void QtGradientEditorPrivate::setCentralRadial(const QPointF &point) +{ + if (centralRadialXSpinBox) + centralRadialXSpinBox->setValue(point.x()); + if (centralRadialYSpinBox) + centralRadialYSpinBox->setValue(point.y()); +} + +void QtGradientEditorPrivate::setFocalRadial(const QPointF &point) +{ + if (focalRadialXSpinBox) + focalRadialXSpinBox->setValue(point.x()); + if (focalRadialYSpinBox) + focalRadialYSpinBox->setValue(point.y()); +} + +void QtGradientEditorPrivate::setRadiusRadial(qreal radius) +{ + if (radiusRadialSpinBox) + radiusRadialSpinBox->setValue(radius); +} + +void QtGradientEditorPrivate::setCentralConical(const QPointF &point) +{ + if (centralConicalXSpinBox) + centralConicalXSpinBox->setValue(point.x()); + if (centralConicalYSpinBox) + centralConicalYSpinBox->setValue(point.y()); +} + +void QtGradientEditorPrivate::setAngleConical(qreal angle) +{ + if (angleConicalSpinBox) + angleConicalSpinBox->setValue(angle); +} + +QtGradientEditor::QtGradientEditor(QWidget *parent) + : QWidget(parent) +{ + d_ptr = new QtGradientEditorPrivate(); + d_ptr->q_ptr = this; + d_ptr->m_type = QGradient::RadialGradient; + d_ptr->m_ui.setupUi(this); + d_ptr->m_gridLayout = 0; + d_ptr->m_hiddenLayout = 0; + d_ptr->m_hiddenWidget = 0; + bool detailsDefault = false; + d_ptr->m_details = !detailsDefault; + d_ptr->m_detailsButtonVisible = true; + bool checkeredDefault = true; + d_ptr->m_backgroundCheckered = !checkeredDefault; + d_ptr->m_gradientStopsController = new QtGradientStopsController(this); + d_ptr->m_gradientStopsController->setUi(&d_ptr->m_ui); + d_ptr->reset(); + d_ptr->setType(QGradient::LinearGradient); + d_ptr->m_combos = true; + d_ptr->setCombos(!d_ptr->m_combos); + + d_ptr->showDetails(detailsDefault); + setBackgroundCheckered(checkeredDefault); + + d_ptr->setStartLinear(QPointF(0, 0)); + d_ptr->setEndLinear(QPointF(1, 1)); + d_ptr->setCentralRadial(QPointF(0.5, 0.5)); + d_ptr->setFocalRadial(QPointF(0.5, 0.5)); + d_ptr->setRadiusRadial(0.5); + d_ptr->setCentralConical(QPointF(0.5, 0.5)); + d_ptr->setAngleConical(0); + + QIcon icon; + icon.addPixmap(style()->standardPixmap(QStyle::SP_ArrowRight), QIcon::Normal, QIcon::Off); + icon.addPixmap(style()->standardPixmap(QStyle::SP_ArrowLeft), QIcon::Normal, QIcon::On); + d_ptr->m_ui.detailsButton->setIcon(icon); + + connect(d_ptr->m_ui.detailsButton, SIGNAL(clicked(bool)), this, SLOT(slotDetailsChanged(bool))); + connect(d_ptr->m_gradientStopsController, SIGNAL(gradientStopsChanged(const QGradientStops &)), + this, SLOT(slotGradientStopsChanged(const QGradientStops &))); + + QIcon iconLinear(QLatin1String(":/trolltech/qtgradienteditor/images/typelinear.png")); + QIcon iconRadial(QLatin1String(":/trolltech/qtgradienteditor/images/typeradial.png")); + QIcon iconConical(QLatin1String(":/trolltech/qtgradienteditor/images/typeconical.png")); + + d_ptr->m_ui.typeComboBox->addItem(iconLinear, tr("Linear")); + d_ptr->m_ui.typeComboBox->addItem(iconRadial, tr("Radial")); + d_ptr->m_ui.typeComboBox->addItem(iconConical, tr("Conical")); + + d_ptr->m_ui.linearButton->setIcon(iconLinear); + d_ptr->m_ui.radialButton->setIcon(iconRadial); + d_ptr->m_ui.conicalButton->setIcon(iconConical); + + d_ptr->m_typeGroup = new QButtonGroup(this); + d_ptr->m_typeGroup->addButton(d_ptr->m_ui.linearButton, 0); + d_ptr->m_typeGroup->addButton(d_ptr->m_ui.radialButton, 1); + d_ptr->m_typeGroup->addButton(d_ptr->m_ui.conicalButton, 2); + + connect(d_ptr->m_typeGroup, SIGNAL(buttonClicked(int)), + this, SLOT(slotTypeChanged(int))); + connect(d_ptr->m_ui.typeComboBox, SIGNAL(activated(int)), + this, SLOT(slotTypeChanged(int))); + + QIcon iconPad(QLatin1String(":/trolltech/qtgradienteditor/images/spreadpad.png")); + QIcon iconRepeat(QLatin1String(":/trolltech/qtgradienteditor/images/spreadrepeat.png")); + QIcon iconReflect(QLatin1String(":/trolltech/qtgradienteditor/images/spreadreflect.png")); + + d_ptr->m_ui.spreadComboBox->addItem(iconPad, tr("Pad")); + d_ptr->m_ui.spreadComboBox->addItem(iconRepeat, tr("Repeat")); + d_ptr->m_ui.spreadComboBox->addItem(iconReflect, tr("Reflect")); + + d_ptr->m_ui.padButton->setIcon(iconPad); + d_ptr->m_ui.repeatButton->setIcon(iconRepeat); + d_ptr->m_ui.reflectButton->setIcon(iconReflect); + + d_ptr->m_spreadGroup = new QButtonGroup(this); + d_ptr->m_spreadGroup->addButton(d_ptr->m_ui.padButton, 0); + d_ptr->m_spreadGroup->addButton(d_ptr->m_ui.repeatButton, 1); + d_ptr->m_spreadGroup->addButton(d_ptr->m_ui.reflectButton, 2); + connect(d_ptr->m_spreadGroup, SIGNAL(buttonClicked(int)), + this, SLOT(slotSpreadChanged(int))); + connect(d_ptr->m_ui.spreadComboBox, SIGNAL(activated(int)), + this, SLOT(slotSpreadChanged(int))); + + connect(d_ptr->m_ui.gradientWidget, SIGNAL(startLinearChanged(const QPointF &)), + this, SLOT(startLinearChanged(const QPointF &))); + connect(d_ptr->m_ui.gradientWidget, SIGNAL(endLinearChanged(const QPointF &)), + this, SLOT(endLinearChanged(const QPointF &))); + connect(d_ptr->m_ui.gradientWidget, SIGNAL(centralRadialChanged(const QPointF &)), + this, SLOT(centralRadialChanged(const QPointF &))); + connect(d_ptr->m_ui.gradientWidget, SIGNAL(focalRadialChanged(const QPointF &)), + this, SLOT(focalRadialChanged(const QPointF &))); + connect(d_ptr->m_ui.gradientWidget, SIGNAL(radiusRadialChanged(qreal)), + this, SLOT(radiusRadialChanged(qreal))); + connect(d_ptr->m_ui.gradientWidget, SIGNAL(centralConicalChanged(const QPointF &)), + this, SLOT(centralConicalChanged(const QPointF &))); + connect(d_ptr->m_ui.gradientWidget, SIGNAL(angleConicalChanged(qreal)), + this, SLOT(angleConicalChanged(qreal))); + + QGradientStops stops = gradient().stops(); + d_ptr->m_gradientStopsController->setGradientStops(stops); + d_ptr->m_ui.gradientWidget->setGradientStops(stops); +} + +QtGradientEditor::~QtGradientEditor() +{ + if (d_ptr->m_hiddenWidget) + delete d_ptr->m_hiddenWidget; + delete d_ptr; +} + +void QtGradientEditor::setGradient(const QGradient &grad) +{ + if (grad == gradient()) + return; + + QGradient::Type type = grad.type(); + int idx = 0; + switch (type) { + case QGradient::LinearGradient: idx = 0; break; + case QGradient::RadialGradient: idx = 1; break; + case QGradient::ConicalGradient: idx = 2; break; + default: return; + } + d_ptr->setType(type); + d_ptr->m_ui.typeComboBox->setCurrentIndex(idx); + d_ptr->m_ui.gradientWidget->setGradientType(type); + d_ptr->m_typeGroup->button(idx)->setChecked(true); + + QGradient::Spread spread = grad.spread(); + switch (spread) { + case QGradient::PadSpread: idx = 0; break; + case QGradient::RepeatSpread: idx = 1; break; + case QGradient::ReflectSpread: idx = 2; break; + default: idx = 0; break; + } + d_ptr->m_ui.spreadComboBox->setCurrentIndex(idx); + d_ptr->m_ui.gradientWidget->setGradientSpread(spread); + d_ptr->m_spreadGroup->button(idx)->setChecked(true); + + if (type == QGradient::LinearGradient) { + QLinearGradient *gr = (QLinearGradient *)(&grad); + d_ptr->setStartLinear(gr->start()); + d_ptr->setEndLinear(gr->finalStop()); + d_ptr->m_ui.gradientWidget->setStartLinear(gr->start()); + d_ptr->m_ui.gradientWidget->setEndLinear(gr->finalStop()); + } else if (type == QGradient::RadialGradient) { + QRadialGradient *gr = (QRadialGradient *)(&grad); + d_ptr->setCentralRadial(gr->center()); + d_ptr->setFocalRadial(gr->focalPoint()); + d_ptr->setRadiusRadial(gr->radius()); + d_ptr->m_ui.gradientWidget->setCentralRadial(gr->center()); + d_ptr->m_ui.gradientWidget->setFocalRadial(gr->focalPoint()); + d_ptr->m_ui.gradientWidget->setRadiusRadial(gr->radius()); + } else if (type == QGradient::ConicalGradient) { + QConicalGradient *gr = (QConicalGradient *)(&grad); + d_ptr->setCentralConical(gr->center()); + d_ptr->setAngleConical(gr->angle()); + d_ptr->m_ui.gradientWidget->setCentralConical(gr->center()); + d_ptr->m_ui.gradientWidget->setAngleConical(gr->angle()); + } + + d_ptr->m_gradientStopsController->setGradientStops(grad.stops()); + d_ptr->m_ui.gradientWidget->setGradientStops(grad.stops()); + d_ptr->updateGradient(false); +} + +QGradient QtGradientEditor::gradient() const +{ + return d_ptr->m_gradient; +} + +bool QtGradientEditor::isBackgroundCheckered() const +{ + return d_ptr->m_backgroundCheckered; +} + +void QtGradientEditor::setBackgroundCheckered(bool checkered) +{ + if (d_ptr->m_backgroundCheckered == checkered) + return; + + d_ptr->m_backgroundCheckered = checkered; + d_ptr->m_ui.hueColorLine->setBackgroundCheckered(checkered); + d_ptr->m_ui.saturationColorLine->setBackgroundCheckered(checkered); + d_ptr->m_ui.valueColorLine->setBackgroundCheckered(checkered); + d_ptr->m_ui.alphaColorLine->setBackgroundCheckered(checkered); + d_ptr->m_ui.gradientWidget->setBackgroundCheckered(checkered); + d_ptr->m_ui.gradientStopsWidget->setBackgroundCheckered(checkered); + d_ptr->m_ui.colorButton->setBackgroundCheckered(checkered); +} + +bool QtGradientEditor::detailsVisible() const +{ + return d_ptr->m_details; +} + +void QtGradientEditor::setDetailsVisible(bool visible) +{ + d_ptr->showDetails(visible); +} + +bool QtGradientEditor::isDetailsButtonVisible() const +{ + return d_ptr->m_detailsButtonVisible; +} + +void QtGradientEditor::setDetailsButtonVisible(bool visible) +{ + if (d_ptr->m_detailsButtonVisible == visible) + return; + + d_ptr->m_detailsButtonVisible = visible; + d_ptr->m_ui.detailsButton->setVisible(visible); +} + +QColor::Spec QtGradientEditor::spec() const +{ + return d_ptr->m_gradientStopsController->spec(); +} + +void QtGradientEditor::setSpec(QColor::Spec spec) +{ + d_ptr->m_gradientStopsController->setSpec(spec); +} + +QT_END_NAMESPACE + +#include "moc_qtgradienteditor.cpp" diff --git a/tools/shared/qtgradienteditor/qtgradienteditor.h b/tools/shared/qtgradienteditor/qtgradienteditor.h new file mode 100644 index 0000000..9974065 --- /dev/null +++ b/tools/shared/qtgradienteditor/qtgradienteditor.h @@ -0,0 +1,111 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the tools applications of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QTGRADIENTEDITOR_H +#define QTGRADIENTEDITOR_H + +#include <QtGui/QWidget> + +QT_BEGIN_NAMESPACE + +class QtGradientEditor : public QWidget +{ + Q_OBJECT + Q_PROPERTY(QGradient gradient READ gradient WRITE setGradient) + Q_PROPERTY(bool backgroundCheckered READ isBackgroundCheckered WRITE setBackgroundCheckered) + Q_PROPERTY(bool detailsVisible READ detailsVisible WRITE setDetailsVisible) + Q_PROPERTY(bool detailsButtonVisible READ isDetailsButtonVisible WRITE setDetailsButtonVisible) +public: + QtGradientEditor(QWidget *parent = 0); + ~QtGradientEditor(); + + void setGradient(const QGradient &gradient); + QGradient gradient() const; + + bool isBackgroundCheckered() const; + void setBackgroundCheckered(bool checkered); + + bool detailsVisible() const; + void setDetailsVisible(bool visible); + + bool isDetailsButtonVisible() const; + void setDetailsButtonVisible(bool visible); + + QColor::Spec spec() const; + void setSpec(QColor::Spec spec); + +signals: + + void gradientChanged(const QGradient &gradient); + void aboutToShowDetails(bool details, int extenstionWidthHint); + +private: + class QtGradientEditorPrivate *d_ptr; + Q_DECLARE_PRIVATE(QtGradientEditor) + Q_DISABLE_COPY(QtGradientEditor) + Q_PRIVATE_SLOT(d_func(), void slotGradientStopsChanged(const QGradientStops &stops)) + Q_PRIVATE_SLOT(d_func(), void slotTypeChanged(int type)) + Q_PRIVATE_SLOT(d_func(), void slotSpreadChanged(int type)) + Q_PRIVATE_SLOT(d_func(), void slotStartLinearXChanged(double value)) + Q_PRIVATE_SLOT(d_func(), void slotStartLinearYChanged(double value)) + Q_PRIVATE_SLOT(d_func(), void slotEndLinearXChanged(double value)) + Q_PRIVATE_SLOT(d_func(), void slotEndLinearYChanged(double value)) + Q_PRIVATE_SLOT(d_func(), void slotCentralRadialXChanged(double value)) + Q_PRIVATE_SLOT(d_func(), void slotCentralRadialYChanged(double value)) + Q_PRIVATE_SLOT(d_func(), void slotFocalRadialXChanged(double value)) + Q_PRIVATE_SLOT(d_func(), void slotFocalRadialYChanged(double value)) + Q_PRIVATE_SLOT(d_func(), void slotRadiusRadialChanged(double value)) + Q_PRIVATE_SLOT(d_func(), void slotCentralConicalXChanged(double value)) + Q_PRIVATE_SLOT(d_func(), void slotCentralConicalYChanged(double value)) + Q_PRIVATE_SLOT(d_func(), void slotAngleConicalChanged(double value)) + Q_PRIVATE_SLOT(d_func(), void slotDetailsChanged(bool details)) + Q_PRIVATE_SLOT(d_func(), void startLinearChanged(const QPointF &)) + Q_PRIVATE_SLOT(d_func(), void endLinearChanged(const QPointF &)) + Q_PRIVATE_SLOT(d_func(), void centralRadialChanged(const QPointF &)) + Q_PRIVATE_SLOT(d_func(), void focalRadialChanged(const QPointF &)) + Q_PRIVATE_SLOT(d_func(), void radiusRadialChanged(qreal)) + Q_PRIVATE_SLOT(d_func(), void centralConicalChanged(const QPointF &)) + Q_PRIVATE_SLOT(d_func(), void angleConicalChanged(qreal)) +}; + +QT_END_NAMESPACE + +#endif diff --git a/tools/shared/qtgradienteditor/qtgradienteditor.pri b/tools/shared/qtgradienteditor/qtgradienteditor.pri new file mode 100644 index 0000000..4cf059e --- /dev/null +++ b/tools/shared/qtgradienteditor/qtgradienteditor.pri @@ -0,0 +1,33 @@ +INCLUDEPATH += $$PWD +DEPENDPATH += $$PWD +FORMS += $$PWD/qtgradienteditor.ui \ + $$PWD/qtgradientdialog.ui \ + $$PWD/qtgradientview.ui \ + $$PWD/qtgradientviewdialog.ui +SOURCES += $$PWD/qtgradientstopsmodel.cpp \ + $$PWD/qtgradientstopswidget.cpp \ + $$PWD/qtgradientstopscontroller.cpp \ + $$PWD/qtgradientwidget.cpp \ + $$PWD/qtgradienteditor.cpp \ + $$PWD/qtgradientdialog.cpp \ + $$PWD/qtcolorbutton.cpp \ + $$PWD/qtcolorline.cpp \ + $$PWD/qtgradientview.cpp \ + $$PWD/qtgradientviewdialog.cpp \ + $$PWD/qtgradientmanager.cpp \ + $$PWD/qtgradientutils.cpp +HEADERS += $$PWD/qtgradientstopsmodel.h \ + $$PWD/qtgradientstopswidget.h \ + $$PWD/qtgradientstopscontroller.h \ + $$PWD/qtgradientwidget.h \ + $$PWD/qtgradienteditor.h \ + $$PWD/qtgradientdialog.h \ + $$PWD/qtcolorbutton.h \ + $$PWD/qtcolorline.h \ + $$PWD/qtgradientview.h \ + $$PWD/qtgradientviewdialog.h \ + $$PWD/qtgradientmanager.h \ + $$PWD/qtgradientutils.h +RESOURCES += $$PWD/qtgradienteditor.qrc + +QT += xml diff --git a/tools/shared/qtgradienteditor/qtgradienteditor.qrc b/tools/shared/qtgradienteditor/qtgradienteditor.qrc new file mode 100644 index 0000000..cce7ba6 --- /dev/null +++ b/tools/shared/qtgradienteditor/qtgradienteditor.qrc @@ -0,0 +1,18 @@ +<!DOCTYPE RCC><RCC version="1.0"> + <qresource prefix="/trolltech/qtgradienteditor"> + <file>images/edit.png</file> + <file>images/zoomin.png</file> + <file>images/zoomout.png</file> + <file>images/up.png</file> + <file>images/down.png</file> + <file>images/plus.png</file> + <file>images/minus.png</file> + <file>images/editdelete.png</file> + <file>images/spreadpad.png</file> + <file>images/spreadrepeat.png</file> + <file>images/spreadreflect.png</file> + <file>images/typelinear.png</file> + <file>images/typeradial.png</file> + <file>images/typeconical.png</file> + </qresource> +</RCC> diff --git a/tools/shared/qtgradienteditor/qtgradienteditor.ui b/tools/shared/qtgradienteditor/qtgradienteditor.ui new file mode 100644 index 0000000..4d103e3 --- /dev/null +++ b/tools/shared/qtgradienteditor/qtgradienteditor.ui @@ -0,0 +1,1377 @@ +<ui version="4.0" > + <comment>********************************************************************* +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the tools applications of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +*********************************************************************</comment> + <class>QtGradientEditor</class> + <widget class="QWidget" name="QtGradientEditor" > + <property name="geometry" > + <rect> + <x>0</x> + <y>0</y> + <width>364</width> + <height>518</height> + </rect> + </property> + <property name="windowTitle" > + <string>Form</string> + </property> + <widget class="QFrame" name="frame" > + <property name="geometry" > + <rect> + <x>10</x> + <y>69</y> + <width>193</width> + <height>150</height> + </rect> + </property> + <property name="sizePolicy" > + <sizepolicy vsizetype="Expanding" hsizetype="Expanding" > + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="frameShape" > + <enum>QFrame::StyledPanel</enum> + </property> + <property name="frameShadow" > + <enum>QFrame::Raised</enum> + </property> + <layout class="QVBoxLayout" > + <property name="spacing" > + <number>6</number> + </property> + <property name="leftMargin" > + <number>0</number> + </property> + <property name="topMargin" > + <number>0</number> + </property> + <property name="rightMargin" > + <number>0</number> + </property> + <property name="bottomMargin" > + <number>0</number> + </property> + <item> + <widget class="QtGradientWidget" native="1" name="gradientWidget" > + <property name="sizePolicy" > + <sizepolicy vsizetype="Expanding" hsizetype="Expanding" > + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="toolTip" > + <string>Gradient Editor</string> + </property> + <property name="whatsThis" > + <string>This area shows a preview of the gradient being edited. It also allows you to edit parameters specific to the gradient's type such as start and final point, radius, etc. by drag & drop.</string> + </property> + </widget> + </item> + </layout> + </widget> + <widget class="QLabel" name="label1" > + <property name="geometry" > + <rect> + <x>209</x> + <y>69</y> + <width>64</width> + <height>23</height> + </rect> + </property> + <property name="text" > + <string>1</string> + </property> + </widget> + <widget class="QDoubleSpinBox" name="spinBox1" > + <property name="geometry" > + <rect> + <x>279</x> + <y>69</y> + <width>73</width> + <height>23</height> + </rect> + </property> + <property name="keyboardTracking" > + <bool>false</bool> + </property> + <property name="decimals" > + <number>3</number> + </property> + <property name="maximum" > + <double>1.000000000000000</double> + </property> + <property name="singleStep" > + <double>0.010000000000000</double> + </property> + </widget> + <widget class="QLabel" name="label2" > + <property name="geometry" > + <rect> + <x>209</x> + <y>99</y> + <width>64</width> + <height>23</height> + </rect> + </property> + <property name="text" > + <string>2</string> + </property> + </widget> + <widget class="QDoubleSpinBox" name="spinBox2" > + <property name="geometry" > + <rect> + <x>279</x> + <y>99</y> + <width>73</width> + <height>23</height> + </rect> + </property> + <property name="keyboardTracking" > + <bool>false</bool> + </property> + <property name="decimals" > + <number>3</number> + </property> + <property name="maximum" > + <double>1.000000000000000</double> + </property> + <property name="singleStep" > + <double>0.010000000000000</double> + </property> + </widget> + <widget class="QLabel" name="label3" > + <property name="geometry" > + <rect> + <x>209</x> + <y>129</y> + <width>64</width> + <height>23</height> + </rect> + </property> + <property name="text" > + <string>3</string> + </property> + </widget> + <widget class="QDoubleSpinBox" name="spinBox3" > + <property name="geometry" > + <rect> + <x>279</x> + <y>129</y> + <width>73</width> + <height>23</height> + </rect> + </property> + <property name="keyboardTracking" > + <bool>false</bool> + </property> + <property name="decimals" > + <number>3</number> + </property> + <property name="maximum" > + <double>1.000000000000000</double> + </property> + <property name="singleStep" > + <double>0.010000000000000</double> + </property> + </widget> + <widget class="QLabel" name="label4" > + <property name="geometry" > + <rect> + <x>209</x> + <y>159</y> + <width>64</width> + <height>23</height> + </rect> + </property> + <property name="text" > + <string>4</string> + </property> + </widget> + <widget class="QDoubleSpinBox" name="spinBox4" > + <property name="geometry" > + <rect> + <x>279</x> + <y>159</y> + <width>73</width> + <height>23</height> + </rect> + </property> + <property name="keyboardTracking" > + <bool>false</bool> + </property> + <property name="decimals" > + <number>3</number> + </property> + <property name="maximum" > + <double>1.000000000000000</double> + </property> + <property name="singleStep" > + <double>0.010000000000000</double> + </property> + </widget> + <widget class="QLabel" name="label5" > + <property name="geometry" > + <rect> + <x>209</x> + <y>189</y> + <width>64</width> + <height>23</height> + </rect> + </property> + <property name="text" > + <string>5</string> + </property> + </widget> + <widget class="QDoubleSpinBox" name="spinBox5" > + <property name="geometry" > + <rect> + <x>279</x> + <y>189</y> + <width>73</width> + <height>23</height> + </rect> + </property> + <property name="keyboardTracking" > + <bool>false</bool> + </property> + <property name="decimals" > + <number>3</number> + </property> + <property name="maximum" > + <double>1.000000000000000</double> + </property> + <property name="singleStep" > + <double>0.010000000000000</double> + </property> + </widget> + <widget class="QtGradientStopsWidget" native="1" name="gradientStopsWidget" > + <property name="geometry" > + <rect> + <x>10</x> + <y>225</y> + <width>193</width> + <height>67</height> + </rect> + </property> + <property name="toolTip" > + <string>Gradient Stops Editor</string> + </property> + <property name="whatsThis" > + <string>This area allows you to edit gradient stops. Double click on the existing stop handle to duplicate it. Double click outside of the existing stop handles to create a new stop. Drag & drop the handle to reposition it. Use right mouse button to popup context menu with extra actions.</string> + </property> + </widget> + <widget class="QLabel" name="zoomLabel" > + <property name="geometry" > + <rect> + <x>209</x> + <y>231</y> + <width>64</width> + <height>23</height> + </rect> + </property> + <property name="text" > + <string>Zoom</string> + </property> + </widget> + <widget class="QToolButton" name="zoomAllButton" > + <property name="geometry" > + <rect> + <x>279</x> + <y>260</y> + <width>72</width> + <height>26</height> + </rect> + </property> + <property name="sizePolicy" > + <sizepolicy vsizetype="Fixed" hsizetype="Preferred" > + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="toolTip" > + <string>Reset Zoom</string> + </property> + <property name="text" > + <string>Reset Zoom</string> + </property> + </widget> + <widget class="QLabel" name="positionLabel" > + <property name="geometry" > + <rect> + <x>209</x> + <y>304</y> + <width>64</width> + <height>23</height> + </rect> + </property> + <property name="text" > + <string>Position</string> + </property> + </widget> + <widget class="QLabel" name="hLabel" > + <property name="geometry" > + <rect> + <x>10</x> + <y>335</y> + <width>32</width> + <height>18</height> + </rect> + </property> + <property name="sizePolicy" > + <sizepolicy vsizetype="Fixed" hsizetype="Preferred" > + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="toolTip" > + <string>Hue</string> + </property> + <property name="text" > + <string>H</string> + </property> + </widget> + <widget class="QFrame" name="frame_2" > + <property name="geometry" > + <rect> + <x>48</x> + <y>333</y> + <width>155</width> + <height>23</height> + </rect> + </property> + <property name="sizePolicy" > + <sizepolicy vsizetype="Preferred" hsizetype="Ignored" > + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="frameShape" > + <enum>QFrame::StyledPanel</enum> + </property> + <property name="frameShadow" > + <enum>QFrame::Raised</enum> + </property> + <layout class="QHBoxLayout" > + <property name="leftMargin" > + <number>0</number> + </property> + <property name="topMargin" > + <number>0</number> + </property> + <property name="rightMargin" > + <number>0</number> + </property> + <property name="bottomMargin" > + <number>0</number> + </property> + <item> + <widget class="QtColorLine" native="1" name="hueColorLine" > + <property name="sizePolicy" > + <sizepolicy vsizetype="Preferred" hsizetype="Expanding" > + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="toolTip" > + <string>Hue</string> + </property> + </widget> + </item> + </layout> + </widget> + <widget class="QLabel" name="hueLabel" > + <property name="geometry" > + <rect> + <x>209</x> + <y>335</y> + <width>64</width> + <height>18</height> + </rect> + </property> + <property name="sizePolicy" > + <sizepolicy vsizetype="Fixed" hsizetype="Preferred" > + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text" > + <string>Hue</string> + </property> + </widget> + <widget class="QLabel" name="sLabel" > + <property name="geometry" > + <rect> + <x>10</x> + <y>364</y> + <width>32</width> + <height>18</height> + </rect> + </property> + <property name="sizePolicy" > + <sizepolicy vsizetype="Fixed" hsizetype="Preferred" > + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="toolTip" > + <string>Saturation</string> + </property> + <property name="text" > + <string>S</string> + </property> + </widget> + <widget class="QFrame" name="frame_5" > + <property name="geometry" > + <rect> + <x>48</x> + <y>362</y> + <width>155</width> + <height>23</height> + </rect> + </property> + <property name="sizePolicy" > + <sizepolicy vsizetype="Preferred" hsizetype="Ignored" > + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="frameShape" > + <enum>QFrame::StyledPanel</enum> + </property> + <property name="frameShadow" > + <enum>QFrame::Raised</enum> + </property> + <layout class="QHBoxLayout" > + <property name="leftMargin" > + <number>0</number> + </property> + <property name="topMargin" > + <number>0</number> + </property> + <property name="rightMargin" > + <number>0</number> + </property> + <property name="bottomMargin" > + <number>0</number> + </property> + <item> + <widget class="QtColorLine" native="1" name="saturationColorLine" > + <property name="sizePolicy" > + <sizepolicy vsizetype="Preferred" hsizetype="Expanding" > + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="toolTip" > + <string>Saturation</string> + </property> + </widget> + </item> + </layout> + </widget> + <widget class="QLabel" name="saturationLabel" > + <property name="geometry" > + <rect> + <x>209</x> + <y>364</y> + <width>64</width> + <height>18</height> + </rect> + </property> + <property name="sizePolicy" > + <sizepolicy vsizetype="Fixed" hsizetype="Preferred" > + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text" > + <string>Sat</string> + </property> + </widget> + <widget class="QLabel" name="vLabel" > + <property name="geometry" > + <rect> + <x>10</x> + <y>393</y> + <width>32</width> + <height>18</height> + </rect> + </property> + <property name="sizePolicy" > + <sizepolicy vsizetype="Fixed" hsizetype="Preferred" > + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="toolTip" > + <string>Value</string> + </property> + <property name="text" > + <string>V</string> + </property> + </widget> + <widget class="QFrame" name="frame_3" > + <property name="geometry" > + <rect> + <x>48</x> + <y>391</y> + <width>155</width> + <height>23</height> + </rect> + </property> + <property name="sizePolicy" > + <sizepolicy vsizetype="Preferred" hsizetype="Ignored" > + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="frameShape" > + <enum>QFrame::StyledPanel</enum> + </property> + <property name="frameShadow" > + <enum>QFrame::Raised</enum> + </property> + <layout class="QHBoxLayout" > + <property name="leftMargin" > + <number>0</number> + </property> + <property name="topMargin" > + <number>0</number> + </property> + <property name="rightMargin" > + <number>0</number> + </property> + <property name="bottomMargin" > + <number>0</number> + </property> + <item> + <widget class="QtColorLine" native="1" name="valueColorLine" > + <property name="sizePolicy" > + <sizepolicy vsizetype="Preferred" hsizetype="Expanding" > + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="toolTip" > + <string>Value</string> + </property> + </widget> + </item> + </layout> + </widget> + <widget class="QLabel" name="valueLabel" > + <property name="geometry" > + <rect> + <x>209</x> + <y>393</y> + <width>64</width> + <height>18</height> + </rect> + </property> + <property name="sizePolicy" > + <sizepolicy vsizetype="Fixed" hsizetype="Preferred" > + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text" > + <string>Val</string> + </property> + </widget> + <widget class="QLabel" name="aLabel" > + <property name="geometry" > + <rect> + <x>10</x> + <y>422</y> + <width>32</width> + <height>18</height> + </rect> + </property> + <property name="sizePolicy" > + <sizepolicy vsizetype="Fixed" hsizetype="Preferred" > + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="toolTip" > + <string>Alpha</string> + </property> + <property name="text" > + <string>A</string> + </property> + </widget> + <widget class="QFrame" name="frame_4" > + <property name="geometry" > + <rect> + <x>48</x> + <y>420</y> + <width>155</width> + <height>23</height> + </rect> + </property> + <property name="sizePolicy" > + <sizepolicy vsizetype="Preferred" hsizetype="Ignored" > + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="frameShape" > + <enum>QFrame::StyledPanel</enum> + </property> + <property name="frameShadow" > + <enum>QFrame::Raised</enum> + </property> + <layout class="QHBoxLayout" > + <property name="leftMargin" > + <number>0</number> + </property> + <property name="topMargin" > + <number>0</number> + </property> + <property name="rightMargin" > + <number>0</number> + </property> + <property name="bottomMargin" > + <number>0</number> + </property> + <item> + <widget class="QtColorLine" native="1" name="alphaColorLine" > + <property name="sizePolicy" > + <sizepolicy vsizetype="Preferred" hsizetype="Expanding" > + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="toolTip" > + <string>Alpha</string> + </property> + </widget> + </item> + </layout> + </widget> + <widget class="QLabel" name="alphaLabel" > + <property name="geometry" > + <rect> + <x>209</x> + <y>422</y> + <width>64</width> + <height>18</height> + </rect> + </property> + <property name="sizePolicy" > + <sizepolicy vsizetype="Fixed" hsizetype="Preferred" > + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text" > + <string>Alpha</string> + </property> + </widget> + <widget class="QComboBox" name="typeComboBox" > + <property name="geometry" > + <rect> + <x>10</x> + <y>40</y> + <width>79</width> + <height>22</height> + </rect> + </property> + <property name="toolTip" > + <string>Type</string> + </property> + </widget> + <widget class="QComboBox" name="spreadComboBox" > + <property name="geometry" > + <rect> + <x>96</x> + <y>40</y> + <width>72</width> + <height>22</height> + </rect> + </property> + <property name="toolTip" > + <string>Spread</string> + </property> + </widget> + <widget class="QLabel" name="colorLabel" > + <property name="geometry" > + <rect> + <x>10</x> + <y>298</y> + <width>32</width> + <height>29</height> + </rect> + </property> + <property name="sizePolicy" > + <sizepolicy vsizetype="Preferred" hsizetype="Fixed" > + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text" > + <string>Color</string> + </property> + </widget> + <widget class="QtColorButton" name="colorButton" > + <property name="geometry" > + <rect> + <x>48</x> + <y>300</y> + <width>26</width> + <height>25</height> + </rect> + </property> + <property name="toolTip" > + <string>Current stop's color</string> + </property> + <property name="text" > + <string/> + </property> + </widget> + <widget class="QRadioButton" name="hsvRadioButton" > + <property name="geometry" > + <rect> + <x>80</x> + <y>301</y> + <width>49</width> + <height>23</height> + </rect> + </property> + <property name="sizePolicy" > + <sizepolicy vsizetype="Fixed" hsizetype="Fixed" > + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="toolTip" > + <string>Show HSV specification</string> + </property> + <property name="text" > + <string>HSV</string> + </property> + <property name="checked" > + <bool>true</bool> + </property> + </widget> + <widget class="QRadioButton" name="rgbRadioButton" > + <property name="geometry" > + <rect> + <x>135</x> + <y>301</y> + <width>49</width> + <height>23</height> + </rect> + </property> + <property name="sizePolicy" > + <sizepolicy vsizetype="Fixed" hsizetype="Fixed" > + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="toolTip" > + <string>Show RGB specification</string> + </property> + <property name="text" > + <string>RGB</string> + </property> + </widget> + <widget class="QWidget" native="1" name="positionWidget" > + <property name="geometry" > + <rect> + <x>279</x> + <y>304</y> + <width>73</width> + <height>23</height> + </rect> + </property> + <layout class="QVBoxLayout" > + <property name="leftMargin" > + <number>0</number> + </property> + <property name="topMargin" > + <number>0</number> + </property> + <property name="rightMargin" > + <number>0</number> + </property> + <property name="bottomMargin" > + <number>0</number> + </property> + <item> + <widget class="QDoubleSpinBox" name="positionSpinBox" > + <property name="toolTip" > + <string>Current stop's position</string> + </property> + <property name="keyboardTracking" > + <bool>false</bool> + </property> + <property name="decimals" > + <number>3</number> + </property> + <property name="minimum" > + <double>0.000000000000000</double> + </property> + <property name="maximum" > + <double>1.000000000000000</double> + </property> + <property name="singleStep" > + <double>0.010000000000000</double> + </property> + <property name="value" > + <double>0.000000000000000</double> + </property> + </widget> + </item> + </layout> + </widget> + <widget class="QWidget" native="1" name="hueWidget" > + <property name="geometry" > + <rect> + <x>279</x> + <y>333</y> + <width>73</width> + <height>23</height> + </rect> + </property> + <layout class="QVBoxLayout" > + <property name="leftMargin" > + <number>0</number> + </property> + <property name="topMargin" > + <number>0</number> + </property> + <property name="rightMargin" > + <number>0</number> + </property> + <property name="bottomMargin" > + <number>0</number> + </property> + <item> + <widget class="QSpinBox" name="hueSpinBox" > + <property name="keyboardTracking" > + <bool>false</bool> + </property> + <property name="maximum" > + <number>359</number> + </property> + </widget> + </item> + </layout> + </widget> + <widget class="QWidget" native="1" name="saturationWidget" > + <property name="geometry" > + <rect> + <x>279</x> + <y>362</y> + <width>73</width> + <height>23</height> + </rect> + </property> + <layout class="QVBoxLayout" > + <property name="leftMargin" > + <number>0</number> + </property> + <property name="topMargin" > + <number>0</number> + </property> + <property name="rightMargin" > + <number>0</number> + </property> + <property name="bottomMargin" > + <number>0</number> + </property> + <item> + <widget class="QSpinBox" name="saturationSpinBox" > + <property name="keyboardTracking" > + <bool>false</bool> + </property> + <property name="maximum" > + <number>255</number> + </property> + </widget> + </item> + </layout> + </widget> + <widget class="QWidget" native="1" name="valueWidget" > + <property name="geometry" > + <rect> + <x>279</x> + <y>391</y> + <width>73</width> + <height>23</height> + </rect> + </property> + <layout class="QVBoxLayout" > + <property name="leftMargin" > + <number>0</number> + </property> + <property name="topMargin" > + <number>0</number> + </property> + <property name="rightMargin" > + <number>0</number> + </property> + <property name="bottomMargin" > + <number>0</number> + </property> + <item> + <widget class="QSpinBox" name="valueSpinBox" > + <property name="keyboardTracking" > + <bool>false</bool> + </property> + <property name="maximum" > + <number>255</number> + </property> + </widget> + </item> + </layout> + </widget> + <widget class="QWidget" native="1" name="alphaWidget" > + <property name="geometry" > + <rect> + <x>279</x> + <y>420</y> + <width>73</width> + <height>23</height> + </rect> + </property> + <layout class="QVBoxLayout" > + <property name="leftMargin" > + <number>0</number> + </property> + <property name="topMargin" > + <number>0</number> + </property> + <property name="rightMargin" > + <number>0</number> + </property> + <property name="bottomMargin" > + <number>0</number> + </property> + <item> + <widget class="QSpinBox" name="alphaSpinBox" > + <property name="keyboardTracking" > + <bool>false</bool> + </property> + <property name="maximum" > + <number>255</number> + </property> + </widget> + </item> + </layout> + </widget> + <widget class="QWidget" native="1" name="zoomWidget" > + <property name="geometry" > + <rect> + <x>279</x> + <y>231</y> + <width>73</width> + <height>23</height> + </rect> + </property> + <layout class="QVBoxLayout" > + <property name="leftMargin" > + <number>0</number> + </property> + <property name="topMargin" > + <number>0</number> + </property> + <property name="rightMargin" > + <number>0</number> + </property> + <property name="bottomMargin" > + <number>0</number> + </property> + <item> + <widget class="QSpinBox" name="zoomSpinBox" > + <property name="keyboardTracking" > + <bool>false</bool> + </property> + <property name="suffix" > + <string>%</string> + </property> + <property name="minimum" > + <number>100</number> + </property> + <property name="maximum" > + <number>10000</number> + </property> + <property name="singleStep" > + <number>100</number> + </property> + <property name="value" > + <number>100</number> + </property> + </widget> + </item> + </layout> + </widget> + <widget class="QWidget" native="1" name="line1Widget" > + <property name="geometry" > + <rect> + <x>209</x> + <y>219</y> + <width>143</width> + <height>16</height> + </rect> + </property> + <layout class="QVBoxLayout" > + <property name="leftMargin" > + <number>0</number> + </property> + <property name="topMargin" > + <number>0</number> + </property> + <property name="rightMargin" > + <number>0</number> + </property> + <property name="bottomMargin" > + <number>0</number> + </property> + <item> + <widget class="Line" name="line1" > + <property name="orientation" > + <enum>Qt::Horizontal</enum> + </property> + </widget> + </item> + </layout> + </widget> + <widget class="QWidget" native="1" name="line2Widget" > + <property name="geometry" > + <rect> + <x>209</x> + <y>292</y> + <width>143</width> + <height>16</height> + </rect> + </property> + <layout class="QVBoxLayout" > + <property name="leftMargin" > + <number>0</number> + </property> + <property name="topMargin" > + <number>0</number> + </property> + <property name="rightMargin" > + <number>0</number> + </property> + <property name="bottomMargin" > + <number>0</number> + </property> + <item> + <widget class="Line" name="line2" > + <property name="orientation" > + <enum>Qt::Horizontal</enum> + </property> + </widget> + </item> + </layout> + </widget> + <widget class="QWidget" native="1" name="zoomButtonsWidget" > + <property name="geometry" > + <rect> + <x>209</x> + <y>260</y> + <width>64</width> + <height>26</height> + </rect> + </property> + <property name="sizePolicy" > + <sizepolicy vsizetype="Preferred" hsizetype="Maximum" > + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <layout class="QHBoxLayout" > + <property name="leftMargin" > + <number>0</number> + </property> + <property name="topMargin" > + <number>0</number> + </property> + <property name="rightMargin" > + <number>0</number> + </property> + <property name="bottomMargin" > + <number>0</number> + </property> + <item> + <widget class="QToolButton" name="zoomInButton" > + <property name="toolTip" > + <string>Zoom In</string> + </property> + </widget> + </item> + <item> + <widget class="QToolButton" name="zoomOutButton" > + <property name="toolTip" > + <string>Zoom Out</string> + </property> + </widget> + </item> + <item> + <spacer> + <property name="orientation" > + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" > + <size> + <width>0</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + </layout> + </widget> + <widget class="QToolButton" name="detailsButton" > + <property name="geometry" > + <rect> + <x>176</x> + <y>40</y> + <width>25</width> + <height>22</height> + </rect> + </property> + <property name="sizePolicy" > + <sizepolicy vsizetype="Ignored" hsizetype="Fixed" > + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="toolTip" > + <string>Toggle details extension</string> + </property> + <property name="text" > + <string>></string> + </property> + <property name="checkable" > + <bool>true</bool> + </property> + <property name="autoRaise" > + <bool>true</bool> + </property> + </widget> + <widget class="QToolButton" name="linearButton" > + <property name="geometry" > + <rect> + <x>10</x> + <y>10</y> + <width>30</width> + <height>26</height> + </rect> + </property> + <property name="toolTip" > + <string>Linear Type</string> + </property> + <property name="text" > + <string>...</string> + </property> + <property name="checkable" > + <bool>true</bool> + </property> + <property name="autoRaise" > + <bool>true</bool> + </property> + </widget> + <widget class="QToolButton" name="radialButton" > + <property name="geometry" > + <rect> + <x>40</x> + <y>10</y> + <width>30</width> + <height>26</height> + </rect> + </property> + <property name="toolTip" > + <string>Radial Type</string> + </property> + <property name="text" > + <string>...</string> + </property> + <property name="checkable" > + <bool>true</bool> + </property> + <property name="autoRaise" > + <bool>true</bool> + </property> + </widget> + <widget class="QToolButton" name="conicalButton" > + <property name="geometry" > + <rect> + <x>70</x> + <y>10</y> + <width>30</width> + <height>26</height> + </rect> + </property> + <property name="toolTip" > + <string>Conical Type</string> + </property> + <property name="text" > + <string>...</string> + </property> + <property name="checkable" > + <bool>true</bool> + </property> + <property name="autoRaise" > + <bool>true</bool> + </property> + </widget> + <widget class="QToolButton" name="padButton" > + <property name="geometry" > + <rect> + <x>110</x> + <y>10</y> + <width>30</width> + <height>26</height> + </rect> + </property> + <property name="toolTip" > + <string>Pad Spread</string> + </property> + <property name="text" > + <string>...</string> + </property> + <property name="checkable" > + <bool>true</bool> + </property> + <property name="autoRaise" > + <bool>true</bool> + </property> + </widget> + <widget class="QToolButton" name="repeatButton" > + <property name="geometry" > + <rect> + <x>140</x> + <y>10</y> + <width>30</width> + <height>26</height> + </rect> + </property> + <property name="toolTip" > + <string>Repeat Spread</string> + </property> + <property name="text" > + <string>...</string> + </property> + <property name="checkable" > + <bool>true</bool> + </property> + <property name="autoRaise" > + <bool>true</bool> + </property> + </widget> + <widget class="QToolButton" name="reflectButton" > + <property name="geometry" > + <rect> + <x>170</x> + <y>10</y> + <width>30</width> + <height>26</height> + </rect> + </property> + <property name="toolTip" > + <string>Reflect Spread</string> + </property> + <property name="text" > + <string>...</string> + </property> + <property name="checkable" > + <bool>true</bool> + </property> + <property name="autoRaise" > + <bool>true</bool> + </property> + </widget> + </widget> + <customwidgets> + <customwidget> + <class>QtColorButton</class> + <extends>QToolButton</extends> + <header>qtcolorbutton.h</header> + </customwidget> + <customwidget> + <class>QtColorLine</class> + <extends>QWidget</extends> + <header>qtcolorline.h</header> + <container>1</container> + </customwidget> + <customwidget> + <class>QtGradientStopsWidget</class> + <extends>QWidget</extends> + <header>qtgradientstopswidget.h</header> + <container>1</container> + </customwidget> + <customwidget> + <class>QtGradientWidget</class> + <extends>QWidget</extends> + <header>qtgradientwidget.h</header> + <container>1</container> + </customwidget> + </customwidgets> + <tabstops> + <tabstop>typeComboBox</tabstop> + <tabstop>spreadComboBox</tabstop> + <tabstop>detailsButton</tabstop> + <tabstop>spinBox1</tabstop> + <tabstop>spinBox2</tabstop> + <tabstop>spinBox3</tabstop> + <tabstop>spinBox4</tabstop> + <tabstop>spinBox5</tabstop> + <tabstop>zoomSpinBox</tabstop> + <tabstop>zoomInButton</tabstop> + <tabstop>zoomOutButton</tabstop> + <tabstop>zoomAllButton</tabstop> + <tabstop>colorButton</tabstop> + <tabstop>hsvRadioButton</tabstop> + <tabstop>rgbRadioButton</tabstop> + <tabstop>positionSpinBox</tabstop> + <tabstop>hueSpinBox</tabstop> + <tabstop>saturationSpinBox</tabstop> + <tabstop>valueSpinBox</tabstop> + <tabstop>alphaSpinBox</tabstop> + </tabstops> + <resources/> + <connections/> +</ui> diff --git a/tools/shared/qtgradienteditor/qtgradientmanager.cpp b/tools/shared/qtgradienteditor/qtgradientmanager.cpp new file mode 100644 index 0000000..51b5d96 --- /dev/null +++ b/tools/shared/qtgradienteditor/qtgradientmanager.cpp @@ -0,0 +1,135 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the tools applications of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qtgradientmanager.h" +#include <QtGui/QPixmap> +#include <QtCore/QMetaEnum> + +QT_BEGIN_NAMESPACE + +QtGradientManager::QtGradientManager(QObject *parent) + : QObject(parent) +{ +} + +QMap<QString, QGradient> QtGradientManager::gradients() const +{ + return m_idToGradient; +} + +QString QtGradientManager::uniqueId(const QString &id) const +{ + if (!m_idToGradient.contains(id)) + return id; + + QString base = id; + while (base.count() > 0 && base.at(base.count() - 1).isDigit()) + base = base.left(base.count() - 1); + QString newId = base; + int counter = 0; + while (m_idToGradient.contains(newId)) { + ++counter; + newId = base + QString::number(counter); + } + return newId; +} + +QString QtGradientManager::addGradient(const QString &id, const QGradient &gradient) +{ + QString newId = uniqueId(id); + + m_idToGradient[newId] = gradient; + + emit gradientAdded(newId, gradient); + + return newId; +} + +void QtGradientManager::removeGradient(const QString &id) +{ + if (!m_idToGradient.contains(id)) + return; + + emit gradientRemoved(id); + + m_idToGradient.remove(id); +} + +void QtGradientManager::renameGradient(const QString &id, const QString &newId) +{ + if (!m_idToGradient.contains(id)) + return; + + if (newId == id) + return; + + QString changedId = uniqueId(newId); + QGradient gradient = m_idToGradient.value(id); + + emit gradientRenamed(id, changedId); + + m_idToGradient.remove(id); + m_idToGradient[changedId] = gradient; +} + +void QtGradientManager::changeGradient(const QString &id, const QGradient &newGradient) +{ + if (!m_idToGradient.contains(id)) + return; + + if (m_idToGradient.value(id) == newGradient) + return; + + emit gradientChanged(id, newGradient); + + m_idToGradient[id] = newGradient; +} + +void QtGradientManager::clear() +{ + QMap<QString, QGradient> grads = gradients(); + QMapIterator<QString, QGradient> itGrad(grads); + while (itGrad.hasNext()) { + removeGradient(itGrad.next().key()); + } +} + +QT_END_NAMESPACE diff --git a/tools/shared/qtgradienteditor/qtgradientmanager.h b/tools/shared/qtgradienteditor/qtgradientmanager.h new file mode 100644 index 0000000..ff9ebf7 --- /dev/null +++ b/tools/shared/qtgradienteditor/qtgradientmanager.h @@ -0,0 +1,92 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the tools applications of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef GRADIENTMANAGER_H +#define GRADIENTMANAGER_H + +#include <QtCore/QObject> +#include <QtCore/QMap> +#include <QtCore/QSize> +#include <QtXml/QDomDocument> +#include <QtXml/QDomElement> +#include <QtGui/QGradient> + +QT_BEGIN_NAMESPACE + +class QGradient; +class QPixmap; +class QColor; + +class QtGradientManager : public QObject +{ + Q_OBJECT +public: + QtGradientManager(QObject *parent = 0); + + QMap<QString, QGradient> gradients() const; + + QString uniqueId(const QString &id) const; + +public slots: + + QString addGradient(const QString &id, const QGradient &gradient); + void renameGradient(const QString &id, const QString &newId); + void changeGradient(const QString &id, const QGradient &newGradient); + void removeGradient(const QString &id); + + //utils + void clear(); + +signals: + + void gradientAdded(const QString &id, const QGradient &gradient); + void gradientRenamed(const QString &id, const QString &newId); + void gradientChanged(const QString &id, const QGradient &newGradient); + void gradientRemoved(const QString &id); + +private: + + QMap<QString, QGradient> m_idToGradient; +}; + +QT_END_NAMESPACE + +#endif diff --git a/tools/shared/qtgradienteditor/qtgradientstopscontroller.cpp b/tools/shared/qtgradienteditor/qtgradientstopscontroller.cpp new file mode 100644 index 0000000..cbc53db --- /dev/null +++ b/tools/shared/qtgradienteditor/qtgradientstopscontroller.cpp @@ -0,0 +1,730 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the tools applications of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/* +TRANSLATOR qdesigner_internal::QtGradientStopsController +*/ + +#include "qtgradientstopscontroller.h" +#include "ui_qtgradienteditor.h" +#include "qtgradientstopsmodel.h" + +#include <QtCore/QTimer> + +QT_BEGIN_NAMESPACE + +class QtGradientStopsControllerPrivate +{ + QtGradientStopsController *q_ptr; + Q_DECLARE_PUBLIC(QtGradientStopsController) +public: + typedef QMap<qreal, QColor> PositionColorMap; + typedef QMap<qreal, QtGradientStop *> PositionStopMap; + + void slotHsvClicked(); + void slotRgbClicked(); + + void slotCurrentStopChanged(QtGradientStop *stop); + void slotStopMoved(QtGradientStop *stop, qreal newPos); + void slotStopsSwapped(QtGradientStop *stop1, QtGradientStop *stop2); + void slotStopChanged(QtGradientStop *stop, const QColor &newColor); + void slotStopSelected(QtGradientStop *stop, bool selected); + void slotStopAdded(QtGradientStop *stop); + void slotStopRemoved(QtGradientStop *stop); + void slotUpdatePositionSpinBox(); + + void slotChangeColor(const QColor &color); + void slotChangeHue(const QColor &color); + void slotChangeSaturation(const QColor &color); + void slotChangeValue(const QColor &color); + void slotChangeAlpha(const QColor &color); + void slotChangeHue(int color); + void slotChangeSaturation(int color); + void slotChangeValue(int color); + void slotChangeAlpha(int color); + void slotChangePosition(double value); + + void slotChangeZoom(int value); + void slotZoomIn(); + void slotZoomOut(); + void slotZoomAll(); + void slotZoomChanged(double zoom); + + void enableCurrent(bool enable); + void setColorSpinBoxes(const QColor &color); + PositionColorMap stopsData(const PositionStopMap &stops) const; + QGradientStops makeGradientStops(const PositionColorMap &data) const; + void updateZoom(double zoom); + + QtGradientStopsModel *m_model; + QColor::Spec m_spec; + + Ui::QtGradientEditor *m_ui; +}; + +void QtGradientStopsControllerPrivate::enableCurrent(bool enable) +{ + m_ui->positionLabel->setEnabled(enable); + m_ui->colorLabel->setEnabled(enable); + m_ui->hLabel->setEnabled(enable); + m_ui->sLabel->setEnabled(enable); + m_ui->vLabel->setEnabled(enable); + m_ui->aLabel->setEnabled(enable); + m_ui->hueLabel->setEnabled(enable); + m_ui->saturationLabel->setEnabled(enable); + m_ui->valueLabel->setEnabled(enable); + m_ui->alphaLabel->setEnabled(enable); + + m_ui->positionSpinBox->setEnabled(enable); + m_ui->colorButton->setEnabled(enable); + + m_ui->hueColorLine->setEnabled(enable); + m_ui->saturationColorLine->setEnabled(enable); + m_ui->valueColorLine->setEnabled(enable); + m_ui->alphaColorLine->setEnabled(enable); + + m_ui->hueSpinBox->setEnabled(enable); + m_ui->saturationSpinBox->setEnabled(enable); + m_ui->valueSpinBox->setEnabled(enable); + m_ui->alphaSpinBox->setEnabled(enable); +} + +QtGradientStopsControllerPrivate::PositionColorMap QtGradientStopsControllerPrivate::stopsData(const PositionStopMap &stops) const +{ + PositionColorMap data; + PositionStopMap::ConstIterator itStop = stops.constBegin(); + while (itStop != stops.constEnd()) { + QtGradientStop *stop = itStop.value(); + data[stop->position()] = stop->color(); + + ++itStop; + } + return data; +} + +QGradientStops QtGradientStopsControllerPrivate::makeGradientStops(const PositionColorMap &data) const +{ + QGradientStops stops; + PositionColorMap::ConstIterator itData = data.constBegin(); + while (itData != data.constEnd()) { + stops << QPair<qreal, QColor>(itData.key(), itData.value()); + + ++itData; + } + return stops; +} + +void QtGradientStopsControllerPrivate::updateZoom(double zoom) +{ + m_ui->gradientStopsWidget->setZoom(zoom); + m_ui->zoomSpinBox->blockSignals(true); + m_ui->zoomSpinBox->setValue(qRound(zoom * 100)); + m_ui->zoomSpinBox->blockSignals(false); + bool zoomInEnabled = true; + bool zoomOutEnabled = true; + bool zoomAllEnabled = true; + if (zoom <= 1) { + zoomAllEnabled = false; + zoomOutEnabled = false; + } else if (zoom >= 100) { + zoomInEnabled = false; + } + m_ui->zoomInButton->setEnabled(zoomInEnabled); + m_ui->zoomOutButton->setEnabled(zoomOutEnabled); + m_ui->zoomAllButton->setEnabled(zoomAllEnabled); +} + +void QtGradientStopsControllerPrivate::slotHsvClicked() +{ + QString h = QApplication::translate("qdesigner_internal::QtGradientStopsController", "H", 0, QApplication::UnicodeUTF8); + QString s = QApplication::translate("qdesigner_internal::QtGradientStopsController", "S", 0, QApplication::UnicodeUTF8); + QString v = QApplication::translate("qdesigner_internal::QtGradientStopsController", "V", 0, QApplication::UnicodeUTF8); + + m_ui->hLabel->setText(h); + m_ui->sLabel->setText(s); + m_ui->vLabel->setText(v); + + h = QApplication::translate("qdesigner_internal::QtGradientStopsController", "Hue", 0, QApplication::UnicodeUTF8); + s = QApplication::translate("qdesigner_internal::QtGradientStopsController", "Sat", 0, QApplication::UnicodeUTF8); + v = QApplication::translate("qdesigner_internal::QtGradientStopsController", "Val", 0, QApplication::UnicodeUTF8); + + const QString hue = QApplication::translate("qdesigner_internal::QtGradientStopsController", "Hue", 0, QApplication::UnicodeUTF8); + const QString saturation = QApplication::translate("qdesigner_internal::QtGradientStopsController", "Saturation", 0, QApplication::UnicodeUTF8); + const QString value = QApplication::translate("qdesigner_internal::QtGradientStopsController", "Value", 0, QApplication::UnicodeUTF8); + + m_ui->hLabel->setToolTip(hue); + m_ui->hueLabel->setText(h); + m_ui->hueColorLine->setToolTip(hue); + m_ui->hueColorLine->setColorComponent(QtColorLine::Hue); + + m_ui->sLabel->setToolTip(saturation); + m_ui->saturationLabel->setText(s); + m_ui->saturationColorLine->setToolTip(saturation); + m_ui->saturationColorLine->setColorComponent(QtColorLine::Saturation); + + m_ui->vLabel->setToolTip(value); + m_ui->valueLabel->setText(v); + m_ui->valueColorLine->setToolTip(value); + m_ui->valueColorLine->setColorComponent(QtColorLine::Value); + + setColorSpinBoxes(m_ui->colorButton->color()); +} + +void QtGradientStopsControllerPrivate::slotRgbClicked() +{ + QString r = QApplication::translate("qdesigner_internal::QtGradientStopsController", "R", 0, QApplication::UnicodeUTF8); + QString g = QApplication::translate("qdesigner_internal::QtGradientStopsController", "G", 0, QApplication::UnicodeUTF8); + QString b = QApplication::translate("qdesigner_internal::QtGradientStopsController", "B", 0, QApplication::UnicodeUTF8); + + m_ui->hLabel->setText(r); + m_ui->sLabel->setText(g); + m_ui->vLabel->setText(b); + + QString red = QApplication::translate("qdesigner_internal::QtGradientStopsController", "Red", 0, QApplication::UnicodeUTF8); + QString green = QApplication::translate("qdesigner_internal::QtGradientStopsController", "Green", 0, QApplication::UnicodeUTF8); + QString blue = QApplication::translate("qdesigner_internal::QtGradientStopsController", "Blue", 0, QApplication::UnicodeUTF8); + + m_ui->hLabel->setToolTip(red); + m_ui->hueLabel->setText(red); + m_ui->hueColorLine->setToolTip(red); + m_ui->hueColorLine->setColorComponent(QtColorLine::Red); + + m_ui->sLabel->setToolTip(green); + m_ui->saturationLabel->setText(green); + m_ui->saturationColorLine->setToolTip(green); + m_ui->saturationColorLine->setColorComponent(QtColorLine::Green); + + m_ui->vLabel->setToolTip(blue); + m_ui->valueLabel->setText(blue); + m_ui->valueColorLine->setToolTip(blue); + m_ui->valueColorLine->setColorComponent(QtColorLine::Blue); + + setColorSpinBoxes(m_ui->colorButton->color()); +} + +void QtGradientStopsControllerPrivate::setColorSpinBoxes(const QColor &color) +{ + m_ui->hueSpinBox->blockSignals(true); + m_ui->saturationSpinBox->blockSignals(true); + m_ui->valueSpinBox->blockSignals(true); + m_ui->alphaSpinBox->blockSignals(true); + if (m_ui->hsvRadioButton->isChecked()) { + if (m_ui->hueSpinBox->maximum() != 359) + m_ui->hueSpinBox->setMaximum(359); + if (m_ui->hueSpinBox->value() != color.hue()) + m_ui->hueSpinBox->setValue(color.hue()); + if (m_ui->saturationSpinBox->value() != color.saturation()) + m_ui->saturationSpinBox->setValue(color.saturation()); + if (m_ui->valueSpinBox->value() != color.value()) + m_ui->valueSpinBox->setValue(color.value()); + } else { + if (m_ui->hueSpinBox->maximum() != 255) + m_ui->hueSpinBox->setMaximum(255); + if (m_ui->hueSpinBox->value() != color.red()) + m_ui->hueSpinBox->setValue(color.red()); + if (m_ui->saturationSpinBox->value() != color.green()) + m_ui->saturationSpinBox->setValue(color.green()); + if (m_ui->valueSpinBox->value() != color.blue()) + m_ui->valueSpinBox->setValue(color.blue()); + } + m_ui->alphaSpinBox->setValue(color.alpha()); + m_ui->hueSpinBox->blockSignals(false); + m_ui->saturationSpinBox->blockSignals(false); + m_ui->valueSpinBox->blockSignals(false); + m_ui->alphaSpinBox->blockSignals(false); +} + +void QtGradientStopsControllerPrivate::slotCurrentStopChanged(QtGradientStop *stop) +{ + if (!stop) { + enableCurrent(false); + return; + } + enableCurrent(true); + + QTimer::singleShot(0, q_ptr, SLOT(slotUpdatePositionSpinBox())); + + m_ui->colorButton->setColor(stop->color()); + m_ui->hueColorLine->setColor(stop->color()); + m_ui->saturationColorLine->setColor(stop->color()); + m_ui->valueColorLine->setColor(stop->color()); + m_ui->alphaColorLine->setColor(stop->color()); + setColorSpinBoxes(stop->color()); +} + +void QtGradientStopsControllerPrivate::slotStopMoved(QtGradientStop *stop, qreal newPos) +{ + QTimer::singleShot(0, q_ptr, SLOT(slotUpdatePositionSpinBox())); + + PositionColorMap stops = stopsData(m_model->stops()); + stops.remove(stop->position()); + stops[newPos] = stop->color(); + + QGradientStops gradStops = makeGradientStops(stops); + emit q_ptr->gradientStopsChanged(gradStops); +} + +void QtGradientStopsControllerPrivate::slotStopsSwapped(QtGradientStop *stop1, QtGradientStop *stop2) +{ + QTimer::singleShot(0, q_ptr, SLOT(slotUpdatePositionSpinBox())); + + PositionColorMap stops = stopsData(m_model->stops()); + const qreal pos1 = stop1->position(); + const qreal pos2 = stop2->position(); + stops[pos1] = stop2->color(); + stops[pos2] = stop1->color(); + + QGradientStops gradStops = makeGradientStops(stops); + emit q_ptr->gradientStopsChanged(gradStops); +} + +void QtGradientStopsControllerPrivate::slotStopAdded(QtGradientStop *stop) +{ + PositionColorMap stops = stopsData(m_model->stops()); + stops[stop->position()] = stop->color(); + + QGradientStops gradStops = makeGradientStops(stops); + emit q_ptr->gradientStopsChanged(gradStops); +} + +void QtGradientStopsControllerPrivate::slotStopRemoved(QtGradientStop *stop) +{ + PositionColorMap stops = stopsData(m_model->stops()); + stops.remove(stop->position()); + + QGradientStops gradStops = makeGradientStops(stops); + emit q_ptr->gradientStopsChanged(gradStops); +} + +void QtGradientStopsControllerPrivate::slotStopChanged(QtGradientStop *stop, const QColor &newColor) +{ + if (m_model->currentStop() == stop) { + m_ui->colorButton->setColor(newColor); + m_ui->hueColorLine->setColor(newColor); + m_ui->saturationColorLine->setColor(newColor); + m_ui->valueColorLine->setColor(newColor); + m_ui->alphaColorLine->setColor(newColor); + setColorSpinBoxes(newColor); + } + + PositionColorMap stops = stopsData(m_model->stops()); + stops[stop->position()] = newColor; + + QGradientStops gradStops = makeGradientStops(stops); + emit q_ptr->gradientStopsChanged(gradStops); +} + +void QtGradientStopsControllerPrivate::slotStopSelected(QtGradientStop *stop, bool selected) +{ + Q_UNUSED(stop) + Q_UNUSED(selected) + QTimer::singleShot(0, q_ptr, SLOT(slotUpdatePositionSpinBox())); +} + +void QtGradientStopsControllerPrivate::slotUpdatePositionSpinBox() +{ + QtGradientStop *current = m_model->currentStop(); + if (!current) + return; + + qreal min = 0.0; + qreal max = 1.0; + const qreal pos = current->position(); + + QtGradientStop *first = m_model->firstSelected(); + QtGradientStop *last = m_model->lastSelected(); + + if (first && last) { + const qreal minPos = pos - first->position() - 0.0004999; + const qreal maxPos = pos + 1.0 - last->position() + 0.0004999; + + if (max > maxPos) + max = maxPos; + if (min < minPos) + min = minPos; + + if (first->position() == 0.0) + min = pos; + if (last->position() == 1.0) + max = pos; + } + + const int spinMin = qRound(m_ui->positionSpinBox->minimum() * 1000); + const int spinMax = qRound(m_ui->positionSpinBox->maximum() * 1000); + + const int newMin = qRound(min * 1000); + const int newMax = qRound(max * 1000); + + m_ui->positionSpinBox->blockSignals(true); + if (spinMin != newMin || spinMax != newMax) { + m_ui->positionSpinBox->setRange((double)newMin / 1000, (double)newMax / 1000); + } + if (m_ui->positionSpinBox->value() != pos) + m_ui->positionSpinBox->setValue(pos); + m_ui->positionSpinBox->blockSignals(false); +} + +void QtGradientStopsControllerPrivate::slotChangeColor(const QColor &color) +{ + QtGradientStop *stop = m_model->currentStop(); + if (!stop) + return; + m_model->changeStop(stop, color); + QList<QtGradientStop *> stops = m_model->selectedStops(); + QListIterator<QtGradientStop *> itStop(stops); + while (itStop.hasNext()) { + QtGradientStop *s = itStop.next(); + if (s != stop) + m_model->changeStop(s, color); + } +} + +void QtGradientStopsControllerPrivate::slotChangeHue(const QColor &color) +{ + QtGradientStop *stop = m_model->currentStop(); + if (!stop) + return; + m_model->changeStop(stop, color); + QList<QtGradientStop *> stops = m_model->selectedStops(); + QListIterator<QtGradientStop *> itStop(stops); + while (itStop.hasNext()) { + QtGradientStop *s = itStop.next(); + if (s != stop) { + QColor c = s->color(); + if (m_ui->hsvRadioButton->isChecked()) + c.setHsvF(color.hueF(), c.saturationF(), c.valueF(), c.alphaF()); + else + c.setRgbF(color.redF(), c.greenF(), c.blueF(), c.alphaF()); + m_model->changeStop(s, c); + } + } +} + +void QtGradientStopsControllerPrivate::slotChangeHue(int color) +{ + QColor c = m_ui->hueColorLine->color(); + if (m_ui->hsvRadioButton->isChecked()) + c.setHsvF((qreal)color / 360.0, c.saturationF(), c.valueF(), c.alphaF()); + else + c.setRed(color); + slotChangeHue(c); +} + +void QtGradientStopsControllerPrivate::slotChangeSaturation(const QColor &color) +{ + QtGradientStop *stop = m_model->currentStop(); + if (!stop) + return; + m_model->changeStop(stop, color); + QList<QtGradientStop *> stops = m_model->selectedStops(); + QListIterator<QtGradientStop *> itStop(stops); + while (itStop.hasNext()) { + QtGradientStop *s = itStop.next(); + if (s != stop) { + QColor c = s->color(); + if (m_ui->hsvRadioButton->isChecked()) { + c.setHsvF(c.hueF(), color.saturationF(), c.valueF(), c.alphaF()); + int hue = c.hue(); + if (hue == 360 || hue == -1) + c.setHsvF(0.0, c.saturationF(), c.valueF(), c.alphaF()); + } else { + c.setRgbF(c.redF(), color.greenF(), c.blueF(), c.alphaF()); + } + m_model->changeStop(s, c); + } + } +} + +void QtGradientStopsControllerPrivate::slotChangeSaturation(int color) +{ + QColor c = m_ui->saturationColorLine->color(); + if (m_ui->hsvRadioButton->isChecked()) + c.setHsvF(c.hueF(), (qreal)color / 255, c.valueF(), c.alphaF()); + else + c.setGreen(color); + slotChangeSaturation(c); +} + +void QtGradientStopsControllerPrivate::slotChangeValue(const QColor &color) +{ + QtGradientStop *stop = m_model->currentStop(); + if (!stop) + return; + m_model->changeStop(stop, color); + QList<QtGradientStop *> stops = m_model->selectedStops(); + QListIterator<QtGradientStop *> itStop(stops); + while (itStop.hasNext()) { + QtGradientStop *s = itStop.next(); + if (s != stop) { + QColor c = s->color(); + if (m_ui->hsvRadioButton->isChecked()) { + c.setHsvF(c.hueF(), c.saturationF(), color.valueF(), c.alphaF()); + int hue = c.hue(); + if (hue == 360 || hue == -1) + c.setHsvF(0.0, c.saturationF(), c.valueF(), c.alphaF()); + } else { + c.setRgbF(c.redF(), c.greenF(), color.blueF(), c.alphaF()); + } + m_model->changeStop(s, c); + } + } +} + +void QtGradientStopsControllerPrivate::slotChangeValue(int color) +{ + QColor c = m_ui->valueColorLine->color(); + if (m_ui->hsvRadioButton->isChecked()) + c.setHsvF(c.hueF(), c.saturationF(), (qreal)color / 255, c.alphaF()); + else + c.setBlue(color); + slotChangeValue(c); +} + +void QtGradientStopsControllerPrivate::slotChangeAlpha(const QColor &color) +{ + QtGradientStop *stop = m_model->currentStop(); + if (!stop) + return; + m_model->changeStop(stop, color); + QList<QtGradientStop *> stops = m_model->selectedStops(); + QListIterator<QtGradientStop *> itStop(stops); + while (itStop.hasNext()) { + QtGradientStop *s = itStop.next(); + if (s != stop) { + QColor c = s->color(); + if (m_ui->hsvRadioButton->isChecked()) { + c.setHsvF(c.hueF(), c.saturationF(), c.valueF(), color.alphaF()); + int hue = c.hue(); + if (hue == 360 || hue == -1) + c.setHsvF(0.0, c.saturationF(), c.valueF(), c.alphaF()); + } else { + c.setRgbF(c.redF(), c.greenF(), c.blueF(), color.alphaF()); + } + m_model->changeStop(s, c); + } + } +} + +void QtGradientStopsControllerPrivate::slotChangeAlpha(int color) +{ + QColor c = m_ui->alphaColorLine->color(); + if (m_ui->hsvRadioButton->isChecked()) + c.setHsvF(c.hueF(), c.saturationF(), c.valueF(), (qreal)color / 255); + else + c.setAlpha(color); + slotChangeAlpha(c); +} + +void QtGradientStopsControllerPrivate::slotChangePosition(double value) +{ + QtGradientStop *stop = m_model->currentStop(); + if (!stop) + return; + + m_model->moveStops(value); +} + +void QtGradientStopsControllerPrivate::slotChangeZoom(int value) +{ + updateZoom(value / 100.0); +} + +void QtGradientStopsControllerPrivate::slotZoomIn() +{ + double newZoom = m_ui->gradientStopsWidget->zoom() * 2; + if (newZoom > 100) + newZoom = 100; + updateZoom(newZoom); +} + +void QtGradientStopsControllerPrivate::slotZoomOut() +{ + double newZoom = m_ui->gradientStopsWidget->zoom() / 2; + if (newZoom < 1) + newZoom = 1; + updateZoom(newZoom); +} + +void QtGradientStopsControllerPrivate::slotZoomAll() +{ + updateZoom(1); +} + +void QtGradientStopsControllerPrivate::slotZoomChanged(double zoom) +{ + updateZoom(zoom); +} + +QtGradientStopsController::QtGradientStopsController(QObject *parent) + : QObject(parent) +{ + d_ptr = new QtGradientStopsControllerPrivate(); + d_ptr->q_ptr = this; + + d_ptr->m_spec = QColor::Hsv; +} + +void QtGradientStopsController::setUi(Ui::QtGradientEditor *ui) +{ + d_ptr->m_ui = ui; + + d_ptr->m_ui->hueColorLine->setColorComponent(QtColorLine::Hue); + d_ptr->m_ui->saturationColorLine->setColorComponent(QtColorLine::Saturation); + d_ptr->m_ui->valueColorLine->setColorComponent(QtColorLine::Value); + d_ptr->m_ui->alphaColorLine->setColorComponent(QtColorLine::Alpha); + + d_ptr->m_model = new QtGradientStopsModel(this); + d_ptr->m_ui->gradientStopsWidget->setGradientStopsModel(d_ptr->m_model); + connect(d_ptr->m_model, SIGNAL(currentStopChanged(QtGradientStop *)), + this, SLOT(slotCurrentStopChanged(QtGradientStop *))); + connect(d_ptr->m_model, SIGNAL(stopMoved(QtGradientStop *, qreal)), + this, SLOT(slotStopMoved(QtGradientStop *, qreal))); + connect(d_ptr->m_model, SIGNAL(stopsSwapped(QtGradientStop *, QtGradientStop *)), + this, SLOT(slotStopsSwapped(QtGradientStop *, QtGradientStop *))); + connect(d_ptr->m_model, SIGNAL(stopChanged(QtGradientStop *, const QColor &)), + this, SLOT(slotStopChanged(QtGradientStop *, const QColor &))); + connect(d_ptr->m_model, SIGNAL(stopSelected(QtGradientStop *, bool)), + this, SLOT(slotStopSelected(QtGradientStop *, bool))); + connect(d_ptr->m_model, SIGNAL(stopAdded(QtGradientStop *)), + this, SLOT(slotStopAdded(QtGradientStop *))); + connect(d_ptr->m_model, SIGNAL(stopRemoved(QtGradientStop *)), + this, SLOT(slotStopRemoved(QtGradientStop *))); + + connect(d_ptr->m_ui->hueColorLine, SIGNAL(colorChanged(const QColor &)), + this, SLOT(slotChangeHue(const QColor &))); + connect(d_ptr->m_ui->saturationColorLine, SIGNAL(colorChanged(const QColor &)), + this, SLOT(slotChangeSaturation(const QColor &))); + connect(d_ptr->m_ui->valueColorLine, SIGNAL(colorChanged(const QColor &)), + this, SLOT(slotChangeValue(const QColor &))); + connect(d_ptr->m_ui->alphaColorLine, SIGNAL(colorChanged(const QColor &)), + this, SLOT(slotChangeAlpha(const QColor &))); + connect(d_ptr->m_ui->colorButton, SIGNAL(colorChanged(const QColor &)), + this, SLOT(slotChangeColor(const QColor &))); + + connect(d_ptr->m_ui->hueSpinBox, SIGNAL(valueChanged(int)), + this, SLOT(slotChangeHue(int))); + connect(d_ptr->m_ui->saturationSpinBox, SIGNAL(valueChanged(int)), + this, SLOT(slotChangeSaturation(int))); + connect(d_ptr->m_ui->valueSpinBox, SIGNAL(valueChanged(int)), + this, SLOT(slotChangeValue(int))); + connect(d_ptr->m_ui->alphaSpinBox, SIGNAL(valueChanged(int)), + this, SLOT(slotChangeAlpha(int))); + + connect(d_ptr->m_ui->positionSpinBox, SIGNAL(valueChanged(double)), + this, SLOT(slotChangePosition(double))); + + connect(d_ptr->m_ui->zoomSpinBox, SIGNAL(valueChanged(int)), + this, SLOT(slotChangeZoom(int))); + connect(d_ptr->m_ui->zoomInButton, SIGNAL(clicked()), + this, SLOT(slotZoomIn())); + connect(d_ptr->m_ui->zoomOutButton, SIGNAL(clicked()), + this, SLOT(slotZoomOut())); + connect(d_ptr->m_ui->zoomAllButton, SIGNAL(clicked()), + this, SLOT(slotZoomAll())); + connect(d_ptr->m_ui->gradientStopsWidget, SIGNAL(zoomChanged(double)), + this, SLOT(slotZoomChanged(double))); + + connect(d_ptr->m_ui->hsvRadioButton, SIGNAL(clicked()), + this, SLOT(slotHsvClicked())); + connect(d_ptr->m_ui->rgbRadioButton, SIGNAL(clicked()), + this, SLOT(slotRgbClicked())); + + d_ptr->enableCurrent(false); + d_ptr->m_ui->zoomInButton->setIcon(QIcon(QLatin1String(":/trolltech/qtgradienteditor/images/zoomin.png"))); + d_ptr->m_ui->zoomOutButton->setIcon(QIcon(QLatin1String(":/trolltech/qtgradienteditor/images/zoomout.png"))); + d_ptr->updateZoom(1); +} + +QtGradientStopsController::~QtGradientStopsController() +{ + delete d_ptr; +} + +void QtGradientStopsController::setGradientStops(const QGradientStops &stops) +{ + d_ptr->m_model->clear(); + QVectorIterator<QPair<qreal, QColor> > it(stops); + QtGradientStop *first = 0; + while (it.hasNext()) { + QPair<qreal, QColor> pair = it.next(); + QtGradientStop *stop = d_ptr->m_model->addStop(pair.first, pair.second); + if (!first) + first = stop; + } + if (first) + d_ptr->m_model->setCurrentStop(first); +} + +QGradientStops QtGradientStopsController::gradientStops() const +{ + QGradientStops stops; + QList<QtGradientStop *> stopsList = d_ptr->m_model->stops().values(); + QListIterator<QtGradientStop *> itStop(stopsList); + while (itStop.hasNext()) { + QtGradientStop *stop = itStop.next(); + stops << QPair<qreal, QColor>(stop->position(), stop->color()); + } + return stops; +} + +QColor::Spec QtGradientStopsController::spec() const +{ + return d_ptr->m_spec; +} + +void QtGradientStopsController::setSpec(QColor::Spec spec) +{ + if (d_ptr->m_spec == spec) + return; + + d_ptr->m_spec = spec; + if (d_ptr->m_spec == QColor::Rgb) { + d_ptr->m_ui->rgbRadioButton->setChecked(true); + d_ptr->slotRgbClicked(); + } else { + d_ptr->m_ui->hsvRadioButton->setChecked(true); + d_ptr->slotHsvClicked(); + } +} + +QT_END_NAMESPACE + +#include "moc_qtgradientstopscontroller.cpp" diff --git a/tools/shared/qtgradienteditor/qtgradientstopscontroller.h b/tools/shared/qtgradienteditor/qtgradientstopscontroller.h new file mode 100644 index 0000000..9f16fb0 --- /dev/null +++ b/tools/shared/qtgradienteditor/qtgradientstopscontroller.h @@ -0,0 +1,106 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the tools applications of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QTGRADIENTSTOPSCONTROLLER_H +#define QTGRADIENTSTOPSCONTROLLER_H + +#include <QtGui/QWidget> + +QT_BEGIN_NAMESPACE + +namespace Ui { + class QtGradientEditor; +} + +class QtGradientStopsController : public QObject +{ + Q_OBJECT +public: + QtGradientStopsController(QObject *parent = 0); + ~QtGradientStopsController(); + + void setUi(Ui::QtGradientEditor *editor); + + void setGradientStops(const QGradientStops &stops); + QGradientStops gradientStops() const; + + QColor::Spec spec() const; + void setSpec(QColor::Spec spec); + +signals: + + void gradientStopsChanged(const QGradientStops &stops); + +private: + class QtGradientStopsControllerPrivate *d_ptr; + Q_DECLARE_PRIVATE(QtGradientStopsController) + Q_DISABLE_COPY(QtGradientStopsController) + Q_PRIVATE_SLOT(d_func(), void slotHsvClicked()) + Q_PRIVATE_SLOT(d_func(), void slotRgbClicked()) + Q_PRIVATE_SLOT(d_func(), void slotCurrentStopChanged(QtGradientStop *stop)) + Q_PRIVATE_SLOT(d_func(), void slotStopMoved(QtGradientStop *stop, qreal newPos)) + Q_PRIVATE_SLOT(d_func(), void slotStopsSwapped(QtGradientStop *stop1, QtGradientStop *stop2)) + Q_PRIVATE_SLOT(d_func(), void slotStopChanged(QtGradientStop *stop, const QColor &newColor)) + Q_PRIVATE_SLOT(d_func(), void slotStopSelected(QtGradientStop *stop, bool selected)) + Q_PRIVATE_SLOT(d_func(), void slotStopAdded(QtGradientStop *stop)) + Q_PRIVATE_SLOT(d_func(), void slotStopRemoved(QtGradientStop *stop)) + Q_PRIVATE_SLOT(d_func(), void slotUpdatePositionSpinBox()) + Q_PRIVATE_SLOT(d_func(), void slotChangeColor(const QColor &color)) + Q_PRIVATE_SLOT(d_func(), void slotChangeHue(const QColor &color)) + Q_PRIVATE_SLOT(d_func(), void slotChangeSaturation(const QColor &color)) + Q_PRIVATE_SLOT(d_func(), void slotChangeValue(const QColor &color)) + Q_PRIVATE_SLOT(d_func(), void slotChangeAlpha(const QColor &color)) + Q_PRIVATE_SLOT(d_func(), void slotChangeHue(int)) + Q_PRIVATE_SLOT(d_func(), void slotChangeSaturation(int)) + Q_PRIVATE_SLOT(d_func(), void slotChangeValue(int)) + Q_PRIVATE_SLOT(d_func(), void slotChangeAlpha(int)) + //Q_PRIVATE_SLOT(d_func(), void slotChangePosition(double newPos)) + Q_PRIVATE_SLOT(d_func(), void slotChangePosition(double value)) + Q_PRIVATE_SLOT(d_func(), void slotChangeZoom(int value)) + Q_PRIVATE_SLOT(d_func(), void slotZoomIn()) + Q_PRIVATE_SLOT(d_func(), void slotZoomOut()) + Q_PRIVATE_SLOT(d_func(), void slotZoomAll()) + Q_PRIVATE_SLOT(d_func(), void slotZoomChanged(double)) +}; + +QT_END_NAMESPACE + +#endif diff --git a/tools/shared/qtgradienteditor/qtgradientstopsmodel.cpp b/tools/shared/qtgradienteditor/qtgradientstopsmodel.cpp new file mode 100644 index 0000000..a632c0f --- /dev/null +++ b/tools/shared/qtgradienteditor/qtgradientstopsmodel.cpp @@ -0,0 +1,480 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the tools applications of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qtgradientstopsmodel.h" +#include <QtGui/QColor> + +QT_BEGIN_NAMESPACE + +class QtGradientStopPrivate +{ +public: + qreal m_position; + QColor m_color; + QtGradientStopsModel *m_model; +}; + +qreal QtGradientStop::position() const +{ + return d_ptr->m_position; +} + +QColor QtGradientStop::color() const +{ + return d_ptr->m_color; +} + +QtGradientStopsModel *QtGradientStop::gradientModel() const +{ + return d_ptr->m_model; +} + +void QtGradientStop::setColor(const QColor &color) +{ + d_ptr->m_color = color; +} + +void QtGradientStop::setPosition(qreal position) +{ + d_ptr->m_position = position; +} + +QtGradientStop::QtGradientStop(QtGradientStopsModel *model) +{ + d_ptr = new QtGradientStopPrivate(); + d_ptr->m_position = 0; + d_ptr->m_color = Qt::white; + d_ptr->m_model = model; +} + +QtGradientStop::~QtGradientStop() +{ + delete d_ptr; +} + +class QtGradientStopsModelPrivate +{ + QtGradientStopsModel *q_ptr; + Q_DECLARE_PUBLIC(QtGradientStopsModel) +public: + QMap<qreal, QtGradientStop *> m_posToStop; + QMap<QtGradientStop *, qreal> m_stopToPos; + QMap<QtGradientStop *, bool> m_selection; + QtGradientStop *m_current; +}; + + + +QtGradientStopsModel::QtGradientStopsModel(QObject *parent) + : QObject(parent) +{ + d_ptr = new QtGradientStopsModelPrivate; + d_ptr->q_ptr = this; + d_ptr->m_current = 0; +} + +QtGradientStopsModel::~QtGradientStopsModel() +{ + clear(); + delete d_ptr; +} + +QtGradientStopsModel::PositionStopMap QtGradientStopsModel::stops() const +{ + return d_ptr->m_posToStop; +} + +QtGradientStop *QtGradientStopsModel::at(qreal pos) const +{ + if (d_ptr->m_posToStop.contains(pos)) + return d_ptr->m_posToStop[pos]; + return 0; +} + +QColor QtGradientStopsModel::color(qreal pos) const +{ + PositionStopMap gradStops = stops(); + if (gradStops.isEmpty()) + return QColor::fromRgbF(pos, pos, pos, 1.0); + if (gradStops.contains(pos)) + return gradStops[pos]->color(); + + gradStops[pos] = 0; + PositionStopMap::ConstIterator itStop = gradStops.constFind(pos); + if (itStop == gradStops.constBegin()) { + ++itStop; + return itStop.value()->color(); + } + if (itStop == --gradStops.constEnd()) { + --itStop; + return itStop.value()->color(); + } + PositionStopMap::ConstIterator itPrev = itStop; + PositionStopMap::ConstIterator itNext = itStop; + --itPrev; + ++itNext; + + double prevX = itPrev.key(); + double nextX = itNext.key(); + + double coefX = (pos - prevX) / (nextX - prevX); + QColor prevCol = itPrev.value()->color(); + QColor nextCol = itNext.value()->color(); + + QColor newColor; + newColor.setRgbF((nextCol.redF() - prevCol.redF() ) * coefX + prevCol.redF(), + (nextCol.greenF() - prevCol.greenF()) * coefX + prevCol.greenF(), + (nextCol.blueF() - prevCol.blueF() ) * coefX + prevCol.blueF(), + (nextCol.alphaF() - prevCol.alphaF()) * coefX + prevCol.alphaF()); + return newColor; +} + +QList<QtGradientStop *> QtGradientStopsModel::selectedStops() const +{ + return d_ptr->m_selection.keys(); +} + +QtGradientStop *QtGradientStopsModel::currentStop() const +{ + return d_ptr->m_current; +} + +bool QtGradientStopsModel::isSelected(QtGradientStop *stop) const +{ + if (d_ptr->m_selection.contains(stop)) + return true; + return false; +} + +QtGradientStop *QtGradientStopsModel::addStop(qreal pos, const QColor &color) +{ + qreal newPos = pos; + if (pos < 0.0) + newPos = 0.0; + if (pos > 1.0) + newPos = 1.0; + if (d_ptr->m_posToStop.contains(newPos)) + return 0; + QtGradientStop *stop = new QtGradientStop(); + stop->setPosition(newPos); + stop->setColor(color); + + d_ptr->m_posToStop[newPos] = stop; + d_ptr->m_stopToPos[stop] = newPos; + + emit stopAdded(stop); + + return stop; +} + +void QtGradientStopsModel::removeStop(QtGradientStop *stop) +{ + if (!d_ptr->m_stopToPos.contains(stop)) + return; + if (currentStop() == stop) + setCurrentStop(0); + selectStop(stop, false); + + emit stopRemoved(stop); + + qreal pos = d_ptr->m_stopToPos[stop]; + d_ptr->m_stopToPos.remove(stop); + d_ptr->m_posToStop.remove(pos); + delete stop; +} + +void QtGradientStopsModel::moveStop(QtGradientStop *stop, qreal newPos) +{ + if (!d_ptr->m_stopToPos.contains(stop)) + return; + if (d_ptr->m_posToStop.contains(newPos)) + return; + + if (newPos > 1.0) + newPos = 1.0; + else if (newPos < 0.0) + newPos = 0.0; + + emit stopMoved(stop, newPos); + + const qreal oldPos = stop->position(); + stop->setPosition(newPos); + d_ptr->m_stopToPos[stop] = newPos; + d_ptr->m_posToStop.remove(oldPos); + d_ptr->m_posToStop[newPos] = stop; +} + +void QtGradientStopsModel::swapStops(QtGradientStop *stop1, QtGradientStop *stop2) +{ + if (stop1 == stop2) + return; + if (!d_ptr->m_stopToPos.contains(stop1)) + return; + if (!d_ptr->m_stopToPos.contains(stop2)) + return; + + emit stopsSwapped(stop1, stop2); + + const qreal pos1 = stop1->position(); + const qreal pos2 = stop2->position(); + stop1->setPosition(pos2); + stop2->setPosition(pos1); + d_ptr->m_stopToPos[stop1] = pos2; + d_ptr->m_stopToPos[stop2] = pos1; + d_ptr->m_posToStop[pos1] = stop2; + d_ptr->m_posToStop[pos2] = stop1; +} + +void QtGradientStopsModel::changeStop(QtGradientStop *stop, const QColor &newColor) +{ + if (!d_ptr->m_stopToPos.contains(stop)) + return; + if (stop->color() == newColor) + return; + + emit stopChanged(stop, newColor); + + stop->setColor(newColor); +} + +void QtGradientStopsModel::selectStop(QtGradientStop *stop, bool select) +{ + if (!d_ptr->m_stopToPos.contains(stop)) + return; + bool selected = d_ptr->m_selection.contains(stop); + if (select == selected) + return; + + emit stopSelected(stop, select); + + if (select) + d_ptr->m_selection[stop] = true; + else + d_ptr->m_selection.remove(stop); +} + +void QtGradientStopsModel::setCurrentStop(QtGradientStop *stop) +{ + if (stop && !d_ptr->m_stopToPos.contains(stop)) + return; + if (stop == currentStop()) + return; + + emit currentStopChanged(stop); + + d_ptr->m_current = stop; +} + +QtGradientStop *QtGradientStopsModel::firstSelected() const +{ + PositionStopMap stopList = stops(); + PositionStopMap::ConstIterator itStop = stopList.constBegin(); + while (itStop != stopList.constEnd()) { + QtGradientStop *stop = itStop.value(); + if (isSelected(stop)) + return stop; + ++itStop; + }; + return 0; +} + +QtGradientStop *QtGradientStopsModel::lastSelected() const +{ + PositionStopMap stopList = stops(); + PositionStopMap::ConstIterator itStop = stopList.constEnd(); + while (itStop != stopList.constBegin()) { + --itStop; + + QtGradientStop *stop = itStop.value(); + if (isSelected(stop)) + return stop; + }; + return 0; +} + +QtGradientStopsModel *QtGradientStopsModel::clone() const +{ + QtGradientStopsModel *model = new QtGradientStopsModel(); + + QMap<qreal, QtGradientStop *> stopsToClone = stops(); + QMapIterator<qreal, QtGradientStop *> it(stopsToClone); + while (it.hasNext()) { + it.next(); + model->addStop(it.key(), it.value()->color()); + } + // clone selection and current also + return model; +} + +void QtGradientStopsModel::moveStops(double newPosition) +{ + QtGradientStop *current = currentStop(); + if (!current) + return; + + double newPos = newPosition; + + if (newPos > 1) + newPos = 1; + else if (newPos < 0) + newPos = 0; + + if (newPos == current->position()) + return; + + double offset = newPos - current->position(); + + QtGradientStop *first = firstSelected(); + QtGradientStop *last = lastSelected(); + + if (first && last) { // multiselection + double maxOffset = 1.0 - last->position(); + double minOffset = -first->position(); + + if (offset > maxOffset) + offset = maxOffset; + else if (offset < minOffset) + offset = minOffset; + + } + + if (offset == 0) + return; + + bool forward = (offset > 0) ? false : true; + + PositionStopMap stopList; + + QList<QtGradientStop *> selected = selectedStops(); + QListIterator<QtGradientStop *> it(selected); + while (it.hasNext()) { + QtGradientStop *stop = it.next(); + stopList[stop->position()] = stop; + } + stopList[current->position()] = current; + + PositionStopMap::ConstIterator itStop = forward ? stopList.constBegin() : stopList.constEnd(); + while (itStop != (forward ? stopList.constEnd() : stopList.constBegin())) { + if (!forward) + --itStop; + QtGradientStop *stop = itStop.value(); + double pos = stop->position() + offset; + if (pos > 1) + pos = 1; + if (pos < 0) + pos = 0; + + if (current == stop) + pos = newPos; + + QtGradientStop *oldStop = at(pos); + if (oldStop && !stopList.values().contains(oldStop)) + removeStop(oldStop); + moveStop(stop, pos); + + if (forward) + ++itStop; + } +} + +void QtGradientStopsModel::clear() +{ + QList<QtGradientStop *> stopsList = stops().values(); + QListIterator<QtGradientStop *> it(stopsList); + while (it.hasNext()) + removeStop(it.next()); +} + +void QtGradientStopsModel::clearSelection() +{ + QList<QtGradientStop *> stopsList = selectedStops(); + QListIterator<QtGradientStop *> it(stopsList); + while (it.hasNext()) + selectStop(it.next(), false); +} + +void QtGradientStopsModel::flipAll() +{ + QMap<qreal, QtGradientStop *> stopsMap = stops(); + QMapIterator<qreal, QtGradientStop *> itStop(stopsMap); + itStop.toBack(); + + QMap<QtGradientStop *, bool> swappedList; + + while (itStop.hasPrevious()) { + itStop.previous(); + + QtGradientStop *stop = itStop.value(); + if (swappedList.contains(stop)) + continue; + const double newPos = 1.0 - itStop.key(); + if (stopsMap.contains(newPos)) { + QtGradientStop *swapped = stopsMap.value(newPos); + swappedList[swapped] = true; + swapStops(stop, swapped); + } else { + moveStop(stop, newPos); + } + } +} + +void QtGradientStopsModel::selectAll() +{ + QList<QtGradientStop *> stopsList = stops().values(); + QListIterator<QtGradientStop *> it(stopsList); + while (it.hasNext()) + selectStop(it.next(), true); +} + +void QtGradientStopsModel::deleteStops() +{ + QList<QtGradientStop *> selected = selectedStops(); + QListIterator<QtGradientStop *> itSel(selected); + while (itSel.hasNext()) { + QtGradientStop *stop = itSel.next(); + removeStop(stop); + } + QtGradientStop *current = currentStop(); + if (current) + removeStop(current); +} + +QT_END_NAMESPACE diff --git a/tools/shared/qtgradienteditor/qtgradientstopsmodel.h b/tools/shared/qtgradienteditor/qtgradientstopsmodel.h new file mode 100644 index 0000000..d4e6b3c --- /dev/null +++ b/tools/shared/qtgradienteditor/qtgradientstopsmodel.h @@ -0,0 +1,121 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the tools applications of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QTGRADIENTSTOPSMODEL_H +#define QTGRADIENTSTOPSMODEL_H + +#include <QtCore/QObject> +#include <QtCore/QMap> + +QT_BEGIN_NAMESPACE + +class QColor; + +class QtGradientStopsModel; + +class QtGradientStop +{ +public: + qreal position() const; + QColor color() const; + QtGradientStopsModel *gradientModel() const; + +private: + void setColor(const QColor &color); + void setPosition(qreal position); + friend class QtGradientStopsModel; + QtGradientStop(QtGradientStopsModel *model = 0); + ~QtGradientStop(); + class QtGradientStopPrivate *d_ptr; +}; + +class QtGradientStopsModel : public QObject +{ + Q_OBJECT +public: + typedef QMap<qreal, QtGradientStop *> PositionStopMap; + + QtGradientStopsModel(QObject *parent = 0); + ~QtGradientStopsModel(); + + PositionStopMap stops() const; + QtGradientStop *at(qreal pos) const; + QColor color(qreal pos) const; // calculated between points + QList<QtGradientStop *> selectedStops() const; + QtGradientStop *currentStop() const; + bool isSelected(QtGradientStop *stop) const; + QtGradientStop *firstSelected() const; + QtGradientStop *lastSelected() const; + QtGradientStopsModel *clone() const; + + QtGradientStop *addStop(qreal pos, const QColor &color); + void removeStop(QtGradientStop *stop); + void moveStop(QtGradientStop *stop, qreal newPos); + void swapStops(QtGradientStop *stop1, QtGradientStop *stop2); + void changeStop(QtGradientStop *stop, const QColor &newColor); + void selectStop(QtGradientStop *stop, bool select); + void setCurrentStop(QtGradientStop *stop); + + void moveStops(double newPosition); // moves current stop to newPos and all selected stops are moved accordingly + void clear(); + void clearSelection(); + void flipAll(); + void selectAll(); + void deleteStops(); + +signals: + void stopAdded(QtGradientStop *stop); + void stopRemoved(QtGradientStop *stop); + void stopMoved(QtGradientStop *stop, qreal newPos); + void stopsSwapped(QtGradientStop *stop1, QtGradientStop *stop2); + void stopChanged(QtGradientStop *stop, const QColor &newColor); + void stopSelected(QtGradientStop *stop, bool selected); + void currentStopChanged(QtGradientStop *stop); + +private: + class QtGradientStopsModelPrivate *d_ptr; + Q_DECLARE_PRIVATE(QtGradientStopsModel) + Q_DISABLE_COPY(QtGradientStopsModel) +}; + +QT_END_NAMESPACE + +#endif diff --git a/tools/shared/qtgradienteditor/qtgradientstopswidget.cpp b/tools/shared/qtgradienteditor/qtgradientstopswidget.cpp new file mode 100644 index 0000000..adaf57d --- /dev/null +++ b/tools/shared/qtgradienteditor/qtgradientstopswidget.cpp @@ -0,0 +1,1156 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the tools applications of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qtgradientstopswidget.h" +#include "qtgradientstopsmodel.h" + +#include <QtCore/QMap> +#include <QtGui/QImage> +#include <QtGui/QPainter> +#include <QtGui/QScrollBar> +#include <QtGui/QMouseEvent> +#include <QtGui/QRubberBand> +#include <QtGui/QMenu> + +QT_BEGIN_NAMESPACE + +class QtGradientStopsWidgetPrivate +{ + QtGradientStopsWidget *q_ptr; + Q_DECLARE_PUBLIC(QtGradientStopsWidget) +public: + typedef QMap<qreal, QColor> PositionColorMap; + typedef QMap<QtGradientStop *, qreal> StopPositionMap; + + void slotStopAdded(QtGradientStop *stop); + void slotStopRemoved(QtGradientStop *stop); + void slotStopMoved(QtGradientStop *stop, qreal newPos); + void slotStopsSwapped(QtGradientStop *stop1, QtGradientStop *stop2); + void slotStopChanged(QtGradientStop *stop, const QColor &newColor); + void slotStopSelected(QtGradientStop *stop, bool selected); + void slotCurrentStopChanged(QtGradientStop *stop); + void slotNewStop(); + void slotDelete(); + void slotFlipAll(); + void slotSelectAll(); + void slotZoomIn(); + void slotZoomOut(); + void slotResetZoom(); + + double fromViewport(int x) const; + double toViewport(double x) const; + QtGradientStop *stopAt(const QPoint &viewportPos) const; + QList<QtGradientStop *> stopsAt(const QPoint &viewportPos) const; + void setupMove(QtGradientStop *stop, int x); + void ensureVisible(double x); // x = stop position + void ensureVisible(QtGradientStop *stop); + QtGradientStop *newStop(const QPoint &viewportPos); + + bool m_backgroundCheckered; + QtGradientStopsModel *m_model; + double m_handleSize; + int m_scaleFactor; + double m_zoom; + +#ifndef QT_NO_DRAGANDDROP + QtGradientStop *m_dragStop; + QtGradientStop *m_changedStop; + QtGradientStop *m_clonedStop; + QtGradientStopsModel *m_dragModel; + QColor m_dragColor; + void clearDrag(); + void removeClonedStop(); + void restoreChangedStop(); + void changeStop(qreal pos); + void cloneStop(qreal pos); +#endif + + QRubberBand *m_rubber; + QPoint m_clickPos; + + QList<QtGradientStop *> m_stops; + + bool m_moving; + int m_moveOffset; + StopPositionMap m_moveStops; + + PositionColorMap m_moveOriginal; +}; + +double QtGradientStopsWidgetPrivate::fromViewport(int x) const +{ + QSize size = q_ptr->viewport()->size(); + int w = size.width(); + int max = q_ptr->horizontalScrollBar()->maximum(); + int val = q_ptr->horizontalScrollBar()->value(); + return ((double)x * m_scaleFactor + w * val) / (w * (m_scaleFactor + max)); +} + +double QtGradientStopsWidgetPrivate::toViewport(double x) const +{ + QSize size = q_ptr->viewport()->size(); + int w = size.width(); + int max = q_ptr->horizontalScrollBar()->maximum(); + int val = q_ptr->horizontalScrollBar()->value(); + return w * (x * (m_scaleFactor + max) - val) / m_scaleFactor; +} + +QtGradientStop *QtGradientStopsWidgetPrivate::stopAt(const QPoint &viewportPos) const +{ + double posY = m_handleSize / 2; + QListIterator<QtGradientStop *> itStop(m_stops); + while (itStop.hasNext()) { + QtGradientStop *stop = itStop.next(); + + double posX = toViewport(stop->position()); + + double x = viewportPos.x() - posX; + double y = viewportPos.y() - posY; + + if ((m_handleSize * m_handleSize / 4) > (x * x + y * y)) + return stop; + } + return 0; +} + +QList<QtGradientStop *> QtGradientStopsWidgetPrivate::stopsAt(const QPoint &viewportPos) const +{ + QList<QtGradientStop *> stops; + double posY = m_handleSize / 2; + QListIterator<QtGradientStop *> itStop(m_stops); + while (itStop.hasNext()) { + QtGradientStop *stop = itStop.next(); + + double posX = toViewport(stop->position()); + + double x = viewportPos.x() - posX; + double y = viewportPos.y() - posY; + + if ((m_handleSize * m_handleSize / 4) > (x * x + y * y)) + stops.append(stop); + } + return stops; +} + +void QtGradientStopsWidgetPrivate::setupMove(QtGradientStop *stop, int x) +{ + m_model->setCurrentStop(stop); + + int viewportX = qRound(toViewport(stop->position())); + m_moveOffset = x - viewportX; + + QList<QtGradientStop *> stops = m_stops; + m_stops.clear(); + QListIterator<QtGradientStop *> itStop(stops); + while (itStop.hasNext()) { + QtGradientStop *s = itStop.next(); + if (m_model->isSelected(s) || s == stop) { + m_moveStops[s] = s->position() - stop->position(); + m_stops.append(s); + } else { + m_moveOriginal[s->position()] = s->color(); + } + } + itStop.toFront(); + while (itStop.hasNext()) { + QtGradientStop *s = itStop.next(); + if (!m_model->isSelected(s)) + m_stops.append(s); + } + m_stops.removeAll(stop); + m_stops.prepend(stop); +} + +void QtGradientStopsWidgetPrivate::ensureVisible(double x) +{ + double viewX = toViewport(x); + if (viewX < 0 || viewX > q_ptr->viewport()->size().width()) { + int max = q_ptr->horizontalScrollBar()->maximum(); + int newVal = qRound(x * (max + m_scaleFactor) - m_scaleFactor / 2); + q_ptr->horizontalScrollBar()->setValue(newVal); + } +} + +void QtGradientStopsWidgetPrivate::ensureVisible(QtGradientStop *stop) +{ + if (!stop) + return; + ensureVisible(stop->position()); +} + +QtGradientStop *QtGradientStopsWidgetPrivate::newStop(const QPoint &viewportPos) +{ + QtGradientStop *copyStop = stopAt(viewportPos); + double posX = fromViewport(viewportPos.x()); + QtGradientStop *stop = m_model->at(posX); + if (!stop) { + QColor newColor; + if (copyStop) + newColor = copyStop->color(); + else + newColor = m_model->color(posX); + if (!newColor.isValid()) + newColor = Qt::white; + stop = m_model->addStop(posX, newColor); + } + return stop; +} + +void QtGradientStopsWidgetPrivate::slotStopAdded(QtGradientStop *stop) +{ + m_stops.append(stop); + q_ptr->viewport()->update(); +} + +void QtGradientStopsWidgetPrivate::slotStopRemoved(QtGradientStop *stop) +{ + m_stops.removeAll(stop); + q_ptr->viewport()->update(); +} + +void QtGradientStopsWidgetPrivate::slotStopMoved(QtGradientStop *stop, qreal newPos) +{ + Q_UNUSED(stop) + Q_UNUSED(newPos) + q_ptr->viewport()->update(); +} + +void QtGradientStopsWidgetPrivate::slotStopsSwapped(QtGradientStop *stop1, QtGradientStop *stop2) +{ + Q_UNUSED(stop1) + Q_UNUSED(stop2) + q_ptr->viewport()->update(); +} + +void QtGradientStopsWidgetPrivate::slotStopChanged(QtGradientStop *stop, const QColor &newColor) +{ + Q_UNUSED(stop) + Q_UNUSED(newColor) + q_ptr->viewport()->update(); +} + +void QtGradientStopsWidgetPrivate::slotStopSelected(QtGradientStop *stop, bool selected) +{ + Q_UNUSED(stop) + Q_UNUSED(selected) + q_ptr->viewport()->update(); +} + +void QtGradientStopsWidgetPrivate::slotCurrentStopChanged(QtGradientStop *stop) +{ + Q_UNUSED(stop) + + if (!m_model) + return; + q_ptr->viewport()->update(); + if (stop) { + m_stops.removeAll(stop); + m_stops.prepend(stop); + } +} + +void QtGradientStopsWidgetPrivate::slotNewStop() +{ + if (!m_model) + return; + + QtGradientStop *stop = newStop(m_clickPos); + + if (!stop) + return; + + m_model->clearSelection(); + m_model->selectStop(stop, true); + m_model->setCurrentStop(stop); +} + +void QtGradientStopsWidgetPrivate::slotDelete() +{ + if (!m_model) + return; + + m_model->deleteStops(); +} + +void QtGradientStopsWidgetPrivate::slotFlipAll() +{ + if (!m_model) + return; + + m_model->flipAll(); +} + +void QtGradientStopsWidgetPrivate::slotSelectAll() +{ + if (!m_model) + return; + + m_model->selectAll(); +} + +void QtGradientStopsWidgetPrivate::slotZoomIn() +{ + double newZoom = q_ptr->zoom() * 2; + if (newZoom > 100) + newZoom = 100; + if (newZoom == q_ptr->zoom()) + return; + + q_ptr->setZoom(newZoom); + emit q_ptr->zoomChanged(q_ptr->zoom()); +} + +void QtGradientStopsWidgetPrivate::slotZoomOut() +{ + double newZoom = q_ptr->zoom() / 2; + if (newZoom < 1) + newZoom = 1; + if (newZoom == q_ptr->zoom()) + return; + + q_ptr->setZoom(newZoom); + emit q_ptr->zoomChanged(q_ptr->zoom()); +} + +void QtGradientStopsWidgetPrivate::slotResetZoom() +{ + if (1 == q_ptr->zoom()) + return; + + q_ptr->setZoom(1); + emit q_ptr->zoomChanged(1); +} + +QtGradientStopsWidget::QtGradientStopsWidget(QWidget *parent) + : QAbstractScrollArea(parent) +{ + d_ptr = new QtGradientStopsWidgetPrivate; + d_ptr->q_ptr = this; + d_ptr->m_backgroundCheckered = true; + d_ptr->m_model = 0; + d_ptr->m_handleSize = 25.0; + d_ptr->m_scaleFactor = 1000; + d_ptr->m_moving = false; + d_ptr->m_zoom = 1; + d_ptr->m_rubber = new QRubberBand(QRubberBand::Rectangle, this); +#ifndef QT_NO_DRAGANDDROP + d_ptr->m_dragStop = 0; + d_ptr->m_changedStop = 0; + d_ptr->m_clonedStop = 0; + d_ptr->m_dragModel = 0; +#endif + setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); + setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded); + horizontalScrollBar()->setRange(0, (int)(d_ptr->m_scaleFactor * (d_ptr->m_zoom - 1) + 0.5)); + horizontalScrollBar()->setPageStep(d_ptr->m_scaleFactor); + horizontalScrollBar()->setSingleStep(4); + viewport()->setAutoFillBackground(false); + + setAcceptDrops(true); + + setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred)); +} + +QtGradientStopsWidget::~QtGradientStopsWidget() +{ + delete d_ptr; +} + +QSize QtGradientStopsWidget::sizeHint() const +{ + return QSize(qRound(2 * d_ptr->m_handleSize), qRound(3 * d_ptr->m_handleSize) + horizontalScrollBar()->sizeHint().height()); +} + +QSize QtGradientStopsWidget::minimumSizeHint() const +{ + return QSize(qRound(2 * d_ptr->m_handleSize), qRound(3 * d_ptr->m_handleSize) + horizontalScrollBar()->minimumSizeHint().height()); +} + +void QtGradientStopsWidget::setBackgroundCheckered(bool checkered) +{ + if (d_ptr->m_backgroundCheckered == checkered) + return; + d_ptr->m_backgroundCheckered = checkered; + update(); +} + +bool QtGradientStopsWidget::isBackgroundCheckered() const +{ + return d_ptr->m_backgroundCheckered; +} + +void QtGradientStopsWidget::setGradientStopsModel(QtGradientStopsModel *model) +{ + if (d_ptr->m_model == model) + return; + + if (d_ptr->m_model) { + disconnect(d_ptr->m_model, SIGNAL(stopAdded(QtGradientStop *)), + this, SLOT(slotStopAdded(QtGradientStop *))); + disconnect(d_ptr->m_model, SIGNAL(stopRemoved(QtGradientStop *)), + this, SLOT(slotStopRemoved(QtGradientStop *))); + disconnect(d_ptr->m_model, SIGNAL(stopMoved(QtGradientStop *, qreal)), + this, SLOT(slotStopMoved(QtGradientStop *, qreal))); + disconnect(d_ptr->m_model, SIGNAL(stopsSwapped(QtGradientStop *, QtGradientStop *)), + this, SLOT(slotStopsSwapped(QtGradientStop *, QtGradientStop *))); + disconnect(d_ptr->m_model, SIGNAL(stopChanged(QtGradientStop *, const QColor &)), + this, SLOT(slotStopChanged(QtGradientStop *, const QColor &))); + disconnect(d_ptr->m_model, SIGNAL(stopSelected(QtGradientStop *, bool)), + this, SLOT(slotStopSelected(QtGradientStop *, bool))); + disconnect(d_ptr->m_model, SIGNAL(currentStopChanged(QtGradientStop *)), + this, SLOT(slotCurrentStopChanged(QtGradientStop *))); + + d_ptr->m_stops.clear(); + } + + d_ptr->m_model = model; + + if (d_ptr->m_model) { + connect(d_ptr->m_model, SIGNAL(stopAdded(QtGradientStop *)), + this, SLOT(slotStopAdded(QtGradientStop *))); + connect(d_ptr->m_model, SIGNAL(stopRemoved(QtGradientStop *)), + this, SLOT(slotStopRemoved(QtGradientStop *))); + connect(d_ptr->m_model, SIGNAL(stopMoved(QtGradientStop *, qreal)), + this, SLOT(slotStopMoved(QtGradientStop *, qreal))); + connect(d_ptr->m_model, SIGNAL(stopsSwapped(QtGradientStop *, QtGradientStop *)), + this, SLOT(slotStopsSwapped(QtGradientStop *, QtGradientStop *))); + connect(d_ptr->m_model, SIGNAL(stopChanged(QtGradientStop *, const QColor &)), + this, SLOT(slotStopChanged(QtGradientStop *, const QColor &))); + connect(d_ptr->m_model, SIGNAL(stopSelected(QtGradientStop *, bool)), + this, SLOT(slotStopSelected(QtGradientStop *, bool))); + connect(d_ptr->m_model, SIGNAL(currentStopChanged(QtGradientStop *)), + this, SLOT(slotCurrentStopChanged(QtGradientStop *))); + + QList<QtGradientStop *> stops = d_ptr->m_model->stops().values(); + QListIterator<QtGradientStop *> itStop(stops); + while (itStop.hasNext()) + d_ptr->slotStopAdded(itStop.next()); + + QList<QtGradientStop *> selected = d_ptr->m_model->selectedStops(); + QListIterator<QtGradientStop *> itSelect(selected); + while (itSelect.hasNext()) + d_ptr->slotStopSelected(itSelect.next(), true); + + d_ptr->slotCurrentStopChanged(d_ptr->m_model->currentStop()); + } +} + +void QtGradientStopsWidget::mousePressEvent(QMouseEvent *e) +{ + typedef QtGradientStopsModel::PositionStopMap PositionStopMap; + if (!d_ptr->m_model) + return; + + if (e->button() != Qt::LeftButton) + return; + + d_ptr->m_moving = true; + + d_ptr->m_moveStops.clear(); + d_ptr->m_moveOriginal.clear(); + d_ptr->m_clickPos = e->pos(); + QtGradientStop *stop = d_ptr->stopAt(e->pos()); + if (stop) { + if (e->modifiers() & Qt::ControlModifier) { + d_ptr->m_model->selectStop(stop, !d_ptr->m_model->isSelected(stop)); + } else if (e->modifiers() & Qt::ShiftModifier) { + QtGradientStop *oldCurrent = d_ptr->m_model->currentStop(); + if (oldCurrent) { + PositionStopMap stops = d_ptr->m_model->stops(); + PositionStopMap::ConstIterator itSt = stops.constFind(oldCurrent->position()); + if (itSt != stops.constEnd()) { + while (itSt != stops.constFind(stop->position())) { + d_ptr->m_model->selectStop(itSt.value(), true); + if (oldCurrent->position() < stop->position()) + ++itSt; + else + --itSt; + } + } + } + d_ptr->m_model->selectStop(stop, true); + } else { + if (!d_ptr->m_model->isSelected(stop)) { + d_ptr->m_model->clearSelection(); + d_ptr->m_model->selectStop(stop, true); + } + } + d_ptr->setupMove(stop, e->pos().x()); + } else { + d_ptr->m_model->clearSelection(); + d_ptr->m_rubber->setGeometry(QRect(d_ptr->m_clickPos, QSize())); + d_ptr->m_rubber->show(); + } + viewport()->update(); +} + +void QtGradientStopsWidget::mouseReleaseEvent(QMouseEvent *e) +{ + if (!d_ptr->m_model) + return; + + if (e->button() != Qt::LeftButton) + return; + + d_ptr->m_moving = false; + d_ptr->m_rubber->hide(); + d_ptr->m_moveStops.clear(); + d_ptr->m_moveOriginal.clear(); +} + +void QtGradientStopsWidget::mouseMoveEvent(QMouseEvent *e) +{ + typedef QtGradientStopsWidgetPrivate::PositionColorMap PositionColorMap; + typedef QtGradientStopsModel::PositionStopMap PositionStopMap; + typedef QtGradientStopsWidgetPrivate::StopPositionMap StopPositionMap; + if (!d_ptr->m_model) + return; + + if (!(e->buttons() & Qt::LeftButton)) + return; + + if (!d_ptr->m_moving) + return; + + if (!d_ptr->m_moveStops.isEmpty()) { + double maxOffset = 0.0; + double minOffset = 0.0; + bool first = true; + StopPositionMap::ConstIterator itStop = d_ptr->m_moveStops.constBegin(); + while (itStop != d_ptr->m_moveStops.constEnd()) { + double offset = itStop.value(); + + if (first) { + maxOffset = offset; + minOffset = offset; + first = false; + } else { + if (maxOffset < offset) + maxOffset = offset; + else if (minOffset > offset) + minOffset = offset; + } + ++itStop; + } + + double viewportMin = d_ptr->toViewport(-minOffset); + double viewportMax = d_ptr->toViewport(1.0 - maxOffset); + + PositionStopMap newPositions; + + int viewportX = e->pos().x() - d_ptr->m_moveOffset; + + if (viewportX > viewport()->size().width()) + viewportX = viewport()->size().width(); + else if (viewportX < 0) + viewportX = 0; + + double posX = d_ptr->fromViewport(viewportX); + + if (viewportX > viewportMax) + posX = 1.0 - maxOffset; + else if (viewportX < viewportMin) + posX = -minOffset; + + itStop = d_ptr->m_moveStops.constBegin(); + while (itStop != d_ptr->m_moveStops.constEnd()) { + QtGradientStop *stop = itStop.key(); + + newPositions[posX + itStop.value()] = stop; + + ++itStop; + } + + bool forward = true; + PositionStopMap::ConstIterator itNewPos = newPositions.constBegin(); + if (itNewPos.value()->position() < itNewPos.key()) + forward = false; + + itNewPos = forward ? newPositions.constBegin() : newPositions.constEnd(); + while (itNewPos != (forward ? newPositions.constEnd() : newPositions.constBegin())) { + if (!forward) + --itNewPos; + QtGradientStop *stop = itNewPos.value(); + double newPos = itNewPos.key(); + if (newPos > 1) + newPos = 1; + else if (newPos < 0) + newPos = 0; + + QtGradientStop *existingStop = d_ptr->m_model->at(newPos); + if (existingStop && !d_ptr->m_moveStops.contains(existingStop)) + d_ptr->m_model->removeStop(existingStop); + d_ptr->m_model->moveStop(stop, newPos); + + if (forward) + ++itNewPos; + } + + PositionColorMap::ConstIterator itOld = d_ptr->m_moveOriginal.constBegin(); + while (itOld != d_ptr->m_moveOriginal.constEnd()) { + double position = itOld.key(); + if (!d_ptr->m_model->at(position)) + d_ptr->m_model->addStop(position, itOld.value()); + + ++itOld; + } + + } else { + QRect r(QRect(d_ptr->m_clickPos, e->pos()).normalized()); + r.translate(1, 0); + d_ptr->m_rubber->setGeometry(r); + //d_ptr->m_model->clearSelection(); + + int xv1 = d_ptr->m_clickPos.x(); + int xv2 = e->pos().x(); + if (xv1 > xv2) { + int temp = xv1; + xv1 = xv2; + xv2 = temp; + } + int yv1 = d_ptr->m_clickPos.y(); + int yv2 = e->pos().y(); + if (yv1 > yv2) { + int temp = yv1; + yv1 = yv2; + yv2 = temp; + } + + QPoint p1, p2; + + if (yv2 < d_ptr->m_handleSize / 2) { + p1 = QPoint(xv1, yv2); + p2 = QPoint(xv2, yv2); + } else if (yv1 > d_ptr->m_handleSize / 2) { + p1 = QPoint(xv1, yv1); + p2 = QPoint(xv2, yv1); + } else { + p1 = QPoint(xv1, qRound(d_ptr->m_handleSize / 2)); + p2 = QPoint(xv2, qRound(d_ptr->m_handleSize / 2)); + } + + QList<QtGradientStop *> beginList = d_ptr->stopsAt(p1); + QList<QtGradientStop *> endList = d_ptr->stopsAt(p2); + + double x1 = d_ptr->fromViewport(xv1); + double x2 = d_ptr->fromViewport(xv2); + + QListIterator<QtGradientStop *> itStop(d_ptr->m_stops); + while (itStop.hasNext()) { + QtGradientStop *stop = itStop.next(); + if ((stop->position() >= x1 && stop->position() <= x2) || + beginList.contains(stop) || endList.contains(stop)) + d_ptr->m_model->selectStop(stop, true); + else + d_ptr->m_model->selectStop(stop, false); + } + } +} + +void QtGradientStopsWidget::mouseDoubleClickEvent(QMouseEvent *e) +{ + if (!d_ptr->m_model) + return; + + if (e->button() != Qt::LeftButton) + return; + + if (d_ptr->m_clickPos != e->pos()) { + mousePressEvent(e); + return; + } + d_ptr->m_moving = true; + d_ptr->m_moveStops.clear(); + d_ptr->m_moveOriginal.clear(); + + QtGradientStop *stop = d_ptr->newStop(e->pos()); + + if (!stop) + return; + + d_ptr->m_model->clearSelection(); + d_ptr->m_model->selectStop(stop, true); + + d_ptr->setupMove(stop, e->pos().x()); + + viewport()->update(); +} + +void QtGradientStopsWidget::keyPressEvent(QKeyEvent *e) +{ + typedef QtGradientStopsModel::PositionStopMap PositionStopMap; + if (!d_ptr->m_model) + return; + + if (e->key() == Qt::Key_Delete || e->key() == Qt::Key_Backspace) { + d_ptr->m_model->deleteStops(); + } else if (e->key() == Qt::Key_Left || e->key() == Qt::Key_Right || + e->key() == Qt::Key_Home || e->key() == Qt::Key_End) { + PositionStopMap stops = d_ptr->m_model->stops(); + if (stops.isEmpty()) + return; + QtGradientStop *newCurrent = 0; + QtGradientStop *current = d_ptr->m_model->currentStop(); + if (!current || e->key() == Qt::Key_Home || e->key() == Qt::Key_End) { + if (e->key() == Qt::Key_Left || e->key() == Qt::Key_Home) + newCurrent = stops.constBegin().value(); + else if (e->key() == Qt::Key_Right || e->key() == Qt::Key_End) + newCurrent = (--stops.constEnd()).value(); + } else { + PositionStopMap::ConstIterator itStop = stops.constBegin(); + while (itStop.value() != current) + ++itStop; + if (e->key() == Qt::Key_Left && itStop != stops.constBegin()) + --itStop; + else if (e->key() == Qt::Key_Right && itStop != --stops.constEnd()) + ++itStop; + newCurrent = itStop.value(); + } + d_ptr->m_model->clearSelection(); + d_ptr->m_model->selectStop(newCurrent, true); + d_ptr->m_model->setCurrentStop(newCurrent); + d_ptr->ensureVisible(newCurrent); + } else if (e->key() == Qt::Key_A) { + if (e->modifiers() & Qt::ControlModifier) + d_ptr->m_model->selectAll(); + } +} + +void QtGradientStopsWidget::paintEvent(QPaintEvent *e) +{ + Q_UNUSED(e) + if (!d_ptr->m_model) + return; + + QtGradientStopsModel *model = d_ptr->m_model; +#ifndef QT_NO_DRAGANDDROP + if (d_ptr->m_dragModel) + model = d_ptr->m_dragModel; +#endif + + QSize size = viewport()->size(); + int w = size.width(); + double h = size.height() - d_ptr->m_handleSize; + if (w <= 0) + return; + + QPixmap pix(size); + QPainter p; + + if (d_ptr->m_backgroundCheckered) { + int pixSize = 20; + QPixmap pm(2 * pixSize, 2 * pixSize); + QPainter pmp(&pm); + pmp.fillRect(0, 0, pixSize, pixSize, Qt::white); + pmp.fillRect(pixSize, pixSize, pixSize, pixSize, Qt::white); + pmp.fillRect(0, pixSize, pixSize, pixSize, Qt::black); + pmp.fillRect(pixSize, 0, pixSize, pixSize, Qt::black); + + p.begin(&pix); + p.setBrushOrigin((size.width() % pixSize + pixSize) / 2, (size.height() % pixSize + pixSize) / 2); + p.fillRect(viewport()->rect(), pm); + p.setBrushOrigin(0, 0); + } else { + p.begin(viewport()); + } + + double viewBegin = (double)w * horizontalScrollBar()->value() / d_ptr->m_scaleFactor; + + int val = horizontalScrollBar()->value(); + int max = horizontalScrollBar()->maximum(); + + double begin = (double)val / (d_ptr->m_scaleFactor + max); + double end = (double)(val + d_ptr->m_scaleFactor) / (d_ptr->m_scaleFactor + max); + double width = end - begin; + + if (h > 0) { + QLinearGradient lg(0, 0, w, 0); + QMap<qreal, QtGradientStop *> stops = model->stops(); + QMapIterator<qreal, QtGradientStop *> itStop(stops); + while (itStop.hasNext()) { + QtGradientStop *stop = itStop.next().value(); + double pos = stop->position(); + if (pos >= begin && pos <= end) { + double gradPos = (pos - begin) / width; + QColor c = stop->color(); + lg.setColorAt(gradPos, c); + } + //lg.setColorAt(stop->position(), stop->color()); + } + lg.setColorAt(0, model->color(begin)); + lg.setColorAt(1, model->color(end)); + QImage img(w, 1, QImage::Format_ARGB32_Premultiplied); + QPainter p1(&img); + p1.setCompositionMode(QPainter::CompositionMode_Source); + + /* + if (viewBegin != 0) + p1.translate(-viewBegin, 0); + if (d_ptr->m_zoom != 1) + p1.scale(d_ptr->m_zoom, 1); + */ + p1.fillRect(0, 0, w, 1, lg); + + p.fillRect(QRectF(0, d_ptr->m_handleSize, w, h), QPixmap::fromImage(img)); + } + + + double handleWidth = d_ptr->m_handleSize * d_ptr->m_scaleFactor / (w * (d_ptr->m_scaleFactor + max)); + + QColor insideColor = QColor::fromRgb(0x20, 0x20, 0x20, 0xFF); + QColor borderColor = QColor(Qt::white); + QColor drawColor; + QColor back1 = QColor(Qt::lightGray); + QColor back2 = QColor(Qt::darkGray); + QColor back = QColor::fromRgb((back1.red() + back2.red()) / 2, + (back1.green() + back2.green()) / 2, + (back1.blue() + back2.blue()) / 2); + + QPen pen; + p.setRenderHint(QPainter::Antialiasing); + QListIterator<QtGradientStop *> itStop(d_ptr->m_stops); + itStop.toBack(); + while (itStop.hasPrevious()) { + QtGradientStop *stop = itStop.previous(); + double x = stop->position(); + if (x >= begin - handleWidth / 2 && x <= end + handleWidth / 2) { + double viewX = x * w * (d_ptr->m_scaleFactor + max) / d_ptr->m_scaleFactor - viewBegin; + p.save(); + QColor c = stop->color(); +#ifndef QT_NO_DRAGANDDROP + if (stop == d_ptr->m_dragStop) + c = d_ptr->m_dragColor; +#endif + if ((0.3 * c.redF() + 0.59 * c.greenF() + 0.11 * c.blueF()) * c.alphaF() + + (0.3 * back.redF() + 0.59 * back.greenF() + 0.11 * back.blueF()) * (1.0 - c.alphaF()) < 0.5) { + drawColor = QColor::fromRgb(0xC0, 0xC0, 0xC0, 0xB0); + } else { + drawColor = QColor::fromRgb(0x40, 0x40, 0x40, 0x80); + } + QRectF rect(viewX - d_ptr->m_handleSize / 2, 0, d_ptr->m_handleSize, d_ptr->m_handleSize); + rect.adjust(0.5, 0.5, -0.5, -0.5); + if (h > 0) { + pen.setWidthF(1); + QLinearGradient lg(0, d_ptr->m_handleSize, 0, d_ptr->m_handleSize + h / 2); + lg.setColorAt(0, drawColor); + QColor alphaZero = drawColor; + alphaZero.setAlpha(0); + lg.setColorAt(1, alphaZero); + pen.setBrush(lg); + p.setPen(pen); + p.drawLine(QPointF(viewX, d_ptr->m_handleSize), QPointF(viewX, d_ptr->m_handleSize + h / 2)); + + pen.setWidthF(1); + pen.setBrush(drawColor); + p.setPen(pen); + QRectF r1 = rect.adjusted(0.5, 0.5, -0.5, -0.5); + QRectF r2 = rect.adjusted(1.5, 1.5, -1.5, -1.5); + QColor inColor = QColor::fromRgb(0x80, 0x80, 0x80, 0x80); + if (!d_ptr->m_model->isSelected(stop)) { + p.setBrush(c); + p.drawEllipse(rect); + } else { + pen.setBrush(insideColor); + pen.setWidthF(2); + p.setPen(pen); + p.setBrush(Qt::NoBrush); + p.drawEllipse(r1); + + pen.setBrush(inColor); + pen.setWidthF(1); + p.setPen(pen); + p.setBrush(c); + p.drawEllipse(r2); + } + + if (d_ptr->m_model->currentStop() == stop) { + p.setBrush(Qt::NoBrush); + pen.setWidthF(5); + pen.setBrush(drawColor); + int corr = 4; + if (!d_ptr->m_model->isSelected(stop)) { + corr = 3; + pen.setWidthF(7); + } + p.setPen(pen); + p.drawEllipse(rect.adjusted(corr, corr, -corr, -corr)); + } + + } + p.restore(); + } + } + if (d_ptr->m_backgroundCheckered) { + p.end(); + p.begin(viewport()); + p.drawPixmap(0, 0, pix); + } + p.end(); +} + +void QtGradientStopsWidget::focusInEvent(QFocusEvent *e) +{ + Q_UNUSED(e) + viewport()->update(); +} + +void QtGradientStopsWidget::focusOutEvent(QFocusEvent *e) +{ + Q_UNUSED(e) + viewport()->update(); +} + +void QtGradientStopsWidget::contextMenuEvent(QContextMenuEvent *e) +{ + if (!d_ptr->m_model) + return; + + d_ptr->m_clickPos = e->pos(); + + QMenu menu(this); + QAction *newStopAction = new QAction(tr("New Stop"), &menu); + QAction *deleteAction = new QAction(tr("Delete"), &menu); + QAction *flipAllAction = new QAction(tr("Flip All"), &menu); + QAction *selectAllAction = new QAction(tr("Select All"), &menu); + QAction *zoomInAction = new QAction(tr("Zoom In"), &menu); + QAction *zoomOutAction = new QAction(tr("Zoom Out"), &menu); + QAction *zoomAllAction = new QAction(tr("Reset Zoom"), &menu); + if (d_ptr->m_model->selectedStops().isEmpty() && !d_ptr->m_model->currentStop()) + deleteAction->setEnabled(false); + if (zoom() <= 1) { + zoomOutAction->setEnabled(false); + zoomAllAction->setEnabled(false); + } else if (zoom() >= 100) { + zoomInAction->setEnabled(false); + } + connect(newStopAction, SIGNAL(triggered()), this, SLOT(slotNewStop())); + connect(deleteAction, SIGNAL(triggered()), this, SLOT(slotDelete())); + connect(flipAllAction, SIGNAL(triggered()), this, SLOT(slotFlipAll())); + connect(selectAllAction, SIGNAL(triggered()), this, SLOT(slotSelectAll())); + connect(zoomInAction, SIGNAL(triggered()), this, SLOT(slotZoomIn())); + connect(zoomOutAction, SIGNAL(triggered()), this, SLOT(slotZoomOut())); + connect(zoomAllAction, SIGNAL(triggered()), this, SLOT(slotResetZoom())); + menu.addAction(newStopAction); + menu.addAction(deleteAction); + menu.addAction(flipAllAction); + menu.addAction(selectAllAction); + menu.addSeparator(); + menu.addAction(zoomInAction); + menu.addAction(zoomOutAction); + menu.addAction(zoomAllAction); + menu.exec(e->globalPos()); +} + +void QtGradientStopsWidget::wheelEvent(QWheelEvent *e) +{ + int numDegrees = e->delta() / 8; + int numSteps = numDegrees / 15; + + int shift = numSteps; + if (shift < 0) + shift = -shift; + int pow = 1 << shift; + //const double c = 0.7071067; // 2 steps per doubled value + const double c = 0.5946036; // 4 steps pre doubled value + // in general c = pow(2, 1 / n) / 2; where n is the step + double factor = pow * c; + + double newZoom = zoom(); + if (numSteps < 0) + newZoom /= factor; + else + newZoom *= factor; + if (newZoom > 100) + newZoom = 100; + if (newZoom < 1) + newZoom = 1; + + if (newZoom == zoom()) + return; + + setZoom(newZoom); + emit zoomChanged(zoom()); +} + +#ifndef QT_NO_DRAGANDDROP +void QtGradientStopsWidget::dragEnterEvent(QDragEnterEvent *event) +{ + const QMimeData *mime = event->mimeData(); + if (!mime->hasColor()) + return; + event->accept(); + d_ptr->m_dragModel = d_ptr->m_model->clone(); + + d_ptr->m_dragColor = qvariant_cast<QColor>(mime->colorData()); + update(); +} + +void QtGradientStopsWidget::dragMoveEvent(QDragMoveEvent *event) +{ + QRectF rect = viewport()->rect(); + rect.adjust(0, d_ptr->m_handleSize, 0, 0); + double x = d_ptr->fromViewport(event->pos().x()); + QtGradientStop *dragStop = d_ptr->stopAt(event->pos()); + if (dragStop) { + event->accept(); + d_ptr->removeClonedStop(); + d_ptr->changeStop(dragStop->position()); + } else if (rect.contains(event->pos())) { + event->accept(); + if (d_ptr->m_model->at(x)) { + d_ptr->removeClonedStop(); + d_ptr->changeStop(x); + } else { + d_ptr->restoreChangedStop(); + d_ptr->cloneStop(x); + } + } else { + event->ignore(); + d_ptr->removeClonedStop(); + d_ptr->restoreChangedStop(); + } + + update(); +} + +void QtGradientStopsWidget::dragLeaveEvent(QDragLeaveEvent *event) +{ + event->accept(); + d_ptr->clearDrag(); + update(); +} + +void QtGradientStopsWidget::dropEvent(QDropEvent *event) +{ + event->accept(); + if (!d_ptr->m_dragModel) + return; + + if (d_ptr->m_changedStop) + d_ptr->m_model->changeStop(d_ptr->m_model->at(d_ptr->m_changedStop->position()), d_ptr->m_dragColor); + else if (d_ptr->m_clonedStop) + d_ptr->m_model->addStop(d_ptr->m_clonedStop->position(), d_ptr->m_dragColor); + + d_ptr->clearDrag(); + update(); +} + +void QtGradientStopsWidgetPrivate::clearDrag() +{ + removeClonedStop(); + restoreChangedStop(); + delete m_dragModel; + m_dragModel = 0; +} + +void QtGradientStopsWidgetPrivate::removeClonedStop() +{ + if (!m_clonedStop) + return; + m_dragModel->removeStop(m_clonedStop); + m_clonedStop = 0; +} + +void QtGradientStopsWidgetPrivate::restoreChangedStop() +{ + if (!m_changedStop) + return; + m_dragModel->changeStop(m_changedStop, m_model->at(m_changedStop->position())->color()); + m_changedStop = 0; + m_dragStop = 0; +} + +void QtGradientStopsWidgetPrivate::changeStop(qreal pos) +{ + QtGradientStop *stop = m_dragModel->at(pos); + if (!stop) + return; + + m_dragModel->changeStop(stop, m_dragColor); + m_changedStop = stop; + m_dragStop = m_model->at(stop->position()); +} + +void QtGradientStopsWidgetPrivate::cloneStop(qreal pos) +{ + if (m_clonedStop) { + m_dragModel->moveStop(m_clonedStop, pos); + return; + } + QtGradientStop *stop = m_dragModel->at(pos); + if (stop) + return; + + m_clonedStop = m_dragModel->addStop(pos, m_dragColor); +} + +#endif + +void QtGradientStopsWidget::setZoom(double zoom) +{ + double z = zoom; + if (z < 1) + z = 1; + else if (z > 100) + z = 100; + + if (d_ptr->m_zoom == z) + return; + + d_ptr->m_zoom = z; + int oldMax = horizontalScrollBar()->maximum(); + int oldVal = horizontalScrollBar()->value(); + horizontalScrollBar()->setRange(0, qRound(d_ptr->m_scaleFactor * (d_ptr->m_zoom - 1))); + int newMax = horizontalScrollBar()->maximum(); + double newVal = (oldVal + (double)d_ptr->m_scaleFactor / 2) * (newMax + d_ptr->m_scaleFactor) + / (oldMax + d_ptr->m_scaleFactor) - (double)d_ptr->m_scaleFactor / 2; + horizontalScrollBar()->setValue(qRound(newVal)); + viewport()->update(); +} + +double QtGradientStopsWidget::zoom() const +{ + return d_ptr->m_zoom; +} + +QT_END_NAMESPACE + +#include "moc_qtgradientstopswidget.cpp" diff --git a/tools/shared/qtgradienteditor/qtgradientstopswidget.h b/tools/shared/qtgradienteditor/qtgradientstopswidget.h new file mode 100644 index 0000000..aafea8b --- /dev/null +++ b/tools/shared/qtgradienteditor/qtgradientstopswidget.h @@ -0,0 +1,115 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the tools applications of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QTGRADIENTSTOPSWIDGET_H +#define QTGRADIENTSTOPSWIDGET_H + +#include <QtGui/QAbstractScrollArea> + +QT_BEGIN_NAMESPACE + +class QtGradientStopsModel; +class QtGradientStopsWidgetPrivate; + +class QtGradientStopsWidget : public QAbstractScrollArea +{ + Q_OBJECT + Q_PROPERTY(bool backgroundCheckered READ isBackgroundCheckered WRITE setBackgroundCheckered) +public: + QtGradientStopsWidget(QWidget *parent = 0); + ~QtGradientStopsWidget(); + + QSize minimumSizeHint() const; + QSize sizeHint() const; + + bool isBackgroundCheckered() const; + void setBackgroundCheckered(bool checkered); + + void setGradientStopsModel(QtGradientStopsModel *model); + + void setZoom(double zoom); + double zoom() const; + +signals: + + void zoomChanged(double zoom); + +protected: + void paintEvent(QPaintEvent *e); + void mousePressEvent(QMouseEvent *e); + void mouseReleaseEvent(QMouseEvent *e); + void mouseMoveEvent(QMouseEvent *e); + void mouseDoubleClickEvent(QMouseEvent *e); + void keyPressEvent(QKeyEvent *e); + void focusInEvent(QFocusEvent *e); + void focusOutEvent(QFocusEvent *e); + void contextMenuEvent(QContextMenuEvent *e); + void wheelEvent(QWheelEvent *e); +#ifndef QT_NO_DRAGANDDROP + void dragEnterEvent(QDragEnterEvent *event); + void dragMoveEvent(QDragMoveEvent *event); + void dragLeaveEvent(QDragLeaveEvent *event); + void dropEvent(QDropEvent *event); +#endif + +private: + QtGradientStopsWidgetPrivate *d_ptr; + Q_DECLARE_PRIVATE(QtGradientStopsWidget) + Q_DISABLE_COPY(QtGradientStopsWidget) + Q_PRIVATE_SLOT(d_func(), void slotStopAdded(QtGradientStop *stop)) + Q_PRIVATE_SLOT(d_func(), void slotStopRemoved(QtGradientStop *stop)) + Q_PRIVATE_SLOT(d_func(), void slotStopMoved(QtGradientStop *stop, qreal newPos)) + Q_PRIVATE_SLOT(d_func(), void slotStopsSwapped(QtGradientStop *stop1, QtGradientStop *stop2)) + Q_PRIVATE_SLOT(d_func(), void slotStopChanged(QtGradientStop *stop, const QColor &newColor)) + Q_PRIVATE_SLOT(d_func(), void slotStopSelected(QtGradientStop *stop, bool selected)) + Q_PRIVATE_SLOT(d_func(), void slotCurrentStopChanged(QtGradientStop *stop)) + Q_PRIVATE_SLOT(d_func(), void slotNewStop()) + Q_PRIVATE_SLOT(d_func(), void slotDelete()) + Q_PRIVATE_SLOT(d_func(), void slotFlipAll()) + Q_PRIVATE_SLOT(d_func(), void slotSelectAll()) + Q_PRIVATE_SLOT(d_func(), void slotZoomIn()) + Q_PRIVATE_SLOT(d_func(), void slotZoomOut()) + Q_PRIVATE_SLOT(d_func(), void slotResetZoom()) +}; + +QT_END_NAMESPACE + +#endif diff --git a/tools/shared/qtgradienteditor/qtgradientutils.cpp b/tools/shared/qtgradienteditor/qtgradientutils.cpp new file mode 100644 index 0000000..2456233 --- /dev/null +++ b/tools/shared/qtgradienteditor/qtgradientutils.cpp @@ -0,0 +1,420 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the tools applications of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qtgradientutils.h" +#include "qtgradientmanager.h" +#include <QtGui/QLinearGradient> +#include <QtGui/QRadialGradient> +#include <QtGui/QConicalGradient> +#include <QtXml/QDomDocument> +#include <QtCore/QDebug> + +QT_BEGIN_NAMESPACE + +static QString gradientTypeToString(QGradient::Type type) +{ + if (type == QGradient::LinearGradient) + return QLatin1String("LinearGradient"); + if (type == QGradient::RadialGradient) + return QLatin1String("RadialGradient"); + if (type == QGradient::ConicalGradient) + return QLatin1String("ConicalGradient"); + return QLatin1String("NoGradient"); +} + +static QGradient::Type stringToGradientType(const QString &name) +{ + if (name == QLatin1String("LinearGradient")) + return QGradient::LinearGradient; + if (name == QLatin1String("RadialGradient")) + return QGradient::RadialGradient; + if (name == QLatin1String("ConicalGradient")) + return QGradient::ConicalGradient; + return QGradient::NoGradient; +} + +static QString gradientSpreadToString(QGradient::Spread spread) +{ + if (spread == QGradient::PadSpread) + return QLatin1String("PadSpread"); + if (spread == QGradient::RepeatSpread) + return QLatin1String("RepeatSpread"); + if (spread == QGradient::ReflectSpread) + return QLatin1String("ReflectSpread"); + return QLatin1String("PadSpread"); +} + +static QGradient::Spread stringToGradientSpread(const QString &name) +{ + if (name == QLatin1String("PadSpread")) + return QGradient::PadSpread; + if (name == QLatin1String("RepeatSpread")) + return QGradient::RepeatSpread; + if (name == QLatin1String("ReflectSpread")) + return QGradient::ReflectSpread; + return QGradient::PadSpread; +} + +static QString gradientCoordinateModeToString(QGradient::CoordinateMode mode) +{ + if (mode == QGradient::LogicalMode) + return QLatin1String("LogicalMode"); + if (mode == QGradient::StretchToDeviceMode) + return QLatin1String("StretchToDeviceMode"); + if (mode == QGradient::ObjectBoundingMode) + return QLatin1String("ObjectBoundingMode"); + return QLatin1String("StretchToDeviceMode"); +} + +static QGradient::CoordinateMode stringToGradientCoordinateMode(const QString &name) +{ + if (name == QLatin1String("LogicalMode")) + return QGradient::LogicalMode; + if (name == QLatin1String("StretchToDeviceMode")) + return QGradient::StretchToDeviceMode; + if (name == QLatin1String("ObjectBoundingMode")) + return QGradient::ObjectBoundingMode; + return QGradient::StretchToDeviceMode; +} + +static QDomElement saveColor(QDomDocument &doc, const QColor &color) +{ + QDomElement colorElem = doc.createElement(QLatin1String("colorData")); + + colorElem.setAttribute(QLatin1String("r"), QString::number(color.red())); + colorElem.setAttribute(QLatin1String("g"), QString::number(color.green())); + colorElem.setAttribute(QLatin1String("b"), QString::number(color.blue())); + colorElem.setAttribute(QLatin1String("a"), QString::number(color.alpha())); + + return colorElem; +} + +static QDomElement saveGradientStop(QDomDocument &doc, const QGradientStop &stop) +{ + QDomElement stopElem = doc.createElement(QLatin1String("stopData")); + + stopElem.setAttribute(QLatin1String("position"), QString::number(stop.first)); + + const QDomElement colorElem = saveColor(doc, stop.second); + stopElem.appendChild(colorElem); + + return stopElem; +} + +static QDomElement saveGradient(QDomDocument &doc, const QGradient &gradient) +{ + QDomElement gradElem = doc.createElement(QLatin1String("gradientData")); + + const QGradient::Type type = gradient.type(); + gradElem.setAttribute(QLatin1String("type"), gradientTypeToString(type)); + gradElem.setAttribute(QLatin1String("spread"), gradientSpreadToString(gradient.spread())); + gradElem.setAttribute(QLatin1String("coordinateMode"), gradientCoordinateModeToString(gradient.coordinateMode())); + + QGradientStops stops = gradient.stops(); + QVectorIterator<QGradientStop > it(stops); + while (it.hasNext()) + gradElem.appendChild(saveGradientStop(doc, it.next())); + + if (type == QGradient::LinearGradient) { + const QLinearGradient &g = *static_cast<const QLinearGradient *>(&gradient); + gradElem.setAttribute(QLatin1String("startX"), QString::number(g.start().x())); + gradElem.setAttribute(QLatin1String("startY"), QString::number(g.start().y())); + gradElem.setAttribute(QLatin1String("endX"), QString::number(g.finalStop().x())); + gradElem.setAttribute(QLatin1String("endY"), QString::number(g.finalStop().y())); + } else if (type == QGradient::RadialGradient) { + const QRadialGradient &g = *static_cast<const QRadialGradient *>(&gradient); + gradElem.setAttribute(QLatin1String("centerX"), QString::number(g.center().x())); + gradElem.setAttribute(QLatin1String("centerY"), QString::number(g.center().y())); + gradElem.setAttribute(QLatin1String("focalX"), QString::number(g.focalPoint().x())); + gradElem.setAttribute(QLatin1String("focalY"), QString::number(g.focalPoint().y())); + gradElem.setAttribute(QLatin1String("radius"), QString::number(g.radius())); + } else if (type == QGradient::ConicalGradient) { + const QConicalGradient &g = *static_cast<const QConicalGradient*>(&gradient); + gradElem.setAttribute(QLatin1String("centerX"), QString::number(g.center().x())); + gradElem.setAttribute(QLatin1String("centerY"), QString::number(g.center().y())); + gradElem.setAttribute(QLatin1String("angle"), QString::number(g.angle())); + } + + return gradElem; +} + +static QColor loadColor(const QDomElement &elem) +{ + if (elem.tagName() != QLatin1String("colorData")) + return QColor(); + + return QColor(elem.attribute(QLatin1String("r")).toInt(), + elem.attribute(QLatin1String("g")).toInt(), + elem.attribute(QLatin1String("b")).toInt(), + elem.attribute(QLatin1String("a")).toInt()); +} + +static QGradientStop loadGradientStop(const QDomElement &elem) +{ + if (elem.tagName() != QLatin1String("stopData")) + return QGradientStop(); + + const qreal pos = static_cast<qreal>(elem.attribute(QLatin1String("position")).toDouble()); + return qMakePair(pos, loadColor(elem.firstChild().toElement())); +} + +static QGradient loadGradient(const QDomElement &elem) +{ + if (elem.tagName() != QLatin1String("gradientData")) + return QLinearGradient(); + + const QGradient::Type type = stringToGradientType(elem.attribute(QLatin1String("type"))); + const QGradient::Spread spread = stringToGradientSpread(elem.attribute(QLatin1String("spread"))); + const QGradient::CoordinateMode mode = stringToGradientCoordinateMode(elem.attribute(QLatin1String("coordinateMode"))); + + QGradient gradient = QLinearGradient(); + + if (type == QGradient::LinearGradient) { + QLinearGradient g; + g.setStart(elem.attribute(QLatin1String("startX")).toDouble(), elem.attribute(QLatin1String("startY")).toDouble()); + g.setFinalStop(elem.attribute(QLatin1String("endX")).toDouble(), elem.attribute(QLatin1String("endY")).toDouble()); + gradient = g; + } else if (type == QGradient::RadialGradient) { + QRadialGradient g; + g.setCenter(elem.attribute(QLatin1String("centerX")).toDouble(), elem.attribute(QLatin1String("centerY")).toDouble()); + g.setFocalPoint(elem.attribute(QLatin1String("focalX")).toDouble(), elem.attribute(QLatin1String("focalY")).toDouble()); + g.setRadius(elem.attribute(QLatin1String("radius")).toDouble()); + gradient = g; + } else if (type == QGradient::ConicalGradient) { + QConicalGradient g; + g.setCenter(elem.attribute(QLatin1String("centerX")).toDouble(), elem.attribute(QLatin1String("centerY")).toDouble()); + g.setAngle(elem.attribute(QLatin1String("angle")).toDouble()); + gradient = g; + } + + QDomElement stopElem = elem.firstChildElement(); + while (!stopElem.isNull()) { + QGradientStop stop = loadGradientStop(stopElem); + + gradient.setColorAt(stop.first, stop.second); + + stopElem = stopElem.nextSiblingElement(); + } + + gradient.setSpread(spread); + gradient.setCoordinateMode(mode); + + return gradient; +} + +QString QtGradientUtils::saveState(const QtGradientManager *manager) +{ + QDomDocument doc; + + QDomElement rootElem = doc.createElement(QLatin1String("gradients")); + + QMap<QString, QGradient> grads = manager->gradients(); + QMapIterator<QString, QGradient> itGrad(grads); + while (itGrad.hasNext()) { + itGrad.next(); + QDomElement idElem = doc.createElement(QLatin1String("gradient")); + idElem.setAttribute(QLatin1String("name"), itGrad.key()); + QDomElement gradElem = saveGradient(doc, itGrad.value()); + idElem.appendChild(gradElem); + + rootElem.appendChild(idElem); + } + + doc.appendChild(rootElem); + + return doc.toString(); +} + +void QtGradientUtils::restoreState(QtGradientManager *manager, const QString &state) +{ + manager->clear(); + + QDomDocument doc; + doc.setContent(state); + + QDomElement rootElem = doc.documentElement(); + + QDomElement gradElem = rootElem.firstChildElement(); + while (!gradElem.isNull()) { + const QString name = gradElem.attribute(QLatin1String("name")); + const QGradient gradient = loadGradient(gradElem.firstChildElement()); + + manager->addGradient(name, gradient); + gradElem = gradElem.nextSiblingElement(); + } +} + +QPixmap QtGradientUtils::gradientPixmap(const QGradient &gradient, const QSize &size, bool checkeredBackground) +{ + QImage image(size, QImage::Format_ARGB32); + QPainter p(&image); + p.setCompositionMode(QPainter::CompositionMode_Source); + + if (checkeredBackground) { + int pixSize = 20; + QPixmap pm(2 * pixSize, 2 * pixSize); + + QPainter pmp(&pm); + pmp.fillRect(0, 0, pixSize, pixSize, Qt::lightGray); + pmp.fillRect(pixSize, pixSize, pixSize, pixSize, Qt::lightGray); + pmp.fillRect(0, pixSize, pixSize, pixSize, Qt::darkGray); + pmp.fillRect(pixSize, 0, pixSize, pixSize, Qt::darkGray); + + p.setBrushOrigin((size.width() % pixSize + pixSize) / 2, (size.height() % pixSize + pixSize) / 2); + p.fillRect(0, 0, size.width(), size.height(), pm); + p.setBrushOrigin(0, 0); + p.setCompositionMode(QPainter::CompositionMode_SourceOver); + } + + const qreal scaleFactor = 0.999999; + p.scale(scaleFactor, scaleFactor); + QGradient grad = gradient; + grad.setCoordinateMode(QGradient::StretchToDeviceMode); + p.fillRect(QRect(0, 0, size.width(), size.height()), grad); + p.drawRect(QRect(0, 0, size.width() - 1, size.height() - 1)); + + return QPixmap::fromImage(image); +} + +static QString styleSheetFillName(const QGradient &gradient) +{ + QString result; + + switch (gradient.type()) { + case QGradient::LinearGradient: + result += QLatin1String("qlineargradient"); + break; + case QGradient::RadialGradient: + result += QLatin1String("qradialgradient"); + break; + case QGradient::ConicalGradient: + result += QLatin1String("qconicalgradient"); + break; + default: + qWarning() << "QtGradientUtils::styleSheetFillName(): gradient type" << gradient.type() << "not supported!"; + break; + } + + return result; +} + +static QStringList styleSheetParameters(const QGradient &gradient) +{ + QStringList result; + + if (gradient.type() != QGradient::ConicalGradient) { + QString spread; + switch (gradient.spread()) { + case QGradient::PadSpread: + spread = QLatin1String("pad"); + break; + case QGradient::ReflectSpread: + spread = QLatin1String("reflect"); + break; + case QGradient::RepeatSpread: + spread = QLatin1String("repeat"); + break; + default: + qWarning() << "QtGradientUtils::styleSheetParameters(): gradient spread" << gradient.spread() << "not supported!"; + break; + } + result << QLatin1String("spread:") + spread; + } + + switch (gradient.type()) { + case QGradient::LinearGradient: { + const QLinearGradient *linearGradient = static_cast<const QLinearGradient*>(&gradient); + result << QLatin1String("x1:") + QString::number(linearGradient->start().x()) + << QLatin1String("y1:") + QString::number(linearGradient->start().y()) + << QLatin1String("x2:") + QString::number(linearGradient->finalStop().x()) + << QLatin1String("y2:") + QString::number(linearGradient->finalStop().y()); + break; + } + case QGradient::RadialGradient: { + const QRadialGradient *radialGradient = static_cast<const QRadialGradient*>(&gradient); + result << QLatin1String("cx:") + QString::number(radialGradient->center().x()) + << QLatin1String("cy:") + QString::number(radialGradient->center().y()) + << QLatin1String("radius:") + QString::number(radialGradient->radius()) + << QLatin1String("fx:") + QString::number(radialGradient->focalPoint().x()) + << QLatin1String("fy:") + QString::number(radialGradient->focalPoint().y()); + break; + } + case QGradient::ConicalGradient: { + const QConicalGradient *conicalGradient = static_cast<const QConicalGradient*>(&gradient); + result << QLatin1String("cx:") + QString::number(conicalGradient->center().x()) + << QLatin1String("cy:") + QString::number(conicalGradient->center().y()) + << QLatin1String("angle:") + QString::number(conicalGradient->angle()); + break; + } + default: + qWarning() << "QtGradientUtils::styleSheetParameters(): gradient type" << gradient.type() << "not supported!"; + break; + } + + return result; +} + +static QStringList styleSheetStops(const QGradient &gradient) +{ + QStringList result; + foreach (QGradientStop stop, gradient.stops()) { + const QColor color = stop.second; + + const QString stopDescription = QLatin1String("stop:") + QString::number(stop.first) + QLatin1String(" rgba(") + + QString::number(color.red()) + QLatin1String(", ") + + QString::number(color.green()) + QLatin1String(", ") + + QString::number(color.blue()) + QLatin1String(", ") + + QString::number(color.alpha()) + QLatin1Char(')'); + result << stopDescription; + } + + return result; +} + +QString QtGradientUtils::styleSheetCode(const QGradient &gradient) +{ + QStringList gradientParameters; + gradientParameters << styleSheetParameters(gradient) << styleSheetStops(gradient); + + return styleSheetFillName(gradient) + QLatin1Char('(') + gradientParameters.join(QLatin1String(", ")) + QLatin1Char(')'); +} + +QT_END_NAMESPACE diff --git a/tools/shared/qtgradienteditor/qtgradientutils.h b/tools/shared/qtgradienteditor/qtgradientutils.h new file mode 100644 index 0000000..2e35652 --- /dev/null +++ b/tools/shared/qtgradienteditor/qtgradientutils.h @@ -0,0 +1,66 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the tools applications of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef GRADIENTUTILS_H +#define GRADIENTUTILS_H + +#include <QtGui/QGradient> +#include <QtGui/QPainter> + +QT_BEGIN_NAMESPACE + +class QtGradientManager; + +class QtGradientUtils +{ +public: + static QString styleSheetCode(const QGradient &gradient); + // utils methods, they could be outside of this class + static QString saveState(const QtGradientManager *manager); + static void restoreState(QtGradientManager *manager, const QString &state); + + static QPixmap gradientPixmap(const QGradient &gradient, const QSize &size = QSize(64, 64), bool checkeredBackground = false); + +}; + +QT_END_NAMESPACE + +#endif diff --git a/tools/shared/qtgradienteditor/qtgradientview.cpp b/tools/shared/qtgradienteditor/qtgradientview.cpp new file mode 100644 index 0000000..ac8ed17 --- /dev/null +++ b/tools/shared/qtgradienteditor/qtgradientview.cpp @@ -0,0 +1,292 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the tools applications of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qtgradientview.h" +#include "qtgradientmanager.h" +#include "qtgradientdialog.h" +#include "qtgradientutils.h" +#include <QtGui/QPainter> +#include <QtGui/QMessageBox> +#include <QtGui/QClipboard> + +QT_BEGIN_NAMESPACE + +void QtGradientView::slotGradientAdded(const QString &id, const QGradient &gradient) +{ + QListWidgetItem *item = new QListWidgetItem(QtGradientUtils::gradientPixmap(gradient), id, m_ui.listWidget); + item->setToolTip(id); + item->setSizeHint(QSize(72, 84)); + item->setFlags(item->flags() | Qt::ItemIsEditable); + + m_idToItem[id] = item; + m_itemToId[item] = id; +} + +void QtGradientView::slotGradientRenamed(const QString &id, const QString &newId) +{ + if (!m_idToItem.contains(id)) + return; + + QListWidgetItem *item = m_idToItem.value(id); + item->setText(newId); + item->setToolTip(newId); + m_itemToId[item] = newId; + m_idToItem.remove(id); + m_idToItem[newId] = item; +} + +void QtGradientView::slotGradientChanged(const QString &id, const QGradient &newGradient) +{ + if (!m_idToItem.contains(id)) + return; + + QListWidgetItem *item = m_idToItem.value(id); + item->setIcon(QtGradientUtils::gradientPixmap(newGradient)); +} + +void QtGradientView::slotGradientRemoved(const QString &id) +{ + if (!m_idToItem.contains(id)) + return; + + QListWidgetItem *item = m_idToItem.value(id); + delete item; + m_itemToId.remove(item); + m_idToItem.remove(id); +} + +void QtGradientView::slotNewGradient() +{ + bool ok; + QListWidgetItem *item = m_ui.listWidget->currentItem(); + QGradient grad = QLinearGradient(); + if (item) + grad = m_manager->gradients().value(m_itemToId.value(item)); + QGradient gradient = QtGradientDialog::getGradient(&ok, grad, this); + if (!ok) + return; + + QString id = m_manager->addGradient(tr("Grad"), gradient); + m_ui.listWidget->setCurrentItem(m_idToItem.value(id)); +} + +void QtGradientView::slotEditGradient() +{ + bool ok; + QListWidgetItem *item = m_ui.listWidget->currentItem(); + if (!item) + return; + + const QString id = m_itemToId.value(item); + QGradient grad = m_manager->gradients().value(id); + QGradient gradient = QtGradientDialog::getGradient(&ok, grad, this); + if (!ok) + return; + + m_manager->changeGradient(id, gradient); +} + +void QtGradientView::slotRemoveGradient() +{ + QListWidgetItem *item = m_ui.listWidget->currentItem(); + if (!item) + return; + + if (QMessageBox::question(this, tr("Remove Gradient"), + tr("Are you sure you want to remove the selected gradient?"), + QMessageBox::Yes | QMessageBox::Cancel, QMessageBox::Cancel) != QMessageBox::Yes) + return; + + const QString id = m_itemToId.value(item); + m_manager->removeGradient(id); +} + +void QtGradientView::slotRenameGradient() +{ + QListWidgetItem *item = m_ui.listWidget->currentItem(); + if (!item) + return; + + m_ui.listWidget->editItem(item); +} + +void QtGradientView::slotRenameGradient(QListWidgetItem *item) +{ + if (!item) + return; + + const QString id = m_itemToId.value(item); + m_manager->renameGradient(id, item->text()); +} + +void QtGradientView::slotCurrentItemChanged(QListWidgetItem *item) +{ + m_editAction->setEnabled(item); + m_renameAction->setEnabled(item); + m_removeAction->setEnabled(item); + emit currentGradientChanged(m_itemToId.value(item)); +} + +void QtGradientView::slotGradientActivated(QListWidgetItem *item) +{ + const QString id = m_itemToId.value(item); + if (!id.isEmpty()) + emit gradientActivated(id); +} + +QtGradientView::QtGradientView(QWidget *parent) + : QWidget(parent) +{ + m_manager = 0; + + m_ui.setupUi(this); + + m_ui.listWidget->setViewMode(QListView::IconMode); + m_ui.listWidget->setMovement(QListView::Static); + m_ui.listWidget->setTextElideMode(Qt::ElideRight); + m_ui.listWidget->setResizeMode(QListWidget::Adjust); + m_ui.listWidget->setIconSize(QSize(64, 64)); + m_ui.listWidget->setEditTriggers(QAbstractItemView::NoEditTriggers); + + QPalette pal = m_ui.listWidget->viewport()->palette(); + int pixSize = 18; + QPixmap pm(2 * pixSize, 2 * pixSize); + + QColor c1 = palette().color(QPalette::Midlight); + QColor c2 = palette().color(QPalette::Dark); + QPainter pmp(&pm); + pmp.fillRect(0, 0, pixSize, pixSize, c1); + pmp.fillRect(pixSize, pixSize, pixSize, pixSize, c1); + pmp.fillRect(0, pixSize, pixSize, pixSize, c2); + pmp.fillRect(pixSize, 0, pixSize, pixSize, c2); + + pal.setBrush(QPalette::Base, QBrush(pm)); + m_ui.listWidget->viewport()->setPalette(pal); + + connect(m_ui.listWidget, SIGNAL(itemDoubleClicked(QListWidgetItem *)), this, SLOT(slotGradientActivated(QListWidgetItem *))); + connect(m_ui.listWidget, SIGNAL(itemChanged(QListWidgetItem *)), this, SLOT(slotRenameGradient(QListWidgetItem *))); + connect(m_ui.listWidget, SIGNAL(currentItemChanged(QListWidgetItem *, QListWidgetItem *)), this, SLOT(slotCurrentItemChanged(QListWidgetItem *))); + + m_newAction = new QAction(QIcon(QLatin1String(":/trolltech/qtgradienteditor/images/plus.png")), tr("New..."), this); + m_editAction = new QAction(QIcon(QLatin1String(":/trolltech/qtgradienteditor/images/edit.png")), tr("Edit..."), this); + m_renameAction = new QAction(tr("Rename"), this); + m_removeAction = new QAction(QIcon(QLatin1String(":/trolltech/qtgradienteditor/images/minus.png")), tr("Remove"), this); + + connect(m_newAction, SIGNAL(triggered()), this, SLOT(slotNewGradient())); + connect(m_editAction, SIGNAL(triggered()), this, SLOT(slotEditGradient())); + connect(m_removeAction, SIGNAL(triggered()), this, SLOT(slotRemoveGradient())); + connect(m_renameAction, SIGNAL(triggered()), this, SLOT(slotRenameGradient())); + + m_ui.listWidget->addAction(m_newAction); + m_ui.listWidget->addAction(m_editAction); + m_ui.listWidget->addAction(m_renameAction); + m_ui.listWidget->addAction(m_removeAction); + + m_ui.newButton->setDefaultAction(m_newAction); + m_ui.editButton->setDefaultAction(m_editAction); + m_ui.renameButton->setDefaultAction(m_renameAction); + m_ui.removeButton->setDefaultAction(m_removeAction); + + m_ui.listWidget->setContextMenuPolicy(Qt::ActionsContextMenu); +} + +void QtGradientView::setGradientManager(QtGradientManager *manager) +{ + if (m_manager == manager) + return; + + if (m_manager) { + disconnect(m_manager, SIGNAL(gradientAdded(const QString &, const QGradient &)), + this, SLOT(slotGradientAdded(const QString &, const QGradient &))); + disconnect(m_manager, SIGNAL(gradientRenamed(const QString &, const QString &)), + this, SLOT(slotGradientRenamed(const QString &, const QString &))); + disconnect(m_manager, SIGNAL(gradientChanged(const QString &, const QGradient &)), + this, SLOT(slotGradientChanged(const QString &, const QGradient &))); + disconnect(m_manager, SIGNAL(gradientRemoved(const QString &)), + this, SLOT(slotGradientRemoved(const QString &))); + + m_ui.listWidget->clear(); + m_idToItem.clear(); + m_itemToId.clear(); + } + + m_manager = manager; + + if (!m_manager) + return; + + QMap<QString, QGradient> gradients = m_manager->gradients(); + QMapIterator<QString, QGradient> itGrad(gradients); + while (itGrad.hasNext()) { + itGrad.next(); + slotGradientAdded(itGrad.key(), itGrad.value()); + } + + connect(m_manager, SIGNAL(gradientAdded(const QString &, const QGradient &)), + this, SLOT(slotGradientAdded(const QString &, const QGradient &))); + connect(m_manager, SIGNAL(gradientRenamed(const QString &, const QString &)), + this, SLOT(slotGradientRenamed(const QString &, const QString &))); + connect(m_manager, SIGNAL(gradientChanged(const QString &, const QGradient &)), + this, SLOT(slotGradientChanged(const QString &, const QGradient &))); + connect(m_manager, SIGNAL(gradientRemoved(const QString &)), + this, SLOT(slotGradientRemoved(const QString &))); +} + +QtGradientManager *QtGradientView::gradientManager() const +{ + return m_manager; +} + +void QtGradientView::setCurrentGradient(const QString &id) +{ + QListWidgetItem *item = m_idToItem.value(id); + if (!item) + return; + + m_ui.listWidget->setCurrentItem(item); +} + +QString QtGradientView::currentGradient() const +{ + return m_itemToId.value(m_ui.listWidget->currentItem()); +} + +QT_END_NAMESPACE diff --git a/tools/shared/qtgradienteditor/qtgradientview.h b/tools/shared/qtgradienteditor/qtgradientview.h new file mode 100644 index 0000000..b1fafd7 --- /dev/null +++ b/tools/shared/qtgradienteditor/qtgradientview.h @@ -0,0 +1,99 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the tools applications of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef GRADIENTVIEW_H +#define GRADIENTVIEW_H + +#include <QtGui/QWidget> +#include <QtCore/QMap> +#include "ui_qtgradientview.h" + +QT_BEGIN_NAMESPACE + +class QtGradientManager; +class QListViewItem; +class QAction; + +class QtGradientView : public QWidget +{ + Q_OBJECT +public: + QtGradientView(QWidget *parent = 0); + + void setGradientManager(QtGradientManager *manager); + QtGradientManager *gradientManager() const; + + void setCurrentGradient(const QString &id); + QString currentGradient() const; + +signals: + void currentGradientChanged(const QString &id); + void gradientActivated(const QString &id); + +private slots: + void slotGradientAdded(const QString &id, const QGradient &gradient); + void slotGradientRenamed(const QString &id, const QString &newId); + void slotGradientChanged(const QString &id, const QGradient &newGradient); + void slotGradientRemoved(const QString &id); + void slotNewGradient(); + void slotEditGradient(); + void slotRemoveGradient(); + void slotRenameGradient(); + void slotRenameGradient(QListWidgetItem *item); + void slotCurrentItemChanged(QListWidgetItem *item); + void slotGradientActivated(QListWidgetItem *item); + +private: + QMap<QString, QListWidgetItem *> m_idToItem; + QMap<QListWidgetItem *, QString> m_itemToId; + + QAction *m_newAction; + QAction *m_editAction; + QAction *m_renameAction; + QAction *m_removeAction; + + QtGradientManager *m_manager; + Ui::QtGradientView m_ui; +}; + +QT_END_NAMESPACE + +#endif diff --git a/tools/shared/qtgradienteditor/qtgradientview.ui b/tools/shared/qtgradienteditor/qtgradientview.ui new file mode 100644 index 0000000..af7267e --- /dev/null +++ b/tools/shared/qtgradienteditor/qtgradientview.ui @@ -0,0 +1,135 @@ +<ui version="4.0" > + <class>QtGradientView</class> + <widget class="QWidget" name="QtGradientView" > + <property name="geometry" > + <rect> + <x>0</x> + <y>0</y> + <width>484</width> + <height>228</height> + </rect> + </property> + <property name="windowTitle" > + <string>Gradient View</string> + </property> + <layout class="QVBoxLayout" > + <property name="leftMargin" > + <number>0</number> + </property> + <property name="topMargin" > + <number>0</number> + </property> + <property name="rightMargin" > + <number>0</number> + </property> + <property name="bottomMargin" > + <number>0</number> + </property> + <item> + <layout class="QHBoxLayout" > + <item> + <widget class="QToolButton" name="newButton" > + <property name="sizePolicy" > + <sizepolicy vsizetype="Minimum" hsizetype="Minimum" > + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text" > + <string>New...</string> + </property> + <property name="toolButtonStyle" > + <enum>Qt::ToolButtonTextBesideIcon</enum> + </property> + <property name="autoRaise" > + <bool>true</bool> + </property> + </widget> + </item> + <item> + <widget class="QToolButton" name="editButton" > + <property name="sizePolicy" > + <sizepolicy vsizetype="Minimum" hsizetype="Minimum" > + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text" > + <string>Edit...</string> + </property> + <property name="toolButtonStyle" > + <enum>Qt::ToolButtonTextBesideIcon</enum> + </property> + <property name="autoRaise" > + <bool>true</bool> + </property> + </widget> + </item> + <item> + <widget class="QToolButton" name="renameButton" > + <property name="sizePolicy" > + <sizepolicy vsizetype="Minimum" hsizetype="Minimum" > + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text" > + <string>Rename</string> + </property> + <property name="toolButtonStyle" > + <enum>Qt::ToolButtonTextBesideIcon</enum> + </property> + <property name="autoRaise" > + <bool>true</bool> + </property> + </widget> + </item> + <item> + <widget class="QToolButton" name="removeButton" > + <property name="sizePolicy" > + <sizepolicy vsizetype="Minimum" hsizetype="Minimum" > + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text" > + <string>Remove</string> + </property> + <property name="toolButtonStyle" > + <enum>Qt::ToolButtonTextBesideIcon</enum> + </property> + <property name="autoRaise" > + <bool>true</bool> + </property> + </widget> + </item> + <item> + <spacer> + <property name="orientation" > + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0" > + <size> + <width>71</width> + <height>26</height> + </size> + </property> + </spacer> + </item> + </layout> + </item> + <item> + <widget class="QListWidget" name="listWidget" /> + </item> + </layout> + </widget> + <tabstops> + <tabstop>listWidget</tabstop> + <tabstop>newButton</tabstop> + <tabstop>editButton</tabstop> + <tabstop>renameButton</tabstop> + <tabstop>removeButton</tabstop> + </tabstops> + <resources/> + <connections/> +</ui> diff --git a/tools/shared/qtgradienteditor/qtgradientviewdialog.cpp b/tools/shared/qtgradienteditor/qtgradientviewdialog.cpp new file mode 100644 index 0000000..c139ec4 --- /dev/null +++ b/tools/shared/qtgradienteditor/qtgradientviewdialog.cpp @@ -0,0 +1,89 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the tools applications of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qtgradientviewdialog.h" +#include "qtgradientmanager.h" +#include <QtGui/QPushButton> + +QT_BEGIN_NAMESPACE + +QtGradientViewDialog::QtGradientViewDialog(QWidget *parent) + : QDialog(parent) +{ + m_ui.setupUi(this); + m_ui.buttonBox->button(QDialogButtonBox::Ok)->setEnabled(false); + connect(m_ui.gradientView, SIGNAL(currentGradientChanged(const QString &)), + this, SLOT(slotGradientSelected(const QString &))); + connect(m_ui.gradientView, SIGNAL(gradientActivated(const QString &)), + this, SLOT(slotGradientActivated(const QString &))); +} + +void QtGradientViewDialog::setGradientManager(QtGradientManager *manager) +{ + m_ui.gradientView->setGradientManager(manager); +} + +QGradient QtGradientViewDialog::getGradient(bool *ok, QtGradientManager *manager, QWidget *parent, const QString &caption) +{ + QtGradientViewDialog dlg(parent); + dlg.setGradientManager(manager); + dlg.setWindowTitle(caption); + QGradient grad = QLinearGradient(); + const int res = dlg.exec(); + if (res == QDialog::Accepted) + grad = dlg.m_ui.gradientView->gradientManager()->gradients().value(dlg.m_ui.gradientView->currentGradient()); + if (ok) + *ok = res == QDialog::Accepted; + return grad; +} + +void QtGradientViewDialog::slotGradientSelected(const QString &id) +{ + m_ui.buttonBox->button(QDialogButtonBox::Ok)->setEnabled(!id.isEmpty()); +} + +void QtGradientViewDialog::slotGradientActivated(const QString &id) +{ + Q_UNUSED(id) + accept(); +} + +QT_END_NAMESPACE diff --git a/tools/shared/qtgradienteditor/qtgradientviewdialog.h b/tools/shared/qtgradienteditor/qtgradientviewdialog.h new file mode 100644 index 0000000..2ec7cdd --- /dev/null +++ b/tools/shared/qtgradienteditor/qtgradientviewdialog.h @@ -0,0 +1,75 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the tools applications of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef GRADIENTVIEWDIALOG_H +#define GRADIENTVIEWDIALOG_H + +#include <QtGui/QWidget> +#include <QtCore/QMap> +#include "ui_qtgradientviewdialog.h" + +QT_BEGIN_NAMESPACE + +class QtGradientManager; + +class QtGradientViewDialog : public QDialog +{ + Q_OBJECT +public: + QtGradientViewDialog(QWidget *parent = 0); + + void setGradientManager(QtGradientManager *manager); + QtGradientManager *gradientManager() const; + + static QGradient getGradient(bool *ok, QtGradientManager *manager, QWidget *parent = 0, const QString &caption = tr("Select Gradient", 0)); + +private slots: + void slotGradientSelected(const QString &id); + void slotGradientActivated(const QString &id); + +private: + Ui::QtGradientViewDialog m_ui; +}; + +QT_END_NAMESPACE + +#endif + diff --git a/tools/shared/qtgradienteditor/qtgradientviewdialog.ui b/tools/shared/qtgradienteditor/qtgradientviewdialog.ui new file mode 100644 index 0000000..ed53209 --- /dev/null +++ b/tools/shared/qtgradienteditor/qtgradientviewdialog.ui @@ -0,0 +1,121 @@ +<ui version="4.0" > + <comment>********************************************************************* +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the tools applications of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +*********************************************************************</comment> + <class>QtGradientViewDialog</class> + <widget class="QDialog" name="QtGradientViewDialog" > + <property name="geometry" > + <rect> + <x>0</x> + <y>0</y> + <width>178</width> + <height>72</height> + </rect> + </property> + <property name="windowTitle" > + <string>Select Gradient</string> + </property> + <layout class="QVBoxLayout" > + <item> + <widget class="QtGradientView" name="gradientView" > + <property name="sizePolicy" > + <sizepolicy vsizetype="MinimumExpanding" hsizetype="MinimumExpanding" > + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + </widget> + </item> + <item> + <widget class="QDialogButtonBox" name="buttonBox" > + <property name="orientation" > + <enum>Qt::Horizontal</enum> + </property> + <property name="standardButtons" > + <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set> + </property> + </widget> + </item> + </layout> + </widget> + <customwidgets> + <customwidget> + <class>QtGradientView</class> + <extends>QFrame</extends> + <header>qtgradientview.h</header> + <container>1</container> + </customwidget> + </customwidgets> + <resources/> + <connections> + <connection> + <sender>buttonBox</sender> + <signal>accepted()</signal> + <receiver>QtGradientViewDialog</receiver> + <slot>accept()</slot> + <hints> + <hint type="sourcelabel" > + <x>72</x> + <y>224</y> + </hint> + <hint type="destinationlabel" > + <x>21</x> + <y>243</y> + </hint> + </hints> + </connection> + <connection> + <sender>buttonBox</sender> + <signal>rejected()</signal> + <receiver>QtGradientViewDialog</receiver> + <slot>reject()</slot> + <hints> + <hint type="sourcelabel" > + <x>168</x> + <y>233</y> + </hint> + <hint type="destinationlabel" > + <x>152</x> + <y>251</y> + </hint> + </hints> + </connection> + </connections> +</ui> diff --git a/tools/shared/qtgradienteditor/qtgradientwidget.cpp b/tools/shared/qtgradienteditor/qtgradientwidget.cpp new file mode 100644 index 0000000..3f6b48d --- /dev/null +++ b/tools/shared/qtgradienteditor/qtgradientwidget.cpp @@ -0,0 +1,817 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the tools applications of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qtgradientwidget.h" +#include <QtCore/QMap> +#include <QtGui/QImage> +#include <QtGui/QPainter> +#include <QtGui/QScrollBar> +#include <QtGui/QMouseEvent> + +#define _USE_MATH_DEFINES + + +#include "math.h" + +#ifndef M_PI +#define M_PI 3.14159265358979323846 +#endif + +QT_BEGIN_NAMESPACE + +class QtGradientWidgetPrivate +{ + QtGradientWidget *q_ptr; + Q_DECLARE_PUBLIC(QtGradientWidget) +public: + QPointF fromViewport(const QPointF &point) const; + QPointF toViewport(const QPointF &point) const; +// void setupDrag(QtGradientStop *stop, int x); + + QPointF checkRange(const QPointF &point) const; + QRectF pointRect(const QPointF &point, double size) const; + + double correctAngle(double angle) const; + void setAngleConical(double angle); + + void paintPoint(QPainter *painter, const QPointF &point, double size) const; + + double m_handleSize; + bool m_backgroundCheckered; + + QGradientStops m_gradientStops; + QGradient::Type m_gradientType; + QGradient::Spread m_gradientSpread; + QPointF m_startLinear; + QPointF m_endLinear; + QPointF m_centralRadial; + QPointF m_focalRadial; + qreal m_radiusRadial; + QPointF m_centralConical; + qreal m_angleConical; + + enum Handle { + NoHandle, + StartLinearHandle, + EndLinearHandle, + CentralRadialHandle, + FocalRadialHandle, + RadiusRadialHandle, + CentralConicalHandle, + AngleConicalHandle + }; + + Handle m_dragHandle; + QPointF m_dragOffset; + //double m_radiusOffset; + double m_radiusFactor; + double m_dragRadius; + double m_angleOffset; + double m_dragAngle; +}; + +double QtGradientWidgetPrivate::correctAngle(double angle) const +{ + double a = angle; + while (a >= 360) + a -= 360; + while (a < 0) + a += 360; + return a; +} + +void QtGradientWidgetPrivate::setAngleConical(double angle) +{ + double a = correctAngle(angle); + if (m_angleConical == a) + return; + m_angleConical = a; + emit q_ptr->angleConicalChanged(m_angleConical); +} + +QRectF QtGradientWidgetPrivate::pointRect(const QPointF &point, double size) const +{ + return QRectF(point.x() - size / 2, point.y() - size / 2, size, size); +} + +QPointF QtGradientWidgetPrivate::checkRange(const QPointF &point) const +{ + QPointF p = point; + if (p.x() > 1) + p.setX(1); + else if (p.x() < 0) + p.setX(0); + if (p.y() > 1) + p.setY(1); + else if (p.y() < 0) + p.setY(0); + return p; +} + +QPointF QtGradientWidgetPrivate::fromViewport(const QPointF &point) const +{ + QSize size = q_ptr->size(); + return QPointF(point.x() / size.width(), point.y() / size.height()); +} + +QPointF QtGradientWidgetPrivate::toViewport(const QPointF &point) const +{ + QSize size = q_ptr->size(); + return QPointF(point.x() * size.width(), point.y() * size.height()); +} + +void QtGradientWidgetPrivate::paintPoint(QPainter *painter, const QPointF &point, double size) const +{ + QPointF pf = toViewport(point); + QRectF rf = pointRect(pf, size); + + QPen pen; + pen.setWidthF(1); + QColor alphaZero = Qt::white; + alphaZero.setAlpha(0); + + painter->save(); + painter->drawEllipse(rf); + + /* + painter->save(); + + QLinearGradient lgV(0, rf.top(), 0, rf.bottom()); + lgV.setColorAt(0, alphaZero); + lgV.setColorAt(0.25, Qt::white); + lgV.setColorAt(0.25, Qt::white); + lgV.setColorAt(1, alphaZero); + pen.setBrush(lgV); + painter->setPen(pen); + + painter->drawLine(QPointF(pf.x(), rf.top()), QPointF(pf.x(), rf.bottom())); + + QLinearGradient lgH(rf.left(), 0, rf.right(), 0); + lgH.setColorAt(0, alphaZero); + lgH.setColorAt(0.5, Qt::white); + lgH.setColorAt(1, alphaZero); + pen.setBrush(lgH); + painter->setPen(pen); + + painter->drawLine(QPointF(rf.left(), pf.y()), QPointF(rf.right(), pf.y())); + + painter->restore(); + */ + + painter->restore(); +} + +/* +void QtGradientWidgetPrivate::setupDrag(QtGradientStop *stop, int x) +{ + m_model->setCurrentStop(stop); + + int viewportX = qRound(toViewport(stop->position())); + m_dragOffset = x - viewportX; + + QList<QtGradientStop *> stops = m_stops; + m_stops.clear(); + QListIterator<QtGradientStop *> itStop(stops); + while (itStop.hasNext()) { + QtGradientStop *s = itStop.next(); + if (m_model->isSelected(s) || s == stop) { + m_dragStops[s] = s->position() - stop->position(); + m_stops.append(s); + } else { + m_dragOriginal[s->position()] = s->color(); + } + } + itStop.toFront(); + while (itStop.hasNext()) { + QtGradientStop *s = itStop.next(); + if (!m_model->isSelected(s)) + m_stops.append(s); + } + m_stops.removeAll(stop); + m_stops.prepend(stop); +} +*/ +//////////////////////////// + +QtGradientWidget::QtGradientWidget(QWidget *parent) + : QWidget(parent) +{ + d_ptr = new QtGradientWidgetPrivate; + d_ptr->q_ptr = this; + d_ptr->m_backgroundCheckered = true; + d_ptr->m_handleSize = 20.0; + d_ptr->m_gradientType = QGradient::LinearGradient; + d_ptr->m_startLinear = QPointF(0, 0); + d_ptr->m_endLinear = QPointF(1, 1); + d_ptr->m_centralRadial = QPointF(0.5, 0.5); + d_ptr->m_focalRadial = QPointF(0.5, 0.5); + d_ptr->m_radiusRadial = 0.5; + d_ptr->m_centralConical = QPointF(0.5, 0.5); + d_ptr->m_angleConical = 0; + d_ptr->m_dragHandle = QtGradientWidgetPrivate::NoHandle; + + setSizePolicy(QSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred)); +} + +QtGradientWidget::~QtGradientWidget() +{ + delete d_ptr; +} + +QSize QtGradientWidget::sizeHint() const +{ + return QSize(176, 176); +} + +QSize QtGradientWidget::minimumSizeHint() const +{ + return QSize(128, 128); +} + +int QtGradientWidget::heightForWidth(int w) const +{ + return w; +} + +void QtGradientWidget::setBackgroundCheckered(bool checkered) +{ + if (d_ptr->m_backgroundCheckered == checkered) + return; + d_ptr->m_backgroundCheckered = checkered; + update(); +} + +bool QtGradientWidget::isBackgroundCheckered() const +{ + return d_ptr->m_backgroundCheckered; +} + +void QtGradientWidget::mousePressEvent(QMouseEvent *e) +{ + if (e->button() != Qt::LeftButton) + return; + + QPoint p = e->pos(); + if (d_ptr->m_gradientType == QGradient::LinearGradient) { + QPointF startPoint = d_ptr->toViewport(d_ptr->m_startLinear); + double x = p.x() - startPoint.x(); + double y = p.y() - startPoint.y(); + + if ((d_ptr->m_handleSize * d_ptr->m_handleSize / 4) > (x * x + y * y)) { + d_ptr->m_dragHandle = QtGradientWidgetPrivate::StartLinearHandle; + d_ptr->m_dragOffset = QPointF(x, y); + update(); + return; + } + + QPointF endPoint = d_ptr->toViewport(d_ptr->m_endLinear); + x = p.x() - endPoint.x(); + y = p.y() - endPoint.y(); + + if ((d_ptr->m_handleSize * d_ptr->m_handleSize / 4) > (x * x + y * y)) { + d_ptr->m_dragHandle = QtGradientWidgetPrivate::EndLinearHandle; + d_ptr->m_dragOffset = QPointF(x, y); + update(); + return; + } + } else if (d_ptr->m_gradientType == QGradient::RadialGradient) { + QPointF focalPoint = d_ptr->toViewport(d_ptr->m_focalRadial); + double x = p.x() - focalPoint.x(); + double y = p.y() - focalPoint.y(); + + if ((d_ptr->m_handleSize * d_ptr->m_handleSize / 9) > (x * x + y * y)) { + d_ptr->m_dragHandle = QtGradientWidgetPrivate::FocalRadialHandle; + d_ptr->m_dragOffset = QPointF(x, y); + update(); + return; + } + + QPointF centralPoint = d_ptr->toViewport(d_ptr->m_centralRadial); + x = p.x() - centralPoint.x(); + y = p.y() - centralPoint.y(); + + if ((d_ptr->m_handleSize * d_ptr->m_handleSize / 4) > (x * x + y * y)) { + d_ptr->m_dragHandle = QtGradientWidgetPrivate::CentralRadialHandle; + d_ptr->m_dragOffset = QPointF(x, y); + update(); + return; + } + + QPointF central = d_ptr->toViewport(d_ptr->m_centralRadial); + QRectF r = d_ptr->pointRect(central, 2 * d_ptr->m_handleSize / 3); + QRectF r1(0, r.y(), size().width(), r.height()); + QRectF r2(r.x(), 0, r.width(), r.y()); + QRectF r3(r.x(), r.y() + r.height(), r.width(), size().height() - r.y() - r.height()); + QPointF pF(p.x(), p.y()); + if (r1.contains(pF) || r2.contains(pF) || r3.contains(pF)) { + x = pF.x() / size().width() - d_ptr->m_centralRadial.x(); + y = pF.y() / size().height() - d_ptr->m_centralRadial.y(); + double clickRadius = sqrt(x * x + y * y); + //d_ptr->m_radiusOffset = d_ptr->m_radiusRadial - clickRadius; + d_ptr->m_radiusFactor = d_ptr->m_radiusRadial / clickRadius; + if (d_ptr->m_radiusFactor == 0) + d_ptr->m_radiusFactor = 1; + d_ptr->m_dragRadius = d_ptr->m_radiusRadial; + d_ptr->m_dragHandle = QtGradientWidgetPrivate::RadiusRadialHandle; + mouseMoveEvent(e); + update(); + return; + } + } else if (d_ptr->m_gradientType == QGradient::ConicalGradient) { + QPointF centralPoint = d_ptr->toViewport(d_ptr->m_centralConical); + double x = p.x() - centralPoint.x(); + double y = p.y() - centralPoint.y(); + + if ((d_ptr->m_handleSize * d_ptr->m_handleSize / 4) > (x * x + y * y)) { + d_ptr->m_dragHandle = QtGradientWidgetPrivate::CentralConicalHandle; + d_ptr->m_dragOffset = QPointF(x, y); + update(); + return; + } + double radius = size().width(); + if (size().height() < radius) + radius = size().height(); + radius /= 2; + double corr = d_ptr->m_handleSize / 3; + radius -= corr; + QPointF vp = d_ptr->toViewport(d_ptr->m_centralConical); + x = p.x() - vp.x(); + y = p.y() - vp.y(); + if (((radius - corr) * (radius - corr) < (x * x + y * y)) && + ((radius + corr) * (radius + corr) > (x * x + y * y))) { + QPointF central = d_ptr->toViewport(d_ptr->m_centralConical); + QPointF current(e->pos().x(), e->pos().y()); + x = current.x() - central.x(); + y = current.y() - central.y(); + x /= size().width() / 2; + y /= size().height() / 2; + double r = sqrt(x * x + y * y); + + double arcSin = asin(y / r); + double arcCos = acos(x / r); + + double angle = arcCos * 180 / M_PI; + if (arcSin > 0) { + angle = -angle; + } + + d_ptr->m_angleOffset = d_ptr->m_angleConical - angle; + d_ptr->m_dragAngle = d_ptr->m_angleConical; + d_ptr->m_dragHandle = QtGradientWidgetPrivate::AngleConicalHandle; + update(); + return; + } + } +} + +void QtGradientWidget::mouseReleaseEvent(QMouseEvent *e) +{ + Q_UNUSED(e) + d_ptr->m_dragHandle = QtGradientWidgetPrivate::NoHandle; + update(); +} + +void QtGradientWidget::mouseMoveEvent(QMouseEvent *e) +{ + if (d_ptr->m_dragHandle == QtGradientWidgetPrivate::NoHandle) + return; + + QPointF newPos = QPointF((double)e->pos().x() - d_ptr->m_dragOffset.x(), + (double)e->pos().y() - d_ptr->m_dragOffset.y()); + QPointF newPoint = d_ptr->fromViewport(newPos); + if (newPoint.x() < 0) + newPoint.setX(0); + else if (newPoint.x() > 1) + newPoint.setX(1); + if (newPoint.y() < 0) + newPoint.setY(0); + else if (newPoint.y() > 1) + newPoint.setY(1); + + if (d_ptr->m_dragHandle == QtGradientWidgetPrivate::StartLinearHandle) { + d_ptr->m_startLinear = newPoint; + emit startLinearChanged(newPoint); + } else if (d_ptr->m_dragHandle == QtGradientWidgetPrivate::EndLinearHandle) { + d_ptr->m_endLinear = newPoint; + emit endLinearChanged(newPoint); + } else if (d_ptr->m_dragHandle == QtGradientWidgetPrivate::CentralRadialHandle) { + d_ptr->m_centralRadial = newPoint; + emit centralRadialChanged(newPoint); + } else if (d_ptr->m_dragHandle == QtGradientWidgetPrivate::FocalRadialHandle) { + d_ptr->m_focalRadial = newPoint; + emit focalRadialChanged(newPoint); + } else if (d_ptr->m_dragHandle == QtGradientWidgetPrivate::RadiusRadialHandle) { + QPointF centralPoint = d_ptr->toViewport(d_ptr->m_centralRadial); + QPointF pF(e->pos().x(), e->pos().y()); + double x = pF.x() - centralPoint.x(); + double y = pF.y() - centralPoint.y(); + + if ((d_ptr->m_handleSize * d_ptr->m_handleSize / 4) > (x * x + y * y)) { + if (d_ptr->m_radiusRadial != d_ptr->m_dragRadius) { + d_ptr->m_radiusRadial = d_ptr->m_dragRadius; + emit radiusRadialChanged(d_ptr->m_radiusRadial); + } + } else { + x = pF.x() / size().width() - d_ptr->m_centralRadial.x(); + y = pF.y() / size().height() - d_ptr->m_centralRadial.y(); + double moveRadius = sqrt(x * x + y * y); + //double newRadius = moveRadius + d_ptr->m_radiusOffset; + double newRadius = moveRadius * d_ptr->m_radiusFactor; + if (newRadius > 2) + newRadius = 2; + d_ptr->m_radiusRadial = newRadius; + emit radiusRadialChanged(d_ptr->m_radiusRadial); + } + } else if (d_ptr->m_dragHandle == QtGradientWidgetPrivate::CentralConicalHandle) { + d_ptr->m_centralConical = newPoint; + emit centralConicalChanged(newPoint); + } else if (d_ptr->m_dragHandle == QtGradientWidgetPrivate::AngleConicalHandle) { + QPointF centralPoint = d_ptr->toViewport(d_ptr->m_centralConical); + QPointF pF(e->pos().x(), e->pos().y()); + double x = pF.x() - centralPoint.x(); + double y = pF.y() - centralPoint.y(); + + if ((d_ptr->m_handleSize * d_ptr->m_handleSize / 4) > (x * x + y * y)) { + if (d_ptr->m_angleConical != d_ptr->m_dragAngle) { + d_ptr->m_angleConical = d_ptr->m_dragAngle; + emit angleConicalChanged(d_ptr->m_angleConical); + } + } else { + QPointF central = d_ptr->toViewport(d_ptr->m_centralConical); + QPointF current = pF; + x = current.x() - central.x(); + y = current.y() - central.y(); + x /= size().width() / 2; + y /= size().height() / 2; + double r = sqrt(x * x + y * y); + + double arcSin = asin(y / r); + double arcCos = acos(x / r); + + double angle = arcCos * 180 / M_PI; + if (arcSin > 0) { + angle = -angle; + } + + angle += d_ptr->m_angleOffset; + + d_ptr->setAngleConical(angle); + } + } + update(); +} + +void QtGradientWidget::mouseDoubleClickEvent(QMouseEvent *e) +{ + mousePressEvent(e); +} + +void QtGradientWidget::paintEvent(QPaintEvent *e) +{ + Q_UNUSED(e) + + QPainter p(this); + + if (d_ptr->m_backgroundCheckered) { + int pixSize = 40; + QPixmap pm(2 * pixSize, 2 * pixSize); + + QPainter pmp(&pm); + pmp.fillRect(0, 0, pixSize, pixSize, Qt::white); + pmp.fillRect(pixSize, pixSize, pixSize, pixSize, Qt::white); + pmp.fillRect(0, pixSize, pixSize, pixSize, Qt::black); + pmp.fillRect(pixSize, 0, pixSize, pixSize, Qt::black); + + p.setBrushOrigin((size().width() % pixSize + pixSize) / 2, (size().height() % pixSize + pixSize) / 2); + p.fillRect(rect(), pm); + p.setBrushOrigin(0, 0); + } + + QGradient *gradient = 0; + switch (d_ptr->m_gradientType) { + case QGradient::LinearGradient: + gradient = new QLinearGradient(d_ptr->m_startLinear, d_ptr->m_endLinear); + break; + case QGradient::RadialGradient: + gradient = new QRadialGradient(d_ptr->m_centralRadial, d_ptr->m_radiusRadial, d_ptr->m_focalRadial); + break; + case QGradient::ConicalGradient: + gradient = new QConicalGradient(d_ptr->m_centralConical, d_ptr->m_angleConical); + break; + default: + break; + } + if (!gradient) + return; + + gradient->setStops(d_ptr->m_gradientStops); + gradient->setSpread(d_ptr->m_gradientSpread); + + p.save(); + p.scale(size().width(), size().height()); + p.fillRect(QRect(0, 0, 1, 1), *gradient); + p.restore(); + + p.setRenderHint(QPainter::Antialiasing); + + QColor c = QColor::fromRgbF(0.5, 0.5, 0.5, 0.5); + QBrush br(c); + p.setBrush(br); + QPen pen(Qt::white); + pen.setWidthF(1); + p.setPen(pen); + QPen dragPen = pen; + dragPen.setWidthF(2); + if (d_ptr->m_gradientType == QGradient::LinearGradient) { + p.save(); + if (d_ptr->m_dragHandle == QtGradientWidgetPrivate::StartLinearHandle) + p.setPen(dragPen); + d_ptr->paintPoint(&p, d_ptr->m_startLinear, d_ptr->m_handleSize); + p.restore(); + + p.save(); + if (d_ptr->m_dragHandle == QtGradientWidgetPrivate::EndLinearHandle) + p.setPen(dragPen); + d_ptr->paintPoint(&p, d_ptr->m_endLinear, d_ptr->m_handleSize); + p.restore(); + } else if (d_ptr->m_gradientType == QGradient::RadialGradient) { + QPointF central = d_ptr->toViewport(d_ptr->m_centralRadial); + + p.save(); + QRectF r = d_ptr->pointRect(central, 2 * d_ptr->m_handleSize / 3); + QRectF r1(0, r.y(), size().width(), r.height()); + QRectF r2(r.x(), 0, r.width(), r.y()); + QRectF r3(r.x(), r.y() + r.height(), r.width(), size().height() - r.y() - r.height()); + p.fillRect(r1, c); + p.fillRect(r2, c); + p.fillRect(r3, c); + p.setBrush(Qt::NoBrush); + p.save(); + if (d_ptr->m_dragHandle == QtGradientWidgetPrivate::CentralRadialHandle) + p.setPen(dragPen); + d_ptr->paintPoint(&p, d_ptr->m_centralRadial, d_ptr->m_handleSize); + p.restore(); + + QRectF rect = QRectF(central.x() - d_ptr->m_radiusRadial * size().width(), + central.y() - d_ptr->m_radiusRadial * size().height(), + 2 * d_ptr->m_radiusRadial * size().width(), + 2 * d_ptr->m_radiusRadial * size().height()); + p.setClipRect(r1); + p.setClipRect(r2, Qt::UniteClip); + p.setClipRect(r3, Qt::UniteClip); + p.drawEllipse(rect); + if (d_ptr->m_dragHandle == QtGradientWidgetPrivate::RadiusRadialHandle) { + p.save(); + p.setPen(dragPen); + QRectF rect = QRectF(central.x() - d_ptr->m_radiusRadial / d_ptr->m_radiusFactor * size().width(), + central.y() - d_ptr->m_radiusRadial / d_ptr->m_radiusFactor * size().height(), + 2 * d_ptr->m_radiusRadial / d_ptr->m_radiusFactor * size().width(), + 2 * d_ptr->m_radiusRadial / d_ptr->m_radiusFactor * size().height()); + p.drawEllipse(rect); + + p.restore(); + } + p.restore(); + + p.save(); + if (d_ptr->m_dragHandle == QtGradientWidgetPrivate::FocalRadialHandle) + p.setPen(dragPen); + d_ptr->paintPoint(&p, d_ptr->m_focalRadial, 2 * d_ptr->m_handleSize / 3); + p.restore(); + } else if (d_ptr->m_gradientType == QGradient::ConicalGradient) { + double radius = size().width(); + if (size().height() < radius) + radius = size().height(); + radius /= 2; + double corr = d_ptr->m_handleSize / 3; + radius -= corr; + QPointF central = d_ptr->toViewport(d_ptr->m_centralConical); + + p.save(); + p.setBrush(Qt::NoBrush); + QPen pen2(c); + pen2.setWidthF(2 * d_ptr->m_handleSize / 3); + p.setPen(pen2); + p.drawEllipse(d_ptr->pointRect(central, 2 * radius)); + p.restore(); + + p.save(); + p.setBrush(Qt::NoBrush); + int pointCount = 2; + for (int i = 0; i < pointCount; i++) { + QPointF ang(cos(M_PI * (i * 180.0 / pointCount + d_ptr->m_angleConical) / 180) * size().width() / 2, + -sin(M_PI * (i * 180.0 / pointCount + d_ptr->m_angleConical) / 180) * size().height() / 2); + double mod = sqrt(ang.x() * ang.x() + ang.y() * ang.y()); + p.drawLine(QPointF(central.x() + ang.x() * (radius - corr) / mod, + central.y() + ang.y() * (radius - corr) / mod), + QPointF(central.x() + ang.x() * (radius + corr) / mod, + central.y() + ang.y() * (radius + corr) / mod)); + p.drawLine(QPointF(central.x() - ang.x() * (radius - corr) / mod, + central.y() - ang.y() * (radius - corr) / mod), + QPointF(central.x() - ang.x() * (radius + corr) / mod, + central.y() - ang.y() * (radius + corr) / mod)); + } + if (d_ptr->m_dragHandle == QtGradientWidgetPrivate::AngleConicalHandle) { + p.save(); + p.setPen(dragPen); + QPointF ang(cos(M_PI * (d_ptr->m_angleConical - d_ptr->m_angleOffset) / 180) * size().width() / 2, + -sin(M_PI * (d_ptr->m_angleConical - d_ptr->m_angleOffset) / 180) * size().height() / 2); + double mod = sqrt(ang.x() * ang.x() + ang.y() * ang.y()); + p.drawLine(QPointF(central.x() + ang.x() * (radius - corr) / mod, + central.y() + ang.y() * (radius - corr) / mod), + QPointF(central.x() + ang.x() * (radius + corr) / mod, + central.y() + ang.y() * (radius + corr) / mod)); + p.restore(); + } + + p.restore(); + + p.save(); + if (d_ptr->m_dragHandle == QtGradientWidgetPrivate::CentralConicalHandle) + p.setPen(dragPen); + d_ptr->paintPoint(&p, d_ptr->m_centralConical, d_ptr->m_handleSize); + p.restore(); + + } + + delete gradient; +} + +void QtGradientWidget::setGradientStops(const QGradientStops &stops) +{ + d_ptr->m_gradientStops = stops; + update(); +} + +QGradientStops QtGradientWidget::gradientStops() const +{ + return d_ptr->m_gradientStops; +} + +void QtGradientWidget::setGradientType(QGradient::Type type) +{ + if (type == QGradient::NoGradient) + return; + if (d_ptr->m_gradientType == type) + return; + + d_ptr->m_gradientType = type; + update(); +} + +QGradient::Type QtGradientWidget::gradientType() const +{ + return d_ptr->m_gradientType; +} + +void QtGradientWidget::setGradientSpread(QGradient::Spread spread) +{ + if (d_ptr->m_gradientSpread == spread) + return; + + d_ptr->m_gradientSpread = spread; + update(); +} + +QGradient::Spread QtGradientWidget::gradientSpread() const +{ + return d_ptr->m_gradientSpread; +} + +void QtGradientWidget::setStartLinear(const QPointF &point) +{ + if (d_ptr->m_startLinear == point) + return; + + d_ptr->m_startLinear = d_ptr->checkRange(point); + update(); +} + +QPointF QtGradientWidget::startLinear() const +{ + return d_ptr->m_startLinear; +} + +void QtGradientWidget::setEndLinear(const QPointF &point) +{ + if (d_ptr->m_endLinear == point) + return; + + d_ptr->m_endLinear = d_ptr->checkRange(point); + update(); +} + +QPointF QtGradientWidget::endLinear() const +{ + return d_ptr->m_endLinear; +} + +void QtGradientWidget::setCentralRadial(const QPointF &point) +{ + if (d_ptr->m_centralRadial == point) + return; + + d_ptr->m_centralRadial = point; + update(); +} + +QPointF QtGradientWidget::centralRadial() const +{ + return d_ptr->m_centralRadial; +} + +void QtGradientWidget::setFocalRadial(const QPointF &point) +{ + if (d_ptr->m_focalRadial == point) + return; + + d_ptr->m_focalRadial = point; + update(); +} + +QPointF QtGradientWidget::focalRadial() const +{ + return d_ptr->m_focalRadial; +} + +void QtGradientWidget::setRadiusRadial(qreal radius) +{ + if (d_ptr->m_radiusRadial == radius) + return; + + d_ptr->m_radiusRadial = radius; + update(); +} + +qreal QtGradientWidget::radiusRadial() const +{ + return d_ptr->m_radiusRadial; +} + +void QtGradientWidget::setCentralConical(const QPointF &point) +{ + if (d_ptr->m_centralConical == point) + return; + + d_ptr->m_centralConical = point; + update(); +} + +QPointF QtGradientWidget::centralConical() const +{ + return d_ptr->m_centralConical; +} + +void QtGradientWidget::setAngleConical(qreal angle) +{ + if (d_ptr->m_angleConical == angle) + return; + + d_ptr->m_angleConical = angle; + update(); +} + +qreal QtGradientWidget::angleConical() const +{ + return d_ptr->m_angleConical; +} + +QT_END_NAMESPACE diff --git a/tools/shared/qtgradienteditor/qtgradientwidget.h b/tools/shared/qtgradienteditor/qtgradientwidget.h new file mode 100644 index 0000000..4dc740b --- /dev/null +++ b/tools/shared/qtgradienteditor/qtgradientwidget.h @@ -0,0 +1,120 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the tools applications of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QTGRADIENTWIDGET_H +#define QTGRADIENTWIDGET_H + +#include <QtGui/QWidget> + +QT_BEGIN_NAMESPACE + +class QtGradientWidget : public QWidget +{ + Q_OBJECT + Q_PROPERTY(bool backgroundCheckered READ isBackgroundCheckered WRITE setBackgroundCheckered) +public: + QtGradientWidget(QWidget *parent = 0); + ~QtGradientWidget(); + + QSize minimumSizeHint() const; + QSize sizeHint() const; + int heightForWidth(int w) const; + + bool isBackgroundCheckered() const; + void setBackgroundCheckered(bool checkered); + + QGradientStops gradientStops() const; + + void setGradientType(QGradient::Type type); + QGradient::Type gradientType() const; + + void setGradientSpread(QGradient::Spread spread); + QGradient::Spread gradientSpread() const; + + void setStartLinear(const QPointF &point); + QPointF startLinear() const; + + void setEndLinear(const QPointF &point); + QPointF endLinear() const; + + void setCentralRadial(const QPointF &point); + QPointF centralRadial() const; + + void setFocalRadial(const QPointF &point); + QPointF focalRadial() const; + + void setRadiusRadial(qreal radius); + qreal radiusRadial() const; + + void setCentralConical(const QPointF &point); + QPointF centralConical() const; + + void setAngleConical(qreal angle); + qreal angleConical() const; + +public slots: + void setGradientStops(const QGradientStops &stops); +signals: + + void startLinearChanged(const QPointF &point); + void endLinearChanged(const QPointF &point); + void centralRadialChanged(const QPointF &point); + void focalRadialChanged(const QPointF &point); + void radiusRadialChanged(qreal radius); + void centralConicalChanged(const QPointF &point); + void angleConicalChanged(qreal angle); + +protected: + void paintEvent(QPaintEvent *e); + void mousePressEvent(QMouseEvent *e); + void mouseReleaseEvent(QMouseEvent *e); + void mouseMoveEvent(QMouseEvent *e); + void mouseDoubleClickEvent(QMouseEvent *e); + +private: + class QtGradientWidgetPrivate *d_ptr; + Q_DECLARE_PRIVATE(QtGradientWidget) + Q_DISABLE_COPY(QtGradientWidget) +}; + +QT_END_NAMESPACE + +#endif diff --git a/tools/shared/qtpropertybrowser/images/cursor-arrow.png b/tools/shared/qtpropertybrowser/images/cursor-arrow.png Binary files differnew file mode 100644 index 0000000..a69ef4e --- /dev/null +++ b/tools/shared/qtpropertybrowser/images/cursor-arrow.png diff --git a/tools/shared/qtpropertybrowser/images/cursor-busy.png b/tools/shared/qtpropertybrowser/images/cursor-busy.png Binary files differnew file mode 100644 index 0000000..53717e4 --- /dev/null +++ b/tools/shared/qtpropertybrowser/images/cursor-busy.png diff --git a/tools/shared/qtpropertybrowser/images/cursor-closedhand.png b/tools/shared/qtpropertybrowser/images/cursor-closedhand.png Binary files differnew file mode 100644 index 0000000..b78dd1d --- /dev/null +++ b/tools/shared/qtpropertybrowser/images/cursor-closedhand.png diff --git a/tools/shared/qtpropertybrowser/images/cursor-cross.png b/tools/shared/qtpropertybrowser/images/cursor-cross.png Binary files differnew file mode 100644 index 0000000..fe38e74 --- /dev/null +++ b/tools/shared/qtpropertybrowser/images/cursor-cross.png diff --git a/tools/shared/qtpropertybrowser/images/cursor-forbidden.png b/tools/shared/qtpropertybrowser/images/cursor-forbidden.png Binary files differnew file mode 100644 index 0000000..2b08c4e --- /dev/null +++ b/tools/shared/qtpropertybrowser/images/cursor-forbidden.png diff --git a/tools/shared/qtpropertybrowser/images/cursor-hand.png b/tools/shared/qtpropertybrowser/images/cursor-hand.png Binary files differnew file mode 100644 index 0000000..d2004ae --- /dev/null +++ b/tools/shared/qtpropertybrowser/images/cursor-hand.png diff --git a/tools/shared/qtpropertybrowser/images/cursor-hsplit.png b/tools/shared/qtpropertybrowser/images/cursor-hsplit.png Binary files differnew file mode 100644 index 0000000..a5667e3 --- /dev/null +++ b/tools/shared/qtpropertybrowser/images/cursor-hsplit.png diff --git a/tools/shared/qtpropertybrowser/images/cursor-ibeam.png b/tools/shared/qtpropertybrowser/images/cursor-ibeam.png Binary files differnew file mode 100644 index 0000000..097fc5f --- /dev/null +++ b/tools/shared/qtpropertybrowser/images/cursor-ibeam.png diff --git a/tools/shared/qtpropertybrowser/images/cursor-openhand.png b/tools/shared/qtpropertybrowser/images/cursor-openhand.png Binary files differnew file mode 100644 index 0000000..9181c85 --- /dev/null +++ b/tools/shared/qtpropertybrowser/images/cursor-openhand.png diff --git a/tools/shared/qtpropertybrowser/images/cursor-sizeall.png b/tools/shared/qtpropertybrowser/images/cursor-sizeall.png Binary files differnew file mode 100644 index 0000000..69f13eb --- /dev/null +++ b/tools/shared/qtpropertybrowser/images/cursor-sizeall.png diff --git a/tools/shared/qtpropertybrowser/images/cursor-sizeb.png b/tools/shared/qtpropertybrowser/images/cursor-sizeb.png Binary files differnew file mode 100644 index 0000000..f37d7b9 --- /dev/null +++ b/tools/shared/qtpropertybrowser/images/cursor-sizeb.png diff --git a/tools/shared/qtpropertybrowser/images/cursor-sizef.png b/tools/shared/qtpropertybrowser/images/cursor-sizef.png Binary files differnew file mode 100644 index 0000000..3b127a0 --- /dev/null +++ b/tools/shared/qtpropertybrowser/images/cursor-sizef.png diff --git a/tools/shared/qtpropertybrowser/images/cursor-sizeh.png b/tools/shared/qtpropertybrowser/images/cursor-sizeh.png Binary files differnew file mode 100644 index 0000000..a9f40cb --- /dev/null +++ b/tools/shared/qtpropertybrowser/images/cursor-sizeh.png diff --git a/tools/shared/qtpropertybrowser/images/cursor-sizev.png b/tools/shared/qtpropertybrowser/images/cursor-sizev.png Binary files differnew file mode 100644 index 0000000..1edbab2 --- /dev/null +++ b/tools/shared/qtpropertybrowser/images/cursor-sizev.png diff --git a/tools/shared/qtpropertybrowser/images/cursor-uparrow.png b/tools/shared/qtpropertybrowser/images/cursor-uparrow.png Binary files differnew file mode 100644 index 0000000..d3e70ef --- /dev/null +++ b/tools/shared/qtpropertybrowser/images/cursor-uparrow.png diff --git a/tools/shared/qtpropertybrowser/images/cursor-vsplit.png b/tools/shared/qtpropertybrowser/images/cursor-vsplit.png Binary files differnew file mode 100644 index 0000000..1beda25 --- /dev/null +++ b/tools/shared/qtpropertybrowser/images/cursor-vsplit.png diff --git a/tools/shared/qtpropertybrowser/images/cursor-wait.png b/tools/shared/qtpropertybrowser/images/cursor-wait.png Binary files differnew file mode 100644 index 0000000..69056c4 --- /dev/null +++ b/tools/shared/qtpropertybrowser/images/cursor-wait.png diff --git a/tools/shared/qtpropertybrowser/images/cursor-whatsthis.png b/tools/shared/qtpropertybrowser/images/cursor-whatsthis.png Binary files differnew file mode 100644 index 0000000..b47601c --- /dev/null +++ b/tools/shared/qtpropertybrowser/images/cursor-whatsthis.png diff --git a/tools/shared/qtpropertybrowser/qtbuttonpropertybrowser.cpp b/tools/shared/qtpropertybrowser/qtbuttonpropertybrowser.cpp new file mode 100644 index 0000000..ecdaf16 --- /dev/null +++ b/tools/shared/qtpropertybrowser/qtbuttonpropertybrowser.cpp @@ -0,0 +1,633 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the tools applications of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qtbuttonpropertybrowser.h" +#include <QtCore/QSet> +#include <QtGui/QGridLayout> +#include <QtGui/QLabel> +#include <QtCore/QTimer> +#include <QtCore/QMap> +#include <QtGui/QToolButton> +#include <QtGui/QStyle> + +#if QT_VERSION >= 0x040400 +QT_BEGIN_NAMESPACE +#endif + +class QtButtonPropertyBrowserPrivate +{ + QtButtonPropertyBrowser *q_ptr; + Q_DECLARE_PUBLIC(QtButtonPropertyBrowser) +public: + + void init(QWidget *parent); + + void propertyInserted(QtBrowserItem *index, QtBrowserItem *afterIndex); + void propertyRemoved(QtBrowserItem *index); + void propertyChanged(QtBrowserItem *index); + QWidget *createEditor(QtProperty *property, QWidget *parent) const + { return q_ptr->createEditor(property, parent); } + + void slotEditorDestroyed(); + void slotUpdate(); + void slotToggled(bool checked); + + struct WidgetItem + { + WidgetItem() : widget(0), label(0), widgetLabel(0), + button(0), container(0), layout(0), /*line(0), */parent(0), expanded(false) { } + QWidget *widget; // can be null + QLabel *label; // main label with property name + QLabel *widgetLabel; // label substitute showing the current value if there is no widget + QToolButton *button; // expandable button for items with children + QWidget *container; // container which is expanded when the button is clicked + QGridLayout *layout; // layout in container + WidgetItem *parent; + QList<WidgetItem *> children; + bool expanded; + }; +private: + void updateLater(); + void updateItem(WidgetItem *item); + void insertRow(QGridLayout *layout, int row) const; + void removeRow(QGridLayout *layout, int row) const; + int gridRow(WidgetItem *item) const; + int gridSpan(WidgetItem *item) const; + void setExpanded(WidgetItem *item, bool expanded); + QToolButton *createButton(QWidget *panret = 0) const; + + QMap<QtBrowserItem *, WidgetItem *> m_indexToItem; + QMap<WidgetItem *, QtBrowserItem *> m_itemToIndex; + QMap<QWidget *, WidgetItem *> m_widgetToItem; + QMap<QObject *, WidgetItem *> m_buttonToItem; + QGridLayout *m_mainLayout; + QList<WidgetItem *> m_children; + QList<WidgetItem *> m_recreateQueue; +}; + +QToolButton *QtButtonPropertyBrowserPrivate::createButton(QWidget *parent) const +{ + QToolButton *button = new QToolButton(parent); + button->setCheckable(true); + button->setSizePolicy(QSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed)); + button->setToolButtonStyle(Qt::ToolButtonTextBesideIcon); + button->setArrowType(Qt::DownArrow); + button->setIconSize(QSize(3, 16)); + /* + QIcon icon; + icon.addPixmap(q_ptr->style()->standardPixmap(QStyle::SP_ArrowDown), QIcon::Normal, QIcon::Off); + icon.addPixmap(q_ptr->style()->standardPixmap(QStyle::SP_ArrowUp), QIcon::Normal, QIcon::On); + button->setIcon(icon); + */ + return button; +} + +int QtButtonPropertyBrowserPrivate::gridRow(WidgetItem *item) const +{ + QList<WidgetItem *> siblings; + if (item->parent) + siblings = item->parent->children; + else + siblings = m_children; + + int row = 0; + QListIterator<WidgetItem *> it(siblings); + while (it.hasNext()) { + WidgetItem *sibling = it.next(); + if (sibling == item) + return row; + row += gridSpan(sibling); + } + return -1; +} + +int QtButtonPropertyBrowserPrivate::gridSpan(WidgetItem *item) const +{ + if (item->container && item->expanded) + return 2; + return 1; +} + +void QtButtonPropertyBrowserPrivate::init(QWidget *parent) +{ + m_mainLayout = new QGridLayout(); + parent->setLayout(m_mainLayout); + QLayoutItem *item = new QSpacerItem(0, 0, + QSizePolicy::Fixed, QSizePolicy::Expanding); + m_mainLayout->addItem(item, 0, 0); +} + +void QtButtonPropertyBrowserPrivate::slotEditorDestroyed() +{ + QWidget *editor = qobject_cast<QWidget *>(q_ptr->sender()); + if (!editor) + return; + if (!m_widgetToItem.contains(editor)) + return; + m_widgetToItem[editor]->widget = 0; + m_widgetToItem.remove(editor); +} + +void QtButtonPropertyBrowserPrivate::slotUpdate() +{ + QListIterator<WidgetItem *> itItem(m_recreateQueue); + while (itItem.hasNext()) { + WidgetItem *item = itItem.next(); + + WidgetItem *parent = item->parent; + QWidget *w = 0; + QGridLayout *l = 0; + const int oldRow = gridRow(item); + if (parent) { + w = parent->container; + l = parent->layout; + } else { + w = q_ptr; + l = m_mainLayout; + } + + int span = 1; + if (!item->widget && !item->widgetLabel) + span = 2; + item->label = new QLabel(w); + item->label->setSizePolicy(QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed)); + l->addWidget(item->label, oldRow, 0, 1, span); + + updateItem(item); + } + m_recreateQueue.clear(); +} + +void QtButtonPropertyBrowserPrivate::setExpanded(WidgetItem *item, bool expanded) +{ + if (item->expanded == expanded) + return; + + if (!item->container) + return; + + item->expanded = expanded; + const int row = gridRow(item); + WidgetItem *parent = item->parent; + QGridLayout *l = 0; + if (parent) + l = parent->layout; + else + l = m_mainLayout; + + if (expanded) { + insertRow(l, row + 1); + l->addWidget(item->container, row + 1, 0, 1, 2); + item->container->show(); + } else { + l->removeWidget(item->container); + item->container->hide(); + removeRow(l, row + 1); + } + + item->button->setChecked(expanded); + item->button->setArrowType(expanded ? Qt::UpArrow : Qt::DownArrow); +} + +void QtButtonPropertyBrowserPrivate::slotToggled(bool checked) +{ + WidgetItem *item = m_buttonToItem.value(q_ptr->sender()); + if (!item) + return; + + setExpanded(item, checked); + + if (checked) + emit q_ptr->expanded(m_itemToIndex.value(item)); + else + emit q_ptr->collapsed(m_itemToIndex.value(item)); +} + +void QtButtonPropertyBrowserPrivate::updateLater() +{ + QTimer::singleShot(0, q_ptr, SLOT(slotUpdate())); +} + +void QtButtonPropertyBrowserPrivate::propertyInserted(QtBrowserItem *index, QtBrowserItem *afterIndex) +{ + WidgetItem *afterItem = m_indexToItem.value(afterIndex); + WidgetItem *parentItem = m_indexToItem.value(index->parent()); + + WidgetItem *newItem = new WidgetItem(); + newItem->parent = parentItem; + + QGridLayout *layout = 0; + QWidget *parentWidget = 0; + int row = -1; + if (!afterItem) { + row = 0; + if (parentItem) + parentItem->children.insert(0, newItem); + else + m_children.insert(0, newItem); + } else { + row = gridRow(afterItem) + gridSpan(afterItem); + if (parentItem) + parentItem->children.insert(parentItem->children.indexOf(afterItem) + 1, newItem); + else + m_children.insert(m_children.indexOf(afterItem) + 1, newItem); + } + + if (!parentItem) { + layout = m_mainLayout; + parentWidget = q_ptr; + } else { + if (!parentItem->container) { + m_recreateQueue.removeAll(parentItem); + WidgetItem *grandParent = parentItem->parent; + QWidget *w = 0; + QGridLayout *l = 0; + const int oldRow = gridRow(parentItem); + if (grandParent) { + w = grandParent->container; + l = grandParent->layout; + } else { + w = q_ptr; + l = m_mainLayout; + } + QFrame *container = new QFrame(); + container->setFrameShape(QFrame::Panel); + container->setFrameShadow(QFrame::Raised); + parentItem->container = container; + parentItem->button = createButton(); + m_buttonToItem[parentItem->button] = parentItem; + q_ptr->connect(parentItem->button, SIGNAL(toggled(bool)), q_ptr, SLOT(slotToggled(bool))); + parentItem->layout = new QGridLayout(); + container->setLayout(parentItem->layout); + if (parentItem->label) { + l->removeWidget(parentItem->label); + delete parentItem->label; + parentItem->label = 0; + } + int span = 1; + if (!parentItem->widget && !parentItem->widgetLabel) + span = 2; + l->addWidget(parentItem->button, oldRow, 0, 1, span); + updateItem(parentItem); + } + layout = parentItem->layout; + parentWidget = parentItem->container; + } + + newItem->label = new QLabel(parentWidget); + newItem->label->setSizePolicy(QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed)); + newItem->widget = createEditor(index->property(), parentWidget); + if (newItem->widget) { + QObject::connect(newItem->widget, SIGNAL(destroyed()), q_ptr, SLOT(slotEditorDestroyed())); + m_widgetToItem[newItem->widget] = newItem; + } else if (index->property()->hasValue()) { + newItem->widgetLabel = new QLabel(parentWidget); + newItem->widgetLabel->setSizePolicy(QSizePolicy(QSizePolicy::Ignored, QSizePolicy::Fixed)); + } + + insertRow(layout, row); + int span = 1; + if (newItem->widget) + layout->addWidget(newItem->widget, row, 1); + else if (newItem->widgetLabel) + layout->addWidget(newItem->widgetLabel, row, 1); + else + span = 2; + layout->addWidget(newItem->label, row, 0, span, 1); + + m_itemToIndex[newItem] = index; + m_indexToItem[index] = newItem; + + updateItem(newItem); +} + +void QtButtonPropertyBrowserPrivate::propertyRemoved(QtBrowserItem *index) +{ + WidgetItem *item = m_indexToItem.value(index); + + m_indexToItem.remove(index); + m_itemToIndex.remove(item); + + WidgetItem *parentItem = item->parent; + + const int row = gridRow(item); + + if (parentItem) + parentItem->children.removeAt(parentItem->children.indexOf(item)); + else + m_children.removeAt(m_children.indexOf(item)); + + const int colSpan = gridSpan(item); + + m_buttonToItem.remove(item->button); + + if (item->widget) + delete item->widget; + if (item->label) + delete item->label; + if (item->widgetLabel) + delete item->widgetLabel; + if (item->button) + delete item->button; + if (item->container) + delete item->container; + + if (!parentItem) { + removeRow(m_mainLayout, row); + if (colSpan > 1) + removeRow(m_mainLayout, row); + } else if (parentItem->children.count() != 0) { + removeRow(parentItem->layout, row); + if (colSpan > 1) + removeRow(parentItem->layout, row); + } else { + const WidgetItem *grandParent = parentItem->parent; + QGridLayout *l = 0; + if (grandParent) { + l = grandParent->layout; + } else { + l = m_mainLayout; + } + + const int parentRow = gridRow(parentItem); + const int parentSpan = gridSpan(parentItem); + + l->removeWidget(parentItem->button); + l->removeWidget(parentItem->container); + delete parentItem->button; + delete parentItem->container; + parentItem->button = 0; + parentItem->container = 0; + parentItem->layout = 0; + if (!m_recreateQueue.contains(parentItem)) + m_recreateQueue.append(parentItem); + if (parentSpan > 1) + removeRow(l, parentRow + 1); + + updateLater(); + } + m_recreateQueue.removeAll(item); + + delete item; +} + +void QtButtonPropertyBrowserPrivate::insertRow(QGridLayout *layout, int row) const +{ + QMap<QLayoutItem *, QRect> itemToPos; + int idx = 0; + while (idx < layout->count()) { + int r, c, rs, cs; + layout->getItemPosition(idx, &r, &c, &rs, &cs); + if (r >= row) { + itemToPos[layout->takeAt(idx)] = QRect(r + 1, c, rs, cs); + } else { + idx++; + } + } + + const QMap<QLayoutItem *, QRect>::ConstIterator icend = itemToPos.constEnd(); + for(QMap<QLayoutItem *, QRect>::ConstIterator it = itemToPos.constBegin(); it != icend; ++it) { + const QRect r = it.value(); + layout->addItem(it.key(), r.x(), r.y(), r.width(), r.height()); + } +} + +void QtButtonPropertyBrowserPrivate::removeRow(QGridLayout *layout, int row) const +{ + QMap<QLayoutItem *, QRect> itemToPos; + int idx = 0; + while (idx < layout->count()) { + int r, c, rs, cs; + layout->getItemPosition(idx, &r, &c, &rs, &cs); + if (r > row) { + itemToPos[layout->takeAt(idx)] = QRect(r - 1, c, rs, cs); + } else { + idx++; + } + } + + const QMap<QLayoutItem *, QRect>::ConstIterator icend = itemToPos.constEnd(); + for(QMap<QLayoutItem *, QRect>::ConstIterator it = itemToPos.constBegin(); it != icend; ++it) { + const QRect r = it.value(); + layout->addItem(it.key(), r.x(), r.y(), r.width(), r.height()); + } +} + +void QtButtonPropertyBrowserPrivate::propertyChanged(QtBrowserItem *index) +{ + WidgetItem *item = m_indexToItem.value(index); + + updateItem(item); +} + +void QtButtonPropertyBrowserPrivate::updateItem(WidgetItem *item) +{ + QtProperty *property = m_itemToIndex[item]->property(); + if (item->button) { + QFont font = item->button->font(); + font.setUnderline(property->isModified()); + item->button->setFont(font); + item->button->setText(property->propertyName()); + item->button->setToolTip(property->toolTip()); + item->button->setStatusTip(property->statusTip()); + item->button->setWhatsThis(property->whatsThis()); + item->button->setEnabled(property->isEnabled()); + } + if (item->label) { + QFont font = item->label->font(); + font.setUnderline(property->isModified()); + item->label->setFont(font); + item->label->setText(property->propertyName()); + item->label->setToolTip(property->toolTip()); + item->label->setStatusTip(property->statusTip()); + item->label->setWhatsThis(property->whatsThis()); + item->label->setEnabled(property->isEnabled()); + } + if (item->widgetLabel) { + QFont font = item->widgetLabel->font(); + font.setUnderline(false); + item->widgetLabel->setFont(font); + item->widgetLabel->setText(property->valueText()); + item->widgetLabel->setToolTip(property->valueText()); + item->widgetLabel->setEnabled(property->isEnabled()); + } + if (item->widget) { + QFont font = item->widget->font(); + font.setUnderline(false); + item->widget->setFont(font); + item->widget->setEnabled(property->isEnabled()); + item->widget->setToolTip(property->valueText()); + } +} + + + +/*! + \class QtButtonPropertyBrowser + \internal + \inmodule QtDesigner + \since 4.4 + + \brief The QtButtonPropertyBrowser class provides a drop down QToolButton + based property browser. + + A property browser is a widget that enables the user to edit a + given set of properties. Each property is represented by a label + specifying the property's name, and an editing widget (e.g. a line + edit or a combobox) holding its value. A property can have zero or + more subproperties. + + QtButtonPropertyBrowser provides drop down button for all nested + properties, i.e. subproperties are enclosed by a container associated with + the drop down button. The parent property's name is displayed as button text. For example: + + \image qtbuttonpropertybrowser.png + + Use the QtAbstractPropertyBrowser API to add, insert and remove + properties from an instance of the QtButtonPropertyBrowser + class. The properties themselves are created and managed by + implementations of the QtAbstractPropertyManager class. + + \sa QtTreePropertyBrowser, QtAbstractPropertyBrowser +*/ + +/*! + \fn void QtButtonPropertyBrowser::collapsed(QtBrowserItem *item) + + This signal is emitted when the \a item is collapsed. + + \sa expanded(), setExpanded() +*/ + +/*! + \fn void QtButtonPropertyBrowser::expanded(QtBrowserItem *item) + + This signal is emitted when the \a item is expanded. + + \sa collapsed(), setExpanded() +*/ + +/*! + Creates a property browser with the given \a parent. +*/ +QtButtonPropertyBrowser::QtButtonPropertyBrowser(QWidget *parent) + : QtAbstractPropertyBrowser(parent) +{ + d_ptr = new QtButtonPropertyBrowserPrivate; + d_ptr->q_ptr = this; + + d_ptr->init(this); +} + +/*! + Destroys this property browser. + + Note that the properties that were inserted into this browser are + \e not destroyed since they may still be used in other + browsers. The properties are owned by the manager that created + them. + + \sa QtProperty, QtAbstractPropertyManager +*/ +QtButtonPropertyBrowser::~QtButtonPropertyBrowser() +{ + const QMap<QtButtonPropertyBrowserPrivate::WidgetItem *, QtBrowserItem *>::ConstIterator icend = d_ptr->m_itemToIndex.constEnd(); + for (QMap<QtButtonPropertyBrowserPrivate::WidgetItem *, QtBrowserItem *>::ConstIterator it = d_ptr->m_itemToIndex.constBegin(); it != icend; ++it) + delete it.key(); + delete d_ptr; +} + +/*! + \reimp +*/ +void QtButtonPropertyBrowser::itemInserted(QtBrowserItem *item, QtBrowserItem *afterItem) +{ + d_ptr->propertyInserted(item, afterItem); +} + +/*! + \reimp +*/ +void QtButtonPropertyBrowser::itemRemoved(QtBrowserItem *item) +{ + d_ptr->propertyRemoved(item); +} + +/*! + \reimp +*/ +void QtButtonPropertyBrowser::itemChanged(QtBrowserItem *item) +{ + d_ptr->propertyChanged(item); +} + +/*! + Sets the \a item to either collapse or expanded, depending on the value of \a expanded. + + \sa isExpanded(), expanded(), collapsed() +*/ + +void QtButtonPropertyBrowser::setExpanded(QtBrowserItem *item, bool expanded) +{ + QtButtonPropertyBrowserPrivate::WidgetItem *itm = d_ptr->m_indexToItem.value(item); + if (itm) + d_ptr->setExpanded(itm, expanded); +} + +/*! + Returns true if the \a item is expanded; otherwise returns false. + + \sa setExpanded() +*/ + +bool QtButtonPropertyBrowser::isExpanded(QtBrowserItem *item) const +{ + QtButtonPropertyBrowserPrivate::WidgetItem *itm = d_ptr->m_indexToItem.value(item); + if (itm) + return itm->expanded; + return false; +} + +#if QT_VERSION >= 0x040400 +QT_END_NAMESPACE +#endif + +#include "moc_qtbuttonpropertybrowser.cpp" diff --git a/tools/shared/qtpropertybrowser/qtbuttonpropertybrowser.h b/tools/shared/qtpropertybrowser/qtbuttonpropertybrowser.h new file mode 100644 index 0000000..0833c2d --- /dev/null +++ b/tools/shared/qtpropertybrowser/qtbuttonpropertybrowser.h @@ -0,0 +1,89 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the tools applications of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QTBUTTONPROPERTYBROWSER_H +#define QTBUTTONPROPERTYBROWSER_H + +#include "qtpropertybrowser.h" + +#if QT_VERSION >= 0x040400 +QT_BEGIN_NAMESPACE +#endif + +class QtButtonPropertyBrowserPrivate; + +class QtButtonPropertyBrowser : public QtAbstractPropertyBrowser +{ + Q_OBJECT +public: + + QtButtonPropertyBrowser(QWidget *parent = 0); + ~QtButtonPropertyBrowser(); + + void setExpanded(QtBrowserItem *item, bool expanded); + bool isExpanded(QtBrowserItem *item) const; + +Q_SIGNALS: + + void collapsed(QtBrowserItem *item); + void expanded(QtBrowserItem *item); + +protected: + virtual void itemInserted(QtBrowserItem *item, QtBrowserItem *afterItem); + virtual void itemRemoved(QtBrowserItem *item); + virtual void itemChanged(QtBrowserItem *item); + +private: + + QtButtonPropertyBrowserPrivate *d_ptr; + Q_DECLARE_PRIVATE(QtButtonPropertyBrowser) + Q_DISABLE_COPY(QtButtonPropertyBrowser) + Q_PRIVATE_SLOT(d_func(), void slotUpdate()) + Q_PRIVATE_SLOT(d_func(), void slotEditorDestroyed()) + Q_PRIVATE_SLOT(d_func(), void slotToggled(bool)) + +}; + +#if QT_VERSION >= 0x040400 +QT_END_NAMESPACE +#endif + +#endif diff --git a/tools/shared/qtpropertybrowser/qteditorfactory.cpp b/tools/shared/qtpropertybrowser/qteditorfactory.cpp new file mode 100644 index 0000000..3e9336f --- /dev/null +++ b/tools/shared/qtpropertybrowser/qteditorfactory.cpp @@ -0,0 +1,2591 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the tools applications of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qteditorfactory.h" +#include "qtpropertybrowserutils_p.h" +#include <QtGui/QSpinBox> +#include <QtGui/QScrollBar> +#include <QtGui/QComboBox> +#include <QtGui/QAbstractItemView> +#include <QtGui/QLineEdit> +#include <QtGui/QDateTimeEdit> +#include <QtGui/QHBoxLayout> +#include <QtGui/QMenu> +#include <QtGui/QKeyEvent> +#include <QtGui/QApplication> +#include <QtGui/QLabel> +#include <QtGui/QToolButton> +#include <QtGui/QColorDialog> +#include <QtGui/QFontDialog> +#include <QtGui/QSpacerItem> +#include <QtCore/QMap> + +#if defined(Q_CC_MSVC) +# pragma warning(disable: 4786) /* MS VS 6: truncating debug info after 255 characters */ +#endif + +#if QT_VERSION >= 0x040400 +QT_BEGIN_NAMESPACE +#endif + +// Set a hard coded left margin to account for the indentation +// of the tree view icon when switching to an editor + +static inline void setupTreeViewEditorMargin(QLayout *lt) +{ + enum { DecorationMargin = 4 }; + if (QApplication::layoutDirection() == Qt::LeftToRight) + lt->setContentsMargins(DecorationMargin, 0, 0, 0); + else + lt->setContentsMargins(0, 0, DecorationMargin, 0); +} + +// ---------- EditorFactoryPrivate : +// Base class for editor factory private classes. Manages mapping of properties to editors and vice versa. + +template <class Editor> +class EditorFactoryPrivate +{ +public: + + typedef QList<Editor *> EditorList; + typedef QMap<QtProperty *, EditorList> PropertyToEditorListMap; + typedef QMap<Editor *, QtProperty *> EditorToPropertyMap; + + Editor *createEditor(QtProperty *property, QWidget *parent); + void initializeEditor(QtProperty *property, Editor *e); + void slotEditorDestroyed(QObject *object); + + PropertyToEditorListMap m_createdEditors; + EditorToPropertyMap m_editorToProperty; +}; + +template <class Editor> +Editor *EditorFactoryPrivate<Editor>::createEditor(QtProperty *property, QWidget *parent) +{ + Editor *editor = new Editor(parent); + initializeEditor(property, editor); + return editor; +} + +template <class Editor> +void EditorFactoryPrivate<Editor>::initializeEditor(QtProperty *property, Editor *editor) +{ + Q_TYPENAME PropertyToEditorListMap::iterator it = m_createdEditors.find(property); + if (it == m_createdEditors.end()) + it = m_createdEditors.insert(property, EditorList()); + it.value().append(editor); + m_editorToProperty.insert(editor, property); +} + +template <class Editor> +void EditorFactoryPrivate<Editor>::slotEditorDestroyed(QObject *object) +{ + const Q_TYPENAME EditorToPropertyMap::iterator ecend = m_editorToProperty.end(); + for (Q_TYPENAME EditorToPropertyMap::iterator itEditor = m_editorToProperty.begin(); itEditor != ecend; ++itEditor) { + if (itEditor.key() == object) { + Editor *editor = itEditor.key(); + QtProperty *property = itEditor.value(); + const Q_TYPENAME PropertyToEditorListMap::iterator pit = m_createdEditors.find(property); + if (pit != m_createdEditors.end()) { + pit.value().removeAll(editor); + if (pit.value().empty()) + m_createdEditors.erase(pit); + } + m_editorToProperty.erase(itEditor); + return; + } + } +} + +// ------------ QtSpinBoxFactory + +class QtSpinBoxFactoryPrivate : public EditorFactoryPrivate<QSpinBox> +{ + QtSpinBoxFactory *q_ptr; + Q_DECLARE_PUBLIC(QtSpinBoxFactory) +public: + + void slotPropertyChanged(QtProperty *property, int value); + void slotRangeChanged(QtProperty *property, int min, int max); + void slotSingleStepChanged(QtProperty *property, int step); + void slotSetValue(int value); +}; + +void QtSpinBoxFactoryPrivate::slotPropertyChanged(QtProperty *property, int value) +{ + if (!m_createdEditors.contains(property)) + return; + QListIterator<QSpinBox *> itEditor(m_createdEditors[property]); + while (itEditor.hasNext()) { + QSpinBox *editor = itEditor.next(); + if (editor->value() != value) { + editor->blockSignals(true); + editor->setValue(value); + editor->blockSignals(false); + } + } +} + +void QtSpinBoxFactoryPrivate::slotRangeChanged(QtProperty *property, int min, int max) +{ + if (!m_createdEditors.contains(property)) + return; + + QtIntPropertyManager *manager = q_ptr->propertyManager(property); + if (!manager) + return; + + QListIterator<QSpinBox *> itEditor(m_createdEditors[property]); + while (itEditor.hasNext()) { + QSpinBox *editor = itEditor.next(); + editor->blockSignals(true); + editor->setRange(min, max); + editor->setValue(manager->value(property)); + editor->blockSignals(false); + } +} + +void QtSpinBoxFactoryPrivate::slotSingleStepChanged(QtProperty *property, int step) +{ + if (!m_createdEditors.contains(property)) + return; + QListIterator<QSpinBox *> itEditor(m_createdEditors[property]); + while (itEditor.hasNext()) { + QSpinBox *editor = itEditor.next(); + editor->blockSignals(true); + editor->setSingleStep(step); + editor->blockSignals(false); + } +} + +void QtSpinBoxFactoryPrivate::slotSetValue(int value) +{ + QObject *object = q_ptr->sender(); + const QMap<QSpinBox *, QtProperty *>::ConstIterator ecend = m_editorToProperty.constEnd(); + for (QMap<QSpinBox *, QtProperty *>::ConstIterator itEditor = m_editorToProperty.constBegin(); itEditor != ecend; ++itEditor) { + if (itEditor.key() == object) { + QtProperty *property = itEditor.value(); + QtIntPropertyManager *manager = q_ptr->propertyManager(property); + if (!manager) + return; + manager->setValue(property, value); + return; + } + } +} + +/*! + \class QtSpinBoxFactory + \internal + \inmodule QtDesigner + \since 4.4 + + \brief The QtSpinBoxFactory class provides QSpinBox widgets for + properties created by QtIntPropertyManager objects. + + \sa QtAbstractEditorFactory, QtIntPropertyManager +*/ + +/*! + Creates a factory with the given \a parent. +*/ +QtSpinBoxFactory::QtSpinBoxFactory(QObject *parent) + : QtAbstractEditorFactory<QtIntPropertyManager>(parent) +{ + d_ptr = new QtSpinBoxFactoryPrivate(); + d_ptr->q_ptr = this; + +} + +/*! + Destroys this factory, and all the widgets it has created. +*/ +QtSpinBoxFactory::~QtSpinBoxFactory() +{ + qDeleteAll(d_ptr->m_editorToProperty.keys()); + delete d_ptr; +} + +/*! + \internal + + Reimplemented from the QtAbstractEditorFactory class. +*/ +void QtSpinBoxFactory::connectPropertyManager(QtIntPropertyManager *manager) +{ + connect(manager, SIGNAL(valueChanged(QtProperty *, int)), + this, SLOT(slotPropertyChanged(QtProperty *, int))); + connect(manager, SIGNAL(rangeChanged(QtProperty *, int, int)), + this, SLOT(slotRangeChanged(QtProperty *, int, int))); + connect(manager, SIGNAL(singleStepChanged(QtProperty *, int)), + this, SLOT(slotSingleStepChanged(QtProperty *, int))); +} + +/*! + \internal + + Reimplemented from the QtAbstractEditorFactory class. +*/ +QWidget *QtSpinBoxFactory::createEditor(QtIntPropertyManager *manager, QtProperty *property, + QWidget *parent) +{ + QSpinBox *editor = d_ptr->createEditor(property, parent); + editor->setSingleStep(manager->singleStep(property)); + editor->setRange(manager->minimum(property), manager->maximum(property)); + editor->setValue(manager->value(property)); + editor->setKeyboardTracking(false); + + connect(editor, SIGNAL(valueChanged(int)), this, SLOT(slotSetValue(int))); + connect(editor, SIGNAL(destroyed(QObject *)), + this, SLOT(slotEditorDestroyed(QObject *))); + return editor; +} + +/*! + \internal + + Reimplemented from the QtAbstractEditorFactory class. +*/ +void QtSpinBoxFactory::disconnectPropertyManager(QtIntPropertyManager *manager) +{ + disconnect(manager, SIGNAL(valueChanged(QtProperty *, int)), + this, SLOT(slotPropertyChanged(QtProperty *, int))); + disconnect(manager, SIGNAL(rangeChanged(QtProperty *, int, int)), + this, SLOT(slotRangeChanged(QtProperty *, int, int))); + disconnect(manager, SIGNAL(singleStepChanged(QtProperty *, int)), + this, SLOT(slotSingleStepChanged(QtProperty *, int))); +} + +// QtSliderFactory + +class QtSliderFactoryPrivate : public EditorFactoryPrivate<QSlider> +{ + QtSliderFactory *q_ptr; + Q_DECLARE_PUBLIC(QtSliderFactory) +public: + void slotPropertyChanged(QtProperty *property, int value); + void slotRangeChanged(QtProperty *property, int min, int max); + void slotSingleStepChanged(QtProperty *property, int step); + void slotSetValue(int value); +}; + +void QtSliderFactoryPrivate::slotPropertyChanged(QtProperty *property, int value) +{ + if (!m_createdEditors.contains(property)) + return; + QListIterator<QSlider *> itEditor(m_createdEditors[property]); + while (itEditor.hasNext()) { + QSlider *editor = itEditor.next(); + editor->blockSignals(true); + editor->setValue(value); + editor->blockSignals(false); + } +} + +void QtSliderFactoryPrivate::slotRangeChanged(QtProperty *property, int min, int max) +{ + if (!m_createdEditors.contains(property)) + return; + + QtIntPropertyManager *manager = q_ptr->propertyManager(property); + if (!manager) + return; + + QListIterator<QSlider *> itEditor(m_createdEditors[property]); + while (itEditor.hasNext()) { + QSlider *editor = itEditor.next(); + editor->blockSignals(true); + editor->setRange(min, max); + editor->setValue(manager->value(property)); + editor->blockSignals(false); + } +} + +void QtSliderFactoryPrivate::slotSingleStepChanged(QtProperty *property, int step) +{ + if (!m_createdEditors.contains(property)) + return; + QListIterator<QSlider *> itEditor(m_createdEditors[property]); + while (itEditor.hasNext()) { + QSlider *editor = itEditor.next(); + editor->blockSignals(true); + editor->setSingleStep(step); + editor->blockSignals(false); + } +} + +void QtSliderFactoryPrivate::slotSetValue(int value) +{ + QObject *object = q_ptr->sender(); + const QMap<QSlider *, QtProperty *>::ConstIterator ecend = m_editorToProperty.constEnd(); + for (QMap<QSlider *, QtProperty *>::ConstIterator itEditor = m_editorToProperty.constBegin(); itEditor != ecend; ++itEditor ) { + if (itEditor.key() == object) { + QtProperty *property = itEditor.value(); + QtIntPropertyManager *manager = q_ptr->propertyManager(property); + if (!manager) + return; + manager->setValue(property, value); + return; + } + } +} + +/*! + \class QtSliderFactory + \internal + \inmodule QtDesigner + \since 4.4 + + \brief The QtSliderFactory class provides QSlider widgets for + properties created by QtIntPropertyManager objects. + + \sa QtAbstractEditorFactory, QtIntPropertyManager +*/ + +/*! + Creates a factory with the given \a parent. +*/ +QtSliderFactory::QtSliderFactory(QObject *parent) + : QtAbstractEditorFactory<QtIntPropertyManager>(parent) +{ + d_ptr = new QtSliderFactoryPrivate(); + d_ptr->q_ptr = this; + +} + +/*! + Destroys this factory, and all the widgets it has created. +*/ +QtSliderFactory::~QtSliderFactory() +{ + qDeleteAll(d_ptr->m_editorToProperty.keys()); + delete d_ptr; +} + +/*! + \internal + + Reimplemented from the QtAbstractEditorFactory class. +*/ +void QtSliderFactory::connectPropertyManager(QtIntPropertyManager *manager) +{ + connect(manager, SIGNAL(valueChanged(QtProperty *, int)), + this, SLOT(slotPropertyChanged(QtProperty *, int))); + connect(manager, SIGNAL(rangeChanged(QtProperty *, int, int)), + this, SLOT(slotRangeChanged(QtProperty *, int, int))); + connect(manager, SIGNAL(singleStepChanged(QtProperty *, int)), + this, SLOT(slotSingleStepChanged(QtProperty *, int))); +} + +/*! + \internal + + Reimplemented from the QtAbstractEditorFactory class. +*/ +QWidget *QtSliderFactory::createEditor(QtIntPropertyManager *manager, QtProperty *property, + QWidget *parent) +{ + QSlider *editor = new QSlider(Qt::Horizontal, parent); + d_ptr->initializeEditor(property, editor); + editor->setSingleStep(manager->singleStep(property)); + editor->setRange(manager->minimum(property), manager->maximum(property)); + editor->setValue(manager->value(property)); + + connect(editor, SIGNAL(valueChanged(int)), this, SLOT(slotSetValue(int))); + connect(editor, SIGNAL(destroyed(QObject *)), + this, SLOT(slotEditorDestroyed(QObject *))); + return editor; +} + +/*! + \internal + + Reimplemented from the QtAbstractEditorFactory class. +*/ +void QtSliderFactory::disconnectPropertyManager(QtIntPropertyManager *manager) +{ + disconnect(manager, SIGNAL(valueChanged(QtProperty *, int)), + this, SLOT(slotPropertyChanged(QtProperty *, int))); + disconnect(manager, SIGNAL(rangeChanged(QtProperty *, int, int)), + this, SLOT(slotRangeChanged(QtProperty *, int, int))); + disconnect(manager, SIGNAL(singleStepChanged(QtProperty *, int)), + this, SLOT(slotSingleStepChanged(QtProperty *, int))); +} + +// QtSliderFactory + +class QtScrollBarFactoryPrivate : public EditorFactoryPrivate<QScrollBar> +{ + QtScrollBarFactory *q_ptr; + Q_DECLARE_PUBLIC(QtScrollBarFactory) +public: + void slotPropertyChanged(QtProperty *property, int value); + void slotRangeChanged(QtProperty *property, int min, int max); + void slotSingleStepChanged(QtProperty *property, int step); + void slotSetValue(int value); +}; + +void QtScrollBarFactoryPrivate::slotPropertyChanged(QtProperty *property, int value) +{ + if (!m_createdEditors.contains(property)) + return; + + QListIterator<QScrollBar *> itEditor( m_createdEditors[property]); + while (itEditor.hasNext()) { + QScrollBar *editor = itEditor.next(); + editor->blockSignals(true); + editor->setValue(value); + editor->blockSignals(false); + } +} + +void QtScrollBarFactoryPrivate::slotRangeChanged(QtProperty *property, int min, int max) +{ + if (!m_createdEditors.contains(property)) + return; + + QtIntPropertyManager *manager = q_ptr->propertyManager(property); + if (!manager) + return; + + QListIterator<QScrollBar *> itEditor( m_createdEditors[property]); + while (itEditor.hasNext()) { + QScrollBar *editor = itEditor.next(); + editor->blockSignals(true); + editor->setRange(min, max); + editor->setValue(manager->value(property)); + editor->blockSignals(false); + } +} + +void QtScrollBarFactoryPrivate::slotSingleStepChanged(QtProperty *property, int step) +{ + if (!m_createdEditors.contains(property)) + return; + QListIterator<QScrollBar *> itEditor(m_createdEditors[property]); + while (itEditor.hasNext()) { + QScrollBar *editor = itEditor.next(); + editor->blockSignals(true); + editor->setSingleStep(step); + editor->blockSignals(false); + } +} + +void QtScrollBarFactoryPrivate::slotSetValue(int value) +{ + QObject *object = q_ptr->sender(); + const QMap<QScrollBar *, QtProperty *>::ConstIterator ecend = m_editorToProperty.constEnd(); + for (QMap<QScrollBar *, QtProperty *>::ConstIterator itEditor = m_editorToProperty.constBegin(); itEditor != ecend; ++itEditor) + if (itEditor.key() == object) { + QtProperty *property = itEditor.value(); + QtIntPropertyManager *manager = q_ptr->propertyManager(property); + if (!manager) + return; + manager->setValue(property, value); + return; + } +} + +/*! + \class QtScrollBarFactory + \internal + \inmodule QtDesigner + \since 4.4 + + \brief The QtScrollBarFactory class provides QScrollBar widgets for + properties created by QtIntPropertyManager objects. + + \sa QtAbstractEditorFactory, QtIntPropertyManager +*/ + +/*! + Creates a factory with the given \a parent. +*/ +QtScrollBarFactory::QtScrollBarFactory(QObject *parent) + : QtAbstractEditorFactory<QtIntPropertyManager>(parent) +{ + d_ptr = new QtScrollBarFactoryPrivate(); + d_ptr->q_ptr = this; + +} + +/*! + Destroys this factory, and all the widgets it has created. +*/ +QtScrollBarFactory::~QtScrollBarFactory() +{ + qDeleteAll(d_ptr->m_editorToProperty.keys()); + delete d_ptr; +} + +/*! + \internal + + Reimplemented from the QtAbstractEditorFactory class. +*/ +void QtScrollBarFactory::connectPropertyManager(QtIntPropertyManager *manager) +{ + connect(manager, SIGNAL(valueChanged(QtProperty *, int)), + this, SLOT(slotPropertyChanged(QtProperty *, int))); + connect(manager, SIGNAL(rangeChanged(QtProperty *, int, int)), + this, SLOT(slotRangeChanged(QtProperty *, int, int))); + connect(manager, SIGNAL(singleStepChanged(QtProperty *, int)), + this, SLOT(slotSingleStepChanged(QtProperty *, int))); +} + +/*! + \internal + + Reimplemented from the QtAbstractEditorFactory class. +*/ +QWidget *QtScrollBarFactory::createEditor(QtIntPropertyManager *manager, QtProperty *property, + QWidget *parent) +{ + QScrollBar *editor = new QScrollBar(Qt::Horizontal, parent); + d_ptr->initializeEditor(property, editor); + editor->setSingleStep(manager->singleStep(property)); + editor->setRange(manager->minimum(property), manager->maximum(property)); + editor->setValue(manager->value(property)); + connect(editor, SIGNAL(valueChanged(int)), this, SLOT(slotSetValue(int))); + connect(editor, SIGNAL(destroyed(QObject *)), + this, SLOT(slotEditorDestroyed(QObject *))); + return editor; +} + +/*! + \internal + + Reimplemented from the QtAbstractEditorFactory class. +*/ +void QtScrollBarFactory::disconnectPropertyManager(QtIntPropertyManager *manager) +{ + disconnect(manager, SIGNAL(valueChanged(QtProperty *, int)), + this, SLOT(slotPropertyChanged(QtProperty *, int))); + disconnect(manager, SIGNAL(rangeChanged(QtProperty *, int, int)), + this, SLOT(slotRangeChanged(QtProperty *, int, int))); + disconnect(manager, SIGNAL(singleStepChanged(QtProperty *, int)), + this, SLOT(slotSingleStepChanged(QtProperty *, int))); +} + +// QtCheckBoxFactory + +class QtCheckBoxFactoryPrivate : public EditorFactoryPrivate<QtBoolEdit> +{ + QtCheckBoxFactory *q_ptr; + Q_DECLARE_PUBLIC(QtCheckBoxFactory) +public: + void slotPropertyChanged(QtProperty *property, bool value); + void slotSetValue(bool value); +}; + +void QtCheckBoxFactoryPrivate::slotPropertyChanged(QtProperty *property, bool value) +{ + if (!m_createdEditors.contains(property)) + return; + + QListIterator<QtBoolEdit *> itEditor(m_createdEditors[property]); + while (itEditor.hasNext()) { + QtBoolEdit *editor = itEditor.next(); + editor->blockCheckBoxSignals(true); + editor->setChecked(value); + editor->blockCheckBoxSignals(false); + } +} + +void QtCheckBoxFactoryPrivate::slotSetValue(bool value) +{ + QObject *object = q_ptr->sender(); + + const QMap<QtBoolEdit *, QtProperty *>::ConstIterator ecend = m_editorToProperty.constEnd(); + for (QMap<QtBoolEdit *, QtProperty *>::ConstIterator itEditor = m_editorToProperty.constBegin(); itEditor != ecend; ++itEditor) + if (itEditor.key() == object) { + QtProperty *property = itEditor.value(); + QtBoolPropertyManager *manager = q_ptr->propertyManager(property); + if (!manager) + return; + manager->setValue(property, value); + return; + } +} + +/*! + \class QtCheckBoxFactory + \internal + \inmodule QtDesigner + \since 4.4 + + \brief The QtCheckBoxFactory class provides QCheckBox widgets for + properties created by QtBoolPropertyManager objects. + + \sa QtAbstractEditorFactory, QtBoolPropertyManager +*/ + +/*! + Creates a factory with the given \a parent. +*/ +QtCheckBoxFactory::QtCheckBoxFactory(QObject *parent) + : QtAbstractEditorFactory<QtBoolPropertyManager>(parent) +{ + d_ptr = new QtCheckBoxFactoryPrivate(); + d_ptr->q_ptr = this; + +} + +/*! + Destroys this factory, and all the widgets it has created. +*/ +QtCheckBoxFactory::~QtCheckBoxFactory() +{ + qDeleteAll(d_ptr->m_editorToProperty.keys()); + delete d_ptr; +} + +/*! + \internal + + Reimplemented from the QtAbstractEditorFactory class. +*/ +void QtCheckBoxFactory::connectPropertyManager(QtBoolPropertyManager *manager) +{ + connect(manager, SIGNAL(valueChanged(QtProperty *, bool)), + this, SLOT(slotPropertyChanged(QtProperty *, bool))); +} + +/*! + \internal + + Reimplemented from the QtAbstractEditorFactory class. +*/ +QWidget *QtCheckBoxFactory::createEditor(QtBoolPropertyManager *manager, QtProperty *property, + QWidget *parent) +{ + QtBoolEdit *editor = d_ptr->createEditor(property, parent); + editor->setChecked(manager->value(property)); + + connect(editor, SIGNAL(toggled(bool)), this, SLOT(slotSetValue(bool))); + connect(editor, SIGNAL(destroyed(QObject *)), + this, SLOT(slotEditorDestroyed(QObject *))); + return editor; +} + +/*! + \internal + + Reimplemented from the QtAbstractEditorFactory class. +*/ +void QtCheckBoxFactory::disconnectPropertyManager(QtBoolPropertyManager *manager) +{ + disconnect(manager, SIGNAL(valueChanged(QtProperty *, bool)), + this, SLOT(slotPropertyChanged(QtProperty *, bool))); +} + +// QtDoubleSpinBoxFactory + +class QtDoubleSpinBoxFactoryPrivate : public EditorFactoryPrivate<QDoubleSpinBox> +{ + QtDoubleSpinBoxFactory *q_ptr; + Q_DECLARE_PUBLIC(QtDoubleSpinBoxFactory) +public: + + void slotPropertyChanged(QtProperty *property, double value); + void slotRangeChanged(QtProperty *property, double min, double max); + void slotSingleStepChanged(QtProperty *property, double step); + void slotDecimalsChanged(QtProperty *property, int prec); + void slotSetValue(double value); +}; + +void QtDoubleSpinBoxFactoryPrivate::slotPropertyChanged(QtProperty *property, double value) +{ + QList<QDoubleSpinBox *> editors = m_createdEditors[property]; + QListIterator<QDoubleSpinBox *> itEditor(m_createdEditors[property]); + while (itEditor.hasNext()) { + QDoubleSpinBox *editor = itEditor.next(); + if (editor->value() != value) { + editor->blockSignals(true); + editor->setValue(value); + editor->blockSignals(false); + } + } +} + +void QtDoubleSpinBoxFactoryPrivate::slotRangeChanged(QtProperty *property, + double min, double max) +{ + if (!m_createdEditors.contains(property)) + return; + + QtDoublePropertyManager *manager = q_ptr->propertyManager(property); + if (!manager) + return; + + QList<QDoubleSpinBox *> editors = m_createdEditors[property]; + QListIterator<QDoubleSpinBox *> itEditor(editors); + while (itEditor.hasNext()) { + QDoubleSpinBox *editor = itEditor.next(); + editor->blockSignals(true); + editor->setRange(min, max); + editor->setValue(manager->value(property)); + editor->blockSignals(false); + } +} + +void QtDoubleSpinBoxFactoryPrivate::slotSingleStepChanged(QtProperty *property, double step) +{ + if (!m_createdEditors.contains(property)) + return; + + QtDoublePropertyManager *manager = q_ptr->propertyManager(property); + if (!manager) + return; + + QList<QDoubleSpinBox *> editors = m_createdEditors[property]; + QListIterator<QDoubleSpinBox *> itEditor(editors); + while (itEditor.hasNext()) { + QDoubleSpinBox *editor = itEditor.next(); + editor->blockSignals(true); + editor->setSingleStep(step); + editor->blockSignals(false); + } +} + +void QtDoubleSpinBoxFactoryPrivate::slotDecimalsChanged(QtProperty *property, int prec) +{ + if (!m_createdEditors.contains(property)) + return; + + QtDoublePropertyManager *manager = q_ptr->propertyManager(property); + if (!manager) + return; + + QList<QDoubleSpinBox *> editors = m_createdEditors[property]; + QListIterator<QDoubleSpinBox *> itEditor(editors); + while (itEditor.hasNext()) { + QDoubleSpinBox *editor = itEditor.next(); + editor->blockSignals(true); + editor->setDecimals(prec); + editor->setValue(manager->value(property)); + editor->blockSignals(false); + } +} + +void QtDoubleSpinBoxFactoryPrivate::slotSetValue(double value) +{ + QObject *object = q_ptr->sender(); + const QMap<QDoubleSpinBox *, QtProperty *>::ConstIterator itcend = m_editorToProperty.constEnd(); + for (QMap<QDoubleSpinBox *, QtProperty *>::ConstIterator itEditor = m_editorToProperty.constBegin(); itEditor != itcend; ++itEditor) { + if (itEditor.key() == object) { + QtProperty *property = itEditor.value(); + QtDoublePropertyManager *manager = q_ptr->propertyManager(property); + if (!manager) + return; + manager->setValue(property, value); + return; + } + } +} + +/*! \class QtDoubleSpinBoxFactory + \internal + \inmodule QtDesigner + \since 4.4 + + \brief The QtDoubleSpinBoxFactory class provides QDoubleSpinBox + widgets for properties created by QtDoublePropertyManager objects. + + \sa QtAbstractEditorFactory, QtDoublePropertyManager +*/ + +/*! + Creates a factory with the given \a parent. +*/ +QtDoubleSpinBoxFactory::QtDoubleSpinBoxFactory(QObject *parent) + : QtAbstractEditorFactory<QtDoublePropertyManager>(parent) +{ + d_ptr = new QtDoubleSpinBoxFactoryPrivate(); + d_ptr->q_ptr = this; + +} + +/*! + Destroys this factory, and all the widgets it has created. +*/ +QtDoubleSpinBoxFactory::~QtDoubleSpinBoxFactory() +{ + qDeleteAll(d_ptr->m_editorToProperty.keys()); + delete d_ptr; +} + +/*! + \internal + + Reimplemented from the QtAbstractEditorFactory class. +*/ +void QtDoubleSpinBoxFactory::connectPropertyManager(QtDoublePropertyManager *manager) +{ + connect(manager, SIGNAL(valueChanged(QtProperty *, double)), + this, SLOT(slotPropertyChanged(QtProperty *, double))); + connect(manager, SIGNAL(rangeChanged(QtProperty *, double, double)), + this, SLOT(slotRangeChanged(QtProperty *, double, double))); + connect(manager, SIGNAL(singleStepChanged(QtProperty *, double)), + this, SLOT(slotSingleStepChanged(QtProperty *, double))); + connect(manager, SIGNAL(decimalsChanged(QtProperty *, int)), + this, SLOT(slotDecimalsChanged(QtProperty *, int))); +} + +/*! + \internal + + Reimplemented from the QtAbstractEditorFactory class. +*/ +QWidget *QtDoubleSpinBoxFactory::createEditor(QtDoublePropertyManager *manager, + QtProperty *property, QWidget *parent) +{ + QDoubleSpinBox *editor = d_ptr->createEditor(property, parent); + editor->setSingleStep(manager->singleStep(property)); + editor->setDecimals(manager->decimals(property)); + editor->setRange(manager->minimum(property), manager->maximum(property)); + editor->setValue(manager->value(property)); + editor->setKeyboardTracking(false); + + connect(editor, SIGNAL(valueChanged(double)), this, SLOT(slotSetValue(double))); + connect(editor, SIGNAL(destroyed(QObject *)), + this, SLOT(slotEditorDestroyed(QObject *))); + return editor; +} + +/*! + \internal + + Reimplemented from the QtAbstractEditorFactory class. +*/ +void QtDoubleSpinBoxFactory::disconnectPropertyManager(QtDoublePropertyManager *manager) +{ + disconnect(manager, SIGNAL(valueChanged(QtProperty *, double)), + this, SLOT(slotPropertyChanged(QtProperty *, double))); + disconnect(manager, SIGNAL(rangeChanged(QtProperty *, double, double)), + this, SLOT(slotRangeChanged(QtProperty *, double, double))); + disconnect(manager, SIGNAL(singleStepChanged(QtProperty *, double)), + this, SLOT(slotSingleStepChanged(QtProperty *, double))); + disconnect(manager, SIGNAL(decimalsChanged(QtProperty *, int)), + this, SLOT(slotDecimalsChanged(QtProperty *, int))); +} + +// QtLineEditFactory + +class QtLineEditFactoryPrivate : public EditorFactoryPrivate<QLineEdit> +{ + QtLineEditFactory *q_ptr; + Q_DECLARE_PUBLIC(QtLineEditFactory) +public: + + void slotPropertyChanged(QtProperty *property, const QString &value); + void slotRegExpChanged(QtProperty *property, const QRegExp ®Exp); + void slotSetValue(const QString &value); +}; + +void QtLineEditFactoryPrivate::slotPropertyChanged(QtProperty *property, + const QString &value) +{ + if (!m_createdEditors.contains(property)) + return; + + QListIterator<QLineEdit *> itEditor( m_createdEditors[property]); + while (itEditor.hasNext()) { + QLineEdit *editor = itEditor.next(); + if (editor->text() != value) + editor->setText(value); + } +} + +void QtLineEditFactoryPrivate::slotRegExpChanged(QtProperty *property, + const QRegExp ®Exp) +{ + if (!m_createdEditors.contains(property)) + return; + + QtStringPropertyManager *manager = q_ptr->propertyManager(property); + if (!manager) + return; + + QListIterator<QLineEdit *> itEditor(m_createdEditors[property]); + while (itEditor.hasNext()) { + QLineEdit *editor = itEditor.next(); + editor->blockSignals(true); + const QValidator *oldValidator = editor->validator(); + QValidator *newValidator = 0; + if (regExp.isValid()) { + newValidator = new QRegExpValidator(regExp, editor); + } + editor->setValidator(newValidator); + if (oldValidator) + delete oldValidator; + editor->blockSignals(false); + } +} + +void QtLineEditFactoryPrivate::slotSetValue(const QString &value) +{ + QObject *object = q_ptr->sender(); + const QMap<QLineEdit *, QtProperty *>::ConstIterator ecend = m_editorToProperty.constEnd(); + for (QMap<QLineEdit *, QtProperty *>::ConstIterator itEditor = m_editorToProperty.constBegin(); itEditor != ecend; ++itEditor) + if (itEditor.key() == object) { + QtProperty *property = itEditor.value(); + QtStringPropertyManager *manager = q_ptr->propertyManager(property); + if (!manager) + return; + manager->setValue(property, value); + return; + } +} + +/*! + \class QtLineEditFactory + \internal + \inmodule QtDesigner + \since 4.4 + + \brief The QtLineEditFactory class provides QLineEdit widgets for + properties created by QtStringPropertyManager objects. + + \sa QtAbstractEditorFactory, QtStringPropertyManager +*/ + +/*! + Creates a factory with the given \a parent. +*/ +QtLineEditFactory::QtLineEditFactory(QObject *parent) + : QtAbstractEditorFactory<QtStringPropertyManager>(parent) +{ + d_ptr = new QtLineEditFactoryPrivate(); + d_ptr->q_ptr = this; + +} + +/*! + Destroys this factory, and all the widgets it has created. +*/ +QtLineEditFactory::~QtLineEditFactory() +{ + qDeleteAll(d_ptr->m_editorToProperty.keys()); + delete d_ptr; +} + +/*! + \internal + + Reimplemented from the QtAbstractEditorFactory class. +*/ +void QtLineEditFactory::connectPropertyManager(QtStringPropertyManager *manager) +{ + connect(manager, SIGNAL(valueChanged(QtProperty *, const QString &)), + this, SLOT(slotPropertyChanged(QtProperty *, const QString &))); + connect(manager, SIGNAL(regExpChanged(QtProperty *, const QRegExp &)), + this, SLOT(slotRegExpChanged(QtProperty *, const QRegExp &))); +} + +/*! + \internal + + Reimplemented from the QtAbstractEditorFactory class. +*/ +QWidget *QtLineEditFactory::createEditor(QtStringPropertyManager *manager, + QtProperty *property, QWidget *parent) +{ + + QLineEdit *editor = d_ptr->createEditor(property, parent); + QRegExp regExp = manager->regExp(property); + if (regExp.isValid()) { + QValidator *validator = new QRegExpValidator(regExp, editor); + editor->setValidator(validator); + } + editor->setText(manager->value(property)); + + connect(editor, SIGNAL(textEdited(const QString &)), + this, SLOT(slotSetValue(const QString &))); + connect(editor, SIGNAL(destroyed(QObject *)), + this, SLOT(slotEditorDestroyed(QObject *))); + return editor; +} + +/*! + \internal + + Reimplemented from the QtAbstractEditorFactory class. +*/ +void QtLineEditFactory::disconnectPropertyManager(QtStringPropertyManager *manager) +{ + disconnect(manager, SIGNAL(valueChanged(QtProperty *, const QString &)), + this, SLOT(slotPropertyChanged(QtProperty *, const QString &))); + disconnect(manager, SIGNAL(regExpChanged(QtProperty *, const QRegExp &)), + this, SLOT(slotRegExpChanged(QtProperty *, const QRegExp &))); +} + +// QtDateEditFactory + +class QtDateEditFactoryPrivate : public EditorFactoryPrivate<QDateEdit> +{ + QtDateEditFactory *q_ptr; + Q_DECLARE_PUBLIC(QtDateEditFactory) +public: + + void slotPropertyChanged(QtProperty *property, const QDate &value); + void slotRangeChanged(QtProperty *property, const QDate &min, const QDate &max); + void slotSetValue(const QDate &value); +}; + +void QtDateEditFactoryPrivate::slotPropertyChanged(QtProperty *property, const QDate &value) +{ + if (!m_createdEditors.contains(property)) + return; + QListIterator<QDateEdit *> itEditor(m_createdEditors[property]); + while (itEditor.hasNext()) { + QDateEdit *editor = itEditor.next(); + editor->blockSignals(true); + editor->setDate(value); + editor->blockSignals(false); + } +} + +void QtDateEditFactoryPrivate::slotRangeChanged(QtProperty *property, + const QDate &min, const QDate &max) +{ + if (!m_createdEditors.contains(property)) + return; + + QtDatePropertyManager *manager = q_ptr->propertyManager(property); + if (!manager) + return; + + QListIterator<QDateEdit *> itEditor(m_createdEditors[property]); + while (itEditor.hasNext()) { + QDateEdit *editor = itEditor.next(); + editor->blockSignals(true); + editor->setDateRange(min, max); + editor->setDate(manager->value(property)); + editor->blockSignals(false); + } +} + +void QtDateEditFactoryPrivate::slotSetValue(const QDate &value) +{ + QObject *object = q_ptr->sender(); + const QMap<QDateEdit *, QtProperty *>::ConstIterator ecend = m_editorToProperty.constEnd(); + for (QMap<QDateEdit *, QtProperty *>::ConstIterator itEditor = m_editorToProperty.constBegin(); itEditor != ecend; ++itEditor) + if (itEditor.key() == object) { + QtProperty *property = itEditor.value(); + QtDatePropertyManager *manager = q_ptr->propertyManager(property); + if (!manager) + return; + manager->setValue(property, value); + return; + } +} + +/*! + \class QtDateEditFactory + \internal + \inmodule QtDesigner + \since 4.4 + + \brief The QtDateEditFactory class provides QDateEdit widgets for + properties created by QtDatePropertyManager objects. + + \sa QtAbstractEditorFactory, QtDatePropertyManager +*/ + +/*! + Creates a factory with the given \a parent. +*/ +QtDateEditFactory::QtDateEditFactory(QObject *parent) + : QtAbstractEditorFactory<QtDatePropertyManager>(parent) +{ + d_ptr = new QtDateEditFactoryPrivate(); + d_ptr->q_ptr = this; + +} + +/*! + Destroys this factory, and all the widgets it has created. +*/ +QtDateEditFactory::~QtDateEditFactory() +{ + qDeleteAll(d_ptr->m_editorToProperty.keys()); + delete d_ptr; +} + +/*! + \internal + + Reimplemented from the QtAbstractEditorFactory class. +*/ +void QtDateEditFactory::connectPropertyManager(QtDatePropertyManager *manager) +{ + connect(manager, SIGNAL(valueChanged(QtProperty *, const QDate &)), + this, SLOT(slotPropertyChanged(QtProperty *, const QDate &))); + connect(manager, SIGNAL(rangeChanged(QtProperty *, const QDate &, const QDate &)), + this, SLOT(slotRangeChanged(QtProperty *, const QDate &, const QDate &))); +} + +/*! + \internal + + Reimplemented from the QtAbstractEditorFactory class. +*/ +QWidget *QtDateEditFactory::createEditor(QtDatePropertyManager *manager, QtProperty *property, + QWidget *parent) +{ + QDateEdit *editor = d_ptr->createEditor(property, parent); + editor->setCalendarPopup(true); + editor->setDateRange(manager->minimum(property), manager->maximum(property)); + editor->setDate(manager->value(property)); + + connect(editor, SIGNAL(dateChanged(const QDate &)), + this, SLOT(slotSetValue(const QDate &))); + connect(editor, SIGNAL(destroyed(QObject *)), + this, SLOT(slotEditorDestroyed(QObject *))); + return editor; +} + +/*! + \internal + + Reimplemented from the QtAbstractEditorFactory class. +*/ +void QtDateEditFactory::disconnectPropertyManager(QtDatePropertyManager *manager) +{ + disconnect(manager, SIGNAL(valueChanged(QtProperty *, const QDate &)), + this, SLOT(slotPropertyChanged(QtProperty *, const QDate &))); + disconnect(manager, SIGNAL(rangeChanged(QtProperty *, const QDate &, const QDate &)), + this, SLOT(slotRangeChanged(QtProperty *, const QDate &, const QDate &))); +} + +// QtTimeEditFactory + +class QtTimeEditFactoryPrivate : public EditorFactoryPrivate<QTimeEdit> +{ + QtTimeEditFactory *q_ptr; + Q_DECLARE_PUBLIC(QtTimeEditFactory) +public: + + void slotPropertyChanged(QtProperty *property, const QTime &value); + void slotSetValue(const QTime &value); +}; + +void QtTimeEditFactoryPrivate::slotPropertyChanged(QtProperty *property, const QTime &value) +{ + if (!m_createdEditors.contains(property)) + return; + QListIterator<QTimeEdit *> itEditor(m_createdEditors[property]); + while (itEditor.hasNext()) { + QTimeEdit *editor = itEditor.next(); + editor->blockSignals(true); + editor->setTime(value); + editor->blockSignals(false); + } +} + +void QtTimeEditFactoryPrivate::slotSetValue(const QTime &value) +{ + QObject *object = q_ptr->sender(); + const QMap<QTimeEdit *, QtProperty *>::ConstIterator ecend = m_editorToProperty.constEnd(); + for (QMap<QTimeEdit *, QtProperty *>::ConstIterator itEditor = m_editorToProperty.constBegin(); itEditor != ecend; ++itEditor) + if (itEditor.key() == object) { + QtProperty *property = itEditor.value(); + QtTimePropertyManager *manager = q_ptr->propertyManager(property); + if (!manager) + return; + manager->setValue(property, value); + return; + } +} + +/*! + \class QtTimeEditFactory + \internal + \inmodule QtDesigner + \since 4.4 + + \brief The QtTimeEditFactory class provides QTimeEdit widgets for + properties created by QtTimePropertyManager objects. + + \sa QtAbstractEditorFactory, QtTimePropertyManager +*/ + +/*! + Creates a factory with the given \a parent. +*/ +QtTimeEditFactory::QtTimeEditFactory(QObject *parent) + : QtAbstractEditorFactory<QtTimePropertyManager>(parent) +{ + d_ptr = new QtTimeEditFactoryPrivate(); + d_ptr->q_ptr = this; + +} + +/*! + Destroys this factory, and all the widgets it has created. +*/ +QtTimeEditFactory::~QtTimeEditFactory() +{ + qDeleteAll(d_ptr->m_editorToProperty.keys()); + delete d_ptr; +} + +/*! + \internal + + Reimplemented from the QtAbstractEditorFactory class. +*/ +void QtTimeEditFactory::connectPropertyManager(QtTimePropertyManager *manager) +{ + connect(manager, SIGNAL(valueChanged(QtProperty *, const QTime &)), + this, SLOT(slotPropertyChanged(QtProperty *, const QTime &))); +} + +/*! + \internal + + Reimplemented from the QtAbstractEditorFactory class. +*/ +QWidget *QtTimeEditFactory::createEditor(QtTimePropertyManager *manager, QtProperty *property, + QWidget *parent) +{ + QTimeEdit *editor = d_ptr->createEditor(property, parent); + editor->setTime(manager->value(property)); + + connect(editor, SIGNAL(timeChanged(const QTime &)), + this, SLOT(slotSetValue(const QTime &))); + connect(editor, SIGNAL(destroyed(QObject *)), + this, SLOT(slotEditorDestroyed(QObject *))); + return editor; +} + +/*! + \internal + + Reimplemented from the QtAbstractEditorFactory class. +*/ +void QtTimeEditFactory::disconnectPropertyManager(QtTimePropertyManager *manager) +{ + disconnect(manager, SIGNAL(valueChanged(QtProperty *, const QTime &)), + this, SLOT(slotPropertyChanged(QtProperty *, const QTime &))); +} + +// QtDateTimeEditFactory + +class QtDateTimeEditFactoryPrivate : public EditorFactoryPrivate<QDateTimeEdit> +{ + QtDateTimeEditFactory *q_ptr; + Q_DECLARE_PUBLIC(QtDateTimeEditFactory) +public: + + void slotPropertyChanged(QtProperty *property, const QDateTime &value); + void slotSetValue(const QDateTime &value); + +}; + +void QtDateTimeEditFactoryPrivate::slotPropertyChanged(QtProperty *property, + const QDateTime &value) +{ + if (!m_createdEditors.contains(property)) + return; + + QListIterator<QDateTimeEdit *> itEditor(m_createdEditors[property]); + while (itEditor.hasNext()) { + QDateTimeEdit *editor = itEditor.next(); + editor->blockSignals(true); + editor->setDateTime(value); + editor->blockSignals(false); + } +} + +void QtDateTimeEditFactoryPrivate::slotSetValue(const QDateTime &value) +{ + QObject *object = q_ptr->sender(); + const QMap<QDateTimeEdit *, QtProperty *>::ConstIterator ecend = m_editorToProperty.constEnd(); + for (QMap<QDateTimeEdit *, QtProperty *>::ConstIterator itEditor = m_editorToProperty.constBegin(); itEditor != ecend; ++itEditor) + if (itEditor.key() == object) { + QtProperty *property = itEditor.value(); + QtDateTimePropertyManager *manager = q_ptr->propertyManager(property); + if (!manager) + return; + manager->setValue(property, value); + return; + } +} + +/*! + \class QtDateTimeEditFactory + \internal + \inmodule QtDesigner + \since 4.4 + + \brief The QtDateTimeEditFactory class provides QDateTimeEdit + widgets for properties created by QtDateTimePropertyManager objects. + + \sa QtAbstractEditorFactory, QtDateTimePropertyManager +*/ + +/*! + Creates a factory with the given \a parent. +*/ +QtDateTimeEditFactory::QtDateTimeEditFactory(QObject *parent) + : QtAbstractEditorFactory<QtDateTimePropertyManager>(parent) +{ + d_ptr = new QtDateTimeEditFactoryPrivate(); + d_ptr->q_ptr = this; + +} + +/*! + Destroys this factory, and all the widgets it has created. +*/ +QtDateTimeEditFactory::~QtDateTimeEditFactory() +{ + qDeleteAll(d_ptr->m_editorToProperty.keys()); + delete d_ptr; +} + +/*! + \internal + + Reimplemented from the QtAbstractEditorFactory class. +*/ +void QtDateTimeEditFactory::connectPropertyManager(QtDateTimePropertyManager *manager) +{ + connect(manager, SIGNAL(valueChanged(QtProperty *, const QDateTime &)), + this, SLOT(slotPropertyChanged(QtProperty *, const QDateTime &))); +} + +/*! + \internal + + Reimplemented from the QtAbstractEditorFactory class. +*/ +QWidget *QtDateTimeEditFactory::createEditor(QtDateTimePropertyManager *manager, + QtProperty *property, QWidget *parent) +{ + QDateTimeEdit *editor = d_ptr->createEditor(property, parent); + editor->setDateTime(manager->value(property)); + + connect(editor, SIGNAL(dateTimeChanged(const QDateTime &)), + this, SLOT(slotSetValue(const QDateTime &))); + connect(editor, SIGNAL(destroyed(QObject *)), + this, SLOT(slotEditorDestroyed(QObject *))); + return editor; +} + +/*! + \internal + + Reimplemented from the QtAbstractEditorFactory class. +*/ +void QtDateTimeEditFactory::disconnectPropertyManager(QtDateTimePropertyManager *manager) +{ + disconnect(manager, SIGNAL(valueChanged(QtProperty *, const QDateTime &)), + this, SLOT(slotPropertyChanged(QtProperty *, const QDateTime &))); +} + +// QtKeySequenceEditorFactory + +class QtKeySequenceEditorFactoryPrivate : public EditorFactoryPrivate<QtKeySequenceEdit> +{ + QtKeySequenceEditorFactory *q_ptr; + Q_DECLARE_PUBLIC(QtKeySequenceEditorFactory) +public: + + void slotPropertyChanged(QtProperty *property, const QKeySequence &value); + void slotSetValue(const QKeySequence &value); +}; + +void QtKeySequenceEditorFactoryPrivate::slotPropertyChanged(QtProperty *property, + const QKeySequence &value) +{ + if (!m_createdEditors.contains(property)) + return; + + QListIterator<QtKeySequenceEdit *> itEditor(m_createdEditors[property]); + while (itEditor.hasNext()) { + QtKeySequenceEdit *editor = itEditor.next(); + editor->blockSignals(true); + editor->setKeySequence(value); + editor->blockSignals(false); + } +} + +void QtKeySequenceEditorFactoryPrivate::slotSetValue(const QKeySequence &value) +{ + QObject *object = q_ptr->sender(); + const QMap<QtKeySequenceEdit *, QtProperty *>::ConstIterator ecend = m_editorToProperty.constEnd(); + for (QMap<QtKeySequenceEdit *, QtProperty *>::ConstIterator itEditor = m_editorToProperty.constBegin(); itEditor != ecend; ++itEditor) + if (itEditor.key() == object) { + QtProperty *property = itEditor.value(); + QtKeySequencePropertyManager *manager = q_ptr->propertyManager(property); + if (!manager) + return; + manager->setValue(property, value); + return; + } +} + +/*! + \class QtKeySequenceEditorFactory + \internal + \inmodule QtDesigner + \since 4.4 + + \brief The QtKeySequenceEditorFactory class provides editor + widgets for properties created by QtKeySequencePropertyManager objects. + + \sa QtAbstractEditorFactory +*/ + +/*! + Creates a factory with the given \a parent. +*/ +QtKeySequenceEditorFactory::QtKeySequenceEditorFactory(QObject *parent) + : QtAbstractEditorFactory<QtKeySequencePropertyManager>(parent) +{ + d_ptr = new QtKeySequenceEditorFactoryPrivate(); + d_ptr->q_ptr = this; + +} + +/*! + Destroys this factory, and all the widgets it has created. +*/ +QtKeySequenceEditorFactory::~QtKeySequenceEditorFactory() +{ + qDeleteAll(d_ptr->m_editorToProperty.keys()); + delete d_ptr; +} + +/*! + \internal + + Reimplemented from the QtAbstractEditorFactory class. +*/ +void QtKeySequenceEditorFactory::connectPropertyManager(QtKeySequencePropertyManager *manager) +{ + connect(manager, SIGNAL(valueChanged(QtProperty *, const QKeySequence &)), + this, SLOT(slotPropertyChanged(QtProperty *, const QKeySequence &))); +} + +/*! + \internal + + Reimplemented from the QtAbstractEditorFactory class. +*/ +QWidget *QtKeySequenceEditorFactory::createEditor(QtKeySequencePropertyManager *manager, + QtProperty *property, QWidget *parent) +{ + QtKeySequenceEdit *editor = d_ptr->createEditor(property, parent); + editor->setKeySequence(manager->value(property)); + + connect(editor, SIGNAL(keySequenceChanged(const QKeySequence &)), + this, SLOT(slotSetValue(const QKeySequence &))); + connect(editor, SIGNAL(destroyed(QObject *)), + this, SLOT(slotEditorDestroyed(QObject *))); + return editor; +} + +/*! + \internal + + Reimplemented from the QtAbstractEditorFactory class. +*/ +void QtKeySequenceEditorFactory::disconnectPropertyManager(QtKeySequencePropertyManager *manager) +{ + disconnect(manager, SIGNAL(valueChanged(QtProperty *, const QKeySequence &)), + this, SLOT(slotPropertyChanged(QtProperty *, const QKeySequence &))); +} + +// QtCharEdit + +class QtCharEdit : public QWidget +{ + Q_OBJECT +public: + QtCharEdit(QWidget *parent = 0); + + QChar value() const; + bool eventFilter(QObject *o, QEvent *e); +public Q_SLOTS: + void setValue(const QChar &value); +Q_SIGNALS: + void valueChanged(const QChar &value); +protected: + void focusInEvent(QFocusEvent *e); + void focusOutEvent(QFocusEvent *e); + void keyPressEvent(QKeyEvent *e); + void keyReleaseEvent(QKeyEvent *e); + bool event(QEvent *e); +private slots: + void slotClearChar(); +private: + void handleKeyEvent(QKeyEvent *e); + + QChar m_value; + QLineEdit *m_lineEdit; +}; + +QtCharEdit::QtCharEdit(QWidget *parent) + : QWidget(parent), m_lineEdit(new QLineEdit(this)) +{ + QHBoxLayout *layout = new QHBoxLayout(this); + layout->addWidget(m_lineEdit); + layout->setMargin(0); + m_lineEdit->installEventFilter(this); + m_lineEdit->setReadOnly(true); + m_lineEdit->setFocusProxy(this); + setFocusPolicy(m_lineEdit->focusPolicy()); + setAttribute(Qt::WA_InputMethodEnabled); +} + +bool QtCharEdit::eventFilter(QObject *o, QEvent *e) +{ + if (o == m_lineEdit && e->type() == QEvent::ContextMenu) { + QContextMenuEvent *c = static_cast<QContextMenuEvent *>(e); + QMenu *menu = m_lineEdit->createStandardContextMenu(); + QList<QAction *> actions = menu->actions(); + QListIterator<QAction *> itAction(actions); + while (itAction.hasNext()) { + QAction *action = itAction.next(); + action->setShortcut(QKeySequence()); + QString actionString = action->text(); + const int pos = actionString.lastIndexOf(QLatin1Char('\t')); + if (pos > 0) + actionString = actionString.remove(pos, actionString.length() - pos); + action->setText(actionString); + } + QAction *actionBefore = 0; + if (actions.count() > 0) + actionBefore = actions[0]; + QAction *clearAction = new QAction(tr("Clear Char"), menu); + menu->insertAction(actionBefore, clearAction); + menu->insertSeparator(actionBefore); + clearAction->setEnabled(!m_value.isNull()); + connect(clearAction, SIGNAL(triggered()), this, SLOT(slotClearChar())); + menu->exec(c->globalPos()); + delete menu; + e->accept(); + return true; + } + + return QWidget::eventFilter(o, e); +} + +void QtCharEdit::slotClearChar() +{ + if (m_value.isNull()) + return; + setValue(QChar()); + emit valueChanged(m_value); +} + +void QtCharEdit::handleKeyEvent(QKeyEvent *e) +{ + const int key = e->key(); + switch (key) { + case Qt::Key_Control: + case Qt::Key_Shift: + case Qt::Key_Meta: + case Qt::Key_Alt: + case Qt::Key_Super_L: + case Qt::Key_Return: + return; + default: + break; + } + + const QString text = e->text(); + if (text.count() != 1) + return; + + const QChar c = text.at(0); + if (!c.isPrint()) + return; + + if (m_value == c) + return; + + m_value = c; + const QString str = m_value.isNull() ? QString() : QString(m_value); + m_lineEdit->setText(str); + e->accept(); + emit valueChanged(m_value); +} + +void QtCharEdit::setValue(const QChar &value) +{ + if (value == m_value) + return; + + m_value = value; + QString str = value.isNull() ? QString() : QString(value); + m_lineEdit->setText(str); +} + +QChar QtCharEdit::value() const +{ + return m_value; +} + +void QtCharEdit::focusInEvent(QFocusEvent *e) +{ + m_lineEdit->event(e); + m_lineEdit->selectAll(); + QWidget::focusInEvent(e); +} + +void QtCharEdit::focusOutEvent(QFocusEvent *e) +{ + m_lineEdit->event(e); + QWidget::focusOutEvent(e); +} + +void QtCharEdit::keyPressEvent(QKeyEvent *e) +{ + handleKeyEvent(e); + e->accept(); +} + +void QtCharEdit::keyReleaseEvent(QKeyEvent *e) +{ + m_lineEdit->event(e); +} + +bool QtCharEdit::event(QEvent *e) +{ + switch(e->type()) { + case QEvent::Shortcut: + case QEvent::ShortcutOverride: + case QEvent::KeyRelease: + e->accept(); + return true; + default: + break; + } + return QWidget::event(e); +} + +// QtCharEditorFactory + +class QtCharEditorFactoryPrivate : public EditorFactoryPrivate<QtCharEdit> +{ + QtCharEditorFactory *q_ptr; + Q_DECLARE_PUBLIC(QtCharEditorFactory) +public: + + void slotPropertyChanged(QtProperty *property, const QChar &value); + void slotSetValue(const QChar &value); + +}; + +void QtCharEditorFactoryPrivate::slotPropertyChanged(QtProperty *property, + const QChar &value) +{ + if (!m_createdEditors.contains(property)) + return; + + QListIterator<QtCharEdit *> itEditor(m_createdEditors[property]); + while (itEditor.hasNext()) { + QtCharEdit *editor = itEditor.next(); + editor->blockSignals(true); + editor->setValue(value); + editor->blockSignals(false); + } +} + +void QtCharEditorFactoryPrivate::slotSetValue(const QChar &value) +{ + QObject *object = q_ptr->sender(); + const QMap<QtCharEdit *, QtProperty *>::ConstIterator ecend = m_editorToProperty.constEnd(); + for (QMap<QtCharEdit *, QtProperty *>::ConstIterator itEditor = m_editorToProperty.constBegin(); itEditor != ecend; ++itEditor) + if (itEditor.key() == object) { + QtProperty *property = itEditor.value(); + QtCharPropertyManager *manager = q_ptr->propertyManager(property); + if (!manager) + return; + manager->setValue(property, value); + return; + } +} + +/*! + \class QtCharEditorFactory + \internal + \inmodule QtDesigner + \since 4.4 + + \brief The QtCharEditorFactory class provides editor + widgets for properties created by QtCharPropertyManager objects. + + \sa QtAbstractEditorFactory +*/ + +/*! + Creates a factory with the given \a parent. +*/ +QtCharEditorFactory::QtCharEditorFactory(QObject *parent) + : QtAbstractEditorFactory<QtCharPropertyManager>(parent) +{ + d_ptr = new QtCharEditorFactoryPrivate(); + d_ptr->q_ptr = this; + +} + +/*! + Destroys this factory, and all the widgets it has created. +*/ +QtCharEditorFactory::~QtCharEditorFactory() +{ + qDeleteAll(d_ptr->m_editorToProperty.keys()); + delete d_ptr; +} + +/*! + \internal + + Reimplemented from the QtAbstractEditorFactory class. +*/ +void QtCharEditorFactory::connectPropertyManager(QtCharPropertyManager *manager) +{ + connect(manager, SIGNAL(valueChanged(QtProperty *, const QChar &)), + this, SLOT(slotPropertyChanged(QtProperty *, const QChar &))); +} + +/*! + \internal + + Reimplemented from the QtAbstractEditorFactory class. +*/ +QWidget *QtCharEditorFactory::createEditor(QtCharPropertyManager *manager, + QtProperty *property, QWidget *parent) +{ + QtCharEdit *editor = d_ptr->createEditor(property, parent); + editor->setValue(manager->value(property)); + + connect(editor, SIGNAL(valueChanged(const QChar &)), + this, SLOT(slotSetValue(const QChar &))); + connect(editor, SIGNAL(destroyed(QObject *)), + this, SLOT(slotEditorDestroyed(QObject *))); + return editor; +} + +/*! + \internal + + Reimplemented from the QtAbstractEditorFactory class. +*/ +void QtCharEditorFactory::disconnectPropertyManager(QtCharPropertyManager *manager) +{ + disconnect(manager, SIGNAL(valueChanged(QtProperty *, const QChar &)), + this, SLOT(slotPropertyChanged(QtProperty *, const QChar &))); +} + +// QtEnumEditorFactory + +class QtEnumEditorFactoryPrivate : public EditorFactoryPrivate<QComboBox> +{ + QtEnumEditorFactory *q_ptr; + Q_DECLARE_PUBLIC(QtEnumEditorFactory) +public: + + void slotPropertyChanged(QtProperty *property, int value); + void slotEnumNamesChanged(QtProperty *property, const QStringList &); + void slotEnumIconsChanged(QtProperty *property, const QMap<int, QIcon> &); + void slotSetValue(int value); +}; + +void QtEnumEditorFactoryPrivate::slotPropertyChanged(QtProperty *property, int value) +{ + if (!m_createdEditors.contains(property)) + return; + + QListIterator<QComboBox *> itEditor(m_createdEditors[property]); + while (itEditor.hasNext()) { + QComboBox *editor = itEditor.next(); + editor->blockSignals(true); + editor->setCurrentIndex(value); + editor->blockSignals(false); + } +} + +void QtEnumEditorFactoryPrivate::slotEnumNamesChanged(QtProperty *property, + const QStringList &enumNames) +{ + if (!m_createdEditors.contains(property)) + return; + + QtEnumPropertyManager *manager = q_ptr->propertyManager(property); + if (!manager) + return; + + QMap<int, QIcon> enumIcons = manager->enumIcons(property); + + QListIterator<QComboBox *> itEditor(m_createdEditors[property]); + while (itEditor.hasNext()) { + QComboBox *editor = itEditor.next(); + editor->blockSignals(true); + editor->clear(); + editor->addItems(enumNames); + const int nameCount = enumNames.count(); + for (int i = 0; i < nameCount; i++) + editor->setItemIcon(i, enumIcons.value(i)); + editor->setCurrentIndex(manager->value(property)); + editor->blockSignals(false); + } +} + +void QtEnumEditorFactoryPrivate::slotEnumIconsChanged(QtProperty *property, + const QMap<int, QIcon> &enumIcons) +{ + if (!m_createdEditors.contains(property)) + return; + + QtEnumPropertyManager *manager = q_ptr->propertyManager(property); + if (!manager) + return; + + const QStringList enumNames = manager->enumNames(property); + QListIterator<QComboBox *> itEditor(m_createdEditors[property]); + while (itEditor.hasNext()) { + QComboBox *editor = itEditor.next(); + editor->blockSignals(true); + const int nameCount = enumNames.count(); + for (int i = 0; i < nameCount; i++) + editor->setItemIcon(i, enumIcons.value(i)); + editor->setCurrentIndex(manager->value(property)); + editor->blockSignals(false); + } +} + +void QtEnumEditorFactoryPrivate::slotSetValue(int value) +{ + QObject *object = q_ptr->sender(); + const QMap<QComboBox *, QtProperty *>::ConstIterator ecend = m_editorToProperty.constEnd(); + for (QMap<QComboBox *, QtProperty *>::ConstIterator itEditor = m_editorToProperty.constBegin(); itEditor != ecend; ++itEditor) + if (itEditor.key() == object) { + QtProperty *property = itEditor.value(); + QtEnumPropertyManager *manager = q_ptr->propertyManager(property); + if (!manager) + return; + manager->setValue(property, value); + return; + } +} + +/*! + \class QtEnumEditorFactory + \internal + \inmodule QtDesigner + \since 4.4 + + \brief The QtEnumEditorFactory class provides QComboBox widgets for + properties created by QtEnumPropertyManager objects. + + \sa QtAbstractEditorFactory, QtEnumPropertyManager +*/ + +/*! + Creates a factory with the given \a parent. +*/ +QtEnumEditorFactory::QtEnumEditorFactory(QObject *parent) + : QtAbstractEditorFactory<QtEnumPropertyManager>(parent) +{ + d_ptr = new QtEnumEditorFactoryPrivate(); + d_ptr->q_ptr = this; + +} + +/*! + Destroys this factory, and all the widgets it has created. +*/ +QtEnumEditorFactory::~QtEnumEditorFactory() +{ + qDeleteAll(d_ptr->m_editorToProperty.keys()); + delete d_ptr; +} + +/*! + \internal + + Reimplemented from the QtAbstractEditorFactory class. +*/ +void QtEnumEditorFactory::connectPropertyManager(QtEnumPropertyManager *manager) +{ + connect(manager, SIGNAL(valueChanged(QtProperty *, int)), + this, SLOT(slotPropertyChanged(QtProperty *, int))); + connect(manager, SIGNAL(enumNamesChanged(QtProperty *, const QStringList &)), + this, SLOT(slotEnumNamesChanged(QtProperty *, const QStringList &))); +} + +/*! + \internal + + Reimplemented from the QtAbstractEditorFactory class. +*/ +QWidget *QtEnumEditorFactory::createEditor(QtEnumPropertyManager *manager, QtProperty *property, + QWidget *parent) +{ + QComboBox *editor = d_ptr->createEditor(property, parent); + editor->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Fixed); + editor->view()->setTextElideMode(Qt::ElideRight); + QStringList enumNames = manager->enumNames(property); + editor->addItems(enumNames); + QMap<int, QIcon> enumIcons = manager->enumIcons(property); + const int enumNamesCount = enumNames.count(); + for (int i = 0; i < enumNamesCount; i++) + editor->setItemIcon(i, enumIcons.value(i)); + editor->setCurrentIndex(manager->value(property)); + + connect(editor, SIGNAL(currentIndexChanged(int)), this, SLOT(slotSetValue(int))); + connect(editor, SIGNAL(destroyed(QObject *)), + this, SLOT(slotEditorDestroyed(QObject *))); + return editor; +} + +/*! + \internal + + Reimplemented from the QtAbstractEditorFactory class. +*/ +void QtEnumEditorFactory::disconnectPropertyManager(QtEnumPropertyManager *manager) +{ + disconnect(manager, SIGNAL(valueChanged(QtProperty *, int)), + this, SLOT(slotPropertyChanged(QtProperty *, int))); + disconnect(manager, SIGNAL(enumNamesChanged(QtProperty *, const QStringList &)), + this, SLOT(slotEnumNamesChanged(QtProperty *, const QStringList &))); +} + +// QtCursorEditorFactory + +Q_GLOBAL_STATIC(QtCursorDatabase, cursorDatabase) + +class QtCursorEditorFactoryPrivate +{ + QtCursorEditorFactory *q_ptr; + Q_DECLARE_PUBLIC(QtCursorEditorFactory) +public: + QtCursorEditorFactoryPrivate(); + + void slotPropertyChanged(QtProperty *property, const QCursor &cursor); + void slotEnumChanged(QtProperty *property, int value); + void slotEditorDestroyed(QObject *object); + + QtEnumEditorFactory *m_enumEditorFactory; + QtEnumPropertyManager *m_enumPropertyManager; + + QMap<QtProperty *, QtProperty *> m_propertyToEnum; + QMap<QtProperty *, QtProperty *> m_enumToProperty; + QMap<QtProperty *, QList<QWidget *> > m_enumToEditors; + QMap<QWidget *, QtProperty *> m_editorToEnum; + bool m_updatingEnum; +}; + +QtCursorEditorFactoryPrivate::QtCursorEditorFactoryPrivate() + : m_updatingEnum(false) +{ + +} + +void QtCursorEditorFactoryPrivate::slotPropertyChanged(QtProperty *property, const QCursor &cursor) +{ + // update enum property + QtProperty *enumProp = m_propertyToEnum.value(property); + if (!enumProp) + return; + + m_updatingEnum = true; + m_enumPropertyManager->setValue(enumProp, cursorDatabase()->cursorToValue(cursor)); + m_updatingEnum = false; +} + +void QtCursorEditorFactoryPrivate::slotEnumChanged(QtProperty *property, int value) +{ + if (m_updatingEnum) + return; + // update cursor property + QtProperty *prop = m_enumToProperty.value(property); + if (!prop) + return; + QtCursorPropertyManager *cursorManager = q_ptr->propertyManager(prop); + if (!cursorManager) + return; +#ifndef QT_NO_CURSOR + cursorManager->setValue(prop, QCursor(cursorDatabase()->valueToCursor(value))); +#endif +} + +void QtCursorEditorFactoryPrivate::slotEditorDestroyed(QObject *object) +{ + // remove from m_editorToEnum map; + // remove from m_enumToEditors map; + // if m_enumToEditors doesn't contains more editors delete enum property; + const QMap<QWidget *, QtProperty *>::ConstIterator ecend = m_editorToEnum.constEnd(); + for (QMap<QWidget *, QtProperty *>::ConstIterator itEditor = m_editorToEnum.constBegin(); itEditor != ecend; ++itEditor) + if (itEditor.key() == object) { + QWidget *editor = itEditor.key(); + QtProperty *enumProp = itEditor.value(); + m_editorToEnum.remove(editor); + m_enumToEditors[enumProp].removeAll(editor); + if (m_enumToEditors[enumProp].isEmpty()) { + m_enumToEditors.remove(enumProp); + QtProperty *property = m_enumToProperty.value(enumProp); + m_enumToProperty.remove(enumProp); + m_propertyToEnum.remove(property); + delete enumProp; + } + return; + } +} + +/*! + \class QtCursorEditorFactory + \internal + \inmodule QtDesigner + \since 4.4 + + \brief The QtCursorEditorFactory class provides QComboBox widgets for + properties created by QtCursorPropertyManager objects. + + \sa QtAbstractEditorFactory, QtCursorPropertyManager +*/ + +/*! + Creates a factory with the given \a parent. +*/ +QtCursorEditorFactory::QtCursorEditorFactory(QObject *parent) + : QtAbstractEditorFactory<QtCursorPropertyManager>(parent) +{ + d_ptr = new QtCursorEditorFactoryPrivate(); + d_ptr->q_ptr = this; + + d_ptr->m_enumEditorFactory = new QtEnumEditorFactory(this); + d_ptr->m_enumPropertyManager = new QtEnumPropertyManager(this); + connect(d_ptr->m_enumPropertyManager, SIGNAL(valueChanged(QtProperty *, int)), + this, SLOT(slotEnumChanged(QtProperty *, int))); + d_ptr->m_enumEditorFactory->addPropertyManager(d_ptr->m_enumPropertyManager); +} + +/*! + Destroys this factory, and all the widgets it has created. +*/ +QtCursorEditorFactory::~QtCursorEditorFactory() +{ + delete d_ptr; +} + +/*! + \internal + + Reimplemented from the QtAbstractEditorFactory class. +*/ +void QtCursorEditorFactory::connectPropertyManager(QtCursorPropertyManager *manager) +{ + connect(manager, SIGNAL(valueChanged(QtProperty *, const QCursor &)), + this, SLOT(slotPropertyChanged(QtProperty *, const QCursor &))); +} + +/*! + \internal + + Reimplemented from the QtAbstractEditorFactory class. +*/ +QWidget *QtCursorEditorFactory::createEditor(QtCursorPropertyManager *manager, QtProperty *property, + QWidget *parent) +{ + QtProperty *enumProp = 0; + if (d_ptr->m_propertyToEnum.contains(property)) { + enumProp = d_ptr->m_propertyToEnum[property]; + } else { + enumProp = d_ptr->m_enumPropertyManager->addProperty(property->propertyName()); + d_ptr->m_enumPropertyManager->setEnumNames(enumProp, cursorDatabase()->cursorShapeNames()); + d_ptr->m_enumPropertyManager->setEnumIcons(enumProp, cursorDatabase()->cursorShapeIcons()); +#ifndef QT_NO_CURSOR + d_ptr->m_enumPropertyManager->setValue(enumProp, cursorDatabase()->cursorToValue(manager->value(property))); +#endif + d_ptr->m_propertyToEnum[property] = enumProp; + d_ptr->m_enumToProperty[enumProp] = property; + } + QtAbstractEditorFactoryBase *af = d_ptr->m_enumEditorFactory; + QWidget *editor = af->createEditor(enumProp, parent); + d_ptr->m_enumToEditors[enumProp].append(editor); + d_ptr->m_editorToEnum[editor] = enumProp; + connect(editor, SIGNAL(destroyed(QObject *)), + this, SLOT(slotEditorDestroyed(QObject *))); + return editor; +} + +/*! + \internal + + Reimplemented from the QtAbstractEditorFactory class. +*/ +void QtCursorEditorFactory::disconnectPropertyManager(QtCursorPropertyManager *manager) +{ + disconnect(manager, SIGNAL(valueChanged(QtProperty *, const QCursor &)), + this, SLOT(slotPropertyChanged(QtProperty *, const QCursor &))); +} + +// QtColorEditWidget + +class QtColorEditWidget : public QWidget { + Q_OBJECT + +public: + QtColorEditWidget(QWidget *parent); + + bool eventFilter(QObject *obj, QEvent *ev); + +public Q_SLOTS: + void setValue(const QColor &value); + +private Q_SLOTS: + void buttonClicked(); + +Q_SIGNALS: + void valueChanged(const QColor &value); + +private: + QColor m_color; + QLabel *m_pixmapLabel; + QLabel *m_label; + QToolButton *m_button; +}; + +QtColorEditWidget::QtColorEditWidget(QWidget *parent) : + QWidget(parent), + m_pixmapLabel(new QLabel), + m_label(new QLabel), + m_button(new QToolButton) +{ + QHBoxLayout *lt = new QHBoxLayout(this); + setupTreeViewEditorMargin(lt); + lt->setSpacing(0); + lt->addWidget(m_pixmapLabel); + lt->addWidget(m_label); + lt->addItem(new QSpacerItem(0, 0, QSizePolicy::Expanding, QSizePolicy::Ignored)); + + m_button->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Ignored); + m_button->setFixedWidth(20); + setFocusProxy(m_button); + setFocusPolicy(m_button->focusPolicy()); + m_button->setText(tr("...")); + m_button->installEventFilter(this); + connect(m_button, SIGNAL(clicked()), this, SLOT(buttonClicked())); + lt->addWidget(m_button); + m_pixmapLabel->setPixmap(QtPropertyBrowserUtils::brushValuePixmap(QBrush(m_color))); + m_label->setText(QtPropertyBrowserUtils::colorValueText(m_color)); +} + +void QtColorEditWidget::setValue(const QColor &c) +{ + if (m_color != c) { + m_color = c; + m_pixmapLabel->setPixmap(QtPropertyBrowserUtils::brushValuePixmap(QBrush(c))); + m_label->setText(QtPropertyBrowserUtils::colorValueText(c)); + } +} + +void QtColorEditWidget::buttonClicked() +{ + bool ok = false; + QRgb oldRgba = m_color.rgba(); + QRgb newRgba = QColorDialog::getRgba(oldRgba, &ok, this); + if (ok && newRgba != oldRgba) { + setValue(QColor::fromRgba(newRgba)); + emit valueChanged(m_color); + } +} + +bool QtColorEditWidget::eventFilter(QObject *obj, QEvent *ev) +{ + if (obj == m_button) { + switch (ev->type()) { + case QEvent::KeyPress: + case QEvent::KeyRelease: { // Prevent the QToolButton from handling Enter/Escape meant control the delegate + switch (static_cast<const QKeyEvent*>(ev)->key()) { + case Qt::Key_Escape: + case Qt::Key_Enter: + case Qt::Key_Return: + ev->ignore(); + return true; + default: + break; + } + } + break; + default: + break; + } + } + return QWidget::eventFilter(obj, ev); +} + +// QtColorEditorFactoryPrivate + +class QtColorEditorFactoryPrivate : public EditorFactoryPrivate<QtColorEditWidget> +{ + QtColorEditorFactory *q_ptr; + Q_DECLARE_PUBLIC(QtColorEditorFactory) +public: + + void slotPropertyChanged(QtProperty *property, const QColor &value); + void slotSetValue(const QColor &value); +}; + +void QtColorEditorFactoryPrivate::slotPropertyChanged(QtProperty *property, + const QColor &value) +{ + const PropertyToEditorListMap::iterator it = m_createdEditors.find(property); + if (it == m_createdEditors.end()) + return; + QListIterator<QtColorEditWidget *> itEditor(it.value()); + + while (itEditor.hasNext()) + itEditor.next()->setValue(value); +} + +void QtColorEditorFactoryPrivate::slotSetValue(const QColor &value) +{ + QObject *object = q_ptr->sender(); + const EditorToPropertyMap::ConstIterator ecend = m_editorToProperty.constEnd(); + for (EditorToPropertyMap::ConstIterator itEditor = m_editorToProperty.constBegin(); itEditor != ecend; ++itEditor) + if (itEditor.key() == object) { + QtProperty *property = itEditor.value(); + QtColorPropertyManager *manager = q_ptr->propertyManager(property); + if (!manager) + return; + manager->setValue(property, value); + return; + } +} + +/*! + \class QtColorEditorFactory + \internal + \inmodule QtDesigner + \since 4.4 + + \brief The QtColorEditorFactory class provides color editing for + properties created by QtColorPropertyManager objects. + + \sa QtAbstractEditorFactory, QtColorPropertyManager +*/ + +/*! + Creates a factory with the given \a parent. +*/ +QtColorEditorFactory::QtColorEditorFactory(QObject *parent) : + QtAbstractEditorFactory<QtColorPropertyManager>(parent), + d_ptr(new QtColorEditorFactoryPrivate()) +{ + d_ptr->q_ptr = this; +} + +/*! + Destroys this factory, and all the widgets it has created. +*/ +QtColorEditorFactory::~QtColorEditorFactory() +{ + qDeleteAll(d_ptr->m_editorToProperty.keys()); + delete d_ptr; +} + +/*! + \internal + + Reimplemented from the QtAbstractEditorFactory class. +*/ +void QtColorEditorFactory::connectPropertyManager(QtColorPropertyManager *manager) +{ + connect(manager, SIGNAL(valueChanged(QtProperty*,QColor)), + this, SLOT(slotPropertyChanged(QtProperty*,QColor))); +} + +/*! + \internal + + Reimplemented from the QtAbstractEditorFactory class. +*/ +QWidget *QtColorEditorFactory::createEditor(QtColorPropertyManager *manager, + QtProperty *property, QWidget *parent) +{ + QtColorEditWidget *editor = d_ptr->createEditor(property, parent); + editor->setValue(manager->value(property)); + connect(editor, SIGNAL(valueChanged(QColor)), this, SLOT(slotSetValue(QColor))); + connect(editor, SIGNAL(destroyed(QObject *)), this, SLOT(slotEditorDestroyed(QObject *))); + return editor; +} + +/*! + \internal + + Reimplemented from the QtAbstractEditorFactory class. +*/ +void QtColorEditorFactory::disconnectPropertyManager(QtColorPropertyManager *manager) +{ + disconnect(manager, SIGNAL(valueChanged(QtProperty*,QColor)), this, SLOT(slotPropertyChanged(QtProperty*,QColor))); +} + +// QtFontEditWidget + +class QtFontEditWidget : public QWidget { + Q_OBJECT + +public: + QtFontEditWidget(QWidget *parent); + + bool eventFilter(QObject *obj, QEvent *ev); + +public Q_SLOTS: + void setValue(const QFont &value); + +private Q_SLOTS: + void buttonClicked(); + +Q_SIGNALS: + void valueChanged(const QFont &value); + +private: + QFont m_font; + QLabel *m_pixmapLabel; + QLabel *m_label; + QToolButton *m_button; +}; + +QtFontEditWidget::QtFontEditWidget(QWidget *parent) : + QWidget(parent), + m_pixmapLabel(new QLabel), + m_label(new QLabel), + m_button(new QToolButton) +{ + QHBoxLayout *lt = new QHBoxLayout(this); + setupTreeViewEditorMargin(lt); + lt->setSpacing(0); + lt->addWidget(m_pixmapLabel); + lt->addWidget(m_label); + lt->addItem(new QSpacerItem(0, 0, QSizePolicy::Expanding, QSizePolicy::Ignored)); + + m_button->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Ignored); + m_button->setFixedWidth(20); + setFocusProxy(m_button); + setFocusPolicy(m_button->focusPolicy()); + m_button->setText(tr("...")); + m_button->installEventFilter(this); + connect(m_button, SIGNAL(clicked()), this, SLOT(buttonClicked())); + lt->addWidget(m_button); + m_pixmapLabel->setPixmap(QtPropertyBrowserUtils::fontValuePixmap(m_font)); + m_label->setText(QtPropertyBrowserUtils::fontValueText(m_font)); +} + +void QtFontEditWidget::setValue(const QFont &f) +{ + if (m_font != f) { + m_font = f; + m_pixmapLabel->setPixmap(QtPropertyBrowserUtils::fontValuePixmap(f)); + m_label->setText(QtPropertyBrowserUtils::fontValueText(f)); + } +} + +void QtFontEditWidget::buttonClicked() +{ + bool ok = false; + QFont newFont = QFontDialog::getFont(&ok, m_font, this, tr("Select Font")); + if (ok && newFont != m_font) { + QFont f = m_font; + // prevent mask for unchanged attributes, don't change other attributes (like kerning, etc...) + if (m_font.family() != newFont.family()) + f.setFamily(newFont.family()); + if (m_font.pointSize() != newFont.pointSize()) + f.setPointSize(newFont.pointSize()); + if (m_font.bold() != newFont.bold()) + f.setBold(newFont.bold()); + if (m_font.italic() != newFont.italic()) + f.setItalic(newFont.italic()); + if (m_font.underline() != newFont.underline()) + f.setUnderline(newFont.underline()); + if (m_font.strikeOut() != newFont.strikeOut()) + f.setStrikeOut(newFont.strikeOut()); + setValue(f); + emit valueChanged(m_font); + } +} + +bool QtFontEditWidget::eventFilter(QObject *obj, QEvent *ev) +{ + if (obj == m_button) { + switch (ev->type()) { + case QEvent::KeyPress: + case QEvent::KeyRelease: { // Prevent the QToolButton from handling Enter/Escape meant control the delegate + switch (static_cast<const QKeyEvent*>(ev)->key()) { + case Qt::Key_Escape: + case Qt::Key_Enter: + case Qt::Key_Return: + ev->ignore(); + return true; + default: + break; + } + } + break; + default: + break; + } + } + return QWidget::eventFilter(obj, ev); +} + +// QtFontEditorFactoryPrivate + +class QtFontEditorFactoryPrivate : public EditorFactoryPrivate<QtFontEditWidget> +{ + QtFontEditorFactory *q_ptr; + Q_DECLARE_PUBLIC(QtFontEditorFactory) +public: + + void slotPropertyChanged(QtProperty *property, const QFont &value); + void slotSetValue(const QFont &value); +}; + +void QtFontEditorFactoryPrivate::slotPropertyChanged(QtProperty *property, + const QFont &value) +{ + const PropertyToEditorListMap::iterator it = m_createdEditors.find(property); + if (it == m_createdEditors.end()) + return; + QListIterator<QtFontEditWidget *> itEditor(it.value()); + + while (itEditor.hasNext()) + itEditor.next()->setValue(value); +} + +void QtFontEditorFactoryPrivate::slotSetValue(const QFont &value) +{ + QObject *object = q_ptr->sender(); + const EditorToPropertyMap::ConstIterator ecend = m_editorToProperty.constEnd(); + for (EditorToPropertyMap::ConstIterator itEditor = m_editorToProperty.constBegin(); itEditor != ecend; ++itEditor) + if (itEditor.key() == object) { + QtProperty *property = itEditor.value(); + QtFontPropertyManager *manager = q_ptr->propertyManager(property); + if (!manager) + return; + manager->setValue(property, value); + return; + } +} + +/*! + \class QtFontEditorFactory + \internal + \inmodule QtDesigner + \since 4.4 + + \brief The QtFontEditorFactory class provides font editing for + properties created by QtFontPropertyManager objects. + + \sa QtAbstractEditorFactory, QtFontPropertyManager +*/ + +/*! + Creates a factory with the given \a parent. +*/ +QtFontEditorFactory::QtFontEditorFactory(QObject *parent) : + QtAbstractEditorFactory<QtFontPropertyManager>(parent), + d_ptr(new QtFontEditorFactoryPrivate()) +{ + d_ptr->q_ptr = this; +} + +/*! + Destroys this factory, and all the widgets it has created. +*/ +QtFontEditorFactory::~QtFontEditorFactory() +{ + qDeleteAll(d_ptr->m_editorToProperty.keys()); + delete d_ptr; +} + +/*! + \internal + + Reimplemented from the QtAbstractEditorFactory class. +*/ +void QtFontEditorFactory::connectPropertyManager(QtFontPropertyManager *manager) +{ + connect(manager, SIGNAL(valueChanged(QtProperty*,QFont)), + this, SLOT(slotPropertyChanged(QtProperty*,QFont))); +} + +/*! + \internal + + Reimplemented from the QtAbstractEditorFactory class. +*/ +QWidget *QtFontEditorFactory::createEditor(QtFontPropertyManager *manager, + QtProperty *property, QWidget *parent) +{ + QtFontEditWidget *editor = d_ptr->createEditor(property, parent); + editor->setValue(manager->value(property)); + connect(editor, SIGNAL(valueChanged(QFont)), this, SLOT(slotSetValue(QFont))); + connect(editor, SIGNAL(destroyed(QObject *)), this, SLOT(slotEditorDestroyed(QObject *))); + return editor; +} + +/*! + \internal + + Reimplemented from the QtAbstractEditorFactory class. +*/ +void QtFontEditorFactory::disconnectPropertyManager(QtFontPropertyManager *manager) +{ + disconnect(manager, SIGNAL(valueChanged(QtProperty*,QFont)), this, SLOT(slotPropertyChanged(QtProperty*,QFont))); +} + +#if QT_VERSION >= 0x040400 +QT_END_NAMESPACE +#endif + +#include "moc_qteditorfactory.cpp" +#include "qteditorfactory.moc" diff --git a/tools/shared/qtpropertybrowser/qteditorfactory.h b/tools/shared/qtpropertybrowser/qteditorfactory.h new file mode 100644 index 0000000..044dd5e --- /dev/null +++ b/tools/shared/qtpropertybrowser/qteditorfactory.h @@ -0,0 +1,401 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the tools applications of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QTEDITORFACTORY_H +#define QTEDITORFACTORY_H + +#include "qtpropertymanager.h" + +#if QT_VERSION >= 0x040400 +QT_BEGIN_NAMESPACE +#endif + +class QtSpinBoxFactoryPrivate; + +class QtSpinBoxFactory : public QtAbstractEditorFactory<QtIntPropertyManager> +{ + Q_OBJECT +public: + QtSpinBoxFactory(QObject *parent = 0); + ~QtSpinBoxFactory(); +protected: + void connectPropertyManager(QtIntPropertyManager *manager); + QWidget *createEditor(QtIntPropertyManager *manager, QtProperty *property, + QWidget *parent); + void disconnectPropertyManager(QtIntPropertyManager *manager); +private: + QtSpinBoxFactoryPrivate *d_ptr; + Q_DECLARE_PRIVATE(QtSpinBoxFactory) + Q_DISABLE_COPY(QtSpinBoxFactory) + Q_PRIVATE_SLOT(d_func(), void slotPropertyChanged(QtProperty *, int)) + Q_PRIVATE_SLOT(d_func(), void slotRangeChanged(QtProperty *, int, int)) + Q_PRIVATE_SLOT(d_func(), void slotSingleStepChanged(QtProperty *, int)) + Q_PRIVATE_SLOT(d_func(), void slotSetValue(int)) + Q_PRIVATE_SLOT(d_func(), void slotEditorDestroyed(QObject *)) +}; + +class QtSliderFactoryPrivate; + +class QtSliderFactory : public QtAbstractEditorFactory<QtIntPropertyManager> +{ + Q_OBJECT +public: + QtSliderFactory(QObject *parent = 0); + ~QtSliderFactory(); +protected: + void connectPropertyManager(QtIntPropertyManager *manager); + QWidget *createEditor(QtIntPropertyManager *manager, QtProperty *property, + QWidget *parent); + void disconnectPropertyManager(QtIntPropertyManager *manager); +private: + QtSliderFactoryPrivate *d_ptr; + Q_DECLARE_PRIVATE(QtSliderFactory) + Q_DISABLE_COPY(QtSliderFactory) + Q_PRIVATE_SLOT(d_func(), void slotPropertyChanged(QtProperty *, int)) + Q_PRIVATE_SLOT(d_func(), void slotRangeChanged(QtProperty *, int, int)) + Q_PRIVATE_SLOT(d_func(), void slotSingleStepChanged(QtProperty *, int)) + Q_PRIVATE_SLOT(d_func(), void slotSetValue(int)) + Q_PRIVATE_SLOT(d_func(), void slotEditorDestroyed(QObject *)) +}; + +class QtScrollBarFactoryPrivate; + +class QtScrollBarFactory : public QtAbstractEditorFactory<QtIntPropertyManager> +{ + Q_OBJECT +public: + QtScrollBarFactory(QObject *parent = 0); + ~QtScrollBarFactory(); +protected: + void connectPropertyManager(QtIntPropertyManager *manager); + QWidget *createEditor(QtIntPropertyManager *manager, QtProperty *property, + QWidget *parent); + void disconnectPropertyManager(QtIntPropertyManager *manager); +private: + QtScrollBarFactoryPrivate *d_ptr; + Q_DECLARE_PRIVATE(QtScrollBarFactory) + Q_DISABLE_COPY(QtScrollBarFactory) + Q_PRIVATE_SLOT(d_func(), void slotPropertyChanged(QtProperty *, int)) + Q_PRIVATE_SLOT(d_func(), void slotRangeChanged(QtProperty *, int, int)) + Q_PRIVATE_SLOT(d_func(), void slotSingleStepChanged(QtProperty *, int)) + Q_PRIVATE_SLOT(d_func(), void slotSetValue(int)) + Q_PRIVATE_SLOT(d_func(), void slotEditorDestroyed(QObject *)) +}; + +class QtCheckBoxFactoryPrivate; + +class QtCheckBoxFactory : public QtAbstractEditorFactory<QtBoolPropertyManager> +{ + Q_OBJECT +public: + QtCheckBoxFactory(QObject *parent = 0); + ~QtCheckBoxFactory(); +protected: + void connectPropertyManager(QtBoolPropertyManager *manager); + QWidget *createEditor(QtBoolPropertyManager *manager, QtProperty *property, + QWidget *parent); + void disconnectPropertyManager(QtBoolPropertyManager *manager); +private: + QtCheckBoxFactoryPrivate *d_ptr; + Q_DECLARE_PRIVATE(QtCheckBoxFactory) + Q_DISABLE_COPY(QtCheckBoxFactory) + Q_PRIVATE_SLOT(d_func(), void slotPropertyChanged(QtProperty *, bool)) + Q_PRIVATE_SLOT(d_func(), void slotSetValue(bool)) + Q_PRIVATE_SLOT(d_func(), void slotEditorDestroyed(QObject *)) +}; + +class QtDoubleSpinBoxFactoryPrivate; + +class QtDoubleSpinBoxFactory : public QtAbstractEditorFactory<QtDoublePropertyManager> +{ + Q_OBJECT +public: + QtDoubleSpinBoxFactory(QObject *parent = 0); + ~QtDoubleSpinBoxFactory(); +protected: + void connectPropertyManager(QtDoublePropertyManager *manager); + QWidget *createEditor(QtDoublePropertyManager *manager, QtProperty *property, + QWidget *parent); + void disconnectPropertyManager(QtDoublePropertyManager *manager); +private: + QtDoubleSpinBoxFactoryPrivate *d_ptr; + Q_DECLARE_PRIVATE(QtDoubleSpinBoxFactory) + Q_DISABLE_COPY(QtDoubleSpinBoxFactory) + Q_PRIVATE_SLOT(d_func(), void slotPropertyChanged(QtProperty *, double)) + Q_PRIVATE_SLOT(d_func(), void slotRangeChanged(QtProperty *, double, double)) + Q_PRIVATE_SLOT(d_func(), void slotSingleStepChanged(QtProperty *, double)) + Q_PRIVATE_SLOT(d_func(), void slotDecimalsChanged(QtProperty *, int)) + Q_PRIVATE_SLOT(d_func(), void slotSetValue(double)) + Q_PRIVATE_SLOT(d_func(), void slotEditorDestroyed(QObject *)) +}; + +class QtLineEditFactoryPrivate; + +class QtLineEditFactory : public QtAbstractEditorFactory<QtStringPropertyManager> +{ + Q_OBJECT +public: + QtLineEditFactory(QObject *parent = 0); + ~QtLineEditFactory(); +protected: + void connectPropertyManager(QtStringPropertyManager *manager); + QWidget *createEditor(QtStringPropertyManager *manager, QtProperty *property, + QWidget *parent); + void disconnectPropertyManager(QtStringPropertyManager *manager); +private: + QtLineEditFactoryPrivate *d_ptr; + Q_DECLARE_PRIVATE(QtLineEditFactory) + Q_DISABLE_COPY(QtLineEditFactory) + Q_PRIVATE_SLOT(d_func(), void slotPropertyChanged(QtProperty *, const QString &)) + Q_PRIVATE_SLOT(d_func(), void slotRegExpChanged(QtProperty *, const QRegExp &)) + Q_PRIVATE_SLOT(d_func(), void slotSetValue(const QString &)) + Q_PRIVATE_SLOT(d_func(), void slotEditorDestroyed(QObject *)) +}; + +class QtDateEditFactoryPrivate; + +class QtDateEditFactory : public QtAbstractEditorFactory<QtDatePropertyManager> +{ + Q_OBJECT +public: + QtDateEditFactory(QObject *parent = 0); + ~QtDateEditFactory(); +protected: + void connectPropertyManager(QtDatePropertyManager *manager); + QWidget *createEditor(QtDatePropertyManager *manager, QtProperty *property, + QWidget *parent); + void disconnectPropertyManager(QtDatePropertyManager *manager); +private: + QtDateEditFactoryPrivate *d_ptr; + Q_DECLARE_PRIVATE(QtDateEditFactory) + Q_DISABLE_COPY(QtDateEditFactory) + Q_PRIVATE_SLOT(d_func(), void slotPropertyChanged(QtProperty *, const QDate &)) + Q_PRIVATE_SLOT(d_func(), void slotRangeChanged(QtProperty *, + const QDate &, const QDate &)) + Q_PRIVATE_SLOT(d_func(), void slotSetValue(const QDate &)) + Q_PRIVATE_SLOT(d_func(), void slotEditorDestroyed(QObject *)) +}; + +class QtTimeEditFactoryPrivate; + +class QtTimeEditFactory : public QtAbstractEditorFactory<QtTimePropertyManager> +{ + Q_OBJECT +public: + QtTimeEditFactory(QObject *parent = 0); + ~QtTimeEditFactory(); +protected: + void connectPropertyManager(QtTimePropertyManager *manager); + QWidget *createEditor(QtTimePropertyManager *manager, QtProperty *property, + QWidget *parent); + void disconnectPropertyManager(QtTimePropertyManager *manager); +private: + QtTimeEditFactoryPrivate *d_ptr; + Q_DECLARE_PRIVATE(QtTimeEditFactory) + Q_DISABLE_COPY(QtTimeEditFactory) + Q_PRIVATE_SLOT(d_func(), void slotPropertyChanged(QtProperty *, const QTime &)) + Q_PRIVATE_SLOT(d_func(), void slotSetValue(const QTime &)) + Q_PRIVATE_SLOT(d_func(), void slotEditorDestroyed(QObject *)) +}; + +class QtDateTimeEditFactoryPrivate; + +class QtDateTimeEditFactory : public QtAbstractEditorFactory<QtDateTimePropertyManager> +{ + Q_OBJECT +public: + QtDateTimeEditFactory(QObject *parent = 0); + ~QtDateTimeEditFactory(); +protected: + void connectPropertyManager(QtDateTimePropertyManager *manager); + QWidget *createEditor(QtDateTimePropertyManager *manager, QtProperty *property, + QWidget *parent); + void disconnectPropertyManager(QtDateTimePropertyManager *manager); +private: + QtDateTimeEditFactoryPrivate *d_ptr; + Q_DECLARE_PRIVATE(QtDateTimeEditFactory) + Q_DISABLE_COPY(QtDateTimeEditFactory) + Q_PRIVATE_SLOT(d_func(), void slotPropertyChanged(QtProperty *, const QDateTime &)) + Q_PRIVATE_SLOT(d_func(), void slotSetValue(const QDateTime &)) + Q_PRIVATE_SLOT(d_func(), void slotEditorDestroyed(QObject *)) +}; + +class QtKeySequenceEditorFactoryPrivate; + +class QtKeySequenceEditorFactory : public QtAbstractEditorFactory<QtKeySequencePropertyManager> +{ + Q_OBJECT +public: + QtKeySequenceEditorFactory(QObject *parent = 0); + ~QtKeySequenceEditorFactory(); +protected: + void connectPropertyManager(QtKeySequencePropertyManager *manager); + QWidget *createEditor(QtKeySequencePropertyManager *manager, QtProperty *property, + QWidget *parent); + void disconnectPropertyManager(QtKeySequencePropertyManager *manager); +private: + QtKeySequenceEditorFactoryPrivate *d_ptr; + Q_DECLARE_PRIVATE(QtKeySequenceEditorFactory) + Q_DISABLE_COPY(QtKeySequenceEditorFactory) + Q_PRIVATE_SLOT(d_func(), void slotPropertyChanged(QtProperty *, const QKeySequence &)) + Q_PRIVATE_SLOT(d_func(), void slotSetValue(const QKeySequence &)) + Q_PRIVATE_SLOT(d_func(), void slotEditorDestroyed(QObject *)) +}; + +class QtCharEditorFactoryPrivate; + +class QtCharEditorFactory : public QtAbstractEditorFactory<QtCharPropertyManager> +{ + Q_OBJECT +public: + QtCharEditorFactory(QObject *parent = 0); + ~QtCharEditorFactory(); +protected: + void connectPropertyManager(QtCharPropertyManager *manager); + QWidget *createEditor(QtCharPropertyManager *manager, QtProperty *property, + QWidget *parent); + void disconnectPropertyManager(QtCharPropertyManager *manager); +private: + QtCharEditorFactoryPrivate *d_ptr; + Q_DECLARE_PRIVATE(QtCharEditorFactory) + Q_DISABLE_COPY(QtCharEditorFactory) + Q_PRIVATE_SLOT(d_func(), void slotPropertyChanged(QtProperty *, const QChar &)) + Q_PRIVATE_SLOT(d_func(), void slotSetValue(const QChar &)) + Q_PRIVATE_SLOT(d_func(), void slotEditorDestroyed(QObject *)) +}; + +class QtEnumEditorFactoryPrivate; + +class QtEnumEditorFactory : public QtAbstractEditorFactory<QtEnumPropertyManager> +{ + Q_OBJECT +public: + QtEnumEditorFactory(QObject *parent = 0); + ~QtEnumEditorFactory(); +protected: + void connectPropertyManager(QtEnumPropertyManager *manager); + QWidget *createEditor(QtEnumPropertyManager *manager, QtProperty *property, + QWidget *parent); + void disconnectPropertyManager(QtEnumPropertyManager *manager); +private: + QtEnumEditorFactoryPrivate *d_ptr; + Q_DECLARE_PRIVATE(QtEnumEditorFactory) + Q_DISABLE_COPY(QtEnumEditorFactory) + Q_PRIVATE_SLOT(d_func(), void slotPropertyChanged(QtProperty *, int)) + Q_PRIVATE_SLOT(d_func(), void slotEnumNamesChanged(QtProperty *, + const QStringList &)) + Q_PRIVATE_SLOT(d_func(), void slotEnumIconsChanged(QtProperty *, + const QMap<int, QIcon> &)) + Q_PRIVATE_SLOT(d_func(), void slotSetValue(int)) + Q_PRIVATE_SLOT(d_func(), void slotEditorDestroyed(QObject *)) +}; + +class QtCursorEditorFactoryPrivate; + +class QtCursorEditorFactory : public QtAbstractEditorFactory<QtCursorPropertyManager> +{ + Q_OBJECT +public: + QtCursorEditorFactory(QObject *parent = 0); + ~QtCursorEditorFactory(); +protected: + void connectPropertyManager(QtCursorPropertyManager *manager); + QWidget *createEditor(QtCursorPropertyManager *manager, QtProperty *property, + QWidget *parent); + void disconnectPropertyManager(QtCursorPropertyManager *manager); +private: + QtCursorEditorFactoryPrivate *d_ptr; + Q_DECLARE_PRIVATE(QtCursorEditorFactory) + Q_DISABLE_COPY(QtCursorEditorFactory) + Q_PRIVATE_SLOT(d_func(), void slotPropertyChanged(QtProperty *, const QCursor &)) + Q_PRIVATE_SLOT(d_func(), void slotEnumChanged(QtProperty *, int)) + Q_PRIVATE_SLOT(d_func(), void slotEditorDestroyed(QObject *)) +}; + +class QtColorEditorFactoryPrivate; + +class QtColorEditorFactory : public QtAbstractEditorFactory<QtColorPropertyManager> +{ + Q_OBJECT +public: + QtColorEditorFactory(QObject *parent = 0); + ~QtColorEditorFactory(); +protected: + void connectPropertyManager(QtColorPropertyManager *manager); + QWidget *createEditor(QtColorPropertyManager *manager, QtProperty *property, + QWidget *parent); + void disconnectPropertyManager(QtColorPropertyManager *manager); +private: + QtColorEditorFactoryPrivate *d_ptr; + Q_DECLARE_PRIVATE(QtColorEditorFactory) + Q_DISABLE_COPY(QtColorEditorFactory) + Q_PRIVATE_SLOT(d_func(), void slotPropertyChanged(QtProperty *, const QColor &)) + Q_PRIVATE_SLOT(d_func(), void slotEditorDestroyed(QObject *)) + Q_PRIVATE_SLOT(d_func(), void slotSetValue(const QColor &)) +}; + +class QtFontEditorFactoryPrivate; + +class QtFontEditorFactory : public QtAbstractEditorFactory<QtFontPropertyManager> +{ + Q_OBJECT +public: + QtFontEditorFactory(QObject *parent = 0); + ~QtFontEditorFactory(); +protected: + void connectPropertyManager(QtFontPropertyManager *manager); + QWidget *createEditor(QtFontPropertyManager *manager, QtProperty *property, + QWidget *parent); + void disconnectPropertyManager(QtFontPropertyManager *manager); +private: + QtFontEditorFactoryPrivate *d_ptr; + Q_DECLARE_PRIVATE(QtFontEditorFactory) + Q_DISABLE_COPY(QtFontEditorFactory) + Q_PRIVATE_SLOT(d_func(), void slotPropertyChanged(QtProperty *, const QFont &)) + Q_PRIVATE_SLOT(d_func(), void slotEditorDestroyed(QObject *)) + Q_PRIVATE_SLOT(d_func(), void slotSetValue(const QFont &)) +}; + +#if QT_VERSION >= 0x040400 +QT_END_NAMESPACE +#endif + +#endif diff --git a/tools/shared/qtpropertybrowser/qtgroupboxpropertybrowser.cpp b/tools/shared/qtpropertybrowser/qtgroupboxpropertybrowser.cpp new file mode 100644 index 0000000..d7c8f0b --- /dev/null +++ b/tools/shared/qtpropertybrowser/qtgroupboxpropertybrowser.cpp @@ -0,0 +1,535 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the tools applications of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qtgroupboxpropertybrowser.h" +#include <QtCore/QSet> +#include <QtGui/QGridLayout> +#include <QtGui/QLabel> +#include <QtGui/QGroupBox> +#include <QtCore/QTimer> +#include <QtCore/QMap> + +#if QT_VERSION >= 0x040400 +QT_BEGIN_NAMESPACE +#endif + +class QtGroupBoxPropertyBrowserPrivate +{ + QtGroupBoxPropertyBrowser *q_ptr; + Q_DECLARE_PUBLIC(QtGroupBoxPropertyBrowser) +public: + + void init(QWidget *parent); + + void propertyInserted(QtBrowserItem *index, QtBrowserItem *afterIndex); + void propertyRemoved(QtBrowserItem *index); + void propertyChanged(QtBrowserItem *index); + QWidget *createEditor(QtProperty *property, QWidget *parent) const + { return q_ptr->createEditor(property, parent); } + + void slotEditorDestroyed(); + void slotUpdate(); + + struct WidgetItem + { + WidgetItem() : widget(0), label(0), widgetLabel(0), + groupBox(0), layout(0), line(0), parent(0) { } + QWidget *widget; // can be null + QLabel *label; + QLabel *widgetLabel; + QGroupBox *groupBox; + QGridLayout *layout; + QFrame *line; + WidgetItem *parent; + QList<WidgetItem *> children; + }; +private: + void updateLater(); + void updateItem(WidgetItem *item); + void insertRow(QGridLayout *layout, int row) const; + void removeRow(QGridLayout *layout, int row) const; + + bool hasHeader(WidgetItem *item) const; + + QMap<QtBrowserItem *, WidgetItem *> m_indexToItem; + QMap<WidgetItem *, QtBrowserItem *> m_itemToIndex; + QMap<QWidget *, WidgetItem *> m_widgetToItem; + QGridLayout *m_mainLayout; + QList<WidgetItem *> m_children; + QList<WidgetItem *> m_recreateQueue; +}; + +void QtGroupBoxPropertyBrowserPrivate::init(QWidget *parent) +{ + m_mainLayout = new QGridLayout(); + parent->setLayout(m_mainLayout); + QLayoutItem *item = new QSpacerItem(0, 0, + QSizePolicy::Fixed, QSizePolicy::Expanding); + m_mainLayout->addItem(item, 0, 0); +} + +void QtGroupBoxPropertyBrowserPrivate::slotEditorDestroyed() +{ + QWidget *editor = qobject_cast<QWidget *>(q_ptr->sender()); + if (!editor) + return; + if (!m_widgetToItem.contains(editor)) + return; + m_widgetToItem[editor]->widget = 0; + m_widgetToItem.remove(editor); +} + +void QtGroupBoxPropertyBrowserPrivate::slotUpdate() +{ + QListIterator<WidgetItem *> itItem(m_recreateQueue); + while (itItem.hasNext()) { + WidgetItem *item = itItem.next(); + + WidgetItem *par = item->parent; + QWidget *w = 0; + QGridLayout *l = 0; + int oldRow = -1; + if (!par) { + w = q_ptr; + l = m_mainLayout; + oldRow = m_children.indexOf(item); + } else { + w = par->groupBox; + l = par->layout; + oldRow = par->children.indexOf(item); + if (hasHeader(par)) + oldRow += 2; + } + + if (item->widget) { + item->widget->setParent(w); + } else if (item->widgetLabel) { + item->widgetLabel->setParent(w); + } else { + item->widgetLabel = new QLabel(w); + } + int span = 1; + if (item->widget) + l->addWidget(item->widget, oldRow, 1, 1, 1); + else if (item->widgetLabel) + l->addWidget(item->widgetLabel, oldRow, 1, 1, 1); + else + span = 2; + item->label = new QLabel(w); + item->label->setSizePolicy(QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed)); + l->addWidget(item->label, oldRow, 0, 1, span); + + updateItem(item); + } + m_recreateQueue.clear(); +} + +void QtGroupBoxPropertyBrowserPrivate::updateLater() +{ + QTimer::singleShot(0, q_ptr, SLOT(slotUpdate())); +} + +void QtGroupBoxPropertyBrowserPrivate::propertyInserted(QtBrowserItem *index, QtBrowserItem *afterIndex) +{ + WidgetItem *afterItem = m_indexToItem.value(afterIndex); + WidgetItem *parentItem = m_indexToItem.value(index->parent()); + + WidgetItem *newItem = new WidgetItem(); + newItem->parent = parentItem; + + QGridLayout *layout = 0; + QWidget *parentWidget = 0; + int row = -1; + if (!afterItem) { + row = 0; + if (parentItem) + parentItem->children.insert(0, newItem); + else + m_children.insert(0, newItem); + } else { + if (parentItem) { + row = parentItem->children.indexOf(afterItem) + 1; + parentItem->children.insert(row, newItem); + } else { + row = m_children.indexOf(afterItem) + 1; + m_children.insert(row, newItem); + } + } + if (parentItem && hasHeader(parentItem)) + row += 2; + + if (!parentItem) { + layout = m_mainLayout; + parentWidget = q_ptr;; + } else { + if (!parentItem->groupBox) { + m_recreateQueue.removeAll(parentItem); + WidgetItem *par = parentItem->parent; + QWidget *w = 0; + QGridLayout *l = 0; + int oldRow = -1; + if (!par) { + w = q_ptr; + l = m_mainLayout; + oldRow = m_children.indexOf(parentItem); + } else { + w = par->groupBox; + l = par->layout; + oldRow = par->children.indexOf(parentItem); + if (hasHeader(par)) + oldRow += 2; + } + parentItem->groupBox = new QGroupBox(w); + parentItem->layout = new QGridLayout(); + parentItem->groupBox->setLayout(parentItem->layout); + if (parentItem->label) { + l->removeWidget(parentItem->label); + delete parentItem->label; + parentItem->label = 0; + } + if (parentItem->widget) { + l->removeWidget(parentItem->widget); + parentItem->widget->setParent(parentItem->groupBox); + parentItem->layout->addWidget(parentItem->widget, 0, 0, 1, 2); + parentItem->line = new QFrame(parentItem->groupBox); + } else if (parentItem->widgetLabel) { + l->removeWidget(parentItem->widgetLabel); + delete parentItem->widgetLabel; + parentItem->widgetLabel = 0; + } + if (parentItem->line) { + parentItem->line->setFrameShape(QFrame::HLine); + parentItem->line->setFrameShadow(QFrame::Sunken); + parentItem->layout->addWidget(parentItem->line, 1, 0, 1, 2); + } + l->addWidget(parentItem->groupBox, oldRow, 0, 1, 2); + updateItem(parentItem); + } + layout = parentItem->layout; + parentWidget = parentItem->groupBox; + } + + newItem->label = new QLabel(parentWidget); + newItem->label->setSizePolicy(QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed)); + newItem->widget = createEditor(index->property(), parentWidget); + if (!newItem->widget) { + newItem->widgetLabel = new QLabel(parentWidget); + } else { + QObject::connect(newItem->widget, SIGNAL(destroyed()), q_ptr, SLOT(slotEditorDestroyed())); + m_widgetToItem[newItem->widget] = newItem; + } + + insertRow(layout, row); + int span = 1; + if (newItem->widget) + layout->addWidget(newItem->widget, row, 1); + else if (newItem->widgetLabel) + layout->addWidget(newItem->widgetLabel, row, 1); + else + span = 2; + layout->addWidget(newItem->label, row, 0, 1, span); + + m_itemToIndex[newItem] = index; + m_indexToItem[index] = newItem; + + updateItem(newItem); +} + +void QtGroupBoxPropertyBrowserPrivate::propertyRemoved(QtBrowserItem *index) +{ + WidgetItem *item = m_indexToItem.value(index); + + m_indexToItem.remove(index); + m_itemToIndex.remove(item); + + WidgetItem *parentItem = item->parent; + + int row = -1; + + if (parentItem) { + row = parentItem->children.indexOf(item); + parentItem->children.removeAt(row); + if (hasHeader(parentItem)) + row += 2; + } else { + row = m_children.indexOf(item); + m_children.removeAt(row); + } + + if (item->widget) + delete item->widget; + if (item->label) + delete item->label; + if (item->widgetLabel) + delete item->widgetLabel; + if (item->groupBox) + delete item->groupBox; + + if (!parentItem) { + removeRow(m_mainLayout, row); + } else if (parentItem->children.count() != 0) { + removeRow(parentItem->layout, row); + } else { + WidgetItem *par = parentItem->parent; + QWidget *w = 0; + QGridLayout *l = 0; + int oldRow = -1; + if (!par) { + w = q_ptr; + l = m_mainLayout; + oldRow = m_children.indexOf(parentItem); + } else { + w = par->groupBox; + l = par->layout; + oldRow = par->children.indexOf(parentItem); + if (hasHeader(par)) + oldRow += 2; + } + + if (parentItem->widget) { + parentItem->widget->hide(); + parentItem->widget->setParent(0); + } else if (parentItem->widgetLabel) { + parentItem->widgetLabel->hide(); + parentItem->widgetLabel->setParent(0); + } else { + //parentItem->widgetLabel = new QLabel(w); + } + l->removeWidget(parentItem->groupBox); + delete parentItem->groupBox; + parentItem->groupBox = 0; + parentItem->line = 0; + parentItem->layout = 0; + if (!m_recreateQueue.contains(parentItem)) + m_recreateQueue.append(parentItem); + updateLater(); + } + m_recreateQueue.removeAll(item); + + delete item; +} + +void QtGroupBoxPropertyBrowserPrivate::insertRow(QGridLayout *layout, int row) const +{ + QMap<QLayoutItem *, QRect> itemToPos; + int idx = 0; + while (idx < layout->count()) { + int r, c, rs, cs; + layout->getItemPosition(idx, &r, &c, &rs, &cs); + if (r >= row) { + itemToPos[layout->takeAt(idx)] = QRect(r + 1, c, rs, cs); + } else { + idx++; + } + } + + const QMap<QLayoutItem *, QRect>::ConstIterator icend = itemToPos.constEnd(); + for (QMap<QLayoutItem *, QRect>::ConstIterator it = itemToPos.constBegin(); it != icend; ++it) { + const QRect r = it.value(); + layout->addItem(it.key(), r.x(), r.y(), r.width(), r.height()); + } +} + +void QtGroupBoxPropertyBrowserPrivate::removeRow(QGridLayout *layout, int row) const +{ + QMap<QLayoutItem *, QRect> itemToPos; + int idx = 0; + while (idx < layout->count()) { + int r, c, rs, cs; + layout->getItemPosition(idx, &r, &c, &rs, &cs); + if (r > row) { + itemToPos[layout->takeAt(idx)] = QRect(r - 1, c, rs, cs); + } else { + idx++; + } + } + + const QMap<QLayoutItem *, QRect>::ConstIterator icend = itemToPos.constEnd(); + for (QMap<QLayoutItem *, QRect>::ConstIterator it = itemToPos.constBegin(); it != icend; ++it) { + const QRect r = it.value(); + layout->addItem(it.key(), r.x(), r.y(), r.width(), r.height()); + } +} + +bool QtGroupBoxPropertyBrowserPrivate::hasHeader(WidgetItem *item) const +{ + if (item->widget) + return true; + return false; +} + +void QtGroupBoxPropertyBrowserPrivate::propertyChanged(QtBrowserItem *index) +{ + WidgetItem *item = m_indexToItem.value(index); + + updateItem(item); +} + +void QtGroupBoxPropertyBrowserPrivate::updateItem(WidgetItem *item) +{ + QtProperty *property = m_itemToIndex[item]->property(); + if (item->groupBox) { + QFont font = item->groupBox->font(); + font.setUnderline(property->isModified()); + item->groupBox->setFont(font); + item->groupBox->setTitle(property->propertyName()); + item->groupBox->setToolTip(property->toolTip()); + item->groupBox->setStatusTip(property->statusTip()); + item->groupBox->setWhatsThis(property->whatsThis()); + item->groupBox->setEnabled(property->isEnabled()); + } + if (item->label) { + QFont font = item->label->font(); + font.setUnderline(property->isModified()); + item->label->setFont(font); + item->label->setText(property->propertyName()); + item->label->setToolTip(property->toolTip()); + item->label->setStatusTip(property->statusTip()); + item->label->setWhatsThis(property->whatsThis()); + item->label->setEnabled(property->isEnabled()); + } + if (item->widgetLabel) { + QFont font = item->widgetLabel->font(); + font.setUnderline(false); + item->widgetLabel->setFont(font); + item->widgetLabel->setText(property->valueText()); + item->widgetLabel->setEnabled(property->isEnabled()); + } + if (item->widget) { + QFont font = item->widget->font(); + font.setUnderline(false); + item->widget->setFont(font); + item->widget->setEnabled(property->isEnabled()); + item->widget->setToolTip(property->valueText()); + } + //item->setIcon(1, property->valueIcon()); +} + + + +/*! + \class QtGroupBoxPropertyBrowser + \internal + \inmodule QtDesigner + \since 4.4 + + \brief The QtGroupBoxPropertyBrowser class provides a QGroupBox + based property browser. + + A property browser is a widget that enables the user to edit a + given set of properties. Each property is represented by a label + specifying the property's name, and an editing widget (e.g. a line + edit or a combobox) holding its value. A property can have zero or + more subproperties. + + QtGroupBoxPropertyBrowser provides group boxes for all nested + properties, i.e. subproperties are enclosed by a group box with + the parent property's name as its title. For example: + + \image qtgroupboxpropertybrowser.png + + Use the QtAbstractPropertyBrowser API to add, insert and remove + properties from an instance of the QtGroupBoxPropertyBrowser + class. The properties themselves are created and managed by + implementations of the QtAbstractPropertyManager class. + + \sa QtTreePropertyBrowser, QtAbstractPropertyBrowser +*/ + +/*! + Creates a property browser with the given \a parent. +*/ +QtGroupBoxPropertyBrowser::QtGroupBoxPropertyBrowser(QWidget *parent) + : QtAbstractPropertyBrowser(parent) +{ + d_ptr = new QtGroupBoxPropertyBrowserPrivate; + d_ptr->q_ptr = this; + + d_ptr->init(this); +} + +/*! + Destroys this property browser. + + Note that the properties that were inserted into this browser are + \e not destroyed since they may still be used in other + browsers. The properties are owned by the manager that created + them. + + \sa QtProperty, QtAbstractPropertyManager +*/ +QtGroupBoxPropertyBrowser::~QtGroupBoxPropertyBrowser() +{ + const QMap<QtGroupBoxPropertyBrowserPrivate::WidgetItem *, QtBrowserItem *>::ConstIterator icend = d_ptr->m_itemToIndex.constEnd(); + for (QMap<QtGroupBoxPropertyBrowserPrivate::WidgetItem *, QtBrowserItem *>::ConstIterator it = d_ptr->m_itemToIndex.constBegin(); it != icend; ++it) + delete it.key(); + delete d_ptr; +} + +/*! + \reimp +*/ +void QtGroupBoxPropertyBrowser::itemInserted(QtBrowserItem *item, QtBrowserItem *afterItem) +{ + d_ptr->propertyInserted(item, afterItem); +} + +/*! + \reimp +*/ +void QtGroupBoxPropertyBrowser::itemRemoved(QtBrowserItem *item) +{ + d_ptr->propertyRemoved(item); +} + +/*! + \reimp +*/ +void QtGroupBoxPropertyBrowser::itemChanged(QtBrowserItem *item) +{ + d_ptr->propertyChanged(item); +} + +#if QT_VERSION >= 0x040400 +QT_END_NAMESPACE +#endif + +#include "moc_qtgroupboxpropertybrowser.cpp" diff --git a/tools/shared/qtpropertybrowser/qtgroupboxpropertybrowser.h b/tools/shared/qtpropertybrowser/qtgroupboxpropertybrowser.h new file mode 100644 index 0000000..29422bd --- /dev/null +++ b/tools/shared/qtpropertybrowser/qtgroupboxpropertybrowser.h @@ -0,0 +1,80 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the tools applications of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QTGROUPBOXPROPERTYBROWSER_H +#define QTGROUPBOXPROPERTYBROWSER_H + +#include "qtpropertybrowser.h" + +#if QT_VERSION >= 0x040400 +QT_BEGIN_NAMESPACE +#endif + +class QtGroupBoxPropertyBrowserPrivate; + +class QtGroupBoxPropertyBrowser : public QtAbstractPropertyBrowser +{ + Q_OBJECT +public: + + QtGroupBoxPropertyBrowser(QWidget *parent = 0); + ~QtGroupBoxPropertyBrowser(); + +protected: + virtual void itemInserted(QtBrowserItem *item, QtBrowserItem *afterItem); + virtual void itemRemoved(QtBrowserItem *item); + virtual void itemChanged(QtBrowserItem *item); + +private: + + QtGroupBoxPropertyBrowserPrivate *d_ptr; + Q_DECLARE_PRIVATE(QtGroupBoxPropertyBrowser) + Q_DISABLE_COPY(QtGroupBoxPropertyBrowser) + Q_PRIVATE_SLOT(d_func(), void slotUpdate()) + Q_PRIVATE_SLOT(d_func(), void slotEditorDestroyed()) + +}; + +#if QT_VERSION >= 0x040400 +QT_END_NAMESPACE +#endif + +#endif diff --git a/tools/shared/qtpropertybrowser/qtpropertybrowser.cpp b/tools/shared/qtpropertybrowser/qtpropertybrowser.cpp new file mode 100644 index 0000000..7254245 --- /dev/null +++ b/tools/shared/qtpropertybrowser/qtpropertybrowser.cpp @@ -0,0 +1,1965 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the tools applications of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qtpropertybrowser.h" +#include <QtCore/QSet> +#include <QtCore/QMap> +#include <QtGui/QIcon> + +#if defined(Q_CC_MSVC) +# pragma warning(disable: 4786) /* MS VS 6: truncating debug info after 255 characters */ +#endif + +#if QT_VERSION >= 0x040400 +QT_BEGIN_NAMESPACE +#endif + +class QtPropertyPrivate +{ +public: + QtPropertyPrivate(QtAbstractPropertyManager *manager) : m_enabled(true), m_modified(false), m_manager(manager) {} + QtProperty *q_ptr; + + QSet<QtProperty *> m_parentItems; + QList<QtProperty *> m_subItems; + + QString m_toolTip; + QString m_statusTip; + QString m_whatsThis; + QString m_name; + bool m_enabled; + bool m_modified; + + QtAbstractPropertyManager * const m_manager; +}; + +class QtAbstractPropertyManagerPrivate +{ + QtAbstractPropertyManager *q_ptr; + Q_DECLARE_PUBLIC(QtAbstractPropertyManager) +public: + void propertyDestroyed(QtProperty *property); + void propertyChanged(QtProperty *property) const; + void propertyRemoved(QtProperty *property, + QtProperty *parentProperty) const; + void propertyInserted(QtProperty *property, QtProperty *parentProperty, + QtProperty *afterProperty) const; + + QSet<QtProperty *> m_properties; +}; + +/*! + \class QtProperty + \internal + \inmodule QtDesigner + \since 4.4 + + \brief The QtProperty class encapsulates an instance of a property. + + Properties are created by objects of QtAbstractPropertyManager + subclasses; a manager can create properties of a given type, and + is used in conjunction with the QtAbstractPropertyBrowser class. A + property is always owned by the manager that created it, which can + be retrieved using the propertyManager() function. + + QtProperty contains the most common property attributes, and + provides functions for retrieving as well as setting their values: + + \table + \header \o Getter \o Setter + \row + \o propertyName() \o setPropertyName() + \row + \o statusTip() \o setStatusTip() + \row + \o toolTip() \o setToolTip() + \row + \o whatsThis() \o setWhatsThis() + \row + \o isEnabled() \o setEnabled() + \row + \o isModified() \o setModified() + \row + \o valueText() \o Nop + \row + \o valueIcon() \o Nop + \endtable + + It is also possible to nest properties: QtProperty provides the + addSubProperty(), insertSubProperty() and removeSubProperty() functions to + manipulate the set of subproperties. Use the subProperties() + function to retrieve a property's current set of subproperties. + Note that nested properties are not owned by the parent property, + i.e. each subproperty is owned by the manager that created it. + + \sa QtAbstractPropertyManager, QtBrowserItem +*/ + +/*! + Creates a property with the given \a manager. + + This constructor is only useful when creating a custom QtProperty + subclass (e.g. QtVariantProperty). To create a regular QtProperty + object, use the QtAbstractPropertyManager::addProperty() + function instead. + + \sa QtAbstractPropertyManager::addProperty() +*/ +QtProperty::QtProperty(QtAbstractPropertyManager *manager) +{ + d_ptr = new QtPropertyPrivate(manager); + d_ptr->q_ptr = this; +} + +/*! + Destroys this property. + + Note that subproperties are detached but not destroyed, i.e. they + can still be used in another context. + + \sa QtAbstractPropertyManager::clear() + +*/ +QtProperty::~QtProperty() +{ + QSetIterator<QtProperty *> itParent(d_ptr->m_parentItems); + while (itParent.hasNext()) { + QtProperty *property = itParent.next(); + property->d_ptr->m_manager->d_ptr->propertyRemoved(this, property); + } + + d_ptr->m_manager->d_ptr->propertyDestroyed(this); + + QListIterator<QtProperty *> itChild(d_ptr->m_subItems); + while (itChild.hasNext()) { + QtProperty *property = itChild.next(); + property->d_ptr->m_parentItems.remove(this); + } + + itParent.toFront(); + while (itParent.hasNext()) { + QtProperty *property = itParent.next(); + property->d_ptr->m_subItems.removeAll(this); + } + delete d_ptr; +} + +/*! + Returns the set of subproperties. + + Note that subproperties are not owned by \e this property, but by + the manager that created them. + + \sa insertSubProperty(), removeSubProperty() +*/ +QList<QtProperty *> QtProperty::subProperties() const +{ + return d_ptr->m_subItems; +} + +/*! + Returns a pointer to the manager that owns this property. +*/ +QtAbstractPropertyManager *QtProperty::propertyManager() const +{ + return d_ptr->m_manager; +} + +/*! + Returns the property's tool tip. + + \sa setToolTip() +*/ +QString QtProperty::toolTip() const +{ + return d_ptr->m_toolTip; +} + +/*! + Returns the property's status tip. + + \sa setStatusTip() +*/ +QString QtProperty::statusTip() const +{ + return d_ptr->m_statusTip; +} + +/*! + Returns the property's "What's This" help text. + + \sa setWhatsThis() +*/ +QString QtProperty::whatsThis() const +{ + return d_ptr->m_whatsThis; +} + +/*! + Returns the property's name. + + \sa setPropertyName() +*/ +QString QtProperty::propertyName() const +{ + return d_ptr->m_name; +} + +/*! + Returns whether the property is enabled. + + \sa setEnabled() +*/ +bool QtProperty::isEnabled() const +{ + return d_ptr->m_enabled; +} + +/*! + Returns whether the property is modified. + + \sa setModified() +*/ +bool QtProperty::isModified() const +{ + return d_ptr->m_modified; +} + +/*! + Returns whether the property has a value. + + \sa QtAbstractPropertyManager::hasValue() +*/ +bool QtProperty::hasValue() const +{ + return d_ptr->m_manager->hasValue(this); +} + +/*! + Returns an icon representing the current state of this property. + + If the given property type can not generate such an icon, this + function returns an invalid icon. + + \sa QtAbstractPropertyManager::valueIcon() +*/ +QIcon QtProperty::valueIcon() const +{ + return d_ptr->m_manager->valueIcon(this); +} + +/*! + Returns a string representing the current state of this property. + + If the given property type can not generate such a string, this + function returns an empty string. + + \sa QtAbstractPropertyManager::valueText() +*/ +QString QtProperty::valueText() const +{ + return d_ptr->m_manager->valueText(this); +} + +/*! + Sets the property's tool tip to the given \a text. + + \sa toolTip() +*/ +void QtProperty::setToolTip(const QString &text) +{ + if (d_ptr->m_toolTip == text) + return; + + d_ptr->m_toolTip = text; + propertyChanged(); +} + +/*! + Sets the property's status tip to the given \a text. + + \sa statusTip() +*/ +void QtProperty::setStatusTip(const QString &text) +{ + if (d_ptr->m_statusTip == text) + return; + + d_ptr->m_statusTip = text; + propertyChanged(); +} + +/*! + Sets the property's "What's This" help text to the given \a text. + + \sa whatsThis() +*/ +void QtProperty::setWhatsThis(const QString &text) +{ + if (d_ptr->m_whatsThis == text) + return; + + d_ptr->m_whatsThis = text; + propertyChanged(); +} + +/*! + \fn void QtProperty::setPropertyName(const QString &name) + + Sets the property's name to the given \a name. + + \sa propertyName() +*/ +void QtProperty::setPropertyName(const QString &text) +{ + if (d_ptr->m_name == text) + return; + + d_ptr->m_name = text; + propertyChanged(); +} + +/*! + Enables or disables the property according to the passed \a enable value. + + \sa isEnabled() +*/ +void QtProperty::setEnabled(bool enable) +{ + if (d_ptr->m_enabled == enable) + return; + + d_ptr->m_enabled = enable; + propertyChanged(); +} + +/*! + Sets the property's modified state according to the passed \a modified value. + + \sa isModified() +*/ +void QtProperty::setModified(bool modified) +{ + if (d_ptr->m_modified == modified) + return; + + d_ptr->m_modified = modified; + propertyChanged(); +} + +/*! + Appends the given \a property to this property's subproperties. + + If the given \a property already is added, this function does + nothing. + + \sa insertSubProperty(), removeSubProperty() +*/ +void QtProperty::addSubProperty(QtProperty *property) +{ + QtProperty *after = 0; + if (d_ptr->m_subItems.count() > 0) + after = d_ptr->m_subItems.last(); + insertSubProperty(property, after); +} + +/*! + \fn void QtProperty::insertSubProperty(QtProperty *property, QtProperty *precedingProperty) + + Inserts the given \a property after the specified \a + precedingProperty into this property's list of subproperties. If + \a precedingProperty is 0, the specified \a property is inserted + at the beginning of the list. + + If the given \a property already is inserted, this function does + nothing. + + \sa addSubProperty(), removeSubProperty() +*/ +void QtProperty::insertSubProperty(QtProperty *property, + QtProperty *afterProperty) +{ + if (!property) + return; + + if (property == this) + return; + + // traverse all children of item. if this item is a child of item then cannot add. + QList<QtProperty *> pendingList = property->subProperties(); + QMap<QtProperty *, bool> visited; + while (!pendingList.isEmpty()) { + QtProperty *i = pendingList.first(); + if (i == this) + return; + pendingList.removeFirst(); + if (visited.contains(i)) + continue; + visited[i] = true; + pendingList += i->subProperties(); + } + + pendingList = subProperties(); + int pos = 0; + int newPos = 0; + QtProperty *properAfterProperty = 0; + while (pos < pendingList.count()) { + QtProperty *i = pendingList.at(pos); + if (i == property) + return; // if item is already inserted in this item then cannot add. + if (i == afterProperty) { + newPos = pos + 1; + properAfterProperty = afterProperty; + } + pos++; + } + + d_ptr->m_subItems.insert(newPos, property); + property->d_ptr->m_parentItems.insert(this); + + d_ptr->m_manager->d_ptr->propertyInserted(property, this, properAfterProperty); +} + +/*! + Removes the given \a property from the list of subproperties + without deleting it. + + \sa addSubProperty(), insertSubProperty() +*/ +void QtProperty::removeSubProperty(QtProperty *property) +{ + if (!property) + return; + + d_ptr->m_manager->d_ptr->propertyRemoved(property, this); + + QList<QtProperty *> pendingList = subProperties(); + int pos = 0; + while (pos < pendingList.count()) { + if (pendingList.at(pos) == property) { + d_ptr->m_subItems.removeAt(pos); + property->d_ptr->m_parentItems.remove(this); + + return; + } + pos++; + } +} + +/*! + \internal +*/ +void QtProperty::propertyChanged() +{ + d_ptr->m_manager->d_ptr->propertyChanged(this); +} + +//////////////////////////////// + +void QtAbstractPropertyManagerPrivate::propertyDestroyed(QtProperty *property) +{ + if (m_properties.contains(property)) { + emit q_ptr->propertyDestroyed(property); + q_ptr->uninitializeProperty(property); + m_properties.remove(property); + } +} + +void QtAbstractPropertyManagerPrivate::propertyChanged(QtProperty *property) const +{ + emit q_ptr->propertyChanged(property); +} + +void QtAbstractPropertyManagerPrivate::propertyRemoved(QtProperty *property, + QtProperty *parentProperty) const +{ + emit q_ptr->propertyRemoved(property, parentProperty); +} + +void QtAbstractPropertyManagerPrivate::propertyInserted(QtProperty *property, + QtProperty *parentProperty, QtProperty *afterProperty) const +{ + emit q_ptr->propertyInserted(property, parentProperty, afterProperty); +} + +/*! + \class QtAbstractPropertyManager + \internal + \inmodule QtDesigner + \since 4.4 + + \brief The QtAbstractPropertyManager provides an interface for + property managers. + + A manager can create and manage properties of a given type, and is + used in conjunction with the QtAbstractPropertyBrowser class. + + When using a property browser widget, the properties are created + and managed by implementations of the QtAbstractPropertyManager + class. To ensure that the properties' values will be displayed + using suitable editing widgets, the managers are associated with + objects of QtAbstractEditorFactory subclasses. The property browser + will use these associations to determine which factories it should + use to create the preferred editing widgets. + + The QtAbstractPropertyManager class provides common functionality + like creating a property using the addProperty() function, and + retrieving the properties created by the manager using the + properties() function. The class also provides signals that are + emitted when the manager's properties change: propertyInserted(), + propertyRemoved(), propertyChanged() and propertyDestroyed(). + + QtAbstractPropertyManager subclasses are supposed to provide their + own type specific API. Note that several ready-made + implementations are available: + + \list + \o QtBoolPropertyManager + \o QtColorPropertyManager + \o QtDatePropertyManager + \o QtDateTimePropertyManager + \o QtDoublePropertyManager + \o QtEnumPropertyManager + \o QtFlagPropertyManager + \o QtFontPropertyManager + \o QtGroupPropertyManager + \o QtIntPropertyManager + \o QtPointPropertyManager + \o QtRectPropertyManager + \o QtSizePropertyManager + \o QtSizePolicyPropertyManager + \o QtStringPropertyManager + \o QtTimePropertyManager + \o QtVariantPropertyManager + \endlist + + \sa QtAbstractEditorFactoryBase, QtAbstractPropertyBrowser, QtProperty +*/ + +/*! + \fn void QtAbstractPropertyManager::propertyInserted(QtProperty *newProperty, + QtProperty *parentProperty, QtProperty *precedingProperty) + + This signal is emitted when a new subproperty is inserted into an + existing property, passing pointers to the \a newProperty, \a + parentProperty and \a precedingProperty as parameters. + + If \a precedingProperty is 0, the \a newProperty was inserted at + the beginning of the \a parentProperty's subproperties list. + + Note that signal is emitted only if the \a parentProperty is created + by this manager. + + \sa QtAbstractPropertyBrowser::itemInserted() +*/ + +/*! + \fn void QtAbstractPropertyManager::propertyChanged(QtProperty *property) + + This signal is emitted whenever a property's data changes, passing + a pointer to the \a property as parameter. + + Note that signal is only emitted for properties that are created by + this manager. + + \sa QtAbstractPropertyBrowser::itemChanged() +*/ + +/*! + \fn void QtAbstractPropertyManager::propertyRemoved(QtProperty *property, QtProperty *parent) + + This signal is emitted when a subproperty is removed, passing + pointers to the removed \a property and the \a parent property as + parameters. + + Note that signal is emitted only when the \a parent property is + created by this manager. + + \sa QtAbstractPropertyBrowser::itemRemoved() +*/ + +/*! + \fn void QtAbstractPropertyManager::propertyDestroyed(QtProperty *property) + + This signal is emitted when the specified \a property is about to + be destroyed. + + Note that signal is only emitted for properties that are created + by this manager. + + \sa clear(), uninitializeProperty() +*/ + +/*! + \fn void QtAbstractPropertyBrowser::currentItemChanged(QtBrowserItem *current) + + This signal is emitted when the current item changes. The current item is specified by \a current. + + \sa QtAbstractPropertyBrowser::setCurrentItem() +*/ + +/*! + Creates an abstract property manager with the given \a parent. +*/ +QtAbstractPropertyManager::QtAbstractPropertyManager(QObject *parent) + : QObject(parent) +{ + d_ptr = new QtAbstractPropertyManagerPrivate; + d_ptr->q_ptr = this; + +} + +/*! + Destroys the manager. All properties created by the manager are + destroyed. +*/ +QtAbstractPropertyManager::~QtAbstractPropertyManager() +{ + clear(); + delete d_ptr; +} + +/*! + Destroys all the properties that this manager has created. + + \sa propertyDestroyed(), uninitializeProperty() +*/ +void QtAbstractPropertyManager::clear() const +{ + while (!properties().isEmpty()) { + QSetIterator<QtProperty *> itProperty(properties()); + QtProperty *prop = itProperty.next(); + delete prop; + } +} + +/*! + Returns the set of properties created by this manager. + + \sa addProperty() +*/ +QSet<QtProperty *> QtAbstractPropertyManager::properties() const +{ + return d_ptr->m_properties; +} + +/*! + Returns whether the given \a property has a value. + + The default implementation of this function returns true. + + \sa QtProperty::hasValue() +*/ +bool QtAbstractPropertyManager::hasValue(const QtProperty *property) const +{ + Q_UNUSED(property) + return true; +} + +/*! + Returns an icon representing the current state of the given \a + property. + + The default implementation of this function returns an invalid + icon. + + \sa QtProperty::valueIcon() +*/ +QIcon QtAbstractPropertyManager::valueIcon(const QtProperty *property) const +{ + Q_UNUSED(property) + return QIcon(); +} + +/*! + Returns a string representing the current state of the given \a + property. + + The default implementation of this function returns an empty + string. + + \sa QtProperty::valueText() +*/ +QString QtAbstractPropertyManager::valueText(const QtProperty *property) const +{ + Q_UNUSED(property) + return QString(); +} + +/*! + Creates a property with the given \a name which then is owned by this manager. + + Internally, this function calls the createProperty() and + initializeProperty() functions. + + \sa initializeProperty(), properties() +*/ +QtProperty *QtAbstractPropertyManager::addProperty(const QString &name) +{ + QtProperty *property = createProperty(); + if (property) { + property->setPropertyName(name); + d_ptr->m_properties.insert(property); + initializeProperty(property); + } + return property; +} + +/*! + Creates a property. + + The base implementation produce QtProperty instances; Reimplement + this function to make this manager produce objects of a QtProperty + subclass. + + \sa addProperty(), initializeProperty() +*/ +QtProperty *QtAbstractPropertyManager::createProperty() +{ + return new QtProperty(this); +} + +/*! + \fn void QtAbstractPropertyManager::initializeProperty(QtProperty *property) = 0 + + This function is called whenever a new valid property pointer has + been created, passing the pointer as parameter. + + The purpose is to let the manager know that the \a property has + been created so that it can provide additional attributes for the + new property, e.g. QtIntPropertyManager adds \l + {QtIntPropertyManager::value()}{value}, \l + {QtIntPropertyManager::minimum()}{minimum} and \l + {QtIntPropertyManager::maximum()}{maximum} attributes. Since each manager + subclass adds type specific attributes, this function is pure + virtual and must be reimplemented when deriving from the + QtAbstractPropertyManager class. + + \sa addProperty(), createProperty() +*/ + +/*! + This function is called just before the specified \a property is destroyed. + + The purpose is to let the property manager know that the \a + property is being destroyed so that it can remove the property's + additional attributes. + + \sa clear(), propertyDestroyed() +*/ +void QtAbstractPropertyManager::uninitializeProperty(QtProperty *property) +{ + Q_UNUSED(property) +} + +//////////////////////////////////// + +/*! + \class QtAbstractEditorFactoryBase + \internal + \inmodule QtDesigner + \since 4.4 + + \brief The QtAbstractEditorFactoryBase provides an interface for + editor factories. + + An editor factory is a class that is able to create an editing + widget of a specified type (e.g. line edits or comboboxes) for a + given QtProperty object, and it is used in conjunction with the + QtAbstractPropertyManager and QtAbstractPropertyBrowser classes. + + When using a property browser widget, the properties are created + and managed by implementations of the QtAbstractPropertyManager + class. To ensure that the properties' values will be displayed + using suitable editing widgets, the managers are associated with + objects of QtAbstractEditorFactory subclasses. The property browser + will use these associations to determine which factories it should + use to create the preferred editing widgets. + + Typically, an editor factory is created by subclassing the + QtAbstractEditorFactory template class which inherits + QtAbstractEditorFactoryBase. But note that several ready-made + implementations are available: + + \list + \o QtCheckBoxFactory + \o QtDateEditFactory + \o QtDateTimeEditFactory + \o QtDoubleSpinBoxFactory + \o QtEnumEditorFactory + \o QtLineEditFactory + \o QtScrollBarFactory + \o QtSliderFactory + \o QtSpinBoxFactory + \o QtTimeEditFactory + \o QtVariantEditorFactory + \endlist + + \sa QtAbstractPropertyManager, QtAbstractPropertyBrowser +*/ + +/*! + \fn virtual QWidget *QtAbstractEditorFactoryBase::createEditor(QtProperty *property, + QWidget *parent) = 0 + + Creates an editing widget (with the given \a parent) for the given + \a property. + + This function is reimplemented in QtAbstractEditorFactory template class + which also provides a pure virtual convenience overload of this + function enabling access to the property's manager. + + \sa QtAbstractEditorFactory::createEditor() +*/ + +/*! + \fn QtAbstractEditorFactoryBase::QtAbstractEditorFactoryBase(QObject *parent = 0) + + Creates an abstract editor factory with the given \a parent. +*/ + +/*! + \fn virtual void QtAbstractEditorFactoryBase::breakConnection(QtAbstractPropertyManager *manager) = 0 + + \internal + + Detaches property manager from factory. + This method is reimplemented in QtAbstractEditorFactory template subclass. + You don't need to reimplement it in your subclasses. Instead implement more convenient + QtAbstractEditorFactory::disconnectPropertyManager() which gives you access to particular manager subclass. +*/ + +/*! + \fn virtual void QtAbstractEditorFactoryBase::managerDestroyed(QObject *manager) = 0 + + \internal + + This method is called when property manager is being destroyed. + Basically it notifies factory not to produce editors for properties owned by \a manager. + You don't need to reimplement it in your subclass. This method is implemented in + QtAbstractEditorFactory template subclass. +*/ + +/*! + \class QtAbstractEditorFactory + \internal + \inmodule QtDesigner + \since 4.4 + + \brief The QtAbstractEditorFactory is the base template class for editor + factories. + + An editor factory is a class that is able to create an editing + widget of a specified type (e.g. line edits or comboboxes) for a + given QtProperty object, and it is used in conjunction with the + QtAbstractPropertyManager and QtAbstractPropertyBrowser classes. + + Note that the QtAbstractEditorFactory functions are using the + PropertyManager template argument class which can be any + QtAbstractPropertyManager subclass. For example: + + \snippet doc/src/snippets/code/tools_shared_qtpropertybrowser_qtpropertybrowser.cpp 0 + + Note that QtSpinBoxFactory by definition creates editing widgets + \e only for properties created by QtIntPropertyManager. + + When using a property browser widget, the properties are created + and managed by implementations of the QtAbstractPropertyManager + class. To ensure that the properties' values will be displayed + using suitable editing widgets, the managers are associated with + objects of QtAbstractEditorFactory subclasses. The property browser will + use these associations to determine which factories it should use + to create the preferred editing widgets. + + A QtAbstractEditorFactory object is capable of producing editors for + several property managers at the same time. To create an + association between this factory and a given manager, use the + addPropertyManager() function. Use the removePropertyManager() function to make + this factory stop producing editors for a given property + manager. Use the propertyManagers() function to retrieve the set of + managers currently associated with this factory. + + Several ready-made implementations of the QtAbstractEditorFactory class + are available: + + \list + \o QtCheckBoxFactory + \o QtDateEditFactory + \o QtDateTimeEditFactory + \o QtDoubleSpinBoxFactory + \o QtEnumEditorFactory + \o QtLineEditFactory + \o QtScrollBarFactory + \o QtSliderFactory + \o QtSpinBoxFactory + \o QtTimeEditFactory + \o QtVariantEditorFactory + \endlist + + When deriving from the QtAbstractEditorFactory class, several pure virtual + functions must be implemented: the connectPropertyManager() function is + used by the factory to connect to the given manager's signals, the + createEditor() function is supposed to create an editor for the + given property controlled by the given manager, and finally the + disconnectPropertyManager() function is used by the factory to disconnect + from the specified manager's signals. + + \sa QtAbstractEditorFactoryBase, QtAbstractPropertyManager +*/ + +/*! + \fn QtAbstractEditorFactory::QtAbstractEditorFactory(QObject *parent = 0) + + Creates an editor factory with the given \a parent. + + \sa addPropertyManager() +*/ + +/*! + \fn QWidget *QtAbstractEditorFactory::createEditor(QtProperty *property, QWidget *parent) + + Creates an editing widget (with the given \a parent) for the given + \a property. +*/ + +/*! + \fn void QtAbstractEditorFactory::addPropertyManager(PropertyManager *manager) + + Adds the given \a manager to this factory's set of managers, + making this factory produce editing widgets for properties created + by the given manager. + + The PropertyManager type is a template argument class, and represents the chosen + QtAbstractPropertyManager subclass. + + \sa propertyManagers(), removePropertyManager() +*/ + +/*! + \fn void QtAbstractEditorFactory::removePropertyManager(PropertyManager *manager) + + Removes the given \a manager from this factory's set of + managers. The PropertyManager type is a template argument class, and may be + any QtAbstractPropertyManager subclass. + + \sa propertyManagers(), addPropertyManager() +*/ + +/*! + \fn virtual void QtAbstractEditorFactory::connectPropertyManager(PropertyManager *manager) = 0 + + Connects this factory to the given \a manager's signals. The + PropertyManager type is a template argument class, and represents + the chosen QtAbstractPropertyManager subclass. + + This function is used internally by the addPropertyManager() function, and + makes it possible to update an editing widget when the associated + property's data changes. This is typically done in custom slots + responding to the signals emitted by the property's manager, + e.g. QtIntPropertyManager::valueChanged() and + QtIntPropertyManager::rangeChanged(). + + \sa propertyManagers(), disconnectPropertyManager() +*/ + +/*! + \fn virtual QWidget *QtAbstractEditorFactory::createEditor(PropertyManager *manager, QtProperty *property, + QWidget *parent) = 0 + + Creates an editing widget with the given \a parent for the + specified \a property created by the given \a manager. The + PropertyManager type is a template argument class, and represents + the chosen QtAbstractPropertyManager subclass. + + This function must be implemented in derived classes: It is + recommended to store a pointer to the widget and map it to the + given \a property, since the widget must be updated whenever the + associated property's data changes. This is typically done in + custom slots responding to the signals emitted by the property's + manager, e.g. QtIntPropertyManager::valueChanged() and + QtIntPropertyManager::rangeChanged(). + + \sa connectPropertyManager() +*/ + +/*! + \fn virtual void QtAbstractEditorFactory::disconnectPropertyManager(PropertyManager *manager) = 0 + + Disconnects this factory from the given \a manager's signals. The + PropertyManager type is a template argument class, and represents + the chosen QtAbstractPropertyManager subclass. + + This function is used internally by the removePropertyManager() function. + + \sa propertyManagers(), connectPropertyManager() +*/ + +/*! + \fn QSet<PropertyManager *> QtAbstractEditorFactory::propertyManagers() const + + Returns the factory's set of associated managers. The + PropertyManager type is a template argument class, and represents + the chosen QtAbstractPropertyManager subclass. + + \sa addPropertyManager(), removePropertyManager() +*/ + +/*! + \fn PropertyManager *QtAbstractEditorFactory::propertyManager(QtProperty *property) const + + Returns the property manager for the given \a property, or 0 if + the given \a property doesn't belong to any of this factory's + registered managers. + + The PropertyManager type is a template argument class, and represents the chosen + QtAbstractPropertyManager subclass. + + \sa propertyManagers() +*/ + +/*! + \fn virtual void QtAbstractEditorFactory::managerDestroyed(QObject *manager) + + \internal + \reimp +*/ + +//////////////////////////////////// +class QtBrowserItemPrivate +{ +public: + QtBrowserItemPrivate(QtAbstractPropertyBrowser *browser, QtProperty *property, QtBrowserItem *parent) + : m_browser(browser), m_property(property), m_parent(parent), q_ptr(0) {} + + void addChild(QtBrowserItem *index, QtBrowserItem *after); + void removeChild(QtBrowserItem *index); + + QtAbstractPropertyBrowser * const m_browser; + QtProperty *m_property; + QtBrowserItem *m_parent; + + QtBrowserItem *q_ptr; + + QList<QtBrowserItem *> m_children; + +}; + +void QtBrowserItemPrivate::addChild(QtBrowserItem *index, QtBrowserItem *after) +{ + if (m_children.contains(index)) + return; + int idx = m_children.indexOf(after) + 1; // we insert after returned idx, if it was -1 then we set idx to 0; + m_children.insert(idx, index); +} + +void QtBrowserItemPrivate::removeChild(QtBrowserItem *index) +{ + m_children.removeAll(index); +} + + +/*! + \class QtBrowserItem + \internal + \inmodule QtDesigner + \since 4.4 + + \brief The QtBrowserItem class represents a property in + a property browser instance. + + Browser items are created whenever a QtProperty is inserted to the + property browser. A QtBrowserItem uniquely identifies a + browser's item. Thus, if the same QtProperty is inserted multiple + times, each occurrence gets its own unique QtBrowserItem. The + items are owned by QtAbstractPropertyBrowser and automatically + deleted when they are removed from the browser. + + You can traverse a browser's properties by calling parent() and + children(). The property and the browser associated with an item + are available as property() and browser(). + + \sa QtAbstractPropertyBrowser, QtProperty +*/ + +/*! + Returns the property which is accosiated with this item. Note that + several items can be associated with the same property instance in + the same property browser. + + \sa QtAbstractPropertyBrowser::items() +*/ + +QtProperty *QtBrowserItem::property() const +{ + return d_ptr->m_property; +} + +/*! + Returns the parent item of \e this item. Returns 0 if \e this item + is associated with top-level property in item's property browser. + + \sa children() +*/ + +QtBrowserItem *QtBrowserItem::parent() const +{ + return d_ptr->m_parent; +} + +/*! + Returns the children items of \e this item. The properties + reproduced from children items are always the same as + reproduced from associated property' children, for example: + + \snippet doc/src/snippets/code/tools_shared_qtpropertybrowser_qtpropertybrowser.cpp 1 + + The \e childrenItems list represents the same list as \e childrenProperties. +*/ + +QList<QtBrowserItem *> QtBrowserItem::children() const +{ + return d_ptr->m_children; +} + +/*! + Returns the property browser which owns \e this item. +*/ + +QtAbstractPropertyBrowser *QtBrowserItem::browser() const +{ + return d_ptr->m_browser; +} + +QtBrowserItem::QtBrowserItem(QtAbstractPropertyBrowser *browser, QtProperty *property, QtBrowserItem *parent) +{ + d_ptr = new QtBrowserItemPrivate(browser, property, parent); + d_ptr->q_ptr = this; +} + +QtBrowserItem::~QtBrowserItem() +{ + delete d_ptr; +} + + +//////////////////////////////////// + +typedef QMap<QtAbstractPropertyBrowser *, QMap<QtAbstractPropertyManager *, + QtAbstractEditorFactoryBase *> > Map1; +typedef QMap<QtAbstractPropertyManager *, QMap<QtAbstractEditorFactoryBase *, + QList<QtAbstractPropertyBrowser *> > > Map2; +Q_GLOBAL_STATIC(Map1, m_viewToManagerToFactory) +Q_GLOBAL_STATIC(Map2, m_managerToFactoryToViews) + +class QtAbstractPropertyBrowserPrivate +{ + QtAbstractPropertyBrowser *q_ptr; + Q_DECLARE_PUBLIC(QtAbstractPropertyBrowser) +public: + QtAbstractPropertyBrowserPrivate(); + + void insertSubTree(QtProperty *property, + QtProperty *parentProperty); + void removeSubTree(QtProperty *property, + QtProperty *parentProperty); + void createBrowserIndexes(QtProperty *property, QtProperty *parentProperty, QtProperty *afterProperty); + void removeBrowserIndexes(QtProperty *property, QtProperty *parentProperty); + QtBrowserItem *createBrowserIndex(QtProperty *property, QtBrowserItem *parentIndex, QtBrowserItem *afterIndex); + void removeBrowserIndex(QtBrowserItem *index); + void clearIndex(QtBrowserItem *index); + + void slotPropertyInserted(QtProperty *property, + QtProperty *parentProperty, QtProperty *afterProperty); + void slotPropertyRemoved(QtProperty *property, QtProperty *parentProperty); + void slotPropertyDestroyed(QtProperty *property); + void slotPropertyDataChanged(QtProperty *property); + + QList<QtProperty *> m_subItems; + QMap<QtAbstractPropertyManager *, QList<QtProperty *> > m_managerToProperties; + QMap<QtProperty *, QList<QtProperty *> > m_propertyToParents; + + QMap<QtProperty *, QtBrowserItem *> m_topLevelPropertyToIndex; + QList<QtBrowserItem *> m_topLevelIndexes; + QMap<QtProperty *, QList<QtBrowserItem *> > m_propertyToIndexes; + + QtBrowserItem *m_currentItem; +}; + +QtAbstractPropertyBrowserPrivate::QtAbstractPropertyBrowserPrivate() : + m_currentItem(0) +{ +} + +void QtAbstractPropertyBrowserPrivate::insertSubTree(QtProperty *property, + QtProperty *parentProperty) +{ + if (m_propertyToParents.contains(property)) { + // property was already inserted, so its manager is connected + // and all its children are inserted and theirs managers are connected + // we just register new parent (parent has to be new). + m_propertyToParents[property].append(parentProperty); + // don't need to update m_managerToProperties map since + // m_managerToProperties[manager] already contains property. + return; + } + QtAbstractPropertyManager *manager = property->propertyManager(); + if (m_managerToProperties[manager].isEmpty()) { + // connect manager's signals + q_ptr->connect(manager, SIGNAL(propertyInserted(QtProperty *, + QtProperty *, QtProperty *)), + q_ptr, SLOT(slotPropertyInserted(QtProperty *, + QtProperty *, QtProperty *))); + q_ptr->connect(manager, SIGNAL(propertyRemoved(QtProperty *, + QtProperty *)), + q_ptr, SLOT(slotPropertyRemoved(QtProperty *, QtProperty *))); + q_ptr->connect(manager, SIGNAL(propertyDestroyed(QtProperty *)), + q_ptr, SLOT(slotPropertyDestroyed(QtProperty *))); + q_ptr->connect(manager, SIGNAL(propertyChanged(QtProperty *)), + q_ptr, SLOT(slotPropertyDataChanged(QtProperty *))); + } + m_managerToProperties[manager].append(property); + m_propertyToParents[property].append(parentProperty); + + QList<QtProperty *> subList = property->subProperties(); + QListIterator<QtProperty *> itSub(subList); + while (itSub.hasNext()) { + QtProperty *subProperty = itSub.next(); + insertSubTree(subProperty, property); + } +} + +void QtAbstractPropertyBrowserPrivate::removeSubTree(QtProperty *property, + QtProperty *parentProperty) +{ + if (!m_propertyToParents.contains(property)) { + // ASSERT + return; + } + + m_propertyToParents[property].removeAll(parentProperty); + if (!m_propertyToParents[property].isEmpty()) + return; + + m_propertyToParents.remove(property); + QtAbstractPropertyManager *manager = property->propertyManager(); + m_managerToProperties[manager].removeAll(property); + if (m_managerToProperties[manager].isEmpty()) { + // disconnect manager's signals + q_ptr->disconnect(manager, SIGNAL(propertyInserted(QtProperty *, + QtProperty *, QtProperty *)), + q_ptr, SLOT(slotPropertyInserted(QtProperty *, + QtProperty *, QtProperty *))); + q_ptr->disconnect(manager, SIGNAL(propertyRemoved(QtProperty *, + QtProperty *)), + q_ptr, SLOT(slotPropertyRemoved(QtProperty *, QtProperty *))); + q_ptr->disconnect(manager, SIGNAL(propertyDestroyed(QtProperty *)), + q_ptr, SLOT(slotPropertyDestroyed(QtProperty *))); + q_ptr->disconnect(manager, SIGNAL(propertyChanged(QtProperty *)), + q_ptr, SLOT(slotPropertyDataChanged(QtProperty *))); + + m_managerToProperties.remove(manager); + } + + QList<QtProperty *> subList = property->subProperties(); + QListIterator<QtProperty *> itSub(subList); + while (itSub.hasNext()) { + QtProperty *subProperty = itSub.next(); + removeSubTree(subProperty, property); + } +} + +void QtAbstractPropertyBrowserPrivate::createBrowserIndexes(QtProperty *property, QtProperty *parentProperty, QtProperty *afterProperty) +{ + QMap<QtBrowserItem *, QtBrowserItem *> parentToAfter; + if (afterProperty) { + QMap<QtProperty *, QList<QtBrowserItem *> >::ConstIterator it = + m_propertyToIndexes.find(afterProperty); + if (it == m_propertyToIndexes.constEnd()) + return; + + QList<QtBrowserItem *> indexes = it.value(); + QListIterator<QtBrowserItem *> itIndex(indexes); + while (itIndex.hasNext()) { + QtBrowserItem *idx = itIndex.next(); + QtBrowserItem *parentIdx = idx->parent(); + if ((parentProperty && parentIdx && parentIdx->property() == parentProperty) || (!parentProperty && !parentIdx)) + parentToAfter[idx->parent()] = idx; + } + } else if (parentProperty) { + QMap<QtProperty *, QList<QtBrowserItem *> >::ConstIterator it = + m_propertyToIndexes.find(parentProperty); + if (it == m_propertyToIndexes.constEnd()) + return; + + QList<QtBrowserItem *> indexes = it.value(); + QListIterator<QtBrowserItem *> itIndex(indexes); + while (itIndex.hasNext()) { + QtBrowserItem *idx = itIndex.next(); + parentToAfter[idx] = 0; + } + } else { + parentToAfter[0] = 0; + } + + const QMap<QtBrowserItem *, QtBrowserItem *>::ConstIterator pcend = parentToAfter.constEnd(); + for (QMap<QtBrowserItem *, QtBrowserItem *>::ConstIterator it = parentToAfter.constBegin(); it != pcend; ++it) + createBrowserIndex(property, it.key(), it.value()); +} + +QtBrowserItem *QtAbstractPropertyBrowserPrivate::createBrowserIndex(QtProperty *property, + QtBrowserItem *parentIndex, QtBrowserItem *afterIndex) +{ + QtBrowserItem *newIndex = new QtBrowserItem(q_ptr, property, parentIndex); + if (parentIndex) { + parentIndex->d_ptr->addChild(newIndex, afterIndex); + } else { + m_topLevelPropertyToIndex[property] = newIndex; + m_topLevelIndexes.insert(m_topLevelIndexes.indexOf(afterIndex) + 1, newIndex); + } + m_propertyToIndexes[property].append(newIndex); + + q_ptr->itemInserted(newIndex, afterIndex); + + QList<QtProperty *> subItems = property->subProperties(); + QListIterator<QtProperty *> itChild(subItems); + QtBrowserItem *afterChild = 0; + while (itChild.hasNext()) { + QtProperty *child = itChild.next(); + afterChild = createBrowserIndex(child, newIndex, afterChild); + } + return newIndex; +} + +void QtAbstractPropertyBrowserPrivate::removeBrowserIndexes(QtProperty *property, QtProperty *parentProperty) +{ + QList<QtBrowserItem *> toRemove; + QMap<QtProperty *, QList<QtBrowserItem *> >::ConstIterator it = + m_propertyToIndexes.find(property); + if (it == m_propertyToIndexes.constEnd()) + return; + + QList<QtBrowserItem *> indexes = it.value(); + QListIterator<QtBrowserItem *> itIndex(indexes); + while (itIndex.hasNext()) { + QtBrowserItem *idx = itIndex.next(); + QtBrowserItem *parentIdx = idx->parent(); + if ((parentProperty && parentIdx && parentIdx->property() == parentProperty) || (!parentProperty && !parentIdx)) + toRemove.append(idx); + } + + QListIterator<QtBrowserItem *> itRemove(toRemove); + while (itRemove.hasNext()) { + QtBrowserItem *index = itRemove.next(); + removeBrowserIndex(index); + } +} + +void QtAbstractPropertyBrowserPrivate::removeBrowserIndex(QtBrowserItem *index) +{ + QList<QtBrowserItem *> children = index->children(); + for (int i = children.count(); i > 0; i--) { + removeBrowserIndex(children.at(i - 1)); + } + + q_ptr->itemRemoved(index); + + if (index->parent()) { + index->parent()->d_ptr->removeChild(index); + } else { + m_topLevelPropertyToIndex.remove(index->property()); + m_topLevelIndexes.removeAll(index); + } + + QtProperty *property = index->property(); + + m_propertyToIndexes[property].removeAll(index); + if (m_propertyToIndexes[property].isEmpty()) + m_propertyToIndexes.remove(property); + + delete index; +} + +void QtAbstractPropertyBrowserPrivate::clearIndex(QtBrowserItem *index) +{ + QList<QtBrowserItem *> children = index->children(); + QListIterator<QtBrowserItem *> itChild(children); + while (itChild.hasNext()) { + clearIndex(itChild.next()); + } + delete index; +} + +void QtAbstractPropertyBrowserPrivate::slotPropertyInserted(QtProperty *property, + QtProperty *parentProperty, QtProperty *afterProperty) +{ + if (!m_propertyToParents.contains(parentProperty)) + return; + createBrowserIndexes(property, parentProperty, afterProperty); + insertSubTree(property, parentProperty); + //q_ptr->propertyInserted(property, parentProperty, afterProperty); +} + +void QtAbstractPropertyBrowserPrivate::slotPropertyRemoved(QtProperty *property, + QtProperty *parentProperty) +{ + if (!m_propertyToParents.contains(parentProperty)) + return; + removeSubTree(property, parentProperty); // this line should be probably moved down after propertyRemoved call + //q_ptr->propertyRemoved(property, parentProperty); + removeBrowserIndexes(property, parentProperty); +} + +void QtAbstractPropertyBrowserPrivate::slotPropertyDestroyed(QtProperty *property) +{ + if (!m_subItems.contains(property)) + return; + q_ptr->removeProperty(property); +} + +void QtAbstractPropertyBrowserPrivate::slotPropertyDataChanged(QtProperty *property) +{ + if (!m_propertyToParents.contains(property)) + return; + + QMap<QtProperty *, QList<QtBrowserItem *> >::ConstIterator it = + m_propertyToIndexes.find(property); + if (it == m_propertyToIndexes.constEnd()) + return; + + QList<QtBrowserItem *> indexes = it.value(); + QListIterator<QtBrowserItem *> itIndex(indexes); + while (itIndex.hasNext()) { + QtBrowserItem *idx = itIndex.next(); + q_ptr->itemChanged(idx); + } + //q_ptr->propertyChanged(property); +} + +/*! + \class QtAbstractPropertyBrowser + \internal + \inmodule QtDesigner + \since 4.4 + + \brief QtAbstractPropertyBrowser provides a base class for + implementing property browsers. + + A property browser is a widget that enables the user to edit a + given set of properties. Each property is represented by a label + specifying the property's name, and an editing widget (e.g. a line + edit or a combobox) holding its value. A property can have zero or + more subproperties. + + \image qtpropertybrowser.png + + The top level properties can be retrieved using the + properties() function. To traverse each property's + subproperties, use the QtProperty::subProperties() function. In + addition, the set of top level properties can be manipulated using + the addProperty(), insertProperty() and removeProperty() + functions. Note that the QtProperty class provides a corresponding + set of functions making it possible to manipulate the set of + subproperties as well. + + To remove all the properties from the property browser widget, use + the clear() function. This function will clear the editor, but it + will not delete the properties since they can still be used in + other editors. + + The properties themselves are created and managed by + implementations of the QtAbstractPropertyManager class. A manager + can handle (i.e. create and manage) properties of a given type. In + the property browser the managers are associated with + implementations of the QtAbstractEditorFactory: A factory is a + class able to create an editing widget of a specified type. + + When using a property browser widget, managers must be created for + each of the required property types before the properties + themselves can be created. To ensure that the properties' values + will be displayed using suitable editing widgets, the managers + must be associated with objects of the preferred factory + implementations using the setFactoryForManager() function. The + property browser will use these associations to determine which + factory it should use to create the preferred editing widget. + + Note that a factory can be associated with many managers, but a + manager can only be associated with one single factory within the + context of a single property browser. The associations between + managers and factories can at any time be removed using the + unsetFactoryForManager() function. + + Whenever the property data changes or a property is inserted or + removed, the itemChanged(), itemInserted() or + itemRemoved() functions are called, respectively. These + functions must be reimplemented in derived classes in order to + update the property browser widget. Be aware that some property + instances can appear several times in an abstract tree + structure. For example: + + \table 100% + \row + \o + \snippet doc/src/snippets/code/tools_shared_qtpropertybrowser_qtpropertybrowser.cpp 2 + \o \image qtpropertybrowser-duplicate.png + \endtable + + The addProperty() function returns a QtBrowserItem that uniquely + identifies the created item. + + To make a property editable in the property browser, the + createEditor() function must be called to provide the + property with a suitable editing widget. + + Note that there are two ready-made property browser + implementations: + + \list + \o QtGroupBoxPropertyBrowser + \o QtTreePropertyBrowser + \endlist + + \sa QtAbstractPropertyManager, QtAbstractEditorFactoryBase +*/ + +/*! + \fn void QtAbstractPropertyBrowser::setFactoryForManager(PropertyManager *manager, + QtAbstractEditorFactory<PropertyManager> *factory) + + Connects the given \a manager to the given \a factory, ensuring + that properties of the \a manager's type will be displayed with an + editing widget suitable for their value. + + For example: + + \snippet doc/src/snippets/code/tools_shared_qtpropertybrowser_qtpropertybrowser.cpp 3 + + In this example the \c myInteger property's value is displayed + with a QSpinBox widget, while the \c myDouble property's value is + displayed with a QDoubleSpinBox widget. + + Note that a factory can be associated with many managers, but a + manager can only be associated with one single factory. If the + given \a manager already is associated with another factory, the + old association is broken before the new one established. + + This function ensures that the given \a manager and the given \a + factory are compatible, and it automatically calls the + QtAbstractEditorFactory::addPropertyManager() function if necessary. + + \sa unsetFactoryForManager() +*/ + +/*! + \fn virtual void QtAbstractPropertyBrowser::itemInserted(QtBrowserItem *insertedItem, + QtBrowserItem *precedingItem) = 0 + + This function is called to update the widget whenever a property + is inserted or added to the property browser, passing pointers to + the \a insertedItem of property and the specified + \a precedingItem as parameters. + + If \a precedingItem is 0, the \a insertedItem was put at + the beginning of its parent item's list of subproperties. If + the parent of \a insertedItem is 0, the \a insertedItem was added as a top + level property of \e this property browser. + + This function must be reimplemented in derived classes. Note that + if the \a insertedItem's property has subproperties, this + method will be called for those properties as soon as the current call is finished. + + \sa insertProperty(), addProperty() +*/ + +/*! + \fn virtual void QtAbstractPropertyBrowser::itemRemoved(QtBrowserItem *item) = 0 + + This function is called to update the widget whenever a property + is removed from the property browser, passing the pointer to the + \a item of the property as parameters. The passed \a item is + deleted just after this call is finished. + + If the the parent of \a item is 0, the removed \a item was a + top level property in this editor. + + This function must be reimplemented in derived classes. Note that + if the removed \a item's property has subproperties, this + method will be called for those properties just before the current call is started. + + \sa removeProperty() +*/ + +/*! + \fn virtual void QtAbstractPropertyBrowser::itemChanged(QtBrowserItem *item) = 0 + + This function is called whenever a property's data changes, + passing a pointer to the \a item of property as parameter. + + This function must be reimplemented in derived classes in order to + update the property browser widget whenever a property's name, + tool tip, status tip, "what's this" text, value text or value icon + changes. + + Note that if the property browser contains several occurrences of + the same property, this method will be called once for each + occurrence (with a different item each time). + + \sa QtProperty, items() +*/ + +/*! + Creates an abstract property browser with the given \a parent. +*/ +QtAbstractPropertyBrowser::QtAbstractPropertyBrowser(QWidget *parent) + : QWidget(parent) +{ + d_ptr = new QtAbstractPropertyBrowserPrivate; + d_ptr->q_ptr = this; + +} + +/*! + Destroys the property browser, and destroys all the items that were + created by this property browser. + + Note that the properties that were displayed in the editor are not + deleted since they still can be used in other editors. Neither + does the destructor delete the property managers and editor + factories that were used by this property browser widget unless + this widget was their parent. + + \sa QtAbstractPropertyManager::~QtAbstractPropertyManager() +*/ +QtAbstractPropertyBrowser::~QtAbstractPropertyBrowser() +{ + QList<QtBrowserItem *> indexes = topLevelItems(); + QListIterator<QtBrowserItem *> itItem(indexes); + while (itItem.hasNext()) + d_ptr->clearIndex(itItem.next()); + delete d_ptr; +} + +/*! + Returns the property browser's list of top level properties. + + To traverse the subproperties, use the QtProperty::subProperties() + function. + + \sa addProperty(), insertProperty(), removeProperty() +*/ +QList<QtProperty *> QtAbstractPropertyBrowser::properties() const +{ + return d_ptr->m_subItems; +} + +/*! + Returns the property browser's list of all items associated + with the given \a property. + + There is one item per instance of the property in the browser. + + \sa topLevelItem() +*/ + +QList<QtBrowserItem *> QtAbstractPropertyBrowser::items(QtProperty *property) const +{ + return d_ptr->m_propertyToIndexes.value(property); +} + +/*! + Returns the top-level items associated with the given \a property. + + Returns 0 if \a property wasn't inserted into this property + browser or isn't a top-level one. + + \sa topLevelItems(), items() +*/ + +QtBrowserItem *QtAbstractPropertyBrowser::topLevelItem(QtProperty *property) const +{ + return d_ptr->m_topLevelPropertyToIndex.value(property); +} + +/*! + Returns the list of top-level items. + + \sa topLevelItem() +*/ + +QList<QtBrowserItem *> QtAbstractPropertyBrowser::topLevelItems() const +{ + return d_ptr->m_topLevelIndexes; +} + +/*! + Removes all the properties from the editor, but does not delete + them since they can still be used in other editors. + + \sa removeProperty(), QtAbstractPropertyManager::clear() +*/ +void QtAbstractPropertyBrowser::clear() +{ + QList<QtProperty *> subList = properties(); + QListIterator<QtProperty *> itSub(subList); + itSub.toBack(); + while (itSub.hasPrevious()) { + QtProperty *property = itSub.previous(); + removeProperty(property); + } +} + +/*! + Appends the given \a property (and its subproperties) to the + property browser's list of top level properties. Returns the item + created by property browser which is associated with the \a property. + In order to get all children items created by the property + browser in this call, the returned item should be traversed. + + If the specified \a property is already added, this function does + nothing and returns 0. + + \sa insertProperty(), QtProperty::addSubProperty(), properties() +*/ +QtBrowserItem *QtAbstractPropertyBrowser::addProperty(QtProperty *property) +{ + QtProperty *afterProperty = 0; + if (d_ptr->m_subItems.count() > 0) + afterProperty = d_ptr->m_subItems.last(); + return insertProperty(property, afterProperty); +} + +/*! + \fn QtBrowserItem *QtAbstractPropertyBrowser::insertProperty(QtProperty *property, + QtProperty *afterProperty) + + Inserts the given \a property (and its subproperties) after + the specified \a afterProperty in the browser's list of top + level properties. Returns item created by property browser which + is associated with the \a property. In order to get all children items + created by the property browser in this call returned item should be traversed. + + If the specified \a afterProperty is 0, the given \a property is + inserted at the beginning of the list. If \a property is + already inserted, this function does nothing and returns 0. + + \sa addProperty(), QtProperty::insertSubProperty(), properties() +*/ +QtBrowserItem *QtAbstractPropertyBrowser::insertProperty(QtProperty *property, + QtProperty *afterProperty) +{ + if (!property) + return 0; + + // if item is already inserted in this item then cannot add. + QList<QtProperty *> pendingList = properties(); + int pos = 0; + int newPos = 0; + QtProperty *properAfterProperty = 0; + while (pos < pendingList.count()) { + QtProperty *prop = pendingList.at(pos); + if (prop == property) + return 0; + if (prop == afterProperty) { + newPos = pos + 1; + properAfterProperty = afterProperty; + } + pos++; + } + d_ptr->createBrowserIndexes(property, 0, afterProperty); + + // traverse inserted subtree and connect to manager's signals + d_ptr->insertSubTree(property, 0); + + d_ptr->m_subItems.insert(newPos, property); + //propertyInserted(property, 0, properAfterProperty); + return topLevelItem(property); +} + +/*! + Removes the specified \a property (and its subproperties) from the + property browser's list of top level properties. All items + that were associated with the given \a property and its children + are deleted. + + Note that the properties are \e not deleted since they can still + be used in other editors. + + \sa clear(), QtProperty::removeSubProperty(), properties() +*/ +void QtAbstractPropertyBrowser::removeProperty(QtProperty *property) +{ + if (!property) + return; + + QList<QtProperty *> pendingList = properties(); + int pos = 0; + while (pos < pendingList.count()) { + if (pendingList.at(pos) == property) { + d_ptr->m_subItems.removeAt(pos); //perhaps this two lines + d_ptr->removeSubTree(property, 0); //should be moved down after propertyRemoved call. + //propertyRemoved(property, 0); + + d_ptr->removeBrowserIndexes(property, 0); + + // when item is deleted, item will call removeItem for top level items, + // and itemRemoved for nested items. + + return; + } + pos++; + } +} + +/*! + Creates an editing widget (with the given \a parent) for the given + \a property according to the previously established associations + between property managers and editor factories. + + If the property is created by a property manager which was not + associated with any of the existing factories in \e this property + editor, the function returns 0. + + To make a property editable in the property browser, the + createEditor() function must be called to provide the + property with a suitable editing widget. + + Reimplement this function to provide additional decoration for the + editing widgets created by the installed factories. + + \sa setFactoryForManager() +*/ +QWidget *QtAbstractPropertyBrowser::createEditor(QtProperty *property, + QWidget *parent) +{ + QtAbstractEditorFactoryBase *factory = 0; + QtAbstractPropertyManager *manager = property->propertyManager(); + + if (m_viewToManagerToFactory()->contains(this) && + (*m_viewToManagerToFactory())[this].contains(manager)) { + factory = (*m_viewToManagerToFactory())[this][manager]; + } + + if (!factory) + return 0; + return factory->createEditor(property, parent); +} + +bool QtAbstractPropertyBrowser::addFactory(QtAbstractPropertyManager *abstractManager, + QtAbstractEditorFactoryBase *abstractFactory) +{ + bool connectNeeded = false; + if (!m_managerToFactoryToViews()->contains(abstractManager) || + !(*m_managerToFactoryToViews())[abstractManager].contains(abstractFactory)) { + connectNeeded = true; + } else if ((*m_managerToFactoryToViews())[abstractManager][abstractFactory] + .contains(this)) { + return connectNeeded; + } + + if (m_viewToManagerToFactory()->contains(this) && + (*m_viewToManagerToFactory())[this].contains(abstractManager)) { + unsetFactoryForManager(abstractManager); + } + + (*m_managerToFactoryToViews())[abstractManager][abstractFactory].append(this); + (*m_viewToManagerToFactory())[this][abstractManager] = abstractFactory; + + return connectNeeded; +} + +/*! + Removes the association between the given \a manager and the + factory bound to it, automatically calling the + QtAbstractEditorFactory::removePropertyManager() function if necessary. + + \sa setFactoryForManager() +*/ +void QtAbstractPropertyBrowser::unsetFactoryForManager(QtAbstractPropertyManager *manager) +{ + if (!m_viewToManagerToFactory()->contains(this) || + !(*m_viewToManagerToFactory())[this].contains(manager)) { + return; + } + + QtAbstractEditorFactoryBase *abstractFactory = + (*m_viewToManagerToFactory())[this][manager]; + (*m_viewToManagerToFactory())[this].remove(manager); + if ((*m_viewToManagerToFactory())[this].isEmpty()) { + (*m_viewToManagerToFactory()).remove(this); + } + + (*m_managerToFactoryToViews())[manager][abstractFactory].removeAll(this); + if ((*m_managerToFactoryToViews())[manager][abstractFactory].isEmpty()) { + (*m_managerToFactoryToViews())[manager].remove(abstractFactory); + abstractFactory->breakConnection(manager); + if ((*m_managerToFactoryToViews())[manager].isEmpty()) { + (*m_managerToFactoryToViews()).remove(manager); + } + } +} + +/*! + Returns the current item in the property browser. + + \sa setCurrentItem() +*/ +QtBrowserItem *QtAbstractPropertyBrowser::currentItem() const +{ + return d_ptr->m_currentItem; +} + +/*! + Sets the current item in the property browser to \a item. + + \sa currentItem(), currentItemChanged() +*/ +void QtAbstractPropertyBrowser::setCurrentItem(QtBrowserItem *item) +{ + QtBrowserItem *oldItem = d_ptr->m_currentItem; + d_ptr->m_currentItem = item; + if (oldItem != item) + emit currentItemChanged(item); +} + +#if QT_VERSION >= 0x040400 +QT_END_NAMESPACE +#endif + +#include "moc_qtpropertybrowser.cpp" diff --git a/tools/shared/qtpropertybrowser/qtpropertybrowser.h b/tools/shared/qtpropertybrowser/qtpropertybrowser.h new file mode 100644 index 0000000..649a9e3 --- /dev/null +++ b/tools/shared/qtpropertybrowser/qtpropertybrowser.h @@ -0,0 +1,315 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the tools applications of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QTPROPERTYBROWSER_H +#define QTPROPERTYBROWSER_H + +#include <QtGui/QWidget> +#include <QtCore/QSet> + +#if QT_VERSION >= 0x040400 +QT_BEGIN_NAMESPACE +#endif + + + +class QtAbstractPropertyManager; +class QtPropertyPrivate; + +class QtProperty +{ +public: + virtual ~QtProperty(); + + QList<QtProperty *> subProperties() const; + + QtAbstractPropertyManager *propertyManager() const; + + QString toolTip() const; + QString statusTip() const; + QString whatsThis() const; + QString propertyName() const; + bool isEnabled() const; + bool isModified() const; + + bool hasValue() const; + QIcon valueIcon() const; + QString valueText() const; + + void setToolTip(const QString &text); + void setStatusTip(const QString &text); + void setWhatsThis(const QString &text); + void setPropertyName(const QString &text); + void setEnabled(bool enable); + void setModified(bool modified); + + void addSubProperty(QtProperty *property); + void insertSubProperty(QtProperty *property, QtProperty *afterProperty); + void removeSubProperty(QtProperty *property); +protected: + explicit QtProperty(QtAbstractPropertyManager *manager); + void propertyChanged(); +private: + friend class QtAbstractPropertyManager; + QtPropertyPrivate *d_ptr; +}; + +class QtAbstractPropertyManagerPrivate; + +class QtAbstractPropertyManager : public QObject +{ + Q_OBJECT +public: + + explicit QtAbstractPropertyManager(QObject *parent = 0); + ~QtAbstractPropertyManager(); + + QSet<QtProperty *> properties() const; + void clear() const; + + QtProperty *addProperty(const QString &name = QString()); +Q_SIGNALS: + + void propertyInserted(QtProperty *property, + QtProperty *parent, QtProperty *after); + void propertyChanged(QtProperty *property); + void propertyRemoved(QtProperty *property, QtProperty *parent); + void propertyDestroyed(QtProperty *property); +protected: + virtual bool hasValue(const QtProperty *property) const; + virtual QIcon valueIcon(const QtProperty *property) const; + virtual QString valueText(const QtProperty *property) const; + virtual void initializeProperty(QtProperty *property) = 0; + virtual void uninitializeProperty(QtProperty *property); + virtual QtProperty *createProperty(); +private: + friend class QtProperty; + QtAbstractPropertyManagerPrivate *d_ptr; + Q_DECLARE_PRIVATE(QtAbstractPropertyManager) + Q_DISABLE_COPY(QtAbstractPropertyManager) +}; + +class QtAbstractEditorFactoryBase : public QObject +{ + Q_OBJECT +public: + virtual QWidget *createEditor(QtProperty *property, QWidget *parent) = 0; +protected: + explicit QtAbstractEditorFactoryBase(QObject *parent = 0) + : QObject(parent) {} + + virtual void breakConnection(QtAbstractPropertyManager *manager) = 0; +protected Q_SLOTS: + virtual void managerDestroyed(QObject *manager) = 0; + + friend class QtAbstractPropertyBrowser; +}; + +template <class PropertyManager> +class QtAbstractEditorFactory : public QtAbstractEditorFactoryBase +{ +public: + explicit QtAbstractEditorFactory(QObject *parent) : QtAbstractEditorFactoryBase(parent) {} + QWidget *createEditor(QtProperty *property, QWidget *parent) + { + QSetIterator<PropertyManager *> it(m_managers); + while (it.hasNext()) { + PropertyManager *manager = it.next(); + if (manager == property->propertyManager()) { + return createEditor(manager, property, parent); + } + } + return 0; + } + void addPropertyManager(PropertyManager *manager) + { + if (m_managers.contains(manager)) + return; + m_managers.insert(manager); + connectPropertyManager(manager); + connect(manager, SIGNAL(destroyed(QObject *)), + this, SLOT(managerDestroyed(QObject *))); + } + void removePropertyManager(PropertyManager *manager) + { + if (!m_managers.contains(manager)) + return; + disconnect(manager, SIGNAL(destroyed(QObject *)), + this, SLOT(managerDestroyed(QObject *))); + disconnectPropertyManager(manager); + m_managers.remove(manager); + } + QSet<PropertyManager *> propertyManagers() const + { + return m_managers; + } + PropertyManager *propertyManager(QtProperty *property) const + { + QtAbstractPropertyManager *manager = property->propertyManager(); + QSetIterator<PropertyManager *> itManager(m_managers); + while (itManager.hasNext()) { + PropertyManager *m = itManager.next(); + if (m == manager) { + return m; + } + } + return 0; + } +protected: + virtual void connectPropertyManager(PropertyManager *manager) = 0; + virtual QWidget *createEditor(PropertyManager *manager, QtProperty *property, + QWidget *parent) = 0; + virtual void disconnectPropertyManager(PropertyManager *manager) = 0; + void managerDestroyed(QObject *manager) + { + QSetIterator<PropertyManager *> it(m_managers); + while (it.hasNext()) { + PropertyManager *m = it.next(); + if (m == manager) { + m_managers.remove(m); + return; + } + } + } +private: + void breakConnection(QtAbstractPropertyManager *manager) + { + QSetIterator<PropertyManager *> it(m_managers); + while (it.hasNext()) { + PropertyManager *m = it.next(); + if (m == manager) { + removePropertyManager(m); + return; + } + } + } +private: + QSet<PropertyManager *> m_managers; + friend class QtAbstractPropertyEditor; +}; + +class QtAbstractPropertyBrowser; +class QtBrowserItemPrivate; + +class QtBrowserItem +{ +public: + QtProperty *property() const; + QtBrowserItem *parent() const; + QList<QtBrowserItem *> children() const; + QtAbstractPropertyBrowser *browser() const; +private: + explicit QtBrowserItem(QtAbstractPropertyBrowser *browser, QtProperty *property, QtBrowserItem *parent); + ~QtBrowserItem(); + QtBrowserItemPrivate *d_ptr; + friend class QtAbstractPropertyBrowserPrivate; +}; + +class QtAbstractPropertyBrowserPrivate; + +class QtAbstractPropertyBrowser : public QWidget +{ + Q_OBJECT +public: + + explicit QtAbstractPropertyBrowser(QWidget *parent = 0); + ~QtAbstractPropertyBrowser(); + + QList<QtProperty *> properties() const; + QList<QtBrowserItem *> items(QtProperty *property) const; + QtBrowserItem *topLevelItem(QtProperty *property) const; + QList<QtBrowserItem *> topLevelItems() const; + void clear(); + + template <class PropertyManager> + void setFactoryForManager(PropertyManager *manager, + QtAbstractEditorFactory<PropertyManager> *factory) { + QtAbstractPropertyManager *abstractManager = manager; + QtAbstractEditorFactoryBase *abstractFactory = factory; + + if (addFactory(abstractManager, abstractFactory)) + factory->addPropertyManager(manager); + } + + void unsetFactoryForManager(QtAbstractPropertyManager *manager); + + QtBrowserItem *currentItem() const; + void setCurrentItem(QtBrowserItem *); + +Q_SIGNALS: + void currentItemChanged(QtBrowserItem *); + +public Q_SLOTS: + + QtBrowserItem *addProperty(QtProperty *property); + QtBrowserItem *insertProperty(QtProperty *property, QtProperty *afterProperty); + void removeProperty(QtProperty *property); + +protected: + + virtual void itemInserted(QtBrowserItem *item, QtBrowserItem *afterItem) = 0; + virtual void itemRemoved(QtBrowserItem *item) = 0; + // can be tooltip, statustip, whatsthis, name, icon, text. + virtual void itemChanged(QtBrowserItem *item) = 0; + + virtual QWidget *createEditor(QtProperty *property, QWidget *parent); +private: + + bool addFactory(QtAbstractPropertyManager *abstractManager, + QtAbstractEditorFactoryBase *abstractFactory); + + QtAbstractPropertyBrowserPrivate *d_ptr; + Q_DECLARE_PRIVATE(QtAbstractPropertyBrowser) + Q_DISABLE_COPY(QtAbstractPropertyBrowser) + Q_PRIVATE_SLOT(d_func(), void slotPropertyInserted(QtProperty *, + QtProperty *, QtProperty *)) + Q_PRIVATE_SLOT(d_func(), void slotPropertyRemoved(QtProperty *, + QtProperty *)) + Q_PRIVATE_SLOT(d_func(), void slotPropertyDestroyed(QtProperty *)) + Q_PRIVATE_SLOT(d_func(), void slotPropertyDataChanged(QtProperty *)) + +}; + +#if QT_VERSION >= 0x040400 +QT_END_NAMESPACE +#endif + +#endif // QTPROPERTYBROWSER_H diff --git a/tools/shared/qtpropertybrowser/qtpropertybrowser.pri b/tools/shared/qtpropertybrowser/qtpropertybrowser.pri new file mode 100644 index 0000000..85c2b8d --- /dev/null +++ b/tools/shared/qtpropertybrowser/qtpropertybrowser.pri @@ -0,0 +1,19 @@ +INCLUDEPATH += $$PWD +DEPENDPATH += $$PWD +SOURCES += $$PWD/qtpropertybrowser.cpp \ + $$PWD/qtpropertymanager.cpp \ + $$PWD/qteditorfactory.cpp \ + $$PWD/qtvariantproperty.cpp \ + $$PWD/qttreepropertybrowser.cpp \ + $$PWD/qtbuttonpropertybrowser.cpp \ + $$PWD/qtgroupboxpropertybrowser.cpp \ + $$PWD/qtpropertybrowserutils.cpp +HEADERS += $$PWD/qtpropertybrowser.h \ + $$PWD/qtpropertymanager.h \ + $$PWD/qteditorfactory.h \ + $$PWD/qtvariantproperty.h \ + $$PWD/qttreepropertybrowser.h \ + $$PWD/qtbuttonpropertybrowser.h \ + $$PWD/qtgroupboxpropertybrowser.h \ + $$PWD/qtpropertybrowserutils_p.h +RESOURCES += $$PWD/qtpropertybrowser.qrc diff --git a/tools/shared/qtpropertybrowser/qtpropertybrowser.qrc b/tools/shared/qtpropertybrowser/qtpropertybrowser.qrc new file mode 100644 index 0000000..4f91ab7 --- /dev/null +++ b/tools/shared/qtpropertybrowser/qtpropertybrowser.qrc @@ -0,0 +1,23 @@ +<RCC version="1.0"> + <qresource prefix="/trolltech/qtpropertybrowser"> + <file>images/cursor-arrow.png</file> + <file>images/cursor-busy.png</file> + <file>images/cursor-closedhand.png</file> + <file>images/cursor-cross.png</file> + <file>images/cursor-forbidden.png</file> + <file>images/cursor-hand.png</file> + <file>images/cursor-hsplit.png</file> + <file>images/cursor-ibeam.png</file> + <file>images/cursor-openhand.png</file> + <file>images/cursor-sizeall.png</file> + <file>images/cursor-sizeb.png</file> + <file>images/cursor-sizef.png</file> + <file>images/cursor-sizeh.png</file> + <file>images/cursor-sizev.png</file> + <file>images/cursor-uparrow.png</file> + <file>images/cursor-vsplit.png</file> + <file>images/cursor-wait.png</file> + <file>images/cursor-whatsthis.png</file> + </qresource> +</RCC> + diff --git a/tools/shared/qtpropertybrowser/qtpropertybrowserutils.cpp b/tools/shared/qtpropertybrowser/qtpropertybrowserutils.cpp new file mode 100644 index 0000000..d689e60 --- /dev/null +++ b/tools/shared/qtpropertybrowser/qtpropertybrowserutils.cpp @@ -0,0 +1,434 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the tools applications of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qtpropertybrowserutils_p.h" +#include <QtGui/QApplication> +#include <QtGui/QPainter> +#include <QtGui/QHBoxLayout> +#include <QtGui/QMouseEvent> +#include <QtGui/QCheckBox> +#include <QtGui/QLineEdit> +#include <QtGui/QMenu> + +#if QT_VERSION >= 0x040400 +QT_BEGIN_NAMESPACE +#endif + +QtCursorDatabase::QtCursorDatabase() +{ + appendCursor(Qt::ArrowCursor, QApplication::translate("QtCursorDatabase", "Arrow", 0, + QApplication::UnicodeUTF8), QIcon(QLatin1String(":/trolltech/qtpropertybrowser/images/cursor-arrow.png"))); + appendCursor(Qt::UpArrowCursor, QApplication::translate("QtCursorDatabase", "Up Arrow", 0, + QApplication::UnicodeUTF8), QIcon(QLatin1String(":/trolltech/qtpropertybrowser/images/cursor-uparrow.png"))); + appendCursor(Qt::CrossCursor, QApplication::translate("QtCursorDatabase", "Cross", 0, + QApplication::UnicodeUTF8), QIcon(QLatin1String(":/trolltech/qtpropertybrowser/images/cursor-cross.png"))); + appendCursor(Qt::WaitCursor, QApplication::translate("QtCursorDatabase", "Wait", 0, + QApplication::UnicodeUTF8), QIcon(QLatin1String(":/trolltech/qtpropertybrowser/images/cursor-wait.png"))); + appendCursor(Qt::IBeamCursor, QApplication::translate("QtCursorDatabase", "IBeam", 0, + QApplication::UnicodeUTF8), QIcon(QLatin1String(":/trolltech/qtpropertybrowser/images/cursor-ibeam.png"))); + appendCursor(Qt::SizeVerCursor, QApplication::translate("QtCursorDatabase", "Size Vertical", 0, + QApplication::UnicodeUTF8), QIcon(QLatin1String(":/trolltech/qtpropertybrowser/images/cursor-sizev.png"))); + appendCursor(Qt::SizeHorCursor, QApplication::translate("QtCursorDatabase", "Size Horizontal", 0, + QApplication::UnicodeUTF8), QIcon(QLatin1String(":/trolltech/qtpropertybrowser/images/cursor-sizeh.png"))); + appendCursor(Qt::SizeFDiagCursor, QApplication::translate("QtCursorDatabase", "Size Backslash", 0, + QApplication::UnicodeUTF8), QIcon(QLatin1String(":/trolltech/qtpropertybrowser/images/cursor-sizef.png"))); + appendCursor(Qt::SizeBDiagCursor, QApplication::translate("QtCursorDatabase", "Size Slash", 0, + QApplication::UnicodeUTF8), QIcon(QLatin1String(":/trolltech/qtpropertybrowser/images/cursor-sizeb.png"))); + appendCursor(Qt::SizeAllCursor, QApplication::translate("QtCursorDatabase", "Size All", 0, + QApplication::UnicodeUTF8), QIcon(QLatin1String(":/trolltech/qtpropertybrowser/images/cursor-sizeall.png"))); + appendCursor(Qt::BlankCursor, QApplication::translate("QtCursorDatabase", "Blank", 0, + QApplication::UnicodeUTF8), QIcon()); + appendCursor(Qt::SplitVCursor, QApplication::translate("QtCursorDatabase", "Split Vertical", 0, + QApplication::UnicodeUTF8), QIcon(QLatin1String(":/trolltech/qtpropertybrowser/images/cursor-vsplit.png"))); + appendCursor(Qt::SplitHCursor, QApplication::translate("QtCursorDatabase", "Split Horizontal", 0, + QApplication::UnicodeUTF8), QIcon(QLatin1String(":/trolltech/qtpropertybrowser/images/cursor-hsplit.png"))); + appendCursor(Qt::PointingHandCursor, QApplication::translate("QtCursorDatabase", "Pointing Hand", 0, + QApplication::UnicodeUTF8), QIcon(QLatin1String(":/trolltech/qtpropertybrowser/images/cursor-hand.png"))); + appendCursor(Qt::ForbiddenCursor, QApplication::translate("QtCursorDatabase", "Forbidden", 0, + QApplication::UnicodeUTF8), QIcon(QLatin1String(":/trolltech/qtpropertybrowser/images/cursor-forbidden.png"))); + appendCursor(Qt::OpenHandCursor, QApplication::translate("QtCursorDatabase", "Open Hand", 0, + QApplication::UnicodeUTF8), QIcon(QLatin1String(":/trolltech/qtpropertybrowser/images/cursor-openhand.png"))); + appendCursor(Qt::ClosedHandCursor, QApplication::translate("QtCursorDatabase", "Closed Hand", 0, + QApplication::UnicodeUTF8), QIcon(QLatin1String(":/trolltech/qtpropertybrowser/images/cursor-closedhand.png"))); + appendCursor(Qt::WhatsThisCursor, QApplication::translate("QtCursorDatabase", "What's This", 0, + QApplication::UnicodeUTF8), QIcon(QLatin1String(":/trolltech/qtpropertybrowser/images/cursor-whatsthis.png"))); + appendCursor(Qt::BusyCursor, QApplication::translate("QtCursorDatabase", "Busy", 0, + QApplication::UnicodeUTF8), QIcon(QLatin1String(":/trolltech/qtpropertybrowser/images/cursor-busy.png"))); +} + +void QtCursorDatabase::appendCursor(Qt::CursorShape shape, const QString &name, const QIcon &icon) +{ + if (m_cursorShapeToValue.contains(shape)) + return; + int value = m_cursorNames.count(); + m_cursorNames.append(name); + m_cursorIcons[value] = icon; + m_valueToCursorShape[value] = shape; + m_cursorShapeToValue[shape] = value; +} + +QStringList QtCursorDatabase::cursorShapeNames() const +{ + return m_cursorNames; +} + +QMap<int, QIcon> QtCursorDatabase::cursorShapeIcons() const +{ + return m_cursorIcons; +} + +QString QtCursorDatabase::cursorToShapeName(const QCursor &cursor) const +{ + int val = cursorToValue(cursor); + if (val >= 0) + return m_cursorNames.at(val); + return QString(); +} + +QIcon QtCursorDatabase::cursorToShapeIcon(const QCursor &cursor) const +{ + int val = cursorToValue(cursor); + return m_cursorIcons.value(val); +} + +int QtCursorDatabase::cursorToValue(const QCursor &cursor) const +{ +#ifndef QT_NO_CURSOR + Qt::CursorShape shape = cursor.shape(); + if (m_cursorShapeToValue.contains(shape)) + return m_cursorShapeToValue[shape]; +#endif + return -1; +} + +#ifndef QT_NO_CURSOR +QCursor QtCursorDatabase::valueToCursor(int value) const +{ + if (m_valueToCursorShape.contains(value)) + return QCursor(m_valueToCursorShape[value]); + return QCursor(); +} +#endif + +QPixmap QtPropertyBrowserUtils::brushValuePixmap(const QBrush &b) +{ + QImage img(16, 16, QImage::Format_ARGB32_Premultiplied); + img.fill(0); + + QPainter painter(&img); + painter.setCompositionMode(QPainter::CompositionMode_Source); + painter.fillRect(0, 0, img.width(), img.height(), b); + QColor color = b.color(); + if (color.alpha() != 255) { // indicate alpha by an inset + QBrush opaqueBrush = b; + color.setAlpha(255); + opaqueBrush.setColor(color); + painter.fillRect(img.width() / 4, img.height() / 4, + img.width() / 2, img.height() / 2, opaqueBrush); + } + painter.end(); + return QPixmap::fromImage(img); +} + +QIcon QtPropertyBrowserUtils::brushValueIcon(const QBrush &b) +{ + return QIcon(brushValuePixmap(b)); +} + +QString QtPropertyBrowserUtils::colorValueText(const QColor &c) +{ + return QApplication::translate("QtPropertyBrowserUtils", "[%1, %2, %3] (%4)", 0, QApplication::UnicodeUTF8) + .arg(QString::number(c.red())) + .arg(QString::number(c.green())) + .arg(QString::number(c.blue())) + .arg(QString::number(c.alpha())); +} + +QPixmap QtPropertyBrowserUtils::fontValuePixmap(const QFont &font) +{ + QFont f = font; + QImage img(16, 16, QImage::Format_ARGB32_Premultiplied); + img.fill(0); + QPainter p(&img); + p.setRenderHint(QPainter::TextAntialiasing, true); + p.setRenderHint(QPainter::Antialiasing, true); + f.setPointSize(13); + p.setFont(f); + QTextOption t; + t.setAlignment(Qt::AlignCenter); + p.drawText(QRect(0, 0, 16, 16), QString(QLatin1Char('A')), t); + return QPixmap::fromImage(img); +} + +QIcon QtPropertyBrowserUtils::fontValueIcon(const QFont &f) +{ + return QIcon(fontValuePixmap(f)); +} + +QString QtPropertyBrowserUtils::fontValueText(const QFont &f) +{ + return QApplication::translate("QtPropertyBrowserUtils", "[%1, %2]", 0, QApplication::UnicodeUTF8) + .arg(f.family()) + .arg(f.pointSize()); +} + + +QtBoolEdit::QtBoolEdit(QWidget *parent) : + QWidget(parent), + m_checkBox(new QCheckBox(this)), + m_textVisible(true) +{ + QHBoxLayout *lt = new QHBoxLayout; + if (QApplication::layoutDirection() == Qt::LeftToRight) + lt->setContentsMargins(4, 0, 0, 0); + else + lt->setContentsMargins(0, 0, 4, 0); + lt->addWidget(m_checkBox); + setLayout(lt); + connect(m_checkBox, SIGNAL(toggled(bool)), this, SIGNAL(toggled(bool))); + setFocusProxy(m_checkBox); + m_checkBox->setText(tr("True")); +} + +void QtBoolEdit::setTextVisible(bool textVisible) +{ + if (m_textVisible == textVisible) + return; + + m_textVisible = textVisible; + if (m_textVisible) + m_checkBox->setText(isChecked() ? tr("True") : tr("False")); + else + m_checkBox->setText(QString()); +} + +Qt::CheckState QtBoolEdit::checkState() const +{ + return m_checkBox->checkState(); +} + +void QtBoolEdit::setCheckState(Qt::CheckState state) +{ + m_checkBox->setCheckState(state); +} + +bool QtBoolEdit::isChecked() const +{ + return m_checkBox->isChecked(); +} + +void QtBoolEdit::setChecked(bool c) +{ + m_checkBox->setChecked(c); + if (!m_textVisible) + return; + m_checkBox->setText(isChecked() ? tr("True") : tr("False")); +} + +bool QtBoolEdit::blockCheckBoxSignals(bool block) +{ + return m_checkBox->blockSignals(block); +} + +void QtBoolEdit::mousePressEvent(QMouseEvent *event) +{ + if (event->buttons() == Qt::LeftButton) { + m_checkBox->click(); + event->accept(); + } else { + QWidget::mousePressEvent(event); + } +} + + +QtKeySequenceEdit::QtKeySequenceEdit(QWidget *parent) + : QWidget(parent), m_num(0), m_lineEdit(new QLineEdit(this)) +{ + QHBoxLayout *layout = new QHBoxLayout(this); + layout->addWidget(m_lineEdit); + layout->setMargin(0); + m_lineEdit->installEventFilter(this); + m_lineEdit->setReadOnly(true); + m_lineEdit->setFocusProxy(this); + setFocusPolicy(m_lineEdit->focusPolicy()); + setAttribute(Qt::WA_InputMethodEnabled); +} + +bool QtKeySequenceEdit::eventFilter(QObject *o, QEvent *e) +{ + if (o == m_lineEdit && e->type() == QEvent::ContextMenu) { + QContextMenuEvent *c = static_cast<QContextMenuEvent *>(e); + QMenu *menu = m_lineEdit->createStandardContextMenu(); + const QList<QAction *> actions = menu->actions(); + QListIterator<QAction *> itAction(actions); + while (itAction.hasNext()) { + QAction *action = itAction.next(); + action->setShortcut(QKeySequence()); + QString actionString = action->text(); + const int pos = actionString.lastIndexOf(QLatin1Char('\t')); + if (pos > 0) + actionString.remove(pos, actionString.length() - pos); + action->setText(actionString); + } + QAction *actionBefore = 0; + if (actions.count() > 0) + actionBefore = actions[0]; + QAction *clearAction = new QAction(tr("Clear Shortcut"), menu); + menu->insertAction(actionBefore, clearAction); + menu->insertSeparator(actionBefore); + clearAction->setEnabled(!m_keySequence.isEmpty()); + connect(clearAction, SIGNAL(triggered()), this, SLOT(slotClearShortcut())); + menu->exec(c->globalPos()); + delete menu; + e->accept(); + return true; + } + + return QWidget::eventFilter(o, e); +} + +void QtKeySequenceEdit::slotClearShortcut() +{ + if (m_keySequence.isEmpty()) + return; + setKeySequence(QKeySequence()); + emit keySequenceChanged(m_keySequence); +} + +void QtKeySequenceEdit::handleKeyEvent(QKeyEvent *e) +{ + int nextKey = e->key(); + if (nextKey == Qt::Key_Control || nextKey == Qt::Key_Shift || + nextKey == Qt::Key_Meta || nextKey == Qt::Key_Alt || + nextKey == Qt::Key_Super_L || nextKey == Qt::Key_AltGr) + return; + + nextKey |= translateModifiers(e->modifiers(), e->text()); + int k0 = m_keySequence[0]; + int k1 = m_keySequence[1]; + int k2 = m_keySequence[2]; + int k3 = m_keySequence[3]; + switch (m_num) { + case 0: k0 = nextKey; k1 = 0; k2 = 0; k3 = 0; break; + case 1: k1 = nextKey; k2 = 0; k3 = 0; break; + case 2: k2 = nextKey; k3 = 0; break; + case 3: k3 = nextKey; break; + default: break; + } + ++m_num; + if (m_num > 3) + m_num = 0; + m_keySequence = QKeySequence(k0, k1, k2, k3); + m_lineEdit->setText(m_keySequence.toString(QKeySequence::NativeText)); + e->accept(); + emit keySequenceChanged(m_keySequence); +} + +void QtKeySequenceEdit::setKeySequence(const QKeySequence &sequence) +{ + if (sequence == m_keySequence) + return; + m_num = 0; + m_keySequence = sequence; + m_lineEdit->setText(m_keySequence.toString(QKeySequence::NativeText)); +} + +QKeySequence QtKeySequenceEdit::keySequence() const +{ + return m_keySequence; +} + +int QtKeySequenceEdit::translateModifiers(Qt::KeyboardModifiers state, const QString &text) const +{ + int result = 0; + if ((state & Qt::ShiftModifier) && (text.size() == 0 || !text.at(0).isPrint() || text.at(0).isLetter() || text.at(0).isSpace())) + result |= Qt::SHIFT; + if (state & Qt::ControlModifier) + result |= Qt::CTRL; + if (state & Qt::MetaModifier) + result |= Qt::META; + if (state & Qt::AltModifier) + result |= Qt::ALT; + return result; +} + +void QtKeySequenceEdit::focusInEvent(QFocusEvent *e) +{ + m_lineEdit->event(e); + m_lineEdit->selectAll(); + QWidget::focusInEvent(e); +} + +void QtKeySequenceEdit::focusOutEvent(QFocusEvent *e) +{ + m_num = 0; + m_lineEdit->event(e); + QWidget::focusOutEvent(e); +} + +void QtKeySequenceEdit::keyPressEvent(QKeyEvent *e) +{ + handleKeyEvent(e); + e->accept(); +} + +void QtKeySequenceEdit::keyReleaseEvent(QKeyEvent *e) +{ + m_lineEdit->event(e); +} + +bool QtKeySequenceEdit::event(QEvent *e) +{ + if (e->type() == QEvent::Shortcut || + e->type() == QEvent::ShortcutOverride || + e->type() == QEvent::KeyRelease) { + e->accept(); + return true; + } + return QWidget::event(e); +} + + + + +#if QT_VERSION >= 0x040400 +QT_END_NAMESPACE +#endif diff --git a/tools/shared/qtpropertybrowser/qtpropertybrowserutils_p.h b/tools/shared/qtpropertybrowser/qtpropertybrowserutils_p.h new file mode 100644 index 0000000..2eab3c8 --- /dev/null +++ b/tools/shared/qtpropertybrowser/qtpropertybrowserutils_p.h @@ -0,0 +1,161 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the tools applications of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of Qt Designer. This header +// file may change from version to version without notice, or even be removed. +// +// We mean it. +// + +#ifndef QTPROPERTYBROWSERUTILS_H +#define QTPROPERTYBROWSERUTILS_H + +#include <QtCore/QMap> +#include <QtGui/QIcon> +#include <QtGui/QWidget> +#include <QtCore/QStringList> + +#if QT_VERSION >= 0x040400 +QT_BEGIN_NAMESPACE +#endif + +class QMouseEvent; +class QCheckBox; +class QLineEdit; + +class QtCursorDatabase +{ +public: + QtCursorDatabase(); + + QStringList cursorShapeNames() const; + QMap<int, QIcon> cursorShapeIcons() const; + QString cursorToShapeName(const QCursor &cursor) const; + QIcon cursorToShapeIcon(const QCursor &cursor) const; + int cursorToValue(const QCursor &cursor) const; +#ifndef QT_NO_CURSOR + QCursor valueToCursor(int value) const; +#endif +private: + void appendCursor(Qt::CursorShape shape, const QString &name, const QIcon &icon); + QStringList m_cursorNames; + QMap<int, QIcon> m_cursorIcons; + QMap<int, Qt::CursorShape> m_valueToCursorShape; + QMap<Qt::CursorShape, int> m_cursorShapeToValue; +}; + +class QtPropertyBrowserUtils +{ +public: + static QPixmap brushValuePixmap(const QBrush &b); + static QIcon brushValueIcon(const QBrush &b); + static QString colorValueText(const QColor &c); + static QPixmap fontValuePixmap(const QFont &f); + static QIcon fontValueIcon(const QFont &f); + static QString fontValueText(const QFont &f); +}; + +class QtBoolEdit : public QWidget { + Q_OBJECT +public: + QtBoolEdit(QWidget *parent = 0); + + bool textVisible() const { return m_textVisible; } + void setTextVisible(bool textVisible); + + Qt::CheckState checkState() const; + void setCheckState(Qt::CheckState state); + + bool isChecked() const; + void setChecked(bool c); + + bool blockCheckBoxSignals(bool block); + +Q_SIGNALS: + void toggled(bool); + +protected: + void mousePressEvent(QMouseEvent * event); + +private: + QCheckBox *m_checkBox; + bool m_textVisible; +}; + +class QtKeySequenceEdit : public QWidget +{ + Q_OBJECT +public: + QtKeySequenceEdit(QWidget *parent = 0); + + QKeySequence keySequence() const; + bool eventFilter(QObject *o, QEvent *e); +public Q_SLOTS: + void setKeySequence(const QKeySequence &sequence); +Q_SIGNALS: + void keySequenceChanged(const QKeySequence &sequence); +protected: + void focusInEvent(QFocusEvent *e); + void focusOutEvent(QFocusEvent *e); + void keyPressEvent(QKeyEvent *e); + void keyReleaseEvent(QKeyEvent *e); + bool event(QEvent *e); +private slots: + void slotClearShortcut(); +private: + void handleKeyEvent(QKeyEvent *e); + int translateModifiers(Qt::KeyboardModifiers state, const QString &text) const; + + int m_num; + QKeySequence m_keySequence; + QLineEdit *m_lineEdit; +}; + +#if QT_VERSION >= 0x040400 +QT_END_NAMESPACE +#endif + +#endif diff --git a/tools/shared/qtpropertybrowser/qtpropertymanager.cpp b/tools/shared/qtpropertybrowser/qtpropertymanager.cpp new file mode 100644 index 0000000..8b84eb9 --- /dev/null +++ b/tools/shared/qtpropertybrowser/qtpropertymanager.cpp @@ -0,0 +1,6493 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the tools applications of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qtpropertymanager.h" +#include "qtpropertybrowserutils_p.h" +#include <QtCore/QDateTime> +#include <QtCore/QLocale> +#include <QtCore/QMap> +#include <QtCore/QTimer> +#include <QtGui/QIcon> +#include <QtCore/QMetaEnum> +#include <QtGui/QFontDatabase> +#include <QtGui/QStyleOption> +#include <QtGui/QStyle> +#include <QtGui/QApplication> +#include <QtGui/QPainter> +#include <QtGui/QLabel> + +#include <limits.h> +#include <float.h> + +#if defined(Q_CC_MSVC) +# pragma warning(disable: 4786) /* MS VS 6: truncating debug info after 255 characters */ +#endif + +#if QT_VERSION >= 0x040400 +QT_BEGIN_NAMESPACE +#endif + +template <class PrivateData, class Value> +static void setSimpleMinimumData(PrivateData *data, const Value &minVal) +{ + data->minVal = minVal; + if (data->maxVal < data->minVal) + data->maxVal = data->minVal; + + if (data->val < data->minVal) + data->val = data->minVal; +} + +template <class PrivateData, class Value> +static void setSimpleMaximumData(PrivateData *data, const Value &maxVal) +{ + data->maxVal = maxVal; + if (data->minVal > data->maxVal) + data->minVal = data->maxVal; + + if (data->val > data->maxVal) + data->val = data->maxVal; +} + +template <class PrivateData, class Value> +static void setSizeMinimumData(PrivateData *data, const Value &newMinVal) +{ + data->minVal = newMinVal; + if (data->maxVal.width() < data->minVal.width()) + data->maxVal.setWidth(data->minVal.width()); + if (data->maxVal.height() < data->minVal.height()) + data->maxVal.setHeight(data->minVal.height()); + + if (data->val.width() < data->minVal.width()) + data->val.setWidth(data->minVal.width()); + if (data->val.height() < data->minVal.height()) + data->val.setHeight(data->minVal.height()); +} + +template <class PrivateData, class Value> +static void setSizeMaximumData(PrivateData *data, const Value &newMaxVal) +{ + data->maxVal = newMaxVal; + if (data->minVal.width() > data->maxVal.width()) + data->minVal.setWidth(data->maxVal.width()); + if (data->minVal.height() > data->maxVal.height()) + data->minVal.setHeight(data->maxVal.height()); + + if (data->val.width() > data->maxVal.width()) + data->val.setWidth(data->maxVal.width()); + if (data->val.height() > data->maxVal.height()) + data->val.setHeight(data->maxVal.height()); +} + +template <class SizeValue> +static SizeValue qBoundSize(const SizeValue &minVal, const SizeValue &val, const SizeValue &maxVal) +{ + SizeValue croppedVal = val; + if (minVal.width() > val.width()) + croppedVal.setWidth(minVal.width()); + else if (maxVal.width() < val.width()) + croppedVal.setWidth(maxVal.width()); + + if (minVal.height() > val.height()) + croppedVal.setHeight(minVal.height()); + else if (maxVal.height() < val.height()) + croppedVal.setHeight(maxVal.height()); + + return croppedVal; +} + +// Match the exact signature of qBound for VS 6. +QSize qBound(QSize minVal, QSize val, QSize maxVal) +{ + return qBoundSize(minVal, val, maxVal); +} + +QSizeF qBound(QSizeF minVal, QSizeF val, QSizeF maxVal) +{ + return qBoundSize(minVal, val, maxVal); +} + +namespace { + +namespace { +template <class Value> +void orderBorders(Value &minVal, Value &maxVal) +{ + if (minVal > maxVal) + qSwap(minVal, maxVal); +} + +template <class Value> +static void orderSizeBorders(Value &minVal, Value &maxVal) +{ + Value fromSize = minVal; + Value toSize = maxVal; + if (fromSize.width() > toSize.width()) { + fromSize.setWidth(maxVal.width()); + toSize.setWidth(minVal.width()); + } + if (fromSize.height() > toSize.height()) { + fromSize.setHeight(maxVal.height()); + toSize.setHeight(minVal.height()); + } + minVal = fromSize; + maxVal = toSize; +} + +void orderBorders(QSize &minVal, QSize &maxVal) +{ + orderSizeBorders(minVal, maxVal); +} + +void orderBorders(QSizeF &minVal, QSizeF &maxVal) +{ + orderSizeBorders(minVal, maxVal); +} + +} +} +//////// + +template <class Value, class PrivateData> +static Value getData(const QMap<const QtProperty *, PrivateData> &propertyMap, + Value PrivateData::*data, + const QtProperty *property, const Value &defaultValue = Value()) +{ + typedef QMap<const QtProperty *, PrivateData> PropertyToData; + typedef Q_TYPENAME PropertyToData::const_iterator PropertyToDataConstIterator; + const PropertyToDataConstIterator it = propertyMap.constFind(property); + if (it == propertyMap.constEnd()) + return defaultValue; + return it.value().*data; +} + +template <class Value, class PrivateData> +static Value getValue(const QMap<const QtProperty *, PrivateData> &propertyMap, + const QtProperty *property, const Value &defaultValue = Value()) +{ + return getData<Value>(propertyMap, &PrivateData::val, property, defaultValue); +} + +template <class Value, class PrivateData> +static Value getMinimum(const QMap<const QtProperty *, PrivateData> &propertyMap, + const QtProperty *property, const Value &defaultValue = Value()) +{ + return getData<Value>(propertyMap, &PrivateData::minVal, property, defaultValue); +} + +template <class Value, class PrivateData> +static Value getMaximum(const QMap<const QtProperty *, PrivateData> &propertyMap, + const QtProperty *property, const Value &defaultValue = Value()) +{ + return getData<Value>(propertyMap, &PrivateData::maxVal, property, defaultValue); +} + +template <class ValueChangeParameter, class Value, class PropertyManager> +static void setSimpleValue(QMap<const QtProperty *, Value> &propertyMap, + PropertyManager *manager, + void (PropertyManager::*propertyChangedSignal)(QtProperty *), + void (PropertyManager::*valueChangedSignal)(QtProperty *, ValueChangeParameter), + QtProperty *property, const Value &val) +{ + typedef QMap<const QtProperty *, Value> PropertyToData; + typedef Q_TYPENAME PropertyToData::iterator PropertyToDataIterator; + const PropertyToDataIterator it = propertyMap.find(property); + if (it == propertyMap.end()) + return; + + if (it.value() == val) + return; + + it.value() = val; + + emit (manager->*propertyChangedSignal)(property); + emit (manager->*valueChangedSignal)(property, val); +} + +template <class ValueChangeParameter, class PropertyManagerPrivate, class PropertyManager, class Value> +static void setValueInRange(PropertyManager *manager, PropertyManagerPrivate *managerPrivate, + void (PropertyManager::*propertyChangedSignal)(QtProperty *), + void (PropertyManager::*valueChangedSignal)(QtProperty *, ValueChangeParameter), + QtProperty *property, const Value &val, + void (PropertyManagerPrivate::*setSubPropertyValue)(QtProperty *, ValueChangeParameter)) +{ + typedef Q_TYPENAME PropertyManagerPrivate::Data PrivateData; + typedef QMap<const QtProperty *, PrivateData> PropertyToData; + typedef Q_TYPENAME PropertyToData::iterator PropertyToDataIterator; + const PropertyToDataIterator it = managerPrivate->m_values.find(property); + if (it == managerPrivate->m_values.end()) + return; + + PrivateData &data = it.value(); + + if (data.val == val) + return; + + const Value oldVal = data.val; + + data.val = qBound(data.minVal, val, data.maxVal); + + if (data.val == oldVal) + return; + + if (setSubPropertyValue) + (managerPrivate->*setSubPropertyValue)(property, data.val); + + emit (manager->*propertyChangedSignal)(property); + emit (manager->*valueChangedSignal)(property, data.val); +} + +template <class ValueChangeParameter, class PropertyManagerPrivate, class PropertyManager, class Value> +static void setBorderValues(PropertyManager *manager, PropertyManagerPrivate *managerPrivate, + void (PropertyManager::*propertyChangedSignal)(QtProperty *), + void (PropertyManager::*valueChangedSignal)(QtProperty *, ValueChangeParameter), + void (PropertyManager::*rangeChangedSignal)(QtProperty *, ValueChangeParameter, ValueChangeParameter), + QtProperty *property, const Value &minVal, const Value &maxVal, + void (PropertyManagerPrivate::*setSubPropertyRange)(QtProperty *, + ValueChangeParameter, ValueChangeParameter, ValueChangeParameter)) +{ + typedef Q_TYPENAME PropertyManagerPrivate::Data PrivateData; + typedef QMap<const QtProperty *, PrivateData> PropertyToData; + typedef Q_TYPENAME PropertyToData::iterator PropertyToDataIterator; + const PropertyToDataIterator it = managerPrivate->m_values.find(property); + if (it == managerPrivate->m_values.end()) + return; + + Value fromVal = minVal; + Value toVal = maxVal; + orderBorders(fromVal, toVal); + + PrivateData &data = it.value(); + + if (data.minVal == fromVal && data.maxVal == toVal) + return; + + const Value oldVal = data.val; + + data.setMinimumValue(fromVal); + data.setMaximumValue(toVal); + + emit (manager->*rangeChangedSignal)(property, data.minVal, data.maxVal); + + if (setSubPropertyRange) + (managerPrivate->*setSubPropertyRange)(property, data.minVal, data.maxVal, data.val); + + if (data.val == oldVal) + return; + + emit (manager->*propertyChangedSignal)(property); + emit (manager->*valueChangedSignal)(property, data.val); +} + +template <class ValueChangeParameter, class PropertyManagerPrivate, class PropertyManager, class Value, class PrivateData> +static void setBorderValue(PropertyManager *manager, PropertyManagerPrivate *managerPrivate, + void (PropertyManager::*propertyChangedSignal)(QtProperty *), + void (PropertyManager::*valueChangedSignal)(QtProperty *, ValueChangeParameter), + void (PropertyManager::*rangeChangedSignal)(QtProperty *, ValueChangeParameter, ValueChangeParameter), + QtProperty *property, + Value (PrivateData::*getRangeVal)() const, + void (PrivateData::*setRangeVal)(ValueChangeParameter), const Value &borderVal, + void (PropertyManagerPrivate::*setSubPropertyRange)(QtProperty *, + ValueChangeParameter, ValueChangeParameter, ValueChangeParameter)) +{ + typedef QMap<const QtProperty *, PrivateData> PropertyToData; + typedef Q_TYPENAME PropertyToData::iterator PropertyToDataIterator; + const PropertyToDataIterator it = managerPrivate->m_values.find(property); + if (it == managerPrivate->m_values.end()) + return; + + PrivateData &data = it.value(); + + if ((data.*getRangeVal)() == borderVal) + return; + + const Value oldVal = data.val; + + (data.*setRangeVal)(borderVal); + + emit (manager->*rangeChangedSignal)(property, data.minVal, data.maxVal); + + if (setSubPropertyRange) + (managerPrivate->*setSubPropertyRange)(property, data.minVal, data.maxVal, data.val); + + if (data.val == oldVal) + return; + + emit (manager->*propertyChangedSignal)(property); + emit (manager->*valueChangedSignal)(property, data.val); +} + +template <class ValueChangeParameter, class PropertyManagerPrivate, class PropertyManager, class Value, class PrivateData> +static void setMinimumValue(PropertyManager *manager, PropertyManagerPrivate *managerPrivate, + void (PropertyManager::*propertyChangedSignal)(QtProperty *), + void (PropertyManager::*valueChangedSignal)(QtProperty *, ValueChangeParameter), + void (PropertyManager::*rangeChangedSignal)(QtProperty *, ValueChangeParameter, ValueChangeParameter), + QtProperty *property, const Value &minVal) +{ + void (PropertyManagerPrivate::*setSubPropertyRange)(QtProperty *, + ValueChangeParameter, ValueChangeParameter, ValueChangeParameter) = 0; + setBorderValue<ValueChangeParameter, PropertyManagerPrivate, PropertyManager, Value, PrivateData>(manager, managerPrivate, + propertyChangedSignal, valueChangedSignal, rangeChangedSignal, + property, &PropertyManagerPrivate::Data::minimumValue, &PropertyManagerPrivate::Data::setMinimumValue, minVal, setSubPropertyRange); +} + +template <class ValueChangeParameter, class PropertyManagerPrivate, class PropertyManager, class Value, class PrivateData> +static void setMaximumValue(PropertyManager *manager, PropertyManagerPrivate *managerPrivate, + void (PropertyManager::*propertyChangedSignal)(QtProperty *), + void (PropertyManager::*valueChangedSignal)(QtProperty *, ValueChangeParameter), + void (PropertyManager::*rangeChangedSignal)(QtProperty *, ValueChangeParameter, ValueChangeParameter), + QtProperty *property, const Value &maxVal) +{ + void (PropertyManagerPrivate::*setSubPropertyRange)(QtProperty *, + ValueChangeParameter, ValueChangeParameter, ValueChangeParameter) = 0; + setBorderValue<ValueChangeParameter, PropertyManagerPrivate, PropertyManager, Value, PrivateData>(manager, managerPrivate, + propertyChangedSignal, valueChangedSignal, rangeChangedSignal, + property, &PropertyManagerPrivate::Data::maximumValue, &PropertyManagerPrivate::Data::setMaximumValue, maxVal, setSubPropertyRange); +} + +class QtMetaEnumWrapper : public QObject +{ + Q_OBJECT + Q_PROPERTY(QSizePolicy::Policy policy READ policy) +public: + QSizePolicy::Policy policy() const { return QSizePolicy::Ignored; } +private: + QtMetaEnumWrapper(QObject *parent) : QObject(parent) {} +}; + +class QtMetaEnumProvider +{ +public: + QtMetaEnumProvider(); + + QStringList policyEnumNames() const { return m_policyEnumNames; } + QStringList languageEnumNames() const { return m_languageEnumNames; } + QStringList countryEnumNames(QLocale::Language language) const { return m_countryEnumNames.value(language); } + + QSizePolicy::Policy indexToSizePolicy(int index) const; + int sizePolicyToIndex(QSizePolicy::Policy policy) const; + + void indexToLocale(int languageIndex, int countryIndex, QLocale::Language *language, QLocale::Country *country) const; + void localeToIndex(QLocale::Language language, QLocale::Country country, int *languageIndex, int *countryIndex) const; + +private: + void initLocale(); + + QStringList m_policyEnumNames; + QStringList m_languageEnumNames; + QMap<QLocale::Language, QStringList> m_countryEnumNames; + QMap<int, QLocale::Language> m_indexToLanguage; + QMap<QLocale::Language, int> m_languageToIndex; + QMap<int, QMap<int, QLocale::Country> > m_indexToCountry; + QMap<QLocale::Language, QMap<QLocale::Country, int> > m_countryToIndex; + QMetaEnum m_policyEnum; +}; + +#if QT_VERSION < 0x040300 + +static QList<QLocale::Country> countriesForLanguage(QLocale::Language language) +{ + QList<QLocale::Country> countries; + QLocale::Country country = QLocale::AnyCountry; + while (country <= QLocale::LastCountry) { + QLocale locale(language, country); + if (locale.language() == language && !countries.contains(locale.country())) + countries << locale.country(); + country = (QLocale::Country)((uint)country + 1); // ++country + } + return countries; +} + +#endif + +static QList<QLocale::Country> sortCountries(const QList<QLocale::Country> &countries) +{ + QMultiMap<QString, QLocale::Country> nameToCountry; + QListIterator<QLocale::Country> itCountry(countries); + while (itCountry.hasNext()) { + QLocale::Country country = itCountry.next(); + nameToCountry.insert(QLocale::countryToString(country), country); + } + return nameToCountry.values(); +} + +void QtMetaEnumProvider::initLocale() +{ + QMultiMap<QString, QLocale::Language> nameToLanguage; + QLocale::Language language = QLocale::C; + while (language <= QLocale::LastLanguage) { + QLocale locale(language); + if (locale.language() == language) + nameToLanguage.insert(QLocale::languageToString(language), language); + language = (QLocale::Language)((uint)language + 1); // ++language + } + + const QLocale system = QLocale::system(); + if (!nameToLanguage.contains(QLocale::languageToString(system.language()))) + nameToLanguage.insert(QLocale::languageToString(system.language()), system.language()); + + QList<QLocale::Language> languages = nameToLanguage.values(); + QListIterator<QLocale::Language> itLang(languages); + while (itLang.hasNext()) { + QLocale::Language language = itLang.next(); + QList<QLocale::Country> countries; +#if QT_VERSION < 0x040300 + countries = countriesForLanguage(language); +#else + countries = QLocale::countriesForLanguage(language); +#endif + if (countries.isEmpty() && language == system.language()) + countries << system.country(); + + if (!countries.isEmpty() && !m_languageToIndex.contains(language)) { + countries = sortCountries(countries); + int langIdx = m_languageEnumNames.count(); + m_indexToLanguage[langIdx] = language; + m_languageToIndex[language] = langIdx; + QStringList countryNames; + QListIterator<QLocale::Country> it(countries); + int countryIdx = 0; + while (it.hasNext()) { + QLocale::Country country = it.next(); + countryNames << QLocale::countryToString(country); + m_indexToCountry[langIdx][countryIdx] = country; + m_countryToIndex[language][country] = countryIdx; + ++countryIdx; + } + m_languageEnumNames << QLocale::languageToString(language); + m_countryEnumNames[language] = countryNames; + } + } +} + +QtMetaEnumProvider::QtMetaEnumProvider() +{ + QMetaProperty p; + + p = QtMetaEnumWrapper::staticMetaObject.property( + QtMetaEnumWrapper::staticMetaObject.propertyOffset() + 0); + m_policyEnum = p.enumerator(); + const int keyCount = m_policyEnum.keyCount(); + for (int i = 0; i < keyCount; i++) + m_policyEnumNames << QLatin1String(m_policyEnum.key(i)); + + initLocale(); +} + +QSizePolicy::Policy QtMetaEnumProvider::indexToSizePolicy(int index) const +{ + return static_cast<QSizePolicy::Policy>(m_policyEnum.value(index)); +} + +int QtMetaEnumProvider::sizePolicyToIndex(QSizePolicy::Policy policy) const +{ + const int keyCount = m_policyEnum.keyCount(); + for (int i = 0; i < keyCount; i++) + if (indexToSizePolicy(i) == policy) + return i; + return -1; +} + +void QtMetaEnumProvider::indexToLocale(int languageIndex, int countryIndex, QLocale::Language *language, QLocale::Country *country) const +{ + QLocale::Language l = QLocale::C; + QLocale::Country c = QLocale::AnyCountry; + if (m_indexToLanguage.contains(languageIndex)) { + l = m_indexToLanguage[languageIndex]; + if (m_indexToCountry.contains(languageIndex) && m_indexToCountry[languageIndex].contains(countryIndex)) + c = m_indexToCountry[languageIndex][countryIndex]; + } + if (language) + *language = l; + if (country) + *country = c; +} + +void QtMetaEnumProvider::localeToIndex(QLocale::Language language, QLocale::Country country, int *languageIndex, int *countryIndex) const +{ + int l = -1; + int c = -1; + if (m_languageToIndex.contains(language)) { + l = m_languageToIndex[language]; + if (m_countryToIndex.contains(language) && m_countryToIndex[language].contains(country)) + c = m_countryToIndex[language][country]; + } + + if (languageIndex) + *languageIndex = l; + if (countryIndex) + *countryIndex = c; +} + +Q_GLOBAL_STATIC(QtMetaEnumProvider, metaEnumProvider) + +// QtGroupPropertyManager + +/*! + \class QtGroupPropertyManager + \internal + \inmodule QtDesigner + \since 4.4 + + \brief The QtGroupPropertyManager provides and manages group properties. + + This class is intended to provide a grouping element without any value. + + \sa QtAbstractPropertyManager +*/ + +/*! + Creates a manager with the given \a parent. +*/ +QtGroupPropertyManager::QtGroupPropertyManager(QObject *parent) + : QtAbstractPropertyManager(parent) +{ + +} + +/*! + Destroys this manager, and all the properties it has created. +*/ +QtGroupPropertyManager::~QtGroupPropertyManager() +{ + +} + +/*! + \reimp +*/ +bool QtGroupPropertyManager::hasValue(const QtProperty *property) const +{ + Q_UNUSED(property) + return false; +} + +/*! + \reimp +*/ +void QtGroupPropertyManager::initializeProperty(QtProperty *property) +{ + Q_UNUSED(property) +} + +/*! + \reimp +*/ +void QtGroupPropertyManager::uninitializeProperty(QtProperty *property) +{ + Q_UNUSED(property) +} + +// QtIntPropertyManager + +class QtIntPropertyManagerPrivate +{ + QtIntPropertyManager *q_ptr; + Q_DECLARE_PUBLIC(QtIntPropertyManager) +public: + + struct Data + { + Data() : val(0), minVal(-INT_MAX), maxVal(INT_MAX), singleStep(1) {} + int val; + int minVal; + int maxVal; + int singleStep; + int minimumValue() const { return minVal; } + int maximumValue() const { return maxVal; } + void setMinimumValue(int newMinVal) { setSimpleMinimumData(this, newMinVal); } + void setMaximumValue(int newMaxVal) { setSimpleMaximumData(this, newMaxVal); } + }; + + typedef QMap<const QtProperty *, Data> PropertyValueMap; + PropertyValueMap m_values; +}; + +/*! + \class QtIntPropertyManager + \internal + \inmodule QtDesigner + \since 4.4 + + \brief The QtIntPropertyManager provides and manages int properties. + + An int property has a current value, and a range specifying the + valid values. The range is defined by a minimum and a maximum + value. + + The property's value and range can be retrieved using the value(), + minimum() and maximum() functions, and can be set using the + setValue(), setMinimum() and setMaximum() slots. Alternatively, + the range can be defined in one go using the setRange() slot. + + In addition, QtIntPropertyManager provides the valueChanged() signal which + is emitted whenever a property created by this manager changes, + and the rangeChanged() signal which is emitted whenever such a + property changes its range of valid values. + + \sa QtAbstractPropertyManager, QtSpinBoxFactory, QtSliderFactory, QtScrollBarFactory +*/ + +/*! + \fn void QtIntPropertyManager::valueChanged(QtProperty *property, int value) + + This signal is emitted whenever a property created by this manager + changes its value, passing a pointer to the \a property and the new + \a value as parameters. + + \sa setValue() +*/ + +/*! + \fn void QtIntPropertyManager::rangeChanged(QtProperty *property, int minimum, int maximum) + + This signal is emitted whenever a property created by this manager + changes its range of valid values, passing a pointer to the + \a property and the new \a minimum and \a maximum values. + + \sa setRange() +*/ + +/*! + \fn void QtIntPropertyManager::singleStepChanged(QtProperty *property, int step) + + This signal is emitted whenever a property created by this manager + changes its single step property, passing a pointer to the + \a property and the new \a step value + + \sa setSingleStep() +*/ + +/*! + Creates a manager with the given \a parent. +*/ +QtIntPropertyManager::QtIntPropertyManager(QObject *parent) + : QtAbstractPropertyManager(parent) +{ + d_ptr = new QtIntPropertyManagerPrivate; + d_ptr->q_ptr = this; +} + +/*! + Destroys this manager, and all the properties it has created. +*/ +QtIntPropertyManager::~QtIntPropertyManager() +{ + clear(); + delete d_ptr; +} + +/*! + Returns the given \a property's value. + + If the given property is not managed by this manager, this + function returns 0. + + \sa setValue() +*/ +int QtIntPropertyManager::value(const QtProperty *property) const +{ + return getValue<int>(d_ptr->m_values, property, 0); +} + +/*! + Returns the given \a property's minimum value. + + \sa setMinimum(), maximum(), setRange() +*/ +int QtIntPropertyManager::minimum(const QtProperty *property) const +{ + return getMinimum<int>(d_ptr->m_values, property, 0); +} + +/*! + Returns the given \a property's maximum value. + + \sa setMaximum(), minimum(), setRange() +*/ +int QtIntPropertyManager::maximum(const QtProperty *property) const +{ + return getMaximum<int>(d_ptr->m_values, property, 0); +} + +/*! + Returns the given \a property's step value. + + The step is typically used to increment or decrement a property value while pressing an arrow key. + + \sa setSingleStep() +*/ +int QtIntPropertyManager::singleStep(const QtProperty *property) const +{ + return getData<int>(d_ptr->m_values, &QtIntPropertyManagerPrivate::Data::singleStep, property, 0); +} + +/*! + \reimp +*/ +QString QtIntPropertyManager::valueText(const QtProperty *property) const +{ + const QtIntPropertyManagerPrivate::PropertyValueMap::const_iterator it = d_ptr->m_values.constFind(property); + if (it == d_ptr->m_values.constEnd()) + return QString(); + return QString::number(it.value().val); +} + +/*! + \fn void QtIntPropertyManager::setValue(QtProperty *property, int value) + + Sets the value of the given \a property to \a value. + + If the specified \a value is not valid according to the given \a + property's range, the \a value is adjusted to the nearest valid + value within the range. + + \sa value(), setRange(), valueChanged() +*/ +void QtIntPropertyManager::setValue(QtProperty *property, int val) +{ + void (QtIntPropertyManagerPrivate::*setSubPropertyValue)(QtProperty *, int) = 0; + setValueInRange<int, QtIntPropertyManagerPrivate, QtIntPropertyManager, int>(this, d_ptr, + &QtIntPropertyManager::propertyChanged, + &QtIntPropertyManager::valueChanged, + property, val, setSubPropertyValue); +} + +/*! + Sets the minimum value for the given \a property to \a minVal. + + When setting the minimum value, the maximum and current values are + adjusted if necessary (ensuring that the range remains valid and + that the current value is within the range). + + \sa minimum(), setRange(), rangeChanged() +*/ +void QtIntPropertyManager::setMinimum(QtProperty *property, int minVal) +{ + setMinimumValue<int, QtIntPropertyManagerPrivate, QtIntPropertyManager, int, QtIntPropertyManagerPrivate::Data>(this, d_ptr, + &QtIntPropertyManager::propertyChanged, + &QtIntPropertyManager::valueChanged, + &QtIntPropertyManager::rangeChanged, + property, minVal); +} + +/*! + Sets the maximum value for the given \a property to \a maxVal. + + When setting maximum value, the minimum and current values are + adjusted if necessary (ensuring that the range remains valid and + that the current value is within the range). + + \sa maximum(), setRange(), rangeChanged() +*/ +void QtIntPropertyManager::setMaximum(QtProperty *property, int maxVal) +{ + setMaximumValue<int, QtIntPropertyManagerPrivate, QtIntPropertyManager, int, QtIntPropertyManagerPrivate::Data>(this, d_ptr, + &QtIntPropertyManager::propertyChanged, + &QtIntPropertyManager::valueChanged, + &QtIntPropertyManager::rangeChanged, + property, maxVal); +} + +/*! + \fn void QtIntPropertyManager::setRange(QtProperty *property, int minimum, int maximum) + + Sets the range of valid values. + + This is a convenience function defining the range of valid values + in one go; setting the \a minimum and \a maximum values for the + given \a property with a single function call. + + When setting a new range, the current value is adjusted if + necessary (ensuring that the value remains within range). + + \sa setMinimum(), setMaximum(), rangeChanged() +*/ +void QtIntPropertyManager::setRange(QtProperty *property, int minVal, int maxVal) +{ + void (QtIntPropertyManagerPrivate::*setSubPropertyRange)(QtProperty *, int, int, int) = 0; + setBorderValues<int, QtIntPropertyManagerPrivate, QtIntPropertyManager, int>(this, d_ptr, + &QtIntPropertyManager::propertyChanged, + &QtIntPropertyManager::valueChanged, + &QtIntPropertyManager::rangeChanged, + property, minVal, maxVal, setSubPropertyRange); +} + +/*! + Sets the step value for the given \a property to \a step. + + The step is typically used to increment or decrement a property value while pressing an arrow key. + + \sa singleStep() +*/ +void QtIntPropertyManager::setSingleStep(QtProperty *property, int step) +{ + const QtIntPropertyManagerPrivate::PropertyValueMap::iterator it = d_ptr->m_values.find(property); + if (it == d_ptr->m_values.end()) + return; + + QtIntPropertyManagerPrivate::Data data = it.value(); + + if (step < 0) + step = 0; + + if (data.singleStep == step) + return; + + data.singleStep = step; + + it.value() = data; + + emit singleStepChanged(property, data.singleStep); +} + +/*! + \reimp +*/ +void QtIntPropertyManager::initializeProperty(QtProperty *property) +{ + d_ptr->m_values[property] = QtIntPropertyManagerPrivate::Data(); +} + +/*! + \reimp +*/ +void QtIntPropertyManager::uninitializeProperty(QtProperty *property) +{ + d_ptr->m_values.remove(property); +} + +// QtDoublePropertyManager + +class QtDoublePropertyManagerPrivate +{ + QtDoublePropertyManager *q_ptr; + Q_DECLARE_PUBLIC(QtDoublePropertyManager) +public: + + struct Data + { + Data() : val(0), minVal(-INT_MAX), maxVal(INT_MAX), singleStep(1), decimals(2) {} + double val; + double minVal; + double maxVal; + double singleStep; + int decimals; + double minimumValue() const { return minVal; } + double maximumValue() const { return maxVal; } + void setMinimumValue(double newMinVal) { setSimpleMinimumData(this, newMinVal); } + void setMaximumValue(double newMaxVal) { setSimpleMaximumData(this, newMaxVal); } + }; + + typedef QMap<const QtProperty *, Data> PropertyValueMap; + PropertyValueMap m_values; +}; + +/*! + \class QtDoublePropertyManager + \internal + \inmodule QtDesigner + \since 4.4 + + \brief The QtDoublePropertyManager provides and manages double properties. + + A double property has a current value, and a range specifying the + valid values. The range is defined by a minimum and a maximum + value. + + The property's value and range can be retrieved using the value(), + minimum() and maximum() functions, and can be set using the + setValue(), setMinimum() and setMaximum() slots. + Alternatively, the range can be defined in one go using the + setRange() slot. + + In addition, QtDoublePropertyManager provides the valueChanged() signal + which is emitted whenever a property created by this manager + changes, and the rangeChanged() signal which is emitted whenever + such a property changes its range of valid values. + + \sa QtAbstractPropertyManager, QtDoubleSpinBoxFactory +*/ + +/*! + \fn void QtDoublePropertyManager::valueChanged(QtProperty *property, double value) + + This signal is emitted whenever a property created by this manager + changes its value, passing a pointer to the \a property and the new + \a value as parameters. + + \sa setValue() +*/ + +/*! + \fn void QtDoublePropertyManager::rangeChanged(QtProperty *property, double minimum, double maximum) + + This signal is emitted whenever a property created by this manager + changes its range of valid values, passing a pointer to the + \a property and the new \a minimum and \a maximum values + + \sa setRange() +*/ + +/*! + \fn void QtDoublePropertyManager::decimalsChanged(QtProperty *property, int prec) + + This signal is emitted whenever a property created by this manager + changes its precision of value, passing a pointer to the + \a property and the new \a prec value + + \sa setDecimals() +*/ + +/*! + \fn void QtDoublePropertyManager::singleStepChanged(QtProperty *property, double step) + + This signal is emitted whenever a property created by this manager + changes its single step property, passing a pointer to the + \a property and the new \a step value + + \sa setSingleStep() +*/ + +/*! + Creates a manager with the given \a parent. +*/ +QtDoublePropertyManager::QtDoublePropertyManager(QObject *parent) + : QtAbstractPropertyManager(parent) +{ + d_ptr = new QtDoublePropertyManagerPrivate; + d_ptr->q_ptr = this; +} + +/*! + Destroys this manager, and all the properties it has created. +*/ +QtDoublePropertyManager::~QtDoublePropertyManager() +{ + clear(); + delete d_ptr; +} + +/*! + Returns the given \a property's value. + + If the given property is not managed by this manager, this + function returns 0. + + \sa setValue() +*/ +double QtDoublePropertyManager::value(const QtProperty *property) const +{ + return getValue<double>(d_ptr->m_values, property, 0.0); +} + +/*! + Returns the given \a property's minimum value. + + \sa maximum(), setRange() +*/ +double QtDoublePropertyManager::minimum(const QtProperty *property) const +{ + return getMinimum<double>(d_ptr->m_values, property, 0.0); +} + +/*! + Returns the given \a property's maximum value. + + \sa minimum(), setRange() +*/ +double QtDoublePropertyManager::maximum(const QtProperty *property) const +{ + return getMaximum<double>(d_ptr->m_values, property, 0.0); +} + +/*! + Returns the given \a property's step value. + + The step is typically used to increment or decrement a property value while pressing an arrow key. + + \sa setSingleStep() +*/ +double QtDoublePropertyManager::singleStep(const QtProperty *property) const +{ + return getData<double>(d_ptr->m_values, &QtDoublePropertyManagerPrivate::Data::singleStep, property, 0); +} + +/*! + Returns the given \a property's precision, in decimals. + + \sa setDecimals() +*/ +int QtDoublePropertyManager::decimals(const QtProperty *property) const +{ + return getData<int>(d_ptr->m_values, &QtDoublePropertyManagerPrivate::Data::decimals, property, 0); +} + +/*! + \reimp +*/ +QString QtDoublePropertyManager::valueText(const QtProperty *property) const +{ + const QtDoublePropertyManagerPrivate::PropertyValueMap::const_iterator it = d_ptr->m_values.constFind(property); + if (it == d_ptr->m_values.constEnd()) + return QString(); + return QString::number(it.value().val, 'f', it.value().decimals); +} + +/*! + \fn void QtDoublePropertyManager::setValue(QtProperty *property, double value) + + Sets the value of the given \a property to \a value. + + If the specified \a value is not valid according to the given + \a property's range, the \a value is adjusted to the nearest valid value + within the range. + + \sa value(), setRange(), valueChanged() +*/ +void QtDoublePropertyManager::setValue(QtProperty *property, double val) +{ + void (QtDoublePropertyManagerPrivate::*setSubPropertyValue)(QtProperty *, double) = 0; + setValueInRange<double, QtDoublePropertyManagerPrivate, QtDoublePropertyManager, double>(this, d_ptr, + &QtDoublePropertyManager::propertyChanged, + &QtDoublePropertyManager::valueChanged, + property, val, setSubPropertyValue); +} + +/*! + Sets the step value for the given \a property to \a step. + + The step is typically used to increment or decrement a property value while pressing an arrow key. + + \sa singleStep() +*/ +void QtDoublePropertyManager::setSingleStep(QtProperty *property, double step) +{ + const QtDoublePropertyManagerPrivate::PropertyValueMap::iterator it = d_ptr->m_values.find(property); + if (it == d_ptr->m_values.end()) + return; + + QtDoublePropertyManagerPrivate::Data data = it.value(); + + if (step < 0) + step = 0; + + if (data.singleStep == step) + return; + + data.singleStep = step; + + it.value() = data; + + emit singleStepChanged(property, data.singleStep); +} + +/*! + \fn void QtDoublePropertyManager::setDecimals(QtProperty *property, int prec) + + Sets the precision of the given \a property to \a prec. + + The valid decimal range is 0-13. The default is 2. + + \sa decimals() +*/ +void QtDoublePropertyManager::setDecimals(QtProperty *property, int prec) +{ + const QtDoublePropertyManagerPrivate::PropertyValueMap::iterator it = d_ptr->m_values.find(property); + if (it == d_ptr->m_values.end()) + return; + + QtDoublePropertyManagerPrivate::Data data = it.value(); + + if (prec > 13) + prec = 13; + else if (prec < 0) + prec = 0; + + if (data.decimals == prec) + return; + + data.decimals = prec; + + it.value() = data; + + emit decimalsChanged(property, data.decimals); +} + +/*! + Sets the minimum value for the given \a property to \a minVal. + + When setting the minimum value, the maximum and current values are + adjusted if necessary (ensuring that the range remains valid and + that the current value is within in the range). + + \sa minimum(), setRange(), rangeChanged() +*/ +void QtDoublePropertyManager::setMinimum(QtProperty *property, double minVal) +{ + setMinimumValue<double, QtDoublePropertyManagerPrivate, QtDoublePropertyManager, double, QtDoublePropertyManagerPrivate::Data>(this, d_ptr, + &QtDoublePropertyManager::propertyChanged, + &QtDoublePropertyManager::valueChanged, + &QtDoublePropertyManager::rangeChanged, + property, minVal); +} + +/*! + Sets the maximum value for the given \a property to \a maxVal. + + When setting the maximum value, the minimum and current values are + adjusted if necessary (ensuring that the range remains valid and + that the current value is within in the range). + + \sa maximum(), setRange(), rangeChanged() +*/ +void QtDoublePropertyManager::setMaximum(QtProperty *property, double maxVal) +{ + setMaximumValue<double, QtDoublePropertyManagerPrivate, QtDoublePropertyManager, double, QtDoublePropertyManagerPrivate::Data>(this, d_ptr, + &QtDoublePropertyManager::propertyChanged, + &QtDoublePropertyManager::valueChanged, + &QtDoublePropertyManager::rangeChanged, + property, maxVal); +} + +/*! + \fn void QtDoublePropertyManager::setRange(QtProperty *property, double minimum, double maximum) + + Sets the range of valid values. + + This is a convenience function defining the range of valid values + in one go; setting the \a minimum and \a maximum values for the + given \a property with a single function call. + + When setting a new range, the current value is adjusted if + necessary (ensuring that the value remains within range). + + \sa setMinimum(), setMaximum(), rangeChanged() +*/ +void QtDoublePropertyManager::setRange(QtProperty *property, double minVal, double maxVal) +{ + void (QtDoublePropertyManagerPrivate::*setSubPropertyRange)(QtProperty *, double, double, double) = 0; + setBorderValues<double, QtDoublePropertyManagerPrivate, QtDoublePropertyManager, double>(this, d_ptr, + &QtDoublePropertyManager::propertyChanged, + &QtDoublePropertyManager::valueChanged, + &QtDoublePropertyManager::rangeChanged, + property, minVal, maxVal, setSubPropertyRange); +} + +/*! + \reimp +*/ +void QtDoublePropertyManager::initializeProperty(QtProperty *property) +{ + d_ptr->m_values[property] = QtDoublePropertyManagerPrivate::Data(); +} + +/*! + \reimp +*/ +void QtDoublePropertyManager::uninitializeProperty(QtProperty *property) +{ + d_ptr->m_values.remove(property); +} + +// QtStringPropertyManager + +class QtStringPropertyManagerPrivate +{ + QtStringPropertyManager *q_ptr; + Q_DECLARE_PUBLIC(QtStringPropertyManager) +public: + + struct Data + { + Data() : regExp(QString(QLatin1Char('*')), Qt::CaseSensitive, QRegExp::Wildcard) + { + } + QString val; + QRegExp regExp; + }; + + typedef QMap<const QtProperty *, Data> PropertyValueMap; + QMap<const QtProperty *, Data> m_values; +}; + +/*! + \class QtStringPropertyManager + \internal + \inmodule QtDesigner + \since 4.4 + + \brief The QtStringPropertyManager provides and manages QString properties. + + A string property's value can be retrieved using the value() + function, and set using the setValue() slot. + + The current value can be checked against a regular expression. To + set the regular expression use the setRegExp() slot, use the + regExp() function to retrieve the currently set expression. + + In addition, QtStringPropertyManager provides the valueChanged() signal + which is emitted whenever a property created by this manager + changes, and the regExpChanged() signal which is emitted whenever + such a property changes its currently set regular expression. + + \sa QtAbstractPropertyManager, QtLineEditFactory +*/ + +/*! + \fn void QtStringPropertyManager::valueChanged(QtProperty *property, const QString &value) + + This signal is emitted whenever a property created by this manager + changes its value, passing a pointer to the \a property and the + new \a value as parameters. + + \sa setValue() +*/ + +/*! + \fn void QtStringPropertyManager::regExpChanged(QtProperty *property, const QRegExp ®Exp) + + This signal is emitted whenever a property created by this manager + changes its currenlty set regular expression, passing a pointer to + the \a property and the new \a regExp as parameters. + + \sa setRegExp() +*/ + +/*! + Creates a manager with the given \a parent. +*/ +QtStringPropertyManager::QtStringPropertyManager(QObject *parent) + : QtAbstractPropertyManager(parent) +{ + d_ptr = new QtStringPropertyManagerPrivate; + d_ptr->q_ptr = this; +} + +/*! + Destroys this manager, and all the properties it has created. +*/ +QtStringPropertyManager::~QtStringPropertyManager() +{ + clear(); + delete d_ptr; +} + +/*! + Returns the given \a property's value. + + If the given property is not managed by this manager, this + function returns an empty string. + + \sa setValue() +*/ +QString QtStringPropertyManager::value(const QtProperty *property) const +{ + return getValue<QString>(d_ptr->m_values, property); +} + +/*! + Returns the given \a property's currently set regular expression. + + If the given \a property is not managed by this manager, this + function returns an empty expression. + + \sa setRegExp() +*/ +QRegExp QtStringPropertyManager::regExp(const QtProperty *property) const +{ + return getData<QRegExp>(d_ptr->m_values, &QtStringPropertyManagerPrivate::Data::regExp, property, QRegExp()); +} + +/*! + \reimp +*/ +QString QtStringPropertyManager::valueText(const QtProperty *property) const +{ + const QtStringPropertyManagerPrivate::PropertyValueMap::const_iterator it = d_ptr->m_values.constFind(property); + if (it == d_ptr->m_values.constEnd()) + return QString(); + return it.value().val; +} + +/*! + \fn void QtStringPropertyManager::setValue(QtProperty *property, const QString &value) + + Sets the value of the given \a property to \a value. + + If the specified \a value doesn't match the given \a property's + regular expression, this function does nothing. + + \sa value(), setRegExp(), valueChanged() +*/ +void QtStringPropertyManager::setValue(QtProperty *property, const QString &val) +{ + const QtStringPropertyManagerPrivate::PropertyValueMap::iterator it = d_ptr->m_values.find(property); + if (it == d_ptr->m_values.end()) + return; + + QtStringPropertyManagerPrivate::Data data = it.value(); + + if (data.val == val) + return; + + if (data.regExp.isValid() && !data.regExp.exactMatch(val)) + return; + + data.val = val; + + it.value() = data; + + emit propertyChanged(property); + emit valueChanged(property, data.val); +} + +/*! + Sets the regular expression of the given \a property to \a regExp. + + \sa regExp(), setValue(), regExpChanged() +*/ +void QtStringPropertyManager::setRegExp(QtProperty *property, const QRegExp ®Exp) +{ + const QtStringPropertyManagerPrivate::PropertyValueMap::iterator it = d_ptr->m_values.find(property); + if (it == d_ptr->m_values.end()) + return; + + QtStringPropertyManagerPrivate::Data data = it.value() ; + + if (data.regExp == regExp) + return; + + data.regExp = regExp; + + it.value() = data; + + emit regExpChanged(property, data.regExp); +} + +/*! + \reimp +*/ +void QtStringPropertyManager::initializeProperty(QtProperty *property) +{ + d_ptr->m_values[property] = QtStringPropertyManagerPrivate::Data(); +} + +/*! + \reimp +*/ +void QtStringPropertyManager::uninitializeProperty(QtProperty *property) +{ + d_ptr->m_values.remove(property); +} + +// QtBoolPropertyManager + +class QtBoolPropertyManagerPrivate +{ + QtBoolPropertyManager *q_ptr; + Q_DECLARE_PUBLIC(QtBoolPropertyManager) +public: + + QMap<const QtProperty *, bool> m_values; +}; + +/*! + \class QtBoolPropertyManager + \internal + \inmodule QtDesigner + \since 4.4 + + \brief The QtBoolPropertyManager class provides and manages boolean properties. + + The property's value can be retrieved using the value() function, + and set using the setValue() slot. + + In addition, QtBoolPropertyManager provides the valueChanged() signal + which is emitted whenever a property created by this manager + changes. + + \sa QtAbstractPropertyManager, QtCheckBoxFactory +*/ + +/*! + \fn void QtBoolPropertyManager::valueChanged(QtProperty *property, bool value) + + This signal is emitted whenever a property created by this manager + changes its value, passing a pointer to the \a property and the + new \a value as parameters. +*/ + +/*! + Creates a manager with the given \a parent. +*/ +QtBoolPropertyManager::QtBoolPropertyManager(QObject *parent) + : QtAbstractPropertyManager(parent) +{ + d_ptr = new QtBoolPropertyManagerPrivate; + d_ptr->q_ptr = this; +} + +/*! + Destroys this manager, and all the properties it has created. +*/ +QtBoolPropertyManager::~QtBoolPropertyManager() +{ + clear(); + delete d_ptr; +} + +/*! + Returns the given \a property's value. + + If the given \a property is not managed by \e this manager, this + function returns false. + + \sa setValue() +*/ +bool QtBoolPropertyManager::value(const QtProperty *property) const +{ + return d_ptr->m_values.value(property, false); +} + +/*! + \reimp +*/ +QString QtBoolPropertyManager::valueText(const QtProperty *property) const +{ + const QMap<const QtProperty *, bool>::const_iterator it = d_ptr->m_values.constFind(property); + if (it == d_ptr->m_values.constEnd()) + return QString(); + + static const QString trueText = tr("True"); + static const QString falseText = tr("False"); + return it.value() ? trueText : falseText; +} + +// Return an icon containing a check box indicator +static QIcon drawCheckBox(bool value) +{ + QStyleOptionButton opt; + opt.state |= value ? QStyle::State_On : QStyle::State_Off; + opt.state |= QStyle::State_Enabled; + const QStyle *style = QApplication::style(); + // Figure out size of an indicator and make sure it is not scaled down in a list view item + // by making the pixmap as big as a list view icon and centering the indicator in it. + // (if it is smaller, it can't be helped) + const int indicatorWidth = style->pixelMetric(QStyle::PM_IndicatorWidth, &opt); + const int indicatorHeight = style->pixelMetric(QStyle::PM_IndicatorHeight, &opt); + const int listViewIconSize = indicatorWidth; + const int pixmapWidth = indicatorWidth; + const int pixmapHeight = qMax(indicatorHeight, listViewIconSize); + + opt.rect = QRect(0, 0, indicatorWidth, indicatorHeight); + QPixmap pixmap = QPixmap(pixmapWidth, pixmapHeight); + pixmap.fill(Qt::transparent); + { + // Center? + const int xoff = (pixmapWidth > indicatorWidth) ? (pixmapWidth - indicatorWidth) / 2 : 0; + const int yoff = (pixmapHeight > indicatorHeight) ? (pixmapHeight - indicatorHeight) / 2 : 0; + QPainter painter(&pixmap); + painter.translate(xoff, yoff); + style->drawPrimitive(QStyle::PE_IndicatorCheckBox, &opt, &painter); + } + return QIcon(pixmap); +} + +/*! + \reimp +*/ +QIcon QtBoolPropertyManager::valueIcon(const QtProperty *property) const +{ + const QMap<const QtProperty *, bool>::const_iterator it = d_ptr->m_values.constFind(property); + if (it == d_ptr->m_values.constEnd()) + return QIcon(); + + static const QIcon checkedIcon = drawCheckBox(true); + static const QIcon uncheckedIcon = drawCheckBox(false); + return it.value() ? checkedIcon : uncheckedIcon; +} + +/*! + \fn void QtBoolPropertyManager::setValue(QtProperty *property, bool value) + + Sets the value of the given \a property to \a value. + + \sa value() +*/ +void QtBoolPropertyManager::setValue(QtProperty *property, bool val) +{ + setSimpleValue<bool, bool, QtBoolPropertyManager>(d_ptr->m_values, this, + &QtBoolPropertyManager::propertyChanged, + &QtBoolPropertyManager::valueChanged, + property, val); +} + +/*! + \reimp +*/ +void QtBoolPropertyManager::initializeProperty(QtProperty *property) +{ + d_ptr->m_values[property] = false; +} + +/*! + \reimp +*/ +void QtBoolPropertyManager::uninitializeProperty(QtProperty *property) +{ + d_ptr->m_values.remove(property); +} + +// QtDatePropertyManager + +class QtDatePropertyManagerPrivate +{ + QtDatePropertyManager *q_ptr; + Q_DECLARE_PUBLIC(QtDatePropertyManager) +public: + + struct Data + { + Data() : val(QDate::currentDate()), minVal(QDate(1752, 9, 14)), + maxVal(QDate(7999, 12, 31)) {} + QDate val; + QDate minVal; + QDate maxVal; + QDate minimumValue() const { return minVal; } + QDate maximumValue() const { return maxVal; } + void setMinimumValue(const QDate &newMinVal) { setSimpleMinimumData(this, newMinVal); } + void setMaximumValue(const QDate &newMaxVal) { setSimpleMaximumData(this, newMaxVal); } + }; + + QString m_format; + + typedef QMap<const QtProperty *, Data> PropertyValueMap; + QMap<const QtProperty *, Data> m_values; +}; + +/*! + \class QtDatePropertyManager + \internal + \inmodule QtDesigner + \since 4.4 + + \brief The QtDatePropertyManager provides and manages QDate properties. + + A date property has a current value, and a range specifying the + valid dates. The range is defined by a minimum and a maximum + value. + + The property's values can be retrieved using the minimum(), + maximum() and value() functions, and can be set using the + setMinimum(), setMaximum() and setValue() slots. Alternatively, + the range can be defined in one go using the setRange() slot. + + In addition, QtDatePropertyManager provides the valueChanged() signal + which is emitted whenever a property created by this manager + changes, and the rangeChanged() signal which is emitted whenever + such a property changes its range of valid dates. + + \sa QtAbstractPropertyManager, QtDateEditFactory, QtDateTimePropertyManager +*/ + +/*! + \fn void QtDatePropertyManager::valueChanged(QtProperty *property, const QDate &value) + + This signal is emitted whenever a property created by this manager + changes its value, passing a pointer to the \a property and the new + \a value as parameters. + + \sa setValue() +*/ + +/*! + \fn void QtDatePropertyManager::rangeChanged(QtProperty *property, const QDate &minimum, const QDate &maximum) + + This signal is emitted whenever a property created by this manager + changes its range of valid dates, passing a pointer to the \a + property and the new \a minimum and \a maximum dates. + + \sa setRange() +*/ + +/*! + Creates a manager with the given \a parent. +*/ +QtDatePropertyManager::QtDatePropertyManager(QObject *parent) + : QtAbstractPropertyManager(parent) +{ + d_ptr = new QtDatePropertyManagerPrivate; + d_ptr->q_ptr = this; + + QLocale loc; + d_ptr->m_format = loc.dateFormat(QLocale::ShortFormat); +} + +/*! + Destroys this manager, and all the properties it has created. +*/ +QtDatePropertyManager::~QtDatePropertyManager() +{ + clear(); + delete d_ptr; +} + +/*! + Returns the given \a property's value. + + If the given \a property is not managed by \e this manager, this + function returns an invalid date. + + \sa setValue() +*/ +QDate QtDatePropertyManager::value(const QtProperty *property) const +{ + return getValue<QDate>(d_ptr->m_values, property); +} + +/*! + Returns the given \a property's minimum date. + + \sa maximum(), setRange() +*/ +QDate QtDatePropertyManager::minimum(const QtProperty *property) const +{ + return getMinimum<QDate>(d_ptr->m_values, property); +} + +/*! + Returns the given \a property's maximum date. + + \sa minimum(), setRange() +*/ +QDate QtDatePropertyManager::maximum(const QtProperty *property) const +{ + return getMaximum<QDate>(d_ptr->m_values, property); +} + +/*! + \reimp +*/ +QString QtDatePropertyManager::valueText(const QtProperty *property) const +{ + const QtDatePropertyManagerPrivate::PropertyValueMap::const_iterator it = d_ptr->m_values.constFind(property); + if (it == d_ptr->m_values.constEnd()) + return QString(); + return it.value().val.toString(d_ptr->m_format); +} + +/*! + \fn void QtDatePropertyManager::setValue(QtProperty *property, const QDate &value) + + Sets the value of the given \a property to \a value. + + If the specified \a value is not a valid date according to the + given \a property's range, the value is adjusted to the nearest + valid value within the range. + + \sa value(), setRange(), valueChanged() +*/ +void QtDatePropertyManager::setValue(QtProperty *property, const QDate &val) +{ + void (QtDatePropertyManagerPrivate::*setSubPropertyValue)(QtProperty *, const QDate &) = 0; + setValueInRange<const QDate &, QtDatePropertyManagerPrivate, QtDatePropertyManager, const QDate>(this, d_ptr, + &QtDatePropertyManager::propertyChanged, + &QtDatePropertyManager::valueChanged, + property, val, setSubPropertyValue); +} + +/*! + Sets the minimum value for the given \a property to \a minVal. + + When setting the minimum value, the maximum and current values are + adjusted if necessary (ensuring that the range remains valid and + that the current value is within in the range). + + \sa minimum(), setRange() +*/ +void QtDatePropertyManager::setMinimum(QtProperty *property, const QDate &minVal) +{ + setMinimumValue<const QDate &, QtDatePropertyManagerPrivate, QtDatePropertyManager, QDate, QtDatePropertyManagerPrivate::Data>(this, d_ptr, + &QtDatePropertyManager::propertyChanged, + &QtDatePropertyManager::valueChanged, + &QtDatePropertyManager::rangeChanged, + property, minVal); +} + +/*! + Sets the maximum value for the given \a property to \a maxVal. + + When setting the maximum value, the minimum and current + values are adjusted if necessary (ensuring that the range remains + valid and that the current value is within in the range). + + \sa maximum(), setRange() +*/ +void QtDatePropertyManager::setMaximum(QtProperty *property, const QDate &maxVal) +{ + setMaximumValue<const QDate &, QtDatePropertyManagerPrivate, QtDatePropertyManager, QDate, QtDatePropertyManagerPrivate::Data>(this, d_ptr, + &QtDatePropertyManager::propertyChanged, + &QtDatePropertyManager::valueChanged, + &QtDatePropertyManager::rangeChanged, + property, maxVal); +} + +/*! + \fn void QtDatePropertyManager::setRange(QtProperty *property, const QDate &minimum, const QDate &maximum) + + Sets the range of valid dates. + + This is a convenience function defining the range of valid dates + in one go; setting the \a minimum and \a maximum values for the + given \a property with a single function call. + + When setting a new date range, the current value is adjusted if + necessary (ensuring that the value remains in date range). + + \sa setMinimum(), setMaximum(), rangeChanged() +*/ +void QtDatePropertyManager::setRange(QtProperty *property, const QDate &minVal, const QDate &maxVal) +{ + void (QtDatePropertyManagerPrivate::*setSubPropertyRange)(QtProperty *, const QDate &, + const QDate &, const QDate &) = 0; + setBorderValues<const QDate &, QtDatePropertyManagerPrivate, QtDatePropertyManager, QDate>(this, d_ptr, + &QtDatePropertyManager::propertyChanged, + &QtDatePropertyManager::valueChanged, + &QtDatePropertyManager::rangeChanged, + property, minVal, maxVal, setSubPropertyRange); +} + +/*! + \reimp +*/ +void QtDatePropertyManager::initializeProperty(QtProperty *property) +{ + d_ptr->m_values[property] = QtDatePropertyManagerPrivate::Data(); +} + +/*! + \reimp +*/ +void QtDatePropertyManager::uninitializeProperty(QtProperty *property) +{ + d_ptr->m_values.remove(property); +} + +// QtTimePropertyManager + +class QtTimePropertyManagerPrivate +{ + QtTimePropertyManager *q_ptr; + Q_DECLARE_PUBLIC(QtTimePropertyManager) +public: + + QString m_format; + + typedef QMap<const QtProperty *, QTime> PropertyValueMap; + PropertyValueMap m_values; +}; + +/*! + \class QtTimePropertyManager + \internal + \inmodule QtDesigner + \since 4.4 + + \brief The QtTimePropertyManager provides and manages QTime properties. + + A time property's value can be retrieved using the value() + function, and set using the setValue() slot. + + In addition, QtTimePropertyManager provides the valueChanged() signal + which is emitted whenever a property created by this manager + changes. + + \sa QtAbstractPropertyManager, QtTimeEditFactory +*/ + +/*! + \fn void QtTimePropertyManager::valueChanged(QtProperty *property, const QTime &value) + + This signal is emitted whenever a property created by this manager + changes its value, passing a pointer to the \a property and the + new \a value as parameters. + + \sa setValue() +*/ + +/*! + Creates a manager with the given \a parent. +*/ +QtTimePropertyManager::QtTimePropertyManager(QObject *parent) + : QtAbstractPropertyManager(parent) +{ + d_ptr = new QtTimePropertyManagerPrivate; + d_ptr->q_ptr = this; + + QLocale loc; + d_ptr->m_format = loc.timeFormat(QLocale::ShortFormat); +} + +/*! + Destroys this manager, and all the properties it has created. +*/ +QtTimePropertyManager::~QtTimePropertyManager() +{ + clear(); + delete d_ptr; +} + +/*! + Returns the given \a property's value. + + If the given property is not managed by this manager, this + function returns an invalid time object. + + \sa setValue() +*/ +QTime QtTimePropertyManager::value(const QtProperty *property) const +{ + return d_ptr->m_values.value(property, QTime()); +} + +/*! + \reimp +*/ +QString QtTimePropertyManager::valueText(const QtProperty *property) const +{ + const QtTimePropertyManagerPrivate::PropertyValueMap::const_iterator it = d_ptr->m_values.constFind(property); + if (it == d_ptr->m_values.constEnd()) + return QString(); + return it.value().toString(d_ptr->m_format); +} + +/*! + \fn void QtTimePropertyManager::setValue(QtProperty *property, const QTime &value) + + Sets the value of the given \a property to \a value. + + \sa value(), valueChanged() +*/ +void QtTimePropertyManager::setValue(QtProperty *property, const QTime &val) +{ + setSimpleValue<const QTime &, QTime, QtTimePropertyManager>(d_ptr->m_values, this, + &QtTimePropertyManager::propertyChanged, + &QtTimePropertyManager::valueChanged, + property, val); +} + +/*! + \reimp +*/ +void QtTimePropertyManager::initializeProperty(QtProperty *property) +{ + d_ptr->m_values[property] = QTime::currentTime(); +} + +/*! + \reimp +*/ +void QtTimePropertyManager::uninitializeProperty(QtProperty *property) +{ + d_ptr->m_values.remove(property); +} + +// QtDateTimePropertyManager + +class QtDateTimePropertyManagerPrivate +{ + QtDateTimePropertyManager *q_ptr; + Q_DECLARE_PUBLIC(QtDateTimePropertyManager) +public: + + QString m_format; + + typedef QMap<const QtProperty *, QDateTime> PropertyValueMap; + PropertyValueMap m_values; +}; + +/*! \class QtDateTimePropertyManager + \internal + \inmodule QtDesigner + \since 4.4 + + \brief The QtDateTimePropertyManager provides and manages QDateTime properties. + + A date and time property has a current value which can be + retrieved using the value() function, and set using the setValue() + slot. In addition, QtDateTimePropertyManager provides the + valueChanged() signal which is emitted whenever a property created + by this manager changes. + + \sa QtAbstractPropertyManager, QtDateTimeEditFactory, QtDatePropertyManager +*/ + +/*! + \fn void QtDateTimePropertyManager::valueChanged(QtProperty *property, const QDateTime &value) + + This signal is emitted whenever a property created by this manager + changes its value, passing a pointer to the \a property and the new + \a value as parameters. +*/ + +/*! + Creates a manager with the given \a parent. +*/ +QtDateTimePropertyManager::QtDateTimePropertyManager(QObject *parent) + : QtAbstractPropertyManager(parent) +{ + d_ptr = new QtDateTimePropertyManagerPrivate; + d_ptr->q_ptr = this; + + QLocale loc; + d_ptr->m_format = loc.dateFormat(QLocale::ShortFormat); + d_ptr->m_format += QLatin1Char(' '); + d_ptr->m_format += loc.timeFormat(QLocale::ShortFormat); +} + +/*! + Destroys this manager, and all the properties it has created. +*/ +QtDateTimePropertyManager::~QtDateTimePropertyManager() +{ + clear(); + delete d_ptr; +} + +/*! + Returns the given \a property's value. + + If the given \a property is not managed by this manager, this + function returns an invalid QDateTime object. + + \sa setValue() +*/ +QDateTime QtDateTimePropertyManager::value(const QtProperty *property) const +{ + return d_ptr->m_values.value(property, QDateTime()); +} + +/*! + \reimp +*/ +QString QtDateTimePropertyManager::valueText(const QtProperty *property) const +{ + const QtDateTimePropertyManagerPrivate::PropertyValueMap::const_iterator it = d_ptr->m_values.constFind(property); + if (it == d_ptr->m_values.constEnd()) + return QString(); + return it.value().toString(d_ptr->m_format); +} + +/*! + \fn void QtDateTimePropertyManager::setValue(QtProperty *property, const QDateTime &value) + + Sets the value of the given \a property to \a value. + + \sa value(), valueChanged() +*/ +void QtDateTimePropertyManager::setValue(QtProperty *property, const QDateTime &val) +{ + setSimpleValue<const QDateTime &, QDateTime, QtDateTimePropertyManager>(d_ptr->m_values, this, + &QtDateTimePropertyManager::propertyChanged, + &QtDateTimePropertyManager::valueChanged, + property, val); +} + +/*! + \reimp +*/ +void QtDateTimePropertyManager::initializeProperty(QtProperty *property) +{ + d_ptr->m_values[property] = QDateTime::currentDateTime(); +} + +/*! + \reimp +*/ +void QtDateTimePropertyManager::uninitializeProperty(QtProperty *property) +{ + d_ptr->m_values.remove(property); +} + +// QtKeySequencePropertyManager + +class QtKeySequencePropertyManagerPrivate +{ + QtKeySequencePropertyManager *q_ptr; + Q_DECLARE_PUBLIC(QtKeySequencePropertyManager) +public: + + QString m_format; + + typedef QMap<const QtProperty *, QKeySequence> PropertyValueMap; + PropertyValueMap m_values; +}; + +/*! \class QtKeySequencePropertyManager + \internal + \inmodule QtDesigner + \since 4.4 + + \brief The QtKeySequencePropertyManager provides and manages QKeySequence properties. + + A key sequence's value can be retrieved using the value() + function, and set using the setValue() slot. + + In addition, QtKeySequencePropertyManager provides the valueChanged() signal + which is emitted whenever a property created by this manager + changes. + + \sa QtAbstractPropertyManager +*/ + +/*! + \fn void QtKeySequencePropertyManager::valueChanged(QtProperty *property, const QKeySequence &value) + + This signal is emitted whenever a property created by this manager + changes its value, passing a pointer to the \a property and the new + \a value as parameters. +*/ + +/*! + Creates a manager with the given \a parent. +*/ +QtKeySequencePropertyManager::QtKeySequencePropertyManager(QObject *parent) + : QtAbstractPropertyManager(parent) +{ + d_ptr = new QtKeySequencePropertyManagerPrivate; + d_ptr->q_ptr = this; +} + +/*! + Destroys this manager, and all the properties it has created. +*/ +QtKeySequencePropertyManager::~QtKeySequencePropertyManager() +{ + clear(); + delete d_ptr; +} + +/*! + Returns the given \a property's value. + + If the given \a property is not managed by this manager, this + function returns an empty QKeySequence object. + + \sa setValue() +*/ +QKeySequence QtKeySequencePropertyManager::value(const QtProperty *property) const +{ + return d_ptr->m_values.value(property, QKeySequence()); +} + +/*! + \reimp +*/ +QString QtKeySequencePropertyManager::valueText(const QtProperty *property) const +{ + const QtKeySequencePropertyManagerPrivate::PropertyValueMap::const_iterator it = d_ptr->m_values.constFind(property); + if (it == d_ptr->m_values.constEnd()) + return QString(); + return it.value().toString(QKeySequence::NativeText); +} + +/*! + \fn void QtKeySequencePropertyManager::setValue(QtProperty *property, const QKeySequence &value) + + Sets the value of the given \a property to \a value. + + \sa value(), valueChanged() +*/ +void QtKeySequencePropertyManager::setValue(QtProperty *property, const QKeySequence &val) +{ + setSimpleValue<const QKeySequence &, QKeySequence, QtKeySequencePropertyManager>(d_ptr->m_values, this, + &QtKeySequencePropertyManager::propertyChanged, + &QtKeySequencePropertyManager::valueChanged, + property, val); +} + +/*! + \reimp +*/ +void QtKeySequencePropertyManager::initializeProperty(QtProperty *property) +{ + d_ptr->m_values[property] = QKeySequence(); +} + +/*! + \reimp +*/ +void QtKeySequencePropertyManager::uninitializeProperty(QtProperty *property) +{ + d_ptr->m_values.remove(property); +} + +// QtCharPropertyManager + +class QtCharPropertyManagerPrivate +{ + QtCharPropertyManager *q_ptr; + Q_DECLARE_PUBLIC(QtCharPropertyManager) +public: + + typedef QMap<const QtProperty *, QChar> PropertyValueMap; + PropertyValueMap m_values; +}; + +/*! \class QtCharPropertyManager + \internal + \inmodule QtDesigner + \since 4.4 + + \brief The QtCharPropertyManager provides and manages QChar properties. + + A char's value can be retrieved using the value() + function, and set using the setValue() slot. + + In addition, QtCharPropertyManager provides the valueChanged() signal + which is emitted whenever a property created by this manager + changes. + + \sa QtAbstractPropertyManager +*/ + +/*! + \fn void QtCharPropertyManager::valueChanged(QtProperty *property, const QChar &value) + + This signal is emitted whenever a property created by this manager + changes its value, passing a pointer to the \a property and the new + \a value as parameters. +*/ + +/*! + Creates a manager with the given \a parent. +*/ +QtCharPropertyManager::QtCharPropertyManager(QObject *parent) + : QtAbstractPropertyManager(parent) +{ + d_ptr = new QtCharPropertyManagerPrivate; + d_ptr->q_ptr = this; +} + +/*! + Destroys this manager, and all the properties it has created. +*/ +QtCharPropertyManager::~QtCharPropertyManager() +{ + clear(); + delete d_ptr; +} + +/*! + Returns the given \a property's value. + + If the given \a property is not managed by this manager, this + function returns an null QChar object. + + \sa setValue() +*/ +QChar QtCharPropertyManager::value(const QtProperty *property) const +{ + return d_ptr->m_values.value(property, QChar()); +} + +/*! + \reimp +*/ +QString QtCharPropertyManager::valueText(const QtProperty *property) const +{ + const QtCharPropertyManagerPrivate::PropertyValueMap::const_iterator it = d_ptr->m_values.constFind(property); + if (it == d_ptr->m_values.constEnd()) + return QString(); + const QChar c = it.value(); + return c.isNull() ? QString() : QString(c); +} + +/*! + \fn void QtCharPropertyManager::setValue(QtProperty *property, const QChar &value) + + Sets the value of the given \a property to \a value. + + \sa value(), valueChanged() +*/ +void QtCharPropertyManager::setValue(QtProperty *property, const QChar &val) +{ + setSimpleValue<const QChar &, QChar, QtCharPropertyManager>(d_ptr->m_values, this, + &QtCharPropertyManager::propertyChanged, + &QtCharPropertyManager::valueChanged, + property, val); +} + +/*! + \reimp +*/ +void QtCharPropertyManager::initializeProperty(QtProperty *property) +{ + d_ptr->m_values[property] = QChar(); +} + +/*! + \reimp +*/ +void QtCharPropertyManager::uninitializeProperty(QtProperty *property) +{ + d_ptr->m_values.remove(property); +} + +// QtLocalePropertyManager + +class QtLocalePropertyManagerPrivate +{ + QtLocalePropertyManager *q_ptr; + Q_DECLARE_PUBLIC(QtLocalePropertyManager) +public: + + QtLocalePropertyManagerPrivate(); + + void slotEnumChanged(QtProperty *property, int value); + void slotPropertyDestroyed(QtProperty *property); + + typedef QMap<const QtProperty *, QLocale> PropertyValueMap; + PropertyValueMap m_values; + + QtEnumPropertyManager *m_enumPropertyManager; + + QMap<const QtProperty *, QtProperty *> m_propertyToLanguage; + QMap<const QtProperty *, QtProperty *> m_propertyToCountry; + + QMap<const QtProperty *, QtProperty *> m_languageToProperty; + QMap<const QtProperty *, QtProperty *> m_countryToProperty; +}; + +QtLocalePropertyManagerPrivate::QtLocalePropertyManagerPrivate() +{ +} + +void QtLocalePropertyManagerPrivate::slotEnumChanged(QtProperty *property, int value) +{ + if (QtProperty *prop = m_languageToProperty.value(property, 0)) { + const QLocale loc = m_values[prop]; + QLocale::Language newLanguage = loc.language(); + QLocale::Country newCountry = loc.country(); + metaEnumProvider()->indexToLocale(value, 0, &newLanguage, 0); + QLocale newLoc(newLanguage, newCountry); + q_ptr->setValue(prop, newLoc); + } else if (QtProperty *prop = m_countryToProperty.value(property, 0)) { + const QLocale loc = m_values[prop]; + QLocale::Language newLanguage = loc.language(); + QLocale::Country newCountry = loc.country(); + metaEnumProvider()->indexToLocale(m_enumPropertyManager->value(m_propertyToLanguage.value(prop)), value, &newLanguage, &newCountry); + QLocale newLoc(newLanguage, newCountry); + q_ptr->setValue(prop, newLoc); + } +} + +void QtLocalePropertyManagerPrivate::slotPropertyDestroyed(QtProperty *property) +{ + if (QtProperty *subProp = m_languageToProperty.value(property, 0)) { + m_propertyToLanguage[subProp] = 0; + m_languageToProperty.remove(property); + } else if (QtProperty *subProp = m_countryToProperty.value(property, 0)) { + m_propertyToCountry[subProp] = 0; + m_countryToProperty.remove(property); + } +} + +/*! + \class QtLocalePropertyManager + \internal + \inmodule QtDesigner + \since 4.4 + + \brief The QtLocalePropertyManager provides and manages QLocale properties. + + A locale property has nested \e language and \e country + subproperties. The top-level property's value can be retrieved + using the value() function, and set using the setValue() slot. + + The subproperties are created by QtEnumPropertyManager object. + These submanager can be retrieved using the subEnumPropertyManager() + function. In order to provide editing widgets for the subproperties + in a property browser widget, this manager must be associated with editor factory. + + In addition, QtLocalePropertyManager provides the valueChanged() + signal which is emitted whenever a property created by this + manager changes. + + \sa QtAbstractPropertyManager, QtEnumPropertyManager +*/ + +/*! + \fn void QtLocalePropertyManager::valueChanged(QtProperty *property, const QLocale &value) + + This signal is emitted whenever a property created by this manager + changes its value, passing a pointer to the \a property and the + new \a value as parameters. + + \sa setValue() +*/ + +/*! + Creates a manager with the given \a parent. +*/ +QtLocalePropertyManager::QtLocalePropertyManager(QObject *parent) + : QtAbstractPropertyManager(parent) +{ + d_ptr = new QtLocalePropertyManagerPrivate; + d_ptr->q_ptr = this; + + d_ptr->m_enumPropertyManager = new QtEnumPropertyManager(this); + connect(d_ptr->m_enumPropertyManager, SIGNAL(valueChanged(QtProperty *, int)), + this, SLOT(slotEnumChanged(QtProperty *, int))); + + connect(d_ptr->m_enumPropertyManager, SIGNAL(propertyDestroyed(QtProperty *)), + this, SLOT(slotPropertyDestroyed(QtProperty *))); +} + +/*! + Destroys this manager, and all the properties it has created. +*/ +QtLocalePropertyManager::~QtLocalePropertyManager() +{ + clear(); + delete d_ptr; +} + +/*! + Returns the manager that creates the nested \e language + and \e country subproperties. + + In order to provide editing widgets for the mentioned subproperties + in a property browser widget, this manager must be associated with + an editor factory. + + \sa QtAbstractPropertyBrowser::setFactoryForManager() +*/ +QtEnumPropertyManager *QtLocalePropertyManager::subEnumPropertyManager() const +{ + return d_ptr->m_enumPropertyManager; +} + +/*! + Returns the given \a property's value. + + If the given property is not managed by this manager, this + function returns the default locale. + + \sa setValue() +*/ +QLocale QtLocalePropertyManager::value(const QtProperty *property) const +{ + return d_ptr->m_values.value(property, QLocale()); +} + +/*! + \reimp +*/ +QString QtLocalePropertyManager::valueText(const QtProperty *property) const +{ + const QtLocalePropertyManagerPrivate::PropertyValueMap::const_iterator it = d_ptr->m_values.constFind(property); + if (it == d_ptr->m_values.constEnd()) + return QString(); + + QLocale loc = it.value(); + + int langIdx = 0; + int countryIdx = 0; + metaEnumProvider()->localeToIndex(loc.language(), loc.country(), &langIdx, &countryIdx); + QString str = tr("%1, %2") + .arg(metaEnumProvider()->languageEnumNames().at(langIdx)) + .arg(metaEnumProvider()->countryEnumNames(loc.language()).at(countryIdx)); + return str; +} + +/*! + \fn void QtLocalePropertyManager::setValue(QtProperty *property, const QLocale &value) + + Sets the value of the given \a property to \a value. Nested + properties are updated automatically. + + \sa value(), valueChanged() +*/ +void QtLocalePropertyManager::setValue(QtProperty *property, const QLocale &val) +{ + const QtLocalePropertyManagerPrivate::PropertyValueMap::iterator it = d_ptr->m_values.find(property); + if (it == d_ptr->m_values.end()) + return; + + const QLocale loc = it.value(); + if (loc == val) + return; + + it.value() = val; + + int langIdx = 0; + int countryIdx = 0; + metaEnumProvider()->localeToIndex(val.language(), val.country(), &langIdx, &countryIdx); + if (loc.language() != val.language()) { + d_ptr->m_enumPropertyManager->setValue(d_ptr->m_propertyToLanguage.value(property), langIdx); + d_ptr->m_enumPropertyManager->setEnumNames(d_ptr->m_propertyToCountry.value(property), + metaEnumProvider()->countryEnumNames(val.language())); + } + d_ptr->m_enumPropertyManager->setValue(d_ptr->m_propertyToCountry.value(property), countryIdx); + + emit propertyChanged(property); + emit valueChanged(property, val); +} + +/*! + \reimp +*/ +void QtLocalePropertyManager::initializeProperty(QtProperty *property) +{ + QLocale val; + d_ptr->m_values[property] = val; + + int langIdx = 0; + int countryIdx = 0; + metaEnumProvider()->localeToIndex(val.language(), val.country(), &langIdx, &countryIdx); + + QtProperty *languageProp = d_ptr->m_enumPropertyManager->addProperty(); + languageProp->setPropertyName(tr("Language")); + d_ptr->m_enumPropertyManager->setEnumNames(languageProp, metaEnumProvider()->languageEnumNames()); + d_ptr->m_enumPropertyManager->setValue(languageProp, langIdx); + d_ptr->m_propertyToLanguage[property] = languageProp; + d_ptr->m_languageToProperty[languageProp] = property; + property->addSubProperty(languageProp); + + QtProperty *countryProp = d_ptr->m_enumPropertyManager->addProperty(); + countryProp->setPropertyName(tr("Country")); + d_ptr->m_enumPropertyManager->setEnumNames(countryProp, metaEnumProvider()->countryEnumNames(val.language())); + d_ptr->m_enumPropertyManager->setValue(countryProp, countryIdx); + d_ptr->m_propertyToCountry[property] = countryProp; + d_ptr->m_countryToProperty[countryProp] = property; + property->addSubProperty(countryProp); +} + +/*! + \reimp +*/ +void QtLocalePropertyManager::uninitializeProperty(QtProperty *property) +{ + QtProperty *languageProp = d_ptr->m_propertyToLanguage[property]; + if (languageProp) { + d_ptr->m_languageToProperty.remove(languageProp); + delete languageProp; + } + d_ptr->m_propertyToLanguage.remove(property); + + QtProperty *countryProp = d_ptr->m_propertyToCountry[property]; + if (countryProp) { + d_ptr->m_countryToProperty.remove(countryProp); + delete countryProp; + } + d_ptr->m_propertyToCountry.remove(property); + + d_ptr->m_values.remove(property); +} + +// QtPointPropertyManager + +class QtPointPropertyManagerPrivate +{ + QtPointPropertyManager *q_ptr; + Q_DECLARE_PUBLIC(QtPointPropertyManager) +public: + + void slotIntChanged(QtProperty *property, int value); + void slotPropertyDestroyed(QtProperty *property); + + typedef QMap<const QtProperty *, QPoint> PropertyValueMap; + PropertyValueMap m_values; + + QtIntPropertyManager *m_intPropertyManager; + + QMap<const QtProperty *, QtProperty *> m_propertyToX; + QMap<const QtProperty *, QtProperty *> m_propertyToY; + + QMap<const QtProperty *, QtProperty *> m_xToProperty; + QMap<const QtProperty *, QtProperty *> m_yToProperty; +}; + +void QtPointPropertyManagerPrivate::slotIntChanged(QtProperty *property, int value) +{ + if (QtProperty *xprop = m_xToProperty.value(property, 0)) { + QPoint p = m_values[xprop]; + p.setX(value); + q_ptr->setValue(xprop, p); + } else if (QtProperty *yprop = m_yToProperty.value(property, 0)) { + QPoint p = m_values[yprop]; + p.setY(value); + q_ptr->setValue(yprop, p); + } +} + +void QtPointPropertyManagerPrivate::slotPropertyDestroyed(QtProperty *property) +{ + if (QtProperty *pointProp = m_xToProperty.value(property, 0)) { + m_propertyToX[pointProp] = 0; + m_xToProperty.remove(property); + } else if (QtProperty *pointProp = m_yToProperty.value(property, 0)) { + m_propertyToY[pointProp] = 0; + m_yToProperty.remove(property); + } +} + +/*! \class QtPointPropertyManager + \internal + \inmodule QtDesigner + \since 4.4 + + \brief The QtPointPropertyManager provides and manages QPoint properties. + + A point property has nested \e x and \e y subproperties. The + top-level property's value can be retrieved using the value() + function, and set using the setValue() slot. + + The subproperties are created by a QtIntPropertyManager object. This + manager can be retrieved using the subIntPropertyManager() function. In + order to provide editing widgets for the subproperties in a + property browser widget, this manager must be associated with an + editor factory. + + In addition, QtPointPropertyManager provides the valueChanged() signal which + is emitted whenever a property created by this manager changes. + + \sa QtAbstractPropertyManager, QtIntPropertyManager, QtPointFPropertyManager +*/ + +/*! + \fn void QtPointPropertyManager::valueChanged(QtProperty *property, const QPoint &value) + + This signal is emitted whenever a property created by this manager + changes its value, passing a pointer to the \a property and the + new \a value as parameters. + + \sa setValue() +*/ + +/*! + Creates a manager with the given \a parent. +*/ +QtPointPropertyManager::QtPointPropertyManager(QObject *parent) + : QtAbstractPropertyManager(parent) +{ + d_ptr = new QtPointPropertyManagerPrivate; + d_ptr->q_ptr = this; + + d_ptr->m_intPropertyManager = new QtIntPropertyManager(this); + connect(d_ptr->m_intPropertyManager, SIGNAL(valueChanged(QtProperty *, int)), + this, SLOT(slotIntChanged(QtProperty *, int))); + connect(d_ptr->m_intPropertyManager, SIGNAL(propertyDestroyed(QtProperty *)), + this, SLOT(slotPropertyDestroyed(QtProperty *))); +} + +/*! + Destroys this manager, and all the properties it has created. +*/ +QtPointPropertyManager::~QtPointPropertyManager() +{ + clear(); + delete d_ptr; +} + +/*! + Returns the manager that creates the nested \e x and \e y + subproperties. + + In order to provide editing widgets for the subproperties in a + property browser widget, this manager must be associated with an + editor factory. + + \sa QtAbstractPropertyBrowser::setFactoryForManager() +*/ +QtIntPropertyManager *QtPointPropertyManager::subIntPropertyManager() const +{ + return d_ptr->m_intPropertyManager; +} + +/*! + Returns the given \a property's value. + + If the given \a property is not managed by this manager, this + function returns a point with coordinates (0, 0). + + \sa setValue() +*/ +QPoint QtPointPropertyManager::value(const QtProperty *property) const +{ + return d_ptr->m_values.value(property, QPoint()); +} + +/*! + \reimp +*/ +QString QtPointPropertyManager::valueText(const QtProperty *property) const +{ + const QtPointPropertyManagerPrivate::PropertyValueMap::const_iterator it = d_ptr->m_values.constFind(property); + if (it == d_ptr->m_values.constEnd()) + return QString(); + const QPoint v = it.value(); + return QString(tr("(%1, %2)").arg(QString::number(v.x())) + .arg(QString::number(v.y()))); +} + +/*! + \fn void QtPointPropertyManager::setValue(QtProperty *property, const QPoint &value) + + Sets the value of the given \a property to \a value. Nested + properties are updated automatically. + + \sa value(), valueChanged() +*/ +void QtPointPropertyManager::setValue(QtProperty *property, const QPoint &val) +{ + const QtPointPropertyManagerPrivate::PropertyValueMap::iterator it = d_ptr->m_values.find(property); + if (it == d_ptr->m_values.end()) + return; + + if (it.value() == val) + return; + + it.value() = val; + d_ptr->m_intPropertyManager->setValue(d_ptr->m_propertyToX[property], val.x()); + d_ptr->m_intPropertyManager->setValue(d_ptr->m_propertyToY[property], val.y()); + + emit propertyChanged(property); + emit valueChanged(property, val); +} + +/*! + \reimp +*/ +void QtPointPropertyManager::initializeProperty(QtProperty *property) +{ + d_ptr->m_values[property] = QPoint(0, 0); + + QtProperty *xProp = d_ptr->m_intPropertyManager->addProperty(); + xProp->setPropertyName(tr("X")); + d_ptr->m_intPropertyManager->setValue(xProp, 0); + d_ptr->m_propertyToX[property] = xProp; + d_ptr->m_xToProperty[xProp] = property; + property->addSubProperty(xProp); + + QtProperty *yProp = d_ptr->m_intPropertyManager->addProperty(); + yProp->setPropertyName(tr("Y")); + d_ptr->m_intPropertyManager->setValue(yProp, 0); + d_ptr->m_propertyToY[property] = yProp; + d_ptr->m_yToProperty[yProp] = property; + property->addSubProperty(yProp); +} + +/*! + \reimp +*/ +void QtPointPropertyManager::uninitializeProperty(QtProperty *property) +{ + QtProperty *xProp = d_ptr->m_propertyToX[property]; + if (xProp) { + d_ptr->m_xToProperty.remove(xProp); + delete xProp; + } + d_ptr->m_propertyToX.remove(property); + + QtProperty *yProp = d_ptr->m_propertyToY[property]; + if (yProp) { + d_ptr->m_yToProperty.remove(yProp); + delete yProp; + } + d_ptr->m_propertyToY.remove(property); + + d_ptr->m_values.remove(property); +} + +// QtPointFPropertyManager + +class QtPointFPropertyManagerPrivate +{ + QtPointFPropertyManager *q_ptr; + Q_DECLARE_PUBLIC(QtPointFPropertyManager) +public: + + struct Data + { + Data() : decimals(2) {} + QPointF val; + int decimals; + }; + + void slotDoubleChanged(QtProperty *property, double value); + void slotPropertyDestroyed(QtProperty *property); + + typedef QMap<const QtProperty *, Data> PropertyValueMap; + PropertyValueMap m_values; + + QtDoublePropertyManager *m_doublePropertyManager; + + QMap<const QtProperty *, QtProperty *> m_propertyToX; + QMap<const QtProperty *, QtProperty *> m_propertyToY; + + QMap<const QtProperty *, QtProperty *> m_xToProperty; + QMap<const QtProperty *, QtProperty *> m_yToProperty; +}; + +void QtPointFPropertyManagerPrivate::slotDoubleChanged(QtProperty *property, double value) +{ + if (QtProperty *prop = m_xToProperty.value(property, 0)) { + QPointF p = m_values[prop].val; + p.setX(value); + q_ptr->setValue(prop, p); + } else if (QtProperty *prop = m_yToProperty.value(property, 0)) { + QPointF p = m_values[prop].val; + p.setY(value); + q_ptr->setValue(prop, p); + } +} + +void QtPointFPropertyManagerPrivate::slotPropertyDestroyed(QtProperty *property) +{ + if (QtProperty *pointProp = m_xToProperty.value(property, 0)) { + m_propertyToX[pointProp] = 0; + m_xToProperty.remove(property); + } else if (QtProperty *pointProp = m_yToProperty.value(property, 0)) { + m_propertyToY[pointProp] = 0; + m_yToProperty.remove(property); + } +} + +/*! \class QtPointFPropertyManager + \internal + \inmodule QtDesigner + \since 4.4 + + \brief The QtPointFPropertyManager provides and manages QPointF properties. + + A point property has nested \e x and \e y subproperties. The + top-level property's value can be retrieved using the value() + function, and set using the setValue() slot. + + The subproperties are created by a QtDoublePropertyManager object. This + manager can be retrieved using the subDoublePropertyManager() function. In + order to provide editing widgets for the subproperties in a + property browser widget, this manager must be associated with an + editor factory. + + In addition, QtPointFPropertyManager provides the valueChanged() signal which + is emitted whenever a property created by this manager changes. + + \sa QtAbstractPropertyManager, QtDoublePropertyManager, QtPointPropertyManager +*/ + +/*! + \fn void QtPointFPropertyManager::valueChanged(QtProperty *property, const QPointF &value) + + This signal is emitted whenever a property created by this manager + changes its value, passing a pointer to the \a property and the + new \a value as parameters. + + \sa setValue() +*/ + +/*! + \fn void QtPointFPropertyManager::decimalsChanged(QtProperty *property, int prec) + + This signal is emitted whenever a property created by this manager + changes its precision of value, passing a pointer to the + \a property and the new \a prec value + + \sa setDecimals() +*/ + +/*! + Creates a manager with the given \a parent. +*/ +QtPointFPropertyManager::QtPointFPropertyManager(QObject *parent) + : QtAbstractPropertyManager(parent) +{ + d_ptr = new QtPointFPropertyManagerPrivate; + d_ptr->q_ptr = this; + + d_ptr->m_doublePropertyManager = new QtDoublePropertyManager(this); + connect(d_ptr->m_doublePropertyManager, SIGNAL(valueChanged(QtProperty *, double)), + this, SLOT(slotDoubleChanged(QtProperty *, double))); + connect(d_ptr->m_doublePropertyManager, SIGNAL(propertyDestroyed(QtProperty *)), + this, SLOT(slotPropertyDestroyed(QtProperty *))); +} + +/*! + Destroys this manager, and all the properties it has created. +*/ +QtPointFPropertyManager::~QtPointFPropertyManager() +{ + clear(); + delete d_ptr; +} + +/*! + Returns the manager that creates the nested \e x and \e y + subproperties. + + In order to provide editing widgets for the subproperties in a + property browser widget, this manager must be associated with an + editor factory. + + \sa QtAbstractPropertyBrowser::setFactoryForManager() +*/ +QtDoublePropertyManager *QtPointFPropertyManager::subDoublePropertyManager() const +{ + return d_ptr->m_doublePropertyManager; +} + +/*! + Returns the given \a property's value. + + If the given \a property is not managed by this manager, this + function returns a point with coordinates (0, 0). + + \sa setValue() +*/ +QPointF QtPointFPropertyManager::value(const QtProperty *property) const +{ + return getValue<QPointF>(d_ptr->m_values, property); +} + +/*! + Returns the given \a property's precision, in decimals. + + \sa setDecimals() +*/ +int QtPointFPropertyManager::decimals(const QtProperty *property) const +{ + return getData<int>(d_ptr->m_values, &QtPointFPropertyManagerPrivate::Data::decimals, property, 0); +} + +/*! + \reimp +*/ +QString QtPointFPropertyManager::valueText(const QtProperty *property) const +{ + const QtPointFPropertyManagerPrivate::PropertyValueMap::const_iterator it = d_ptr->m_values.constFind(property); + if (it == d_ptr->m_values.constEnd()) + return QString(); + const QPointF v = it.value().val; + const int dec = it.value().decimals; + return QString(tr("(%1, %2)").arg(QString::number(v.x(), 'f', dec)) + .arg(QString::number(v.y(), 'f', dec))); +} + +/*! + \fn void QtPointFPropertyManager::setValue(QtProperty *property, const QPointF &value) + + Sets the value of the given \a property to \a value. Nested + properties are updated automatically. + + \sa value(), valueChanged() +*/ +void QtPointFPropertyManager::setValue(QtProperty *property, const QPointF &val) +{ + const QtPointFPropertyManagerPrivate::PropertyValueMap::iterator it = d_ptr->m_values.find(property); + if (it == d_ptr->m_values.end()) + return; + + if (it.value().val == val) + return; + + it.value().val = val; + d_ptr->m_doublePropertyManager->setValue(d_ptr->m_propertyToX[property], val.x()); + d_ptr->m_doublePropertyManager->setValue(d_ptr->m_propertyToY[property], val.y()); + + emit propertyChanged(property); + emit valueChanged(property, val); +} + +/*! + \fn void QtPointFPropertyManager::setDecimals(QtProperty *property, int prec) + + Sets the precision of the given \a property to \a prec. + + The valid decimal range is 0-13. The default is 2. + + \sa decimals() +*/ +void QtPointFPropertyManager::setDecimals(QtProperty *property, int prec) +{ + const QtPointFPropertyManagerPrivate::PropertyValueMap::iterator it = d_ptr->m_values.find(property); + if (it == d_ptr->m_values.end()) + return; + + QtPointFPropertyManagerPrivate::Data data = it.value(); + + if (prec > 13) + prec = 13; + else if (prec < 0) + prec = 0; + + if (data.decimals == prec) + return; + + data.decimals = prec; + d_ptr->m_doublePropertyManager->setDecimals(d_ptr->m_propertyToX[property], prec); + d_ptr->m_doublePropertyManager->setDecimals(d_ptr->m_propertyToY[property], prec); + + it.value() = data; + + emit decimalsChanged(property, data.decimals); +} + +/*! + \reimp +*/ +void QtPointFPropertyManager::initializeProperty(QtProperty *property) +{ + d_ptr->m_values[property] = QtPointFPropertyManagerPrivate::Data(); + + QtProperty *xProp = d_ptr->m_doublePropertyManager->addProperty(); + xProp->setPropertyName(tr("X")); + d_ptr->m_doublePropertyManager->setDecimals(xProp, decimals(property)); + d_ptr->m_doublePropertyManager->setValue(xProp, 0); + d_ptr->m_propertyToX[property] = xProp; + d_ptr->m_xToProperty[xProp] = property; + property->addSubProperty(xProp); + + QtProperty *yProp = d_ptr->m_doublePropertyManager->addProperty(); + yProp->setPropertyName(tr("Y")); + d_ptr->m_doublePropertyManager->setDecimals(yProp, decimals(property)); + d_ptr->m_doublePropertyManager->setValue(yProp, 0); + d_ptr->m_propertyToY[property] = yProp; + d_ptr->m_yToProperty[yProp] = property; + property->addSubProperty(yProp); +} + +/*! + \reimp +*/ +void QtPointFPropertyManager::uninitializeProperty(QtProperty *property) +{ + QtProperty *xProp = d_ptr->m_propertyToX[property]; + if (xProp) { + d_ptr->m_xToProperty.remove(xProp); + delete xProp; + } + d_ptr->m_propertyToX.remove(property); + + QtProperty *yProp = d_ptr->m_propertyToY[property]; + if (yProp) { + d_ptr->m_yToProperty.remove(yProp); + delete yProp; + } + d_ptr->m_propertyToY.remove(property); + + d_ptr->m_values.remove(property); +} + +// QtSizePropertyManager + +class QtSizePropertyManagerPrivate +{ + QtSizePropertyManager *q_ptr; + Q_DECLARE_PUBLIC(QtSizePropertyManager) +public: + + void slotIntChanged(QtProperty *property, int value); + void slotPropertyDestroyed(QtProperty *property); + void setValue(QtProperty *property, const QSize &val); + void setRange(QtProperty *property, + const QSize &minVal, const QSize &maxVal, const QSize &val); + + struct Data + { + Data() : val(QSize(0, 0)), minVal(QSize(0, 0)), maxVal(QSize(INT_MAX, INT_MAX)) {} + QSize val; + QSize minVal; + QSize maxVal; + QSize minimumValue() const { return minVal; } + QSize maximumValue() const { return maxVal; } + void setMinimumValue(const QSize &newMinVal) { setSizeMinimumData(this, newMinVal); } + void setMaximumValue(const QSize &newMaxVal) { setSizeMaximumData(this, newMaxVal); } + }; + + typedef QMap<const QtProperty *, Data> PropertyValueMap; + PropertyValueMap m_values; + + QtIntPropertyManager *m_intPropertyManager; + + QMap<const QtProperty *, QtProperty *> m_propertyToW; + QMap<const QtProperty *, QtProperty *> m_propertyToH; + + QMap<const QtProperty *, QtProperty *> m_wToProperty; + QMap<const QtProperty *, QtProperty *> m_hToProperty; +}; + +void QtSizePropertyManagerPrivate::slotIntChanged(QtProperty *property, int value) +{ + if (QtProperty *prop = m_wToProperty.value(property, 0)) { + QSize s = m_values[prop].val; + s.setWidth(value); + q_ptr->setValue(prop, s); + } else if (QtProperty *prop = m_hToProperty.value(property, 0)) { + QSize s = m_values[prop].val; + s.setHeight(value); + q_ptr->setValue(prop, s); + } +} + +void QtSizePropertyManagerPrivate::slotPropertyDestroyed(QtProperty *property) +{ + if (QtProperty *pointProp = m_wToProperty.value(property, 0)) { + m_propertyToW[pointProp] = 0; + m_wToProperty.remove(property); + } else if (QtProperty *pointProp = m_hToProperty.value(property, 0)) { + m_propertyToH[pointProp] = 0; + m_hToProperty.remove(property); + } +} + +void QtSizePropertyManagerPrivate::setValue(QtProperty *property, const QSize &val) +{ + m_intPropertyManager->setValue(m_propertyToW.value(property), val.width()); + m_intPropertyManager->setValue(m_propertyToH.value(property), val.height()); +} + +void QtSizePropertyManagerPrivate::setRange(QtProperty *property, + const QSize &minVal, const QSize &maxVal, const QSize &val) +{ + QtProperty *wProperty = m_propertyToW.value(property); + QtProperty *hProperty = m_propertyToH.value(property); + m_intPropertyManager->setRange(wProperty, minVal.width(), maxVal.width()); + m_intPropertyManager->setValue(wProperty, val.width()); + m_intPropertyManager->setRange(hProperty, minVal.height(), maxVal.height()); + m_intPropertyManager->setValue(hProperty, val.height()); +} + +/*! + \class QtSizePropertyManager + \internal + \inmodule QtDesigner + \since 4.4 + + \brief The QtSizePropertyManager provides and manages QSize properties. + + A size property has nested \e width and \e height + subproperties. The top-level property's value can be retrieved + using the value() function, and set using the setValue() slot. + + The subproperties are created by a QtIntPropertyManager object. This + manager can be retrieved using the subIntPropertyManager() function. In + order to provide editing widgets for the subproperties in a + property browser widget, this manager must be associated with an + editor factory. + + A size property also has a range of valid values defined by a + minimum size and a maximum size. These sizes can be retrieved + using the minimum() and the maximum() functions, and set using the + setMinimum() and setMaximum() slots. Alternatively, the range can + be defined in one go using the setRange() slot. + + In addition, QtSizePropertyManager provides the valueChanged() signal + which is emitted whenever a property created by this manager + changes, and the rangeChanged() signal which is emitted whenever + such a property changes its range of valid sizes. + + \sa QtAbstractPropertyManager, QtIntPropertyManager, QtSizeFPropertyManager +*/ + +/*! + \fn void QtSizePropertyManager::valueChanged(QtProperty *property, const QSize &value) + + This signal is emitted whenever a property created by this manager + changes its value, passing a pointer to the \a property and the new + \a value as parameters. + + \sa setValue() +*/ + +/*! + \fn void QtSizePropertyManager::rangeChanged(QtProperty *property, const QSize &minimum, const QSize &maximum) + + This signal is emitted whenever a property created by this manager + changes its range of valid sizes, passing a pointer to the \a + property and the new \a minimum and \a maximum sizes. + + \sa setRange() +*/ + +/*! + Creates a manager with the given \a parent. +*/ +QtSizePropertyManager::QtSizePropertyManager(QObject *parent) + : QtAbstractPropertyManager(parent) +{ + d_ptr = new QtSizePropertyManagerPrivate; + d_ptr->q_ptr = this; + + d_ptr->m_intPropertyManager = new QtIntPropertyManager(this); + connect(d_ptr->m_intPropertyManager, SIGNAL(valueChanged(QtProperty *, int)), + this, SLOT(slotIntChanged(QtProperty *, int))); + connect(d_ptr->m_intPropertyManager, SIGNAL(propertyDestroyed(QtProperty *)), + this, SLOT(slotPropertyDestroyed(QtProperty *))); +} + +/*! + Destroys this manager, and all the properties it has created. +*/ +QtSizePropertyManager::~QtSizePropertyManager() +{ + clear(); + delete d_ptr; +} + +/*! + Returns the manager that creates the nested \e width and \e height + subproperties. + + In order to provide editing widgets for the \e width and \e height + properties in a property browser widget, this manager must be + associated with an editor factory. + + \sa QtAbstractPropertyBrowser::setFactoryForManager() +*/ +QtIntPropertyManager *QtSizePropertyManager::subIntPropertyManager() const +{ + return d_ptr->m_intPropertyManager; +} + +/*! + Returns the given \a property's value. + + If the given \a property is not managed by this manager, this + function returns an invalid size + + \sa setValue() +*/ +QSize QtSizePropertyManager::value(const QtProperty *property) const +{ + return getValue<QSize>(d_ptr->m_values, property); +} + +/*! + Returns the given \a property's minimum size value. + + \sa setMinimum(), maximum(), setRange() +*/ +QSize QtSizePropertyManager::minimum(const QtProperty *property) const +{ + return getMinimum<QSize>(d_ptr->m_values, property); +} + +/*! + Returns the given \a property's maximum size value. + + \sa setMaximum(), minimum(), setRange() +*/ +QSize QtSizePropertyManager::maximum(const QtProperty *property) const +{ + return getMaximum<QSize>(d_ptr->m_values, property); +} + +/*! + \reimp +*/ +QString QtSizePropertyManager::valueText(const QtProperty *property) const +{ + const QtSizePropertyManagerPrivate::PropertyValueMap::const_iterator it = d_ptr->m_values.constFind(property); + if (it == d_ptr->m_values.constEnd()) + return QString(); + const QSize v = it.value().val; + return QString(tr("%1 x %2").arg(QString::number(v.width())) + .arg(QString::number(v.height()))); +} + +/*! + \fn void QtSizePropertyManager::setValue(QtProperty *property, const QSize &value) + + Sets the value of the given \a property to \a value. + + If the specified \a value is not valid according to the given \a + property's size range, the \a value is adjusted to the nearest + valid value within the size range. + + \sa value(), setRange(), valueChanged() +*/ +void QtSizePropertyManager::setValue(QtProperty *property, const QSize &val) +{ + setValueInRange<const QSize &, QtSizePropertyManagerPrivate, QtSizePropertyManager, const QSize>(this, d_ptr, + &QtSizePropertyManager::propertyChanged, + &QtSizePropertyManager::valueChanged, + property, val, &QtSizePropertyManagerPrivate::setValue); +} + +/*! + Sets the minimum size value for the given \a property to \a minVal. + + When setting the minimum size value, the maximum and current + values are adjusted if necessary (ensuring that the size range + remains valid and that the current value is within the range). + + \sa minimum(), setRange(), rangeChanged() +*/ +void QtSizePropertyManager::setMinimum(QtProperty *property, const QSize &minVal) +{ + setBorderValue<const QSize &, QtSizePropertyManagerPrivate, QtSizePropertyManager, QSize, QtSizePropertyManagerPrivate::Data>(this, d_ptr, + &QtSizePropertyManager::propertyChanged, + &QtSizePropertyManager::valueChanged, + &QtSizePropertyManager::rangeChanged, + property, + &QtSizePropertyManagerPrivate::Data::minimumValue, + &QtSizePropertyManagerPrivate::Data::setMinimumValue, + minVal, &QtSizePropertyManagerPrivate::setRange); +} + +/*! + Sets the maximum size value for the given \a property to \a maxVal. + + When setting the maximum size value, the minimum and current + values are adjusted if necessary (ensuring that the size range + remains valid and that the current value is within the range). + + \sa maximum(), setRange(), rangeChanged() +*/ +void QtSizePropertyManager::setMaximum(QtProperty *property, const QSize &maxVal) +{ + setBorderValue<const QSize &, QtSizePropertyManagerPrivate, QtSizePropertyManager, QSize, QtSizePropertyManagerPrivate::Data>(this, d_ptr, + &QtSizePropertyManager::propertyChanged, + &QtSizePropertyManager::valueChanged, + &QtSizePropertyManager::rangeChanged, + property, + &QtSizePropertyManagerPrivate::Data::maximumValue, + &QtSizePropertyManagerPrivate::Data::setMaximumValue, + maxVal, &QtSizePropertyManagerPrivate::setRange); +} + +/*! + \fn void QtSizePropertyManager::setRange(QtProperty *property, const QSize &minimum, const QSize &maximum) + + Sets the range of valid values. + + This is a convenience function defining the range of valid values + in one go; setting the \a minimum and \a maximum values for the + given \a property with a single function call. + + When setting a new range, the current value is adjusted if + necessary (ensuring that the value remains within the range). + + \sa setMinimum(), setMaximum(), rangeChanged() +*/ +void QtSizePropertyManager::setRange(QtProperty *property, const QSize &minVal, const QSize &maxVal) +{ + setBorderValues<const QSize &, QtSizePropertyManagerPrivate, QtSizePropertyManager, QSize>(this, d_ptr, + &QtSizePropertyManager::propertyChanged, + &QtSizePropertyManager::valueChanged, + &QtSizePropertyManager::rangeChanged, + property, minVal, maxVal, &QtSizePropertyManagerPrivate::setRange); +} + +/*! + \reimp +*/ +void QtSizePropertyManager::initializeProperty(QtProperty *property) +{ + d_ptr->m_values[property] = QtSizePropertyManagerPrivate::Data(); + + QtProperty *wProp = d_ptr->m_intPropertyManager->addProperty(); + wProp->setPropertyName(tr("Width")); + d_ptr->m_intPropertyManager->setValue(wProp, 0); + d_ptr->m_intPropertyManager->setMinimum(wProp, 0); + d_ptr->m_propertyToW[property] = wProp; + d_ptr->m_wToProperty[wProp] = property; + property->addSubProperty(wProp); + + QtProperty *hProp = d_ptr->m_intPropertyManager->addProperty(); + hProp->setPropertyName(tr("Height")); + d_ptr->m_intPropertyManager->setValue(hProp, 0); + d_ptr->m_intPropertyManager->setMinimum(hProp, 0); + d_ptr->m_propertyToH[property] = hProp; + d_ptr->m_hToProperty[hProp] = property; + property->addSubProperty(hProp); +} + +/*! + \reimp +*/ +void QtSizePropertyManager::uninitializeProperty(QtProperty *property) +{ + QtProperty *wProp = d_ptr->m_propertyToW[property]; + if (wProp) { + d_ptr->m_wToProperty.remove(wProp); + delete wProp; + } + d_ptr->m_propertyToW.remove(property); + + QtProperty *hProp = d_ptr->m_propertyToH[property]; + if (hProp) { + d_ptr->m_hToProperty.remove(hProp); + delete hProp; + } + d_ptr->m_propertyToH.remove(property); + + d_ptr->m_values.remove(property); +} + +// QtSizeFPropertyManager + +class QtSizeFPropertyManagerPrivate +{ + QtSizeFPropertyManager *q_ptr; + Q_DECLARE_PUBLIC(QtSizeFPropertyManager) +public: + + void slotDoubleChanged(QtProperty *property, double value); + void slotPropertyDestroyed(QtProperty *property); + void setValue(QtProperty *property, const QSizeF &val); + void setRange(QtProperty *property, + const QSizeF &minVal, const QSizeF &maxVal, const QSizeF &val); + + struct Data + { + Data() : val(QSizeF(0, 0)), minVal(QSizeF(0, 0)), maxVal(QSizeF(INT_MAX, INT_MAX)), decimals(2) {} + QSizeF val; + QSizeF minVal; + QSizeF maxVal; + int decimals; + QSizeF minimumValue() const { return minVal; } + QSizeF maximumValue() const { return maxVal; } + void setMinimumValue(const QSizeF &newMinVal) { setSizeMinimumData(this, newMinVal); } + void setMaximumValue(const QSizeF &newMaxVal) { setSizeMaximumData(this, newMaxVal); } + }; + + typedef QMap<const QtProperty *, Data> PropertyValueMap; + PropertyValueMap m_values; + + QtDoublePropertyManager *m_doublePropertyManager; + + QMap<const QtProperty *, QtProperty *> m_propertyToW; + QMap<const QtProperty *, QtProperty *> m_propertyToH; + + QMap<const QtProperty *, QtProperty *> m_wToProperty; + QMap<const QtProperty *, QtProperty *> m_hToProperty; +}; + +void QtSizeFPropertyManagerPrivate::slotDoubleChanged(QtProperty *property, double value) +{ + if (QtProperty *prop = m_wToProperty.value(property, 0)) { + QSizeF s = m_values[prop].val; + s.setWidth(value); + q_ptr->setValue(prop, s); + } else if (QtProperty *prop = m_hToProperty.value(property, 0)) { + QSizeF s = m_values[prop].val; + s.setHeight(value); + q_ptr->setValue(prop, s); + } +} + +void QtSizeFPropertyManagerPrivate::slotPropertyDestroyed(QtProperty *property) +{ + if (QtProperty *pointProp = m_wToProperty.value(property, 0)) { + m_propertyToW[pointProp] = 0; + m_wToProperty.remove(property); + } else if (QtProperty *pointProp = m_hToProperty.value(property, 0)) { + m_propertyToH[pointProp] = 0; + m_hToProperty.remove(property); + } +} + +void QtSizeFPropertyManagerPrivate::setValue(QtProperty *property, const QSizeF &val) +{ + m_doublePropertyManager->setValue(m_propertyToW.value(property), val.width()); + m_doublePropertyManager->setValue(m_propertyToH.value(property), val.height()); +} + +void QtSizeFPropertyManagerPrivate::setRange(QtProperty *property, + const QSizeF &minVal, const QSizeF &maxVal, const QSizeF &val) +{ + m_doublePropertyManager->setRange(m_propertyToW[property], minVal.width(), maxVal.width()); + m_doublePropertyManager->setValue(m_propertyToW[property], val.width()); + m_doublePropertyManager->setRange(m_propertyToH[property], minVal.height(), maxVal.height()); + m_doublePropertyManager->setValue(m_propertyToH[property], val.height()); +} + +/*! + \class QtSizeFPropertyManager + \internal + \inmodule QtDesigner + \since 4.4 + + \brief The QtSizeFPropertyManager provides and manages QSizeF properties. + + A size property has nested \e width and \e height + subproperties. The top-level property's value can be retrieved + using the value() function, and set using the setValue() slot. + + The subproperties are created by a QtDoublePropertyManager object. This + manager can be retrieved using the subDoublePropertyManager() function. In + order to provide editing widgets for the subproperties in a + property browser widget, this manager must be associated with an + editor factory. + + A size property also has a range of valid values defined by a + minimum size and a maximum size. These sizes can be retrieved + using the minimum() and the maximum() functions, and set using the + setMinimum() and setMaximum() slots. Alternatively, the range can + be defined in one go using the setRange() slot. + + In addition, QtSizeFPropertyManager provides the valueChanged() signal + which is emitted whenever a property created by this manager + changes, and the rangeChanged() signal which is emitted whenever + such a property changes its range of valid sizes. + + \sa QtAbstractPropertyManager, QtDoublePropertyManager, QtSizePropertyManager +*/ + +/*! + \fn void QtSizeFPropertyManager::valueChanged(QtProperty *property, const QSizeF &value) + + This signal is emitted whenever a property created by this manager + changes its value, passing a pointer to the \a property and the new + \a value as parameters. + + \sa setValue() +*/ + +/*! + \fn void QtSizeFPropertyManager::rangeChanged(QtProperty *property, const QSizeF &minimum, const QSizeF &maximum) + + This signal is emitted whenever a property created by this manager + changes its range of valid sizes, passing a pointer to the \a + property and the new \a minimum and \a maximum sizes. + + \sa setRange() +*/ + +/*! + \fn void QtSizeFPropertyManager::decimalsChanged(QtProperty *property, int prec) + + This signal is emitted whenever a property created by this manager + changes its precision of value, passing a pointer to the + \a property and the new \a prec value + + \sa setDecimals() +*/ + +/*! + Creates a manager with the given \a parent. +*/ +QtSizeFPropertyManager::QtSizeFPropertyManager(QObject *parent) + : QtAbstractPropertyManager(parent) +{ + d_ptr = new QtSizeFPropertyManagerPrivate; + d_ptr->q_ptr = this; + + d_ptr->m_doublePropertyManager = new QtDoublePropertyManager(this); + connect(d_ptr->m_doublePropertyManager, SIGNAL(valueChanged(QtProperty *, double)), + this, SLOT(slotDoubleChanged(QtProperty *, double))); + connect(d_ptr->m_doublePropertyManager, SIGNAL(propertyDestroyed(QtProperty *)), + this, SLOT(slotPropertyDestroyed(QtProperty *))); +} + +/*! + Destroys this manager, and all the properties it has created. +*/ +QtSizeFPropertyManager::~QtSizeFPropertyManager() +{ + clear(); + delete d_ptr; +} + +/*! + Returns the manager that creates the nested \e width and \e height + subproperties. + + In order to provide editing widgets for the \e width and \e height + properties in a property browser widget, this manager must be + associated with an editor factory. + + \sa QtAbstractPropertyBrowser::setFactoryForManager() +*/ +QtDoublePropertyManager *QtSizeFPropertyManager::subDoublePropertyManager() const +{ + return d_ptr->m_doublePropertyManager; +} + +/*! + Returns the given \a property's value. + + If the given \a property is not managed by this manager, this + function returns an invalid size + + \sa setValue() +*/ +QSizeF QtSizeFPropertyManager::value(const QtProperty *property) const +{ + return getValue<QSizeF>(d_ptr->m_values, property); +} + +/*! + Returns the given \a property's precision, in decimals. + + \sa setDecimals() +*/ +int QtSizeFPropertyManager::decimals(const QtProperty *property) const +{ + return getData<int>(d_ptr->m_values, &QtSizeFPropertyManagerPrivate::Data::decimals, property, 0); +} + +/*! + Returns the given \a property's minimum size value. + + \sa setMinimum(), maximum(), setRange() +*/ +QSizeF QtSizeFPropertyManager::minimum(const QtProperty *property) const +{ + return getMinimum<QSizeF>(d_ptr->m_values, property); +} + +/*! + Returns the given \a property's maximum size value. + + \sa setMaximum(), minimum(), setRange() +*/ +QSizeF QtSizeFPropertyManager::maximum(const QtProperty *property) const +{ + return getMaximum<QSizeF>(d_ptr->m_values, property); +} + +/*! + \reimp +*/ +QString QtSizeFPropertyManager::valueText(const QtProperty *property) const +{ + const QtSizeFPropertyManagerPrivate::PropertyValueMap::const_iterator it = d_ptr->m_values.constFind(property); + if (it == d_ptr->m_values.constEnd()) + return QString(); + const QSizeF v = it.value().val; + const int dec = it.value().decimals; + return QString(tr("%1 x %2").arg(QString::number(v.width(), 'f', dec)) + .arg(QString::number(v.height(), 'f', dec))); +} + +/*! + \fn void QtSizeFPropertyManager::setValue(QtProperty *property, const QSizeF &value) + + Sets the value of the given \a property to \a value. + + If the specified \a value is not valid according to the given \a + property's size range, the \a value is adjusted to the nearest + valid value within the size range. + + \sa value(), setRange(), valueChanged() +*/ +void QtSizeFPropertyManager::setValue(QtProperty *property, const QSizeF &val) +{ + setValueInRange<const QSizeF &, QtSizeFPropertyManagerPrivate, QtSizeFPropertyManager, QSizeF>(this, d_ptr, + &QtSizeFPropertyManager::propertyChanged, + &QtSizeFPropertyManager::valueChanged, + property, val, &QtSizeFPropertyManagerPrivate::setValue); +} + +/*! + \fn void QtSizeFPropertyManager::setDecimals(QtProperty *property, int prec) + + Sets the precision of the given \a property to \a prec. + + The valid decimal range is 0-13. The default is 2. + + \sa decimals() +*/ +void QtSizeFPropertyManager::setDecimals(QtProperty *property, int prec) +{ + const QtSizeFPropertyManagerPrivate::PropertyValueMap::iterator it = d_ptr->m_values.find(property); + if (it == d_ptr->m_values.end()) + return; + + QtSizeFPropertyManagerPrivate::Data data = it.value(); + + if (prec > 13) + prec = 13; + else if (prec < 0) + prec = 0; + + if (data.decimals == prec) + return; + + data.decimals = prec; + d_ptr->m_doublePropertyManager->setDecimals(d_ptr->m_propertyToW[property], prec); + d_ptr->m_doublePropertyManager->setDecimals(d_ptr->m_propertyToH[property], prec); + + it.value() = data; + + emit decimalsChanged(property, data.decimals); +} + +/*! + Sets the minimum size value for the given \a property to \a minVal. + + When setting the minimum size value, the maximum and current + values are adjusted if necessary (ensuring that the size range + remains valid and that the current value is within the range). + + \sa minimum(), setRange(), rangeChanged() +*/ +void QtSizeFPropertyManager::setMinimum(QtProperty *property, const QSizeF &minVal) +{ + setBorderValue<const QSizeF &, QtSizeFPropertyManagerPrivate, QtSizeFPropertyManager, QSizeF, QtSizeFPropertyManagerPrivate::Data>(this, d_ptr, + &QtSizeFPropertyManager::propertyChanged, + &QtSizeFPropertyManager::valueChanged, + &QtSizeFPropertyManager::rangeChanged, + property, + &QtSizeFPropertyManagerPrivate::Data::minimumValue, + &QtSizeFPropertyManagerPrivate::Data::setMinimumValue, + minVal, &QtSizeFPropertyManagerPrivate::setRange); +} + +/*! + Sets the maximum size value for the given \a property to \a maxVal. + + When setting the maximum size value, the minimum and current + values are adjusted if necessary (ensuring that the size range + remains valid and that the current value is within the range). + + \sa maximum(), setRange(), rangeChanged() +*/ +void QtSizeFPropertyManager::setMaximum(QtProperty *property, const QSizeF &maxVal) +{ + setBorderValue<const QSizeF &, QtSizeFPropertyManagerPrivate, QtSizeFPropertyManager, QSizeF, QtSizeFPropertyManagerPrivate::Data>(this, d_ptr, + &QtSizeFPropertyManager::propertyChanged, + &QtSizeFPropertyManager::valueChanged, + &QtSizeFPropertyManager::rangeChanged, + property, + &QtSizeFPropertyManagerPrivate::Data::maximumValue, + &QtSizeFPropertyManagerPrivate::Data::setMaximumValue, + maxVal, &QtSizeFPropertyManagerPrivate::setRange); +} + +/*! + \fn void QtSizeFPropertyManager::setRange(QtProperty *property, const QSizeF &minimum, const QSizeF &maximum) + + Sets the range of valid values. + + This is a convenience function defining the range of valid values + in one go; setting the \a minimum and \a maximum values for the + given \a property with a single function call. + + When setting a new range, the current value is adjusted if + necessary (ensuring that the value remains within the range). + + \sa setMinimum(), setMaximum(), rangeChanged() +*/ +void QtSizeFPropertyManager::setRange(QtProperty *property, const QSizeF &minVal, const QSizeF &maxVal) +{ + setBorderValues<const QSizeF &, QtSizeFPropertyManagerPrivate, QtSizeFPropertyManager, QSizeF>(this, d_ptr, + &QtSizeFPropertyManager::propertyChanged, + &QtSizeFPropertyManager::valueChanged, + &QtSizeFPropertyManager::rangeChanged, + property, minVal, maxVal, &QtSizeFPropertyManagerPrivate::setRange); +} + +/*! + \reimp +*/ +void QtSizeFPropertyManager::initializeProperty(QtProperty *property) +{ + d_ptr->m_values[property] = QtSizeFPropertyManagerPrivate::Data(); + + QtProperty *wProp = d_ptr->m_doublePropertyManager->addProperty(); + wProp->setPropertyName(tr("Width")); + d_ptr->m_doublePropertyManager->setDecimals(wProp, decimals(property)); + d_ptr->m_doublePropertyManager->setValue(wProp, 0); + d_ptr->m_doublePropertyManager->setMinimum(wProp, 0); + d_ptr->m_propertyToW[property] = wProp; + d_ptr->m_wToProperty[wProp] = property; + property->addSubProperty(wProp); + + QtProperty *hProp = d_ptr->m_doublePropertyManager->addProperty(); + hProp->setPropertyName(tr("Height")); + d_ptr->m_doublePropertyManager->setDecimals(hProp, decimals(property)); + d_ptr->m_doublePropertyManager->setValue(hProp, 0); + d_ptr->m_doublePropertyManager->setMinimum(hProp, 0); + d_ptr->m_propertyToH[property] = hProp; + d_ptr->m_hToProperty[hProp] = property; + property->addSubProperty(hProp); +} + +/*! + \reimp +*/ +void QtSizeFPropertyManager::uninitializeProperty(QtProperty *property) +{ + QtProperty *wProp = d_ptr->m_propertyToW[property]; + if (wProp) { + d_ptr->m_wToProperty.remove(wProp); + delete wProp; + } + d_ptr->m_propertyToW.remove(property); + + QtProperty *hProp = d_ptr->m_propertyToH[property]; + if (hProp) { + d_ptr->m_hToProperty.remove(hProp); + delete hProp; + } + d_ptr->m_propertyToH.remove(property); + + d_ptr->m_values.remove(property); +} + +// QtRectPropertyManager + +class QtRectPropertyManagerPrivate +{ + QtRectPropertyManager *q_ptr; + Q_DECLARE_PUBLIC(QtRectPropertyManager) +public: + + void slotIntChanged(QtProperty *property, int value); + void slotPropertyDestroyed(QtProperty *property); + void setConstraint(QtProperty *property, const QRect &constraint, const QRect &val); + + struct Data + { + Data() : val(0, 0, 0, 0) {} + QRect val; + QRect constraint; + }; + + typedef QMap<const QtProperty *, Data> PropertyValueMap; + PropertyValueMap m_values; + + QtIntPropertyManager *m_intPropertyManager; + + QMap<const QtProperty *, QtProperty *> m_propertyToX; + QMap<const QtProperty *, QtProperty *> m_propertyToY; + QMap<const QtProperty *, QtProperty *> m_propertyToW; + QMap<const QtProperty *, QtProperty *> m_propertyToH; + + QMap<const QtProperty *, QtProperty *> m_xToProperty; + QMap<const QtProperty *, QtProperty *> m_yToProperty; + QMap<const QtProperty *, QtProperty *> m_wToProperty; + QMap<const QtProperty *, QtProperty *> m_hToProperty; +}; + +void QtRectPropertyManagerPrivate::slotIntChanged(QtProperty *property, int value) +{ + if (QtProperty *prop = m_xToProperty.value(property, 0)) { + QRect r = m_values[prop].val; + r.moveLeft(value); + q_ptr->setValue(prop, r); + } else if (QtProperty *prop = m_yToProperty.value(property)) { + QRect r = m_values[prop].val; + r.moveTop(value); + q_ptr->setValue(prop, r); + } else if (QtProperty *prop = m_wToProperty.value(property, 0)) { + Data data = m_values[prop]; + QRect r = data.val; + r.setWidth(value); + if (!data.constraint.isNull() && data.constraint.x() + data.constraint.width() < r.x() + r.width()) { + r.moveLeft(data.constraint.left() + data.constraint.width() - r.width()); + } + q_ptr->setValue(prop, r); + } else if (QtProperty *prop = m_hToProperty.value(property, 0)) { + Data data = m_values[prop]; + QRect r = data.val; + r.setHeight(value); + if (!data.constraint.isNull() && data.constraint.y() + data.constraint.height() < r.y() + r.height()) { + r.moveTop(data.constraint.top() + data.constraint.height() - r.height()); + } + q_ptr->setValue(prop, r); + } +} + +void QtRectPropertyManagerPrivate::slotPropertyDestroyed(QtProperty *property) +{ + if (QtProperty *pointProp = m_xToProperty.value(property, 0)) { + m_propertyToX[pointProp] = 0; + m_xToProperty.remove(property); + } else if (QtProperty *pointProp = m_yToProperty.value(property, 0)) { + m_propertyToY[pointProp] = 0; + m_yToProperty.remove(property); + } else if (QtProperty *pointProp = m_wToProperty.value(property, 0)) { + m_propertyToW[pointProp] = 0; + m_wToProperty.remove(property); + } else if (QtProperty *pointProp = m_hToProperty.value(property, 0)) { + m_propertyToH[pointProp] = 0; + m_hToProperty.remove(property); + } +} + +void QtRectPropertyManagerPrivate::setConstraint(QtProperty *property, + const QRect &constraint, const QRect &val) +{ + const bool isNull = constraint.isNull(); + const int left = isNull ? INT_MIN : constraint.left(); + const int right = isNull ? INT_MAX : constraint.left() + constraint.width(); + const int top = isNull ? INT_MIN : constraint.top(); + const int bottom = isNull ? INT_MAX : constraint.top() + constraint.height(); + const int width = isNull ? INT_MAX : constraint.width(); + const int height = isNull ? INT_MAX : constraint.height(); + + m_intPropertyManager->setRange(m_propertyToX[property], left, right); + m_intPropertyManager->setRange(m_propertyToY[property], top, bottom); + m_intPropertyManager->setRange(m_propertyToW[property], 0, width); + m_intPropertyManager->setRange(m_propertyToH[property], 0, height); + + m_intPropertyManager->setValue(m_propertyToX[property], val.x()); + m_intPropertyManager->setValue(m_propertyToY[property], val.y()); + m_intPropertyManager->setValue(m_propertyToW[property], val.width()); + m_intPropertyManager->setValue(m_propertyToH[property], val.height()); +} + +/*! + \class QtRectPropertyManager + \internal + \inmodule QtDesigner + \since 4.4 + + \brief The QtRectPropertyManager provides and manages QRect properties. + + A rectangle property has nested \e x, \e y, \e width and \e height + subproperties. The top-level property's value can be retrieved + using the value() function, and set using the setValue() slot. + + The subproperties are created by a QtIntPropertyManager object. This + manager can be retrieved using the subIntPropertyManager() function. In + order to provide editing widgets for the subproperties in a + property browser widget, this manager must be associated with an + editor factory. + + A rectangle property also has a constraint rectangle which can be + retrieved using the constraint() function, and set using the + setConstraint() slot. + + In addition, QtRectPropertyManager provides the valueChanged() signal + which is emitted whenever a property created by this manager + changes, and the constraintChanged() signal which is emitted + whenever such a property changes its constraint rectangle. + + \sa QtAbstractPropertyManager, QtIntPropertyManager, QtRectFPropertyManager +*/ + +/*! + \fn void QtRectPropertyManager::valueChanged(QtProperty *property, const QRect &value) + + This signal is emitted whenever a property created by this manager + changes its value, passing a pointer to the \a property and the new + \a value as parameters. + + \sa setValue() +*/ + +/*! + \fn void QtRectPropertyManager::constraintChanged(QtProperty *property, const QRect &constraint) + + This signal is emitted whenever property changes its constraint + rectangle, passing a pointer to the \a property and the new \a + constraint rectangle as parameters. + + \sa setConstraint() +*/ + +/*! + Creates a manager with the given \a parent. +*/ +QtRectPropertyManager::QtRectPropertyManager(QObject *parent) + : QtAbstractPropertyManager(parent) +{ + d_ptr = new QtRectPropertyManagerPrivate; + d_ptr->q_ptr = this; + + d_ptr->m_intPropertyManager = new QtIntPropertyManager(this); + connect(d_ptr->m_intPropertyManager, SIGNAL(valueChanged(QtProperty *, int)), + this, SLOT(slotIntChanged(QtProperty *, int))); + connect(d_ptr->m_intPropertyManager, SIGNAL(propertyDestroyed(QtProperty *)), + this, SLOT(slotPropertyDestroyed(QtProperty *))); +} + +/*! + Destroys this manager, and all the properties it has created. +*/ +QtRectPropertyManager::~QtRectPropertyManager() +{ + clear(); + delete d_ptr; +} + +/*! + Returns the manager that creates the nested \e x, \e y, \e width + and \e height subproperties. + + In order to provide editing widgets for the mentioned + subproperties in a property browser widget, this manager must be + associated with an editor factory. + + \sa QtAbstractPropertyBrowser::setFactoryForManager() +*/ +QtIntPropertyManager *QtRectPropertyManager::subIntPropertyManager() const +{ + return d_ptr->m_intPropertyManager; +} + +/*! + Returns the given \a property's value. + + If the given \a property is not managed by this manager, this + function returns an invalid rectangle. + + \sa setValue(), constraint() +*/ +QRect QtRectPropertyManager::value(const QtProperty *property) const +{ + return getValue<QRect>(d_ptr->m_values, property); +} + +/*! + Returns the given \a property's constraining rectangle. If returned value is null QRect it means there is no constraint applied. + + \sa value(), setConstraint() +*/ +QRect QtRectPropertyManager::constraint(const QtProperty *property) const +{ + return getData<QRect>(d_ptr->m_values, &QtRectPropertyManagerPrivate::Data::constraint, property, QRect()); +} + +/*! + \reimp +*/ +QString QtRectPropertyManager::valueText(const QtProperty *property) const +{ + const QtRectPropertyManagerPrivate::PropertyValueMap::const_iterator it = d_ptr->m_values.constFind(property); + if (it == d_ptr->m_values.constEnd()) + return QString(); + const QRect v = it.value().val; + return QString(tr("[(%1, %2), %3 x %4]").arg(QString::number(v.x())) + .arg(QString::number(v.y())) + .arg(QString::number(v.width())) + .arg(QString::number(v.height()))); +} + +/*! + \fn void QtRectPropertyManager::setValue(QtProperty *property, const QRect &value) + + Sets the value of the given \a property to \a value. Nested + properties are updated automatically. + + If the specified \a value is not inside the given \a property's + constraining rectangle, the value is adjusted accordingly to fit + within the constraint. + + \sa value(), setConstraint(), valueChanged() +*/ +void QtRectPropertyManager::setValue(QtProperty *property, const QRect &val) +{ + const QtRectPropertyManagerPrivate::PropertyValueMap::iterator it = d_ptr->m_values.find(property); + if (it == d_ptr->m_values.end()) + return; + + QtRectPropertyManagerPrivate::Data data = it.value(); + + QRect newRect = val.normalized(); + if (!data.constraint.isNull() && !data.constraint.contains(newRect)) { + const QRect r1 = data.constraint; + const QRect r2 = newRect; + newRect.setLeft(qMax(r1.left(), r2.left())); + newRect.setRight(qMin(r1.right(), r2.right())); + newRect.setTop(qMax(r1.top(), r2.top())); + newRect.setBottom(qMin(r1.bottom(), r2.bottom())); + if (newRect.width() < 0 || newRect.height() < 0) + return; + } + + if (data.val == newRect) + return; + + data.val = newRect; + + it.value() = data; + d_ptr->m_intPropertyManager->setValue(d_ptr->m_propertyToX[property], newRect.x()); + d_ptr->m_intPropertyManager->setValue(d_ptr->m_propertyToY[property], newRect.y()); + d_ptr->m_intPropertyManager->setValue(d_ptr->m_propertyToW[property], newRect.width()); + d_ptr->m_intPropertyManager->setValue(d_ptr->m_propertyToH[property], newRect.height()); + + emit propertyChanged(property); + emit valueChanged(property, data.val); +} + +/*! + Sets the given \a property's constraining rectangle to \a + constraint. + + When setting the constraint, the current value is adjusted if + necessary (ensuring that the current rectangle value is inside the + constraint). In order to reset the constraint pass a null QRect value. + + \sa setValue(), constraint(), constraintChanged() +*/ +void QtRectPropertyManager::setConstraint(QtProperty *property, const QRect &constraint) +{ + const QtRectPropertyManagerPrivate::PropertyValueMap::iterator it = d_ptr->m_values.find(property); + if (it == d_ptr->m_values.end()) + return; + + QtRectPropertyManagerPrivate::Data data = it.value(); + + QRect newConstraint = constraint.normalized(); + if (data.constraint == newConstraint) + return; + + const QRect oldVal = data.val; + + data.constraint = newConstraint; + + if (!data.constraint.isNull() && !data.constraint.contains(oldVal)) { + QRect r1 = data.constraint; + QRect r2 = data.val; + + if (r2.width() > r1.width()) + r2.setWidth(r1.width()); + if (r2.height() > r1.height()) + r2.setHeight(r1.height()); + if (r2.left() < r1.left()) + r2.moveLeft(r1.left()); + else if (r2.right() > r1.right()) + r2.moveRight(r1.right()); + if (r2.top() < r1.top()) + r2.moveTop(r1.top()); + else if (r2.bottom() > r1.bottom()) + r2.moveBottom(r1.bottom()); + + data.val = r2; + } + + it.value() = data; + + emit constraintChanged(property, data.constraint); + + d_ptr->setConstraint(property, data.constraint, data.val); + + if (data.val == oldVal) + return; + + emit propertyChanged(property); + emit valueChanged(property, data.val); +} + +/*! + \reimp +*/ +void QtRectPropertyManager::initializeProperty(QtProperty *property) +{ + d_ptr->m_values[property] = QtRectPropertyManagerPrivate::Data(); + + QtProperty *xProp = d_ptr->m_intPropertyManager->addProperty(); + xProp->setPropertyName(tr("X")); + d_ptr->m_intPropertyManager->setValue(xProp, 0); + d_ptr->m_propertyToX[property] = xProp; + d_ptr->m_xToProperty[xProp] = property; + property->addSubProperty(xProp); + + QtProperty *yProp = d_ptr->m_intPropertyManager->addProperty(); + yProp->setPropertyName(tr("Y")); + d_ptr->m_intPropertyManager->setValue(yProp, 0); + d_ptr->m_propertyToY[property] = yProp; + d_ptr->m_yToProperty[yProp] = property; + property->addSubProperty(yProp); + + QtProperty *wProp = d_ptr->m_intPropertyManager->addProperty(); + wProp->setPropertyName(tr("Width")); + d_ptr->m_intPropertyManager->setValue(wProp, 0); + d_ptr->m_intPropertyManager->setMinimum(wProp, 0); + d_ptr->m_propertyToW[property] = wProp; + d_ptr->m_wToProperty[wProp] = property; + property->addSubProperty(wProp); + + QtProperty *hProp = d_ptr->m_intPropertyManager->addProperty(); + hProp->setPropertyName(tr("Height")); + d_ptr->m_intPropertyManager->setValue(hProp, 0); + d_ptr->m_intPropertyManager->setMinimum(hProp, 0); + d_ptr->m_propertyToH[property] = hProp; + d_ptr->m_hToProperty[hProp] = property; + property->addSubProperty(hProp); +} + +/*! + \reimp +*/ +void QtRectPropertyManager::uninitializeProperty(QtProperty *property) +{ + QtProperty *xProp = d_ptr->m_propertyToX[property]; + if (xProp) { + d_ptr->m_xToProperty.remove(xProp); + delete xProp; + } + d_ptr->m_propertyToX.remove(property); + + QtProperty *yProp = d_ptr->m_propertyToY[property]; + if (yProp) { + d_ptr->m_yToProperty.remove(yProp); + delete yProp; + } + d_ptr->m_propertyToY.remove(property); + + QtProperty *wProp = d_ptr->m_propertyToW[property]; + if (wProp) { + d_ptr->m_wToProperty.remove(wProp); + delete wProp; + } + d_ptr->m_propertyToW.remove(property); + + QtProperty *hProp = d_ptr->m_propertyToH[property]; + if (hProp) { + d_ptr->m_hToProperty.remove(hProp); + delete hProp; + } + d_ptr->m_propertyToH.remove(property); + + d_ptr->m_values.remove(property); +} + +// QtRectFPropertyManager + +class QtRectFPropertyManagerPrivate +{ + QtRectFPropertyManager *q_ptr; + Q_DECLARE_PUBLIC(QtRectFPropertyManager) +public: + + void slotDoubleChanged(QtProperty *property, double value); + void slotPropertyDestroyed(QtProperty *property); + void setConstraint(QtProperty *property, const QRectF &constraint, const QRectF &val); + + struct Data + { + Data() : val(0, 0, 0, 0), decimals(2) {} + QRectF val; + QRectF constraint; + int decimals; + }; + + typedef QMap<const QtProperty *, Data> PropertyValueMap; + PropertyValueMap m_values; + + QtDoublePropertyManager *m_doublePropertyManager; + + QMap<const QtProperty *, QtProperty *> m_propertyToX; + QMap<const QtProperty *, QtProperty *> m_propertyToY; + QMap<const QtProperty *, QtProperty *> m_propertyToW; + QMap<const QtProperty *, QtProperty *> m_propertyToH; + + QMap<const QtProperty *, QtProperty *> m_xToProperty; + QMap<const QtProperty *, QtProperty *> m_yToProperty; + QMap<const QtProperty *, QtProperty *> m_wToProperty; + QMap<const QtProperty *, QtProperty *> m_hToProperty; +}; + +void QtRectFPropertyManagerPrivate::slotDoubleChanged(QtProperty *property, double value) +{ + if (QtProperty *prop = m_xToProperty.value(property, 0)) { + QRectF r = m_values[prop].val; + r.moveLeft(value); + q_ptr->setValue(prop, r); + } else if (QtProperty *prop = m_yToProperty.value(property, 0)) { + QRectF r = m_values[prop].val; + r.moveTop(value); + q_ptr->setValue(prop, r); + } else if (QtProperty *prop = m_wToProperty.value(property, 0)) { + Data data = m_values[prop]; + QRectF r = data.val; + r.setWidth(value); + if (!data.constraint.isNull() && data.constraint.x() + data.constraint.width() < r.x() + r.width()) { + r.moveLeft(data.constraint.left() + data.constraint.width() - r.width()); + } + q_ptr->setValue(prop, r); + } else if (QtProperty *prop = m_hToProperty.value(property, 0)) { + Data data = m_values[prop]; + QRectF r = data.val; + r.setHeight(value); + if (!data.constraint.isNull() && data.constraint.y() + data.constraint.height() < r.y() + r.height()) { + r.moveTop(data.constraint.top() + data.constraint.height() - r.height()); + } + q_ptr->setValue(prop, r); + } +} + +void QtRectFPropertyManagerPrivate::slotPropertyDestroyed(QtProperty *property) +{ + if (QtProperty *pointProp = m_xToProperty.value(property, 0)) { + m_propertyToX[pointProp] = 0; + m_xToProperty.remove(property); + } else if (QtProperty *pointProp = m_yToProperty.value(property, 0)) { + m_propertyToY[pointProp] = 0; + m_yToProperty.remove(property); + } else if (QtProperty *pointProp = m_wToProperty.value(property, 0)) { + m_propertyToW[pointProp] = 0; + m_wToProperty.remove(property); + } else if (QtProperty *pointProp = m_hToProperty.value(property, 0)) { + m_propertyToH[pointProp] = 0; + m_hToProperty.remove(property); + } +} + +void QtRectFPropertyManagerPrivate::setConstraint(QtProperty *property, + const QRectF &constraint, const QRectF &val) +{ + const bool isNull = constraint.isNull(); + const float left = isNull ? FLT_MIN : constraint.left(); + const float right = isNull ? FLT_MAX : constraint.left() + constraint.width(); + const float top = isNull ? FLT_MIN : constraint.top(); + const float bottom = isNull ? FLT_MAX : constraint.top() + constraint.height(); + const float width = isNull ? FLT_MAX : constraint.width(); + const float height = isNull ? FLT_MAX : constraint.height(); + + m_doublePropertyManager->setRange(m_propertyToX[property], left, right); + m_doublePropertyManager->setRange(m_propertyToY[property], top, bottom); + m_doublePropertyManager->setRange(m_propertyToW[property], 0, width); + m_doublePropertyManager->setRange(m_propertyToH[property], 0, height); + + m_doublePropertyManager->setValue(m_propertyToX[property], val.x()); + m_doublePropertyManager->setValue(m_propertyToY[property], val.y()); + m_doublePropertyManager->setValue(m_propertyToW[property], val.width()); + m_doublePropertyManager->setValue(m_propertyToH[property], val.height()); +} + +/*! + \class QtRectFPropertyManager + \internal + \inmodule QtDesigner + \since 4.4 + + \brief The QtRectFPropertyManager provides and manages QRectF properties. + + A rectangle property has nested \e x, \e y, \e width and \e height + subproperties. The top-level property's value can be retrieved + using the value() function, and set using the setValue() slot. + + The subproperties are created by a QtDoublePropertyManager object. This + manager can be retrieved using the subDoublePropertyManager() function. In + order to provide editing widgets for the subproperties in a + property browser widget, this manager must be associated with an + editor factory. + + A rectangle property also has a constraint rectangle which can be + retrieved using the constraint() function, and set using the + setConstraint() slot. + + In addition, QtRectFPropertyManager provides the valueChanged() signal + which is emitted whenever a property created by this manager + changes, and the constraintChanged() signal which is emitted + whenever such a property changes its constraint rectangle. + + \sa QtAbstractPropertyManager, QtDoublePropertyManager, QtRectPropertyManager +*/ + +/*! + \fn void QtRectFPropertyManager::valueChanged(QtProperty *property, const QRectF &value) + + This signal is emitted whenever a property created by this manager + changes its value, passing a pointer to the \a property and the new + \a value as parameters. + + \sa setValue() +*/ + +/*! + \fn void QtRectFPropertyManager::constraintChanged(QtProperty *property, const QRectF &constraint) + + This signal is emitted whenever property changes its constraint + rectangle, passing a pointer to the \a property and the new \a + constraint rectangle as parameters. + + \sa setConstraint() +*/ + +/*! + \fn void QtRectFPropertyManager::decimalsChanged(QtProperty *property, int prec) + + This signal is emitted whenever a property created by this manager + changes its precision of value, passing a pointer to the + \a property and the new \a prec value + + \sa setDecimals() +*/ + +/*! + Creates a manager with the given \a parent. +*/ +QtRectFPropertyManager::QtRectFPropertyManager(QObject *parent) + : QtAbstractPropertyManager(parent) +{ + d_ptr = new QtRectFPropertyManagerPrivate; + d_ptr->q_ptr = this; + + d_ptr->m_doublePropertyManager = new QtDoublePropertyManager(this); + connect(d_ptr->m_doublePropertyManager, SIGNAL(valueChanged(QtProperty *, double)), + this, SLOT(slotDoubleChanged(QtProperty *, double))); + connect(d_ptr->m_doublePropertyManager, SIGNAL(propertyDestroyed(QtProperty *)), + this, SLOT(slotPropertyDestroyed(QtProperty *))); +} + +/*! + Destroys this manager, and all the properties it has created. +*/ +QtRectFPropertyManager::~QtRectFPropertyManager() +{ + clear(); + delete d_ptr; +} + +/*! + Returns the manager that creates the nested \e x, \e y, \e width + and \e height subproperties. + + In order to provide editing widgets for the mentioned + subproperties in a property browser widget, this manager must be + associated with an editor factory. + + \sa QtAbstractPropertyBrowser::setFactoryForManager() +*/ +QtDoublePropertyManager *QtRectFPropertyManager::subDoublePropertyManager() const +{ + return d_ptr->m_doublePropertyManager; +} + +/*! + Returns the given \a property's value. + + If the given \a property is not managed by this manager, this + function returns an invalid rectangle. + + \sa setValue(), constraint() +*/ +QRectF QtRectFPropertyManager::value(const QtProperty *property) const +{ + return getValue<QRectF>(d_ptr->m_values, property); +} + +/*! + Returns the given \a property's precision, in decimals. + + \sa setDecimals() +*/ +int QtRectFPropertyManager::decimals(const QtProperty *property) const +{ + return getData<int>(d_ptr->m_values, &QtRectFPropertyManagerPrivate::Data::decimals, property, 0); +} + +/*! + Returns the given \a property's constraining rectangle. If returned value is null QRectF it means there is no constraint applied. + + \sa value(), setConstraint() +*/ +QRectF QtRectFPropertyManager::constraint(const QtProperty *property) const +{ + return getData<QRectF>(d_ptr->m_values, &QtRectFPropertyManagerPrivate::Data::constraint, property, QRect()); +} + +/*! + \reimp +*/ +QString QtRectFPropertyManager::valueText(const QtProperty *property) const +{ + const QtRectFPropertyManagerPrivate::PropertyValueMap::const_iterator it = d_ptr->m_values.constFind(property); + if (it == d_ptr->m_values.constEnd()) + return QString(); + const QRectF v = it.value().val; + const int dec = it.value().decimals; + return QString(tr("[(%1, %2), %3 x %4]").arg(QString::number(v.x(), 'f', dec)) + .arg(QString::number(v.y(), 'f', dec)) + .arg(QString::number(v.width(), 'f', dec)) + .arg(QString::number(v.height(), 'f', dec))); +} + +/*! + \fn void QtRectFPropertyManager::setValue(QtProperty *property, const QRectF &value) + + Sets the value of the given \a property to \a value. Nested + properties are updated automatically. + + If the specified \a value is not inside the given \a property's + constraining rectangle, the value is adjusted accordingly to fit + within the constraint. + + \sa value(), setConstraint(), valueChanged() +*/ +void QtRectFPropertyManager::setValue(QtProperty *property, const QRectF &val) +{ + const QtRectFPropertyManagerPrivate::PropertyValueMap::iterator it = d_ptr->m_values.find(property); + if (it == d_ptr->m_values.end()) + return; + + QtRectFPropertyManagerPrivate::Data data = it.value(); + + QRectF newRect = val.normalized(); + if (!data.constraint.isNull() && !data.constraint.contains(newRect)) { + const QRectF r1 = data.constraint; + const QRectF r2 = newRect; + newRect.setLeft(qMax(r1.left(), r2.left())); + newRect.setRight(qMin(r1.right(), r2.right())); + newRect.setTop(qMax(r1.top(), r2.top())); + newRect.setBottom(qMin(r1.bottom(), r2.bottom())); + if (newRect.width() < 0 || newRect.height() < 0) + return; + } + + if (data.val == newRect) + return; + + data.val = newRect; + + it.value() = data; + d_ptr->m_doublePropertyManager->setValue(d_ptr->m_propertyToX[property], newRect.x()); + d_ptr->m_doublePropertyManager->setValue(d_ptr->m_propertyToY[property], newRect.y()); + d_ptr->m_doublePropertyManager->setValue(d_ptr->m_propertyToW[property], newRect.width()); + d_ptr->m_doublePropertyManager->setValue(d_ptr->m_propertyToH[property], newRect.height()); + + emit propertyChanged(property); + emit valueChanged(property, data.val); +} + +/*! + Sets the given \a property's constraining rectangle to \a + constraint. + + When setting the constraint, the current value is adjusted if + necessary (ensuring that the current rectangle value is inside the + constraint). In order to reset the constraint pass a null QRectF value. + + \sa setValue(), constraint(), constraintChanged() +*/ +void QtRectFPropertyManager::setConstraint(QtProperty *property, const QRectF &constraint) +{ + const QtRectFPropertyManagerPrivate::PropertyValueMap::iterator it = d_ptr->m_values.find(property); + if (it == d_ptr->m_values.end()) + return; + + QtRectFPropertyManagerPrivate::Data data = it.value(); + + QRectF newConstraint = constraint.normalized(); + if (data.constraint == newConstraint) + return; + + const QRectF oldVal = data.val; + + data.constraint = newConstraint; + + if (!data.constraint.isNull() && !data.constraint.contains(oldVal)) { + QRectF r1 = data.constraint; + QRectF r2 = data.val; + + if (r2.width() > r1.width()) + r2.setWidth(r1.width()); + if (r2.height() > r1.height()) + r2.setHeight(r1.height()); + if (r2.left() < r1.left()) + r2.moveLeft(r1.left()); + else if (r2.right() > r1.right()) + r2.moveRight(r1.right()); + if (r2.top() < r1.top()) + r2.moveTop(r1.top()); + else if (r2.bottom() > r1.bottom()) + r2.moveBottom(r1.bottom()); + + data.val = r2; + } + + it.value() = data; + + emit constraintChanged(property, data.constraint); + + d_ptr->setConstraint(property, data.constraint, data.val); + + if (data.val == oldVal) + return; + + emit propertyChanged(property); + emit valueChanged(property, data.val); +} + +/*! + \fn void QtRectFPropertyManager::setDecimals(QtProperty *property, int prec) + + Sets the precision of the given \a property to \a prec. + + The valid decimal range is 0-13. The default is 2. + + \sa decimals() +*/ +void QtRectFPropertyManager::setDecimals(QtProperty *property, int prec) +{ + const QtRectFPropertyManagerPrivate::PropertyValueMap::iterator it = d_ptr->m_values.find(property); + if (it == d_ptr->m_values.end()) + return; + + QtRectFPropertyManagerPrivate::Data data = it.value(); + + if (prec > 13) + prec = 13; + else if (prec < 0) + prec = 0; + + if (data.decimals == prec) + return; + + data.decimals = prec; + d_ptr->m_doublePropertyManager->setDecimals(d_ptr->m_propertyToX[property], prec); + d_ptr->m_doublePropertyManager->setDecimals(d_ptr->m_propertyToY[property], prec); + d_ptr->m_doublePropertyManager->setDecimals(d_ptr->m_propertyToW[property], prec); + d_ptr->m_doublePropertyManager->setDecimals(d_ptr->m_propertyToH[property], prec); + + it.value() = data; + + emit decimalsChanged(property, data.decimals); +} + +/*! + \reimp +*/ +void QtRectFPropertyManager::initializeProperty(QtProperty *property) +{ + d_ptr->m_values[property] = QtRectFPropertyManagerPrivate::Data(); + + QtProperty *xProp = d_ptr->m_doublePropertyManager->addProperty(); + xProp->setPropertyName(tr("X")); + d_ptr->m_doublePropertyManager->setDecimals(xProp, decimals(property)); + d_ptr->m_doublePropertyManager->setValue(xProp, 0); + d_ptr->m_propertyToX[property] = xProp; + d_ptr->m_xToProperty[xProp] = property; + property->addSubProperty(xProp); + + QtProperty *yProp = d_ptr->m_doublePropertyManager->addProperty(); + yProp->setPropertyName(tr("Y")); + d_ptr->m_doublePropertyManager->setDecimals(yProp, decimals(property)); + d_ptr->m_doublePropertyManager->setValue(yProp, 0); + d_ptr->m_propertyToY[property] = yProp; + d_ptr->m_yToProperty[yProp] = property; + property->addSubProperty(yProp); + + QtProperty *wProp = d_ptr->m_doublePropertyManager->addProperty(); + wProp->setPropertyName(tr("Width")); + d_ptr->m_doublePropertyManager->setDecimals(wProp, decimals(property)); + d_ptr->m_doublePropertyManager->setValue(wProp, 0); + d_ptr->m_doublePropertyManager->setMinimum(wProp, 0); + d_ptr->m_propertyToW[property] = wProp; + d_ptr->m_wToProperty[wProp] = property; + property->addSubProperty(wProp); + + QtProperty *hProp = d_ptr->m_doublePropertyManager->addProperty(); + hProp->setPropertyName(tr("Height")); + d_ptr->m_doublePropertyManager->setDecimals(hProp, decimals(property)); + d_ptr->m_doublePropertyManager->setValue(hProp, 0); + d_ptr->m_doublePropertyManager->setMinimum(hProp, 0); + d_ptr->m_propertyToH[property] = hProp; + d_ptr->m_hToProperty[hProp] = property; + property->addSubProperty(hProp); +} + +/*! + \reimp +*/ +void QtRectFPropertyManager::uninitializeProperty(QtProperty *property) +{ + QtProperty *xProp = d_ptr->m_propertyToX[property]; + if (xProp) { + d_ptr->m_xToProperty.remove(xProp); + delete xProp; + } + d_ptr->m_propertyToX.remove(property); + + QtProperty *yProp = d_ptr->m_propertyToY[property]; + if (yProp) { + d_ptr->m_yToProperty.remove(yProp); + delete yProp; + } + d_ptr->m_propertyToY.remove(property); + + QtProperty *wProp = d_ptr->m_propertyToW[property]; + if (wProp) { + d_ptr->m_wToProperty.remove(wProp); + delete wProp; + } + d_ptr->m_propertyToW.remove(property); + + QtProperty *hProp = d_ptr->m_propertyToH[property]; + if (hProp) { + d_ptr->m_hToProperty.remove(hProp); + delete hProp; + } + d_ptr->m_propertyToH.remove(property); + + d_ptr->m_values.remove(property); +} + +// QtEnumPropertyManager + +class QtEnumPropertyManagerPrivate +{ + QtEnumPropertyManager *q_ptr; + Q_DECLARE_PUBLIC(QtEnumPropertyManager) +public: + + struct Data + { + Data() : val(-1) {} + int val; + QStringList enumNames; + QMap<int, QIcon> enumIcons; + }; + + typedef QMap<const QtProperty *, Data> PropertyValueMap; + PropertyValueMap m_values; +}; + +/*! + \class QtEnumPropertyManager + \internal + \inmodule QtDesigner + \since 4.4 + + \brief The QtEnumPropertyManager provides and manages enum properties. + + Each enum property has an associated list of enum names which can + be retrieved using the enumNames() function, and set using the + corresponding setEnumNames() function. An enum property's value is + represented by an index in this list, and can be retrieved and set + using the value() and setValue() slots respectively. + + Each enum value can also have an associated icon. The mapping from + values to icons can be set using the setEnumIcons() function and + queried with the enumIcons() function. + + In addition, QtEnumPropertyManager provides the valueChanged() signal + which is emitted whenever a property created by this manager + changes. The enumNamesChanged() or enumIconsChanged() signal is emitted + whenever the list of enum names or icons is altered. + + \sa QtAbstractPropertyManager, QtEnumEditorFactory +*/ + +/*! + \fn void QtEnumPropertyManager::valueChanged(QtProperty *property, int value) + + This signal is emitted whenever a property created by this manager + changes its value, passing a pointer to the \a property and the new + \a value as parameters. + + \sa setValue() +*/ + +/*! + \fn void QtEnumPropertyManager::enumNamesChanged(QtProperty *property, const QStringList &names) + + This signal is emitted whenever a property created by this manager + changes its enum names, passing a pointer to the \a property and + the new \a names as parameters. + + \sa setEnumNames() +*/ + +/*! + \fn void QtEnumPropertyManager::enumIconsChanged(QtProperty *property, const QMap<int, QIcon> &icons) + + This signal is emitted whenever a property created by this manager + changes its enum icons, passing a pointer to the \a property and + the new mapping of values to \a icons as parameters. + + \sa setEnumIcons() +*/ + +/*! + Creates a manager with the given \a parent. +*/ +QtEnumPropertyManager::QtEnumPropertyManager(QObject *parent) + : QtAbstractPropertyManager(parent) +{ + d_ptr = new QtEnumPropertyManagerPrivate; + d_ptr->q_ptr = this; +} + +/*! + Destroys this manager, and all the properties it has created. +*/ +QtEnumPropertyManager::~QtEnumPropertyManager() +{ + clear(); + delete d_ptr; +} + +/*! + Returns the given \a property's value which is an index in the + list returned by enumNames() + + If the given property is not managed by this manager, this + function returns -1. + + \sa enumNames(), setValue() +*/ +int QtEnumPropertyManager::value(const QtProperty *property) const +{ + return getValue<int>(d_ptr->m_values, property, -1); +} + +/*! + Returns the given \a property's list of enum names. + + \sa value(), setEnumNames() +*/ +QStringList QtEnumPropertyManager::enumNames(const QtProperty *property) const +{ + return getData<QStringList>(d_ptr->m_values, &QtEnumPropertyManagerPrivate::Data::enumNames, property, QStringList()); +} + +/*! + Returns the given \a property's map of enum values to their icons. + + \sa value(), setEnumIcons() +*/ +QMap<int, QIcon> QtEnumPropertyManager::enumIcons(const QtProperty *property) const +{ + return getData<QMap<int, QIcon> >(d_ptr->m_values, &QtEnumPropertyManagerPrivate::Data::enumIcons, property, QMap<int, QIcon>()); +} + +/*! + \reimp +*/ +QString QtEnumPropertyManager::valueText(const QtProperty *property) const +{ + const QtEnumPropertyManagerPrivate::PropertyValueMap::const_iterator it = d_ptr->m_values.constFind(property); + if (it == d_ptr->m_values.constEnd()) + return QString(); + + const QtEnumPropertyManagerPrivate::Data &data = it.value(); + + const int v = data.val; + if (v >= 0 && v < data.enumNames.count()) + return data.enumNames.at(v); + return QString(); +} + +/*! + \reimp +*/ +QIcon QtEnumPropertyManager::valueIcon(const QtProperty *property) const +{ + const QtEnumPropertyManagerPrivate::PropertyValueMap::const_iterator it = d_ptr->m_values.constFind(property); + if (it == d_ptr->m_values.constEnd()) + return QIcon(); + + const QtEnumPropertyManagerPrivate::Data &data = it.value(); + + const int v = data.val; + return data.enumIcons.value(v); +} + +/*! + \fn void QtEnumPropertyManager::setValue(QtProperty *property, int value) + + Sets the value of the given \a property to \a value. + + The specified \a value must be less than the size of the given \a + property's enumNames() list, and larger than (or equal to) 0. + + \sa value(), valueChanged() +*/ +void QtEnumPropertyManager::setValue(QtProperty *property, int val) +{ + const QtEnumPropertyManagerPrivate::PropertyValueMap::iterator it = d_ptr->m_values.find(property); + if (it == d_ptr->m_values.end()) + return; + + QtEnumPropertyManagerPrivate::Data data = it.value(); + + if (val >= data.enumNames.count()) + return; + + if (val < 0 && data.enumNames.count() > 0) + return; + + if (val < 0) + val = -1; + + if (data.val == val) + return; + + data.val = val; + + it.value() = data; + + emit propertyChanged(property); + emit valueChanged(property, data.val); +} + +/*! + Sets the given \a property's list of enum names to \a + enumNames. The \a property's current value is reset to 0 + indicating the first item of the list. + + If the specified \a enumNames list is empty, the \a property's + current value is set to -1. + + \sa enumNames(), enumNamesChanged() +*/ +void QtEnumPropertyManager::setEnumNames(QtProperty *property, const QStringList &enumNames) +{ + const QtEnumPropertyManagerPrivate::PropertyValueMap::iterator it = d_ptr->m_values.find(property); + if (it == d_ptr->m_values.end()) + return; + + QtEnumPropertyManagerPrivate::Data data = it.value(); + + if (data.enumNames == enumNames) + return; + + data.enumNames = enumNames; + + data.val = -1; + + if (enumNames.count() > 0) + data.val = 0; + + it.value() = data; + + emit enumNamesChanged(property, data.enumNames); + + emit propertyChanged(property); + emit valueChanged(property, data.val); +} + +/*! + Sets the given \a property's map of enum values to their icons to \a + enumIcons. + + Each enum value can have associated icon. This association is represented with passed \a enumIcons map. + + \sa enumNames(), enumNamesChanged() +*/ +void QtEnumPropertyManager::setEnumIcons(QtProperty *property, const QMap<int, QIcon> &enumIcons) +{ + const QtEnumPropertyManagerPrivate::PropertyValueMap::iterator it = d_ptr->m_values.find(property); + if (it == d_ptr->m_values.end()) + return; + + it.value().enumIcons = enumIcons; + + emit enumIconsChanged(property, it.value().enumIcons); + + emit propertyChanged(property); +} + +/*! + \reimp +*/ +void QtEnumPropertyManager::initializeProperty(QtProperty *property) +{ + d_ptr->m_values[property] = QtEnumPropertyManagerPrivate::Data(); +} + +/*! + \reimp +*/ +void QtEnumPropertyManager::uninitializeProperty(QtProperty *property) +{ + d_ptr->m_values.remove(property); +} + +// QtFlagPropertyManager + +class QtFlagPropertyManagerPrivate +{ + QtFlagPropertyManager *q_ptr; + Q_DECLARE_PUBLIC(QtFlagPropertyManager) +public: + + void slotBoolChanged(QtProperty *property, bool value); + void slotPropertyDestroyed(QtProperty *property); + + struct Data + { + Data() : val(-1) {} + int val; + QStringList flagNames; + }; + + typedef QMap<const QtProperty *, Data> PropertyValueMap; + PropertyValueMap m_values; + + QtBoolPropertyManager *m_boolPropertyManager; + + QMap<const QtProperty *, QList<QtProperty *> > m_propertyToFlags; + + QMap<const QtProperty *, QtProperty *> m_flagToProperty; +}; + +void QtFlagPropertyManagerPrivate::slotBoolChanged(QtProperty *property, bool value) +{ + QtProperty *prop = m_flagToProperty.value(property, 0); + if (prop == 0) + return; + + QListIterator<QtProperty *> itProp(m_propertyToFlags[prop]); + int level = 0; + while (itProp.hasNext()) { + QtProperty *p = itProp.next(); + if (p == property) { + int v = m_values[prop].val; + if (value) { + v |= (1 << level); + } else { + v &= ~(1 << level); + } + q_ptr->setValue(prop, v); + return; + } + level++; + } +} + +void QtFlagPropertyManagerPrivate::slotPropertyDestroyed(QtProperty *property) +{ + QtProperty *flagProperty = m_flagToProperty.value(property, 0); + if (flagProperty == 0) + return; + + m_propertyToFlags[flagProperty].replace(m_propertyToFlags[flagProperty].indexOf(property), 0); + m_flagToProperty.remove(property); +} + +/*! + \class QtFlagPropertyManager + \internal + \inmodule QtDesigner + \since 4.4 + + \brief The QtFlagPropertyManager provides and manages flag properties. + + Each flag property has an associated list of flag names which can + be retrieved using the flagNames() function, and set using the + corresponding setFlagNames() function. + + The flag manager provides properties with nested boolean + subproperties representing each flag, i.e. a flag property's value + is the binary combination of the subproperties' values. A + property's value can be retrieved and set using the value() and + setValue() slots respectively. The combination of flags is represented + by single int value - that's why it's possible to store up to + 32 independent flags in one flag property. + + The subproperties are created by a QtBoolPropertyManager object. This + manager can be retrieved using the subBoolPropertyManager() function. In + order to provide editing widgets for the subproperties in a + property browser widget, this manager must be associated with an + editor factory. + + In addition, QtFlagPropertyManager provides the valueChanged() signal + which is emitted whenever a property created by this manager + changes, and the flagNamesChanged() signal which is emitted + whenever the list of flag names is altered. + + \sa QtAbstractPropertyManager, QtBoolPropertyManager +*/ + +/*! + \fn void QtFlagPropertyManager::valueChanged(QtProperty *property, int value) + + This signal is emitted whenever a property created by this manager + changes its value, passing a pointer to the \a property and the new + \a value as parameters. + + \sa setValue() +*/ + +/*! + \fn void QtFlagPropertyManager::flagNamesChanged(QtProperty *property, const QStringList &names) + + This signal is emitted whenever a property created by this manager + changes its flag names, passing a pointer to the \a property and the + new \a names as parameters. + + \sa setFlagNames() +*/ + +/*! + Creates a manager with the given \a parent. +*/ +QtFlagPropertyManager::QtFlagPropertyManager(QObject *parent) + : QtAbstractPropertyManager(parent) +{ + d_ptr = new QtFlagPropertyManagerPrivate; + d_ptr->q_ptr = this; + + d_ptr->m_boolPropertyManager = new QtBoolPropertyManager(this); + connect(d_ptr->m_boolPropertyManager, SIGNAL(valueChanged(QtProperty *, bool)), + this, SLOT(slotBoolChanged(QtProperty *, bool))); + connect(d_ptr->m_boolPropertyManager, SIGNAL(propertyDestroyed(QtProperty *)), + this, SLOT(slotPropertyDestroyed(QtProperty *))); +} + +/*! + Destroys this manager, and all the properties it has created. +*/ +QtFlagPropertyManager::~QtFlagPropertyManager() +{ + clear(); + delete d_ptr; +} + +/*! + Returns the manager that produces the nested boolean subproperties + representing each flag. + + In order to provide editing widgets for the subproperties in a + property browser widget, this manager must be associated with an + editor factory. + + \sa QtAbstractPropertyBrowser::setFactoryForManager() +*/ +QtBoolPropertyManager *QtFlagPropertyManager::subBoolPropertyManager() const +{ + return d_ptr->m_boolPropertyManager; +} + +/*! + Returns the given \a property's value. + + If the given property is not managed by this manager, this + function returns 0. + + \sa flagNames(), setValue() +*/ +int QtFlagPropertyManager::value(const QtProperty *property) const +{ + return getValue<int>(d_ptr->m_values, property, 0); +} + +/*! + Returns the given \a property's list of flag names. + + \sa value(), setFlagNames() +*/ +QStringList QtFlagPropertyManager::flagNames(const QtProperty *property) const +{ + return getData<QStringList>(d_ptr->m_values, &QtFlagPropertyManagerPrivate::Data::flagNames, property, QStringList()); +} + +/*! + \reimp +*/ +QString QtFlagPropertyManager::valueText(const QtProperty *property) const +{ + const QtFlagPropertyManagerPrivate::PropertyValueMap::const_iterator it = d_ptr->m_values.constFind(property); + if (it == d_ptr->m_values.constEnd()) + return QString(); + + const QtFlagPropertyManagerPrivate::Data &data = it.value(); + + QString str; + int level = 0; + const QChar bar = QLatin1Char('|'); + const QStringList::const_iterator fncend = data.flagNames.constEnd(); + for (QStringList::const_iterator it = data.flagNames.constBegin(); it != fncend; ++it) { + if (data.val & (1 << level)) { + if (!str.isEmpty()) + str += bar; + str += *it; + } + + level++; + } + return str; +} + +/*! + \fn void QtFlagPropertyManager::setValue(QtProperty *property, int value) + + Sets the value of the given \a property to \a value. Nested + properties are updated automatically. + + The specified \a value must be less than the binary combination of + the property's flagNames() list size (i.e. less than 2\sup n, + where \c n is the size of the list) and larger than (or equal to) + 0. + + \sa value(), valueChanged() +*/ +void QtFlagPropertyManager::setValue(QtProperty *property, int val) +{ + const QtFlagPropertyManagerPrivate::PropertyValueMap::iterator it = d_ptr->m_values.find(property); + if (it == d_ptr->m_values.end()) + return; + + QtFlagPropertyManagerPrivate::Data data = it.value(); + + if (data.val == val) + return; + + if (val > (1 << data.flagNames.count()) - 1) + return; + + if (val < 0) + return; + + data.val = val; + + it.value() = data; + + QListIterator<QtProperty *> itProp(d_ptr->m_propertyToFlags[property]); + int level = 0; + while (itProp.hasNext()) { + QtProperty *prop = itProp.next(); + if (prop) + d_ptr->m_boolPropertyManager->setValue(prop, val & (1 << level)); + level++; + } + + emit propertyChanged(property); + emit valueChanged(property, data.val); +} + +/*! + Sets the given \a property's list of flag names to \a flagNames. The + property's current value is reset to 0 indicating the first item + of the list. + + \sa flagNames(), flagNamesChanged() +*/ +void QtFlagPropertyManager::setFlagNames(QtProperty *property, const QStringList &flagNames) +{ + const QtFlagPropertyManagerPrivate::PropertyValueMap::iterator it = d_ptr->m_values.find(property); + if (it == d_ptr->m_values.end()) + return; + + QtFlagPropertyManagerPrivate::Data data = it.value(); + + if (data.flagNames == flagNames) + return; + + data.flagNames = flagNames; + data.val = 0; + + it.value() = data; + + QListIterator<QtProperty *> itProp(d_ptr->m_propertyToFlags[property]); + while (itProp.hasNext()) { + QtProperty *prop = itProp.next(); + if (prop) { + delete prop; + d_ptr->m_flagToProperty.remove(prop); + } + } + d_ptr->m_propertyToFlags[property].clear(); + + QStringListIterator itFlag(flagNames); + while (itFlag.hasNext()) { + const QString flagName = itFlag.next(); + QtProperty *prop = d_ptr->m_boolPropertyManager->addProperty(); + prop->setPropertyName(flagName); + property->addSubProperty(prop); + d_ptr->m_propertyToFlags[property].append(prop); + d_ptr->m_flagToProperty[prop] = property; + } + + emit flagNamesChanged(property, data.flagNames); + + emit propertyChanged(property); + emit valueChanged(property, data.val); +} + +/*! + \reimp +*/ +void QtFlagPropertyManager::initializeProperty(QtProperty *property) +{ + d_ptr->m_values[property] = QtFlagPropertyManagerPrivate::Data(); + + d_ptr->m_propertyToFlags[property] = QList<QtProperty *>(); +} + +/*! + \reimp +*/ +void QtFlagPropertyManager::uninitializeProperty(QtProperty *property) +{ + QListIterator<QtProperty *> itProp(d_ptr->m_propertyToFlags[property]); + while (itProp.hasNext()) { + QtProperty *prop = itProp.next(); + if (prop) { + delete prop; + d_ptr->m_flagToProperty.remove(prop); + } + } + d_ptr->m_propertyToFlags.remove(property); + + d_ptr->m_values.remove(property); +} + +// QtSizePolicyPropertyManager + +class QtSizePolicyPropertyManagerPrivate +{ + QtSizePolicyPropertyManager *q_ptr; + Q_DECLARE_PUBLIC(QtSizePolicyPropertyManager) +public: + + QtSizePolicyPropertyManagerPrivate(); + + void slotIntChanged(QtProperty *property, int value); + void slotEnumChanged(QtProperty *property, int value); + void slotPropertyDestroyed(QtProperty *property); + + typedef QMap<const QtProperty *, QSizePolicy> PropertyValueMap; + PropertyValueMap m_values; + + QtIntPropertyManager *m_intPropertyManager; + QtEnumPropertyManager *m_enumPropertyManager; + + QMap<const QtProperty *, QtProperty *> m_propertyToHPolicy; + QMap<const QtProperty *, QtProperty *> m_propertyToVPolicy; + QMap<const QtProperty *, QtProperty *> m_propertyToHStretch; + QMap<const QtProperty *, QtProperty *> m_propertyToVStretch; + + QMap<const QtProperty *, QtProperty *> m_hPolicyToProperty; + QMap<const QtProperty *, QtProperty *> m_vPolicyToProperty; + QMap<const QtProperty *, QtProperty *> m_hStretchToProperty; + QMap<const QtProperty *, QtProperty *> m_vStretchToProperty; +}; + +QtSizePolicyPropertyManagerPrivate::QtSizePolicyPropertyManagerPrivate() +{ +} + +void QtSizePolicyPropertyManagerPrivate::slotIntChanged(QtProperty *property, int value) +{ + if (QtProperty *prop = m_hStretchToProperty.value(property, 0)) { + QSizePolicy sp = m_values[prop]; + sp.setHorizontalStretch(value); + q_ptr->setValue(prop, sp); + } else if (QtProperty *prop = m_vStretchToProperty.value(property, 0)) { + QSizePolicy sp = m_values[prop]; + sp.setVerticalStretch(value); + q_ptr->setValue(prop, sp); + } +} + +void QtSizePolicyPropertyManagerPrivate::slotEnumChanged(QtProperty *property, int value) +{ + if (QtProperty *prop = m_hPolicyToProperty.value(property, 0)) { + QSizePolicy sp = m_values[prop]; + sp.setHorizontalPolicy(metaEnumProvider()->indexToSizePolicy(value)); + q_ptr->setValue(prop, sp); + } else if (QtProperty *prop = m_vPolicyToProperty.value(property, 0)) { + QSizePolicy sp = m_values[prop]; + sp.setVerticalPolicy(metaEnumProvider()->indexToSizePolicy(value)); + q_ptr->setValue(prop, sp); + } +} + +void QtSizePolicyPropertyManagerPrivate::slotPropertyDestroyed(QtProperty *property) +{ + if (QtProperty *pointProp = m_hStretchToProperty.value(property, 0)) { + m_propertyToHStretch[pointProp] = 0; + m_hStretchToProperty.remove(property); + } else if (QtProperty *pointProp = m_vStretchToProperty.value(property, 0)) { + m_propertyToVStretch[pointProp] = 0; + m_vStretchToProperty.remove(property); + } else if (QtProperty *pointProp = m_hPolicyToProperty.value(property, 0)) { + m_propertyToHPolicy[pointProp] = 0; + m_hPolicyToProperty.remove(property); + } else if (QtProperty *pointProp = m_vPolicyToProperty.value(property, 0)) { + m_propertyToVPolicy[pointProp] = 0; + m_vPolicyToProperty.remove(property); + } +} + +/*! + \class QtSizePolicyPropertyManager + \internal + \inmodule QtDesigner + \since 4.4 + + \brief The QtSizePolicyPropertyManager provides and manages QSizePolicy properties. + + A size policy property has nested \e horizontalPolicy, \e + verticalPolicy, \e horizontalStretch and \e verticalStretch + subproperties. The top-level property's value can be retrieved + using the value() function, and set using the setValue() slot. + + The subproperties are created by QtIntPropertyManager and QtEnumPropertyManager + objects. These managers can be retrieved using the subIntPropertyManager() + and subEnumPropertyManager() functions respectively. In order to provide + editing widgets for the subproperties in a property browser widget, + these managers must be associated with editor factories. + + In addition, QtSizePolicyPropertyManager provides the valueChanged() + signal which is emitted whenever a property created by this + manager changes. + + \sa QtAbstractPropertyManager, QtIntPropertyManager, QtEnumPropertyManager +*/ + +/*! + \fn void QtSizePolicyPropertyManager::valueChanged(QtProperty *property, const QSizePolicy &value) + + This signal is emitted whenever a property created by this manager + changes its value, passing a pointer to the \a property and the + new \a value as parameters. + + \sa setValue() +*/ + +/*! + Creates a manager with the given \a parent. +*/ +QtSizePolicyPropertyManager::QtSizePolicyPropertyManager(QObject *parent) + : QtAbstractPropertyManager(parent) +{ + d_ptr = new QtSizePolicyPropertyManagerPrivate; + d_ptr->q_ptr = this; + + d_ptr->m_intPropertyManager = new QtIntPropertyManager(this); + connect(d_ptr->m_intPropertyManager, SIGNAL(valueChanged(QtProperty *, int)), + this, SLOT(slotIntChanged(QtProperty *, int))); + d_ptr->m_enumPropertyManager = new QtEnumPropertyManager(this); + connect(d_ptr->m_enumPropertyManager, SIGNAL(valueChanged(QtProperty *, int)), + this, SLOT(slotEnumChanged(QtProperty *, int))); + + connect(d_ptr->m_intPropertyManager, SIGNAL(propertyDestroyed(QtProperty *)), + this, SLOT(slotPropertyDestroyed(QtProperty *))); + connect(d_ptr->m_enumPropertyManager, SIGNAL(propertyDestroyed(QtProperty *)), + this, SLOT(slotPropertyDestroyed(QtProperty *))); +} + +/*! + Destroys this manager, and all the properties it has created. +*/ +QtSizePolicyPropertyManager::~QtSizePolicyPropertyManager() +{ + clear(); + delete d_ptr; +} + +/*! + Returns the manager that creates the nested \e horizontalStretch + and \e verticalStretch subproperties. + + In order to provide editing widgets for the mentioned subproperties + in a property browser widget, this manager must be associated with + an editor factory. + + \sa QtAbstractPropertyBrowser::setFactoryForManager() +*/ +QtIntPropertyManager *QtSizePolicyPropertyManager::subIntPropertyManager() const +{ + return d_ptr->m_intPropertyManager; +} + +/*! + Returns the manager that creates the nested \e horizontalPolicy + and \e verticalPolicy subproperties. + + In order to provide editing widgets for the mentioned subproperties + in a property browser widget, this manager must be associated with + an editor factory. + + \sa QtAbstractPropertyBrowser::setFactoryForManager() +*/ +QtEnumPropertyManager *QtSizePolicyPropertyManager::subEnumPropertyManager() const +{ + return d_ptr->m_enumPropertyManager; +} + +/*! + Returns the given \a property's value. + + If the given property is not managed by this manager, this + function returns the default size policy. + + \sa setValue() +*/ +QSizePolicy QtSizePolicyPropertyManager::value(const QtProperty *property) const +{ + return d_ptr->m_values.value(property, QSizePolicy()); +} + +/*! + \reimp +*/ +QString QtSizePolicyPropertyManager::valueText(const QtProperty *property) const +{ + const QtSizePolicyPropertyManagerPrivate::PropertyValueMap::const_iterator it = d_ptr->m_values.constFind(property); + if (it == d_ptr->m_values.constEnd()) + return QString(); + + const QSizePolicy sp = it.value(); + const QtMetaEnumProvider *mep = metaEnumProvider(); + const int hIndex = mep->sizePolicyToIndex(sp.horizontalPolicy()); + const int vIndex = mep->sizePolicyToIndex(sp.verticalPolicy()); + //! Unknown size policy on reading invalid uic3 files + const QString hPolicy = hIndex != -1 ? mep->policyEnumNames().at(hIndex) : tr("<Invalid>"); + const QString vPolicy = vIndex != -1 ? mep->policyEnumNames().at(vIndex) : tr("<Invalid>"); + const QString str = tr("[%1, %2, %3, %4]").arg(hPolicy, vPolicy).arg(sp.horizontalStretch()).arg(sp.verticalStretch()); + return str; +} + +/*! + \fn void QtSizePolicyPropertyManager::setValue(QtProperty *property, const QSizePolicy &value) + + Sets the value of the given \a property to \a value. Nested + properties are updated automatically. + + \sa value(), valueChanged() +*/ +void QtSizePolicyPropertyManager::setValue(QtProperty *property, const QSizePolicy &val) +{ + const QtSizePolicyPropertyManagerPrivate::PropertyValueMap::iterator it = d_ptr->m_values.find(property); + if (it == d_ptr->m_values.end()) + return; + + if (it.value() == val) + return; + + it.value() = val; + + d_ptr->m_enumPropertyManager->setValue(d_ptr->m_propertyToHPolicy[property], + metaEnumProvider()->sizePolicyToIndex(val.horizontalPolicy())); + d_ptr->m_enumPropertyManager->setValue(d_ptr->m_propertyToVPolicy[property], + metaEnumProvider()->sizePolicyToIndex(val.verticalPolicy())); + d_ptr->m_intPropertyManager->setValue(d_ptr->m_propertyToHStretch[property], + val.horizontalStretch()); + d_ptr->m_intPropertyManager->setValue(d_ptr->m_propertyToVStretch[property], + val.verticalStretch()); + + emit propertyChanged(property); + emit valueChanged(property, val); +} + +/*! + \reimp +*/ +void QtSizePolicyPropertyManager::initializeProperty(QtProperty *property) +{ + QSizePolicy val; + d_ptr->m_values[property] = val; + + QtProperty *hPolicyProp = d_ptr->m_enumPropertyManager->addProperty(); + hPolicyProp->setPropertyName(tr("Horizontal Policy")); + d_ptr->m_enumPropertyManager->setEnumNames(hPolicyProp, metaEnumProvider()->policyEnumNames()); + d_ptr->m_enumPropertyManager->setValue(hPolicyProp, + metaEnumProvider()->sizePolicyToIndex(val.horizontalPolicy())); + d_ptr->m_propertyToHPolicy[property] = hPolicyProp; + d_ptr->m_hPolicyToProperty[hPolicyProp] = property; + property->addSubProperty(hPolicyProp); + + QtProperty *vPolicyProp = d_ptr->m_enumPropertyManager->addProperty(); + vPolicyProp->setPropertyName(tr("Vertical Policy")); + d_ptr->m_enumPropertyManager->setEnumNames(vPolicyProp, metaEnumProvider()->policyEnumNames()); + d_ptr->m_enumPropertyManager->setValue(vPolicyProp, + metaEnumProvider()->sizePolicyToIndex(val.verticalPolicy())); + d_ptr->m_propertyToVPolicy[property] = vPolicyProp; + d_ptr->m_vPolicyToProperty[vPolicyProp] = property; + property->addSubProperty(vPolicyProp); + + QtProperty *hStretchProp = d_ptr->m_intPropertyManager->addProperty(); + hStretchProp->setPropertyName(tr("Horizontal Stretch")); + d_ptr->m_intPropertyManager->setValue(hStretchProp, val.horizontalStretch()); + d_ptr->m_intPropertyManager->setRange(hStretchProp, 0, 0xff); + d_ptr->m_propertyToHStretch[property] = hStretchProp; + d_ptr->m_hStretchToProperty[hStretchProp] = property; + property->addSubProperty(hStretchProp); + + QtProperty *vStretchProp = d_ptr->m_intPropertyManager->addProperty(); + vStretchProp->setPropertyName(tr("Vertical Stretch")); + d_ptr->m_intPropertyManager->setValue(vStretchProp, val.verticalStretch()); + d_ptr->m_intPropertyManager->setRange(vStretchProp, 0, 0xff); + d_ptr->m_propertyToVStretch[property] = vStretchProp; + d_ptr->m_vStretchToProperty[vStretchProp] = property; + property->addSubProperty(vStretchProp); + +} + +/*! + \reimp +*/ +void QtSizePolicyPropertyManager::uninitializeProperty(QtProperty *property) +{ + QtProperty *hPolicyProp = d_ptr->m_propertyToHPolicy[property]; + if (hPolicyProp) { + d_ptr->m_hPolicyToProperty.remove(hPolicyProp); + delete hPolicyProp; + } + d_ptr->m_propertyToHPolicy.remove(property); + + QtProperty *vPolicyProp = d_ptr->m_propertyToVPolicy[property]; + if (vPolicyProp) { + d_ptr->m_vPolicyToProperty.remove(vPolicyProp); + delete vPolicyProp; + } + d_ptr->m_propertyToVPolicy.remove(property); + + QtProperty *hStretchProp = d_ptr->m_propertyToHStretch[property]; + if (hStretchProp) { + d_ptr->m_hStretchToProperty.remove(hStretchProp); + delete hStretchProp; + } + d_ptr->m_propertyToHStretch.remove(property); + + QtProperty *vStretchProp = d_ptr->m_propertyToVStretch[property]; + if (vStretchProp) { + d_ptr->m_vStretchToProperty.remove(vStretchProp); + delete vStretchProp; + } + d_ptr->m_propertyToVStretch.remove(property); + + d_ptr->m_values.remove(property); +} + +// QtFontPropertyManager: +// QtFontPropertyManagerPrivate has a mechanism for reacting +// to QApplication::fontDatabaseChanged() [4.5], which is emitted +// when someone loads an application font. The signals are compressed +// using a timer with interval 0, which then causes the family +// enumeration manager to re-set its strings and index values +// for each property. + +Q_GLOBAL_STATIC(QFontDatabase, fontDatabase) + +class QtFontPropertyManagerPrivate +{ + QtFontPropertyManager *q_ptr; + Q_DECLARE_PUBLIC(QtFontPropertyManager) +public: + + QtFontPropertyManagerPrivate(); + + void slotIntChanged(QtProperty *property, int value); + void slotEnumChanged(QtProperty *property, int value); + void slotBoolChanged(QtProperty *property, bool value); + void slotPropertyDestroyed(QtProperty *property); + void slotFontDatabaseChanged(); + void slotFontDatabaseDelayedChange(); + + QStringList m_familyNames; + + typedef QMap<const QtProperty *, QFont> PropertyValueMap; + PropertyValueMap m_values; + + QtIntPropertyManager *m_intPropertyManager; + QtEnumPropertyManager *m_enumPropertyManager; + QtBoolPropertyManager *m_boolPropertyManager; + + QMap<const QtProperty *, QtProperty *> m_propertyToFamily; + QMap<const QtProperty *, QtProperty *> m_propertyToPointSize; + QMap<const QtProperty *, QtProperty *> m_propertyToBold; + QMap<const QtProperty *, QtProperty *> m_propertyToItalic; + QMap<const QtProperty *, QtProperty *> m_propertyToUnderline; + QMap<const QtProperty *, QtProperty *> m_propertyToStrikeOut; + QMap<const QtProperty *, QtProperty *> m_propertyToKerning; + + QMap<const QtProperty *, QtProperty *> m_familyToProperty; + QMap<const QtProperty *, QtProperty *> m_pointSizeToProperty; + QMap<const QtProperty *, QtProperty *> m_boldToProperty; + QMap<const QtProperty *, QtProperty *> m_italicToProperty; + QMap<const QtProperty *, QtProperty *> m_underlineToProperty; + QMap<const QtProperty *, QtProperty *> m_strikeOutToProperty; + QMap<const QtProperty *, QtProperty *> m_kerningToProperty; + + bool m_settingValue; + QTimer *m_fontDatabaseChangeTimer; +}; + +QtFontPropertyManagerPrivate::QtFontPropertyManagerPrivate() : + m_settingValue(false), + m_fontDatabaseChangeTimer(0) +{ +} + +void QtFontPropertyManagerPrivate::slotIntChanged(QtProperty *property, int value) +{ + if (m_settingValue) + return; + if (QtProperty *prop = m_pointSizeToProperty.value(property, 0)) { + QFont f = m_values[prop]; + f.setPointSize(value); + q_ptr->setValue(prop, f); + } +} + +void QtFontPropertyManagerPrivate::slotEnumChanged(QtProperty *property, int value) +{ + if (m_settingValue) + return; + if (QtProperty *prop = m_familyToProperty.value(property, 0)) { + QFont f = m_values[prop]; + f.setFamily(m_familyNames.at(value)); + q_ptr->setValue(prop, f); + } +} + +void QtFontPropertyManagerPrivate::slotBoolChanged(QtProperty *property, bool value) +{ + if (m_settingValue) + return; + if (QtProperty *prop = m_boldToProperty.value(property, 0)) { + QFont f = m_values[prop]; + f.setBold(value); + q_ptr->setValue(prop, f); + } else if (QtProperty *prop = m_italicToProperty.value(property, 0)) { + QFont f = m_values[prop]; + f.setItalic(value); + q_ptr->setValue(prop, f); + } else if (QtProperty *prop = m_underlineToProperty.value(property, 0)) { + QFont f = m_values[prop]; + f.setUnderline(value); + q_ptr->setValue(prop, f); + } else if (QtProperty *prop = m_strikeOutToProperty.value(property, 0)) { + QFont f = m_values[prop]; + f.setStrikeOut(value); + q_ptr->setValue(prop, f); + } else if (QtProperty *prop = m_kerningToProperty.value(property, 0)) { + QFont f = m_values[prop]; + f.setKerning(value); + q_ptr->setValue(prop, f); + } +} + +void QtFontPropertyManagerPrivate::slotPropertyDestroyed(QtProperty *property) +{ + if (QtProperty *pointProp = m_pointSizeToProperty.value(property, 0)) { + m_propertyToPointSize[pointProp] = 0; + m_pointSizeToProperty.remove(property); + } else if (QtProperty *pointProp = m_familyToProperty.value(property, 0)) { + m_propertyToFamily[pointProp] = 0; + m_familyToProperty.remove(property); + } else if (QtProperty *pointProp = m_boldToProperty.value(property, 0)) { + m_propertyToBold[pointProp] = 0; + m_boldToProperty.remove(property); + } else if (QtProperty *pointProp = m_italicToProperty.value(property, 0)) { + m_propertyToItalic[pointProp] = 0; + m_italicToProperty.remove(property); + } else if (QtProperty *pointProp = m_underlineToProperty.value(property, 0)) { + m_propertyToUnderline[pointProp] = 0; + m_underlineToProperty.remove(property); + } else if (QtProperty *pointProp = m_strikeOutToProperty.value(property, 0)) { + m_propertyToStrikeOut[pointProp] = 0; + m_strikeOutToProperty.remove(property); + } else if (QtProperty *pointProp = m_kerningToProperty.value(property, 0)) { + m_propertyToKerning[pointProp] = 0; + m_kerningToProperty.remove(property); + } +} + +void QtFontPropertyManagerPrivate::slotFontDatabaseChanged() +{ + if (!m_fontDatabaseChangeTimer) { + m_fontDatabaseChangeTimer = new QTimer(q_ptr); + m_fontDatabaseChangeTimer->setInterval(0); + m_fontDatabaseChangeTimer->setSingleShot(true); + QObject::connect(m_fontDatabaseChangeTimer, SIGNAL(timeout()), q_ptr, SLOT(slotFontDatabaseDelayedChange())); + } + if (!m_fontDatabaseChangeTimer->isActive()) + m_fontDatabaseChangeTimer->start(); +} + +void QtFontPropertyManagerPrivate::slotFontDatabaseDelayedChange() +{ + typedef QMap<const QtProperty *, QtProperty *> PropertyPropertyMap; + // rescan available font names + const QStringList oldFamilies = m_familyNames; + m_familyNames = fontDatabase()->families(); + + // Adapt all existing properties + if (!m_propertyToFamily.empty()) { + PropertyPropertyMap::const_iterator cend = m_propertyToFamily.constEnd(); + for (PropertyPropertyMap::const_iterator it = m_propertyToFamily.constBegin(); it != cend; ++it) { + QtProperty *familyProp = it.value(); + const int oldIdx = m_enumPropertyManager->value(familyProp); + int newIdx = m_familyNames.indexOf(oldFamilies.at(oldIdx)); + if (newIdx < 0) + newIdx = 0; + m_enumPropertyManager->setEnumNames(familyProp, m_familyNames); + m_enumPropertyManager->setValue(familyProp, newIdx); + } + } +} + +/*! + \class QtFontPropertyManager + \internal + \inmodule QtDesigner + \since 4.4 + + \brief The QtFontPropertyManager provides and manages QFont properties. + + A font property has nested \e family, \e pointSize, \e bold, \e + italic, \e underline, \e strikeOut and \e kerning subproperties. The top-level + property's value can be retrieved using the value() function, and + set using the setValue() slot. + + The subproperties are created by QtIntPropertyManager, QtEnumPropertyManager and + QtBoolPropertyManager objects. These managers can be retrieved using the + corresponding subIntPropertyManager(), subEnumPropertyManager() and + subBoolPropertyManager() functions. In order to provide editing widgets + for the subproperties in a property browser widget, these managers + must be associated with editor factories. + + In addition, QtFontPropertyManager provides the valueChanged() signal + which is emitted whenever a property created by this manager + changes. + + \sa QtAbstractPropertyManager, QtEnumPropertyManager, QtIntPropertyManager, QtBoolPropertyManager +*/ + +/*! + \fn void QtFontPropertyManager::valueChanged(QtProperty *property, const QFont &value) + + This signal is emitted whenever a property created by this manager + changes its value, passing a pointer to the \a property and the + new \a value as parameters. + + \sa setValue() +*/ + +/*! + Creates a manager with the given \a parent. +*/ +QtFontPropertyManager::QtFontPropertyManager(QObject *parent) + : QtAbstractPropertyManager(parent) +{ + d_ptr = new QtFontPropertyManagerPrivate; + d_ptr->q_ptr = this; +#if QT_VERSION >= 0x040500 + QObject::connect(qApp, SIGNAL(fontDatabaseChanged()), this, SLOT(slotFontDatabaseChanged())); +#endif + + d_ptr->m_intPropertyManager = new QtIntPropertyManager(this); + connect(d_ptr->m_intPropertyManager, SIGNAL(valueChanged(QtProperty *, int)), + this, SLOT(slotIntChanged(QtProperty *, int))); + d_ptr->m_enumPropertyManager = new QtEnumPropertyManager(this); + connect(d_ptr->m_enumPropertyManager, SIGNAL(valueChanged(QtProperty *, int)), + this, SLOT(slotEnumChanged(QtProperty *, int))); + d_ptr->m_boolPropertyManager = new QtBoolPropertyManager(this); + connect(d_ptr->m_boolPropertyManager, SIGNAL(valueChanged(QtProperty *, bool)), + this, SLOT(slotBoolChanged(QtProperty *, bool))); + + connect(d_ptr->m_intPropertyManager, SIGNAL(propertyDestroyed(QtProperty *)), + this, SLOT(slotPropertyDestroyed(QtProperty *))); + connect(d_ptr->m_enumPropertyManager, SIGNAL(propertyDestroyed(QtProperty *)), + this, SLOT(slotPropertyDestroyed(QtProperty *))); + connect(d_ptr->m_boolPropertyManager, SIGNAL(propertyDestroyed(QtProperty *)), + this, SLOT(slotPropertyDestroyed(QtProperty *))); +} + +/*! + Destroys this manager, and all the properties it has created. +*/ +QtFontPropertyManager::~QtFontPropertyManager() +{ + clear(); + delete d_ptr; +} + +/*! + Returns the manager that creates the \e pointSize subproperty. + + In order to provide editing widgets for the \e pointSize property + in a property browser widget, this manager must be associated + with an editor factory. + + \sa QtAbstractPropertyBrowser::setFactoryForManager() +*/ +QtIntPropertyManager *QtFontPropertyManager::subIntPropertyManager() const +{ + return d_ptr->m_intPropertyManager; +} + +/*! + Returns the manager that create the \e family subproperty. + + In order to provide editing widgets for the \e family property + in a property browser widget, this manager must be associated + with an editor factory. + + \sa QtAbstractPropertyBrowser::setFactoryForManager() +*/ +QtEnumPropertyManager *QtFontPropertyManager::subEnumPropertyManager() const +{ + return d_ptr->m_enumPropertyManager; +} + +/*! + Returns the manager that creates the \e bold, \e italic, \e underline, + \e strikeOut and \e kerning subproperties. + + In order to provide editing widgets for the mentioned properties + in a property browser widget, this manager must be associated with + an editor factory. + + \sa QtAbstractPropertyBrowser::setFactoryForManager() +*/ +QtBoolPropertyManager *QtFontPropertyManager::subBoolPropertyManager() const +{ + return d_ptr->m_boolPropertyManager; +} + +/*! + Returns the given \a property's value. + + If the given property is not managed by this manager, this + function returns a font object that uses the application's default + font. + + \sa setValue() +*/ +QFont QtFontPropertyManager::value(const QtProperty *property) const +{ + return d_ptr->m_values.value(property, QFont()); +} + +/*! + \reimp +*/ +QString QtFontPropertyManager::valueText(const QtProperty *property) const +{ + const QtFontPropertyManagerPrivate::PropertyValueMap::const_iterator it = d_ptr->m_values.constFind(property); + if (it == d_ptr->m_values.constEnd()) + return QString(); + + return QtPropertyBrowserUtils::fontValueText(it.value()); +} + +/*! + \reimp +*/ +QIcon QtFontPropertyManager::valueIcon(const QtProperty *property) const +{ + const QtFontPropertyManagerPrivate::PropertyValueMap::const_iterator it = d_ptr->m_values.constFind(property); + if (it == d_ptr->m_values.constEnd()) + return QIcon(); + + return QtPropertyBrowserUtils::fontValueIcon(it.value()); +} + +/*! + \fn void QtFontPropertyManager::setValue(QtProperty *property, const QFont &value) + + Sets the value of the given \a property to \a value. Nested + properties are updated automatically. + + \sa value(), valueChanged() +*/ +void QtFontPropertyManager::setValue(QtProperty *property, const QFont &val) +{ + const QtFontPropertyManagerPrivate::PropertyValueMap::iterator it = d_ptr->m_values.find(property); + if (it == d_ptr->m_values.end()) + return; + + const QFont oldVal = it.value(); + if (oldVal == val && oldVal.resolve() == val.resolve()) + return; + + it.value() = val; + + int idx = d_ptr->m_familyNames.indexOf(val.family()); + if (idx == -1) + idx = 0; + bool settingValue = d_ptr->m_settingValue; + d_ptr->m_settingValue = true; + d_ptr->m_enumPropertyManager->setValue(d_ptr->m_propertyToFamily[property], idx); + d_ptr->m_intPropertyManager->setValue(d_ptr->m_propertyToPointSize[property], val.pointSize()); + d_ptr->m_boolPropertyManager->setValue(d_ptr->m_propertyToBold[property], val.bold()); + d_ptr->m_boolPropertyManager->setValue(d_ptr->m_propertyToItalic[property], val.italic()); + d_ptr->m_boolPropertyManager->setValue(d_ptr->m_propertyToUnderline[property], val.underline()); + d_ptr->m_boolPropertyManager->setValue(d_ptr->m_propertyToStrikeOut[property], val.strikeOut()); + d_ptr->m_boolPropertyManager->setValue(d_ptr->m_propertyToKerning[property], val.kerning()); + d_ptr->m_settingValue = settingValue; + + emit propertyChanged(property); + emit valueChanged(property, val); +} + +/*! + \reimp +*/ +void QtFontPropertyManager::initializeProperty(QtProperty *property) +{ + QFont val; + d_ptr->m_values[property] = val; + + QtProperty *familyProp = d_ptr->m_enumPropertyManager->addProperty(); + familyProp->setPropertyName(tr("Family")); + if (d_ptr->m_familyNames.empty()) + d_ptr->m_familyNames = fontDatabase()->families(); + d_ptr->m_enumPropertyManager->setEnumNames(familyProp, d_ptr->m_familyNames); + int idx = d_ptr->m_familyNames.indexOf(val.family()); + if (idx == -1) + idx = 0; + d_ptr->m_enumPropertyManager->setValue(familyProp, idx); + d_ptr->m_propertyToFamily[property] = familyProp; + d_ptr->m_familyToProperty[familyProp] = property; + property->addSubProperty(familyProp); + + QtProperty *pointSizeProp = d_ptr->m_intPropertyManager->addProperty(); + pointSizeProp->setPropertyName(tr("Point Size")); + d_ptr->m_intPropertyManager->setValue(pointSizeProp, val.pointSize()); + d_ptr->m_intPropertyManager->setMinimum(pointSizeProp, 1); + d_ptr->m_propertyToPointSize[property] = pointSizeProp; + d_ptr->m_pointSizeToProperty[pointSizeProp] = property; + property->addSubProperty(pointSizeProp); + + QtProperty *boldProp = d_ptr->m_boolPropertyManager->addProperty(); + boldProp->setPropertyName(tr("Bold")); + d_ptr->m_boolPropertyManager->setValue(boldProp, val.bold()); + d_ptr->m_propertyToBold[property] = boldProp; + d_ptr->m_boldToProperty[boldProp] = property; + property->addSubProperty(boldProp); + + QtProperty *italicProp = d_ptr->m_boolPropertyManager->addProperty(); + italicProp->setPropertyName(tr("Italic")); + d_ptr->m_boolPropertyManager->setValue(italicProp, val.italic()); + d_ptr->m_propertyToItalic[property] = italicProp; + d_ptr->m_italicToProperty[italicProp] = property; + property->addSubProperty(italicProp); + + QtProperty *underlineProp = d_ptr->m_boolPropertyManager->addProperty(); + underlineProp->setPropertyName(tr("Underline")); + d_ptr->m_boolPropertyManager->setValue(underlineProp, val.underline()); + d_ptr->m_propertyToUnderline[property] = underlineProp; + d_ptr->m_underlineToProperty[underlineProp] = property; + property->addSubProperty(underlineProp); + + QtProperty *strikeOutProp = d_ptr->m_boolPropertyManager->addProperty(); + strikeOutProp->setPropertyName(tr("Strikeout")); + d_ptr->m_boolPropertyManager->setValue(strikeOutProp, val.strikeOut()); + d_ptr->m_propertyToStrikeOut[property] = strikeOutProp; + d_ptr->m_strikeOutToProperty[strikeOutProp] = property; + property->addSubProperty(strikeOutProp); + + QtProperty *kerningProp = d_ptr->m_boolPropertyManager->addProperty(); + kerningProp->setPropertyName(tr("Kerning")); + d_ptr->m_boolPropertyManager->setValue(kerningProp, val.kerning()); + d_ptr->m_propertyToKerning[property] = kerningProp; + d_ptr->m_kerningToProperty[kerningProp] = property; + property->addSubProperty(kerningProp); +} + +/*! + \reimp +*/ +void QtFontPropertyManager::uninitializeProperty(QtProperty *property) +{ + QtProperty *familyProp = d_ptr->m_propertyToFamily[property]; + if (familyProp) { + d_ptr->m_familyToProperty.remove(familyProp); + delete familyProp; + } + d_ptr->m_propertyToFamily.remove(property); + + QtProperty *pointSizeProp = d_ptr->m_propertyToPointSize[property]; + if (pointSizeProp) { + d_ptr->m_pointSizeToProperty.remove(pointSizeProp); + delete pointSizeProp; + } + d_ptr->m_propertyToPointSize.remove(property); + + QtProperty *boldProp = d_ptr->m_propertyToBold[property]; + if (boldProp) { + d_ptr->m_boldToProperty.remove(boldProp); + delete boldProp; + } + d_ptr->m_propertyToBold.remove(property); + + QtProperty *italicProp = d_ptr->m_propertyToItalic[property]; + if (italicProp) { + d_ptr->m_italicToProperty.remove(italicProp); + delete italicProp; + } + d_ptr->m_propertyToItalic.remove(property); + + QtProperty *underlineProp = d_ptr->m_propertyToUnderline[property]; + if (underlineProp) { + d_ptr->m_underlineToProperty.remove(underlineProp); + delete underlineProp; + } + d_ptr->m_propertyToUnderline.remove(property); + + QtProperty *strikeOutProp = d_ptr->m_propertyToStrikeOut[property]; + if (strikeOutProp) { + d_ptr->m_strikeOutToProperty.remove(strikeOutProp); + delete strikeOutProp; + } + d_ptr->m_propertyToStrikeOut.remove(property); + + QtProperty *kerningProp = d_ptr->m_propertyToKerning[property]; + if (kerningProp) { + d_ptr->m_kerningToProperty.remove(kerningProp); + delete kerningProp; + } + d_ptr->m_propertyToKerning.remove(property); + + d_ptr->m_values.remove(property); +} + +// QtColorPropertyManager + +class QtColorPropertyManagerPrivate +{ + QtColorPropertyManager *q_ptr; + Q_DECLARE_PUBLIC(QtColorPropertyManager) +public: + + void slotIntChanged(QtProperty *property, int value); + void slotPropertyDestroyed(QtProperty *property); + + typedef QMap<const QtProperty *, QColor> PropertyValueMap; + PropertyValueMap m_values; + + QtIntPropertyManager *m_intPropertyManager; + + QMap<const QtProperty *, QtProperty *> m_propertyToR; + QMap<const QtProperty *, QtProperty *> m_propertyToG; + QMap<const QtProperty *, QtProperty *> m_propertyToB; + QMap<const QtProperty *, QtProperty *> m_propertyToA; + + QMap<const QtProperty *, QtProperty *> m_rToProperty; + QMap<const QtProperty *, QtProperty *> m_gToProperty; + QMap<const QtProperty *, QtProperty *> m_bToProperty; + QMap<const QtProperty *, QtProperty *> m_aToProperty; +}; + +void QtColorPropertyManagerPrivate::slotIntChanged(QtProperty *property, int value) +{ + if (QtProperty *prop = m_rToProperty.value(property, 0)) { + QColor c = m_values[prop]; + c.setRed(value); + q_ptr->setValue(prop, c); + } else if (QtProperty *prop = m_gToProperty.value(property, 0)) { + QColor c = m_values[prop]; + c.setGreen(value); + q_ptr->setValue(prop, c); + } else if (QtProperty *prop = m_bToProperty.value(property, 0)) { + QColor c = m_values[prop]; + c.setBlue(value); + q_ptr->setValue(prop, c); + } else if (QtProperty *prop = m_aToProperty.value(property, 0)) { + QColor c = m_values[prop]; + c.setAlpha(value); + q_ptr->setValue(prop, c); + } +} + +void QtColorPropertyManagerPrivate::slotPropertyDestroyed(QtProperty *property) +{ + if (QtProperty *pointProp = m_rToProperty.value(property, 0)) { + m_propertyToR[pointProp] = 0; + m_rToProperty.remove(property); + } else if (QtProperty *pointProp = m_gToProperty.value(property, 0)) { + m_propertyToG[pointProp] = 0; + m_gToProperty.remove(property); + } else if (QtProperty *pointProp = m_bToProperty.value(property, 0)) { + m_propertyToB[pointProp] = 0; + m_bToProperty.remove(property); + } else if (QtProperty *pointProp = m_aToProperty.value(property, 0)) { + m_propertyToA[pointProp] = 0; + m_aToProperty.remove(property); + } +} + +/*! + \class QtColorPropertyManager + \internal + \inmodule QtDesigner + \since 4.4 + + \brief The QtColorPropertyManager provides and manages QColor properties. + + A color property has nested \e red, \e green and \e blue + subproperties. The top-level property's value can be retrieved + using the value() function, and set using the setValue() slot. + + The subproperties are created by a QtIntPropertyManager object. This + manager can be retrieved using the subIntPropertyManager() function. In + order to provide editing widgets for the subproperties in a + property browser widget, this manager must be associated with an + editor factory. + + In addition, QtColorPropertyManager provides the valueChanged() signal + which is emitted whenever a property created by this manager + changes. + + \sa QtAbstractPropertyManager, QtAbstractPropertyBrowser, QtIntPropertyManager +*/ + +/*! + \fn void QtColorPropertyManager::valueChanged(QtProperty *property, const QColor &value) + + This signal is emitted whenever a property created by this manager + changes its value, passing a pointer to the \a property and the new + \a value as parameters. + + \sa setValue() +*/ + +/*! + Creates a manager with the given \a parent. +*/ +QtColorPropertyManager::QtColorPropertyManager(QObject *parent) + : QtAbstractPropertyManager(parent) +{ + d_ptr = new QtColorPropertyManagerPrivate; + d_ptr->q_ptr = this; + + d_ptr->m_intPropertyManager = new QtIntPropertyManager(this); + connect(d_ptr->m_intPropertyManager, SIGNAL(valueChanged(QtProperty *, int)), + this, SLOT(slotIntChanged(QtProperty *, int))); + + connect(d_ptr->m_intPropertyManager, SIGNAL(propertyDestroyed(QtProperty *)), + this, SLOT(slotPropertyDestroyed(QtProperty *))); +} + +/*! + Destroys this manager, and all the properties it has created. +*/ +QtColorPropertyManager::~QtColorPropertyManager() +{ + clear(); + delete d_ptr; +} + +/*! + Returns the manager that produces the nested \e red, \e green and + \e blue subproperties. + + In order to provide editing widgets for the subproperties in a + property browser widget, this manager must be associated with an + editor factory. + + \sa QtAbstractPropertyBrowser::setFactoryForManager() +*/ +QtIntPropertyManager *QtColorPropertyManager::subIntPropertyManager() const +{ + return d_ptr->m_intPropertyManager; +} + +/*! + Returns the given \a property's value. + + If the given \a property is not managed by \e this manager, this + function returns an invalid color. + + \sa setValue() +*/ +QColor QtColorPropertyManager::value(const QtProperty *property) const +{ + return d_ptr->m_values.value(property, QColor()); +} + +/*! + \reimp +*/ + +QString QtColorPropertyManager::valueText(const QtProperty *property) const +{ + const QtColorPropertyManagerPrivate::PropertyValueMap::const_iterator it = d_ptr->m_values.constFind(property); + if (it == d_ptr->m_values.constEnd()) + return QString(); + + return QtPropertyBrowserUtils::colorValueText(it.value()); +} + +/*! + \reimp +*/ + +QIcon QtColorPropertyManager::valueIcon(const QtProperty *property) const +{ + const QtColorPropertyManagerPrivate::PropertyValueMap::const_iterator it = d_ptr->m_values.constFind(property); + if (it == d_ptr->m_values.constEnd()) + return QIcon(); + return QtPropertyBrowserUtils::brushValueIcon(QBrush(it.value())); +} + +/*! + \fn void QtColorPropertyManager::setValue(QtProperty *property, const QColor &value) + + Sets the value of the given \a property to \a value. Nested + properties are updated automatically. + + \sa value(), valueChanged() +*/ +void QtColorPropertyManager::setValue(QtProperty *property, const QColor &val) +{ + const QtColorPropertyManagerPrivate::PropertyValueMap::iterator it = d_ptr->m_values.find(property); + if (it == d_ptr->m_values.end()) + return; + + if (it.value() == val) + return; + + it.value() = val; + + d_ptr->m_intPropertyManager->setValue(d_ptr->m_propertyToR[property], val.red()); + d_ptr->m_intPropertyManager->setValue(d_ptr->m_propertyToG[property], val.green()); + d_ptr->m_intPropertyManager->setValue(d_ptr->m_propertyToB[property], val.blue()); + d_ptr->m_intPropertyManager->setValue(d_ptr->m_propertyToA[property], val.alpha()); + + emit propertyChanged(property); + emit valueChanged(property, val); +} + +/*! + \reimp +*/ +void QtColorPropertyManager::initializeProperty(QtProperty *property) +{ + QColor val; + d_ptr->m_values[property] = val; + + QtProperty *rProp = d_ptr->m_intPropertyManager->addProperty(); + rProp->setPropertyName(tr("Red")); + d_ptr->m_intPropertyManager->setValue(rProp, val.red()); + d_ptr->m_intPropertyManager->setRange(rProp, 0, 0xFF); + d_ptr->m_propertyToR[property] = rProp; + d_ptr->m_rToProperty[rProp] = property; + property->addSubProperty(rProp); + + QtProperty *gProp = d_ptr->m_intPropertyManager->addProperty(); + gProp->setPropertyName(tr("Green")); + d_ptr->m_intPropertyManager->setValue(gProp, val.green()); + d_ptr->m_intPropertyManager->setRange(gProp, 0, 0xFF); + d_ptr->m_propertyToG[property] = gProp; + d_ptr->m_gToProperty[gProp] = property; + property->addSubProperty(gProp); + + QtProperty *bProp = d_ptr->m_intPropertyManager->addProperty(); + bProp->setPropertyName(tr("Blue")); + d_ptr->m_intPropertyManager->setValue(bProp, val.blue()); + d_ptr->m_intPropertyManager->setRange(bProp, 0, 0xFF); + d_ptr->m_propertyToB[property] = bProp; + d_ptr->m_bToProperty[bProp] = property; + property->addSubProperty(bProp); + + QtProperty *aProp = d_ptr->m_intPropertyManager->addProperty(); + aProp->setPropertyName(tr("Alpha")); + d_ptr->m_intPropertyManager->setValue(aProp, val.alpha()); + d_ptr->m_intPropertyManager->setRange(aProp, 0, 0xFF); + d_ptr->m_propertyToA[property] = aProp; + d_ptr->m_aToProperty[aProp] = property; + property->addSubProperty(aProp); +} + +/*! + \reimp +*/ +void QtColorPropertyManager::uninitializeProperty(QtProperty *property) +{ + QtProperty *rProp = d_ptr->m_propertyToR[property]; + if (rProp) { + d_ptr->m_rToProperty.remove(rProp); + delete rProp; + } + d_ptr->m_propertyToR.remove(property); + + QtProperty *gProp = d_ptr->m_propertyToG[property]; + if (gProp) { + d_ptr->m_gToProperty.remove(gProp); + delete gProp; + } + d_ptr->m_propertyToG.remove(property); + + QtProperty *bProp = d_ptr->m_propertyToB[property]; + if (bProp) { + d_ptr->m_bToProperty.remove(bProp); + delete bProp; + } + d_ptr->m_propertyToB.remove(property); + + QtProperty *aProp = d_ptr->m_propertyToA[property]; + if (aProp) { + d_ptr->m_aToProperty.remove(aProp); + delete aProp; + } + d_ptr->m_propertyToA.remove(property); + + d_ptr->m_values.remove(property); +} + +// QtCursorPropertyManager + +Q_GLOBAL_STATIC(QtCursorDatabase, cursorDatabase) + +class QtCursorPropertyManagerPrivate +{ + QtCursorPropertyManager *q_ptr; + Q_DECLARE_PUBLIC(QtCursorPropertyManager) +public: + typedef QMap<const QtProperty *, QCursor> PropertyValueMap; + PropertyValueMap m_values; +}; + +/*! + \class QtCursorPropertyManager + \internal + \inmodule QtDesigner + \since 4.4 + + \brief The QtCursorPropertyManager provides and manages QCursor properties. + + A cursor property has a current value which can be + retrieved using the value() function, and set using the setValue() + slot. In addition, QtCursorPropertyManager provides the + valueChanged() signal which is emitted whenever a property created + by this manager changes. + + \sa QtAbstractPropertyManager +*/ + +/*! + \fn void QtCursorPropertyManager::valueChanged(QtProperty *property, const QCursor &value) + + This signal is emitted whenever a property created by this manager + changes its value, passing a pointer to the \a property and the new + \a value as parameters. + + \sa setValue() +*/ + +/*! + Creates a manager with the given \a parent. +*/ +QtCursorPropertyManager::QtCursorPropertyManager(QObject *parent) + : QtAbstractPropertyManager(parent) +{ + d_ptr = new QtCursorPropertyManagerPrivate; + d_ptr->q_ptr = this; +} + +/*! + Destroys this manager, and all the properties it has created. +*/ +QtCursorPropertyManager::~QtCursorPropertyManager() +{ + clear(); + delete d_ptr; +} + +/*! + Returns the given \a property's value. + + If the given \a property is not managed by this manager, this + function returns a default QCursor object. + + \sa setValue() +*/ +#ifndef QT_NO_CURSOR +QCursor QtCursorPropertyManager::value(const QtProperty *property) const +{ + return d_ptr->m_values.value(property, QCursor()); +} +#endif + +/*! + \reimp +*/ +QString QtCursorPropertyManager::valueText(const QtProperty *property) const +{ + const QtCursorPropertyManagerPrivate::PropertyValueMap::const_iterator it = d_ptr->m_values.constFind(property); + if (it == d_ptr->m_values.constEnd()) + return QString(); + + return cursorDatabase()->cursorToShapeName(it.value()); +} + +/*! + \reimp +*/ +QIcon QtCursorPropertyManager::valueIcon(const QtProperty *property) const +{ + const QtCursorPropertyManagerPrivate::PropertyValueMap::const_iterator it = d_ptr->m_values.constFind(property); + if (it == d_ptr->m_values.constEnd()) + return QIcon(); + + return cursorDatabase()->cursorToShapeIcon(it.value()); +} + +/*! + \fn void QtCursorPropertyManager::setValue(QtProperty *property, const QCursor &value) + + Sets the value of the given \a property to \a value. + + \sa value(), valueChanged() +*/ +void QtCursorPropertyManager::setValue(QtProperty *property, const QCursor &value) +{ +#ifndef QT_NO_CURSOR + const QtCursorPropertyManagerPrivate::PropertyValueMap::iterator it = d_ptr->m_values.find(property); + if (it == d_ptr->m_values.end()) + return; + + if (it.value().shape() == value.shape() && value.shape() != Qt::BitmapCursor) + return; + + it.value() = value; + + emit propertyChanged(property); + emit valueChanged(property, value); +#endif +} + +/*! + \reimp +*/ +void QtCursorPropertyManager::initializeProperty(QtProperty *property) +{ +#ifndef QT_NO_CURSOR + d_ptr->m_values[property] = QCursor(); +#endif +} + +/*! + \reimp +*/ +void QtCursorPropertyManager::uninitializeProperty(QtProperty *property) +{ + d_ptr->m_values.remove(property); +} + +#if QT_VERSION >= 0x040400 +QT_END_NAMESPACE +#endif + +#include "moc_qtpropertymanager.cpp" +#include "qtpropertymanager.moc" diff --git a/tools/shared/qtpropertybrowser/qtpropertymanager.h b/tools/shared/qtpropertybrowser/qtpropertymanager.h new file mode 100644 index 0000000..90fe5c0 --- /dev/null +++ b/tools/shared/qtpropertybrowser/qtpropertymanager.h @@ -0,0 +1,750 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the tools applications of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QTPROPERTYMANAGER_H +#define QTPROPERTYMANAGER_H + +#include "qtpropertybrowser.h" + +#if QT_VERSION >= 0x040400 +QT_BEGIN_NAMESPACE +#endif + +class QDate; +class QTime; +class QDateTime; +class QLocale; + +class QtGroupPropertyManager : public QtAbstractPropertyManager +{ + Q_OBJECT +public: + QtGroupPropertyManager(QObject *parent = 0); + ~QtGroupPropertyManager(); + +protected: + virtual bool hasValue(const QtProperty *property) const; + + virtual void initializeProperty(QtProperty *property); + virtual void uninitializeProperty(QtProperty *property); +}; + +class QtIntPropertyManagerPrivate; + +class QtIntPropertyManager : public QtAbstractPropertyManager +{ + Q_OBJECT +public: + QtIntPropertyManager(QObject *parent = 0); + ~QtIntPropertyManager(); + + int value(const QtProperty *property) const; + int minimum(const QtProperty *property) const; + int maximum(const QtProperty *property) const; + int singleStep(const QtProperty *property) const; + +public Q_SLOTS: + void setValue(QtProperty *property, int val); + void setMinimum(QtProperty *property, int minVal); + void setMaximum(QtProperty *property, int maxVal); + void setRange(QtProperty *property, int minVal, int maxVal); + void setSingleStep(QtProperty *property, int step); +Q_SIGNALS: + void valueChanged(QtProperty *property, int val); + void rangeChanged(QtProperty *property, int minVal, int maxVal); + void singleStepChanged(QtProperty *property, int step); +protected: + QString valueText(const QtProperty *property) const; + virtual void initializeProperty(QtProperty *property); + virtual void uninitializeProperty(QtProperty *property); +private: + QtIntPropertyManagerPrivate *d_ptr; + Q_DECLARE_PRIVATE(QtIntPropertyManager) + Q_DISABLE_COPY(QtIntPropertyManager) +}; + +class QtBoolPropertyManagerPrivate; + +class QtBoolPropertyManager : public QtAbstractPropertyManager +{ + Q_OBJECT +public: + QtBoolPropertyManager(QObject *parent = 0); + ~QtBoolPropertyManager(); + + bool value(const QtProperty *property) const; + +public Q_SLOTS: + void setValue(QtProperty *property, bool val); +Q_SIGNALS: + void valueChanged(QtProperty *property, bool val); +protected: + QString valueText(const QtProperty *property) const; + QIcon valueIcon(const QtProperty *property) const; + virtual void initializeProperty(QtProperty *property); + virtual void uninitializeProperty(QtProperty *property); +private: + QtBoolPropertyManagerPrivate *d_ptr; + Q_DECLARE_PRIVATE(QtBoolPropertyManager) + Q_DISABLE_COPY(QtBoolPropertyManager) +}; + +class QtDoublePropertyManagerPrivate; + +class QtDoublePropertyManager : public QtAbstractPropertyManager +{ + Q_OBJECT +public: + QtDoublePropertyManager(QObject *parent = 0); + ~QtDoublePropertyManager(); + + double value(const QtProperty *property) const; + double minimum(const QtProperty *property) const; + double maximum(const QtProperty *property) const; + double singleStep(const QtProperty *property) const; + int decimals(const QtProperty *property) const; + +public Q_SLOTS: + void setValue(QtProperty *property, double val); + void setMinimum(QtProperty *property, double minVal); + void setMaximum(QtProperty *property, double maxVal); + void setRange(QtProperty *property, double minVal, double maxVal); + void setSingleStep(QtProperty *property, double step); + void setDecimals(QtProperty *property, int prec); +Q_SIGNALS: + void valueChanged(QtProperty *property, double val); + void rangeChanged(QtProperty *property, double minVal, double maxVal); + void singleStepChanged(QtProperty *property, double step); + void decimalsChanged(QtProperty *property, int prec); +protected: + QString valueText(const QtProperty *property) const; + virtual void initializeProperty(QtProperty *property); + virtual void uninitializeProperty(QtProperty *property); +private: + QtDoublePropertyManagerPrivate *d_ptr; + Q_DECLARE_PRIVATE(QtDoublePropertyManager) + Q_DISABLE_COPY(QtDoublePropertyManager) +}; + +class QtStringPropertyManagerPrivate; + +class QtStringPropertyManager : public QtAbstractPropertyManager +{ + Q_OBJECT +public: + QtStringPropertyManager(QObject *parent = 0); + ~QtStringPropertyManager(); + + QString value(const QtProperty *property) const; + QRegExp regExp(const QtProperty *property) const; + +public Q_SLOTS: + void setValue(QtProperty *property, const QString &val); + void setRegExp(QtProperty *property, const QRegExp ®Exp); +Q_SIGNALS: + void valueChanged(QtProperty *property, const QString &val); + void regExpChanged(QtProperty *property, const QRegExp ®Exp); +protected: + QString valueText(const QtProperty *property) const; + virtual void initializeProperty(QtProperty *property); + virtual void uninitializeProperty(QtProperty *property); +private: + QtStringPropertyManagerPrivate *d_ptr; + Q_DECLARE_PRIVATE(QtStringPropertyManager) + Q_DISABLE_COPY(QtStringPropertyManager) +}; + +class QtDatePropertyManagerPrivate; + +class QtDatePropertyManager : public QtAbstractPropertyManager +{ + Q_OBJECT +public: + QtDatePropertyManager(QObject *parent = 0); + ~QtDatePropertyManager(); + + QDate value(const QtProperty *property) const; + QDate minimum(const QtProperty *property) const; + QDate maximum(const QtProperty *property) const; + +public Q_SLOTS: + void setValue(QtProperty *property, const QDate &val); + void setMinimum(QtProperty *property, const QDate &minVal); + void setMaximum(QtProperty *property, const QDate &maxVal); + void setRange(QtProperty *property, const QDate &minVal, const QDate &maxVal); +Q_SIGNALS: + void valueChanged(QtProperty *property, const QDate &val); + void rangeChanged(QtProperty *property, const QDate &minVal, const QDate &maxVal); +protected: + QString valueText(const QtProperty *property) const; + virtual void initializeProperty(QtProperty *property); + virtual void uninitializeProperty(QtProperty *property); +private: + QtDatePropertyManagerPrivate *d_ptr; + Q_DECLARE_PRIVATE(QtDatePropertyManager) + Q_DISABLE_COPY(QtDatePropertyManager) +}; + +class QtTimePropertyManagerPrivate; + +class QtTimePropertyManager : public QtAbstractPropertyManager +{ + Q_OBJECT +public: + QtTimePropertyManager(QObject *parent = 0); + ~QtTimePropertyManager(); + + QTime value(const QtProperty *property) const; + +public Q_SLOTS: + void setValue(QtProperty *property, const QTime &val); +Q_SIGNALS: + void valueChanged(QtProperty *property, const QTime &val); +protected: + QString valueText(const QtProperty *property) const; + virtual void initializeProperty(QtProperty *property); + virtual void uninitializeProperty(QtProperty *property); +private: + QtTimePropertyManagerPrivate *d_ptr; + Q_DECLARE_PRIVATE(QtTimePropertyManager) + Q_DISABLE_COPY(QtTimePropertyManager) +}; + +class QtDateTimePropertyManagerPrivate; + +class QtDateTimePropertyManager : public QtAbstractPropertyManager +{ + Q_OBJECT +public: + QtDateTimePropertyManager(QObject *parent = 0); + ~QtDateTimePropertyManager(); + + QDateTime value(const QtProperty *property) const; + +public Q_SLOTS: + void setValue(QtProperty *property, const QDateTime &val); +Q_SIGNALS: + void valueChanged(QtProperty *property, const QDateTime &val); +protected: + QString valueText(const QtProperty *property) const; + virtual void initializeProperty(QtProperty *property); + virtual void uninitializeProperty(QtProperty *property); +private: + QtDateTimePropertyManagerPrivate *d_ptr; + Q_DECLARE_PRIVATE(QtDateTimePropertyManager) + Q_DISABLE_COPY(QtDateTimePropertyManager) +}; + +class QtKeySequencePropertyManagerPrivate; + +class QtKeySequencePropertyManager : public QtAbstractPropertyManager +{ + Q_OBJECT +public: + QtKeySequencePropertyManager(QObject *parent = 0); + ~QtKeySequencePropertyManager(); + + QKeySequence value(const QtProperty *property) const; + +public Q_SLOTS: + void setValue(QtProperty *property, const QKeySequence &val); +Q_SIGNALS: + void valueChanged(QtProperty *property, const QKeySequence &val); +protected: + QString valueText(const QtProperty *property) const; + virtual void initializeProperty(QtProperty *property); + virtual void uninitializeProperty(QtProperty *property); +private: + QtKeySequencePropertyManagerPrivate *d_ptr; + Q_DECLARE_PRIVATE(QtKeySequencePropertyManager) + Q_DISABLE_COPY(QtKeySequencePropertyManager) +}; + +class QtCharPropertyManagerPrivate; + +class QtCharPropertyManager : public QtAbstractPropertyManager +{ + Q_OBJECT +public: + QtCharPropertyManager(QObject *parent = 0); + ~QtCharPropertyManager(); + + QChar value(const QtProperty *property) const; + +public Q_SLOTS: + void setValue(QtProperty *property, const QChar &val); +Q_SIGNALS: + void valueChanged(QtProperty *property, const QChar &val); +protected: + QString valueText(const QtProperty *property) const; + virtual void initializeProperty(QtProperty *property); + virtual void uninitializeProperty(QtProperty *property); +private: + QtCharPropertyManagerPrivate *d_ptr; + Q_DECLARE_PRIVATE(QtCharPropertyManager) + Q_DISABLE_COPY(QtCharPropertyManager) +}; + +class QtEnumPropertyManager; +class QtLocalePropertyManagerPrivate; + +class QtLocalePropertyManager : public QtAbstractPropertyManager +{ + Q_OBJECT +public: + QtLocalePropertyManager(QObject *parent = 0); + ~QtLocalePropertyManager(); + + QtEnumPropertyManager *subEnumPropertyManager() const; + + QLocale value(const QtProperty *property) const; + +public Q_SLOTS: + void setValue(QtProperty *property, const QLocale &val); +Q_SIGNALS: + void valueChanged(QtProperty *property, const QLocale &val); +protected: + QString valueText(const QtProperty *property) const; + virtual void initializeProperty(QtProperty *property); + virtual void uninitializeProperty(QtProperty *property); +private: + QtLocalePropertyManagerPrivate *d_ptr; + Q_DECLARE_PRIVATE(QtLocalePropertyManager) + Q_DISABLE_COPY(QtLocalePropertyManager) + Q_PRIVATE_SLOT(d_func(), void slotEnumChanged(QtProperty *, int)) + Q_PRIVATE_SLOT(d_func(), void slotPropertyDestroyed(QtProperty *)) +}; + +class QtPointPropertyManagerPrivate; + +class QtPointPropertyManager : public QtAbstractPropertyManager +{ + Q_OBJECT +public: + QtPointPropertyManager(QObject *parent = 0); + ~QtPointPropertyManager(); + + QtIntPropertyManager *subIntPropertyManager() const; + + QPoint value(const QtProperty *property) const; + +public Q_SLOTS: + void setValue(QtProperty *property, const QPoint &val); +Q_SIGNALS: + void valueChanged(QtProperty *property, const QPoint &val); +protected: + QString valueText(const QtProperty *property) const; + virtual void initializeProperty(QtProperty *property); + virtual void uninitializeProperty(QtProperty *property); +private: + QtPointPropertyManagerPrivate *d_ptr; + Q_DECLARE_PRIVATE(QtPointPropertyManager) + Q_DISABLE_COPY(QtPointPropertyManager) + Q_PRIVATE_SLOT(d_func(), void slotIntChanged(QtProperty *, int)) + Q_PRIVATE_SLOT(d_func(), void slotPropertyDestroyed(QtProperty *)) +}; + +class QtPointFPropertyManagerPrivate; + +class QtPointFPropertyManager : public QtAbstractPropertyManager +{ + Q_OBJECT +public: + QtPointFPropertyManager(QObject *parent = 0); + ~QtPointFPropertyManager(); + + QtDoublePropertyManager *subDoublePropertyManager() const; + + QPointF value(const QtProperty *property) const; + int decimals(const QtProperty *property) const; + +public Q_SLOTS: + void setValue(QtProperty *property, const QPointF &val); + void setDecimals(QtProperty *property, int prec); +Q_SIGNALS: + void valueChanged(QtProperty *property, const QPointF &val); + void decimalsChanged(QtProperty *property, int prec); +protected: + QString valueText(const QtProperty *property) const; + virtual void initializeProperty(QtProperty *property); + virtual void uninitializeProperty(QtProperty *property); +private: + QtPointFPropertyManagerPrivate *d_ptr; + Q_DECLARE_PRIVATE(QtPointFPropertyManager) + Q_DISABLE_COPY(QtPointFPropertyManager) + Q_PRIVATE_SLOT(d_func(), void slotDoubleChanged(QtProperty *, double)) + Q_PRIVATE_SLOT(d_func(), void slotPropertyDestroyed(QtProperty *)) +}; + +class QtSizePropertyManagerPrivate; + +class QtSizePropertyManager : public QtAbstractPropertyManager +{ + Q_OBJECT +public: + QtSizePropertyManager(QObject *parent = 0); + ~QtSizePropertyManager(); + + QtIntPropertyManager *subIntPropertyManager() const; + + QSize value(const QtProperty *property) const; + QSize minimum(const QtProperty *property) const; + QSize maximum(const QtProperty *property) const; + +public Q_SLOTS: + void setValue(QtProperty *property, const QSize &val); + void setMinimum(QtProperty *property, const QSize &minVal); + void setMaximum(QtProperty *property, const QSize &maxVal); + void setRange(QtProperty *property, const QSize &minVal, const QSize &maxVal); +Q_SIGNALS: + void valueChanged(QtProperty *property, const QSize &val); + void rangeChanged(QtProperty *property, const QSize &minVal, const QSize &maxVal); +protected: + QString valueText(const QtProperty *property) const; + virtual void initializeProperty(QtProperty *property); + virtual void uninitializeProperty(QtProperty *property); +private: + QtSizePropertyManagerPrivate *d_ptr; + Q_DECLARE_PRIVATE(QtSizePropertyManager) + Q_DISABLE_COPY(QtSizePropertyManager) + Q_PRIVATE_SLOT(d_func(), void slotIntChanged(QtProperty *, int)) + Q_PRIVATE_SLOT(d_func(), void slotPropertyDestroyed(QtProperty *)) +}; + +class QtSizeFPropertyManagerPrivate; + +class QtSizeFPropertyManager : public QtAbstractPropertyManager +{ + Q_OBJECT +public: + QtSizeFPropertyManager(QObject *parent = 0); + ~QtSizeFPropertyManager(); + + QtDoublePropertyManager *subDoublePropertyManager() const; + + QSizeF value(const QtProperty *property) const; + QSizeF minimum(const QtProperty *property) const; + QSizeF maximum(const QtProperty *property) const; + int decimals(const QtProperty *property) const; + +public Q_SLOTS: + void setValue(QtProperty *property, const QSizeF &val); + void setMinimum(QtProperty *property, const QSizeF &minVal); + void setMaximum(QtProperty *property, const QSizeF &maxVal); + void setRange(QtProperty *property, const QSizeF &minVal, const QSizeF &maxVal); + void setDecimals(QtProperty *property, int prec); +Q_SIGNALS: + void valueChanged(QtProperty *property, const QSizeF &val); + void rangeChanged(QtProperty *property, const QSizeF &minVal, const QSizeF &maxVal); + void decimalsChanged(QtProperty *property, int prec); +protected: + QString valueText(const QtProperty *property) const; + virtual void initializeProperty(QtProperty *property); + virtual void uninitializeProperty(QtProperty *property); +private: + QtSizeFPropertyManagerPrivate *d_ptr; + Q_DECLARE_PRIVATE(QtSizeFPropertyManager) + Q_DISABLE_COPY(QtSizeFPropertyManager) + Q_PRIVATE_SLOT(d_func(), void slotDoubleChanged(QtProperty *, double)) + Q_PRIVATE_SLOT(d_func(), void slotPropertyDestroyed(QtProperty *)) +}; + +class QtRectPropertyManagerPrivate; + +class QtRectPropertyManager : public QtAbstractPropertyManager +{ + Q_OBJECT +public: + QtRectPropertyManager(QObject *parent = 0); + ~QtRectPropertyManager(); + + QtIntPropertyManager *subIntPropertyManager() const; + + QRect value(const QtProperty *property) const; + QRect constraint(const QtProperty *property) const; + +public Q_SLOTS: + void setValue(QtProperty *property, const QRect &val); + void setConstraint(QtProperty *property, const QRect &constraint); +Q_SIGNALS: + void valueChanged(QtProperty *property, const QRect &val); + void constraintChanged(QtProperty *property, const QRect &constraint); +protected: + QString valueText(const QtProperty *property) const; + virtual void initializeProperty(QtProperty *property); + virtual void uninitializeProperty(QtProperty *property); +private: + QtRectPropertyManagerPrivate *d_ptr; + Q_DECLARE_PRIVATE(QtRectPropertyManager) + Q_DISABLE_COPY(QtRectPropertyManager) + Q_PRIVATE_SLOT(d_func(), void slotIntChanged(QtProperty *, int)) + Q_PRIVATE_SLOT(d_func(), void slotPropertyDestroyed(QtProperty *)) +}; + +class QtRectFPropertyManagerPrivate; + +class QtRectFPropertyManager : public QtAbstractPropertyManager +{ + Q_OBJECT +public: + QtRectFPropertyManager(QObject *parent = 0); + ~QtRectFPropertyManager(); + + QtDoublePropertyManager *subDoublePropertyManager() const; + + QRectF value(const QtProperty *property) const; + QRectF constraint(const QtProperty *property) const; + int decimals(const QtProperty *property) const; + +public Q_SLOTS: + void setValue(QtProperty *property, const QRectF &val); + void setConstraint(QtProperty *property, const QRectF &constraint); + void setDecimals(QtProperty *property, int prec); +Q_SIGNALS: + void valueChanged(QtProperty *property, const QRectF &val); + void constraintChanged(QtProperty *property, const QRectF &constraint); + void decimalsChanged(QtProperty *property, int prec); +protected: + QString valueText(const QtProperty *property) const; + virtual void initializeProperty(QtProperty *property); + virtual void uninitializeProperty(QtProperty *property); +private: + QtRectFPropertyManagerPrivate *d_ptr; + Q_DECLARE_PRIVATE(QtRectFPropertyManager) + Q_DISABLE_COPY(QtRectFPropertyManager) + Q_PRIVATE_SLOT(d_func(), void slotDoubleChanged(QtProperty *, double)) + Q_PRIVATE_SLOT(d_func(), void slotPropertyDestroyed(QtProperty *)) +}; + +class QtEnumPropertyManagerPrivate; + +class QtEnumPropertyManager : public QtAbstractPropertyManager +{ + Q_OBJECT +public: + QtEnumPropertyManager(QObject *parent = 0); + ~QtEnumPropertyManager(); + + int value(const QtProperty *property) const; + QStringList enumNames(const QtProperty *property) const; + QMap<int, QIcon> enumIcons(const QtProperty *property) const; + +public Q_SLOTS: + void setValue(QtProperty *property, int val); + void setEnumNames(QtProperty *property, const QStringList &names); + void setEnumIcons(QtProperty *property, const QMap<int, QIcon> &icons); +Q_SIGNALS: + void valueChanged(QtProperty *property, int val); + void enumNamesChanged(QtProperty *property, const QStringList &names); + void enumIconsChanged(QtProperty *property, const QMap<int, QIcon> &icons); +protected: + QString valueText(const QtProperty *property) const; + QIcon valueIcon(const QtProperty *property) const; + virtual void initializeProperty(QtProperty *property); + virtual void uninitializeProperty(QtProperty *property); +private: + QtEnumPropertyManagerPrivate *d_ptr; + Q_DECLARE_PRIVATE(QtEnumPropertyManager) + Q_DISABLE_COPY(QtEnumPropertyManager) +}; + +class QtFlagPropertyManagerPrivate; + +class QtFlagPropertyManager : public QtAbstractPropertyManager +{ + Q_OBJECT +public: + QtFlagPropertyManager(QObject *parent = 0); + ~QtFlagPropertyManager(); + + QtBoolPropertyManager *subBoolPropertyManager() const; + + int value(const QtProperty *property) const; + QStringList flagNames(const QtProperty *property) const; + +public Q_SLOTS: + void setValue(QtProperty *property, int val); + void setFlagNames(QtProperty *property, const QStringList &names); +Q_SIGNALS: + void valueChanged(QtProperty *property, int val); + void flagNamesChanged(QtProperty *property, const QStringList &names); +protected: + QString valueText(const QtProperty *property) const; + virtual void initializeProperty(QtProperty *property); + virtual void uninitializeProperty(QtProperty *property); +private: + QtFlagPropertyManagerPrivate *d_ptr; + Q_DECLARE_PRIVATE(QtFlagPropertyManager) + Q_DISABLE_COPY(QtFlagPropertyManager) + Q_PRIVATE_SLOT(d_func(), void slotBoolChanged(QtProperty *, bool)) + Q_PRIVATE_SLOT(d_func(), void slotPropertyDestroyed(QtProperty *)) +}; + +class QtSizePolicyPropertyManagerPrivate; + +class QtSizePolicyPropertyManager : public QtAbstractPropertyManager +{ + Q_OBJECT +public: + QtSizePolicyPropertyManager(QObject *parent = 0); + ~QtSizePolicyPropertyManager(); + + QtIntPropertyManager *subIntPropertyManager() const; + QtEnumPropertyManager *subEnumPropertyManager() const; + + QSizePolicy value(const QtProperty *property) const; + +public Q_SLOTS: + void setValue(QtProperty *property, const QSizePolicy &val); +Q_SIGNALS: + void valueChanged(QtProperty *property, const QSizePolicy &val); +protected: + QString valueText(const QtProperty *property) const; + virtual void initializeProperty(QtProperty *property); + virtual void uninitializeProperty(QtProperty *property); +private: + QtSizePolicyPropertyManagerPrivate *d_ptr; + Q_DECLARE_PRIVATE(QtSizePolicyPropertyManager) + Q_DISABLE_COPY(QtSizePolicyPropertyManager) + Q_PRIVATE_SLOT(d_func(), void slotIntChanged(QtProperty *, int)) + Q_PRIVATE_SLOT(d_func(), void slotEnumChanged(QtProperty *, int)) + Q_PRIVATE_SLOT(d_func(), void slotPropertyDestroyed(QtProperty *)) +}; + +class QtFontPropertyManagerPrivate; + +class QtFontPropertyManager : public QtAbstractPropertyManager +{ + Q_OBJECT +public: + QtFontPropertyManager(QObject *parent = 0); + ~QtFontPropertyManager(); + + QtIntPropertyManager *subIntPropertyManager() const; + QtEnumPropertyManager *subEnumPropertyManager() const; + QtBoolPropertyManager *subBoolPropertyManager() const; + + QFont value(const QtProperty *property) const; + +public Q_SLOTS: + void setValue(QtProperty *property, const QFont &val); +Q_SIGNALS: + void valueChanged(QtProperty *property, const QFont &val); +protected: + QString valueText(const QtProperty *property) const; + QIcon valueIcon(const QtProperty *property) const; + virtual void initializeProperty(QtProperty *property); + virtual void uninitializeProperty(QtProperty *property); +private: + QtFontPropertyManagerPrivate *d_ptr; + Q_DECLARE_PRIVATE(QtFontPropertyManager) + Q_DISABLE_COPY(QtFontPropertyManager) + Q_PRIVATE_SLOT(d_func(), void slotIntChanged(QtProperty *, int)) + Q_PRIVATE_SLOT(d_func(), void slotEnumChanged(QtProperty *, int)) + Q_PRIVATE_SLOT(d_func(), void slotBoolChanged(QtProperty *, bool)) + Q_PRIVATE_SLOT(d_func(), void slotPropertyDestroyed(QtProperty *)) + Q_PRIVATE_SLOT(d_func(), void slotFontDatabaseChanged()) + Q_PRIVATE_SLOT(d_func(), void slotFontDatabaseDelayedChange()) +}; + +class QtColorPropertyManagerPrivate; + +class QtColorPropertyManager : public QtAbstractPropertyManager +{ + Q_OBJECT +public: + QtColorPropertyManager(QObject *parent = 0); + ~QtColorPropertyManager(); + + QtIntPropertyManager *subIntPropertyManager() const; + + QColor value(const QtProperty *property) const; + +public Q_SLOTS: + void setValue(QtProperty *property, const QColor &val); +Q_SIGNALS: + void valueChanged(QtProperty *property, const QColor &val); +protected: + QString valueText(const QtProperty *property) const; + QIcon valueIcon(const QtProperty *property) const; + virtual void initializeProperty(QtProperty *property); + virtual void uninitializeProperty(QtProperty *property); +private: + QtColorPropertyManagerPrivate *d_ptr; + Q_DECLARE_PRIVATE(QtColorPropertyManager) + Q_DISABLE_COPY(QtColorPropertyManager) + Q_PRIVATE_SLOT(d_func(), void slotIntChanged(QtProperty *, int)) + Q_PRIVATE_SLOT(d_func(), void slotPropertyDestroyed(QtProperty *)) +}; + +class QtCursorPropertyManagerPrivate; + +class QtCursorPropertyManager : public QtAbstractPropertyManager +{ + Q_OBJECT +public: + QtCursorPropertyManager(QObject *parent = 0); + ~QtCursorPropertyManager(); + +#ifndef QT_NO_CURSOR + QCursor value(const QtProperty *property) const; +#endif + +public Q_SLOTS: + void setValue(QtProperty *property, const QCursor &val); +Q_SIGNALS: + void valueChanged(QtProperty *property, const QCursor &val); +protected: + QString valueText(const QtProperty *property) const; + QIcon valueIcon(const QtProperty *property) const; + virtual void initializeProperty(QtProperty *property); + virtual void uninitializeProperty(QtProperty *property); +private: + QtCursorPropertyManagerPrivate *d_ptr; + Q_DECLARE_PRIVATE(QtCursorPropertyManager) + Q_DISABLE_COPY(QtCursorPropertyManager) +}; + +#if QT_VERSION >= 0x040400 +QT_END_NAMESPACE +#endif + +#endif diff --git a/tools/shared/qtpropertybrowser/qttreepropertybrowser.cpp b/tools/shared/qtpropertybrowser/qttreepropertybrowser.cpp new file mode 100644 index 0000000..ed262e5 --- /dev/null +++ b/tools/shared/qtpropertybrowser/qttreepropertybrowser.cpp @@ -0,0 +1,1048 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the tools applications of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qttreepropertybrowser.h" +#include <QtCore/QSet> +#include <QtGui/QIcon> +#include <QtGui/QTreeWidget> +#include <QtGui/QItemDelegate> +#include <QtGui/QHBoxLayout> +#include <QtGui/QHeaderView> +#include <QtGui/QPainter> +#include <QtGui/QApplication> +#include <QtGui/QFocusEvent> +#include <QtGui/QStyle> +#include <QtGui/QPalette> + +#if QT_VERSION >= 0x040400 +QT_BEGIN_NAMESPACE +#endif + +class QtPropertyEditorView; + +class QtTreePropertyBrowserPrivate +{ + QtTreePropertyBrowser *q_ptr; + Q_DECLARE_PUBLIC(QtTreePropertyBrowser) + +public: + QtTreePropertyBrowserPrivate(); + void init(QWidget *parent); + + void propertyInserted(QtBrowserItem *index, QtBrowserItem *afterIndex); + void propertyRemoved(QtBrowserItem *index); + void propertyChanged(QtBrowserItem *index); + QWidget *createEditor(QtProperty *property, QWidget *parent) const + { return q_ptr->createEditor(property, parent); } + QtProperty *indexToProperty(const QModelIndex &index) const; + QTreeWidgetItem *indexToItem(const QModelIndex &index) const; + QtBrowserItem *indexToBrowserItem(const QModelIndex &index) const; + bool lastColumn(int column) const; + void disableItem(QTreeWidgetItem *item) const; + void enableItem(QTreeWidgetItem *item) const; + bool hasValue(QTreeWidgetItem *item) const; + + void slotCollapsed(const QModelIndex &index); + void slotExpanded(const QModelIndex &index); + + QColor calculatedBackgroundColor(QtBrowserItem *item) const; + + QtPropertyEditorView *treeWidget() const { return m_treeWidget; } + bool markPropertiesWithoutValue() const { return m_markPropertiesWithoutValue; } + + QtBrowserItem *currentItem() const; + void setCurrentItem(QtBrowserItem *browserItem, bool block); + void editItem(QtBrowserItem *browserItem); + + void slotCurrentBrowserItemChanged(QtBrowserItem *item); + void slotCurrentTreeItemChanged(QTreeWidgetItem *newItem, QTreeWidgetItem *); + + QTreeWidgetItem *editedItem() const; + +private: + void updateItem(QTreeWidgetItem *item); + + QMap<QtBrowserItem *, QTreeWidgetItem *> m_indexToItem; + QMap<QTreeWidgetItem *, QtBrowserItem *> m_itemToIndex; + + QMap<QtBrowserItem *, QColor> m_indexToBackgroundColor; + + QtPropertyEditorView *m_treeWidget; + + bool m_headerVisible; + QtTreePropertyBrowser::ResizeMode m_resizeMode; + class QtPropertyEditorDelegate *m_delegate; + bool m_markPropertiesWithoutValue; + bool m_browserChangedBlocked; + QIcon m_expandIcon; +}; + +// ------------ QtPropertyEditorView +class QtPropertyEditorView : public QTreeWidget +{ + Q_OBJECT +public: + QtPropertyEditorView(QWidget *parent = 0); + + void setEditorPrivate(QtTreePropertyBrowserPrivate *editorPrivate) + { m_editorPrivate = editorPrivate; } + + QTreeWidgetItem *indexToItem(const QModelIndex &index) const + { return itemFromIndex(index); } + +protected: + void keyPressEvent(QKeyEvent *event); + void mousePressEvent(QMouseEvent *event); + void drawRow(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const; + +private: + QtTreePropertyBrowserPrivate *m_editorPrivate; +}; + +QtPropertyEditorView::QtPropertyEditorView(QWidget *parent) : + QTreeWidget(parent), + m_editorPrivate(0) +{ + connect(header(), SIGNAL(sectionDoubleClicked(int)), this, SLOT(resizeColumnToContents(int))); +} + +void QtPropertyEditorView::drawRow(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const +{ + QStyleOptionViewItemV3 opt = option; + bool hasValue = true; + if (m_editorPrivate) { + QtProperty *property = m_editorPrivate->indexToProperty(index); + if (property) + hasValue = property->hasValue(); + } + if (!hasValue && m_editorPrivate->markPropertiesWithoutValue()) { + const QColor c = option.palette.color(QPalette::Dark); + painter->fillRect(option.rect, c); + opt.palette.setColor(QPalette::AlternateBase, c); + } else { + const QColor c = m_editorPrivate->calculatedBackgroundColor(m_editorPrivate->indexToBrowserItem(index)); + if (c.isValid()) { + painter->fillRect(option.rect, c); + opt.palette.setColor(QPalette::AlternateBase, c.lighter(112)); + } + } + QTreeWidget::drawRow(painter, opt, index); + QColor color = static_cast<QRgb>(QApplication::style()->styleHint(QStyle::SH_Table_GridLineColor, &opt)); + painter->save(); + painter->setPen(QPen(color)); + painter->drawLine(opt.rect.x(), opt.rect.bottom(), opt.rect.right(), opt.rect.bottom()); + painter->restore(); +} + +void QtPropertyEditorView::keyPressEvent(QKeyEvent *event) +{ + switch (event->key()) { + case Qt::Key_Return: + case Qt::Key_Enter: + case Qt::Key_Space: // Trigger Edit + if (!m_editorPrivate->editedItem()) + if (const QTreeWidgetItem *item = currentItem()) + if (item->columnCount() >= 2 && ((item->flags() & (Qt::ItemIsEditable | Qt::ItemIsEnabled)) == (Qt::ItemIsEditable | Qt::ItemIsEnabled))) { + event->accept(); + // If the current position is at column 0, move to 1. + QModelIndex index = currentIndex(); + if (index.column() == 0) { + index = index.sibling(index.row(), 1); + setCurrentIndex(index); + } + edit(index); + return; + } + break; + default: + break; + } + QTreeWidget::keyPressEvent(event); +} + +void QtPropertyEditorView::mousePressEvent(QMouseEvent *event) +{ + QTreeWidget::mousePressEvent(event); + QTreeWidgetItem *item = itemAt(event->pos()); + + if (item) { + if ((item != m_editorPrivate->editedItem()) && (event->button() == Qt::LeftButton) + && (header()->logicalIndexAt(event->pos().x()) == 1) + && ((item->flags() & (Qt::ItemIsEditable | Qt::ItemIsEnabled)) == (Qt::ItemIsEditable | Qt::ItemIsEnabled))) { + editItem(item, 1); + } else if (!m_editorPrivate->hasValue(item) && m_editorPrivate->markPropertiesWithoutValue() && !rootIsDecorated()) { + if (event->pos().x() + header()->offset() < 20) + item->setExpanded(!item->isExpanded()); + } + } +} + +// ------------ QtPropertyEditorDelegate +class QtPropertyEditorDelegate : public QItemDelegate +{ + Q_OBJECT +public: + QtPropertyEditorDelegate(QObject *parent = 0) + : QItemDelegate(parent), m_editorPrivate(0), m_editedItem(0), m_editedWidget(0) + {} + + void setEditorPrivate(QtTreePropertyBrowserPrivate *editorPrivate) + { m_editorPrivate = editorPrivate; } + + QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &option, + const QModelIndex &index) const; + + void updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, + const QModelIndex &index) const; + + void paint(QPainter *painter, const QStyleOptionViewItem &option, + const QModelIndex &index) const; + + QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const; + + void setModelData(QWidget *, QAbstractItemModel *, + const QModelIndex &) const {} + + void setEditorData(QWidget *, const QModelIndex &) const {} + + bool eventFilter(QObject *object, QEvent *event); + void closeEditor(QtProperty *property); + + QTreeWidgetItem *editedItem() const { return m_editedItem; } + +private slots: + void slotEditorDestroyed(QObject *object); + +private: + int indentation(const QModelIndex &index) const; + + typedef QMap<QWidget *, QtProperty *> EditorToPropertyMap; + mutable EditorToPropertyMap m_editorToProperty; + + typedef QMap<QtProperty *, QWidget *> PropertyToEditorMap; + mutable PropertyToEditorMap m_propertyToEditor; + QtTreePropertyBrowserPrivate *m_editorPrivate; + mutable QTreeWidgetItem *m_editedItem; + mutable QWidget *m_editedWidget; +}; + +int QtPropertyEditorDelegate::indentation(const QModelIndex &index) const +{ + if (!m_editorPrivate) + return 0; + + QTreeWidgetItem *item = m_editorPrivate->indexToItem(index); + int indent = 0; + while (item->parent()) { + item = item->parent(); + ++indent; + } + if (m_editorPrivate->treeWidget()->rootIsDecorated()) + ++indent; + return indent * m_editorPrivate->treeWidget()->indentation(); +} + +void QtPropertyEditorDelegate::slotEditorDestroyed(QObject *object) +{ + if (QWidget *w = qobject_cast<QWidget *>(object)) { + const EditorToPropertyMap::iterator it = m_editorToProperty.find(w); + if (it != m_editorToProperty.end()) { + m_propertyToEditor.remove(it.value()); + m_editorToProperty.erase(it); + } + if (m_editedWidget == w) { + m_editedWidget = 0; + m_editedItem = 0; + } + } +} + +void QtPropertyEditorDelegate::closeEditor(QtProperty *property) +{ + if (QWidget *w = m_propertyToEditor.value(property, 0)) + w->deleteLater(); +} + +QWidget *QtPropertyEditorDelegate::createEditor(QWidget *parent, + const QStyleOptionViewItem &, const QModelIndex &index) const +{ + if (index.column() == 1 && m_editorPrivate) { + QtProperty *property = m_editorPrivate->indexToProperty(index); + QTreeWidgetItem *item = m_editorPrivate->indexToItem(index); + if (property && item && (item->flags() & Qt::ItemIsEnabled)) { + QWidget *editor = m_editorPrivate->createEditor(property, parent); + if (editor) { + editor->setAutoFillBackground(true); + editor->installEventFilter(const_cast<QtPropertyEditorDelegate *>(this)); + connect(editor, SIGNAL(destroyed(QObject *)), this, SLOT(slotEditorDestroyed(QObject *))); + m_propertyToEditor[property] = editor; + m_editorToProperty[editor] = property; + m_editedItem = item; + m_editedWidget = editor; + } + return editor; + } + } + return 0; +} + +void QtPropertyEditorDelegate::updateEditorGeometry(QWidget *editor, + const QStyleOptionViewItem &option, const QModelIndex &index) const +{ + Q_UNUSED(index) + editor->setGeometry(option.rect.adjusted(0, 0, 0, -1)); +} + +void QtPropertyEditorDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, + const QModelIndex &index) const +{ + bool hasValue = true; + if (m_editorPrivate) { + QtProperty *property = m_editorPrivate->indexToProperty(index); + if (property) + hasValue = property->hasValue(); + } + QStyleOptionViewItemV3 opt = option; + if ((m_editorPrivate && index.column() == 0) || !hasValue) { + QtProperty *property = m_editorPrivate->indexToProperty(index); + if (property && property->isModified()) { + opt.font.setBold(true); + opt.fontMetrics = QFontMetrics(opt.font); + } + } + QColor c; + if (!hasValue && m_editorPrivate->markPropertiesWithoutValue()) { + c = opt.palette.color(QPalette::Dark); + opt.palette.setColor(QPalette::Text, opt.palette.color(QPalette::BrightText)); + } else { + c = m_editorPrivate->calculatedBackgroundColor(m_editorPrivate->indexToBrowserItem(index)); + if (c.isValid() && (opt.features & QStyleOptionViewItemV2::Alternate)) + c = c.lighter(112); + } + if (c.isValid()) + painter->fillRect(option.rect, c); + opt.state &= ~QStyle::State_HasFocus; + QItemDelegate::paint(painter, opt, index); + + opt.palette.setCurrentColorGroup(QPalette::Active); + QColor color = static_cast<QRgb>(QApplication::style()->styleHint(QStyle::SH_Table_GridLineColor, &opt)); + painter->save(); + painter->setPen(QPen(color)); + if (!m_editorPrivate || (!m_editorPrivate->lastColumn(index.column()) && hasValue)) { + int right = (option.direction == Qt::LeftToRight) ? option.rect.right() : option.rect.left(); + painter->drawLine(right, option.rect.y(), right, option.rect.bottom()); + } + painter->restore(); +} + +QSize QtPropertyEditorDelegate::sizeHint(const QStyleOptionViewItem &option, + const QModelIndex &index) const +{ + return QItemDelegate::sizeHint(option, index) + QSize(3, 4); +} + +bool QtPropertyEditorDelegate::eventFilter(QObject *object, QEvent *event) +{ + if (event->type() == QEvent::FocusOut) { + QFocusEvent *fe = static_cast<QFocusEvent *>(event); + if (fe->reason() == Qt::ActiveWindowFocusReason) + return false; + } + return QItemDelegate::eventFilter(object, event); +} + +// -------- QtTreePropertyBrowserPrivate implementation +QtTreePropertyBrowserPrivate::QtTreePropertyBrowserPrivate() : + m_treeWidget(0), + m_headerVisible(true), + m_resizeMode(QtTreePropertyBrowser::Stretch), + m_delegate(0), + m_markPropertiesWithoutValue(false), + m_browserChangedBlocked(false) +{ +} + +// Draw an icon indicating opened/closing branches +static QIcon drawIndicatorIcon(const QPalette &palette, QStyle *style) +{ + QPixmap pix(14, 14); + pix.fill(Qt::transparent); + QStyleOption branchOption; + QRect r(QPoint(0, 0), pix.size()); + branchOption.rect = QRect(2, 2, 9, 9); // ### hardcoded in qcommonstyle.cpp + branchOption.palette = palette; + branchOption.state = QStyle::State_Children; + + QPainter p; + // Draw closed state + p.begin(&pix); + style->drawPrimitive(QStyle::PE_IndicatorBranch, &branchOption, &p); + p.end(); + QIcon rc = pix; + rc.addPixmap(pix, QIcon::Selected, QIcon::Off); + // Draw opened state + branchOption.state |= QStyle::State_Open; + pix.fill(Qt::transparent); + p.begin(&pix); + style->drawPrimitive(QStyle::PE_IndicatorBranch, &branchOption, &p); + p.end(); + + rc.addPixmap(pix, QIcon::Normal, QIcon::On); + rc.addPixmap(pix, QIcon::Selected, QIcon::On); + return rc; +} + +void QtTreePropertyBrowserPrivate::init(QWidget *parent) +{ + QHBoxLayout *layout = new QHBoxLayout(parent); + layout->setMargin(0); + m_treeWidget = new QtPropertyEditorView(parent); + m_treeWidget->setEditorPrivate(this); + m_treeWidget->setIconSize(QSize(18, 18)); + layout->addWidget(m_treeWidget); + + m_treeWidget->setColumnCount(2); + QStringList labels; + labels.append(QApplication::translate("QtTreePropertyBrowser", "Property", 0, QApplication::UnicodeUTF8)); + labels.append(QApplication::translate("QtTreePropertyBrowser", "Value", 0, QApplication::UnicodeUTF8)); + m_treeWidget->setHeaderLabels(labels); + m_treeWidget->setAlternatingRowColors(true); + m_treeWidget->setEditTriggers(QAbstractItemView::EditKeyPressed); + m_delegate = new QtPropertyEditorDelegate(parent); + m_delegate->setEditorPrivate(this); + m_treeWidget->setItemDelegate(m_delegate); + m_treeWidget->header()->setMovable(false); + m_treeWidget->header()->setResizeMode(QHeaderView::Stretch); + + m_expandIcon = drawIndicatorIcon(q_ptr->palette(), q_ptr->style()); + + QObject::connect(m_treeWidget, SIGNAL(collapsed(const QModelIndex &)), q_ptr, SLOT(slotCollapsed(const QModelIndex &))); + QObject::connect(m_treeWidget, SIGNAL(expanded(const QModelIndex &)), q_ptr, SLOT(slotExpanded(const QModelIndex &))); + QObject::connect(m_treeWidget, SIGNAL(currentItemChanged(QTreeWidgetItem*,QTreeWidgetItem*)), q_ptr, SLOT(slotCurrentTreeItemChanged(QTreeWidgetItem*,QTreeWidgetItem*))); +} + +QtBrowserItem *QtTreePropertyBrowserPrivate::currentItem() const +{ + if (QTreeWidgetItem *treeItem = m_treeWidget->currentItem()) + return m_itemToIndex.value(treeItem); + return 0; +} + +void QtTreePropertyBrowserPrivate::setCurrentItem(QtBrowserItem *browserItem, bool block) +{ + const bool blocked = block ? m_treeWidget->blockSignals(true) : false; + if (browserItem == 0) + m_treeWidget->setCurrentItem(0); + else + m_treeWidget->setCurrentItem(m_indexToItem.value(browserItem)); + if (block) + m_treeWidget->blockSignals(blocked); +} + +QtProperty *QtTreePropertyBrowserPrivate::indexToProperty(const QModelIndex &index) const +{ + QTreeWidgetItem *item = m_treeWidget->indexToItem(index); + QtBrowserItem *idx = m_itemToIndex.value(item); + if (idx) + return idx->property(); + return 0; +} + +QtBrowserItem *QtTreePropertyBrowserPrivate::indexToBrowserItem(const QModelIndex &index) const +{ + QTreeWidgetItem *item = m_treeWidget->indexToItem(index); + return m_itemToIndex.value(item); +} + +QTreeWidgetItem *QtTreePropertyBrowserPrivate::indexToItem(const QModelIndex &index) const +{ + return m_treeWidget->indexToItem(index); +} + +bool QtTreePropertyBrowserPrivate::lastColumn(int column) const +{ + return m_treeWidget->header()->visualIndex(column) == m_treeWidget->columnCount() - 1; +} + +void QtTreePropertyBrowserPrivate::disableItem(QTreeWidgetItem *item) const +{ + Qt::ItemFlags flags = item->flags(); + if (flags & Qt::ItemIsEnabled) { + flags &= ~Qt::ItemIsEnabled; + item->setFlags(flags); + m_delegate->closeEditor(m_itemToIndex[item]->property()); + const int childCount = item->childCount(); + for (int i = 0; i < childCount; i++) { + QTreeWidgetItem *child = item->child(i); + disableItem(child); + } + } +} + +void QtTreePropertyBrowserPrivate::enableItem(QTreeWidgetItem *item) const +{ + Qt::ItemFlags flags = item->flags(); + flags |= Qt::ItemIsEnabled; + item->setFlags(flags); + const int childCount = item->childCount(); + for (int i = 0; i < childCount; i++) { + QTreeWidgetItem *child = item->child(i); + QtProperty *property = m_itemToIndex[child]->property(); + if (property->isEnabled()) { + enableItem(child); + } + } +} + +bool QtTreePropertyBrowserPrivate::hasValue(QTreeWidgetItem *item) const +{ + QtBrowserItem *browserItem = m_itemToIndex.value(item); + if (browserItem) + return browserItem->property()->hasValue(); + return false; +} + +void QtTreePropertyBrowserPrivate::propertyInserted(QtBrowserItem *index, QtBrowserItem *afterIndex) +{ + QTreeWidgetItem *afterItem = m_indexToItem.value(afterIndex); + QTreeWidgetItem *parentItem = m_indexToItem.value(index->parent()); + + QTreeWidgetItem *newItem = 0; + if (parentItem) { + newItem = new QTreeWidgetItem(parentItem, afterItem); + } else { + newItem = new QTreeWidgetItem(m_treeWidget, afterItem); + } + m_itemToIndex[newItem] = index; + m_indexToItem[index] = newItem; + + newItem->setFlags(newItem->flags() | Qt::ItemIsEditable); + m_treeWidget->setItemExpanded(newItem, true); + + updateItem(newItem); +} + +void QtTreePropertyBrowserPrivate::propertyRemoved(QtBrowserItem *index) +{ + QTreeWidgetItem *item = m_indexToItem.value(index); + + if (m_treeWidget->currentItem() == item) { + m_treeWidget->setCurrentItem(0); + } + + delete item; + + m_indexToItem.remove(index); + m_itemToIndex.remove(item); + m_indexToBackgroundColor.remove(index); +} + +void QtTreePropertyBrowserPrivate::propertyChanged(QtBrowserItem *index) +{ + QTreeWidgetItem *item = m_indexToItem.value(index); + + updateItem(item); +} + +void QtTreePropertyBrowserPrivate::updateItem(QTreeWidgetItem *item) +{ + QtProperty *property = m_itemToIndex[item]->property(); + QIcon expandIcon; + if (property->hasValue()) { + QString toolTip = property->toolTip(); + if (toolTip.isEmpty()) + toolTip = property->valueText(); + item->setToolTip(1, toolTip); + item->setIcon(1, property->valueIcon()); + item->setText(1, property->valueText()); + } else if (markPropertiesWithoutValue() && !m_treeWidget->rootIsDecorated()) { + expandIcon = m_expandIcon; + } + item->setIcon(0, expandIcon); + item->setFirstColumnSpanned(!property->hasValue()); + item->setToolTip(0, property->propertyName()); + item->setStatusTip(0, property->statusTip()); + item->setWhatsThis(0, property->whatsThis()); + item->setText(0, property->propertyName()); + bool wasEnabled = item->flags() & Qt::ItemIsEnabled; + bool isEnabled = wasEnabled; + if (property->isEnabled()) { + QTreeWidgetItem *parent = item->parent(); + if (!parent || (parent->flags() & Qt::ItemIsEnabled)) + isEnabled = true; + else + isEnabled = false; + } else { + isEnabled = false; + } + if (wasEnabled != isEnabled) { + if (isEnabled) + enableItem(item); + else + disableItem(item); + } + m_treeWidget->viewport()->update(); +} + +QColor QtTreePropertyBrowserPrivate::calculatedBackgroundColor(QtBrowserItem *item) const +{ + QtBrowserItem *i = item; + const QMap<QtBrowserItem *, QColor>::const_iterator itEnd = m_indexToBackgroundColor.constEnd(); + while (i) { + QMap<QtBrowserItem *, QColor>::const_iterator it = m_indexToBackgroundColor.constFind(i); + if (it != itEnd) + return it.value(); + i = i->parent(); + } + return QColor(); +} + +void QtTreePropertyBrowserPrivate::slotCollapsed(const QModelIndex &index) +{ + QTreeWidgetItem *item = indexToItem(index); + QtBrowserItem *idx = m_itemToIndex.value(item); + if (item) + emit q_ptr->collapsed(idx); +} + +void QtTreePropertyBrowserPrivate::slotExpanded(const QModelIndex &index) +{ + QTreeWidgetItem *item = indexToItem(index); + QtBrowserItem *idx = m_itemToIndex.value(item); + if (item) + emit q_ptr->expanded(idx); +} + +void QtTreePropertyBrowserPrivate::slotCurrentBrowserItemChanged(QtBrowserItem *item) +{ + if (!m_browserChangedBlocked && item != currentItem()) + setCurrentItem(item, true); +} + +void QtTreePropertyBrowserPrivate::slotCurrentTreeItemChanged(QTreeWidgetItem *newItem, QTreeWidgetItem *) +{ + QtBrowserItem *browserItem = newItem ? m_itemToIndex.value(newItem) : 0; + m_browserChangedBlocked = true; + q_ptr->setCurrentItem(browserItem); + m_browserChangedBlocked = false; +} + +QTreeWidgetItem *QtTreePropertyBrowserPrivate::editedItem() const +{ + return m_delegate->editedItem(); +} + +void QtTreePropertyBrowserPrivate::editItem(QtBrowserItem *browserItem) +{ + if (QTreeWidgetItem *treeItem = m_indexToItem.value(browserItem, 0)) { + m_treeWidget->setCurrentItem (treeItem, 1); + m_treeWidget->editItem(treeItem, 1); + } +} + +/*! + \class QtTreePropertyBrowser + \internal + \inmodule QtDesigner + \since 4.4 + + \brief The QtTreePropertyBrowser class provides QTreeWidget based + property browser. + + A property browser is a widget that enables the user to edit a + given set of properties. Each property is represented by a label + specifying the property's name, and an editing widget (e.g. a line + edit or a combobox) holding its value. A property can have zero or + more subproperties. + + QtTreePropertyBrowser provides a tree based view for all nested + properties, i.e. properties that have subproperties can be in an + expanded (subproperties are visible) or collapsed (subproperties + are hidden) state. For example: + + \image qttreepropertybrowser.png + + Use the QtAbstractPropertyBrowser API to add, insert and remove + properties from an instance of the QtTreePropertyBrowser class. + The properties themselves are created and managed by + implementations of the QtAbstractPropertyManager class. + + \sa QtGroupBoxPropertyBrowser, QtAbstractPropertyBrowser +*/ + +/*! + \fn void QtTreePropertyBrowser::collapsed(QtBrowserItem *item) + + This signal is emitted when the \a item is collapsed. + + \sa expanded(), setExpanded() +*/ + +/*! + \fn void QtTreePropertyBrowser::expanded(QtBrowserItem *item) + + This signal is emitted when the \a item is expanded. + + \sa collapsed(), setExpanded() +*/ + +/*! + Creates a property browser with the given \a parent. +*/ +QtTreePropertyBrowser::QtTreePropertyBrowser(QWidget *parent) + : QtAbstractPropertyBrowser(parent) +{ + d_ptr = new QtTreePropertyBrowserPrivate; + d_ptr->q_ptr = this; + + d_ptr->init(this); + connect(this, SIGNAL(currentItemChanged(QtBrowserItem*)), this, SLOT(slotCurrentBrowserItemChanged(QtBrowserItem*))); +} + +/*! + Destroys this property browser. + + Note that the properties that were inserted into this browser are + \e not destroyed since they may still be used in other + browsers. The properties are owned by the manager that created + them. + + \sa QtProperty, QtAbstractPropertyManager +*/ +QtTreePropertyBrowser::~QtTreePropertyBrowser() +{ + delete d_ptr; +} + +/*! + \property QtTreePropertyBrowser::indentation + \brief indentation of the items in the tree view. +*/ +int QtTreePropertyBrowser::indentation() const +{ + return d_ptr->m_treeWidget->indentation(); +} + +void QtTreePropertyBrowser::setIndentation(int i) +{ + d_ptr->m_treeWidget->setIndentation(i); +} + +/*! + \property QtTreePropertyBrowser::rootIsDecorated + \brief whether to show controls for expanding and collapsing root items. +*/ +bool QtTreePropertyBrowser::rootIsDecorated() const +{ + return d_ptr->m_treeWidget->rootIsDecorated(); +} + +void QtTreePropertyBrowser::setRootIsDecorated(bool show) +{ + d_ptr->m_treeWidget->setRootIsDecorated(show); + QMapIterator<QTreeWidgetItem *, QtBrowserItem *> it(d_ptr->m_itemToIndex); + while (it.hasNext()) { + QtProperty *property = it.next().value()->property(); + if (!property->hasValue()) + d_ptr->updateItem(it.key()); + } +} + +/*! + \property QtTreePropertyBrowser::alternatingRowColors + \brief whether to draw the background using alternating colors. + By default this property is set to true. +*/ +bool QtTreePropertyBrowser::alternatingRowColors() const +{ + return d_ptr->m_treeWidget->alternatingRowColors(); +} + +void QtTreePropertyBrowser::setAlternatingRowColors(bool enable) +{ + d_ptr->m_treeWidget->setAlternatingRowColors(enable); + QMapIterator<QTreeWidgetItem *, QtBrowserItem *> it(d_ptr->m_itemToIndex); +} + +/*! + \property QtTreePropertyBrowser::headerVisible + \brief whether to show the header. +*/ +bool QtTreePropertyBrowser::isHeaderVisible() const +{ + return d_ptr->m_headerVisible; +} + +void QtTreePropertyBrowser::setHeaderVisible(bool visible) +{ + if (d_ptr->m_headerVisible == visible) + return; + + d_ptr->m_headerVisible = visible; + d_ptr->m_treeWidget->header()->setVisible(visible); +} + +/*! + \enum QtTreePropertyBrowser::ResizeMode + + The resize mode specifies the behavior of the header sections. + + \value Interactive The user can resize the sections. + The sections can also be resized programmatically using setSplitterPosition(). + + \value Fixed The user cannot resize the section. + The section can only be resized programmatically using setSplitterPosition(). + + \value Stretch QHeaderView will automatically resize the section to fill the available space. + The size cannot be changed by the user or programmatically. + + \value ResizeToContents QHeaderView will automatically resize the section to its optimal + size based on the contents of the entire column. + The size cannot be changed by the user or programmatically. + + \sa setResizeMode() +*/ + +/*! + \property QtTreePropertyBrowser::resizeMode + \brief the resize mode of setions in the header. +*/ + +QtTreePropertyBrowser::ResizeMode QtTreePropertyBrowser::resizeMode() const +{ + return d_ptr->m_resizeMode; +} + +void QtTreePropertyBrowser::setResizeMode(QtTreePropertyBrowser::ResizeMode mode) +{ + if (d_ptr->m_resizeMode == mode) + return; + + d_ptr->m_resizeMode = mode; + QHeaderView::ResizeMode m = QHeaderView::Stretch; + switch (mode) { + case QtTreePropertyBrowser::Interactive: m = QHeaderView::Interactive; break; + case QtTreePropertyBrowser::Fixed: m = QHeaderView::Fixed; break; + case QtTreePropertyBrowser::ResizeToContents: m = QHeaderView::ResizeToContents; break; + case QtTreePropertyBrowser::Stretch: + default: m = QHeaderView::Stretch; break; + } + d_ptr->m_treeWidget->header()->setResizeMode(m); +} + +/*! + \property QtTreePropertyBrowser::splitterPosition + \brief the position of the splitter between the colunms. +*/ + +int QtTreePropertyBrowser::splitterPosition() const +{ + return d_ptr->m_treeWidget->header()->sectionSize(0); +} + +void QtTreePropertyBrowser::setSplitterPosition(int position) +{ + d_ptr->m_treeWidget->header()->resizeSection(0, position); +} + +/*! + Sets the \a item to either collapse or expanded, depending on the value of \a expanded. + + \sa isExpanded(), expanded(), collapsed() +*/ + +void QtTreePropertyBrowser::setExpanded(QtBrowserItem *item, bool expanded) +{ + QTreeWidgetItem *treeItem = d_ptr->m_indexToItem.value(item); + if (treeItem) + treeItem->setExpanded(expanded); +} + +/*! + Returns true if the \a item is expanded; otherwise returns false. + + \sa setExpanded() +*/ + +bool QtTreePropertyBrowser::isExpanded(QtBrowserItem *item) const +{ + QTreeWidgetItem *treeItem = d_ptr->m_indexToItem.value(item); + if (treeItem) + return treeItem->isExpanded(); + return false; +} + +/*! + Returns true if the \a item is visible; otherwise returns false. + + \sa setItemVisible() + \since 4.5 +*/ + +bool QtTreePropertyBrowser::isItemVisible(QtBrowserItem *item) const +{ + if (const QTreeWidgetItem *treeItem = d_ptr->m_indexToItem.value(item)) + return !treeItem->isHidden(); + return false; +} + +/*! + Sets the \a item to be visible, depending on the value of \a visible. + + \sa isItemVisible() + \since 4.5 +*/ + +void QtTreePropertyBrowser::setItemVisible(QtBrowserItem *item, bool visible) +{ + if (QTreeWidgetItem *treeItem = d_ptr->m_indexToItem.value(item)) + treeItem->setHidden(!visible); +} + +/*! + Sets the \a item's background color to \a color. Note that while item's background + is rendered every second row is being drawn with alternate color (which is a bit lighter than items \a color) + + \sa backgroundColor(), calculatedBackgroundColor() +*/ + +void QtTreePropertyBrowser::setBackgroundColor(QtBrowserItem *item, const QColor &color) +{ + if (!d_ptr->m_indexToItem.contains(item)) + return; + if (color.isValid()) + d_ptr->m_indexToBackgroundColor[item] = color; + else + d_ptr->m_indexToBackgroundColor.remove(item); + d_ptr->m_treeWidget->viewport()->update(); +} + +/*! + Returns the \a item's color. If there is no color set for item it returns invalid color. + + \sa calculatedBackgroundColor(), setBackgroundColor() +*/ + +QColor QtTreePropertyBrowser::backgroundColor(QtBrowserItem *item) const +{ + return d_ptr->m_indexToBackgroundColor.value(item); +} + +/*! + Returns the \a item's color. If there is no color set for item it returns parent \a item's + color (if there is no color set for parent it returns grandparent's color and so on). In case + the color is not set for \a item and it's top level item it returns invalid color. + + \sa backgroundColor(), setBackgroundColor() +*/ + +QColor QtTreePropertyBrowser::calculatedBackgroundColor(QtBrowserItem *item) const +{ + return d_ptr->calculatedBackgroundColor(item); +} + +/*! + \property QtTreePropertyBrowser::propertiesWithoutValueMarked + \brief whether to enable or disable marking properties without value. + + When marking is enabled the item's background is rendered in dark color and item's + foreground is rendered with light color. + + \sa propertiesWithoutValueMarked() +*/ +void QtTreePropertyBrowser::setPropertiesWithoutValueMarked(bool mark) +{ + if (d_ptr->m_markPropertiesWithoutValue == mark) + return; + + d_ptr->m_markPropertiesWithoutValue = mark; + QMapIterator<QTreeWidgetItem *, QtBrowserItem *> it(d_ptr->m_itemToIndex); + while (it.hasNext()) { + QtProperty *property = it.next().value()->property(); + if (!property->hasValue()) + d_ptr->updateItem(it.key()); + } + d_ptr->m_treeWidget->viewport()->update(); +} + +bool QtTreePropertyBrowser::propertiesWithoutValueMarked() const +{ + return d_ptr->m_markPropertiesWithoutValue; +} + +/*! + \reimp +*/ +void QtTreePropertyBrowser::itemInserted(QtBrowserItem *item, QtBrowserItem *afterItem) +{ + d_ptr->propertyInserted(item, afterItem); +} + +/*! + \reimp +*/ +void QtTreePropertyBrowser::itemRemoved(QtBrowserItem *item) +{ + d_ptr->propertyRemoved(item); +} + +/*! + \reimp +*/ +void QtTreePropertyBrowser::itemChanged(QtBrowserItem *item) +{ + d_ptr->propertyChanged(item); +} + +/*! + Sets the current item to \a item and opens the relevant editor for it. +*/ +void QtTreePropertyBrowser::editItem(QtBrowserItem *item) +{ + d_ptr->editItem(item); +} + +#if QT_VERSION >= 0x040400 +QT_END_NAMESPACE +#endif + +#include "moc_qttreepropertybrowser.cpp" +#include "qttreepropertybrowser.moc" diff --git a/tools/shared/qtpropertybrowser/qttreepropertybrowser.h b/tools/shared/qtpropertybrowser/qttreepropertybrowser.h new file mode 100644 index 0000000..63bd7f6 --- /dev/null +++ b/tools/shared/qtpropertybrowser/qttreepropertybrowser.h @@ -0,0 +1,138 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the tools applications of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QTTREEPROPERTYBROWSER_H +#define QTTREEPROPERTYBROWSER_H + +#include "qtpropertybrowser.h" + +#if QT_VERSION >= 0x040400 +QT_BEGIN_NAMESPACE +#endif + +class QTreeWidgetItem; +class QtTreePropertyBrowserPrivate; + +class QtTreePropertyBrowser : public QtAbstractPropertyBrowser +{ + Q_OBJECT + Q_ENUMS(ResizeMode) + Q_PROPERTY(int indentation READ indentation WRITE setIndentation) + Q_PROPERTY(bool rootIsDecorated READ rootIsDecorated WRITE setRootIsDecorated) + Q_PROPERTY(bool alternatingRowColors READ alternatingRowColors WRITE setAlternatingRowColors) + Q_PROPERTY(bool headerVisible READ isHeaderVisible WRITE setHeaderVisible) + Q_PROPERTY(ResizeMode resizeMode READ resizeMode WRITE setResizeMode) + Q_PROPERTY(int splitterPosition READ splitterPosition WRITE setSplitterPosition) + Q_PROPERTY(bool propertiesWithoutValueMarked READ propertiesWithoutValueMarked WRITE setPropertiesWithoutValueMarked) +public: + + enum ResizeMode + { + Interactive, + Stretch, + Fixed, + ResizeToContents + }; + + QtTreePropertyBrowser(QWidget *parent = 0); + ~QtTreePropertyBrowser(); + + int indentation() const; + void setIndentation(int i); + + bool rootIsDecorated() const; + void setRootIsDecorated(bool show); + + bool alternatingRowColors() const; + void setAlternatingRowColors(bool enable); + + bool isHeaderVisible() const; + void setHeaderVisible(bool visible); + + ResizeMode resizeMode() const; + void setResizeMode(ResizeMode mode); + + int splitterPosition() const; + void setSplitterPosition(int position); + + void setExpanded(QtBrowserItem *item, bool expanded); + bool isExpanded(QtBrowserItem *item) const; + + bool isItemVisible(QtBrowserItem *item) const; + void setItemVisible(QtBrowserItem *item, bool visible); + + void setBackgroundColor(QtBrowserItem *item, const QColor &color); + QColor backgroundColor(QtBrowserItem *item) const; + QColor calculatedBackgroundColor(QtBrowserItem *item) const; + + void setPropertiesWithoutValueMarked(bool mark); + bool propertiesWithoutValueMarked() const; + + void editItem(QtBrowserItem *item); + +Q_SIGNALS: + + void collapsed(QtBrowserItem *item); + void expanded(QtBrowserItem *item); + +protected: + virtual void itemInserted(QtBrowserItem *item, QtBrowserItem *afterItem); + virtual void itemRemoved(QtBrowserItem *item); + virtual void itemChanged(QtBrowserItem *item); + +private: + + QtTreePropertyBrowserPrivate *d_ptr; + Q_DECLARE_PRIVATE(QtTreePropertyBrowser) + Q_DISABLE_COPY(QtTreePropertyBrowser) + + Q_PRIVATE_SLOT(d_func(), void slotCollapsed(const QModelIndex &)) + Q_PRIVATE_SLOT(d_func(), void slotExpanded(const QModelIndex &)) + Q_PRIVATE_SLOT(d_func(), void slotCurrentBrowserItemChanged(QtBrowserItem *)) + Q_PRIVATE_SLOT(d_func(), void slotCurrentTreeItemChanged(QTreeWidgetItem *, QTreeWidgetItem *)) + +}; + +#if QT_VERSION >= 0x040400 +QT_END_NAMESPACE +#endif + +#endif diff --git a/tools/shared/qtpropertybrowser/qtvariantproperty.cpp b/tools/shared/qtpropertybrowser/qtvariantproperty.cpp new file mode 100644 index 0000000..7e1975e --- /dev/null +++ b/tools/shared/qtpropertybrowser/qtvariantproperty.cpp @@ -0,0 +1,2282 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the tools applications of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qtvariantproperty.h" +#include "qtpropertymanager.h" +#include "qteditorfactory.h" +#include <QtCore/QVariant> +#include <QtGui/QIcon> +#include <QtCore/QDate> +#include <QtCore/QLocale> + +#if defined(Q_CC_MSVC) +# pragma warning(disable: 4786) /* MS VS 6: truncating debug info after 255 characters */ +#endif + +#if QT_VERSION >= 0x040400 +QT_BEGIN_NAMESPACE +#endif + +class QtEnumPropertyType +{ +}; + + +class QtFlagPropertyType +{ +}; + + +class QtGroupPropertyType +{ +}; + +#if QT_VERSION >= 0x040400 +QT_END_NAMESPACE +#endif + +Q_DECLARE_METATYPE(QtEnumPropertyType) +Q_DECLARE_METATYPE(QtFlagPropertyType) +Q_DECLARE_METATYPE(QtGroupPropertyType) + +#if QT_VERSION >= 0x040400 +QT_BEGIN_NAMESPACE +#endif + +/*! + Returns the type id for an enum property. + + Note that the property's value type can be retrieved using the + valueType() function (which is QVariant::Int for the enum property + type). + + \sa propertyType(), valueType() +*/ +int QtVariantPropertyManager::enumTypeId() +{ + return qMetaTypeId<QtEnumPropertyType>(); +} + +/*! + Returns the type id for a flag property. + + Note that the property's value type can be retrieved using the + valueType() function (which is QVariant::Int for the flag property + type). + + \sa propertyType(), valueType() +*/ +int QtVariantPropertyManager::flagTypeId() +{ + return qMetaTypeId<QtFlagPropertyType>(); +} + +/*! + Returns the type id for a group property. + + Note that the property's value type can be retrieved using the + valueType() function (which is QVariant::Invalid for the group + property type, since it doesn't provide any value). + + \sa propertyType(), valueType() +*/ +int QtVariantPropertyManager::groupTypeId() +{ + return qMetaTypeId<QtGroupPropertyType>(); +} + +/*! + Returns the type id for a icon map attribute. + + Note that the property's attribute type can be retrieved using the + attributeType() function. + + \sa attributeType(), QtEnumPropertyManager::enumIcons() +*/ +int QtVariantPropertyManager::iconMapTypeId() +{ + return qMetaTypeId<QtIconMap>(); +} + +typedef QMap<const QtProperty *, QtProperty *> PropertyMap; +Q_GLOBAL_STATIC(PropertyMap, propertyToWrappedProperty) + +static QtProperty *wrappedProperty(QtProperty *property) +{ + return propertyToWrappedProperty()->value(property, 0); +} + +class QtVariantPropertyPrivate +{ + QtVariantProperty *q_ptr; +public: + QtVariantPropertyPrivate(QtVariantPropertyManager *m) : manager(m) {} + + QtVariantPropertyManager *manager; +}; + +/*! + \class QtVariantProperty + \internal + \inmodule QtDesigner + \since 4.4 + + \brief The QtVariantProperty class is a convenience class handling + QVariant based properties. + + QtVariantProperty provides additional API: A property's type, + value type, attribute values and current value can easily be + retrieved using the propertyType(), valueType(), attributeValue() + and value() functions respectively. In addition, the attribute + values and the current value can be set using the corresponding + setValue() and setAttribute() functions. + + For example, instead of writing: + + \snippet doc/src/snippets/code/tools_shared_qtpropertybrowser_qtvariantproperty.cpp 0 + + you can write: + + \snippet doc/src/snippets/code/tools_shared_qtpropertybrowser_qtvariantproperty.cpp 1 + + QtVariantProperty instances can only be created by the + QtVariantPropertyManager class. + + \sa QtProperty, QtVariantPropertyManager, QtVariantEditorFactory +*/ + +/*! + Creates a variant property using the given \a manager. + + Do not use this constructor to create variant property instances; + use the QtVariantPropertyManager::addProperty() function + instead. This constructor is used internally by the + QtVariantPropertyManager::createProperty() function. + + \sa QtVariantPropertyManager +*/ +QtVariantProperty::QtVariantProperty(QtVariantPropertyManager *manager) + : QtProperty(manager), d_ptr(new QtVariantPropertyPrivate(manager)) +{ + +} + +/*! + Destroys this property. + + \sa QtProperty::~QtProperty() +*/ +QtVariantProperty::~QtVariantProperty() +{ + delete d_ptr; +} + +/*! + Returns the property's current value. + + \sa valueType(), setValue() +*/ +QVariant QtVariantProperty::value() const +{ + return d_ptr->manager->value(this); +} + +/*! + Returns this property's value for the specified \a attribute. + + QtVariantPropertyManager provides a couple of related functions: + \l{QtVariantPropertyManager::attributes()}{attributes()} and + \l{QtVariantPropertyManager::attributeType()}{attributeType()}. + + \sa setAttribute() +*/ +QVariant QtVariantProperty::attributeValue(const QString &attribute) const +{ + return d_ptr->manager->attributeValue(this, attribute); +} + +/*! + Returns the type of this property's value. + + \sa propertyType() +*/ +int QtVariantProperty::valueType() const +{ + return d_ptr->manager->valueType(this); +} + +/*! + Returns this property's type. + + QtVariantPropertyManager provides several related functions: + \l{QtVariantPropertyManager::enumTypeId()}{enumTypeId()}, + \l{QtVariantPropertyManager::flagTypeId()}{flagTypeId()} and + \l{QtVariantPropertyManager::groupTypeId()}{groupTypeId()}. + + \sa valueType() +*/ +int QtVariantProperty::propertyType() const +{ + return d_ptr->manager->propertyType(this); +} + +/*! + Sets the value of this property to \a value. + + The specified \a value must be of the type returned by + valueType(), or of a type that can be converted to valueType() + using the QVariant::canConvert() function; otherwise this function + does nothing. + + \sa value() +*/ +void QtVariantProperty::setValue(const QVariant &value) +{ + d_ptr->manager->setValue(this, value); +} + +/*! + Sets the \a attribute of property to \a value. + + QtVariantPropertyManager provides the related + \l{QtVariantPropertyManager::setAttribute()}{setAttribute()} + function. + + \sa attributeValue() +*/ +void QtVariantProperty::setAttribute(const QString &attribute, const QVariant &value) +{ + d_ptr->manager->setAttribute(this, attribute, value); +} + +class QtVariantPropertyManagerPrivate +{ + QtVariantPropertyManager *q_ptr; + Q_DECLARE_PUBLIC(QtVariantPropertyManager) +public: + QtVariantPropertyManagerPrivate(); + + bool m_creatingProperty; + bool m_creatingSubProperties; + bool m_destroyingSubProperties; + int m_propertyType; + + void slotValueChanged(QtProperty *property, int val); + void slotRangeChanged(QtProperty *property, int min, int max); + void slotSingleStepChanged(QtProperty *property, int step); + void slotValueChanged(QtProperty *property, double val); + void slotRangeChanged(QtProperty *property, double min, double max); + void slotSingleStepChanged(QtProperty *property, double step); + void slotDecimalsChanged(QtProperty *property, int prec); + void slotValueChanged(QtProperty *property, bool val); + void slotValueChanged(QtProperty *property, const QString &val); + void slotRegExpChanged(QtProperty *property, const QRegExp ®Exp); + void slotValueChanged(QtProperty *property, const QDate &val); + void slotRangeChanged(QtProperty *property, const QDate &min, const QDate &max); + void slotValueChanged(QtProperty *property, const QTime &val); + void slotValueChanged(QtProperty *property, const QDateTime &val); + void slotValueChanged(QtProperty *property, const QKeySequence &val); + void slotValueChanged(QtProperty *property, const QChar &val); + void slotValueChanged(QtProperty *property, const QLocale &val); + void slotValueChanged(QtProperty *property, const QPoint &val); + void slotValueChanged(QtProperty *property, const QPointF &val); + void slotValueChanged(QtProperty *property, const QSize &val); + void slotRangeChanged(QtProperty *property, const QSize &min, const QSize &max); + void slotValueChanged(QtProperty *property, const QSizeF &val); + void slotRangeChanged(QtProperty *property, const QSizeF &min, const QSizeF &max); + void slotValueChanged(QtProperty *property, const QRect &val); + void slotConstraintChanged(QtProperty *property, const QRect &val); + void slotValueChanged(QtProperty *property, const QRectF &val); + void slotConstraintChanged(QtProperty *property, const QRectF &val); + void slotValueChanged(QtProperty *property, const QColor &val); + void slotEnumChanged(QtProperty *property, int val); + void slotEnumNamesChanged(QtProperty *property, const QStringList &enumNames); + void slotEnumIconsChanged(QtProperty *property, const QMap<int, QIcon> &enumIcons); + void slotValueChanged(QtProperty *property, const QSizePolicy &val); + void slotValueChanged(QtProperty *property, const QFont &val); + void slotValueChanged(QtProperty *property, const QCursor &val); + void slotFlagChanged(QtProperty *property, int val); + void slotFlagNamesChanged(QtProperty *property, const QStringList &flagNames); + void slotPropertyInserted(QtProperty *property, QtProperty *parent, QtProperty *after); + void slotPropertyRemoved(QtProperty *property, QtProperty *parent); + + void valueChanged(QtProperty *property, const QVariant &val); + + int internalPropertyToType(QtProperty *property) const; + QtVariantProperty *createSubProperty(QtVariantProperty *parent, QtVariantProperty *after, + QtProperty *internal); + void removeSubProperty(QtVariantProperty *property); + + QMap<int, QtAbstractPropertyManager *> m_typeToPropertyManager; + QMap<int, QMap<QString, int> > m_typeToAttributeToAttributeType; + + QMap<const QtProperty *, QPair<QtVariantProperty *, int> > m_propertyToType; + + QMap<int, int> m_typeToValueType; + + + QMap<QtProperty *, QtVariantProperty *> m_internalToProperty; + + const QString m_constraintAttribute; + const QString m_singleStepAttribute; + const QString m_decimalsAttribute; + const QString m_enumIconsAttribute; + const QString m_enumNamesAttribute; + const QString m_flagNamesAttribute; + const QString m_maximumAttribute; + const QString m_minimumAttribute; + const QString m_regExpAttribute; +}; + +QtVariantPropertyManagerPrivate::QtVariantPropertyManagerPrivate() : + m_constraintAttribute(QLatin1String("constraint")), + m_singleStepAttribute(QLatin1String("singleStep")), + m_decimalsAttribute(QLatin1String("decimals")), + m_enumIconsAttribute(QLatin1String("enumIcons")), + m_enumNamesAttribute(QLatin1String("enumNames")), + m_flagNamesAttribute(QLatin1String("flagNames")), + m_maximumAttribute(QLatin1String("maximum")), + m_minimumAttribute(QLatin1String("minimum")), + m_regExpAttribute(QLatin1String("regExp")) +{ +} + +int QtVariantPropertyManagerPrivate::internalPropertyToType(QtProperty *property) const +{ + int type = 0; + QtAbstractPropertyManager *internPropertyManager = property->propertyManager(); + if (qobject_cast<QtIntPropertyManager *>(internPropertyManager)) + type = QVariant::Int; + else if (qobject_cast<QtEnumPropertyManager *>(internPropertyManager)) + type = QtVariantPropertyManager::enumTypeId(); + else if (qobject_cast<QtBoolPropertyManager *>(internPropertyManager)) + type = QVariant::Bool; + else if (qobject_cast<QtDoublePropertyManager *>(internPropertyManager)) + type = QVariant::Double; + return type; +} + +QtVariantProperty *QtVariantPropertyManagerPrivate::createSubProperty(QtVariantProperty *parent, + QtVariantProperty *after, QtProperty *internal) +{ + int type = internalPropertyToType(internal); + if (!type) + return 0; + + bool wasCreatingSubProperties = m_creatingSubProperties; + m_creatingSubProperties = true; + + QtVariantProperty *varChild = q_ptr->addProperty(type, internal->propertyName()); + + m_creatingSubProperties = wasCreatingSubProperties; + + varChild->setPropertyName(internal->propertyName()); + varChild->setToolTip(internal->toolTip()); + varChild->setStatusTip(internal->statusTip()); + varChild->setWhatsThis(internal->whatsThis()); + + parent->insertSubProperty(varChild, after); + + m_internalToProperty[internal] = varChild; + propertyToWrappedProperty()->insert(varChild, internal); + return varChild; +} + +void QtVariantPropertyManagerPrivate::removeSubProperty(QtVariantProperty *property) +{ + QtProperty *internChild = wrappedProperty(property); + bool wasDestroyingSubProperties = m_destroyingSubProperties; + m_destroyingSubProperties = true; + delete property; + m_destroyingSubProperties = wasDestroyingSubProperties; + m_internalToProperty.remove(internChild); + propertyToWrappedProperty()->remove(property); +} + +void QtVariantPropertyManagerPrivate::slotPropertyInserted(QtProperty *property, + QtProperty *parent, QtProperty *after) +{ + if (m_creatingProperty) + return; + + QtVariantProperty *varParent = m_internalToProperty.value(parent, 0); + if (!varParent) + return; + + QtVariantProperty *varAfter = 0; + if (after) { + varAfter = m_internalToProperty.value(after, 0); + if (!varAfter) + return; + } + + createSubProperty(varParent, varAfter, property); +} + +void QtVariantPropertyManagerPrivate::slotPropertyRemoved(QtProperty *property, QtProperty *parent) +{ + Q_UNUSED(parent) + + QtVariantProperty *varProperty = m_internalToProperty.value(property, 0); + if (!varProperty) + return; + + removeSubProperty(varProperty); +} + +void QtVariantPropertyManagerPrivate::valueChanged(QtProperty *property, const QVariant &val) +{ + QtVariantProperty *varProp = m_internalToProperty.value(property, 0); + if (!varProp) + return; + emit q_ptr->valueChanged(varProp, val); + emit q_ptr->propertyChanged(varProp); +} + +void QtVariantPropertyManagerPrivate::slotValueChanged(QtProperty *property, int val) +{ + valueChanged(property, QVariant(val)); +} + +void QtVariantPropertyManagerPrivate::slotRangeChanged(QtProperty *property, int min, int max) +{ + if (QtVariantProperty *varProp = m_internalToProperty.value(property, 0)) { + emit q_ptr->attributeChanged(varProp, m_minimumAttribute, QVariant(min)); + emit q_ptr->attributeChanged(varProp, m_maximumAttribute, QVariant(max)); + } +} + +void QtVariantPropertyManagerPrivate::slotSingleStepChanged(QtProperty *property, int step) +{ + if (QtVariantProperty *varProp = m_internalToProperty.value(property, 0)) + emit q_ptr->attributeChanged(varProp, m_singleStepAttribute, QVariant(step)); +} + +void QtVariantPropertyManagerPrivate::slotValueChanged(QtProperty *property, double val) +{ + valueChanged(property, QVariant(val)); +} + +void QtVariantPropertyManagerPrivate::slotRangeChanged(QtProperty *property, double min, double max) +{ + if (QtVariantProperty *varProp = m_internalToProperty.value(property, 0)) { + emit q_ptr->attributeChanged(varProp, m_minimumAttribute, QVariant(min)); + emit q_ptr->attributeChanged(varProp, m_maximumAttribute, QVariant(max)); + } +} + +void QtVariantPropertyManagerPrivate::slotSingleStepChanged(QtProperty *property, double step) +{ + if (QtVariantProperty *varProp = m_internalToProperty.value(property, 0)) + emit q_ptr->attributeChanged(varProp, m_singleStepAttribute, QVariant(step)); +} + +void QtVariantPropertyManagerPrivate::slotDecimalsChanged(QtProperty *property, int prec) +{ + if (QtVariantProperty *varProp = m_internalToProperty.value(property, 0)) + emit q_ptr->attributeChanged(varProp, m_decimalsAttribute, QVariant(prec)); +} + +void QtVariantPropertyManagerPrivate::slotValueChanged(QtProperty *property, bool val) +{ + valueChanged(property, QVariant(val)); +} + +void QtVariantPropertyManagerPrivate::slotValueChanged(QtProperty *property, const QString &val) +{ + valueChanged(property, QVariant(val)); +} + +void QtVariantPropertyManagerPrivate::slotRegExpChanged(QtProperty *property, const QRegExp ®Exp) +{ + if (QtVariantProperty *varProp = m_internalToProperty.value(property, 0)) + emit q_ptr->attributeChanged(varProp, m_regExpAttribute, QVariant(regExp)); +} + +void QtVariantPropertyManagerPrivate::slotValueChanged(QtProperty *property, const QDate &val) +{ + valueChanged(property, QVariant(val)); +} + +void QtVariantPropertyManagerPrivate::slotRangeChanged(QtProperty *property, const QDate &min, const QDate &max) +{ + if (QtVariantProperty *varProp = m_internalToProperty.value(property, 0)) { + emit q_ptr->attributeChanged(varProp, m_minimumAttribute, QVariant(min)); + emit q_ptr->attributeChanged(varProp, m_maximumAttribute, QVariant(max)); + } +} + +void QtVariantPropertyManagerPrivate::slotValueChanged(QtProperty *property, const QTime &val) +{ + valueChanged(property, QVariant(val)); +} + +void QtVariantPropertyManagerPrivate::slotValueChanged(QtProperty *property, const QDateTime &val) +{ + valueChanged(property, QVariant(val)); +} + +void QtVariantPropertyManagerPrivate::slotValueChanged(QtProperty *property, const QKeySequence &val) +{ + QVariant v; + qVariantSetValue(v, val); + valueChanged(property, v); +} + +void QtVariantPropertyManagerPrivate::slotValueChanged(QtProperty *property, const QChar &val) +{ + valueChanged(property, QVariant(val)); +} + +void QtVariantPropertyManagerPrivate::slotValueChanged(QtProperty *property, const QLocale &val) +{ + valueChanged(property, QVariant(val)); +} + +void QtVariantPropertyManagerPrivate::slotValueChanged(QtProperty *property, const QPoint &val) +{ + valueChanged(property, QVariant(val)); +} + +void QtVariantPropertyManagerPrivate::slotValueChanged(QtProperty *property, const QPointF &val) +{ + valueChanged(property, QVariant(val)); +} + +void QtVariantPropertyManagerPrivate::slotValueChanged(QtProperty *property, const QSize &val) +{ + valueChanged(property, QVariant(val)); +} + +void QtVariantPropertyManagerPrivate::slotRangeChanged(QtProperty *property, const QSize &min, const QSize &max) +{ + if (QtVariantProperty *varProp = m_internalToProperty.value(property, 0)) { + emit q_ptr->attributeChanged(varProp, m_minimumAttribute, QVariant(min)); + emit q_ptr->attributeChanged(varProp, m_maximumAttribute, QVariant(max)); + } +} + +void QtVariantPropertyManagerPrivate::slotValueChanged(QtProperty *property, const QSizeF &val) +{ + valueChanged(property, QVariant(val)); +} + +void QtVariantPropertyManagerPrivate::slotRangeChanged(QtProperty *property, const QSizeF &min, const QSizeF &max) +{ + if (QtVariantProperty *varProp = m_internalToProperty.value(property, 0)) { + emit q_ptr->attributeChanged(varProp, m_minimumAttribute, QVariant(min)); + emit q_ptr->attributeChanged(varProp, m_maximumAttribute, QVariant(max)); + } +} + +void QtVariantPropertyManagerPrivate::slotValueChanged(QtProperty *property, const QRect &val) +{ + valueChanged(property, QVariant(val)); +} + +void QtVariantPropertyManagerPrivate::slotConstraintChanged(QtProperty *property, const QRect &constraint) +{ + if (QtVariantProperty *varProp = m_internalToProperty.value(property, 0)) + emit q_ptr->attributeChanged(varProp, m_constraintAttribute, QVariant(constraint)); +} + +void QtVariantPropertyManagerPrivate::slotValueChanged(QtProperty *property, const QRectF &val) +{ + valueChanged(property, QVariant(val)); +} + +void QtVariantPropertyManagerPrivate::slotConstraintChanged(QtProperty *property, const QRectF &constraint) +{ + if (QtVariantProperty *varProp = m_internalToProperty.value(property, 0)) + emit q_ptr->attributeChanged(varProp, m_constraintAttribute, QVariant(constraint)); +} + +void QtVariantPropertyManagerPrivate::slotValueChanged(QtProperty *property, const QColor &val) +{ + valueChanged(property, QVariant(val)); +} + +void QtVariantPropertyManagerPrivate::slotEnumNamesChanged(QtProperty *property, const QStringList &enumNames) +{ + if (QtVariantProperty *varProp = m_internalToProperty.value(property, 0)) + emit q_ptr->attributeChanged(varProp, m_enumNamesAttribute, QVariant(enumNames)); +} + +void QtVariantPropertyManagerPrivate::slotEnumIconsChanged(QtProperty *property, const QMap<int, QIcon> &enumIcons) +{ + if (QtVariantProperty *varProp = m_internalToProperty.value(property, 0)) { + QVariant v; + qVariantSetValue(v, enumIcons); + emit q_ptr->attributeChanged(varProp, m_enumIconsAttribute, v); + } +} + +void QtVariantPropertyManagerPrivate::slotValueChanged(QtProperty *property, const QSizePolicy &val) +{ + valueChanged(property, QVariant(val)); +} + +void QtVariantPropertyManagerPrivate::slotValueChanged(QtProperty *property, const QFont &val) +{ + valueChanged(property, QVariant(val)); +} + +void QtVariantPropertyManagerPrivate::slotValueChanged(QtProperty *property, const QCursor &val) +{ +#ifndef QT_NO_CURSOR + valueChanged(property, QVariant(val)); +#endif +} + +void QtVariantPropertyManagerPrivate::slotFlagNamesChanged(QtProperty *property, const QStringList &flagNames) +{ + if (QtVariantProperty *varProp = m_internalToProperty.value(property, 0)) + emit q_ptr->attributeChanged(varProp, m_flagNamesAttribute, QVariant(flagNames)); +} + +/*! + \class QtVariantPropertyManager + \internal + \inmodule QtDesigner + \since 4.4 + + \brief The QtVariantPropertyManager class provides and manages QVariant based properties. + + QtVariantPropertyManager provides the addProperty() function which + creates QtVariantProperty objects. The QtVariantProperty class is + a convenience class handling QVariant based properties inheriting + QtProperty. A QtProperty object created by a + QtVariantPropertyManager instance can be converted into a + QtVariantProperty object using the variantProperty() function. + + The property's value can be retrieved using the value(), and set + using the setValue() slot. In addition the property's type, and + the type of its value, can be retrieved using the propertyType() + and valueType() functions respectively. + + A property's type is a QVariant::Type enumerator value, and + usually a property's type is the same as its value type. But for + some properties the types differ, for example for enums, flags and + group types in which case QtVariantPropertyManager provides the + enumTypeId(), flagTypeId() and groupTypeId() functions, + respectively, to identify their property type (the value types are + QVariant::Int for the enum and flag types, and QVariant::Invalid + for the group type). + + Use the isPropertyTypeSupported() function to check if a particular + property type is supported. The currently supported property types + are: + + \table + \header + \o Property Type + \o Property Type Id + \row + \o int + \o QVariant::Int + \row + \o double + \o QVariant::Double + \row + \o bool + \o QVariant::Bool + \row + \o QString + \o QVariant::String + \row + \o QDate + \o QVariant::Date + \row + \o QTime + \o QVariant::Time + \row + \o QDateTime + \o QVariant::DateTime + \row + \o QKeySequence + \o QVariant::KeySequence + \row + \o QChar + \o QVariant::Char + \row + \o QLocale + \o QVariant::Locale + \row + \o QPoint + \o QVariant::Point + \row + \o QPointF + \o QVariant::PointF + \row + \o QSize + \o QVariant::Size + \row + \o QSizeF + \o QVariant::SizeF + \row + \o QRect + \o QVariant::Rect + \row + \o QRectF + \o QVariant::RectF + \row + \o QColor + \o QVariant::Color + \row + \o QSizePolicy + \o QVariant::SizePolicy + \row + \o QFont + \o QVariant::Font + \row + \o QCursor + \o QVariant::Cursor + \row + \o enum + \o enumTypeId() + \row + \o flag + \o flagTypeId() + \row + \o group + \o groupTypeId() + \endtable + + Each property type can provide additional attributes, + e.g. QVariant::Int and QVariant::Double provides minimum and + maximum values. The currently supported attributes are: + + \table + \header + \o Property Type + \o Attribute Name + \o Attribute Type + \row + \o \c int + \o minimum + \o QVariant::Int + \row + \o + \o maximum + \o QVariant::Int + \row + \o + \o singleStep + \o QVariant::Int + \row + \o \c double + \o minimum + \o QVariant::Double + \row + \o + \o maximum + \o QVariant::Double + \row + \o + \o singleStep + \o QVariant::Double + \row + \o + \o decimals + \o QVariant::Int + \row + \o QString + \o regExp + \o QVariant::RegExp + \row + \o QDate + \o minimum + \o QVariant::Date + \row + \o + \o maximum + \o QVariant::Date + \row + \o QPointF + \o decimals + \o QVariant::Int + \row + \o QSize + \o minimum + \o QVariant::Size + \row + \o + \o maximum + \o QVariant::Size + \row + \o QSizeF + \o minimum + \o QVariant::SizeF + \row + \o + \o maximum + \o QVariant::SizeF + \row + \o + \o decimals + \o QVariant::Int + \row + \o QRect + \o constraint + \o QVariant::Rect + \row + \o QRectF + \o constraint + \o QVariant::RectF + \row + \o + \o decimals + \o QVariant::Int + \row + \o \c enum + \o enumNames + \o QVariant::StringList + \row + \o + \o enumIcons + \o iconMapTypeId() + \row + \o \c flag + \o flagNames + \o QVariant::StringList + \endtable + + The attributes for a given property type can be retrieved using + the attributes() function. Each attribute has a value type which + can be retrieved using the attributeType() function, and a value + accessible through the attributeValue() function. In addition, the + value can be set using the setAttribute() slot. + + QtVariantManager also provides the valueChanged() signal which is + emitted whenever a property created by this manager change, and + the attributeChanged() signal which is emitted whenever an + attribute of such a property changes. + + \sa QtVariantProperty, QtVariantEditorFactory +*/ + +/*! + \fn void QtVariantPropertyManager::valueChanged(QtProperty *property, const QVariant &value) + + This signal is emitted whenever a property created by this manager + changes its value, passing a pointer to the \a property and the + new \a value as parameters. + + \sa setValue() +*/ + +/*! + \fn void QtVariantPropertyManager::attributeChanged(QtProperty *property, + const QString &attribute, const QVariant &value) + + This signal is emitted whenever an attribute of a property created + by this manager changes its value, passing a pointer to the \a + property, the \a attribute and the new \a value as parameters. + + \sa setAttribute() +*/ + +/*! + Creates a manager with the given \a parent. +*/ +QtVariantPropertyManager::QtVariantPropertyManager(QObject *parent) + : QtAbstractPropertyManager(parent) +{ + d_ptr = new QtVariantPropertyManagerPrivate; + d_ptr->q_ptr = this; + + d_ptr->m_creatingProperty = false; + d_ptr->m_creatingSubProperties = false; + d_ptr->m_destroyingSubProperties = false; + d_ptr->m_propertyType = 0; + + // IntPropertyManager + QtIntPropertyManager *intPropertyManager = new QtIntPropertyManager(this); + d_ptr->m_typeToPropertyManager[QVariant::Int] = intPropertyManager; + d_ptr->m_typeToAttributeToAttributeType[QVariant::Int][d_ptr->m_minimumAttribute] = QVariant::Int; + d_ptr->m_typeToAttributeToAttributeType[QVariant::Int][d_ptr->m_maximumAttribute] = QVariant::Int; + d_ptr->m_typeToAttributeToAttributeType[QVariant::Int][d_ptr->m_singleStepAttribute] = QVariant::Int; + d_ptr->m_typeToValueType[QVariant::Int] = QVariant::Int; + connect(intPropertyManager, SIGNAL(valueChanged(QtProperty *, int)), + this, SLOT(slotValueChanged(QtProperty *, int))); + connect(intPropertyManager, SIGNAL(rangeChanged(QtProperty *, int, int)), + this, SLOT(slotRangeChanged(QtProperty *, int, int))); + connect(intPropertyManager, SIGNAL(singleStepChanged(QtProperty *, int)), + this, SLOT(slotSingleStepChanged(QtProperty *, int))); + // DoublePropertyManager + QtDoublePropertyManager *doublePropertyManager = new QtDoublePropertyManager(this); + d_ptr->m_typeToPropertyManager[QVariant::Double] = doublePropertyManager; + d_ptr->m_typeToAttributeToAttributeType[QVariant::Double][d_ptr->m_minimumAttribute] = + QVariant::Double; + d_ptr->m_typeToAttributeToAttributeType[QVariant::Double][d_ptr->m_maximumAttribute] = + QVariant::Double; + d_ptr->m_typeToAttributeToAttributeType[QVariant::Double][d_ptr->m_singleStepAttribute] = + QVariant::Double; + d_ptr->m_typeToAttributeToAttributeType[QVariant::Double][d_ptr->m_decimalsAttribute] = + QVariant::Int; + d_ptr->m_typeToValueType[QVariant::Double] = QVariant::Double; + connect(doublePropertyManager, SIGNAL(valueChanged(QtProperty *, double)), + this, SLOT(slotValueChanged(QtProperty *, double))); + connect(doublePropertyManager, SIGNAL(rangeChanged(QtProperty *, double, double)), + this, SLOT(slotRangeChanged(QtProperty *, double, double))); + connect(doublePropertyManager, SIGNAL(singleStepChanged(QtProperty *, double)), + this, SLOT(slotSingleStepChanged(QtProperty *, double))); + connect(doublePropertyManager, SIGNAL(decimalsChanged(QtProperty *, int)), + this, SLOT(slotDecimalsChanged(QtProperty *, int))); + // BoolPropertyManager + QtBoolPropertyManager *boolPropertyManager = new QtBoolPropertyManager(this); + d_ptr->m_typeToPropertyManager[QVariant::Bool] = boolPropertyManager; + d_ptr->m_typeToValueType[QVariant::Bool] = QVariant::Bool; + connect(boolPropertyManager, SIGNAL(valueChanged(QtProperty *, bool)), + this, SLOT(slotValueChanged(QtProperty *, bool))); + // StringPropertyManager + QtStringPropertyManager *stringPropertyManager = new QtStringPropertyManager(this); + d_ptr->m_typeToPropertyManager[QVariant::String] = stringPropertyManager; + d_ptr->m_typeToValueType[QVariant::String] = QVariant::String; + d_ptr->m_typeToAttributeToAttributeType[QVariant::String][d_ptr->m_regExpAttribute] = + QVariant::RegExp; + connect(stringPropertyManager, SIGNAL(valueChanged(QtProperty *, const QString &)), + this, SLOT(slotValueChanged(QtProperty *, const QString &))); + connect(stringPropertyManager, SIGNAL(regExpChanged(QtProperty *, const QRegExp &)), + this, SLOT(slotRegExpChanged(QtProperty *, const QRegExp &))); + // DatePropertyManager + QtDatePropertyManager *datePropertyManager = new QtDatePropertyManager(this); + d_ptr->m_typeToPropertyManager[QVariant::Date] = datePropertyManager; + d_ptr->m_typeToValueType[QVariant::Date] = QVariant::Date; + d_ptr->m_typeToAttributeToAttributeType[QVariant::Date][d_ptr->m_minimumAttribute] = + QVariant::Date; + d_ptr->m_typeToAttributeToAttributeType[QVariant::Date][d_ptr->m_maximumAttribute] = + QVariant::Date; + connect(datePropertyManager, SIGNAL(valueChanged(QtProperty *, const QDate &)), + this, SLOT(slotValueChanged(QtProperty *, const QDate &))); + connect(datePropertyManager, SIGNAL(rangeChanged(QtProperty *, const QDate &, const QDate &)), + this, SLOT(slotRangeChanged(QtProperty *, const QDate &, const QDate &))); + // TimePropertyManager + QtTimePropertyManager *timePropertyManager = new QtTimePropertyManager(this); + d_ptr->m_typeToPropertyManager[QVariant::Time] = timePropertyManager; + d_ptr->m_typeToValueType[QVariant::Time] = QVariant::Time; + connect(timePropertyManager, SIGNAL(valueChanged(QtProperty *, const QTime &)), + this, SLOT(slotValueChanged(QtProperty *, const QTime &))); + // DateTimePropertyManager + QtDateTimePropertyManager *dateTimePropertyManager = new QtDateTimePropertyManager(this); + d_ptr->m_typeToPropertyManager[QVariant::DateTime] = dateTimePropertyManager; + d_ptr->m_typeToValueType[QVariant::DateTime] = QVariant::DateTime; + connect(dateTimePropertyManager, SIGNAL(valueChanged(QtProperty *, const QDateTime &)), + this, SLOT(slotValueChanged(QtProperty *, const QDateTime &))); + // KeySequencePropertyManager + QtKeySequencePropertyManager *keySequencePropertyManager = new QtKeySequencePropertyManager(this); + d_ptr->m_typeToPropertyManager[QVariant::KeySequence] = keySequencePropertyManager; + d_ptr->m_typeToValueType[QVariant::KeySequence] = QVariant::KeySequence; + connect(keySequencePropertyManager, SIGNAL(valueChanged(QtProperty *, const QKeySequence &)), + this, SLOT(slotValueChanged(QtProperty *, const QKeySequence &))); + // CharPropertyManager + QtCharPropertyManager *charPropertyManager = new QtCharPropertyManager(this); + d_ptr->m_typeToPropertyManager[QVariant::Char] = charPropertyManager; + d_ptr->m_typeToValueType[QVariant::Char] = QVariant::Char; + connect(charPropertyManager, SIGNAL(valueChanged(QtProperty *, const QChar &)), + this, SLOT(slotValueChanged(QtProperty *, const QChar &))); + // LocalePropertyManager + QtLocalePropertyManager *localePropertyManager = new QtLocalePropertyManager(this); + d_ptr->m_typeToPropertyManager[QVariant::Locale] = localePropertyManager; + d_ptr->m_typeToValueType[QVariant::Locale] = QVariant::Locale; + connect(localePropertyManager, SIGNAL(valueChanged(QtProperty *, const QLocale &)), + this, SLOT(slotValueChanged(QtProperty *, const QLocale &))); + connect(localePropertyManager->subEnumPropertyManager(), SIGNAL(valueChanged(QtProperty *, int)), + this, SLOT(slotValueChanged(QtProperty *, int))); + connect(localePropertyManager, SIGNAL(propertyInserted(QtProperty *, QtProperty *, QtProperty *)), + this, SLOT(slotPropertyInserted(QtProperty *, QtProperty *, QtProperty *))); + connect(localePropertyManager, SIGNAL(propertyRemoved(QtProperty *, QtProperty *)), + this, SLOT(slotPropertyRemoved(QtProperty *, QtProperty *))); + // PointPropertyManager + QtPointPropertyManager *pointPropertyManager = new QtPointPropertyManager(this); + d_ptr->m_typeToPropertyManager[QVariant::Point] = pointPropertyManager; + d_ptr->m_typeToValueType[QVariant::Point] = QVariant::Point; + connect(pointPropertyManager, SIGNAL(valueChanged(QtProperty *, const QPoint &)), + this, SLOT(slotValueChanged(QtProperty *, const QPoint &))); + connect(pointPropertyManager->subIntPropertyManager(), SIGNAL(valueChanged(QtProperty *, int)), + this, SLOT(slotValueChanged(QtProperty *, int))); + connect(pointPropertyManager, SIGNAL(propertyInserted(QtProperty *, QtProperty *, QtProperty *)), + this, SLOT(slotPropertyInserted(QtProperty *, QtProperty *, QtProperty *))); + connect(pointPropertyManager, SIGNAL(propertyRemoved(QtProperty *, QtProperty *)), + this, SLOT(slotPropertyRemoved(QtProperty *, QtProperty *))); + // PointFPropertyManager + QtPointFPropertyManager *pointFPropertyManager = new QtPointFPropertyManager(this); + d_ptr->m_typeToPropertyManager[QVariant::PointF] = pointFPropertyManager; + d_ptr->m_typeToValueType[QVariant::PointF] = QVariant::PointF; + d_ptr->m_typeToAttributeToAttributeType[QVariant::PointF][d_ptr->m_decimalsAttribute] = + QVariant::Int; + connect(pointFPropertyManager, SIGNAL(valueChanged(QtProperty *, const QPointF &)), + this, SLOT(slotValueChanged(QtProperty *, const QPointF &))); + connect(pointFPropertyManager, SIGNAL(decimalsChanged(QtProperty *, int)), + this, SLOT(slotDecimalsChanged(QtProperty *, int))); + connect(pointFPropertyManager->subDoublePropertyManager(), SIGNAL(valueChanged(QtProperty *, double)), + this, SLOT(slotValueChanged(QtProperty *, double))); + connect(pointFPropertyManager, SIGNAL(propertyInserted(QtProperty *, QtProperty *, QtProperty *)), + this, SLOT(slotPropertyInserted(QtProperty *, QtProperty *, QtProperty *))); + connect(pointFPropertyManager, SIGNAL(propertyRemoved(QtProperty *, QtProperty *)), + this, SLOT(slotPropertyRemoved(QtProperty *, QtProperty *))); + // SizePropertyManager + QtSizePropertyManager *sizePropertyManager = new QtSizePropertyManager(this); + d_ptr->m_typeToPropertyManager[QVariant::Size] = sizePropertyManager; + d_ptr->m_typeToValueType[QVariant::Size] = QVariant::Size; + d_ptr->m_typeToAttributeToAttributeType[QVariant::Size][d_ptr->m_minimumAttribute] = + QVariant::Size; + d_ptr->m_typeToAttributeToAttributeType[QVariant::Size][d_ptr->m_maximumAttribute] = + QVariant::Size; + connect(sizePropertyManager, SIGNAL(valueChanged(QtProperty *, const QSize &)), + this, SLOT(slotValueChanged(QtProperty *, const QSize &))); + connect(sizePropertyManager, SIGNAL(rangeChanged(QtProperty *, const QSize &, const QSize &)), + this, SLOT(slotRangeChanged(QtProperty *, const QSize &, const QSize &))); + connect(sizePropertyManager->subIntPropertyManager(), SIGNAL(valueChanged(QtProperty *, int)), + this, SLOT(slotValueChanged(QtProperty *, int))); + connect(sizePropertyManager->subIntPropertyManager(), SIGNAL(rangeChanged(QtProperty *, int, int)), + this, SLOT(slotRangeChanged(QtProperty *, int, int))); + connect(sizePropertyManager, SIGNAL(propertyInserted(QtProperty *, QtProperty *, QtProperty *)), + this, SLOT(slotPropertyInserted(QtProperty *, QtProperty *, QtProperty *))); + connect(sizePropertyManager, SIGNAL(propertyRemoved(QtProperty *, QtProperty *)), + this, SLOT(slotPropertyRemoved(QtProperty *, QtProperty *))); + // SizeFPropertyManager + QtSizeFPropertyManager *sizeFPropertyManager = new QtSizeFPropertyManager(this); + d_ptr->m_typeToPropertyManager[QVariant::SizeF] = sizeFPropertyManager; + d_ptr->m_typeToValueType[QVariant::SizeF] = QVariant::SizeF; + d_ptr->m_typeToAttributeToAttributeType[QVariant::SizeF][d_ptr->m_minimumAttribute] = + QVariant::SizeF; + d_ptr->m_typeToAttributeToAttributeType[QVariant::SizeF][d_ptr->m_maximumAttribute] = + QVariant::SizeF; + d_ptr->m_typeToAttributeToAttributeType[QVariant::SizeF][d_ptr->m_decimalsAttribute] = + QVariant::Int; + connect(sizeFPropertyManager, SIGNAL(valueChanged(QtProperty *, const QSizeF &)), + this, SLOT(slotValueChanged(QtProperty *, const QSizeF &))); + connect(sizeFPropertyManager, SIGNAL(rangeChanged(QtProperty *, const QSizeF &, const QSizeF &)), + this, SLOT(slotRangeChanged(QtProperty *, const QSizeF &, const QSizeF &))); + connect(sizeFPropertyManager, SIGNAL(decimalsChanged(QtProperty *, int)), + this, SLOT(slotDecimalsChanged(QtProperty *, int))); + connect(sizeFPropertyManager->subDoublePropertyManager(), SIGNAL(valueChanged(QtProperty *, double)), + this, SLOT(slotValueChanged(QtProperty *, double))); + connect(sizeFPropertyManager->subDoublePropertyManager(), SIGNAL(rangeChanged(QtProperty *, double, double)), + this, SLOT(slotRangeChanged(QtProperty *, double, double))); + connect(sizeFPropertyManager, SIGNAL(propertyInserted(QtProperty *, QtProperty *, QtProperty *)), + this, SLOT(slotPropertyInserted(QtProperty *, QtProperty *, QtProperty *))); + connect(sizeFPropertyManager, SIGNAL(propertyRemoved(QtProperty *, QtProperty *)), + this, SLOT(slotPropertyRemoved(QtProperty *, QtProperty *))); + // RectPropertyManager + QtRectPropertyManager *rectPropertyManager = new QtRectPropertyManager(this); + d_ptr->m_typeToPropertyManager[QVariant::Rect] = rectPropertyManager; + d_ptr->m_typeToValueType[QVariant::Rect] = QVariant::Rect; + d_ptr->m_typeToAttributeToAttributeType[QVariant::Rect][d_ptr->m_constraintAttribute] = + QVariant::Rect; + connect(rectPropertyManager, SIGNAL(valueChanged(QtProperty *, const QRect &)), + this, SLOT(slotValueChanged(QtProperty *, const QRect &))); + connect(rectPropertyManager, SIGNAL(constraintChanged(QtProperty *, const QRect &)), + this, SLOT(slotConstraintChanged(QtProperty *, const QRect &))); + connect(rectPropertyManager->subIntPropertyManager(), SIGNAL(valueChanged(QtProperty *, int)), + this, SLOT(slotValueChanged(QtProperty *, int))); + connect(rectPropertyManager->subIntPropertyManager(), SIGNAL(rangeChanged(QtProperty *, int, int)), + this, SLOT(slotRangeChanged(QtProperty *, int, int))); + connect(rectPropertyManager, SIGNAL(propertyInserted(QtProperty *, QtProperty *, QtProperty *)), + this, SLOT(slotPropertyInserted(QtProperty *, QtProperty *, QtProperty *))); + connect(rectPropertyManager, SIGNAL(propertyRemoved(QtProperty *, QtProperty *)), + this, SLOT(slotPropertyRemoved(QtProperty *, QtProperty *))); + // RectFPropertyManager + QtRectFPropertyManager *rectFPropertyManager = new QtRectFPropertyManager(this); + d_ptr->m_typeToPropertyManager[QVariant::RectF] = rectFPropertyManager; + d_ptr->m_typeToValueType[QVariant::RectF] = QVariant::RectF; + d_ptr->m_typeToAttributeToAttributeType[QVariant::RectF][d_ptr->m_constraintAttribute] = + QVariant::RectF; + d_ptr->m_typeToAttributeToAttributeType[QVariant::RectF][d_ptr->m_decimalsAttribute] = + QVariant::Int; + connect(rectFPropertyManager, SIGNAL(valueChanged(QtProperty *, const QRectF &)), + this, SLOT(slotValueChanged(QtProperty *, const QRectF &))); + connect(rectFPropertyManager, SIGNAL(constraintChanged(QtProperty *, const QRectF &)), + this, SLOT(slotConstraintChanged(QtProperty *, const QRectF &))); + connect(rectFPropertyManager, SIGNAL(decimalsChanged(QtProperty *, int)), + this, SLOT(slotDecimalsChanged(QtProperty *, int))); + connect(rectFPropertyManager->subDoublePropertyManager(), SIGNAL(valueChanged(QtProperty *, double)), + this, SLOT(slotValueChanged(QtProperty *, double))); + connect(rectFPropertyManager->subDoublePropertyManager(), SIGNAL(rangeChanged(QtProperty *, double, double)), + this, SLOT(slotRangeChanged(QtProperty *, double, double))); + connect(rectFPropertyManager, SIGNAL(propertyInserted(QtProperty *, QtProperty *, QtProperty *)), + this, SLOT(slotPropertyInserted(QtProperty *, QtProperty *, QtProperty *))); + connect(rectFPropertyManager, SIGNAL(propertyRemoved(QtProperty *, QtProperty *)), + this, SLOT(slotPropertyRemoved(QtProperty *, QtProperty *))); + // ColorPropertyManager + QtColorPropertyManager *colorPropertyManager = new QtColorPropertyManager(this); + d_ptr->m_typeToPropertyManager[QVariant::Color] = colorPropertyManager; + d_ptr->m_typeToValueType[QVariant::Color] = QVariant::Color; + connect(colorPropertyManager, SIGNAL(valueChanged(QtProperty *, const QColor &)), + this, SLOT(slotValueChanged(QtProperty *, const QColor &))); + connect(colorPropertyManager->subIntPropertyManager(), SIGNAL(valueChanged(QtProperty *, int)), + this, SLOT(slotValueChanged(QtProperty *, int))); + connect(colorPropertyManager, SIGNAL(propertyInserted(QtProperty *, QtProperty *, QtProperty *)), + this, SLOT(slotPropertyInserted(QtProperty *, QtProperty *, QtProperty *))); + connect(colorPropertyManager, SIGNAL(propertyRemoved(QtProperty *, QtProperty *)), + this, SLOT(slotPropertyRemoved(QtProperty *, QtProperty *))); + // EnumPropertyManager + int enumId = enumTypeId(); + QtEnumPropertyManager *enumPropertyManager = new QtEnumPropertyManager(this); + d_ptr->m_typeToPropertyManager[enumId] = enumPropertyManager; + d_ptr->m_typeToValueType[enumId] = QVariant::Int; + d_ptr->m_typeToAttributeToAttributeType[enumId][d_ptr->m_enumNamesAttribute] = + QVariant::StringList; + d_ptr->m_typeToAttributeToAttributeType[enumId][d_ptr->m_enumIconsAttribute] = + iconMapTypeId(); + connect(enumPropertyManager, SIGNAL(valueChanged(QtProperty *, int)), + this, SLOT(slotValueChanged(QtProperty *, int))); + connect(enumPropertyManager, SIGNAL(enumNamesChanged(QtProperty *, const QStringList &)), + this, SLOT(slotEnumNamesChanged(QtProperty *, const QStringList &))); + connect(enumPropertyManager, SIGNAL(enumIconsChanged(QtProperty *, const QMap<int, QIcon> &)), + this, SLOT(slotEnumIconsChanged(QtProperty *, const QMap<int, QIcon> &))); + // SizePolicyPropertyManager + QtSizePolicyPropertyManager *sizePolicyPropertyManager = new QtSizePolicyPropertyManager(this); + d_ptr->m_typeToPropertyManager[QVariant::SizePolicy] = sizePolicyPropertyManager; + d_ptr->m_typeToValueType[QVariant::SizePolicy] = QVariant::SizePolicy; + connect(sizePolicyPropertyManager, SIGNAL(valueChanged(QtProperty *, const QSizePolicy &)), + this, SLOT(slotValueChanged(QtProperty *, const QSizePolicy &))); + connect(sizePolicyPropertyManager->subIntPropertyManager(), SIGNAL(valueChanged(QtProperty *, int)), + this, SLOT(slotValueChanged(QtProperty *, int))); + connect(sizePolicyPropertyManager->subIntPropertyManager(), SIGNAL(rangeChanged(QtProperty *, int, int)), + this, SLOT(slotRangeChanged(QtProperty *, int, int))); + connect(sizePolicyPropertyManager->subEnumPropertyManager(), SIGNAL(valueChanged(QtProperty *, int)), + this, SLOT(slotValueChanged(QtProperty *, int))); + connect(sizePolicyPropertyManager->subEnumPropertyManager(), + SIGNAL(enumNamesChanged(QtProperty *, const QStringList &)), + this, SLOT(slotEnumNamesChanged(QtProperty *, const QStringList &))); + connect(sizePolicyPropertyManager, SIGNAL(propertyInserted(QtProperty *, QtProperty *, QtProperty *)), + this, SLOT(slotPropertyInserted(QtProperty *, QtProperty *, QtProperty *))); + connect(sizePolicyPropertyManager, SIGNAL(propertyRemoved(QtProperty *, QtProperty *)), + this, SLOT(slotPropertyRemoved(QtProperty *, QtProperty *))); + // FontPropertyManager + QtFontPropertyManager *fontPropertyManager = new QtFontPropertyManager(this); + d_ptr->m_typeToPropertyManager[QVariant::Font] = fontPropertyManager; + d_ptr->m_typeToValueType[QVariant::Font] = QVariant::Font; + connect(fontPropertyManager, SIGNAL(valueChanged(QtProperty *, const QFont &)), + this, SLOT(slotValueChanged(QtProperty *, const QFont &))); + connect(fontPropertyManager->subIntPropertyManager(), SIGNAL(valueChanged(QtProperty *, int)), + this, SLOT(slotValueChanged(QtProperty *, int))); + connect(fontPropertyManager->subIntPropertyManager(), SIGNAL(rangeChanged(QtProperty *, int, int)), + this, SLOT(slotRangeChanged(QtProperty *, int, int))); + connect(fontPropertyManager->subEnumPropertyManager(), SIGNAL(valueChanged(QtProperty *, int)), + this, SLOT(slotValueChanged(QtProperty *, int))); + connect(fontPropertyManager->subEnumPropertyManager(), + SIGNAL(enumNamesChanged(QtProperty *, const QStringList &)), + this, SLOT(slotEnumNamesChanged(QtProperty *, const QStringList &))); + connect(fontPropertyManager->subBoolPropertyManager(), SIGNAL(valueChanged(QtProperty *, bool)), + this, SLOT(slotValueChanged(QtProperty *, bool))); + connect(fontPropertyManager, SIGNAL(propertyInserted(QtProperty *, QtProperty *, QtProperty *)), + this, SLOT(slotPropertyInserted(QtProperty *, QtProperty *, QtProperty *))); + connect(fontPropertyManager, SIGNAL(propertyRemoved(QtProperty *, QtProperty *)), + this, SLOT(slotPropertyRemoved(QtProperty *, QtProperty *))); + // CursorPropertyManager + QtCursorPropertyManager *cursorPropertyManager = new QtCursorPropertyManager(this); + d_ptr->m_typeToPropertyManager[QVariant::Cursor] = cursorPropertyManager; + d_ptr->m_typeToValueType[QVariant::Cursor] = QVariant::Cursor; + connect(cursorPropertyManager, SIGNAL(valueChanged(QtProperty *, const QCursor &)), + this, SLOT(slotValueChanged(QtProperty *, const QCursor &))); + // FlagPropertyManager + int flagId = flagTypeId(); + QtFlagPropertyManager *flagPropertyManager = new QtFlagPropertyManager(this); + d_ptr->m_typeToPropertyManager[flagId] = flagPropertyManager; + d_ptr->m_typeToValueType[flagId] = QVariant::Int; + d_ptr->m_typeToAttributeToAttributeType[flagId][d_ptr->m_flagNamesAttribute] = + QVariant::StringList; + connect(flagPropertyManager, SIGNAL(valueChanged(QtProperty *, int)), + this, SLOT(slotValueChanged(QtProperty *, int))); + connect(flagPropertyManager, SIGNAL(flagNamesChanged(QtProperty *, const QStringList &)), + this, SLOT(slotFlagNamesChanged(QtProperty *, const QStringList &))); + connect(flagPropertyManager->subBoolPropertyManager(), SIGNAL(valueChanged(QtProperty *, bool)), + this, SLOT(slotValueChanged(QtProperty *, bool))); + connect(flagPropertyManager, SIGNAL(propertyInserted(QtProperty *, QtProperty *, QtProperty *)), + this, SLOT(slotPropertyInserted(QtProperty *, QtProperty *, QtProperty *))); + connect(flagPropertyManager, SIGNAL(propertyRemoved(QtProperty *, QtProperty *)), + this, SLOT(slotPropertyRemoved(QtProperty *, QtProperty *))); + // FlagPropertyManager + int groupId = groupTypeId(); + QtGroupPropertyManager *groupPropertyManager = new QtGroupPropertyManager(this); + d_ptr->m_typeToPropertyManager[groupId] = groupPropertyManager; + d_ptr->m_typeToValueType[groupId] = QVariant::Invalid; +} + +/*! + Destroys this manager, and all the properties it has created. +*/ +QtVariantPropertyManager::~QtVariantPropertyManager() +{ + clear(); + delete d_ptr; +} + +/*! + Returns the given \a property converted into a QtVariantProperty. + + If the \a property was not created by this variant manager, the + function returns 0. + + \sa createProperty() +*/ +QtVariantProperty *QtVariantPropertyManager::variantProperty(const QtProperty *property) const +{ + const QMap<const QtProperty *, QPair<QtVariantProperty *, int> >::const_iterator it = d_ptr->m_propertyToType.constFind(property); + if (it == d_ptr->m_propertyToType.constEnd()) + return 0; + return it.value().first; +} + +/*! + Returns true if the given \a propertyType is supported by this + variant manager; otherwise false. + + \sa propertyType() +*/ +bool QtVariantPropertyManager::isPropertyTypeSupported(int propertyType) const +{ + if (d_ptr->m_typeToValueType.contains(propertyType)) + return true; + return false; +} + +/*! + Creates and returns a variant property of the given \a propertyType + with the given \a name. + + If the specified \a propertyType is not supported by this variant + manager, this function returns 0. + + Do not use the inherited + QtAbstractPropertyManager::addProperty() function to create a + variant property (that function will always return 0 since it will + not be clear what type the property should have). + + \sa isPropertyTypeSupported() +*/ +QtVariantProperty *QtVariantPropertyManager::addProperty(int propertyType, const QString &name) +{ + if (!isPropertyTypeSupported(propertyType)) + return 0; + + bool wasCreating = d_ptr->m_creatingProperty; + d_ptr->m_creatingProperty = true; + d_ptr->m_propertyType = propertyType; + QtProperty *property = QtAbstractPropertyManager::addProperty(name); + d_ptr->m_creatingProperty = wasCreating; + d_ptr->m_propertyType = 0; + + if (!property) + return 0; + + return variantProperty(property); +} + +/*! + Returns the given \a property's value. + + If the given \a property is not managed by this manager, this + function returns an invalid variant. + + \sa setValue() +*/ +QVariant QtVariantPropertyManager::value(const QtProperty *property) const +{ + QtProperty *internProp = propertyToWrappedProperty()->value(property, 0); + if (internProp == 0) + return QVariant(); + + QtAbstractPropertyManager *manager = internProp->propertyManager(); + if (QtIntPropertyManager *intManager = qobject_cast<QtIntPropertyManager *>(manager)) { + return intManager->value(internProp); + } else if (QtDoublePropertyManager *doubleManager = qobject_cast<QtDoublePropertyManager *>(manager)) { + return doubleManager->value(internProp); + } else if (QtBoolPropertyManager *boolManager = qobject_cast<QtBoolPropertyManager *>(manager)) { + return boolManager->value(internProp); + } else if (QtStringPropertyManager *stringManager = qobject_cast<QtStringPropertyManager *>(manager)) { + return stringManager->value(internProp); + } else if (QtDatePropertyManager *dateManager = qobject_cast<QtDatePropertyManager *>(manager)) { + return dateManager->value(internProp); + } else if (QtTimePropertyManager *timeManager = qobject_cast<QtTimePropertyManager *>(manager)) { + return timeManager->value(internProp); + } else if (QtDateTimePropertyManager *dateTimeManager = qobject_cast<QtDateTimePropertyManager *>(manager)) { + return dateTimeManager->value(internProp); + } else if (QtKeySequencePropertyManager *keySequenceManager = qobject_cast<QtKeySequencePropertyManager *>(manager)) { + return keySequenceManager->value(internProp); + } else if (QtCharPropertyManager *charManager = qobject_cast<QtCharPropertyManager *>(manager)) { + return charManager->value(internProp); + } else if (QtLocalePropertyManager *localeManager = qobject_cast<QtLocalePropertyManager *>(manager)) { + return localeManager->value(internProp); + } else if (QtPointPropertyManager *pointManager = qobject_cast<QtPointPropertyManager *>(manager)) { + return pointManager->value(internProp); + } else if (QtPointFPropertyManager *pointFManager = qobject_cast<QtPointFPropertyManager *>(manager)) { + return pointFManager->value(internProp); + } else if (QtSizePropertyManager *sizeManager = qobject_cast<QtSizePropertyManager *>(manager)) { + return sizeManager->value(internProp); + } else if (QtSizeFPropertyManager *sizeFManager = qobject_cast<QtSizeFPropertyManager *>(manager)) { + return sizeFManager->value(internProp); + } else if (QtRectPropertyManager *rectManager = qobject_cast<QtRectPropertyManager *>(manager)) { + return rectManager->value(internProp); + } else if (QtRectFPropertyManager *rectFManager = qobject_cast<QtRectFPropertyManager *>(manager)) { + return rectFManager->value(internProp); + } else if (QtColorPropertyManager *colorManager = qobject_cast<QtColorPropertyManager *>(manager)) { + return colorManager->value(internProp); + } else if (QtEnumPropertyManager *enumManager = qobject_cast<QtEnumPropertyManager *>(manager)) { + return enumManager->value(internProp); + } else if (QtSizePolicyPropertyManager *sizePolicyManager = + qobject_cast<QtSizePolicyPropertyManager *>(manager)) { + return sizePolicyManager->value(internProp); + } else if (QtFontPropertyManager *fontManager = qobject_cast<QtFontPropertyManager *>(manager)) { + return fontManager->value(internProp); +#ifndef QT_NO_CURSOR + } else if (QtCursorPropertyManager *cursorManager = qobject_cast<QtCursorPropertyManager *>(manager)) { + return cursorManager->value(internProp); +#endif + } else if (QtFlagPropertyManager *flagManager = qobject_cast<QtFlagPropertyManager *>(manager)) { + return flagManager->value(internProp); + } + return QVariant(); +} + +/*! + Returns the given \a property's value type. + + \sa propertyType() +*/ +int QtVariantPropertyManager::valueType(const QtProperty *property) const +{ + int propType = propertyType(property); + return valueType(propType); +} + +/*! + \overload + + Returns the value type associated with the given \a propertyType. +*/ +int QtVariantPropertyManager::valueType(int propertyType) const +{ + if (d_ptr->m_typeToValueType.contains(propertyType)) + return d_ptr->m_typeToValueType[propertyType]; + return 0; +} + +/*! + Returns the given \a property's type. + + \sa valueType() +*/ +int QtVariantPropertyManager::propertyType(const QtProperty *property) const +{ + const QMap<const QtProperty *, QPair<QtVariantProperty *, int> >::const_iterator it = d_ptr->m_propertyToType.constFind(property); + if (it == d_ptr->m_propertyToType.constEnd()) + return 0; + return it.value().second; +} + +/*! + Returns the given \a property's value for the specified \a + attribute + + If the given \a property was not created by \e this manager, or if + the specified \a attribute does not exist, this function returns + an invalid variant. + + \sa attributes(), attributeType(), setAttribute() +*/ +QVariant QtVariantPropertyManager::attributeValue(const QtProperty *property, const QString &attribute) const +{ + int propType = propertyType(property); + if (!propType) + return QVariant(); + + QMap<int, QMap<QString, int> >::ConstIterator it = + d_ptr->m_typeToAttributeToAttributeType.find(propType); + if (it == d_ptr->m_typeToAttributeToAttributeType.constEnd()) + return QVariant(); + + QMap<QString, int> attributes = it.value(); + QMap<QString, int>::ConstIterator itAttr = attributes.find(attribute); + if (itAttr == attributes.constEnd()) + return QVariant(); + + QtProperty *internProp = propertyToWrappedProperty()->value(property, 0); + if (internProp == 0) + return QVariant(); + + QtAbstractPropertyManager *manager = internProp->propertyManager(); + if (QtIntPropertyManager *intManager = qobject_cast<QtIntPropertyManager *>(manager)) { + if (attribute == d_ptr->m_maximumAttribute) + return intManager->maximum(internProp); + if (attribute == d_ptr->m_minimumAttribute) + return intManager->minimum(internProp); + if (attribute == d_ptr->m_singleStepAttribute) + return intManager->singleStep(internProp); + return QVariant(); + } else if (QtDoublePropertyManager *doubleManager = qobject_cast<QtDoublePropertyManager *>(manager)) { + if (attribute == d_ptr->m_maximumAttribute) + return doubleManager->maximum(internProp); + if (attribute == d_ptr->m_minimumAttribute) + return doubleManager->minimum(internProp); + if (attribute == d_ptr->m_singleStepAttribute) + return doubleManager->singleStep(internProp); + if (attribute == d_ptr->m_decimalsAttribute) + return doubleManager->decimals(internProp); + return QVariant(); + } else if (QtStringPropertyManager *stringManager = qobject_cast<QtStringPropertyManager *>(manager)) { + if (attribute == d_ptr->m_regExpAttribute) + return stringManager->regExp(internProp); + return QVariant(); + } else if (QtDatePropertyManager *dateManager = qobject_cast<QtDatePropertyManager *>(manager)) { + if (attribute == d_ptr->m_maximumAttribute) + return dateManager->maximum(internProp); + if (attribute == d_ptr->m_minimumAttribute) + return dateManager->minimum(internProp); + return QVariant(); + } else if (QtPointFPropertyManager *pointFManager = qobject_cast<QtPointFPropertyManager *>(manager)) { + if (attribute == d_ptr->m_decimalsAttribute) + return pointFManager->decimals(internProp); + return QVariant(); + } else if (QtSizePropertyManager *sizeManager = qobject_cast<QtSizePropertyManager *>(manager)) { + if (attribute == d_ptr->m_maximumAttribute) + return sizeManager->maximum(internProp); + if (attribute == d_ptr->m_minimumAttribute) + return sizeManager->minimum(internProp); + return QVariant(); + } else if (QtSizeFPropertyManager *sizeFManager = qobject_cast<QtSizeFPropertyManager *>(manager)) { + if (attribute == d_ptr->m_maximumAttribute) + return sizeFManager->maximum(internProp); + if (attribute == d_ptr->m_minimumAttribute) + return sizeFManager->minimum(internProp); + if (attribute == d_ptr->m_decimalsAttribute) + return sizeFManager->decimals(internProp); + return QVariant(); + } else if (QtRectPropertyManager *rectManager = qobject_cast<QtRectPropertyManager *>(manager)) { + if (attribute == d_ptr->m_constraintAttribute) + return rectManager->constraint(internProp); + return QVariant(); + } else if (QtRectFPropertyManager *rectFManager = qobject_cast<QtRectFPropertyManager *>(manager)) { + if (attribute == d_ptr->m_constraintAttribute) + return rectFManager->constraint(internProp); + if (attribute == d_ptr->m_decimalsAttribute) + return rectFManager->decimals(internProp); + return QVariant(); + } else if (QtEnumPropertyManager *enumManager = qobject_cast<QtEnumPropertyManager *>(manager)) { + if (attribute == d_ptr->m_enumNamesAttribute) + return enumManager->enumNames(internProp); + if (attribute == d_ptr->m_enumIconsAttribute) { + QVariant v; + qVariantSetValue(v, enumManager->enumIcons(internProp)); + return v; + } + return QVariant(); + } else if (QtFlagPropertyManager *flagManager = qobject_cast<QtFlagPropertyManager *>(manager)) { + if (attribute == d_ptr->m_flagNamesAttribute) + return flagManager->flagNames(internProp); + return QVariant(); + } + return QVariant(); +} + +/*! + Returns a list of the given \a propertyType 's attributes. + + \sa attributeValue(), attributeType() +*/ +QStringList QtVariantPropertyManager::attributes(int propertyType) const +{ + QMap<int, QMap<QString, int> >::ConstIterator it = + d_ptr->m_typeToAttributeToAttributeType.find(propertyType); + if (it == d_ptr->m_typeToAttributeToAttributeType.constEnd()) + return QStringList(); + return it.value().keys(); +} + +/*! + Returns the type of the specified \a attribute of the given \a + propertyType. + + If the given \a propertyType is not supported by \e this manager, + or if the given \a propertyType does not possess the specified \a + attribute, this function returns QVariant::Invalid. + + \sa attributes(), valueType() +*/ +int QtVariantPropertyManager::attributeType(int propertyType, const QString &attribute) const +{ + QMap<int, QMap<QString, int> >::ConstIterator it = + d_ptr->m_typeToAttributeToAttributeType.find(propertyType); + if (it == d_ptr->m_typeToAttributeToAttributeType.constEnd()) + return 0; + + QMap<QString, int> attributes = it.value(); + QMap<QString, int>::ConstIterator itAttr = attributes.find(attribute); + if (itAttr == attributes.constEnd()) + return 0; + return itAttr.value(); +} + +/*! + \fn void QtVariantPropertyManager::setValue(QtProperty *property, const QVariant &value) + + Sets the value of the given \a property to \a value. + + The specified \a value must be of a type returned by valueType(), + or of type that can be converted to valueType() using the + QVariant::canConvert() function, otherwise this function does + nothing. + + \sa value(), QtVariantProperty::setValue(), valueChanged() +*/ +void QtVariantPropertyManager::setValue(QtProperty *property, const QVariant &val) +{ + int propType = val.userType(); + if (!propType) + return; + + int valType = valueType(property); + + if (propType != valType && !val.canConvert(static_cast<QVariant::Type>(valType))) + return; + + QtProperty *internProp = propertyToWrappedProperty()->value(property, 0); + if (internProp == 0) + return; + + + QtAbstractPropertyManager *manager = internProp->propertyManager(); + if (QtIntPropertyManager *intManager = qobject_cast<QtIntPropertyManager *>(manager)) { + intManager->setValue(internProp, qVariantValue<int>(val)); + return; + } else if (QtDoublePropertyManager *doubleManager = qobject_cast<QtDoublePropertyManager *>(manager)) { + doubleManager->setValue(internProp, qVariantValue<double>(val)); + return; + } else if (QtBoolPropertyManager *boolManager = qobject_cast<QtBoolPropertyManager *>(manager)) { + boolManager->setValue(internProp, qVariantValue<bool>(val)); + return; + } else if (QtStringPropertyManager *stringManager = qobject_cast<QtStringPropertyManager *>(manager)) { + stringManager->setValue(internProp, qVariantValue<QString>(val)); + return; + } else if (QtDatePropertyManager *dateManager = qobject_cast<QtDatePropertyManager *>(manager)) { + dateManager->setValue(internProp, qVariantValue<QDate>(val)); + return; + } else if (QtTimePropertyManager *timeManager = qobject_cast<QtTimePropertyManager *>(manager)) { + timeManager->setValue(internProp, qVariantValue<QTime>(val)); + return; + } else if (QtDateTimePropertyManager *dateTimeManager = qobject_cast<QtDateTimePropertyManager *>(manager)) { + dateTimeManager->setValue(internProp, qVariantValue<QDateTime>(val)); + return; + } else if (QtKeySequencePropertyManager *keySequenceManager = qobject_cast<QtKeySequencePropertyManager *>(manager)) { + keySequenceManager->setValue(internProp, qVariantValue<QKeySequence>(val)); + return; + } else if (QtCharPropertyManager *charManager = qobject_cast<QtCharPropertyManager *>(manager)) { + charManager->setValue(internProp, qVariantValue<QChar>(val)); + return; + } else if (QtLocalePropertyManager *localeManager = qobject_cast<QtLocalePropertyManager *>(manager)) { + localeManager->setValue(internProp, qVariantValue<QLocale>(val)); + return; + } else if (QtPointPropertyManager *pointManager = qobject_cast<QtPointPropertyManager *>(manager)) { + pointManager->setValue(internProp, qVariantValue<QPoint>(val)); + return; + } else if (QtPointFPropertyManager *pointFManager = qobject_cast<QtPointFPropertyManager *>(manager)) { + pointFManager->setValue(internProp, qVariantValue<QPointF>(val)); + return; + } else if (QtSizePropertyManager *sizeManager = qobject_cast<QtSizePropertyManager *>(manager)) { + sizeManager->setValue(internProp, qVariantValue<QSize>(val)); + return; + } else if (QtSizeFPropertyManager *sizeFManager = qobject_cast<QtSizeFPropertyManager *>(manager)) { + sizeFManager->setValue(internProp, qVariantValue<QSizeF>(val)); + return; + } else if (QtRectPropertyManager *rectManager = qobject_cast<QtRectPropertyManager *>(manager)) { + rectManager->setValue(internProp, qVariantValue<QRect>(val)); + return; + } else if (QtRectFPropertyManager *rectFManager = qobject_cast<QtRectFPropertyManager *>(manager)) { + rectFManager->setValue(internProp, qVariantValue<QRectF>(val)); + return; + } else if (QtColorPropertyManager *colorManager = qobject_cast<QtColorPropertyManager *>(manager)) { + colorManager->setValue(internProp, qVariantValue<QColor>(val)); + return; + } else if (QtEnumPropertyManager *enumManager = qobject_cast<QtEnumPropertyManager *>(manager)) { + enumManager->setValue(internProp, qVariantValue<int>(val)); + return; + } else if (QtSizePolicyPropertyManager *sizePolicyManager = + qobject_cast<QtSizePolicyPropertyManager *>(manager)) { + sizePolicyManager->setValue(internProp, qVariantValue<QSizePolicy>(val)); + return; + } else if (QtFontPropertyManager *fontManager = qobject_cast<QtFontPropertyManager *>(manager)) { + fontManager->setValue(internProp, qVariantValue<QFont>(val)); + return; +#ifndef QT_NO_CURSOR + } else if (QtCursorPropertyManager *cursorManager = qobject_cast<QtCursorPropertyManager *>(manager)) { + cursorManager->setValue(internProp, qVariantValue<QCursor>(val)); + return; +#endif + } else if (QtFlagPropertyManager *flagManager = qobject_cast<QtFlagPropertyManager *>(manager)) { + flagManager->setValue(internProp, qVariantValue<int>(val)); + return; + } +} + +/*! + Sets the value of the specified \a attribute of the given \a + property, to \a value. + + The new \a value's type must be of the type returned by + attributeType(), or of a type that can be converted to + attributeType() using the QVariant::canConvert() function, + otherwise this function does nothing. + + \sa attributeValue(), QtVariantProperty::setAttribute(), attributeChanged() +*/ +void QtVariantPropertyManager::setAttribute(QtProperty *property, + const QString &attribute, const QVariant &value) +{ + QVariant oldAttr = attributeValue(property, attribute); + if (!oldAttr.isValid()) + return; + + int attrType = value.userType(); + if (!attrType) + return; + + if (attrType != attributeType(propertyType(property), attribute) && + !value.canConvert((QVariant::Type)attrType)) + return; + + QtProperty *internProp = propertyToWrappedProperty()->value(property, 0); + if (internProp == 0) + return; + + QtAbstractPropertyManager *manager = internProp->propertyManager(); + if (QtIntPropertyManager *intManager = qobject_cast<QtIntPropertyManager *>(manager)) { + if (attribute == d_ptr->m_maximumAttribute) + intManager->setMaximum(internProp, qVariantValue<int>(value)); + else if (attribute == d_ptr->m_minimumAttribute) + intManager->setMinimum(internProp, qVariantValue<int>(value)); + else if (attribute == d_ptr->m_singleStepAttribute) + intManager->setSingleStep(internProp, qVariantValue<int>(value)); + return; + } else if (QtDoublePropertyManager *doubleManager = qobject_cast<QtDoublePropertyManager *>(manager)) { + if (attribute == d_ptr->m_maximumAttribute) + doubleManager->setMaximum(internProp, qVariantValue<double>(value)); + if (attribute == d_ptr->m_minimumAttribute) + doubleManager->setMinimum(internProp, qVariantValue<double>(value)); + if (attribute == d_ptr->m_singleStepAttribute) + doubleManager->setSingleStep(internProp, qVariantValue<double>(value)); + if (attribute == d_ptr->m_decimalsAttribute) + doubleManager->setDecimals(internProp, qVariantValue<int>(value)); + return; + } else if (QtStringPropertyManager *stringManager = qobject_cast<QtStringPropertyManager *>(manager)) { + if (attribute == d_ptr->m_regExpAttribute) + stringManager->setRegExp(internProp, qVariantValue<QRegExp>(value)); + return; + } else if (QtDatePropertyManager *dateManager = qobject_cast<QtDatePropertyManager *>(manager)) { + if (attribute == d_ptr->m_maximumAttribute) + dateManager->setMaximum(internProp, qVariantValue<QDate>(value)); + if (attribute == d_ptr->m_minimumAttribute) + dateManager->setMinimum(internProp, qVariantValue<QDate>(value)); + return; + } else if (QtPointFPropertyManager *pointFManager = qobject_cast<QtPointFPropertyManager *>(manager)) { + if (attribute == d_ptr->m_decimalsAttribute) + pointFManager->setDecimals(internProp, qVariantValue<int>(value)); + return; + } else if (QtSizePropertyManager *sizeManager = qobject_cast<QtSizePropertyManager *>(manager)) { + if (attribute == d_ptr->m_maximumAttribute) + sizeManager->setMaximum(internProp, qVariantValue<QSize>(value)); + if (attribute == d_ptr->m_minimumAttribute) + sizeManager->setMinimum(internProp, qVariantValue<QSize>(value)); + return; + } else if (QtSizeFPropertyManager *sizeFManager = qobject_cast<QtSizeFPropertyManager *>(manager)) { + if (attribute == d_ptr->m_maximumAttribute) + sizeFManager->setMaximum(internProp, qVariantValue<QSizeF>(value)); + if (attribute == d_ptr->m_minimumAttribute) + sizeFManager->setMinimum(internProp, qVariantValue<QSizeF>(value)); + if (attribute == d_ptr->m_decimalsAttribute) + sizeFManager->setDecimals(internProp, qVariantValue<int>(value)); + return; + } else if (QtRectPropertyManager *rectManager = qobject_cast<QtRectPropertyManager *>(manager)) { + if (attribute == d_ptr->m_constraintAttribute) + rectManager->setConstraint(internProp, qVariantValue<QRect>(value)); + return; + } else if (QtRectFPropertyManager *rectFManager = qobject_cast<QtRectFPropertyManager *>(manager)) { + if (attribute == d_ptr->m_constraintAttribute) + rectFManager->setConstraint(internProp, qVariantValue<QRectF>(value)); + if (attribute == d_ptr->m_decimalsAttribute) + rectFManager->setDecimals(internProp, qVariantValue<int>(value)); + return; + } else if (QtEnumPropertyManager *enumManager = qobject_cast<QtEnumPropertyManager *>(manager)) { + if (attribute == d_ptr->m_enumNamesAttribute) + enumManager->setEnumNames(internProp, qVariantValue<QStringList>(value)); + if (attribute == d_ptr->m_enumIconsAttribute) + enumManager->setEnumIcons(internProp, qVariantValue<QtIconMap>(value)); + return; + } else if (QtFlagPropertyManager *flagManager = qobject_cast<QtFlagPropertyManager *>(manager)) { + if (attribute == d_ptr->m_flagNamesAttribute) + flagManager->setFlagNames(internProp, qVariantValue<QStringList>(value)); + return; + } +} + +/*! + \reimp +*/ +bool QtVariantPropertyManager::hasValue(const QtProperty *property) const +{ + if (propertyType(property) == groupTypeId()) + return false; + return true; +} + +/*! + \reimp +*/ +QString QtVariantPropertyManager::valueText(const QtProperty *property) const +{ + const QtProperty *internProp = propertyToWrappedProperty()->value(property, 0); + return internProp ? internProp->valueText() : QString(); +} + +/*! + \reimp +*/ +QIcon QtVariantPropertyManager::valueIcon(const QtProperty *property) const +{ + const QtProperty *internProp = propertyToWrappedProperty()->value(property, 0); + return internProp ? internProp->valueIcon() : QIcon(); +} + +/*! + \reimp +*/ +void QtVariantPropertyManager::initializeProperty(QtProperty *property) +{ + QtVariantProperty *varProp = variantProperty(property); + if (!varProp) + return; + + QMap<int, QtAbstractPropertyManager *>::ConstIterator it = + d_ptr->m_typeToPropertyManager.find(d_ptr->m_propertyType); + if (it != d_ptr->m_typeToPropertyManager.constEnd()) { + QtProperty *internProp = 0; + if (!d_ptr->m_creatingSubProperties) { + QtAbstractPropertyManager *manager = it.value(); + internProp = manager->addProperty(); + d_ptr->m_internalToProperty[internProp] = varProp; + } + propertyToWrappedProperty()->insert(varProp, internProp); + if (internProp) { + QList<QtProperty *> children = internProp->subProperties(); + QListIterator<QtProperty *> itChild(children); + QtVariantProperty *lastProperty = 0; + while (itChild.hasNext()) { + QtVariantProperty *prop = d_ptr->createSubProperty(varProp, lastProperty, itChild.next()); + lastProperty = prop ? prop : lastProperty; + } + } + } +} + +/*! + \reimp +*/ +void QtVariantPropertyManager::uninitializeProperty(QtProperty *property) +{ + const QMap<const QtProperty *, QPair<QtVariantProperty *, int> >::iterator type_it = d_ptr->m_propertyToType.find(property); + if (type_it == d_ptr->m_propertyToType.end()) + return; + + PropertyMap::iterator it = propertyToWrappedProperty()->find(property); + if (it != propertyToWrappedProperty()->end()) { + QtProperty *internProp = it.value(); + if (internProp) { + d_ptr->m_internalToProperty.remove(internProp); + if (!d_ptr->m_destroyingSubProperties) { + delete internProp; + } + } + propertyToWrappedProperty()->erase(it); + } + d_ptr->m_propertyToType.erase(type_it); +} + +/*! + \reimp +*/ +QtProperty *QtVariantPropertyManager::createProperty() +{ + if (!d_ptr->m_creatingProperty) + return 0; + + QtVariantProperty *property = new QtVariantProperty(this); + d_ptr->m_propertyToType.insert(property, qMakePair(property, d_ptr->m_propertyType)); + + return property; +} + +///////////////////////////// + +class QtVariantEditorFactoryPrivate +{ + QtVariantEditorFactory *q_ptr; + Q_DECLARE_PUBLIC(QtVariantEditorFactory) +public: + + QtSpinBoxFactory *m_spinBoxFactory; + QtDoubleSpinBoxFactory *m_doubleSpinBoxFactory; + QtCheckBoxFactory *m_checkBoxFactory; + QtLineEditFactory *m_lineEditFactory; + QtDateEditFactory *m_dateEditFactory; + QtTimeEditFactory *m_timeEditFactory; + QtDateTimeEditFactory *m_dateTimeEditFactory; + QtKeySequenceEditorFactory *m_keySequenceEditorFactory; + QtCharEditorFactory *m_charEditorFactory; + QtEnumEditorFactory *m_comboBoxFactory; + QtCursorEditorFactory *m_cursorEditorFactory; + QtColorEditorFactory *m_colorEditorFactory; + QtFontEditorFactory *m_fontEditorFactory; + + QMap<QtAbstractEditorFactoryBase *, int> m_factoryToType; + QMap<int, QtAbstractEditorFactoryBase *> m_typeToFactory; +}; + +/*! + \class QtVariantEditorFactory + \internal + \inmodule QtDesigner + \since 4.4 + + \brief The QtVariantEditorFactory class provides widgets for properties + created by QtVariantPropertyManager objects. + + The variant factory provides the following widgets for the + specified property types: + + \table + \header + \o Property Type + \o Widget + \row + \o \c int + \o QSpinBox + \row + \o \c double + \o QDoubleSpinBox + \row + \o \c bool + \o QCheckBox + \row + \o QString + \o QLineEdit + \row + \o QDate + \o QDateEdit + \row + \o QTime + \o QTimeEdit + \row + \o QDateTime + \o QDateTimeEdit + \row + \o QKeySequence + \o customized editor + \row + \o QChar + \o customized editor + \row + \o \c enum + \o QComboBox + \row + \o QCursor + \o QComboBox + \endtable + + Note that QtVariantPropertyManager supports several additional property + types for which the QtVariantEditorFactory class does not provide + editing widgets, e.g. QPoint and QSize. To provide widgets for other + types using the variant approach, derive from the QtVariantEditorFactory + class. + + \sa QtAbstractEditorFactory, QtVariantPropertyManager +*/ + +/*! + Creates a factory with the given \a parent. +*/ +QtVariantEditorFactory::QtVariantEditorFactory(QObject *parent) + : QtAbstractEditorFactory<QtVariantPropertyManager>(parent) +{ + d_ptr = new QtVariantEditorFactoryPrivate(); + d_ptr->q_ptr = this; + + d_ptr->m_spinBoxFactory = new QtSpinBoxFactory(this); + d_ptr->m_factoryToType[d_ptr->m_spinBoxFactory] = QVariant::Int; + d_ptr->m_typeToFactory[QVariant::Int] = d_ptr->m_spinBoxFactory; + + d_ptr->m_doubleSpinBoxFactory = new QtDoubleSpinBoxFactory(this); + d_ptr->m_factoryToType[d_ptr->m_doubleSpinBoxFactory] = QVariant::Double; + d_ptr->m_typeToFactory[QVariant::Double] = d_ptr->m_doubleSpinBoxFactory; + + d_ptr->m_checkBoxFactory = new QtCheckBoxFactory(this); + d_ptr->m_factoryToType[d_ptr->m_checkBoxFactory] = QVariant::Bool; + d_ptr->m_typeToFactory[QVariant::Bool] = d_ptr->m_checkBoxFactory; + + d_ptr->m_lineEditFactory = new QtLineEditFactory(this); + d_ptr->m_factoryToType[d_ptr->m_lineEditFactory] = QVariant::String; + d_ptr->m_typeToFactory[QVariant::String] = d_ptr->m_lineEditFactory; + + d_ptr->m_dateEditFactory = new QtDateEditFactory(this); + d_ptr->m_factoryToType[d_ptr->m_dateEditFactory] = QVariant::Date; + d_ptr->m_typeToFactory[QVariant::Date] = d_ptr->m_dateEditFactory; + + d_ptr->m_timeEditFactory = new QtTimeEditFactory(this); + d_ptr->m_factoryToType[d_ptr->m_timeEditFactory] = QVariant::Time; + d_ptr->m_typeToFactory[QVariant::Time] = d_ptr->m_timeEditFactory; + + d_ptr->m_dateTimeEditFactory = new QtDateTimeEditFactory(this); + d_ptr->m_factoryToType[d_ptr->m_dateTimeEditFactory] = QVariant::DateTime; + d_ptr->m_typeToFactory[QVariant::DateTime] = d_ptr->m_dateTimeEditFactory; + + d_ptr->m_keySequenceEditorFactory = new QtKeySequenceEditorFactory(this); + d_ptr->m_factoryToType[d_ptr->m_keySequenceEditorFactory] = QVariant::KeySequence; + d_ptr->m_typeToFactory[QVariant::KeySequence] = d_ptr->m_keySequenceEditorFactory; + + d_ptr->m_charEditorFactory = new QtCharEditorFactory(this); + d_ptr->m_factoryToType[d_ptr->m_charEditorFactory] = QVariant::Char; + d_ptr->m_typeToFactory[QVariant::Char] = d_ptr->m_charEditorFactory; + + d_ptr->m_cursorEditorFactory = new QtCursorEditorFactory(this); + d_ptr->m_factoryToType[d_ptr->m_cursorEditorFactory] = QVariant::Cursor; + d_ptr->m_typeToFactory[QVariant::Cursor] = d_ptr->m_cursorEditorFactory; + + d_ptr->m_colorEditorFactory = new QtColorEditorFactory(this); + d_ptr->m_factoryToType[d_ptr->m_colorEditorFactory] = QVariant::Color; + d_ptr->m_typeToFactory[QVariant::Color] = d_ptr->m_colorEditorFactory; + + d_ptr->m_fontEditorFactory = new QtFontEditorFactory(this); + d_ptr->m_factoryToType[d_ptr->m_fontEditorFactory] = QVariant::Font; + d_ptr->m_typeToFactory[QVariant::Font] = d_ptr->m_fontEditorFactory; + + d_ptr->m_comboBoxFactory = new QtEnumEditorFactory(this); + const int enumId = QtVariantPropertyManager::enumTypeId(); + d_ptr->m_factoryToType[d_ptr->m_comboBoxFactory] = enumId; + d_ptr->m_typeToFactory[enumId] = d_ptr->m_comboBoxFactory; +} + +/*! + Destroys this factory, and all the widgets it has created. +*/ +QtVariantEditorFactory::~QtVariantEditorFactory() +{ + delete d_ptr; +} + +/*! + \internal + + Reimplemented from the QtAbstractEditorFactory class. +*/ +void QtVariantEditorFactory::connectPropertyManager(QtVariantPropertyManager *manager) +{ + QList<QtIntPropertyManager *> intPropertyManagers = qFindChildren<QtIntPropertyManager *>(manager); + QListIterator<QtIntPropertyManager *> itInt(intPropertyManagers); + while (itInt.hasNext()) + d_ptr->m_spinBoxFactory->addPropertyManager(itInt.next()); + + QList<QtDoublePropertyManager *> doublePropertyManagers = qFindChildren<QtDoublePropertyManager *>(manager); + QListIterator<QtDoublePropertyManager *> itDouble(doublePropertyManagers); + while (itDouble.hasNext()) + d_ptr->m_doubleSpinBoxFactory->addPropertyManager(itDouble.next()); + + QList<QtBoolPropertyManager *> boolPropertyManagers = qFindChildren<QtBoolPropertyManager *>(manager); + QListIterator<QtBoolPropertyManager *> itBool(boolPropertyManagers); + while (itBool.hasNext()) + d_ptr->m_checkBoxFactory->addPropertyManager(itBool.next()); + + QList<QtStringPropertyManager *> stringPropertyManagers = qFindChildren<QtStringPropertyManager *>(manager); + QListIterator<QtStringPropertyManager *> itString(stringPropertyManagers); + while (itString.hasNext()) + d_ptr->m_lineEditFactory->addPropertyManager(itString.next()); + + QList<QtDatePropertyManager *> datePropertyManagers = qFindChildren<QtDatePropertyManager *>(manager); + QListIterator<QtDatePropertyManager *> itDate(datePropertyManagers); + while (itDate.hasNext()) + d_ptr->m_dateEditFactory->addPropertyManager(itDate.next()); + + QList<QtTimePropertyManager *> timePropertyManagers = qFindChildren<QtTimePropertyManager *>(manager); + QListIterator<QtTimePropertyManager *> itTime(timePropertyManagers); + while (itTime.hasNext()) + d_ptr->m_timeEditFactory->addPropertyManager(itTime.next()); + + QList<QtDateTimePropertyManager *> dateTimePropertyManagers = qFindChildren<QtDateTimePropertyManager *>(manager); + QListIterator<QtDateTimePropertyManager *> itDateTime(dateTimePropertyManagers); + while (itDateTime.hasNext()) + d_ptr->m_dateTimeEditFactory->addPropertyManager(itDateTime.next()); + + QList<QtKeySequencePropertyManager *> keySequencePropertyManagers = qFindChildren<QtKeySequencePropertyManager *>(manager); + QListIterator<QtKeySequencePropertyManager *> itKeySequence(keySequencePropertyManagers); + while (itKeySequence.hasNext()) + d_ptr->m_keySequenceEditorFactory->addPropertyManager(itKeySequence.next()); + + QList<QtCharPropertyManager *> charPropertyManagers = qFindChildren<QtCharPropertyManager *>(manager); + QListIterator<QtCharPropertyManager *> itChar(charPropertyManagers); + while (itChar.hasNext()) + d_ptr->m_charEditorFactory->addPropertyManager(itChar.next()); + + QList<QtLocalePropertyManager *> localePropertyManagers = qFindChildren<QtLocalePropertyManager *>(manager); + QListIterator<QtLocalePropertyManager *> itLocale(localePropertyManagers); + while (itLocale.hasNext()) + d_ptr->m_comboBoxFactory->addPropertyManager(itLocale.next()->subEnumPropertyManager()); + + QList<QtPointPropertyManager *> pointPropertyManagers = qFindChildren<QtPointPropertyManager *>(manager); + QListIterator<QtPointPropertyManager *> itPoint(pointPropertyManagers); + while (itPoint.hasNext()) + d_ptr->m_spinBoxFactory->addPropertyManager(itPoint.next()->subIntPropertyManager()); + + QList<QtPointFPropertyManager *> pointFPropertyManagers = qFindChildren<QtPointFPropertyManager *>(manager); + QListIterator<QtPointFPropertyManager *> itPointF(pointFPropertyManagers); + while (itPointF.hasNext()) + d_ptr->m_doubleSpinBoxFactory->addPropertyManager(itPointF.next()->subDoublePropertyManager()); + + QList<QtSizePropertyManager *> sizePropertyManagers = qFindChildren<QtSizePropertyManager *>(manager); + QListIterator<QtSizePropertyManager *> itSize(sizePropertyManagers); + while (itSize.hasNext()) + d_ptr->m_spinBoxFactory->addPropertyManager(itSize.next()->subIntPropertyManager()); + + QList<QtSizeFPropertyManager *> sizeFPropertyManagers = qFindChildren<QtSizeFPropertyManager *>(manager); + QListIterator<QtSizeFPropertyManager *> itSizeF(sizeFPropertyManagers); + while (itSizeF.hasNext()) + d_ptr->m_doubleSpinBoxFactory->addPropertyManager(itSizeF.next()->subDoublePropertyManager()); + + QList<QtRectPropertyManager *> rectPropertyManagers = qFindChildren<QtRectPropertyManager *>(manager); + QListIterator<QtRectPropertyManager *> itRect(rectPropertyManagers); + while (itRect.hasNext()) + d_ptr->m_spinBoxFactory->addPropertyManager(itRect.next()->subIntPropertyManager()); + + QList<QtRectFPropertyManager *> rectFPropertyManagers = qFindChildren<QtRectFPropertyManager *>(manager); + QListIterator<QtRectFPropertyManager *> itRectF(rectFPropertyManagers); + while (itRectF.hasNext()) + d_ptr->m_doubleSpinBoxFactory->addPropertyManager(itRectF.next()->subDoublePropertyManager()); + + QList<QtColorPropertyManager *> colorPropertyManagers = qFindChildren<QtColorPropertyManager *>(manager); + QListIterator<QtColorPropertyManager *> itColor(colorPropertyManagers); + while (itColor.hasNext()) { + QtColorPropertyManager *manager = itColor.next(); + d_ptr->m_colorEditorFactory->addPropertyManager(manager); + d_ptr->m_spinBoxFactory->addPropertyManager(manager->subIntPropertyManager()); + } + + QList<QtEnumPropertyManager *> enumPropertyManagers = qFindChildren<QtEnumPropertyManager *>(manager); + QListIterator<QtEnumPropertyManager *> itEnum(enumPropertyManagers); + while (itEnum.hasNext()) + d_ptr->m_comboBoxFactory->addPropertyManager(itEnum.next()); + + QList<QtSizePolicyPropertyManager *> sizePolicyPropertyManagers = qFindChildren<QtSizePolicyPropertyManager *>(manager); + QListIterator<QtSizePolicyPropertyManager *> itSizePolicy(sizePolicyPropertyManagers); + while (itSizePolicy.hasNext()) { + QtSizePolicyPropertyManager *manager = itSizePolicy.next(); + d_ptr->m_spinBoxFactory->addPropertyManager(manager->subIntPropertyManager()); + d_ptr->m_comboBoxFactory->addPropertyManager(manager->subEnumPropertyManager()); + } + + QList<QtFontPropertyManager *> fontPropertyManagers = qFindChildren<QtFontPropertyManager *>(manager); + QListIterator<QtFontPropertyManager *> itFont(fontPropertyManagers); + while (itFont.hasNext()) { + QtFontPropertyManager *manager = itFont.next(); + d_ptr->m_fontEditorFactory->addPropertyManager(manager); + d_ptr->m_spinBoxFactory->addPropertyManager(manager->subIntPropertyManager()); + d_ptr->m_comboBoxFactory->addPropertyManager(manager->subEnumPropertyManager()); + d_ptr->m_checkBoxFactory->addPropertyManager(manager->subBoolPropertyManager()); + } + + QList<QtCursorPropertyManager *> cursorPropertyManagers = qFindChildren<QtCursorPropertyManager *>(manager); + QListIterator<QtCursorPropertyManager *> itCursor(cursorPropertyManagers); + while (itCursor.hasNext()) + d_ptr->m_cursorEditorFactory->addPropertyManager(itCursor.next()); + + QList<QtFlagPropertyManager *> flagPropertyManagers = qFindChildren<QtFlagPropertyManager *>(manager); + QListIterator<QtFlagPropertyManager *> itFlag(flagPropertyManagers); + while (itFlag.hasNext()) + d_ptr->m_checkBoxFactory->addPropertyManager(itFlag.next()->subBoolPropertyManager()); +} + +/*! + \internal + + Reimplemented from the QtAbstractEditorFactory class. +*/ +QWidget *QtVariantEditorFactory::createEditor(QtVariantPropertyManager *manager, QtProperty *property, + QWidget *parent) +{ + const int propType = manager->propertyType(property); + QtAbstractEditorFactoryBase *factory = d_ptr->m_typeToFactory.value(propType, 0); + if (!factory) + return 0; + return factory->createEditor(wrappedProperty(property), parent); +} + +/*! + \internal + + Reimplemented from the QtAbstractEditorFactory class. +*/ +void QtVariantEditorFactory::disconnectPropertyManager(QtVariantPropertyManager *manager) +{ + QList<QtIntPropertyManager *> intPropertyManagers = qFindChildren<QtIntPropertyManager *>(manager); + QListIterator<QtIntPropertyManager *> itInt(intPropertyManagers); + while (itInt.hasNext()) + d_ptr->m_spinBoxFactory->removePropertyManager(itInt.next()); + + QList<QtDoublePropertyManager *> doublePropertyManagers = qFindChildren<QtDoublePropertyManager *>(manager); + QListIterator<QtDoublePropertyManager *> itDouble(doublePropertyManagers); + while (itDouble.hasNext()) + d_ptr->m_doubleSpinBoxFactory->removePropertyManager(itDouble.next()); + + QList<QtBoolPropertyManager *> boolPropertyManagers = qFindChildren<QtBoolPropertyManager *>(manager); + QListIterator<QtBoolPropertyManager *> itBool(boolPropertyManagers); + while (itBool.hasNext()) + d_ptr->m_checkBoxFactory->removePropertyManager(itBool.next()); + + QList<QtStringPropertyManager *> stringPropertyManagers = qFindChildren<QtStringPropertyManager *>(manager); + QListIterator<QtStringPropertyManager *> itString(stringPropertyManagers); + while (itString.hasNext()) + d_ptr->m_lineEditFactory->removePropertyManager(itString.next()); + + QList<QtDatePropertyManager *> datePropertyManagers = qFindChildren<QtDatePropertyManager *>(manager); + QListIterator<QtDatePropertyManager *> itDate(datePropertyManagers); + while (itDate.hasNext()) + d_ptr->m_dateEditFactory->removePropertyManager(itDate.next()); + + QList<QtTimePropertyManager *> timePropertyManagers = qFindChildren<QtTimePropertyManager *>(manager); + QListIterator<QtTimePropertyManager *> itTime(timePropertyManagers); + while (itTime.hasNext()) + d_ptr->m_timeEditFactory->removePropertyManager(itTime.next()); + + QList<QtDateTimePropertyManager *> dateTimePropertyManagers = qFindChildren<QtDateTimePropertyManager *>(manager); + QListIterator<QtDateTimePropertyManager *> itDateTime(dateTimePropertyManagers); + while (itDateTime.hasNext()) + d_ptr->m_dateTimeEditFactory->removePropertyManager(itDateTime.next()); + + QList<QtKeySequencePropertyManager *> keySequencePropertyManagers = qFindChildren<QtKeySequencePropertyManager *>(manager); + QListIterator<QtKeySequencePropertyManager *> itKeySequence(keySequencePropertyManagers); + while (itKeySequence.hasNext()) + d_ptr->m_keySequenceEditorFactory->removePropertyManager(itKeySequence.next()); + + QList<QtCharPropertyManager *> charPropertyManagers = qFindChildren<QtCharPropertyManager *>(manager); + QListIterator<QtCharPropertyManager *> itChar(charPropertyManagers); + while (itChar.hasNext()) + d_ptr->m_charEditorFactory->removePropertyManager(itChar.next()); + + QList<QtLocalePropertyManager *> localePropertyManagers = qFindChildren<QtLocalePropertyManager *>(manager); + QListIterator<QtLocalePropertyManager *> itLocale(localePropertyManagers); + while (itLocale.hasNext()) + d_ptr->m_comboBoxFactory->removePropertyManager(itLocale.next()->subEnumPropertyManager()); + + QList<QtPointPropertyManager *> pointPropertyManagers = qFindChildren<QtPointPropertyManager *>(manager); + QListIterator<QtPointPropertyManager *> itPoint(pointPropertyManagers); + while (itPoint.hasNext()) + d_ptr->m_spinBoxFactory->removePropertyManager(itPoint.next()->subIntPropertyManager()); + + QList<QtPointFPropertyManager *> pointFPropertyManagers = qFindChildren<QtPointFPropertyManager *>(manager); + QListIterator<QtPointFPropertyManager *> itPointF(pointFPropertyManagers); + while (itPointF.hasNext()) + d_ptr->m_doubleSpinBoxFactory->removePropertyManager(itPointF.next()->subDoublePropertyManager()); + + QList<QtSizePropertyManager *> sizePropertyManagers = qFindChildren<QtSizePropertyManager *>(manager); + QListIterator<QtSizePropertyManager *> itSize(sizePropertyManagers); + while (itSize.hasNext()) + d_ptr->m_spinBoxFactory->removePropertyManager(itSize.next()->subIntPropertyManager()); + + QList<QtSizeFPropertyManager *> sizeFPropertyManagers = qFindChildren<QtSizeFPropertyManager *>(manager); + QListIterator<QtSizeFPropertyManager *> itSizeF(sizeFPropertyManagers); + while (itSizeF.hasNext()) + d_ptr->m_doubleSpinBoxFactory->removePropertyManager(itSizeF.next()->subDoublePropertyManager()); + + QList<QtRectPropertyManager *> rectPropertyManagers = qFindChildren<QtRectPropertyManager *>(manager); + QListIterator<QtRectPropertyManager *> itRect(rectPropertyManagers); + while (itRect.hasNext()) + d_ptr->m_spinBoxFactory->removePropertyManager(itRect.next()->subIntPropertyManager()); + + QList<QtRectFPropertyManager *> rectFPropertyManagers = qFindChildren<QtRectFPropertyManager *>(manager); + QListIterator<QtRectFPropertyManager *> itRectF(rectFPropertyManagers); + while (itRectF.hasNext()) + d_ptr->m_doubleSpinBoxFactory->removePropertyManager(itRectF.next()->subDoublePropertyManager()); + + QList<QtColorPropertyManager *> colorPropertyManagers = qFindChildren<QtColorPropertyManager *>(manager); + QListIterator<QtColorPropertyManager *> itColor(colorPropertyManagers); + while (itColor.hasNext()) { + QtColorPropertyManager *manager = itColor.next(); + d_ptr->m_colorEditorFactory->removePropertyManager(manager); + d_ptr->m_spinBoxFactory->removePropertyManager(manager->subIntPropertyManager()); + } + + QList<QtEnumPropertyManager *> enumPropertyManagers = qFindChildren<QtEnumPropertyManager *>(manager); + QListIterator<QtEnumPropertyManager *> itEnum(enumPropertyManagers); + while (itEnum.hasNext()) + d_ptr->m_comboBoxFactory->removePropertyManager(itEnum.next()); + + QList<QtSizePolicyPropertyManager *> sizePolicyPropertyManagers = qFindChildren<QtSizePolicyPropertyManager *>(manager); + QListIterator<QtSizePolicyPropertyManager *> itSizePolicy(sizePolicyPropertyManagers); + while (itSizePolicy.hasNext()) { + QtSizePolicyPropertyManager *manager = itSizePolicy.next(); + d_ptr->m_spinBoxFactory->removePropertyManager(manager->subIntPropertyManager()); + d_ptr->m_comboBoxFactory->removePropertyManager(manager->subEnumPropertyManager()); + } + + QList<QtFontPropertyManager *> fontPropertyManagers = qFindChildren<QtFontPropertyManager *>(manager); + QListIterator<QtFontPropertyManager *> itFont(fontPropertyManagers); + while (itFont.hasNext()) { + QtFontPropertyManager *manager = itFont.next(); + d_ptr->m_fontEditorFactory->removePropertyManager(manager); + d_ptr->m_spinBoxFactory->removePropertyManager(manager->subIntPropertyManager()); + d_ptr->m_comboBoxFactory->removePropertyManager(manager->subEnumPropertyManager()); + d_ptr->m_checkBoxFactory->removePropertyManager(manager->subBoolPropertyManager()); + } + + QList<QtCursorPropertyManager *> cursorPropertyManagers = qFindChildren<QtCursorPropertyManager *>(manager); + QListIterator<QtCursorPropertyManager *> itCursor(cursorPropertyManagers); + while (itCursor.hasNext()) + d_ptr->m_cursorEditorFactory->removePropertyManager(itCursor.next()); + + QList<QtFlagPropertyManager *> flagPropertyManagers = qFindChildren<QtFlagPropertyManager *>(manager); + QListIterator<QtFlagPropertyManager *> itFlag(flagPropertyManagers); + while (itFlag.hasNext()) + d_ptr->m_checkBoxFactory->removePropertyManager(itFlag.next()->subBoolPropertyManager()); +} + +#if QT_VERSION >= 0x040400 +QT_END_NAMESPACE +#endif + +#include "moc_qtvariantproperty.cpp" diff --git a/tools/shared/qtpropertybrowser/qtvariantproperty.h b/tools/shared/qtpropertybrowser/qtvariantproperty.h new file mode 100644 index 0000000..91397d8 --- /dev/null +++ b/tools/shared/qtpropertybrowser/qtvariantproperty.h @@ -0,0 +1,181 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the tools applications of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QTVARIANTPROPERTY_H +#define QTVARIANTPROPERTY_H + +#include "qtpropertybrowser.h" +#include <QtCore/QVariant> +#include <QtGui/QIcon> + +#if QT_VERSION >= 0x040400 +QT_BEGIN_NAMESPACE +#endif + +typedef QMap<int, QIcon> QtIconMap; + +class QtVariantPropertyManager; + +class QtVariantProperty : public QtProperty +{ +public: + ~QtVariantProperty(); + QVariant value() const; + QVariant attributeValue(const QString &attribute) const; + int valueType() const; + int propertyType() const; + + void setValue(const QVariant &value); + void setAttribute(const QString &attribute, const QVariant &value); +protected: + QtVariantProperty(QtVariantPropertyManager *manager); +private: + friend class QtVariantPropertyManager; + class QtVariantPropertyPrivate *d_ptr; +}; + +class QtVariantPropertyManager : public QtAbstractPropertyManager +{ + Q_OBJECT +public: + QtVariantPropertyManager(QObject *parent = 0); + ~QtVariantPropertyManager(); + + virtual QtVariantProperty *addProperty(int propertyType, const QString &name = QString()); + + int propertyType(const QtProperty *property) const; + int valueType(const QtProperty *property) const; + QtVariantProperty *variantProperty(const QtProperty *property) const; + + virtual bool isPropertyTypeSupported(int propertyType) const; + virtual int valueType(int propertyType) const; + virtual QStringList attributes(int propertyType) const; + virtual int attributeType(int propertyType, const QString &attribute) const; + + virtual QVariant value(const QtProperty *property) const; + virtual QVariant attributeValue(const QtProperty *property, const QString &attribute) const; + + static int enumTypeId(); + static int flagTypeId(); + static int groupTypeId(); + static int iconMapTypeId(); +public Q_SLOTS: + virtual void setValue(QtProperty *property, const QVariant &val); + virtual void setAttribute(QtProperty *property, + const QString &attribute, const QVariant &value); +Q_SIGNALS: + void valueChanged(QtProperty *property, const QVariant &val); + void attributeChanged(QtProperty *property, + const QString &attribute, const QVariant &val); +protected: + virtual bool hasValue(const QtProperty *property) const; + QString valueText(const QtProperty *property) const; + QIcon valueIcon(const QtProperty *property) const; + virtual void initializeProperty(QtProperty *property); + virtual void uninitializeProperty(QtProperty *property); + virtual QtProperty *createProperty(); +private: + class QtVariantPropertyManagerPrivate *d_ptr; + Q_PRIVATE_SLOT(d_func(), void slotValueChanged(QtProperty *, int)) + Q_PRIVATE_SLOT(d_func(), void slotRangeChanged(QtProperty *, int, int)) + Q_PRIVATE_SLOT(d_func(), void slotSingleStepChanged(QtProperty *, int)) + Q_PRIVATE_SLOT(d_func(), void slotValueChanged(QtProperty *, double)) + Q_PRIVATE_SLOT(d_func(), void slotRangeChanged(QtProperty *, double, double)) + Q_PRIVATE_SLOT(d_func(), void slotSingleStepChanged(QtProperty *, double)) + Q_PRIVATE_SLOT(d_func(), void slotDecimalsChanged(QtProperty *, int)) + Q_PRIVATE_SLOT(d_func(), void slotValueChanged(QtProperty *, bool)) + Q_PRIVATE_SLOT(d_func(), void slotValueChanged(QtProperty *, const QString &)) + Q_PRIVATE_SLOT(d_func(), void slotRegExpChanged(QtProperty *, const QRegExp &)) + Q_PRIVATE_SLOT(d_func(), void slotValueChanged(QtProperty *, const QDate &)) + Q_PRIVATE_SLOT(d_func(), void slotRangeChanged(QtProperty *, const QDate &, const QDate &)) + Q_PRIVATE_SLOT(d_func(), void slotValueChanged(QtProperty *, const QTime &)) + Q_PRIVATE_SLOT(d_func(), void slotValueChanged(QtProperty *, const QDateTime &)) + Q_PRIVATE_SLOT(d_func(), void slotValueChanged(QtProperty *, const QKeySequence &)) + Q_PRIVATE_SLOT(d_func(), void slotValueChanged(QtProperty *, const QChar &)) + Q_PRIVATE_SLOT(d_func(), void slotValueChanged(QtProperty *, const QLocale &)) + Q_PRIVATE_SLOT(d_func(), void slotValueChanged(QtProperty *, const QPoint &)) + Q_PRIVATE_SLOT(d_func(), void slotValueChanged(QtProperty *, const QPointF &)) + Q_PRIVATE_SLOT(d_func(), void slotValueChanged(QtProperty *, const QSize &)) + Q_PRIVATE_SLOT(d_func(), void slotRangeChanged(QtProperty *, const QSize &, const QSize &)) + Q_PRIVATE_SLOT(d_func(), void slotValueChanged(QtProperty *, const QSizeF &)) + Q_PRIVATE_SLOT(d_func(), void slotRangeChanged(QtProperty *, const QSizeF &, const QSizeF &)) + Q_PRIVATE_SLOT(d_func(), void slotValueChanged(QtProperty *, const QRect &)) + Q_PRIVATE_SLOT(d_func(), void slotConstraintChanged(QtProperty *, const QRect &)) + Q_PRIVATE_SLOT(d_func(), void slotValueChanged(QtProperty *, const QRectF &)) + Q_PRIVATE_SLOT(d_func(), void slotConstraintChanged(QtProperty *, const QRectF &)) + Q_PRIVATE_SLOT(d_func(), void slotValueChanged(QtProperty *, const QColor &)) + Q_PRIVATE_SLOT(d_func(), void slotEnumNamesChanged(QtProperty *, const QStringList &)) + Q_PRIVATE_SLOT(d_func(), void slotEnumIconsChanged(QtProperty *, const QMap<int, QIcon> &)) + Q_PRIVATE_SLOT(d_func(), void slotValueChanged(QtProperty *, const QSizePolicy &)) + Q_PRIVATE_SLOT(d_func(), void slotValueChanged(QtProperty *, const QFont &)) + Q_PRIVATE_SLOT(d_func(), void slotValueChanged(QtProperty *, const QCursor &)) + Q_PRIVATE_SLOT(d_func(), void slotFlagNamesChanged(QtProperty *, const QStringList &)) + + Q_PRIVATE_SLOT(d_func(), void slotPropertyInserted(QtProperty *, QtProperty *, QtProperty *)) + Q_PRIVATE_SLOT(d_func(), void slotPropertyRemoved(QtProperty *, QtProperty *)) + Q_DECLARE_PRIVATE(QtVariantPropertyManager) + Q_DISABLE_COPY(QtVariantPropertyManager) +}; + +class QtVariantEditorFactory : public QtAbstractEditorFactory<QtVariantPropertyManager> +{ + Q_OBJECT +public: + QtVariantEditorFactory(QObject *parent = 0); + ~QtVariantEditorFactory(); +protected: + void connectPropertyManager(QtVariantPropertyManager *manager); + QWidget *createEditor(QtVariantPropertyManager *manager, QtProperty *property, + QWidget *parent); + void disconnectPropertyManager(QtVariantPropertyManager *manager); +private: + class QtVariantEditorFactoryPrivate *d_ptr; + Q_DECLARE_PRIVATE(QtVariantEditorFactory) + Q_DISABLE_COPY(QtVariantEditorFactory) +}; + +#if QT_VERSION >= 0x040400 +QT_END_NAMESPACE +#endif + +Q_DECLARE_METATYPE(QIcon) +Q_DECLARE_METATYPE(QtIconMap) +#endif diff --git a/tools/shared/qttoolbardialog/images/back.png b/tools/shared/qttoolbardialog/images/back.png Binary files differnew file mode 100644 index 0000000..e58177f --- /dev/null +++ b/tools/shared/qttoolbardialog/images/back.png diff --git a/tools/shared/qttoolbardialog/images/down.png b/tools/shared/qttoolbardialog/images/down.png Binary files differnew file mode 100644 index 0000000..29d1d44 --- /dev/null +++ b/tools/shared/qttoolbardialog/images/down.png diff --git a/tools/shared/qttoolbardialog/images/forward.png b/tools/shared/qttoolbardialog/images/forward.png Binary files differnew file mode 100644 index 0000000..34b91f0 --- /dev/null +++ b/tools/shared/qttoolbardialog/images/forward.png diff --git a/tools/shared/qttoolbardialog/images/minus.png b/tools/shared/qttoolbardialog/images/minus.png Binary files differnew file mode 100644 index 0000000..d6f233d --- /dev/null +++ b/tools/shared/qttoolbardialog/images/minus.png diff --git a/tools/shared/qttoolbardialog/images/plus.png b/tools/shared/qttoolbardialog/images/plus.png Binary files differnew file mode 100644 index 0000000..40df113 --- /dev/null +++ b/tools/shared/qttoolbardialog/images/plus.png diff --git a/tools/shared/qttoolbardialog/images/up.png b/tools/shared/qttoolbardialog/images/up.png Binary files differnew file mode 100644 index 0000000..e437312 --- /dev/null +++ b/tools/shared/qttoolbardialog/images/up.png diff --git a/tools/shared/qttoolbardialog/qttoolbardialog.cpp b/tools/shared/qttoolbardialog/qttoolbardialog.cpp new file mode 100644 index 0000000..f15c4bc --- /dev/null +++ b/tools/shared/qttoolbardialog/qttoolbardialog.cpp @@ -0,0 +1,1877 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the tools applications of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qttoolbardialog.h" +#include "ui_qttoolbardialog.h" + +#include <QtCore/QSet> +#include <QtGui/QtEvents> +#include <QtGui/QAction> +#include <QtGui/QToolBar> +#include <QtGui/QMainWindow> +#include <QtGui/QHeaderView> +#include <QtGui/QPushButton> + +QT_BEGIN_NAMESPACE + +class QtFullToolBarManagerPrivate; + +class QtFullToolBarManager : public QObject +{ + Q_OBJECT +public: + QtFullToolBarManager(QObject *parent); + ~QtFullToolBarManager(); + + void setMainWindow(QMainWindow *mainWindow); + QMainWindow *mainWindow() const; + + void addCategory(const QString &category); + bool hasCategory(const QString &category) const; + QStringList categories() const; + QList<QAction *> categoryActions(const QString &category) const; + QString actionCategory(QAction *action) const; + + // only non-separator + void addAction(QAction *action, const QString &category); + + void removeAction(QAction *action); + + QSet<QAction *> actions() const; + bool isWidgetAction(QAction *action) const; + + /* + Adds (registers) toolBar. Adds (registers) actions that already exists in toolBar. + Remembers toolbar and its actions as a default. + */ + void addDefaultToolBar(QToolBar *toolBar, const QString &category); + + void removeDefaultToolBar(QToolBar *toolBar); + // NULL on action list means separator. + QMap<QToolBar *, QList<QAction *> > defaultToolBars() const; + bool isDefaultToolBar(QToolBar *toolBar) const; + + QToolBar *createToolBar(const QString &toolBarName); + void deleteToolBar(QToolBar *toolBar); // only those which were created, not added + + QList<QAction *> actions(QToolBar *toolBar) const; + + void setToolBars(const QMap<QToolBar *, QList<QAction *> > &actions); + void setToolBar(QToolBar *toolBar, const QList<QAction *> &actions); + + QMap<QToolBar *, QList<QAction *> > toolBarsActions() const; + QByteArray saveState(int version = 0) const; + bool restoreState(const QByteArray &state, int version = 0); + +public slots: + + void resetToolBar(QToolBar *toolBar); + void resetAllToolBars(); + +signals: + void toolBarCreated(QToolBar *toolBar); + void toolBarRemoved(QToolBar *toolBar); + + /* + If QToolBarWidgetAction was in another tool bar and is inserted into + this toolBar, toolBarChanged is first emitted for other toolbar - without + that action. (Another approach may be that user first must call setToolBar + without that action for old tool bar) + */ + void toolBarChanged(QToolBar *toolBar, const QList<QAction *> &actions); + +private: + QtFullToolBarManagerPrivate *d_ptr; + Q_DECLARE_PRIVATE(QtFullToolBarManager) + Q_DISABLE_COPY(QtFullToolBarManager) +}; + +class QtFullToolBarManagerPrivate +{ + class QtFullToolBarManager *q_ptr; + Q_DECLARE_PUBLIC(QtFullToolBarManager) + +public: + + QToolBar *toolBarWidgetAction(QAction *action) const; + void removeWidgetActions(const QMap<QToolBar *, QList<QAction *> > &actions); + + enum { + VersionMarker = 0xff, + ToolBarMarker = 0xfe, + CustomToolBarMarker = 0xfd, + }; + + void saveState(QDataStream &stream) const; + bool restoreState(QDataStream &stream) const; + QToolBar *findDefaultToolBar(const QString &objectName) const; + QAction *findAction(const QString &actionName) const; + + QToolBar *toolBarByName(const QString &toolBarName) const; + + QtFullToolBarManagerPrivate(); + + QMap<QString, QList<QAction *> > categoryToActions; + QMap<QAction *, QString> actionToCategory; + + QSet<QAction *> allActions; + QMap<QAction *, QToolBar *> widgetActions; + QSet<QAction *> regularActions; + QMap<QAction *, QList<QToolBar *> > actionToToolBars; + + QMap<QToolBar *, QList<QAction *> > toolBars; + QMap<QToolBar *, QList<QAction *> > toolBarsWithSeparators; + QMap<QToolBar *, QList<QAction *> > defaultToolBars; + QList<QToolBar *> customToolBars; + + QMainWindow *theMainWindow; +}; + + + + +QtFullToolBarManagerPrivate::QtFullToolBarManagerPrivate() + : theMainWindow(0) +{ +} + +QToolBar *QtFullToolBarManagerPrivate::toolBarWidgetAction(QAction *action) const +{ + if (widgetActions.contains(action)) + return widgetActions.value(action); + return 0; +} + +void QtFullToolBarManagerPrivate::removeWidgetActions(const QMap<QToolBar *, QList<QAction *> > + &actions) +{ + QMap<QToolBar *, QList<QAction *> >::ConstIterator itToolBar = actions.constBegin(); + while (itToolBar != actions.constEnd()) { + QToolBar *toolBar = itToolBar.key(); + QList<QAction *> newActions = toolBars.value(toolBar); + QList<QAction *> newActionsWithSeparators = toolBarsWithSeparators.value(toolBar); + + QList<QAction *> removedActions; + QList<QAction *> actionList = itToolBar.value(); + QListIterator<QAction *> itAction(actionList); + while (itAction.hasNext()) { + QAction *action = itAction.next(); + if (newActions.contains(action) && toolBarWidgetAction(action) == toolBar) { + newActions.removeAll(action); + newActionsWithSeparators.removeAll(action); + removedActions.append(action); + } + } + + //emit q_ptr->toolBarChanged(toolBar, newActions); + + toolBars.insert(toolBar, newActions); + toolBarsWithSeparators.insert(toolBar, newActionsWithSeparators); + QListIterator<QAction *> itRemovedAction(removedActions); + while (itRemovedAction.hasNext()) { + QAction *oldAction = itRemovedAction.next(); + widgetActions.insert(oldAction, 0); + actionToToolBars[oldAction].removeAll(toolBar); + } + + ++itToolBar; + } +} + +void QtFullToolBarManagerPrivate::saveState(QDataStream &stream) const +{ + stream << (uchar) ToolBarMarker; + stream << defaultToolBars.size(); + QMap<QToolBar *, QList<QAction *> >::ConstIterator itToolBar = + defaultToolBars.constBegin(); + while (itToolBar != defaultToolBars.constEnd()) { + QToolBar *tb = itToolBar.key(); + if (tb->objectName().isEmpty()) { + qWarning("QtToolBarManager::saveState(): 'objectName' not set for QToolBar " + "%p '%s', using 'windowTitle' instead", + tb, tb->windowTitle().toLocal8Bit().constData()); + stream << tb->windowTitle(); + } else { + stream << tb->objectName(); + } + + stream << toolBars[tb].size(); + QListIterator<QAction *> itAction(toolBars[tb]); + while (itAction.hasNext()) { + QAction *action = itAction.next(); + + if (action) { + if (action->objectName().isEmpty()) { + qWarning("QtToolBarManager::saveState(): 'objectName' not set for QAction " + "%p '%s', using 'text' instead", + action, action->text().toLocal8Bit().constData()); + stream << action->text(); + } else { + stream << action->objectName(); + } + } else { + stream << QString(); + } + } + ++itToolBar; + } + + + stream << (uchar) CustomToolBarMarker; + stream << toolBars.size() - defaultToolBars.size(); + itToolBar = toolBars.constBegin(); + while (itToolBar != toolBars.constEnd()) { + QToolBar *tb = itToolBar.key(); + if (!defaultToolBars.contains(tb)) { + stream << tb->objectName(); + stream << tb->windowTitle(); + + stream << toolBars[tb].size(); + QListIterator<QAction *> itAction(toolBars[tb]); + while (itAction.hasNext()) { + QAction *action = itAction.next(); + + if (action) { + if (action->objectName().isEmpty()) { + qWarning("QtToolBarManager::saveState(): 'objectName' not set for QAction " + "%p '%s', using 'text' instead", + action, action->text().toLocal8Bit().constData()); + stream << action->text(); + } else { + stream << action->objectName(); + } + } else { + stream << QString(); + } + } + } + ++itToolBar; + } +} + +bool QtFullToolBarManagerPrivate::restoreState(QDataStream &stream) const +{ + uchar tmarker; + stream >> tmarker; + if (tmarker != ToolBarMarker) + return false; + + int toolBars; + stream >> toolBars; + for (int i = 0; i < toolBars; i++) { + QString objectName; + stream >> objectName; + int actionCount; + stream >> actionCount; + QList<QAction *> actions; + for (int j = 0; j < actionCount; j++) { + QString actionName; + stream >> actionName; + + if (actionName.isEmpty()) + actions.append(0); + else { + QAction *action = findAction(actionName); + if (action) + actions.append(action); + } + } + + QToolBar *toolBar = findDefaultToolBar(objectName); + if (toolBar) + q_ptr->setToolBar(toolBar, actions); + } + + + + uchar ctmarker; + stream >> ctmarker; + if (ctmarker != CustomToolBarMarker) + return false; + + QList<QToolBar *> oldCustomToolBars = customToolBars; + + stream >> toolBars; + for (int i = 0; i < toolBars; i++) { + QString objectName; + QString toolBarName; + int actionCount; + stream >> objectName; + stream >> toolBarName; + stream >> actionCount; + QList<QAction *> actions; + for (int j = 0; j < actionCount; j++) { + QString actionName; + stream >> actionName; + + if (actionName.isEmpty()) + actions.append(0); + else { + QAction *action = findAction(actionName); + if (action) + actions.append(action); + } + } + + QToolBar *toolBar = toolBarByName(objectName); + if (toolBar) { + toolBar->setWindowTitle(toolBarName); + oldCustomToolBars.removeAll(toolBar); + } + else + toolBar = q_ptr->createToolBar(toolBarName); + if (toolBar) { + toolBar->setObjectName(objectName); + q_ptr->setToolBar(toolBar, actions); + } + } + QListIterator<QToolBar *> itToolBar(oldCustomToolBars); + while (itToolBar.hasNext()) + q_ptr->deleteToolBar(itToolBar.next()); + return true; +} + +QToolBar *QtFullToolBarManagerPrivate::findDefaultToolBar(const QString &objectName) const +{ + QMap<QToolBar *, QList<QAction *> >::ConstIterator itToolBar = + defaultToolBars.constBegin(); + while (itToolBar != defaultToolBars.constEnd()) { + QToolBar *tb = itToolBar.key(); + if (tb->objectName() == objectName) + return tb; + + ++itToolBar; + } + + qWarning("QtToolBarManager::restoreState(): cannot find a QToolBar named " + "'%s', trying to match using 'windowTitle' instead.", + objectName.toLocal8Bit().constData()); + + itToolBar = defaultToolBars.constBegin(); + while (itToolBar != defaultToolBars.constEnd()) { + QToolBar *tb = itToolBar.key(); + if (tb->windowTitle() == objectName) + return tb; + + ++itToolBar; + } + qWarning("QtToolBarManager::restoreState(): cannot find a QToolBar with " + "matching 'windowTitle' (looking for '%s').", + objectName.toLocal8Bit().constData()); + + return 0; +} + +QAction *QtFullToolBarManagerPrivate::findAction(const QString &actionName) const +{ + QSetIterator<QAction *> itAction(allActions); + while (itAction.hasNext()) { + QAction *action = itAction.next(); + + if (action->objectName() == actionName) + return action; + } + qWarning("QtToolBarManager::restoreState(): cannot find a QAction named " + "'%s', trying to match using 'text' instead.", + actionName.toLocal8Bit().constData()); + + itAction.toFront(); + while (itAction.hasNext()) { + QAction *action = itAction.next(); + + if (action->text() == actionName) + return action; + } + qWarning("QtToolBarManager::restoreState(): cannot find a QAction with " + "matching 'text' (looking for '%s').", + actionName.toLocal8Bit().constData()); + + return 0; +} + +QToolBar *QtFullToolBarManagerPrivate::toolBarByName(const QString &toolBarName) const +{ + QMap<QToolBar *, QList<QAction *> >::ConstIterator itToolBar = toolBars.constBegin(); + while (itToolBar != toolBars.constEnd()) { + QToolBar *toolBar = itToolBar.key(); + if (toolBar->objectName() == toolBarName) + return toolBar; + + ++itToolBar; + } + return 0; +} + +////////////////////////////// + +QtFullToolBarManager::QtFullToolBarManager(QObject *parent) + : QObject(parent) +{ + d_ptr = new QtFullToolBarManagerPrivate; + d_ptr->q_ptr = this; +} + +QtFullToolBarManager::~QtFullToolBarManager() +{ + delete d_ptr; +} + +void QtFullToolBarManager::setMainWindow(QMainWindow *mainWindow) +{ + d_ptr->theMainWindow = mainWindow; +} + +QMainWindow *QtFullToolBarManager::mainWindow() const +{ + return d_ptr->theMainWindow; +} + +void QtFullToolBarManager::addCategory(const QString &category) +{ + d_ptr->categoryToActions[category] = QList<QAction *>(); +} + +bool QtFullToolBarManager::hasCategory(const QString &category) const +{ + return d_ptr->categoryToActions.contains(category); +} + +QStringList QtFullToolBarManager::categories() const +{ + return d_ptr->categoryToActions.keys(); +} + +QList<QAction *> QtFullToolBarManager::categoryActions(const QString &category) const +{ + QMap<QString, QList<QAction *> >::ConstIterator it = + d_ptr->categoryToActions.find(category); + if (it != d_ptr->categoryToActions.constEnd()) + return it.value(); + return QList<QAction *>(); +} + +QString QtFullToolBarManager::actionCategory(QAction *action) const +{ + QMap<QAction *, QString>::ConstIterator it = d_ptr->actionToCategory.find(action); + if (it != d_ptr->actionToCategory.constEnd()) + return it.value(); + return QString(); +} + +void QtFullToolBarManager::addAction(QAction *action, const QString &category) +{ + if (!action) + return; + if (action->isSeparator()) + return; + if (d_ptr->allActions.contains(action)) + return; + if (QLatin1String(action->metaObject()->className()) == + QLatin1String("QToolBarWidgetAction")) + d_ptr->widgetActions.insert(action, 0); + else + d_ptr->regularActions.insert(action); + d_ptr->allActions.insert(action); + d_ptr->categoryToActions[category].append(action); + d_ptr->actionToCategory[action] = category; +} + +void QtFullToolBarManager::removeAction(QAction *action) +{ + if (!d_ptr->allActions.contains(action)) + return; + + QList<QToolBar *> toolBars = d_ptr->actionToToolBars[action]; + QListIterator<QToolBar *> itToolBar(toolBars); + while (itToolBar.hasNext()) { + QToolBar *toolBar = itToolBar.next(); + + d_ptr->toolBars[toolBar].removeAll(action); + d_ptr->toolBarsWithSeparators[toolBar].removeAll(action); + + toolBar->removeAction(action); + } + + QMap<QToolBar *, QList<QAction *> >::ConstIterator itDefault = + d_ptr->defaultToolBars.constBegin(); + while (itDefault != d_ptr->defaultToolBars.constEnd()) { + if (itDefault.value().contains(action)) + d_ptr->defaultToolBars[itDefault.key()].removeAll(action); + + itDefault++; + } + + d_ptr->allActions.remove(action); + d_ptr->widgetActions.remove(action); + d_ptr->regularActions.remove(action); + d_ptr->actionToToolBars.remove(action); + + QString category = d_ptr->actionToCategory.value(action); + d_ptr->actionToCategory.remove(action); + d_ptr->categoryToActions[category].removeAll(action); + + if (d_ptr->categoryToActions[category].isEmpty()) + d_ptr->categoryToActions.remove(category); +} + +QSet<QAction *> QtFullToolBarManager::actions() const +{ + return d_ptr->allActions; +} + +bool QtFullToolBarManager::isWidgetAction(QAction *action) const +{ + if (d_ptr->widgetActions.contains(action)) + return true; + return false; +} + +void QtFullToolBarManager::addDefaultToolBar(QToolBar *toolBar, const QString &category) +{ + if (!toolBar) + return; + if (d_ptr->toolBars.contains(toolBar)) + return; + // could be also checked if toolBar belongs to mainwindow + + QList<QAction *> newActionsWithSeparators; + QList<QAction *> newActions; + QList<QAction *> actions = toolBar->actions(); + QListIterator<QAction *> itAction(actions); + while (itAction.hasNext()) { + QAction *action = itAction.next(); + addAction(action, category); + if (d_ptr->widgetActions.contains(action)) + d_ptr->widgetActions.insert(action, toolBar); + newActionsWithSeparators.append(action); + if (action->isSeparator()) + action = 0; + else + d_ptr->actionToToolBars[action].append(toolBar); + newActions.append(action); + } + d_ptr->defaultToolBars.insert(toolBar, newActions); + //Below could be done by call setToolBar() if we want signal emission here. + d_ptr->toolBars.insert(toolBar, newActions); + d_ptr->toolBarsWithSeparators.insert(toolBar, newActionsWithSeparators); +} + +void QtFullToolBarManager::removeDefaultToolBar(QToolBar *toolBar) +{ + if (!d_ptr->defaultToolBars.contains(toolBar)) + return; + + QList<QAction *> defaultActions = d_ptr->defaultToolBars[toolBar]; + setToolBar(toolBar, QList<QAction *>()); + QListIterator<QAction *> itAction(defaultActions); + while (itAction.hasNext()) + removeAction(itAction.next()); + + d_ptr->toolBars.remove(toolBar); + d_ptr->toolBarsWithSeparators.remove(toolBar); + d_ptr->defaultToolBars.remove(toolBar); + + itAction.toFront(); + while (itAction.hasNext()) { + QAction *action = itAction.next(); + if (action) + toolBar->insertAction(0, action); + else + toolBar->insertSeparator(0); + } +} + +QMap<QToolBar *, QList<QAction *> > QtFullToolBarManager::defaultToolBars() const +{ + return d_ptr->defaultToolBars; +} + +bool QtFullToolBarManager::isDefaultToolBar(QToolBar *toolBar) const +{ + if (d_ptr->defaultToolBars.contains(toolBar)) + return true; + return false; +} + +QToolBar *QtFullToolBarManager::createToolBar(const QString &toolBarName) +{ + if (!mainWindow()) + return 0; + QToolBar *toolBar = new QToolBar(toolBarName, mainWindow()); + int i = 1; + const QString prefix = QLatin1String("_Custom_Toolbar_"); + QString name = QString(QLatin1String("%1%2")).arg(prefix).arg(i); + while (d_ptr->toolBarByName(name)) + name = QString(QLatin1String("%1%2")).arg(prefix).arg(++i); + toolBar->setObjectName(name); + mainWindow()->addToolBar(toolBar); + d_ptr->customToolBars.append(toolBar); + d_ptr->toolBars.insert(toolBar, QList<QAction *>()); + d_ptr->toolBarsWithSeparators.insert(toolBar, QList<QAction *>()); + return toolBar; +} + +void QtFullToolBarManager::deleteToolBar(QToolBar *toolBar) +{ + if (!d_ptr->toolBars.contains(toolBar)) + return; + if (d_ptr->defaultToolBars.contains(toolBar)) + return; + setToolBar(toolBar, QList<QAction *>()); + d_ptr->customToolBars.removeAll(toolBar); + d_ptr->toolBars.remove(toolBar); + d_ptr->toolBarsWithSeparators.remove(toolBar); + delete toolBar; +} + +QList<QAction *> QtFullToolBarManager::actions(QToolBar *toolBar) const +{ + if (d_ptr->toolBars.contains(toolBar)) + return d_ptr->toolBars.value(toolBar); + return QList<QAction *>(); +} + +void QtFullToolBarManager::setToolBars(const QMap<QToolBar *, QList<QAction *> > &actions) +{ + QMap<QToolBar *, QList<QAction *> >::ConstIterator it = actions.constBegin(); + while (it != actions.constEnd()) { + setToolBar(it.key(), it.value()); + ++it; + } +} + +void QtFullToolBarManager::setToolBar(QToolBar *toolBar, const QList<QAction *> &actions) +{ + if (!toolBar) + return; + if (!d_ptr->toolBars.contains(toolBar)) + return; + + if (actions == d_ptr->toolBars[toolBar]) + return; + + QMap<QToolBar *, QList<QAction *> > toRemove; + + QList<QAction *> newActions; + QListIterator<QAction *> itAction(actions); + while (itAction.hasNext()) { + QAction *action = itAction.next(); + if (!action || (!newActions.contains(action) && d_ptr->allActions.contains(action))) + newActions.append(action); + + QToolBar *oldToolBar = d_ptr->toolBarWidgetAction(action); + if (oldToolBar && oldToolBar != toolBar) + toRemove[oldToolBar].append(action); + } + + d_ptr->removeWidgetActions(toRemove); + + QList<QAction *> oldActions = d_ptr->toolBarsWithSeparators.value(toolBar); + QListIterator<QAction *> itOldAction(oldActions); + while (itOldAction.hasNext()) { + QAction *action = itOldAction.next(); + /* + When addDefaultToolBar() separator actions could be checked if they are + inserted in other toolbars - if yes then create new one. + */ + if (d_ptr->toolBarWidgetAction(action) == toolBar) + d_ptr->widgetActions.insert(action, 0); + toolBar->removeAction(action); + if (action->isSeparator()) + delete action; + else + d_ptr->actionToToolBars[action].removeAll(toolBar); + } + + QList<QAction *> newActionsWithSeparators; + QListIterator<QAction *> itNewActions(newActions); + while (itNewActions.hasNext()) { + QAction *action = itNewActions.next(); + QAction *newAction = 0; + if (!action) + newAction = toolBar->insertSeparator(0); + if (d_ptr->allActions.contains(action)) { + toolBar->insertAction(0, action); + newAction = action; + d_ptr->actionToToolBars[action].append(toolBar); + } + newActionsWithSeparators.append(newAction); + } + d_ptr->toolBars.insert(toolBar, newActions); + d_ptr->toolBarsWithSeparators.insert(toolBar, newActionsWithSeparators); +} + +QMap<QToolBar *, QList<QAction *> > QtFullToolBarManager::toolBarsActions() const +{ + return d_ptr->toolBars; +} + +void QtFullToolBarManager::resetToolBar(QToolBar *toolBar) +{ + if (!isDefaultToolBar(toolBar)) + return; + setToolBar(toolBar, defaultToolBars().value(toolBar)); +} + +void QtFullToolBarManager::resetAllToolBars() +{ + setToolBars(defaultToolBars()); + QList<QToolBar *> oldCustomToolBars = d_ptr->customToolBars; + QListIterator<QToolBar *> itToolBar(oldCustomToolBars); + while (itToolBar.hasNext()) { + deleteToolBar(itToolBar.next()); + } +} + +QByteArray QtFullToolBarManager::saveState(int version) const +{ + QByteArray data; + QDataStream stream(&data, QIODevice::WriteOnly); + stream << QtFullToolBarManagerPrivate::VersionMarker; + stream << version; + d_ptr->saveState(stream); + return data; +} + +bool QtFullToolBarManager::restoreState(const QByteArray &state, int version) +{ + QByteArray sd = state; + QDataStream stream(&sd, QIODevice::ReadOnly); + int marker, v; + stream >> marker; + stream >> v; + if (marker != QtFullToolBarManagerPrivate::VersionMarker || v != version) + return false; + return d_ptr->restoreState(stream); +} + + +class QtToolBarManagerPrivate +{ + class QtToolBarManager *q_ptr; + Q_DECLARE_PUBLIC(QtToolBarManager) +public: + QtFullToolBarManager *manager; +}; + +////////////////////////////////////// + +/*! \class QtToolBarManager + \internal + \inmodule QtDesigner + \since 4.4 + + \brief The QtToolBarManager class provides toolbar management for + main windows. + + The QtToolBarManager is typically used with a QtToolBarDialog + which allows the user to customize the toolbars for a given main + window. The QtToolBarDialog class's functionality is controlled by + an instance of the QtToolBarManager class, and the main window is + specified using the QtToolBarManager class's setMainWindow() + function. + + The currently specified main window can be retrieved using the + mainWindow() function. + + The toolbar manager holds lists of the given main window's actions + and toolbars, and can add actions and toolbars to these + lists using the addAction() and addToolBar() functions + respectively. The actions can in addition be categorized + acccording to the user's preferences. The toolbar manager can also + remove custom actions and toolbars using the removeAction() and + removeToolBar() functions. + + Finally, the QtToolBarManager is able to save the customized state + of its toolbars using the saveState() function as well as restore + the toolbars' saved state using restoreState() function. + + \sa QtToolBarDialog +*/ + +/*! + Creates a toolbar manager with the given \a parent. +*/ +QtToolBarManager::QtToolBarManager(QObject *parent) + : QObject(parent) +{ + d_ptr = new QtToolBarManagerPrivate; + d_ptr->q_ptr = this; + + d_ptr->manager = new QtFullToolBarManager(this); +} + +/*! + Destroys the toolbar manager. +*/ +QtToolBarManager::~QtToolBarManager() +{ + delete d_ptr; +} + +/*! + Sets the main window upon which the toolbar manager operates, to + be the given \a mainWindow. +*/ +void QtToolBarManager::setMainWindow(QMainWindow *mainWindow) +{ + d_ptr->manager->setMainWindow(mainWindow); +} + +/*! + Returns the main window associated this toolbar manager. +*/ +QMainWindow *QtToolBarManager::mainWindow() const +{ + return d_ptr->manager->mainWindow(); +} + +/*! + Adds the given \a action to the given \a category in the manager's + list of actions. If the \a category doesn't exist it is created. + Only non separator actions can be added. If the action is already + added to the list, the function doesn't do anything. + + \sa removeAction() +*/ +void QtToolBarManager::addAction(QAction *action, const QString &category) +{ + d_ptr->manager->addAction(action, category); +} + +/*! + Removes the specified \a action from the manager's list of + actions. The action is also removed from all the registered + toolbars. If the specified \a action is the only action in its + category, that category is removed as well. + + \sa addAction() +*/ +void QtToolBarManager::removeAction(QAction *action) +{ + d_ptr->manager->removeAction(action); +} + +/*! + Adds the given \a toolBar to the manager's toolbar list. + + All the \a toolBar's actions are automatically added to the given + \a category in the manager's list of actions if they're not + already there. The manager remembers which toolbar the actions + belonged to, so, when the \a toolBar is removed, its actions will + be removed as well. + + Custom toolbars are created with the main window returned by + the mainWindow() function, as its parent. + + \sa removeToolBar() +*/ +void QtToolBarManager::addToolBar(QToolBar *toolBar, const QString &category) +{ + d_ptr->manager->addDefaultToolBar(toolBar, category); +} + +/*! + Removes the specified \a toolBar from the manager's list. All the + actions that existed in the specified \a toolBar when it was + added are removed as well. + + \sa addToolBar() +*/ +void QtToolBarManager::removeToolBar(QToolBar *toolBar) +{ + d_ptr->manager->removeDefaultToolBar(toolBar); +} + +/*! + Returns the manager's toolbar list. +*/ +QList<QToolBar *> QtToolBarManager::toolBars() const +{ + return d_ptr->manager->toolBarsActions().keys(); +} + +/* +void QtToolBarManager::resetToolBar(QToolBar *toolBar) +{ + d_ptr->manager->resetToolBar(toolBar); +} + +void QtToolBarManager::resetAllToolBars() +{ + d_ptr->manager->resetAllToolBars(); +} +*/ + +/*! + Saves the state of the toolbar manager's toolbars. The \a version + number is stored as part of the data. + + Identifies all the QToolBar and QAction objects by their object + name property. Ensure that this property is unique for each + QToolBar and QAction that you add using the QtToolBarManager. + + Returns an identifier for the state which can be passed along with + the version number to the restoreState() function to restore the + saved state. + + \sa restoreState() +*/ +QByteArray QtToolBarManager::saveState(int version) const +{ + return d_ptr->manager->saveState(version); +} + +/*! + Restores the saved state of the toolbar manager's toolbars. The + \a version number is compared with the version number of the + stored \a state. + + Returns true if the version numbers are matching and the toolbar + manager's state is restored; otherwise the toolbar manager's state + is left unchanged and the function returns false. + + Note that the state of the toolbar manager's toolbars should be + restored before restoring the state of the main window's toolbars + and dockwidgets using the QMainWindow::restoreState() function. In + that way the restoreState() function can create the custom + toolbars before the QMainWindow::restoreState() function restores + the custom toolbars' positions. + + \sa saveState() +*/ +bool QtToolBarManager::restoreState(const QByteArray &state, int version) +{ + return d_ptr->manager->restoreState(state, version); +} + +////////////////////// + +class ToolBarItem { +public: + ToolBarItem() : tb(0) {} + ToolBarItem(QToolBar *toolBar) : tb(toolBar) {} + ToolBarItem(QToolBar *toolBar, const QString &toolBarName) + : tb(toolBar), tbName(toolBarName) {} + ToolBarItem(const QString &toolBarName) : tb(0), tbName(toolBarName) {} + QToolBar *toolBar() const + { return tb; } + void setToolBar(QToolBar *toolBar) + { tb = toolBar; } + QString toolBarName() const + { return tbName; } + void setToolBarName(const QString &toolBarName) + { tbName = toolBarName; } +private: + QToolBar *tb; + QString tbName; +}; + +class QtToolBarDialogPrivate { + QtToolBarDialog *q_ptr; + Q_DECLARE_PUBLIC(QtToolBarDialog) +public: + QtToolBarDialogPrivate() + : toolBarManager(0), + currentAction(0), + currentToolBar(0) + { } + + ToolBarItem *createItem(QToolBar *toolBar); + ToolBarItem *createItem(const QString &toolBarName); + void deleteItem(ToolBarItem *item); + + void newClicked(); + void removeClicked(); + void defaultClicked(); + void okClicked(); + void applyClicked(); + void cancelClicked(); + void upClicked(); + void downClicked(); + void leftClicked(); + void rightClicked(); + void renameClicked(); + void toolBarRenamed(QListWidgetItem *item); + void currentActionChanged(QTreeWidgetItem *current); + void currentToolBarChanged(QListWidgetItem *current); + void currentToolBarActionChanged(QListWidgetItem *current); + + void removeToolBar(ToolBarItem *item); + bool isDefaultToolBar(ToolBarItem *item) const; + void setButtons(); + void clearOld(); + void fillNew(); + QtFullToolBarManager *toolBarManager; + QMap<ToolBarItem *, QList<QAction *> > currentState; + QMap<QToolBar *, ToolBarItem *> toolBarItems; + QSet<ToolBarItem *> createdItems; + QSet<ToolBarItem *> removedItems; + + QSet<ToolBarItem *> allToolBarItems; + + // static + QTreeWidgetItem *currentAction; + QMap<QAction *, QTreeWidgetItem *> actionToItem; + QMap<QTreeWidgetItem *, QAction *> itemToAction; + + // dynamic + ToolBarItem *currentToolBar; + QMap<ToolBarItem *, QListWidgetItem *> toolBarToItem; + QMap<QListWidgetItem *, ToolBarItem *> itemToToolBar; + + // dynamic + QMap<QAction *, QListWidgetItem *> actionToCurrentItem; + QMap<QListWidgetItem *, QAction *> currentItemToAction; + + QMap<QAction *, ToolBarItem *> widgetActionToToolBar; + QMap<ToolBarItem *, QSet<QAction *> > toolBarToWidgetActions; + + QString separatorText; + Ui::QtToolBarDialog ui; +}; + +ToolBarItem *QtToolBarDialogPrivate::createItem(QToolBar *toolBar) +{ + if (!toolBar) + return 0; + ToolBarItem *item = new ToolBarItem(toolBar, toolBar->windowTitle()); + allToolBarItems.insert(item); + return item; +} + +ToolBarItem *QtToolBarDialogPrivate::createItem(const QString &toolBarName) +{ + ToolBarItem *item = new ToolBarItem(toolBarName); + allToolBarItems.insert(item); + return item; +} + +void QtToolBarDialogPrivate::deleteItem(ToolBarItem *item) +{ + if (!allToolBarItems.contains(item)) + return; + allToolBarItems.remove(item); + delete item; +} + +void QtToolBarDialogPrivate::clearOld() +{ + ui.actionTree->clear(); + ui.toolBarList->clear(); + ui.currentToolBarList->clear(); + ui.removeButton->setEnabled(false); + ui.newButton->setEnabled(false); + ui.upButton->setEnabled(false); + ui.downButton->setEnabled(false); + ui.leftButton->setEnabled(false); + ui.rightButton->setEnabled(false); + + actionToItem.clear(); + itemToAction.clear(); + toolBarToItem.clear(); + itemToToolBar.clear(); + actionToCurrentItem.clear(); + currentItemToAction.clear(); + widgetActionToToolBar.clear(); + toolBarToWidgetActions.clear(); + + toolBarItems.clear(); + currentState.clear(); + createdItems.clear(); + removedItems.clear(); + QSetIterator<ToolBarItem *> itItem(allToolBarItems); + while (itItem.hasNext()) + delete itItem.next(); + allToolBarItems.clear(); + + currentToolBar = 0; + currentAction = 0; +} + +void QtToolBarDialogPrivate::fillNew() +{ + if (!toolBarManager) + return; + + QTreeWidgetItem *item = new QTreeWidgetItem(ui.actionTree); + item->setText(0, separatorText); + ui.actionTree->setCurrentItem(item); + currentAction = item; + actionToItem.insert(0, item); + itemToAction.insert(item, 0); + QStringList categories = toolBarManager->categories(); + QStringListIterator itCategory(categories); + while (itCategory.hasNext()) { + QString category = itCategory.next(); + QTreeWidgetItem *categoryItem = new QTreeWidgetItem(ui.actionTree); + categoryItem->setText(0, category); + QList<QAction *> actions = toolBarManager->categoryActions(category); + QListIterator<QAction *> itAction(actions); + while (itAction.hasNext()) { + QAction *action = itAction.next(); + item = new QTreeWidgetItem(categoryItem); + item->setText(0, action->text()); + item->setIcon(0, action->icon()); + item->setTextAlignment(0, Qt::AlignLeft | Qt::AlignVCenter | Qt::TextShowMnemonic); + actionToItem.insert(action, item); + itemToAction.insert(item, action); + if (toolBarManager->isWidgetAction(action)) { + item->setData(0, Qt::TextColorRole, QColor(Qt::blue)); + widgetActionToToolBar.insert(action, 0); + } + item->setFlags(item->flags() | Qt::ItemIsDragEnabled); + } + ui.actionTree->setItemExpanded(categoryItem, true); + } + //ui.actionTree->sortItems(0, Qt::AscendingOrder); + + QMap<QToolBar *, QList<QAction *> > toolBars = toolBarManager->toolBarsActions(); + QMap<QToolBar *, QList<QAction *> >::ConstIterator it = toolBars.constBegin(); + while (it != toolBars.constEnd()) { + QToolBar *toolBar = it.key(); + ToolBarItem *tbItem = createItem(toolBar); + toolBarItems.insert(toolBar, tbItem); + QListWidgetItem *item = new QListWidgetItem(toolBar->windowTitle(), + ui.toolBarList); + toolBarToItem.insert(tbItem, item); + itemToToolBar.insert(item, tbItem); + QList<QAction *> actions = it.value(); + QListIterator<QAction *> itAction(actions); + while (itAction.hasNext()) { + QAction *action = itAction.next(); + if (toolBarManager->isWidgetAction(action)) { + widgetActionToToolBar.insert(action, tbItem); + toolBarToWidgetActions[tbItem].insert(action); + } + } + currentState.insert(tbItem, actions); + if (it == toolBars.constBegin()) + ui.toolBarList->setCurrentItem(item); + if (isDefaultToolBar(tbItem)) + item->setData(Qt::TextColorRole, QColor(Qt::darkGreen)); + else + item->setFlags(item->flags() | Qt::ItemIsEditable); + + ++it; + } + ui.toolBarList->sortItems(); + setButtons(); +} + +bool QtToolBarDialogPrivate::isDefaultToolBar(ToolBarItem *item) const +{ + if (!item) + return false; + if (!item->toolBar()) + return false; + return toolBarManager->isDefaultToolBar(item->toolBar()); +} + +void QtToolBarDialogPrivate::setButtons() +{ + bool newEnabled = false; + bool removeEnabled = false; + bool renameEnabled = false; + bool upEnabled = false; + bool downEnabled = false; + bool leftEnabled = false; + bool rightEnabled = false; + + if (toolBarManager) { + newEnabled = true; + removeEnabled = !isDefaultToolBar(currentToolBar); + renameEnabled = removeEnabled; + QListWidgetItem *currentToolBarAction = ui.currentToolBarList->currentItem(); + if (currentToolBarAction) { + int row = ui.currentToolBarList->row(currentToolBarAction); + upEnabled = row > 0; + downEnabled = row < ui.currentToolBarList->count() - 1; + leftEnabled = true; + } + if (currentAction && currentToolBar) + rightEnabled = true; + } + ui.newButton->setEnabled(newEnabled); + ui.removeButton->setEnabled(removeEnabled); + ui.renameButton->setEnabled(renameEnabled); + ui.upButton->setEnabled(upEnabled); + ui.downButton->setEnabled(downEnabled); + ui.leftButton->setEnabled(leftEnabled); + ui.rightButton->setEnabled(rightEnabled); +} + +void QtToolBarDialogPrivate::newClicked() +{ + QString toolBarName = QtToolBarDialog::tr("Custom Toolbar"); // = QInputDialog::getString(); + // produce unique name + ToolBarItem *item = createItem(toolBarName); + currentState.insert(item, QList<QAction *>()); + createdItems.insert(item); + QListWidgetItem *i = new QListWidgetItem(toolBarName, ui.toolBarList); + i->setFlags(i->flags() | Qt::ItemIsEditable); + ui.toolBarList->setCurrentItem(i); + itemToToolBar.insert(i, item); + toolBarToItem.insert(item, i); + ui.toolBarList->sortItems(); + ui.toolBarList->setCurrentItem(i); + currentToolBarChanged(i); + renameClicked(); +} + +void QtToolBarDialogPrivate::removeToolBar(ToolBarItem *item) +{ + if (!item) + return; + if (item->toolBar() && toolBarManager->isDefaultToolBar(item->toolBar())) + return; + if (!toolBarToItem.contains(item)) + return; + QListWidgetItem *i = toolBarToItem.value(item); + bool wasCurrent = false; + if (i == ui.toolBarList->currentItem()) + wasCurrent = true; + int row = ui.toolBarList->row(i); + QMap<ToolBarItem *, QSet<QAction *> >::ConstIterator itToolBar = + toolBarToWidgetActions.find(item); + if (itToolBar != toolBarToWidgetActions.constEnd()) { + QSet<QAction *> actions = itToolBar.value(); + QSetIterator<QAction *> itAction(actions); + while (itAction.hasNext()) { + QAction *action = itAction.next(); + widgetActionToToolBar.insert(action, 0); + } + toolBarToWidgetActions.remove(item); + } + + currentState.remove(item); + createdItems.remove(item); + toolBarToItem.remove(item); + itemToToolBar.remove(i); + delete i; + if (item->toolBar()) + removedItems.insert(item); + else + deleteItem(item); + if (wasCurrent) { + if (row == ui.toolBarList->count()) + row--; + if (row < 0) + ; + else + ui.toolBarList->setCurrentRow(row); + } + setButtons(); +} + +void QtToolBarDialogPrivate::removeClicked() +{ + QListWidgetItem *i = ui.toolBarList->currentItem(); + if (!i) + return; + ToolBarItem *item = itemToToolBar.value(i); + removeToolBar(item); +} + +void QtToolBarDialogPrivate::defaultClicked() +{ + QMap<QToolBar *, QList<QAction *> > defaultToolBars = toolBarManager->defaultToolBars(); + QMap<QToolBar *, QList<QAction *> >::ConstIterator itToolBar = defaultToolBars.constBegin(); + while (itToolBar != defaultToolBars.constEnd()) { + QToolBar *toolBar = itToolBar.key(); + ToolBarItem *toolBarItem = toolBarItems.value(toolBar); + + if (toolBarToWidgetActions.contains(toolBarItem)) { + QSetIterator<QAction *> itAction(toolBarToWidgetActions.value(toolBarItem)); + while (itAction.hasNext()) + widgetActionToToolBar.insert(itAction.next(), 0); + toolBarToWidgetActions.remove(toolBarItem); + } + + currentState.remove(toolBarItem); + + QListIterator<QAction *> itAction(itToolBar.value()); + while (itAction.hasNext()) { + QAction *action = itAction.next(); + if (toolBarManager->isWidgetAction(action)) { + ToolBarItem *otherToolBar = widgetActionToToolBar.value(action); + if (otherToolBar) { + toolBarToWidgetActions[otherToolBar].remove(action); + currentState[otherToolBar].removeAll(action); + } + widgetActionToToolBar.insert(action, toolBarItem); + toolBarToWidgetActions[toolBarItem].insert(action); + } + } + currentState.insert(toolBarItem, itToolBar.value()); + + ++itToolBar; + } + currentToolBarChanged(toolBarToItem.value(currentToolBar)); + + QList<ToolBarItem *> toolBars = currentState.keys(); + QListIterator<ToolBarItem *> itTb(toolBars); + while (itTb.hasNext()) + removeToolBar(itTb.next()); +} + +void QtToolBarDialogPrivate::okClicked() +{ + applyClicked(); + q_ptr->accept(); +} + +void QtToolBarDialogPrivate::applyClicked() +{ + QMap<ToolBarItem *, QList<QAction *> > toolBars = currentState; + QMap<ToolBarItem *, QList<QAction *> >::ConstIterator itToolBar = toolBars.constBegin(); + while (itToolBar != toolBars.constEnd()) { + ToolBarItem *item = itToolBar.key(); + QToolBar *toolBar = item->toolBar(); + if (toolBar) { + toolBarManager->setToolBar(toolBar, itToolBar.value()); + toolBar->setWindowTitle(item->toolBarName()); + } + + ++itToolBar; + } + + QSet<ToolBarItem *> toRemove = removedItems; + QSetIterator<ToolBarItem *> itRemove(toRemove); + while (itRemove.hasNext()) { + ToolBarItem *item = itRemove.next(); + QToolBar *toolBar = item->toolBar(); + removedItems.remove(item); + currentState.remove(item); + deleteItem(item); + if (toolBar) + toolBarManager->deleteToolBar(toolBar); + } + + QSet<ToolBarItem *> toCreate = createdItems; + QSetIterator<ToolBarItem *> itCreate(toCreate); + while (itCreate.hasNext()) { + ToolBarItem *item = itCreate.next(); + QString toolBarName = item->toolBarName(); + createdItems.remove(item); + QList<QAction *> actions = currentState.value(item); + QToolBar *toolBar = toolBarManager->createToolBar(toolBarName); + item->setToolBar(toolBar); + toolBarManager->setToolBar(toolBar, actions); + } +} + +void QtToolBarDialogPrivate::upClicked() +{ + QListWidgetItem *currentToolBarAction = ui.currentToolBarList->currentItem(); + if (!currentToolBarAction) + return; + int row = ui.currentToolBarList->row(currentToolBarAction); + if (row == 0) + return; + ui.currentToolBarList->takeItem(row); + int newRow = row - 1; + ui.currentToolBarList->insertItem(newRow, currentToolBarAction); + QList<QAction *> actions = currentState.value(currentToolBar); + QAction *action = actions.at(row); + actions.removeAt(row); + actions.insert(newRow, action); + currentState.insert(currentToolBar, actions); + ui.currentToolBarList->setCurrentItem(currentToolBarAction); + setButtons(); +} + +void QtToolBarDialogPrivate::downClicked() +{ + QListWidgetItem *currentToolBarAction = ui.currentToolBarList->currentItem(); + if (!currentToolBarAction) + return; + int row = ui.currentToolBarList->row(currentToolBarAction); + if (row == ui.currentToolBarList->count() - 1) + return; + ui.currentToolBarList->takeItem(row); + int newRow = row + 1; + ui.currentToolBarList->insertItem(newRow, currentToolBarAction); + QList<QAction *> actions = currentState.value(currentToolBar); + QAction *action = actions.at(row); + actions.removeAt(row); + actions.insert(newRow, action); + currentState.insert(currentToolBar, actions); + ui.currentToolBarList->setCurrentItem(currentToolBarAction); + setButtons(); +} + +void QtToolBarDialogPrivate::leftClicked() +{ + QListWidgetItem *currentToolBarAction = ui.currentToolBarList->currentItem(); + if (!currentToolBarAction) + return; + int row = ui.currentToolBarList->row(currentToolBarAction); + currentState[currentToolBar].removeAt(row); + QAction *action = currentItemToAction.value(currentToolBarAction); + if (widgetActionToToolBar.contains(action)) { + ToolBarItem *item = widgetActionToToolBar.value(action); + if (item == currentToolBar) { // have to be + toolBarToWidgetActions[item].remove(action); + if (toolBarToWidgetActions[item].empty()) + toolBarToWidgetActions.remove(item); + } + widgetActionToToolBar.insert(action, 0); + } + if (action) + actionToCurrentItem.remove(action); + currentItemToAction.remove(currentToolBarAction); + delete currentToolBarAction; + if (row == ui.currentToolBarList->count()) + row--; + if (row >= 0) { + QListWidgetItem *item = ui.currentToolBarList->item(row); + ui.currentToolBarList->setCurrentItem(item); + } + setButtons(); +} + +void QtToolBarDialogPrivate::rightClicked() +{ + if (!currentAction) + return; + if (!currentToolBar) + return; + QListWidgetItem *currentToolBarAction = ui.currentToolBarList->currentItem(); + + QAction *action = itemToAction.value(currentAction); + QListWidgetItem *item = 0; + if (action) { + if (currentState[currentToolBar].contains(action)) { + item = actionToCurrentItem.value(action); + if (item == currentToolBarAction) + return; + int row = ui.currentToolBarList->row(item); + ui.currentToolBarList->takeItem(row); + currentState[currentToolBar].removeAt(row); + // only reorder here + } else { + item = new QListWidgetItem(action->text()); + item->setIcon(action->icon()); + item->setTextAlignment(Qt::AlignLeft | Qt::AlignVCenter | Qt::TextShowMnemonic); + currentItemToAction.insert(item, action); + actionToCurrentItem.insert(action, item); + if (widgetActionToToolBar.contains(action)) { + item->setData(Qt::TextColorRole, QColor(Qt::blue)); + ToolBarItem *toolBar = widgetActionToToolBar.value(action); + if (toolBar) { + currentState[toolBar].removeAll(action); + toolBarToWidgetActions[toolBar].remove(action); + if (toolBarToWidgetActions[toolBar].empty()) + toolBarToWidgetActions.remove(toolBar); + } + widgetActionToToolBar.insert(action, currentToolBar); + toolBarToWidgetActions[currentToolBar].insert(action); + } + } + } else { + item = new QListWidgetItem(separatorText); + currentItemToAction.insert(item, 0); + } + + int row = ui.currentToolBarList->count(); + if (currentToolBarAction) { + row = ui.currentToolBarList->row(currentToolBarAction) + 1; + } + ui.currentToolBarList->insertItem(row, item); + currentState[currentToolBar].insert(row, action); + ui.currentToolBarList->setCurrentItem(item); + + setButtons(); +} + +void QtToolBarDialogPrivate::renameClicked() +{ + if (!currentToolBar) + return; + + QListWidgetItem *item = toolBarToItem.value(currentToolBar); + ui.toolBarList->editItem(item); +} + +void QtToolBarDialogPrivate::toolBarRenamed(QListWidgetItem *item) +{ + if (!currentToolBar) + return; + + ToolBarItem *tbItem = itemToToolBar.value(item); + if (!tbItem) + return; + tbItem->setToolBarName(item->text()); + //ui.toolBarList->sortItems(); +} + +void QtToolBarDialogPrivate::currentActionChanged(QTreeWidgetItem *current) +{ + if (itemToAction.contains(current)) + currentAction = current; + else + currentAction = NULL; + setButtons(); +} + +void QtToolBarDialogPrivate::currentToolBarChanged(QListWidgetItem *current) +{ + currentToolBar = itemToToolBar.value(current); + ui.currentToolBarList->clear(); + actionToCurrentItem.clear(); + currentItemToAction.clear(); + setButtons(); + if (!currentToolBar) { + return; + } + QList<QAction *> actions = currentState.value(currentToolBar); + QListIterator<QAction *> itAction(actions); + QListWidgetItem *first = 0; + while (itAction.hasNext()) { + QAction *action = itAction.next(); + QString actionName = separatorText; + if (action) + actionName = action->text(); + QListWidgetItem *item = new QListWidgetItem(actionName, ui.currentToolBarList); + if (action) { + item->setIcon(action->icon()); + item->setTextAlignment(Qt::AlignLeft | Qt::AlignVCenter | Qt::TextShowMnemonic); + actionToCurrentItem.insert(action, item); + if (widgetActionToToolBar.contains(action)) + item->setData(Qt::TextColorRole, QColor(Qt::blue)); + } + currentItemToAction.insert(item, action); + if (!first) + first = item; + } + if (first) + ui.currentToolBarList->setCurrentItem(first); +} + +void QtToolBarDialogPrivate::currentToolBarActionChanged(QListWidgetItem *) +{ + setButtons(); +} + +void QtToolBarDialogPrivate::cancelClicked() +{ + // just nothing + q_ptr->reject(); +} + +////////////////////// +/* +class FeedbackItemDelegate : public QItemDelegate +{ + Q_OBJECT +public: + FeedbackItemDelegate(QObject *parent = 0) : QItemDelegate(parent) { } + + virtual void paint(QPainter *painter, const QStyleOptionViewItem &option, + const QModelIndex & index) const; + virtual QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const; +}; + +void FeedbackItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, + const QModelIndex &index) const +{ + if () + painter->save(); + QRect r = option.rect; + float yCentral = r.height() / 2.0; + float margin = 2.0; + float arrowWidth = 5.0; + float width = 20; + qDebug("rect: x %d, y %d, w %d, h %d", r.x(), r.y(), r.width(), r.height()); + QLineF lineBase(0.0 + margin, r.y() + yCentral, width - margin, r.y() + yCentral); + QLineF lineArrowLeft(width - margin - arrowWidth, r.y() + yCentral - arrowWidth, + width - margin, r.y() + yCentral); + QLineF lineArrowRight(width - margin - arrowWidth, r.y() + yCentral + arrowWidth, + width - margin, r.y() + yCentral); + painter->drawLine(lineBase); + painter->drawLine(lineArrowLeft); + painter->drawLine(lineArrowRight); + painter->translate(QPoint(width, 0)); + QItemDelegate::paint(painter, option, index); + painter->restore(); +} + +QSize FeedbackItemDelegate::sizeHint(const QStyleOptionViewItem &option, + const QModelIndex &index) const +{ + //return QItemDelegate::sizeHint(option, index); + QSize s = QItemDelegate::sizeHint(option, index); + s.setWidth(s.width() - 20); + return s; +} + +class QtToolBarListWidget : public QListWidget +{ + Q_OBJECT +public: + QtToolBarListWidget(QWidget *parent) : QListWidget(parent), actionDrag(false) {} + +protected: + void startDrag(Qt::DropActions supportedActions); + + void dragEnterEvent(QDragEnterEvent *event); + void dragMoveEvent(QDragMoveEvent *event); + void dragLeaveEvent(QDragLeaveEvent *); + void dropEvent(QDropEvent *event); + + void setDragAction(const QString *action) { actionName = action; } +private: + QPersistentModelIndex lastDropIndicator; + QString actionName; + bool actionDrag; +}; + +void QtToolBarListWidget::startDrag(Qt::DropActions supportedActions) +{ + QListWidgetItem *item = currentItem(); + if (item) { + actionName = QString(); + emit aboutToDrag(item); + if (!actionName.isEmpty()) { + QDrag *drag = new QDrag(this); + QMimeData *data = new QMimeData; + data->setData("action", actionName.toLocal8Bit().constData()); + drag->setMimeData(data); + drag->start(supportedActions); + } + } +} + +void QtToolBarListWidget::dragEnterEvent(QDragEnterEvent *event) +{ + const QMimeData *mime = event->mimeData(); + actionDrag = mime->hasFormat("action"); + if (actionDrag) + event->accept(); + else + event->ignore(); +} + +void QtToolBarListWidget::dragMoveEvent(QDragMoveEvent *event) +{ + event->ignore(); + if (actionDrag) { + QPoint p = event->pos(); + QListWidgetItem *item = itemAt(p); + Indicator indic = QtToolBarListWidget::None; + if (item) { + QRect rect = visualItemRect(item); + if (p.y() - rect.top() < rect.height() / 2) + indic = QtToolBarListWidget::Above; + else + indic = QtToolBarListWidget::Below; + } + setIndicator(item, indic); + event->accept(); + } +} + +void QtToolBarListWidget::dragLeaveEvent(QDragLeaveEvent *) +{ + if (actionDrag) { + actionDrag = false; + setIndicator(item, QtToolBarListWidget::None); + } +} + +void QtToolBarListWidget::dropEvent(QDropEvent *event) +{ + if (actionDrag) { + QListWidgetItem *item = indicatorItem(); + Indicator indic = indicator(); + QByteArray array = event->mimeData()->data("action"); + QDataStream stream(&array, QIODevice::ReadOnly); + QString action; + stream >> action; + emit actionDropped(action, item, ); + + actionDrag = false; + setIndicator(item, QtToolBarListWidget::None); + } +} +*/ + +/*! \class QtToolBarDialog + \internal + \inmodule QtDesigner + \since 4.4 + + \brief The QtToolBarDialog class provides a dialog for customizing + toolbars. + + QtToolBarDialog allows the user to customize the toolbars for a + given main window. + + \image qttoolbardialog.png + + The dialog lets the users add, rename and remove custom toolbars. + Note that built-in toolbars are marked with a green color, and + cannot be removed or renamed. + + The users can also add and remove actions from the toolbars. An + action can be added to many toolbars, but a toolbar can only + contain one instance of each action. Actions that contains a + widget are marked with a blue color in the list of actions, and + can only be added to one single toolbar. + + Finally, the users can add separators to the toolbars. + + The original toolbars can be restored by clicking the \gui + {Restore all} button. All custom toolbars will then be removed, + and all built-in toolbars will be restored to their original state. + + The QtToolBarDialog class's functionality is controlled by an + instance of the QtToolBarManager class, and the main window is + specified using the QtToolBarManager::setMainWindow() function. + + All you need to do to use QtToolBarDialog is to specify an + QtToolBarManager instance and call the QDialog::exec() slot: + + \snippet doc/src/snippets/code/tools_shared_qttoolbardialog_qttoolbardialog.cpp 0 + + \sa QtToolBarManager +*/ + +/*! + Creates a toolbar dialog with the given \a parent and the specified + window \a flags. +*/ +QtToolBarDialog::QtToolBarDialog(QWidget *parent, Qt::WindowFlags flags) + : QDialog(parent, flags) +{ + d_ptr = new QtToolBarDialogPrivate; + d_ptr->q_ptr = this; + d_ptr->ui.setupUi(this); + d_ptr->separatorText = tr("< S E P A R A T O R >"); + + d_ptr->ui.actionTree->setColumnCount(1); + d_ptr->ui.actionTree->setRootIsDecorated(false); + d_ptr->ui.actionTree->header()->hide(); + + d_ptr->ui.upButton->setIcon(QIcon(QLatin1String(":/trolltech/qttoolbardialog/images/up.png"))); + d_ptr->ui.downButton->setIcon(QIcon(QLatin1String(":/trolltech/qttoolbardialog/images/down.png"))); + d_ptr->ui.leftButton->setIcon(QIcon(QLatin1String(":/trolltech/qttoolbardialog/images/back.png"))); + d_ptr->ui.rightButton->setIcon(QIcon(QLatin1String(":/trolltech/qttoolbardialog/images/forward.png"))); + d_ptr->ui.newButton->setIcon(QIcon(QLatin1String(":/trolltech/qttoolbardialog/images/plus.png"))); + d_ptr->ui.removeButton->setIcon(QIcon(QLatin1String(":/trolltech/qttoolbardialog/images/minus.png"))); + + connect(d_ptr->ui.newButton, SIGNAL(clicked()), this, SLOT(newClicked())); + connect(d_ptr->ui.removeButton, SIGNAL(clicked()), this, SLOT(removeClicked())); + connect(d_ptr->ui.renameButton, SIGNAL(clicked()), this, SLOT(renameClicked())); + connect(d_ptr->ui.upButton, SIGNAL(clicked()), this, SLOT(upClicked())); + connect(d_ptr->ui.downButton, SIGNAL(clicked()), this, SLOT(downClicked())); + connect(d_ptr->ui.leftButton, SIGNAL(clicked()), this, SLOT(leftClicked())); + connect(d_ptr->ui.rightButton, SIGNAL(clicked()), this, SLOT(rightClicked())); + + connect(d_ptr->ui.buttonBox->button(QDialogButtonBox::RestoreDefaults), SIGNAL(clicked()), this, SLOT(defaultClicked())); + connect(d_ptr->ui.buttonBox->button(QDialogButtonBox::Ok), SIGNAL(clicked()), this, SLOT(okClicked())); + connect(d_ptr->ui.buttonBox->button(QDialogButtonBox::Apply), SIGNAL(clicked()), this, SLOT(applyClicked())); + connect(d_ptr->ui.buttonBox->button(QDialogButtonBox::Cancel), SIGNAL(clicked()), this, SLOT(cancelClicked())); + + connect(d_ptr->ui.actionTree, SIGNAL(currentItemChanged(QTreeWidgetItem *, QTreeWidgetItem *)), + this, SLOT(currentActionChanged(QTreeWidgetItem *))); + connect(d_ptr->ui.toolBarList, SIGNAL(currentItemChanged(QListWidgetItem *, QListWidgetItem *)), + this, SLOT(currentToolBarChanged(QListWidgetItem *))); + connect(d_ptr->ui.currentToolBarList, + SIGNAL(currentItemChanged(QListWidgetItem *, QListWidgetItem *)), + this, SLOT(currentToolBarActionChanged(QListWidgetItem *))); + + connect(d_ptr->ui.actionTree, SIGNAL(itemDoubleClicked(QTreeWidgetItem *, int)), + this, SLOT(rightClicked())); + connect(d_ptr->ui.currentToolBarList, SIGNAL(itemDoubleClicked(QListWidgetItem *)), + this, SLOT(leftClicked())); + connect(d_ptr->ui.toolBarList, SIGNAL(itemChanged(QListWidgetItem *)), + this, SLOT(toolBarRenamed(QListWidgetItem *))); +} + +/*! + Destroys the toolbar dialog. +*/ +QtToolBarDialog::~QtToolBarDialog() +{ + d_ptr->clearOld(); + delete d_ptr; +} + +/*! + Connects the toolbar dialog to the given \a toolBarManager. Then, + when exec() is called, the toolbar dialog will operate using the + given \a toolBarManager. +*/ +void QtToolBarDialog::setToolBarManager(QtToolBarManager *toolBarManager) +{ + if (d_ptr->toolBarManager == toolBarManager->d_ptr->manager) + return; + if (isVisible()) + d_ptr->clearOld(); + d_ptr->toolBarManager = toolBarManager->d_ptr->manager; + if (isVisible()) + d_ptr->fillNew(); +} + +/*! + \reimp +*/ +void QtToolBarDialog::showEvent(QShowEvent *event) +{ + if (!event->spontaneous()) + d_ptr->fillNew(); +} + +/*! + \reimp +*/ +void QtToolBarDialog::hideEvent(QHideEvent *event) +{ + if (!event->spontaneous()) + d_ptr->clearOld(); +} + +QT_END_NAMESPACE + +#include "moc_qttoolbardialog.cpp" +#include "qttoolbardialog.moc" diff --git a/tools/shared/qttoolbardialog/qttoolbardialog.h b/tools/shared/qttoolbardialog/qttoolbardialog.h new file mode 100644 index 0000000..879b437 --- /dev/null +++ b/tools/shared/qttoolbardialog/qttoolbardialog.h @@ -0,0 +1,138 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the tools applications of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of Qt Designer. This header +// file may change from version to version without notice, or even be removed. +// +// We mean it. +// + +#ifndef QTTOOLBARDIALOG_H +#define QTTOOLBARDIALOG_H + +#include <QtGui/QDialog> + +QT_BEGIN_NAMESPACE + +class QMainWindow; +class QAction; +class QToolBar; + +class QtToolBarManagerPrivate; + +class QtToolBarManager : public QObject +{ + Q_OBJECT +public: + + QtToolBarManager(QObject *parent = 0); + ~QtToolBarManager(); + + void setMainWindow(QMainWindow *mainWindow); + QMainWindow *mainWindow() const; + + void addAction(QAction *action, const QString &category); + void removeAction(QAction *action); + + void addToolBar(QToolBar *toolBar, const QString &category); + void removeToolBar(QToolBar *toolBar); + + QList<QToolBar *> toolBars() const; + + QByteArray saveState(int version = 0) const; + bool restoreState(const QByteArray &state, int version = 0); + +private: + + friend class QtToolBarDialog; + QtToolBarManagerPrivate *d_ptr; + Q_DECLARE_PRIVATE(QtToolBarManager) + Q_DISABLE_COPY(QtToolBarManager) +}; + +class QtToolBarDialogPrivate; + +class QtToolBarDialog : public QDialog +{ + Q_OBJECT +public: + + QtToolBarDialog(QWidget *parent = 0, Qt::WindowFlags flags = 0); + ~QtToolBarDialog(); + + void setToolBarManager(QtToolBarManager *toolBarManager); + +protected: + + void showEvent(QShowEvent *event); + void hideEvent(QHideEvent *event); + +private: + + QtToolBarDialogPrivate *d_ptr; + Q_DECLARE_PRIVATE(QtToolBarDialog) + Q_DISABLE_COPY(QtToolBarDialog) + + Q_PRIVATE_SLOT(d_func(), void newClicked()) + Q_PRIVATE_SLOT(d_func(), void removeClicked()) + Q_PRIVATE_SLOT(d_func(), void defaultClicked()) + Q_PRIVATE_SLOT(d_func(), void okClicked()) + Q_PRIVATE_SLOT(d_func(), void applyClicked()) + Q_PRIVATE_SLOT(d_func(), void cancelClicked()) + Q_PRIVATE_SLOT(d_func(), void upClicked()) + Q_PRIVATE_SLOT(d_func(), void downClicked()) + Q_PRIVATE_SLOT(d_func(), void leftClicked()) + Q_PRIVATE_SLOT(d_func(), void rightClicked()) + Q_PRIVATE_SLOT(d_func(), void renameClicked()) + Q_PRIVATE_SLOT(d_func(), void toolBarRenamed(QListWidgetItem *)) + Q_PRIVATE_SLOT(d_func(), void currentActionChanged(QTreeWidgetItem *)) + Q_PRIVATE_SLOT(d_func(), void currentToolBarChanged(QListWidgetItem *)) + Q_PRIVATE_SLOT(d_func(), void currentToolBarActionChanged(QListWidgetItem *)) +}; + +QT_END_NAMESPACE + +#endif diff --git a/tools/shared/qttoolbardialog/qttoolbardialog.pri b/tools/shared/qttoolbardialog/qttoolbardialog.pri new file mode 100644 index 0000000..5aca447 --- /dev/null +++ b/tools/shared/qttoolbardialog/qttoolbardialog.pri @@ -0,0 +1,6 @@ +INCLUDEPATH += $$PWD +DEPENDPATH += $$PWD +SOURCES += $$PWD/qttoolbardialog.cpp +HEADERS += $$PWD/qttoolbardialog.h +FORMS += $$PWD/qttoolbardialog.ui +RESOURCES += $$PWD/qttoolbardialog.qrc diff --git a/tools/shared/qttoolbardialog/qttoolbardialog.qrc b/tools/shared/qttoolbardialog/qttoolbardialog.qrc new file mode 100644 index 0000000..ce03366 --- /dev/null +++ b/tools/shared/qttoolbardialog/qttoolbardialog.qrc @@ -0,0 +1,10 @@ +<RCC version="1.0"> + <qresource prefix="/trolltech/qttoolbardialog"> + <file>images/up.png</file> + <file>images/down.png</file> + <file>images/forward.png</file> + <file>images/back.png</file> + <file>images/plus.png</file> + <file>images/minus.png</file> + </qresource> +</RCC> diff --git a/tools/shared/qttoolbardialog/qttoolbardialog.ui b/tools/shared/qttoolbardialog/qttoolbardialog.ui new file mode 100644 index 0000000..c4ad934 --- /dev/null +++ b/tools/shared/qttoolbardialog/qttoolbardialog.ui @@ -0,0 +1,207 @@ +<ui version="4.0" > + <class>QtToolBarDialog</class> + <widget class="QDialog" name="QtToolBarDialog" > + <property name="geometry" > + <rect> + <x>0</x> + <y>0</y> + <width>583</width> + <height>508</height> + </rect> + </property> + <property name="windowTitle" > + <string>Customize Toolbars</string> + </property> + <layout class="QGridLayout" > + <property name="margin" > + <number>8</number> + </property> + <property name="spacing" > + <number>6</number> + </property> + <item rowspan="3" row="1" column="0" > + <widget class="QTreeWidget" name="actionTree" > + <column> + <property name="text" > + <string>1</string> + </property> + </column> + </widget> + </item> + <item row="0" column="0" > + <widget class="QLabel" name="label" > + <property name="text" > + <string>Actions</string> + </property> + </widget> + </item> + <item row="0" column="1" colspan="2" > + <layout class="QHBoxLayout" > + <property name="spacing" > + <number>6</number> + </property> + <property name="margin" > + <number>0</number> + </property> + <item> + <widget class="QLabel" name="label_2" > + <property name="text" > + <string>Toolbars</string> + </property> + </widget> + </item> + <item> + <widget class="QToolButton" name="newButton" > + <property name="toolTip" > + <string>Add new toolbar</string> + </property> + <property name="text" > + <string>New</string> + </property> + </widget> + </item> + <item> + <widget class="QToolButton" name="removeButton" > + <property name="toolTip" > + <string>Remove selected toolbar</string> + </property> + <property name="text" > + <string>Remove</string> + </property> + </widget> + </item> + <item> + <widget class="QToolButton" name="renameButton" > + <property name="toolTip" > + <string>Rename toolbar</string> + </property> + <property name="text" > + <string>Rename</string> + </property> + </widget> + </item> + </layout> + </item> + <item row="3" column="1" > + <layout class="QVBoxLayout" > + <property name="spacing" > + <number>6</number> + </property> + <property name="margin" > + <number>0</number> + </property> + <item> + <widget class="QToolButton" name="upButton" > + <property name="sizePolicy" > + <sizepolicy vsizetype="Fixed" hsizetype="Minimum" > + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="toolTip" > + <string>Move action up</string> + </property> + <property name="text" > + <string>Up</string> + </property> + </widget> + </item> + <item> + <widget class="QToolButton" name="leftButton" > + <property name="sizePolicy" > + <sizepolicy vsizetype="Fixed" hsizetype="Minimum" > + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="toolTip" > + <string>Remove action from toolbar</string> + </property> + <property name="text" > + <string><-</string> + </property> + </widget> + </item> + <item> + <widget class="QToolButton" name="rightButton" > + <property name="sizePolicy" > + <sizepolicy vsizetype="Fixed" hsizetype="Minimum" > + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="toolTip" > + <string>Add action to toolbar</string> + </property> + <property name="text" > + <string>-></string> + </property> + </widget> + </item> + <item> + <widget class="QToolButton" name="downButton" > + <property name="sizePolicy" > + <sizepolicy vsizetype="Fixed" hsizetype="Minimum" > + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="toolTip" > + <string>Move action down</string> + </property> + <property name="text" > + <string>Down</string> + </property> + </widget> + </item> + <item> + <spacer> + <property name="orientation" > + <enum>Qt::Vertical</enum> + </property> + <property name="sizeHint" stdset="0" > + <size> + <width>29</width> + <height>16</height> + </size> + </property> + </spacer> + </item> + </layout> + </item> + <item row="3" column="2" > + <widget class="QListWidget" name="currentToolBarList" /> + </item> + <item row="2" column="1" colspan="2" > + <widget class="QLabel" name="label_3" > + <property name="text" > + <string>Current Toolbar Actions</string> + </property> + </widget> + </item> + <item row="1" column="1" colspan="2" > + <widget class="QListWidget" name="toolBarList" /> + </item> + <item row="5" column="0" colspan="3" > + <widget class="QDialogButtonBox" name="buttonBox" > + <property name="standardButtons" > + <set>QDialogButtonBox::Apply|QDialogButtonBox::Cancel|QDialogButtonBox::Ok|QDialogButtonBox::RestoreDefaults</set> + </property> + </widget> + </item> + </layout> + </widget> + <tabstops> + <tabstop>newButton</tabstop> + <tabstop>removeButton</tabstop> + <tabstop>renameButton</tabstop> + <tabstop>toolBarList</tabstop> + <tabstop>upButton</tabstop> + <tabstop>leftButton</tabstop> + <tabstop>rightButton</tabstop> + <tabstop>downButton</tabstop> + <tabstop>currentToolBarList</tabstop> + </tabstops> + <resources/> + <connections/> +</ui> |