00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025 #include "qxtitemdelegate.h"
00026 #include "qxtitemdelegate_p.h"
00027 #include <QApplication>
00028 #include <QTreeView>
00029 #include <QPainter>
00030 #include <QTimer>
00031
00032 static const int TOP_LEVEL_EXTENT = 2;
00033
00034 QxtItemDelegatePrivate::QxtItemDelegatePrivate() :
00035 textVisible(true),
00036 progressFormat("%1%"),
00037 elide(Qt::ElideMiddle),
00038 style(Qxt::NoDecoration)
00039 {
00040 }
00041
00042 void QxtItemDelegatePrivate::paintButton(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index, const QTreeView* view) const
00043 {
00044
00045 QStyleOptionButton buttonOption;
00046 buttonOption.state = option.state;
00047 #ifdef Q_WS_MAC
00048 buttonOption.state |= QStyle::State_Raised;
00049 #endif
00050 buttonOption.state &= ~QStyle::State_HasFocus;
00051 if (view->isExpanded(index))
00052 buttonOption.state |= QStyle::State_Sunken;
00053 buttonOption.rect = option.rect;
00054 buttonOption.palette = option.palette;
00055 buttonOption.features = QStyleOptionButton::None;
00056 view->style()->drawControl(QStyle::CE_PushButton, &buttonOption, painter, view);
00057
00058
00059 static const int i = 9;
00060 const QRect& r = option.rect;
00061 if (index.model()->hasChildren(index))
00062 {
00063 QStyleOption branchOption;
00064 branchOption.initFrom(view);
00065 if (branchOption.direction == Qt::LeftToRight)
00066 branchOption.rect = QRect(r.left() + i / 2, r.top() + (r.height() - i) / 2, i, i);
00067 else
00068 branchOption.rect = QRect(r.right() - i / 2 - i, r.top() + (r.height() - i) / 2, i, i);
00069 branchOption.palette = option.palette;
00070 branchOption.state = QStyle::State_Children;
00071 if (view->isExpanded(index))
00072 branchOption.state |= QStyle::State_Open;
00073 view->style()->drawPrimitive(QStyle::PE_IndicatorBranch, &branchOption, painter, view);
00074 }
00075
00076
00077 QRect textrect = QRect(r.left() + i * 2, r.top(), r.width() - ((5 * i) / 2), r.height());
00078 #if QT_VERSION < 0x040200
00079 QString text = QItemDelegate::elidedText(option.fontMetrics, textrect.width(), elide, index.data().toString());
00080 #else // QT_VERSION >= 0x040200
00081 QString text = option.fontMetrics.elidedText(index.data().toString(), elide, textrect.width());
00082 #endif // QT_VERSION
00083 view->style()->drawItemText(painter, textrect, Qt::AlignCenter, option.palette, view->isEnabled(), text);
00084 }
00085
00086 void QxtItemDelegatePrivate::paintMenu(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index, const QTreeView* view) const
00087 {
00088
00089 QStyleOptionMenuItem menuOption;
00090 menuOption.palette = view->palette();
00091 menuOption.fontMetrics = view->fontMetrics();
00092 menuOption.state = QStyle::State_None;
00093
00094
00095 if (view->isEnabled() && index.model()->flags(index) & Qt::ItemIsEnabled)
00096 menuOption.state |= QStyle::State_Enabled;
00097 else
00098 menuOption.palette.setCurrentColorGroup(QPalette::Disabled);
00099 menuOption.state |= QStyle::State_Selected;
00100 menuOption.state |= QStyle::State_Sunken;
00101 menuOption.state |= QStyle::State_HasFocus;
00102 menuOption.rect = option.rect;
00103 menuOption.text = index.data().toString();
00104 menuOption.icon = QIcon(index.data(Qt::DecorationRole).value<QPixmap>());
00105 view->style()->drawControl(QStyle::CE_MenuBarItem, &menuOption, painter, view);
00106
00107
00108 if (index.model()->hasChildren(index))
00109 {
00110 QStyle::PrimitiveElement arrow;
00111 if (view->isExpanded(index))
00112 arrow = QStyle::PE_IndicatorArrowUp;
00113 else
00114 arrow = QStyle::PE_IndicatorArrowDown;
00115 static const int i = 9;
00116 const QRect& r = option.rect;
00117 menuOption.rect = QRect(r.left() + i / 2, r.top() + (r.height() - i) / 2, i, i);
00118 view->style()->drawPrimitive(arrow, &menuOption, painter, view);
00119 }
00120 }
00121
00122 void QxtItemDelegatePrivate::paintProgress(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const
00123 {
00124 QVariant min = index.data(QxtItemDelegate::ProgressMinimumRole);
00125 QVariant max = index.data(QxtItemDelegate::ProgressMaximumRole);
00126
00127 QStyleOptionProgressBar opt;
00128 opt.minimum = (min.isValid() && min.canConvert(QVariant::Int)) ? min.toInt() : 0;
00129 opt.maximum = (max.isValid() && max.canConvert(QVariant::Int)) ? max.toInt() : 100;
00130 opt.progress = index.data(QxtItemDelegate::ProgressValueRole).toInt();
00131 opt.rect = option.rect;
00132 opt.textVisible = textVisible;
00133 opt.text = progressFormat.arg(opt.progress);
00134 QApplication::style()->drawControl(QStyle::CE_ProgressBar, &opt, painter, 0);
00135
00136 QWidget* viewport = dynamic_cast<QWidget*>(painter->device());
00137 if (viewport)
00138 {
00139 if (opt.minimum == 0 && opt.maximum == 0)
00140 {
00141 if (!updatedItems.contains(viewport))
00142 connect(viewport, SIGNAL(destroyed()), this, SLOT(viewDestroyed()));
00143 updatedItems.replace(viewport, index);
00144 }
00145 else
00146 {
00147 updatedItems.remove(viewport, index);
00148 if (!updatedItems.contains(viewport))
00149 disconnect(viewport, SIGNAL(destroyed()), this, SLOT(viewDestroyed()));
00150 }
00151 }
00152
00153 if (updatedItems.isEmpty())
00154 {
00155 if (updateTimer.isActive())
00156 updateTimer.stop();
00157 }
00158 else
00159 {
00160 if (!updateTimer.isActive())
00161 updateTimer.start(1000 / 25, const_cast<QxtItemDelegatePrivate*>(this));
00162 }
00163 }
00164
00165 void QxtItemDelegatePrivate::setCurrentEditor(QWidget* editor, const QModelIndex& index) const
00166 {
00167 currentEditor = editor;
00168 currentEdited = index;
00169 }
00170
00171 void QxtItemDelegatePrivate::timerEvent(QTimerEvent* event)
00172 {
00173 if (event->timerId() == updateTimer.timerId())
00174 {
00175 QMutableHashIterator<QWidget*, QPersistentModelIndex> it(updatedItems);
00176 while (it.hasNext())
00177 {
00178 it.next();
00179 if (!it.key())
00180 {
00181 it.remove();
00182 continue;
00183 }
00184
00185
00186 if (QAbstractItemView* view = qobject_cast<QAbstractItemView*>(it.key()->parentWidget()))
00187 view->update(it.value());
00188 else
00189 it.key()->update();
00190 }
00191 }
00192 }
00193
00194 void QxtItemDelegatePrivate::viewDestroyed()
00195 {
00196 QWidget* viewport = qobject_cast<QWidget*>(sender());
00197 if (viewport)
00198 {
00199 updatedItems.remove(viewport);
00200 }
00201 }
00202
00203 void QxtItemDelegatePrivate::closeEditor(QWidget* editor)
00204 {
00205 if (currentEdited.isValid() && editor == currentEditor)
00206 {
00207 setCurrentEditor(0, QModelIndex());
00208 emit qxt_p().editingFinished(currentEdited);
00209 }
00210 }
00211
00271 QxtItemDelegate::QxtItemDelegate(QObject* parent) : QItemDelegate(parent)
00272 {
00273 QXT_INIT_PRIVATE(QxtItemDelegate);
00274 connect(this, SIGNAL(closeEditor(QWidget*)), &qxt_d(), SLOT(closeEditor(QWidget*)));
00275 }
00276
00280 QxtItemDelegate::~QxtItemDelegate()
00281 {}
00282
00298 Qxt::DecorationStyle QxtItemDelegate::decorationStyle() const
00299 {
00300 return qxt_d().style;
00301 }
00302
00303 void QxtItemDelegate::setDecorationStyle(Qxt::DecorationStyle style)
00304 {
00305 qxt_d().style = style;
00306 }
00307
00319 Qt::TextElideMode QxtItemDelegate::elideMode() const
00320 {
00321 return qxt_d().elide;
00322 }
00323
00324 void QxtItemDelegate::setElideMode(Qt::TextElideMode mode)
00325 {
00326 qxt_d().elide = mode;
00327 }
00328
00343 QString QxtItemDelegate::progressTextFormat() const
00344 {
00345 return qxt_d().progressFormat;
00346 }
00347
00348 void QxtItemDelegate::setProgressTextFormat(const QString& format)
00349 {
00350 qxt_d().progressFormat = format;
00351 }
00352
00364 bool QxtItemDelegate::isProgressTextVisible() const
00365 {
00366 return qxt_d().textVisible;
00367 }
00368
00369 void QxtItemDelegate::setProgressTextVisible(bool visible)
00370 {
00371 qxt_d().textVisible = visible;
00372 }
00373
00377 QWidget* QxtItemDelegate::createEditor(QWidget* parent, const QStyleOptionViewItem& option, const QModelIndex& index) const
00378 {
00379 QWidget* editor = QItemDelegate::createEditor(parent, option, index);
00380 qxt_d().setCurrentEditor(editor, index);
00381 emit const_cast<QxtItemDelegate*>(this)->editingStarted(index);
00382 return editor;
00383 }
00384
00388 void QxtItemDelegate::setModelData(QWidget* editor, QAbstractItemModel* model, const QModelIndex& index) const
00389 {
00390 QItemDelegate::setModelData(editor, model, index);
00391 qxt_d().setCurrentEditor(0, QModelIndex());
00392 emit const_cast<QxtItemDelegate*>(this)->editingFinished(index);
00393 }
00394
00398 void QxtItemDelegate::paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const
00399 {
00400 const QAbstractItemModel* model = index.model();
00401 const QTreeView* tree = qobject_cast<QTreeView*>(parent());
00402 const bool topLevel = !index.parent().isValid();
00403
00404 if (tree && model && topLevel && qxt_d().style != Qxt::NoDecoration)
00405 {
00406 QStyleOptionViewItem opt;
00407 opt.QStyleOption::operator=(option);
00408 opt.showDecorationSelected = false;
00409
00410 QModelIndex valid = model->index(index.row(), 0);
00411 QModelIndex sibling = valid;
00412 while (sibling.isValid())
00413 {
00414 opt.rect |= tree->visualRect(sibling);
00415 sibling = sibling.sibling(sibling.row(), sibling.column() + 1);
00416 }
00417
00418 switch (qxt_d().style)
00419 {
00420 case Qxt::Buttonlike:
00421 qxt_d().paintButton(painter, opt, valid, tree);
00422 break;
00423 case Qxt::Menulike:
00424 qxt_d().paintMenu(painter, opt, valid, tree);
00425 break;
00426 default:
00427 qWarning("QxtItemDelegate::paint() unknown decoration style");
00428 QItemDelegate::paint(painter, opt, valid);
00429 break;
00430 }
00431 }
00432 else
00433 {
00434 QItemDelegate::paint(painter, option, index);
00435
00436 const QVariant data = index.data(ProgressValueRole);
00437 if (data.isValid() && data.canConvert(QVariant::Int))
00438 qxt_d().paintProgress(painter, option, index);
00439 }
00440 }
00441
00445 QSize QxtItemDelegate::sizeHint(const QStyleOptionViewItem& option, const QModelIndex& index) const
00446 {
00447
00448 QSize size = QItemDelegate::sizeHint(option, index);
00449 if (!index.parent().isValid())
00450 size += QSize(TOP_LEVEL_EXTENT, TOP_LEVEL_EXTENT);
00451 return size;
00452 }