refactor: split tool to libdtkcore-bin
authorIceyer <me@iceyer.net>
Mon, 22 Jan 2018 08:10:31 +0000 (16:10 +0800)
committerleaeasy <leaeasy@gmail.com>
Mon, 22 Jan 2018 08:37:08 +0000 (16:37 +0800)
Change-Id: Ide59c0f11faea6592b2801daa41816336358ad85

13 files changed:
debian/control
debian/libdtkcore-bin.install [new file with mode: 0644]
debian/libdtkcore-dev.install
dtkcore.pro
tool/license/license-updater.py [deleted file]
tool/settings/main.cpp [deleted file]
tool/settings/settings.pro [deleted file]
tool/tool.pro [deleted file]
tools/script/dtk-license.py [new file with mode: 0644]
tools/script/dtk-translate.py [new file with mode: 0644]
tools/settings/main.cpp [new file with mode: 0644]
tools/settings/settings.pro [new file with mode: 0644]
tools/tools.pro [new file with mode: 0644]

index 92f64308597a830ebdfb74ad0fcb909a62a7101e..910fc9b067c41d5b32c2fbec0b3db1ba3485083a 100644 (file)
@@ -15,6 +15,14 @@ Description: Deepin Tool Kit Core library
  .
  This package contains the shared libraries.
 
+Package: libdtkcore-bin
+Architecture: any
+Depends: ${shlibs:Depends}, ${misc:Depends}, libdtkcore2( =${binary:Version})
+Description: Deepin Tool Kit Core Utilities
+ DtkCore is base devel library of Deepin Qt/C++ applications.
+ .
+ This package contains the utilities of DtkCore
+
 Package: libdtkcore-dev
 Architecture: any
 Depends: ${shlibs:Depends}, ${misc:Depends}, libdtkcore2( =${binary:Version})
diff --git a/debian/libdtkcore-bin.install b/debian/libdtkcore-bin.install
new file mode 100644 (file)
index 0000000..b808e55
--- /dev/null
@@ -0,0 +1 @@
+usr/lib/dtk2/*
index df188d8cbf1cb2dcea138bc6afb291260db68a29..60e21e315c6098c660ef1fb45ae9a9b3569bd78b 100644 (file)
@@ -1,6 +1,5 @@
 usr/lib/*/lib*.so
 usr/include
 usr/lib/*/pkgconfig/*.pc
-usr/lib/dtk2/*
 usr/lib/*/cmake/*/*.cmake
 usr/lib/*/libdtk/modules/*
index c776e7057ba55b70e0e1aaa94e5c455ffb8cfb11..370c5fd0920fee3d5b776afaa9ec287b8f706e42 100644 (file)
@@ -6,4 +6,4 @@ SUBDIRS +=   \
     src \
     tests
 
-!mac:!win*: SUBDIRS += tool
+!mac:!win*: SUBDIRS += tools
diff --git a/tool/license/license-updater.py b/tool/license/license-updater.py
deleted file mode 100644 (file)
index bc3a071..0000000
+++ /dev/null
@@ -1,320 +0,0 @@
-#!/usr/bin/env python
-
-import fnmatch
-import os
-import argparse
-import re
-import datetime
-
-
-license_header = '''/*\n'''
-license_empty = ''' *\n'''
-license_copyright_prifix = ''' * Copyright (C) {0}\n'''
-license_copyright_indent = ''' *               {0}\n'''
-license_author_prifix = ''' * Author:     {0}\n'''
-license_person_indent = ''' *             {0}\n'''
-license_maintainer_prifix = ''' * Maintainer: {0}\n'''
-license_tail = ''' */\n\n'''
-default_license_body = ''' * 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 3 of the License, or
- * 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 <http://www.gnu.org/licenses/>.
-'''
-
-
-def isInt(value):
-    try:
-        int(value)
-        return True
-    except ValueError:
-        return False
-
-
-class Copyright:
-    def __init__(self, line):
-        self.year_start = datetime.datetime.now().year
-        self.year_end = datetime.datetime.now().year
-
-        if "copyright" in line.lower():
-            line = line[re.search("copyright", line, re.IGNORECASE).end():]
-
-        copyright_sysbol = re.search("\(.\)", line, re.IGNORECASE)
-        if copyright_sysbol is not None:
-            copyright_brace_end_pos = copyright_sysbol.end()
-            line = line[copyright_brace_end_pos:]
-            pass
-
-        if re.search("[0-9]+", line) is not None:
-            year_start_pos = re.search("[0-9]+", line).start()
-            year_start_end_pos = re.search("[0-9]+", line).end()
-            self.year_start = int(line[year_start_pos: year_start_end_pos])
-            line = line[year_start_end_pos:]
-
-        if re.search("[0-9]+", line) is not None:
-            year_end_pos = re.search("[0-9]+", line).start()
-            year_end_end_pos = re.search("[0-9]+", line).end()
-            if re.search("~", line) is not None:
-                year_spilt = re.search("~", line).start()
-                if (year_spilt < year_end_pos):
-                    self.year_end = int(line[year_end_pos: year_end_end_pos])
-                    line = line[year_end_end_pos:]
-
-        self.name = line.strip()
-
-    def string(self):
-        return "{0} ~ {1} {2}".format(
-            self.year_start,
-            self.year_end,
-            self.name)
-
-
-class Person:
-    def __init__(self, line):
-        if re.search(":", line, re.IGNORECASE) is not None:
-            split_end = re.search(":", line).end()
-            line = line[split_end:]
-
-        self.name = line.strip()
-
-
-def filter_files(file_list, ext_list):
-    for file in file_list:
-        for ext in ext_list:
-            if fnmatch.fnmatch(file, ext):
-                yield file
-                break
-
-
-class Source:
-    def __init__(self, filename):
-        self.body = []
-        self.copyrights = {}
-        self.authors = {}
-        self.maintainers = {}
-        self.filename = filename
-        self.is_deepin_copyright = False
-        self.update_license(filename)
-
-    def update_license(self, filename):
-        find_license_start = False
-        find_license_end = False
-
-        parse_copyright_start = False
-        parse_author_start = False
-        parse_maintainer_start = False
-
-        with open(filename, "r") as f:
-            print("process:", filename)
-            for line in f:
-                if line.strip().startswith("/*") and (0 == len(self.body)):
-                    find_license_start = True
-
-                if (0 != len(self.body)) or (0 != len(line.strip())):
-                    self.body.append(line)
-
-                if "*/" in line.strip() and find_license_start:
-                    if not find_license_end:
-                        # print("clean body")
-                        self.body = []
-                    find_license_end = True
-
-                if find_license_start and not find_license_end:
-                    if re.search("(\*)+", line):
-                        # remove *****
-                        line = line[re.search("(\*)+", line).end():]
-
-                    if "copyright" in line.lower():
-                        parse_copyright_start = True
-                        parse_author_start = False
-                        parse_maintainer_start = False
-                    if "author" in line.lower():
-                        parse_copyright_start = False
-                        parse_author_start = True
-                        parse_maintainer_start = False
-                    if "maintainer" in line.lower():
-                        parse_copyright_start = False
-                        parse_author_start = False
-                        parse_maintainer_start = True
-                    if 0 == len(line.strip()):
-                        parse_copyright_start = False
-                        parse_author_start = False
-                        parse_maintainer_start = False
-
-                    if parse_copyright_start:
-                        cr = Copyright(line)
-                        self.copyrights[cr.name] = cr
-
-                    if parse_author_start:
-                        p = Person(line)
-                        self.authors[p.name] = p
-
-                    if parse_maintainer_start:
-                        p = Person(line)
-                        self.maintainers[p.name] = p
-
-    def fix_deepin(self):
-        new_cr = {}
-        self.is_deepin_copyright = False
-        for k, cr in self.copyrights.items():
-            if "deepin" in cr.name.lower():
-                cr.name = "Deepin Technology Co., Ltd."
-                self.is_deepin_copyright = True
-            new_cr[cr.name] = cr
-        self.copyrights = new_cr
-
-    def dump(self):
-        for cr in self.copyrights:
-            print(cr.year_start, cr.year_end, cr.name)
-        for a in self.authors:
-            print(a.name)
-        for a in self.maintainers:
-            print(a.name)
-        print("body size:", len(self.body))
-
-    def save(self):
-        wf = open(self.filename, 'w')
-        wf.write(license_header)
-
-        if len(self.copyrights):
-            write_first = False
-            for k, cr in self.copyrights.items():
-                if not write_first:
-                    wf.write(license_copyright_prifix.format(cr.string()))
-                    write_first = True
-                else:
-                    wf.write(license_copyright_indent.format(cr.string()))
-            wf.write(license_empty)
-
-        if len(self.authors):
-            write_first = False
-            for k, author in self.authors.items():
-                if not write_first:
-                    wf.write(license_author_prifix.format(author.name))
-                    write_first = True
-                else:
-                    wf.write(license_person_indent.format(author.name))
-            wf.write(license_empty)
-
-        if len(self.maintainers):
-            write_first = False
-            for k, maintainer in self.maintainers.items():
-                if not write_first:
-                    wf.write(license_maintainer_prifix.format(maintainer.name))
-                    write_first = True
-                else:
-                    wf.write(license_person_indent.format(maintainer.name))
-            wf.write(license_empty)
-
-        wf.write(default_license_body)
-        wf.write(license_tail)
-
-        for l in self.body:
-            wf.write(l)
-        wf.close()
-
-
-def parse_args():
-    parser = argparse.ArgumentParser()
-    parser.add_argument('--authors', help='''authors split by ":". For example:\n
-        "Iceyer <me@iceyer.net>:Li He <lihe@deepin.com>"''')
-    parser.add_argument('--maintainers', help='''maintainers split by ":". For example: \n
-        "Iceyer <me@iceyer.net>:Li He <lihe@deepin.com>"''')
-    parser.add_argument('--copyrights', help='''copyrights split by ":". For example: \n
-        "2011 ~ 2017 Deepin Technology Co., Ltd.:2011 ~ 2017 Li He"''')
-    parser.add_argument('--fix-deepin',  dest='fixdeepin',
-                        action='store_const', const=True, default=False, help='''
-                        fix deein copyrights''')
-    parser.add_argument('dir',  help='''
-                        source code dir''')
-
-    args = parser.parse_args()
-    return args
-
-
-def match_files(dir):
-    EXTENSIONS = "*.cpp", "*.c", "*.h", "*.go"
-    matches = []
-    for root, dirnames, filenames in os.walk(dir):
-        for filename in filter_files(filenames, EXTENSIONS):
-            matches.append(os.path.join(root, filename))
-    return matches
-
-
-def test():
-    cr = Copyright("Copyright (C)  Deepin Technology Co., Ltd.")
-    print(cr.year_start, cr.year_end, cr.name)
-    cr = Copyright("Copyright (C) 2007 Deepin Technology Co., Ltd.")
-    print(cr.year_start, cr.year_end, cr.name)
-    cr = Copyright("Copyright (C) 2007 ~ 2016 Deepin Technology Co., Ltd.")
-    print(cr.year_start, cr.year_end, cr.name)
-
-    p = Person("Author:     Wang Yong <wangyong@deepin.com>")
-    print(p.name)
-    p = Person("    Wang Yong <wangyong@deepin.com>")
-    print(p.name)
-
-
-def get_authors(args):
-    authors = []
-    if args.authors is not None:
-        for a in args.authors.split(":"):
-            authors.append(Person(a))
-    return authors
-
-
-def get_copyrights(args):
-    copyrights = []
-    if args.copyrights is not None:
-        for a in args.copyrights.split(":"):
-            copyrights.append(Copyright(a))
-    return copyrights
-
-
-def get_maintainers(args):
-    maintainers = []
-    if args.maintainers is not None:
-        for a in args.maintainers.split(":"):
-            maintainers.append(Copyright(a))
-    return maintainers
-
-
-def main():
-    args = parse_args()
-    authors = get_authors(args)
-    copyrights = get_copyrights(args)
-    maintainers = get_maintainers(args)
-    fixdeepin = args.fixdeepin
-    files = match_files(args.dir)
-
-    for filename in files:
-        s = Source(filename)
-        # s.dump()
-        if fixdeepin:
-            s.fix_deepin()
-        if not s.is_deepin_copyright and 0 != len(s.copyrights):
-            continue
-
-        if 0 == len(s.copyrights):
-            for cr in copyrights:
-                s.copyrights[cr.name] = cr
-
-        for p in authors:
-            s.authors[p.name] = p
-
-        for p in maintainers:
-            s.maintainers[p.name] = p
-
-        s.save()
-        # s.dump()
-
-
-if __name__ == "__main__":
-    main()
diff --git a/tool/settings/main.cpp b/tool/settings/main.cpp
deleted file mode 100644 (file)
index c976b85..0000000
+++ /dev/null
@@ -1,287 +0,0 @@
-/*
- * Copyright (C) 2017 ~ 2017 Deepin Technology Co., Ltd.
- *
- * 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 3 of the License, or
- * 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 <http://www.gnu.org/licenses/>.
- */
-
-#include <QCoreApplication>
-
-#include <iostream>
-
-#include <QDebug>
-#include <QFile>
-#include <QCommandLineParser>
-
-#include "settings/dsettings.h"
-#include "settings/dsettingsgroup.h"
-#include "settings/dsettingsoption.h"
-
-#include <QFile>
-#include <QJsonDocument>
-#include <QJsonObject>
-
-#include <QDomDocument>
-
-static QString CppTemplate =
-    "#include <DSettings>\n"
-    "\n"
-    "void GenerateSettingTranslate()\n"
-    "{\n"
-    "%1"
-    "}\n";
-
-/*
- *  GVariant Type Name/Code      C++ Type Name          QVariant Type Name
- *  --------------------------------------------------------------------------
- *  boolean            b         bool                   QVariant::Bool
- *  byte               y         char                   QVariant::Char
- *  int16              n         int                    QVariant::Int
- *  uint16             q         unsigned int           QVariant::UInt
- *  int32              i         int                    QVariant::Int
- *  uint32             u         unsigned int           QVariant::UInt
- *  int64              x         long long              QVariant::LongLong
- *  uint64             t         unsigned long long     QVariant::ULongLong
- *  double             d         double                 QVariant::Double
- *  string             s         QString                QVariant::String
- *  string array*      as        QStringList            QVariant::StringList
- *  byte array         ay        QByteArray             QVariant::ByteArray
- *  dictionary         a{ss}     QVariantMap            QVariant::Map
-*/
-
-QString gsettings_type_from_QVarint(const QVariant::Type qtype)
-{
-    switch (qtype) {
-    case QVariant::Bool:
-        return "b";
-    case QVariant::Int:
-        return "i";
-    case QVariant::UInt:
-        return "u";
-    case QVariant::LongLong:
-        return "x";
-    case QVariant::ULongLong:
-        return "t";
-    case QVariant::Double:
-        return "d";
-    case QVariant::String:
-        return "s";
-    case QVariant::StringList:
-        return "as";
-    case QVariant::ByteArray:
-        return "ay";
-    case QVariant::Map:
-        return "a{ss}";
-    default:
-        return "";
-    }
-}
-
-QString gsettings_value_from_QVarint(const QVariant value)
-{
-    switch (value.type()) {
-    case QVariant::Bool:
-        return value.toString();
-    case QVariant::Int:
-        return value.toString();
-    case QVariant::UInt:
-        return value.toString();
-    case QVariant::LongLong:
-        return value.toString();
-    case QVariant::ULongLong:
-        return value.toString();
-    case QVariant::Double:
-        return value.toString();
-    case QVariant::String:
-        return QString("\"%1\"").arg(value.toString());
-    case QVariant::StringList:
-        return value.toString();
-    case QVariant::ByteArray:
-        return value.toString();
-    case QVariant::Map:
-        return value.toString();
-    default:
-        return "";
-    }
-}
-
-
-QJsonObject parseGSettingsMeta(const QString &jsonPath)
-{
-    QFile jsonFile(jsonPath);
-    jsonFile.open(QIODevice::ReadOnly);
-    auto jsonData = jsonFile.readAll();
-    jsonFile.close();
-
-    QJsonDocument jsonDoc = QJsonDocument::fromJson(jsonData);
-    return jsonDoc.object().value("gsettings").toObject();
-}
-
-static bool writeGSettingXML(Dtk::Core::DSettings *settings,
-                             QJsonObject gsettingsMeta,
-                             const QString &xmlPath)
-{
-    QDomDocument document;
-
-    QDomProcessingInstruction header = document.createProcessingInstruction("xml",
-                                       "version=\"1.0\" encoding=\"utf-8\"");
-    document.appendChild(header);
-
-    QDomElement schemalist = document.createElement("schemalist");
-
-    auto id = gsettingsMeta.value("id").toString();
-    auto path = gsettingsMeta.value("path").toString();
-    QDomElement schema = document.createElement("schema");
-    schema.setAttribute("id", id);
-    schema.setAttribute("path", path);
-
-    for (QString key : settings->keys()) {
-        auto codeKey = QString(key).replace(".", "-").replace("_", "-");
-        auto value = settings->option(key)->value();
-        auto gtype = gsettings_type_from_QVarint(value.type());
-        if (gtype.isEmpty()) {
-            qDebug() << "skip unsupport type:" << value.type() << key;
-            continue;
-        }
-
-        QDomElement keyXml = document.createElement("key");
-        keyXml.setAttribute("name", codeKey);
-        keyXml.setAttribute("type", gtype);
-
-        QString defaultData = gsettings_value_from_QVarint(value);
-        QDomElement defaultEle = document.createElement("default");
-        QDomCharacterData data = document.createTextNode(defaultData);
-        defaultEle.appendChild(data);
-        keyXml.appendChild(defaultEle);
-
-        schema.appendChild(keyXml);
-    }
-
-    schemalist.appendChild(schema);
-    document.appendChild(schemalist);
-
-    QFile file(xmlPath);
-    if (!file.open(QIODevice::WriteOnly)) {
-        return false;
-    }
-    QTextStream stream(&file);
-    stream << document.toString();
-    file.close();
-    return true;
-}
-
-int main(int argc, char *argv[])
-{
-    QCoreApplication app(argc, argv);
-    app.setOrganizationName("deepin");
-    app.setApplicationName("dtk-settings-tools");
-    app.setApplicationVersion("0.1.2");
-
-    QCommandLineParser parser;
-    parser.setApplicationDescription("Generate translation of dtksetting.");
-    parser.addHelpOption();
-    parser.addVersionOption();
-
-    QCommandLineOption gsettingsArg(QStringList() << "g" << "gsettings",
-                                    QCoreApplication::tr("generate gsetting schema"),
-                                    "xml-file");
-
-    QCommandLineOption outputFileArg(QStringList() << "o" << "output",
-                                     QCoreApplication::tr("Output cpp file"),
-                                     "cpp-file");
-    parser.addOption(gsettingsArg);
-    parser.addOption(outputFileArg);
-    parser.addPositionalArgument("json-file", QCoreApplication::tr("Json file description config"));
-    parser.process(app);
-
-    if (0 == (parser.optionNames().length() + parser.positionalArguments().length())) {
-        parser.showHelp(0);
-    }
-
-    auto jsonFile = parser.positionalArguments().value(0);
-    auto settings = Dtk::Core::DSettings::fromJsonFile(jsonFile);
-
-    QMap<QString, QString> transtaleMaps;
-
-//    qDebug() << settings->groupKeys();
-    for (QString groupKey : settings->groupKeys()) {
-        auto codeKey = QString(groupKey).replace(".", "_");
-        auto group = settings->group(groupKey);
-//        qDebug() << codeKey << group->name();
-        // add Name
-        if (!group->name().isEmpty()) {
-            transtaleMaps.insert("group_" + codeKey + "Name", group->name());
-        }
-
-        // TODO: only two level
-        for (auto childGroup : group->childGroups()) {
-            auto codeKey = childGroup->key().replace(".", "_");
-//            qDebug() << codeKey << childGroup->name();
-            // add Name
-            if (!childGroup->name().isEmpty()) {
-                transtaleMaps.insert("group_" + codeKey + "Name", childGroup->name());
-            }
-        }
-    }
-
-    for (QString key : settings->keys()) {
-        auto codeKey = QString(key).replace(".", "_");
-        auto opt = settings->option(key);
-
-        // add Name
-        if (!opt->name().isEmpty()) {
-            transtaleMaps.insert(codeKey + "Name", opt->name());
-        }
-
-        // add text
-        if (!opt->data("text").toString().isEmpty()) {
-            transtaleMaps.insert(codeKey + "Text", opt->data("text").toString());
-        }
-
-        // add items
-        if (!opt->data("items").toStringList().isEmpty()) {
-            auto items = opt->data("items").toStringList();
-            for (int i = 0; i < items.length(); ++i) {
-                transtaleMaps.insert(codeKey + QString("Text%1").arg(i), items.value(i));
-            }
-        }
-    }
-
-    transtaleMaps.insert("reset_button_name", "Restore Defaults");
-
-    QString cppCode;
-    for (auto key : transtaleMaps.keys()) {
-        auto stringCode = QString("    auto %1 = QObject::tr(\"%2\");\n").arg(key).arg(transtaleMaps.value(key));
-        cppCode.append(stringCode);
-    }
-
-
-    if (parser.isSet(outputFileArg)) {
-        QString outputCpp = CppTemplate.arg(cppCode);
-        QFile outputFile(parser.value(outputFileArg));
-        if (!outputFile.open(QIODevice::WriteOnly)) {
-            qCritical() << "can not open output file!";
-            exit(1);
-        }
-        outputFile.write(outputCpp.toUtf8());
-        outputFile.close();
-    }
-
-    if (parser.isSet(gsettingsArg)) {
-        QString outputXml = parser.value(gsettingsArg);
-        writeGSettingXML(settings, parseGSettingsMeta(jsonFile), outputXml);
-    }
-
-    return 0;
-}
-
diff --git a/tool/settings/settings.pro b/tool/settings/settings.pro
deleted file mode 100644 (file)
index 8dcb34c..0000000
+++ /dev/null
@@ -1,29 +0,0 @@
-QT += core xml
-QT -= gui
-
-CONFIG += c++11
-
-TARGET = dtk-settings-tool
-CONFIG += console link_pkgconfig
-CONFIG -= app_bundle
-PKGCONFIG += gsettings-qt
-
-TEMPLATE = app
-
-SOURCES += main.cpp
-
-isEmpty(PREFIX){
-    PREFIX = /usr
-}
-
-binary.files += $${OUT_PWD}/dtk-settings-tool
-binary.path = $${PREFIX}/lib/dtk2
-
-INSTALLS += binary
-
-win32:CONFIG(release, debug|release): LIBS += -L$$OUT_PWD/../../src/release/ -ldtkcore
-else:win32:CONFIG(debug, debug|release): LIBS += -L$$OUT_PWD/../../src/debug/ -ldtkcore
-else:unix: LIBS += -L$$OUT_PWD/../../src/ -ldtkcore
-
-INCLUDEPATH += $$PWD/../../src
-DEPENDPATH += $$PWD/../../src
diff --git a/tool/tool.pro b/tool/tool.pro
deleted file mode 100644 (file)
index aeaeb47..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-TEMPLATE = subdirs
-
-CONFIG += ordered
-
-SUBDIRS +=   \
-    settings \
diff --git a/tools/script/dtk-license.py b/tools/script/dtk-license.py
new file mode 100644 (file)
index 0000000..bc3a071
--- /dev/null
@@ -0,0 +1,320 @@
+#!/usr/bin/env python
+
+import fnmatch
+import os
+import argparse
+import re
+import datetime
+
+
+license_header = '''/*\n'''
+license_empty = ''' *\n'''
+license_copyright_prifix = ''' * Copyright (C) {0}\n'''
+license_copyright_indent = ''' *               {0}\n'''
+license_author_prifix = ''' * Author:     {0}\n'''
+license_person_indent = ''' *             {0}\n'''
+license_maintainer_prifix = ''' * Maintainer: {0}\n'''
+license_tail = ''' */\n\n'''
+default_license_body = ''' * 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 3 of the License, or
+ * 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 <http://www.gnu.org/licenses/>.
+'''
+
+
+def isInt(value):
+    try:
+        int(value)
+        return True
+    except ValueError:
+        return False
+
+
+class Copyright:
+    def __init__(self, line):
+        self.year_start = datetime.datetime.now().year
+        self.year_end = datetime.datetime.now().year
+
+        if "copyright" in line.lower():
+            line = line[re.search("copyright", line, re.IGNORECASE).end():]
+
+        copyright_sysbol = re.search("\(.\)", line, re.IGNORECASE)
+        if copyright_sysbol is not None:
+            copyright_brace_end_pos = copyright_sysbol.end()
+            line = line[copyright_brace_end_pos:]
+            pass
+
+        if re.search("[0-9]+", line) is not None:
+            year_start_pos = re.search("[0-9]+", line).start()
+            year_start_end_pos = re.search("[0-9]+", line).end()
+            self.year_start = int(line[year_start_pos: year_start_end_pos])
+            line = line[year_start_end_pos:]
+
+        if re.search("[0-9]+", line) is not None:
+            year_end_pos = re.search("[0-9]+", line).start()
+            year_end_end_pos = re.search("[0-9]+", line).end()
+            if re.search("~", line) is not None:
+                year_spilt = re.search("~", line).start()
+                if (year_spilt < year_end_pos):
+                    self.year_end = int(line[year_end_pos: year_end_end_pos])
+                    line = line[year_end_end_pos:]
+
+        self.name = line.strip()
+
+    def string(self):
+        return "{0} ~ {1} {2}".format(
+            self.year_start,
+            self.year_end,
+            self.name)
+
+
+class Person:
+    def __init__(self, line):
+        if re.search(":", line, re.IGNORECASE) is not None:
+            split_end = re.search(":", line).end()
+            line = line[split_end:]
+
+        self.name = line.strip()
+
+
+def filter_files(file_list, ext_list):
+    for file in file_list:
+        for ext in ext_list:
+            if fnmatch.fnmatch(file, ext):
+                yield file
+                break
+
+
+class Source:
+    def __init__(self, filename):
+        self.body = []
+        self.copyrights = {}
+        self.authors = {}
+        self.maintainers = {}
+        self.filename = filename
+        self.is_deepin_copyright = False
+        self.update_license(filename)
+
+    def update_license(self, filename):
+        find_license_start = False
+        find_license_end = False
+
+        parse_copyright_start = False
+        parse_author_start = False
+        parse_maintainer_start = False
+
+        with open(filename, "r") as f:
+            print("process:", filename)
+            for line in f:
+                if line.strip().startswith("/*") and (0 == len(self.body)):
+                    find_license_start = True
+
+                if (0 != len(self.body)) or (0 != len(line.strip())):
+                    self.body.append(line)
+
+                if "*/" in line.strip() and find_license_start:
+                    if not find_license_end:
+                        # print("clean body")
+                        self.body = []
+                    find_license_end = True
+
+                if find_license_start and not find_license_end:
+                    if re.search("(\*)+", line):
+                        # remove *****
+                        line = line[re.search("(\*)+", line).end():]
+
+                    if "copyright" in line.lower():
+                        parse_copyright_start = True
+                        parse_author_start = False
+                        parse_maintainer_start = False
+                    if "author" in line.lower():
+                        parse_copyright_start = False
+                        parse_author_start = True
+                        parse_maintainer_start = False
+                    if "maintainer" in line.lower():
+                        parse_copyright_start = False
+                        parse_author_start = False
+                        parse_maintainer_start = True
+                    if 0 == len(line.strip()):
+                        parse_copyright_start = False
+                        parse_author_start = False
+                        parse_maintainer_start = False
+
+                    if parse_copyright_start:
+                        cr = Copyright(line)
+                        self.copyrights[cr.name] = cr
+
+                    if parse_author_start:
+                        p = Person(line)
+                        self.authors[p.name] = p
+
+                    if parse_maintainer_start:
+                        p = Person(line)
+                        self.maintainers[p.name] = p
+
+    def fix_deepin(self):
+        new_cr = {}
+        self.is_deepin_copyright = False
+        for k, cr in self.copyrights.items():
+            if "deepin" in cr.name.lower():
+                cr.name = "Deepin Technology Co., Ltd."
+                self.is_deepin_copyright = True
+            new_cr[cr.name] = cr
+        self.copyrights = new_cr
+
+    def dump(self):
+        for cr in self.copyrights:
+            print(cr.year_start, cr.year_end, cr.name)
+        for a in self.authors:
+            print(a.name)
+        for a in self.maintainers:
+            print(a.name)
+        print("body size:", len(self.body))
+
+    def save(self):
+        wf = open(self.filename, 'w')
+        wf.write(license_header)
+
+        if len(self.copyrights):
+            write_first = False
+            for k, cr in self.copyrights.items():
+                if not write_first:
+                    wf.write(license_copyright_prifix.format(cr.string()))
+                    write_first = True
+                else:
+                    wf.write(license_copyright_indent.format(cr.string()))
+            wf.write(license_empty)
+
+        if len(self.authors):
+            write_first = False
+            for k, author in self.authors.items():
+                if not write_first:
+                    wf.write(license_author_prifix.format(author.name))
+                    write_first = True
+                else:
+                    wf.write(license_person_indent.format(author.name))
+            wf.write(license_empty)
+
+        if len(self.maintainers):
+            write_first = False
+            for k, maintainer in self.maintainers.items():
+                if not write_first:
+                    wf.write(license_maintainer_prifix.format(maintainer.name))
+                    write_first = True
+                else:
+                    wf.write(license_person_indent.format(maintainer.name))
+            wf.write(license_empty)
+
+        wf.write(default_license_body)
+        wf.write(license_tail)
+
+        for l in self.body:
+            wf.write(l)
+        wf.close()
+
+
+def parse_args():
+    parser = argparse.ArgumentParser()
+    parser.add_argument('--authors', help='''authors split by ":". For example:\n
+        "Iceyer <me@iceyer.net>:Li He <lihe@deepin.com>"''')
+    parser.add_argument('--maintainers', help='''maintainers split by ":". For example: \n
+        "Iceyer <me@iceyer.net>:Li He <lihe@deepin.com>"''')
+    parser.add_argument('--copyrights', help='''copyrights split by ":". For example: \n
+        "2011 ~ 2017 Deepin Technology Co., Ltd.:2011 ~ 2017 Li He"''')
+    parser.add_argument('--fix-deepin',  dest='fixdeepin',
+                        action='store_const', const=True, default=False, help='''
+                        fix deein copyrights''')
+    parser.add_argument('dir',  help='''
+                        source code dir''')
+
+    args = parser.parse_args()
+    return args
+
+
+def match_files(dir):
+    EXTENSIONS = "*.cpp", "*.c", "*.h", "*.go"
+    matches = []
+    for root, dirnames, filenames in os.walk(dir):
+        for filename in filter_files(filenames, EXTENSIONS):
+            matches.append(os.path.join(root, filename))
+    return matches
+
+
+def test():
+    cr = Copyright("Copyright (C)  Deepin Technology Co., Ltd.")
+    print(cr.year_start, cr.year_end, cr.name)
+    cr = Copyright("Copyright (C) 2007 Deepin Technology Co., Ltd.")
+    print(cr.year_start, cr.year_end, cr.name)
+    cr = Copyright("Copyright (C) 2007 ~ 2016 Deepin Technology Co., Ltd.")
+    print(cr.year_start, cr.year_end, cr.name)
+
+    p = Person("Author:     Wang Yong <wangyong@deepin.com>")
+    print(p.name)
+    p = Person("    Wang Yong <wangyong@deepin.com>")
+    print(p.name)
+
+
+def get_authors(args):
+    authors = []
+    if args.authors is not None:
+        for a in args.authors.split(":"):
+            authors.append(Person(a))
+    return authors
+
+
+def get_copyrights(args):
+    copyrights = []
+    if args.copyrights is not None:
+        for a in args.copyrights.split(":"):
+            copyrights.append(Copyright(a))
+    return copyrights
+
+
+def get_maintainers(args):
+    maintainers = []
+    if args.maintainers is not None:
+        for a in args.maintainers.split(":"):
+            maintainers.append(Copyright(a))
+    return maintainers
+
+
+def main():
+    args = parse_args()
+    authors = get_authors(args)
+    copyrights = get_copyrights(args)
+    maintainers = get_maintainers(args)
+    fixdeepin = args.fixdeepin
+    files = match_files(args.dir)
+
+    for filename in files:
+        s = Source(filename)
+        # s.dump()
+        if fixdeepin:
+            s.fix_deepin()
+        if not s.is_deepin_copyright and 0 != len(s.copyrights):
+            continue
+
+        if 0 == len(s.copyrights):
+            for cr in copyrights:
+                s.copyrights[cr.name] = cr
+
+        for p in authors:
+            s.authors[p.name] = p
+
+        for p in maintainers:
+            s.maintainers[p.name] = p
+
+        s.save()
+        # s.dump()
+
+
+if __name__ == "__main__":
+    main()
diff --git a/tools/script/dtk-translate.py b/tools/script/dtk-translate.py
new file mode 100644 (file)
index 0000000..9cb06f8
--- /dev/null
@@ -0,0 +1,18 @@
+#!env python
+
+import sys,os,fnmatch
+from subprocess import call
+
+translations_dir = os.getcwd() + "/translations"
+if (len(sys.argv) == 2):
+    translations_dir = sys.argv[1] + "/translations"
+
+print("set translations dir:", translations_dir)
+
+tslist = fnmatch.filter(os.listdir(translations_dir), '*.ts')
+
+# This would print all the files and directories
+for tsfile in tslist:
+    tspath = translations_dir + "/" + tsfile
+    print ("process", tspath)
+    call(["lrelease", tspath])
diff --git a/tools/settings/main.cpp b/tools/settings/main.cpp
new file mode 100644 (file)
index 0000000..c976b85
--- /dev/null
@@ -0,0 +1,287 @@
+/*
+ * Copyright (C) 2017 ~ 2017 Deepin Technology Co., Ltd.
+ *
+ * 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 3 of the License, or
+ * 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 <http://www.gnu.org/licenses/>.
+ */
+
+#include <QCoreApplication>
+
+#include <iostream>
+
+#include <QDebug>
+#include <QFile>
+#include <QCommandLineParser>
+
+#include "settings/dsettings.h"
+#include "settings/dsettingsgroup.h"
+#include "settings/dsettingsoption.h"
+
+#include <QFile>
+#include <QJsonDocument>
+#include <QJsonObject>
+
+#include <QDomDocument>
+
+static QString CppTemplate =
+    "#include <DSettings>\n"
+    "\n"
+    "void GenerateSettingTranslate()\n"
+    "{\n"
+    "%1"
+    "}\n";
+
+/*
+ *  GVariant Type Name/Code      C++ Type Name          QVariant Type Name
+ *  --------------------------------------------------------------------------
+ *  boolean            b         bool                   QVariant::Bool
+ *  byte               y         char                   QVariant::Char
+ *  int16              n         int                    QVariant::Int
+ *  uint16             q         unsigned int           QVariant::UInt
+ *  int32              i         int                    QVariant::Int
+ *  uint32             u         unsigned int           QVariant::UInt
+ *  int64              x         long long              QVariant::LongLong
+ *  uint64             t         unsigned long long     QVariant::ULongLong
+ *  double             d         double                 QVariant::Double
+ *  string             s         QString                QVariant::String
+ *  string array*      as        QStringList            QVariant::StringList
+ *  byte array         ay        QByteArray             QVariant::ByteArray
+ *  dictionary         a{ss}     QVariantMap            QVariant::Map
+*/
+
+QString gsettings_type_from_QVarint(const QVariant::Type qtype)
+{
+    switch (qtype) {
+    case QVariant::Bool:
+        return "b";
+    case QVariant::Int:
+        return "i";
+    case QVariant::UInt:
+        return "u";
+    case QVariant::LongLong:
+        return "x";
+    case QVariant::ULongLong:
+        return "t";
+    case QVariant::Double:
+        return "d";
+    case QVariant::String:
+        return "s";
+    case QVariant::StringList:
+        return "as";
+    case QVariant::ByteArray:
+        return "ay";
+    case QVariant::Map:
+        return "a{ss}";
+    default:
+        return "";
+    }
+}
+
+QString gsettings_value_from_QVarint(const QVariant value)
+{
+    switch (value.type()) {
+    case QVariant::Bool:
+        return value.toString();
+    case QVariant::Int:
+        return value.toString();
+    case QVariant::UInt:
+        return value.toString();
+    case QVariant::LongLong:
+        return value.toString();
+    case QVariant::ULongLong:
+        return value.toString();
+    case QVariant::Double:
+        return value.toString();
+    case QVariant::String:
+        return QString("\"%1\"").arg(value.toString());
+    case QVariant::StringList:
+        return value.toString();
+    case QVariant::ByteArray:
+        return value.toString();
+    case QVariant::Map:
+        return value.toString();
+    default:
+        return "";
+    }
+}
+
+
+QJsonObject parseGSettingsMeta(const QString &jsonPath)
+{
+    QFile jsonFile(jsonPath);
+    jsonFile.open(QIODevice::ReadOnly);
+    auto jsonData = jsonFile.readAll();
+    jsonFile.close();
+
+    QJsonDocument jsonDoc = QJsonDocument::fromJson(jsonData);
+    return jsonDoc.object().value("gsettings").toObject();
+}
+
+static bool writeGSettingXML(Dtk::Core::DSettings *settings,
+                             QJsonObject gsettingsMeta,
+                             const QString &xmlPath)
+{
+    QDomDocument document;
+
+    QDomProcessingInstruction header = document.createProcessingInstruction("xml",
+                                       "version=\"1.0\" encoding=\"utf-8\"");
+    document.appendChild(header);
+
+    QDomElement schemalist = document.createElement("schemalist");
+
+    auto id = gsettingsMeta.value("id").toString();
+    auto path = gsettingsMeta.value("path").toString();
+    QDomElement schema = document.createElement("schema");
+    schema.setAttribute("id", id);
+    schema.setAttribute("path", path);
+
+    for (QString key : settings->keys()) {
+        auto codeKey = QString(key).replace(".", "-").replace("_", "-");
+        auto value = settings->option(key)->value();
+        auto gtype = gsettings_type_from_QVarint(value.type());
+        if (gtype.isEmpty()) {
+            qDebug() << "skip unsupport type:" << value.type() << key;
+            continue;
+        }
+
+        QDomElement keyXml = document.createElement("key");
+        keyXml.setAttribute("name", codeKey);
+        keyXml.setAttribute("type", gtype);
+
+        QString defaultData = gsettings_value_from_QVarint(value);
+        QDomElement defaultEle = document.createElement("default");
+        QDomCharacterData data = document.createTextNode(defaultData);
+        defaultEle.appendChild(data);
+        keyXml.appendChild(defaultEle);
+
+        schema.appendChild(keyXml);
+    }
+
+    schemalist.appendChild(schema);
+    document.appendChild(schemalist);
+
+    QFile file(xmlPath);
+    if (!file.open(QIODevice::WriteOnly)) {
+        return false;
+    }
+    QTextStream stream(&file);
+    stream << document.toString();
+    file.close();
+    return true;
+}
+
+int main(int argc, char *argv[])
+{
+    QCoreApplication app(argc, argv);
+    app.setOrganizationName("deepin");
+    app.setApplicationName("dtk-settings-tools");
+    app.setApplicationVersion("0.1.2");
+
+    QCommandLineParser parser;
+    parser.setApplicationDescription("Generate translation of dtksetting.");
+    parser.addHelpOption();
+    parser.addVersionOption();
+
+    QCommandLineOption gsettingsArg(QStringList() << "g" << "gsettings",
+                                    QCoreApplication::tr("generate gsetting schema"),
+                                    "xml-file");
+
+    QCommandLineOption outputFileArg(QStringList() << "o" << "output",
+                                     QCoreApplication::tr("Output cpp file"),
+                                     "cpp-file");
+    parser.addOption(gsettingsArg);
+    parser.addOption(outputFileArg);
+    parser.addPositionalArgument("json-file", QCoreApplication::tr("Json file description config"));
+    parser.process(app);
+
+    if (0 == (parser.optionNames().length() + parser.positionalArguments().length())) {
+        parser.showHelp(0);
+    }
+
+    auto jsonFile = parser.positionalArguments().value(0);
+    auto settings = Dtk::Core::DSettings::fromJsonFile(jsonFile);
+
+    QMap<QString, QString> transtaleMaps;
+
+//    qDebug() << settings->groupKeys();
+    for (QString groupKey : settings->groupKeys()) {
+        auto codeKey = QString(groupKey).replace(".", "_");
+        auto group = settings->group(groupKey);
+//        qDebug() << codeKey << group->name();
+        // add Name
+        if (!group->name().isEmpty()) {
+            transtaleMaps.insert("group_" + codeKey + "Name", group->name());
+        }
+
+        // TODO: only two level
+        for (auto childGroup : group->childGroups()) {
+            auto codeKey = childGroup->key().replace(".", "_");
+//            qDebug() << codeKey << childGroup->name();
+            // add Name
+            if (!childGroup->name().isEmpty()) {
+                transtaleMaps.insert("group_" + codeKey + "Name", childGroup->name());
+            }
+        }
+    }
+
+    for (QString key : settings->keys()) {
+        auto codeKey = QString(key).replace(".", "_");
+        auto opt = settings->option(key);
+
+        // add Name
+        if (!opt->name().isEmpty()) {
+            transtaleMaps.insert(codeKey + "Name", opt->name());
+        }
+
+        // add text
+        if (!opt->data("text").toString().isEmpty()) {
+            transtaleMaps.insert(codeKey + "Text", opt->data("text").toString());
+        }
+
+        // add items
+        if (!opt->data("items").toStringList().isEmpty()) {
+            auto items = opt->data("items").toStringList();
+            for (int i = 0; i < items.length(); ++i) {
+                transtaleMaps.insert(codeKey + QString("Text%1").arg(i), items.value(i));
+            }
+        }
+    }
+
+    transtaleMaps.insert("reset_button_name", "Restore Defaults");
+
+    QString cppCode;
+    for (auto key : transtaleMaps.keys()) {
+        auto stringCode = QString("    auto %1 = QObject::tr(\"%2\");\n").arg(key).arg(transtaleMaps.value(key));
+        cppCode.append(stringCode);
+    }
+
+
+    if (parser.isSet(outputFileArg)) {
+        QString outputCpp = CppTemplate.arg(cppCode);
+        QFile outputFile(parser.value(outputFileArg));
+        if (!outputFile.open(QIODevice::WriteOnly)) {
+            qCritical() << "can not open output file!";
+            exit(1);
+        }
+        outputFile.write(outputCpp.toUtf8());
+        outputFile.close();
+    }
+
+    if (parser.isSet(gsettingsArg)) {
+        QString outputXml = parser.value(gsettingsArg);
+        writeGSettingXML(settings, parseGSettingsMeta(jsonFile), outputXml);
+    }
+
+    return 0;
+}
+
diff --git a/tools/settings/settings.pro b/tools/settings/settings.pro
new file mode 100644 (file)
index 0000000..e973d88
--- /dev/null
@@ -0,0 +1,32 @@
+QT += core xml
+QT -= gui
+
+CONFIG += c++11
+
+TARGET = dtk-settings
+CONFIG += console link_pkgconfig
+CONFIG -= app_bundle
+PKGCONFIG += gsettings-qt
+
+TEMPLATE = app
+
+SOURCES += main.cpp
+
+isEmpty(PREFIX){
+    PREFIX = /usr
+}
+
+binary.files += $${OUT_PWD}/dtk-settings
+binary.path = $${PREFIX}/lib/dtk2/libexec
+
+script.files += $${PWD}/../script/*.py
+script.path = $${PREFIX}/lib/dtk2
+
+INSTALLS += binary script
+
+win32:CONFIG(release, debug|release): LIBS += -L$$OUT_PWD/../../src/release/ -ldtkcore
+else:win32:CONFIG(debug, debug|release): LIBS += -L$$OUT_PWD/../../src/debug/ -ldtkcore
+else:unix: LIBS += -L$$OUT_PWD/../../src/ -ldtkcore
+
+INCLUDEPATH += $$PWD/../../src
+DEPENDPATH += $$PWD/../../src
diff --git a/tools/tools.pro b/tools/tools.pro
new file mode 100644 (file)
index 0000000..aeaeb47
--- /dev/null
@@ -0,0 +1,6 @@
+TEMPLATE = subdirs
+
+CONFIG += ordered
+
+SUBDIRS +=   \
+    settings \