xea2kmt.cpp 21.6 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
/***************************************************************************
                          xea2kmt.cpp
                          -------------------
    copyright            : (C) 2014 by Ralf Habacker <ralf.habacker@freenet.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.                                   *
 *                                                                         *
 ***************************************************************************/

17
18
#include "../kmymoney/mymoney/mymoneyaccount.h"

19
#include <QDir>
20
21
#include <QFile>
#include <QStringList>
22
#include <QMap>
23
24
#include <QTextStream>
#include <QXmlStreamReader>
Łukasz Wojniłowicz's avatar
Łukasz Wojniłowicz committed
25
#include <QDebug>
26

27
28
29
#include "mymoneyenums.h"

using namespace eMyMoney;
30
31
32
33
34
35
36
37
38
39

QDebug operator <<(QDebug out, const QXmlStreamNamespaceDeclaration &a)
{
    out << "QXmlStreamNamespaceDeclaration("
        << "prefix:" << a.prefix().toString()
        << "namespaceuri:" << a.namespaceUri().toString()
        << ")";
    return out;
}

40
41
42
43
44
45
46
47
48
49
50
QDebug operator <<(QDebug out, const QXmlStreamAttribute &a)
{
    out << "QXmlStreamAttribute("
        << "prefix:" << a.prefix().toString()
        << "namespaceuri:" << a.namespaceUri().toString()
        << "name:" << a.name().toString()
        << " value:" << a.value().toString()
        << ")";
    return out;
}

51
static bool debug = false;
52
static bool verbose = false;
53
54
55
56
static bool withID = false;
static bool noLevel1Names = false;
static bool withTax = false;
static bool prefixNameWithCode = false;
Ralf Habacker's avatar
Ralf Habacker committed
57

58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
typedef QMap<QString,QString> DirNameMapType;

/**
 * map to hold differences from gnucash to kmymoney template directory
 * @return directory name map
 */
DirNameMapType &getDirNameMap()
{
    static DirNameMapType dirNameMap;
    dirNameMap["cs"] = "cs_CZ";
    dirNameMap["da"] = "dk";
    dirNameMap["ja"] = "ja_JP";
    dirNameMap["ko"] = "ko_KR";
    dirNameMap["nb"] = "nb_NO";
    dirNameMap["nl"] = "nl_NL";
    dirNameMap["ru"] = "ru_RU";
    return dirNameMap;
}

Ralf Habacker's avatar
Ralf Habacker committed
77
78
int toKMyMoneyAccountType(const QString &type)
{
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
    if(type == "ROOT")              return (int)Account::Type::Unknown;
    else if (type == "BANK")        return (int)Account::Type::Checkings;
    else if (type == "CASH")        return (int)Account::Type::Cash;
    else if (type == "CREDIT")      return (int)Account::Type::CreditCard;
    else if (type == "INVEST")      return (int)Account::Type::Investment;
    else if (type == "RECEIVABLE")  return (int)Account::Type::Asset;
    else if (type == "ASSET")       return (int)Account::Type::Asset;
    else if (type == "PAYABLE")     return (int)Account::Type::Liability;
    else if (type == "LIABILITY")   return (int)Account::Type::Liability;
    else if (type == "CURRENCY")    return (int)Account::Type::Currency;
    else if (type == "INCOME")      return (int)Account::Type::Income;
    else if (type == "EXPENSE")     return (int)Account::Type::Expense;
    else if (type == "STOCK")       return (int)Account::Type::Stock;
    else if (type == "MUTUAL")      return (int)Account::Type::Stock;
    else if (type == "EQUITY")      return (int)Account::Type::Equity;
Ralf Habacker's avatar
Ralf Habacker committed
94
95
96
    else return 99; // unknown
}

97
98
class TemplateAccount {
public:
Ralf Habacker's avatar
Ralf Habacker committed
99
100
    typedef QList<TemplateAccount> List;
    typedef QList<TemplateAccount*> PointerList;
101
    typedef QMap<QString,QString> SlotList;
Ralf Habacker's avatar
Ralf Habacker committed
102

103
    QString id;
Łukasz Wojniłowicz's avatar
Łukasz Wojniłowicz committed
104
105
    QString m_type;
    QString m_name;
106
107
    QString code;
    QString parent;
108
    SlotList slotList;
109
110
111
112
113
114
115

    TemplateAccount()
    {
    }

    TemplateAccount(const TemplateAccount &b)
      : id(b.id),
Łukasz Wojniłowicz's avatar
Łukasz Wojniłowicz committed
116
117
        m_type(b.m_type),
        m_name(b.m_name),
118
        code(b.code),
119
120
        parent(b.parent),
        slotList(b.slotList)
121
122
123
124
125
126
    {
    }

    void clear()
    {
        id = "";
Łukasz Wojniłowicz's avatar
Łukasz Wojniłowicz committed
127
128
        m_type = "";
        m_name = "";
129
130
        code = "";
        parent = "";
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
        slotList.clear();
    }

    bool readSlots(QXmlStreamReader &xml)
    {
        while (!xml.atEnd()) {
            QXmlStreamReader::TokenType type = xml.readNext();
            if (type == QXmlStreamReader::StartElement) {
                QStringRef _name = xml.name();
                if (_name == "slot") {
                    type = xml.readNext();
                    if (type == QXmlStreamReader::Characters)
                        type = xml.readNext();
                    if (type == QXmlStreamReader::StartElement) {
                        QStringRef name = xml.name();
                        QString key, value;
                        if (name == "key")
                            key = xml.readElementText(QXmlStreamReader::SkipChildElements).trimmed();
                        type = xml.readNext();
                        if (type == QXmlStreamReader::Characters)
                            type = xml.readNext();
                        if (type == QXmlStreamReader::StartElement) {
                            name = xml.name();
                            if (name == "value")
                                value = xml.readElementText(QXmlStreamReader::SkipChildElements).trimmed();
                        }
                        if (!key.isEmpty() && !value.isEmpty())
                            slotList[key] = value;
                    }
                }
            } else if (type == QXmlStreamReader::EndElement) {
                QStringRef _name = xml.name();
                if (_name  == "slots")
                    return true;
            }
        }
        return true;
168
169
170
171
172
173
174
    }

    bool read(QXmlStreamReader &xml)
    {
        while (!xml.atEnd()) {
            xml.readNext();
            QStringRef _name = xml.name();
175
            if (xml.isEndElement() && _name == "account") {
Łukasz Wojniłowicz's avatar
Łukasz Wojniłowicz committed
176
177
                if (prefixNameWithCode && !code.isEmpty() && !m_name.startsWith(code))
                    m_name = code + ' ' + m_name;
178
                return true;
179
            }
180
181
182
            if (xml.isStartElement())
            {
                if (_name == "name")
Łukasz Wojniłowicz's avatar
Łukasz Wojniłowicz committed
183
                    m_name = xml.readElementText(QXmlStreamReader::SkipChildElements).trimmed();
184
                else if (_name == "id")
185
                    id = xml.readElementText(QXmlStreamReader::SkipChildElements).trimmed();
186
                else if (_name == "type")
Łukasz Wojniłowicz's avatar
Łukasz Wojniłowicz committed
187
                    m_type = xml.readElementText(QXmlStreamReader::SkipChildElements).trimmed();
188
                else if (_name == "code")
189
                    code = xml.readElementText(QXmlStreamReader::SkipChildElements).trimmed();
190
                else if (_name == "parent")
191
192
193
                    parent = xml.readElementText(QXmlStreamReader::SkipChildElements).trimmed();
                else if (_name == "slots")
                    readSlots(xml);
194
195
                else
                {
196
                    xml.readElementText(QXmlStreamReader::SkipChildElements);
Ralf Habacker's avatar
Ralf Habacker committed
197
198
                    if (debug)
                        qDebug() << "skipping" << _name.toString();
199
200
201
202
203
204
205
206
207
208
                }
            }
        }
        return false;
    }
};

QDebug operator <<(QDebug out, const TemplateAccount &a)
{
    out << "TemplateAccount("
Łukasz Wojniłowicz's avatar
Łukasz Wojniłowicz committed
209
        << "name:" << a.m_name
210
        << "id:" << a.id
Łukasz Wojniłowicz's avatar
Łukasz Wojniłowicz committed
211
        << "type:" << a.m_type
212
213
        << "code:" << a.code
        << "parent:" << a.parent
214
        << "slotList:" << a.slotList
215
216
217
218
        << ")\n";
    return out;
}

Ralf Habacker's avatar
Ralf Habacker committed
219
220
221
222
223
224
225
226
227
QDebug operator <<(QDebug out, const TemplateAccount::PointerList &a)
{
    out << "TemplateAccount::List(";
    foreach(const TemplateAccount *account, a)
            out << *account;
    out << ")";
    return out;
}

228
229
230
231
232
class TemplateFile {
public:
    QString title;
    QString longDescription;
    QString shortDescription;
Ralf Habacker's avatar
Ralf Habacker committed
233
    TemplateAccount::List accounts;
234
235
236
237
238
239
240
241

    bool read(QXmlStreamReader &xml)
    {
        Q_ASSERT(xml.isStartElement() && xml.name() == "gnc-account-example");

        while (xml.readNextStartElement()) {
            QStringRef name = xml.name();
            if (xml.name() == "title")
Ralf Habacker's avatar
Ralf Habacker committed
242
                title = xml.readElementText().trimmed();
243
            else if (xml.name() == "short-description")
244
                shortDescription = xml.readElementText().trimmed().replace("  ", " ");
245
            else if (xml.name() == "long-description")
246
                longDescription = xml.readElementText().trimmed().replace("  ", " ");
247
248
249
250
251
252
253
254
            else if (xml.name() == "account")
            {
                TemplateAccount account;
                if (account.read(xml))
                    accounts.append(account);
            }
            else
            {
Ralf Habacker's avatar
Ralf Habacker committed
255
256
                if (debug)
                    qDebug() << "skipping" << name.toString();
257
258
259
260
261
262
                xml.skipCurrentElement();
            }
        }
        return true;
    }

Ralf Habacker's avatar
Ralf Habacker committed
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
    bool writeAsXml(QXmlStreamWriter &xml)
    {
        xml.writeStartElement("","title");
        xml.writeCharacters(title);
        xml.writeEndElement();
        xml.writeStartElement("","shortdesc");
        xml.writeCharacters(shortDescription);
        xml.writeEndElement();
        xml.writeStartElement("","longdesc");
        xml.writeCharacters(longDescription);
        xml.writeEndElement();
        xml.writeStartElement("","accounts");
        bool result = writeAccountsAsXml(xml);
        xml.writeEndElement();
        return result;
    }

    bool writeAccountsAsXml(QXmlStreamWriter &xml, const QString &id="", int index=0)
    {
        TemplateAccount::PointerList list;

        if (index == 0)
            list = accountsByType("ROOT");
        else
            list = accountsByParentID(id);

        foreach(TemplateAccount *account, list)
        {
Łukasz Wojniłowicz's avatar
Łukasz Wojniłowicz committed
291
            if (account->m_type != "ROOT")
Ralf Habacker's avatar
Ralf Habacker committed
292
293
            {
                xml.writeStartElement("","account");
Łukasz Wojniłowicz's avatar
Łukasz Wojniłowicz committed
294
295
                xml.writeAttribute("type", QString::number(toKMyMoneyAccountType(account->m_type)));
                xml.writeAttribute("name", noLevel1Names && index < 2 ? "" : account->m_name);
296
297
                if (withID)
                    xml.writeAttribute("id", account->id);
298
299
300
301
                if (withTax) {
                    if (account->slotList.contains("tax-related")) {
                        xml.writeStartElement("flag");
                        xml.writeAttribute("name","Tax");
302
                        xml.writeAttribute("value",account->slotList["tax-related"] == "1" ? "Yes" : "No");
303
304
305
                        xml.writeEndElement();
                    }
                }
306
307
308
309
310
311
                if (account->slotList.contains("equity-type") && account->slotList["equity-type"] == "opening-balance") {
                    xml.writeStartElement("flag");
                    xml.writeAttribute("name","OpeningBalanceAccount");
                    xml.writeAttribute("value","Yes");
                    xml.writeEndElement();
                }
Ralf Habacker's avatar
Ralf Habacker committed
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
            }
            index++;
            writeAccountsAsXml(xml, account->id, index);
            index--;
            xml.writeEndElement();
        }
        return true;
    }

    TemplateAccount *account(const QString &id)
    {
        for(int i=0; i < accounts.size(); i++)
        {
            TemplateAccount &account = accounts[i];
            if (account.id == id)
                return &account;
        }
        return 0;
    }

    TemplateAccount::PointerList accountsByType(const QString &type)
    {
        TemplateAccount::PointerList list;
        for(int i=0; i < accounts.size(); i++)
        {
            TemplateAccount &account = accounts[i];
Łukasz Wojniłowicz's avatar
Łukasz Wojniłowicz committed
338
            if (account.m_type == type)
Ralf Habacker's avatar
Ralf Habacker committed
339
340
341
342
343
344
345
346
                list.append(&account);
        }
        return list;
    }


    static bool nameLessThan(TemplateAccount *a1, TemplateAccount *a2)
    {
Łukasz Wojniłowicz's avatar
Łukasz Wojniłowicz committed
347
        return a1->m_name < a2->m_name;
Ralf Habacker's avatar
Ralf Habacker committed
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
    }

    TemplateAccount::PointerList accountsByParentID(const QString &parentID)
    {
        TemplateAccount::PointerList list;

        for(int i=0; i < accounts.size(); i++)
        {
            TemplateAccount &account = accounts[i];
            if (account.parent == parentID)
                list.append(&account);
        }
        qSort(list.begin(), list.end(), nameLessThan);
        return list;
    }

    bool dumpTemplates(const QString &id="", int index=0)
    {
        TemplateAccount::PointerList list;

        if (index == 0)
            list = accountsByType("ROOT");
        else
            list = accountsByParentID(id);

        foreach(TemplateAccount *account, list)
        {
            QString a;
            a.fill(' ', index);
Łukasz Wojniłowicz's avatar
Łukasz Wojniłowicz committed
377
            qDebug() << a << account->m_name << toKMyMoneyAccountType(account->m_type);
Ralf Habacker's avatar
Ralf Habacker committed
378
379
380
381
382
383
            index++;
            dumpTemplates(account->id, index);
            index--;
        }
        return true;
    }
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
};

QDebug operator <<(QDebug out, const TemplateFile &a)
{
    out << "TemplateFile("
        << "title:" << a.title
        << "short description:" << a.shortDescription
        << "long description:" << a.longDescription
        << "accounts:";
    foreach(const TemplateAccount &account, a.accounts)
        out << account;
    out << ")";
    return out;
}

class GnuCashAccountTemplateReader {
public:
    GnuCashAccountTemplateReader()
    {
    }

    bool read(const QString &filename)
    {
        QFile file(filename);
        QTextStream in(&file);
Ralf Habacker's avatar
Ralf Habacker committed
409
        in.setCodec("utf-8");
410
411
412

        if(!file.open(QIODevice::ReadOnly))
            return false;
Ralf Habacker's avatar
Ralf Habacker committed
413
        inFileName = filename;
414
415
416
417
418
419
420
421
        return read(in.device());
    }

    TemplateFile &result()
    {
        return _template;
    }

Ralf Habacker's avatar
Ralf Habacker committed
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
    bool dumpTemplates()
    {
        return _template.dumpTemplates();
    }

    bool writeAsXml(const QString &filename=QString())
    {
        if (filename.isEmpty())
        {
            QTextStream stream(stdout);
            return writeAsXml(stream.device());
        }
        else
        {
            QFile file(filename);
            if(!file.open(QIODevice::WriteOnly))
                return false;
            return writeAsXml(&file);
        }
    }

443
protected:
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458

    bool checkAndUpdateAvailableNamespaces(QXmlStreamReader &xml)
    {
        if (xml.namespaceDeclarations().size() < 5)
        {
            qWarning() << "gnucash template file is missing required name space declarations; adding by self";
        }
        xml.addExtraNamespaceDeclaration(QXmlStreamNamespaceDeclaration("act", "http://www.gnucash.org/XML/act"));
        xml.addExtraNamespaceDeclaration(QXmlStreamNamespaceDeclaration("gnc", "http://www.gnucash.org/XML/gnc"));
        xml.addExtraNamespaceDeclaration(QXmlStreamNamespaceDeclaration("gnc-act", "http://www.gnucash.org/XML/gnc-act"));
        xml.addExtraNamespaceDeclaration(QXmlStreamNamespaceDeclaration("cmdty","http://www.gnucash.org/XML/cmdty"));
        xml.addExtraNamespaceDeclaration(QXmlStreamNamespaceDeclaration("slot","http://www.gnucash.org/XML/slot"));
        return true;
    }

459
460
    bool read(QIODevice *device)
    {
Łukasz Wojniłowicz's avatar
Łukasz Wojniłowicz committed
461
462
        m_xml.setDevice(device);
        while(!m_xml.atEnd())
Ralf Habacker's avatar
Ralf Habacker committed
463
        {
Łukasz Wojniłowicz's avatar
Łukasz Wojniłowicz committed
464
465
            m_xml.readNext();
            if (m_xml.isStartElement())
Ralf Habacker's avatar
Ralf Habacker committed
466
            {
Łukasz Wojniłowicz's avatar
Łukasz Wojniłowicz committed
467
                if (m_xml.name() == "gnc-account-example")
468
                {
Łukasz Wojniłowicz's avatar
Łukasz Wojniłowicz committed
469
470
                    checkAndUpdateAvailableNamespaces(m_xml);
                    _template.read(m_xml);
471
                }
Ralf Habacker's avatar
Ralf Habacker committed
472
                else
Łukasz Wojniłowicz's avatar
Łukasz Wojniłowicz committed
473
                    m_xml.raiseError(QObject::tr("The file is not an gnucash account template file."));
Ralf Habacker's avatar
Ralf Habacker committed
474
            }
475
        }
Łukasz Wojniłowicz's avatar
Łukasz Wojniłowicz committed
476
477
478
        if (m_xml.error() != QXmlStreamReader::NoError)
            qWarning() << m_xml.errorString();
        return !m_xml.error();
479
480
    }

Ralf Habacker's avatar
Ralf Habacker committed
481
482
    bool writeAsXml(QIODevice *device)
    {
Ralf Habacker's avatar
Ralf Habacker committed
483
        QXmlStreamWriter xml(device);
Ralf Habacker's avatar
Ralf Habacker committed
484
485
486
487
488
        xml.setAutoFormatting(true);
        xml.setAutoFormattingIndent(1);
        xml.setCodec("utf-8");
        xml.writeStartDocument();

489
490
        QString fileName = inFileName;
        fileName.replace(QRegExp(".*/accounts"),"accounts");
Ralf Habacker's avatar
Ralf Habacker committed
491
492
493
494
495
496
        xml.writeComment(QString("\n"
            "     Converted using xea2kmt from GnuCash sources\n"
            "\n"
            "        %1\n"
            "\n"
            "     Please check the source file for possible copyright\n"
Yuri Chornoivan's avatar
Yuri Chornoivan committed
497
            "     and license information.\n"
Ralf Habacker's avatar
Ralf Habacker committed
498
499
500
501
502
        ).arg(fileName));
        xml.writeDTD("<!DOCTYPE KMYMONEY-TEMPLATE>");
        xml.writeStartElement("","kmymoney-account-template");
        bool result = _template.writeAsXml(xml);
        xml.writeEndElement();
503
        xml.writeEndDocument();
Ralf Habacker's avatar
Ralf Habacker committed
504
505
506
        return result;
    }

Łukasz Wojniłowicz's avatar
Łukasz Wojniłowicz committed
507
    QXmlStreamReader m_xml;
508
    TemplateFile _template;
Ralf Habacker's avatar
Ralf Habacker committed
509
    QString inFileName;
510
511
};

512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
void scanDir(QDir dir, QStringList &files)
{
    dir.setNameFilters(QStringList("*.gnucash-xea"));
    dir.setFilter(QDir::Files | QDir::NoDotAndDotDot | QDir::NoSymLinks);

    if (debug)
        qDebug() << "Scanning: " << dir.path();

    QStringList fileList = dir.entryList();
    for (int i=0; i<fileList.count(); i++)
    {
        if (debug)
            qDebug() << "Found file: " << fileList[i];
        files.append(QString("%1/%2").arg(dir.absolutePath()).arg(fileList[i]));
    }

    dir.setFilter(QDir::AllDirs | QDir::NoDotAndDotDot | QDir::NoSymLinks);
    QStringList dirList = dir.entryList();
    for (int i=0; i<dirList.size(); ++i)
    {
        QString newPath = QString("%1/%2").arg(dir.absolutePath()).arg(dirList.at(i));
        scanDir(QDir(newPath), files);
    }
}

bool convertFile(const QString &inFile, const QString &outFile)
{
    GnuCashAccountTemplateReader reader;
    if (!reader.read(inFile))
        return false;
    return reader.writeAsXml(outFile);
}

int convertFileStructure(const QString &indir, const QString &outdir)
{
    DirNameMapType &dirNameMap = getDirNameMap();
    // get gnucash account files
    QDir d(indir);
    QStringList files;
    scanDir(d, files);

    QString inPath = d.absolutePath();
    QDir outDir(outdir);
    QString outPath = outDir.absolutePath();
    QStringList mapKeys = dirNameMap.keys();
    int result = 0;

    // process templates
    foreach (const QString &file, files)
    {
562
        if (debug || verbose)
563
564
565
566
            qDebug() << "processing" << file;

        // create output file dir
        QFileInfo fi(file);
567
568
569
570
        auto outFileName = fi.canonicalFilePath();
        outFileName.replace(inPath, outPath);
        outFileName.remove("acctchrt_");
        outFileName.replace(".gnucash-xea", ".kmt");
571
572
        foreach(const QString &key, mapKeys)
        {
573
            if (outFileName.contains('/' + key + '/'))
574
                outFileName = outFileName.replace('/' + key + '/', '/' + dirNameMap[key] + '/');
575
576
577
        }
        fi.setFile(outFileName);

Łukasz Wojniłowicz's avatar
Łukasz Wojniłowicz committed
578
        d = fi.absolutePath();
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
        if (!d.exists())
        {
            if  (debug)
                qDebug() << "creating path " << fi.absolutePath();
            d.mkpath(fi.absolutePath());
        }
        if (debug)
            qDebug() << "writing to " << outFileName;
        if (!convertFile(file, outFileName))
        {
            qWarning() << "could not create" << outFileName;
            result = 1;
        }
    }
    return result;
}

596
597
int main(int argc, char *argv[])
{
598
    if (argc < 2 || (argc == 2 && QLatin1String(argv[1]) == "--help"))
Ralf Habacker's avatar
Ralf Habacker committed
599
    {
600
        qWarning() << "xea2kmt: convert gnucash template file to kmymoney template file";
Ralf Habacker's avatar
Ralf Habacker committed
601
        qWarning() << argv[0] << "<options> <gnucash-template-file> [<kmymoney-template-output-file>]";
602
        qWarning() << argv[0] << "<options> --in-dir <gnucash-template-files-root> --out-dir <kmymoney-template-files-root>";
Ralf Habacker's avatar
Ralf Habacker committed
603
        qWarning() << "options:";
604
605
606
607
        qWarning() << "          --debug                   - output debug information";
        qWarning() << "          --help                    - this page";
        qWarning() << "          --no-level1-names         - do not export account names for top level accounts";
        qWarning() << "          --prefix-name-with-code   - prefix account name with account code if present";
608
        qWarning() << "          --verbose                 - output processing information";
609
610
        qWarning() << "          --with-id                 - write account id attribute";
        qWarning() << "          --with-tax-related        - parse and export gnucash 'tax-related' flag";
611
612
        qWarning() << "          --in-dir <dir>            - search for gnucash templates files in <dir>";
        qWarning() << "          --out-dir <dir>           - generate kmymoney templates below <dir";
Ralf Habacker's avatar
Ralf Habacker committed
613
614
        return -1;
    }
615

Ralf Habacker's avatar
Ralf Habacker committed
616
617
    QString inFileName;
    QString outFileName;
618
619
    QString inDir;
    QString outDir;
620
    for(int i = 1; i < argc; i++)
Ralf Habacker's avatar
Ralf Habacker committed
621
    {
622
623
624
        QString arg = QLatin1String(argv[i]);
        if (arg == "--debug")
            debug = true;
625
626
        else if (arg == "--verbose")
            verbose = true;
627
628
        else if (arg == "--with-id")
            withID = true;
629
630
        else if (arg == "--no-level1-names")
            noLevel1Names = true;
631
632
        else if (arg == "--with-tax-related")
            withTax = true;
633
634
        else if (arg == "--prefix-name-with-code")
            prefixNameWithCode = true;
635
636
637
638
        else if (arg == "--in-dir")
            inDir = argv[++i];
        else if (arg == "--out-dir")
            outDir = argv[++i];
Yuri Chornoivan's avatar
Yuri Chornoivan committed
639
        else if (!arg.startsWith(QLatin1String("--")))
640
641
642
643
644
645
646
647
648
649
650
        {
            if (inFileName.isEmpty())
                inFileName = arg;
            else
                outFileName = arg;
        }
        else
        {
            qWarning() << "invalid command line parameter'" << arg << "'";
            return -1;
        }
Ralf Habacker's avatar
Ralf Habacker committed
651
652
    }

653
654
655
656
657
    if (!inDir.isEmpty() && !outDir.isEmpty())
    {
        return convertFileStructure(inDir, outDir);
    }

Ralf Habacker's avatar
Ralf Habacker committed
658
659
660
661
662
663
664
665
666
    GnuCashAccountTemplateReader reader;
    bool result = reader.read(inFileName);
    if (debug)
    {
        qDebug() << reader.result();
        reader.dumpTemplates();
    }
    reader.writeAsXml(outFileName);
    return result ? 0 : -2;
667
}