diff --git a/CHANGELOG b/CHANGELOG index b4a88e06f..99bceefe0 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,1976 +1,1977 @@ skrooge (2.22.0) + *Correction bug 417163: Date 31/12 => 02/12 *Correction: Merge of number of operation *Correction: Fix Get Hot New Stuff legacy Endpoints *Correction: Files not able to be checked out on Windows -- Stephane MANKOWSKI skrooge (2.21.0) *Correction bug 411958: Import CSV fails if account is empty *Correction bug 409166: skrooge appdata.xml missing release 2.20.0 *Correction bug 409703: No guide or tooltip for + icon in Categories form, and inconsistent *Correction bug 409165: skrooge appdata.xml gets warnings from validation-strict on flathub *Correction bug 412494: Skrooge flatpak silently fails to import anything from Amex QFX *Correction bug 412831: Filter for custom properties have to be prefixed with v_operation_display_all *Correction bug D22508: Get rid of obsolete methods *Correction bug D24327: Build flatpak with latest libofx 0.9.15 *Correction bug: Import CSV with comma when headers are forced (no automatic detection) *Correction bug: blank spaces at units "Internet code" (see: https://forum.kde.org/viewtopic.php?f=210&t=163184&p=424630&hilit=skrooge#p424630) *Correction: Import CSV file with footer line *Correction: Dashboard readability improvement (see: https://forum.kde.org/viewtopic.php?f=210&t=162650) *Feature D22484: Support using category, account, payee or unit properties in reports *Feature: New source of unite: ratesapi.io (see: https://forum.kde.org/viewtopic.php?f=210&t=162312&sid=c31044c567a38f04e7276263d3720df8) -- Stephane MANKOWSKI Sun, 01 Dec 2019 12:39:25 +0100 skrooge (2.20.0) *Correction bug 406903: no message when Skrooge can't open .skg file given on command line *Correction bug 406904: skrooge command-line help "--+[URL]" doesn't match its behavior *Correction bug 406741: QFX Date Import *Correction bug 407280: Skrooge flatpak unintentionally builds unused tests *Correction bug 407279: Skrooge flatpak needs later libofx *Correction bug 407257: Importing GNUcash (Account name instead of AccountID) *Correction bug 409026: skrooge appdata.xml fails validation on flathub, needs release and content_rating tags *Correction: aqbanking corrections: * Added auto repair for certain banks (Sprada, Netbank, Comdirect). * Added --disable-auto-repair command line option * Added --prefer-valutadate command line option * Removed --balance command line option *Correction: getNetWorth (used to compute PFS) is now computed by using all accounts *Correction: Remove color of hyperlinks in dashboard for a better rendering in dark theme *Correction: Remove broken quotes sources (BitcoinAverage, BitcoinCharts) *Correction: Better handling of the mode and comment field using the aqbanking import backend. *Feature: New REGEXPCAPTURE operator in "Search & Process" to capture a value by regular expression *Feature: Import backend aqbanking allows to import accounts without an IBAN. (See https://phabricator.kde.org/D20875) -- Stephane MANKOWSKI Sun, 23 Jun 2019 09:27:55 +0200 skrooge (2.19.0) *Correction bug 406321: ERR-8/ERR-5 importing qfx file, "More than one object returned in 'v_account' for 't_number='''" *Correction bug 406243: Skrooge does not import share operations in QIF file correctly *Correction bug 406270: Skrooge does not import investment operations in QIF correctly *Correction bug 406271: Skrooge does not import description of tags in QIF file into Tracker comment *Correction bug 406266: Skrooge does not import shares in QIF correctly *Correction bug 405578: build a nightly debug Skrooge flatpak *Correction bug 406488: crash importing a CSV *Correction bug 406549: Edit menu in Skrooge handbook is missing Skip, adds Find; missing context menu documentation *Correction: Add missing file categories_previous_period_table.html in monthly report *Correction: Migration failure with sqlite >= 3.25.0 due to ALTER TABLE behavior modification *Correction: Migration failure when some i_number are NULL *Correction: build skroogeconvert as a regular ("nongui") executable instead of an app bundle *Correction: prevent runtime discarding of the app icon if icon-from-theme lookup doesn't work (which it doesn't by default on OS X) *Correction: generate a multi-scale icon from all png icons size 256px and smaller *Feature: Tracker with running balance in "Operations" page *Performances: Better performances in payee view to compute recommended categories *Performances: Better performances in dashboard and monthly report when amounts by accounts *Performances: Better performances in dashboard to find all payee without operation *Performances: Better performances in "Delete payees without operation" -- Stephane MANKOWSKI Sat, 20 Apr 2019 14:03:43 +0200 skrooge (2.18.0) *Correction bug 403575: skrooge w/ -DSKG_WEBENGINE=ON: ui_skgtablewithgraph.h:15:10: fatal error: QtWebKitWidgets/QWebView: No such file or directory *Correction bug 403675: App crashes with segfault after second import *Correction bug 402330: error importing QIF File "SKGImportPluginQif::importFile() RC=[ERR-5]: SKGCategoryObject::addCategory failed because linked object is not yet saved in the database. *Correction bug 403725: import Quicken tags from QIF as Skrooge trackers *Correction bug 403985: kgbasegui/skgwebview.h:28:10: fatal error: qwebview.h: No such file or directory *Correction: Import KMYMONEY with non utf8 characters doesn't work (see https://forum.kde.org/viewtopic.php?f=210&t=156506) *Correction: Import KMYMONEY of scheduled operations from the next operation to add instead of the first one (to avoid duplicate) *Correction: Import KMYMONEY of shares with only one split must be done with the unit of the share *Correction: Nb occurrences and last date are not aligned on weekly schedules *Correction: Display all occurrences of a schedule in dashboard not only the first one *Correction: Display the currency symbol at the right place in scheduled operations *Correction: Display correctly the amount in "highlighted operations" in dashboard *Correction: The advice "Advice are very long to compute" can now be rejected *Correction: Add date in "Bank (light)" widget in html mode *Correction: Remove template from "Highlighted operation" widget *Feature: Better help for "Internet code" of sources in unit page *Feature: New MSN source of download for quotes *Feature: File can be made anonymous in a reversible mode *Feature: In "Operations" page, possibility to view all operations of an account + its credit cards associated *Feature: The number of years for forecasts based on scheduled operations can be choosen from settings *Feature: Possibility to choose the max date of schedules in dashboard *Feature: New action to skip scheduled operations *Feature: Possibility to skip scheduled operations from dashboard *Feature: Addition of options (Incomes, Expenditures, Transfers, ...) in contextual menu of graphs in "Account" page *Feature: Addition of options (Days, Weeks, Months, ...) in contextual menu of graphs in "Account" page -- Stephane MANKOWSKI Mon, 11 Feb 2019 21:32:09 +0100 skrooge (2.17.0) *Correction bug 400695: Designer plugins get installed as versioned libraries *Correction bug 400724: Import of Quicken 2012 .QIF file failed due to tags *Correction bug 402031: ERR-4/ERR-5 opening relative path to .skg from command line, then zombie Skrooge *Correction: Transfer created with value at 0. Regression due to 399672. (see https://forum.kde.org/viewtopic.php?f=210&t=155713&p=406978) *Correction: QIF import with transfer on split (see https://forum.kde.org/viewtopic.php?f=210&t=155614) *Correction: Add delay (300 ms) on text filter *Correction: "Search & Process" create a duplicate a duplicated category in some cases *Correction: Compliance with SQLCipher 4 *Correction: Close SQL database in mmb import *Feature: Like on transfer, the ratio is requested when creating a share operation (see https://forum.kde.org/viewtopic.php?f=210&t=155605&p=406979) *Feature: Progress bar in taskbar *Feature: Support only QT >= 5.7.0 -- Stephane MANKOWSKI Sun, 16 Dec 2018 17:50:46 +0100 skrooge (2.16.0) *Correction bug 398683: Periodic crashes on dashboard *Correction bug 397611: [ERR-5]: Format de date non pris en charge importation boobank *Correction bug 399480: Grammar mistake in .po file / - s missing in simple *Correction bug 399482: Wrong plural form in .po-File *Correction bug 399483: Spelling mistake in .po file "Transfert" should be "Transfer" *Correction bug 399672: Modifying multiple selected operations into transfers creates empty category and tracker if not identical *Correction: Ofx import must import FEE as debit *Correction: Document migration fails if format is "d.MM.yy 'г" (see: https://forum.kde.org/viewtopic.php?f=210&t=155575) *Correction: Inconsistency in "Incomes vs Expenditures" on sub operations with trackers *Correction: Build on windows *Correction: Use CPU instead CPU for QML (needed for printing) *Correction: Set background color on print to avoid print preview with black background on dark theme *Feature: Selection above, below or parent when delete an object *Performances: Solve performance issue due to new feature : More tooltips on "Operations" table -- Stephane MANKOWSKI Sun, 04 Nov 2018 14:12:43 +0100 skrooge (2.15.0) *Correction bug 397018: Check sqlcipher installation (issue detected on GENTOO) *Correction: Crash when sort a grouped view *Correction: Avoid to create 2 categories with the same name under the same category by using drag and drop *Correction: Avoid too many computation in SKGAccountObject::getPossibleReconciliations *Feature: Addition of a new option to check if import has been broken *Feature: More tooltips on "Operations" table -- Stephane MANKOWSKI Wed, 15 Aug 2018 22:01:16 +0200 skrooge (2.14.0) *Correction bug 394857: Reports do not graph operations by week correctly *Correction bug 395328: Bad perfo in SKGAccountObject::getPossibleReconciliations when too many operations *Correction: Sort on second column does not work with grouping *Correction: Change bootstrap url in templates *Correction: Better grouping for "Week", "Month", "Semester", ... *Correction: Report with forecast based on budget use the account using the most the category *Correction: Respan of group header must work when auto resize is disabled too *Correction: Import backend of account with "." in name *Correction: Remove error in boobank commands *Correction: Set automatically the bank account only when the icon is changed *Correction: The application is hidden when the dashboard is opened on an empty document *Correction: On operation page, the sort by the balance attribute sorts operations by date+id to have correct balances *Correction: Weboob backend doesn't work with option if account name has "id" *Feature: Addition of "Import date" on account object *Feature: Possibility to merge accounts with or without updating the initial balance *Performances: Improvement of performance of SKGTreeView::selectObjects and SKGTreeView::getState when grouping with many groups -- Stephane MANKOWSKI Sun, 24 Jun 2018 19:00:18 +0200 skrooge (2.13.0) *Correction bug 392828: Choose what to display on selection *Correction: Simple search in "Search & Process" doesn't escape words *Correction: Add notification (sound) on all creations / modifications of objects *Feature: Possibility to open concerned operations when auto reconciliation failed *Feature: Option on report to show decimals or not *Feature: Option "Execute on not checked operations" on "Search & Process" page *Feature: Addition of "Reconciliation balance" attribut on "Account" + icon to check if previous reconciliation has been broken or not *Feature: Addition of a new option to check if reconciliation has been broken -- Stephane MANKOWSKI Mon, 07 May 2018 20:31:26 +0200 skrooge (2.12.0) *Correction bug 389867: Amount Input Changes Value Prematurely *Correction bug 389866: Date Input Field Not Localized *Correction bug 389899: Split dates aren't updated when copying previous entry *Correction bug 390223: Opening d/l QFX file opens new skrooge file instead of importing into existing - opened file *Correction: Remove compilation warning (-Wsign-promo) *Correction: Can't resize the window and its width exceeds the screen (https://forum.kde.org/viewtopic.php?f=210&t=151023) *Correction: Search and process doesn't work in template mode with category used (see: https://forum.kde.org/viewtopic.php?f=210&t=150940) *Correction: No sound notification when an operation is created (see: https://forum.kde.org/viewtopic.php?f=210&t=151296) *Feature: All bookmarked report can be easily added to the dashboard with the + menu *Feature: New "Treemap" graph mode in reports *Feature: Automatic merge of payees, accounts and units when updated with another existing name *Feature: Alpha numerical values are now supported for number of operation (see: https://forum.kde.org/viewtopic.php?f=210&t=150988&p=394706) *Feature: Addition of a new option to displaythe environment variables used by Skrooge -- Stephane MANKOWSKI Thu, 08 Mar 2018 20:06:43 +0100 skrooge (2.11.0) *Correction bug 386942: .py scripts in /usr/bin *Correction bug 388955: Splitting Currency and Amount into separate columns *Correction: Better account number in weboob import *Correction: Weboob import is now importing account with better name (use of "label") *Correction: Weboob import compliant with utf8 *Correction: Failure when launching "skrooge filename.xxx" when filename.xxx is a file to import *Correction: "Switch closed" is available on unit but units are not closable *Correction: When a transfer is created only one of both operation has the tracker set: https://forum.kde.org/viewtopic.php?f=210&t=143127&p=384834#p384834 *Correction: Export of selection when selection size > 1 doesn't work *Correction: Define alternative icons when a "poor" icon set is used (like by default on gnome: Tango) *Feature: Tips of the day are now clickable and in the main page (not more popup panel) *Feature: Skrooge knows now 100 cryptocurrencies and is able to download their quotation *Feature: Enable AA_EnableHighDpiScaling if Qt version >= 5.6 *Performances: Better performances by resizing only visible columns (this is useful on payee table when category is hidden) *Performances: Better performances in the computation of the automatic category for a payee *Performances: Improvement of performance in SKGImportExportManager::findAndGroupTransfers. 11552 ms => 285 ms -- Stephane MANKOWSKI Sat, 03 Feb 2018 11:16:35 +0100 skrooge (2.10.5) *Correction bug 386594: Can not load share prices for French stocks -- Stephane MANKOWSKI Sat, 25 Nov 2017 23:15:27 +0100 skrooge (2.10.0) *Correction bug 383758: Report unreadable because element outlines are to thick *Correction bug 384119: Operation without suboperation after a kmy import *Correction bug 375865: Quick fill: select/enter item does not lock payee *Correction bug 384801: Converting multiple operations with different amounts to "transfer" type changes all amounts to 0 *Correction bug 384802: When creating multiple transfers into a different currency use the correct exchange rate for each date *Correction bug 385002: Display and edit default category for payee *Correction bug 385277: Wrong budget for split-operations with unaligned dates *Correction bug 384803: Creating many transfers to a different currency leads to uninterruptible series of dialog boxes *Correction bug 385990: Altered budgets aren't displayed until you reload the tab *Correction bug 386285: The minimum/maximum limit in account definition is interpreted as Primary Currency *Correction: Bad english in help on rules *Correction: Memory leaks *Correction: The source of unit download is now able to support date in "en_EN" locale event if this is not the system locale. Mandatory for implementing a Google Finance source. *Correction: Don't display the page of operations when the import is canceled *Correction: Better error messages in backend import *Correction: Optimisation in backend import *Correction: Optimise html of monthy reports *Correction: Port from QWebKit to QWebEngine *Correction: Avoid to compute too many combinations (and take hours) when trying to do an automatic reconciliation *Correction: Backend import must match account with id with letter like this 123456A@ldl *Correction: Never merge 2 accounts with same name in backend import *Correction: Crash when selecting many lines in search & process page *Correction: Enable print functions only when at least one page is opened *New feature: New "Google Finance" source of download for units *New feature: The source of unit download can be now an external script *New feature: New import backend "weboob_coming" importing coming operations (can be used for card with deferred debit) *New feature: A payee can be closed. Then it won't be available in combo boxes in operation page *New feature: A category can be closed. Then it won't be available in combo boxes in operation page *New feature: New parameters in boobank backend to be able to import operations only since a specified date *New feature: Export ledger format *New feature: The tooltip of "Search" explains now how the entered value is understood *Performances: Better performances on initial load (avoid to intialise a document before loading one other) -- Stephane MANKOWSKI Thu, 02 Nov 2017 21:17:06 +0100 skrooge (2.9.0) *Correction bug 380235: Reports table view: missing characters *Correction bug 380232: Yahoo api discontinued *Correction bug 380187: Shares always use the current rate/value. On unit page, you can choose if you want to see the history of the unit value or the history of the amount owned *Correction bug 380827: Pie chart alignment *Correction bug 380460: Failure when loading file from skrooge 1.12 *Correction bug 380821: Add keyboard shortcut to rename bookmarks *Correction bug 380820: Custom banks do not use their custom icon/image *Correction bug 380818: Cash account is not associated with a bank *Correction bug 380802: Going back and forth from "fullscreen mode" (Ctrl+Shift+F) loses the focus on "pages" tab on the left sidebar *Correction bug 381056: Dashboard portfolio widget: Wrong percentage values *Correction bug 381562: csv file import: unable to detect matching account *Correction bug 381168: Change tab order of properties editor *Correction bug 381847: Income & Expenditure widget does not match corresponding report *Correction bug 382162: Wrong budget in root categories if subcategories also include subcategories *Correction: Multithreading SQL connections must be compliant with SQLite mode *Correction: Temporary skg file protected by password are not well restore *Correction: Replacement of missing icons *Correction: Auto apply on advice duplicates remaining advice *Correction: The "duplicate" function creates operation with invalid creation date *Correction: Regular expressions for CSV import are now translatable *Correction: Values are not refreshed in amortization table when annual rate or insurance rate are modified *Correction: Zoom on dashboard widget in QML doesn't work *Correction: No refresh of "month" in the title of some dashboard widgets *Correction: In about, the authors of sub plugins are now displayed *New feature: New import backend using aqbanking *New feature: Import backends can now have parameters *New feature: Skrooge is now able to export only the selected accounts or operations *New feature: Bulk mode in import backends *New feature: In "Monthly Report", possibility to get attributes on pointed objects *New feature: Addition of new BitcoinAverage source to be able to download bitcoin rates (due to unavailability of BitcoinCharts) *Performances: Avoid advice computation in dashboard when the dashboard is not the current page *Performances: Better performance in advice "Some payees seem to be identical" *Performances: Better performances on load and save -- Stephane MANKOWSKI Sat, 12 Aug 2017 10:11:37 +0200 skrooge (2.8.1) *Correction: Bad display of information of current account when a second document is opened -- Stephane MANKOWSKI Sat, 15 Apr 2017 20:41:56 +0200 skrooge (2.8.0) *Correction bug 375721: Right-click (context menu) reload view *Correction bug 375875: Changing password does not work *Correction bug 375712: See operation for a payee *Correction bug 376025: Clear fields don't restore currency *Correction bug 375865: Quick fill: select/enter item does not lock payee is not well computed *Correction: The "Other" category in dashboard and report widget name "5 main categories of expenditure" *Correction: Sometimes the sort on date in operation table is not the same than the sort used to compute the balance, this causes troubles *Correction: Create fake operation doesn't work on account not having the primary unit (https://forum.kde.org/viewtopic.php?f=210&t=138803&sid=d0d34f728ef7f41bb6c32764ccf3d8f6) *Correction: "Income vs Expenditure" dashboard widget is not refreshed when data are modified *Correction: Bad display in "5 main categories of expenditure" in QML dashboard widget *Correction: Better performance in "Incomes vs Expenditures" dashboard widget *Correction: Duplication of operation must not duplicate the creation date *New feature 375866: Quick fill find operations in other account *New feature: New columns visible in operation table *New feature: New "budget" dashboard widget in QML *Performances: Better performances by using multithreading and caching *Performances: Better performances in "Apply all recommended corrections" -- Stephane MANKOWSKI Wed, 05 Apr 2017 20:24:45 +0200 skrooge (2.7.0) *Correction: Due to a security hole, sqlcipher is no more an option. If you use password protection, we strongly encourage you to use this version of Skrooge and to change your password *Correction: "Delete" and "Add property" are never activated in "Simulator" page *Correction: Current periods (Quarter, Semester, Year) must be available in some widgets of the dashboard *Correction: Only previous months are relevant in "Personal finance indicator" of the dashboard *Correction: Boobank backend does not import transactions when the date format is YYYY-MM-DD 00:00:00 *Correction: Remove "Stooq monthly history.txt" because it does not work *Correction: Description of SKGPeriodEdit is not correct *New feature: Addition of the "Other" category in dashboard and report widget name "5 main categories of expenditure" *New feature: New grantlee filter to execute the sql order you want on the document. This will improve html reports *New feature: New grantlee filter to convert an integer in file size format (example: 390.2 MB) *New feature: Ability to open a file property by url *New feature: CSV export from report is now able to export raw values (http://forum.kde.org/viewtopic.php?f=210&t=112209&p=290153#p290153) *New feature: Resize of account number in "Accounts" page to be able to entre IBAN number *New feature: "Rename" for all dashboard widget *New feature: "Search & process" is now possible on bank name. This allows to create an alarm based on the deposit guarantee level per bank -- Stephane MANKOWSKI Sun, 22 Jan 2017 17:45:58 +0100 skrooge (2.6.0) *Correction bug 372470: Scheduled transactions on dashboard *Correction bug 372938: merge imported operations wrong warning about different amounts *Correction bug 373147: Dashboard/Scheduled operations typo *Correction: Remove old skrooge icons to use the official breeze icons *Correction: Do not install namelink for private library *Correction: Avoid inconsistency when primary unit is not well defined (https://forum.kde.org/viewtopic.php?f=210&t=136856) *Correction: QIF import fails when non utf8 chars are found *Correction: Display all type of item in "Search & Process" *Correction: Execution of "template" rule after import destroys the template itself (https://forum.kde.org/viewtopic.php?f=210&t=137121&sid=b3336f56f03d79f50ad7d53b9e919076) *Correction: Recovery of the working copy doesn't work in sqlcypher mode *Correction: Better performances and memory use in SKGAccountObject::getPossibleReconciliations *Correction: Better automatic account selection by using bank and agency numbers *Correction: Bad unit symbols in min and max limits in accounts page *Correction: Impossible to duplicate a page not having selection (eg. Dashboard, monthly report) *Correction: The dock "Message" is not reinitialized when a new file is loaded *Correction: In budget module, replacement of "Remove existing budgets" by "Remove existing budgets for xxx" *Correction: BitcoinCharts currency import order must be inverted because CSV file has been inverted *Correction: Better display for "Income vs Expenditure" on QML dashboard *Correction: New limit to history size set to 999 instead of 99 *Correction: To avoid partial import with backend, the import is fully done in case of delta detected *Correction: weboob backend is now searching transactions on date AND rdate to avoid missing transaction *Correction: Skrooge is now able to download addition stuff (monthly report template, quote source) with knewstuff *Correction: Open file property fails when the property name contains the full path (https://forum.kde.org/viewtopic.php?f=210&t=137528) *Correction: Avoid duplicated operation when importing attached accounts with weboob *Correction: Group on suboperations must display min, average and maw amounts (https://forum.kde.org/viewtopic.php?f=210&t=137569) *Correction: The option "Import only operations since the last imported one" must not be applied with backend import *Correction: "Estimated interests" are now in QML in dashboard and are available for monthly reports *Correction: Addition of tooltips on each operator in "Search & Process" *New feature: Addition of "nocolor" to the "money" Grantlee filter *New feature: Remove .skg in backup file name if .skg is added in the prefix (https://forum.kde.org/viewtopic.php?f=210&t=136518&p=366065#p366065) *New feature: "Alarm" dashboard widget is now compliant with QML mode -- Stephane MANKOWSKI Tue, 27 Dec 2016 18:42:32 +0100 skrooge (2.5.0) *Correction bug 364407: Doesn't build with Qt 5.7 *Correction bug 366025: Skrooge perpetually asks me to save updated tab state *Correction bug 368196: Delete sub-operations in edit delete selected operation in list *Correction bug 368356: Show amount sign on lost focus *Correction bug 368195: No lock on target account for a transfer *Correction bug 369090: Transfers sub operation created by template has wrong date *Correction: Migration connect from ui file to cpp file *Correction: Better colors of amounts in tooltips of advices *Correction: The 31 of the month, in budget page, "Previous month" does not work *Correction: When a second instance of Skrooge is launched with a file as argument, the file must be imported in the first instance of Skrooge *Correction: Since QT5.7, no more dependency on KDELibs4Support *correction: Dates wrong on dashboard - date format instead of the date itself *Correction: Keep properties when 2 operations are merged *Correction: Correction in weboob backend to avoid missing transactions and improve performances *New feature: Massive update is now available for amount in "Operation" page *New feature: Massive update is now available for date in "Operation" page *New feature: Capability to set/change order of budget rules *New feature: Tooltip on modified amount of budget to explain the reasons of modifications *New feature: Import of PDF invoice -- Stephane MANKOWSKI Sun, 25 Sep 2016 09:00:24 +0200 skrooge (2.4.0) *Correction bug 359679: Building the v2.3.0 package on Arch Linux dies with an error 'isnan' was not declared in this scope *Correction bug 362231: Lost date in imported split operation *Correction: Corruption of document after removing the password *Correction: In unit page and dashboard widget the annual performance is now computed on a year (not with an extrapolation of the last performance) *Correction: Refresh "Interest" dashboard widget when operations are modified *Correction: Copy needed files in local when a new template (for monthly report) is created *Correction: All advices are not displayed in dashboard *Correction: More setPlaceholderText for better GUI *Correction: Responsive report is now using highchart *New feature: New tutorial grantlee template to learn how to develop a new template *New feature: New option to select if the dashboard must be in html or qml. Qml mode is still experimental -- Stephane MANKOWSKI Fri, 06 May 2016 21:07:29 +0200 skrooge (2.3.0) *Correction bug 357081: No option to disable tray icon *Correction bug 357414: Bad display amount in split editor *Correction bug 358315: Typo in .desktop file leads to KRunner freeze *Correction: Avoid failure in kmy import when sub category already exists *Correction: Better autoreconciliation (the autoreconciliation can be done even when operations are not well sorted) *Correction: Migration to nullptr *Correction: Replace "XXX* yyy = new XXX" by "auto yyy = new XXX" *Correction: Thanks to regular expression, the "word" function is now able to interpret "N:1234" as a 2 words "N" and "1234" *Correction: Better icons (correction of installation for breeze) *Correction: Autoreconciliation doesn't work for accounts in other units than the primary *Correction: Better computation of the preferred currency for QIF import *Correction: After a modification or an creation the focus must be given to the table *Correction: Error when launching Skrooge from krunner *Correction: Bad sums in reports *New feature: New column "Balance import" in account page with an indicator to know if the account is still aligned with import balance *New feature: Check balance of accounts after import with backend *New feature: New "Personal Finance Score" in monthly reports *New feature: New "Personal Finance Score" in dashboard *New feature: Selection sum is now in the status bar *New feature: On tables, when the filter changes, the selection remains visible *New feature: Ctrl+Maj+V allows to validate OR UNVALIDATE the imported operations -- Stephane MANKOWSKI Sun, 21 Feb 2016 21:55:44 +0100 skrooge (2.2.0) *Correction bug 352674: SQLite version of the system not aligned with embedded in Qt when using sqlcipher *Correction bug 349961: Values in "Text" report are clickable to open corresponding operations *Correction bug 349976: Default categories for payees *Correction bug 354139: Pb when opening operations in sub-operation view *Correction bug 341463: Monthly reports include transfers between accounts and shows as income/expenses *Correction bug 354439: Re-open close account with money: wrong warning *Correction bug 354463: Incomes/Expenditures in monthly reports do not account for sub-operations of split operations *Correction bug 354424: Displayed balance is 0,00 and operation is ignored afterwards *Correction bug 354817: Arrows should increment/decrement operation number *Correction bug 355376: Category too small in split editor *Correction bug 355956: Not existent type in dashboard *Correction: Drag and drop file is now able to move a file *Correction: The WORD function of "Search & Replace" is no more sensible of useless space *Correction: Open skrooge document from desktop *Correction: Set open source licence on svg files *Correction: Correction ofx import in ECM_ENABLE_SANITIZERS='address' mode *Correction: Better print of dashboards by printing each widget individually *Correction: Better counting of pages in print function *Correction: Monthly reports with "default" template is now printed in only one page (remove page-break-before: always) *Correction: Monthly reports with "responsive" template must not print url *Correction: Migration from sqlite to sqlcipher mode does not work when the password contains the character " *Correction: In "Search & Process", the between function must work when v1 Sun, 29 Nov 2015 18:48:31 +0100 skrooge (2.1.1) *Correction bug 351977: Missing Comment in desktop file *Correction bug 350722: Sudden date change from 20XX to 19XX *Correction: Upload of knewhotstuff does not work *Correction: Avoid performance issue when an operation is created very far in the future (example: 01/01/8015) *New feature: New source of download "GrandTrunk" better than yahoo finance for currencies -- Stephane MANKOWSKI Fri, 11 Sep 2015 13:10:09 +0200 skrooge (2.1.0) *Correction bug 349349: Allow to enter year with 2 digits only *Correction bug 349328: Bad date on split operation after fast edition *Correction bug 349327: Bad date format for sub-operation display in split tab *Correction bug 349624: Add operator on fast filter *Correction bug 349776: Freeze when splitting and editing a future operation *Correction bug 349329: Tools should display modifications before applying them *Correction bug 349961: Split value of operations in reports/exports *Correction bug 350154: Cannot change rate symbol (%) position in Simulations panel *Correction bug 350722: Sudden date change from 20XX to 19XX *Correction bug 350937: Some words are not translated *Correction bug 340647: Encrypted Skrooge file is decrypted in-place *Correction: Authorize only word characters and space in name of templates of reports *Correction: Authorize only word characters and space in name of source of quotes *Correction: Missing unit symbol in monthly report *Correction: Failure on export *Correction: Bad display in period selector of "Income & Expenditure" dashboard widget *Correction: Bad filters in some open file dialog *Correction: Error when open link with non ASCII characters *Correction: Better detection of unaligne dates between operations and sub operations *Correction: The first update of monthly report must take into account the selected template instead of using the default one *Correction: Add credits page in "About" *Correction: Double click on skrooge document opens skrooge but the document is not loaded *Correction: Code rework for contextual menus *New feature: "Open..." action in contextual menu of reports *New feature: New function to import simple rules (payee=xxx => category=yyy) from csv file *New feature: More period options in dashboard widgets *New feature: "5 main categories of expenditure" in dashboard and report is now clickable *New feature: "Quotes" in dashboard and report is now clickable *New feature: Addition of list of key users in credits *New feature: Messages/errors can have associated action *New feature: "Open operations modified by this transaction" *New feature: Delete items in history -- Stephane MANKOWSKI Thu, 27 Aug 2015 19:20:30 +0200 skrooge (2.0.0) *Correction bug 347762: Invalid error message for SQLite version check after an update of SQLite *Correction bug 324653: Auto-Hide Scrollbars for Report Graphs *Correction bug 348865: Do not show translated tooltip *Correction bug 348490: Split with almost 0 operation *Correction: Porting on KF5 / QT5 *Correction: Use of Q_DECL_OVERRIDE *Correction: Bad account selected in editor when a closed operation is selected *New feature: Close action available in menu and contectual menu -- Stephane MANKOWSKI Sun, 14 Jun 2015 18:16:43 +0200 skrooge (1.12.5) *Correction bug 348619: Freeze amount should freeze unit *Correction bug 348621: Field order with tab key *Correction bug 348620: Display of multiple operations with common fields *Correction bug 348568: Payee with operations in 0 operation group *Correction bug 345994: Bad unit on some operation after search *Correction: Build for QT built with -reduce-relocations -- Stephane MANKOWSKI Wed, 03 Jun 2015 22:07:31 +0200 skrooge (1.12.0) *Correction bug 345974: Skrooge alarms keep firing up regardless of specified alert amount *Correction bug 346151: Fast edition do not fill operation sign *Correction bug 345998: Add tooltip for all history actions *Correction bug 345799: Moved then hiden column displayed *New feature: Automatic point operations created during reconciliation *New feature: "Simple" mode in "Search and process" page *Performances: Better performances on selection change in "operation" page -- Stephane MANKOWSKI Thu, 07 May 2015 20:46:21 +0200 skrooge (1.11.0) *Correction bug 341020: End of text in lineedit hides under the "clear" icon button *Correction bug 341450: Empty skg_bill.csv is created every time I launch Skrooge *Correction bug 341463: Monthly reports include transfers between accounts and shows as income/expenses *Correction bug 342737: Multiple date modifications on scheduled operations *Correction bug 343730: Resize/hide internal filter panel in report *Correction bug 335945: Support making split operations from standard operations by search and process *Correction bug 344250: Bank ING-DIRECT in France has changed its bank number *Correction bug 345580: Share without tax should not be split *Correction bug 345654: Btn Add grayed after entering values information *Correction bug 345661: Selecting multiple operations: amount is not ----- *Correction bug 345719: Enhance fast search/filter on lists *Correction bug 345826: Bas edit fields on list sub-operation after search *Correction bug 345416: Crash when searching on 'type' field *Correction: "Search" and "Report" do not work on properties of suboperations *Correction: Bad tooltips in "Report" for expand and collapse *Correction: Support invalid OFX file having debit with positive amount *Correction: Timeline does not work in some cases *Correction: More flexibility during import of ofx file not having id on transactions *Correction: Anonymized file is renamed to avoid accidental overwrite of the current file *Correction: weboob backend compliant with version 1.0 *Correction: Avoid crash and generate an error when the sqlite version of the system is not aligned with the sqlite version embedded in QT *Correction: Open suboperation from multi selected operations *Correction: Avoid deletion of previous file and backup during save in case of file system full *Correction: When a folder of bookmark a tab doesn't have the right icon *Correction: Stable sort when sorting by date to avoid ununderstandable balance *Correction: In table, when rows are groupes, the row representing the group spans all columns *Correction: Avoid crash in Add properties on suboperations *New feature 343766: Better custom report configuration *New feature: New dock to be able to see all messages displayed *New feature: Alarm messages can be have parameters for the total amount (%1), alarm amount (%2) and difference (%3) *New feature: Show sum of spendings in tables when operations are grouped *New feature: New advice detecting scheduled operations having date not aligned with the last inserted operation *New feature: The target directory of the backuped file can be force *New feature: Now some advices are recommended *New feature: In settings, you can define default comments, payees and categories for fake, commission and tax operations *New feature: New button on advices widget to apply all recommended advices *New feature: Display average, min and max on groups in tables *New feature: WORD function is now able to extract word from the right by using negative parameters *New feature: Addition of "Creation date" on operations -- Stephane MANKOWSKI Sun, 05 Apr 2015 19:18:04 +0200 skrooge (1.10.0) *Correction bug 334626: When doing a transfer, my specification of + or - is ignored *Correction bug 335943: Please add column "number of operations" to categories view *Correction bug 336320: OFX file import duplicates the last 12 transactions *Correction bug 338351: Reconciliation with additional currencies *Correction bug 338993: Change main currency fails to update amounts *Correction bug 338994: Currency rate not saved for transactions *Correction: Open URL does not work in unit page *Correction: Wrong date in message "Operation 'XXX' will be inserted in YYY days" *Correction: Auto repair of qif file not having sum of suboperation amount != operation amount *Correction: Better error message on mny import when java is not installed *Correction: Weboob0g backend is now compliant with weboob version 0h *Correction: Correction in bitcoin quote download *Correction: Remove duplicate in "To Account" field on operations *Correction: Import of mode for mny files *Correction: Better detection of transfers in mny import *Correction: Automatic resize of columns in "Search and Process" edit panel to facilitate the creation/update of rules *Correction: Missing template "categories_month_table" *Correction: For credit card account, the binding of account is optional *Correction: Remove useless "Expand All" and "Collapse All" on history table *Correction: "Add property" and "Delete" is now working on sub operations *Correction: "Highlight" is disabled on sub operations *New feature: The future can be added or not in "Current" or "Last" periods *New feature: Defered credit card management *New feature: Capacity to apply a template on operations *New feature: Capacity to automatically apply a template on operations from "Search and Process" *New feature: Sort of table memorize the previous sort to be able to sort by column 1 and column 2 *New feature: New advice to inform the user when the monetary decimal symbol is not defined in KDE localization settings *New feature: 2 options in graphs, one for limits visibility, one for average visibility *New feature: New advice to detect similar payees *New feature: New advice to detect similar categories *New feature: Add in documentation how to use kdewallet with weboob backend *New feature: Import iif file *Performances: Better performances in "Possible schedule" *Performances: Better performances in dashboard -- Stephane MANKOWSKI Tue, 28 Oct 2014 20:57:41 +0100 skrooge (1.9.0) *Correction bug 327148: Version 1.8.0 doesn't build *Correction bug 328335: Wish for fixed table row header *Correction bug 326764: When printing hard copy of report, only data in view in window is printed, not full report data *Correction bug 329568: Simulator utility problem *Correction bug 329825: When opening crypted file with false password skrooge falsely states the file is corrupted *Correction bug 329876: Weboob import from paypal ignores dates and creates account "0" *Correction bug 330354: Budget forecast duplicates operation creation *Correction bug 330428: Sorting doesn't work on Reconciliation date in Accounts view *Correction bug 331191: Obsolete term „Context“ in docbook *Correction: Remove conflict on CTRL+C shortcut *Correction: Import mny does not work with space in file name *Correction: In case of failure during backup file creation a warning message is displayed instead of an error avoiding to save the file *Correction: Refresh delta during reconciliation *Correction: Better PDF export from Monthly report *Correction: Import CSV unit file with "," as separator *Correction: Better KMyMoney import *Correction: Imported "Wallet" accounts are in bank named '' *Correction: Avoid wrong transfert in Grisbi import *Correction: The option "Import only operations since the last imported one" uses a delay of 4 days to avoid missing operations due to value date *Correction: Avoid error in import of homebank file without parent attribute on categories *Correction: Correction for unit download with Stooq *New feature: More option in "Income & Expenditure" dashboard widget *New feature: New shortcuts for "Expand all" and "Collapse all" *New feature: Operations can be split by date *New feature: Imports (csv, qif) support date format like this: 31Dec2012 *New feature: Import CSV support now "semicolon", "comma" and "tab" as separator *New feature: Monthly report is now able to display reports on months, quarter, semesters and years *New feature: New "responsive" template for monthly reports *New feature: In graph, sums are now all computed *New feature: Pareto curve in graph *New feature: New "quarter" and "semester" period in graph and "Incomes & Expenditures" dashboard widget *New feature: Ability to reorder the suboperations in the split operation *New feature: Better date filtering in operation page *New feature: More operators is "Search" panel *New feature: New statistic plugin -- Stephane MANKOWSKI Sat, 12 Apr 2014 16:11:26 +0200 skrooge (1.8.0) *Correction bug 319706: OFX trntype not imported, rest okay *Correction bug 320114: Wrong bank balance at dashboard *Correction bug 320112: Importing CSV operations with mixed " and ' text field separators *Correction bug 320226: Monthly report does not work due to missing template *Correction bug 320240: Impossible to enter exact amount for given unit in pop-up *Correction bug 320242: Transaction confirmation pop-up doesn't use defined unit value for transaction date for suggested value *Correction bug 320261: Dashboard "Income & expenditure": no values, strange colors *Correction bug 320157: Skrooge not working when .skg file is located on Samba share *Correction bug 320323: Add function ("rest to") In budget *Correction bug 320298: Default automatic format detection while importing a file leads to wrong entries creation *Correction bug 320070: Allow changing operation date through "Search & Process" *Correction bug 320716: Skrooge does not import all operations using weboob *Correction bug 320717: Use rdate instead of date in weboob backend *Correction bug 319993: Please adopt application logo/icon for smaller resolutions ==> skrooge-mini can be choosen for small resolutions *Correction bug 319990: Please fix icon alignment in Pages tab *Correction bug 322306: Skrooge Crash using Forecast Schedule *Correction bug 322069: Designer plugins should be unversioned .so files *Correction bug 323380: Minor date bug when using the stock portfolio widgets *Correction bug 320066: Crash importing KmyMoney exported file from Skrooge *Correction bug 324972: Import fails without an error when account is defined in CSV *Correction bug 325081: Add a « Yesterday » choice in the date picker *Correction bug 325174: Importing from gnucash file doesn't import accounts fo types 'Mutual Fund' nor 'Credit Card' *Correction bug 325223: Crash when exiting skrooge *Correction bug 324008: Erreur when importing .mny file. Error when analysing categories.json *Correction bug 325675: Build error in skgfileplugin.cpp for openSUSE 12.2 KDE 4.9 *Correction: KMyMoney exports does not need a check of integrity anymore *Correction: Addition of all icons in size 256 and 512 *Correction: Block drop of a bookmark under another bookmark *Correction: Bad date format detection when the second value is 9 (example: 3/9/04) *Correction: Remove the "Bank account " string in the name of the account name created by an OFX import *Correction: Icon for "Amount entered" *Correction: Authorize long number for operations like 5490990004 *Correction: Default graph mode = line *Correction: Better detection of duplicate operations after import *Correction: JSON export based on QJson *Correction: The setting "Import only operations since the last imported one" allows importation for the same date (< instead of <=) *Correction: Impossible to change state of operation from suboperation view *Correction: More permissive "Open duplicate" *Correction: Better setting layout for import/export *Correction: Import/Export minimum and maximum balance in KMyMoney importer *Correction: Import minimum balance in Grisbi importer *Correction: Import minimum balance in Homebank importer *Correction: New "weboob0g" backend compliant with the Weboob 0.g *Correction: When a file is selected for the icon of the bank, the file name is displayed in the name of the bank *Correction: In simulation page, the interest are computed with only operations with type=currency, not with shares *Correction: Error when importing skg file by double clicking when skrooge already open *Correction: No more password panel when the user loads an invalid Skrooge file *Correction: In report, the forecast based on budget is displayed even when no operation in account *Correction: Shortcuts in "Show" menus *New feature: Notifications and error messages are now based on KMessageWidget *New feature: The restore file is now base on KMessageWidget *New feature: Option to auto download from backend on opening file (default=false) *New feature: Import Microsoft Money documents (.mny) protected or not *New feature: Tarballs are not uploaded on download.kde.org *New feature: Addition of russian banks *New feature: Reopen last page closed *New feature: Max and min limits on accounts *New feature: Better and new advices based on limits of accounts *New feature: Sound emmission on operation creation *New feature: Import "Budgetary allocation" and "Fiscal year" from Grisbi files as properties *New feature: Information message explaining how to exist full screen mode *New feature: Addition of date of last reconciliation on account *New feature: Amount owned on unit table *New feature: Download date on unit table *New feature: New account type: Pension *New feature: New set of categories for french people *New feature: Addition of "Configure notifications..." in configuration menu *New feature: Download and add bills as property by using boobill (weboob) *New feature: Rename of property *New feature: Export HTML and ODT from tables *New feature: Automatic process to recover a corrupted file *New feature: Possibility to print current page *Performances: Better performances in dashboard *Performances: Better performances in monthly report *Performances: Better performances in import of multi files (or from backend) by applying "search & process" rules only one time *Performances: Better performances in kmy export *Performances: Better performances by avoid to refresh autocompletion on widgets after light transactions -- Stephane MANKOWSKI Sat, 05 Oct 2013 18:54:16 +0200 skrooge (1.7.1) *Correction bug 319565: Bad performances on ubuntu 13.04 *New feature: Open report from dashboard widgets -- Stephane MANKOWSKI Thu, 09 May 2013 22:28:28 +0200 skrooge (1.7.0) *Correction bug 316604: Income and Expense widget on the dashboard does not respect suboperations in split operations *Correction bug 316796: Reports crash when closed normally *Correction bug 318063: New file format (AFB120 CFONB) *Correction bug 279967: When automatically started at login, Skrooge is always displayed on all desktops *Correction bug 319145: Multiple currency support still buggy *Correction: Group operations with more than 2 operations selected *Correction: Group operations with already grouped operations *Correction: Hide internal properties in "Search & process", in operation page and in the function "Add property" *Correction: QIF import does not support mix of date format *Correction: The advice action "Remove groups with only one operation" does not remove the operation but the group *Correction: Better performances in kmymoney import and all other imports *Correction: skroogeconvert does not support files without path (example: skroogeconvert -in t.csv -out t.kmy) *Correction: Better performances of skroogeconvert in case of skg import or export *Correction: Global better performances by using the right index on unit table *Correction: Rename "Undo document" to "Revert document" *Correction: Reduce the number of messages when using backend import *Correction: Possibility to group tables on properties *Correction: Better support of import/export with url *Correction: Better merging of operations in QIF import *New feature: More modification functions in "Search & Process" panel for Payee, Account, Tracker *New feature: New "capitalize" function in "Search & Process" panel *New feature: New attributes "Unit" and "Transfer" in "Search & Process" panel *New feature: All update functions are now available for properties in "Search & Process" panel *New feature: New icon in tab bar to create new page *New feature: 'To account' in operation table and "Search & Process" *New feature: More attributes in line and column in reports (graph) *New feature: Monthly reports and main page use the general font of KDE *New feature: Possibility to force the date format for qif and csv imports *New feature: More functions in tool menu *New feature: More tips of the days *New feature: Dispay option "Hide pointed operations" in operation page *New feature: Possibility to group tables on hidden column *New feature: Facilitate creation of standard currencies with auto completion *New feature: Addition of the new currency "Bitcoin" with automatic download of the rate *New feature: In dashboard and monthly report, banks can be clicked to open corresponding operations *New feature: In report, the graph correction can be done by multiply or divide -- Stephane MANKOWSKI Sat, 04 May 2013 16:49:45 +0200 skrooge (1.6.0) *Correction bug 314389: weboob import does not work *Correction bug 314743: Can not resize window when operations tab is displayed *Correction bug 313926: Version 1.5.1 shows warnings *Correction bug 313948: Skrooge crashed after double clicking on an account after using clean import tool *Correction bug 313928: Warnings during build on OS X > 10.6 *Correction: Splash screen and notifications on windows *Correction: Better error management in weboob import plugin *Correction: Faster and without notification units downloads *Correction: Facilitate toolbar customization *Correction: Bad date format identification in some cases *Correction: Remove traces "Attempt to use QAction 'XXX' with KXMLGUIFactory" *Correction: Activation of link in "Incomes and Expenditures" dashboard widget *Correction: Operations in "Loan" accounts are not more taken into account in budget and "Incomes and Expenditures" dashboard widget *Correction: More point styles in graph and better rendering *Correction: Display of infinity symbol in dashboards and monthly reports *New feature: "Open all" and "Bookmark current page here" in the bookmark button *New feature: Button in bookmark dock to discover the contextual menu *New feature: Buttons on dashboard widgets to discover the contextual menu *New feature: New cursor on dashboard widgets to show that widgets are moveable *New feature: New dashboard (fast remove, fast add, fast move, fast drag & drop) *New feature: ToolButton displaying contextual actions on top right of tables *New feature: "Pages" launchers can be added in the toolbar *New feature: New WORD function in "Search & process" to extract a word of an attribute *New feature: More generic import through backends *New feature: Support values like this "3128/100" in imports -- Stephane MANKOWSKI Mon, 25 Feb 2013 18:06:13 +0100 skrooge (1.5.1) *Correction: Avoid endless "wait cursor" in case of canceled load of protected file *Correction: More robust weboob import for backend not supporting parallel download *Correction: Operations page layout with very long comments -- Stephane MANKOWSKI Tue, 22 Jan 2013 21:09:04 +0100 skrooge (1.5.0) *Correction bug 311252: Creating account with existing name just modify the existing one *Correction bug 312609: Banks widgets at the dashboard show wrong values *Correction bug 312671: Compile warnings *Correction bug 312859: Searching for an empty payee doesn't seem to work *Correction bug 313140: Thousands of compile warnings when using [-pedantic] [PATCH provided by Andi Clemens] *Correction bug 313141: Adjust layout in preferences window [PATCH provided by Andi Clemens] *Correction bug 271292: "Set to upper" process does not work with all characters *Correction bug 263265: Support regexps on imported data *Correction bug 313268: Better layout fot the "comment" field in the operations view *Correction bug 313240: Transfers between accounts with different currencies show as income/expense *Correction: Disable "Pin this page" when no page is opened *Correction: Disable "Print" and "Print preview" when no page is opened *Correction: Correction in the show menu of the operation page when only one account with ";" in the name *Correction: Pb of propagation for budget rule with Period=Current Year *Correction: Avoid duplicate message in notification *Correction: Avoid to set an operation in more than one budget item when "garbage" budgets are used *Correction: Display reconciliation field when the "Reconcile" function is called from the page of accounts *Correction: Transfers ignored by default in" "Incomes & Expenditures" widget and reports *Correction: Adapt the size of the "Account" field to the lenght of the accounts names *Correction: Set focus on "Date:" field after insertion or update of an operation *New feature: New "Process Immediately" method to process immedialetly some scheduled operations *New feature: Multiselection for "Jump to the operation" in scheduled operation page *New feature: New advice to detect non alignment of comments (operation vs suboperation) for simpe operations *New feature: New advice to detect operations without mode *New feature: New option Automatic refresh/Manual refresh in advice dashboard widget *New feature: New advice to switch on "Manual refresh" when advice are very long to compute *New feature: New advice to detect too complex unit definition like this: IBM => $ => £ => € (not supported) *New feature: Possibility to do graphic reports with the bank as column of line *New feature: Automatic import through weboob (http://weboob.org/) *Perfo: Better performances in advices by avoiding to compute dismissed advice *Perfo: Better performances in categories and payees tables *Perfo: Big performances improvement for huge transaction like imports or massive delete of accounts -- Stephane MANKOWSKI Sat, 19 Jan 2013 16:31:49 +0100 skrooge (1.4.0) *Correction bug 306517: "Incomes & expenses" widget displays a wrong sum for expenses *Correction bug 308050: Untranslatable strings in 'Budget' Page *Correction bug 308395: "list of operations" screen : inoperative filters (hide closed operations >1 & 2 weeks) *Correction bug 310372: Word completion in the comment field in standard operation does not work even if it was added via split operation *Correction: Better colors in "Expenditures vs Icomes" dashboard widget *Correction: Support qif file having Type:Class with description *Correction: Remove "All" in operation menu when only one account is created *Correction: Move "Export ..." menu in "File" menu *Correction: Bad display of account having a "&" in operation page *Correction: Move "Processing" actions in the main menu named "Tools" *Correction: Hide title when reset filter in operation page *Correction: Better performances in SKGDocumentBank::computeBalances by using compound query *Correction: Avoid freeze when a very old value (example: 14-11-0012) is entered by error for a unit *Correction: Avoid freeze in reports when a very old operation (example: 14-11-0012) is entered by error *Correction: "Quantity owned" in unit page does not initial amount of accounts *New feature: New button on unit page for opening the web site of the download source *New feature: Warning on closing non null account *New feature: Support for Activities *New feature: "Stock portfolio" in monthly report *New feature: "Stock portfolio" dashboard widget based on monthly report *New feature: Possibility to add hyperlinks in monthly reports *New feature: Export html in monthly reports *New feature: New widgets for dashboard *New feature: 2 new templates for monthly report are delivered by default *New feature: 2 new advices detecting very old values of unit and very old operations *New feature: New advice checking if budgets rules are treated *New feature: New option for import to "Import only operations since the last imported one" -- Stephane MANKOWSKI Sun, 09 Dec 2012 11:51:43 +0100 skrooge (1.3.3) *Correction bug 305880: On the Dashboard, scheduled transactions have wrong number of decimal places *Correction bug 306119: Cannot open document created in 1.3.0 with 1.3.2 *Correction bug 305879: Account panel shows Edition - should be Addition *Correction: Smaller bank icon selector in "Accounts" page *Correction: Set default type as "currency" in "Units" page when primary and secondary units are already defined *New feature: Add "savings" as type of account *New feature: "Tracked" operations in option of "Income vs expenditure" widget of dashboard *New feature: Export JSON -- Stephane MANKOWSKI Mon, 03 Sep 2012 16:25:21 +0200 skrooge (1.3.2) *Correction bug 300228: Failed to import from KMyMoney file *Correction bug 301137: 'To Account' of an existing money transfer is displayed incorrectly in edit area *Correction bug 302388: Gnucash import failes: Better error message in case of negative value for a currency *Correction bug 302502: Message for possible schedule incomplete *Correction bug 303527:Support more time options for ‘show checked operations’ *Correction bug 304003: Crash when removing transaction number of transactions with duplicate account numbers *Correction bug 304313: Importing a KMyMoney file results in error: "[ERR-11]: 'KMYMONEY-KMYMONEY-TEMPORARY-ACCOUNT': You are not authorized to delete this account because it contains some checked operations" *Correction: Rename columns of budget table *Correction: Better CSV and TXT exports of tables grouped by a column *Correction: Better SVG export of tables *Correction: Restore palette in tables after print *Correction: Do not display disabled schedules in dashboard *Correction: Remove text on common icons in toolbar by using QAction::LowPriority *Correction: In "Scheduled operations" page, the button "Jump to the operation" opens the operation page in template mode to authorize updates *Correction: New wording; "To be Checked" instead of "Foreseen" or "In Transit"; "Checked" instead of "cleared" or "validated" *Correction: Better mouse icon when closing pined page *Correction: Remove X confirmation messages when close a document having X pinned pages *Correction: Focus on opened page from bookmarks when the current page is pinned *Correction: Allow massive update in account page *Correction: Avoid bad table display when grouped *New feature: Progress bar in budget table for active budgets *New feature: "Open report" button from search page to open report without saving the query *New feature: Option to ignore operation tracked in reports *New feature: Option to ignore operation grouped in reports -- Stephane MANKOWSKI Mon, 06 Aug 2012 12:24:18 +0200 skrooge (1.3.0) *Correction bug 291512: Show hide checked operations setting are not retained *Correction bug 291550: Advice (dashboard) about operations with empty category : case of transfers *Correction bug 292225: Skrooge 1.2.0 crash on opening report *Correction bug 293398: Display Graph windows during Account Creation *Correction bug 293397: Error on duplicate account name creation *Correction bug 293580: Select/unselect "import state" column will display empty field *Correction bug 293941: Skrooge crashed on deleting split operation *Correction bug 278220: Wrong values in Monthly Report "Amounts in accounts" *Correction bug 296204: add balance entered in Operations *Correction bug 297722: Copy/paste comment in the table of a split operation leads to a wrong behaviour *Correction: creation of subcategories with entered number *Correction: hide templates when open operations from other pages *Correction: Use radio button in "Show" menus when needed *Correction: Support import of gnucash file without "gnc:book" *Correction: Generate an error message when trying to import a missing ofx file *Correction: FastEdition does not work when more than one "operation" page is opened *Correction: Crash on QIF export when the document has 3 operations grouped with op1.value=-op2.value *Correction: Refresh of graphs when unit values are modified *Correction: Install the grantlee filter plugin into the correct location. *Correction: Avoid empty "Account" page when no account exist *Correction: No automatic resize of columns when "auto resize" is not check *Correction: Addition the "rate" in internet code tool tip. *Correction: Amounts are displayed with the right number of digits in "operation" and "account" table. *Correction: Refresh view when a new appearance is selected *Correction: Bad computation of fake operation in case of multi selection *New feature: Better display of "Show" menu in operation table *New feature: Colors in "Incomes and Expenditure" dashboard widget *New feature: "Search & Process" is now working on comments of sub operations *New feature: "Base 100" mode *New feature: Skrooge is now able to import file have amounts with unit symbole (example: -$8.35) *New feature: Possibility to pin/unpin pages -- Stephane MANKOWSKI Mon, 23 Apr 2012 11:45:09 +0200 skrooge (1.2.0) *Correction bug 288683: E: skrooge-common: arch-dependent-file-in-usr-share usr/share/kde4/apps/skrooge/plugins/grantlee/0.2/grantlee_skroogefilters.so *Correction bug 290626: No support of OFX format *Correction: Avoid suboperations pointing on unused category when all categories are deleted *Correction: Hide internal properties in property dock *Correction: A new document is no more considered as modified *Correction: Advice "xxx is an old tracker" modified to use the LASTDATE instead of the FIRSTDATE *Correction: Better display in "Income & Expenditure" dashboard widget + addition of "Saving" *Correction: In "Account" page, "Other ..." in icon list is now working *Correction: Correction for advice "Possible schedule 'xxx'" *Correction: Hide internal properties in graph *Correction: Bug on inline edition on comment & mode *Correction: Optimisation on "anonymize" function for big files *Correction: Highlight switch on category *Correction: In operations tab, provide a "show" menu as for other plugins *Correction: Avoid duplication of some categories when search and process is used *Correction: Avoid modifications in interest table *Correction: Fast edition refreshs the "comment" field *Correction: The autocompletion list for number displays only the numbers of the selected account *Correction: Monthly report create .kde directory event if .kde4 must be used *New feature: Fields of update part of the search & process panel are not editable to facilitate the completion *New feature: Import of non local files (example: http://myserver/document.qif) *New feature: Export of non local files (example: http://myserver/document.qif) *New feature: Dashboard > Shares & Indexes renamed to "Quotes" and provide a possibility to select all available Units (Objects, Currencies etc.) *New feature: Operations > Transfer: do not display a name of a chosen source account in the field of target account *New feature: New mode in reports *New feature: Memorize expanded groups in bookmarks *New feature: "Incomes & Expenditures" widget is clickable *New feature: Highlight on units *New feature: Addition of "Show" menu in scheduled operations *New feature: Hide title in "Scheduled operations" if at least one schedule is existing *New feature: Open "Scheduled operations" when an operation is scheduled *New feature: SKGTreeView scrollbars are sticked on maximum position *New feature: SKGTableWidget scrollbars are sticked on maximum position *New feature: New "Open operations" function in contextual menu (connected with double click - support multi selection) -- Stephane MANKOWSKI Mon, 09 Jan 2012 11:01:12 +0100 skrooge (1.1.1) *Correction: "Highlighted only" is by default disabled in "Account" widget *Correction: Mysterious crash in SKGTreeView::onExpand -- Stephane MANKOWSKI Wed, 23 Nov 2011 21:44:09 +0100 skrooge (1.1.0) *Correction bug 283683: Can not add a new operation after modifying the values on an existing one *Correction bug 284220: Closed account still showing up in accounts combobox of "operations" tab *Correction bug 283840: Skrooge is unable to download units for a past period, but it works for the current day ==> Better warning message *Correction bug 284073: Expressions in splitted operation amount are not calculated *Correction bug 283842: If I add today a past operation in a different unit than the principal, the amount calculated uses the present unit value, and not that of the specific date *Correction bug 284752: Skrooge does not look for Grantlee at build time *Correction bug 284843: OFX import does not work on UTF-8 encoded files *Correction bug 285289: Misspell found: reconciliation instead of reconciliation *Correction bug 285880: Cumulative amount of main categories do not appear *Correction bug 286538: Renaming categories doesn't rename relevant search/process rules (not fixed but better error management) *Correction: Better colors in "5 main variations" widget for dashboard *Correction: Installation of grantlee_skroogefilters.so in only one place and not hardcoded *Correction: No more error when importing skg file with payees *Correction: Addition of an error message on loading of a document generated by a most recent version (example loading on a 1.0.0 document into Skrooge 0.9.1) *Correction: Addition of missing date for x axis on unit graph *Correction: Import homebank set types of accounts *Correction: Possibility to remove an empty account without warning *Correction: Better performances during migration *Correction: Change language of the document on open if the language of KDE has changed *Correction: Better affectation of payees and comments during gnucash import *Correction: Better default size of the "category" panel in the split table to avoid manual resizing *Correction: Better performances during import of multi files by applying "search & process" rules only at the end *New feature: New type of account "Loan", transfer from/to this kind of account are considered as "expenditure" in reports *New feature: New function to remove useless values in unit (the curve is preserved but useless values are removed) *New feature: New tag for grantlee to be able to use standard palette. Colors of the "Default" template are coming from the KDE palette now. *New feature: Possibility to download values of units with regular expressions. *New feature: Possibility to create/modify monthy template directly from skrooge *New feature: More detail in progress bar *New feature: New advice to find and repair operations in groups with only one operation *New feature: New advice to find potential monthly schedule -- Stephane MANKOWSKI Mon, 21 Nov 2011 15:31:03 +0100 skrooge (1.0.0) *Correction bug 280362: Skrooge is not accepting dots or commas *Correction bug 280897: Unit wont set on mt940 import when there are existing operations *Correction bug 280915: The import logic should use an existing account based on bank name read from :20: and the account number read from :25: *Correction bug 282983: Multi-currency transactions not anchored to the exchange rate of the day of the transaction *Correction bug 283246: Some text is hard to read with dark color theme *Correction: Better performances in check box of operation, account, tracker pages *Correction: Grisbi import with split operations does not work *Correction: Capability to open read only file *Correction: Completion on substring available only in "Dropdown list" mode *Correction: To improve performances, the refresh of advices is done when dashboard is activated and only if refresh is needed *Correction: To improve performances, the refresh of models is done for views in current page *Correction: To improve performances, the refresh of graphs is done for graphs in current page *Correction: "Delete unused" of category page tries a delete only on categories really not used *Correction: Various correction in bookmarks (enable/disable in menu, bad management in parent/child relation) *Correction: Cascading delete in categories and bookmarks *New feature: New function to bookmark all opened page in one click *New feature: Addition of "Once a week" for scheduled operations *New feature: Merge of trackers by drag & drop *New feature: "Count" mode in reports *New feature: In table views, when at least one scroll bar is visible, the corner widget allows to display the contextual menu of the header *New feature: Graphs can be corrected by an indice defined in unit page *New feature: Less icon in tool bar by default. New "Fast edit" button in operation editor. *New feature: Add copy menu in contextual menu for cells *New feature: Advice for closed account with amount<>0 *New feature: "Autostart" and "Remove autostart" available in multi selection *New feature: In krunner, A string like "buy 10 ESSO" allows to quickly prepare add a new operation in skrooge. Advices in dashboard allows to finalize the creation *New feature: "Auto start" bookmarks are not opened if the key SHIFT is maintained pressed during the start of Skrooge *New feature: Grouping function in all tables *New feature: New menu to lock/unlock docks *New feature: Allow menu hiding *New feature: "Monthly report" widgets for the dashboard can be set on current month -- Stephane MANKOWSKI Mon, 03 Oct 2011 14:21:04 +0200 skrooge (0.9.1) *Correction bug 271294: Modifying transactions with spaces in their amounts causes them to be reset to 0 *Correction bug 275963: Operations imported in the primary currency unit, not the account unit *Correction bug 278004: Skrooge installs library files with wrong version numbers *Correction bug 278220: Wrong values in Monthly Report "Amounts in accounts" *Correction bug 279421: General reports problems/request *Correction bug 275956: Possibility to display different accounts in different currency units *Correction: Change icons and remove useless icons *Correction: Hide useless "Add" and "Update" buttons in amortization table of "Simulation" page *Correction: No display of initial value (0000) in graph when history mode is not selected *Correction: Now the forecast period is equal to the real period *Correction: Addition of "Add category" in contextual menu of "Category" page *Correction: Differentiation between "Sum" and "Pourcent" mode of PIE graphs *Correction: When "operation" page is an a particular account, the editor is cleaned with this account *Correction: Remove password when anonymize a document *Correction: Better performance by simulating "materialized views" with tables (used for categories and budgets) *Correction: In CSV import, if 2 "amount" columns are found then the first one is considered as a debit and the second one as a credit *Correction: During import, in case of doubt, MM_DD is preferred than DD_MM *Correction: Imports are supporting dates with backslashes like 29\06\2011 *Correction: Better performances *Correction: Saving the state of 'Categories Page' ignores the resized columns with (Auto resize: off) *Correction: CSV import supports multiline file like: date;amount;comment;type "1/1/2010";1000;"transfer 1 from account A to account B";TRANSFER "2/2/2010";2000;"transfer 2 from account A to account C";TRANSFER *Correction: Protection again empty date ==> if the user remove date string then the current date is used *Correction: Toolbar is realy configurable *Correction: Import of encrypted skrooge files *Correction: Better print when many pages are open *Correction: Missing gsb format in import file selection panel *New feature: Graphs in "Bank and Account" page *New feature: Addition of "Jump to the operation" in contextual menu of "Scheduled operations" page *New feature: Properties can be a copy of a file or a link to an existing file *New feature: In all pages, possibility to hide line by using operator - in "Search" field *New feature: Addition of "Highlight" status on catagories and payees *New feature: In reports, the first columns is resizable and has a tooltip for a better display *New feature: "Expand all" and "Collapse all" in category and bookmark trees *New feature: An option to set a frequency of units download (once a day/week/month) *New feature: Properties associated by drag & drop can be copied or linked (ALT+) *New feature: CTRL+C enables copying of selected cells of tables -- Stephane MANKOWSKI Mon, 15 Aug 2011 18:53:00 +0200 skrooge (0.9.0) *Correction bug 273692: Weird overlay in each dashboard widget *Correction bug 268933: Category editing is tedious and confusing *Correction bug 270207: Cannot enter positive value (credit) for operations in my account *Correction bug 270450: Add a wallet as a distinct account *Correction bug 271529: Add a search box to the Categories tab *Correction bug 271708: Wrong account transfer merging when importing QIF files *Correction bug 272863: Allow to choose which wallet store password in *Correction bug 274777: inconsistency between amounts&nb of operations displayed by modules Tiers, Categories and Operations *Correction bug 274993: Generation of forecast in a report depends on the option "auto-write" *Correction: Error during QIF import if unit is already existing *Correction: Open property file with space *Correction: Selected items always on top in graphs *Correction: Symbol in legend when "Point" is the selected mode of graph *Correction: Skrooge crashes on change of icon for folders in bookmark dock *Correction: Show progress bar only when needed *Correction: Bad values when customized dates are changed in reports *Correction: Better draw of pies in graphs *Correction: "Antialiasing" option in settings panel + automatic refresh of graphs after settings modification *Correction: "find and group transfer" does not work if 2 operations with same date and same amount *Correction: Homebank import supports budgets and scheduled operation *Correction: Change "Context" by "Pages" *Correction: Better computation of forecast period for "Scheduled" and "Budget" modes *Correction: Better performance in advice for scheduled operations *Correction: Better proportion in reports in BUBBLE mode *New feature: Formula is autorized in splitted amount (must start by =) *New feature: Ensure visibility of selected items in graph *New feature: New logo with rupee symbol *New feature: New button to reset internal filter in reports *New feature: Settings for "Reports" to select colors *New feature: Information zone in budget to display budgeted amount based on selected budgets *New feature: New contextual action "New category" on categories *New feature: Balance and balance of the day in account widgets (table, dashboard) *New feature: Merge of an imported operation with a manual operation is now possible even if amounts are different *New feature: Button on "Scheduled operations" to jump to the operation template for edition *New feature: New advice to align scheduled operation amount with the last amount inserted *New feature: New kind of graph "stack of columns" *New feature: New kind of graph (values in % of columns) *New feature: New setting to select the color of outline in reports *New feature: New setting to enable/disable balances computation -- Stephane MANKOWSKI Mon, 06 Jun 2011 14:00:49 +0200 skrooge (0.8.1) *Correction bug 259417: Units: graph unreadable when values are missing for some dates ==> "Show origin" allows to show/hide the origin of the graph for a better display *Correction bug 259416: Report: showing limits, average and tendency does not work in mode "Sum" *Correction bug 259414: Feature request: select previously selected tab when closing a tab *Correction bug 259412: Date chooser field: keyboard shortcuts do not work *Correction bug 257324: No icon for Skrooge in the Gnome menu *Correction bug 261001: Better integration on OS X *Correction bug 261318: Amount field calculator gives too many digits *Correction bug 262511: Wrong widget placement in properties subwindow *Correction bug 263263: Separate field for income and expenditure when importing CSV files *Correction bug 263716: Conversion multiple records to "transfer" type cause all have the same ammount *Correction bug 266703: Window exceeds screen size on Netbook *Correction bug 267442: Support for mt940 files *Correction bug 267773: Skrooge always start maximized *Correction bug 267996: Export CSV not unique identifier *Correction: Bad fullname and cumulative amount on categories after a drag and drop *Correction: Import csv with "sign" column before "amount" *Correction: All items are in "Skrooge" category in "Configure shortcuts" *Correction: No symbol for curves of indexes *Correction: "XX is an old tracker" advice does not give the right result when after 31 december *Correction: GNUCash import creates sometimes "wrong" splits with values close to 0 *Correction: Better initial state for the window (docks, maximized) *Correction: Bookmark of report *Correction: Many small correction in "interest" computation (tooltips, items in combo box, computation, ...) *Correction: Bad unit in "unit" page for units having a unit reference *Correction: Better tooltips in report (usefull for huge report where lines title is not visible) *Correction: Better management of codex for exports *Correction: Bad value when update of transfer is done from target account of the transfer *New feature: Import csv with ' as cote (for "Money Manager Ex" exports) *New feature: Import csv is now possible on file without header *New feature: Import csv supports more than one "category" column *New feature: Import "Money Manager EX" file *New feature: Change icon on bookmarks *New feature: "Open potential duplicates" *New feature: Massive update on budgets *New feature: Delete is more secured. *New feature: Force mode on delete. *New feature: Possibility to change the account of operations even when only operations of one account are displayed (useful for credit card) *New feature: New "Search & Process" panel *New feature: Property dock is able to display all properties *New feature: New "About" panel using KDE 4.6 features *New feature: Better mass update on "account", "payee", "tracker" and "unit" pages *New feature: Possibility to merge accounts by using massive update on name of accounts *New feature: Possibility to merge payees by using massive update on name of payees *New feature: Possibility to merge units by using massive update on name of units *New feature: Possibility to merge categories by using massive update on name of categories *New feature: Timeline in reports *New feature: Some fields are directly editable in view *New feature: Completion for all fields with operators (=upper and =lower for the moment) *New feature: New "stacked area" graph type *New feature: New "bubble" graph type *New feature: New button in "operation" page to freeze/unfreeze all fields with text *New feature: Better zoom widget in contextual menu of reports -- Stephane MANKOWSKI Mon, 14 Mar 2011 15:40:34 +0100 skrooge (0.8.0) *Correction bug 250350: Impossible to update an operation of a closed tracker *Correction bug 250403: Dashboard "Shares & Indexes" shows wrong percentaged variation *Correction bug 250677: Bank account choice do not use the country information *Correction bug 246973: Dashboard should be more customizable *Correction bug 251465: Wrong totals with second currency accounts *Correction bug 252869: Skrooge doesn't import KMM bank names correctly *Correction bug 255133: Skrooge crash on ofx import (With wrong data format. Bug in libOFX) *Correction bug 221207: Budget and forecast for accounts *Correction bug 256214: Skrooge after full screen mode I have only StartPage *Correction bug 257322: Installation doesn't depend from "QCA OSSL plugin for libqca2" (libqca2-plugin-ossl is not optional) *Correction bug 258307: comment from main split operation duplicated *Correction bug 258621: Skrooge crashes when KDE session is closed *Correction: Better dashboard display by using a flow layout *Correction: Bookmark of report having "Columns: -- Nothing --" *Correction: Support of "!type:prices" for QIF import and export *Correction: Better export KMyMoney *Correction: Better detection of double during imports *Correction: Protection again sql injection *Correction: Graph redraw even on hidden tabs *Correction: Crash on selection of a cell when graph is hidden in reports *Correction: Refresh of page in case of reset default state *Correction: Boorkmark of "operation" page in template mode *Correction: In report, hide columns or lines without property *New feature: On reports, average and limits are available if "All values in positive" is used too *New feature: Download of all additional information as properties for units (new setting to activate this mode) *New feature: Skrooge is able to store passwords in KDE wallet (new setting to activate this mode) *New feature: Scheduled operations with warning are in bold in dashboard *New feature: Show/hide properties as a column in tables *New feature: Auto point of imported operations to obtain the expected final balance *New feature: Reorder widget in dashboard by drag & drop *New feature: Floating panel in dashboard to remove or zoom widgets *New feature: Accounts can be merged by drag & drop (useful after an import) *New feature: Units can be merged by drag & drop (useful after an import) *New feature: Automatic import of csv columns as properties based on regular expression *New feature: New report capabilities *New feature: Sub total in reports *New feature: New advice for bank without account *New feature: New icons for banks of South Africa (Thank you David) *New feature: OR operator (+) supported in string filters *New feature: New contextual menu in html pages for export as pdf, odt, image and copy *New feature: Possible to show/hide items in context list *New feature: Forecast based on budgets *New feature: Multi selection in report table and graph *New feature: New "show" button *New feature: Better performances on dashboard *New feature: Better performances on tracker page *New feature: New function on operation: "Merge sub operations" *New feature: New advice for budgets *New feature: Possibility to dismiss kind of advices *New feature: Hide tendency line column -- Stephane MANKOWSKI Mon, 06 Dec 2010 15:31:21 +0100 skrooge (0.7.3) *Correction bug 245847: skrooge 0.7.3: 'pow10' was not declared in this scope *Correction bug 213786: Account balance is not displayed *Correction bug 246178: Dashboard "Income & Expenses" widget counting transfers *Correction bug 246408: Skrooge prints hardcopy *Correction bug 246977: In reports from selected data the date selection should be all data *Correction bug 247445: Linker error in skgbasemodelertest/skgtestnodes.cpp *Correction bug 246976: 'Select all' option in menu edit *Correction bug 249955: No password request after hardware crash *Correction: Better management of print option (collate, nb copy, from, to, last page first) *Correction: Do not authorize creation of operation with "-------" *Correction: In report, capability to create history with of property *Correction: In report, do not allow hiding table or graph by resizing *Correction: Import QIF with !Account section containing more than one account and with D attribute (Thank you Dennis) *New feature: Properties with a 'http' or 'file' url as value can be opened from skrooge (useful to set bank site on an account) *New feature: New daskboard component to know money per bank *New feature: Bookmarks in a menu *New feature: Context in a toolbar (useful for small screen) *New feature: Advice widget in dashboard *New feature: Full screen (useful for small screen) *New feature: Addition of file as property by drag and drop *New feature: Tables are scrolled "bottom" or "top" based on sort order -- Stephane MANKOWSKI Sun, 05 Sep 2010 07:36:37 +0200 skrooge (0.7.2) *Correction bug 237498: Skrooge crash on saving preferences (when system tray is not available) *Correction bug 238087: kAmountEdit widget in Operations plugin isn't properly localized *Correction bug 238477: Cannot open base if partition is full *Correction bug 240600: Skrooge must be able to export as a sqlite database *Correction bug 240640: Skrooge crash after password entered - input file DELETED at failure *Correction bug 234597: Gnucash import issues with two accounts with the same name *Correction bug 240601: Skrooge must be able to export an anonymized file *Correction bug 243738: Import of Gnucash file that has CNY currency fails *Correction bug 245254: Category creation failed on first level *Correction: Drag & drop of categories *Correction: Import skg file with tracker or interest simulation *Correction: No XML export of tables sqlite_sequence and sqlite_stat1 *Correction: Layouts compatible with small screen (1024x768) *Correction: Open right page when click on "Estimated interest" in dashboard applet *New feature: Zoom on tables by using CTRL+wheel *New feature: Search button is "Search & process" page to be able to search operations without creating a rule *New feature: Click on a column in "Search & process" editor removes the column *New feature: CTRL+F opens the "Search & process" panel with a condition based on current selection *New feature: Stability of colors in graph *New feature: Selection of colors in graph (saved and restored) *New feature: "Add property" to add easily properties *New feature: skg files saved on a FTP server can be loaded directly from Skrooge. Save is not possible. *New feature: New "Payee" page *New feature: Merge of payees by drag & drop *New feature: Report plugin is able to display graph based on properties *New feature: Possibility to select icon file for a bank *New feature: Any kind of file as property *New feature: Go home -- Stephane MANKOWSKI Sat, 24 Jul 2010 10:00:00 +0200 skrooge (0.7.1) *Correction bug 233895: Switching account from 1 type to another with multi-sel is modifying the initial balance *Correction bug 233930: QIF address field is not imported *Correction bug 234595: Better handling of category deletion ==> Reparent operations on parent category when a category is removed *Correction bug 234608: Some gnucash notes are lost during import phase *Correction bug 234771: Problem importing ofx file *Correction bug 234845: Bad Account after importing ofx *Correction bug 235689: Cannot localize quotation marks *Correction bug 234596: Customisable date format in operations panel *Correction bug 236753: Search but not process on attribute *Correction: Rename "Import CSV unit..." in "Import currency values..." *Correction: Better management of constraints in data model *Correction: Conflict on categories when importing twice a gnc document *Correction: Conflict on categories when importing twice a xhb document *Correction: Conflict on categories when importing twice a gsb document *Correction: Conflict during property update *Correction: Modification of trackers in splitter operations from "Search and process" *Correction: Transfer when signe + is specified before the value *Correction: Various modifications on "Search & Process" *Correction: Replacement of [%1] by '%1' for localization *Correction: No more direct sqlite prerequisit *New feature: Better performances on "File/New" (first Save is longer) *New feature: Usage of KNewPasswordDialog and KPasswordDialog for password protection *New feature: Applet for dashboard to display tip of the day *New feature: CSV import of splits and transfers *New feature: CSV import is able to oncatenate many attributes in "comment" or "payee" *New feature: CSV import is to import unknown attributes as properties *New feature: Export XML *New feature: "Search & Process" is able to search on properties values *New feature: "Search & Process" is able to update, insert and delete properties (prop='' to delete it) *New feature: All currencies are now available in unit page (Thanks to KCurrencyCode) *New feature: Properties are displayed on tooltips *New feature: Open property picture associated to an object -- Stephane MANKOWSKI Mon, 10 May 2010 15:21:33 +0200 skrooge (0.7.0) *Correction bug 225855: Monthly Report: difference in percentage is wrong *Correction bug 225980: Share download not in primary currency : value not correct *Correction bug 226451: .skg file incorrectly identified as password-protected ==> New document icon to identify encrypted files *Correction bug 228808: Gnucash import: scheduled operation at 0 euros *Correction bug 228904: Gnucash import should not take into account recurrent operation containing loan formulas *Correction bug 230175: Sometimes report plugin resizes Skrooge over the screen size *Correction bug 232937: Search & Process : if a category has no operation yet, it doesn't appear in the possible categories for "update" *Correction wis 228901: Manage Liability accounts (loan, etc...) *Correction wis 197409: There's no way to define initial balance of non-OFX account *Correction wis 224933: A legend in the graphics *Correction wis 224042: Possibility to store several CSV import schemes ==> Implemented by regular expression in automatic mapping. *Correction wis 225818: Change skrooge desktop file description *Correction wis 226963: Export CSV of split operations *Correction wis 228170: Skrooge must be able to import skg file *Correction of forecast computation on scheduled operations *Correction of export of "Initial balance" for QIF and CSV *Correction of import of "Initial balance" for QIF and CSV *Correction of import of "Initial balance" for OFX *Correction: Better error message in case of repository of document is RO *Correction on confirmation message *Correction selection on graph (histogram and stack) *New feature: "Weighted moving average" in reports *New feature: Specific font and color for disabled schedule (nbtime = 0) *New feature: Addition of "First date" and "Last date" in trackers *New feature: Amortization table *New feature: import gnucash document *New feature: import kmymoney document *New feature: import skrooge document (can be used to merge documents) *New feature: import grisbi document *New feature: import homebank document *New feature: export kmymoney document *New feature: export skrooge document (without history) *New feature: possible to create a bookmark even when a bookmark is already selected *New feature: button to clean history (reduce the size of the file) *New feature: all settings in only one file. WARNING: check your settings. *New feature: generic modeler is ready to be used by other applications. *New feature: "5 main variations" in monthly report. *New feature: New key accelerator to enable editor of current page -- Stephane MANKOWSKI Mon, 05 Apr 2010 20:00:00 +0200 skrooge (0.6.0) *Correction wis 215668: Dashboard is too big to be a real dashboard *Correction bug 216520: Incorrect import of a transfer when inside a splitted operation (a splitted operation can not be a transfer) *Correction bug 217896: UK Currency and Date formats displayed for Scheduled Transactions in Dashboard *Correction bug 217743: Configuring Banks and Accounts Section (Bank name update issue) *Correction bug 219791: No progress bar during export QIF *Correction bug 219750: Delete key in split table remove the full line *Correction bug 214508: Provide a balance evolution graph *Correction wis 220659: Option to "Apply rules on to imported operations" automatically after an import *Correction cra 220936: Crash on double click on bookmarks *Correction cra 222340: Freezes after some time *Correction bug 222339: CVS import: problem with decimal point and comma *Correction wis 220663: Selected operations must still visible after a sort modification *Correction wis 223848: make libofx an optional dependency *Correction wis 224676: keyboard shortcut for modify and add operation *Correction wis 209314: key scrolling does not work, and click on a line has odd behaviour *Correction bug 224932: Graphic Report SVG export bug + wish on a legend *Possible to define favorite account *Possible to define favorite search *New gui for search and process *Delete icon on each suboperation line *Compatibility with bespin theme *Do not collapse tree after editing one of its items *More options in "Report" page *New function to delete unused categories *Selection in pages list is now synchronized with current page *New option in contextual menu of report to hide bottom tool bar *Edition of splitted operations by single click *Clean button in operation table is renamed "Clear form" *Better export QIF for investment *Better display on reports (average, min and max are displayed if only one curve is drawn) *Better display on reports (linear regression is displayed if only one curve is drawn) *Option to show/hide average and limits in graph *Selection of year for interets computation *Correction in sum of operation computation when suboperations are selected *Graph proportion adapted to view size *"Account position" is replaced by "Ending balance" *Avoid cpu loop when double click on operation fields on KDE 4.4 *Completion based on substrings *Better import of QIF files when both side of the import do not have exactly the same date *Correction on update category and tracker for transfers *Completion on comments -- Stephane MANKOWSKI Sat, 06 Feb 2010 09:00:00 +0100 skrooge (0.5.5) *Disable some functions on sub-operations *Correction on update of a splitted operation by a split returned by Fast Edition *Correction bug 215995: SQL Error when attempting to display a report in history mode *Correction bug 215754: Invest account is incorrectly imported as current account *Correction bug 214809: Incorrect import of a transfer *Correction bug 214851: Incorrect import of 'investment account' QIF file *Correction bug 216348: Account filters synchronisation problem in the operation HMI *Correction bug 216522: Incorrect import of transfer (twice imported) *Correction bug 216551: Click in blank area make 'date' widget to extend its size *Correction bug 216514: Incorrect import of QIF file when account names are similar *Correction bug 216520: Incorrect import of a transfer when inside a splitted operation (transfer of suboperation is not supported) *Correction crash 215992: Skrooge crash when clicking on "rapport" menu *Correction regression on "Open report" (P0) *Invertion of colors in report (more saturation for new operations) -- Stephane MANKOWSKI Sun, 29 Nov 2009 15:00:00 +0100 skrooge (0.5.4) *Correction bug 211579: Irregular percent value in monthly report amounts in accounts *Correction bug 212313: Can not update a lot of operations *Correction bug 211029: Skrooge should have an better account evolution graphic *Correction bug 213783: Account balance computation is inaccurate *Correction bug 214045: Import CSV date format problem *Correction bug 214097: Can not search on multiple criteria. (OR is not supported) *Correction bug 214157: Impossible to import an ofx file from a directory containing special characters *Correction bug 214462: Does not use primary currency unit when importing, and does not warn on import of splitted operation with multiple currencies *Correction bug 214447: Auto save the open document at closing *Correction bug 214794: Incorrect report of warning when importing QIF file *Correction bug 214809: Incorrect import of a transfer *Correction bug 214849: CSV export from grid is not correct *Correction bug 214904: Can not download a stock/share quotation *Correction bug 214851: Incorrect import of 'investment account' QIF file *Correction bug 215114: Button to customize dashboard *Correction bug 215620: Can not import QIF file with skrooge version SVN 1052520 *Correction bug 215656: History reports are wrong if first date is not selected *Correction bug 215658: Some editors are modified when a bookmark is created *Correction on double click of a template of transfer *Update of both side of a transfer is now possible *Only one fast edition. User is be able to lock some fields before. *Interest can be computed with 360 and 365/366 days method *New splashscreen size *New graph gui with "Quarters", "Semesters", "Weeks" and "Days" *Zoom with CTRL+wheel on graph *Dashboard is automatically launched when a new document is created *Use of graph component in unit page *New button to clean editor in operations page *Correction on scheduled transfers *New report widget for dashboard (all reports can be added to dashboard) *Addition of "Del" shortcut to delete suboperations in split panel *New tooltip on operation status *New function "Open sub operations" to display all sub operations. Useful to filter them. *New function to reconciliate an account from bank page *Better QIF import/export of account type -- Stephane MANKOWSKI Mon, 23 Nov 2009 14:00:00 +0100 skrooge (0.5.3) *Correction bug 209451: Display quantity of each unit *Correction bug 209457: Number of decimal for each unit must be different *Correction bug 209453: Impot must avoid double even when operations are not validated *Correction bug 209529: Unable to reconcile. Delta zero but "Validate checked operations" tick still grayed out *Correction bug 208939: "Search and process" does not work anymore *Correction bug 209610: Skrooge doesn not work if "Maximum undo depth" is 0 *Correction bug 209542: Automatic conversion of schedule *Correction bug 209672: Amount of indexes must be displayed without unit symbol *Correction bug 209705: Importing investments from csv doesn't import the dollar amount of shares purchased *Correction bug 209705: Find&Group is now able to detect share purchase/sale *Correction bug 209702: Need the ability to be able to manually group transfers *Correction bug 209914: executable bits set for skgalarmboardwidget.h *Correction bug 209905: currency import is broken *Correction bug 209912: rpmlint warnings after installation: unused-direct-shlib-dependency *Correction bug 209053: Savings account support request *Correction bug 210946: columns are always resized to content when opening operations tab *Save icon in tab bar to overwrite bookmarks or current context *New dashboard plugin for highlighted operations *New dashboard plugin for estimated interests *"Backward" & "Forward" navigation on pages *New unit "Swedish krona" *New command to open operations modified during last user action (useful after an import or a processing) -- Stephane MANKOWSKI Mon, 19 Oct 2009 12:00:00 +0200 skrooge (0.5.2) *Correction bug 207927: skrooge summary field uncomplete bank account name *Correction bug 208130: 'Import CSV Unit' menu puts data into the 'Operations' tab *Correction bug 208210: Multiple clause research/update in french *Correction bug 208194: Skrooge loose all data on file migration *Correction bug 208040: Error when entering shares information *Correction bug 208459: Skrooge crashes when changing tab *Correction bug 209317: key scrolling very long *Better performance in report by using QTimer *Better performance bank page by using QTimer *New SKGDateEdit with more features *Delivery of default categories and bookmarks for pt. Thanks Caio de Campos Ferreira. *Better performance when opening pages *Correction on monthly report for a better display with dark theme *New widget on dashboard for alarms *SKGDateEdit validation on lose focus *Automatic detection of CSV separator during import -- Stephane MANKOWSKI Sun, 04 Oct 2009 16:00:00 +0200 skrooge (0.5.1) *Correction bug 205471: Impossible to know how to check an operation *Correction bug 205466: Date missing in reports *Correction bug 193426: Ability to create from scratch a "recurrent operation" *Correction bug 203787: Balance should be displayed for each operation in the operation context. Correction done: balance is displayed on tooltip because it is better for performances than in column. *Correction bug 206894: Crash second import CSV *Correction bug 206459: "Search & process" must be able to do complex update *Correction bug 199539: Dashboard must be customisable *Correction bug 207249: rpmlint error: debuginfo-without-sources (including a fix) *Correction bug 207246: rpmlint warning shared-lib-calls-exit /usr/lib64/libskgbasemodeler.so.0.5.0 exit@GLIBC_2.2.5 (for fedora packaging) *Correction bug 207232: skrooge must use kfilterproxysearchline *Correction bug 207274: "Fast edit" behavior must be modifiable by settings *Correction bug 191966: Treeviews collapsed when updated *Correction bug 207672: Align amount values on the right for cleaner views *Correction bug 207713: Display some information after applying a process *Correction bug 200790: Search creation doesn't take not validate predicate *New function to create template of operations *New function to schedule templates *New function to create template from existing operations *Double click on template creates the operation *New shortcut for import *Attribute to define the maximum number of occurrence for scheduled operations *Attribute to define the last occurrence date *A setting allows to create automatically a template when an operation is scheduled *Selection is done on duplicated object after a "Duplicate" *Selection is done on created template after a "Create template" *Correction message in history when an object is deleted *Download button always visible on unit plugin *Infinite symbol when number of occurrences is not checked *Addition of "Custom..." on graph dates *New spash screen *New function to overwrite bookmarks after a modification *Filter capability on "search & process" table *Editors are no more clean when the selection is empty. A second click is needed -- Stephane MANKOWSKI Sun, 20 Sep 2009 00:00:00 +0200 skrooge (0.5.0) *Correction bug 201316: import qif extra tag support *Correction bug 201157: Graphs no longer displayed *Correction bug 201289: Compiler error on GCC 4.1.2 (enum with KDE_EXPORT or similar macro) *Correction bug 201451: qif import other liability account type *Correction bug 201697: Pointed operation can be deleted *Correction bug 201800: Filter issue with number formatting *Correction bug 202167: Payee list should be ordered in a case insensitive way *Correction bug 202341: Combobox lists are not sorted in a locale-aware way *Correction bug 202384: Skrooge always wants to update report bookmarks on exit *Correction bug 202636: Hidden columns are sometimes displayed *Correction bug 203894: Skrooge crashes when launched with --nofork *Correction activation of "Values" button in "Units" page *New password is no more displayed when changed *New function to merge an imported operation with an operation manually entered *New refund icon *New widget for dashboard "Shares and indexes" *Modification titles on "operation" pages to differentiate "operations" and "sub operations" *"sub operations" can be identified by a specific font and color (see settings) *Correction bug: Created search is not selected after creation *Correction performance issue on zoom when antialiasing is enable *Addition of 5 main categories of expenditure in monthly reports *Rename "Bookmark" for operation by "Highlight" *Rename "Trait" by "Process" *Set minimum size for amounts fields *Only one "Import..." command for all supported format. *Support of QFX import *New settings for import CSV *Dashboard is now clickable *Dashboard is modifiable (see contextual menu on each widget) and state can be saved *Addition of "Fast edition" without amount modification. It is useful to modify imported operations *Only one instance of skrooge can be launched. *Imports can be done in command line. Example "skrooge myfile.ofx" with skrooge running *If an invalid expression is entered for the amount, the field is written in red, and the expression is kept to allow correction from the user (previously, 0 was displayed). *"New tab" is now managed by Ctrl+Shift+T *Popup to ask if you want to save current state of pages. *Bookmark storage is no more dependant of language translation -- Stephane MANKOWSKI Fri, 28 Aug 2009 21:00:00 +0200 skrooge (0.3.0) *Correction bug 191970: Attach receipts (images) to transactions *Addition of "Trackers" for lines in report *Correction bug 195254: Do not allow to link operations to a closed tracker *Correction bug 195026: A setting must allow to clean history when the application is [saved] *Correction bug 194826: End user must be to validate an import *Correction bug 196444: Can not validate reconciliation (delta = -0.00) *Correction bug 196745: Categories are not added to a split operation *Correction bug 197287: Add backup file management *Correction bug 197288: Manage working document copy *Correction bug 197835: Reconciliation mode : currency problem *Correction bug 198077: Comments do not appear in every Operations windows *Correction bug 198583: foreign currency accounts should display in their native currency in dashboard. *Correction bug 198786: Categories are not easily read *Correction bug 199196: build error in skgbankgui *Correction bug 199543: Splash screen display must be defined by settings *After an import, skrooge is able to execute some rules to clean imported operations *Correction in dashboard *Addition of "Reset state" on tabs to reset default state of plugins *Most important category and refund are displayed for split operations *Display detail of selected operations in information area of "operation" page *Main tab position can be selected in settings -- Stephane MANKOWSKI Sat, 11 Jul 2009 16:00:00 +0200 skrooge (0.2.9) *Correction bug 2787146: Single click on bookmarks *Correction bug 191972: Selection is not well kept *Correction bug 191975: Add Labels for X values in histograms and stack reports *Correction bug 191968: Information string on top of page is too long (no word wrap) *Correction bug 192687: fonts too large on report *Correction bug 192832: Do not take amount sign into account for transfers *Correction bug 191967: Skrooge must be able to display an history global and for each account. *Correction bug 193423: context list scrolls down only after 8 mouse molette rotation *Correction bug 193431: "recurrent operation" trigger can not be set on D day *Correction bug 193421: bugs to be registered via bug database (not email) *Correction bug 194650: Fast edit must work on Tracker attribute *Correction bug 194765: Number of operations by account must be displayed in bank plugin *Addition of bank icon on account combo boxes *Addition of Canadian dollar *Addition of one more view (based on selection) in operation plugin *Better managment of dependency between units *New settings on unit download *Skrooge tries to find the most adapted account during import file without account information inside *Update of nls part of data model when language is changed *"Open report" on an element of a report open a new report with exactly same settings than first one *Addition of "scheduled operations" in dashboard plugin *New operation editor *Better management of messages in status bar *New editor in unit plugin *Middle click is able to open new page from context or bookmarks -- Stephane MANKOWSKI Sun, 31 May 2009 23:00:00 +0200 skrooge (0.2.8) *Correction bug 2782399 :Skrooge must create a backup file *Correction bug 2783111 :Typo *Correction bug 2515571 :New plugin to follow refunds *Correction bug 2785938 :Single click *Correction bug 2786183 :Load standard categories? *Correction bug 2682777 :Label are not well placed *Correction bug 2579926 :Improve category plugin performances *Correction bug 2665265 :Edit names directly in treeview *Correction for amount comparison in validation mode *Correction import ofx when bankid is empty in ofx file *Correction mime type for KDE4 *Better performances on open document with password required -- Stephane MANKOWSKI Mon, 04 May 2009 15:00:00 +0200 skrooge (0.2.7) *Correction bug 2513827 :global print function *Correction bug 2692667 :Automatic icon resize is driven by bookmarks only *Correction bug 2714592 :Skrooge must be able to manage properties on all objects *Correction bug 2733958 :Auto hide *Correction bug 2747379 :Only allow to "pre-check" operations *Correction bug 2750464 :Impossible to update the date of a split operation *Correction bug 2778333 :Enhance hidden panels discoverability *Correction bug 2777697 :bookmark modifications are not kept when closing skrooge *Old method to split an operation is no more available *"Undo document" is no more in toolbar by default *Remove useless icons from tool bar *When "Save" is clicked in a new document, automatically interpret it as "Save as" *New menu with shortcuts to open pages *Better automatic linear scale in reports -- Stephane MANKOWSKI Mon, 27 Apr 2009 15:00:00 +0200 skrooge (0.2.6) *Correction bug 2692651 :antialias on graphs *Correction bug 2692665 :Wrong currency label in stock tab *Correction bug 2692605 :Title of a report for a selection contains only ",,,," *Correction bug 2692648 :New dialog box on exit *Correction bug 2692664 :add support for split & grouped operations in fast edition *Correction bug 2692656 :More details on recurrent operations view *Correction bug 2645610 :Bad performance on "find transfers" *Correction bug 2692681 :Reconciliate mode in operations view *Correction bug 2706987 :no report generated *Correction bug 2716734 :Better category & unit creation during operation creation *Correction bug 2720760 :Popup messages are displayed twice -- Stephane MANKOWSKI Sun, 29 Mar 2009 20:00:00 +0200 skrooge (0.2.5) *Correction bug 2664613 :Not possible to show a column without reseting all *Correction bug 2633375 :2 columns for quantity *Correction bug 2674862 :Bad performances on undo/redo for categories *Correction bug 2675606 :Bookmark reorder doesn't work *Correction bug 2685241 :Add postive sign in amount field for positive operations *Correction bug 2685236 :Option to ask again if modified bookmark should be saved *Correction bug 2685270 :Impossible to modify comment on operation and sub operations *Correction bug 2687115 :filter value is not save whan bookmark a report *Correction bug 2685335 :Pie like in firelight *Debug plugin is able to do a "EXPLAIN QUERY PLAN" *Path for bash is not more hardcoded in script for BSD compatibily -- Stephane MANKOWSKI Mon, 16 Mar 2009 14:00:00 +0100 skrooge (0.2.4) *Correction bug 2608762 :Cannot create a bookmark folder if no bookmark exist yet *Correction bug 2633444 :Add "import std categories" in import menu *Correction bug 2638120 :Unable to import cvs or qif from "la banque postale (fr) *Correction bug 2564982 :Creation of default bookmark *Correction bug 2640959 :Impossible to import OFX file -- Stephane MANKOWSKI Mon, 02 Mar 2009 20:00:00 +0100 skrooge (0.2.3) *Correction bug 2608762 :Creation of category branch in one shoot *Correction bug 2608768 :Crash in category creation *Correction bug 2586878 :skrooge crashes if category too deep *Correction bug 2446175 :better split operations *Correction bug :sum column always displays 0 in category page *Addition of comment on suboperations *Better performances to compute next values for operation numbers *Icon in system tray *"export SKGTRACESQL=xxx" is able to trace all sql order taking more than xxx ms -- Stephane MANKOWSKI Mon, 23 Feb 2009 21:51:12 +0100 skrooge (0.2.2) *Correction bug 2556346 :README should list kdesdk-scripts as buildtime dependency *Correction bug 2556406 :Pound sterling missing in currency list, difficult to add *Correction bug 2556340 :CMakeLists should use correct libraries and check for Sqlite (Thank you lindevel for the patch) *Correction bug 2555861 :"make package_source" contains too many files *Correction bug 2557366 :Wrong password *Correction bug 2556381 :Impossible to change negative quantities into positive ones? *Correction bug 2530932 :Better autostart bookmarks management -- Stephane MANKOWSKI Wed, 11 Feb 2009 21:51:12 +0100 skrooge (0.2.1) *Correction bug 2517386 :Move of category is not done *Correction bug 2519334 :Smooth scolling in category view *Correction bug 2517388 :Selection must be set on created operation *Correction bug 2519847 :Duplicate operation *Correction bug 2520516 :Security of skg file *Correction bug 2545021 :compilation fails because po/listFiles.sh is not executable *Correction bug 2549911 :Import standard categories *Correction bug 2526148 :Double click on graph in report *Correction bug 2520530 :KToolBarPopupAction for undo/redo *Addition of icon for stocks *Bookmark can be deleted from contextual menu *Icons are resized relative to list width -- Stephane MANKOWSKI Sun, 01 Feb 2009 20:00:00 +0100 skrooge (0.2.0) *Correction bug 2489823 :automatically remember changes on columns for bookmarks *Correction bug 2487934 :Specific Column for "scheduled" icon *Correction bug 2487866 :deselect lines in table views *Correction bug 2487981 :add a column for total of operations including subcategories *Monthly report is now base on QWebView and contain google graph *Addition of exports in report tables (TXT, CSV) *Report can be opened from bank, operation or unit page *Report can be opened from report *Better graph *Addition of print *Long transaction can be interrupted *Better warning message with history -- Stephane MANKOWSKI Mon, 19 Jan 2009 20:00:00 +0100 skrooge (0.1.9) *Better contextual menu on tables *New feature in monthly report *Better performances for monthy report generation *Better graphics in report plugin *Addition of exports in all tables *Addition of exports in report graphs (PDF, SVG, picture) -- Stephane MANKOWSKI Sat, 03 Jan 2009 20:00:00 +0100 skrooge (0.1.8) *Correction bug 2299303 :Calcul de balance erroné *Correction bug 2446162 :Distinction for future operations *Correction bug 2446184 :Reduce spacing between rows *Correction bug 2256687 :No more icon in application menu *Correction crach in qtdesigner due to SKGTableView *Addition "open bookmarks" to display all bookmarked operations *Addition of sale of stocks *Addition of "split of stock" -- Stephane MANKOWSKI Tue, 22 Dec 2009 20:00:00 +0100 skrooge (0.1.7) *Correction bug 2385144 :Unexpected display of unit in operations list *Correction bug 2390926 :Problem with Action/$/€ *Correction bug 2390747 :Operations transferred not found *Correction bug 2384834 :Multi-Selection and Ctrl-P does not work *Correction bug 2311993 :Difference between operation and valuation not done *Correction bug 2385059 :Possibility to remove (modify) buggy unit value *Correction bug: Inversion year(s) and day(s) in recurrent operations *Correction wrong mapping on all table when column are reordered *Correction request 2379612: categories edition & creation *Selection is now kept after modifications *New "Monthly report" plugin *Computation of RIB key *Addition contextual menu on all table *Addition contextual menu on tabs *Addition of short date in tooltip on fancy date *Addition of smooth scrolling in table views *Addition of indexes (CAC 40, NASDAQ, ...) in data model -- Stephane MANKOWSKI Tue, 15 Dec 2009 20:00:00 +0100 skrooge (0.1.6) *Support of import unit values in CSV format like: date;value 01/01/2008;50 03/03/2008;60 *Correction bug 2340201 :crash on QIF export *Correction bug in import if 2 operations with same attributes (date, amount, ...) *Correction concerning performance issue in all tables *Correction bug 2299354 :Ability to change and memorize column width *Columns can be switched in "auto resize" mode *Correction bug 2298982 :An account shall have a currency *Preferred table's organisation can be save as default *Better organisation of pies in report plugin -- Stephane MANKOWSKI Tue, 01 Dec 2009 20:00:00 +0100 skrooge (0.1.5) *Correction bug 2307068: Incorrect import of QIF file *Columns order is now saved in bookmark for operation, account, recurrent operations and unit plugins *Sort is now saved in bookmark for operation, account, recurrent operations and unit plugins *Correction bug 2327676: Many import QIF correction *Columns can be show or hidden (see contextual menu) and this state is saved in bookmarks *Better performances (x100) in report. *Correction bug 2316459: skrooge does not support out-of-source build *Correction bug 2298621: Unable to delete a "principal currency". ==> It is now possible to delete a unit except if this unit is already used by at least one operation *Correction bug 2326576: Field empty by default *Correction bug 2306914: "Tip of the day" dialog can not be removed -- Stephane MANKOWSKI Tue, 24 Nov 2009 20:00:00 +0100 skrooge (0.1.4) *New icons *Bookmarks folders are opened sorted and focus is set on the first one *Correction (inversion sign of operations) in transfer creation *Buy stock is now possible *Correction bug 2298773: Unit and amount are not aligned *Correction bug 2298674: Montant en EUR même si unité EUR n'existe pas *Correction bug 2298471: Unable to change type of a unit *Correction bug 2299384: File/Close closes the current page *Correction bug 2299524 *Correction bug 2299519: "Mode" should not be mandatory *Optimisation in open "operation" pages *Correction bug 2299600: Values of a unit are not sorted out *Correction bug 2299947: Unit can not be used if no symbol is defined ==> Symbol is now mandatory *Correction bug 2301337 *Correction bug 2300013:Une ventilation est une catégorie *Correction bug 2278703:Zoom fit when opening report tab *Comment on account *Tab name is now set with the name of the bookmark -- Stephane MANKOWSKI Tue, 17 Nov 2009 20:00:00 +0100 skrooge (0.1.3) *Vertical alignment in all views *Detection of the sign of an operation (during creation) based on category *Average in report *Sum column is now displayed only if more than one column is displayed in report plugin *Correction bug in report when sort is set on last column and the report is refreshed with less columns *Correction abend on delete *Modeler is now able to store messages on transaction. *Display messages by notification *Addition of recurrent operations (creation, update, delete, automatic insertion, warn, ...) *Correction in duplication of recurrent operations: Now, status, bookmark, importation id are not duplicated *Correction on optimisation of undo/redo transaction: optimisation removed :-) *Multi selection is supported by recurrent operations creation icon *Massive update on recurrent operation *Implementation enhancement 2272115 concerning calculator behavior *Correction update of split operations *Set default order in all tables *Sort bookmark by drag and drop -- Stephane MANKOWSKI Sat, 14 Nov 2009 20:00:00 +0100 skrooge (0.1.2) *Support of categories in QIF import *Support of csv file with empty lines *Support of categories in QIF export *Correction bug 2229770: automatic erase of duplicated operations *New design for operation and account plugin *Addition of first draft of recurrent operations -- Stephane MANKOWSKI Tue, 10 Nov 2009 20:00:00 +0100 skrooge (0.1.1) *Optimisation widget refresh after a huge QIF import *Optimisation performance of QIF export *Optimisation performance of CSV export *Optimisation performance of "find and Group transfers" *Addition of "Close", "Close All" and "Close All Other" to manage pages *Correction on download unit *Addition of the name of the file in the title of the man window *Addition of sort in report plugin -- Stephane MANKOWSKI Tue, 03 Nov 2009 20:00:00 +0100 skrooge (0.1.0) * QIF import/export * CSV import/export * Basic graphs * Several tabs to help you organize your work * Infinite undo/redo (even after the file was closed !) * Instant filtering on operations * Infinite levels of categories -- Stephane MANKOWSKI Mon, 02 Nov 2009 20:08:00 +0100 diff --git a/skgbasemodeler/skgservices.cpp b/skgbasemodeler/skgservices.cpp index 1b410ec05..c82961f73 100644 --- a/skgbasemodeler/skgservices.cpp +++ b/skgbasemodeler/skgservices.cpp @@ -1,2042 +1,2037 @@ /*************************************************************************** * 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 * This file implements classes SKGServices. * * @author Stephane MANKOWSKI / Guillaume DE BURE */ #include "skgservices.h" #include #include #include #include #ifndef Q_OS_WIN #include #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "skgdocument.h" #include "skgtraces.h" #define SQLCIPHERHEARDER "SQLCipher format" int SKGServices::SKGSqlTraces = (SKGServices::getEnvVariable(QStringLiteral("SKGTRACESQL")).isEmpty() ? -1 : SKGServices::stringToInt(SKGServices::getEnvVariable(QStringLiteral("SKGTRACESQL")))); SKGError SKGServices::m_lastCallbackError; QString SKGServices::searchCriteriasToWhereClause(const SKGServices::SKGSearchCriteriaList& iSearchCriterias, const QStringList& iAttributes, const SKGDocument* iDocument, bool iForDisplay) { QString whereclause; int nbCriterias = iSearchCriterias.count(); int nbAttributes = iAttributes.count(); for (int i = 0; i < nbCriterias; ++i) { SKGSearchCriteria criteria = iSearchCriterias.at(i); QString subWhereClause; int nbWords = criteria.words.count(); for (int w = 0; w < nbWords; ++w) { QString subWhereClause2; QString word = criteria.words[w].toLower(); QString att; QString op(':'); bool modeStartWith = true; // Check if the word follows the format attribute:value int pos = word.indexOf(QStringLiteral(":")); int pos2 = word.indexOf(QStringLiteral("<=")); int pos3 = word.indexOf(QStringLiteral(">=")); int pos4 = word.indexOf(QStringLiteral("=")); int pos5 = word.indexOf(QStringLiteral("<")); int pos6 = word.indexOf(QStringLiteral(">")); int pos7 = word.indexOf(QStringLiteral("#")); int opLength = 1; if (pos2 != -1 && (pos2 < pos || pos == -1)) { pos = pos2; opLength = 2; } if (pos3 != -1 && (pos3 < pos || pos == -1)) { pos = pos3; opLength = 2; } if (pos4 != -1 && (pos4 < pos || pos == -1)) { pos = pos4; } if (pos5 != -1 && (pos5 < pos || pos == -1)) { pos = pos5; } if (pos6 != -1 && (pos6 < pos || pos == -1)) { pos = pos6; } if (pos7 != -1 && (pos7 < pos || pos == -1)) { pos = pos7; } if (pos != -1) { att = word.left(pos); if (att.endsWith(QStringLiteral("."))) { modeStartWith = false; att = att.left(att.count() - 1); } op = word.mid(pos, opLength); word = word.right(word.count() - pos - op.count()); } word = SKGServices::stringToSqlString(word); for (int j = 0; j < nbAttributes; ++j) { QString attDatabase = iAttributes.at(j); QString attForComparison = (iDocument != nullptr ? iDocument->getDisplay(attDatabase) : attDatabase).toLower(); if (att.isEmpty() || (modeStartWith && attForComparison.startsWith(att)) || (!modeStartWith && attForComparison.compare(att, Qt::CaseInsensitive) == 0)) { if (iForDisplay) { QString n = attForComparison + op + word; if (subWhereClause2.isEmpty()) { subWhereClause2 = n; } else { subWhereClause2 = i18nc("Logical condition", "%1 or %2", subWhereClause2, n); } } else { if (!subWhereClause2.isEmpty()) { subWhereClause2 = subWhereClause2 % " OR "; } if (attDatabase.startsWith(QLatin1String("p_"))) { // Case property QString propName = attDatabase.right(attDatabase.length() - 2); if (op == QStringLiteral(":")) { subWhereClause2 = subWhereClause2 % "i_PROPPNAME='" % SKGServices::stringToSqlString(propName) % "' AND (lower(i_PROPVALUE) LIKE '%" % word % "%')"; } else if (op == QStringLiteral("#")) { subWhereClause2 = subWhereClause2 % "i_PROPPNAME='" % SKGServices::stringToSqlString(propName) % "' AND REGEXP('" % word % "',i_PROPVALUE)"; } else { attDatabase = "i_PROPPNAME='" % SKGServices::stringToSqlString(propName) % "' AND i_PROPVALUE"; subWhereClause2 = subWhereClause2 % attDatabase % op % word; } } else { // Case normal attribute if (op == QStringLiteral(":")) { subWhereClause2 = subWhereClause2 % "lower(" % attDatabase % ") LIKE '%" % word % "%'"; } else if (op == QStringLiteral("#")) { subWhereClause2 = subWhereClause2 % "REGEXP('" % word % "'," % attDatabase % ")"; } else { if (attDatabase.startsWith(QLatin1String("f_")) || attDatabase.startsWith(QLatin1String("i_"))) { subWhereClause2 = subWhereClause2 % attDatabase % op % word; } else { subWhereClause2 = subWhereClause2 % "lower(" % attDatabase % ")" % op % "'" % word % "'"; } } } } } } if (iForDisplay) { if (!subWhereClause2.isEmpty()) { if (subWhereClause.isEmpty()) { subWhereClause = subWhereClause2; } else { subWhereClause = i18nc("Logical condition", "(%1) and (%2)", subWhereClause, subWhereClause2); } } } else { if (!subWhereClause2.isEmpty()) { if (!subWhereClause.isEmpty()) { subWhereClause = subWhereClause % " AND "; } subWhereClause = subWhereClause % "(" % subWhereClause2 % ")"; } else { subWhereClause = QStringLiteral("1=0"); } } } if (iForDisplay) { if (!subWhereClause.isEmpty()) { if (criteria.mode == '+') { if (whereclause.isEmpty()) { whereclause = subWhereClause; } else { whereclause = i18nc("Logical condition", "(%1) and (%2)", whereclause, subWhereClause); } } else if (criteria.mode == '-') { if (subWhereClause.isEmpty()) { whereclause = i18nc("Logical condition", "not (%1)", subWhereClause); } else { whereclause = i18nc("Logical condition", "(%1) and not (%2)", whereclause, subWhereClause); } } } } else { if (!subWhereClause.isEmpty()) { if (criteria.mode == '+') { if (!whereclause.isEmpty()) { whereclause = whereclause % " OR "; } whereclause = whereclause % "(" % subWhereClause % ")"; } else if (criteria.mode == '-') { if (!whereclause.isEmpty()) { whereclause = whereclause % " AND NOT"; } else { whereclause = QStringLiteral("NOT"); } whereclause = whereclause % "(" % subWhereClause % ")"; } } } } return whereclause; } SKGServices::SKGSearchCriteriaList SKGServices::stringToSearchCriterias(const QString& iString) { SKGServices::SKGSearchCriteriaList output; QStringList words = SKGServices::splitCSVLine(iString, ' ', true); int nbwords = words.count(); output.reserve(nbwords); SKGServices::SKGSearchCriteria criteria; criteria.mode = '+'; bool atLeastOnePlus = false; for (int i = 0; i < nbwords; ++i) { QString word = words.at(i); bool isWordStartingByPlus = word.startsWith(QLatin1String("+")); bool isWordStartingByLess = word.startsWith(QLatin1String("-")); if (isWordStartingByPlus || isWordStartingByLess) { QChar nextChar; if (word.count() > 1) { nextChar = word[1]; } if (nextChar < '0' || nextChar > '9') { word = word.right(word.length() - 1); if (Q_LIKELY(i != 0)) { if (criteria.mode == '-') { output.push_back(criteria); } else { output.push_front(criteria); atLeastOnePlus = true; } } criteria.words.clear(); criteria.mode = (isWordStartingByPlus ? '+' : '-'); } } criteria.words.push_back(word); } if (criteria.mode == '-') { output.push_back(criteria); } else { output.push_front(criteria); atLeastOnePlus = true; } if (!atLeastOnePlus) { // Add a '+' always true SKGServices::SKGSearchCriteria criteria2; criteria2.mode = '+'; criteria2.words.push_back(QLatin1String("")); output.push_front(criteria2); } return output; } QString SKGServices::getEnvVariable(const QString& iAttribute) { return QString::fromUtf8(qgetenv(iAttribute.toUtf8().constData())); } QString SKGServices::intToString(qlonglong iNumber) { QString output; output.setNum(iNumber); return output; } qlonglong SKGServices::stringToInt(const QString& iNumber) { if (Q_UNLIKELY(iNumber.isEmpty())) { return 0; } bool ok; qlonglong output = iNumber.toLongLong(&ok); if (Q_LIKELY(!ok)) { SKGTRACE << "WARNING: SKGServices::stringToInt(" << iNumber << ") failed" << endl; } return output; } QString SKGServices::stringToSqlString(const QString& iString) { QString output; for (const auto& c : iString) { if (c.isPrint() || c == QChar('\n')) { output.append(QChar(c)); } } output.replace('\'', QStringLiteral("''")); return output; } QString SKGServices::stringToHtml(const QString& iString) { QString output = iString; output.replace('&', QStringLiteral("&")); // Must be done first output.replace('<', QStringLiteral("<")); output.replace('>', QStringLiteral(">")); output.replace('"', QStringLiteral(""")); return output; } QString SKGServices::htmlToString(const QString& iString) { QString output = iString; output.replace(QStringLiteral("<"), QStringLiteral("<")); output.replace(QStringLiteral(">"), QStringLiteral(">")); output.replace(QStringLiteral("""), QStringLiteral("\"")); output.replace(QStringLiteral("&"), QStringLiteral("&")); return output; } QString SKGServices::stringsToCsv(const QStringList& iList, QChar iSeparator) { QString output; int nb = iList.count(); for (int i = 0; i < nb; ++i) { output.append(SKGServices::stringToCsv(iList.at(i))); if (Q_LIKELY(i < nb - 1)) { output.append(iSeparator); } } return output; } QString SKGServices::stringToCsv(const QString& iNumber) { QString output = iNumber; output.replace('"', QStringLiteral("#SKGDOUBLECOTE#")); output.replace(QStringLiteral("#SKGDOUBLECOTE#"), QStringLiteral("\"\"")); output = '"' % output % '"'; return output; } double SKGServices::stringToDouble(const QString& iNumber) { if (Q_UNLIKELY(iNumber.isEmpty() || iNumber == QStringLiteral("nan"))) { return 0; } if (Q_UNLIKELY(iNumber == QStringLiteral("inf"))) { return 1e300; } if (Q_UNLIKELY(iNumber == QStringLiteral("-inf"))) { return -1e300; } QString number = iNumber; number.remove(QRegExp(QStringLiteral("[^0-9-+/eE,.]"))); if (number.contains(QStringLiteral("/"))) { // Use script engine QScriptEngine myEngine; QScriptValue result = myEngine.evaluate(number); if (result.isNumber()) { return result.toNumber(); } } bool ok; double output = number.toDouble(&ok); if (Q_LIKELY(!ok)) { QString tmp = number; tmp.replace(',', '.'); if (tmp.count('.') > 1) { tmp.remove(tmp.indexOf('.'), 1); } output = tmp.toDouble(&ok); if (Q_LIKELY(!ok)) { QString tmp2 = number; tmp2.replace('.', ','); if (tmp2.count(',') > 1) { tmp2.remove(tmp2.indexOf(','), 1); } output = tmp2.toDouble(&ok); if (!ok) { QString tmp3 = number; tmp3.remove(','); output = tmp3.toDouble(&ok); } } } if (Q_LIKELY(!ok)) { SKGTRACE << "WARNING: SKGServices::stringToDouble(" << iNumber << ") failed" << endl; } return output; } QString SKGServices::doubleToString(double iNumber) { QString output; output.setNum(iNumber, 'g', 10); return output; } QString SKGServices::getNextString(const QString& iString) { QString output = iString; bool ok; qlonglong val = output.toLongLong(&ok); if (Q_LIKELY(ok)) { // This is a int output = SKGServices::intToString(val + 1); } else { // This is a string output = QLatin1String(""); } return output; } QString SKGServices::dateToPeriod(QDate iDate, const QString& iPeriod) { QString period; if (iPeriod == QStringLiteral("D")) { // Day period = iDate.toString(QStringLiteral("yyyy-MM-dd")); } else if (iPeriod == QStringLiteral("W")) { // Week period = iDate.toString(QStringLiteral("yyyy-W")) % SKGServices::intToString(iDate.weekNumber()).rightJustified(2, '0'); } else if (iPeriod == QStringLiteral("M")) { // Month period = iDate.toString(QStringLiteral("yyyy-MM")); } else if (iPeriod == QStringLiteral("Q")) { // Quarter period = iDate.toString(QStringLiteral("yyyy-Q")) % (iDate.month() <= 3 ? '1' : (iDate.month() <= 6 ? '2' : (iDate.month() <= 9 ? '3' : '4'))); } else if (iPeriod == QStringLiteral("S")) { // Semester period = iDate.toString(QStringLiteral("yyyy-S")) % (iDate.month() <= 6 ? '1' : '2'); } else if (iPeriod == QStringLiteral("Y")) { // Year period = iDate.toString(QStringLiteral("yyyy")); } return period; } QString SKGServices::timeToString(const QDateTime& iDateTime) { QDateTime d = iDateTime; if (Q_UNLIKELY(!d.isValid())) { d = QDateTime::currentDateTime(); } return d.toString(QStringLiteral("yyyy-MM-dd HH:mm:ss")); } QString SKGServices::dateToSqlString(QDate iDate) { return dateToSqlString(QDateTime(iDate)); } QString SKGServices::dateToSqlString(const QDateTime& iDateTime) { QDateTime d = iDateTime; if (Q_UNLIKELY(!d.isValid())) { d = QDateTime::currentDateTime(); } return d.toString(QStringLiteral("yyyy-MM-dd")); } int SKGServices::nbWorkingDays(QDate iFrom, QDate iTo) { int nb = 0; QDate min = (iFrom < iTo ? iFrom : iTo); QDate max = (iFrom < iTo ? iTo : iFrom); while (min != max) { if (min.dayOfWeek() <= 5) { ++nb; } min = min.addDays(1); } if (nb == 0) { nb = 1; } return nb; } QDateTime SKGServices::stringToTime(const QString& iDateString) { QDateTime output = QDateTime::fromString(iDateString, QStringLiteral("yyyy-MM-dd HH:mm:ss")); if (Q_UNLIKELY(!output.isValid())) { output = QDateTime::fromString(iDateString, QStringLiteral("yyyy-MM-dd")); } return output; } QDate SKGServices::partialStringToDate(const QString& iDateString, bool iFixupBackward) { QDate result; QStringList items = iDateString.split('/'); int size = items.count(); bool ok = false; if (size == 1) { int dayCount = items.at(0).toInt(&ok); - result = QDate::currentDate(); - result = result.addDays(dayCount - result.day()); + result = QDate(QDate::currentDate().year(), QDate::currentDate().month(), dayCount); ; if (iFixupBackward) { if (result > QDate::currentDate()) { result = result.addMonths(-1); } } else { if (result < QDate::currentDate()) { result = result.addMonths(1); } } } else if (size == 2) { int dayCount = items.at(0).toInt(&ok); int monthCount = items.at(1).toInt(&ok); - result = QDate::currentDate(); - result = result.addDays(dayCount - result.day()); - result = result.addMonths(monthCount - result.month()); + result = QDate(QDate::currentDate().year(), monthCount, dayCount); ; if (iFixupBackward) { if (result > QDate::currentDate()) { result = result.addYears(-1); } } else { if (result < QDate::currentDate()) { result = result.addYears(1); } } } else if (size == 3) { int dayCount = items.at(0).toInt(&ok); int monthCount = items.at(1).toInt(&ok); int yearCount = items.at(2).toInt(&ok); int lengthYear = items.at(2).count(); - result = QDate::currentDate(); - result = result.addDays(dayCount - result.day()); - result = result.addMonths(monthCount - result.month()); + result = QDate(QDate::currentDate().year(), monthCount, dayCount); ; if (lengthYear < 4) { auto y = static_cast(result.year() / qPow(10, lengthYear)) * qPow(10, lengthYear) + yearCount; if (y > result.year() && iFixupBackward) { y = y - qPow(10, lengthYear); } else if (y < result.year() && !iFixupBackward) { y = y + qPow(10, lengthYear); } result = result.addYears(y - result.year()); } else { result = result.addYears(yearCount - result.year()); } } if (!ok) { result = QDate(); } return result; } QStringList SKGServices::splitCSVLine(const QString& iString, QChar iSeparator, bool iCoteDefineBlock) { return splitCSVLine(iString, iSeparator, iCoteDefineBlock, nullptr); } QStringList SKGServices::splitCSVLine(const QString& iString, QChar iSeparator, bool iCoteDefineBlock, QChar* oRealSeparator) { QStringList items; QString item; bool isInBlock = false; QChar realSeparator = iSeparator; QChar cote = ' '; // Not yet defined int nb = iString.length(); items.reserve(nb); for (int pos = 0; pos < nb; ++pos) { QChar c = iString.at(pos); if (isInBlock) { if (c == cote) { if (pos < nb - 1 && iString.at(pos + 1) == cote) { ++pos; // separator escaped } else { items.push_back(item); item.clear(); isInBlock = false; // 320112 vvvv // Reset the block character to autorize mix cote = ' '; // 320112 ^^^^ if (realSeparator != ' ') while (pos < nb - 1 && iString.at(pos + 1) == ' ') { ++pos; } ++pos; if (pos < nb) { realSeparator = iString.at(pos); // To get the real separator } } } if (isInBlock) { item += c; } } else if ((c == '\"' || c == '\'') && item.trimmed().isEmpty() && iCoteDefineBlock) { if (cote == ' ') { cote = c; // Set the real cote char } isInBlock = true; item.clear(); } else if (QString(c) == realSeparator) { items.push_back(item); item.clear(); isInBlock = false; // 320112 vvvv // Reset the block character to autorize mix cote = ' '; // 320112 ^^^^ } else { item += c; } } if (!item.isEmpty() || (nb > 0 && iString.at(nb - 1) == realSeparator)) { items.push_back(item); } if (oRealSeparator != nullptr) { *oRealSeparator = realSeparator; } if (isInBlock) { items.clear(); } return items; } QString SKGServices::getDateFormat(const QStringList& iDates) { SKGTRACEINFUNC(2) bool f_YYYY_MM_DD = true; bool f_YYYYMMDD = true; bool f_DDMMYYYY = true; bool f_MMDDYYYY = true; bool f_MM_DD_YY = true; bool f_DD_MM_YY = true; bool f_MM_DD_YYYY = true; bool f_DD_MM_YYYY = true; bool f_DDMMMYYYY = true; bool f_DD_MMM_YY = true; bool f_DD_MMM_YYYY = true; // Build regexp QRegExp rx(QStringLiteral("(.+)-(.+)-(.+)")); // Check all dates int nb = iDates.count(); for (int i = 0; i < nb; ++i) { QString val = iDates.at(i).trimmed(); if (val.count() > 10) { auto l = SKGServices::splitCSVLine(val, ' '); val = l[0]; } if (!val.isEmpty()) { val = val.replace(' ', '0'); val = val.replace('\\', '-'); val = val.replace('/', '-'); val = val.replace('.', '-'); val = val.replace(QStringLiteral("'20"), QStringLiteral("-20")); val = val.replace(QStringLiteral("' "), QStringLiteral("-200")); val = val.replace('\'', QStringLiteral("-20")); val = val.replace(QStringLiteral("-90"), QStringLiteral("-1990")); val = val.replace(QStringLiteral("-91"), QStringLiteral("-1991")); val = val.replace(QStringLiteral("-92"), QStringLiteral("-1992")); val = val.replace(QStringLiteral("-93"), QStringLiteral("-1993")); val = val.replace(QStringLiteral("-94"), QStringLiteral("-1994")); val = val.replace(QStringLiteral("-95"), QStringLiteral("-1995")); val = val.replace(QStringLiteral("-96"), QStringLiteral("-1996")); val = val.replace(QStringLiteral("-97"), QStringLiteral("-1997")); val = val.replace(QStringLiteral("-98"), QStringLiteral("-1998")); val = val.replace(QStringLiteral("-99"), QStringLiteral("-1999")); if (rx.indexIn(val) == -1) { f_YYYY_MM_DD = false; f_MM_DD_YY = false; f_DD_MM_YY = false; f_MM_DD_YYYY = false; f_DD_MM_YYYY = false; f_DD_MMM_YY = false; f_DD_MMM_YYYY = false; if (val.length() == 8) { auto left2 = SKGServices::stringToInt(val.left(2)); if (left2 > 12) { f_MMDDYYYY = false; } if (left2 > 31) { f_DDMMYYYY = false; } auto mid2 = SKGServices::stringToInt(val.mid(2, 2)); if (mid2 > 12) { f_DDMMYYYY = false; } if (mid2 > 31) { f_MMDDYYYY = false; } auto mid4 = SKGServices::stringToInt(val.mid(4, 2)); if (mid4 > 12) { f_YYYYMMDD = false; } auto right2 = SKGServices::stringToInt(val.right(2)); if (right2 > 31) { f_YYYYMMDD = false; } f_DDMMMYYYY = false; } else if (val.length() == 9) { f_MMDDYYYY = false; f_DDMMYYYY = false; f_YYYYMMDD = false; } else { f_MMDDYYYY = false; f_DDMMYYYY = false; f_YYYYMMDD = false; f_DDMMMYYYY = false; } } else { f_YYYYMMDD = false; f_DDMMYYYY = false; f_MMDDYYYY = false; f_DDMMMYYYY = false; QString v1 = rx.cap(1); QString v2 = rx.cap(2); QString v3 = rx.cap(3); if (SKGServices::stringToInt(v1) > 12) { f_MM_DD_YY = false; f_MM_DD_YYYY = false; } if (SKGServices::stringToInt(v2) > 12) { f_DD_MM_YY = false; f_DD_MM_YYYY = false; } if (v2.length() > 2) { f_MM_DD_YY = false; f_MM_DD_YYYY = false; f_DD_MM_YY = false; f_DD_MM_YYYY = false; f_YYYY_MM_DD = false; } if (v2.length() != 3) { f_DD_MMM_YYYY = false; f_DD_MMM_YY = false; } if (SKGServices::stringToInt(v1) > 31 || SKGServices::stringToInt(v2) > 31) { f_MM_DD_YY = false; f_MM_DD_YYYY = false; f_DD_MM_YY = false; f_DD_MM_YYYY = false; } if (SKGServices::stringToInt(v3) > 31) { f_YYYY_MM_DD = false; } if (v1.length() == 4) { f_MM_DD_YY = false; f_DD_MM_YY = false; f_MM_DD_YYYY = false; f_DD_MM_YYYY = false; } else { // To be more permissive and support mix of date: f_YYYY_MM_DD = false; } if (v3.length() == 4) { f_YYYY_MM_DD = false; f_MM_DD_YY = false; f_DD_MM_YY = false; } else { // To be more permissive and support mix of date: f_MM_DD_YYYY = false; // To be more permissive and support mix of date: f_DD_MM_YYYY = false; } } } } if (f_YYYYMMDD) { return QStringLiteral("YYYYMMDD"); } if (f_MMDDYYYY) { return QStringLiteral("MMDDYYYY"); } if (f_DDMMYYYY) { return QStringLiteral("DDMMYYYY"); } if (f_DD_MM_YY && f_MM_DD_YY) { QString sFormat = QLocale().dateFormat(QLocale::ShortFormat); if (sFormat.startsWith(QLatin1String("%m")) || sFormat.startsWith(QLatin1String("%n"))) { return QStringLiteral("MM-DD-YY"); } return QStringLiteral("DD-MM-YY"); } if (f_MM_DD_YY) { return QStringLiteral("MM-DD-YY"); } if (f_DD_MM_YY) { return QStringLiteral("DD-MM-YY"); } if (f_DD_MM_YYYY && f_MM_DD_YYYY) { QString sFormat = QLocale().dateFormat(QLocale::ShortFormat); if (sFormat.startsWith(QLatin1String("%m")) || sFormat.startsWith(QLatin1String("%n"))) { return QStringLiteral("MM-DD-YYYY"); } return QStringLiteral("DD-MM-YYYY"); } if (f_MM_DD_YYYY) { return QStringLiteral("MM-DD-YYYY"); } if (f_DD_MM_YYYY) { return QStringLiteral("DD-MM-YYYY"); } if (f_YYYY_MM_DD) { return QStringLiteral("YYYY-MM-DD"); } if (f_DDMMMYYYY) { return QStringLiteral("DDMMMYYYY"); } if (f_DD_MMM_YY) { return QStringLiteral("DD-MMM-YY"); } if (f_DD_MMM_YYYY) { return QStringLiteral("DD-MMM-YYYY"); } return QLatin1String(""); } QString SKGServices::toPercentageString(double iAmount, int iNbDecimal) { return toCurrencyString(iAmount, QString(), iNbDecimal) % " %"; } QString SKGServices::toCurrencyString(double iAmount, const QString& iSymbol, int iNbDecimal) { if (iSymbol == QStringLiteral("%")) { return toPercentageString(iAmount, iNbDecimal); } return QLocale::system().toCurrencyString(iAmount, iSymbol.isEmpty() ? QStringLiteral(" ") : iSymbol, iNbDecimal).trimmed(); } QString SKGServices::dateToSqlString(const QString& iDate, const QString& iFormat) { QString input = iDate; if (input.count() > 10) { auto l = SKGServices::splitCSVLine(input, ' '); input = l[0]; } QString format = QStringLiteral("yyyy-MM-dd"); QString YYYY = QStringLiteral("0000"); QString MM = QStringLiteral("00"); QString DD = QStringLiteral("00"); if (iFormat == QStringLiteral("YYYYMMDD")) { YYYY = input.mid(0, 4); MM = input.mid(4, 2); DD = input.mid(6, 2); } else if (iFormat == QStringLiteral("DDMMYYYY") || iFormat == QStringLiteral("DDMMYY")) { YYYY = input.mid(4, 4); MM = input.mid(2, 2); DD = input.mid(0, 2); } else if (iFormat == QStringLiteral("DDMMMYYYY") || iFormat == QStringLiteral("DDMMMYY")) { YYYY = input.mid(5, 4); MM = input.mid(2, 3); DD = input.mid(0, 2); format = QStringLiteral("yyyy-MMM-dd"); } else if (iFormat == QStringLiteral("MMDDYYYY") || iFormat == QStringLiteral("MMDDYY")) { YYYY = input.mid(4, 4); MM = input.mid(0, 2); DD = input.mid(2, 2); } else { QString val = input; val = val.replace(' ', '0'); val = val.replace('\\', '-'); val = val.replace('/', '-'); val = val.replace('.', '-'); val = val.replace(QStringLiteral("'20"), QStringLiteral("-20")); val = val.replace(QStringLiteral("' "), QStringLiteral("-200")); val = val.replace('\'', QStringLiteral("-20")); val = val.replace(QStringLiteral("-90"), QStringLiteral("-1990")); val = val.replace(QStringLiteral("-91"), QStringLiteral("-1991")); val = val.replace(QStringLiteral("-92"), QStringLiteral("-1992")); val = val.replace(QStringLiteral("-93"), QStringLiteral("-1993")); val = val.replace(QStringLiteral("-94"), QStringLiteral("-1994")); val = val.replace(QStringLiteral("-95"), QStringLiteral("-1995")); val = val.replace(QStringLiteral("-96"), QStringLiteral("-1996")); val = val.replace(QStringLiteral("-97"), QStringLiteral("-1997")); val = val.replace(QStringLiteral("-98"), QStringLiteral("-1998")); val = val.replace(QStringLiteral("-99"), QStringLiteral("-1999")); QRegExp rx(QStringLiteral("(.+)-(.+)-(.+)")); if (rx.indexIn(val) != -1) { QString v1 = rx.cap(1); QString v2 = rx.cap(2); QString v3 = rx.cap(3); if (iFormat == QStringLiteral("YYYY-MM-DD")) { YYYY = v1; MM = v2; DD = v3; } else if (iFormat == QStringLiteral("MM/DD/YY") || iFormat == QStringLiteral("MM-DD-YY") || iFormat == QStringLiteral("MM/DD/YYYY") || iFormat == QStringLiteral("MM-DD-YYYY")) { MM = v1; DD = v2; YYYY = v3; } else if (iFormat == QStringLiteral("DD/MM/YY") || iFormat == QStringLiteral("DD-MM-YY") || iFormat == QStringLiteral("DD/MM/YYYY") || iFormat == QStringLiteral("DD-MM-YYYY")) { DD = v1; MM = v2; YYYY = v3; } else if (iFormat == QStringLiteral("DD/MMM/YY") || iFormat == QStringLiteral("DD-MMM-YY") || iFormat == QStringLiteral("DD/MMM/YYYY") || iFormat == QStringLiteral("DD-MMM-YYYY")) { DD = v1; MM = v2; YYYY = v3; format = QStringLiteral("yyyy-MMM-dd"); } } } if (MM.length() == 1) { MM = '0' % MM; } if (DD.length() == 1) { DD = '0' % DD; } if (YYYY.length() == 1) { YYYY = '0' % YYYY; } if (YYYY.length() == 2) { if (stringToInt(YYYY) > 70) { YYYY = "19" % YYYY; } else { YYYY = "20" % YYYY; } } QString date = YYYY % '-' % MM % '-' % DD; date.replace(' ', '0'); return dateToSqlString(QDateTime::fromString(date, format)); } QString SKGServices::getPeriodWhereClause(const QString& iPeriod, const QString& iDateAttribute) { QString output = QStringLiteral("1=0"); if (iPeriod == QStringLiteral("ALL")) { output = QStringLiteral("1=1"); } else if (iPeriod.length() == 4) { // 2014 output = "STRFTIME('%Y'," + SKGServices::stringToSqlString(iDateAttribute) + ")='" + SKGServices::stringToSqlString(iPeriod) + '\''; } else if (iPeriod.length() == 7 && iPeriod[4] == '-') { if (iPeriod[5] == 'S') { // 2014-S1 output = "STRFTIME('%Y'," + SKGServices::stringToSqlString(iDateAttribute) + ")||'-S'||(CASE WHEN STRFTIME('%m'," + SKGServices::stringToSqlString(iDateAttribute) + ")<='06' THEN '1' ELSE '2' END)='" + SKGServices::stringToSqlString(iPeriod) + '\''; } else if (iPeriod[5] == 'Q') { // 2014-Q1 output = "STRFTIME('%Y'," + SKGServices::stringToSqlString(iDateAttribute) + ")||'-Q'||(CASE WHEN STRFTIME('%m'," + SKGServices::stringToSqlString(iDateAttribute) + ")<='03' THEN '1' WHEN STRFTIME('%m'," + SKGServices::stringToSqlString(iDateAttribute) + ")<='06' THEN '2' WHEN STRFTIME('%m'," + SKGServices::stringToSqlString(iDateAttribute) + ")<='09' THEN '3' ELSE '4' END)='" + SKGServices::stringToSqlString(iPeriod) + '\''; } else { // 2014-07 output = "STRFTIME('%Y-%m'," + SKGServices::stringToSqlString(iDateAttribute) + ")='" + SKGServices::stringToSqlString(iPeriod) + '\''; } } return output; } QDate SKGServices::periodToDate(const QString& iPeriod) { QDate output; if (iPeriod == QStringLiteral("ALL")) { output = QDate::currentDate(); } else if (iPeriod.length() == 4) { // 2014 output = QDate::fromString(iPeriod, QStringLiteral("yyyy")).addYears(1).addDays(-1); } else if (iPeriod.length() == 7) { if (iPeriod[5] == 'S') { // 2014-S1 output = QDate::fromString(iPeriod, QStringLiteral("yyyy-SM")); output = output.addMonths(output.month() * 6 - output.month()); // convert semester in month output = output.addMonths(1).addDays(-1); } else if (iPeriod[5] == 'Q') { // 2014-Q1 output = QDate::fromString(iPeriod, QStringLiteral("yyyy-QM")); output = output.addMonths(output.month() * 3 - output.month()); // convert quarter in month output = output.addMonths(1).addDays(-1); } else { // 2014-07 output = QDate::fromString(iPeriod, QStringLiteral("yyyy-MM")).addMonths(1).addDays(-1); } } return output; } QString SKGServices::getNeighboringPeriod(const QString& iPeriod, int iDelta) { QString output = QStringLiteral("1=0"); if (iPeriod.length() == 4) { // 2014 QDate date = QDate::fromString(iPeriod, QStringLiteral("yyyy")).addYears(iDelta); output = date.toString(QStringLiteral("yyyy")); } else if (iPeriod.length() == 7) { if (iPeriod[5] == 'S') { // 2014-S1 QDate date2 = QDate::fromString(iPeriod, QStringLiteral("yyyy-SM")); date2 = date2.addMonths(date2.month() * 6 - date2.month()); // convert semester in month date2 = date2.addMonths(6 * iDelta); output = date2.toString(QStringLiteral("yyyy-S")) % (date2.month() <= 6 ? '1' : '2'); } else if (iPeriod[5] == 'Q') { // 2014-Q1 QDate date2 = QDate::fromString(iPeriod, QStringLiteral("yyyy-QM")); date2 = date2.addMonths(date2.month() * 3 - date2.month()); // convert quarter in month date2 = date2.addMonths(3 * iDelta); output = date2.toString(QStringLiteral("yyyy-Q")) % (date2.month() <= 3 ? '1' : (date2.month() <= 6 ? '2' : (date2.month() <= 9 ? '3' : '4'))); } else { // 2014-07 QDate date2 = QDate::fromString(iPeriod, QStringLiteral("yyyy-MM")).addMonths(iDelta); output = date2.toString(QStringLiteral("yyyy-MM")); } } return output; } QStringList SKGServices::tableToDump(const SKGStringListList& iTable, SKGServices::DumpMode iMode) { SKGTRACEINFUNC(10) // initialisation QStringList oResult; // Compute max size of each column int* maxSizes = nullptr; int nbMaxSizes = 0; if (iMode == DUMP_TEXT) { int nb = iTable.count(); for (int i = 0; i < nb; ++i) { const QStringList& line = iTable.at(i); int nb2 = line.size(); if (maxSizes == nullptr) { nbMaxSizes = nb2; maxSizes = new int[nbMaxSizes]; for (int j = 0; j < nbMaxSizes; ++j) { maxSizes[j] = 0; } } for (int j = 0; j < nb2; ++j) { const QString& s = line.at(j); if (j < nbMaxSizes && s.length() > maxSizes[j]) { maxSizes[j] = s.length(); } } } } // dump int nb = iTable.count(); oResult.reserve(nb); for (int i = 0; i < nb; ++i) { QString lineFormated; if (iMode == DUMP_TEXT) { lineFormated = QStringLiteral("| "); } const QStringList& line = iTable.at(i); int nb2 = line.size(); for (int j = 0; j < nb2; ++j) { QString s = line.at(j); s.remove('\n'); if (iMode == DUMP_CSV) { if (j > 0) { lineFormated += ';'; } lineFormated += stringToCsv(s); } else if (maxSizes != nullptr) { if (j < nbMaxSizes) { s = s.leftJustified(maxSizes[j], ' '); } lineFormated += s % " | "; } } oResult.push_back(lineFormated); } // delete if (maxSizes != nullptr) { delete [] maxSizes; maxSizes = nullptr; } return oResult; } QString SKGServices::getRealTable(const QString& iTable) { QString output = iTable; if (output.length() > 2 && output.startsWith(QLatin1String("v_"))) { output = output.mid(2, output.length() - 2); int pos = output.indexOf(QStringLiteral("_")); if (pos != -1) { output = output.left(pos); } } return output; } SKGError SKGServices::downloadToStream(const QUrl& iSourceUrl, QByteArray& oStream) { SKGError err; SKGTRACEINFUNCRC(10, err) QString tmpFile; if (iSourceUrl.isLocalFile()) { tmpFile = iSourceUrl.toLocalFile(); } else { err = download(iSourceUrl, tmpFile); } IFOK(err) { // Open file QFile file(tmpFile); if (Q_UNLIKELY(!file.open(QIODevice::ReadOnly))) { err.setReturnCode(ERR_FAIL).setMessage(i18nc("An information message", "Open file '%1' failed", tmpFile)); } else { oStream = file.readAll(); // close file file.close(); } if (!iSourceUrl.isLocalFile()) { QFile(tmpFile).remove(); } } return err; } SKGError SKGServices::download(const QUrl& iSourceUrl, QString& oTemporaryFile) { SKGError err; SKGTRACEINFUNCRC(10, err) QTemporaryFile tmpFile; tmpFile.setAutoRemove(false); if (tmpFile.open()) { err = upload(iSourceUrl, QUrl::fromLocalFile(tmpFile.fileName())); IFOK(err) oTemporaryFile = tmpFile.fileName(); } return err; } SKGError SKGServices::upload(const QUrl& iSourceUrl, const QUrl& iDescUrl) { SKGError err; SKGTRACEINFUNCRC(10, err) if (iDescUrl != iSourceUrl) { if (iDescUrl.isLocalFile() && iSourceUrl.isLocalFile()) { QFile(iDescUrl.toLocalFile()).remove(); if (!QFile::copy(iSourceUrl.toLocalFile(), iDescUrl.toLocalFile())) { err = SKGError(ERR_ABORT, i18nc("Error message", "Impossible to copy '%1' to '%2'", iSourceUrl.toDisplayString(), iDescUrl.toDisplayString())); } } else { KIO::FileCopyJob* getJob = KIO::file_copy(iSourceUrl, iDescUrl, -1, KIO::Overwrite | KIO::HideProgressInfo); if (!getJob->exec()) { err.setReturnCode(ERR_ABORT).setMessage(getJob->errorString()); err.addError(ERR_ABORT, i18nc("Error message", "Impossible to copy '%1' to '%2'", iSourceUrl.toDisplayString(), iDescUrl.toDisplayString())); } } } return err; } SKGError SKGServices::cryptFile(const QString& iFileSource, const QString& iFileTarget, const QString& iPassword, bool iEncrypt, const QString& iHeaderFile, bool& oModeSQLCipher) { SKGError err; SKGTRACEINFUNCRC(10, err) SKGTRACEL(10) << "Input parameter [iFileSource]=[" << iFileSource << ']' << endl; SKGTRACEL(10) << "Input parameter [iFileTarget]=[" << iFileTarget << ']' << endl; SKGTRACEL(10) << "Input parameter [iPassword] =[" << iPassword << ']' << endl; SKGTRACEL(10) << "Input parameter [iHeaderFile]=[" << iHeaderFile << ']' << endl; oModeSQLCipher = false; // Read document QByteArray input; QByteArray uba; err = downloadToStream(QUrl::fromUserInput(iFileSource), input); IFOK(err) { bool isFileEncrypted = (input.startsWith(QByteArray((iHeaderFile % "_ENCRYPT").toLatin1()))); bool sqliteMode = (input.left(15) == "SQLite format 3"); SKGTRACEL(10) << "isFileEncrypted=[" << static_cast(isFileEncrypted) << ']' << endl; // !!!!! Remove Cipher encryption to remove security hole (thank you to Vincent P) !!!!! // Only in sqlcipher mode. WARNING: in sqlite mode the issue is still there => add a message to push people to swith in sqlcipher mode if (iEncrypt && !sqliteMode) { // The input file is a sqlcipher file and we must save it // We just have to add a new header to the input file uba.reserve(input.length() + iHeaderFile.length() + 11); uba.append(iHeaderFile.toLatin1()); uba.append(!iPassword.isEmpty() ? "_ENCRYPTE3-" : "_DECRYPTE3-"); uba.append(input); oModeSQLCipher = true; } else if (!iEncrypt && input.startsWith(QByteArray((iHeaderFile % "_ENCRYPTE3-").toLatin1()))) { // This check is done to improve performances if (iPassword.isEmpty() || iPassword == QStringLiteral("DEFAULTPASSWORD")) { err = SKGError(ERR_ENCRYPTION, i18nc("Error message", "Wrong password")); } else { // The input file encrypter with the new mode // We just have to remove the header if (!iHeaderFile.isEmpty() && input.startsWith(iHeaderFile.toLatin1())) { input = input.right(input.length() - iHeaderFile.length() - 11); } uba = input; oModeSQLCipher = true; } } else { // WARNING: This part is not really secured but is kept for compatibility SKGTRACEL(10) << "Mode not secured" << endl; QCA::Initializer init; QCA::SymmetricKey key(QByteArray("skrooge")); SKGTRACEL(10) << "QCA::Initializer done" << endl; if (!iPassword.isEmpty() && !QCA::isSupported("aes128-ecb")) { // Set error message err.setReturnCode(ERR_INSTALL); // To avoid password request err.setMessage(i18nc("An error message about encryption", "AES128 encryption is not supported (%1). Please install qca-ossl.", QCA::supportedFeatures().join(QStringLiteral(",")))); } else { QCA::Cipher* cipher = nullptr; QCA::InitializationVector iv(iPassword.toLatin1()); // Create a 128 bit AES cipher object using Cipher Block Chaining (CBC) mode if ((isFileEncrypted || iEncrypt) && !iPassword.isEmpty()) { cipher = new QCA::Cipher(QStringLiteral("aes128"), QCA::Cipher::CBC, // use Default padding, which is equivalent to PKCS7 for CBC QCA::Cipher::DefaultPadding, iEncrypt ? QCA::Encode : QCA::Decode, key, iv); } // BUG 249955 vvv if ((cipher == nullptr) && isFileEncrypted) { err = SKGError(ERR_ENCRYPTION, i18nc("Error message about encrypting a file", "Encryption failed")); } // BUG 249955 ^^^ // Suppress header SKGTRACEL(10) << "input=[" << input.left(50) << "...]" << endl; if (!iHeaderFile.isEmpty() && input.startsWith(iHeaderFile.toLatin1())) { input = input.right(input.length() - iHeaderFile.length() - 11); } SKGTRACEL(10) << "input without header=[" << input.left(50) << "...]" << endl; QCA::SecureArray u; if (cipher != nullptr) { if (!err) { // Process encryption or decryption u = cipher->process(input); // We need to check if that update() call worked. if (!cipher->ok()) { err = SKGError(ERR_UNEXPECTED, i18nc("Error message about encrypting a file", "Encryption failed")); } else { uba = u.toByteArray(); } } } else { uba = input; } IFOK(err) { // Check if decryption is OK SKGTRACEL(10) << "output 1=[" << uba.left(50) << "...]" << endl; if (!iEncrypt) { if (!uba.startsWith(QByteArray("SQLite format 3"))) { if (!uba.startsWith(SQLCIPHERHEARDER)) { if (isFileEncrypted) { err = SKGError(ERR_ENCRYPTION, i18nc("Error message", "Wrong password")); } else { oModeSQLCipher = true; } } else { uba = uba.right(uba.length() - QStringLiteral(SQLCIPHERHEARDER).length()); oModeSQLCipher = true; } } } } IFOK(err) { // Add headers if (iEncrypt && !iHeaderFile.isEmpty()) { QByteArray h = (iHeaderFile % (cipher != nullptr ? "_ENCRYPTED-" : "_DECRYPTED-")).toLatin1(); uba = uba.insert(0, h); } } delete cipher; cipher = nullptr; } } SKGTRACEL(10) << "output 2=[" << uba.left(50) << "...]" << endl; // output the results of that stage IFOK(err) { SKGTRACEIN(10, "SKGServices::cryptFile-save file") QSaveFile fileOutput(iFileTarget); if (!fileOutput.open(QIODevice::WriteOnly)) { err = SKGError(ERR_WRITEACCESS, i18nc("Error message: writing a file failed", "Write file '%1' failed", iFileTarget)); } else { // Write document fileOutput.write(uba); // Close the file if (!fileOutput.commit()) { IFOK(err) { err = SKGError(ERR_WRITEACCESS, i18nc("Error message: writing a file failed", "Write file '%1' failed", iFileTarget)); } } } } } SKGTRACEL(10) << "Output parameter [oModeSQLCipher]=[" << static_cast(oModeSQLCipher) << ']' << endl; return err; } SKGError SKGServices::copySqliteDatabaseToXml(const QSqlDatabase& iDb, QDomDocument& oDocument) { SKGError err; SKGTRACEINFUNCRC(10, err) oDocument = QDomDocument(QStringLiteral("SKGML")); QDomElement document = oDocument.createElement(QStringLiteral("document")); oDocument.appendChild(document); // Copy the tables QStringList listTables = iDb.tables(); int nb = listTables.count(); for (int i = 0; !err && i < nb; ++i) { const QString& tableName = listTables.at(i); if (!tableName.startsWith(QLatin1String("sqlite_")) && !tableName.startsWith(QLatin1String("vm_"))) { QDomElement table = oDocument.createElement(QStringLiteral("table")); document.appendChild(table); table.setAttribute(QStringLiteral("name"), tableName); SKGStringListList listRows; err = SKGServices::executeSelectSqliteOrder(iDb, "SELECT * FROM " % tableName, listRows); int nbRows = listRows.count(); if (nbRows != 0) { const QStringList& titles = listRows.at(0); for (int j = 1; !err && j < nbRows; ++j) { // Forget title const QStringList& values = listRows.at(j); QDomElement row = oDocument.createElement(QStringLiteral("row")); table.appendChild(row); int nbVals = values.count(); for (int k = 0; k < nbVals; ++k) { row.setAttribute(titles.at(k), values.at(k)); } } } } } return err; } SKGError SKGServices::copySqliteDatabase(const QSqlDatabase& iFileDb, const QSqlDatabase& iMemoryDb, bool iFromFileToMemory, const QString& iPassword) { SKGError err; SKGTRACEINFUNCRC(10, err) SKGTRACEL(20) << "Input parameter [iFileDb]=[" << iFileDb.databaseName() << ']' << endl; SKGTRACEL(20) << "Input parameter [iMemoryDb]=[" << iMemoryDb.databaseName() << ']' << endl; SKGTRACEL(10) << "Input parameter [iFromFileToMemory]=[" << (iFromFileToMemory ? "FILE->MEMORY" : "MEMORY->FILE") << ']' << endl; QString dbFileName = iFileDb.databaseName(); // Copy the tables SKGStringListList listTables; int nb = 0; IFOK(err) { err = SKGServices::executeSelectSqliteOrder((iFromFileToMemory ? iFileDb : iMemoryDb), QStringLiteral("SELECT sql, tbl_name FROM sqlite_master WHERE type='table' AND sql NOT NULL and name NOT LIKE 'sqlite_%'"), listTables); nb = listTables.count(); for (int i = 1; !err && i < nb; ++i) { // Forget header QString val = listTables.at(i).at(0); err = SKGServices::executeSqliteOrder((iFromFileToMemory ? iMemoryDb : iFileDb), val); } } // Attach db IFOK(err) { QString add; if (!iPassword.isEmpty()) { add = " KEY '" % SKGServices::stringToSqlString(iPassword) % "'"; } err = SKGServices::executeSqliteOrder(iMemoryDb, "ATTACH DATABASE '" % dbFileName % "' as source" % add); } // Copy records IFOK(err) { err = SKGServices::executeSqliteOrder(iMemoryDb, QStringLiteral("BEGIN")); IFOK(err) { for (int i = 1; !err && i < nb; ++i) { // Forget header QString val = listTables.at(i).at(1); if (iFromFileToMemory) { err = SKGServices::executeSqliteOrder(iMemoryDb, "insert into main." % val % " select * from source." % val); } else { err = SKGServices::executeSqliteOrder(iMemoryDb, "insert into source." % val % " select * from main." % val); } } } SKGServices::executeSqliteOrder(iMemoryDb, QStringLiteral("COMMIT")); } // Detach { SKGError err2 = SKGServices::executeSqliteOrder(iMemoryDb, QStringLiteral("DETACH DATABASE source")); if (!err && err2) { err = err2; } } // Optimization IFOK(err) { QStringList optimization; optimization << QStringLiteral("PRAGMA case_sensitive_like=true") << QStringLiteral("PRAGMA journal_mode=MEMORY") << QStringLiteral("PRAGMA temp_store=MEMORY") // << QStringLiteral("PRAGMA locking_mode=EXCLUSIVE") << QStringLiteral("PRAGMA synchronous = OFF") << QStringLiteral("PRAGMA recursive_triggers=true"); err = SKGServices::executeSqliteOrders(iFromFileToMemory ? iMemoryDb : iFileDb, optimization); } // Copy the indexes IFOK(err) { SKGStringListList listSqlOrder; err = SKGServices::executeSelectSqliteOrder((iFromFileToMemory ? iFileDb : iMemoryDb), QStringLiteral("SELECT sql FROM sqlite_master WHERE type='index' AND sql NOT NULL and name NOT LIKE 'sqlite_%'"), listSqlOrder); int nb2 = listSqlOrder.count(); for (int i = 1; !err && i < nb2; ++i) { // Forget header QString val = listSqlOrder.at(i).at(0); err = SKGServices::executeSqliteOrder((iFromFileToMemory ? iMemoryDb : iFileDb), val); } } // Copy the views IFOK(err) { SKGStringListList listSqlOrder; err = SKGServices::executeSelectSqliteOrder((iFromFileToMemory ? iFileDb : iMemoryDb), QStringLiteral("SELECT sql FROM sqlite_master WHERE type='view' AND sql NOT NULL and name NOT LIKE 'sqlite_%'"), listSqlOrder); int nb2 = listSqlOrder.count(); for (int i = 1; !err && i < nb2; ++i) { // Forget header QString val = listSqlOrder.at(i).at(0); err = SKGServices::executeSqliteOrder((iFromFileToMemory ? iMemoryDb : iFileDb), val); } } // Copy the triggers, must be done after the views IFOK(err) { SKGStringListList listSqlOrder; err = SKGServices::executeSelectSqliteOrder((iFromFileToMemory ? iFileDb : iMemoryDb), QStringLiteral("SELECT sql FROM sqlite_master WHERE type='trigger' AND sql NOT NULL and name NOT LIKE 'sqlite_%'"), listSqlOrder); int nb2 = listSqlOrder.count(); for (int i = 1; !err && i < nb2; ++i) { // Forget header QString val = listSqlOrder.at(i).at(0); err = SKGServices::executeSqliteOrder((iFromFileToMemory ? iMemoryDb : iFileDb), val); } } // Check if created file exists if (!err && !iFromFileToMemory && !QFile(dbFileName).exists()) { err.setReturnCode(ERR_FAIL).setMessage(i18nc("An error message: creating a file failed", "Creation file '%1' failed", dbFileName)); } IFKO(err) { err.addError(SQLLITEERROR + ERR_FAIL, i18nc("Error message: something failed", "%1 failed", QStringLiteral("SKGServices::copySqliteDatabase()"))); } return err; } SKGError SKGServices::executeSqliteOrders(const QSqlDatabase& iDb, const QStringList& iSqlOrders) { SKGError err; _SKGTRACEINFUNCRC(10, err) int nb = iSqlOrders.count(); for (int i = 0; !err && i < nb; ++i) { err = executeSqliteOrder(iDb, iSqlOrders.at(i)); } return err; } SKGError SKGServices::executeSqliteOrder(const QSqlDatabase& iDb, const QString& iSqlOrder, const QMap& iBind, int* iLastId) { SKGError err; _SKGTRACEINFUNCRC(10, err) SKGTRACEL(20) << "Input parameter [iSqlOrder]=[" << iSqlOrder << ']' << endl; QSqlQuery query(QString(), iDb); query.setForwardOnly(true); double elapse = 0; if (SKGServices::SKGSqlTraces != -1) { elapse = SKGServices::getMicroTime(); } // Prepare sql order bool prep = query.prepare(iSqlOrder); // Bind values QMapIterator i(iBind); while (i.hasNext()) { i.next(); query.bindValue(i.key(), i.value()); } if (!prep || !query.exec()) { QSqlError sqlError = query.lastError(); if (sqlError.nativeErrorCode().toInt() != 19 /*SQLITE_CONSTRAINT*/ && iSqlOrder != QStringLiteral("SELECT count(*) FROM sqlite_master") /*Test password*/) { SKGTRACE << "WARNING: " << iSqlOrder << endl; SKGTRACE << " returns :" << sqlError.text() << endl; } err = SKGError(SQLLITEERROR + sqlError.nativeErrorCode().toInt(), iSqlOrder); err.addError(SQLLITEERROR + sqlError.nativeErrorCode().toInt(), sqlError.text()); if (sqlError.nativeErrorCode().toInt() == 19 && iSqlOrder.startsWith(QLatin1String("INSERT "))) { err.addError(ERR_FAIL, i18nc("Error message", "Creation failed. The object already exists.")); } } else { if (iLastId != nullptr) { *iLastId = query.lastInsertId().toInt(); } } if (SKGServices::SKGSqlTraces != -1) { elapse = SKGServices::getMicroTime() - elapse; if (elapse >= SKGServices::SKGSqlTraces) { SKGTRACE << "executeSqliteOrder :" << iSqlOrder << " TIME=" << elapse << " ms" << endl; } } return err; } SKGError SKGServices::executeSqliteOrder(const QSqlDatabase& iDb, const QString& iSqlOrder, int* iLastId) { return executeSqliteOrder(iDb, iSqlOrder, QMap< QString, QVariant >(), iLastId); } SKGError SKGServices::dumpSelectSqliteOrder(const QSqlDatabase& iDb, const QString& iSqlOrder, SKGServices::DumpMode iMode) { return dumpSelectSqliteOrder(iDb, iSqlOrder, nullptr, iMode); } SKGError SKGServices::dumpSelectSqliteOrder(const QSqlDatabase& iDb, const QString& iSqlOrder, QTextStream* oStream, SKGServices::DumpMode iMode) { SKGError err; _SKGTRACEINFUNCRC(10, err) SKGTRACEL(20) << "Input parameter [iSqlOrder]=[" << iSqlOrder << ']' << endl; // initialisation QStringList oResult; err = SKGServices::dumpSelectSqliteOrder(iDb, iSqlOrder, oResult, iMode); IFOK(err) { // dump int nb = oResult.size(); for (int i = 0; i < nb; ++i) { if (oStream == nullptr) { SKGTRACESUITE << oResult.at(i) << endl; } else { *oStream << oResult.at(i) << endl; } } } return err; } SKGError SKGServices::dumpSelectSqliteOrder(const QSqlDatabase& iDb, const QString& iSqlOrder, QString& oResult, SKGServices::DumpMode iMode) { SKGError err; _SKGTRACEINFUNCRC(10, err) // initialisation oResult = QLatin1String(""); QStringList oResultTmp; err = SKGServices::dumpSelectSqliteOrder(iDb, iSqlOrder, oResultTmp, iMode); IFOK(err) { // dump int nb = oResultTmp.size(); for (int i = 0; i < nb; ++i) { oResult += oResultTmp.at(i) % '\n'; } } return err; } SKGError SKGServices::dumpSelectSqliteOrder(const QSqlDatabase& iDb, const QString& iSqlOrder, QStringList& oResult, SKGServices::DumpMode iMode) { SKGError err; _SKGTRACEINFUNCRC(10, err) // Execution of sql order SKGStringListList oResultTmp; err = executeSelectSqliteOrder(iDb, iSqlOrder, oResultTmp); IFOK(err) oResult = tableToDump(oResultTmp, iMode); return err; } SKGError SKGServices::executeSingleSelectSqliteOrder(const QSqlDatabase& iDb, const QString& iSqlOrder, QString& oResult) { SKGStringListList result; SKGError err = executeSelectSqliteOrder(iDb, iSqlOrder, result); oResult = result.value(1).value(0); return err; } SKGError SKGServices::executeSelectSqliteOrder(const QSqlDatabase& iDb, const QString& iSqlOrder, SKGStringListList& oResult) { SKGError err; _SKGTRACEINFUNCRC(10, err) // initialisation oResult.clear(); QSqlQuery query(QString(), iDb); query.setForwardOnly(true); double elapse = 0; if (SKGServices::SKGSqlTraces != -1) { elapse = SKGServices::getMicroTime(); } if (!query.exec(iSqlOrder)) { QSqlError sqlError = query.lastError(); if (qApp->thread() == QThread::currentThread()) { SKGTRACE << "WARNING: " << iSqlOrder << endl; SKGTRACE << " returns :" << sqlError.text() << endl; } err = SKGError(SQLLITEERROR + sqlError.nativeErrorCode().toInt(), iSqlOrder); err.addError(SQLLITEERROR + sqlError.nativeErrorCode().toInt(), sqlError.text()); } else { double elapse1 = 0; if (SKGServices::SKGSqlTraces != -1) { elapse1 = SKGServices::getMicroTime() - elapse; } // Addition of column names QSqlRecord rec = query.record(); QStringList line; int index = 0; while (index != -1) { QString val = rec.fieldName(index); if (!val.isEmpty()) { line.push_back(val); ++index; } else { index = -1; } } oResult.push_back(line); // Addition of rows while (query.next()) { QStringList line2; int index2 = 0; while (index2 != -1) { QVariant val = query.value(index2); if (val.isValid()) { line2.push_back(val.toString()); ++index2; } else { index2 = -1; } } oResult.push_back(line2); } if (SKGServices::SKGSqlTraces != -1) { double elapse2 = SKGServices::getMicroTime() - elapse; if (elapse1 >= SKGServices::SKGSqlTraces) { SKGTRACE << "executeSqliteOrder:" << iSqlOrder << " TIME=" << elapse1 << " ms, (with fetch):" << elapse2 << " ms" << endl; } } } return err; } SKGError SKGServices::readPropertyFile(const QString& iFileName, QHash< QString, QString >& oProperties) { SKGError err; oProperties.clear(); // Open file QFile file(iFileName); if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { err = SKGError(ERR_FAIL, i18nc("An erro message", "Open file '%1' failed", iFileName)); } else { // Read file QTextStream stream(&file); while (!stream.atEnd() && !err) { // Read line QString line = stream.readLine().trimmed(); if (!line.isEmpty() && !line.startsWith(QLatin1String("#"))) { int pos = line.indexOf(QStringLiteral("=")); if (pos != -1) { oProperties[line.left(pos).trimmed().toLower()] = line.right(line.count() - pos - 1); } } } // close file file.close(); } return err; } double SKGServices::getMicroTime() { #ifdef Q_OS_WIN return static_cast(GetTickCount()); #else struct timeval tv {}; struct timezone tz {}; // get time gettimeofday(&tv, &tz); // return time return (static_cast(1000.0 * tv.tv_sec)) + (static_cast(tv.tv_usec / 1000)); #endif } SKGStringListList SKGServices::getBase100Table(const SKGStringListList& iTable) { SKGTRACEINFUNC(10) // Build history SKGStringListList output; int nblines = iTable.count(); int nbCols = 0; if (nblines != 0) { nbCols = iTable.at(0).count(); } output.reserve(nblines + 1); output.push_back(iTable.at(0)); // Create table for (int i = 1; i < nblines; ++i) { QStringList newLine; newLine.reserve(nbCols + 1); newLine.push_back(iTable.at(i).at(0)); double valInitial = 0; for (int j = 1; j < nbCols; ++j) { double val = SKGServices::stringToDouble(iTable.at(i).at(j)); if (j == 1) { valInitial = val; val = 100.0; } else { if (valInitial != 0.0) { val = 100.0 * val / valInitial; } } newLine.push_back(SKGServices::doubleToString(val)); } output.push_back(newLine); } return output; } SKGStringListList SKGServices::getPercentTable(const SKGStringListList& iTable, bool iOfColumns, bool iAbsolute) { SKGTRACEINFUNC(10) // Build history SKGStringListList output; int nblines = iTable.count(); int nbCols = 0; if (nblines != 0) { nbCols = iTable.at(0).count(); } output.reserve(nblines + 1); output.push_back(iTable.at(0)); // Compute sums QList sums; if (iOfColumns) { // Compute sum of columns sums.reserve(nbCols); for (int j = 1; j < nbCols; ++j) { // Compute sum double sum = 0; for (int i = 1; i < nblines; ++i) { double v = SKGServices::stringToDouble(iTable.at(i).at(j)); sum += (iAbsolute ? qAbs(v) : v); } sums.push_back(sum); } } else { // Compute sum of lines sums.reserve(nblines); for (int j = 1; j < nblines; ++j) { // Compute sum double sum = 0; for (int i = 1; i < nbCols; ++i) { double v = SKGServices::stringToDouble(iTable.at(j).at(i)); sum += (iAbsolute ? qAbs(v) : v); } sums.push_back(sum); } } // Create table for (int i = 1; i < nblines; ++i) { QStringList newLine; newLine.reserve(nbCols + 1); newLine.push_back(iTable.at(i).at(0)); for (int j = 1; j < nbCols; ++j) { double val = SKGServices::stringToDouble(iTable.at(i).at(j)); val = (iAbsolute ? qAbs(val) : val); double sum = (iOfColumns ? sums.at(j - 1) : sums.at(i - 1)); newLine.push_back(SKGServices::doubleToString(sum == 0.0 ? 0.0 : 100.0 * val / sum)); } output.push_back(newLine); } return output; } SKGStringListList SKGServices::getHistorizedTable(const SKGStringListList& iTable) { SKGTRACEINFUNC(10) // Build history SKGStringListList output; int nblines = iTable.count(); int nbCols = 0; if (nblines != 0) { nbCols = iTable.at(0).count(); } output.reserve(nblines + 1); output.push_back(iTable.at(0)); for (int i = 1; i < nblines; ++i) { QStringList newLine; newLine.reserve(nbCols + 1); newLine.push_back(iTable.at(i).at(0)); double sum = 0; for (int j = 1; j < nbCols; ++j) { sum += SKGServices::stringToDouble(iTable.at(i).at(j)); newLine.push_back(SKGServices::doubleToString(sum)); } output.push_back(newLine); } return output; } QString SKGServices::encodeForUrl(const QString& iString) { return QUrl::toPercentEncoding(iString); } QIcon SKGServices::fromTheme(const QString& iName, const QStringList& iOverlays) { QIcon output; if (!iOverlays.isEmpty()) { output = KDE::icon(iName, iOverlays); } else { output = KDE::icon(iName); } if (output.isNull() && !iName.isEmpty()) { static QHash alternatives; if (alternatives.count() == 0) { // Build alternatives alternatives[QStringLiteral("arrow-down")] = QStringLiteral("go-down"); alternatives[QStringLiteral("arrow-right")] = QStringLiteral("go-next"); alternatives[QStringLiteral("arrow-up")] = QStringLiteral("go-up"); alternatives[QStringLiteral("arrow-down-double")] = QStringLiteral("go-down"); alternatives[QStringLiteral("arrow-up-double")] = QStringLiteral("go-up"); alternatives[QStringLiteral("bookmark")] = QStringLiteral("bookmark-new"); alternatives[QStringLiteral("bookmarks")] = QStringLiteral("bookmark-new"); alternatives[QStringLiteral("checkbox")] = QStringLiteral("emblem-symbolic-link"); alternatives[QStringLiteral("chronometer")] = QStringLiteral("appointment"); alternatives[QStringLiteral("configure")] = QStringLiteral("preferences-desktop"); alternatives[QStringLiteral("dashboard-show")] = QStringLiteral("user-desktop"); alternatives[QStringLiteral("dialog-cancel")] = QStringLiteral("process-stop"); alternatives[QStringLiteral("dialog-close")] = QStringLiteral("process-stop"); alternatives[QStringLiteral("dialog-ok")] = QLatin1String(""); alternatives[QStringLiteral("download-later")] = QStringLiteral("internet-services"); alternatives[QStringLiteral("download")] = QStringLiteral("internet-services"); alternatives[QStringLiteral("draw-freehand")] = QStringLiteral("accessories-text-editor"); alternatives[QStringLiteral("edit-guides")] = QStringLiteral("text-x-generic"); alternatives[QStringLiteral("edit-rename")] = QStringLiteral("accessories-text-editor"); alternatives[QStringLiteral("emblem-locked")] = QStringLiteral("lock"); alternatives[QStringLiteral("exchange-positions")] = QLatin1String(""); alternatives[QStringLiteral("format-fill-color")] = QLatin1String(""); alternatives[QStringLiteral("games-solve")] = QStringLiteral("application-certificate"); alternatives[QStringLiteral("get-hot-new-stuff")] = QStringLiteral("applications-other"); alternatives[QStringLiteral("irc-operator")] = QLatin1String(""); alternatives[QStringLiteral("ktip")] = QStringLiteral("dialog-information"); alternatives[QStringLiteral("labplot-xy-plot-two-axes-centered-origin")] = QStringLiteral("x-office-spreadsheet"); alternatives[QStringLiteral("layer-visible-off")] = QLatin1String(""); alternatives[QStringLiteral("layer-visible-on")] = QLatin1String(""); alternatives[QStringLiteral("merge")] = QLatin1String(""); alternatives[QStringLiteral("office-chart-area")] = QStringLiteral("x-office-spreadsheet"); alternatives[QStringLiteral("office-chart-area-stacked")] = QStringLiteral("x-office-spreadsheet"); alternatives[QStringLiteral("office-chart-bar-percentage")] = QStringLiteral("x-office-spreadsheet"); alternatives[QStringLiteral("office-chart-bar")] = QStringLiteral("x-office-spreadsheet"); alternatives[QStringLiteral("office-chart-bar-stacked")] = QStringLiteral("x-office-spreadsheet"); alternatives[QStringLiteral("office-chart-line")] = QStringLiteral("x-office-spreadsheet"); alternatives[QStringLiteral("office-chart-line-stacked")] = QStringLiteral("x-office-spreadsheet"); alternatives[QStringLiteral("office-chart-pie")] = QStringLiteral("x-office-spreadsheet"); alternatives[QStringLiteral("office-chart-ring")] = QStringLiteral("x-office-spreadsheet"); alternatives[QStringLiteral("map-flat")] = QStringLiteral("x-office-spreadsheet"); alternatives[QStringLiteral("office-chart-scatter")] = QStringLiteral("x-office-spreadsheet"); alternatives[QStringLiteral("preview")] = QStringLiteral("document-print-preview"); alternatives[QStringLiteral("quickopen")] = QStringLiteral("emblem-symbolic-link"); alternatives[QStringLiteral("run-build-configure")] = QStringLiteral("media-playback-start"); alternatives[QStringLiteral("run-build")] = QStringLiteral("media-playback-start"); alternatives[QStringLiteral("show-menu")] = QStringLiteral("applications-system"); alternatives[QStringLiteral("skrooge_category")] = QStringLiteral("folder-open"); alternatives[QStringLiteral("split")] = QStringLiteral("edit-cut"); alternatives[QStringLiteral("taxes-finances")] = QStringLiteral("fonts"); alternatives[QStringLiteral("tools-wizard")] = QStringLiteral("applications-other"); alternatives[QStringLiteral("user-group-properties")] = QStringLiteral("system-users"); alternatives[QStringLiteral("user-properties")] = QStringLiteral("document-properties"); alternatives[QStringLiteral("utilities-file-archiver")] = QStringLiteral("package-x-generic"); alternatives[QStringLiteral("vcs-conflicting")] = QStringLiteral("dialog-warning"); alternatives[QStringLiteral("vcs-normal")] = QStringLiteral("dialog-information"); alternatives[QStringLiteral("view-bank-account-checking")] = QStringLiteral("go-home"); alternatives[QStringLiteral("view-bank-account")] = QStringLiteral("x-office-address-book"); alternatives[QStringLiteral("view-bank-account-savings")] = QStringLiteral("go-home"); alternatives[QStringLiteral("view-bank")] = QStringLiteral("go-home"); alternatives[QStringLiteral("view-calendar-journal")] = QStringLiteral("x-office-calendar"); alternatives[QStringLiteral("view-calendar-month")] = QStringLiteral("x-office-calendar"); alternatives[QStringLiteral("view-calendar")] = QStringLiteral("x-office-calendar"); alternatives[QStringLiteral("view-calendar-week")] = QStringLiteral("x-office-calendar"); alternatives[QStringLiteral("view-calendar-whatsnext")] = QStringLiteral("x-office-calendar"); alternatives[QStringLiteral("view-categories")] = QStringLiteral("folder-open"); alternatives[QStringLiteral("view-categories-expenditures")] = QStringLiteral("face-sad"); alternatives[QStringLiteral("view-categories-incomes")] = QStringLiteral("face-smile"); alternatives[QStringLiteral("view-file-columns")] = QStringLiteral("go-home"); alternatives[QStringLiteral("view-financial-list")] = QStringLiteral("go-home"); alternatives[QStringLiteral("view-investment")] = QStringLiteral("go-home"); alternatives[QStringLiteral("view-list-details")] = QStringLiteral("go-home"); alternatives[QStringLiteral("view-list-text")] = QStringLiteral("go-home"); alternatives[QStringLiteral("view-pim-calendar")] = QStringLiteral("x-office-spreadsheet"); alternatives[QStringLiteral("view-statistics")] = QStringLiteral("x-office-spreadsheet"); alternatives[QStringLiteral("window-duplicate")] = QStringLiteral("edit-copy"); alternatives[QStringLiteral("zoom-fit-width")] = QStringLiteral("media-playback-stop"); alternatives[QStringLiteral("smallclock")] = QLatin1String(""); alternatives[QStringLiteral("edit_undo")] = QStringLiteral("edit-undo"); alternatives[QStringLiteral("nextuntranslated")] = QStringLiteral("debug-execute-to-cursor"); alternatives[QStringLiteral("format-precision-less")] = QStringLiteral("visibility"); } bool alternativeEmpty = false; if (alternatives.contains(iName)) { auto alternative = alternatives.value(iName); alternativeEmpty = (alternative.isEmpty()); if (!alternativeEmpty) { if (!iOverlays.isEmpty()) { output = KDE::icon(alternative, iOverlays); } else { output = KDE::icon(alternative); } } } if (output.isNull() && !alternativeEmpty) { SKGTRACE << "WARNING: Icon [" << iName << "] not found" << endl; output = KDE::icon(QStringLiteral("script-error")); if (output.isNull()) { output = KDE::icon(QStringLiteral("image-missing")); } } } return output; } QString SKGServices::getMajorVersion(const QString& iVersion) { QString output = iVersion; int pos = output.indexOf('.'); if (pos != -1) { pos = output.indexOf('.', pos + 1); if (pos != -1) { output = output.left(pos); } } return output; } QString SKGServices::getFullPathCommandLine(const QString& iCommandLine) { QString output = iCommandLine; if (!output.isEmpty()) { auto pathWords = SKGServices::splitCSVLine(output, QLatin1Char(' ')); QString fullpath = QStandardPaths::locate(QStandardPaths::GenericDataLocation, qApp->applicationName() % "/" % pathWords.at(0)); if (!fullpath.isEmpty()) { pathWords[0] = fullpath; output = pathWords.join(QLatin1Char(' ')); } } return output; } diff --git a/tests/skgbasemodelertest/skgtestbase.cpp b/tests/skgbasemodelertest/skgtestbase.cpp index 927bd9e11..eb1b65f61 100644 --- a/tests/skgbasemodelertest/skgtestbase.cpp +++ b/tests/skgbasemodelertest/skgtestbase.cpp @@ -1,738 +1,741 @@ /*************************************************************************** * 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 * This file is a test script. * * @author Stephane MANKOWSKI / Guillaume DE BURE */ #include "skgtestmacro.h" /** * The main function of the unit test * @param argc the number of arguments * @param argv the list of arguments */ void test_getPeriodWhereClause(int& nberror, int& nbcheck, bool showonlyfailures) { SKGTEST(QStringLiteral("CONV:getPeriodWhereClause"), SKGServices::getPeriodWhereClause(QStringLiteral("2014")), QStringLiteral("STRFTIME('%Y',d_date)='2014'")) SKGTEST(QStringLiteral("CONV:getPeriodWhereClause"), SKGServices::getPeriodWhereClause(QStringLiteral("2014-02")), QStringLiteral("STRFTIME('%Y-%m',d_date)='2014-02'")) SKGTEST(QStringLiteral("CONV:getPeriodWhereClause"), SKGServices::getPeriodWhereClause(QStringLiteral("2014-10")), QStringLiteral("STRFTIME('%Y-%m',d_date)='2014-10'")) SKGTEST(QStringLiteral("CONV:getPeriodWhereClause"), SKGServices::getPeriodWhereClause(QStringLiteral("2014-Q2")), QStringLiteral("STRFTIME('%Y',d_date)||'-Q'||(CASE WHEN STRFTIME('%m',d_date)<='03' THEN '1' WHEN STRFTIME('%m',d_date)<='06' THEN '2' WHEN STRFTIME('%m',d_date)<='09' THEN '3' ELSE '4' END)='2014-Q2'")) SKGTEST(QStringLiteral("CONV:getPeriodWhereClause"), SKGServices::getPeriodWhereClause(QStringLiteral("2014-S2")), QStringLiteral("STRFTIME('%Y',d_date)||'-S'||(CASE WHEN STRFTIME('%m',d_date)<='06' THEN '1' ELSE '2' END)='2014-S2'")) SKGTEST(QStringLiteral("CONV:getPeriodWhereClause"), SKGServices::getPeriodWhereClause(QStringLiteral("INVALID STRING")), QStringLiteral("1=0")) SKGTEST(QStringLiteral("CONV:getPeriodWhereClause"), SKGServices::getPeriodWhereClause(QStringLiteral("ALL")), QStringLiteral("1=1")) } void test_getNeighboringPeriod(int& nberror, int& nbcheck, bool showonlyfailures) { SKGTEST(QStringLiteral("CONV:getNeighboringPeriod"), SKGServices::getNeighboringPeriod(QStringLiteral("2014")), QStringLiteral("2013")) SKGTEST(QStringLiteral("CONV:getNeighboringPeriod"), SKGServices::getNeighboringPeriod(QStringLiteral("2014-10")), QStringLiteral("2014-09")) SKGTEST(QStringLiteral("CONV:getNeighboringPeriod"), SKGServices::getNeighboringPeriod(QStringLiteral("2014-01")), QStringLiteral("2013-12")) SKGTEST(QStringLiteral("CONV:getNeighboringPeriod"), SKGServices::getNeighboringPeriod(QStringLiteral("2014-Q2")), QStringLiteral("2014-Q1")) SKGTEST(QStringLiteral("CONV:getNeighboringPeriod"), SKGServices::getNeighboringPeriod(QStringLiteral("2014-Q1")), QStringLiteral("2013-Q4")) SKGTEST(QStringLiteral("CONV:getNeighboringPeriod"), SKGServices::getNeighboringPeriod(QStringLiteral("2014-S2")), QStringLiteral("2014-S1")) SKGTEST(QStringLiteral("CONV:getNeighboringPeriod"), SKGServices::getNeighboringPeriod(QStringLiteral("2014-S1")), QStringLiteral("2013-S2")) SKGTEST(QStringLiteral("CONV:getNeighboringPeriod"), SKGServices::getNeighboringPeriod(QStringLiteral("INVALID STRING")), QStringLiteral("1=0")) SKGTEST(QStringLiteral("CONV:getNeighboringPeriod"), SKGServices::getNeighboringPeriod(QStringLiteral("ALL")), QStringLiteral("1=0")) SKGTEST(QStringLiteral("CONV:getNeighboringPeriod +1"), SKGServices::getNeighboringPeriod(QStringLiteral("2014"), 1), QStringLiteral("2015")) SKGTEST(QStringLiteral("CONV:getNeighboringPeriod +1"), SKGServices::getNeighboringPeriod(QStringLiteral("2014-10"), 1), QStringLiteral("2014-11")) SKGTEST(QStringLiteral("CONV:getNeighboringPeriod +1"), SKGServices::getNeighboringPeriod(QStringLiteral("2014-01"), 1), QStringLiteral("2014-02")) SKGTEST(QStringLiteral("CONV:getNeighboringPeriod +1"), SKGServices::getNeighboringPeriod(QStringLiteral("2014-Q4"), 1), QStringLiteral("2015-Q1")) SKGTEST(QStringLiteral("CONV:getNeighboringPeriod +1"), SKGServices::getNeighboringPeriod(QStringLiteral("2014-Q2"), 1), QStringLiteral("2014-Q3")) SKGTEST(QStringLiteral("CONV:getNeighboringPeriod +1"), SKGServices::getNeighboringPeriod(QStringLiteral("2014-Q1"), 1), QStringLiteral("2014-Q2")) SKGTEST(QStringLiteral("CONV:getNeighboringPeriod +1"), SKGServices::getNeighboringPeriod(QStringLiteral("2014-S2"), 1), QStringLiteral("2015-S1")) SKGTEST(QStringLiteral("CONV:getNeighboringPeriod +1"), SKGServices::getNeighboringPeriod(QStringLiteral("2014-S1"), 1), QStringLiteral("2014-S2")) } void test_periodToDate(int& nberror, int& nbcheck, bool showonlyfailures) { SKGTEST(QStringLiteral("CONV:periodToDate"), SKGServices::periodToDate(QStringLiteral("2014")).toString(), QDate(2014, 12, 31).toString()) SKGTEST(QStringLiteral("CONV:periodToDate"), SKGServices::periodToDate(QStringLiteral("2014-S1")).toString(), QDate(2014, 6, 30).toString()) SKGTEST(QStringLiteral("CONV:periodToDate"), SKGServices::periodToDate(QStringLiteral("2014-S2")).toString(), QDate(2014, 12, 31).toString()) SKGTEST(QStringLiteral("CONV:periodToDate"), SKGServices::periodToDate(QStringLiteral("2014-Q1")).toString(), QDate(2014, 3, 31).toString()) SKGTEST(QStringLiteral("CONV:periodToDate"), SKGServices::periodToDate(QStringLiteral("2014-Q2")).toString(), QDate(2014, 6, 30).toString()) SKGTEST(QStringLiteral("CONV:periodToDate"), SKGServices::periodToDate(QStringLiteral("2014-Q3")).toString(), QDate(2014, 9, 30).toString()) SKGTEST(QStringLiteral("CONV:periodToDate"), SKGServices::periodToDate(QStringLiteral("2014-Q4")).toString(), QDate(2014, 12, 31).toString()) SKGTEST(QStringLiteral("CONV:periodToDate"), SKGServices::periodToDate(QStringLiteral("2014-01")).toString(), QDate(2014, 1, 31).toString()) SKGTEST(QStringLiteral("CONV:periodToDate"), SKGServices::periodToDate(QStringLiteral("2014-07")).toString(), QDate(2014, 7, 31).toString()) SKGTEST(QStringLiteral("CONV:periodToDate"), SKGServices::periodToDate(QStringLiteral("ALL")).toString(), QDate::currentDate().toString()) } void test_partialStringToDate(int& nberror, int& nbcheck, bool showonlyfailures) { SKGTEST(QStringLiteral("CONV:partialStringToDate"), SKGServices::partialStringToDate(QStringLiteral("INVALID"), true).toString(), QLatin1String("")) QDate currentMonth10 = QDate::currentDate(); currentMonth10 = currentMonth10.addDays(10 - QDate::currentDate().day()); QDate current0102(QDate::currentDate().year(), 2, 1); + QDate current3112(QDate::currentDate().year(), 12, 31); SKGTEST(QStringLiteral("CONV:partialStringToDate"), SKGServices::partialStringToDate(QStringLiteral("10"), true).toString(), (currentMonth10 <= QDate::currentDate() ? currentMonth10 : currentMonth10.addMonths(-1)).toString()) SKGTEST(QStringLiteral("CONV:partialStringToDate"), SKGServices::partialStringToDate(QStringLiteral("1/2"), true).toString(), (current0102 <= QDate::currentDate() ? current0102 : current0102.addYears(-1)).toString()) + SKGTEST(QStringLiteral("CONV:partialStringToDate"), SKGServices::partialStringToDate(QStringLiteral("31/12"), true).toString(), (current3112 <= QDate::currentDate() ? current3112 : current3112.addYears(-1)).toString()) + SKGTEST(QStringLiteral("CONV:partialStringToDate"), SKGServices::partialStringToDate(QStringLiteral("1/2/14"), true).toString(), QDate(2014, 2, 1).toString()) SKGTEST(QStringLiteral("CONV:partialStringToDate"), SKGServices::partialStringToDate(QStringLiteral("1/2/99"), true).toString(), QDate(1999, 2, 1).toString()) SKGTEST(QStringLiteral("CONV:partialStringToDate"), SKGServices::partialStringToDate(QStringLiteral("1/2/014"), true).toString(), QDate(2014, 2, 1).toString()) SKGTEST(QStringLiteral("CONV:partialStringToDate"), SKGServices::partialStringToDate(QStringLiteral("1/2/199"), true).toString(), QDate(1199, 2, 1).toString()) SKGTEST(QStringLiteral("CONV:partialStringToDate"), SKGServices::partialStringToDate(QStringLiteral("1/2/1014"), true).toString(), QDate(1014, 2, 1).toString()) SKGTEST(QStringLiteral("CONV:partialStringToDate"), SKGServices::partialStringToDate(QStringLiteral("1/2/2222"), true).toString(), QDate(2222, 2, 1).toString()) SKGTEST(QStringLiteral("CONV:partialStringToDate"), SKGServices::partialStringToDate(QStringLiteral("10"), false).toString(), (currentMonth10 >= QDate::currentDate() ? currentMonth10 : currentMonth10.addMonths(1)).toString()) SKGTEST(QStringLiteral("CONV:partialStringToDate"), SKGServices::partialStringToDate(QStringLiteral("1/2"), false).toString(), (current0102 >= QDate::currentDate() ? current0102 : current0102.addYears(1)).toString()) SKGTEST(QStringLiteral("CONV:partialStringToDate"), SKGServices::partialStringToDate(QStringLiteral("1/2/14"), false).toString(), QDate(2114, 2, 1).toString()) SKGTEST(QStringLiteral("CONV:partialStringToDate"), SKGServices::partialStringToDate(QStringLiteral("1/2/99"), false).toString(), QDate(2099, 2, 1).toString()) SKGTEST(QStringLiteral("CONV:partialStringToDate"), SKGServices::partialStringToDate(QStringLiteral("1/2/014"), false).toString(), QDate(3014, 2, 1).toString()) SKGTEST(QStringLiteral("CONV:partialStringToDate"), SKGServices::partialStringToDate(QStringLiteral("1/2/199"), false).toString(), QDate(2199, 2, 1).toString()) SKGTEST(QStringLiteral("CONV:partialStringToDate"), SKGServices::partialStringToDate(QStringLiteral("1/2/1014"), false).toString(), QDate(1014, 2, 1).toString()) SKGTEST(QStringLiteral("CONV:partialStringToDate"), SKGServices::partialStringToDate(QStringLiteral("1/2/2222"), false).toString(), QDate(2222, 2, 1).toString()) } void test_conversions(int& nberror, int& nbcheck, bool showonlyfailures) { SKGTEST(QStringLiteral("CONV:dateToPeriod"), SKGServices::dateToPeriod(QDate(2013, 03, 05), QStringLiteral("D")), QStringLiteral("2013-03-05")) SKGTEST(QStringLiteral("CONV:dateToPeriod"), SKGServices::dateToPeriod(QDate(2013, 01, 01), QStringLiteral("W")), QStringLiteral("2013-W01")) SKGTEST(QStringLiteral("CONV:dateToPeriod"), SKGServices::dateToPeriod(QDate(2013, 03, 05), QStringLiteral("W")), QStringLiteral("2013-W10")) SKGTEST(QStringLiteral("CONV:dateToPeriod"), SKGServices::dateToPeriod(QDate(2013, 03, 05), QStringLiteral("M")), QStringLiteral("2013-03")) SKGTEST(QStringLiteral("CONV:dateToPeriod"), SKGServices::dateToPeriod(QDate(2013, 03, 05), QStringLiteral("Q")), QStringLiteral("2013-Q1")) SKGTEST(QStringLiteral("CONV:dateToPeriod"), SKGServices::dateToPeriod(QDate(2013, 03, 05), QStringLiteral("S")), QStringLiteral("2013-S1")) SKGTEST(QStringLiteral("CONV:dateToPeriod"), SKGServices::dateToPeriod(QDate(2013, 03, 05), QStringLiteral("Y")), QStringLiteral("2013")) SKGTEST(QStringLiteral("CONV:intToString"), SKGServices::intToString(10), QStringLiteral("10")) SKGTEST(QStringLiteral("CONV:intToString"), SKGServices::intToString(5490990004), QStringLiteral("5490990004")) SKGTEST(QStringLiteral("CONV:stringToInt"), SKGServices::stringToInt(QStringLiteral("56")), 56) SKGTEST(QStringLiteral("CONV:stringToInt"), SKGServices::stringToInt(QStringLiteral("HELLO")), 0) SKGTEST(QStringLiteral("CONV:stringToInt"), SKGServices::stringToInt(QStringLiteral("5HELLO")), 0) SKGTEST(QStringLiteral("CONV:stringToInt"), SKGServices::stringToInt(QStringLiteral("5490990004")), 5490990004) SKGTEST(QStringLiteral("CONV:doubleToString"), SKGServices::doubleToString(10), QStringLiteral("10")) SKGTEST(QStringLiteral("CONV:doubleToString"), SKGServices::doubleToString(5.3), QStringLiteral("5.3")) SKGTEST(QStringLiteral("CONV:doubleToString"), SKGServices::doubleToString(11111115.33), QStringLiteral("11111115.33")) SKGTEST(QStringLiteral("CONV:doubleToString"), SKGServices::doubleToString(119999.11), QStringLiteral("119999.11")) SKGTEST(QStringLiteral("CONV:stringToDouble"), SKGServices::stringToDouble(QStringLiteral("10")) - 10, 0) SKGTEST(QStringLiteral("CONV:stringToDouble"), SKGServices::stringToDouble(QStringLiteral("5.3")) - 5.3, 0) SKGTEST(QStringLiteral("CONV:stringToDouble"), SKGServices::stringToDouble(QStringLiteral("11111115.33")) - 11111115.33, 0) SKGTEST(QStringLiteral("CONV:stringToDouble"), SKGServices::stringToDouble(QStringLiteral("25,000.00")) - 25000.00, 0) SKGTEST(QStringLiteral("CONV:stringToDouble"), SKGServices::stringToDouble(QStringLiteral("1.307,40")) - 1307.40, 0) SKGTEST(QStringLiteral("CONV:stringToDouble"), SKGServices::stringToDouble(QStringLiteral("2 150,10")) - 2150.10, 0) SKGTEST(QStringLiteral("CONV:stringToDouble"), SKGServices::stringToDouble(QStringLiteral("-$8.35")) + 8.35, 0) SKGTEST(QStringLiteral("CONV:stringToDouble"), SKGServices::stringToDouble(QStringLiteral("8.35€")) - 8.35, 0) SKGTEST(QStringLiteral("CONV:stringToDouble"), SKGServices::stringToDouble(QStringLiteral("1234.56e-02")) - 12.3456, 0) SKGTEST(QStringLiteral("CONV:stringToDouble"), SKGServices::stringToDouble(QStringLiteral("31238/100")) - 312.38, 0) SKGTEST(QStringLiteral("CONV:stringToDouble"), SKGServices::stringToDouble(QStringLiteral("31238/abc")), 0) SKGTEST(QStringLiteral("CONV:stringToDouble"), SKGServices::stringToDouble(QStringLiteral("nan")), 0) SKGTEST(QStringLiteral("CONV:stringToDouble"), SKGServices::stringToDouble(QStringLiteral("inf")), 1e300) SKGTEST(QStringLiteral("CONV:stringToDouble"), SKGServices::stringToDouble(QStringLiteral("-inf")), -1e300) SKGTEST(QStringLiteral("CONV:stringToDouble"), SKGServices::stringToDouble(QStringLiteral("00000000194065")), 194065) SKGServices::timeToString(QDateTime()); SKGTEST(QStringLiteral("CONV:stringToTime"), SKGServices::timeToString(SKGServices::stringToTime(QStringLiteral("1970-07-16"))), QStringLiteral("1970-07-16 00:00:00")) SKGTEST(QStringLiteral("CONV:stringToTime"), SKGServices::timeToString(SKGServices::stringToTime(QStringLiteral("2008-04-20"))), QStringLiteral("2008-04-20 00:00:00")) SKGTEST(QStringLiteral("CONV:stringToTime"), SKGServices::dateToSqlString(SKGServices::stringToTime(QStringLiteral("1970-07-16"))), QStringLiteral("1970-07-16")) SKGTEST(QStringLiteral("CONV:stringToTime"), SKGServices::dateToSqlString(SKGServices::stringToTime(QStringLiteral("2008-04-20"))), QStringLiteral("2008-04-20")) SKGTESTBOOL("CONV:SKGServices::getMicroTime", (SKGServices::getMicroTime() > 0), true) SKGTEST(QStringLiteral("STR:dateToSqlString"), SKGServices::dateToSqlString(QStringLiteral("20080525"), QStringLiteral("YYYYMMDD")), QStringLiteral("2008-05-25")) SKGTEST(QStringLiteral("STR:dateToSqlString"), SKGServices::dateToSqlString(QStringLiteral("2008-05-25"), QStringLiteral("YYYY-MM-DD")), QStringLiteral("2008-05-25")) SKGTEST(QStringLiteral("STR:dateToSqlString"), SKGServices::dateToSqlString(QStringLiteral("2008-05-25 00:00:00"), QStringLiteral("YYYY-MM-DD")), QStringLiteral("2008-05-25")) SKGTEST(QStringLiteral("STR:dateToSqlString"), SKGServices::dateToSqlString(QStringLiteral("05/25/08"), QStringLiteral("MM/DD/YY")), QStringLiteral("2008-05-25")) SKGTEST(QStringLiteral("STR:dateToSqlString"), SKGServices::dateToSqlString(QStringLiteral("05/25/78"), QStringLiteral("MM/DD/YY")), QStringLiteral("1978-05-25")) SKGTEST(QStringLiteral("STR:dateToSqlString"), SKGServices::dateToSqlString(QStringLiteral("05-25-08"), QStringLiteral("MM-DD-YY")), QStringLiteral("2008-05-25")) SKGTEST(QStringLiteral("STR:dateToSqlString"), SKGServices::dateToSqlString(QStringLiteral("05-25-78"), QStringLiteral("MM-DD-YY")), QStringLiteral("1978-05-25")) SKGTEST(QStringLiteral("STR:dateToSqlString"), SKGServices::dateToSqlString(QStringLiteral("5/25/08"), QStringLiteral("MM/DD/YY")), QStringLiteral("2008-05-25")) SKGTEST(QStringLiteral("STR:dateToSqlString"), SKGServices::dateToSqlString(QStringLiteral("5/25/78"), QStringLiteral("MM/DD/YY")), QStringLiteral("1978-05-25")) SKGTEST(QStringLiteral("STR:dateToSqlString"), SKGServices::dateToSqlString(QStringLiteral("5-25-08"), QStringLiteral("MM-DD-YY")), QStringLiteral("2008-05-25")) SKGTEST(QStringLiteral("STR:dateToSqlString"), SKGServices::dateToSqlString(QStringLiteral("5-6-08"), QStringLiteral("MM-DD-YY")), QStringLiteral("2008-05-06")) SKGTEST(QStringLiteral("STR:dateToSqlString"), SKGServices::dateToSqlString(QStringLiteral("5-25-78"), QStringLiteral("MM-DD-YY")), QStringLiteral("1978-05-25")) SKGTEST(QStringLiteral("STR:dateToSqlString"), SKGServices::dateToSqlString(QStringLiteral("25/05/08"), QStringLiteral("DD/MM/YY")), QStringLiteral("2008-05-25")) SKGTEST(QStringLiteral("STR:dateToSqlString"), SKGServices::dateToSqlString(QStringLiteral("25/05/78"), QStringLiteral("DD/MM/YY")), QStringLiteral("1978-05-25")) SKGTEST(QStringLiteral("STR:dateToSqlString"), SKGServices::dateToSqlString(QStringLiteral("25-05-08"), QStringLiteral("DD-MM-YY")), QStringLiteral("2008-05-25")) SKGTEST(QStringLiteral("STR:dateToSqlString"), SKGServices::dateToSqlString(QStringLiteral("25-05-78"), QStringLiteral("DD-MM-YY")), QStringLiteral("1978-05-25")) SKGTEST(QStringLiteral("STR:dateToSqlString"), SKGServices::dateToSqlString(QStringLiteral("25/05/2008"), QStringLiteral("DD/MM/YYYY")), QStringLiteral("2008-05-25")) SKGTEST(QStringLiteral("STR:dateToSqlString"), SKGServices::dateToSqlString(QStringLiteral("25-05-2008"), QStringLiteral("DD-MM-YYYY")), QStringLiteral("2008-05-25")) SKGTEST(QStringLiteral("STR:dateToSqlString"), SKGServices::dateToSqlString(QStringLiteral("5/25/2008"), QStringLiteral("MM/DD/YYYY")), QStringLiteral("2008-05-25")) SKGTEST(QStringLiteral("STR:dateToSqlString"), SKGServices::dateToSqlString(QStringLiteral("5-25-2008"), QStringLiteral("MM-DD-YYYY")), QStringLiteral("2008-05-25")) SKGTEST(QStringLiteral("STR:dateToSqlString"), SKGServices::dateToSqlString(QStringLiteral("5-6-2008"), QStringLiteral("MM-DD-YYYY")), QStringLiteral("2008-05-06")) SKGTEST(QStringLiteral("STR:dateToSqlString"), SKGServices::dateToSqlString(QStringLiteral("5-6-8"), QStringLiteral("MM-DD-YYYY")), QStringLiteral("2008-05-06")) SKGTEST(QStringLiteral("STR:dateToSqlString"), SKGServices::dateToSqlString(QStringLiteral("3.21.01"), QStringLiteral("MM-DD-YY")), QStringLiteral("2001-03-21")) SKGTEST(QStringLiteral("STR:dateToSqlString"), SKGServices::dateToSqlString(QStringLiteral("1/ 1' 6"), QStringLiteral("DD-MM-YY")), QStringLiteral("2006-01-01")) SKGTEST(QStringLiteral("STR:dateToSqlString"), SKGServices::dateToSqlString(QStringLiteral("6/ 1/94"), QStringLiteral("DD-MM-YY")), QStringLiteral("1994-01-06")) SKGTEST(QStringLiteral("STR:dateToSqlString"), SKGServices::dateToSqlString(QStringLiteral("21/12'2001"), QStringLiteral("DD-MM-YYYY")), QStringLiteral("2001-12-21")) SKGTEST(QStringLiteral("STR:dateToSqlString"), SKGServices::dateToSqlString(QStringLiteral("21122001"), QStringLiteral("DDMMYYYY")), QStringLiteral("2001-12-21")) SKGTEST(QStringLiteral("STR:dateToSqlString"), SKGServices::dateToSqlString(QStringLiteral("12212001"), QStringLiteral("MMDDYYYY")), QStringLiteral("2001-12-21")) SKGTEST(QStringLiteral("STR:dateToSqlString"), SKGServices::dateToSqlString(QStringLiteral("010203"), QStringLiteral("MMDDYY")), QStringLiteral("2003-01-02")) SKGTEST(QStringLiteral("STR:dateToSqlString"), SKGServices::dateToSqlString(QStringLiteral("010203"), QStringLiteral("DDMMYY")), QStringLiteral("2003-02-01")) SKGTEST(QStringLiteral("STR:dateToSqlString"), SKGServices::dateToSqlString(QStringLiteral("3/9/04"), QStringLiteral("DD-MM-YY")), QStringLiteral("2004-09-03")) SKGTEST(QStringLiteral("STR:dateToSqlString"), SKGServices::dateToSqlString(QStringLiteral("31Dec2005"), QStringLiteral("DDMMMYYYY")), QStringLiteral("2005-12-31")) SKGTEST(QStringLiteral("STR:dateToSqlString"), SKGServices::dateToSqlString(QStringLiteral("31-Dec-2005"), QStringLiteral("DD-MMM-YYYY")), QStringLiteral("2005-12-31")) SKGTEST(QStringLiteral("STR:dateToSqlString"), SKGServices::dateToSqlString(QStringLiteral("31/Dec/2005"), QStringLiteral("DD/MMM/YYYY")), QStringLiteral("2005-12-31")) SKGTEST(QStringLiteral("STR:dateToSqlString"), SKGServices::dateToSqlString(QStringLiteral("31Dec05"), QStringLiteral("DDMMMYY")), QStringLiteral("2005-12-31")) SKGTEST(QStringLiteral("STR:dateToSqlString"), SKGServices::dateToSqlString(QStringLiteral("31-Dec-05"), QStringLiteral("DD-MMM-YY")), QStringLiteral("2005-12-31")) SKGTEST(QStringLiteral("STR:dateToSqlString"), SKGServices::dateToSqlString(QStringLiteral("31/Dec/05"), QStringLiteral("DD/MMM/YY")), QStringLiteral("2005-12-31")) SKGTEST(QStringLiteral("STR:dateToSqlString"), SKGServices::dateToSqlString(QStringLiteral("31DEC2005"), QStringLiteral("DDMMMYYYY")), QStringLiteral("2005-12-31")) SKGTEST(QStringLiteral("STR:dateToSqlString"), SKGServices::dateToSqlString(QStringLiteral("INVALIDDATE"), QStringLiteral("DD-MM-YY")), SKGServices::dateToSqlString(QDateTime::currentDateTime())) SKGTEST(QStringLiteral("STR:dateToSqlString"), SKGServices::dateToSqlString(QStringLiteral("02.01.2015"), QStringLiteral("DD-MM-YYYY")), QStringLiteral("2015-01-02")) } void test_nbWorkingDays(int& nberror, int& nbcheck, bool showonlyfailures) { SKGTEST(QStringLiteral("SKGServices::nbWorkingDays"), SKGServices::nbWorkingDays(QDate(2010, 9, 3), QDate(2010, 9, 6)), 1) SKGTEST(QStringLiteral("SKGServices::nbWorkingDays"), SKGServices::nbWorkingDays(QDate(2010, 9, 6), QDate(2010, 9, 3)), 1) SKGTEST(QStringLiteral("SKGServices::nbWorkingDays"), SKGServices::nbWorkingDays(QDate(2010, 9, 3), QDate(2010, 9, 3)), 1) SKGTEST(QStringLiteral("SKGServices::nbWorkingDays"), SKGServices::nbWorkingDays(QDate(2010, 9, 1), QDate(2010, 9, 3)), 2) SKGTEST(QStringLiteral("SKGServices::nbWorkingDays"), SKGServices::nbWorkingDays(QDate(2010, 9, 1), QDate(2010, 9, 8)), 5) } void test_getnext(int& nberror, int& nbcheck, bool showonlyfailures) { SKGTEST(QStringLiteral("SKGServices::getNextString"), SKGServices::getNextString(QStringLiteral("12345")), QStringLiteral("12346")) SKGTEST(QStringLiteral("SKGServices::getNextString"), SKGServices::getNextString(QStringLiteral("9")), QStringLiteral("10")) } void test_errors(int& nberror, int& nbcheck, bool showonlyfailures) { { SKGTraces::cleanProfilingStatistics(); SKGError err; SKGTEST(QStringLiteral("ERR:Default RC"), err.getReturnCode(), 0) SKGTEST(QStringLiteral("ERR:Default RC"), err.getReturnCode(), 0) SKGTESTBOOL("ERR:isWarning", err.isWarning(), false) SKGTESTBOOL("ERR:isSucceeded", err.isSucceeded(), true) SKGTESTBOOL("ERR:isFailed", err.isFailed(), false) SKGTESTBOOL("ERR:!", !err, true) SKGTESTBOOL("ERR:operator bool", err, false) SKGTESTBOOL("ERR:getPreviousError", (err.getPreviousError() == nullptr), true) SKGTEST(QStringLiteral("ERR:Default message"), err.getMessage(), QLatin1String("")) err.setReturnCode(10); err.setMessage(QStringLiteral("Invalid parameter")); SKGTEST(QStringLiteral("ERR:getHistoricalSize"), err.getHistoricalSize(), 0) SKGTEST(QStringLiteral("ERR:RC 10"), err.getReturnCode(), 10) SKGTEST(QStringLiteral("ERR:MSG Invalid parameter"), err.getMessage(), QStringLiteral("Invalid parameter")) err.addError(11, QStringLiteral("Message 11")); SKGTESTBOOL("ERR:isWarning", err.isWarning(), false) SKGTESTBOOL("ERR:isSucceeded", err.isSucceeded(), false) SKGTESTBOOL("ERR:isFailed", err.isFailed(), true) SKGTESTBOOL("ERR:!", !err, false) SKGTESTBOOL("ERR:operator bool", err, true) SKGTEST(QStringLiteral("ERR:getHistoricalSize"), err.getHistoricalSize(), 1) err.addError(-12, QStringLiteral("Message 12")); SKGTESTBOOL("ERR:isWarning", err.isWarning(), true) SKGTESTBOOL("ERR:isSucceeded", err.isSucceeded(), true) SKGTESTBOOL("ERR:isFailed", err.isFailed(), false) SKGTESTBOOL("ERR:!", !err, true) SKGTESTBOOL("ERR:operator bool", err, false) SKGTEST(QStringLiteral("ERR:getHistoricalSize"), err.getHistoricalSize(), 2) SKGTEST(QStringLiteral("ERR:getFullMessageWithHistorical"), err.getFullMessageWithHistorical(), QStringLiteral("[WAR--12]: Message 12\n[ERR-11]: Message 11\n[ERR-10]: Invalid parameter")) } { SKGTraces::cleanProfilingStatistics(); SKGError err; err.setReturnCode(10).setMessage(QStringLiteral("Invalid parameter")).addError(11, QStringLiteral("Message 11")); SKGTEST(QStringLiteral("ERR:getHistoricalSize"), err.getHistoricalSize(), 1) SKGTEST(QStringLiteral("ERR:RC 10"), err.getReturnCode(), 11) SKGTEST(QStringLiteral("ERR:MSG Message 11"), err.getMessage(), QStringLiteral("Message 11")) } } void test_getDateFormat(int& nberror, int& nbcheck, bool showonlyfailures) { { QStringList dates; dates << QStringLiteral("19/08/2008"); SKGTEST(QStringLiteral("STR:getDateFormat"), SKGServices::getDateFormat(dates), QStringLiteral("DD-MM-YYYY")) } { QStringList dates; dates << QStringLiteral("20080819"); SKGTEST(QStringLiteral("STR:getDateFormat"), SKGServices::getDateFormat(dates), QStringLiteral("YYYYMMDD")) } { QStringList dates; dates << QStringLiteral("10141989"); SKGTEST(QStringLiteral("STR:getDateFormat"), SKGServices::getDateFormat(dates), QStringLiteral("MMDDYYYY")) } { QStringList dates; dates << QStringLiteral("14101989"); SKGTEST(QStringLiteral("STR:getDateFormat"), SKGServices::getDateFormat(dates), QStringLiteral("DDMMYYYY")) } { QStringList dates; dates << QStringLiteral("05/08/2008") << QStringLiteral("19/08/2008"); SKGTEST(QStringLiteral("STR:getDateFormat"), SKGServices::getDateFormat(dates), QStringLiteral("DD-MM-YYYY")) } { QStringList dates; dates << QStringLiteral("19/ 1' 6"); SKGTEST(QStringLiteral("STR:getDateFormat"), SKGServices::getDateFormat(dates), QStringLiteral("DD-MM-YYYY")) } { QStringList dates; dates << QStringLiteral("21/12'2001"); SKGTEST(QStringLiteral("STR:getDateFormat"), SKGServices::getDateFormat(dates), QStringLiteral("DD-MM-YYYY")) } { QStringList dates; dates << QStringLiteral("6/ 1/94"); SKGTEST(QStringLiteral("STR:getDateFormat"), SKGServices::getDateFormat(dates), QStringLiteral("DD-MM-YYYY")) } { QStringList dates; dates << QStringLiteral("10.29.07"); SKGTEST(QStringLiteral("STR:getDateFormat"), SKGServices::getDateFormat(dates), QStringLiteral("MM-DD-YY")) } { QStringList dates; dates << QStringLiteral("10.05.07"); SKGTEST(QStringLiteral("STR:getDateFormat"), SKGServices::getDateFormat(dates), QStringLiteral("DD-MM-YY")) } { QStringList dates; dates << QStringLiteral("2001.10.25"); SKGTEST(QStringLiteral("STR:getDateFormat"), SKGServices::getDateFormat(dates), QStringLiteral("YYYY-MM-DD")) } { QStringList dates; dates << QStringLiteral("45450116"); SKGTEST(QStringLiteral("STR:getDateFormat"), SKGServices::getDateFormat(dates), QStringLiteral("YYYYMMDD")) } { QStringList dates; dates << QStringLiteral("7/14' 0") << QStringLiteral("11/30/99"); SKGTEST(QStringLiteral("STR:getDateFormat"), SKGServices::getDateFormat(dates), QStringLiteral("MM-DD-YYYY")) } { QStringList dates; dates << QStringLiteral("10/ 8'10"); SKGTEST(QStringLiteral("STR:getDateFormat"), SKGServices::getDateFormat(dates), QStringLiteral("DD-MM-YYYY")) } { QStringList dates; dates << QStringLiteral("7/8/06"); SKGTEST(QStringLiteral("STR:getDateFormat"), SKGServices::getDateFormat(dates), QStringLiteral("DD-MM-YY")) } { QStringList dates; dates << QStringLiteral("7/8/06") << QStringLiteral("11/30/99") << QStringLiteral("7/14' 0"); SKGTEST(QStringLiteral("STR:getDateFormat"), SKGServices::getDateFormat(dates), QStringLiteral("MM-DD-YYYY")) } { QStringList dates; dates << QStringLiteral("3/9/04"); SKGTEST(QStringLiteral("STR:getDateFormat"), SKGServices::getDateFormat(dates), QStringLiteral("DD-MM-YY")) } { QStringList dates; dates << QStringLiteral("31Dec2005"); SKGTEST(QStringLiteral("STR:getDateFormat"), SKGServices::getDateFormat(dates), QStringLiteral("DDMMMYYYY")) } { QStringList dates; dates << QStringLiteral("31-Dec-05"); SKGTEST(QStringLiteral("STR:getDateFormat"), SKGServices::getDateFormat(dates), QStringLiteral("DD-MMM-YY")) } { QStringList dates; dates << QStringLiteral("2008-05-25 00:00:00"); SKGTEST(QStringLiteral("STR:getDateFormat"), SKGServices::getDateFormat(dates), QStringLiteral("YYYY-MM-DD")) } { QStringList dates; dates << QStringLiteral("2008-05-25 01:02:03"); SKGTEST(QStringLiteral("STR:getDateFormat"), SKGServices::getDateFormat(dates), QStringLiteral("YYYY-MM-DD")) } { QStringList dates; QFile inputFile(SKGTest::getTestPath(QStringLiteral("IN")) % "/dates.txt"); if (inputFile.open(QIODevice::ReadOnly)) { QTextStream in(&inputFile); while (!in.atEnd()) { QString l = in.readLine().trimmed(); if (!l.isEmpty()) { dates << l; } } inputFile.close(); } SKGTEST(QStringLiteral("STR:dats.count"), dates.count(), 2364) SKGTEST(QStringLiteral("STR:getDateFormat"), SKGServices::getDateFormat(dates), QStringLiteral("MM-DD-YY")) } { QStringList dates; dates << QStringLiteral(" 7/8/06 ") << QLatin1String(""); SKGTEST(QStringLiteral("STR:getDateFormat"), SKGServices::getDateFormat(dates), QStringLiteral("DD-MM-YY")) } { QStringList dates; dates << QStringLiteral("99999999") << QStringLiteral("9999999999"); SKGTEST(QStringLiteral("STR:getDateFormat"), SKGServices::getDateFormat(dates), QLatin1String("")) } } void test_csv(int& nberror, int& nbcheck, bool showonlyfailures) { SKGTEST(QStringLiteral("STR:stringToCsv"), SKGServices::stringToCsv(QStringLiteral("ABC")), QStringLiteral("\"ABC\"")) SKGTEST(QStringLiteral("STR:stringToCsv"), SKGServices::stringToCsv(QStringLiteral("ABC;CDE")), QStringLiteral("\"ABC;CDE\"")) SKGTEST(QStringLiteral("STR:stringToCsv"), SKGServices::stringToCsv(QStringLiteral("AB \"C\" DE")), QStringLiteral("\"AB \"\"C\"\" DE\"")) SKGTEST(QStringLiteral("STR:stringToCsv"), SKGServices::stringToCsv(QStringLiteral("AB \"C\";DE")), QStringLiteral("\"AB \"\"C\"\";DE\"")) QStringList parameters = SKGServices::splitCSVLine(QStringLiteral("52.33,\"9/28/2010\",52.36,231803,52.33,0.00,+0.15,-,0.00,-,0.00,0.00,0.00,0.00,\"- - -\",\"-\",-,\"n\",N/A,0,+15.82,+43.33%,9,672,-1.08,-2.02%,-,-,\"51.76 - 52.57\",0.00,0.00,N/A,N/A,N/A,N/A,\"-\",51.91,52.18,-,\"+0.29%\",N/A,N/A,\"N/A\",N/A,\"N/A\",N/A,N/A,N/A,-,N/A,\"11:35am\",N/A,211524,-,\"36.51 - 53.41\",\"- - +0.29%\",\"Paris\",N/A,\"DASSAULT SYST.\""), ','); SKGTEST(QStringLiteral("STR:splitCSVLine count"), parameters.count(), 59) parameters = SKGServices::splitCSVLine(QStringLiteral("2013-04-02;transfer;\"a2\";'some text 2';-20,13"), ';', true); SKGTEST(QStringLiteral("STR:splitCSVLine count"), parameters.count(), 5) SKGTEST(QStringLiteral("STR:splitCSVLine"), parameters[0], QStringLiteral("2013-04-02")) SKGTEST(QStringLiteral("STR:splitCSVLine"), parameters[1], QStringLiteral("transfer")) SKGTEST(QStringLiteral("STR:splitCSVLine"), parameters[2], QStringLiteral("a2")) SKGTEST(QStringLiteral("STR:splitCSVLine"), parameters[3], QStringLiteral("some text 2")) SKGTEST(QStringLiteral("STR:splitCSVLine"), parameters[4], QStringLiteral("-20,13")) parameters = SKGServices::splitCSVLine(QStringLiteral("\"A;'B\";'A;\"B'"), ';', true); SKGTEST(QStringLiteral("STR:splitCSVLine count"), parameters.count(), 2) SKGTEST(QStringLiteral("STR:splitCSVLine"), parameters[0], QStringLiteral("A;'B")) SKGTEST(QStringLiteral("STR:splitCSVLine"), parameters[1], QStringLiteral("A;\"B")) SKGTEST(QStringLiteral("STR:stringToHtml"), SKGServices::stringToHtml(QStringLiteral("&")), QStringLiteral("<hello>&<world>")) SKGTEST(QStringLiteral("STR:htmlToString"), SKGServices::htmlToString(QStringLiteral("<hello>&<world>")), QStringLiteral("&")) parameters = SKGServices::splitCSVLine(SKGServices::stringToCsv(QStringLiteral("Y")) % ';' % SKGServices::stringToCsv(QStringLiteral("A;B"))); SKGTEST(QStringLiteral("STR:splitCSVLine count"), parameters.count(), 2) SKGTEST(QStringLiteral("STR:splitCSVLine"), parameters[0], QStringLiteral("Y")) SKGTEST(QStringLiteral("STR:splitCSVLine"), parameters[1], QStringLiteral("A;B")) parameters = SKGServices::splitCSVLine(QStringLiteral("A;\"B;C\";D")); SKGTEST(QStringLiteral("STR:splitCSVLine count"), parameters.count(), 3) SKGTEST(QStringLiteral("STR:splitCSVLine"), parameters[0], QStringLiteral("A")) SKGTEST(QStringLiteral("STR:splitCSVLine"), parameters[1], QStringLiteral("B;C")) SKGTEST(QStringLiteral("STR:splitCSVLine"), parameters[2], QStringLiteral("D")) parameters = SKGServices::splitCSVLine(QStringLiteral("'A';'B'")); SKGTEST(QStringLiteral("STR:splitCSVLine count"), parameters.count(), 2) SKGTEST(QStringLiteral("STR:splitCSVLine"), parameters[0], QStringLiteral("A")) SKGTEST(QStringLiteral("STR:splitCSVLine"), parameters[1], QStringLiteral("B")) parameters = SKGServices::splitCSVLine(QStringLiteral("\"A ' B\",\"C\"")); SKGTEST(QStringLiteral("STR:splitCSVLine count"), parameters.count(), 2) SKGTEST(QStringLiteral("STR:splitCSVLine"), parameters[0], QStringLiteral("A ' B")) SKGTEST(QStringLiteral("STR:splitCSVLine"), parameters[1], QStringLiteral("C")) parameters = SKGServices::splitCSVLine(QStringLiteral("'A \" B','C'")); SKGTEST(QStringLiteral("STR:splitCSVLine count"), parameters.count(), 2) SKGTEST(QStringLiteral("STR:splitCSVLine"), parameters[0], QStringLiteral("A \" B")) SKGTEST(QStringLiteral("STR:splitCSVLine"), parameters[1], QStringLiteral("C")) QChar realsep; parameters = SKGServices::splitCSVLine(QStringLiteral("\"A\",18,\"B\""), ';', true, &realsep); SKGTEST(QStringLiteral("STR:splitCSVLine count"), parameters.count(), 3) SKGTEST(QStringLiteral("STR:splitCSVLine"), parameters[0], QStringLiteral("A")) SKGTEST(QStringLiteral("STR:splitCSVLine"), parameters[1], QStringLiteral("18")) SKGTEST(QStringLiteral("STR:splitCSVLine"), parameters[2], QStringLiteral("B")) SKGTEST(QStringLiteral("STR:sep"), realsep, ',') parameters = SKGServices::splitCSVLine(QStringLiteral("30/05/2008;RETRAIT ESPECES AGENCE; ; 100,00;DEBIT;")); SKGTEST(QStringLiteral("STR:splitCSVLine count"), parameters.count(), 6) parameters = SKGServices::splitCSVLine(QStringLiteral("A|\"B\";\"C\""), '|', false); SKGTEST(QStringLiteral("STR:splitCSVLine count"), parameters.count(), 2) SKGTEST(QStringLiteral("STR:splitCSVLine"), parameters[0], QStringLiteral("A")) SKGTEST(QStringLiteral("STR:splitCSVLine"), parameters[1], QStringLiteral("\"B\";\"C\"")) parameters = SKGServices::splitCSVLine(QStringLiteral("+123 \"-abc def\" \"e:f\" e:f"), ' ', true); SKGTEST(QStringLiteral("STR:splitCSVLine count"), parameters.count(), 4) SKGTEST(QStringLiteral("STR:splitCSVLine"), parameters[0], QStringLiteral("+123")) SKGTEST(QStringLiteral("STR:splitCSVLine"), parameters[1], QStringLiteral("-abc def")) SKGTEST(QStringLiteral("STR:splitCSVLine"), parameters[2], QStringLiteral("e:f")) SKGTEST(QStringLiteral("STR:splitCSVLine"), parameters[3], QStringLiteral("e:f")) parameters = SKGServices::splitCSVLine(QStringLiteral("A; \"B\"; \"C\" ;\"D\" ;E"), ';', true); SKGTEST(QStringLiteral("STR:splitCSVLine count"), parameters.count(), 5) SKGTEST(QStringLiteral("STR:splitCSVLine"), parameters[0], QStringLiteral("A")) SKGTEST(QStringLiteral("STR:splitCSVLine"), parameters[1], QStringLiteral("B")) SKGTEST(QStringLiteral("STR:splitCSVLine"), parameters[2], QStringLiteral("C")) SKGTEST(QStringLiteral("STR:splitCSVLine"), parameters[3], QStringLiteral("D")) SKGTEST(QStringLiteral("STR:splitCSVLine"), parameters[4], QStringLiteral("E")) SKGTEST(QStringLiteral("STR:splitCSVLine words"), SKGServices::splitCSVLine(QStringLiteral("w1 w2"), ' ', true).count(), 2) SKGTEST(QStringLiteral("STR:splitCSVLine words"), SKGServices::splitCSVLine(QStringLiteral("\"w1 w1\""), ' ', true).count(), 1) SKGTEST(QStringLiteral("STR:splitCSVLine words"), SKGServices::splitCSVLine(QStringLiteral("\"w1 w1\" w2 \"w3 w3 w3\" w4"), ' ', true).count(), 4) QChar realseparator; SKGTEST(QStringLiteral("STR:splitCSVLine comma"), SKGServices::splitCSVLine(QStringLiteral("date,payee,amount"), ';', true, &realseparator).count(), 1) SKGTEST(QStringLiteral("STR:splitCSVLine comma"), realseparator, ';') QString t(QStringLiteral("Export Format, Date (YYYY-MM-DD as UTC), Time (HH:MM:SS), Merchant, Txn Amount (Funding Card), Txn Currency (Funding Card), Txn Amount (Foreign Spend), Txn Currency (Foreign Spend), Card Name, Card Last 4 Digits, Type, Category, Notes")); SKGTEST(QStringLiteral("STR:splitCSVLine comma"), SKGServices::splitCSVLine(t, ';', true, &realseparator).count(), 1) SKGTEST(QStringLiteral("STR:splitCSVLine comma"), SKGServices::splitCSVLine(t, ',', true, &realseparator).count(), 13) } void test_stringToSearchCriterias(int& nberror, int& nbcheck, bool showonlyfailures) { SKGServices::SKGSearchCriteriaList criterias = SKGServices::stringToSearchCriterias(QStringLiteral("abc +def +ghi")); SKGTEST(QStringLiteral("STR:stringToSearchCriterias count"), criterias.count(), 3) SKGTEST(QStringLiteral("STR:stringToSearchCriterias mode"), criterias[0].mode, '+') SKGTEST(QStringLiteral("STR:stringToSearchCriterias words count"), criterias[0].words.count(), 1) SKGTEST(QStringLiteral("STR:stringToSearchCriterias word"), criterias[0].words[0], QStringLiteral("ghi")) SKGTEST(QStringLiteral("STR:stringToSearchCriterias mode"), criterias[1].mode, '+') SKGTEST(QStringLiteral("STR:stringToSearchCriterias words count"), criterias[1].words.count(), 1) SKGTEST(QStringLiteral("STR:stringToSearchCriterias word"), criterias[1].words[0], QStringLiteral("def")) SKGTEST(QStringLiteral("STR:stringToSearchCriterias mode"), criterias[2].mode, '+') SKGTEST(QStringLiteral("STR:stringToSearchCriterias words count"), criterias[2].words.count(), 1) SKGTEST(QStringLiteral("STR:stringToSearchCriterias word"), criterias[2].words[0], QStringLiteral("abc")) criterias = SKGServices::stringToSearchCriterias(QStringLiteral("-abc +def ghi")); SKGTEST(QStringLiteral("STR:stringToSearchCriterias count"), criterias.count(), 2) SKGTEST(QStringLiteral("STR:stringToSearchCriterias mode"), criterias[0].mode, '+') SKGTEST(QStringLiteral("STR:stringToSearchCriterias words count"), criterias[0].words.count(), 2) SKGTEST(QStringLiteral("STR:stringToSearchCriterias word"), criterias[0].words[0], QStringLiteral("def")) SKGTEST(QStringLiteral("STR:stringToSearchCriterias word"), criterias[0].words[1], QStringLiteral("ghi")) SKGTEST(QStringLiteral("STR:stringToSearchCriterias mode"), criterias[1].mode, '-') SKGTEST(QStringLiteral("STR:stringToSearchCriterias words count"), criterias[1].words.count(), 1) SKGTEST(QStringLiteral("STR:stringToSearchCriterias word"), criterias[1].words[0], QStringLiteral("abc")) criterias = SKGServices::stringToSearchCriterias(QStringLiteral("-abc +def ghi -10")); SKGTEST(QStringLiteral("STR:stringToSearchCriterias count"), criterias.count(), 2) SKGTEST(QStringLiteral("STR:stringToSearchCriterias mode"), criterias[0].mode, '+') SKGTEST(QStringLiteral("STR:stringToSearchCriterias words count"), criterias[0].words.count(), 3) SKGTEST(QStringLiteral("STR:stringToSearchCriterias word"), criterias[0].words[0], QStringLiteral("def")) SKGTEST(QStringLiteral("STR:stringToSearchCriterias word"), criterias[0].words[1], QStringLiteral("ghi")) SKGTEST(QStringLiteral("STR:stringToSearchCriterias word"), criterias[0].words[2], QStringLiteral("-10")) SKGTEST(QStringLiteral("STR:stringToSearchCriterias mode"), criterias[1].mode, '-') SKGTEST(QStringLiteral("STR:stringToSearchCriterias words count"), criterias[1].words.count(), 1) SKGTEST(QStringLiteral("STR:stringToSearchCriterias word"), criterias[1].words[0], QStringLiteral("abc")) criterias = SKGServices::stringToSearchCriterias(QStringLiteral("-10")); SKGTEST(QStringLiteral("STR:stringToSearchCriterias count"), criterias.count(), 1) SKGTEST(QStringLiteral("STR:stringToSearchCriterias mode"), criterias[0].mode, '+') SKGTEST(QStringLiteral("STR:stringToSearchCriterias words count"), criterias[0].words.count(), 1) SKGTEST(QStringLiteral("STR:stringToSearchCriterias word"), criterias[0].words[0], QStringLiteral("-10")) criterias = SKGServices::stringToSearchCriterias(QStringLiteral("-abc")); SKGTEST(QStringLiteral("STR:stringToSearchCriterias count"), criterias.count(), 2) SKGTEST(QStringLiteral("STR:stringToSearchCriterias mode"), criterias[0].mode, '+') SKGTEST(QStringLiteral("STR:stringToSearchCriterias words count"), criterias[0].words.count(), 1) SKGTEST(QStringLiteral("STR:stringToSearchCriterias word"), criterias[0].words[0], QLatin1String("")) SKGTEST(QStringLiteral("STR:stringToSearchCriterias mode"), criterias[1].mode, '-') SKGTEST(QStringLiteral("STR:stringToSearchCriterias words count"), criterias[1].words.count(), 1) SKGTEST(QStringLiteral("STR:stringToSearchCriterias word"), criterias[1].words[0], QStringLiteral("abc")) criterias = SKGServices::stringToSearchCriterias(QStringLiteral("\"abc def ghi\" \"123 456\"")); SKGTEST(QStringLiteral("STR:stringToSearchCriterias count"), criterias.count(), 1) SKGTEST(QStringLiteral("STR:stringToSearchCriterias mode"), criterias[0].mode, '+') SKGTEST(QStringLiteral("STR:stringToSearchCriterias words count"), criterias[0].words.count(), 2) SKGTEST(QStringLiteral("STR:stringToSearchCriterias word"), criterias[0].words[0], QStringLiteral("abc def ghi")) SKGTEST(QStringLiteral("STR:stringToSearchCriterias word"), criterias[0].words[1], QStringLiteral("123 456")) criterias = SKGServices::stringToSearchCriterias(QStringLiteral("\"-payee:abc def : ghi\" +amount:25")); SKGTEST(QStringLiteral("STR:stringToSearchCriterias count"), criterias.count(), 2) SKGTEST(QStringLiteral("STR:stringToSearchCriterias mode"), criterias[0].mode, '+') SKGTEST(QStringLiteral("STR:stringToSearchCriterias words count"), criterias[0].words.count(), 1) SKGTEST(QStringLiteral("STR:stringToSearchCriterias word"), criterias[0].words[0], QStringLiteral("amount:25")) SKGTEST(QStringLiteral("STR:stringToSearchCriterias mode"), criterias[1].mode, '-') SKGTEST(QStringLiteral("STR:stringToSearchCriterias words count"), criterias[1].words.count(), 1) SKGTEST(QStringLiteral("STR:stringToSearchCriterias word"), criterias[1].words[0], QStringLiteral("payee:abc def : ghi")) SKGTEST(QStringLiteral("STR:searchCriteriasToWhereClause"), SKGServices::searchCriteriasToWhereClause(SKGServices::stringToSearchCriterias(QStringLiteral("ToTo")), QStringList() << QStringLiteral("d_DATEOP") << QStringLiteral("i_number") << QStringLiteral("t_PAYEE") << QStringLiteral("t_bookmarked"), nullptr), QStringLiteral("((lower(d_DATEOP) LIKE '%toto%' OR lower(i_number) LIKE '%toto%' OR lower(t_PAYEE) LIKE '%toto%' OR lower(t_bookmarked) LIKE '%toto%'))")); SKGTEST(QStringLiteral("STR:searchCriteriasToWhereClause"), SKGServices::searchCriteriasToWhereClause(SKGServices::stringToSearchCriterias(QStringLiteral("i_num:ToTo")), QStringList() << QStringLiteral("d_DATEOP") << QStringLiteral("i_number") << QStringLiteral("t_PAYEE") << QStringLiteral("t_bookmarked"), nullptr), QStringLiteral("((lower(i_number) LIKE '%toto%'))")); SKGTEST(QStringLiteral("STR:searchCriteriasToWhereClause"), SKGServices::searchCriteriasToWhereClause(SKGServices::stringToSearchCriterias(QStringLiteral("i_num=1234")), QStringList() << QStringLiteral("d_DATEOP") << QStringLiteral("i_number") << QStringLiteral("t_PAYEE") << QStringLiteral("t_bookmarked"), nullptr), QStringLiteral("((i_number=1234))")); SKGTEST(QStringLiteral("STR:searchCriteriasToWhereClause"), SKGServices::searchCriteriasToWhereClause(SKGServices::stringToSearchCriterias(QStringLiteral("t_PAYEE>ToTo")), QStringList() << QStringLiteral("d_DATEOP") << QStringLiteral("i_number") << QStringLiteral("t_PAYEE") << QStringLiteral("t_bookmarked"), nullptr), QStringLiteral("((lower(t_PAYEE)>'toto'))")); SKGTEST(QStringLiteral("STR:searchCriteriasToWhereClause"), SKGServices::searchCriteriasToWhereClause(SKGServices::stringToSearchCriterias(QStringLiteral("t_PAYEE=ToTo")), QStringList() << QStringLiteral("d_DATEOP") << QStringLiteral("i_number") << QStringLiteral("t_PAYEE") << QStringLiteral("t_bookmarked"), nullptr), QStringLiteral("((lower(t_PAYEE)>='toto'))")); SKGTEST(QStringLiteral("STR:searchCriteriasToWhereClause"), SKGServices::searchCriteriasToWhereClause(SKGServices::stringToSearchCriterias(QStringLiteral("t_PAYEE<=ToTo")), QStringList() << QStringLiteral("d_DATEOP") << QStringLiteral("i_number") << QStringLiteral("t_PAYEE") << QStringLiteral("t_bookmarked"), nullptr), QStringLiteral("((lower(t_PAYEE)<='toto'))")); SKGTEST(QStringLiteral("STR:searchCriteriasToWhereClause"), SKGServices::searchCriteriasToWhereClause(SKGServices::stringToSearchCriterias(QStringLiteral("t_PAYEE=ToTo")), QStringList() << QStringLiteral("d_DATEOP") << QStringLiteral("i_number") << QStringLiteral("t_PAYEE") << QStringLiteral("t_bookmarked"), nullptr), QStringLiteral("((lower(t_PAYEE)='toto'))")); SKGTEST(QStringLiteral("STR:searchCriteriasToWhereClause"), SKGServices::searchCriteriasToWhereClause(SKGServices::stringToSearchCriterias(QStringLiteral("t_PAYEE#^t[o|a]to$")), QStringList() << QStringLiteral("d_DATEOP") << QStringLiteral("i_number") << QStringLiteral("t_PAYEE") << QStringLiteral("t_bookmarked"), nullptr), QStringLiteral("((REGEXP('^t[o|a]to$',t_PAYEE)))")); SKGTEST(QStringLiteral("STR:searchCriteriasToWhereClause"), SKGServices::searchCriteriasToWhereClause(SKGServices::stringToSearchCriterias(QStringLiteral("+i_number<20 +i_number>30")), QStringList() << QStringLiteral("d_DATEOP") << QStringLiteral("i_number") << QStringLiteral("t_PAYEE") << QStringLiteral("t_bookmarked"), nullptr), QStringLiteral("((i_number>30)) OR ((i_number<20))")); SKGTEST(QStringLiteral("STR:searchCriteriasToWhereClause"), SKGServices::searchCriteriasToWhereClause(SKGServices::stringToSearchCriterias(QStringLiteral("d_DATEOP>2015-05-04")), QStringList() << QStringLiteral("d_DATEOP") << QStringLiteral("i_number") << QStringLiteral("t_PAYEE") << QStringLiteral("t_bookmarked"), nullptr), QStringLiteral("((lower(d_DATEOP)>'2015-05-04'))")); SKGTEST(QStringLiteral("STR:searchCriteriasToWhereClause"), SKGServices::searchCriteriasToWhereClause(SKGServices::stringToSearchCriterias(QStringLiteral("notfound:ToTo")), QStringList() << QStringLiteral("d_DATEOP") << QStringLiteral("i_number") << QStringLiteral("t_PAYEE") << QStringLiteral("t_bookmarked"), nullptr), QStringLiteral("(1=0)")); SKGTEST(QStringLiteral("STR:searchCriteriasToWhereClause"), SKGServices::searchCriteriasToWhereClause(SKGServices::stringToSearchCriterias(QStringLiteral("v1 v2 +v3 -v4 -v5")), QStringList() << QStringLiteral("t_comment"), nullptr), QStringLiteral("((lower(t_comment) LIKE '%v3%')) OR ((lower(t_comment) LIKE '%v1%') AND (lower(t_comment) LIKE '%v2%')) AND NOT((lower(t_comment) LIKE '%v4%')) AND NOT((lower(t_comment) LIKE '%v5%'))")); SKGTEST(QStringLiteral("STR:searchCriteriasToWhereClause"), SKGServices::searchCriteriasToWhereClause(SKGServices::stringToSearchCriterias(QStringLiteral("v1 v2 +v3 -v4 -v5")), QStringList() << QStringLiteral("t_comment"), nullptr, true), QStringLiteral("(((t_comment:v3) and ((t_comment:v1) and (t_comment:v2))) and not (t_comment:v4)) and not (t_comment:v5)")); SKGTEST(QStringLiteral("STR:searchCriteriasToWhereClause"), SKGServices::searchCriteriasToWhereClause(SKGServices::stringToSearchCriterias(QStringLiteral("-v5")), QStringList() << QStringLiteral("t_comment"), nullptr), QStringLiteral("((lower(t_comment) LIKE '%%')) AND NOT((lower(t_comment) LIKE '%v5%'))")); SKGTEST(QStringLiteral("STR:searchCriteriasToWhereClause"), SKGServices::searchCriteriasToWhereClause(SKGServices::stringToSearchCriterias(QStringLiteral("a'b")), QStringList() << QStringLiteral("t_comment"), nullptr), QStringLiteral("((lower(t_comment) LIKE '%a''b%'))")); SKGTEST(QStringLiteral("STR:searchCriteriasToWhereClause"), SKGServices::searchCriteriasToWhereClause(SKGServices::stringToSearchCriterias(QStringLiteral("-v5")), QStringList() << QStringLiteral("t_comment"), nullptr, true), QStringLiteral("(t_comment:) and not (t_comment:v5)")); SKGTEST(QStringLiteral("STR:searchCriteriasToWhereClause"), SKGServices::searchCriteriasToWhereClause(SKGServices::stringToSearchCriterias(QStringLiteral(":ToTo")), QStringList() << QStringLiteral("p_prop1") << QStringLiteral("p_prop2"), nullptr), QStringLiteral("((i_PROPPNAME='prop1' AND (lower(i_PROPVALUE) LIKE '%toto%') OR i_PROPPNAME='prop2' AND (lower(i_PROPVALUE) LIKE '%toto%')))")); SKGTEST(QStringLiteral("STR:searchCriteriasToWhereClause"), SKGServices::searchCriteriasToWhereClause(SKGServices::stringToSearchCriterias(QStringLiteral(":ToTo")), QStringList() << QStringLiteral("p_prop1") << QStringLiteral("p_prop2"), nullptr, true), QStringLiteral("p_prop1:toto or p_prop2:toto")); SKGTEST(QStringLiteral("STR:searchCriteriasToWhereClause"), SKGServices::searchCriteriasToWhereClause(SKGServices::stringToSearchCriterias(QStringLiteral("#ToTo")), QStringList() << QStringLiteral("p_prop1") << QStringLiteral("p_prop2"), nullptr), QStringLiteral("((i_PROPPNAME='prop1' AND REGEXP('toto',i_PROPVALUE) OR i_PROPPNAME='prop2' AND REGEXP('toto',i_PROPVALUE)))")); SKGTEST(QStringLiteral("STR:searchCriteriasToWhereClause"), SKGServices::searchCriteriasToWhereClause(SKGServices::stringToSearchCriterias(QStringLiteral("t_att>10")), QStringList() << QStringLiteral("t_att") << QStringLiteral("t_att1"), nullptr), QStringLiteral("((lower(t_att)>'10' OR lower(t_att1)>'10'))")); SKGTEST(QStringLiteral("STR:searchCriteriasToWhereClause"), SKGServices::searchCriteriasToWhereClause(SKGServices::stringToSearchCriterias(QStringLiteral("t_att.>10")), QStringList() << QStringLiteral("t_att") << QStringLiteral("t_att1"), nullptr), QStringLiteral("((lower(t_att)>'10'))")); SKGTEST(QStringLiteral("STR:searchCriteriasToWhereClause"), SKGServices::searchCriteriasToWhereClause(SKGServices::stringToSearchCriterias(QStringLiteral("t_att.>10")), QStringList() << QStringLiteral("t_att") << QStringLiteral("t_att1"), nullptr, true), QStringLiteral("t_att>10")); } int main(int argc, char** argv) { Q_UNUSED(argc) Q_UNUSED(argv) // Init test SKGINITTEST(true) // Test class SKGError test_errors(nberror, nbcheck, showonlyfailures); // SKGServices { test_getPeriodWhereClause(nberror, nbcheck, showonlyfailures); test_getNeighboringPeriod(nberror, nbcheck, showonlyfailures); test_periodToDate(nberror, nbcheck, showonlyfailures); test_partialStringToDate(nberror, nbcheck, showonlyfailures); test_conversions(nberror, nbcheck, showonlyfailures); test_nbWorkingDays(nberror, nbcheck, showonlyfailures); test_getDateFormat(nberror, nbcheck, showonlyfailures); test_csv(nberror, nbcheck, showonlyfailures); test_stringToSearchCriterias(nberror, nbcheck, showonlyfailures); test_getnext(nberror, nbcheck, showonlyfailures); // Various test SKGStringListList table; table.push_back(QStringList() << QStringLiteral("Person") << QStringLiteral("Salary") << QStringLiteral("Age")); table.push_back(QStringList() << QStringLiteral("John") << QStringLiteral("58000") << QStringLiteral("33")); table.push_back(QStringList() << QStringLiteral("Paul") << QStringLiteral("42000") << QStringLiteral("25")); table.push_back(QStringList() << QStringLiteral("Alan") << QStringLiteral("65000") << QStringLiteral("41")); SKGServices::getBase100Table(table); SKGServices::getPercentTable(table, true, false); SKGServices::getPercentTable(table, false, true); SKGServices::getHistorizedTable(table); SKGTEST(QStringLiteral("STR:encodeForUrl"), SKGServices::encodeForUrl(QStringLiteral("abc")), QStringLiteral("abc")) SKGTEST(QStringLiteral("STR:getMajorVersion"), SKGServices::getMajorVersion(QStringLiteral("4.3.12.3")), QStringLiteral("4.3")) SKGTEST(QStringLiteral("STR:getMajorVersion"), SKGServices::getMajorVersion(QStringLiteral("4.3.12")), QStringLiteral("4.3")) SKGTEST(QStringLiteral("STR:getMajorVersion"), SKGServices::getMajorVersion(QStringLiteral("4.3")), QStringLiteral("4.3")) SKGTEST(QStringLiteral("STR:getMajorVersion"), SKGServices::getMajorVersion(QStringLiteral("4")), QStringLiteral("4")) SKGTEST(QStringLiteral("STR:toCurrencyString"), SKGServices::toCurrencyString(5.12341234, QStringLiteral("F"), 2).remove(' '), QStringLiteral("5.12F")) SKGTEST(QStringLiteral("STR:toCurrencyString"), SKGServices::toCurrencyString(-5.12341234, QStringLiteral("F"), 4).remove(' '), QStringLiteral("-5.1234F")) SKGTEST(QStringLiteral("STR:toPercentageString"), SKGServices::toPercentageString(5.12341234, 2), QStringLiteral("5.12 %")) SKGTEST(QStringLiteral("STR:toPercentageString"), SKGServices::toPercentageString(5.12341234, 4), QStringLiteral("5.1234 %")) QByteArray tmp; SKGTESTERROR(QStringLiteral("STR:downloadToStream"), SKGServices::downloadToStream(QUrl::fromLocalFile(QStringLiteral("notfound")), tmp), false) SKGTEST(QStringLiteral("STR:getFullPathCommandLine"), SKGServices::getFullPathCommandLine(QStringLiteral("skrooge-release.py --help")), QStringLiteral("skrooge-release.py --help")) } // End test SKGENDTEST() }