1 /*
2  *  SPDX-FileCopyrightText: 2014 Andreas Cord-Landwehr <cordlandwehr@kde.org>
3  *
4  *  SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
5  */
6 
7 #include "edgetypesdelegate.h"
8 #include "libgraphtheory/dialogs/edgetypeproperties.h"
9 #include "libgraphtheory/models/edgetypemodel.h"
10 #include <KColorButton>
11 #include <KLocalizedString>
12 #include <QAbstractItemView>
13 #include <QToolButton>
14 #include <QLabel>
15 #include <QLineEdit>
16 #include <QPainter>
17 #include <QPointer>
18 #include <QApplication>
19 #include <QDebug>
20 
21 using namespace GraphTheory;
22 
EdgeTypesDelegate(QAbstractItemView * parent)23 EdgeTypesDelegate::EdgeTypesDelegate(QAbstractItemView* parent)
24     : KWidgetItemDelegate(parent, parent->viewport())
25 {
26 
27 }
28 
~EdgeTypesDelegate()29 EdgeTypesDelegate::~EdgeTypesDelegate()
30 {
31 
32 }
33 
paint(QPainter * painter,const QStyleOptionViewItem & option,const QModelIndex & index) const34 void EdgeTypesDelegate::paint(QPainter* painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
35 {
36     if (!index.isValid()) {
37         return;
38     }
39     QApplication::style()->drawPrimitive(QStyle::PE_PanelItemViewItem, &option, painter, nullptr);
40 }
41 
sizeHint(const QStyleOptionViewItem & option,const QModelIndex & index) const42 QSize EdgeTypesDelegate::sizeHint(const QStyleOptionViewItem& option, const QModelIndex& index) const
43 {
44     Q_UNUSED(index);
45     int iconHeight = option.decorationSize.height() + (m_vPadding * 2); //icon height + padding either side
46     int textHeight = option.fontMetrics.height()*2 + (m_vPadding * 2) + 10; // text height * 2 + padding + some space between the lines
47     return QSize(-1,qMax(iconHeight, textHeight)); // any width, he view should give us the whole thing
48 }
49 
createItemWidgets(const QModelIndex & index) const50 QList< QWidget* > EdgeTypesDelegate::createItemWidgets(const QModelIndex &index) const
51 {
52     // items created by this method and added to the return-list will be
53     // deleted by KWidgetItemDelegate
54 
55     KColorButton *colorButton = new KColorButton(index.data(EdgeTypeModel::ColorRole).value<QColor>());
56     colorButton->setFlat(true);
57     QToolButton *direction = new QToolButton();
58     direction->setCheckable(true);
59     direction->setToolTip(i18n("Direction of edges of edge type."));
60     QLineEdit *title = new QLineEdit(index.data(EdgeTypeModel::TitleRole).toString());
61     title->setMinimumWidth(100);
62     QLabel *idLabel = new QLabel(index.data(EdgeTypeModel::IdRole).toString());
63     idLabel->setToolTip(i18n("Unique ID of edge type."));
64     QToolButton *propertiesButton = new QToolButton();
65     propertiesButton->setIcon(QIcon::fromTheme("document-properties"));
66 
67     connect(colorButton, &KColorButton::changed, this, &EdgeTypesDelegate::onColorChanged);
68     connect(colorButton, &KColorButton::pressed, this, &EdgeTypesDelegate::onColorDialogOpened);
69     connect(direction, &QToolButton::toggled, this, &EdgeTypesDelegate::onDirectionSwitched);
70     connect(title, &QLineEdit::textEdited, this, &EdgeTypesDelegate::onNameChanged);
71     connect(propertiesButton, &QToolButton::clicked, this, &EdgeTypesDelegate::showPropertiesDialog);
72 
73     return { colorButton, direction, title, idLabel, propertiesButton };
74 }
75 
updateItemWidgets(const QList<QWidget * > widgets,const QStyleOptionViewItem & option,const QPersistentModelIndex & index) const76 void EdgeTypesDelegate::updateItemWidgets(const QList< QWidget* > widgets, const QStyleOptionViewItem& option, const QPersistentModelIndex& index) const
77 {
78     // widgets:
79     // Color | Direction | Title | ID
80 
81     if (!index.isValid()) {
82         return;
83     }
84 
85     Q_ASSERT(widgets.size() == 5);
86 
87     KColorButton *colorButton = qobject_cast<KColorButton*>(widgets.at(0));
88     QToolButton *directionSwitch = qobject_cast<QToolButton*>(widgets.at(1));
89     QLineEdit *title = qobject_cast<QLineEdit*>(widgets.at(2));
90     QLabel *id = qobject_cast<QLabel*>(widgets.at(3));
91     QToolButton *propertiesButton = qobject_cast<QToolButton*>(widgets.at(4));
92 
93     Q_ASSERT(colorButton);
94     Q_ASSERT(directionSwitch);
95     Q_ASSERT(title);
96     Q_ASSERT(id);
97     Q_ASSERT(propertiesButton);
98 
99     colorButton->setColor(index.data(EdgeTypeModel::ColorRole).value<QColor>());
100     if (index.data(EdgeTypeModel::DirectionRole).toInt() == EdgeType::Unidirectional) {
101         directionSwitch->setIcon(QIcon::fromTheme("rocsunidirectional"));
102     } else {
103         directionSwitch->setIcon(QIcon::fromTheme("rocsbidirectional"));
104     }
105     title->setText(index.data(EdgeTypeModel::TitleRole).toString());
106     id->setText(index.data(EdgeTypeModel::IdRole).toString());
107 
108     QRect outerRect(0, 0, option.rect.width(), option.rect.height());
109     QRect contentRect = outerRect.adjusted(m_hPadding, m_vPadding, -m_hPadding, -m_vPadding);
110 
111     int colorButtonLeftMargin = contentRect.left();
112     int colorButtonTopMargin = (outerRect.height() - colorButton->height()) / 2;
113     colorButton->move(colorButtonLeftMargin, colorButtonTopMargin);
114 
115     int directionSwitchLeftMargin = colorButtonLeftMargin + + colorButton->width() + 10;
116     int directionSwitchTopMargin = (outerRect.height() - directionSwitch->height()) / 2;
117     directionSwitch->move(directionSwitchLeftMargin, directionSwitchTopMargin);
118 
119     int titleLeftMargin = directionSwitchLeftMargin + directionSwitch->width() + 10;
120     int titleTopMargin = (outerRect.height() - title->height()) / 2;
121     title->move(titleLeftMargin, titleTopMargin);
122 
123     // construct remaining from right to left
124     int propertiesLeftMargin = contentRect.right() - propertiesButton->width() - m_hPadding;
125     int propertiesTopMargin = (outerRect.height() - propertiesButton->height()) / 2;
126     propertiesButton->move(propertiesLeftMargin, propertiesTopMargin);
127 
128     int idLeftMargin = propertiesLeftMargin - id->width() - 10;
129     int idTopMargin = (outerRect.height() - id->height()) / 2;
130     id->move(idLeftMargin, idTopMargin);
131 
132 
133     // title gets remaining space
134     title->setFixedWidth(qMax(0, idLeftMargin - titleLeftMargin - 10));
135 }
136 
onColorChanged(const QColor & color)137 void EdgeTypesDelegate::onColorChanged(const QColor &color)
138 {
139     // use temporary stored index, since focusedIndex() does not return current index
140     // reason: the color dialog signal does not allow for correct index estimation
141     Q_EMIT colorChanged(m_workaroundColorButtonIndex, color);
142 }
143 
onColorDialogOpened()144 void EdgeTypesDelegate::onColorDialogOpened()
145 {
146     m_workaroundColorButtonIndex = focusedIndex();
147 }
148 
onNameChanged(const QString & name)149 void EdgeTypesDelegate::onNameChanged(const QString &name)
150 {
151     QModelIndex index = focusedIndex();
152     Q_EMIT nameChanged(index, name);
153 }
154 
onDirectionSwitched()155 void EdgeTypesDelegate::onDirectionSwitched()
156 {
157     QModelIndex index = focusedIndex();
158     EdgeType::Direction direction = static_cast<EdgeType::Direction>(
159         index.data(EdgeTypeModel::DirectionRole).toInt());
160 
161     const EdgeType::Direction newDirection = direction == EdgeType::Bidirectional
162         ? EdgeType::Unidirectional
163         : EdgeType::Bidirectional;
164 
165     Q_EMIT directionChanged(index, newDirection);
166 }
167 
showPropertiesDialog()168 void EdgeTypesDelegate::showPropertiesDialog()
169 {
170     QModelIndex index = focusedIndex();
171     EdgeType *type = qobject_cast<EdgeType*>(index.data(EdgeTypeModel::DataRole).value<QObject*>());
172     QPointer<EdgeTypeProperties> dialog = new EdgeTypeProperties(nullptr);
173     dialog->setType(type->self());
174     dialog->exec();
175     delete dialog;
176 }
177