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