diff --git a/kmymoney/plugins/qif/config/mymoneyqifprofile.cpp b/kmymoney/plugins/qif/config/mymoneyqifprofile.cpp index c04b216d7..c6269ca1f 100644 --- a/kmymoney/plugins/qif/config/mymoneyqifprofile.cpp +++ b/kmymoney/plugins/qif/config/mymoneyqifprofile.cpp @@ -1,1003 +1,1003 @@ /*************************************************************************** mymoneyqifprofile.cpp - description ------------------- begin : Tue Dec 24 2002 copyright : (C) 2002 by Thomas Baumgart email : thb@net-bembel.de ***************************************************************************/ /*************************************************************************** * * * 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. * * * ***************************************************************************/ #include "mymoneyqifprofile.h" // ---------------------------------------------------------------------------- // QT Includes #include #include #include #include // ---------------------------------------------------------------------------- // KDE Includes #include #include #include // ---------------------------------------------------------------------------- // Project Includes #include "mymoneyexception.h" #include "mymoneymoney.h" #include "mymoneyenums.h" /* * CENTURY_BREAK is used to identfy the century for a two digit year * * if yr is < CENTURY_BREAK it is in 2000 * if yr is >= CENTURY_BREAK it is in 1900 * * so with CENTURY_BREAK being 70 the following will happen: * * 00..69 -> 2000..2069 * 70..99 -> 1970..1999 */ const int CENTURY_BREAK = 70; class MyMoneyQifProfile::Private { public: Private() : m_changeCount(3, 0), m_lastValue(3, 0), m_largestValue(3, 0) { } void getThirdPosition(); void dissectDate(QVector& parts, const QString& txt) const; QVector m_changeCount; QVector m_lastValue; QVector m_largestValue; QMap m_partPos; }; void MyMoneyQifProfile::Private::dissectDate(QVector& parts, const QString& txt) const { QRegExp nonDelimChars("[ 0-9a-zA-Z]"); int part = 0; // the current part we scan int pos; // the current scan position int maxPartSize = txt.length() > 6 ? 4 : 2; // the maximum size of a part // some fu... up MS-Money versions write two delimiter in a row // so we need to keep track of them. Example: D14/12/'08 bool lastWasDelim = false; // separate the parts of the date and keep the locations of the delimiters for (pos = 0; pos < txt.length() && part < 3; ++pos) { if (nonDelimChars.indexIn(txt[pos]) == -1) { if (!lastWasDelim) { ++part; maxPartSize = 0; // make sure to pick the right one depending if next char is numeric or not lastWasDelim = true; } } else { lastWasDelim = false; // check if the part is over and we did not see a delimiter if ((maxPartSize != 0) && (parts[part].length() == maxPartSize)) { ++part; maxPartSize = 0; } if (maxPartSize == 0) { maxPartSize = txt[pos].isDigit() ? 2 : 3; if (part == 2) maxPartSize = 4; } if (part < 3) parts[part] += txt[pos]; } } if (part == 3) { // invalid date for (int i = 0; i < 3; ++i) { parts[i] = '0'; } } } void MyMoneyQifProfile::Private::getThirdPosition() { // if we have detected two parts we can calculate the third and its position if (m_partPos.count() == 2) { QList partsPresent = m_partPos.keys(); QStringList partsAvail = QString("d,m,y").split(','); int missingIndex = -1; int value = 0; for (int i = 0; i < 3; ++i) { if (!partsPresent.contains(partsAvail[i][0])) { missingIndex = i; } else { value += m_partPos[partsAvail[i][0]]; } } m_partPos[partsAvail[missingIndex][0]] = 3 - value; } } MyMoneyQifProfile::MyMoneyQifProfile() : d(new Private), m_isDirty(false) { clear(); } MyMoneyQifProfile::MyMoneyQifProfile(const QString& name) : d(new Private), m_isDirty(false) { loadProfile(name); } MyMoneyQifProfile::~MyMoneyQifProfile() { delete d; } void MyMoneyQifProfile::clear() { m_dateFormat = "%d.%m.%yyyy"; m_apostropheFormat = "2000-2099"; m_valueMode = ""; m_filterScriptImport = ""; m_filterScriptExport = ""; - m_filterFileType = "*.qif"; + m_filterFileType = "*.qif *.QIF"; m_decimal.clear(); m_decimal['$'] = m_decimal['Q'] = m_decimal['T'] = m_decimal['O'] = m_decimal['I'] = QLocale().decimalPoint(); m_thousands.clear(); m_thousands['$'] = m_thousands['Q'] = m_thousands['T'] = m_thousands['O'] = m_thousands['I'] = QLocale().groupSeparator(); m_openingBalanceText = "Opening Balance"; m_voidMark = "VOID "; m_accountDelimiter = '['; m_profileName = ""; m_profileDescription = ""; m_profileType = "Bank"; m_attemptMatchDuplicates = true; } void MyMoneyQifProfile::loadProfile(const QString& name) { KSharedConfigPtr config = KSharedConfig::openConfig(); KConfigGroup grp = config->group(name); clear(); m_profileName = name; m_profileDescription = grp.readEntry("Description", m_profileDescription); m_profileType = grp.readEntry("Type", m_profileType); m_dateFormat = grp.readEntry("DateFormat", m_dateFormat); m_apostropheFormat = grp.readEntry("ApostropheFormat", m_apostropheFormat); m_accountDelimiter = grp.readEntry("AccountDelimiter", m_accountDelimiter); m_openingBalanceText = grp.readEntry("OpeningBalance", m_openingBalanceText); m_voidMark = grp.readEntry("VoidMark", m_voidMark); m_filterScriptImport = grp.readEntry("FilterScriptImport", m_filterScriptImport); m_filterScriptExport = grp.readEntry("FilterScriptExport", m_filterScriptExport); m_filterFileType = grp.readEntry("FilterFileType", m_filterFileType); m_attemptMatchDuplicates = grp.readEntry("AttemptMatchDuplicates", m_attemptMatchDuplicates); // make sure, we remove any old stuff for now grp.deleteEntry("FilterScript"); QString tmp = QString(m_decimal['Q']) + m_decimal['T'] + m_decimal['I'] + m_decimal['$'] + m_decimal['O']; tmp = grp.readEntry("Decimal", tmp); m_decimal['Q'] = tmp[0]; m_decimal['T'] = tmp[1]; m_decimal['I'] = tmp[2]; m_decimal['$'] = tmp[3]; m_decimal['O'] = tmp[4]; tmp = QString(m_thousands['Q']) + m_thousands['T'] + m_thousands['I'] + m_thousands['$'] + m_thousands['O']; tmp = grp.readEntry("Thousand", tmp); m_thousands['Q'] = tmp[0]; m_thousands['T'] = tmp[1]; m_thousands['I'] = tmp[2]; m_thousands['$'] = tmp[3]; m_thousands['O'] = tmp[4]; m_isDirty = false; } void MyMoneyQifProfile::saveProfile() { if (m_isDirty == true) { KSharedConfigPtr config = KSharedConfig::openConfig(); KConfigGroup grp = config->group(m_profileName); grp.writeEntry("Description", m_profileDescription); grp.writeEntry("Type", m_profileType); grp.writeEntry("DateFormat", m_dateFormat); grp.writeEntry("ApostropheFormat", m_apostropheFormat); grp.writeEntry("AccountDelimiter", m_accountDelimiter); grp.writeEntry("OpeningBalance", m_openingBalanceText); grp.writeEntry("VoidMark", m_voidMark); grp.writeEntry("FilterScriptImport", m_filterScriptImport); grp.writeEntry("FilterScriptExport", m_filterScriptExport); grp.writeEntry("FilterFileType", m_filterFileType); grp.writeEntry("AttemptMatchDuplicates", m_attemptMatchDuplicates); QString tmp; tmp = QString(m_decimal['Q']) + m_decimal['T'] + m_decimal['I'] + m_decimal['$'] + m_decimal['O']; grp.writeEntry("Decimal", tmp); tmp = QString(m_thousands['Q']) + m_thousands['T'] + m_thousands['I'] + m_thousands['$'] + m_thousands['O']; grp.writeEntry("Thousand", tmp); } m_isDirty = false; } void MyMoneyQifProfile::setProfileName(const QString& name) { if (m_profileName != name) m_isDirty = true; m_profileName = name; } void MyMoneyQifProfile::setProfileDescription(const QString& desc) { if (m_profileDescription != desc) m_isDirty = true; m_profileDescription = desc; } void MyMoneyQifProfile::setProfileType(const QString& type) { if (m_profileType != type) m_isDirty = true; m_profileType = type; } void MyMoneyQifProfile::setOutputDateFormat(const QString& dateFormat) { if (m_dateFormat != dateFormat) m_isDirty = true; m_dateFormat = dateFormat; } void MyMoneyQifProfile::setInputDateFormat(const QString& dateFormat) { int j = -1; if (dateFormat.length() > 0) { for (int i = 0; i < dateFormat.length() - 1; ++i) { if (dateFormat[i] == '%') { d->m_partPos[dateFormat[++i]] = ++j; } } } } void MyMoneyQifProfile::setApostropheFormat(const QString& apostropheFormat) { if (m_apostropheFormat != apostropheFormat) m_isDirty = true; m_apostropheFormat = apostropheFormat; } void MyMoneyQifProfile::setAmountDecimal(const QChar& def, const QChar& chr) { QChar ch(chr); if (ch == QChar()) ch = ' '; if (m_decimal[def] != ch) m_isDirty = true; m_decimal[def] = ch; } void MyMoneyQifProfile::setAmountThousands(const QChar& def, const QChar& chr) { QChar ch(chr); if (ch == QChar()) ch = ' '; if (m_thousands[def] != ch) m_isDirty = true; m_thousands[def] = ch; } const QChar MyMoneyQifProfile::amountDecimal(const QChar& def) const { QChar chr = m_decimal[def]; return chr; } const QChar MyMoneyQifProfile::amountThousands(const QChar& def) const { QChar chr = m_thousands[def]; return chr; } void MyMoneyQifProfile::setAccountDelimiter(const QString& delim) { QString txt(delim); if (txt.isEmpty()) txt = ' '; else if (txt[0] != '[') txt = '['; if (m_accountDelimiter[0] != txt[0]) m_isDirty = true; m_accountDelimiter = txt[0]; } void MyMoneyQifProfile::setOpeningBalanceText(const QString& txt) { if (m_openingBalanceText != txt) m_isDirty = true; m_openingBalanceText = txt; } void MyMoneyQifProfile::setVoidMark(const QString& txt) { if (m_voidMark != txt) m_isDirty = true; m_voidMark = txt; } const QString MyMoneyQifProfile::accountDelimiter() const { QString rc; if (m_accountDelimiter[0] == ' ') rc = ' '; else rc = "[]"; return rc; } const QString MyMoneyQifProfile::date(const QDate& datein) const { QString::const_iterator format = m_dateFormat.begin();; QString buffer; QChar delim; int maskLen; QChar maskChar; while (format != m_dateFormat.end()) { if (*format == '%') { maskLen = 0; maskChar = *(++format); while ((format != m_dateFormat.end()) && (*format == maskChar)) { ++maskLen; ++format; } if (maskChar == 'd') { if (! delim.isNull()) buffer += delim; buffer += QString::number(datein.day()).rightJustified(2, '0'); } else if (maskChar == 'm') { if (! delim.isNull()) buffer += delim; if (maskLen == 3) buffer += QLocale().monthName(datein.month(), QLocale::ShortFormat); else buffer += QString::number(datein.month()).rightJustified(2, '0'); } else if (maskChar == 'y') { if (maskLen == 2) { buffer += twoDigitYear(delim, datein.year()); } else { if (! delim.isNull()) buffer += delim; buffer += QString::number(datein.year()); } break; } else { throw MYMONEYEXCEPTION_CSTRING("Invalid char in QifProfile date field"); } delim = 0; } else { if (! delim.isNull()) buffer += delim; delim = *format++; } } return buffer; } const QDate MyMoneyQifProfile::date(const QString& datein) const { // in case we don't know the format, we return an invalid date if (d->m_partPos.count() != 3) return QDate(); QVector scannedParts(3); d->dissectDate(scannedParts, datein); int yr, mon, day; bool ok; yr = scannedParts[d->m_partPos['y']].toInt(); mon = scannedParts[d->m_partPos['m']].toInt(&ok); if (!ok) { QStringList monthNames = QString("jan,feb,mar,apr,may,jun,jul,aug,sep,oct,nov,dec").split(','); int j; for (j = 1; j <= 12; ++j) { if ((QLocale().monthName(j, QLocale::ShortFormat).toLower() == scannedParts[d->m_partPos['m']].toLower()) || (monthNames[j-1] == scannedParts[d->m_partPos['m']].toLower())) { mon = j; break; } } if (j == 13) { qWarning("Unknown month '%s'", qPrintable(scannedParts[d->m_partPos['m']])); return QDate(); } } day = scannedParts[d->m_partPos['d']].toInt(); if (yr < 100) { // two digit year information? if (yr < CENTURY_BREAK) // less than the CENTURY_BREAK we assume this century yr += 2000; else yr += 1900; } return QDate(yr, mon, day); #if 0 QString scannedDelim[2]; QString formatParts[3]; QString formatDelim[2]; int part; int delim; unsigned int i, j; part = -1; delim = 0; for (i = 0; i < m_dateFormat.length(); ++i) { if (m_dateFormat[i] == '%') { ++part; if (part == 3) { qWarning("MyMoneyQifProfile::date(const QString& datein) Too many parts in date format"); return QDate(); } ++i; } switch (m_dateFormat[i].toLatin1()) { case 'm': case 'd': case 'y': formatParts[part] += m_dateFormat[i]; break; case '/': case '-': case '.': case '\'': if (delim == 2) { qWarning("MyMoneyQifProfile::date(const QString& datein) Too many delimiters in date format"); return QDate(); } formatDelim[delim] = m_dateFormat[i]; ++delim; break; default: qWarning("MyMoneyQifProfile::date(const QString& datein) Invalid char in date format"); return QDate(); } } part = 0; delim = 0; bool prevWasChar = false; for (i = 0; i < datein.length(); ++i) { switch (datein[i].toLatin1()) { case '/': case '.': case '-': case '\'': if (delim == 2) { qWarning("MyMoneyQifProfile::date(const QString& datein) Too many delimiters in date field"); return QDate(); } scannedDelim[delim] = datein[i]; ++delim; ++part; prevWasChar = false; break; default: if (prevWasChar && datein[i].isDigit()) { ++part; prevWasChar = false; } if (datein[i].isLetter()) prevWasChar = true; // replace blank with 0 scannedParts[part] += (datein[i] == ' ') ? QChar('0') : datein[i]; break; } } int day = 1, mon = 1, yr = 1900; bool ok = false; for (i = 0; i < 2; ++i) { if (scannedDelim[i] != formatDelim[i] && scannedDelim[i] != QChar('\'')) { qWarning("MyMoneyQifProfile::date(const QString& datein) Invalid delimiter '%s' when '%s' was expected", scannedDelim[i].toLatin1(), formatDelim[i].toLatin1()); return QDate(); } } QString msg; for (i = 0; i < 3; ++i) { switch (formatParts[i][0].toLatin1()) { case 'd': day = scannedParts[i].toUInt(&ok); if (!ok) msg = "Invalid numeric character in day string"; break; case 'm': if (formatParts[i].length() != 3) { mon = scannedParts[i].toUInt(&ok); if (!ok) msg = "Invalid numeric character in month string"; } else { for (j = 1; j <= 12; ++j) { if (QLocale().monthName(j, 2000, true).toLower() == formatParts[i].toLower()) { mon = j; ok = true; break; } } if (j == 13) { msg = "Unknown month '" + scannedParts[i] + "'"; } } break; case 'y': ok = false; if (scannedParts[i].length() == formatParts[i].length()) { yr = scannedParts[i].toUInt(&ok); if (!ok) msg = "Invalid numeric character in month string"; if (yr < 100) { // two digit year info if (i > 1) { ok = true; if (scannedDelim[i-1] == QChar('\'')) { if (m_apostropheFormat == "1900-1949") { if (yr < 50) yr += 1900; else yr += 2000; } else if (m_apostropheFormat == "1900-1999") { yr += 1900; } else if (m_apostropheFormat == "2000-2099") { yr += 2000; } else { msg = "Unsupported apostropheFormat!"; ok = false; } } else { if (m_apostropheFormat == "1900-1949") { if (yr < 50) yr += 2000; else yr += 1900; } else if (m_apostropheFormat == "1900-1999") { yr += 2000; } else if (m_apostropheFormat == "2000-2099") { yr += 1900; } else { msg = "Unsupported apostropheFormat!"; ok = false; } } } else { msg = "Year as first parameter is not supported!"; } } else if (yr < 1900) { msg = "Year not in range < 100 or >= 1900!"; } else { ok = true; } } else { msg = QString("Length of year (%1) does not match expected length (%2).") .arg(scannedParts[i].length()).arg(formatParts[i].length()); } break; } if (!msg.isEmpty()) { qWarning("MyMoneyQifProfile::date(const QString& datein) %s", msg.toLatin1()); return QDate(); } } return QDate(yr, mon, day); #endif } const QString MyMoneyQifProfile::twoDigitYear(const QChar& delim, int yr) const { QChar realDelim = delim; QString buffer; if (!delim.isNull()) { if ((m_apostropheFormat == "1900-1949" && yr <= 1949) || (m_apostropheFormat == "1900-1999" && yr <= 1999) || (m_apostropheFormat == "2000-2099" && yr >= 2000)) realDelim = '\''; buffer += realDelim; } yr -= 1900; if (yr > 100) yr -= 100; if (yr < 10) buffer += '0'; buffer += QString::number(yr); return buffer; } const QString MyMoneyQifProfile::value(const QChar& def, const MyMoneyMoney& valuein) const { QChar _decimalSeparator; QChar _thousandsSeparator; QString res; _decimalSeparator = MyMoneyMoney::decimalSeparator(); _thousandsSeparator = MyMoneyMoney::thousandSeparator(); eMyMoney::Money::signPosition _signPosition = MyMoneyMoney::negativeMonetarySignPosition(); MyMoneyMoney::setDecimalSeparator(amountDecimal(def).toLatin1()); MyMoneyMoney::setThousandSeparator(amountThousands(def).toLatin1()); MyMoneyMoney::setNegativeMonetarySignPosition(eMyMoney::Money::BeforeQuantityMoney); res = valuein.formatMoney("", 2); MyMoneyMoney::setDecimalSeparator(_decimalSeparator); MyMoneyMoney::setThousandSeparator(_thousandsSeparator); MyMoneyMoney::setNegativeMonetarySignPosition(_signPosition); return res; } const MyMoneyMoney MyMoneyQifProfile::value(const QChar& def, const QString& valuein) const { QChar _decimalSeparator; QChar _thousandsSeparator; MyMoneyMoney res; _decimalSeparator = MyMoneyMoney::decimalSeparator(); _thousandsSeparator = MyMoneyMoney::thousandSeparator(); eMyMoney::Money::signPosition _signPosition = MyMoneyMoney::negativeMonetarySignPosition(); MyMoneyMoney::setDecimalSeparator(amountDecimal(def).toLatin1()); MyMoneyMoney::setThousandSeparator(amountThousands(def).toLatin1()); MyMoneyMoney::setNegativeMonetarySignPosition(eMyMoney::Money::BeforeQuantityMoney); res = MyMoneyMoney(valuein); MyMoneyMoney::setDecimalSeparator(_decimalSeparator); MyMoneyMoney::setThousandSeparator(_thousandsSeparator); MyMoneyMoney::setNegativeMonetarySignPosition(_signPosition); return res; } void MyMoneyQifProfile::setFilterScriptImport(const QString& script) { if (m_filterScriptImport != script) m_isDirty = true; m_filterScriptImport = script; } void MyMoneyQifProfile::setFilterScriptExport(const QString& script) { if (m_filterScriptExport != script) m_isDirty = true; m_filterScriptExport = script; } void MyMoneyQifProfile::setFilterFileType(const QString& txt) { if (m_filterFileType != txt) m_isDirty = true; m_filterFileType = txt; } void MyMoneyQifProfile::setAttemptMatchDuplicates(bool f) { if (m_attemptMatchDuplicates != f) m_isDirty = true; m_attemptMatchDuplicates = f; } const QString MyMoneyQifProfile::inputDateFormat() const { QStringList list; possibleDateFormats(list); if (list.count() == 1) return list.first(); return QString(); } void MyMoneyQifProfile::possibleDateFormats(QStringList& list) const { QStringList defaultList = QString("y,m,d:y,d,m:m,d,y:m,y,d:d,m,y:d,y,m").split(':'); list.clear(); QStringList::const_iterator it_d; for (it_d = defaultList.constBegin(); it_d != defaultList.constEnd(); ++it_d) { const QStringList parts = (*it_d).split(',', QString::SkipEmptyParts); int i; for (i = 0; i < 3; ++i) { if (d->m_partPos.contains(parts[i][0])) { if (d->m_partPos[parts[i][0]] != i) break; } // months can't be larger than 12 if (parts[i] == "m" && d->m_largestValue[i] > 12) break; // days can't be larger than 31 if (parts[i] == "d" && d->m_largestValue[i] > 31) break; } // matches all tests if (i == 3) { QString format = *it_d; format.replace('y', "%y"); format.replace('m', "%m"); format.replace('d', "%d"); format.replace(',', " "); list << format; } } // if we haven't found any, then there's something wrong. // in this case, we present the full list and let the user decide if (list.count() == 0) { for (it_d = defaultList.constBegin(); it_d != defaultList.constEnd(); ++it_d) { QString format = *it_d; format.replace('y', "%y"); format.replace('m', "%m"); format.replace('d', "%d"); format.replace(',', " "); list << format; } } } void MyMoneyQifProfile::autoDetect(const QStringList& lines) { m_dateFormat.clear(); m_decimal.clear(); m_thousands.clear(); QString numericRecords = "BT$OIQ"; QStringList::const_iterator it; int datesScanned = 0; // section: used to switch between different QIF sections, // because the Record identifiers are ambigous between sections // eg. in transaction records, T identifies a total amount, in // account sections it's the type. // // 0 - unknown // 1 - account // 2 - transactions // 3 - prices int section = 0; QRegExp price("\"(.*)\",(.*),\"(.*)\""); for (it = lines.begin(); it != lines.end(); ++it) { QChar c((*it)[0]); if (c == '!') { QString sname = (*it).toLower(); if (!sname.startsWith(QLatin1String("!option:"))) { section = 0; if (sname.startsWith(QLatin1String("!account"))) section = 1; else if (sname.startsWith(QLatin1String("!type"))) { if (sname.startsWith(QLatin1String("!type:cat")) || sname.startsWith(QLatin1String("!type:payee")) || sname.startsWith(QLatin1String("!type:security")) || sname.startsWith(QLatin1String("!type:class"))) { section = 0; } else if (sname.startsWith(QLatin1String("!type:price"))) { section = 3; } else section = 2; } } } switch (section) { case 1: if (c == 'B') { scanNumeric((*it).mid(1), m_decimal[c], m_thousands[c]); } break; case 2: if (numericRecords.contains(c)) { scanNumeric((*it).mid(1), m_decimal[c], m_thousands[c]); } else if ((c == 'D') && (m_dateFormat.isEmpty())) { if (d->m_partPos.count() != 3) { scanDate((*it).mid(1)); ++datesScanned; if (d->m_partPos.count() == 2) { // if we have detected two parts we can calculate the third and its position d->getThirdPosition(); } } } break; case 3: if (price.indexIn(*it) != -1) { scanNumeric(price.cap(2), m_decimal['P'], m_thousands['P']); scanDate(price.cap(3)); ++datesScanned; } break; } } // the following algorithm is only applied if we have more // than 20 dates found. Smaller numbers have shown that the // results are inaccurate which leads to a reduced number of // date formats presented to choose from. if (d->m_partPos.count() != 3 && datesScanned > 20) { QMap sortedPos; // make sure to reset the known parts for the following algorithm if (d->m_partPos.contains('y')) { d->m_changeCount[d->m_partPos['y']] = -1; for (int i = 0; i < 3; ++i) { if (d->m_partPos['y'] == i) continue; // can we say for sure that we hit the day field? if (d->m_largestValue[i] > 12) { d->m_partPos['d'] = i; } } } if (d->m_partPos.contains('d')) d->m_changeCount[d->m_partPos['d']] = -1; if (d->m_partPos.contains('m')) d->m_changeCount[d->m_partPos['m']] = -1; for (int i = 0; i < 3; ++i) { if (d->m_changeCount[i] != -1) { sortedPos[d->m_changeCount[i]] = i; } } QMap::const_iterator it_a; QMap::const_iterator it_b; switch (sortedPos.count()) { case 1: // all the same // let the user decide, we can't figure it out break; case 2: // two are the same, we treat the largest as the day // if it's 20% larger than the other one and let the // user pick the other two { it_b = sortedPos.constBegin(); it_a = it_b; ++it_b; double a = d->m_changeCount[*it_a]; double b = d->m_changeCount[*it_b]; if (b > (a * 1.2)) { d->m_partPos['d'] = *it_b; } } break; case 3: // three different, we check if they are 20% apart each it_b = sortedPos.constBegin(); for (int i = 0; i < 2; ++i) { it_a = it_b; ++it_b; double a = d->m_changeCount[*it_a]; double b = d->m_changeCount[*it_b]; if (b > (a * 1.2)) { switch (i) { case 0: d->m_partPos['y'] = *it_a; break; case 1: d->m_partPos['d'] = *it_b; break; } } } break; } // extract the last if necessary and possible date position d->getThirdPosition(); } } void MyMoneyQifProfile::scanNumeric(const QString& txt, QChar& decimal, QChar& thousands) const { QChar first, second; QRegExp numericChars("[0-9-()]"); for (int i = 0; i < txt.length(); ++i) { const QChar& c = txt[i]; if (numericChars.indexIn(c) == -1) { if (c == '.' || c == ',') { first = second; second = c; } } } if (!second.isNull()) decimal = second; if (!first.isNull()) thousands = first; } void MyMoneyQifProfile::scanDate(const QString& txt) const { // extract the parts from the txt QVector parts(3); // the various parts of the date d->dissectDate(parts, txt); // now analyze the parts for (int i = 0; i < 3; ++i) { bool ok; int value = parts[i].toInt(&ok); if (!ok) { // this should happen only if the part is non-numeric -> month d->m_partPos['m'] = i; } else if (value != 0) { if (value != d->m_lastValue[i]) { d->m_changeCount[i]++; d->m_lastValue[i] = value; if (value > d->m_largestValue[i]) d->m_largestValue[i] = value; } // if it's > 31 it can only be years if (value > 31) { d->m_partPos['y'] = i; } // and if it's in between 12 and 32 and we already identified the // position for the year it must be days if ((value > 12) && (value < 32) && d->m_partPos.contains('y')) { d->m_partPos['d'] = i; } } } } diff --git a/kmymoney/plugins/qif/import/kimportdlg.cpp b/kmymoney/plugins/qif/import/kimportdlg.cpp index 5d45ee476..5e7429190 100644 --- a/kmymoney/plugins/qif/import/kimportdlg.cpp +++ b/kmymoney/plugins/qif/import/kimportdlg.cpp @@ -1,206 +1,204 @@ /*************************************************************************** kimportdlg.cpp - description ------------------- begin : Wed May 16 2001 copyright : (C) 2001 by Michael Edwardes email : mte@users.sourceforge.net Javier Campos Morales Felix Rodriguez Thomas Baumgart ***************************************************************************/ /*************************************************************************** * * * 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. * * * ***************************************************************************/ #include "kimportdlg.h" // ---------------------------------------------------------------------------- // QT Headers #include #include #include #include #include #include // ---------------------------------------------------------------------------- // KDE Headers #include #include #include #include #include #include #include // ---------------------------------------------------------------------------- // Project Headers #include "kmymoneyutils.h" #include "mymoneyfile.h" #include "mymoneyaccount.h" #include "../config/mymoneyqifprofile.h" #include using namespace Icons; KImportDlg::KImportDlg(QWidget *parent) : KImportDlgDecl(parent) { // Set all the last used options readConfig(); loadProfiles(true); // load button icons KGuiItem okButtenItem(i18n("&Import"), Icons::get(Icon::DocumentImport), i18n("Start operation"), i18n("Use this to start the import operation")); KGuiItem::assign(m_buttonBox->button(QDialogButtonBox::Ok), okButtenItem); KGuiItem browseButtenItem(i18n("&Browse..."), Icons::get(Icon::DocumentOpen), i18n("Select filename"), i18n("Use this to select a filename to export to")); KGuiItem::assign(m_qbuttonBrowse, browseButtenItem); KGuiItem newButtenItem(i18nc("New profile", "&New..."), Icons::get(Icon::DocumentNew), i18n("Create a new profile"), i18n("Use this to open the profile editor")); // connect the buttons to their functionality - connect(m_qbuttonBrowse, SIGNAL(clicked()), this, SLOT(slotBrowse())); - connect(m_buttonBox, SIGNAL(accepted()), this, SLOT(slotOkClicked())); - connect(m_buttonBox, SIGNAL(rejected()), this, SLOT(reject())); + connect(m_qbuttonBrowse, &QPushButton::clicked, this, &KImportDlg::slotBrowse); + connect(m_buttonBox, &QDialogButtonBox::accepted, this, &KImportDlg::slotOkClicked); + connect(m_buttonBox, &QDialogButtonBox::rejected, this, &KImportDlg::reject); // connect the change signals to the check slot and perform initial check - connect(m_qlineeditFile, SIGNAL(textChanged(QString)), this, - SLOT(slotFileTextChanged(QString))); + connect(m_qlineeditFile, &KLineEdit::textChanged, this, &KImportDlg::slotFileTextChanged); // setup button enable status slotFileTextChanged(m_qlineeditFile->text()); } KImportDlg::~KImportDlg() { } void KImportDlg::slotBrowse() { // determine what the browse prefix should be from the current profile MyMoneyQifProfile tmpprofile; tmpprofile.loadProfile("Profile-" + profile()); - - QUrl file = QFileDialog::getOpenFileUrl(this, i18n("Import File..."), QUrl("kfiledialog:///kmymoney-import"), - i18n("Import files (%1);;All files (%2)", tmpprofile.filterFileType(), "*") - ); + QUrl file = QFileDialog::getOpenFileUrl(this, + i18n("Import File..."), + QUrl::fromLocalFile(m_qlineeditFile->text()), + i18n("Import files (%1);;All files (%2)", tmpprofile.filterFileType(), "*")); if (!file.isEmpty()) { m_qlineeditFile->setText(file.toDisplayString(QUrl::PreferLocalFile)); } } void KImportDlg::slotOkClicked() { // Save the used options. writeConfig(); // leave dialog directly accept(); } void KImportDlg::readConfig() { KSharedConfigPtr kconfig = KSharedConfig::openConfig(); KConfigGroup kgrp = kconfig->group("Last Use Settings"); m_qlineeditFile->setText(kgrp.readEntry("KImportDlg_LastFile")); - } void KImportDlg::writeConfig() { KSharedConfigPtr kconfig = KSharedConfig::openConfig(); KConfigGroup grp = kconfig->group("Last Use Settings"); grp.writeEntry("KImportDlg_LastFile", m_qlineeditFile->text()); grp.writeEntry("KImportDlg_LastProfile", m_profileComboBox->currentText()); kconfig->sync(); } /** Make sure the text input is ok */ void KImportDlg::slotFileTextChanged(const QString& text) { bool fileExists = false; if (file().isValid()) { Q_CONSTEXPR short int detailLevel = 0; // it's a file or a directory or a symlink, or it doesn't exist KIO::StatJob* statjob = KIO::stat(file(), KIO::StatJob::SourceSide, detailLevel); bool noerror = statjob->exec(); if (noerror) { // We want a file fileExists = !statjob->statResult().isDir(); } } if (!text.isEmpty() && fileExists) { // m_qcomboboxDateFormat->setEnabled(true); m_buttonBox->button(QDialogButtonBox::Ok)->setEnabled(true); m_qlineeditFile->setText(text); } else { // m_qcomboboxDateFormat->setEnabled(false); m_buttonBox->button(QDialogButtonBox::Ok)->setEnabled(false); } } void KImportDlg::loadProfiles(const bool selectLast) { QString current = m_profileComboBox->currentText(); m_profileComboBox->clear(); QStringList list; KSharedConfigPtr config = KSharedConfig::openConfig(); KConfigGroup grp = config->group("Profiles"); list = grp.readEntry("profiles", QStringList()); list.sort(); m_profileComboBox->addItems(list); if (selectLast == true) { config->group("Last Use Settings"); current = grp.readEntry("KImportDlg_LastProfile"); } int index = m_profileComboBox->findText(current, Qt::MatchExactly); if (index > -1) { m_profileComboBox->setCurrentIndex(index); } else { m_profileComboBox->setCurrentIndex(0); } } void KImportDlg::addCategories(QStringList& strList, const QString& id, const QString& leadIn) const { MyMoneyFile *file = MyMoneyFile::instance(); QString name; MyMoneyAccount account = file->account(id); QStringList accList = account.accountList(); QStringList::ConstIterator it_a; for (it_a = accList.constBegin(); it_a != accList.constEnd(); ++it_a) { account = file->account(*it_a); strList << leadIn + account.name(); addCategories(strList, *it_a, leadIn + account.name() + MyMoneyFile::AccountSeparator); } }