diff --git a/plugins/skrooge/skrooge_budget/skgbudgetpluginwidget.cpp b/plugins/skrooge/skrooge_budget/skgbudgetpluginwidget.cpp index 2074268ec..17a365442 100644 --- a/plugins/skrooge/skrooge_budget/skgbudgetpluginwidget.cpp +++ b/plugins/skrooge/skrooge_budget/skgbudgetpluginwidget.cpp @@ -1,834 +1,840 @@ /*************************************************************************** * Copyright (C) 2008 by S. MANKOWSKI / G. DE BURE support@mankowski.fr * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program. If not, see * ***************************************************************************/ /** @file * A skrooge plugin to manage budgets. * * @author Stephane MANKOWSKI */ #include "skgbudgetpluginwidget.h" #include #include #include "skgbudgetdelegate.h" #include "skgbudgetobject.h" #include "skgbudgetruleobject.h" #include "skgcategoryobject.h" #include "skgdocument.h" #include "skgmainpanel.h" #include "skgobjectmodel.h" #include "skgtraces.h" #include "skgtransactionmng.h" SKGBudgetPluginWidget::SKGBudgetPluginWidget(QWidget* iParent, SKGDocument* iDocument) : SKGTabPage(iParent, iDocument), m_objectModel(nullptr) { SKGTRACEINFUNC(1) if (iDocument == nullptr) { return; } ui.setupUi(this); ui.kUseScheduledOperation->hide(); ui.kTopBtn->setIcon(SKGServices::fromTheme(QStringLiteral("arrow-up-double"))); ui.kUpBtn->setIcon(SKGServices::fromTheme(QStringLiteral("arrow-up"))); ui.kDownBtn->setIcon(SKGServices::fromTheme(QStringLiteral("arrow-down"))); ui.kBottomBtn->setIcon(SKGServices::fromTheme(QStringLiteral("arrow-down-double"))); ui.kPeriodLbl->setText(i18n("%1:", iDocument->getDisplay(QStringLiteral("t_period")))); ui.kYearLbl->setText(i18n("%1:", iDocument->getDisplay(QStringLiteral("i_year")))); ui.kMonthLbl->setText(i18n("%1:", iDocument->getDisplay(QStringLiteral("i_month")))); ui.kAmountLabel->setText(i18n("%1:", iDocument->getDisplay(QStringLiteral("f_value")))); ui.kCategoryLabel->setText(i18n("%1:", iDocument->getDisplay(QStringLiteral("t_category")))); ui.kYearCheck->setText(i18n("%1:", iDocument->getDisplay(QStringLiteral("i_year")))); ui.kMonthCheck->setText(i18n("%1:", iDocument->getDisplay(QStringLiteral("i_month")))); ui.kCategoryCheck->setText(i18n("%1:", iDocument->getDisplay(QStringLiteral("t_category")))); ui.kPeriodLbl2->setText(i18n("%1:", iDocument->getDisplay(QStringLiteral("t_period")))); ui.kAmountLabel2->setText(i18n("%1:", iDocument->getDisplay(QStringLiteral("f_value")))); ui.kCategoryTransferCheck->setText(i18n("%1:", iDocument->getDisplay(QStringLiteral("t_category")))); ui.kYear->setValue(QDate::currentDate().year()); ui.kYearAutoBase->setValue(QDate::currentDate().year()); ui.kMonth->setValue(QDate::currentDate().month()); ui.kPeriod->addItem(i18nc("Noun, how to define a budget period", "Monthly")); ui.kPeriod->addItem(i18nc("Noun, how to define a budget period", "Yearly")); ui.kPeriod->addItem(i18nc("Noun, how to define a budget period", "Individual")); ui.kView->getShowWidget()->addItem(QStringLiteral("all"), i18nc("Noun, budget items to display", "All"), QLatin1String(""), QLatin1String(""), QStringLiteral("current;currentYear;currentMonth;previousYear;previousMonth"), QStringLiteral("none"), QLatin1String(""), QLatin1String(""), Qt::META + Qt::Key_A); ui.kView->getShowWidget()->addItem(QStringLiteral("none"), i18nc("Noun, budget items to display", "None"), QLatin1String(""), QStringLiteral("1=0"), QLatin1String(""), // Check when checked QStringLiteral("all;current;currentYear;currentMonth;previousYear;previousMonth"), // Uncheck when checked QLatin1String(""), // Check when unchecked QStringLiteral("all"), // Uncheck when unchecked Qt::META + Qt::Key_0); ui.kView->getShowWidget()->addSeparator(); ui.kView->getShowWidget()->addItem(QStringLiteral("current"), i18nc("Noun, budget items to display", "Current"), QStringLiteral("view-calendar-whatsnext"), QStringLiteral("t_PERIOD>=STRFTIME('%Y-%m', date('now')) OR t_PERIOD=STRFTIME('%Y', date('now'))"), QStringLiteral("currentMonth"), // Check when checked QStringLiteral("none"), // Uncheck when checked QLatin1String(""), // Check when unchecked QStringLiteral("all"), // Uncheck when unchecked Qt::META + Qt::Key_1); ui.kView->getShowWidget()->addSeparator(); ui.kView->getShowWidget()->addItem(QStringLiteral("currentYear"), i18nc("Noun, budget items to display", "Current year"), QStringLiteral("view-calendar-month"), QStringLiteral("t_PERIOD LIKE STRFTIME('%Y', date('now'))||'%'"), QLatin1String(""), QStringLiteral("none"), QLatin1String(""), QStringLiteral("all"), Qt::META + Qt::Key_3); ui.kView->getShowWidget()->addItem(QStringLiteral("currentMonth"), i18nc("Noun, budget items to display", "Current month"), QStringLiteral("view-calendar-week"), QStringLiteral("t_PERIOD=STRFTIME('%Y-%m', date('now'))"), QLatin1String(""), QStringLiteral("none"), QLatin1String(""), QStringLiteral("all;current"), Qt::META + Qt::Key_2); ui.kView->getShowWidget()->addSeparator(); ui.kView->getShowWidget()->addItem(QStringLiteral("previousYear"), i18nc("Noun, budget items to display", "Previous year"), QStringLiteral("view-calendar-month"), QStringLiteral("t_PERIOD LIKE STRFTIME('%Y', date('now','start of year','-1 day'))||'%'"), QLatin1String(""), QStringLiteral("none"), QLatin1String(""), QStringLiteral("all"), Qt::META + Qt::Key_5); ui.kView->getShowWidget()->addItem(QStringLiteral("previousMonth"), i18nc("Noun, budget items to display", "Previous month"), QStringLiteral("view-calendar-week"), QStringLiteral("t_PERIOD=STRFTIME('%Y-%m', date('now','start of month','-1 day'))"), QLatin1String(""), QStringLiteral("none"), QLatin1String(""), QStringLiteral("all"), Qt::META + Qt::Key_4); ui.kView->getShowWidget()->setDefaultState(QStringLiteral("current;currentMonth")); m_timer.setSingleShot(true); connect(&m_timer, &QTimer::timeout, this, &SKGBudgetPluginWidget::refreshInfoZone, Qt::QueuedConnection); ui.kConditionCmb->addItem(i18nc("Noun, condition item to a apply a transfer of budget", "All"), static_cast(SKGBudgetRuleObject::ALL)); ui.kConditionCmb->addItem(i18nc("Noun, condition item to a apply a transfer of budget", "Negative"), static_cast(SKGBudgetRuleObject::NEGATIVE)); ui.kConditionCmb->addItem(i18nc("Noun, condition item to a apply a transfer of budget", "Positive"), static_cast(SKGBudgetRuleObject::POSITIVE)); ui.kModeCmb->addItem(i18nc("Noun, mode item to a apply a transfer of budget", "Next"), static_cast(SKGBudgetRuleObject::NEXT)); ui.kModeCmb->addItem(i18nc("Noun, mode item to a apply a transfer of budget", "Current"), static_cast(SKGBudgetRuleObject::CURRENT)); ui.kModeCmb->addItem(i18nc("Noun, mode item to a apply a transfer of budget", "Current year"), static_cast(SKGBudgetRuleObject::YEAR)); ui.kView->getView()->setItemDelegate(new SKGBudgetDelegate(ui.kView->getView(), getDocument())); auto* doc = qobject_cast(getDocument()); if (doc != nullptr) { ui.kUnitCmb->addItem(QStringLiteral("%")); ui.kUnitCmb->addItem(doc->getPrimaryUnit().Symbol); ui.kUnit->setText(doc->getPrimaryUnit().Symbol); // Bind operation view m_objectModel = new SKGObjectModel(doc, QStringLiteral("v_budget_display"), QStringLiteral("1=0"), this, QLatin1String(""), false); ui.kView->setModel(m_objectModel); ui.kSortButton->setVisible(false); } connect(ui.kView->getView(), &SKGTreeView::doubleClicked, SKGMainPanel::getMainPanel()->getGlobalAction(QStringLiteral("open")).data(), &QAction::trigger); connect(ui.kView->getView(), &SKGTreeView::selectionChangedDelayed, this, [ = ] {this->onSelectionChanged();}); // Add Standard KDE Icons to buttons to Operations ui.kModifyBtn->setIcon(SKGServices::fromTheme(QStringLiteral("dialog-ok"))); ui.kAddBtn->setIcon(SKGServices::fromTheme(QStringLiteral("list-add"))); QAction* processAction = SKGMainPanel::getMainPanel()->getGlobalAction(QStringLiteral("tool_process_budget_rules")); if (processAction != nullptr) { ui.kProcessBtn->setIcon(processAction->icon()); connect(ui.kProcessBtn, &QPushButton::clicked, processAction, &QAction::trigger); } { SKGWidgetSelector::SKGListQWidget list; list.push_back(ui.SKGManualSection); list.push_back(ui.SKGEditionButtonsSection); ui.kWidgetSelector->addButton(SKGServices::fromTheme(QStringLiteral("user-properties")), i18n("Manual"), i18n("Display the edit panel for standard budget"), list); } { SKGWidgetSelector::SKGListQWidget list; list.push_back(ui.SKGAutoSection); list.push_back(ui.SKGEditionButtonsSection); ui.kWidgetSelector->addButton(SKGServices::fromTheme(QStringLiteral("games-solve")), i18n("Auto"), i18n("Display the edit panel for automatic budgets"), list); } { SKGWidgetSelector::SKGListQWidget list; list.push_back(ui.SKGRuleSection); list.push_back(ui.SKGEditionButtonsSection); ui.kWidgetSelector->addButton(SKGServices::fromTheme(QStringLiteral("run-build")), i18n("Rules"), i18n("Display the edit panel for rules"), list); } connect(ui.kWidgetSelector, &SKGWidgetSelector::selectedModeChanged, this, &SKGBudgetPluginWidget::onBtnModeClicked, Qt::QueuedConnection); connect(ui.kAddBtn, &QPushButton::clicked, this, &SKGBudgetPluginWidget::onAddClicked); connect(ui.kModifyBtn, &QPushButton::clicked, this, &SKGBudgetPluginWidget::onUpdateClicked); connect(ui.kAmountEdit, &SKGCalculatorEdit::textChanged, this, &SKGBudgetPluginWidget::onCreatorModified); connect(ui.kPeriod, static_cast(&SKGComboBox::currentTextChanged), this, &SKGBudgetPluginWidget::onCreatorModified); connect(ui.kYearCheck, &QCheckBox::toggled, ui.kYearRule, &QSpinBox::setEnabled); connect(ui.kMonthCheck, &QCheckBox::toggled, ui.kMonthRule, &QSpinBox::setEnabled); connect(ui.kCategoryCheck, &QCheckBox::toggled, ui.kCategoryRule, &SKGComboBox::setEnabled); connect(ui.kCategoryTransferCheck, &QCheckBox::toggled, ui.kCategoryTransfer, &SKGComboBox::setEnabled); connect(ui.kModeCmb, static_cast(&SKGComboBox::currentIndexChanged), this, &SKGBudgetPluginWidget::onCreatorModified); connect(ui.kAutoBudgetCheck, &QCheckBox::toggled, ui.kYearAutoBase, &QSpinBox::setEnabled); connect(ui.kAutoBudgetCheck, &QCheckBox::toggled, ui.kRemovePrevious, &QCheckBox::setEnabled); connect(ui.kAutoBudgetCheck, &QCheckBox::toggled, ui.kUseScheduledOperation, &QCheckBox::setEnabled); connect(ui.kTopBtn, &QToolButton::clicked, this, &SKGBudgetPluginWidget::onTop); connect(ui.kUpBtn, &QToolButton::clicked, this, &SKGBudgetPluginWidget::onUp); connect(ui.kDownBtn, &QToolButton::clicked, this, &SKGBudgetPluginWidget::onDown); connect(ui.kBottomBtn, &QToolButton::clicked, this, &SKGBudgetPluginWidget::onBottom); +#if QT_VERSION < QT_VERSION_CHECK(5, 14, 0) + connect(ui.kYearAuto, static_cast(&QSpinBox::valueChanged), this, [ = ](const QString & text) { + ui.kRemovePrevious->setText(i18nc("Option", "Remove existing budgets for %1", text)); + }); +#else connect(ui.kYearAuto, &QSpinBox::textChanged, this, [ = ](const QString & text) { ui.kRemovePrevious->setText(i18nc("Option", "Remove existing budgets for %1", text)); }); +#endif ui.kYearAuto->setValue(QDate::currentDate().year()); ui.kWidgetSelector->setSelectedMode(0); // Set Event filters to catch CTRL+ENTER or SHIFT+ENTER this->installEventFilter(this); // Refresh connect(getDocument(), &SKGDocument::tableModified, this, &SKGBudgetPluginWidget::dataModified, Qt::QueuedConnection); dataModified(QLatin1String(""), 0); } SKGBudgetPluginWidget::~SKGBudgetPluginWidget() { SKGTRACEINFUNC(1) m_objectModel = nullptr; } bool SKGBudgetPluginWidget::eventFilter(QObject* iObject, QEvent* iEvent) { if ((iEvent != nullptr) && iEvent->type() == QEvent::KeyPress) { auto* keyEvent = dynamic_cast(iEvent); if (keyEvent && (keyEvent->key() == Qt::Key_Return || keyEvent->key() == Qt::Key_Enter) && iObject == this) { if ((QApplication::keyboardModifiers() & Qt::ControlModifier) != 0u && ui.kAddBtn->isEnabled()) { ui.kAddBtn->click(); } else if ((QApplication::keyboardModifiers() &Qt::ShiftModifier) != 0u && ui.kModifyBtn->isEnabled()) { ui.kModifyBtn->click(); } } } return SKGTabPage::eventFilter(iObject, iEvent); } QString SKGBudgetPluginWidget::getState() { SKGTRACEINFUNC(10) QDomDocument doc(QStringLiteral("SKGML")); QDomElement root = doc.createElement(QStringLiteral("parameters")); doc.appendChild(root); root.setAttribute(QStringLiteral("currentPage"), SKGServices::intToString(ui.kWidgetSelector->getSelectedMode())); if ((m_objectModel != nullptr) && m_objectModel->getRealTable() == QStringLiteral("budget")) { root.setAttribute(QStringLiteral("view"), ui.kView->getState()); root.setAttribute(QStringLiteral("viewRule"), m_viewRule); } else { root.setAttribute(QStringLiteral("view"), m_viewBudget); root.setAttribute(QStringLiteral("viewRule"), ui.kView->getState()); } return doc.toString(); } void SKGBudgetPluginWidget::setState(const QString& iState) { SKGTRACEINFUNC(10) QDomDocument doc(QStringLiteral("SKGML")); doc.setContent(iState); QDomElement root = doc.documentElement(); QString currentPage = root.attribute(QStringLiteral("currentPage")); if (currentPage.isEmpty()) { currentPage = '0'; } ui.kWidgetSelector->setSelectedMode(SKGServices::stringToInt(currentPage)); m_viewBudget = root.attribute(QStringLiteral("view")); m_viewRule = root.attribute(QStringLiteral("viewRule")); if ((m_objectModel != nullptr) && m_objectModel->getRealTable() == QStringLiteral("budget")) { ui.kView->setState(m_viewBudget); } else { ui.kView->setState(m_viewRule); } } QString SKGBudgetPluginWidget::getDefaultStateAttribute() { return QStringLiteral("SKGBUDGET_DEFAULT_PARAMETERS"); } QWidget* SKGBudgetPluginWidget::mainWidget() { return ui.kView->getView(); } void SKGBudgetPluginWidget::refresh() { SKGTRACEINFUNC(1) QSqlDatabase* db = getDocument()->getMainDatabase(); setEnabled(db != nullptr); if (db != nullptr) { // Refresh yours widgets here } } void SKGBudgetPluginWidget::dataModified(const QString& iTableName, int iIdTransaction, bool iLightTransaction) { SKGTRACEINFUNC(10) Q_UNUSED(iIdTransaction) // Refresh widgets if (iTableName == QStringLiteral("budget") || iTableName.isEmpty()) { // Refresh info area m_timer.start(300); } if (!iLightTransaction) { if (iTableName == QStringLiteral("category") || iTableName.isEmpty()) { // Set type category SKGMainPanel::fillWithDistinctValue(QList() << ui.kCategoryEdit << ui.kCategoryRule << ui.kCategoryTransfer, getDocument(), QStringLiteral("category"), QStringLiteral("t_fullname"), QLatin1String("")); } } } void SKGBudgetPluginWidget::onBtnModeClicked(int mode) { SKGTRACEINFUNC(10) if (m_objectModel == nullptr) { return; } if (mode == 2 && m_objectModel->getTable() != QStringLiteral("v_budgetrule_display")) { ui.kView->getShowWidget()->setEnabled(false); m_viewBudget = ui.kView->getState(); m_objectModel->setFilter(QLatin1String("")); m_objectModel->setTable(QStringLiteral("v_budgetrule_display")); ui.kSortButton->setVisible(true); ui.kView->setState(m_viewRule); } else if (mode != 2 && m_objectModel->getTable() != QStringLiteral("v_budget_display")) { ui.kView->getShowWidget()->setEnabled(true); m_viewRule = ui.kView->getState(); m_objectModel->setTable(QStringLiteral("v_budget_display")); ui.kSortButton->setVisible(false); ui.kView->setState(m_viewBudget); } onCreatorModified(); } void SKGBudgetPluginWidget::onAddClicked() { SKGError err; _SKGTRACEINFUNCRC(10, err) if (ui.kWidgetSelector->getSelectedMode() == 2) { // Creation of a rule QStringList uniqueIDs; { SKGBEGINTRANSACTION(*getDocument(), i18nc("Noun, name of the user action", "Budget rule creation"), err) SKGBudgetRuleObject budgetRule(getDocument()); IFOKDO(err, updateBudgetRule(budgetRule)) IFOKDO(err, budgetRule.setOrder(-1)) IFOKDO(err, budgetRule.save()) uniqueIDs.push_back(budgetRule.getUniqueID()); // Send message IFOKDO(err, budgetRule.getDocument()->sendMessage(i18nc("An information to the user", "The budget rule '%1' has been added", budgetRule.getDisplayName()), SKGDocument::Hidden)) } // status bar IFOK(err) { err = SKGError(0, i18nc("Successful message after an user action", "Budget rule created")); ui.kView->getView()->selectObjects(uniqueIDs); } else { err.addError(ERR_FAIL, i18nc("Error message", "Budget rule creation failed")); } } else { // Creation of a budget QStringList uniqueIDs; { SKGBEGINPROGRESSTRANSACTION(*getDocument(), i18nc("Noun, name of the user action", "Budget creation"), err, 2) if (ui.kWidgetSelector->getSelectedMode() == 0) { // Manual creation int mode = ui.kPeriod->currentIndex(); if (mode == 0) { // Monthly for (int m = 1; !err && m <= 12; ++m) { SKGBudgetObject budget(getDocument()); IFOKDO(err, updateBudget(budget, m)) // Send message IFOKDO(err, getDocument()->sendMessage(i18nc("An information to the user", "The budget '%1' has been added", budget.getDisplayName()), SKGDocument::Hidden)) uniqueIDs.push_back(budget.getUniqueID()); } } else if (mode == 1) { // Yearly SKGBudgetObject budget(getDocument()); IFOKDO(err, updateBudget(budget, 0)) // Send message IFOKDO(err, getDocument()->sendMessage(i18nc("An information to the user", "The budget '%1' has been added", budget.getDisplayName()), SKGDocument::Hidden)) uniqueIDs.push_back(budget.getUniqueID()); } else { // Individual SKGBudgetObject budget(getDocument()); IFOKDO(err, updateBudget(budget)) // Send message IFOKDO(err, getDocument()->sendMessage(i18nc("An information to the user", "The budget '%1' has been added", budget.getDisplayName()), SKGDocument::Hidden)) uniqueIDs.push_back(budget.getUniqueID()); } } else { // Automatic creation if (ui.kAutoBudgetCheck->isChecked()) { err = SKGBudgetObject::createAutomaticBudget(qobject_cast(getDocument()), ui.kYearAuto->value(), ui.kYearAutoBase->value(), ui.kUseScheduledOperation->isChecked(), ui.kRemovePrevious->isChecked()); } IFOKDO(err, getDocument()->stepForward(1)) IFOKDO(err, SKGBudgetObject::balanceBudget(qobject_cast(getDocument()), ui.kYearAuto->value(), (ui.kBalancingMonthly->isChecked() ? 0 : -1), ui.kBalancingAnnual->isChecked())); IFOKDO(err, getDocument()->stepForward(2)) } } // status bar IFOK(err) { err = SKGError(0, i18nc("Successful message after an user action", "Budget created")); ui.kView->getView()->selectObjects(uniqueIDs); } else { err.addError(ERR_FAIL, i18nc("Error message", "Budget creation failed")); } } // Display error SKGMainPanel::displayErrorMessage(err, true); } void SKGBudgetPluginWidget::onUpdateClicked() { SKGError err; SKGTRACEINFUNCRC(10, err) // Get Selection SKGObjectBase::SKGListSKGObjectBase selection = getSelectedObjects(); if (ui.kWidgetSelector->getSelectedMode() == 2) { { SKGBEGINTRANSACTION(*getDocument(), i18nc("Noun, name of the user action", "Budget rule update"), err) SKGBudgetRuleObject rule(selection.at(0)); IFOKDO(err, updateBudgetRule(rule)) // Send message IFOKDO(err, rule.getDocument()->sendMessage(i18nc("An information to the user", "The budget rule '%1' has been updated", rule.getDisplayName()), SKGDocument::Hidden)) } // status bar IFOK(err) { err = SKGError(0, i18nc("Successful message after an user action", "Budget rule updated")); } else { err.addError(ERR_FAIL, i18nc("Error message", "Budget rule update failed")); } } else { { int nb = selection.count(); SKGBEGINPROGRESSTRANSACTION(*getDocument(), i18nc("Noun, name of the user action", "Budget update"), err, nb) for (int i = 0; !err && i < nb; ++i) { SKGBudgetObject budget(selection.at(i)); int mode = ui.kPeriod->currentIndex(); if (mode == 1) { // Yearly err = updateBudget(budget, 0); } else { // Individual err = updateBudget(budget); } IFOKDO(err, getDocument()->stepForward(i + 1)) } } // status bar IFOK(err) { err = SKGError(0, i18nc("Successful message after an user action", "Budget updated")); } else { err.addError(ERR_FAIL, i18nc("Error message", "Budget update failed")); } } // Display error SKGMainPanel::displayErrorMessage(err, true); // Set focus on table ui.kView->getView()->setFocus(); } SKGError SKGBudgetPluginWidget::updateBudget(SKGBudgetObject& iBudget, int iMonth) { SKGError err; if (!err && ui.kYear->isEnabled()) { err = iBudget.setYear(ui.kYear->value()); } if (!err && ui.kMonth->isEnabled()) { err = iBudget.setMonth(iMonth != -1 ? iMonth : ui.kMonth->value()); } SKGCategoryObject cat; QString catName = ui.kCategoryEdit->text().trimmed(); IFOKDO(err, SKGCategoryObject::createPathCategory(qobject_cast(getDocument()), catName, cat, true)) IFOKDO(err, iBudget.setCategory(cat)) IFOKDO(err, iBudget.enableSubCategoriesInclusion(ui.kIncludingSubCategories->isChecked())) double val = ui.kAmountEdit->value(); // Is the sign forced ? if (ui.kAmountEdit->sign() == 0) { // No SKGObjectBase cat2(cat.getDocument(), QStringLiteral("v_category_display"), cat.getID()); // Are we able to find to sign with the category ? if (cat2.getAttribute(QStringLiteral("t_TYPEEXPENSE")) == QStringLiteral("-")) { val = -val; } } IFOKDO(err, iBudget.setBudgetedAmount(val)) IFOKDO(err, iBudget.save()) return err; } SKGError SKGBudgetPluginWidget::updateBudgetRule(SKGBudgetRuleObject& iRule) { SKGError err; SKGCategoryObject cat; QString catName = ui.kCategoryRule->text().trimmed(); IFOKDO(err, SKGCategoryObject::createPathCategory(qobject_cast(getDocument()), catName, cat, true)) SKGCategoryObject catchange; QString catchangeName = ui.kCategoryTransfer->text().trimmed(); IFOKDO(err, SKGCategoryObject::createPathCategory(qobject_cast(getDocument()), catchangeName, catchange, true)) IFOKDO(err, iRule.enableCategoryCondition(ui.kCategoryCheck->isChecked())) IFOKDO(err, iRule.setBudgetCategory(cat)) IFOKDO(err, iRule.enableYearCondition(ui.kYearCheck->isChecked())) IFOKDO(err, iRule.setBudgetYear(ui.kYearRule->value())) IFOKDO(err, iRule.enableMonthCondition(ui.kMonthCheck->isChecked())) IFOKDO(err, iRule.setBudgetMonth(ui.kMonthRule->value())) IFOK(err) { bool absolute = (ui.kUnitCmb->currentIndex() == 1); double val = ui.kAmountEdit2->value(); if (!absolute) { val = qMin(qMax(static_cast(0), val), static_cast(100)); } err = iRule.setQuantity(val, absolute); } IFOKDO(err, iRule.setCondition(static_cast(ui.kConditionCmb->itemData(ui.kConditionCmb->currentIndex()).toInt()))) IFOKDO(err, iRule.enableCategoryChange(ui.kCategoryTransferCheck->isChecked())) IFOKDO(err, iRule.setTransfer(static_cast(ui.kModeCmb->itemData(ui.kModeCmb->currentIndex()).toInt()), catchange)) IFOKDO(err, iRule.save()) return err; } void SKGBudgetPluginWidget::onCreatorModified() { bool test = !ui.kAmountEdit->text().isEmpty() && !ui.kYear->text().isEmpty(); ui.kAddBtn->setEnabled(test || ui.kWidgetSelector->getSelectedMode() != 0); ui.kModifyBtn->setEnabled((test && ui.kPeriod->currentIndex() != 0 && ui.kWidgetSelector->getSelectedMode() == 0 && (getNbSelectedObjects() != 0)) || (ui.kWidgetSelector->getSelectedMode() == 2 && getNbSelectedObjects() == 1)); bool monthCondition = (ui.kPeriod->currentIndex() == 2 || ui.kWidgetSelector->getSelectedMode() == 2); ui.kMonthLbl->setVisible(monthCondition); ui.kMonth->setVisible(monthCondition); } void SKGBudgetPluginWidget::onSelectionChanged() { SKGTRACEINFUNC(10) if (m_objectModel == nullptr) { return; } SKGObjectBase::SKGListSKGObjectBase objs = getSelectedObjects(); int nb = objs.count(); int mode = ui.kWidgetSelector->getSelectedMode(); if (nb != 0) { if (m_objectModel->getRealTable() == QStringLiteral("budget")) { SKGBudgetObject budget(objs.at(0)); ui.kYear->setValue(budget.getYear()); ui.kMonth->setValue(budget.getMonth()); ui.kAmountEdit->setValue(budget.getBudgetedAmount()); ui.kCategoryEdit->setText(budget.getAttribute(QStringLiteral("t_CATEGORY"))); ui.kPeriod->setCurrentIndex(budget.getMonth() == 0 ? 1 : 2); // Set yearly or individual ui.kIncludingSubCategories->setChecked(budget.isSubCategoriesInclusionEnabled()); if (mode > 0) { ui.kWidgetSelector->setSelectedMode(0); } } else { SKGBudgetRuleObject rule(objs.at(0)); ui.kYearCheck->setChecked(rule.isYearConditionEnabled()); ui.kYearRule->setValue(rule.getBudgetYear()); ui.kMonthCheck->setChecked(rule.isMonthConditionEnabled()); ui.kMonthRule->setValue(rule.getBudgetMonth()); ui.kCategoryCheck->setChecked(rule.isCategoryConditionEnabled()); ui.kCategoryRule->setText(rule.getAttribute(QStringLiteral("t_CATEGORYCONDITION"))); ui.kCategoryTransferCheck->setChecked(rule.isCategoryChangeEnabled()); ui.kCategoryTransfer->setText(rule.getAttribute(QStringLiteral("t_CATEGORY"))); ui.kUnitCmb->setCurrentIndex(rule.isAbolute() ? 1 : 0); ui.kAmountEdit2->setValue(rule.getQuantity()); ui.kModeCmb->setCurrentIndex(ui.kModeCmb->findData(static_cast(rule.getTransferMode()))); ui.kConditionCmb->setCurrentIndex(ui.kConditionCmb->findData(static_cast(rule.getCondition()))); } } ui.kPeriod->setEnabled(nb <= 1); ui.kYear->setEnabled(nb <= 1); ui.kMonth->setEnabled(nb <= 1); onCreatorModified(); refreshInfoZone(); Q_EMIT selectionChanged(); } void SKGBudgetPluginWidget::activateEditor() { if (ui.kWidgetSelector->getSelectedMode() == -1) { ui.kWidgetSelector->setSelectedMode(0); } ui.kAmountEdit->setFocus(); } bool SKGBudgetPluginWidget::isEditor() { return true; } void SKGBudgetPluginWidget::refreshInfoZone() { SKGTRACEINFUNC(10) auto* doc = qobject_cast(getDocument()); if ((doc != nullptr) && ui.kWidgetSelector->getSelectedMode() != 2) { SKGServices::SKGUnitInfo primary = doc->getPrimaryUnit(); SKGServices::SKGUnitInfo secondary = doc->getSecondaryUnit(); // Refresh info area with selection SKGObjectBase::SKGListSKGObjectBase selection = getSelectedObjects(); double budgeted = 0; double modified = 0; int nb = selection.count(); for (int i = 0; i < nb; ++i) { SKGBudgetObject budget(selection.at(i)); budgeted += budget.getBudgetedAmount(); modified += budget.getBudgetedModifiedAmount(); } QString budgetedS = doc->formatMoney(budgeted, primary); QString modifiedS = doc->formatMoney(modified, primary); QString v = (budgetedS == modifiedS ? budgetedS : modifiedS % " " % budgetedS % ""); if (nb != 0) { ui.kInfo->setText(i18np("Selection: %1 budget for %2", "Selection: %1 budgets for %2", nb, v)); if (!secondary.Symbol.isEmpty() && (secondary.Value != 0.0)) { budgetedS = doc->formatMoney(budgeted, secondary); modifiedS = doc->formatMoney(modified, secondary); v = (budgetedS == modifiedS ? budgetedS : modifiedS % " " % budgetedS % ""); } ui.kInfo->setToolTip(i18np("Selection: %1 budget for %2", "Selection: %1 budgets for %2", nb, v)); } else { ui.kInfo->setText(i18nc("Noun", "Selection: none")); ui.kInfo->setToolTip(i18nc("Noun", "Selection: none")); } } } void SKGBudgetPluginWidget::onTop() { SKGError err; SKGTRACEINFUNCRC(1, err) // Get rules SKGObjectBase::SKGListSKGObjectBase rules = getSelectedObjects(); int nb = rules.count(); { SKGBEGINPROGRESSTRANSACTION(*getDocument(), i18nc("Noun, name of the user action", "Budget rule update"), err, nb) for (int i = nb - 1; !err && i >= 0; --i) { SKGBudgetRuleObject rule(rules.at(i)); double order = 1; SKGStringListList result; err = getDocument()->executeSelectSqliteOrder(QStringLiteral("SELECT min(f_sortorder) from budgetrule"), result); if (!err && result.count() == 2) { order = SKGServices::stringToDouble(result.at(1).at(0)) - 1; } IFOKDO(err, rule.setOrder(order)) IFOKDO(err, rule.save()) // Send message IFOKDO(err, getDocument()->sendMessage(i18nc("An information to the user", "The budget rule '%1' has been updated", rule.getDisplayName()), SKGDocument::Hidden)) IFOKDO(err, getDocument()->stepForward(i + 1)) } } // status bar IFOKDO(err, SKGError(0, i18nc("Successful message after an user action", "Budget rule updated"))) else { err.addError(ERR_FAIL, i18nc("Error message", "Budget rule update failed")); } // Display error SKGMainPanel::displayErrorMessage(err); } void SKGBudgetPluginWidget::onUp() { SKGError err; SKGTRACEINFUNCRC(1, err) // Get rules SKGObjectBase::SKGListSKGObjectBase rules = getSelectedObjects(); int nb = rules.count(); { SKGBEGINPROGRESSTRANSACTION(*getDocument(), i18nc("Noun, name of the user action", "Budget rule update"), err, nb) for (int i = 0; !err && i < nb; ++i) { SKGBudgetRuleObject rule(rules.at(i)); double order = rule.getOrder(); SKGStringListList result; err = getDocument()->executeSelectSqliteOrder("SELECT f_sortorder from budgetrule where f_sortorder<" % SKGServices::doubleToString(order) % " ORDER BY f_sortorder DESC", result); IFOK(err) { if (result.count() == 2) { order = SKGServices::stringToDouble(result.at(1).at(0)) - 1; } else if (result.count() >= 2) { order = (SKGServices::stringToDouble(result.at(1).at(0)) + SKGServices::stringToDouble(result.at(2).at(0))) / 2; } } IFOKDO(err, rule.setOrder(order)) IFOKDO(err, rule.save()) // Send message IFOKDO(err, getDocument()->sendMessage(i18nc("An information to the user", "The budget rule '%1' has been updated", rule.getDisplayName()), SKGDocument::Hidden)) IFOKDO(err, getDocument()->stepForward(i + 1)) } } // status bar IFOKDO(err, SKGError(0, i18nc("Successful message after an user action", "Budget rule updated"))) else { err.addError(ERR_FAIL, i18nc("Error message", "Budget rule update failed")); } // Display error SKGMainPanel::displayErrorMessage(err); } void SKGBudgetPluginWidget::onDown() { SKGError err; SKGTRACEINFUNCRC(1, err) // Get rules SKGObjectBase::SKGListSKGObjectBase rules = getSelectedObjects(); int nb = rules.count(); { SKGBEGINPROGRESSTRANSACTION(*getDocument(), i18nc("Noun, name of the user action", "Budget rule update"), err, nb) for (int i = nb - 1; !err && i >= 0; --i) { SKGBudgetRuleObject rule(rules.at(i)); double order = rule.getOrder(); SKGStringListList result; err = getDocument()->executeSelectSqliteOrder("SELECT f_sortorder from budgetrule where f_sortorder>" % SKGServices::doubleToString(order) % " ORDER BY f_sortorder ASC", result); IFOK(err) { if (result.count() == 2) { order = SKGServices::stringToDouble(result.at(1).at(0)) + 1; } else if (result.count() >= 2) { order = (SKGServices::stringToDouble(result.at(1).at(0)) + SKGServices::stringToDouble(result.at(2).at(0))) / 2; } } IFOKDO(err, rule.setOrder(order)) IFOKDO(err, rule.save()) // Send message IFOKDO(err, getDocument()->sendMessage(i18nc("An information to the user", "The budget rule '%1' has been updated", rule.getDisplayName()), SKGDocument::Hidden)) IFOKDO(err, getDocument()->stepForward(i + 1)) } } // status bar IFOKDO(err, SKGError(0, i18nc("Successful message after an user action", "Budget rule updated"))) else { err.addError(ERR_FAIL, i18nc("Error message", "Budget rule update failed")); } // Display error SKGMainPanel::displayErrorMessage(err); } void SKGBudgetPluginWidget::onBottom() { SKGError err; SKGTRACEINFUNCRC(1, err) // Get rules SKGObjectBase::SKGListSKGObjectBase rules = getSelectedObjects(); int nb = rules.count(); { SKGBEGINPROGRESSTRANSACTION(*getDocument(), i18nc("Noun, name of the user action", "Budget rule update"), err, nb) for (int i = 0; !err && i < nb; ++i) { SKGBudgetRuleObject rule(rules.at(i)); double order = 1; SKGStringListList result; err = getDocument()->executeSelectSqliteOrder(QStringLiteral("SELECT max(f_sortorder) from budgetrule"), result); if (!err && result.count() == 2) { order = SKGServices::stringToDouble(result.at(1).at(0)) + 1; } IFOKDO(err, rule.setOrder(order)) IFOKDO(err, rule.save()) // Send message IFOKDO(err, getDocument()->sendMessage(i18nc("An information to the user", "The budget rule '%1' has been updated", rule.getDisplayName()), SKGDocument::Hidden)) IFOKDO(err, getDocument()->stepForward(i + 1)) } } // status bar IFOKDO(err, SKGError(0, i18nc("Successful message after an user action", "Budget rule updated"))) else { err.addError(ERR_FAIL, i18nc("Error message", "Budget rule update failed")); } // Display error SKGMainPanel::displayErrorMessage(err); } diff --git a/scripts/skrooge-release.py b/scripts/skrooge-release.py index 8b28b5855..10ed6f4c7 100755 --- a/scripts/skrooge-release.py +++ b/scripts/skrooge-release.py @@ -1,383 +1,382 @@ #!/usr/bin/env python3 # -*- coding: utf-8 -*- #************************************************************************** #* Copyright (C) 2017 by S. MANKOWSKI / G. DE BURE support@mankowski.fr #* Redistribution and use in source and binary forms, with or without #* modification, are permitted provided that the following conditions #* are met: #* #* 1. Redistributions of source code must retain the above copyright #* notice, this list of conditions and the following disclaimer. #* 2. Redistributions in binary form must reproduce the above copyright #* notice, this list of conditions and the following disclaimer in the #* documentation and/or other materials provided with the distribution. #* #* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR #* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES #* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. #* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, #* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT #* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, #* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY #* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT #* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF #* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #************************************************************************** import argparse import datetime import os import shutil import subprocess import sys import fileinput __VERSION__ = '1.0.0' toolPath=os.path.dirname(os.path.realpath(__file__)) localPath=os.path.dirname(toolPath) tempDir='/data' class Releasor(object): def __init__(self, args): self.ubuntuVersions=['bionic', 'disco', 'eoan', 'focal'] self.workdingDir=os.path.join(tempDir, 'skrooge-release_' + args.version) print("# Working directory :" + self.workdingDir) if args.version.endswith(".0") or args.stable: self.ppa = "ppa" self.ppatotreat = ["beta", self.ppa] else: self.ppa = "beta" self.ppatotreat = [self.ppa] if os.path.exists(self.workdingDir): self.logfile = open(os.path.join(self.workdingDir, 'log.txt'), 'w') else: self.logfile = None def prepareWorkingDirectory(self, args): print('# Prepare the working directory') if os.path.exists(self.workdingDir): print('# Remove '+self.workdingDir) shutil.rmtree(self.workdingDir) os.mkdir(self.workdingDir) os.chdir(self.workdingDir) self.logfile = open(os.path.join(self.workdingDir, 'log.txt'), 'w') print('# DONE') return 0 def makeTarFile(self, args): rc = 0 if args.fromtar: print('# Make the tar file from '+args.fromtar) dst = os.path.join(self.workdingDir, 'skrooge-'+args.version+'.tar.xz') shutil.copyfile(args.fromtar, dst) print('# DONE') else: print('# Make the tar file') cmd = ['git', 'clone', 'https://github.com/KDE/releaseme.git'] self.logfile.write('### '+' '.join(cmd)+'\n') rc = subprocess.call(cmd, stdout=self.logfile, stderr=self.logfile) if rc == 0: cmd = ['releaseme/tarme.rb', '--version', args.version, '--origin', 'trunk', 'skrooge'] self.logfile.write('### '+' '.join(cmd)+'\n') rc = subprocess.call(cmd, stdout=self.logfile, stderr=self.logfile) shutil.rmtree(os.path.join(self.workdingDir, 'skrooge-'+args.version)) shutil.rmtree('releaseme') os.remove(os.path.join(self.workdingDir, 'release_data')) sig_file = os.path.join(self.workdingDir, 'skrooge-'+args.version+'.tar.xz.sig') if os.path.exists(sig_file): os.remove(sig_file) print('# '+("DONE" if rc == 0 else "FAILED")) return rc def updateTarFile(self, args): print('# Update the tar file') os.chdir(self.workdingDir) p = 'skrooge-'+args.version if os.path.exists(p): shutil.rmtree(p) tarfile = 'skrooge-'+args.version+'.tar.xz' print('# Untar '+tarfile) cmd = ['tar', '-xvf', tarfile] self.logfile.write('### '+' '.join(cmd)+'\n') rc = subprocess.call(cmd, stdout=self.logfile, stderr=self.logfile) if rc == 0: print('# Change the CMakeLists.txt') with open(os.path.join(p, 'CMakeLists.txt'), 'r') as fileCMakeLists: CMakeListsContent = '' for line in fileCMakeLists: if line.startswith('SET(SKG_VERSION'): print('# SKG_VERSION changes to "'+args.version+'"') CMakeListsContent += 'SET(SKG_VERSION "'+args.version+'")\n' else: if line.startswith('SET(SKG_BETA'): bb = 'BETA' if self.ppa == "beta" else '' print('# SKG_BETA changes to "'+bb+'"') CMakeListsContent += 'SET(SKG_BETA "'+bb+'")\n' else: if line.startswith('FEATURE_SUMMARY'): CMakeListsContent += line break else: CMakeListsContent += line with open(os.path.join(p, 'CMakeLists.txt'), 'w') as fileCMakeLists: fileCMakeLists.write(CMakeListsContent) #for line in fileinput.input(['skrooge/org.kde.skrooge.appdata.xml'], inplace=True): # print(line.replace('', '\n'), end='') print('# Build the new splash screen') buildPath = os.path.join(p, 'build') os.mkdir(buildPath) os.chdir(buildPath) cmd = ['cmake', '..', '-DCMAKE_INSTALL_PREFIX=`kf5-config --prefix`', '-DQT_PLUGIN_INSTALL_DIR=`kf5-config --qt-plugins`'] self.logfile.write('### '+' '.join(cmd)+'\n') rc = subprocess.call(cmd, stdout=self.logfile, stderr=self.logfile) if rc == 0: cmd = ['make', 'splash'] self.logfile.write('### '+' '.join(cmd)+'\n') rc = subprocess.call(cmd, stdout=self.logfile, stderr=self.logfile) if rc == 0: print('# Create the tar file') os.chdir(self.workdingDir) shutil.rmtree(buildPath) os.remove(tarfile) cmd = ['tar', '-cJf', tarfile, p] rc = subprocess.call(cmd, stdout=self.logfile, stderr=self.logfile) self.logfile.write('### '+' '.join(cmd)+'\n') if rc == 0: cmd = ['gpg2', '--armor', '--detach-sig', '-o', tarfile+'.sig', tarfile] self.logfile.write('### '+' '.join(cmd)+'\n') rc = subprocess.call(cmd, stdout=self.logfile, stderr=self.logfile) if rc == 0: print("Skrooge "+args.version+" released\n\nHi,\n\nCould you publish the following files in skrooge/"+("stable" if args.stable else "unstable")+"?\n") cmd = ['sha256sum', tarfile] self.logfile.write('### '+' '.join(cmd)+'\n') rc = subprocess.call(cmd) if rc == 0: cmd = ['sha256sum', tarfile+'.sig'] self.logfile.write('### '+' '.join(cmd)+'\n') rc = subprocess.call(cmd) print("Thank you.\nRegards.\n" ) if rc == 0: shutil.rmtree(p) print('# '+("DONE" if rc == 0 else "FAILED")) return rc def modify(self, args): print('# Get dsc') os.chdir(self.workdingDir) cmd = ['apt', 'source', 'skrooge'] self.logfile.write('### '+' '.join(cmd)+'\n') rc = subprocess.call(cmd, stdout=self.logfile, stderr=self.logfile) if rc == 0: previousPackage = [os.path.join(self.workdingDir, o) for o in os.listdir(self.workdingDir) if os.path.isdir(os.path.join(self.workdingDir, o)) and o.startswith('skrooge-')][0] print('# previousPackage='+previousPackage) os.chdir(previousPackage) if os.path.exists('debian'): shutil.rmtree('debian') cmd = ['tar', '-xvf', os.path.join(toolPath, 'skrooge-release-debian.tar.gz')] self.logfile.write('### '+' '.join(cmd)+'\n') rc = subprocess.call(cmd, stdout=self.logfile, stderr=self.logfile) if rc == 0: cmd = ['uupdate', '-u', 'skrooge-'+args.version+'.tar.xz'] self.logfile.write('### '+' '.join(cmd)+'\n') rc = subprocess.call(cmd, stdout=self.logfile, stderr=self.logfile) if rc == 0: # Read the changelog os.chdir('../skrooge-'+args.version) with open(os.path.join(self.workdingDir, 'skrooge-'+args.version+'/CHANGELOG'), 'r') as fileChangelog: fileChangelog.readline() # To pass the first line changelogContent = '' done = False for line in fileChangelog: if line.strip() == '' and done == False: changelogContent += ' -- Stephane MANKOWSKI (Perso) {}\n'.format(datetime.datetime.now().strftime('%a, %d %b %Y %H:%M:%S +0100')) done = True if not line.startswith(' -- '): changelogContent += line # for ppa in self.ppatotreat: for i in range(len(self.ubuntuVersions)): print('# {}/{}: {} - {}'.format(i+1, len(self.ubuntuVersions), self.ubuntuVersions[i], ppa)) f = open(os.path.join(self.workdingDir, 'skrooge-'+args.version+'/debian/control'), 'r') cf = f.read() f.close() - - if self.ubuntuVersions[i] == 'eoan': - print('# make changes for '+self.ubuntuVersions[i]) - f = open(os.path.join(self.workdingDir, 'skrooge-'+args.version+'/debian/control'), 'w') - f.write(cf.replace('libqjson-dev, \n', '').replace('libqjson0, ', '')) - f.close() + + print('# make changes for '+self.ubuntuVersions[i]) + f = open(os.path.join(self.workdingDir, 'skrooge-'+args.version+'/debian/control'), 'w') + f.write(cf.replace('libqjson-dev, \n', '').replace('libqjson0, ', '')) + f.close() with open(os.path.join(self.workdingDir, 'skrooge-'+args.version+'/debian/changelog'), 'w') as fileDebianChangelog: fileDebianChangelog.write('skrooge ('+args.version+'-0ubuntu1~'+ppa+str(i+1)+') '+self.ubuntuVersions[i]+'; urgency=medium\n') fileDebianChangelog.write(changelogContent+'\n') cmd = ['debuild', '-S', '-sa'] self.logfile.write('### '+' '.join(cmd)+'\n') rc = subprocess.call(cmd, stdout=self.logfile, stderr=self.logfile) if rc!=0: break if rc!=0: break print('# '+("DONE" if rc == 0 else "FAILED")) return rc def publishLaunchpad(self, args): print('# Publish on launchpad') rc = 0 if not args.publish: print('# Publication ignored') os.chdir(self.workdingDir) for ppa in self.ppatotreat: for i in range(len(self.ubuntuVersions)): print('# {}/{}: {} {}'.format(i+1, len(self.ubuntuVersions), self.ubuntuVersions[i], ppa)) cmd = ['dput', '-f', 'ppa:s-mankowski/'+ppa+'-kf5', 'skrooge_'+args.version+'-0ubuntu1~'+ppa+str(i+1)+'_source.changes'] if not args.publish: print('# '+' '.join(cmd)+'\n') else: self.logfile.write('### '+' '.join(cmd)+'\n') rc = subprocess.call(cmd, stdout=self.logfile, stderr=self.logfile) if rc!=0: break print('# '+("DONE" if rc == 0 else "FAILED")) return rc def publishKDE(self, args): print('# Publish on kde') rc = 0 if not args.publish: print("# Publication ignored") os.chdir(self.workdingDir) cmd = ['kdecp5', 'skrooge-'+args.version+'.tar.xz', 'ftp://upload.kde.org/incoming'] if not args.publish: print('# '+' '.join(cmd)+'\n') else: self.logfile.write('### '+' '.join(cmd)+'\n') rc = subprocess.call(cmd, stdout=self.logfile, stderr=self.logfile) if rc == 0: self.logfile.write('### '+' '.join(cmd)+'\n') cmd = ['kdecp5', 'skrooge-'+args.version+'.tar.xz.sig', 'ftp://upload.kde.org/incoming'] if not args.publish: print('# '+' '.join(cmd)+'\n') else: self.logfile.write('### '+' '.join(cmd)+'\n') rc = subprocess.call(cmd, stdout=self.logfile, stderr=self.logfile) print('# '+("DONE" if rc == 0 else "FAILED")) return rc def buildAppImage(self, args): print('# Generate App Image') os.chdir(self.workdingDir) targteappimage = os.path.join(self.workdingDir, "skrooge-"+args.version+'-x86_64.AppImage') if os.path.exists(targteappimage): os.remove(targteappimage) cmd = ['wget', '-c', '-nv', 'https://raw.githubusercontent.com/probonopd/AppImages/master/pkg2appimage'] self.logfile.write('### '+' '.join(cmd)+'\n') rc = subprocess.call(cmd, stdout=self.logfile, stderr=self.logfile) if rc == 0: #for line in fileinput.input(['pkg2appimage'], inplace=True): # print(line.replace('trusty', 'bionic').replace('xenial', 'bionic'), end='') os.chmod('./pkg2appimage', 0o775) if args.fromlocal: print('# Get appimage.yml from local path') cmd = ['cp', os.path.join(localPath, 'appimage.yml'), '.'] else: cmd = ['wget', '-c', '-nv', 'https://cgit.kde.org/skrooge.git/plain/appimage.yml'] self.logfile.write('### '+' '.join(cmd)+'\n') rc = subprocess.call(cmd, stdout=self.logfile, stderr=self.logfile) if rc == 0: if not args.stable: for line in fileinput.input(['appimage.yml'], inplace=True): print(line.replace('ppa-kf5', 'beta-kf5'), end='') cmd = ['./pkg2appimage', 'appimage.yml'] self.logfile.write('### '+' '.join(cmd)+'\n') rc = subprocess.call(cmd, stdout=self.logfile, stderr=self.logfile) if rc == 0: appimage_file = [os.path.join(self.workdingDir, "out/"+o) for o in os.listdir("./out") if o.endswith('.AppImage')][0] shutil.move(appimage_file, targteappimage) print('# '+("DONE" if rc == 0 else "FAILED")) return rc def buildSnap(self, args): print('# Generate Snap') os.chdir(self.workdingDir) targteappimage = os.path.join(self.workdingDir, "skrooge_"+args.version+'_amd64.snap') if os.path.exists(targteappimage): os.remove(targteappimage) if args.fromlocal: print('# Get snapcraft.yaml from local path') cmd = ['cp', os.path.join(localPath, 'snapcraft.yaml'), '.'] else: cmd = ['wget', '-c', '-nv', 'https://cgit.kde.org/skrooge.git/plain/snapcraft.yaml'] self.logfile.write('### '+' '.join(cmd)+'\n') rc = subprocess.call(cmd, stdout=self.logfile, stderr=self.logfile) if rc == 0: for line in fileinput.input(['snapcraft.yaml'], inplace=True): print(line.replace('version: "X.X.X"', 'version: "'+args.version+'"').replace('source: XXX', 'source: '+localPath if args.fromlocal else 'source: git://anongit.kde.org/skrooge.git'), end='') cmd = ['snapcraft'] self.logfile.write('### '+' '.join(cmd)+'\n') rc = subprocess.call(cmd, stdout=self.logfile, stderr=self.logfile) print('# '+("DONE" if rc == 0 else "FAILED")) # TO PUBLISH https://docs.snapcraft.io/build-snaps/c # snapcraft push --release=edge skrooge_*.snap return rc def main(): parser = argparse.ArgumentParser(prog='skrooge-release', description='skrooge release maker') # Global arguments parser.add_argument('--version', required=True, help='The release version') parser.add_argument('--fromtar', required=False, help='To copy an existing tar file instead of building it from git') parser.add_argument('--pwd', required=False, help='The password') parser.add_argument('--stable', action='store_true', help='To define this version as a master version') parser.add_argument('--publish', action='store_true', help='To publish on launchpad and KDE') parser.add_argument('--appimage', action='store_true', help='To generate the appimage only') parser.add_argument('--snap', action='store_true', help='To generate the snap only') parser.add_argument('--fromlocal', action='store_true', help='To generate The snap and the appimage from local path (' + localPath + ')') args = parser.parse_args() print("#####################") print("# Launching release #") print("#####################") print("# Version :" + args.version) print("# Stable :" + ("Y" if args.stable else "N")) print("# Publish :" + ("Y" if args.publish else "N")) print("# Appimage :" + ("Y" if args.appimage else "N")) print("# Snap :" + ("Y" if args.snap else "N")) if args.fromlocal: print("# From local path :" + localPath) # Launch the release r = Releasor(args) rc = 0 rc=r.prepareWorkingDirectory(args) if(rc == 0 and not (args.appimage or args.snap)): rc=r.makeTarFile(args) if(rc == 0 and not (args.appimage or args.snap)): rc=r.updateTarFile(args) if(rc == 0 and not (args.appimage or args.snap)): rc=r.modify(args) if(rc == 0 and not (args.appimage or args.snap)): rc=r.publishLaunchpad(args) if(rc == 0 and not (args.appimage or args.snap)): rc=r.publishKDE(args) if(rc == 0 and args.appimage): rc=r.buildAppImage(args) if(rc == 0 and args.snap): rc=r.buildSnap(args) print("#####################") print("# End of release #" if rc == 0 else "# FAILURE #") print("#####################") return rc if __name__ == '__main__': sys.exit(main())