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())