<commit_before>#include "assert.hh"
#include "buffer.hh"
#include "buffer_manager.hh"
#include "buffer_utils.hh"
#include "client_manager.hh"
#include "color_registry.hh"
#include "command_manager.hh"
#include "commands.hh"
#include "context.hh"
#include "debug.hh"
#include "event_manager.hh"
#include "file.hh"
#include "highlighters.hh"
#include "hook_manager.hh"
#include "ncurses.hh"
#include "option_manager.hh"
#include "keymap_manager.hh"
#include "parameters_parser.hh"
#include "register_manager.hh"
#include "remote.hh"
#include "shell_manager.hh"
#include "string.hh"
#include "window.hh"

#if defined(__APPLE__)
#include <mach-o/dyld.h>
#endif

#include <unordered_map>
#include <locale>
#include <signal.h>

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>

using namespace Kakoune;

void run_unit_tests();

String runtime_directory()
{
    char buffer[2048];
#if defined(__linux__) || defined(__CYGWIN__)
    ssize_t res = readlink("/proc/self/exe", buffer, 2048);
    kak_assert(res != -1);
    buffer[res] = '\0';
#elif defined(__APPLE__)
    uint32_t bufsize = 2048;
    _NSGetExecutablePath(buffer, &bufsize);
    char* canonical_path = realpath(buffer, nullptr);
    strncpy(buffer, canonical_path, 2048);
    free(canonical_path);
#else
# error "finding executable path is not implemented on this platform"
#endif
    char* ptr = strrchr(buffer, '/');
    if (not ptr)
        throw runtime_error("unable to determine runtime directory");
    return String(buffer, ptr) + "/../share/kak";
}

void register_env_vars()
{
    static const struct {
        const char* name;
        String (*func)(StringView, const Context&);
    } env_vars[] = { {
            "bufname",
            [](StringView name, const Context& context)
            { return context.buffer().display_name(); }
        }, {
            "buffile",
            [](StringView name, const Context& context) -> String
            { return context.buffer().name(); }
        }, {
            "timestamp",
            [](StringView name, const Context& context)
            { return to_string(context.buffer().timestamp()); }
        }, {
            "selection",
            [](StringView name, const Context& context)
            { const Selection& sel = context.selections().main();
              return content(context.buffer(), sel); }
        }, {
            "selections",
            [](StringView name, const Context& context)
            { auto sels = context.selections_content();
              String res;
              for (size_t i = 0; i < sels.size(); ++i)
              {
                  res += escape(sels[i], ':', '\\');
                  if (i != sels.size() - 1)
                      res += ':';
              }
              return res; }
        }, {
            "runtime",
            [](StringView name, const Context& context)
            { return runtime_directory(); }
        }, {
            "opt_.+",
            [](StringView name, const Context& context)
            { return context.options()[name.substr(4_byte)].get_as_string(); }
        }, {
            "reg_.+",
            [](StringView name, const Context& context) -> String
            { return RegisterManager::instance()[name[4]].values(context)[0]; }
        }, {
            "client_env_.+",
            [](StringView name, const Context& context) -> String
            { return context.client().get_env_var(name.substr(11_byte)); }
        }, {
            "session",
            [](StringView name, const Context& context) -> String
            { return Server::instance().session(); }
        }, {
            "client",
            [](StringView name, const Context& context) -> String
            { return context.name(); }
        }, {
            "cursor_line",
            [](StringView name, const Context& context)
            { return to_string(context.selections().main().cursor().line + 1); }
        }, {
            "cursor_column",
            [](StringView name, const Context& context)
            { return to_string(context.selections().main().cursor().column + 1); }
        }, {
            "cursor_char_column",
            [](StringView name, const Context& context)
            { auto coord = context.selections().main().cursor();
              return to_string(context.buffer()[coord.line].char_count_to(coord.column) + 1); }
        }, {
            "selection_desc",
            [](StringView name, const Context& context)
            { auto& sel = context.selections().main();
                auto beg = sel.min();
                return to_string(beg.line + 1) + ':' + to_string(beg.column + 1) + '+' +
                       to_string((int)context.buffer().distance(beg, sel.max())+1); }
        }, {
            "window_width",
            [](StringView name, const Context& context)
            { return to_string(context.window().dimensions().column); }
        }, {
            "window_height",
            [](StringView name, const Context& context)
            { return to_string(context.window().dimensions().line); }
    } };

    ShellManager& shell_manager = ShellManager::instance();
    for (auto& env_var : env_vars)
        shell_manager.register_env_var(env_var.name, env_var.func);
}

void register_registers()
{
    using StringList = std::vector<String>;
    static const struct {
        char name;
        StringList (*func)(const Context&);
    } dyn_regs[] = {
        { '%', [](const Context& context) { return StringList{{context.buffer().display_name()}}; } },
        { '.', [](const Context& context) { return context.selections_content(); } },
        { '#', [](const Context& context) {
            StringList res;
            for (size_t i = 1; i < context.selections().size(); ++i)
                res.push_back(to_string((int)i));
            return res;
        } }
    };

    RegisterManager& register_manager = RegisterManager::instance();
    for (auto& dyn_reg : dyn_regs)
        register_manager.register_dynamic_register(dyn_reg.name, dyn_reg.func);

    for (size_t i = 0; i < 10; ++i)
    {
        register_manager.register_dynamic_register('0'+i,
            [i](const Context& context) {
                std::vector<String> result;
                for (auto& sel : context.selections())
                    result.emplace_back(i < sel.captures().size() ? sel.captures()[i] : "");
                return result;
            });
    }
}

void create_local_client(const String& init_command)
{
    class LocalNCursesUI : public NCursesUI
    {
        ~LocalNCursesUI()
        {
            if (not ClientManager::instance().empty() and fork())
            {
                this->NCursesUI::~NCursesUI();
                puts("detached from terminal\n");
                exit(0);
            }
        }
    };

    if (not isatty(1))
        throw runtime_error("stdout is not a tty");

    if (not isatty(0))
    {
        // move stdin to another fd, and restore tty as stdin
        int fd = dup(0);
        int tty = open("/dev/tty", O_RDONLY);
        dup2(tty, 0);
        close(tty);
        create_fifo_buffer("*stdin*", fd);
    }

    UserInterface* ui = new LocalNCursesUI{};
    static Client* client = ClientManager::instance().create_client(
        std::unique_ptr<UserInterface>{ui}, get_env_vars(), init_command);
    signal(SIGHUP, [](int) {
        if (client)
            ClientManager::instance().remove_client(*client);
        client = nullptr;
    });
}

void signal_handler(int signal)
{
    NCursesUI::abort();
    const char* text = nullptr;
    switch (signal)
    {
        case SIGSEGV: text = "SIGSEGV"; break;
        case SIGFPE:  text = "SIGFPE";  break;
        case SIGQUIT: text = "SIGQUIT"; break;
        case SIGTERM: text = "SIGTERM"; break;
    }
    on_assert_failed(text);
    if (Server::has_instance())
        Server::instance().close_session();
    abort();
}

int run_client(const String& session, const String& init_command)
{
    try
    {
        EventManager event_manager;
        auto client = connect_to(session,
                                 std::unique_ptr<UserInterface>{new NCursesUI{}},
                                 get_env_vars(),
                                 init_command);
        while (true)
            event_manager.handle_next_events();
    }
    catch (peer_disconnected&)
    {
        fputs("disconnected from server\n", stderr);
        return -1;
    }
    catch (connection_failed& e)
    {
        fputs(e.what(), stderr);
        return -1;
    }
    return 0;
}

int kakoune(const ParametersParser& parser)
{
    if (parser.has_option("p"))
    {
        for (auto opt : { "c", "n", "s", "d", "e" })
        {
            if (parser.has_option(opt))
            {
                fprintf(stderr, "error: -%s makes not sense with -p\n", opt);
                return -1;
            }
        }
        char buf[512];
        String command;
        while (ssize_t count = read(0, buf, 512))
        {
            if (count < 0)
            {
                fprintf(stderr, "error while reading stdin\n");
                return -1;
            }
            command += String{buf, buf + count};
        }
        try
        {
            send_command(parser.option_value("p"), command);
        }
        catch (connection_failed& e)
        {
            fputs(e.what(), stderr);
            return -1;
        }
        return 0;
    }

    String init_command;
    if (parser.has_option("e"))
        init_command = parser.option_value("e");

    if (parser.has_option("c"))
    {
        for (auto opt : { "n", "s", "d" })
        {
            if (parser.has_option(opt))
            {
                fprintf(stderr, "error: -%s makes not sense with -c\n", opt);
                return -1;
            }
        }
        return run_client(parser.option_value("c"), init_command);
    }

    const bool daemon = parser.has_option("d");
    static bool terminate = false;
    if (daemon)
    {
        if (not parser.has_option("s"))
        {
            fputs("-d needs a session name to be specified with -s\n", stderr);
            return -1;
        }
        if (pid_t child = fork())
        {
            printf("Kakoune forked to background, for session '%s'\n"
                   "send SIGTERM to process %d for closing the session\n",
                   parser.option_value("s").c_str(), child);
            exit(0);
        }
        signal(SIGTERM, [](int) { terminate = true; });
    }

    EventManager        event_manager;
    GlobalOptions       global_options;
    GlobalHooks         global_hooks;
    GlobalKeymaps       global_keymaps;
    ShellManager        shell_manager;
    CommandManager      command_manager;
    BufferManager       buffer_manager;
    RegisterManager     register_manager;
    HighlighterRegistry highlighter_registry;
    DefinedHighlighters defined_highlighters;
    ColorRegistry       color_registry;
    ClientManager       client_manager;

    run_unit_tests();

    register_env_vars();
    register_registers();
    register_commands();
    register_highlighters();

    write_debug("*** This is the debug buffer, where debug info will be written ***");
    write_debug("pid: " + to_string(getpid()));

    Server server(parser.has_option("s") ? parser.option_value("s") : to_string(getpid()));
    write_debug("session: " + server.session());

    if (not parser.has_option("n")) try
    {
        Context initialisation_context;
        command_manager.execute("source " + runtime_directory() + "/kakrc",
                                initialisation_context);
    }
    catch (Kakoune::runtime_error& error)
    {
        write_debug("error while parsing kakrc:\n    "_str + error.what());
    }
    catch (Kakoune::client_removed&)
    {
        write_debug("error while parsing kakrc: asked to quit");
    }

    {
        Context empty_context;
        global_hooks.run_hook("KakBegin", "", empty_context);
    }

    if (parser.positional_count() != 0) try
    {
        // create buffers in reverse order so that the first given buffer
        // is the most recently created one.
        for (int i = parser.positional_count() - 1; i >= 0; --i)
        {
            const String& file = parser[i];
            if (not create_buffer_from_file(file))
                new Buffer(file, Buffer::Flags::New | Buffer::Flags::File);
        }
    }
    catch (Kakoune::runtime_error& error)
    {
         write_debug("error while opening command line files: "_str + error.what());
    }
    else
        new Buffer("*scratch*", Buffer::Flags::None);

    if (not daemon)
        create_local_client(init_command);

    while (not terminate and (not client_manager.empty() or daemon))
        event_manager.handle_next_events();

    {
        Context empty_context;
        global_hooks.run_hook("KakEnd", "", empty_context);
    }
    return 0;
}

int main(int argc, char* argv[])
{
    setlocale(LC_ALL, "");

    signal(SIGSEGV, signal_handler);
    signal(SIGFPE,  signal_handler);
    signal(SIGQUIT, signal_handler);
    signal(SIGTERM, signal_handler);

    std::vector<String> params;
    for (size_t i = 1; i < argc; ++i)
        params.push_back(argv[i]);

    const ParameterDesc param_desc{
        SwitchMap{ { "c", { true, "connect to given session" } },
                   { "e", { true, "execute argument on initialisation" } },
                   { "n", { false, "do not source kakrc files on startup" } },
                   { "s", { true, "set session name" } },
                   { "d", { false, "run as a headless session (requires -s)" } },
                   { "p", { true, "just send stdin as commands to the given session" } } }
    };
    try
    {
        kakoune(ParametersParser(params, param_desc));
    }
    catch (Kakoune::parameter_error& error)
    {
        printf("Error: %s\n"
               "Valid switches:\n"
               "%s",
               error.what(), generate_switches_doc(param_desc.switches).c_str());
       return -1;
    }
    catch (Kakoune::exception& error)
    {
        on_assert_failed(("uncaught exception:\n"_str + error.what()).c_str());
        return -1;
    }
    catch (std::exception& error)
    {
        on_assert_failed(("uncaught exception:\n"_str + error.what()).c_str());
        return -1;
    }
    catch (...)
    {
        on_assert_failed("uncaught exception");
        return -1;
    }
    return 0;
}
<commit_msg>Add kak_selections_desc en vars, containing : separated descs<commit_after>#include "assert.hh"
#include "buffer.hh"
#include "buffer_manager.hh"
#include "buffer_utils.hh"
#include "client_manager.hh"
#include "color_registry.hh"
#include "command_manager.hh"
#include "commands.hh"
#include "context.hh"
#include "debug.hh"
#include "event_manager.hh"
#include "file.hh"
#include "highlighters.hh"
#include "hook_manager.hh"
#include "ncurses.hh"
#include "option_manager.hh"
#include "keymap_manager.hh"
#include "parameters_parser.hh"
#include "register_manager.hh"
#include "remote.hh"
#include "shell_manager.hh"
#include "string.hh"
#include "window.hh"

#if defined(__APPLE__)
#include <mach-o/dyld.h>
#endif

#include <unordered_map>
#include <locale>
#include <signal.h>

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>

using namespace Kakoune;

void run_unit_tests();

String runtime_directory()
{
    char buffer[2048];
#if defined(__linux__) || defined(__CYGWIN__)
    ssize_t res = readlink("/proc/self/exe", buffer, 2048);
    kak_assert(res != -1);
    buffer[res] = '\0';
#elif defined(__APPLE__)
    uint32_t bufsize = 2048;
    _NSGetExecutablePath(buffer, &bufsize);
    char* canonical_path = realpath(buffer, nullptr);
    strncpy(buffer, canonical_path, 2048);
    free(canonical_path);
#else
# error "finding executable path is not implemented on this platform"
#endif
    char* ptr = strrchr(buffer, '/');
    if (not ptr)
        throw runtime_error("unable to determine runtime directory");
    return String(buffer, ptr) + "/../share/kak";
}

void register_env_vars()
{
    static const struct {
        const char* name;
        String (*func)(StringView, const Context&);
    } env_vars[] = { {
            "bufname",
            [](StringView name, const Context& context)
            { return context.buffer().display_name(); }
        }, {
            "buffile",
            [](StringView name, const Context& context) -> String
            { return context.buffer().name(); }
        }, {
            "timestamp",
            [](StringView name, const Context& context)
            { return to_string(context.buffer().timestamp()); }
        }, {
            "selection",
            [](StringView name, const Context& context)
            { const Selection& sel = context.selections().main();
              return content(context.buffer(), sel); }
        }, {
            "selections",
            [](StringView name, const Context& context)
            { auto sels = context.selections_content();
              String res;
              for (size_t i = 0; i < sels.size(); ++i)
              {
                  res += escape(sels[i], ':', '\\');
                  if (i != sels.size() - 1)
                      res += ':';
              }
              return res; }
        }, {
            "runtime",
            [](StringView name, const Context& context)
            { return runtime_directory(); }
        }, {
            "opt_.+",
            [](StringView name, const Context& context)
            { return context.options()[name.substr(4_byte)].get_as_string(); }
        }, {
            "reg_.+",
            [](StringView name, const Context& context) -> String
            { return RegisterManager::instance()[name[4]].values(context)[0]; }
        }, {
            "client_env_.+",
            [](StringView name, const Context& context) -> String
            { return context.client().get_env_var(name.substr(11_byte)); }
        }, {
            "session",
            [](StringView name, const Context& context) -> String
            { return Server::instance().session(); }
        }, {
            "client",
            [](StringView name, const Context& context) -> String
            { return context.name(); }
        }, {
            "cursor_line",
            [](StringView name, const Context& context)
            { return to_string(context.selections().main().cursor().line + 1); }
        }, {
            "cursor_column",
            [](StringView name, const Context& context)
            { return to_string(context.selections().main().cursor().column + 1); }
        }, {
            "cursor_char_column",
            [](StringView name, const Context& context)
            { auto coord = context.selections().main().cursor();
              return to_string(context.buffer()[coord.line].char_count_to(coord.column) + 1); }
        }, {
            "selection_desc",
            [](StringView name, const Context& context)
            { auto& sel = context.selections().main();
                auto beg = sel.min();
                return to_string(beg.line + 1) + '.' + to_string(beg.column + 1) + '+' +
                       to_string((int)context.buffer().distance(beg, sel.max())+1); }
        }, {
            "selections_desc",
            [](StringView name, const Context& context)
            {
                String res;
                for (auto& sel : context.selections())
                {
                    auto beg = sel.min();
                    if (not res.empty())
                        res += ':';
                    res += to_string(beg.line + 1) + '.' + to_string(beg.column + 1) + '+' +
                           to_string((int)context.buffer().distance(beg, sel.max())+1);
                }
                return res;
            }
        }, {
            "window_width",
            [](StringView name, const Context& context)
            { return to_string(context.window().dimensions().column); }
        }, {
            "window_height",
            [](StringView name, const Context& context)
            { return to_string(context.window().dimensions().line); }
    } };

    ShellManager& shell_manager = ShellManager::instance();
    for (auto& env_var : env_vars)
        shell_manager.register_env_var(env_var.name, env_var.func);
}

void register_registers()
{
    using StringList = std::vector<String>;
    static const struct {
        char name;
        StringList (*func)(const Context&);
    } dyn_regs[] = {
        { '%', [](const Context& context) { return StringList{{context.buffer().display_name()}}; } },
        { '.', [](const Context& context) { return context.selections_content(); } },
        { '#', [](const Context& context) {
            StringList res;
            for (size_t i = 1; i < context.selections().size(); ++i)
                res.push_back(to_string((int)i));
            return res;
        } }
    };

    RegisterManager& register_manager = RegisterManager::instance();
    for (auto& dyn_reg : dyn_regs)
        register_manager.register_dynamic_register(dyn_reg.name, dyn_reg.func);

    for (size_t i = 0; i < 10; ++i)
    {
        register_manager.register_dynamic_register('0'+i,
            [i](const Context& context) {
                std::vector<String> result;
                for (auto& sel : context.selections())
                    result.emplace_back(i < sel.captures().size() ? sel.captures()[i] : "");
                return result;
            });
    }
}

void create_local_client(const String& init_command)
{
    class LocalNCursesUI : public NCursesUI
    {
        ~LocalNCursesUI()
        {
            if (not ClientManager::instance().empty() and fork())
            {
                this->NCursesUI::~NCursesUI();
                puts("detached from terminal\n");
                exit(0);
            }
        }
    };

    if (not isatty(1))
        throw runtime_error("stdout is not a tty");

    if (not isatty(0))
    {
        // move stdin to another fd, and restore tty as stdin
        int fd = dup(0);
        int tty = open("/dev/tty", O_RDONLY);
        dup2(tty, 0);
        close(tty);
        create_fifo_buffer("*stdin*", fd);
    }

    UserInterface* ui = new LocalNCursesUI{};
    static Client* client = ClientManager::instance().create_client(
        std::unique_ptr<UserInterface>{ui}, get_env_vars(), init_command);
    signal(SIGHUP, [](int) {
        if (client)
            ClientManager::instance().remove_client(*client);
        client = nullptr;
    });
}

void signal_handler(int signal)
{
    NCursesUI::abort();
    const char* text = nullptr;
    switch (signal)
    {
        case SIGSEGV: text = "SIGSEGV"; break;
        case SIGFPE:  text = "SIGFPE";  break;
        case SIGQUIT: text = "SIGQUIT"; break;
        case SIGTERM: text = "SIGTERM"; break;
    }
    on_assert_failed(text);
    if (Server::has_instance())
        Server::instance().close_session();
    abort();
}

int run_client(const String& session, const String& init_command)
{
    try
    {
        EventManager event_manager;
        auto client = connect_to(session,
                                 std::unique_ptr<UserInterface>{new NCursesUI{}},
                                 get_env_vars(),
                                 init_command);
        while (true)
            event_manager.handle_next_events();
    }
    catch (peer_disconnected&)
    {
        fputs("disconnected from server\n", stderr);
        return -1;
    }
    catch (connection_failed& e)
    {
        fputs(e.what(), stderr);
        return -1;
    }
    return 0;
}

int kakoune(const ParametersParser& parser)
{
    if (parser.has_option("p"))
    {
        for (auto opt : { "c", "n", "s", "d", "e" })
        {
            if (parser.has_option(opt))
            {
                fprintf(stderr, "error: -%s makes not sense with -p\n", opt);
                return -1;
            }
        }
        char buf[512];
        String command;
        while (ssize_t count = read(0, buf, 512))
        {
            if (count < 0)
            {
                fprintf(stderr, "error while reading stdin\n");
                return -1;
            }
            command += String{buf, buf + count};
        }
        try
        {
            send_command(parser.option_value("p"), command);
        }
        catch (connection_failed& e)
        {
            fputs(e.what(), stderr);
            return -1;
        }
        return 0;
    }

    String init_command;
    if (parser.has_option("e"))
        init_command = parser.option_value("e");

    if (parser.has_option("c"))
    {
        for (auto opt : { "n", "s", "d" })
        {
            if (parser.has_option(opt))
            {
                fprintf(stderr, "error: -%s makes not sense with -c\n", opt);
                return -1;
            }
        }
        return run_client(parser.option_value("c"), init_command);
    }

    const bool daemon = parser.has_option("d");
    static bool terminate = false;
    if (daemon)
    {
        if (not parser.has_option("s"))
        {
            fputs("-d needs a session name to be specified with -s\n", stderr);
            return -1;
        }
        if (pid_t child = fork())
        {
            printf("Kakoune forked to background, for session '%s'\n"
                   "send SIGTERM to process %d for closing the session\n",
                   parser.option_value("s").c_str(), child);
            exit(0);
        }
        signal(SIGTERM, [](int) { terminate = true; });
    }

    EventManager        event_manager;
    GlobalOptions       global_options;
    GlobalHooks         global_hooks;
    GlobalKeymaps       global_keymaps;
    ShellManager        shell_manager;
    CommandManager      command_manager;
    BufferManager       buffer_manager;
    RegisterManager     register_manager;
    HighlighterRegistry highlighter_registry;
    DefinedHighlighters defined_highlighters;
    ColorRegistry       color_registry;
    ClientManager       client_manager;

    run_unit_tests();

    register_env_vars();
    register_registers();
    register_commands();
    register_highlighters();

    write_debug("*** This is the debug buffer, where debug info will be written ***");
    write_debug("pid: " + to_string(getpid()));

    Server server(parser.has_option("s") ? parser.option_value("s") : to_string(getpid()));
    write_debug("session: " + server.session());

    if (not parser.has_option("n")) try
    {
        Context initialisation_context;
        command_manager.execute("source " + runtime_directory() + "/kakrc",
                                initialisation_context);
    }
    catch (Kakoune::runtime_error& error)
    {
        write_debug("error while parsing kakrc:\n    "_str + error.what());
    }
    catch (Kakoune::client_removed&)
    {
        write_debug("error while parsing kakrc: asked to quit");
    }

    {
        Context empty_context;
        global_hooks.run_hook("KakBegin", "", empty_context);
    }

    if (parser.positional_count() != 0) try
    {
        // create buffers in reverse order so that the first given buffer
        // is the most recently created one.
        for (int i = parser.positional_count() - 1; i >= 0; --i)
        {
            const String& file = parser[i];
            if (not create_buffer_from_file(file))
                new Buffer(file, Buffer::Flags::New | Buffer::Flags::File);
        }
    }
    catch (Kakoune::runtime_error& error)
    {
         write_debug("error while opening command line files: "_str + error.what());
    }
    else
        new Buffer("*scratch*", Buffer::Flags::None);

    if (not daemon)
        create_local_client(init_command);

    while (not terminate and (not client_manager.empty() or daemon))
        event_manager.handle_next_events();

    {
        Context empty_context;
        global_hooks.run_hook("KakEnd", "", empty_context);
    }
    return 0;
}

int main(int argc, char* argv[])
{
    setlocale(LC_ALL, "");

    signal(SIGSEGV, signal_handler);
    signal(SIGFPE,  signal_handler);
    signal(SIGQUIT, signal_handler);
    signal(SIGTERM, signal_handler);

    std::vector<String> params;
    for (size_t i = 1; i < argc; ++i)
        params.push_back(argv[i]);

    const ParameterDesc param_desc{
        SwitchMap{ { "c", { true, "connect to given session" } },
                   { "e", { true, "execute argument on initialisation" } },
                   { "n", { false, "do not source kakrc files on startup" } },
                   { "s", { true, "set session name" } },
                   { "d", { false, "run as a headless session (requires -s)" } },
                   { "p", { true, "just send stdin as commands to the given session" } } }
    };
    try
    {
        kakoune(ParametersParser(params, param_desc));
    }
    catch (Kakoune::parameter_error& error)
    {
        printf("Error: %s\n"
               "Valid switches:\n"
               "%s",
               error.what(), generate_switches_doc(param_desc.switches).c_str());
       return -1;
    }
    catch (Kakoune::exception& error)
    {
        on_assert_failed(("uncaught exception:\n"_str + error.what()).c_str());
        return -1;
    }
    catch (std::exception& error)
    {
        on_assert_failed(("uncaught exception:\n"_str + error.what()).c_str());
        return -1;
    }
    catch (...)
    {
        on_assert_failed("uncaught exception");
        return -1;
    }
    return 0;
}
<|endoftext|>


<commit_before>#include <Core/Animation/Handle/HandleWeightOperation.hpp>

#include <utility>
#include <Core/Log/Log.hpp>

namespace Ra {
namespace Core {
namespace Animation {

WeightMatrix extractWeightMatrix(const MeshWeight &weight,
                                 const uint weight_size)
{
    WeightMatrix W(weight.size(), weight_size);
    W.setZero();
    for (uint i = 0; i < weight.size(); ++i)
    {
        for (const auto& w : weight[i])
        {
            W.coeffRef(i, w.first) = w.second;
        }
    }
    return W;
}

MeshWeight extractMeshWeight(Eigen::Ref<const WeightMatrix> matrix)
{
    MeshWeight W(matrix.rows());
    for (int i = 0; i < matrix.rows(); ++i)
    {
        for (int j = 0; j < matrix.cols(); ++j)
        {
            if (matrix.coeff(i, j) != 0.0)
            {
                std::pair<uint, Scalar> w(uint(j), matrix.coeff(i, j));
                W[i].push_back(w);
            }
        }
    }
    return W;
}

WeightMatrix partitionOfUnity( Eigen::Ref<const WeightMatrix> weights ) {
    WeightMatrix W = weights;
    normalizeWeights(W);
    return W;
}

uint getMaxWeightIndex(Eigen::Ref<const WeightMatrix> weights,
                       const uint vertexID ) {
    uint maxId = uint( -1 );
    VectorN row = weights.row( vertexID );
    row.maxCoeff(&maxId);
    return maxId;
}

void getMaxWeightIndex( Eigen::Ref<const WeightMatrix> weights,
                        std::vector< uint >& handleID ) {
    handleID.resize( weights.rows() );
    for( int i = 0; i < weights.rows(); ++i ) {
        handleID[i] = getMaxWeightIndex( weights, i );
    }
}

void checkWeightMatrix( Eigen::Ref<const WeightMatrix> matrix,
                        const bool FAIL_ON_ASSERT, const bool MT ) {
    if( check_NAN( matrix, FAIL_ON_ASSERT, MT ) ) {
        LOG( logDEBUG ) << "Matrix is good.";
    } else {
        LOG( logDEBUG ) << "Matrix is not good.";
    }

    if( check_NoWeightVertex( matrix, FAIL_ON_ASSERT, MT ) ) {
        LOG( logDEBUG ) << "Matrix is good.";
    } else {
        LOG( logDEBUG ) << "Matrix is not good.";
    }
}

bool RA_CORE_API check_NAN(Eigen::Ref<const WeightMatrix> matrix,
                           const bool FAIL_ON_ASSERT, const bool MT ) {
    using Iterator = Eigen::Ref<const WeightMatrix>::InnerIterator;
    int status = 1;
    LOG( logDEBUG ) << "Searching for nans in the matrix...";
    if( MT ) {
        #pragma omp parallel for
        for( int k = 0; k < matrix.outerSize(); ++k ) {
            for( Iterator it( matrix, k ); it; ++it ) {
                const Scalar      value = it.value();
                const int check = std::isnan( value ) ? 0 : 1;
                #pragma omp atomic
                status &= check ;
            }
        }
        if( status == 0 ) {
            if( FAIL_ON_ASSERT ) {
                CORE_ASSERT( false, "At least an element is nan" );
            } else {
                LOG( logDEBUG ) << "At least an element is nan";
            }
        }
    } else {
        for( int k = 0; k < matrix.outerSize(); ++k ) {
            for( Iterator it( matrix, k ); it; ++it ) {
                const uint        i     = it.row();
                const uint        j     = it.col();
                const Scalar      value = it.value();
                const std::string text  = "Element (" + std::to_string( i ) + "," + std::to_string(j) + ") is nan.";
                if( FAIL_ON_ASSERT ) {
                    CORE_ASSERT( !std::isnan( value ), text.c_str() );
                } else {
                    if( std::isnan( value ) ) {
                        LOG( logDEBUG ) << text;
                        status = 0;
                    }
                }
            }
        }
    }
    return status != 0;
}

bool RA_CORE_API check_NoWeightVertex( Eigen::Ref<const WeightMatrix> matrix,
                                       const bool FAIL_ON_ASSERT, const bool MT ) {
    int status = 1;
    LOG( logDEBUG ) << "Searching for empty rows in the matrix...";
    if( MT ) {
        #pragma omp parallel for
        for( int i = 0; i < matrix.rows(); ++i ) {
            Sparse row = matrix.row( i );
            const int check = ( row.nonZeros() > 0 ) ? 1 : 0;
            #pragma omp atomic
            status &= check;
        }
        if( status == 0 ) {
            if( FAIL_ON_ASSERT ) {
                CORE_ASSERT( false, "At least a vertex as no weights" );
            } else {
                LOG( logDEBUG ) << "At least a vertex as no weights";
            }
        }
    } else {
        for( int i = 0; i < matrix.rows(); ++i ) {
            Sparse row = matrix.row( i );
            if( row.nonZeros() == 0 ) {
                const std::string text = "Vertex " + std::to_string( i ) + " has no weights.";
                if( FAIL_ON_ASSERT ) {
                    CORE_ASSERT( false, text.c_str() );
                } else {
                    status = 0;
                    LOG( logDEBUG ) << text;
                }
            }
        }
    }
    return status != 0;
}

bool RA_CORE_API normalizeWeights(Eigen::Ref<WeightMatrix> matrix, const bool MT)
{
    CORE_UNUSED(MT)

    bool skinningWeightOk = true;

    #pragma omp parallel for if(MT)
    for (int k = 0; k < matrix.innerSize(); ++k)
    {
        const Scalar sum = matrix.row( k ).sum();
        if(! Ra::Core::Math::areApproxEqual(sum, Scalar(0))){
            skinningWeightOk &= Ra::Core::Math::areApproxEqual(sum, Scalar(1));
            matrix.row( k ) /= sum;
        }
    }
    return ! skinningWeightOk;
}

} // namespace Animation
} // Namespace Core
} // Namespace Ra
<commit_msg>Normalized only when necessary<commit_after>#include <Core/Animation/Handle/HandleWeightOperation.hpp>

#include <utility>
#include <Core/Log/Log.hpp>

namespace Ra {
namespace Core {
namespace Animation {

WeightMatrix extractWeightMatrix(const MeshWeight &weight,
                                 const uint weight_size)
{
    WeightMatrix W(weight.size(), weight_size);
    W.setZero();
    for (uint i = 0; i < weight.size(); ++i)
    {
        for (const auto& w : weight[i])
        {
            W.coeffRef(i, w.first) = w.second;
        }
    }
    return W;
}

MeshWeight extractMeshWeight(Eigen::Ref<const WeightMatrix> matrix)
{
    MeshWeight W(matrix.rows());
    for (int i = 0; i < matrix.rows(); ++i)
    {
        for (int j = 0; j < matrix.cols(); ++j)
        {
            if (matrix.coeff(i, j) != 0.0)
            {
                std::pair<uint, Scalar> w(uint(j), matrix.coeff(i, j));
                W[i].push_back(w);
            }
        }
    }
    return W;
}

WeightMatrix partitionOfUnity( Eigen::Ref<const WeightMatrix> weights ) {
    WeightMatrix W = weights;
    normalizeWeights(W);
    return W;
}

uint getMaxWeightIndex(Eigen::Ref<const WeightMatrix> weights,
                       const uint vertexID ) {
    uint maxId = uint( -1 );
    VectorN row = weights.row( vertexID );
    row.maxCoeff(&maxId);
    return maxId;
}

void getMaxWeightIndex( Eigen::Ref<const WeightMatrix> weights,
                        std::vector< uint >& handleID ) {
    handleID.resize( weights.rows() );
    for( int i = 0; i < weights.rows(); ++i ) {
        handleID[i] = getMaxWeightIndex( weights, i );
    }
}

void checkWeightMatrix( Eigen::Ref<const WeightMatrix> matrix,
                        const bool FAIL_ON_ASSERT, const bool MT ) {
    if( check_NAN( matrix, FAIL_ON_ASSERT, MT ) ) {
        LOG( logDEBUG ) << "Matrix is good.";
    } else {
        LOG( logDEBUG ) << "Matrix is not good.";
    }

    if( check_NoWeightVertex( matrix, FAIL_ON_ASSERT, MT ) ) {
        LOG( logDEBUG ) << "Matrix is good.";
    } else {
        LOG( logDEBUG ) << "Matrix is not good.";
    }
}

bool RA_CORE_API check_NAN(Eigen::Ref<const WeightMatrix> matrix,
                           const bool FAIL_ON_ASSERT, const bool MT ) {
    using Iterator = Eigen::Ref<const WeightMatrix>::InnerIterator;
    int status = 1;
    LOG( logDEBUG ) << "Searching for nans in the matrix...";
    if( MT ) {
        #pragma omp parallel for
        for( int k = 0; k < matrix.outerSize(); ++k ) {
            for( Iterator it( matrix, k ); it; ++it ) {
                const Scalar      value = it.value();
                const int check = std::isnan( value ) ? 0 : 1;
                #pragma omp atomic
                status &= check ;
            }
        }
        if( status == 0 ) {
            if( FAIL_ON_ASSERT ) {
                CORE_ASSERT( false, "At least an element is nan" );
            } else {
                LOG( logDEBUG ) << "At least an element is nan";
            }
        }
    } else {
        for( int k = 0; k < matrix.outerSize(); ++k ) {
            for( Iterator it( matrix, k ); it; ++it ) {
                const uint        i     = it.row();
                const uint        j     = it.col();
                const Scalar      value = it.value();
                const std::string text  = "Element (" + std::to_string( i ) + "," + std::to_string(j) + ") is nan.";
                if( FAIL_ON_ASSERT ) {
                    CORE_ASSERT( !std::isnan( value ), text.c_str() );
                } else {
                    if( std::isnan( value ) ) {
                        LOG( logDEBUG ) << text;
                        status = 0;
                    }
                }
            }
        }
    }
    return status != 0;
}

bool RA_CORE_API check_NoWeightVertex( Eigen::Ref<const WeightMatrix> matrix,
                                       const bool FAIL_ON_ASSERT, const bool MT ) {
    int status = 1;
    LOG( logDEBUG ) << "Searching for empty rows in the matrix...";
    if( MT ) {
        #pragma omp parallel for
        for( int i = 0; i < matrix.rows(); ++i ) {
            Sparse row = matrix.row( i );
            const int check = ( row.nonZeros() > 0 ) ? 1 : 0;
            #pragma omp atomic
            status &= check;
        }
        if( status == 0 ) {
            if( FAIL_ON_ASSERT ) {
                CORE_ASSERT( false, "At least a vertex as no weights" );
            } else {
                LOG( logDEBUG ) << "At least a vertex as no weights";
            }
        }
    } else {
        for( int i = 0; i < matrix.rows(); ++i ) {
            Sparse row = matrix.row( i );
            if( row.nonZeros() == 0 ) {
                const std::string text = "Vertex " + std::to_string( i ) + " has no weights.";
                if( FAIL_ON_ASSERT ) {
                    CORE_ASSERT( false, text.c_str() );
                } else {
                    status = 0;
                    LOG( logDEBUG ) << text;
                }
            }
        }
    }
    return status != 0;
}

bool RA_CORE_API normalizeWeights(Eigen::Ref<WeightMatrix> matrix, const bool MT)
{
    CORE_UNUSED(MT);

    bool skinningWeightOk = true;

    #pragma omp parallel for if(MT)
    for (int k = 0; k < matrix.innerSize(); ++k)
    {
        const Scalar sum = matrix.row( k ).sum();
        if(! Ra::Core::Math::areApproxEqual(sum, Scalar(0))){
            if (! Ra::Core::Math::areApproxEqual(sum, Scalar(1))){
                skinningWeightOk = false ;
                matrix.row( k ) /= sum;
            }
        }
    }
    return ! skinningWeightOk;
}

} // namespace Animation
} // Namespace Core
} // Namespace Ra
<|endoftext|>


<commit_before>/*
    This file is part of KOrganizer.

    Copyright (c) 2003,2004 Cornelius Schumacher <schumacher@kde.org>

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

    As a special exception, permission is given to link this program
    with any edition of Qt, and distribute the resulting executable,
    without including the source code for Qt in the source distribution.
*/

#include "resourceview.h"

#include <klistview.h>
#include <klocale.h>
#include <kdebug.h>
#include <kglobal.h>
#include <kmessagebox.h>
#include <kresources/resource.h>
#include <kresources/configdialog.h>
#include <kinputdialog.h>
#include <libkcal/calendarresources.h>
#include <resourceremote.h>

#include <qhbox.h>
#include <qlayout.h>
#include <qlabel.h>
#include <qpushbutton.h>
#include <qpopupmenu.h>

#include "koprefs.h"

using namespace KCal;

ResourceViewFactory::ResourceViewFactory( KCal::CalendarResources *calendar,
                                          CalendarView *view )
  : mCalendar( calendar ), mView( view ), mResourceView( 0 )
{
}

CalendarViewExtension *ResourceViewFactory::create( QWidget *parent )
{
  mResourceView = new ResourceView( mCalendar, parent );

  QObject::connect( mResourceView, SIGNAL( resourcesChanged() ),
                    mView, SLOT( updateView() ) );
  QObject::connect( mResourceView, SIGNAL( resourcesChanged() ),
                    mView, SLOT( updateCategories() ) );

  QObject::connect( mCalendar,
                    SIGNAL( signalResourceAdded( ResourceCalendar * ) ),
                    mResourceView,
                    SLOT( addResourceItem( ResourceCalendar * ) ) );
  QObject::connect( mCalendar,
                    SIGNAL( signalResourceModified( ResourceCalendar * ) ),
                    mResourceView,
                    SLOT( updateResourceItem( ResourceCalendar * ) ) );
  QObject::connect( mCalendar, SIGNAL( signalResourceAdded( ResourceCalendar * ) ),
                    mView, SLOT( updateCategories() ) );
  QObject::connect( mCalendar, SIGNAL( signalResourceModified( ResourceCalendar * ) ),
                    mView, SLOT( updateCategories() ) );

  return mResourceView;
}

ResourceView *ResourceViewFactory::resourceView() const
{
  return mResourceView;
}

ResourceItem::ResourceItem( ResourceCalendar *resource, ResourceView *view,
                            KListView *parent )
  : QCheckListItem( parent, resource->resourceName(), CheckBox ),
    mResource( resource ), mView( view ), mBlockStateChange( false ),
    mIsSubresource( false ), mResourceIdentifier(),
    mSubItemsCreated( false )
{
  setGuiState();

  if ( mResource->isActive() ) {
    createSubresourceItems();
  }
}

void ResourceItem::createSubresourceItems() {
  const QStringList subresources = mResource->subresources();
  if ( !subresources.isEmpty() ) {
    setOpen( true );
    setExpandable( true );
    // This resource has subresources
    QStringList::ConstIterator it;
    for ( it=subresources.begin(); it!=subresources.end(); ++it ) {
      ( void )new ResourceItem( mResource, *it, mResource->labelForSubresource( *it ),
                                mView, this );
    }
  }
  mSubItemsCreated = true;
}

ResourceItem::ResourceItem( KCal::ResourceCalendar *resource,
                            const QString& sub, const QString& label,
                            ResourceView *view, ResourceItem* parent )

  : QCheckListItem( parent, label, CheckBox ), mResource( resource ),
    mView( view ), mBlockStateChange( false ), mIsSubresource( true ),
    mSubItemsCreated( false )
{
  mResourceIdentifier = sub;
  setGuiState();
}

void ResourceItem::setGuiState()
{
  mBlockStateChange = true;
  if ( mIsSubresource )
    setOn( mResource->subresourceActive( mResourceIdentifier ) );
  else
    setOn( mResource->isActive() );
  mBlockStateChange = false;
}

void ResourceItem::stateChange( bool active )
{
  if ( mBlockStateChange ) return;

  if ( mIsSubresource ) {
    mResource->setSubresourceActive( mResourceIdentifier, active );
  } else {
    if ( active ) {
      if ( mResource->load() ) {
        mResource->setActive( true );
        if ( !mSubItemsCreated )
          createSubresourceItems();
      }
    } else {
      if ( mResource->save() ) mResource->setActive( false );
      mView->requestClose( mResource );
    }

    setOpen( mResource->isActive() && childCount() > 0 );

    setGuiState();
  }

  mView->emitResourcesChanged();
}

void ResourceItem::update()
{
  setGuiState();
}

ResourceView::ResourceView( KCal::CalendarResources *calendar,
                            QWidget *parent, const char *name )
  : CalendarViewExtension( parent, name ), mCalendar( calendar )
{
  QBoxLayout *topLayout = new QVBoxLayout( this );

  mListView = new KListView( this );
  mListView->addColumn( i18n("Calendar") );
  mListView->setResizeMode( QListView::LastColumn );
  topLayout->addWidget( mListView );

  QHBox *buttonBox = new QHBox( this );
  topLayout->addWidget( buttonBox );

  mAddButton = new QPushButton( i18n("Add..."), buttonBox, "add" );
  mEditButton = new QPushButton( i18n("Edit..."), buttonBox, "edit" );
  mDeleteButton = new QPushButton( i18n("Remove"), buttonBox, "del" );
  mDeleteButton->setDisabled( true );
  mEditButton->setDisabled( true );

  connect( mListView, SIGNAL( clicked( QListViewItem * ) ),
           SLOT( currentChanged( QListViewItem * ) ) );
  connect( mAddButton, SIGNAL( clicked() ), SLOT( addResource() ) );
  connect( mDeleteButton, SIGNAL( clicked() ), SLOT( removeResource() ) );
  connect( mEditButton, SIGNAL( clicked() ), SLOT( editResource() ) );
  connect( mListView, SIGNAL( doubleClicked ( QListViewItem *, const QPoint &,
                                              int ) ),
           SLOT( editResource() ) );
  connect( mListView, SIGNAL( contextMenuRequested ( QListViewItem *,
                                                     const QPoint &, int ) ),
           SLOT( contextMenuRequested( QListViewItem *, const QPoint &,
                                       int ) ) );
  updateView();
}

ResourceView::~ResourceView()
{
}

void ResourceView::updateView()
{
  mListView->clear();

  KCal::CalendarResourceManager *manager = mCalendar->resourceManager();

  KCal::CalendarResourceManager::Iterator it;
  for( it = manager->begin(); it != manager->end(); ++it ) {
    addResourceItem( *it );
  }
}

void ResourceView::emitResourcesChanged()
{
  emit resourcesChanged();
}

void ResourceView::addResource()
{
  KCal::CalendarResourceManager *manager = mCalendar->resourceManager();

  QStringList types = manager->resourceTypeNames();
  QStringList descs = manager->resourceTypeDescriptions();
  bool ok = false;
  QString desc = KInputDialog::getItem( i18n( "Resource Configuration" ),
      i18n( "Please select type of the new resource:" ), descs, 0, false, &ok,
            this );
  if ( !ok )
    return;

  QString type = types[ descs.findIndex( desc ) ];

  // Create new resource
  ResourceCalendar *resource = manager->createResource( type );
  if( !resource ) {
    KMessageBox::error( this, i18n("<qt>Unable to create resource of type %1.</qt>")
                              .arg( type ) );
    return;
  }

  resource->setResourceName( i18n("%1 resource").arg( type ) );

  KRES::ConfigDialog dlg( this, QString("calendar"), resource,
                          "KRES::ConfigDialog" );

  if ( dlg.exec() ) {
    resource->setTimeZoneId( KOPrefs::instance()->mTimeZoneId );
    if ( resource->isActive() ) {
      resource->open();
      resource->load();
    }
    manager->add( resource );
    addResourceItem( resource );
  } else {
    delete resource;
    resource = 0;
  }
}

void ResourceView::addResourceItem( ResourceCalendar *resource )
{
  new ResourceItem( resource, this, mListView );

  connect( resource, SIGNAL( signalSubresourceAdded( ResourceCalendar *,
                                                     const QString &,
                                                     const QString &,
                                                     const QString & ) ),
           SLOT( slotSubresourceAdded( ResourceCalendar *, const QString &,
                                       const QString &, const QString & ) ) );

  connect( resource, SIGNAL( signalSubresourceAdded( ResourceCalendar *,
                                                     const QString &,
                                                     const QString & ) ),
           SLOT( slotSubresourceAdded( ResourceCalendar *, const QString &,
                                       const QString & ) ) );

  connect( resource, SIGNAL( signalSubresourceRemoved( ResourceCalendar *,
                                                       const QString &,
                                                       const QString & ) ),
           SLOT( slotSubresourceRemoved( ResourceCalendar *, const QString &,
                                         const QString & ) ) );

  connect( resource, SIGNAL( resourceSaved( ResourceCalendar * ) ),
           SLOT( closeResource( ResourceCalendar * ) ) );

  emitResourcesChanged();
}

// FIXME proko2: merge once we are back in HEAD by porting imap resource
void ResourceView::slotSubresourceAdded( ResourceCalendar *calendar,
                                         const QString& type,
                                         const QString& resource )
{
   slotSubresourceAdded( calendar, type, resource, resource );
}

// Add a new entry
void ResourceView::slotSubresourceAdded( ResourceCalendar *calendar,
                                         const QString& /*type*/,
                                         const QString& resource,
                                         const QString& label)
{
  QListViewItem *i = mListView->findItem( calendar->resourceName(), 0 );
  if ( !i )
    // Not found
    return;

  ResourceItem *item = static_cast<ResourceItem *>( i );
  ( void )new ResourceItem( calendar, resource, label, this, item );
}

// Remove an entry
void ResourceView::slotSubresourceRemoved( ResourceCalendar */*calendar*/,
                                           const QString &/*type*/,
                                           const QString &resource )
{
  delete findItemByIdentifier( resource );
  emitResourcesChanged();
}

void ResourceView::closeResource( ResourceCalendar *r )
{
  if ( mResourcesToClose.find( r ) >= 0 ) {
    r->close();
    mResourcesToClose.remove( r );
  }
}

void ResourceView::updateResourceItem( ResourceCalendar *resource )
{
  ResourceItem *item = findItem( resource );
  if ( item ) {
    item->update();
  }
}

ResourceItem *ResourceView::currentItem()
{
  QListViewItem *item = mListView->currentItem();
  ResourceItem *rItem = static_cast<ResourceItem *>( item );
  return rItem;
}

void ResourceView::removeResource()
{
  ResourceItem *item = currentItem();
  if ( !item ) return;

  int km = KMessageBox::warningContinueCancel( this,
        i18n("<qt>Do you really want to remove the resource %1?</qt>")
        .arg( item->text( 0 ) ), "",
        KGuiItem( i18n("&Remove" ), "editdelete") );
  if ( km == KMessageBox::Cancel ) return;

// Don't be so restricitve
#if 0
  if ( item->resource() == mCalendar->resourceManager()->standardResource() ) {
    KMessageBox::sorry( this,
                        i18n( "You cannot remove your standard resource." ) );
    return;
  }
#endif
  if ( item->isSubresource() ) {
    // TODO delete the folder in KMail
  } else {
    mCalendar->resourceManager()->remove( item->resource() );
    mListView->takeItem( item );
    delete item;
  }
  emitResourcesChanged();
}

void ResourceView::editResource()
{
  ResourceItem *item = currentItem();

  ResourceCalendar *resource = item->resource();

  KRES::ConfigDialog dlg( this, QString("calendar"), resource,
                          "KRES::ConfigDialog" );

  if ( dlg.exec() ) {
    item->setText( 0, resource->resourceName() );

    mCalendar->resourceManager()->change( resource );
  }
}

void ResourceView::currentChanged( QListViewItem *item)
{
   ResourceItem *i = currentItem();
   if ( !item || i->isSubresource() ) {
     mDeleteButton->setEnabled( false );
     mEditButton->setEnabled( false );
   } else {
     mDeleteButton->setEnabled( true );
     mEditButton->setEnabled( true );
   }
}

ResourceItem *ResourceView::findItem( ResourceCalendar *r )
{
  QListViewItem *item;
  ResourceItem *i = 0;
  for( item = mListView->firstChild(); item; item = item->nextSibling() ) {
    i = static_cast<ResourceItem *>( item );
    if ( i->resource() == r ) break;
  }
  return i;
}

ResourceItem *ResourceView::findItemByIdentifier( const QString& id )
{
  QListViewItem *item;
  ResourceItem *i = 0;
  for( item = mListView->firstChild(); item; item = item->itemBelow() ) {
    i = static_cast<ResourceItem *>( item );
    if ( i->resourceIdentifier() == id )
       return i;
  }
  return 0;
}

void ResourceView::contextMenuRequested ( QListViewItem *i,
                                          const QPoint &pos, int )
{
  ResourceItem *item = static_cast<ResourceItem *>( i );

  QPopupMenu *menu = new QPopupMenu( this );
  connect( menu, SIGNAL( aboutToHide() ), menu, SLOT( deleteLater() ) );
  if ( item ) {
    int reloadId = menu->insertItem( i18n("Reload"), this,
                                     SLOT( reloadResource() ) );
    menu->setItemEnabled( reloadId, item->resource()->isActive() );
    int saveId = menu->insertItem( i18n("Save"), this,
                                   SLOT( saveResource() ) );
    menu->setItemEnabled( saveId, item->resource()->isActive() );
    menu->insertSeparator();
    menu->insertItem( i18n("Show Info"), this, SLOT( showInfo() ) );
    if ( !item->isSubresource() ) {
      menu->insertItem( i18n("Edit..."), this, SLOT( editResource() ) );
      menu->insertItem( i18n("Remove"), this, SLOT( removeResource() ) );
    }
    menu->insertSeparator();
 }
  menu->insertItem( i18n("Add..."), this, SLOT( addResource() ) );

  menu->popup( pos );
}

void ResourceView::showInfo()
{
  ResourceItem *item = currentItem();
  if ( !item ) return;

  QString txt = "<qt>" + item->resource()->infoText() + "</qt>";
  KMessageBox::information( this, txt );
}

void ResourceView::reloadResource()
{
  ResourceItem *item = currentItem();
  if ( !item ) return;

  ResourceCalendar *r = item->resource();
  r->load();
}

void ResourceView::saveResource()
{
  ResourceItem *item = currentItem();
  if ( !item ) return;

  ResourceCalendar *r = item->resource();
  r->save();
}

void ResourceView::showButtons( bool visible )
{
  if ( visible ) {
    mAddButton->show();
    mDeleteButton->show();
    mEditButton->show();
  } else {
    mAddButton->hide();
    mDeleteButton->hide();
    mEditButton->hide();
  }
}

void ResourceView::requestClose( ResourceCalendar *r )
{
  mResourcesToClose.append( r );
}

#include "resourceview.moc"
<commit_msg>Make the Add and Remove buttons functional with subresources, in particular, make it possible to add Kolab folders in KMail from  within KOrganizer, and remove them.<commit_after>/*
    This file is part of KOrganizer.

    Copyright (c) 2003,2004 Cornelius Schumacher <schumacher@kde.org>

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

    As a special exception, permission is given to link this program
    with any edition of Qt, and distribute the resulting executable,
    without including the source code for Qt in the source distribution.
*/

#include "resourceview.h"

#include <klistview.h>
#include <klocale.h>
#include <kdebug.h>
#include <kglobal.h>
#include <kmessagebox.h>
#include <kresources/resource.h>
#include <kresources/configdialog.h>
#include <kinputdialog.h>
#include <libkcal/calendarresources.h>
#include <resourceremote.h>

#include <qhbox.h>
#include <qlayout.h>
#include <qlabel.h>
#include <qpushbutton.h>
#include <qpopupmenu.h>

#include "koprefs.h"

using namespace KCal;

ResourceViewFactory::ResourceViewFactory( KCal::CalendarResources *calendar,
                                          CalendarView *view )
  : mCalendar( calendar ), mView( view ), mResourceView( 0 )
{
}

CalendarViewExtension *ResourceViewFactory::create( QWidget *parent )
{
  mResourceView = new ResourceView( mCalendar, parent );

  QObject::connect( mResourceView, SIGNAL( resourcesChanged() ),
                    mView, SLOT( updateView() ) );
  QObject::connect( mResourceView, SIGNAL( resourcesChanged() ),
                    mView, SLOT( updateCategories() ) );

  QObject::connect( mCalendar,
                    SIGNAL( signalResourceAdded( ResourceCalendar * ) ),
                    mResourceView,
                    SLOT( addResourceItem( ResourceCalendar * ) ) );
  QObject::connect( mCalendar,
                    SIGNAL( signalResourceModified( ResourceCalendar * ) ),
                    mResourceView,
                    SLOT( updateResourceItem( ResourceCalendar * ) ) );
  QObject::connect( mCalendar, SIGNAL( signalResourceAdded( ResourceCalendar * ) ),
                    mView, SLOT( updateCategories() ) );
  QObject::connect( mCalendar, SIGNAL( signalResourceModified( ResourceCalendar * ) ),
                    mView, SLOT( updateCategories() ) );

  return mResourceView;
}

ResourceView *ResourceViewFactory::resourceView() const
{
  return mResourceView;
}

ResourceItem::ResourceItem( ResourceCalendar *resource, ResourceView *view,
                            KListView *parent )
  : QCheckListItem( parent, resource->resourceName(), CheckBox ),
    mResource( resource ), mView( view ), mBlockStateChange( false ),
    mIsSubresource( false ), mResourceIdentifier(),
    mSubItemsCreated( false )
{
  setGuiState();

  if ( mResource->isActive() ) {
    createSubresourceItems();
  }
}

void ResourceItem::createSubresourceItems() {
  const QStringList subresources = mResource->subresources();
  if ( !subresources.isEmpty() ) {
    setOpen( true );
    setExpandable( true );
    // This resource has subresources
    QStringList::ConstIterator it;
    for ( it=subresources.begin(); it!=subresources.end(); ++it ) {
      ( void )new ResourceItem( mResource, *it, mResource->labelForSubresource( *it ),
                                mView, this );
    }
  }
  mSubItemsCreated = true;
}

ResourceItem::ResourceItem( KCal::ResourceCalendar *resource,
                            const QString& sub, const QString& label,
                            ResourceView *view, ResourceItem* parent )

  : QCheckListItem( parent, label, CheckBox ), mResource( resource ),
    mView( view ), mBlockStateChange( false ), mIsSubresource( true ),
    mSubItemsCreated( false )
{
  mResourceIdentifier = sub;
  setGuiState();
}

void ResourceItem::setGuiState()
{
  mBlockStateChange = true;
  if ( mIsSubresource )
    setOn( mResource->subresourceActive( mResourceIdentifier ) );
  else
    setOn( mResource->isActive() );
  mBlockStateChange = false;
}

void ResourceItem::stateChange( bool active )
{
  if ( mBlockStateChange ) return;

  if ( mIsSubresource ) {
    mResource->setSubresourceActive( mResourceIdentifier, active );
  } else {
    if ( active ) {
      if ( mResource->load() ) {
        mResource->setActive( true );
        if ( !mSubItemsCreated )
          createSubresourceItems();
      }
    } else {
      if ( mResource->save() ) mResource->setActive( false );
      mView->requestClose( mResource );
    }

    setOpen( mResource->isActive() && childCount() > 0 );

    setGuiState();
  }

  mView->emitResourcesChanged();
}

void ResourceItem::update()
{
  setGuiState();
}

ResourceView::ResourceView( KCal::CalendarResources *calendar,
                            QWidget *parent, const char *name )
  : CalendarViewExtension( parent, name ), mCalendar( calendar )
{
  QBoxLayout *topLayout = new QVBoxLayout( this );

  mListView = new KListView( this );
  mListView->addColumn( i18n("Calendar") );
  mListView->setResizeMode( QListView::LastColumn );
  topLayout->addWidget( mListView );

  QHBox *buttonBox = new QHBox( this );
  topLayout->addWidget( buttonBox );

  mAddButton = new QPushButton( i18n("Add..."), buttonBox, "add" );
  mEditButton = new QPushButton( i18n("Edit..."), buttonBox, "edit" );
  mDeleteButton = new QPushButton( i18n("Remove"), buttonBox, "del" );
  mEditButton->setDisabled( true );

  connect( mListView, SIGNAL( clicked( QListViewItem * ) ),
           SLOT( currentChanged( QListViewItem * ) ) );
  connect( mAddButton, SIGNAL( clicked() ), SLOT( addResource() ) );
  connect( mDeleteButton, SIGNAL( clicked() ), SLOT( removeResource() ) );
  connect( mEditButton, SIGNAL( clicked() ), SLOT( editResource() ) );
  connect( mListView, SIGNAL( doubleClicked ( QListViewItem *, const QPoint &,
                                              int ) ),
           SLOT( editResource() ) );
  connect( mListView, SIGNAL( contextMenuRequested ( QListViewItem *,
                                                     const QPoint &, int ) ),
           SLOT( contextMenuRequested( QListViewItem *, const QPoint &,
                                       int ) ) );
  updateView();
}

ResourceView::~ResourceView()
{
}

void ResourceView::updateView()
{
  mListView->clear();

  KCal::CalendarResourceManager *manager = mCalendar->resourceManager();

  KCal::CalendarResourceManager::Iterator it;
  for( it = manager->begin(); it != manager->end(); ++it ) {
    addResourceItem( *it );
  }
}

void ResourceView::emitResourcesChanged()
{
  emit resourcesChanged();
}

void ResourceView::addResource()
{
  bool ok = false;
  KCal::CalendarResourceManager *manager = mCalendar->resourceManager();
  ResourceItem *i = static_cast<ResourceItem*>( mListView->selectedItem() );
  if ( i && ( i->isSubresource() || i->resource()->canHaveSubresources() ) ) {
    const QString folderName = KInputDialog::getText( i18n( "Add Subresource" ),
            i18n( "Please enter a name for the new subresource" ), QString::null,
            &ok, this );
    if ( !ok )
      return;
    const QString parentId = i->isSubresource() ? i->resourceIdentifier() : QString:: null;
    if ( !i->resource()->addSubresource( folderName, parentId ) ) {
      KMessageBox::error( this, i18n("<qt>Unable to create subresource %1.</qt>")
                                .arg( folderName ) );
    }
    return;
  }

  QStringList types = manager->resourceTypeNames();
  QStringList descs = manager->resourceTypeDescriptions();
  QString desc = KInputDialog::getItem( i18n( "Resource Configuration" ),
      i18n( "Please select type of the new resource:" ), descs, 0, false, &ok,
            this );
  if ( !ok )
    return;

  QString type = types[ descs.findIndex( desc ) ];

  // Create new resource
  ResourceCalendar *resource = manager->createResource( type );
  if( !resource ) {
    KMessageBox::error( this, i18n("<qt>Unable to create resource of type %1.</qt>")
                              .arg( type ) );
    return;
  }

  resource->setResourceName( i18n("%1 resource").arg( type ) );

  KRES::ConfigDialog dlg( this, QString("calendar"), resource,
                          "KRES::ConfigDialog" );

  if ( dlg.exec() ) {
    resource->setTimeZoneId( KOPrefs::instance()->mTimeZoneId );
    if ( resource->isActive() ) {
      resource->open();
      resource->load();
    }
    manager->add( resource );
    addResourceItem( resource );
  } else {
    delete resource;
    resource = 0;
  }
}

void ResourceView::addResourceItem( ResourceCalendar *resource )
{
  new ResourceItem( resource, this, mListView );

  connect( resource, SIGNAL( signalSubresourceAdded( ResourceCalendar *,
                                                     const QString &,
                                                     const QString &,
                                                     const QString & ) ),
           SLOT( slotSubresourceAdded( ResourceCalendar *, const QString &,
                                       const QString &, const QString & ) ) );

  connect( resource, SIGNAL( signalSubresourceAdded( ResourceCalendar *,
                                                     const QString &,
                                                     const QString & ) ),
           SLOT( slotSubresourceAdded( ResourceCalendar *, const QString &,
                                       const QString & ) ) );

  connect( resource, SIGNAL( signalSubresourceRemoved( ResourceCalendar *,
                                                       const QString &,
                                                       const QString & ) ),
           SLOT( slotSubresourceRemoved( ResourceCalendar *, const QString &,
                                         const QString & ) ) );

  connect( resource, SIGNAL( resourceSaved( ResourceCalendar * ) ),
           SLOT( closeResource( ResourceCalendar * ) ) );

  emitResourcesChanged();
}

// FIXME proko2: merge once we are back in HEAD by porting imap resource
void ResourceView::slotSubresourceAdded( ResourceCalendar *calendar,
                                         const QString& type,
                                         const QString& resource )
{
   slotSubresourceAdded( calendar, type, resource, resource );
}

// Add a new entry
void ResourceView::slotSubresourceAdded( ResourceCalendar *calendar,
                                         const QString& /*type*/,
                                         const QString& resource,
                                         const QString& label)
{
  QListViewItem *i = mListView->findItem( calendar->resourceName(), 0 );
  if ( !i )
    // Not found
    return;

  ResourceItem *item = static_cast<ResourceItem *>( i );
  ( void )new ResourceItem( calendar, resource, label, this, item );
}

// Remove an entry
void ResourceView::slotSubresourceRemoved( ResourceCalendar */*calendar*/,
                                           const QString &/*type*/,
                                           const QString &resource )
{
  delete findItemByIdentifier( resource );
  emitResourcesChanged();
}

void ResourceView::closeResource( ResourceCalendar *r )
{
  if ( mResourcesToClose.find( r ) >= 0 ) {
    r->close();
    mResourcesToClose.remove( r );
  }
}

void ResourceView::updateResourceItem( ResourceCalendar *resource )
{
  ResourceItem *item = findItem( resource );
  if ( item ) {
    item->update();
  }
}

ResourceItem *ResourceView::currentItem()
{
  QListViewItem *item = mListView->currentItem();
  ResourceItem *rItem = static_cast<ResourceItem *>( item );
  return rItem;
}

void ResourceView::removeResource()
{
  ResourceItem *item = currentItem();
  if ( !item ) return;

  const QString warningMsg = item->isSubresource() ?
        i18n("<qt>Do you really want to remove the subresource %1? "
              "Note that its contents will be completely deleted. This "
              "operation cannot be undone. </qt>").arg( item->text( 0 ) ) :
        i18n("<qt>Do you really want to remove the resource %1?</qt>").arg( item->text( 0 ) );

  int km = KMessageBox::warningContinueCancel( this, warningMsg, "",
        KGuiItem( i18n("&Remove" ), "editdelete") );
  if ( km == KMessageBox::Cancel ) return;

// Don't be so restricitve
#if 0
  if ( item->resource() == mCalendar->resourceManager()->standardResource() ) {
    KMessageBox::sorry( this,
                        i18n( "You cannot remove your standard resource." ) );
    return;
  }
#endif
  if ( item->isSubresource() ) {
    if ( !item->resource()->removeSubresource( item->resourceIdentifier() ) )
      KMessageBox::sorry( this,
              i18n ("<qt>Failed to remove the subresource %1. The "
                  "reason could be that it is a built-in one which cannot "
                  "be removed, or that the removal of the underlying storage "
                  "folder failed.</qt>").arg( item->resource()->name() ) );
      return;
  } else {
    mCalendar->resourceManager()->remove( item->resource() );
  }
  mListView->takeItem( item );
  delete item;
  emitResourcesChanged();
}

void ResourceView::editResource()
{
  ResourceItem *item = currentItem();

  ResourceCalendar *resource = item->resource();

  KRES::ConfigDialog dlg( this, QString("calendar"), resource,
                          "KRES::ConfigDialog" );

  if ( dlg.exec() ) {
    item->setText( 0, resource->resourceName() );

    mCalendar->resourceManager()->change( resource );
  }
}

void ResourceView::currentChanged( QListViewItem *item)
{
   ResourceItem *i = currentItem();
   if ( !item || i->isSubresource() ) {
     mEditButton->setEnabled( false );
   } else {
     mEditButton->setEnabled( true );
   }
}

ResourceItem *ResourceView::findItem( ResourceCalendar *r )
{
  QListViewItem *item;
  ResourceItem *i = 0;
  for( item = mListView->firstChild(); item; item = item->nextSibling() ) {
    i = static_cast<ResourceItem *>( item );
    if ( i->resource() == r ) break;
  }
  return i;
}

ResourceItem *ResourceView::findItemByIdentifier( const QString& id )
{
  QListViewItem *item;
  ResourceItem *i = 0;
  for( item = mListView->firstChild(); item; item = item->itemBelow() ) {
    i = static_cast<ResourceItem *>( item );
    if ( i->resourceIdentifier() == id )
       return i;
  }
  return 0;
}

void ResourceView::contextMenuRequested ( QListViewItem *i,
                                          const QPoint &pos, int )
{
  ResourceItem *item = static_cast<ResourceItem *>( i );

  QPopupMenu *menu = new QPopupMenu( this );
  connect( menu, SIGNAL( aboutToHide() ), menu, SLOT( deleteLater() ) );
  if ( item ) {
    int reloadId = menu->insertItem( i18n("Reload"), this,
                                     SLOT( reloadResource() ) );
    menu->setItemEnabled( reloadId, item->resource()->isActive() );
    int saveId = menu->insertItem( i18n("Save"), this,
                                   SLOT( saveResource() ) );
    menu->setItemEnabled( saveId, item->resource()->isActive() );
    menu->insertSeparator();
    menu->insertItem( i18n("Show Info"), this, SLOT( showInfo() ) );
    if ( !item->isSubresource() ) {
      menu->insertItem( i18n("Edit..."), this, SLOT( editResource() ) );
      menu->insertItem( i18n("Remove"), this, SLOT( removeResource() ) );
    }
    menu->insertSeparator();
 }
  menu->insertItem( i18n("Add..."), this, SLOT( addResource() ) );

  menu->popup( pos );
}

void ResourceView::showInfo()
{
  ResourceItem *item = currentItem();
  if ( !item ) return;

  QString txt = "<qt>" + item->resource()->infoText() + "</qt>";
  KMessageBox::information( this, txt );
}

void ResourceView::reloadResource()
{
  ResourceItem *item = currentItem();
  if ( !item ) return;

  ResourceCalendar *r = item->resource();
  r->load();
}

void ResourceView::saveResource()
{
  ResourceItem *item = currentItem();
  if ( !item ) return;

  ResourceCalendar *r = item->resource();
  r->save();
}

void ResourceView::showButtons( bool visible )
{
  if ( visible ) {
    mAddButton->show();
    mDeleteButton->show();
    mEditButton->show();
  } else {
    mAddButton->hide();
    mDeleteButton->hide();
    mEditButton->hide();
  }
}

void ResourceView::requestClose( ResourceCalendar *r )
{
  mResourcesToClose.append( r );
}

#include "resourceview.moc"
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2004, Mart Kelder (mart.kde@hccnet.nl)
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 */

#include "kio_single_subject.h"

#include "mailsubject.h"
#include "kio_proto.h"

#include <kdebug.h>
#include <klocale.h>
#include <kurl.h>
#include <kio/global.h>
#include <kio/scheduler.h>
#include <kio/job.h>
#include <kio/jobclasses.h>
#include <krfcdate.h>

#include <QRegExp>
#include <QString>
#include <QVariant>
//Added by qt3to4:
#include <QTextStream>

KIO_Single_Subject::KIO_Single_Subject( QObject * parent,
		    KUrl &kurl, KIO::MetaData &metadata, const KIO_Protocol * protocol, KIO::Slave *& slave,
		    const QString &url, const long size )
		: QObject( parent )
{
	_kurl = new KUrl( kurl );
	_metadata = new KIO::MetaData( metadata );
	_protocol = protocol;
	_name = new QString( url );
	_size = size;
	_message = new QString;

	init( slave );
}

KIO_Single_Subject::~KIO_Single_Subject( )
{
	if( _job )
		KIO::Scheduler::cancelJob( _job );
	delete _kurl;
	delete _metadata;
	delete _name;
	delete _message;
}

void KIO_Single_Subject::init( KIO::Slave *& slave)
{
	_job = KIO::get( *_kurl, false, false );
	_job->addMetaData( *_metadata );

	connect( _job, SIGNAL( result( KJob* ) ), this, SLOT( slotResult( KJob* ) ) );
	connect( _job, SIGNAL( data         (KIO::Job *, const QByteArray &) ),
	         this, SLOT( slotData(KIO::Job *, const QByteArray &) ) );

	if( _protocol->connectionBased( ) && slave )
		KIO::Scheduler::assignJobToSlave( slave , _job );
	else
		KIO::Scheduler::scheduleJob( _job );

}

void KIO_Single_Subject::parseMail( QString * message, KornMailSubject *subject, bool fullMessage )
{
	QTextStream stream( message, QIODevice::ReadOnly );
	QString line;
	QRegExp rx_sender( "^[fF]rom: " ); //Ex: From: ...
	QRegExp rx_sender_has_name1( "^[fF]rom:\\s*(\\w+[\\w\\s]*)\\<" ); //Ex: From: A name<email@domein.country>
	QRegExp rx_sender_has_name2( "^[fF]rom:\\s*\\\"\\s*(\\w+[\\w\\s]*)\\\""); //Ex: From: "A name"<a@invalid>
	QRegExp rx_subject( "^[sS]ubject: " ); //Ex: Subject: ...
	QRegExp rx_date  ( "^[dD]ate: ");
	bool inheader = true;
	int fieldnumber = 0;

	while ( ! stream.atEnd() )
	{
		line = stream.readLine();
		if( line.isEmpty() && fieldnumber >= 2 )
			inheader = false;

		if( inheader )
		{
			if( rx_sender.indexIn( line ) == 0 )
			{
				if( rx_sender_has_name1.indexIn( line ) == 0 )
					subject->setSender( rx_sender_has_name1.cap( 1 )  );
				else if(rx_sender_has_name2.indexIn( line ) == 0)
					subject->setSender( rx_sender_has_name2.cap( 1 ) );
				else
					subject->setSender( line.remove( rx_sender ) );
				++fieldnumber;
			}
			else if( rx_subject.indexIn( line ) == 0 )
			{
				subject->setSubject( line.remove( rx_subject ) );
				++fieldnumber;
			}
			else if( rx_date.indexIn( line ) == 0 )
			{
	                 	subject->setDate( KRFCDate::parseDate( line.right( line.length() - 6 ) ) );
				++fieldnumber;
			}
		}
	}

	subject->setHeader( *message, fullMessage );
}

void KIO_Single_Subject::slotData( KIO::Job* job, const QByteArray& data )
{
	if( job != _job )
		kWarning() << i18n( "Got invalid job; something strange happened?" ) << endl;
	if( !data.isEmpty() )
		_message->append( data );
}

//KIO::Scheduler::disconnectSlave missing  if connection stops
void KIO_Single_Subject::slotResult( KJob *job )
{
	if( job != _job )
		kWarning() << i18n( "Got invalid job; something strange happened?" ) << endl;

	if( job->error() )
	{
		kWarning() << i18n( "Error when fetching %1: %2", *_name, job->errorString() ) << endl;
	} else {
		KornMailSubject * mailSubject = new KornMailSubject( QVariant( *_name ), 0 );
		parseMail( _message, mailSubject, _protocol->fullMessage() );
		mailSubject->setSize( _size );
		emit readSubject( mailSubject );
	}

	_job = 0;

	emit finished( this );
}

#include "kio_single_subject.moc"
<commit_msg>port to kdatetime<commit_after>/*
 * Copyright (C) 2004, Mart Kelder (mart.kde@hccnet.nl)
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 */

#include "kio_single_subject.h"

#include "mailsubject.h"
#include "kio_proto.h"

#include <kdebug.h>
#include <klocale.h>
#include <kurl.h>
#include <kio/global.h>
#include <kio/scheduler.h>
#include <kio/job.h>
#include <kio/jobclasses.h>
#include <kdatetime.h>

#include <QRegExp>
#include <QString>
#include <QVariant>
//Added by qt3to4:
#include <QTextStream>

KIO_Single_Subject::KIO_Single_Subject( QObject * parent,
		    KUrl &kurl, KIO::MetaData &metadata, const KIO_Protocol * protocol, KIO::Slave *& slave,
		    const QString &url, const long size )
		: QObject( parent )
{
	_kurl = new KUrl( kurl );
	_metadata = new KIO::MetaData( metadata );
	_protocol = protocol;
	_name = new QString( url );
	_size = size;
	_message = new QString;

	init( slave );
}

KIO_Single_Subject::~KIO_Single_Subject( )
{
	if( _job )
		KIO::Scheduler::cancelJob( _job );
	delete _kurl;
	delete _metadata;
	delete _name;
	delete _message;
}

void KIO_Single_Subject::init( KIO::Slave *& slave)
{
	_job = KIO::get( *_kurl, false, false );
	_job->addMetaData( *_metadata );

	connect( _job, SIGNAL( result( KJob* ) ), this, SLOT( slotResult( KJob* ) ) );
	connect( _job, SIGNAL( data         (KIO::Job *, const QByteArray &) ),
	         this, SLOT( slotData(KIO::Job *, const QByteArray &) ) );

	if( _protocol->connectionBased( ) && slave )
		KIO::Scheduler::assignJobToSlave( slave , _job );
	else
		KIO::Scheduler::scheduleJob( _job );

}

void KIO_Single_Subject::parseMail( QString * message, KornMailSubject *subject, bool fullMessage )
{
	QTextStream stream( message, QIODevice::ReadOnly );
	QString line;
	QRegExp rx_sender( "^[fF]rom: " ); //Ex: From: ...
	QRegExp rx_sender_has_name1( "^[fF]rom:\\s*(\\w+[\\w\\s]*)\\<" ); //Ex: From: A name<email@domein.country>
	QRegExp rx_sender_has_name2( "^[fF]rom:\\s*\\\"\\s*(\\w+[\\w\\s]*)\\\""); //Ex: From: "A name"<a@invalid>
	QRegExp rx_subject( "^[sS]ubject: " ); //Ex: Subject: ...
	QRegExp rx_date  ( "^[dD]ate: ");
	bool inheader = true;
	int fieldnumber = 0;

	while ( ! stream.atEnd() )
	{
		line = stream.readLine();
		if( line.isEmpty() && fieldnumber >= 2 )
			inheader = false;

		if( inheader )
		{
			if( rx_sender.indexIn( line ) == 0 )
			{
				if( rx_sender_has_name1.indexIn( line ) == 0 )
					subject->setSender( rx_sender_has_name1.cap( 1 )  );
				else if(rx_sender_has_name2.indexIn( line ) == 0)
					subject->setSender( rx_sender_has_name2.cap( 1 ) );
				else
					subject->setSender( line.remove( rx_sender ) );
				++fieldnumber;
			}
			else if( rx_subject.indexIn( line ) == 0 )
			{
				subject->setSubject( line.remove( rx_subject ) );
				++fieldnumber;
			}
			else if( rx_date.indexIn( line ) == 0 )
			{
				KDateTime dt = KDateTime::fromString(  line.right(  line.length() - 6 ),
									KDateTime::RFCDate );
	                 	subject->setDate( dt.toTime_t() );
				++fieldnumber;
			}
		}
	}

	subject->setHeader( *message, fullMessage );
}

void KIO_Single_Subject::slotData( KIO::Job* job, const QByteArray& data )
{
	if( job != _job )
		kWarning() << i18n( "Got invalid job; something strange happened?" ) << endl;
	if( !data.isEmpty() )
		_message->append( data );
}

//KIO::Scheduler::disconnectSlave missing  if connection stops
void KIO_Single_Subject::slotResult( KJob *job )
{
	if( job != _job )
		kWarning() << i18n( "Got invalid job; something strange happened?" ) << endl;

	if( job->error() )
	{
		kWarning() << i18n( "Error when fetching %1: %2", *_name, job->errorString() ) << endl;
	} else {
		KornMailSubject * mailSubject = new KornMailSubject( QVariant( *_name ), 0 );
		parseMail( _message, mailSubject, _protocol->fullMessage() );
		mailSubject->setSize( _size );
		emit readSubject( mailSubject );
	}

	_job = 0;

	emit finished( this );
}

#include "kio_single_subject.moc"
<|endoftext|>


<commit_before>#include "stdafx.h"

static float CalcRadius(const Mesh* m)
{
	const Block& b = m->GetRawDatas();
	float maxSq = 0;
	for (auto& it : b.vertices) {
		float sq = XMVectorGetX(XMVector3LengthSq(XMLoadFloat3(&it.xyz)));
		maxSq = std::max(maxSq, sq);
	}
	return sqrt(maxSq);
}

App::App() : scale(1), lastX(-1), lastY(-1), meshTiny(nullptr)
{
	quat = XMQuaternionIdentity();
	ZeroMemory(mesh, sizeof(mesh));
}

App::~App()
{
}

void App::Init(const char* fileName)
{
	Destroy();

	meshTiny = new MeshX("C:\\Program Files (x86)\\Microsoft DirectX SDK (August 2009)\\Samples\\Media\\Tiny\\tiny.x");

	if (fileName) {
		const char* ext = strrchr(fileName, '.');
		mesh[0] = new Bvh(fileName);
	} else {
		mesh[0] = new Bvh("D:\\github\\aachan.bvh");
		mesh[1] = new Bvh("D:\\github\\kashiyuka.bvh");
		mesh[2] = new Bvh("D:\\github\\nocchi.bvh");
	}

	float radius = CalcRadius(mesh[0]);
	scale = 1 / std::max(0.00001f, radius);

	matrixMan.Set(MatrixMan::PROJ, XMMatrixPerspectiveFovLH(45 * XM_PI / 180, (float)SCR_W / SCR_H, 0.1f, 1000.0f));
}

void App::MouseWheel(float delta)
{
	if (delta > 0) {
		scale *= 1.1f;
	}
	if (delta < 0) {
		scale /= 1.1f;
	}
}

void App::LButtonDown(float x, float y)
{
	lastX = x;
	lastY = y;
}

void App::LButtonUp(float x, float y)
{
	MouseMove(x, y);
	lastX = lastY = -1;
}

void App::MouseMove(float x, float y)
{
	if (lastX < 0 || lastY < 0) {
		return;
	}
	float dx = x - lastX;
	float dy = - (y - lastY);

	lastX = x;
	lastY = y;

	XMVECTOR axis = XMVectorSet(-dy, dx, 0, 0);
	float len = XMVectorGetX(XMVector2Length(axis));
	if (!len) {
		return;
	}

	XMVECTOR q = XMQuaternionRotationAxis(axis, len * -2 * XM_PI);
	quat = XMQuaternionMultiply(quat, q);
}

void App::Draw()
{
	LARGE_INTEGER t, f;
	QueryPerformanceCounter(&t);
	QueryPerformanceFrequency(&f);
	float time = (float)((double)t.QuadPart / f.QuadPart);

//	XMMATRIX mRot = XMMatrixRotationQuaternion(XMQuaternionRotationAxis(XMVectorSet(1, 0, 0, 0), time / 2 * XM_PI));
	XMMATRIX mRot = XMMatrixRotationQuaternion(quat);
	XMMATRIX mScale = XMMatrixScaling(scale, scale, scale);

	matrixMan.Set(MatrixMan::WORLD, mScale * mRot);

	float dist = 3;
//	float rot = time / 5 * XM_PI;
	float rot = XM_PI;
	matrixMan.Set(MatrixMan::VIEW, XMMatrixLookAtLH(XMVectorSet(sin(rot) * dist, 0, cos(rot) * dist, 1), XMVectorSet(0, 0, 0, 0), XMVectorSet(0, 1, 0, 0)));

	for (auto& it : mesh) {
		if (it && meshTiny) {
//			it->Draw(0, time);
			meshTiny->DrawBvh(it, time);
		}
	}
}

void App::Destroy()
{
	SAFE_DELETE(mesh[0]);
	SAFE_DELETE(mesh[1]);
	SAFE_DELETE(mesh[2]);
	SAFE_DELETE(meshTiny);
}
<commit_msg>for test<commit_after>#include "stdafx.h"

static float CalcRadius(const Mesh* m)
{
	const Block& b = m->GetRawDatas();
	float maxSq = 0;
	for (auto& it : b.vertices) {
		float sq = XMVectorGetX(XMVector3LengthSq(XMLoadFloat3(&it.xyz)));
		maxSq = std::max(maxSq, sq);
	}
	return sqrt(maxSq);
}

App::App() : scale(1), lastX(-1), lastY(-1), meshTiny(nullptr)
{
	quat = XMQuaternionIdentity();
	ZeroMemory(mesh, sizeof(mesh));
}

App::~App()
{
}

void App::Init(const char* fileName)
{
	Destroy();

	meshTiny = new MeshX("C:\\Program Files (x86)\\Microsoft DirectX SDK (August 2009)\\Samples\\Media\\Tiny\\tiny.x");

	if (fileName) {
		const char* ext = strrchr(fileName, '.');
		mesh[0] = new Bvh(fileName);
	} else {
		mesh[0] = new Bvh("D:\\github\\aachan.bvh");
		mesh[1] = new Bvh("D:\\github\\kashiyuka.bvh");
		mesh[2] = new Bvh("D:\\github\\nocchi.bvh");
	}

	float radius = CalcRadius(mesh[0]);
	scale = 1 / std::max(0.00001f, radius);

	matrixMan.Set(MatrixMan::PROJ, XMMatrixPerspectiveFovLH(45 * XM_PI / 180, (float)SCR_W / SCR_H, 0.1f, 1000.0f));
}

void App::MouseWheel(float delta)
{
	if (delta > 0) {
		scale *= 1.1f;
	}
	if (delta < 0) {
		scale /= 1.1f;
	}
}

void App::LButtonDown(float x, float y)
{
	lastX = x;
	lastY = y;
}

void App::LButtonUp(float x, float y)
{
	MouseMove(x, y);
	lastX = lastY = -1;
}

void App::MouseMove(float x, float y)
{
	if (lastX < 0 || lastY < 0) {
		return;
	}
	float dx = x - lastX;
	float dy = - (y - lastY);

	lastX = x;
	lastY = y;

	XMVECTOR axis = XMVectorSet(-dy, dx, 0, 0);
	float len = XMVectorGetX(XMVector2Length(axis));
	if (!len) {
		return;
	}

	XMVECTOR q = XMQuaternionRotationAxis(axis, len * -2 * XM_PI);
	quat = XMQuaternionMultiply(quat, q);
}

void App::Draw()
{
	LARGE_INTEGER t, f;
	QueryPerformanceCounter(&t);
	QueryPerformanceFrequency(&f);
	float time = (float)((double)t.QuadPart / f.QuadPart);

//	XMMATRIX mRot = XMMatrixRotationQuaternion(XMQuaternionRotationAxis(XMVectorSet(1, 0, 0, 0), time / 2 * XM_PI));
	XMMATRIX mRot = XMMatrixRotationQuaternion(quat);
	XMMATRIX mScale = XMMatrixScaling(scale, scale, scale);

	matrixMan.Set(MatrixMan::WORLD, mScale * mRot);

	float dist = 3;
//	float rot = time / 5 * XM_PI;
	float rot = XM_PI;
	matrixMan.Set(MatrixMan::VIEW, XMMatrixLookAtLH(XMVectorSet(sin(rot) * dist, 0, cos(rot) * dist, 1), XMVectorSet(0, 0, 0, 0), XMVectorSet(0, 1, 0, 0)));

	for (auto& it : mesh) {
		if (it && meshTiny) {
			it->Draw(0, time);
			meshTiny->DrawBvh(it, time);
		}
	}
}

void App::Destroy()
{
	SAFE_DELETE(mesh[0]);
	SAFE_DELETE(mesh[1]);
	SAFE_DELETE(mesh[2]);
	SAFE_DELETE(meshTiny);
}
<|endoftext|>


<commit_before>#include "Camera.hpp"

Camera::Camera() {
	// TODO: Should be defined dynamically
	m_inputModel.bindKey(GLFW_KEY_W,
	                     [&]() { m_spatialModel.translate(1.0f, 0.0f, 0.0f); });

	m_inputModel.bindKey(GLFW_KEY_A,
	                     [&]() { m_spatialModel.translate(0.0f, 1.0f, 0.0f); });

	m_inputModel.bindKey(GLFW_KEY_S,
	                     [&]() { m_spatialModel.translate(-1.0f, 0.0f, 0.0f); });

	m_inputModel.bindKey(GLFW_KEY_D,
	                     [&]() { m_spatialModel.translate(0.0f, -1.0f, 0.0f); });

	m_inputModel.bindKey(GLFW_KEY_Z,
	                     [&]() { m_spatialModel.translate(0.0f, 0.0f, 1.0f); });

	m_inputModel.bindKey(GLFW_KEY_X,
	                     [&]() { m_spatialModel.translate(0.0f, 0.0f, -1.0f); });

	m_inputModel.bindMouse([&](glm::dvec2 lastPos, glm::dvec2 newPos) {
		m_spatialModel.rotate(0.0f,
		                      -((newPos.y - lastPos.y) / 128.0f),
		                      -((newPos.x - lastPos.x) / 128.0f));
		std::stringstream message;
		message << "Mouse moved: " << lastPos.x << "," << lastPos.y << " -> "
		        << newPos.x << "," << newPos.y;
		g_logger->write(Logger::LOG_DEBUG, message.str());
	});
}

glm::vec4 Camera::getPosition() { return m_spatialModel.position(); }

glm::mat4 Camera::getViewMatrix() {
	glm::mat4 orientationMatrix = glm::mat4_cast(m_spatialModel.orientation());

	glm::vec4 forward = orientationMatrix * SpatialModel::canonicalForward;
	glm::vec4 up      = orientationMatrix * SpatialModel::canonicalUp;

	m_viewMatrix = glm::lookAt(glm::vec3(m_spatialModel.position()),
	                           glm::vec3(m_spatialModel.position() + forward),
	                           glm::vec3(up));

	return m_viewMatrix;
}

void Camera::processInput(GLFWwindow& window) { m_inputModel.update(window); }
<commit_msg>Remove old, noisy debug message<commit_after>#include "Camera.hpp"

Camera::Camera() {
	// TODO: Should be defined dynamically
	m_inputModel.bindKey(GLFW_KEY_W,
	                     [&]() { m_spatialModel.translate(1.0f, 0.0f, 0.0f); });

	m_inputModel.bindKey(GLFW_KEY_A,
	                     [&]() { m_spatialModel.translate(0.0f, 1.0f, 0.0f); });

	m_inputModel.bindKey(GLFW_KEY_S,
	                     [&]() { m_spatialModel.translate(-1.0f, 0.0f, 0.0f); });

	m_inputModel.bindKey(GLFW_KEY_D,
	                     [&]() { m_spatialModel.translate(0.0f, -1.0f, 0.0f); });

	m_inputModel.bindKey(GLFW_KEY_Z,
	                     [&]() { m_spatialModel.translate(0.0f, 0.0f, 1.0f); });

	m_inputModel.bindKey(GLFW_KEY_X,
	                     [&]() { m_spatialModel.translate(0.0f, 0.0f, -1.0f); });

	m_inputModel.bindMouse([&](glm::dvec2 lastPos, glm::dvec2 newPos) {
		m_spatialModel.rotate(0.0f,
		                      -((newPos.y - lastPos.y) / 128.0f),
		                      -((newPos.x - lastPos.x) / 128.0f));
	});
}

glm::vec4 Camera::getPosition() { return m_spatialModel.position(); }

glm::mat4 Camera::getViewMatrix() {
	glm::mat4 orientationMatrix = glm::mat4_cast(m_spatialModel.orientation());

	glm::vec4 forward = orientationMatrix * SpatialModel::canonicalForward;
	glm::vec4 up      = orientationMatrix * SpatialModel::canonicalUp;

	m_viewMatrix = glm::lookAt(glm::vec3(m_spatialModel.position()),
	                           glm::vec3(m_spatialModel.position() + forward),
	                           glm::vec3(up));

	return m_viewMatrix;
}

void Camera::processInput(GLFWwindow& window) { m_inputModel.update(window); }
<|endoftext|>


<commit_before>#ifndef _ESP_BRACZ_DEADRAIL_PROTO_HARDWARE_HXX_
#define _ESP_BRACZ_DEADRAIL_PROTO_HARDWARE_HXX_

#include "freertos_drivers/esp8266/Esp8266Gpio.hxx"
#include "freertos_drivers/common/BlinkerGPIO.hxx"
#include "freertos_drivers/common/DummyGPIO.hxx"
#include "utils/GpioInitializer.hxx"

struct HW
{
    GPIO_PIN(BLINKER_RAW, GpioOutputSafeHigh, 2);
    static constexpr bool blinker_invert = true;

    GPIO_PIN(MOT_A_HI, GpioOutputSafeLow, 14);
    GPIO_PIN(MOT_A_LO, GpioOutputSafeLow, 12);

    GPIO_PIN(MOT_B_HI, GpioOutputSafeLow, 5);
    GPIO_PIN(MOT_B_LO, GpioOutputSafeLow, 13);

    static constexpr bool invertLow = false;

    // forward: A=HI B=LO

    // typedef BLINKER_Pin LIGHT_FRONT_Pin;
    typedef DummyPin LIGHT_BACK_Pin;
    //GPIO_PIN(LIGHT_BACK, GpioOutputSafeLow, ??? RX pin);
    //typedef DummyPin LIGHT_FRONT_Pin;
    //GPIO_PIN(LIGHT_FRONT, GpioOutputSafeLow, 4);
    GPIO_PIN(LIGHT_FRONT, GpioOutputSafeLow, 4);
    typedef DummyPin F1_Pin;

    // Doubles as manual request pin.
    GPIO_PIN(REQ_BLOAD, GpioInputPU, 4);

    GPIO_PIN(ASEL1, GpioOutputSafeHigh, 0);
    typedef BLINKER_Pin ASEL2_Pin;
    //GPIO_PIN(ASEL2, GpioOutputSafeHigh, 2);

    GPIO_PIN(CHRG_EN, GpioOutputSafeLow, 15);

    typedef DummyPin BootloaderActivePin;

    typedef GpioInitializer<        //
        MOT_A_HI_Pin, MOT_A_LO_Pin, //
        MOT_B_HI_Pin, MOT_B_LO_Pin, //
        LIGHT_FRONT_Pin, LIGHT_BACK_Pin, //
        ASEL1_Pin, ASEL2_Pin, //
        CHRG_EN_Pin> GpioInit;

    typedef GpioInitializer<        //
        MOT_A_HI_Pin, MOT_A_LO_Pin, //
        MOT_B_HI_Pin, MOT_B_LO_Pin, //
        //LIGHT_FRONT_Pin, LIGHT_BACK_Pin, //
        ASEL1_Pin, ASEL2_Pin, //
        REQ_BLOAD_Pin, //
        CHRG_EN_Pin> GpioBootloaderInit;

};

#endif // _ESP_DEADRAIL_PROTO_HARDWARE_HXX_
<commit_msg>Switch motor outputs.<commit_after>#ifndef _ESP_BRACZ_DEADRAIL_PROTO_HARDWARE_HXX_
#define _ESP_BRACZ_DEADRAIL_PROTO_HARDWARE_HXX_

#include "freertos_drivers/esp8266/Esp8266Gpio.hxx"
#include "freertos_drivers/common/BlinkerGPIO.hxx"
#include "freertos_drivers/common/DummyGPIO.hxx"
#include "utils/GpioInitializer.hxx"

struct HW
{
    GPIO_PIN(BLINKER_RAW, GpioOutputSafeHigh, 2);
    static constexpr bool blinker_invert = true;

    GPIO_PIN(MOT_A_HI, GpioOutputSafeLow, 5);
    GPIO_PIN(MOT_A_LO, GpioOutputSafeLow, 13);

    GPIO_PIN(MOT_B_HI, GpioOutputSafeLow, 14);
    GPIO_PIN(MOT_B_LO, GpioOutputSafeLow, 12);

    static constexpr bool invertLow = false;

    // forward: A=HI B=LO

    // typedef BLINKER_Pin LIGHT_FRONT_Pin;
    typedef DummyPin LIGHT_BACK_Pin;
    //GPIO_PIN(LIGHT_BACK, GpioOutputSafeLow, ??? RX pin);
    //typedef DummyPin LIGHT_FRONT_Pin;
    //GPIO_PIN(LIGHT_FRONT, GpioOutputSafeLow, 4);
    GPIO_PIN(LIGHT_FRONT, GpioOutputSafeLow, 4);
    typedef DummyPin F1_Pin;

    // Doubles as manual request pin.
    GPIO_PIN(REQ_BLOAD, GpioInputPU, 4);

    GPIO_PIN(ASEL1, GpioOutputSafeHigh, 0);
    typedef BLINKER_Pin ASEL2_Pin;
    //GPIO_PIN(ASEL2, GpioOutputSafeHigh, 2);

    GPIO_PIN(CHRG_EN, GpioOutputSafeLow, 15);

    typedef DummyPin BootloaderActivePin;

    typedef GpioInitializer<        //
        MOT_A_HI_Pin, MOT_A_LO_Pin, //
        MOT_B_HI_Pin, MOT_B_LO_Pin, //
        LIGHT_FRONT_Pin, LIGHT_BACK_Pin, //
        ASEL1_Pin, ASEL2_Pin, //
        CHRG_EN_Pin> GpioInit;

    typedef GpioInitializer<        //
        MOT_A_HI_Pin, MOT_A_LO_Pin, //
        MOT_B_HI_Pin, MOT_B_LO_Pin, //
        //LIGHT_FRONT_Pin, LIGHT_BACK_Pin, //
        ASEL1_Pin, ASEL2_Pin, //
        REQ_BLOAD_Pin, //
        CHRG_EN_Pin> GpioBootloaderInit;

};

#endif // _ESP_DEADRAIL_PROTO_HARDWARE_HXX_
<|endoftext|>