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  * A skrooge plugin to search and process operations.
8  *
9  * @author Stephane MANKOWSKI
10  */
11 #include "skgsearchpluginwidget.h"
12 
13 #include <qdir.h>
14 #include <qdom.h>
15 #include <qevent.h>
16 
17 #include "skgbankincludes.h"
18 #include "skgcategoryobject.h"
19 #include "skgdocument.h"
20 #include "skgmainpanel.h"
21 #include "skgobjectmodel.h"
22 #include "skgruleobject.h"
23 #include "skgservices.h"
24 #include "skgtraces.h"
25 
SKGSearchPluginWidget(QWidget * iParent,SKGDocument * iDocument)26 SKGSearchPluginWidget::SKGSearchPluginWidget(QWidget* iParent, SKGDocument* iDocument)
27     : SKGTabPage(iParent, iDocument)
28 {
29     SKGTRACEINFUNC(1)
30     if (iDocument == nullptr) {
31         return;
32     }
33 
34     ui.setupUi(this);
35     auto msg = i18nc("Message template", "Message to display when alarm is triggered (%1 is the total amount, %2 is the alarm amount, %3 the difference)", "%1", "%2", "%3");
36     ui.kAlarmMessage->setToolTip(msg);
37     ui.kAlarmMessage->setStatusTip(msg);
38 
39     ui.kView->getShowWidget()->addItem(QStringLiteral("search"), i18nc("Noun, a search", "Search"), QStringLiteral("edit-find"), QStringLiteral("t_action_type='S'"), QLatin1String(""), QLatin1String(""), QLatin1String(""), QLatin1String(""), Qt::META + Qt::Key_S);
40     ui.kView->getShowWidget()->addItem(QStringLiteral("update"), i18nc("Noun, a modification", "Update"), QStringLiteral("view-refresh"), QStringLiteral("t_action_type='U'"), QLatin1String(""), QLatin1String(""), QLatin1String(""), QLatin1String(""), Qt::META + Qt::Key_U);
41     ui.kView->getShowWidget()->addItem(QStringLiteral("alarm"), i18nc("Noun, an alarm", "Alarm"), QStringLiteral("dialog-warning"), QStringLiteral("t_action_type='A'"), QLatin1String(""), QLatin1String(""), QLatin1String(""), QLatin1String(""), Qt::META + Qt::Key_A);
42     ui.kView->getShowWidget()->addItem(QStringLiteral("template"), i18nc("Noun, a modification by applying a template", "Template"), QStringLiteral("edit-guides"), QStringLiteral("t_action_type='T'"), QLatin1String(""), QLatin1String(""), QLatin1String(""), QLatin1String(""), Qt::META + Qt::Key_T);
43     ui.kView->getShowWidget()->addSeparator();
44     ui.kView->getShowWidget()->addItem(QStringLiteral("highlighted"), i18nc("Adjective, an highlighted item", "Highlighted"), QStringLiteral("bookmarks"), QStringLiteral("t_bookmarked='Y'"), QLatin1String(""), QLatin1String(""), QLatin1String(""), QLatin1String(""), Qt::META + Qt::Key_H);
45     ui.kView->getShowWidget()->setDefaultState(QStringLiteral("search;update;alarm;template;highlighted"));
46 
47     // Add Standard KDE Icons to buttons
48     ui.kUpdate->setIcon(SKGServices::fromTheme(QStringLiteral("dialog-ok")));
49     ui.kAdd->setIcon(SKGServices::fromTheme(QStringLiteral("list-add")));
50     ui.kSearch->setIcon(SKGServices::fromTheme(QStringLiteral("edit-find")));
51     QStringList overlayopen;
52     overlayopen.push_back(QStringLiteral("quickopen"));
53     ui.kOpenReport->setIcon(SKGServices::fromTheme(QStringLiteral("view-statistics"), overlayopen));
54 
55     ui.kTopBtn->setIcon(SKGServices::fromTheme(QStringLiteral("arrow-up-double")));
56     ui.kUpBtn->setIcon(SKGServices::fromTheme(QStringLiteral("arrow-up")));
57     ui.kDownBtn->setIcon(SKGServices::fromTheme(QStringLiteral("arrow-down")));
58     ui.kBottomBtn->setIcon(SKGServices::fromTheme(QStringLiteral("arrow-down-double")));
59 
60     {
61         SKGWidgetSelector::SKGListQWidget list;
62         list.push_back(ui.kQueryGrp);
63         list.push_back(ui.kBtnFrm);
64         ui.kWidgetSelector->addButton(SKGServices::fromTheme(QStringLiteral("edit-find")), i18n("Search"), i18n("Display the edit panel for searches"), list);
65     }
66     {
67         SKGWidgetSelector::SKGListQWidget list;
68         list.push_back(ui.kQueryGrp);
69         list.push_back(ui.kBtnFrm);
70         list.push_back(ui.kActionGrp);
71         ui.kWidgetSelector->addButton(SKGServices::fromTheme(QStringLiteral("view-refresh")), i18n("Update"), i18n("Display the edit panel for updates"), list);
72     }
73     {
74         SKGWidgetSelector::SKGListQWidget list;
75         list.push_back(ui.kQueryGrp);
76         list.push_back(ui.kBtnFrm);
77         list.push_back(ui.kAlarmFrm);
78         ui.kWidgetSelector->addButton(SKGServices::fromTheme(QStringLiteral("dialog-warning")), i18n("Alarm"), i18n("Display the edit panel for alarm"), list);
79     }
80     {
81         SKGWidgetSelector::SKGListQWidget list;
82         list.push_back(ui.kQueryGrp);
83         list.push_back(ui.kBtnFrm);
84         list.push_back(ui.kTemplateFrm);
85         ui.kWidgetSelector->addButton(SKGServices::fromTheme(QStringLiteral("edit-guides")), i18n("Template"), i18n("Display the edit panel for updates by templates"), list);
86     }
87 
88     QStringList attributeForQuery;
89     attributeForQuery.reserve(40);
90     attributeForQuery << QStringLiteral("d_DATEOP") << QStringLiteral("t_number") << QStringLiteral("t_mode") << QStringLiteral("t_PAYEE") << QStringLiteral("t_comment") << QStringLiteral("t_REALCOMMENT") << QStringLiteral("t_REALCATEGORY") << QStringLiteral("t_status") << QStringLiteral("t_bookmarked") << QStringLiteral("t_imported") << QStringLiteral("t_TRANSFER") << QStringLiteral("t_UNIT") << QStringLiteral("t_ACCOUNT") << QStringLiteral("t_BANK") << QStringLiteral("t_TOACCOUNT") << QStringLiteral("f_REALCURRENTAMOUNT") << QStringLiteral("t_REALREFUND") << QStringLiteral("f_BALANCE") << QStringLiteral("i_NBSUBOPERATIONS");
91     QStringList attributeForUpdate;
92     attributeForUpdate.reserve(40);
93     attributeForUpdate << QStringLiteral("d_DATEOP") << QStringLiteral("t_number") << QStringLiteral("t_mode") << QStringLiteral("t_PAYEE") << QStringLiteral("t_comment") << QStringLiteral("t_status") << QStringLiteral("t_bookmarked") << QStringLiteral("t_imported") << QStringLiteral("t_REALCOMMENT") << QStringLiteral("t_REALCATEGORY") << QStringLiteral("t_ACCOUNT") << QStringLiteral("t_REALREFUND") << QStringLiteral("t_UNIT");
94     // WARNING: trigger must be modified if this list is modifier
95 
96     // Adding properties
97     QStringList properties;
98     iDocument->getDistinctValues(QStringLiteral("parameters"), QStringLiteral("t_name"), QStringLiteral("(t_uuid_parent like '%-operation' OR t_uuid_parent like '%-suboperation') AND t_name NOT LIKE 'SKG_%'"), properties);
99     int nb = properties.count();
100     for (int i = 0; i < nb; ++i) {
101         attributeForQuery.push_back("p_" % properties.at(i));
102         attributeForUpdate.push_back("p_" % properties.at(i));
103     }
104 
105     ui.kQueryCreator->setParameters(iDocument, QStringLiteral("v_suboperation_consolidated"), attributeForQuery);
106     ui.kActionCreator->setParameters(iDocument, QStringLiteral("v_suboperation_consolidated"), attributeForUpdate, true);
107 
108     // Bind operation view
109     ui.kView->setModel(new SKGObjectModel(qobject_cast<SKGDocumentBank*>(getDocument()), QStringLiteral("v_rule_display"), QStringLiteral("1=1 ORDER BY f_sortorder"), this, QLatin1String(""), false));
110     ui.kView->getView()->sortByColumn(0, Qt::AscendingOrder);
111 
112     // Add registered global action in contextual menu
113     if (SKGMainPanel::getMainPanel() != nullptr) {
114         auto menu = new QMenu(this);
115         menu->setIcon(SKGServices::fromTheme(QStringLiteral("system-run")));
116         menu->addAction(SKGMainPanel::getMainPanel()->getGlobalAction(QStringLiteral("execute_all")));
117         menu->addAction(SKGMainPanel::getMainPanel()->getGlobalAction(QStringLiteral("execute_imported")));
118         menu->addAction(SKGMainPanel::getMainPanel()->getGlobalAction(QStringLiteral("execute_not_validated")));
119         menu->addAction(SKGMainPanel::getMainPanel()->getGlobalAction(QStringLiteral("execute_notchecked")));
120 
121         ui.kApply->setIcon(menu->icon());
122         ui.kApply->setMenu(menu);
123         ui.kApply->setPopupMode(QToolButton::InstantPopup);
124     }
125 
126     ui.kWidgetSelector->setSelectedMode(0);
127 
128     connect(ui.kView->getView(), &SKGTreeView::clickEmptyArea, this, &SKGSearchPluginWidget::cleanEditor);
129     connect(ui.kView->getView(), &SKGTreeView::doubleClicked, SKGMainPanel::getMainPanel()->getGlobalAction(QStringLiteral("open")).data(), &QAction::trigger);
130     connect(ui.kView->getView(), &SKGTreeView::selectionChangedDelayed, this, [ = ] {this->onSelectionChanged();});
131     connect(ui.kQueryCreator, &SKGQueryCreator::search, this, &SKGSearchPluginWidget::onOpen);
132 
133     connect(ui.kAdd, &QPushButton::clicked, this, &SKGSearchPluginWidget::onAddRule);
134     connect(ui.kUpdate, &QPushButton::clicked, this, &SKGSearchPluginWidget::onModifyRule);
135     connect(ui.kTopBtn, &QToolButton::clicked, this, &SKGSearchPluginWidget::onTop);
136     connect(ui.kUpBtn, &QToolButton::clicked, this, &SKGSearchPluginWidget::onUp);
137     connect(ui.kDownBtn, &QToolButton::clicked, this, &SKGSearchPluginWidget::onDown);
138     connect(ui.kBottomBtn, &QToolButton::clicked, this, &SKGSearchPluginWidget::onBottom);
139     connect(ui.kOpenReport, &QPushButton::clicked, this, &SKGSearchPluginWidget::onOpen);
140     connect(ui.kSearch, &QPushButton::clicked, this, &SKGSearchPluginWidget::onOpen);
141 
142     // Refresh
143     connect(getDocument(), &SKGDocument::tableModified, this, &SKGSearchPluginWidget::dataModified, Qt::QueuedConnection);
144     dataModified(QLatin1String(""), 0);
145 
146     onSelectionChanged();
147 
148     // Set Event filters to catch CTRL+ENTER or SHIFT+ENTER
149     this->installEventFilter(this);
150 }
151 
~SKGSearchPluginWidget()152 SKGSearchPluginWidget::~SKGSearchPluginWidget()
153 {
154     SKGTRACEINFUNC(1)
155 }
156 
eventFilter(QObject * iObject,QEvent * iEvent)157 bool SKGSearchPluginWidget::eventFilter(QObject* iObject, QEvent* iEvent)
158 {
159     if ((iEvent != nullptr) && iEvent->type() == QEvent::KeyPress) {
160         auto* keyEvent = dynamic_cast<QKeyEvent*>(iEvent);
161         if (keyEvent && (keyEvent->key() == Qt::Key_Return || keyEvent->key() == Qt::Key_Enter) && iObject == this) {
162             if ((QApplication::keyboardModifiers() & Qt::ControlModifier) != 0u && ui.kAdd->isEnabled()) {
163                 ui.kAdd->click();
164             } else if ((QApplication::keyboardModifiers() &Qt::ShiftModifier) != 0u && ui.kUpdate->isEnabled()) {
165                 ui.kUpdate->click();
166             }
167         }
168     }
169 
170     return SKGTabPage::eventFilter(iObject, iEvent);
171 }
172 
getState()173 QString SKGSearchPluginWidget::getState()
174 {
175     SKGTRACEINFUNC(10)
176     QDomDocument doc(QStringLiteral("SKGML"));
177     QDomElement root = doc.createElement(QStringLiteral("parameters"));
178     doc.appendChild(root);
179     root.setAttribute(QStringLiteral("currentPage"), SKGServices::intToString(ui.kWidgetSelector->getSelectedMode()));
180     root.setAttribute(QStringLiteral("view"), ui.kView->getState());
181     return doc.toString();
182 }
183 
setState(const QString & iState)184 void SKGSearchPluginWidget::setState(const QString& iState)
185 {
186     SKGTRACEINFUNC(10)
187     QDomDocument doc(QStringLiteral("SKGML"));
188     doc.setContent(iState);
189     QDomElement root = doc.documentElement();
190 
191     QString currentPage = root.attribute(QStringLiteral("currentPage"));
192     QString xmlsearchcondition = root.attribute(QStringLiteral("xmlsearchcondition"));
193 
194     if (currentPage.isEmpty()) {
195         currentPage = '0';
196     }
197 
198     ui.kWidgetSelector->setSelectedMode(SKGServices::stringToInt(currentPage));
199     ui.kQueryCreator->setXMLCondition(xmlsearchcondition);
200     ui.kView->setState(root.attribute(QStringLiteral("view")));
201 }
202 
getDefaultStateAttribute()203 QString SKGSearchPluginWidget::getDefaultStateAttribute()
204 {
205     return QStringLiteral("SKGSEARCH_DEFAULT_PARAMETERS");
206 }
207 
mainWidget()208 QWidget* SKGSearchPluginWidget::mainWidget()
209 {
210     return ui.kView->getView();
211 }
212 
getSelectedObjects()213 SKGObjectBase::SKGListSKGObjectBase SKGSearchPluginWidget::getSelectedObjects()
214 {
215     SKGObjectBase::SKGListSKGObjectBase list = ui.kView->getView()->getSelectedObjects();
216 
217     // Sort selection by f_sortorder. It is mandatory for reorder functions
218     std::stable_sort(list.begin(), list.end());
219 
220     return list;
221 }
222 
getNbSelectedObjects()223 int SKGSearchPluginWidget::getNbSelectedObjects()
224 {
225     return ui.kView->getView()->getNbSelectedObjects();
226 }
227 
dataModified(const QString & iTableName,int iIdTransaction)228 void SKGSearchPluginWidget::dataModified(const QString& iTableName, int iIdTransaction)
229 {
230     SKGTRACEINFUNC(1)
231     Q_UNUSED(iIdTransaction)
232 
233     // Refresh account list
234     if (iTableName == QStringLiteral("unit") || iTableName.isEmpty()) {
235         ui.kAlarmUnit->setText(qobject_cast<SKGDocumentBank*>(getDocument())->getPrimaryUnit().Symbol);
236     }
237 
238     if (iTableName == QStringLiteral("operation") || iTableName.isEmpty()) {
239         // Fill combo boxes
240         SKGStringListList result;
241         getDocument()->executeSelectSqliteOrder(QStringLiteral("SELECT id, t_displayname FROM v_operation_displayname WHERE t_template='Y' ORDER BY t_displayname"), result);
242         int nb2 = result.count();
243         for (int i = 1; i < nb2; ++i) {  // Ignore header
244             const QStringList& r = result.at(i);
245             ui.kTemplate->addItem(r.at(1), r.at(0));
246         }
247     }
248 }
249 
onAddRule()250 void SKGSearchPluginWidget::onAddRule()
251 {
252     SKGError err;
253     SKGTRACEINFUNCRC(1, err) {
254         SKGRuleObject rule;
255         {
256             SKGBEGINTRANSACTION(*getDocument(), i18nc("Noun, name of the user action", "Search and process creation"), err)
257             rule = SKGRuleObject(getDocument());
258             IFOKDO(err, rule.setXMLSearchDefinition(ui.kQueryCreator->getXMLCondition()))
259             IFOKDO(err, rule.setOrder(-1))
260 
261             QString xml = getXMLActionDefinition();
262             IFOKDO(err, rule.setActionType(xml.isEmpty() ? SKGRuleObject::SEARCH : SKGRuleObject::ActionType(ui.kWidgetSelector->getSelectedMode())))
263             IFOKDO(err, rule.setXMLActionDefinition(xml))
264             IFOKDO(err, rule.save())
265 
266             // Send message
267             IFOKDO(err, rule.getDocument()->sendMessage(i18nc("An information to the user", "The search rule '%1' have been added", rule.getDisplayName()), SKGDocument::Hidden))
268         }
269 
270         // status bar
271         IFOK(err) {
272             err = SKGError(0, i18nc("Successful message after an user action", "Search and process created"));
273             ui.kView->getView()->selectObject(rule.getUniqueID());
274         } else {
275             err.addError(ERR_FAIL, i18nc("Error message",  "Search and process creation failed"));
276         }
277     }
278 
279     // Display error
280     SKGMainPanel::displayErrorMessage(err, true);
281 }
282 
onOpen()283 void SKGSearchPluginWidget::onOpen()
284 {
285     SKGError err;
286     SKGTRACEINFUNCRC(1, err)
287     SKGRuleObject rule;
288     QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
289     rule = SKGRuleObject(getDocument());
290     IFOKDO(err, rule.setXMLSearchDefinition(ui.kQueryCreator->getXMLCondition()))
291     IFOKDO(err, rule.setOrder(-1))
292 
293     QString xml = getXMLActionDefinition();
294     IFOKDO(err, rule.setActionType(xml.isEmpty() ? SKGRuleObject::SEARCH : SKGRuleObject::ActionType(ui.kWidgetSelector->getSelectedMode())))
295     IFOKDO(err, rule.setXMLActionDefinition(xml))
296     IFOK(err) open(rule, (sender() == ui.kOpenReport ? SKGSearchPluginWidget::REPORT : SKGSearchPluginWidget::TABLE));
297     QApplication::restoreOverrideCursor();
298 
299     // Display error
300     SKGMainPanel::displayErrorMessage(err);
301 }
302 
onModifyRule()303 void SKGSearchPluginWidget::onModifyRule()
304 {
305     SKGError err;
306     SKGTRACEINFUNCRC(1, err) {
307         SKGBEGINTRANSACTION(*getDocument(), i18nc("Noun, name of the user action", "Search and process update"), err)
308         SKGObjectBase::SKGListSKGObjectBase rules = getSelectedObjects();
309         if (rules.count() == 1) {
310             SKGRuleObject rule(rules.at(0));
311             IFOKDO(err, rule.setXMLSearchDefinition(ui.kQueryCreator->getXMLCondition()))
312             QString xml = getXMLActionDefinition();
313             IFOKDO(err, rule.setActionType(xml.isEmpty() ? SKGRuleObject::SEARCH : SKGRuleObject::ActionType(ui.kWidgetSelector->getSelectedMode())))
314             IFOKDO(err, rule.setXMLActionDefinition(xml))
315             IFOKDO(err, rule.save())
316 
317             // Send message
318             IFOKDO(err, rule.getDocument()->sendMessage(i18nc("An information to the user", "The search rule '%1' have been updated", rule.getDisplayName()), SKGDocument::Hidden))
319         }
320     }
321 
322     // status bar
323     IFOKDO(err, SKGError(0, i18nc("Successful message after an user action", "Search and process updated")))
324     else {
325         err.addError(ERR_FAIL, i18nc("Error message",  "Search and process update failed"));
326     }
327 
328     // Display error
329     SKGMainPanel::displayErrorMessage(err, true);
330 
331     // Set focus on table
332     ui.kView->getView()->setFocus();
333 }
334 
onSelectionChanged()335 void SKGSearchPluginWidget::onSelectionChanged()
336 {
337     SKGObjectBase::SKGListSKGObjectBase selection = getSelectedObjects();
338     int nbSel = selection.count();
339 
340     ui.kTopBtn->setEnabled(nbSel > 0);
341     ui.kUpBtn->setEnabled(nbSel > 0);
342     ui.kDownBtn->setEnabled(nbSel > 0);
343     ui.kBottomBtn->setEnabled(nbSel > 0);
344     ui.kUpdate->setEnabled(nbSel == 1);
345     ui.kApply->setEnabled(nbSel > 0);
346 
347     if (nbSel > 0) {
348         SKGRuleObject rule(selection.at(0));
349         ui.kQueryCreator->setXMLCondition(rule.getXMLSearchDefinition());
350 
351         int index = qMax(0, static_cast<int>(rule.getActionType()));
352         if (ui.kWidgetSelector->getSelectedMode() != -1) {
353             ui.kWidgetSelector->setSelectedMode(index);
354         }
355         if (index == 1) {
356             // Set update mode
357             ui.kActionCreator->setXMLCondition(rule.getXMLActionDefinition());
358         } else if (index == 2) {
359             // Set alarm mode
360             QDomDocument doc(QStringLiteral("SKGML"));
361             doc.setContent(rule.getXMLActionDefinition());
362 
363             QDomElement element = doc.documentElement();
364             QDomElement elementLine = element.firstChild().toElement();
365             QDomElement elementElement = elementLine.firstChild().toElement();
366             ui.kAlarmAmount->setValue(SKGServices::stringToDouble(elementElement.attribute(QStringLiteral("value"))));
367             ui.kAlarmMessage->setText(elementElement.attribute(QStringLiteral("value2")));
368         } else if (index == 3) {
369             // Set template mode
370             QDomDocument doc(QStringLiteral("SKGML"));
371             doc.setContent(rule.getXMLActionDefinition());
372 
373             QDomElement element = doc.documentElement();
374             QDomElement elementLine = element.firstChild().toElement();
375             QDomElement elementElement = elementLine.firstChild().toElement();
376             ui.kTemplate->setCurrentIndex(ui.kTemplate->findData(elementElement.attribute(QStringLiteral("value"))));
377         }
378     }
379 
380     onEditorModified();
381 
382     Q_EMIT selectionChanged();
383 }
384 
onTop()385 void SKGSearchPluginWidget::onTop()
386 {
387     SKGError err;
388     SKGTRACEINFUNCRC(1, err)
389 
390     // Get rules
391     SKGObjectBase::SKGListSKGObjectBase  rules = getSelectedObjects();
392     int nb = rules.count();
393     {
394         SKGBEGINPROGRESSTRANSACTION(*getDocument(), i18nc("Noun, name of the user action", "Search update"), err, nb)
395         for (int i = nb - 1; !err && i >= 0; --i) {
396             SKGRuleObject rule(rules.at(i));
397 
398             double order = 1;
399             SKGStringListList result;
400             err = getDocument()->executeSelectSqliteOrder(QStringLiteral("SELECT min(f_sortorder) from rule"), result);
401             if (!err && result.count() == 2) {
402                 order = SKGServices::stringToDouble(result.at(1).at(0)) - 1;
403             }
404 
405             IFOKDO(err, rule.setOrder(order))
406             IFOKDO(err, rule.save())
407 
408             // Send message
409             IFOKDO(err, getDocument()->sendMessage(i18nc("An information to the user", "The search '%1' has been updated", rule.getDisplayName()), SKGDocument::Hidden))
410 
411             IFOKDO(err, getDocument()->stepForward(i + 1))
412         }
413     }
414 
415     // status bar
416     IFOKDO(err, SKGError(0, i18nc("Successful message after an user action", "Search updated")))
417     else {
418         err.addError(ERR_FAIL, i18nc("Error message",  "Search update failed"));
419     }
420 
421     // Display error
422     SKGMainPanel::displayErrorMessage(err);
423 }
424 
onUp()425 void SKGSearchPluginWidget::onUp()
426 {
427     SKGError err;
428     SKGTRACEINFUNCRC(1, err)
429 
430     // Get rules
431     SKGObjectBase::SKGListSKGObjectBase  rules = getSelectedObjects();
432     int nb = rules.count();
433     {
434         SKGBEGINPROGRESSTRANSACTION(*getDocument(), i18nc("Noun, name of the user action", "Search update"), err, nb)
435         for (int i = 0; !err && i < nb; ++i) {
436             SKGRuleObject rule(rules.at(i));
437 
438             double order = rule.getOrder();
439             SKGStringListList result;
440             err = getDocument()->executeSelectSqliteOrder("SELECT f_sortorder from rule where f_sortorder<" % SKGServices::doubleToString(order) % " ORDER BY f_sortorder DESC", result);
441             IFOK(err) {
442                 if (result.count() == 2) {
443                     order = SKGServices::stringToDouble(result.at(1).at(0)) - 1;
444                 } else if (result.count() >= 2) {
445                     order = (SKGServices::stringToDouble(result.at(1).at(0)) + SKGServices::stringToDouble(result.at(2).at(0))) / 2;
446                 }
447             }
448 
449             IFOKDO(err, rule.setOrder(order))
450             IFOKDO(err, rule.save())
451 
452             // Send message
453             IFOKDO(err, getDocument()->sendMessage(i18nc("An information to the user", "The search '%1' has been updated", rule.getDisplayName()), SKGDocument::Hidden))
454 
455             IFOKDO(err, getDocument()->stepForward(i + 1))
456         }
457     }
458 
459     // status bar
460     IFOKDO(err, SKGError(0, i18nc("Successful message after an user action", "Search updated")))
461     else {
462         err.addError(ERR_FAIL, i18nc("Error message",  "Search update failed"));
463     }
464 
465     // Display error
466     SKGMainPanel::displayErrorMessage(err);
467 }
468 
onDown()469 void SKGSearchPluginWidget::onDown()
470 {
471     SKGError err;
472     SKGTRACEINFUNCRC(1, err)
473 
474     // Get rules
475     SKGObjectBase::SKGListSKGObjectBase  rules = getSelectedObjects();
476     int nb = rules.count();
477     {
478         SKGBEGINPROGRESSTRANSACTION(*getDocument(), i18nc("Noun, name of the user action", "Search update"), err, nb)
479         for (int i = nb - 1; !err && i >= 0; --i) {
480             SKGRuleObject rule(rules.at(i));
481 
482             double order = rule.getOrder();
483             SKGStringListList result;
484             err = getDocument()->executeSelectSqliteOrder("SELECT f_sortorder from rule where f_sortorder>" % SKGServices::doubleToString(order) % " ORDER BY f_sortorder ASC", result);
485             IFOK(err) {
486                 if (result.count() == 2) {
487                     order = SKGServices::stringToDouble(result.at(1).at(0)) + 1;
488                 } else if (result.count() >= 2) {
489                     order = (SKGServices::stringToDouble(result.at(1).at(0)) + SKGServices::stringToDouble(result.at(2).at(0))) / 2;
490                 }
491             }
492 
493             IFOKDO(err, rule.setOrder(order))
494             IFOKDO(err, rule.save())
495 
496             // Send message
497             IFOKDO(err, getDocument()->sendMessage(i18nc("An information to the user", "The search '%1' has been updated", rule.getDisplayName()), SKGDocument::Hidden))
498 
499             IFOKDO(err, getDocument()->stepForward(i + 1))
500         }
501     }
502 
503     // status bar
504     IFOKDO(err, SKGError(0, i18nc("Successful message after an user action", "Search updated")))
505     else {
506         err.addError(ERR_FAIL, i18nc("Error message",  "Search update failed"));
507     }
508 
509     // Display error
510     SKGMainPanel::displayErrorMessage(err);
511 }
512 
onBottom()513 void SKGSearchPluginWidget::onBottom()
514 {
515     SKGError err;
516     SKGTRACEINFUNCRC(1, err)
517 
518     // Get rules
519     SKGObjectBase::SKGListSKGObjectBase  rules = getSelectedObjects();
520     int nb = rules.count();
521     {
522         SKGBEGINPROGRESSTRANSACTION(*getDocument(), i18nc("Noun, name of the user action", "Search update"), err, nb)
523         for (int i = 0; !err && i < nb; ++i) {
524             SKGRuleObject rule(rules.at(i));
525 
526             double order = 1;
527             SKGStringListList result;
528             err = getDocument()->executeSelectSqliteOrder(QStringLiteral("SELECT max(f_sortorder) from rule"), result);
529             if (!err && result.count() == 2) {
530                 order = SKGServices::stringToDouble(result.at(1).at(0)) + 1;
531             }
532 
533             IFOKDO(err, rule.setOrder(order))
534             IFOKDO(err, rule.save())
535 
536             // Send message
537             IFOKDO(err, getDocument()->sendMessage(i18nc("An information to the user", "The search '%1' has been updated", rule.getDisplayName()), SKGDocument::Hidden))
538 
539             IFOKDO(err, getDocument()->stepForward(i + 1))
540         }
541     }
542 
543     // status bar
544     IFOKDO(err, SKGError(0, i18nc("Successful message after an user action", "Search updated")))
545     else {
546         err.addError(ERR_FAIL, i18nc("Error message",  "Search update failed"));
547     }
548 
549     // Display error
550     SKGMainPanel::displayErrorMessage(err);
551 }
552 
open(const SKGRuleObject & iRule,OpenMode iMode)553 void SKGSearchPluginWidget::open(const SKGRuleObject& iRule, OpenMode iMode)
554 {
555     _SKGTRACEINFUNC(10)
556 
557     // Build where clause and title
558     QString wc = "i_SUBOPID in (SELECT i_SUBOPID FROM v_operation_prop WHERE " % iRule.getSelectSqlOrder() % ')';
559     QString title = i18nc("Noun, a list of items", "Sub operations corresponding to rule '%1'",  iRule.getSearchDescription());
560 
561     // Call operation plugin
562     QDomDocument doc(QStringLiteral("SKGML"));
563     doc.setContent(SKGMainPanel::getMainPanel()->getDocument()->getParameter(iMode == TABLE ? QStringLiteral("SKGOPERATION_CONSOLIDATED_DEFAULT_PARAMETERS") : QStringLiteral("SKGREPORT_DEFAULT_PARAMETERS")));
564     QDomElement root = doc.documentElement();
565     if (root.isNull()) {
566         root = doc.createElement(QStringLiteral("parameters"));
567         doc.appendChild(root);
568     }
569 
570     root.setAttribute(QStringLiteral("operationWhereClause"), wc);
571     root.setAttribute(QStringLiteral("title"), title);
572     root.setAttribute(QStringLiteral("title_icon"), QStringLiteral("edit-find"));
573 
574     if (iMode == TABLE) {
575         root.setAttribute(QStringLiteral("operationTable"), QStringLiteral("v_suboperation_consolidated"));
576         root.setAttribute(QStringLiteral("currentPage"), QStringLiteral("-1"));
577         SKGMainPanel::getMainPanel()->openPage(SKGMainPanel::getMainPanel()->getPluginByName(QStringLiteral("Skrooge operation plugin")), -1, doc.toString(), i18nc("Noun, a list of items", "Sub operations"));
578     } else {
579         root.setAttribute(QStringLiteral("period"), QStringLiteral("0"));
580         SKGMainPanel::getMainPanel()->openPage(SKGMainPanel::getMainPanel()->getPluginByName(QStringLiteral("Skrooge report plugin")), -1, doc.toString());
581     }
582 }
583 
onEditorModified()584 void SKGSearchPluginWidget::onEditorModified()
585 {
586     SKGObjectBase::SKGListSKGObjectBase selection = getSelectedObjects();
587     int nbSelect = selection.count();
588     ui.kUpdate->setEnabled(nbSelect == 1);
589     ui.kQueryInfo->setText(QLatin1String(""));
590 
591     if (nbSelect == 1) {
592         SKGRuleObject rule(selection.at(0));
593 
594         // Build where clause and title
595         QString wc = rule.getSelectSqlOrder();
596 
597         SKGStringListList result;
598         int vAll = 0;
599         getDocument()->executeSelectSqliteOrder("SELECT count(distinct(id)) from v_operation_prop WHERE " % wc, result);
600         if (result.count() == 2) {
601             vAll = SKGServices::stringToInt(result.at(1).at(0));
602         }
603 
604         int vNotChecked = 0;
605         getDocument()->executeSelectSqliteOrder("SELECT count(distinct(id)) from v_operation_prop WHERE t_status!='Y' AND " % wc, result);
606         if (result.count() == 2) {
607             vNotChecked = SKGServices::stringToInt(result.at(1).at(0));
608         }
609 
610         int vImported = 0;
611         getDocument()->executeSelectSqliteOrder("SELECT count(distinct(id)) from v_operation_prop WHERE t_imported!='N' AND " % wc, result);
612         if (result.count() == 2) {
613             vImported = SKGServices::stringToInt(result.at(1).at(0));
614         }
615 
616         int vNotValidatedl = 0;
617         getDocument()->executeSelectSqliteOrder("SELECT count(distinct(id)) from v_operation_prop WHERE t_imported='P' AND " % wc, result);
618         if (result.count() == 2) {
619             vNotValidatedl = SKGServices::stringToInt(result.at(1).at(0));
620         }
621 
622         ui.kQueryInfo->setText(i18np("%1 operation found (%2 imported, %3 not yet validated, %4 not checked).", "%1 operations found (%2 imported, %3 not yet validated, %4 not checked).", vAll, vImported, vNotValidatedl, vNotChecked));
623     }
624 }
625 
cleanEditor()626 void SKGSearchPluginWidget::cleanEditor()
627 {
628     if (getNbSelectedObjects() == 0) {
629         ui.kQueryCreator->clearContents();
630         ui.kActionCreator->clearContents();
631     }
632 }
633 
getXMLActionDefinition()634 QString SKGSearchPluginWidget::getXMLActionDefinition()
635 {
636     QString output;
637     if (ui.kWidgetSelector->getSelectedMode() == 1) {
638         // Mode update
639         output = ui.kActionCreator->getXMLCondition();
640     } else if (ui.kWidgetSelector->getSelectedMode() == 2) {
641         // Mode alarm
642         QDomDocument doc(QStringLiteral("SKGML"));
643         QDomElement element = doc.createElement(QStringLiteral("element"));
644         doc.appendChild(element);
645 
646         QDomElement elementLine = doc.createElement(QStringLiteral("element"));
647         element.appendChild(elementLine);
648 
649         QDomElement elementElement = doc.createElement(QStringLiteral("element"));
650         elementLine.appendChild(elementElement);
651 
652         elementElement.setAttribute(QStringLiteral("attribute"), QStringLiteral("f_REALCURRENTAMOUNT"));
653         elementElement.setAttribute(QStringLiteral("operator"), QStringLiteral("ABS(TOTAL(#ATT#))#OP##V1#,ABS(TOTAL(#ATT#)), #V1#, '#V2S#'"));
654         elementElement.setAttribute(QStringLiteral("operator2"), QStringLiteral(">="));
655         elementElement.setAttribute(QStringLiteral("value"), SKGServices::doubleToString(ui.kAlarmAmount->value()));
656         elementElement.setAttribute(QStringLiteral("value2"), ui.kAlarmMessage->text());
657 
658         output = doc.toString();
659     } else if (ui.kWidgetSelector->getSelectedMode() == 3) {
660         // Mode template
661         QDomDocument doc(QStringLiteral("SKGML"));
662         QDomElement element = doc.createElement(QStringLiteral("element"));
663         doc.appendChild(element);
664 
665         QDomElement elementLine = doc.createElement(QStringLiteral("element"));
666         element.appendChild(elementLine);
667 
668         QDomElement elementElement = doc.createElement(QStringLiteral("element"));
669         elementLine.appendChild(elementElement);
670 
671         elementElement.setAttribute(QStringLiteral("attribute"), QStringLiteral("id"));
672         elementElement.setAttribute(QStringLiteral("operator"), QStringLiteral("APPLYTEMPLATE(#V1#)"));
673         elementElement.setAttribute(QStringLiteral("value"), ui.kTemplate->itemData(ui.kTemplate->currentIndex()).toString());
674         elementElement.setAttribute(QStringLiteral("value2"), ui.kTemplate->currentText());
675 
676         output = doc.toString();
677     }
678     return output;
679 }
680 
isEditor()681 bool SKGSearchPluginWidget::isEditor()
682 {
683     return true;
684 }
685 
activateEditor()686 void SKGSearchPluginWidget::activateEditor()
687 {
688     if (ui.kWidgetSelector->getSelectedMode() == -1) {
689         ui.kWidgetSelector->setSelectedMode(0);
690     }
691 }
692 
693 
694 
695 
696