1 /* ============================================================
2 *
3 * This file is a part of KDE project
4 *
5 *
6 * Date : 2009-07-05
7 * Description : A combobox delegate to display in image lists.
8 *
9 * Copyright (C) 2009 by Pieter Edelman <pieter dot edelman at gmx dot net>
10 *
11 * This program is free software; you can redistribute it
12 * and/or modify it under the terms of the GNU General
13 * Public License as published by the Free Software Foundation;
14 * either version 2, or (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
20 *
21 * ============================================================ */
22
23 #include "comboboxdelegate.h"
24
25 // Qt includes
26
27 #include <QApplication>
28 #include <QComboBox>
29 #include <QPaintEvent>
30 #include <QStyleOption>
31
32 // Local includes
33
34 #include "kipiplugins_debug.h"
35
36 namespace KIPIFlickrPlugin
37 {
38
ComboBoxDelegate(KPImagesList * const parent,const QMap<int,QString> & items)39 ComboBoxDelegate::ComboBoxDelegate(KPImagesList* const parent, const QMap<int, QString>& items)
40 : QAbstractItemDelegate(parent),
41 m_parent(parent),
42 m_items(items),
43 m_rowEdited(-1)
44 {
45 // Figure out the maximum width of a displayed item from the items list and
46 // save it in the m_size parameter.
47 QFontMetrics listFont = parent->fontMetrics();
48 m_size = QSize(0, listFont.height());
49 int tmpWidth = 0;
50 QMapIterator<int, QString> i(m_items);
51
52 while (i.hasNext())
53 {
54 i.next();
55 tmpWidth = listFont.width(i.value());
56
57 if (tmpWidth > m_size.width())
58 {
59 m_size.setWidth(tmpWidth);
60 }
61 }
62 }
63
startEditing(QTreeWidgetItem * item,int column)64 void ComboBoxDelegate::startEditing(QTreeWidgetItem* item, int column)
65 {
66 // Start editing the item. This is part of a hack to make sure the item text
67 // doesn't get painted whenever a combobox is drawn (otherwise the text can
68 // be seen around the edges of the combobox. This method breaks the OO
69 // paradigm.
70 m_rowEdited = m_parent->listView()->currentIndex().row();
71 item->setFlags(item->flags() | Qt::ItemIsEditable);
72 m_parent->listView()->editItem(item, column);
73 item->setFlags(item->flags() & ~Qt::ItemIsEditable);
74 }
75
paint(QPainter * painter,const QStyleOptionViewItem & option,const QModelIndex & index) const76 void ComboBoxDelegate::paint(QPainter* painter,
77 const QStyleOptionViewItem& option,
78 const QModelIndex& index) const
79 {
80 // Draw a panel item primitive element as background.
81 QStyle* const style = QApplication::style();
82 style->drawPrimitive(QStyle::PE_PanelItemViewItem, &option, painter);
83
84 // If the element that gets painted is not currently edited, the item text
85 // should be displayed.
86 // Note that this method to detect which item is edited is a horrible hack
87 // to work around the fact that there's no reliable way to detect if an item
88 // is being edited from the parameters (although the documentation suggests
89 // QStyle::State_Editing should be set in the option.flags parameter).
90 if (m_rowEdited != index.row())
91 {
92 // Get the currently selected index in the items list.
93 int currIndex = (index.data()).value<int>();
94
95 // PE: These values are found by trial and error. I don't have any idea
96 // if it's actually correct, but it seems to work across all themes.
97 QPalette::ColorRole textColor = QPalette::Text;
98
99 if (option.state & QStyle::State_Selected)
100 {
101 textColor = QPalette::HighlightedText;
102 }
103
104 // Draw the text.
105 style->drawItemText(painter, option.rect, option.displayAlignment,
106 option.palette, true, m_items[currIndex],
107 textColor);
108 }
109 }
110
sizeHint(const QStyleOptionViewItem &,const QModelIndex &) const111 QSize ComboBoxDelegate::sizeHint(const QStyleOptionViewItem&, const QModelIndex&) const
112 {
113 // Return the size based on the widest item in the items list.
114 return m_size;
115 }
116
createEditor(QWidget * parent,const QStyleOptionViewItem & option,const QModelIndex &) const117 QWidget* ComboBoxDelegate::createEditor(QWidget* parent, const QStyleOptionViewItem& option,
118 const QModelIndex&) const
119 {
120 // This method returns the widget that should be used to edit the current
121 // element, which is in this case a QComboBox with the items supplied by
122 // the user items list on construction.
123 QComboBox* const cb = new QComboBox(parent);
124 QMapIterator<int, QString> i(m_items);
125
126 while (i.hasNext())
127 {
128 i.next();
129 cb->addItem(i.value(), QVariant(i.key()));
130 }
131
132 // Set the geometry
133 cb->setGeometry(option.rect);
134
135 // If the index is changed, the editing should be finished and the editor
136 // destroyed.
137 connect(cb, SIGNAL(activated(int)),
138 this, SLOT(slotCommitAndCloseEditor(int)));
139
140 // To keep track of the item being edited, the m_rowEdited parameter should
141 // be reset when the editor is destroyed.
142 connect(cb, SIGNAL(destroyed(QObject*)),
143 this, SLOT(slotResetEditedState(QObject*)));
144
145 return cb;
146 }
147
setEditorData(QWidget * editor,const QModelIndex & index) const148 void ComboBoxDelegate::setEditorData(QWidget* editor, const QModelIndex& index) const
149 {
150 // Scroll the combobox to the current selected state on initialization.
151 QComboBox* const cb = qobject_cast<QComboBox*>(editor);
152
153 for (int i = 0; i < cb->count(); ++i)
154 {
155 if (cb->itemData(i).toInt() == index.data().toInt())
156 {
157 cb->setCurrentIndex(i);
158 }
159 }
160 }
161
setModelData(QWidget * editor,QAbstractItemModel * model,const QModelIndex & index) const162 void ComboBoxDelegate::setModelData(QWidget* editor, QAbstractItemModel* model,
163 const QModelIndex& index) const
164 {
165 // Write the data to the model when finishing has completed.
166 QComboBox* const cb = qobject_cast<QComboBox*>(editor);
167 int selected = cb->itemData(cb->currentIndex()).toInt();
168 model->setData(index, selected);
169 }
170
slotCommitAndCloseEditor(int)171 void ComboBoxDelegate::slotCommitAndCloseEditor(int)
172 {
173 // Emit the proper signals when editing has finished.
174 QComboBox* const editor = qobject_cast<QComboBox*>(sender());
175 emit commitData(editor);
176 emit closeEditor(editor);
177 }
178
slotResetEditedState(QObject *)179 void ComboBoxDelegate::slotResetEditedState(QObject*)
180 {
181 m_rowEdited = -1;
182 }
183
184 } // namespace KIPIFlickrPlugin
185