1 /*
2     This file is part of the Okteta Kasten module, made within the KDE community.
3 
4     SPDX-FileCopyrightText: 2009 Friedrich W. H. Kossebau <kossebau@kde.org>
5 
6     SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
7 */
8 
9 #include "addresscombobox_p.hpp"
10 #include "addresscombobox.hpp"
11 
12 // KF
13 #include <KLocalizedString>
14 // Qt
15 #include <QLayout>
16 #include <QLineEdit>
17 #include <QAbstractItemView>
18 
19 /*
20    Problem: what to do if the format is changed for which the current string is not valid?
21    Solution: we always convert the string to the new format, so there is never such a situation
22  */
23 
24 namespace Okteta {
25 
formatStrings()26 static const QStringList& formatStrings()
27 {
28     static QStringList list = QStringList {
29 //         i18nc("@item:inlistbox guessing the format of the address by the input",      "Auto"),
30         i18nc("@item:inlistbox coding of offset in the hexadecimal format", "Hex"),
31         i18nc("@item:inlistbox coding of offset in the decimal format",     "Dec"),
32         i18nc("@item:inlistbox coding of offset in the expression format",  "Expr"),
33     };
34     return list;
35 }
36 
init()37 void AddressComboBoxPrivate::init()
38 {
39     Q_Q(AddressComboBox);
40 
41     auto* baseLayout = new QHBoxLayout(q);
42     baseLayout->setContentsMargins(0, 0, 0, 0);
43     baseLayout->setSpacing(0);
44 
45     mFormatComboBox = new KComboBox(q);
46     mFormatComboBox->addItems(formatStrings());
47     QObject::connect(mFormatComboBox, QOverload<int>::of(&QComboBox::activated),
48                      q, [&](int index) { onFormatChanged(index); });
49 
50     mValueComboBox = new KComboBox(q);
51     mValueComboBox->setEditable(true);
52     mValueComboBox->setMaxCount(10);
53     mValueComboBox->setInsertPolicy(QComboBox::NoInsert);
54     mValueComboBox->setDuplicatesEnabled(false);
55     q->setFocusProxy(mValueComboBox);
56     QObject::connect(mValueComboBox->lineEdit(), &QLineEdit::textEdited,
57                      q, [&](const QString& text) { onValueEdited(text); });
58     QAbstractItemView* formatComboBoxListView = mFormatComboBox->view();
59     QObject::connect(formatComboBoxListView, &QAbstractItemView::activated,
60                      mValueComboBox, QOverload<>::of(&KComboBox::setFocus));
61     // TODO: is a workaround for Qt 4.5.1 which doesn't emit activated() for mouse clicks
62     QObject::connect(formatComboBoxListView, &QAbstractItemView::pressed,
63                      mValueComboBox, QOverload<>::of(&KComboBox::setFocus));
64     mValidator = new AddressValidator(mValueComboBox, AddressValidator::HexadecimalCoding);
65     const AddressValidator::Coding coding =
66         static_cast<AddressValidator::Coding>(mFormatComboBox->currentIndex());
67     mValidator->setCodec(coding);
68     mValueComboBox->setValidator(mValidator);
69     QObject::connect(mValueComboBox, QOverload<int>::of(&QComboBox::activated),
70                      q, [&](int index) { onValueActivated(index); });
71     baseLayout->addWidget(mFormatComboBox);
72     baseLayout->addWidget(mValueComboBox, 1);
73     QWidget::setTabOrder(mFormatComboBox, mValueComboBox);
74 }
75 
rememberCurrentAddress()76 void AddressComboBoxPrivate::rememberCurrentAddress()
77 {
78     // don't insert same value multiple times in a row
79     if (mValueComboBox->itemText(0) != mValueComboBox->currentText()) {
80         mValueComboBox->insertItem(-1, mValueComboBox->currentText(), mFormatComboBox->currentIndex());
81     }
82 }
83 
onFormatChanged(int formatIndex)84 void AddressComboBoxPrivate::onFormatChanged(int formatIndex)
85 {
86     Q_Q(AddressComboBox);
87 
88     const QString currentValueText = mValueComboBox->currentText();
89     const bool isCurrentValueTextEmpty = currentValueText.isEmpty();
90 
91     AddressValidator::AddressType addressType;
92     Address address;
93     if (isCurrentValueTextEmpty) {
94         address = -1;
95         addressType = mAddressType;
96     } else {
97         address = mValidator->toAddress(currentValueText, &addressType);
98     }
99 
100     mValidator->setCodec(static_cast<AddressValidator::Coding>(formatIndex));
101 
102     if (!isCurrentValueTextEmpty) {
103         const QString convertedValueText = mValidator->toString(address, addressType);
104         mValueComboBox->setEditText(convertedValueText);
105     }
106 
107     if (mAddressType != addressType) {
108         mAddressType = addressType;
109         emit q->addressTypeChanged(mAddressType);
110     }
111     emit q->formatChanged(formatIndex);
112 }
113 
onValueEdited(const QString & value)114 void AddressComboBoxPrivate::onValueEdited(const QString& value)
115 {
116     Q_Q(AddressComboBox);
117 
118     AddressValidator::AddressType addressType;
119     const Address address = mValidator->toAddress(value, &addressType);
120 
121     if (mAddressType != addressType) {
122         mAddressType = addressType;
123         emit q->addressTypeChanged(mAddressType);
124     }
125     emit q->addressChanged(address);
126 }
127 
onValueActivated(int index)128 void AddressComboBoxPrivate::onValueActivated(int index)
129 {
130     Q_Q(AddressComboBox);
131 
132     if (index != -1) {
133         const int oldFormatIndex = mFormatComboBox->currentIndex();
134         const int itemFormatIndex = mValueComboBox->itemData(index).toInt();
135 
136         const bool isOtherFormat = (oldFormatIndex != itemFormatIndex);
137         if (isOtherFormat) {
138             mFormatComboBox->setCurrentIndex(itemFormatIndex);
139             mValidator->setCodec(static_cast<AddressValidator::Coding>(itemFormatIndex));
140 
141         }
142         const QString currentValueText = mValueComboBox->currentText();
143 
144         AddressValidator::AddressType addressType;
145         const Address address = mValidator->toAddress(currentValueText, &addressType);
146 
147         if (mAddressType != addressType) {
148             mAddressType = addressType;
149             emit q->addressTypeChanged(mAddressType);
150         }
151         emit q->addressChanged(address);
152         if (isOtherFormat) {
153             emit q->formatChanged(itemFormatIndex);
154         }
155     }
156 }
157 
158 }
159