1 /***************************************************************************
2  * SPDX-FileCopyrightText: 2021 S. MANKOWSKI stephane@mankowski.fr
3  * SPDX-FileCopyrightText: 2021 G. DE BURE support@mankowski.fr
4  * SPDX-License-Identifier: GPL-3.0-or-later
5  ***************************************************************************/
6 /** @file
7  * This file is a query creator for skrooge
8  *
9  * @author Stephane MANKOWSKI / Guillaume DE BURE
10  */
11 #include "skgpredicatcreator.h"
12 
13 #include <qapplication.h>
14 #include <qcheckbox.h>
15 #include <qdom.h>
16 #include <qlineedit.h>
17 #include <qtablewidget.h>
18 
19 #include "skgcalculatoredit.h"
20 #include "skgcombobox.h"
21 #include "skgdateedit.h"
22 #include "skgdocument.h"
23 #include "skgmainpanel.h"
24 #include "skgruleobject.h"
25 #include "skgservices.h"
26 
SKGPredicatCreator(QWidget * iParent,SKGDocument * document,const QString & attribute,bool iModeUpdate,const QStringList & iListAtt)27 SKGPredicatCreator::SKGPredicatCreator(QWidget* iParent, SKGDocument* document, const QString& attribute, bool iModeUpdate, const QStringList& iListAtt)
28     : QWidget(iParent), m_updateMode(iModeUpdate), m_kValue1(nullptr), m_kValue2(nullptr), m_kAttributes(nullptr)
29 {
30     SKGServices::AttributeType attType = SKGServices::TEXT;
31     if (document != nullptr) {
32         attType = document->getAttributeType(attribute);
33     }
34 
35     // Build
36     this->setAutoFillBackground(true);
37     this->resize(491, 25);
38     auto horizontalLayout = new QHBoxLayout(this);
39     horizontalLayout->setSpacing(2);
40     horizontalLayout->setMargin(0);
41     horizontalLayout->setObjectName(QStringLiteral("horizontalLayout"));
42     m_kOperator = new SKGComboBox(this);
43     m_kOperator->setObjectName(QStringLiteral("kOperator"));
44     m_kOperator->setSizeAdjustPolicy(KComboBox::AdjustToContentsOnFirstShow);
45     QSizePolicy newSizePolicy2(QSizePolicy::Fixed, QSizePolicy::Fixed);
46     newSizePolicy2.setHorizontalStretch(0);
47     newSizePolicy2.setVerticalStretch(0);
48     newSizePolicy2.setHeightForWidth(m_kOperator->sizePolicy().hasHeightForWidth());
49     m_kOperator->setSizePolicy(newSizePolicy2);
50 
51     horizontalLayout->addWidget(m_kOperator);
52     int nbAtt = iListAtt.count();
53     if (nbAtt != 0) {
54         m_kAttributes = new SKGComboBox(this);
55         if (m_kAttributes != nullptr) {
56             m_kAttributes->setObjectName(QStringLiteral("kAttributes"));
57             m_kAttributes->setMinimumSize(QSize(100, 0));
58             m_kAttributes->setEditable(false);
59             QSizePolicy newSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
60             newSizePolicy.setHorizontalStretch(0);
61             newSizePolicy.setVerticalStretch(0);
62             newSizePolicy.setHeightForWidth(m_kAttributes->sizePolicy().hasHeightForWidth());
63             m_kAttributes->setSizePolicy(newSizePolicy);
64 
65             horizontalLayout->addWidget(m_kAttributes);
66 
67             for (const auto& att : qAsConst(iListAtt)) {
68                 if (document != nullptr) {
69                     m_kAttributes->addItem(document->getIcon(att), document->getDisplay(att), att);
70                 }
71             }
72         }
73     }
74     if (attType == SKGServices::TEXT) {
75         auto cmbVal1 = new SKGComboBox(this);
76         if (cmbVal1 != nullptr) {
77             cmbVal1->setObjectName(QStringLiteral("cmbVal1"));
78             cmbVal1->setMinimumSize(QSize(100, 0));
79             cmbVal1->setEditable(true);
80             QSizePolicy newSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
81             newSizePolicy.setHorizontalStretch(0);
82             newSizePolicy.setVerticalStretch(0);
83             newSizePolicy.setHeightForWidth(cmbVal1->sizePolicy().hasHeightForWidth());
84             cmbVal1->setSizePolicy(newSizePolicy);
85             cmbVal1->lineEdit()->setPlaceholderText(i18n("Value"));
86 
87             horizontalLayout->addWidget(cmbVal1);
88             m_kValue1 = cmbVal1;
89         }
90         auto cmbVal2 = new SKGComboBox(this);
91         if (cmbVal2 != nullptr) {
92             cmbVal2->setObjectName(QStringLiteral("cmbVal2"));
93             cmbVal2->setMinimumSize(QSize(100, 0));
94             cmbVal2->setEditable(true);
95             QSizePolicy newSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
96             newSizePolicy.setHorizontalStretch(0);
97             newSizePolicy.setVerticalStretch(0);
98             newSizePolicy.setHeightForWidth(cmbVal2->sizePolicy().hasHeightForWidth());
99             cmbVal2->setSizePolicy(newSizePolicy);
100             cmbVal2->lineEdit()->setPlaceholderText(i18n("Value"));
101 
102             horizontalLayout->addWidget(cmbVal2);
103             m_kValue2 = cmbVal2;
104         }
105 
106         if (document != nullptr) {
107             QString realTable = QStringLiteral("operation");
108             QString realAtt = attribute;
109             QString realCond = QLatin1String("");
110             if (attribute == QStringLiteral("t_REALCATEGORY")) {
111                 realTable = QStringLiteral("category");
112                 realAtt = QStringLiteral("t_fullname");
113             } else if (attribute == QStringLiteral("t_BANK")) {
114                 realTable = QStringLiteral("bank");
115                 realAtt = QStringLiteral("t_name");
116             } else if (attribute == QStringLiteral("t_ACCOUNT") || attribute == QStringLiteral("t_TOACCOUNT")) {
117                 realTable = QStringLiteral("account");
118                 realAtt = QStringLiteral("t_name");
119             } else if (attribute == QStringLiteral("t_UNIT")) {
120                 realTable = QStringLiteral("unit");
121                 realAtt = QStringLiteral("t_name");
122             } else if (attribute == QStringLiteral("t_REALCOMMENT")) {
123                 realTable = QStringLiteral("suboperation");
124                 realAtt = QStringLiteral("t_comment");
125             } else if (attribute == QStringLiteral("t_REALREFUND")) {
126                 realTable = QStringLiteral("refund");
127                 realAtt = QStringLiteral("t_name");
128             } else if (attribute == QStringLiteral("t_PAYEE")) {
129                 realTable = QStringLiteral("payee");
130                 realAtt = QStringLiteral("t_name");
131             } else if (attribute.startsWith(QLatin1String("p_"))) {
132                 realTable = QStringLiteral("parameters");
133                 realAtt = QStringLiteral("t_value");
134                 realCond = "t_name='" % attribute.right(attribute.length() - 2) % '\'';
135             }
136             SKGMainPanel::fillWithDistinctValue(QList<QWidget*>() << cmbVal1 << cmbVal2, document, realTable, realAtt, realCond);
137         }
138     } else  if (attType == SKGServices::INTEGER || attType == SKGServices::FLOAT) {
139         auto cmbVal1 = new SKGCalculatorEdit(this);
140         if (cmbVal1 != nullptr) {
141             cmbVal1->setObjectName(QStringLiteral("cmbVal1"));
142             cmbVal1->setMode(SKGCalculatorEdit::EXPRESSION);
143             cmbVal1->setMinimumSize(QSize(100, 0));
144 
145             horizontalLayout->addWidget(cmbVal1);
146             m_kValue1 = cmbVal1;
147         }
148         auto cmbVal2 = new SKGCalculatorEdit(this);
149         if (cmbVal2 != nullptr) {
150             cmbVal2->setObjectName(QStringLiteral("cmbVal2"));
151             cmbVal2->setMode(SKGCalculatorEdit::EXPRESSION);
152             cmbVal2->setMinimumSize(QSize(100, 0));
153 
154             horizontalLayout->addWidget(cmbVal2);
155             m_kValue2 = cmbVal2;
156         }
157     } else  if (attType == SKGServices::DATE) {
158         if (iModeUpdate) {
159             auto cmbVal1 = new SKGComboBox(this);
160             if (cmbVal1 != nullptr) {
161                 cmbVal1->setObjectName(QStringLiteral("cmbVal1"));
162                 cmbVal1->setMinimumSize(QSize(100, 0));
163                 cmbVal1->setEditable(true);
164                 QSizePolicy newSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
165                 newSizePolicy.setHorizontalStretch(0);
166                 newSizePolicy.setVerticalStretch(0);
167                 newSizePolicy.setHeightForWidth(cmbVal1->sizePolicy().hasHeightForWidth());
168                 cmbVal1->setSizePolicy(newSizePolicy);
169                 cmbVal1->lineEdit()->setPlaceholderText(i18n("Value"));
170 
171                 horizontalLayout->addWidget(cmbVal1);
172                 m_kValue1 = cmbVal1;
173             }
174 
175             auto cmbVal2 = new SKGComboBox(this);
176             if (cmbVal2 != nullptr) {
177                 cmbVal2->setObjectName(QStringLiteral("cmbVal2"));
178                 cmbVal2->setMinimumSize(QSize(100, 0));
179                 cmbVal2->setEditable(false);
180                 QSizePolicy newSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
181                 newSizePolicy.setHorizontalStretch(0);
182                 newSizePolicy.setVerticalStretch(0);
183                 newSizePolicy.setHeightForWidth(cmbVal2->sizePolicy().hasHeightForWidth());
184                 cmbVal2->setSizePolicy(newSizePolicy);
185                 cmbVal2->addItems(QStringList() << QStringLiteral("YYYYMMDD") << QStringLiteral("MMDDYYYY") << QStringLiteral("DDMMYYYY")
186                                   << QStringLiteral("MM-DD-YY") << QStringLiteral("DD-MM-YY") << QStringLiteral("MM-DD-YYYY") << QStringLiteral("DD-MM-YYYY") << QStringLiteral("YYYY-MM-DD"));
187                 horizontalLayout->addWidget(cmbVal2);
188                 m_kValue2 = cmbVal2;
189             }
190         } else {
191             auto cmbVal1 = new SKGDateEdit(this);
192             if (cmbVal1 != nullptr) {
193                 cmbVal1->setObjectName(QStringLiteral("cmbVal1"));
194                 cmbVal1->setMinimumSize(QSize(100, 0));
195 
196                 horizontalLayout->addWidget(cmbVal1);
197                 m_kValue1 = cmbVal1;
198             }
199 
200             auto cmbVal2 = new SKGDateEdit(this);
201             if (cmbVal2 != nullptr) {
202                 cmbVal2->setObjectName(QStringLiteral("cmbVal2"));
203                 cmbVal2->setMinimumSize(QSize(100, 0));
204 
205                 horizontalLayout->addWidget(cmbVal2);
206                 m_kValue2 = cmbVal2;
207             }
208         }
209     } else  if (attType == SKGServices::BOOL || attType == SKGServices::TRISTATE) {
210         auto cmbVal1 = new QCheckBox(this);
211         if (cmbVal1 != nullptr) {
212             cmbVal1->setObjectName(QStringLiteral("cmbVal1"));
213             cmbVal1->setMinimumSize(QSize(100, 0));
214             cmbVal1->setTristate(attType == SKGServices::TRISTATE);
215 
216             horizontalLayout->addWidget(cmbVal1);
217             m_kValue1 = cmbVal1;
218         }
219     }
220 
221     // Fill combo boxes
222     m_kOperator->clear();
223     m_kOperator->addItem(QLatin1String(""), "");
224 
225     if (m_kValue1 != nullptr) {
226         m_kValue1->installEventFilter(this);
227     }
228     if (m_kValue2 != nullptr) {
229         m_kValue2->installEventFilter(this);
230     }
231     if (m_kOperator != nullptr) {
232         m_kOperator->installEventFilter(this);
233     }
234     if (m_kAttributes != nullptr) {
235         m_kAttributes->installEventFilter(this);
236     }
237 
238     QStringList listOps = SKGRuleObject::getListOfOperators(attType, m_updateMode ? SKGRuleObject::UPDATE : SKGRuleObject::SEARCH);
239     int nb = listOps.count();
240     if (iModeUpdate && attribute == QStringLiteral("t_REALCATEGORY") && nb > 1) {
241         nb = 1;    // TODO(Stephane MANKOWSKI): unblock t_REALCATEGORY
242     }
243     for (int i = 0; i < nb; ++i) {
244         const QString& op = listOps.at(i);
245         QString nlsOp = SKGRuleObject::getDisplayForOperator(op,
246                         i18nc("Default value", "..."),
247                         i18nc("Default value", "..."),
248                         i18nc("Noun, an item's attribute", "attribute"));
249         if (m_kOperator != nullptr) {
250             m_kOperator->addItem(nlsOp, op);
251         }
252     }
253 
254     connect(m_kOperator, static_cast<void (SKGComboBox::*)(const QString&)>(&SKGComboBox::currentTextChanged), this, &SKGPredicatCreator::onOperatorChanged);
255     onOperatorChanged();
256 }
257 
~SKGPredicatCreator()258 SKGPredicatCreator::~SKGPredicatCreator()
259 {
260     m_kOperator = nullptr;
261     m_kValue1 = nullptr;
262     m_kValue2 = nullptr;
263     m_kAttributes = nullptr;
264 }
265 
eventFilter(QObject * iObject,QEvent * iEvent)266 bool SKGPredicatCreator::eventFilter(QObject* iObject, QEvent* iEvent)
267 {
268     Q_UNUSED(iObject)
269     if ((iEvent != nullptr) && (iEvent->type() == QEvent::FocusIn || iEvent->type() == QEvent::FocusOut)) {
270         QObject* appliFocus = QApplication::focusWidget();
271 
272         while (appliFocus != nullptr) {
273             if (appliFocus == this) {
274                 break;
275             }
276             appliFocus = appliFocus->parent();
277         }
278         if (appliFocus == nullptr) {
279             Q_EMIT editingFinished();
280         }
281     }
282     return false;
283 }
284 
onOperatorChanged()285 void SKGPredicatCreator::onOperatorChanged()
286 {
287     QString req;
288     if (m_kOperator != nullptr) {
289         req = m_kOperator->itemData(m_kOperator->currentIndex()).toString();
290 
291         m_kOperator->setToolTip(SKGRuleObject::getToolTipForOperator(req));
292     }
293     if (m_kValue1 != nullptr) {
294         m_kValue1->setVisible(req.contains(QStringLiteral("#V1S#")) || req.contains(QStringLiteral("#V1#")));
295     }
296     if (m_kValue2 != nullptr) {
297         m_kValue2->setVisible(req.contains(QStringLiteral("#V2S#")) || req.contains(QStringLiteral("#V2#")) || req.contains(QStringLiteral("#DF#")));
298     }
299     if (m_kAttributes != nullptr) {
300         m_kAttributes->setVisible(req.contains(QStringLiteral("#ATT2#")));
301     }
302 }
303 
text()304 QString SKGPredicatCreator::text()
305 {
306     return SKGPredicatCreator::getTextFromXml(xmlDescription());
307 }
308 
getTextFromXml(const QString & iXML)309 QString SKGPredicatCreator::getTextFromXml(const QString& iXML)
310 {
311     QDomDocument doc(QStringLiteral("SKGML"));
312     doc.setContent(iXML);
313     QDomElement root = doc.documentElement();
314     QString output = SKGRuleObject::getDisplayForOperator(root.attribute(QStringLiteral("operator")),
315                      root.attribute(QStringLiteral("value")),
316                      root.attribute(QStringLiteral("value2")),
317                      root.attribute(QStringLiteral("att2s")));
318     return output;
319 }
320 
xmlDescription()321 QString SKGPredicatCreator::xmlDescription()
322 {
323     QString output;
324     if (m_kOperator != nullptr) {
325         QString op = m_kOperator->itemData(m_kOperator->currentIndex()).toString();
326         if (!op.isEmpty()) {
327             QDomDocument doc(QStringLiteral("SKGML"));
328             QDomElement root = doc.createElement(QStringLiteral("element"));
329             doc.appendChild(root);
330 
331             // Condition
332             root.setAttribute(QStringLiteral("operator"), op);
333             if ((m_kValue1 != nullptr) && m_kValue1->isVisible()) {
334                 auto* cmbVal1 = qobject_cast<SKGDateEdit*> (m_kValue1);
335                 if (cmbVal1 != nullptr) {
336                     root.setAttribute(QStringLiteral("value"), SKGServices::dateToSqlString(cmbVal1->date()));
337                 } else {
338                     auto* cmbVal12 = qobject_cast<SKGCalculatorEdit*> (m_kValue1);
339                     if (cmbVal12 != nullptr) {
340                         root.setAttribute(QStringLiteral("value"), cmbVal12->text());
341                     } else {
342                         auto* cmbVal13 = qobject_cast<QCheckBox*> (m_kValue1);
343                         if (cmbVal13 != nullptr) {
344                             root.setAttribute(QStringLiteral("value"), cmbVal13->checkState() == Qt::Checked ? QStringLiteral("Y") : cmbVal13->checkState() == Qt::Unchecked ? QStringLiteral("N") : QStringLiteral("P"));
345                         } else {
346                             auto* cmbVal14 = qobject_cast<SKGComboBox*> (m_kValue1);
347                             if (cmbVal14 != nullptr) {
348                                 root.setAttribute(QStringLiteral("value"), cmbVal14->text());
349                             }
350                         }
351                     }
352                 }
353             }
354             if ((m_kValue2 != nullptr) && m_kValue2->isVisible()) {
355                 auto* cmbVal2 = qobject_cast<SKGDateEdit*> (m_kValue2);
356                 if (cmbVal2 != nullptr) {
357                     root.setAttribute(QStringLiteral("value2"), SKGServices::dateToSqlString(cmbVal2->date()));
358                 } else {
359                     auto* cmbVal21 = qobject_cast<SKGCalculatorEdit*> (m_kValue2);
360                     if (cmbVal21 != nullptr) {
361                         root.setAttribute(QStringLiteral("value2"), cmbVal21->text());
362                     } else {
363                         auto* cmbVal22 = qobject_cast<SKGComboBox*> (m_kValue2);
364                         if (cmbVal22 != nullptr) {
365                             root.setAttribute(QStringLiteral("value2"), cmbVal22->text());
366                         }
367                     }
368                 }
369             }
370 
371             if ((m_kAttributes != nullptr) && m_kAttributes->isVisible()) {
372                 root.setAttribute(QStringLiteral("att2"), m_kAttributes->itemData(m_kAttributes->currentIndex()).toString());
373                 root.setAttribute(QStringLiteral("att2s"), m_kAttributes->text());
374             }
375 
376             output = doc.toString();
377         }
378     }
379     return output;
380 }
381 
setXmlDescription(const QString & iXML)382 void SKGPredicatCreator::setXmlDescription(const QString& iXML)
383 {
384     QDomDocument doc(QStringLiteral("SKGML"));
385     doc.setContent(iXML);
386     QDomElement root = doc.documentElement();
387 
388     // Condition
389     if (m_kOperator != nullptr) {
390         m_kOperator->setCurrentIndex(m_kOperator->findData(root.attribute(QStringLiteral("operator"))));
391         auto* cmbVal1 = qobject_cast<SKGDateEdit*> (m_kValue1);
392         if (cmbVal1 != nullptr) {
393             cmbVal1->setDate(SKGServices::stringToTime(root.attribute(QStringLiteral("value"))).date());
394         } else {
395             auto* cmbVal12 = qobject_cast<SKGCalculatorEdit*> (m_kValue1);
396             if (cmbVal12 != nullptr) {
397                 cmbVal12->setText(root.attribute(QStringLiteral("value")));
398             } else {
399                 auto* cmbVal13 = qobject_cast<QCheckBox*> (m_kValue1);
400                 if (cmbVal13 != nullptr) {
401                     cmbVal13->setCheckState(root.attribute(QStringLiteral("value")) == QStringLiteral("Y") ? Qt::Checked : root.attribute(QStringLiteral("value")) == QStringLiteral("P") ? Qt::PartiallyChecked : Qt::Unchecked);
402                 } else {
403                     auto* cmbVal14 = qobject_cast<SKGComboBox*> (m_kValue1);
404                     if (cmbVal14 != nullptr) {
405                         cmbVal14->setText(root.attribute(QStringLiteral("value")));
406                     }
407                 }
408             }
409         }
410 
411         auto* cmbVal2 = qobject_cast<SKGDateEdit*> (m_kValue2);
412         if (cmbVal2 != nullptr) {
413             cmbVal2->setDate(SKGServices::stringToTime(root.attribute(QStringLiteral("value2"))).date());
414         } else {
415             auto* cmbVal22 = qobject_cast<SKGCalculatorEdit*> (m_kValue2);
416             if (cmbVal22 != nullptr) {
417                 cmbVal22->setText(root.attribute(QStringLiteral("value2")));
418             } else {
419                 auto* cmbVal23 = qobject_cast<SKGComboBox*> (m_kValue2);
420                 if (cmbVal23 != nullptr) {
421                     cmbVal23->setText(root.attribute(QStringLiteral("value2")));
422                 }
423             }
424         }
425 
426         if (m_kAttributes != nullptr) {
427             m_kAttributes->setCurrentIndex(m_kAttributes->findData(root.attribute(QStringLiteral("att2"))));
428         }
429     }
430 
431     emit xmlDescriptionChanged();
432 }
433 
434 
435 
436