File indexing completed on 2025-01-19 03:55:41
0001 /* ============================================================ 0002 * 0003 * This file is a part of digiKam project 0004 * https://www.digikam.org 0005 * 0006 * Date : 2009-07-05 0007 * Description : A combobox delegate to display in Web service image lists. 0008 * 0009 * SPDX-FileCopyrightText: 2009 by Pieter Edelman <pieter dot edelman at gmx dot net> 0010 * 0011 * SPDX-License-Identifier: GPL-2.0-or-later 0012 * 0013 * ============================================================ */ 0014 0015 #include "wscomboboxdelegate.h" 0016 0017 // Qt includes 0018 0019 #include <QApplication> 0020 #include <QComboBox> 0021 #include <QPaintEvent> 0022 #include <QStyleOption> 0023 0024 // Local includes 0025 0026 #include "digikam_debug.h" 0027 0028 namespace Digikam 0029 { 0030 0031 class Q_DECL_HIDDEN ComboBoxDelegate::Private 0032 { 0033 public: 0034 0035 explicit Private() 0036 : parent (nullptr), 0037 rowEdited(-1) 0038 { 0039 } 0040 0041 DItemsList* parent; 0042 QMap<int, QString> items; 0043 0044 /* 0045 * The row in the view that is currently being edited. Should be -1 to 0046 * indicate that no row is edited. 0047 */ 0048 int rowEdited; 0049 0050 QSize size; 0051 }; 0052 0053 ComboBoxDelegate::ComboBoxDelegate(DItemsList* const parent, const QMap<int, QString>& items) 0054 : QAbstractItemDelegate(parent), 0055 d (new Private) 0056 { 0057 d->parent = parent; 0058 d->items = items; 0059 0060 // Figure out the maximum width of a displayed item from the items list and 0061 // save it in the d->size parameter. 0062 0063 QFontMetrics listFont = parent->fontMetrics(); 0064 d->size = QSize(0, listFont.height()); 0065 int tmpWidth = 0; 0066 QMapIterator<int, QString> i(d->items); 0067 0068 while (i.hasNext()) 0069 { 0070 i.next(); 0071 0072 tmpWidth = listFont.horizontalAdvance(i.value()); 0073 0074 if (tmpWidth > d->size.width()) 0075 { 0076 d->size.setWidth(tmpWidth); 0077 } 0078 } 0079 } 0080 0081 ComboBoxDelegate::~ComboBoxDelegate() 0082 { 0083 delete d; 0084 } 0085 0086 void ComboBoxDelegate::startEditing(QTreeWidgetItem* item, int column) 0087 { 0088 // Start editing the item. This is part of a hack to make sure the item text 0089 // doesn't get painted whenever a combobox is drawn (otherwise the text can 0090 // be seen around the edges of the combobox. This method breaks the OO 0091 // paradigm. 0092 0093 d->rowEdited = d->parent->listView()->currentIndex().row(); 0094 item->setFlags(item->flags() | Qt::ItemIsEditable); 0095 d->parent->listView()->editItem(item, column); 0096 item->setFlags(item->flags() & ~Qt::ItemIsEditable); 0097 } 0098 0099 void ComboBoxDelegate::paint(QPainter* painter, 0100 const QStyleOptionViewItem& option, 0101 const QModelIndex& index) const 0102 { 0103 // Draw a panel item primitive element as background. 0104 0105 QStyle* const style = QApplication::style(); 0106 style->drawPrimitive(QStyle::PE_PanelItemViewItem, &option, painter); 0107 0108 // If the element that gets painted is not currently edited, the item text 0109 // should be displayed. 0110 // Note that this method to detect which item is edited is a horrible hack 0111 // to work around the fact that there's no reliable way to detect if an item 0112 // is being edited from the parameters (although the documentation suggests 0113 // QStyle::State_Editing should be set in the option.flags parameter). 0114 0115 if (d->rowEdited != index.row()) 0116 { 0117 // Get the currently selected index in the items list. 0118 0119 int currIndex = (index.data()).value<int>(); 0120 0121 // PE: These values are found by trial and error. I don't have any idea 0122 // if it's actually correct, but it seems to work across all themes. 0123 0124 QPalette::ColorRole textColor = QPalette::Text; 0125 0126 if (option.state & QStyle::State_Selected) 0127 { 0128 textColor = QPalette::HighlightedText; 0129 } 0130 0131 // Draw the text. 0132 0133 style->drawItemText(painter, option.rect, option.displayAlignment, 0134 option.palette, true, d->items[currIndex], 0135 textColor); 0136 } 0137 } 0138 0139 QSize ComboBoxDelegate::sizeHint(const QStyleOptionViewItem&, const QModelIndex&) const 0140 { 0141 // Return the size based on the widest item in the items list. 0142 0143 return d->size; 0144 } 0145 0146 QWidget* ComboBoxDelegate::createEditor(QWidget* parent, 0147 const QStyleOptionViewItem& option, 0148 const QModelIndex&) const 0149 { 0150 // This method returns the widget that should be used to edit the current 0151 // element, which is in this case a QComboBox with the items supplied by 0152 // the user items list on construction. 0153 0154 QComboBox* const cb = new QComboBox(parent); 0155 QMapIterator<int, QString> i(d->items); 0156 0157 while (i.hasNext()) 0158 { 0159 i.next(); 0160 cb->addItem(i.value(), QVariant(i.key())); 0161 } 0162 0163 // Set the geometry 0164 0165 cb->setGeometry(option.rect); 0166 0167 // If the index is changed, the editing should be finished and the editor 0168 // destroyed. 0169 0170 connect(cb, SIGNAL(activated(int)), 0171 this, SLOT(slotCommitAndCloseEditor(int))); 0172 0173 // To keep track of the item being edited, the d->rowEdited parameter should 0174 // be reset when the editor is destroyed. 0175 0176 connect(cb, SIGNAL(destroyed(QObject*)), 0177 this, SLOT(slotResetEditedState(QObject*))); 0178 0179 return cb; 0180 } 0181 0182 void ComboBoxDelegate::setEditorData(QWidget* editor, const QModelIndex& index) const 0183 { 0184 // Scroll the combobox to the current selected state on initialization. 0185 0186 QComboBox* const cb = qobject_cast<QComboBox*>(editor); 0187 0188 for (int i = 0 ; i < cb->count() ; ++i) 0189 { 0190 if (cb->itemData(i).toInt() == index.data().toInt()) 0191 { 0192 cb->setCurrentIndex(i); 0193 } 0194 } 0195 } 0196 0197 void ComboBoxDelegate::setModelData(QWidget* editor, 0198 QAbstractItemModel* model, 0199 const QModelIndex& index) const 0200 { 0201 // Write the data to the model when finishing has completed. 0202 0203 QComboBox* const cb = qobject_cast<QComboBox*>(editor); 0204 int selected = cb->itemData(cb->currentIndex()).toInt(); 0205 model->setData(index, selected); 0206 } 0207 0208 void ComboBoxDelegate::slotCommitAndCloseEditor(int) 0209 { 0210 // Emit the proper signals when editing has finished. 0211 0212 QComboBox* const editor = qobject_cast<QComboBox*>(sender()); 0213 Q_EMIT commitData(editor); 0214 Q_EMIT closeEditor(editor); 0215 } 0216 0217 void ComboBoxDelegate::slotResetEditedState(QObject*) 0218 { 0219 d->rowEdited = -1; 0220 } 0221 0222 } // namespace Digikam 0223 0224 #include "moc_wscomboboxdelegate.cpp"