1 /*
2 SPDX-License-Identifier: GPL-2.0-or-later
3 SPDX-FileCopyrightText: 2002-2021 Umbrello UML Modeller Authors <umbrello-devel@kde.org>
4 */
5
6 // own header
7 #include "selectoperationdialog.h"
8
9 // local includes
10 #include "attribute.h"
11 #include "classifier.h"
12 #include "debug_utils.h"
13 #include "linkwidget.h"
14 #include "operation.h"
15 #include "umlclassifierlistitemlist.h"
16 #include "umlscene.h"
17 #include "umlview.h"
18 #include "dialog_utils.h"
19
20 // kde includes
21 #include <klineedit.h>
22 #include <kcombobox.h>
23 #include <KLocalizedString>
24
25 // qt includes
26 #include <QCheckBox>
27 #include <QGridLayout>
28 #include <QGroupBox>
29 #include <QLabel>
30 #include <QPushButton>
31 #include <QRadioButton>
32 #include <QVBoxLayout>
33
caseInsensitiveLessThan(const UMLOperation * s1,const UMLOperation * s2)34 bool caseInsensitiveLessThan(const UMLOperation *s1, const UMLOperation *s2)
35 {
36 return s1->name().toLower() < s2->name().toLower();
37 }
38
39 /**
40 * Constructs a SelectOperationDialog instance.
41 *
42 * @param parent The parent to this instance.
43 * @param c The concept to get the operations from.
44 * @param enableAutoIncrement Flag to enable auto increment checkbox
45 */
SelectOperationDialog(UMLView * parent,UMLClassifier * c,LinkWidget * widget,bool enableAutoIncrement)46 SelectOperationDialog::SelectOperationDialog(UMLView *parent, UMLClassifier * c, LinkWidget *widget, bool enableAutoIncrement)
47 : SinglePageDialogBase(parent),
48 m_id(CUSTOM),
49 m_pView(parent),
50 m_classifier(c),
51 m_widget(widget),
52 m_enableAutoIncrement(enableAutoIncrement)
53 {
54 setCaption(i18n("Select Operation"));
55
56 QFrame *frame = new QFrame(this);
57 setMainWidget(frame);
58
59 QVBoxLayout * topLayout = new QVBoxLayout(frame);
60
61 m_pOpGB = new QGroupBox(i18n("Select Operation"));
62 topLayout->addWidget(m_pOpGB);
63
64 QGridLayout * mainLayout = new QGridLayout(m_pOpGB);
65 Dialog_Utils::makeLabeledEditField(mainLayout, 0,
66 m_pSeqL, i18n("Sequence number:"),
67 m_pSeqLE);
68
69 m_pOpAS = new QCheckBox(i18n("Auto increment:"), m_pOpGB);
70 mainLayout->addWidget(m_pOpAS, 0, 2);
71 connect(m_pOpAS, SIGNAL(toggled(bool)), this, SLOT(slotAutoIncrementChecked(bool)));
72 m_pOpAS->setEnabled(enableAutoIncrement);
73
74 m_pOpRB = new QLabel(i18n("Class operation:"), m_pOpGB);
75 mainLayout->addWidget(m_pOpRB, 1, 0);
76
77 m_pOpCB = new KComboBox(m_pOpGB);
78 #if QT_VERSION < 0x050000
79 m_pOpCB->setCompletionMode(KGlobalSettings::CompletionPopup);
80 #endif
81 m_pOpCB->setDuplicatesEnabled(false); // only allow one of each type in box
82 connect(m_pOpCB, SIGNAL(currentIndexChanged(int)), this, SLOT(slotIndexChanged(int)));
83 mainLayout->addWidget(m_pOpCB, 1, 1, 1, 2);
84
85 m_newOperationButton = new QPushButton(i18n("New Operation..."), m_pOpGB);
86 connect(m_newOperationButton, SIGNAL(clicked()), this, SLOT(slotNewOperation()));
87 mainLayout->addWidget(m_newOperationButton, 1, 3);
88
89 m_pCustomRB = new QLabel(i18n("Custom operation:"), m_pOpGB);
90 mainLayout->addWidget(m_pCustomRB, 2, 0);
91
92 m_pOpLE = new KLineEdit(m_pOpGB);
93 connect(m_pOpLE, SIGNAL(textChanged(QString)), this, SLOT(slotTextChanged(QString)));
94 mainLayout->addWidget(m_pOpLE, 2, 1, 1, 2);
95 setupOperationsList();
96 enableButtonOk(false);
97 setupDialog();
98 }
99
100 /**
101 * Standard destructor.
102 */
~SelectOperationDialog()103 SelectOperationDialog::~SelectOperationDialog()
104 {
105 }
106
107 /**
108 * Returns the operation to display.
109 *
110 * @return The operation to display.
111 */
getOpText()112 QString SelectOperationDialog::getOpText()
113 {
114 if (m_pOpLE->text().isEmpty())
115 return m_pOpCB->currentText();
116 else
117 return m_pOpLE->text();
118 }
119
120 /**
121 * Return whether the user selected a class operation
122 * or a custom operation.
123 *
124 * @return True if user selected a class operation,
125 * false if user selected a custom operation
126 */
isClassOp() const127 bool SelectOperationDialog::isClassOp() const
128 {
129 return (m_id == OP);
130 }
131
132 /**
133 * Set the custom operation text.
134 *
135 * @param op The operation to set as the custom operation.
136 */
setCustomOp(const QString & op)137 void SelectOperationDialog::setCustomOp(const QString &op)
138 {
139 m_pOpLE->setText(op);
140 slotTextChanged(op);
141 }
142
143 /**
144 * Handle auto increment checkbox click.
145 */
slotAutoIncrementChecked(bool state)146 void SelectOperationDialog::slotAutoIncrementChecked(bool state)
147 {
148 m_enableAutoIncrement = state;
149 if (state && m_pSeqLE->text().isEmpty())
150 m_pSeqLE->setText(m_pView->umlScene()->autoIncrementSequenceValue());
151 }
152
153 /**
154 * Handle new operation button click.
155 */
slotNewOperation()156 void SelectOperationDialog::slotNewOperation()
157 {
158 UMLOperation *op = m_classifier->createOperation();
159 if (!op)
160 return;
161 setupOperationsList();
162 setClassOp(op->toString(Uml::SignatureType::SigNoVis));
163 enableButtonOk(true);
164 }
165
166 /**
167 * Handle combox box changes.
168 */
slotIndexChanged(int index)169 void SelectOperationDialog::slotIndexChanged(int index)
170 {
171 if (index != -1) {
172 m_pOpLE->setText(QString());
173 m_id = OP;
174 enableButtonOk(true);
175 }
176 if (m_pOpCB->currentText().isEmpty()) {
177 enableButtonOk(false);
178 }
179 }
180
181 /**
182 * Handle custom line edit changes.
183 */
slotTextChanged(const QString & text)184 void SelectOperationDialog::slotTextChanged(const QString &text)
185 {
186 if (text.isEmpty()) {
187 enableButtonOk(false);
188 }
189 else {
190 m_pOpCB->setCurrentIndex(-1);
191 m_id = CUSTOM;
192 enableButtonOk(true);
193 }
194 }
195
196 /**
197 * Set the class operation text.
198 *
199 * @param op The operation to set as the class operation.
200 * @return false if no such operation exists.
201 */
setClassOp(const QString & op)202 bool SelectOperationDialog::setClassOp(const QString &op)
203 {
204 for (int i = 1; i != m_pOpCB->count(); ++i) {
205 if (m_pOpCB->itemText(i) == op) {
206 m_pOpCB->setCurrentIndex(i);
207 slotIndexChanged(i);
208 return true;
209 }
210 }
211 return false;
212 }
213
214 /**
215 * Setup dialog operations list.
216 */
setupOperationsList()217 void SelectOperationDialog::setupOperationsList()
218 {
219 m_pOpCB->clear();
220 UMLOperationList list = m_classifier->getOpList(true);
221 if (list.count() > 0)
222 m_pOpCB->insertItem(0, QString());
223 qSort(list.begin(), list.end(), caseInsensitiveLessThan);
224 foreach(UMLOperation * obj, list) {
225 QString s = obj->toString(Uml::SignatureType::SigNoVis);
226 m_pOpCB->insertItem(list.count(), s);
227 m_pOpCB->completionObject()->addItem(s);
228 }
229 m_nOpCount = m_classifier->operations();
230 }
231
232 /**
233 * Returns the sequence number for the operation.
234 *
235 * @return Returns the sequence number for the operation.
236 */
getSeqNumber()237 QString SelectOperationDialog::getSeqNumber()
238 {
239 return m_pSeqLE->text();
240 }
241
242 /**
243 * Set the sequence number text.
244 *
245 * @param num The number to set the sequence to.
246 */
setSeqNumber(const QString & num)247 void SelectOperationDialog::setSeqNumber(const QString &num)
248 {
249 m_pSeqLE->setText(num);
250 }
251
252 /**
253 * Set the flag for auto increment sequence numbering.
254 * @param state the state of the flag
255 */
setAutoIncrementSequence(bool state)256 void SelectOperationDialog::setAutoIncrementSequence(bool state)
257 {
258 m_pOpAS->setChecked(state);
259 }
260
261 /**
262 * Return the flag for auto increment sequence numbering.
263 */
autoIncrementSequence()264 bool SelectOperationDialog::autoIncrementSequence()
265 {
266 return m_pOpAS->isChecked();
267 }
268
269 /**
270 * internal setup function
271 */
setupDialog()272 void SelectOperationDialog::setupDialog()
273 {
274 if (m_enableAutoIncrement && m_pView->umlScene()->autoIncrementSequence()) {
275 setAutoIncrementSequence(true);
276 setSeqNumber(m_pView->umlScene()->autoIncrementSequenceValue());
277 } else
278 setSeqNumber(m_widget->sequenceNumber());
279
280 if (m_widget->operation() == 0) {
281 setCustomOp(m_widget->lwOperationText());
282 } else {
283 setClassOp(m_widget->lwOperationText());
284 }
285 }
286
287 /**
288 * apply changes to the related instamces
289 * @return true - success
290 * @return false - failure
291 */
apply()292 bool SelectOperationDialog::apply()
293 {
294 QString opText = getOpText();
295 if (isClassOp()) {
296 Model_Utils::OpDescriptor od;
297 Model_Utils::Parse_Status st = Model_Utils::parseOperation(opText, od, m_classifier);
298 if (st == Model_Utils::PS_OK) {
299 UMLClassifierList selfAndAncestors = m_classifier->findSuperClassConcepts();
300 selfAndAncestors.prepend(m_classifier);
301 UMLOperation *op = 0;
302 foreach (UMLClassifier *cl, selfAndAncestors) {
303 op = cl->findOperation(od.m_name, od.m_args);
304 if (op) {
305 break;
306 }
307 }
308 if (!op) {
309 // The op does not yet exist. Create a new one.
310 UMLObject *o = m_classifier->createOperation(od.m_name, 0, &od.m_args);
311 op = o->asUMLOperation();
312 }
313 if (od.m_pReturnType) {
314 op->setType(od.m_pReturnType);
315 }
316
317 m_widget->setOperation(op);
318 opText.clear();
319 } else {
320 m_widget->setOperation(0);
321 }
322 } else {
323 m_widget->setOperation(0);
324 }
325 m_widget->setSequenceNumber(getSeqNumber());
326 m_widget->setOperationText(opText);
327 if (m_enableAutoIncrement) {
328 m_pView->umlScene()->setAutoIncrementSequence(autoIncrementSequence());
329 }
330 return true;
331 }
332