<commit_before>/*
 * Launch and manage "Local HTTP" child processes.
 *
 * author: Max Kellermann <mk@cm4all.com>
 */

#include "child_stock.hxx"
#include "child_socket.hxx"
#include "stock/MapStock.hxx"
#include "stock/Stock.hxx"
#include "stock/Class.hxx"
#include "stock/Item.hxx"
#include "child_manager.hxx"
#include "gerrno.h"
#include "system/sigutil.h"
#include "pool.hxx"

#include <glib.h>

#include <assert.h>
#include <unistd.h>
#include <sched.h>

struct ChildStockItem final : PoolStockItem {
    const char *key;

    const ChildStockClass *cls;
    void *cls_ctx = nullptr;

    ChildSocket socket;
    pid_t pid = -1;

    bool busy;

    ChildStockItem(struct pool &_pool, CreateStockItem c)
        :PoolStockItem(_pool, c) {}

    ~ChildStockItem() override;

    /* virtual methods from class StockItem */
    bool Borrow(gcc_unused void *ctx) override {
        assert(!busy);
        busy = true;

        return true;
    }

    bool Release(gcc_unused void *ctx) override {
        assert(busy);
        busy = false;

        /* reuse this item only if the child process hasn't exited */
        return pid > 0;
    }
};

static void
child_stock_child_callback(int status gcc_unused, void *ctx)
{
    auto *item = (ChildStockItem *)ctx;

    item->pid = -1;

    if (!item->busy)
        item->InvokeIdleDisconnect();
}

struct ChildStockArgs {
    struct pool *pool;
    const char *key;
    void *info;
    const ChildStockClass *cls;
    void *cls_ctx;
    int fd;
    sigset_t *signals;
};

gcc_noreturn
static int
child_stock_fn(void *ctx)
{
    const auto *args = (const ChildStockArgs *)ctx;
    const int fd = args->fd;

    install_default_signal_handlers();
    leave_signal_section(args->signals);

    dup2(fd, 0);
    close(fd);

    int result = args->cls->run(args->pool, args->key, args->info,
                                args->cls_ctx);
    _exit(result);
}

static pid_t
child_stock_start(struct pool *pool, const char *key, void *info,
                  int clone_flags,
                  const ChildStockClass *cls, void *ctx,
                  int fd, GError **error_r)
{
    /* avoid race condition due to libevent signal handler in child
       process */
    sigset_t signals;
    enter_signal_section(&signals);

    ChildStockArgs args = {
        pool, key, info,
        cls, ctx,
        fd,
        &signals,
    };

    char stack[8192];

    int pid = clone(child_stock_fn, stack + sizeof(stack),
                    clone_flags, &args);
    if (pid < 0) {
        set_error_errno_msg(error_r, "clone() failed");
        leave_signal_section(&signals);
        return -1;
    }

    leave_signal_section(&signals);

    close(fd);

    return pid;
}

/*
 * stock class
 *
 */

static void
child_stock_create(void *stock_ctx,
                   struct pool &parent_pool, CreateStockItem c,
                   const char *key, void *info,
                   gcc_unused struct pool &caller_pool,
                   gcc_unused struct async_operation_ref &async_ref)
{
    const auto *cls = (const ChildStockClass *)stock_ctx;

    auto &pool = *pool_new_linear(&parent_pool, "child_stock_child", 2048);
    auto *item = NewFromPool<ChildStockItem>(pool, pool, c);

    item->key = key = p_strdup(&pool, key);
    item->cls = cls;

    GError *error = nullptr;
    void *cls_ctx = nullptr;
    if (cls->prepare != nullptr) {
        cls_ctx = cls->prepare(&pool, key, info, &error);
        if (cls_ctx == nullptr) {
            item->InvokeCreateError(error);
            return;
        }
    }

    item->cls_ctx = cls_ctx;

    int socket_type = cls->socket_type != nullptr
        ? cls->socket_type(key, info, cls_ctx)
        : SOCK_STREAM;

    int fd = item->socket.Create(socket_type, &error);
    if (fd < 0) {
        if (cls_ctx != nullptr)
            cls->free(cls_ctx);
        item->InvokeCreateError(error);
        return;
    }

    int clone_flags = SIGCHLD;
    if (cls->clone_flags != nullptr)
        clone_flags = cls->clone_flags(key, info, clone_flags, cls_ctx);

    pid_t pid = item->pid = child_stock_start(&pool, key, info, clone_flags,
                                              cls, cls_ctx, fd, &error);
    if (pid < 0) {
        if (cls_ctx != nullptr)
            cls->free(cls_ctx);
        item->InvokeCreateError(error);
        return;
    }

    child_register(pid, key, child_stock_child_callback, item);

    item->busy = true;
    item->InvokeCreateSuccess();
}

ChildStockItem::~ChildStockItem()
{
    if (pid >= 0)
        child_kill_signal(pid, cls->shutdown_signal);

    if (socket.IsDefined())
        socket.Unlink();

    if (cls_ctx != nullptr)
        cls->free(cls_ctx);
}

static constexpr StockClass child_stock_class = {
    .create = child_stock_create,
};

/*
 * interface
 *
 */

StockMap *
child_stock_new(struct pool *pool, unsigned limit, unsigned max_idle,
                const ChildStockClass *cls)
{
    assert(cls != nullptr);
    assert((cls->prepare == nullptr) == (cls->free == nullptr));
    assert(cls->shutdown_signal != 0);
    assert(cls->run != nullptr);

    union {
        const ChildStockClass *in;
        void *out;
    } u = { .in = cls };

    return hstock_new(*pool, child_stock_class, u.out, limit, max_idle);
}

const char *
child_stock_item_key(const StockItem *_item)
{
    const auto *item = (const ChildStockItem *)_item;

    return item->key;
}

int
child_stock_item_connect(const StockItem *_item, GError **error_r)
{
    const auto *item = (const ChildStockItem *)_item;

    return item->socket.Connect(error_r);
}

void
child_stock_put(StockMap *hstock, StockItem *_item,
                bool destroy)
{
    auto *item = (ChildStockItem *)_item;

    hstock_put(*hstock, item->key, *item, destroy);
}
<commit_msg>child_stock: move code to ChildStockItem constructor<commit_after>/*
 * Launch and manage "Local HTTP" child processes.
 *
 * author: Max Kellermann <mk@cm4all.com>
 */

#include "child_stock.hxx"
#include "child_socket.hxx"
#include "stock/MapStock.hxx"
#include "stock/Stock.hxx"
#include "stock/Class.hxx"
#include "stock/Item.hxx"
#include "child_manager.hxx"
#include "gerrno.h"
#include "system/sigutil.h"
#include "pool.hxx"

#include <glib.h>

#include <assert.h>
#include <unistd.h>
#include <sched.h>

struct ChildStockItem final : PoolStockItem {
    const char *const key;

    const ChildStockClass *const cls;
    void *cls_ctx = nullptr;

    ChildSocket socket;
    pid_t pid = -1;

    bool busy = true;

    ChildStockItem(struct pool &_pool, CreateStockItem c,
                   const char *_key,
                   const ChildStockClass &_cls)
        :PoolStockItem(_pool, c),
         key(_key),
         cls(&_cls) {}

    ~ChildStockItem() override;

    /* virtual methods from class StockItem */
    bool Borrow(gcc_unused void *ctx) override {
        assert(!busy);
        busy = true;

        return true;
    }

    bool Release(gcc_unused void *ctx) override {
        assert(busy);
        busy = false;

        /* reuse this item only if the child process hasn't exited */
        return pid > 0;
    }
};

static void
child_stock_child_callback(int status gcc_unused, void *ctx)
{
    auto *item = (ChildStockItem *)ctx;

    item->pid = -1;

    if (!item->busy)
        item->InvokeIdleDisconnect();
}

struct ChildStockArgs {
    struct pool *pool;
    const char *key;
    void *info;
    const ChildStockClass *cls;
    void *cls_ctx;
    int fd;
    sigset_t *signals;
};

gcc_noreturn
static int
child_stock_fn(void *ctx)
{
    const auto *args = (const ChildStockArgs *)ctx;
    const int fd = args->fd;

    install_default_signal_handlers();
    leave_signal_section(args->signals);

    dup2(fd, 0);
    close(fd);

    int result = args->cls->run(args->pool, args->key, args->info,
                                args->cls_ctx);
    _exit(result);
}

static pid_t
child_stock_start(struct pool *pool, const char *key, void *info,
                  int clone_flags,
                  const ChildStockClass *cls, void *ctx,
                  int fd, GError **error_r)
{
    /* avoid race condition due to libevent signal handler in child
       process */
    sigset_t signals;
    enter_signal_section(&signals);

    ChildStockArgs args = {
        pool, key, info,
        cls, ctx,
        fd,
        &signals,
    };

    char stack[8192];

    int pid = clone(child_stock_fn, stack + sizeof(stack),
                    clone_flags, &args);
    if (pid < 0) {
        set_error_errno_msg(error_r, "clone() failed");
        leave_signal_section(&signals);
        return -1;
    }

    leave_signal_section(&signals);

    close(fd);

    return pid;
}

/*
 * stock class
 *
 */

static void
child_stock_create(void *stock_ctx,
                   struct pool &parent_pool, CreateStockItem c,
                   const char *key, void *info,
                   gcc_unused struct pool &caller_pool,
                   gcc_unused struct async_operation_ref &async_ref)
{
    const auto *cls = (const ChildStockClass *)stock_ctx;

    auto &pool = *pool_new_linear(&parent_pool, "child_stock_child", 2048);
    auto *item = NewFromPool<ChildStockItem>(pool, pool, c,
                                             p_strdup(&pool, key), *cls);

    GError *error = nullptr;
    void *cls_ctx = nullptr;
    if (cls->prepare != nullptr) {
        cls_ctx = cls->prepare(&pool, key, info, &error);
        if (cls_ctx == nullptr) {
            item->InvokeCreateError(error);
            return;
        }
    }

    item->cls_ctx = cls_ctx;

    int socket_type = cls->socket_type != nullptr
        ? cls->socket_type(key, info, cls_ctx)
        : SOCK_STREAM;

    int fd = item->socket.Create(socket_type, &error);
    if (fd < 0) {
        if (cls_ctx != nullptr)
            cls->free(cls_ctx);
        item->InvokeCreateError(error);
        return;
    }

    int clone_flags = SIGCHLD;
    if (cls->clone_flags != nullptr)
        clone_flags = cls->clone_flags(key, info, clone_flags, cls_ctx);

    pid_t pid = item->pid = child_stock_start(&pool, key, info, clone_flags,
                                              cls, cls_ctx, fd, &error);
    if (pid < 0) {
        if (cls_ctx != nullptr)
            cls->free(cls_ctx);
        item->InvokeCreateError(error);
        return;
    }

    child_register(pid, key, child_stock_child_callback, item);

    item->InvokeCreateSuccess();
}

ChildStockItem::~ChildStockItem()
{
    if (pid >= 0)
        child_kill_signal(pid, cls->shutdown_signal);

    if (socket.IsDefined())
        socket.Unlink();

    if (cls_ctx != nullptr)
        cls->free(cls_ctx);
}

static constexpr StockClass child_stock_class = {
    .create = child_stock_create,
};

/*
 * interface
 *
 */

StockMap *
child_stock_new(struct pool *pool, unsigned limit, unsigned max_idle,
                const ChildStockClass *cls)
{
    assert(cls != nullptr);
    assert((cls->prepare == nullptr) == (cls->free == nullptr));
    assert(cls->shutdown_signal != 0);
    assert(cls->run != nullptr);

    union {
        const ChildStockClass *in;
        void *out;
    } u = { .in = cls };

    return hstock_new(*pool, child_stock_class, u.out, limit, max_idle);
}

const char *
child_stock_item_key(const StockItem *_item)
{
    const auto *item = (const ChildStockItem *)_item;

    return item->key;
}

int
child_stock_item_connect(const StockItem *_item, GError **error_r)
{
    const auto *item = (const ChildStockItem *)_item;

    return item->socket.Connect(error_r);
}

void
child_stock_put(StockMap *hstock, StockItem *_item,
                bool destroy)
{
    auto *item = (ChildStockItem *)_item;

    hstock_put(*hstock, item->key, *item, destroy);
}
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2009-2022, Albertas Vyšniauskas
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
 *
 *     * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
 *     * Neither the name of the software author nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
 * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
 * OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include "uiDialogEdit.h"
#include "uiListPalette.h"
#include "uiUtilities.h"
#include "ColorList.h"
#include "ColorObject.h"
#include "ColorSpaces.h"
#include "Channels.h"
#include "dynv/Map.h"
#include "GlobalState.h"
#include "I18N.h"
#include "common/Guard.h"
#include "common/Match.h"
#include "common/Format.h"
#include "math/Algorithms.h"
#include <array>
#include <algorithm>
namespace {
struct DialogEditArgs {
	ColorList &selectedColorList;
	GlobalState &gs;
	dynv::Ref options;
	ColorList *previewColorList;
	const ColorSpaceDescription *colorSpace;
	struct Channel {
		GtkWidget *label, *alignment, *adjustmentRange;
		const ChannelDescription *channel;
	};
	std::array<Channel, 5> channels;
	GtkWidget *dialog, *colorSpaceComboBox, *relativeCheck, *previewExpander;
	DialogEditArgs(ColorList &selectedColorList, GlobalState &gs, GtkWindow *parent):
		selectedColorList(selectedColorList),
		gs(gs) {
		options = gs.settings().getOrCreateMap("gpick.edit");
		colorSpace = &common::matchById(colorSpaces(), options->getString("color_space", "rgb"));
		dialog = gtk_dialog_new_with_buttons(_("Edit colors"), parent, GtkDialogFlags(GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT), GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, GTK_STOCK_OK, GTK_RESPONSE_OK, nullptr);
		gtk_window_set_default_size(GTK_WINDOW(dialog), options->getInt32("window.width", -1), options->getInt32("window.height", -1));
		gtk_dialog_set_alternative_button_order(GTK_DIALOG(dialog), GTK_RESPONSE_OK, GTK_RESPONSE_CANCEL, -1);
		Grid grid(2, 3 + channels.size());
		grid.add(gtk_label_aligned_new(_("Color space:"), 0, 0.5, 0, 0));
		grid.add(colorSpaceComboBox = gtk_combo_box_text_new(), true);
		for (const auto &i: colorSpaces()) {
			gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(colorSpaceComboBox), _(i.name));
			if (&i == colorSpace)
				gtk_combo_box_set_active(GTK_COMBO_BOX(colorSpaceComboBox), &i - colorSpaces().data());
		}
		g_signal_connect(G_OBJECT(colorSpaceComboBox), "changed", G_CALLBACK(DialogEditArgs::onColorSpaceChange), this);
		grid.nextColumn();
		grid.add(relativeCheck = gtk_check_button_new_with_mnemonic(_("_Relative adjustment")), true);
		gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(relativeCheck), options->getBool("relative", true));
		g_signal_connect(G_OBJECT(relativeCheck), "toggled", G_CALLBACK(DialogEditArgs::onRelativeChange), this);
		size_t index = 0;
		for (auto &channel: channels) {
			channel.label = gtk_label_new("");
			channel.alignment = gtk_alignment_new(0, 0.5, 0, 0);
			gtk_container_add(GTK_CONTAINER(channel.alignment), channel.label);
			grid.add(channel.alignment);
			grid.add(channel.adjustmentRange = gtk_hscale_new_with_range(-100, 100, 1), true);
			gtk_range_set_value(GTK_RANGE(channel.adjustmentRange), options->getFloat(common::format("adjustment{}", index), 0) * 100);
			g_signal_connect(G_OBJECT(channel.adjustmentRange), "value-changed", G_CALLBACK(DialogEditArgs::onAdjustmentChange), this);
			g_signal_connect(G_OBJECT(channel.adjustmentRange), "format-value", G_CALLBACK(DialogEditArgs::onFormat), this);
			++index;
		}
		grid.add(previewExpander = palette_list_preview_new(&gs, true, options->getBool("show_preview", true), gs.getColorList(), &previewColorList), true, 2);
		setDialogContent(dialog, grid);
		setupChannels();
		update(true);
	}
	~DialogEditArgs() {
		gint width, height;
		gtk_window_get_size(GTK_WINDOW(dialog), &width, &height);
		options->set("window.width", width);
		options->set("window.height", height);
		options->set<bool>("show_preview", gtk_expander_get_expanded(GTK_EXPANDER(previewExpander)));
		gtk_widget_destroy(dialog);
		color_list_destroy(previewColorList);
	}
	void run() {
		if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_OK) {
			update(false);
			options->set("color_space", colorSpace->id);
			options->set("relative", gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(relativeCheck)));
			size_t index = 0;
			for (auto &channel: channels) {
				options->set(common::format("adjustment{}", index), static_cast<float>(gtk_range_get_value(GTK_RANGE(channel.adjustmentRange)) / 100));
				++index;
			}
		}
	}
	void update(bool preview) {
		if (preview)
			color_list_remove_all(previewColorList);
		colorSpace = &colorSpaces()[gtk_combo_box_get_active(GTK_COMBO_BOX(colorSpaceComboBox))];
		bool relative = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(relativeCheck));
		size_t index = 0;
		float adjustments[channels.size()];
		for (auto &channel: channels) {
			adjustments[index] = static_cast<float>(gtk_range_get_value(GTK_RANGE(channel.adjustmentRange)) / 100);
			++index;
		}
		ColorList &colorList = preview ? *previewColorList : *gs.getColorList();
		common::Guard colorListGuard(color_list_start_changes(&colorList), color_list_end_changes, &colorList);
		for (auto i = selectedColorList.colors.begin(); i != selectedColorList.colors.end(); ++i) {
			Color color = (*i)->getColor();
			float alpha = color.alpha;
			color = std::invoke(colorSpace->convertTo, color);
			for (size_t j = 0, end = std::min<size_t>(channels.size(), Color::MemberCount); j != end; ++j) {
				const auto &channel = *channels[j].channel;
				if (relative) {
					if (channel.wrap)
						color.data[j] = math::wrap(color.data[j] + color.data[j] * adjustments[j], channel.min, channel.max);
					else
						color.data[j] = math::clamp(color.data[j] + color.data[j] * adjustments[j], channel.min, channel.max);
				} else  {
					if (channel.wrap)
						color.data[j] = math::wrap(color.data[j] + (channel.max - channel.min) * adjustments[j], channel.min, channel.max);
					else
						color.data[j] = math::clamp(color.data[j] + (channel.max - channel.min) * adjustments[j], channel.min, channel.max);
				}
			}
			color = std::invoke(colorSpace->convertFrom, color);
			if ((colorSpace->flags & ColorSpaceFlags::externalAlpha) == ColorSpaceFlags::externalAlpha) {
				color.alpha = math::clamp(color.alpha + alpha * adjustments[4], 0, 1);
				color.alpha = alpha;
			}
			if (preview) {
				ColorObject *colorObject = color_list_new_color_object(&colorList, &color);
				colorObject->setName((*i)->getName());
				color_list_add_color_object(&colorList, colorObject, 1);
				colorObject->release();
			} else {
				(*i)->setColor(color);
			}
		}
	}
	void setupChannels() {
		size_t index = 0;
		for (const auto &channel: ::channels()) {
			if (channel.allColorSpaces || channel.colorSpace == colorSpace->type) {
				auto text = std::string(_(channel.name)) + ':';
				gtk_label_set_text(GTK_LABEL(channels[index].label), text.c_str());
				channels[index].channel = &channel;
				gtk_widget_show(channels[index].alignment);
				gtk_widget_show(channels[index].adjustmentRange);
				++index;
			}
		}
		for (; index < channels.size(); ++index) {
			gtk_widget_hide(channels[index].alignment);
			gtk_widget_hide(channels[index].adjustmentRange);
		}
	}
	static void onColorSpaceChange(GtkWidget *, DialogEditArgs *args) {
		args->colorSpace = &colorSpaces()[gtk_combo_box_get_active(GTK_COMBO_BOX(args->colorSpaceComboBox))];
		args->setupChannels();
		args->update(true);
	}
	static void onAdjustmentChange(GtkWidget *, DialogEditArgs *args) {
		args->update(true);
	}
	static void onRelativeChange(GtkWidget *, DialogEditArgs *args) {
		args->update(true);
	}
	static gchar *onFormat(GtkScale *, gdouble value) {
		return g_strdup_printf("%d%%", static_cast<int>(value));
	}
};
}
void dialog_edit_show(GtkWindow *parent, ColorList &selectedColorList, GlobalState &gs) {
	DialogEditArgs args(selectedColorList, gs, parent);
	args.run();
}
<commit_msg>Add missing RGB normalize call after multiple color edit.<commit_after>/*
 * Copyright (c) 2009-2022, Albertas Vyšniauskas
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
 *
 *     * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
 *     * Neither the name of the software author nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
 * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
 * OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include "uiDialogEdit.h"
#include "uiListPalette.h"
#include "uiUtilities.h"
#include "ColorList.h"
#include "ColorObject.h"
#include "ColorSpaces.h"
#include "Channels.h"
#include "dynv/Map.h"
#include "GlobalState.h"
#include "I18N.h"
#include "common/Guard.h"
#include "common/Match.h"
#include "common/Format.h"
#include "math/Algorithms.h"
#include <array>
#include <algorithm>
namespace {
struct DialogEditArgs {
	ColorList &selectedColorList;
	GlobalState &gs;
	dynv::Ref options;
	ColorList *previewColorList;
	const ColorSpaceDescription *colorSpace;
	struct Channel {
		GtkWidget *label, *alignment, *adjustmentRange;
		const ChannelDescription *channel;
	};
	std::array<Channel, 5> channels;
	GtkWidget *dialog, *colorSpaceComboBox, *relativeCheck, *previewExpander;
	DialogEditArgs(ColorList &selectedColorList, GlobalState &gs, GtkWindow *parent):
		selectedColorList(selectedColorList),
		gs(gs) {
		options = gs.settings().getOrCreateMap("gpick.edit");
		colorSpace = &common::matchById(colorSpaces(), options->getString("color_space", "rgb"));
		dialog = gtk_dialog_new_with_buttons(_("Edit colors"), parent, GtkDialogFlags(GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT), GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, GTK_STOCK_OK, GTK_RESPONSE_OK, nullptr);
		gtk_window_set_default_size(GTK_WINDOW(dialog), options->getInt32("window.width", -1), options->getInt32("window.height", -1));
		gtk_dialog_set_alternative_button_order(GTK_DIALOG(dialog), GTK_RESPONSE_OK, GTK_RESPONSE_CANCEL, -1);
		Grid grid(2, 3 + channels.size());
		grid.add(gtk_label_aligned_new(_("Color space:"), 0, 0.5, 0, 0));
		grid.add(colorSpaceComboBox = gtk_combo_box_text_new(), true);
		for (const auto &i: colorSpaces()) {
			gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(colorSpaceComboBox), _(i.name));
			if (&i == colorSpace)
				gtk_combo_box_set_active(GTK_COMBO_BOX(colorSpaceComboBox), &i - colorSpaces().data());
		}
		g_signal_connect(G_OBJECT(colorSpaceComboBox), "changed", G_CALLBACK(DialogEditArgs::onColorSpaceChange), this);
		grid.nextColumn();
		grid.add(relativeCheck = gtk_check_button_new_with_mnemonic(_("_Relative adjustment")), true);
		gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(relativeCheck), options->getBool("relative", true));
		g_signal_connect(G_OBJECT(relativeCheck), "toggled", G_CALLBACK(DialogEditArgs::onRelativeChange), this);
		size_t index = 0;
		for (auto &channel: channels) {
			channel.label = gtk_label_new("");
			channel.alignment = gtk_alignment_new(0, 0.5, 0, 0);
			gtk_container_add(GTK_CONTAINER(channel.alignment), channel.label);
			grid.add(channel.alignment);
			grid.add(channel.adjustmentRange = gtk_hscale_new_with_range(-100, 100, 1), true);
			gtk_range_set_value(GTK_RANGE(channel.adjustmentRange), options->getFloat(common::format("adjustment{}", index), 0) * 100);
			g_signal_connect(G_OBJECT(channel.adjustmentRange), "value-changed", G_CALLBACK(DialogEditArgs::onAdjustmentChange), this);
			g_signal_connect(G_OBJECT(channel.adjustmentRange), "format-value", G_CALLBACK(DialogEditArgs::onFormat), this);
			++index;
		}
		grid.add(previewExpander = palette_list_preview_new(&gs, true, options->getBool("show_preview", true), gs.getColorList(), &previewColorList), true, 2);
		setDialogContent(dialog, grid);
		setupChannels();
		update(true);
	}
	~DialogEditArgs() {
		gint width, height;
		gtk_window_get_size(GTK_WINDOW(dialog), &width, &height);
		options->set("window.width", width);
		options->set("window.height", height);
		options->set<bool>("show_preview", gtk_expander_get_expanded(GTK_EXPANDER(previewExpander)));
		gtk_widget_destroy(dialog);
		color_list_destroy(previewColorList);
	}
	void run() {
		if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_OK) {
			update(false);
			options->set("color_space", colorSpace->id);
			options->set("relative", gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(relativeCheck)));
			size_t index = 0;
			for (auto &channel: channels) {
				options->set(common::format("adjustment{}", index), static_cast<float>(gtk_range_get_value(GTK_RANGE(channel.adjustmentRange)) / 100));
				++index;
			}
		}
	}
	void update(bool preview) {
		if (preview)
			color_list_remove_all(previewColorList);
		colorSpace = &colorSpaces()[gtk_combo_box_get_active(GTK_COMBO_BOX(colorSpaceComboBox))];
		bool relative = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(relativeCheck));
		size_t index = 0;
		float adjustments[channels.size()];
		for (auto &channel: channels) {
			adjustments[index] = static_cast<float>(gtk_range_get_value(GTK_RANGE(channel.adjustmentRange)) / 100);
			++index;
		}
		ColorList &colorList = preview ? *previewColorList : *gs.getColorList();
		common::Guard colorListGuard(color_list_start_changes(&colorList), color_list_end_changes, &colorList);
		for (auto i = selectedColorList.colors.begin(); i != selectedColorList.colors.end(); ++i) {
			Color color = (*i)->getColor();
			float alpha = color.alpha;
			color = std::invoke(colorSpace->convertTo, color);
			for (size_t j = 0, end = std::min<size_t>(channels.size(), Color::MemberCount); j != end; ++j) {
				const auto &channel = *channels[j].channel;
				if (relative) {
					if (channel.wrap)
						color.data[j] = math::wrap(color.data[j] + color.data[j] * adjustments[j], channel.min, channel.max);
					else
						color.data[j] = math::clamp(color.data[j] + color.data[j] * adjustments[j], channel.min, channel.max);
				} else  {
					if (channel.wrap)
						color.data[j] = math::wrap(color.data[j] + (channel.max - channel.min) * adjustments[j], channel.min, channel.max);
					else
						color.data[j] = math::clamp(color.data[j] + (channel.max - channel.min) * adjustments[j], channel.min, channel.max);
				}
			}
			color = std::invoke(colorSpace->convertFrom, color);
			if ((colorSpace->flags & ColorSpaceFlags::externalAlpha) == ColorSpaceFlags::externalAlpha) {
				color.alpha = math::clamp(color.alpha + alpha * adjustments[4], 0, 1);
				color.alpha = alpha;
			}
			color.normalizeRgbInplace();
			if (preview) {
				ColorObject *colorObject = color_list_new_color_object(&colorList, &color);
				colorObject->setName((*i)->getName());
				color_list_add_color_object(&colorList, colorObject, 1);
				colorObject->release();
			} else {
				(*i)->setColor(color);
			}
		}
	}
	void setupChannels() {
		size_t index = 0;
		for (const auto &channel: ::channels()) {
			if (channel.allColorSpaces || channel.colorSpace == colorSpace->type) {
				auto text = std::string(_(channel.name)) + ':';
				gtk_label_set_text(GTK_LABEL(channels[index].label), text.c_str());
				channels[index].channel = &channel;
				gtk_widget_show(channels[index].alignment);
				gtk_widget_show(channels[index].adjustmentRange);
				++index;
			}
		}
		for (; index < channels.size(); ++index) {
			gtk_widget_hide(channels[index].alignment);
			gtk_widget_hide(channels[index].adjustmentRange);
		}
	}
	static void onColorSpaceChange(GtkWidget *, DialogEditArgs *args) {
		args->colorSpace = &colorSpaces()[gtk_combo_box_get_active(GTK_COMBO_BOX(args->colorSpaceComboBox))];
		args->setupChannels();
		args->update(true);
	}
	static void onAdjustmentChange(GtkWidget *, DialogEditArgs *args) {
		args->update(true);
	}
	static void onRelativeChange(GtkWidget *, DialogEditArgs *args) {
		args->update(true);
	}
	static gchar *onFormat(GtkScale *, gdouble value) {
		return g_strdup_printf("%d%%", static_cast<int>(value));
	}
};
}
void dialog_edit_show(GtkWindow *parent, ColorList &selectedColorList, GlobalState &gs) {
	DialogEditArgs args(selectedColorList, gs, parent);
	args.run();
}
<|endoftext|>


<commit_before>/*

@Copyright Barrett Adair 2015-2017
Distributed under the Boost Software License, Version 1.0.
(See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt)

*/

#ifndef BOOST_CLBL_TRTS_FUNCTION_TYPE_HPP
#define BOOST_CLBL_TRTS_FUNCTION_TYPE_HPP

#include <boost/callable_traits/detail/core.hpp>

namespace boost { namespace callable_traits {

//[ function_type_hpp
/*`[section:ref_function_type function_type]
[heading Header]
``#include <boost/callable_traits/function_type.hpp>``
[heading Definition]
*/

template<typename T>
using function_type_t = //see below
//<-
    detail::try_but_fail_if_invalid<typename detail::traits<
            detail::shallow_decay<T>>::function_type,
        cannot_determine_parameters_for_this_type>;

namespace detail {

    template<typename T, typename = std::false_type>
    struct function_type_impl {};

    template<typename T>
    struct function_type_impl <T, typename std::is_same<
        function_type_t<T>, detail::dummy>::type>
    {
        using type = function_type_t<T>;
    };
}

//->

template<typename T>
struct function_type : detail::function_type_impl<T> {};

//<-
}} // namespace boost::callable_traits
//->

/*`
[heading Constraints]
* `T` must be one of the following:
  * function
  * function pointer
  * function reference
  * member function pointer
  * member data pointer
  * user-defined type with a non-overloaded `operator()`
  * type of a non-generic lambda

[heading Behavior]
* When the constraints are violated, a substitution failure occurs.
* When `T` is a function, the aliased type is identical to `T`, except that the aliased function type will not have member qualifiers or the `transaction_safe` specifier.
* When `T` is a function pointer, the aliased type is equivalent to `std::remove_pointer_t<T>`.
* When `T` is a function reference, the aliased type is equivalent to `std::remove_reference_t<T>`.
* When `T` is a function object, the aliased type is a function type with the same return type and parameter list as `T`'s `operator()`.
* When `T` is a member function pointer, the aliased type is a function type with the same return type as `T`, and the first parameter is a reference to the parent class of `T`, qualified according to the member qualifiers on `T`. The subsequent parameters, if any, are the parameter types of `T`.
* When `T` is a member data pointer, the aliased type is a function type returning the underlying member type of `T`, taking a single parameter, which is a `const` reference to the parent type of `T`.
* In all cases, the aliased function type will not have member qualifiers, and will not have the `transaction_safe` specifier.

[heading Input/Output Examples]
[table
    [[`T`]                              [`function_type_t<T>`]]
    [[`void(int)`]                      [`void(int)`]]
    [[`void(int) const`]                [`void(int)`]]
    [[`void(int) transaction_safe`]     [`void(int)`]]
    [[`void(*const &)(int)`]            [`void(int)`]]
    [[`void(&)(int)`]                   [`void(int)`]]
    [[`void(* volatile)()`]             [`void()`]]
    [[`int(foo::*)(int)`]               [`int(foo&, int)`]]
    [[`int(foo::*)(int) const`]         [`int(const foo&, int)`]]
    [[`void(foo::*)() volatile &&`]     [`void(volatile foo&&)`]]
    [[`int foo::*`]                     [`int(const foo&)`]]
    [[`const int foo::*`]               [`int(const foo&)`]]
    [[`int`]                            [(substitution failure)]]
]

[heading Example Program]
[import ../example/function_type.cpp]
[function_type]
[endsect]
*/
//]

#endif
<commit_msg>Delete function_type.hpp<commit_after><|endoftext|>


<commit_before>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: tpaction.hxx,v $
 *
 *  $Revision: 1.10 $
 *
 *  last change: $Author: kz $ $Date: 2006-12-12 17:49:15 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library 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
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

#ifndef _SD_TPACTION_HXX
#define _SD_TPACTION_HXX

#ifndef _COM_SUN_STAR_PRESENTATION_CLICKACTION_HPP_
#include <com/sun/star/presentation/ClickAction.hpp>
#endif
#ifndef _COM_SUN_STAR_PRESENTATION_ANIMATIONEFFECT_HPP_
#include <com/sun/star/presentation/AnimationEffect.hpp>
#endif

#ifndef _SVT_FILEDLG_HXX //autogen
#include <svtools/filedlg.hxx>
#endif

#ifndef _SV_GROUP_HXX //autogen
#include <vcl/group.hxx>
#endif

#ifndef _SV_FIXED_HXX //autogen
#include <vcl/fixed.hxx>
#endif

#ifndef _SOUND_HXX //autogen
#include <vcl/sound.hxx>
#endif
#ifndef _SVX_DLG_CTRL_HXX //autogen
#include <svx/dlgctrl.hxx>
#endif
#ifndef _SFXTABDLG_HXX //autogen
#include <sfx2/tabdlg.hxx>
#endif
#ifndef _BASEDLGS_HXX //autogen
#include <sfx2/basedlgs.hxx>
#endif
#ifndef _SFXTABDLG_HXX //autogen
#include <sfx2/tabdlg.hxx>
#endif
#include "sdtreelb.hxx"
#include "anmdef.hxx"

#include <vector>

class ::sd::View;
class SdDrawDocument;

/*************************************************************************
|*
|* Effekte-SingleTab-Dialog
|*
\************************************************************************/
class SdActionDlg : public SfxSingleTabDialog
{
private:
    const SfxItemSet&   rOutAttrs;

public:

            SdActionDlg( Window* pParent, const SfxItemSet* pAttr, ::sd::View* pView );
            ~SdActionDlg() {};
};

/*************************************************************************
|*
|* Interaktions-Tab-Page
|*
\************************************************************************/

class SdTPAction : public SfxTabPage
{
private:
    FixedText               aFtAction;              // always visible
    ListBox                 aLbAction;

    FixedText               aFtTree;                // jump destination controls
    SdPageObjsTLB           aLbTree;
    SdPageObjsTLB           aLbTreeDocument;
    ListBox                 aLbOLEAction;

    FixedLine               aFlSeparator;
    Edit                    aEdtSound;
    Edit                    aEdtBookmark;
    Edit                    aEdtDocument;
    Edit                    aEdtProgram;
    Edit                    aEdtMacro;
    PushButton              aBtnSearch;
    PushButton              aBtnSeek;

    const SfxItemSet&       rOutAttrs;
    const ::sd::View*       mpView;
    SdDrawDocument*         mpDoc;
    XColorTable*            pColTab;

    BOOL                    bTreeUpdated;
    List*                   pCurrentActions;
    String                  aLastFile;
    ::std::vector< long >   aVerbVector;

    //------------------------------------

    DECL_LINK( ClickSearchHdl, void * );
    DECL_LINK( ClickActionHdl, void * );
    DECL_LINK( SelectTreeHdl, void * );
    DECL_LINK( CheckFileHdl, void * );

    void                    UpdateTree();
    virtual void            OpenFileDialog();
    ::com::sun::star::presentation::ClickAction     GetActualClickAction();
    void                    SetActualClickAction( ::com::sun::star::presentation::ClickAction eCA );
    void                    SetActualAnimationEffect( ::com::sun::star::presentation::AnimationEffect eAE );
    void                    SetEditText( String const & rStr );
    String                  GetEditText( BOOL bURL = FALSE );
    String                  GetMacroName( const String& rPath );
    USHORT                  GetClickActionSdResId( ::com::sun::star::presentation::ClickAction eCA );
    USHORT                  GetAnimationEffectSdResId( ::com::sun::star::presentation::AnimationEffect eAE );

public:
            SdTPAction( Window* pParent, const SfxItemSet& rInAttrs );
            ~SdTPAction();

    static  SfxTabPage* Create( Window*, const SfxItemSet& );
    static  USHORT*    GetRanges();

    virtual BOOL FillItemSet( SfxItemSet& );
    virtual void Reset( const SfxItemSet & );

    virtual void ActivatePage( const SfxItemSet& rSet );
    virtual int  DeactivatePage( SfxItemSet* pSet );

    void    Construct();

    void    SetView( const ::sd::View* pSdView );

    using TabPage::ActivatePage;
    using TabPage::DeactivatePage;
};

#endif      // _SD_TPACTION_HXX

<commit_msg>INTEGRATION: CWS unifysound01_DEV300 (1.10.182); FILE MERGED 2007/08/30 08:28:00 cmc 1.10.182.1: #i81144# move filepicker from vcl sound to avmedia sound<commit_after>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: tpaction.hxx,v $
 *
 *  $Revision: 1.11 $
 *
 *  last change: $Author: kz $ $Date: 2008-03-07 16:27:35 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library 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
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

#ifndef _SD_TPACTION_HXX
#define _SD_TPACTION_HXX

#ifndef _COM_SUN_STAR_PRESENTATION_CLICKACTION_HPP_
#include <com/sun/star/presentation/ClickAction.hpp>
#endif
#ifndef _COM_SUN_STAR_PRESENTATION_ANIMATIONEFFECT_HPP_
#include <com/sun/star/presentation/AnimationEffect.hpp>
#endif

#ifndef _SVT_FILEDLG_HXX //autogen
#include <svtools/filedlg.hxx>
#endif

#ifndef _SV_GROUP_HXX //autogen
#include <vcl/group.hxx>
#endif

#ifndef _SV_FIXED_HXX //autogen
#include <vcl/fixed.hxx>
#endif

#ifndef _SVX_DLG_CTRL_HXX //autogen
#include <svx/dlgctrl.hxx>
#endif
#ifndef _SFXTABDLG_HXX //autogen
#include <sfx2/tabdlg.hxx>
#endif
#ifndef _BASEDLGS_HXX //autogen
#include <sfx2/basedlgs.hxx>
#endif
#ifndef _SFXTABDLG_HXX //autogen
#include <sfx2/tabdlg.hxx>
#endif
#include "sdtreelb.hxx"
#include "anmdef.hxx"

#include <vector>

class ::sd::View;
class SdDrawDocument;

/*************************************************************************
|*
|* Effekte-SingleTab-Dialog
|*
\************************************************************************/
class SdActionDlg : public SfxSingleTabDialog
{
private:
    const SfxItemSet&   rOutAttrs;

public:

            SdActionDlg( Window* pParent, const SfxItemSet* pAttr, ::sd::View* pView );
            ~SdActionDlg() {};
};

/*************************************************************************
|*
|* Interaktions-Tab-Page
|*
\************************************************************************/

class SdTPAction : public SfxTabPage
{
private:
    FixedText               aFtAction;              // always visible
    ListBox                 aLbAction;

    FixedText               aFtTree;                // jump destination controls
    SdPageObjsTLB           aLbTree;
    SdPageObjsTLB           aLbTreeDocument;
    ListBox                 aLbOLEAction;

    FixedLine               aFlSeparator;
    Edit                    aEdtSound;
    Edit                    aEdtBookmark;
    Edit                    aEdtDocument;
    Edit                    aEdtProgram;
    Edit                    aEdtMacro;
    PushButton              aBtnSearch;
    PushButton              aBtnSeek;

    const SfxItemSet&       rOutAttrs;
    const ::sd::View*       mpView;
    SdDrawDocument*         mpDoc;
    XColorTable*            pColTab;

    BOOL                    bTreeUpdated;
    List*                   pCurrentActions;
    String                  aLastFile;
    ::std::vector< long >   aVerbVector;

    //------------------------------------

    DECL_LINK( ClickSearchHdl, void * );
    DECL_LINK( ClickActionHdl, void * );
    DECL_LINK( SelectTreeHdl, void * );
    DECL_LINK( CheckFileHdl, void * );

    void                    UpdateTree();
    virtual void            OpenFileDialog();
    ::com::sun::star::presentation::ClickAction     GetActualClickAction();
    void                    SetActualClickAction( ::com::sun::star::presentation::ClickAction eCA );
    void                    SetActualAnimationEffect( ::com::sun::star::presentation::AnimationEffect eAE );
    void                    SetEditText( String const & rStr );
    String                  GetEditText( BOOL bURL = FALSE );
    String                  GetMacroName( const String& rPath );
    USHORT                  GetClickActionSdResId( ::com::sun::star::presentation::ClickAction eCA );
    USHORT                  GetAnimationEffectSdResId( ::com::sun::star::presentation::AnimationEffect eAE );

public:
            SdTPAction( Window* pParent, const SfxItemSet& rInAttrs );
            ~SdTPAction();

    static  SfxTabPage* Create( Window*, const SfxItemSet& );
    static  USHORT*    GetRanges();

    virtual BOOL FillItemSet( SfxItemSet& );
    virtual void Reset( const SfxItemSet & );

    virtual void ActivatePage( const SfxItemSet& rSet );
    virtual int  DeactivatePage( SfxItemSet* pSet );

    void    Construct();

    void    SetView( const ::sd::View* pSdView );

    using TabPage::ActivatePage;
    using TabPage::DeactivatePage;
};

#endif      // _SD_TPACTION_HXX

<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  $RCSfile: DDriver.cxx,v $
 *
 *  $Revision: 1.5 $
 *
 *  last change: $Author: oj $ $Date: 2002-08-21 13:15:02 $
 *
 *  The Contents of this file are made available subject to the terms of
 *  either of the following licenses
 *
 *         - GNU Lesser General Public License Version 2.1
 *         - Sun Industry Standards Source License Version 1.1
 *
 *  Sun Microsystems Inc., October, 2000
 *
 *  GNU Lesser General Public License Version 2.1
 *  =============================================
 *  Copyright 2000 by Sun Microsystems, Inc.
 *  901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License version 2.1, as published by the Free Software Foundation.
 *
 *  This library 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
 *  Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *  MA  02111-1307  USA
 *
 *
 *  Sun Industry Standards Source License Version 1.1
 *  =================================================
 *  The contents of this file are subject to the Sun Industry Standards
 *  Source License Version 1.1 (the "License"); You may not use this file
 *  except in compliance with the License. You may obtain a copy of the
 *  License at http://www.openoffice.org/license.html.
 *
 *  Software provided under this License is provided on an "AS IS" basis,
 *  WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
 *  WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
 *  MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
 *  See the License for the specific provisions governing your rights and
 *  obligations concerning the Software.
 *
 *  The Initial Developer of the Original Code is: Sun Microsystems, Inc.
 *
 *  Copyright: 2000 by Sun Microsystems, Inc.
 *
 *  All Rights Reserved.
 *
 *  Contributor(s): _______________________________________
 *
 *
 ************************************************************************/

#ifndef _CONNECTIVITY_DBASE_DDRIVER_HXX_
#include "dbase/DDriver.hxx"
#endif
#ifndef _CONNECTIVITY_DBASE_DCONNECTION_HXX_
#include "dbase/DConnection.hxx"
#endif
#ifndef _COM_SUN_STAR_LANG_DISPOSEDEXCEPTION_HPP_
#include <com/sun/star/lang/DisposedException.hpp>
#endif
#ifndef _DBHELPER_DBEXCEPTION_HXX_
#include "connectivity/dbexception.hxx"
#endif

using namespace connectivity::dbase;
using namespace connectivity::file;
using namespace ::com::sun::star::uno;
using namespace ::com::sun::star::beans;
using namespace ::com::sun::star::sdbcx;
using namespace ::com::sun::star::sdbc;
using namespace ::com::sun::star::lang;

// static ServiceInfo
//------------------------------------------------------------------------------
rtl::OUString ODriver::getImplementationName_Static(  ) throw(RuntimeException)
{
    return rtl::OUString::createFromAscii("com.sun.star.comp.sdbc.dbase.ODriver");
}

//------------------------------------------------------------------
::rtl::OUString SAL_CALL ODriver::getImplementationName(  ) throw(RuntimeException)
{
    return getImplementationName_Static();
}

//------------------------------------------------------------------
::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface >  SAL_CALL connectivity::dbase::ODriver_CreateInstance(const ::com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory >& _rxFactory) throw( ::com::sun::star::uno::Exception )
{
    return *(new ODriver(_rxFactory));
}
// --------------------------------------------------------------------------------
Reference< XConnection > SAL_CALL ODriver::connect( const ::rtl::OUString& url, const Sequence< PropertyValue >& info ) throw(SQLException, RuntimeException)
{
    ::osl::MutexGuard aGuard( m_aMutex );
    if (ODriver_BASE::rBHelper.bDisposed)
        throw DisposedException();

    if ( ! acceptsURL(url) )
        return NULL;

    ODbaseConnection* pCon = new ODbaseConnection(this);
    pCon->construct(url,info);
    Reference< XConnection > xCon = pCon;
    m_xConnections.push_back(WeakReferenceHelper(*pCon));

    return xCon;
}
// --------------------------------------------------------------------------------
sal_Bool SAL_CALL ODriver::acceptsURL( const ::rtl::OUString& url ) throw(SQLException, RuntimeException)
{
    return !url.compareTo(::rtl::OUString::createFromAscii("sdbc:dbase:"),11);
}
// -----------------------------------------------------------------------------

<commit_msg>INTEGRATION: CWS insight01 (1.5.94); FILE MERGED 2003/08/04 10:41:05 oj 1.5.94.2: #111090# further coding 2003/08/04 06:11:35 oj 1.5.94.1: #111075# ongoing work<commit_after>/*************************************************************************
 *
 *  $RCSfile: DDriver.cxx,v $
 *
 *  $Revision: 1.6 $
 *
 *  last change: $Author: hr $ $Date: 2004-08-02 16:59:35 $
 *
 *  The Contents of this file are made available subject to the terms of
 *  either of the following licenses
 *
 *         - GNU Lesser General Public License Version 2.1
 *         - Sun Industry Standards Source License Version 1.1
 *
 *  Sun Microsystems Inc., October, 2000
 *
 *  GNU Lesser General Public License Version 2.1
 *  =============================================
 *  Copyright 2000 by Sun Microsystems, Inc.
 *  901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License version 2.1, as published by the Free Software Foundation.
 *
 *  This library 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
 *  Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *  MA  02111-1307  USA
 *
 *
 *  Sun Industry Standards Source License Version 1.1
 *  =================================================
 *  The contents of this file are subject to the Sun Industry Standards
 *  Source License Version 1.1 (the "License"); You may not use this file
 *  except in compliance with the License. You may obtain a copy of the
 *  License at http://www.openoffice.org/license.html.
 *
 *  Software provided under this License is provided on an "AS IS" basis,
 *  WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
 *  WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
 *  MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
 *  See the License for the specific provisions governing your rights and
 *  obligations concerning the Software.
 *
 *  The Initial Developer of the Original Code is: Sun Microsystems, Inc.
 *
 *  Copyright: 2000 by Sun Microsystems, Inc.
 *
 *  All Rights Reserved.
 *
 *  Contributor(s): _______________________________________
 *
 *
 ************************************************************************/

#ifndef _CONNECTIVITY_DBASE_DDRIVER_HXX_
#include "dbase/DDriver.hxx"
#endif
#ifndef _CONNECTIVITY_DBASE_DCONNECTION_HXX_
#include "dbase/DConnection.hxx"
#endif
#ifndef _COM_SUN_STAR_LANG_DISPOSEDEXCEPTION_HPP_
#include <com/sun/star/lang/DisposedException.hpp>
#endif
#ifndef _DBHELPER_DBEXCEPTION_HXX_
#include "connectivity/dbexception.hxx"
#endif

using namespace connectivity::dbase;
using namespace connectivity::file;
using namespace ::com::sun::star::uno;
using namespace ::com::sun::star::beans;
using namespace ::com::sun::star::sdbcx;
using namespace ::com::sun::star::sdbc;
using namespace ::com::sun::star::lang;

// static ServiceInfo
//------------------------------------------------------------------------------
rtl::OUString ODriver::getImplementationName_Static(  ) throw(RuntimeException)
{
    return rtl::OUString::createFromAscii("com.sun.star.comp.sdbc.dbase.ODriver");
}

//------------------------------------------------------------------
::rtl::OUString SAL_CALL ODriver::getImplementationName(  ) throw(RuntimeException)
{
    return getImplementationName_Static();
}

//------------------------------------------------------------------
::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface >  SAL_CALL connectivity::dbase::ODriver_CreateInstance(const ::com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory >& _rxFactory) throw( ::com::sun::star::uno::Exception )
{
    return *(new ODriver(_rxFactory));
}
// --------------------------------------------------------------------------------
Reference< XConnection > SAL_CALL ODriver::connect( const ::rtl::OUString& url, const Sequence< PropertyValue >& info ) throw(SQLException, RuntimeException)
{
    ::osl::MutexGuard aGuard( m_aMutex );
    if (ODriver_BASE::rBHelper.bDisposed)
        throw DisposedException();

    if ( ! acceptsURL(url) )
        return NULL;

    ODbaseConnection* pCon = new ODbaseConnection(this);
    pCon->construct(url,info);
    Reference< XConnection > xCon = pCon;
    m_xConnections.push_back(WeakReferenceHelper(*pCon));

    return xCon;
}
// --------------------------------------------------------------------------------
sal_Bool SAL_CALL ODriver::acceptsURL( const ::rtl::OUString& url ) throw(SQLException, RuntimeException)
{
    return !url.compareTo(::rtl::OUString::createFromAscii("sdbc:dbase:"),11);
}
// -----------------------------------------------------------------------------
Sequence< DriverPropertyInfo > SAL_CALL ODriver::getPropertyInfo( const ::rtl::OUString& url, const Sequence< PropertyValue >& info ) throw(SQLException, RuntimeException)
{
    if ( acceptsURL(url) )
    {
        ::std::vector< DriverPropertyInfo > aDriverInfo;

        Sequence< ::rtl::OUString > aBoolean(2);
        aBoolean[0] = ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("0"));
        aBoolean[1] = ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("1"));

        aDriverInfo.push_back(DriverPropertyInfo(
                ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("CharSet"))
                ,::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("CharSet of the database."))
                ,sal_False
                ,::rtl::OUString()
                ,Sequence< ::rtl::OUString >())
                );
        aDriverInfo.push_back(DriverPropertyInfo(
                ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("ShowDeleted"))
                ,::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("Display inactive records."))
                ,sal_False
                ,::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("0"))
                ,aBoolean)
                );
        aDriverInfo.push_back(DriverPropertyInfo(
                ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("EnableSQL92Check"))
                ,::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("Use SQL92 naming constraints."))
                ,sal_False
                ,::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("0"))
                ,aBoolean)
                );
        return Sequence< DriverPropertyInfo >(aDriverInfo.begin(),aDriverInfo.size());
    }

    ::dbtools::throwGenericSQLException(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("Invalid URL!")) ,*this);
    return Sequence< DriverPropertyInfo >();
}
// -----------------------------------------------------------------------------

<|endoftext|>


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

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

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

    This library 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
    Library General Public License for more details.

    You should have received a copy of the GNU Library General Public License
    along with this library; see the file COPYING.LIB.  If not, write to
    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
    Boston, MA 02110-1301, USA.
*/

#include <typeinfo>
#include <stdlib.h>

#include <qdatetime.h>
#include <qstring.h>
#include <qptrlist.h>

#include <klocale.h>
#include <kdebug.h>
#include <kurl.h>
#include <kio/job.h>
#include <kstandarddirs.h>

#include <kabc/stdaddressbook.h>
#include <kabc/locknull.h>

#include "libkcal/vcaldrag.h"
#include "libkcal/vcalformat.h"
#include "libkcal/icalformat.h"
#include "libkcal/exceptions.h"
#include "libkcal/incidence.h"
#include "libkcal/event.h"
#include "libkcal/todo.h"
#include "libkcal/journal.h"
#include "libkcal/filestorage.h"
#include "libkcal/alarm.h"

#include <kresources/configwidget.h>

#include "resourcekabcconfig.h"

#include "resourcekabc.h"

using namespace KCal;

extern "C"
{
  void *init_kcal_kabc()
  {
	  KGlobal::locale()->insertCatalogue( "kres_birthday" );
    KGlobal::locale()->insertCatalogue( "libkcal" );
    return new KRES::PluginFactory<ResourceKABC,ResourceKABCConfig>();
  }
}

ResourceKABC::ResourceKABC( const KConfig* config )
  : ResourceCalendar( config ), mCalendar( QString::fromLatin1( "UTC" ) ),
    mAlarmDays( 1 ), mAlarm( false ), mUseCategories( false )
{
  if ( config ) {
    readConfig( config );
  }

  init();
}

ResourceKABC::ResourceKABC()
  : ResourceCalendar( 0 ), mCalendar( QString::fromLatin1( "UTC" ) ),
    mAlarmDays( 1 ), mAlarm( false ), mUseCategories( false )
{
  init();
}

ResourceKABC::~ResourceKABC()
{
  delete mLock;
}

void ResourceKABC::init()
{
  setType( "birthdays" );

  setReadOnly( true );

  mLock = new KABC::LockNull( false );

  mAddressbook = 0;
}

void ResourceKABC::readConfig( const KConfig *config )
{
  mAlarmDays = config->readNumEntry( "AlarmDays", 1 );
  mAlarm = config->readBoolEntry( "Alarm", false );
  mCategories = config->readListEntry( "Categories" );
  mUseCategories = config->readBoolEntry( "UseCategories", false );
}

void ResourceKABC::writeConfig( KConfig *config )
{
  ResourceCalendar::writeConfig( config );
  config->writeEntry( "AlarmDays", mAlarmDays );
  config->writeEntry( "Alarm", mAlarm );
  config->writeEntry( "Categories", mCategories );
  config->writeEntry( "UseCategories", mUseCategories );
}

bool ResourceKABC::doOpen()
{
  kdDebug(5800) << "ResourceKABC::doOpen()" << endl;

  mAddressbook = KABC::StdAddressBook::self( true );
  connect( mAddressbook, SIGNAL(addressBookChanged(AddressBook*)), SLOT( reload() ) );

  return true;
}

bool ResourceKABC::doLoad()
{
  kdDebug(5800) << "ResourceKABC::load()" << endl;

  mCalendar.close();

  // import from kabc
  QString summary;
  QStringList::ConstIterator strIt;
  const QStringList::ConstIterator endStrIt = mCategories.end();
  KABC::Addressee::List anniversaries;
  KABC::Addressee::List::Iterator addrIt;

  KABC::AddressBook::Iterator it;
  const KABC::AddressBook::Iterator endIt = mAddressbook->end();
  for ( it = mAddressbook->begin(); it != endIt; ++it ) {

    if ( mUseCategories ) {
      bool hasCategory = false;
      QStringList categories = (*it).categories();
      for ( strIt = mCategories.begin(); strIt != endStrIt; ++strIt )
        if ( categories.contains( *strIt ) ) {
          hasCategory = true;
          break;
        }

      if ( !hasCategory )
        continue;
    }

    QDate birthdate = (*it).birthday().date();
    QString name_1, email_1, uid_1;
    if ( birthdate.isValid() ) {
      kdDebug(5800) << "found a birthday " << birthdate.toString() << endl;

      name_1 = (*it).nickName();
      email_1 = (*it).fullEmail();
      uid_1 = (*it).uid();
      if (name_1.isEmpty()) name_1 = (*it).realName();
      summary = i18n("%1's birthday").arg( name_1 );

      Event *ev = new Event();
      ev->setUid( uid_1+"_KABC_Birthday");

      ev->setDtStart(birthdate);
      ev->setDtEnd(birthdate);
      ev->setHasEndDate(true);
      ev->setFloats(true);
      ev->setTransparency( Event::Transparent );

      ev->setCustomProperty("KABC", "BIRTHDAY", "YES");
      ev->setCustomProperty("KABC", "UID-1", uid_1 );
      ev->setCustomProperty("KABC", "NAME-1", name_1 );
      ev->setCustomProperty("KABC", "EMAIL-1", email_1 );
      kdDebug(5800) << "ResourceKABC::doLoad: uid:" << uid_1 << " name: " << name_1
        << " email: " << email_1 << endl;
      ev->setSummary(summary);

      // Set the recurrence
      Recurrence *vRecurrence = ev->recurrence();
      vRecurrence->setStartDate( birthdate );
      vRecurrence->setYearly( 1 );
      if ( birthdate.month()==2 && birthdate.day()==29 ) {
        vRecurrence->addYearlyDay( 60 );
      }

      ev->clearAlarms();

      if ( mAlarm ) {
        // Set the alarm
        Alarm* vAlarm = ev->newAlarm();
        vAlarm->setText(summary);
        vAlarm->setTime(birthdate);
        // 24 hours before
        vAlarm->setStartOffset( -1440 * mAlarmDays );
        vAlarm->setEnabled(true);
      }

      // insert category
      ev->setCategories(i18n("Birthday"));

      ev->setReadOnly( true );
      mCalendar.addEvent(ev);
      kdDebug(5800) << "imported " << birthdate.toString() << endl;
    }

    QString anniversary_string = (*it).custom( "KADDRESSBOOK", "X-Anniversary" );
    if (anniversary_string.isEmpty() )
      continue;
    QDateTime anniversary = QDate::fromString( anniversary_string, Qt::ISODate );
    if ( !anniversary.isValid() )
      continue;

    QString name = (*it).custom( "KADDRESSBOOK", "X-SpousesName" );
    if ( name.isEmpty() )
      anniversaries.append( *it );
    else {
      bool found = false;
      for ( addrIt = anniversaries.begin(); addrIt != anniversaries.end(); ++addrIt ) {
        if ( name == (*addrIt).realName() ) {
          QDateTime spouseAnniversary = QDate::fromString( (*addrIt).custom( "KADDRESSBOOK", "X-Anniversary" ), Qt::ISODate );
          if ( anniversary == spouseAnniversary ) {
            found = true;
            break;

          }
        }
      }

      if ( !found )
        anniversaries.append( *it );
    }
  }

  for ( addrIt = anniversaries.begin(); addrIt != anniversaries.end(); ++addrIt ) {
    QDate anniversary = QDate::fromString( (*addrIt).custom( "KADDRESSBOOK", "X-Anniversary" ), Qt::ISODate );
    kdDebug(5800) << "found a anniversary " << anniversary.toString() << endl;
    QString name;
    QString name_1 = (*addrIt).nickName();
    QString uid_1 = (*addrIt).uid();
    QString email_1 = (*addrIt).fullEmail();
    if ( name_1.isEmpty() )
      name_1 = (*addrIt).realName();

    QString spouseName = (*addrIt).custom( "KADDRESSBOOK", "X-SpousesName" );
    QString name_2,email_2,uid_2;
    if ( !spouseName.isEmpty() ) {
      //TODO: find a KABC:Addressee of the spouse
      //      Probably easiest would be to use a QMap (as the spouse's entry was already searched above!
      KABC::Addressee spouse;
      spouse.setNameFromString( spouseName );
      uid_2 = spouse.uid();
      email_2 = spouse.fullEmail();
      name_2 = spouse.nickName();
      if ( name_2.isEmpty() )
        name_2 = spouse.givenName();
      summary = i18n("insert names of both spouses", "%1's & %2's anniversary").arg( name_1 ).arg( name_2 );
    } else {
      summary = i18n("only one spouse in addressbook, insert the name", "%1's anniversary").arg( name_1 );
    }

    Event *ev = new Event();
      ev->setUid( (*it).uid()+"_KABC_Anniversary");

    ev->setDtStart(anniversary);
    ev->setDtEnd(anniversary);
    ev->setHasEndDate(true);
    ev->setFloats(true);

    ev->setSummary(summary);

    ev->setCustomProperty( "KABC", "BIRTHDAY", "YES" );

    ev->setCustomProperty( "KABC", "UID-1", (*it).uid() );
    ev->setCustomProperty( "KABC", "NAME-1", name_1 );
    ev->setCustomProperty( "KABC", "EMAIL-1", email_1 );
    ev->setCustomProperty( "KABC", "ANNIVERSARY", "YES" );
    if ( !spouseName.isEmpty() ) {
      ev->setCustomProperty("KABC", "UID-2", uid_2 );
      ev->setCustomProperty("KABC", "NAME-2", spouseName );
      ev->setCustomProperty("KABC", "EMAIL-2", email_2 );
    }
    // Set the recurrence
    Recurrence *vRecurrence = ev->recurrence();
    vRecurrence->setStartDate( anniversary );
    vRecurrence->setYearly( 1 );
    if ( anniversary.month()==2 && anniversary.day()==29 ) {
      vRecurrence->addYearlyDay( 60 );
    }

    ev->clearAlarms();

    if ( mAlarm ) {
      // Set the alarm
      Alarm* vAlarm = ev->newAlarm();
      vAlarm->setText(summary);
      vAlarm->setTime(anniversary);
      // 24 hours before
      vAlarm->setStartOffset( -1440 * mAlarmDays );
      vAlarm->setEnabled(true);
    }

    // insert category
    ev->setCategories(i18n("Anniversary"));

    ev->setReadOnly( true );
    mCalendar.addEvent(ev);
    kdDebug(5800) << "imported " << anniversary.toString() << endl;
  }

  return true;
}

void ResourceKABC::setAlarm( bool a )
{
  mAlarm = a;
}

bool ResourceKABC::alarm()
{
  return mAlarm;
}

void ResourceKABC::setAlarmDays( int ad )
{
  mAlarmDays = ad;
}

int ResourceKABC::alarmDays()
{
  return mAlarmDays;
}

void ResourceKABC::setCategories( const QStringList &categories )
{
  mCategories = categories;
}

QStringList ResourceKABC::categories() const
{
  return mCategories;
}

void ResourceKABC::setUseCategories( bool useCategories )
{
  mUseCategories = useCategories;
}

bool ResourceKABC::useCategories() const
{
  return mUseCategories;
}

bool ResourceKABC::doSave()
{
  // is always read only!
  return true;
}

bool ResourceKABC::isSaving()
{
  return false;
}

KABC::Lock *ResourceKABC::lock()
{
  return mLock;
}

bool ResourceKABC::addEvent(Event*)
{
  return false;
}

bool ResourceKABC::deleteEvent(Event*)
{
  return false;
}

Event *ResourceKABC::event( const QString &uid )
{
  return mCalendar.event( uid );
}

Event::List ResourceKABC::rawEventsForDate( const QDate &date,
                                             EventSortField sortField,
                                             SortDirection sortDirection )
{
  return mCalendar.rawEventsForDate( date, sortField, sortDirection );
}

Event::List ResourceKABC::rawEvents( const QDate &start, const QDate &end,
                                          bool inclusive )
{
  return mCalendar.rawEvents( start, end, inclusive );
}

Event::List ResourceKABC::rawEventsForDate(const QDateTime &qdt)
{
  return mCalendar.rawEventsForDate( qdt.date() );
}

Event::List ResourceKABC::rawEvents( EventSortField sortField, SortDirection sortDirection )
{
  return mCalendar.rawEvents( sortField, sortDirection );
}

bool ResourceKABC::addTodo(Todo*)
{
  return false;
}

bool ResourceKABC::deleteTodo(Todo*)
{
  return false;
}

Todo::List ResourceKABC::rawTodos( TodoSortField sortField, SortDirection sortDirection )
{
  return mCalendar.rawTodos( sortField, sortDirection );
}

Todo *ResourceKABC::todo( const QString &uid )
{
  return mCalendar.todo( uid );
}

Todo::List ResourceKABC::rawTodosForDate( const QDate &date )
{
  return mCalendar.rawTodosForDate( date );
}

bool ResourceKABC::addJournal(Journal*)
{
  return false;
}

bool ResourceKABC::deleteJournal(Journal*)
{
  return false;
}

Journal *ResourceKABC::journal(const QString &uid)
{
  return mCalendar.journal( uid );
}

Journal::List ResourceKABC::rawJournals( JournalSortField sortField, SortDirection sortDirection )
{
  return mCalendar.rawJournals( sortField, sortDirection );
}

Journal::List ResourceKABC::rawJournalsForDate( const QDate &date )
{
  return mCalendar.rawJournalsForDate( date );
}

Alarm::List ResourceKABC::alarmsTo( const QDateTime &to )
{
  return mCalendar.alarmsTo( to );
}

Alarm::List ResourceKABC::alarms( const QDateTime &from, const QDateTime &to )
{
//  kdDebug(5800) << "ResourceKABC::alarms(" << from.toString() << " - " << to.toString() << ")\n";

  return mCalendar.alarms( from, to );
}

void ResourceKABC::dump() const
{
  ResourceCalendar::dump();
}

void ResourceKABC::reload()
{
  load();
}

void ResourceKABC::setTimeZoneId( const QString& tzid )
{
  mCalendar.setTimeZoneId( tzid );
}

bool ResourceKABC::setValue( const QString &key, const QString &value )
{
  if ( key == "AlarmDays" ) {
    bool ok;
    int days = value.toInt( &ok );
    if ( ok ) mAlarmDays = days;
    return ok;
  } else if ( key == "Alarm" ) {
    if ( value == "true" ) {
      mAlarm = true;
      return true;
    } else if ( value == "false" ) {
      mAlarm = false;
      return true;
    } else return false;
  } else
    return ResourceCalendar::setValue( key, value );
}

#include "resourcekabc.moc"
<commit_msg>By default, show a reminder on the birthday.<commit_after>/*
    This file is part of libkcal.

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

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

    This library 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
    Library General Public License for more details.

    You should have received a copy of the GNU Library General Public License
    along with this library; see the file COPYING.LIB.  If not, write to
    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
    Boston, MA 02110-1301, USA.
*/

#include <typeinfo>
#include <stdlib.h>

#include <qdatetime.h>
#include <qstring.h>
#include <qptrlist.h>

#include <klocale.h>
#include <kdebug.h>
#include <kurl.h>
#include <kio/job.h>
#include <kstandarddirs.h>

#include <kabc/stdaddressbook.h>
#include <kabc/locknull.h>

#include "libkcal/vcaldrag.h"
#include "libkcal/vcalformat.h"
#include "libkcal/icalformat.h"
#include "libkcal/exceptions.h"
#include "libkcal/incidence.h"
#include "libkcal/event.h"
#include "libkcal/todo.h"
#include "libkcal/journal.h"
#include "libkcal/filestorage.h"
#include "libkcal/alarm.h"

#include <kresources/configwidget.h>

#include "resourcekabcconfig.h"

#include "resourcekabc.h"

using namespace KCal;

extern "C"
{
  void *init_kcal_kabc()
  {
	  KGlobal::locale()->insertCatalogue( "kres_birthday" );
    KGlobal::locale()->insertCatalogue( "libkcal" );
    return new KRES::PluginFactory<ResourceKABC,ResourceKABCConfig>();
  }
}

ResourceKABC::ResourceKABC( const KConfig* config )
  : ResourceCalendar( config ), mCalendar( QString::fromLatin1( "UTC" ) ),
    mAlarmDays( 0 ), mAlarm( true ), mUseCategories( false )
{
  if ( config ) {
    readConfig( config );
  }

  init();
}

ResourceKABC::ResourceKABC()
  : ResourceCalendar( 0 ), mCalendar( QString::fromLatin1( "UTC" ) ),
    mAlarmDays( 0 ), mAlarm( true ), mUseCategories( false )
{
  init();
}

ResourceKABC::~ResourceKABC()
{
  delete mLock;
}

void ResourceKABC::init()
{
  setType( "birthdays" );

  setReadOnly( true );

  mLock = new KABC::LockNull( false );

  mAddressbook = 0;
}

void ResourceKABC::readConfig( const KConfig *config )
{
  mAlarmDays = config->readNumEntry( "AlarmDays", 0 );
  mAlarm = config->readBoolEntry( "Alarm", true );
  mCategories = config->readListEntry( "Categories" );
  mUseCategories = config->readBoolEntry( "UseCategories", false );
}

void ResourceKABC::writeConfig( KConfig *config )
{
  ResourceCalendar::writeConfig( config );
  config->writeEntry( "AlarmDays", mAlarmDays );
  config->writeEntry( "Alarm", mAlarm );
  config->writeEntry( "Categories", mCategories );
  config->writeEntry( "UseCategories", mUseCategories );
}

bool ResourceKABC::doOpen()
{
  kdDebug(5800) << "ResourceKABC::doOpen()" << endl;

  mAddressbook = KABC::StdAddressBook::self( true );
  connect( mAddressbook, SIGNAL(addressBookChanged(AddressBook*)), SLOT( reload() ) );

  return true;
}

bool ResourceKABC::doLoad()
{
  kdDebug(5800) << "ResourceKABC::load()" << endl;

  mCalendar.close();

  // import from kabc
  QString summary;
  QStringList::ConstIterator strIt;
  const QStringList::ConstIterator endStrIt = mCategories.end();
  KABC::Addressee::List anniversaries;
  KABC::Addressee::List::Iterator addrIt;

  KABC::AddressBook::Iterator it;
  const KABC::AddressBook::Iterator endIt = mAddressbook->end();
  for ( it = mAddressbook->begin(); it != endIt; ++it ) {

    if ( mUseCategories ) {
      bool hasCategory = false;
      QStringList categories = (*it).categories();
      for ( strIt = mCategories.begin(); strIt != endStrIt; ++strIt )
        if ( categories.contains( *strIt ) ) {
          hasCategory = true;
          break;
        }

      if ( !hasCategory )
        continue;
    }

    QDate birthdate = (*it).birthday().date();
    QString name_1, email_1, uid_1;
    if ( birthdate.isValid() ) {
      kdDebug(5800) << "found a birthday " << birthdate.toString() << endl;

      name_1 = (*it).nickName();
      email_1 = (*it).fullEmail();
      uid_1 = (*it).uid();
      if (name_1.isEmpty()) name_1 = (*it).realName();
      summary = i18n("%1's birthday").arg( name_1 );

      Event *ev = new Event();
      ev->setUid( uid_1+"_KABC_Birthday");

      ev->setDtStart(birthdate);
      ev->setDtEnd(birthdate);
      ev->setHasEndDate(true);
      ev->setFloats(true);
      ev->setTransparency( Event::Transparent );

      ev->setCustomProperty("KABC", "BIRTHDAY", "YES");
      ev->setCustomProperty("KABC", "UID-1", uid_1 );
      ev->setCustomProperty("KABC", "NAME-1", name_1 );
      ev->setCustomProperty("KABC", "EMAIL-1", email_1 );
      kdDebug(5800) << "ResourceKABC::doLoad: uid:" << uid_1 << " name: " << name_1
        << " email: " << email_1 << endl;
      ev->setSummary(summary);

      // Set the recurrence
      Recurrence *vRecurrence = ev->recurrence();
      vRecurrence->setStartDate( birthdate );
      vRecurrence->setYearly( 1 );
      if ( birthdate.month()==2 && birthdate.day()==29 ) {
        vRecurrence->addYearlyDay( 60 );
      }

      ev->clearAlarms();

      if ( mAlarm ) {
        // Set the alarm
        Alarm* vAlarm = ev->newAlarm();
        vAlarm->setText(summary);
        vAlarm->setTime(birthdate);
        // 24 hours before
        vAlarm->setStartOffset( -1440 * mAlarmDays );
        vAlarm->setEnabled(true);
      }

      // insert category
      ev->setCategories(i18n("Birthday"));

      ev->setReadOnly( true );
      mCalendar.addEvent(ev);
      kdDebug(5800) << "imported " << birthdate.toString() << endl;
    }

    QString anniversary_string = (*it).custom( "KADDRESSBOOK", "X-Anniversary" );
    if (anniversary_string.isEmpty() )
      continue;
    QDateTime anniversary = QDate::fromString( anniversary_string, Qt::ISODate );
    if ( !anniversary.isValid() )
      continue;

    QString name = (*it).custom( "KADDRESSBOOK", "X-SpousesName" );
    if ( name.isEmpty() )
      anniversaries.append( *it );
    else {
      bool found = false;
      for ( addrIt = anniversaries.begin(); addrIt != anniversaries.end(); ++addrIt ) {
        if ( name == (*addrIt).realName() ) {
          QDateTime spouseAnniversary = QDate::fromString( (*addrIt).custom( "KADDRESSBOOK", "X-Anniversary" ), Qt::ISODate );
          if ( anniversary == spouseAnniversary ) {
            found = true;
            break;

          }
        }
      }

      if ( !found )
        anniversaries.append( *it );
    }
  }

  for ( addrIt = anniversaries.begin(); addrIt != anniversaries.end(); ++addrIt ) {
    QDate anniversary = QDate::fromString( (*addrIt).custom( "KADDRESSBOOK", "X-Anniversary" ), Qt::ISODate );
    kdDebug(5800) << "found a anniversary " << anniversary.toString() << endl;
    QString name;
    QString name_1 = (*addrIt).nickName();
    QString uid_1 = (*addrIt).uid();
    QString email_1 = (*addrIt).fullEmail();
    if ( name_1.isEmpty() )
      name_1 = (*addrIt).realName();

    QString spouseName = (*addrIt).custom( "KADDRESSBOOK", "X-SpousesName" );
    QString name_2,email_2,uid_2;
    if ( !spouseName.isEmpty() ) {
      //TODO: find a KABC:Addressee of the spouse
      //      Probably easiest would be to use a QMap (as the spouse's entry was already searched above!
      KABC::Addressee spouse;
      spouse.setNameFromString( spouseName );
      uid_2 = spouse.uid();
      email_2 = spouse.fullEmail();
      name_2 = spouse.nickName();
      if ( name_2.isEmpty() )
        name_2 = spouse.givenName();
      summary = i18n("insert names of both spouses", "%1's & %2's anniversary").arg( name_1 ).arg( name_2 );
    } else {
      summary = i18n("only one spouse in addressbook, insert the name", "%1's anniversary").arg( name_1 );
    }

    Event *ev = new Event();
      ev->setUid( (*it).uid()+"_KABC_Anniversary");

    ev->setDtStart(anniversary);
    ev->setDtEnd(anniversary);
    ev->setHasEndDate(true);
    ev->setFloats(true);

    ev->setSummary(summary);

    ev->setCustomProperty( "KABC", "BIRTHDAY", "YES" );

    ev->setCustomProperty( "KABC", "UID-1", (*it).uid() );
    ev->setCustomProperty( "KABC", "NAME-1", name_1 );
    ev->setCustomProperty( "KABC", "EMAIL-1", email_1 );
    ev->setCustomProperty( "KABC", "ANNIVERSARY", "YES" );
    if ( !spouseName.isEmpty() ) {
      ev->setCustomProperty("KABC", "UID-2", uid_2 );
      ev->setCustomProperty("KABC", "NAME-2", spouseName );
      ev->setCustomProperty("KABC", "EMAIL-2", email_2 );
    }
    // Set the recurrence
    Recurrence *vRecurrence = ev->recurrence();
    vRecurrence->setStartDate( anniversary );
    vRecurrence->setYearly( 1 );
    if ( anniversary.month()==2 && anniversary.day()==29 ) {
      vRecurrence->addYearlyDay( 60 );
    }

    ev->clearAlarms();

    if ( mAlarm ) {
      // Set the alarm
      Alarm* vAlarm = ev->newAlarm();
      vAlarm->setText(summary);
      vAlarm->setTime(anniversary);
      // 24 hours before
      vAlarm->setStartOffset( -1440 * mAlarmDays );
      vAlarm->setEnabled(true);
    }

    // insert category
    ev->setCategories(i18n("Anniversary"));

    ev->setReadOnly( true );
    mCalendar.addEvent(ev);
    kdDebug(5800) << "imported " << anniversary.toString() << endl;
  }

  return true;
}

void ResourceKABC::setAlarm( bool a )
{
  mAlarm = a;
}

bool ResourceKABC::alarm()
{
  return mAlarm;
}

void ResourceKABC::setAlarmDays( int ad )
{
  mAlarmDays = ad;
}

int ResourceKABC::alarmDays()
{
  return mAlarmDays;
}

void ResourceKABC::setCategories( const QStringList &categories )
{
  mCategories = categories;
}

QStringList ResourceKABC::categories() const
{
  return mCategories;
}

void ResourceKABC::setUseCategories( bool useCategories )
{
  mUseCategories = useCategories;
}

bool ResourceKABC::useCategories() const
{
  return mUseCategories;
}

bool ResourceKABC::doSave()
{
  // is always read only!
  return true;
}

bool ResourceKABC::isSaving()
{
  return false;
}

KABC::Lock *ResourceKABC::lock()
{
  return mLock;
}

bool ResourceKABC::addEvent(Event*)
{
  return false;
}

bool ResourceKABC::deleteEvent(Event*)
{
  return false;
}

Event *ResourceKABC::event( const QString &uid )
{
  return mCalendar.event( uid );
}

Event::List ResourceKABC::rawEventsForDate( const QDate &date,
                                             EventSortField sortField,
                                             SortDirection sortDirection )
{
  return mCalendar.rawEventsForDate( date, sortField, sortDirection );
}

Event::List ResourceKABC::rawEvents( const QDate &start, const QDate &end,
                                          bool inclusive )
{
  return mCalendar.rawEvents( start, end, inclusive );
}

Event::List ResourceKABC::rawEventsForDate(const QDateTime &qdt)
{
  return mCalendar.rawEventsForDate( qdt.date() );
}

Event::List ResourceKABC::rawEvents( EventSortField sortField, SortDirection sortDirection )
{
  return mCalendar.rawEvents( sortField, sortDirection );
}

bool ResourceKABC::addTodo(Todo*)
{
  return false;
}

bool ResourceKABC::deleteTodo(Todo*)
{
  return false;
}

Todo::List ResourceKABC::rawTodos( TodoSortField sortField, SortDirection sortDirection )
{
  return mCalendar.rawTodos( sortField, sortDirection );
}

Todo *ResourceKABC::todo( const QString &uid )
{
  return mCalendar.todo( uid );
}

Todo::List ResourceKABC::rawTodosForDate( const QDate &date )
{
  return mCalendar.rawTodosForDate( date );
}

bool ResourceKABC::addJournal(Journal*)
{
  return false;
}

bool ResourceKABC::deleteJournal(Journal*)
{
  return false;
}

Journal *ResourceKABC::journal(const QString &uid)
{
  return mCalendar.journal( uid );
}

Journal::List ResourceKABC::rawJournals( JournalSortField sortField, SortDirection sortDirection )
{
  return mCalendar.rawJournals( sortField, sortDirection );
}

Journal::List ResourceKABC::rawJournalsForDate( const QDate &date )
{
  return mCalendar.rawJournalsForDate( date );
}

Alarm::List ResourceKABC::alarmsTo( const QDateTime &to )
{
  return mCalendar.alarmsTo( to );
}

Alarm::List ResourceKABC::alarms( const QDateTime &from, const QDateTime &to )
{
//  kdDebug(5800) << "ResourceKABC::alarms(" << from.toString() << " - " << to.toString() << ")\n";

  return mCalendar.alarms( from, to );
}

void ResourceKABC::dump() const
{
  ResourceCalendar::dump();
}

void ResourceKABC::reload()
{
  load();
}

void ResourceKABC::setTimeZoneId( const QString& tzid )
{
  mCalendar.setTimeZoneId( tzid );
}

bool ResourceKABC::setValue( const QString &key, const QString &value )
{
  if ( key == "AlarmDays" ) {
    bool ok;
    int days = value.toInt( &ok );
    if ( ok ) mAlarmDays = days;
    return ok;
  } else if ( key == "Alarm" ) {
    if ( value == "true" ) {
      mAlarm = true;
      return true;
    } else if ( value == "false" ) {
      mAlarm = false;
      return true;
    } else return false;
  } else
    return ResourceCalendar::setValue( key, value );
}

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


<commit_before>/*
 * ZmQML - QML binding for zeromq.
 *
 * Copyright (C) 2014 Riccardo Ferrazzo
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 */

#include "zmqsocket.h"
#include "zmqcontext.h"

#include <QDebug>
#include <QSocketNotifier>
#include <QUuid>

inline void zmqError(const QString &message) {
    qWarning() << message << zmq_strerror(zmq_errno());
}

ZMQSocket::ZMQSocket(QObject *parent) :
    QObject(parent),
    _type(Null),
    _identity(QUuid::createUuid().toByteArray()),
    _method(Unset),
    socket(0)
{}

ZMQSocket::~ZMQSocket()
{
    if (socket)
        zmq_close(socket);
}

bool ZMQSocket::ready() const
{
    return bool(socket);
}

ZMQSocket::SocketType ZMQSocket::type() const
{
    return _type;
}

QByteArray ZMQSocket::identity() const
{
    return _identity;
}

ZMQSocket::ConnectionMethod ZMQSocket::method() const
{
    return _method;
}

QVariantList ZMQSocket::addresses() const
{
    return _addr;
}

QByteArray ZMQSocket::subscription() const
{
    return _subscription;
}

void ZMQSocket::setType(const ZMQSocket::SocketType type)
{
    if (_type != Null)
        return;

    _type = type;
    emit typeChanged();

    setup();
}

void ZMQSocket::setIdentity(const QByteArray &id)
{
    if (_identity == id)
        return;

    if (socket) {
        zmq_setsockopt(socket, ZMQ_IDENTITY, (void *) id.data(), id.size());
    }

    _identity = id;
    emit identityChanged();
}

void ZMQSocket::setMethod(const ZMQSocket::ConnectionMethod method)
{
    if (_method != Unset)
        return;

    _method = method;
    emit methodChanged();

    setup();
}

void ZMQSocket::setAddresses(const QVariantList &addresses)
{
    if (_addr.length() > 0 && socket) {
        int (*dfun)(void *, const char*) = _method == Connect ? zmq_disconnect : zmq_unbind;

        foreach (const QVariant &a, _addr) {
            int rc = dfun(socket, qPrintable(a.toUrl().toString()));

            if (rc < 0)
                zmqError("Disconnection error:");
        }

        int (*cfun)(void *, const char*) = _method == Connect ? zmq_connect : zmq_bind;
        int result;

        foreach(const QVariant &addr, addresses) {
            result = cfun(socket, qPrintable(addr.toUrl().toString()));

            if (result == -1)
                zmqError("Connection error:");
        }

    }

    _addr = addresses;
    emit addressesChanged();

    if (!socket)
        setup();
}

void ZMQSocket::setSubscription(const QByteArray &sub)
{
    if (_subscription == sub)
        return;

    if (socket && _type == Sub) {
        zmq_setsockopt(socket, ZMQ_UNSUBSCRIBE, (void *) _subscription.data(), _subscription.size());
        zmq_setsockopt(socket, ZMQ_SUBSCRIBE, (void *) sub.data(), sub.size());
    }

    _subscription = sub;
    emit subscriptionChanged();
}

bool ZMQSocket::setSockOption(ZMQSocket::SockOption option, int value)
{
    if (!socket) {
        qWarning() << "Error, socket not ready";
        return false;
    }

    const int rc = zmq_setsockopt(socket, int(option), (void*) &value, size_t(sizeof(int)));

    return rc >= 0;
}

void ZMQSocket::sendMessage(const QByteArray &message)
{
    const int res = zmq_send(socket, message.data(), message.size(), 0);

    if (res == -1) {
        zmqError("Error sending message:");
        return;
    }
}

void ZMQSocket::sendMessage(const QList<QByteArray> &message)
{
    QList<QByteArray>::const_iterator i;
    for (i = message.constBegin(); i != message.constEnd(); ++i) {
        int flags = (i+1) == message.constEnd() ? 0 : ZMQ_SNDMORE;

        const int res = zmq_send(socket, (*i).constData(), (*i).size(), flags);

        if (res == -1) {
            zmqError("Error sending message:");
            return;
        }
    }
}

void ZMQSocket::setup()
{
    if (_type == Null || _method == Unset || _addr.length() == 0)
        return;

    socket = zmq_socket(ZMQContext::instance()->context, int(_type));

    if (!socket) {
        zmqError("Socket creation error:");
        return;
    }

    emit readyChanged();

    zmq_setsockopt(socket, ZMQ_IDENTITY, (void *) _identity.data(), _identity.size());

    qint32 fd;
    size_t size = sizeof(fd);
    zmq_getsockopt(socket, ZMQ_FD, &fd, &size);

    notifier = new QSocketNotifier(fd, QSocketNotifier::Read, this);

    connect(notifier, &QSocketNotifier::activated,
        [=]() {
            notifier->setEnabled(false);

            qint8 more = 1;
            QList<QByteArray> message;

            while(more == 1){
                int event;
                size_t ev_size = sizeof(event);
                zmq_getsockopt(socket, ZMQ_EVENTS, (void *) &event, &ev_size);

                if (!(event & ZMQ_POLLIN))
                    break;

                zmq_msg_t part;
                int rc = zmq_msg_init(&part);
                if (rc < 0) {
                    zmqError("Error initializing message:");
                    break;
                }

                const int res = zmq_msg_recv(&part, socket, ZMQ_NOBLOCK);

                if (res < 0)
                    continue;

                message << QByteArray((char *) zmq_msg_data(&part), zmq_msg_size(&part));

                zmq_msg_close(&part);

                size_t size = sizeof(quint8);
                zmq_getsockopt(socket, ZMQ_RCVMORE, (void *)&more, &size);
            }

            if (message.length() > 0)
                emit messageReceived(message);

            notifier->setEnabled(true);
        }
    );

    int (*fun)(void *, const char*) = _method == Connect ? zmq_connect : zmq_bind;
    int result;

    foreach(const QVariant &addr, _addr) {
        result = fun(socket, qPrintable(addr.toUrl().toString()));

        if (result == -1)
            zmqError("Connection error:");
    }

    if (_type == Sub) {
        zmq_setsockopt(socket, ZMQ_SUBSCRIBE, (void *) _subscription.data(), _subscription.size());
    }
}
<commit_msg>Print an error when fails to set identity<commit_after>/*
 * ZmQML - QML binding for zeromq.
 *
 * Copyright (C) 2014 Riccardo Ferrazzo
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 */

#include "zmqsocket.h"
#include "zmqcontext.h"

#include <QDebug>
#include <QSocketNotifier>
#include <QUuid>

inline void zmqError(const QString &message) {
    qWarning() << message << zmq_strerror(zmq_errno());
}

ZMQSocket::ZMQSocket(QObject *parent) :
    QObject(parent),
    _type(Null),
    _identity(QUuid::createUuid().toByteArray()),
    _method(Unset),
    socket(0)
{}

ZMQSocket::~ZMQSocket()
{
    if (socket)
        zmq_close(socket);
}

bool ZMQSocket::ready() const
{
    return bool(socket);
}

ZMQSocket::SocketType ZMQSocket::type() const
{
    return _type;
}

QByteArray ZMQSocket::identity() const
{
    return _identity;
}

ZMQSocket::ConnectionMethod ZMQSocket::method() const
{
    return _method;
}

QVariantList ZMQSocket::addresses() const
{
    return _addr;
}

QByteArray ZMQSocket::subscription() const
{
    return _subscription;
}

void ZMQSocket::setType(const ZMQSocket::SocketType type)
{
    if (_type != Null)
        return;

    _type = type;
    emit typeChanged();

    setup();
}

void ZMQSocket::setIdentity(const QByteArray &id)
{
    if (_identity == id)
        return;

    if (socket) {
        int rc = zmq_setsockopt(socket, ZMQ_IDENTITY, (void *) id.data(), id.size());
        if (rc < 0 )
            zmqError("Identity error:");
    }

    _identity = id;
    emit identityChanged();
}

void ZMQSocket::setMethod(const ZMQSocket::ConnectionMethod method)
{
    if (_method != Unset)
        return;

    _method = method;
    emit methodChanged();

    setup();
}

void ZMQSocket::setAddresses(const QVariantList &addresses)
{
    if (_addr.length() > 0 && socket) {
        int (*dfun)(void *, const char*) = _method == Connect ? zmq_disconnect : zmq_unbind;

        foreach (const QVariant &a, _addr) {
            int rc = dfun(socket, qPrintable(a.toUrl().toString()));

            if (rc < 0)
                zmqError("Disconnection error:");
        }

        int (*cfun)(void *, const char*) = _method == Connect ? zmq_connect : zmq_bind;
        int result;

        foreach(const QVariant &addr, addresses) {
            result = cfun(socket, qPrintable(addr.toUrl().toString()));

            if (result == -1)
                zmqError("Connection error:");
        }

    }

    _addr = addresses;
    emit addressesChanged();

    if (!socket)
        setup();
}

void ZMQSocket::setSubscription(const QByteArray &sub)
{
    if (_subscription == sub)
        return;

    if (socket && _type == Sub) {
        zmq_setsockopt(socket, ZMQ_UNSUBSCRIBE, (void *) _subscription.data(), _subscription.size());
        zmq_setsockopt(socket, ZMQ_SUBSCRIBE, (void *) sub.data(), sub.size());
    }

    _subscription = sub;
    emit subscriptionChanged();
}

bool ZMQSocket::setSockOption(ZMQSocket::SockOption option, int value)
{
    if (!socket) {
        qWarning() << "Error, socket not ready";
        return false;
    }

    const int rc = zmq_setsockopt(socket, int(option), (void*) &value, size_t(sizeof(int)));

    return rc >= 0;
}

void ZMQSocket::sendMessage(const QByteArray &message)
{
    const int res = zmq_send(socket, message.data(), message.size(), 0);

    if (res == -1) {
        zmqError("Error sending message:");
        return;
    }
}

void ZMQSocket::sendMessage(const QList<QByteArray> &message)
{
    QList<QByteArray>::const_iterator i;
    for (i = message.constBegin(); i != message.constEnd(); ++i) {
        int flags = (i+1) == message.constEnd() ? 0 : ZMQ_SNDMORE;

        const int res = zmq_send(socket, (*i).constData(), (*i).size(), flags);

        if (res == -1) {
            zmqError("Error sending message:");
            return;
        }
    }
}

void ZMQSocket::setup()
{
    if (_type == Null || _method == Unset || _addr.length() == 0)
        return;

    socket = zmq_socket(ZMQContext::instance()->context, int(_type));

    if (!socket) {
        zmqError("Socket creation error:");
        return;
    }

    emit readyChanged();

    zmq_setsockopt(socket, ZMQ_IDENTITY, (void *) _identity.data(), _identity.size());

    qint32 fd;
    size_t size = sizeof(fd);
    zmq_getsockopt(socket, ZMQ_FD, &fd, &size);

    notifier = new QSocketNotifier(fd, QSocketNotifier::Read, this);

    connect(notifier, &QSocketNotifier::activated,
        [=]() {
            notifier->setEnabled(false);

            qint8 more = 1;
            QList<QByteArray> message;

            while(more == 1){
                int event;
                size_t ev_size = sizeof(event);
                zmq_getsockopt(socket, ZMQ_EVENTS, (void *) &event, &ev_size);

                if (!(event & ZMQ_POLLIN))
                    break;

                zmq_msg_t part;
                int rc = zmq_msg_init(&part);
                if (rc < 0) {
                    zmqError("Error initializing message:");
                    break;
                }

                const int res = zmq_msg_recv(&part, socket, ZMQ_NOBLOCK);

                if (res < 0)
                    continue;

                message << QByteArray((char *) zmq_msg_data(&part), zmq_msg_size(&part));

                zmq_msg_close(&part);

                size_t size = sizeof(quint8);
                zmq_getsockopt(socket, ZMQ_RCVMORE, (void *)&more, &size);
            }

            if (message.length() > 0)
                emit messageReceived(message);

            notifier->setEnabled(true);
        }
    );

    int (*fun)(void *, const char*) = _method == Connect ? zmq_connect : zmq_bind;
    int result;

    foreach(const QVariant &addr, _addr) {
        result = fun(socket, qPrintable(addr.toUrl().toString()));

        if (result == -1)
            zmqError("Connection error:");
    }

    if (_type == Sub) {
        zmq_setsockopt(socket, ZMQ_SUBSCRIBE, (void *) _subscription.data(), _subscription.size());
    }
}
<|endoftext|>