<commit_before>/*
  +----------------------------------------------------------------------+
  | Swoole                                                               |
  +----------------------------------------------------------------------+
  | This source file is subject to version 2.0 of the Apache license,    |
  | that is bundled with this package in the file LICENSE, and is        |
  | available through the world-wide-web at the following url:           |
  | http://www.apache.org/licenses/LICENSE-2.0.html                      |
  | If you did not receive a copy of the Apache2.0 license and are unable|
  | to obtain it through the world-wide-web, please send a note to       |
  | license@swoole.com so we can mail you a copy immediately.            |
  +----------------------------------------------------------------------+
  | Author: Tianfeng Han  <mikan.tenny@gmail.com>                        |
  +----------------------------------------------------------------------+
*/

#include "php_swoole_cxx.h"
#include "swoole_http.h"
#include "websocket.h"

#include "main/rfc1867.h"

#ifdef SW_USE_HTTP2
#include "http2.h"
#endif

using namespace swoole;
using swoole::coroutine::Socket;

swString *swoole_http_buffer;
#ifdef SW_HAVE_COMPRESSION
/* not only be used by zlib but also be used by br */
swString *swoole_zlib_buffer;
#endif
swString *swoole_http_form_data_buffer;

zend_class_entry *swoole_http_server_ce;
zend_object_handlers swoole_http_server_handlers;

static bool http_context_send_data(http_context* ctx, const char *data, size_t length);
static bool http_context_send_file(http_context* ctx, const char *file, uint32_t l_file, off_t offset, size_t length);
static bool http_context_disconnect(http_context* ctx);

int php_swoole_http_onReceive(swServer *serv, swEventData *req)
{
    int fd = req->info.fd;
    int from_fd = req->info.server_fd;

    swConnection *conn = swServer_connection_verify_no_ssl(serv, fd);
    if (!conn)
    {
        swoole_error_log(SW_LOG_NOTICE, SW_ERROR_SESSION_NOT_EXIST, "connection[%d] is closed", fd);
        return SW_ERR;
    }

    swListenPort *port = (swListenPort *) serv->connection_list[from_fd].object;
    //other server port
    if (!port->open_http_protocol)
    {
        return php_swoole_onReceive(serv, req);
    }
    //websocket client
    if (conn->websocket_status == WEBSOCKET_STATUS_ACTIVE)
    {
        return swoole_websocket_onMessage(serv, req);
    }
#ifdef SW_USE_HTTP2
    if (conn->http2_stream)
    {
        return swoole_http2_server_onFrame(serv, conn, req);
    }
#endif

    http_context *ctx = swoole_http_context_new(fd);
    swoole_http_server_init_context(serv, ctx);

    zval *zdata = &ctx->request.zdata;
    php_swoole_get_recv_data(serv, zdata, req, NULL, 0);

    swTraceLog(SW_TRACE_SERVER, "http request from %d with %d bytes: <<EOF\n%.*s\nEOF", fd, (int) Z_STRLEN_P(zdata), (int) Z_STRLEN_P(zdata), Z_STRVAL_P(zdata));

    zval args[2], *zrequest_object = &args[0], *zresponse_object = &args[1];
    args[0] = *ctx->request.zobject;
    args[1] = *ctx->response.zobject;

    swoole_http_parser *parser = &ctx->parser;
    parser->data = ctx;
    swoole_http_parser_init(parser, PHP_HTTP_REQUEST);

    size_t parsed_n = swoole_http_requset_parse(ctx, Z_STRVAL_P(zdata), Z_STRLEN_P(zdata));
    if (parsed_n < Z_STRLEN_P(zdata))
    {
#ifdef SW_HTTP_BAD_REQUEST_PACKET
        ctx->send(ctx, SW_STRL(SW_HTTP_BAD_REQUEST_PACKET));
#endif
        ctx->close(ctx);
        swNotice("request is illegal and it has been discarded, %ld bytes unprocessed", Z_STRLEN_P(zdata) - parsed_n);
        goto _dtor_and_return;
    }

    do {
        zval *zserver = ctx->request.zserver;
        swConnection *serv_sock = swServer_connection_get(serv, conn->server_fd);
        if (serv_sock)
        {
            add_assoc_long(zserver, "server_port", swConnection_get_port(serv_sock->socket_type, &serv_sock->info));
        }
        add_assoc_long(zserver, "remote_port", swConnection_get_port(conn->socket_type, &conn->info));
        add_assoc_string(zserver, "remote_addr", (char *) swConnection_get_ip(conn->socket_type, &conn->info));
        add_assoc_long(zserver, "master_time", conn->last_time);
    } while (0);

    // begin to check and call registerd callback
    do {
        zend_fcall_info_cache *fci_cache = NULL;

        if (conn->websocket_status == WEBSOCKET_STATUS_CONNECTION)
        {
            fci_cache = php_swoole_server_get_fci_cache(serv, from_fd, SW_SERVER_CB_onHandShake);
            if (fci_cache == NULL)
            {
                swoole_websocket_onHandshake(serv, port, ctx);
                goto _dtor_and_return;
            }
            else
            {
                conn->websocket_status = WEBSOCKET_STATUS_HANDSHAKE;
                ctx->upgrade = 1;
            }
        }
        else
        {
            fci_cache = php_swoole_server_get_fci_cache(serv, from_fd, SW_SERVER_CB_onRequest);
            if (fci_cache == NULL)
            {
                swoole_websocket_onRequest(ctx);
                goto _dtor_and_return;
            }
        }

        if (UNEXPECTED(!zend::function::call(fci_cache, 2, args, NULL, SwooleG.enable_coroutine)))
        {
            php_swoole_error(E_WARNING, "%s->onRequest handler error", ZSTR_VAL(swoole_http_server_ce->name));
    #ifdef SW_HTTP_SERVICE_UNAVAILABLE_PACKET
            ctx->send(ctx, SW_STRL(SW_HTTP_SERVICE_UNAVAILABLE_PACKET));
    #endif
            ctx->close(ctx);
        }
    } while (0);

    _dtor_and_return:
    zval_ptr_dtor(zrequest_object);
    zval_ptr_dtor(zresponse_object);

    return SW_OK;
}

void php_swoole_http_onClose(swServer *serv, swDataHead *ev)
{
    int fd = ev->fd;
    swConnection *conn = swWorker_get_connection(serv, fd);
    if (!conn)
    {
        return;
    }
#ifdef SW_USE_HTTP2
    if (conn->http2_stream)
    {
        swoole_http2_server_session_free(conn);
    }
#endif
    php_swoole_onClose(serv, ev);
}

void php_swoole_http_server_minit(int module_number)
{
    SW_INIT_CLASS_ENTRY_EX(swoole_http_server, "Swoole\\Http\\Server", "swoole_http_server", NULL, NULL, swoole_server);
    SW_SET_CLASS_SERIALIZABLE(swoole_http_server, zend_class_serialize_deny, zend_class_unserialize_deny);
    SW_SET_CLASS_CLONEABLE(swoole_http_server, sw_zend_class_clone_deny);
    SW_SET_CLASS_UNSET_PROPERTY_HANDLER(swoole_http_server, sw_zend_class_unset_property_deny);

    zend_declare_property_null(swoole_http_server_ce, ZEND_STRL("onRequest"), ZEND_ACC_PRIVATE);

    swoole_http_buffer = swString_new(SW_HTTP_RESPONSE_INIT_SIZE);
    if (!swoole_http_buffer)
    {
        php_swoole_fatal_error(E_ERROR, "[swoole_http_buffer] swString_new(%d) failed", SW_HTTP_RESPONSE_INIT_SIZE);
        return;
    }
}

http_context* swoole_http_context_new(int fd)
{
    http_context *ctx = (http_context *) ecalloc(1, sizeof(http_context));
    if (UNEXPECTED(!ctx))
    {
        swoole_error_log(SW_LOG_ERROR, SW_ERROR_MALLOC_FAIL, "ecalloc(%ld) failed", sizeof(http_context));
        return NULL;
    }

    zval *zrequest_object = &ctx->request._zobject;
    ctx->request.zobject = zrequest_object;
    object_init_ex(zrequest_object, swoole_http_request_ce);
    php_swoole_http_request_set_context(zrequest_object, ctx);

    zval *zresponse_object = &ctx->response._zobject;
    ctx->response.zobject = zresponse_object;
    object_init_ex(zresponse_object, swoole_http_response_ce);
    php_swoole_http_response_set_context(zresponse_object, ctx);

    zend_update_property_long(swoole_http_request_ce, zrequest_object, ZEND_STRL("fd"), fd);
    zend_update_property_long(swoole_http_response_ce, zresponse_object, ZEND_STRL("fd"), fd);

#if PHP_MEMORY_DEBUG
    php_vmstat.new_http_request ++;
#endif

    swoole_http_init_and_read_property(swoole_http_request_ce, zrequest_object, &ctx->request.zserver, ZEND_STRL("server"));
    swoole_http_init_and_read_property(swoole_http_request_ce, zrequest_object, &ctx->request.zheader, ZEND_STRL("header"));
    ctx->fd = fd;

    return ctx;
}

void swoole_http_server_init_context(swServer *serv, http_context *ctx)
{
    ctx->parse_cookie = serv->http_parse_cookie;
    ctx->parse_body = serv->http_parse_post;
    ctx->parse_files = serv->http_parse_files;
#ifdef SW_HAVE_COMPRESSION
    ctx->enable_compression = serv->http_compression;
#endif
    ctx->private_data = serv;
    ctx->upload_tmp_dir = serv->upload_tmp_dir;
    ctx->send = http_context_send_data;
    ctx->sendfile = http_context_send_file;
    ctx->close = http_context_disconnect;
}

void swoole_http_context_copy(http_context *src, http_context *dst)
{
    dst->parse_cookie = src->parse_cookie;
    dst->parse_body = src->parse_body;
    dst->parse_files = src->parse_files;
#ifdef SW_HAVE_COMPRESSION
    dst->enable_compression = src->enable_compression;
#endif
    dst->private_data = src->private_data;
    dst->upload_tmp_dir = src->upload_tmp_dir;
    dst->send = src->send;
    dst->sendfile = src->sendfile;
    dst->close = src->close;
}

void swoole_http_context_free(http_context *ctx)
{
    if (ctx->request.zobject)
    {
        php_swoole_http_request_set_context(ctx->request.zobject, NULL);
    }
    php_swoole_http_response_set_context(ctx->response.zobject, NULL);
    http_request *req = &ctx->request;
    http_response *res = &ctx->response;
    if (req->path)
    {
        efree(req->path);
    }
    if (Z_TYPE(req->zdata) == IS_STRING)
    {
        zend_string_release(Z_STR(req->zdata));
    }
#ifdef SW_USE_HTTP2
    if (req->h2_data_buffer)
    {
        swString_free(req->h2_data_buffer);
    }
#endif
    if (res->reason)
    {
        efree(res->reason);
    }
    efree(ctx);
}

void php_swoole_http_server_init_global_variant()
{
    swoole_http_form_data_buffer = swString_new(SW_HTTP_RESPONSE_INIT_SIZE);
    if (!swoole_http_form_data_buffer)
    {
        php_swoole_fatal_error(E_ERROR, "[swoole_http_form_data_buffer] swString_new(%d) failed", SW_HTTP_RESPONSE_INIT_SIZE);
        return;
    }

    //for is_uploaded_file and move_uploaded_file
    if (!SG(rfc1867_uploaded_files))
    {
        ALLOC_HASHTABLE(SG(rfc1867_uploaded_files));
        zend_hash_init(SG(rfc1867_uploaded_files), 8, NULL, NULL, 0);
    }
}

http_context* php_swoole_http_request_get_and_check_context(zval *zobject)
{
    http_context *ctx = php_swoole_http_request_get_context(zobject);
    if (!ctx)
    {
        php_swoole_fatal_error(E_WARNING, "http request is unavailable (maybe it has been ended)");
    }
    return ctx;
}

http_context* php_swoole_http_response_get_and_check_context(zval *zobject, bool check_end)
{
    http_context *ctx = php_swoole_http_response_get_context(zobject);
    if (!ctx || (check_end && ctx->end))
    {
        php_swoole_fatal_error(E_WARNING, "http response is unavailable (maybe it has been ended or detached)");
        return NULL;
    }
    return ctx;
}

bool http_context_send_data(http_context* ctx, const char *data, size_t length)
{
    swServer *serv = (swServer *) ctx->private_data;
    zval *return_value = (zval *) ctx->private_data_2;
    ssize_t ret = serv->send(serv, ctx->fd, (void*) data, length);
    if (ret < 0 && SwooleG.error == SW_ERROR_OUTPUT_SEND_YIELD)
    {
        zval _yield_data;
        ZVAL_STRINGL(&_yield_data, swoole_http_buffer->str, swoole_http_buffer->length);
        php_swoole_server_send_yield(serv, ctx->fd, &_yield_data, return_value);
        if (Z_TYPE_P(return_value) == IS_FALSE)
        {
            ctx->chunk = 0;
            ctx->send_header = 0;
        }
    }
    return ret == SW_OK;
}

static bool http_context_send_file(http_context* ctx, const char *file, uint32_t l_file, off_t offset, size_t length)
{
    swServer *serv = (swServer *) ctx->private_data;
    return serv->sendfile(serv, ctx->fd, file, l_file, offset, length) == SW_OK;
}

static bool http_context_disconnect(http_context* ctx)
{
    swServer *serv = (swServer *) ctx->private_data;
    return serv->close(serv, ctx->fd, 0) == SW_OK;
}
<commit_msg>Revert "Always alloc swoole_http_buffer"<commit_after>/*
  +----------------------------------------------------------------------+
  | Swoole                                                               |
  +----------------------------------------------------------------------+
  | This source file is subject to version 2.0 of the Apache license,    |
  | that is bundled with this package in the file LICENSE, and is        |
  | available through the world-wide-web at the following url:           |
  | http://www.apache.org/licenses/LICENSE-2.0.html                      |
  | If you did not receive a copy of the Apache2.0 license and are unable|
  | to obtain it through the world-wide-web, please send a note to       |
  | license@swoole.com so we can mail you a copy immediately.            |
  +----------------------------------------------------------------------+
  | Author: Tianfeng Han  <mikan.tenny@gmail.com>                        |
  +----------------------------------------------------------------------+
*/

#include "php_swoole_cxx.h"
#include "swoole_http.h"
#include "websocket.h"

#include "main/rfc1867.h"

#ifdef SW_USE_HTTP2
#include "http2.h"
#endif

using namespace swoole;
using swoole::coroutine::Socket;

swString *swoole_http_buffer;
#ifdef SW_HAVE_COMPRESSION
/* not only be used by zlib but also be used by br */
swString *swoole_zlib_buffer;
#endif
swString *swoole_http_form_data_buffer;

zend_class_entry *swoole_http_server_ce;
zend_object_handlers swoole_http_server_handlers;

static bool http_context_send_data(http_context* ctx, const char *data, size_t length);
static bool http_context_send_file(http_context* ctx, const char *file, uint32_t l_file, off_t offset, size_t length);
static bool http_context_disconnect(http_context* ctx);

int php_swoole_http_onReceive(swServer *serv, swEventData *req)
{
    int fd = req->info.fd;
    int from_fd = req->info.server_fd;

    swConnection *conn = swServer_connection_verify_no_ssl(serv, fd);
    if (!conn)
    {
        swoole_error_log(SW_LOG_NOTICE, SW_ERROR_SESSION_NOT_EXIST, "connection[%d] is closed", fd);
        return SW_ERR;
    }

    swListenPort *port = (swListenPort *) serv->connection_list[from_fd].object;
    //other server port
    if (!port->open_http_protocol)
    {
        return php_swoole_onReceive(serv, req);
    }
    //websocket client
    if (conn->websocket_status == WEBSOCKET_STATUS_ACTIVE)
    {
        return swoole_websocket_onMessage(serv, req);
    }
#ifdef SW_USE_HTTP2
    if (conn->http2_stream)
    {
        return swoole_http2_server_onFrame(serv, conn, req);
    }
#endif

    http_context *ctx = swoole_http_context_new(fd);
    swoole_http_server_init_context(serv, ctx);

    zval *zdata = &ctx->request.zdata;
    php_swoole_get_recv_data(serv, zdata, req, NULL, 0);

    swTraceLog(SW_TRACE_SERVER, "http request from %d with %d bytes: <<EOF\n%.*s\nEOF", fd, (int) Z_STRLEN_P(zdata), (int) Z_STRLEN_P(zdata), Z_STRVAL_P(zdata));

    zval args[2], *zrequest_object = &args[0], *zresponse_object = &args[1];
    args[0] = *ctx->request.zobject;
    args[1] = *ctx->response.zobject;

    swoole_http_parser *parser = &ctx->parser;
    parser->data = ctx;
    swoole_http_parser_init(parser, PHP_HTTP_REQUEST);

    size_t parsed_n = swoole_http_requset_parse(ctx, Z_STRVAL_P(zdata), Z_STRLEN_P(zdata));
    if (parsed_n < Z_STRLEN_P(zdata))
    {
#ifdef SW_HTTP_BAD_REQUEST_PACKET
        ctx->send(ctx, SW_STRL(SW_HTTP_BAD_REQUEST_PACKET));
#endif
        ctx->close(ctx);
        swNotice("request is illegal and it has been discarded, %ld bytes unprocessed", Z_STRLEN_P(zdata) - parsed_n);
        goto _dtor_and_return;
    }

    do {
        zval *zserver = ctx->request.zserver;
        swConnection *serv_sock = swServer_connection_get(serv, conn->server_fd);
        if (serv_sock)
        {
            add_assoc_long(zserver, "server_port", swConnection_get_port(serv_sock->socket_type, &serv_sock->info));
        }
        add_assoc_long(zserver, "remote_port", swConnection_get_port(conn->socket_type, &conn->info));
        add_assoc_string(zserver, "remote_addr", (char *) swConnection_get_ip(conn->socket_type, &conn->info));
        add_assoc_long(zserver, "master_time", conn->last_time);
    } while (0);

    // begin to check and call registerd callback
    do {
        zend_fcall_info_cache *fci_cache = NULL;

        if (conn->websocket_status == WEBSOCKET_STATUS_CONNECTION)
        {
            fci_cache = php_swoole_server_get_fci_cache(serv, from_fd, SW_SERVER_CB_onHandShake);
            if (fci_cache == NULL)
            {
                swoole_websocket_onHandshake(serv, port, ctx);
                goto _dtor_and_return;
            }
            else
            {
                conn->websocket_status = WEBSOCKET_STATUS_HANDSHAKE;
                ctx->upgrade = 1;
            }
        }
        else
        {
            fci_cache = php_swoole_server_get_fci_cache(serv, from_fd, SW_SERVER_CB_onRequest);
            if (fci_cache == NULL)
            {
                swoole_websocket_onRequest(ctx);
                goto _dtor_and_return;
            }
        }

        if (UNEXPECTED(!zend::function::call(fci_cache, 2, args, NULL, SwooleG.enable_coroutine)))
        {
            php_swoole_error(E_WARNING, "%s->onRequest handler error", ZSTR_VAL(swoole_http_server_ce->name));
    #ifdef SW_HTTP_SERVICE_UNAVAILABLE_PACKET
            ctx->send(ctx, SW_STRL(SW_HTTP_SERVICE_UNAVAILABLE_PACKET));
    #endif
            ctx->close(ctx);
        }
    } while (0);

    _dtor_and_return:
    zval_ptr_dtor(zrequest_object);
    zval_ptr_dtor(zresponse_object);

    return SW_OK;
}

void php_swoole_http_onClose(swServer *serv, swDataHead *ev)
{
    int fd = ev->fd;
    swConnection *conn = swWorker_get_connection(serv, fd);
    if (!conn)
    {
        return;
    }
#ifdef SW_USE_HTTP2
    if (conn->http2_stream)
    {
        swoole_http2_server_session_free(conn);
    }
#endif
    php_swoole_onClose(serv, ev);
}

void php_swoole_http_server_minit(int module_number)
{
    SW_INIT_CLASS_ENTRY_EX(swoole_http_server, "Swoole\\Http\\Server", "swoole_http_server", NULL, NULL, swoole_server);
    SW_SET_CLASS_SERIALIZABLE(swoole_http_server, zend_class_serialize_deny, zend_class_unserialize_deny);
    SW_SET_CLASS_CLONEABLE(swoole_http_server, sw_zend_class_clone_deny);
    SW_SET_CLASS_UNSET_PROPERTY_HANDLER(swoole_http_server, sw_zend_class_unset_property_deny);

    zend_declare_property_null(swoole_http_server_ce, ZEND_STRL("onRequest"), ZEND_ACC_PRIVATE);
}

http_context* swoole_http_context_new(int fd)
{
    http_context *ctx = (http_context *) ecalloc(1, sizeof(http_context));
    if (UNEXPECTED(!ctx))
    {
        swoole_error_log(SW_LOG_ERROR, SW_ERROR_MALLOC_FAIL, "ecalloc(%ld) failed", sizeof(http_context));
        return NULL;
    }

    zval *zrequest_object = &ctx->request._zobject;
    ctx->request.zobject = zrequest_object;
    object_init_ex(zrequest_object, swoole_http_request_ce);
    php_swoole_http_request_set_context(zrequest_object, ctx);

    zval *zresponse_object = &ctx->response._zobject;
    ctx->response.zobject = zresponse_object;
    object_init_ex(zresponse_object, swoole_http_response_ce);
    php_swoole_http_response_set_context(zresponse_object, ctx);

    zend_update_property_long(swoole_http_request_ce, zrequest_object, ZEND_STRL("fd"), fd);
    zend_update_property_long(swoole_http_response_ce, zresponse_object, ZEND_STRL("fd"), fd);

#if PHP_MEMORY_DEBUG
    php_vmstat.new_http_request ++;
#endif

    swoole_http_init_and_read_property(swoole_http_request_ce, zrequest_object, &ctx->request.zserver, ZEND_STRL("server"));
    swoole_http_init_and_read_property(swoole_http_request_ce, zrequest_object, &ctx->request.zheader, ZEND_STRL("header"));
    ctx->fd = fd;

    return ctx;
}

void swoole_http_server_init_context(swServer *serv, http_context *ctx)
{
    ctx->parse_cookie = serv->http_parse_cookie;
    ctx->parse_body = serv->http_parse_post;
    ctx->parse_files = serv->http_parse_files;
#ifdef SW_HAVE_COMPRESSION
    ctx->enable_compression = serv->http_compression;
#endif
    ctx->private_data = serv;
    ctx->upload_tmp_dir = serv->upload_tmp_dir;
    ctx->send = http_context_send_data;
    ctx->sendfile = http_context_send_file;
    ctx->close = http_context_disconnect;
}

void swoole_http_context_copy(http_context *src, http_context *dst)
{
    dst->parse_cookie = src->parse_cookie;
    dst->parse_body = src->parse_body;
    dst->parse_files = src->parse_files;
#ifdef SW_HAVE_COMPRESSION
    dst->enable_compression = src->enable_compression;
#endif
    dst->private_data = src->private_data;
    dst->upload_tmp_dir = src->upload_tmp_dir;
    dst->send = src->send;
    dst->sendfile = src->sendfile;
    dst->close = src->close;
}

void swoole_http_context_free(http_context *ctx)
{
    if (ctx->request.zobject)
    {
        php_swoole_http_request_set_context(ctx->request.zobject, NULL);
    }
    php_swoole_http_response_set_context(ctx->response.zobject, NULL);
    http_request *req = &ctx->request;
    http_response *res = &ctx->response;
    if (req->path)
    {
        efree(req->path);
    }
    if (Z_TYPE(req->zdata) == IS_STRING)
    {
        zend_string_release(Z_STR(req->zdata));
    }
#ifdef SW_USE_HTTP2
    if (req->h2_data_buffer)
    {
        swString_free(req->h2_data_buffer);
    }
#endif
    if (res->reason)
    {
        efree(res->reason);
    }
    efree(ctx);
}

void php_swoole_http_server_init_global_variant()
{
    swoole_http_buffer = swString_new(SW_HTTP_RESPONSE_INIT_SIZE);
    if (!swoole_http_buffer)
    {
        php_swoole_fatal_error(E_ERROR, "[swoole_http_buffer] swString_new(%d) failed", SW_HTTP_RESPONSE_INIT_SIZE);
        return;
    }

    swoole_http_form_data_buffer = swString_new(SW_HTTP_RESPONSE_INIT_SIZE);
    if (!swoole_http_form_data_buffer)
    {
        php_swoole_fatal_error(E_ERROR, "[swoole_http_form_data_buffer] swString_new(%d) failed", SW_HTTP_RESPONSE_INIT_SIZE);
        return;
    }

    //for is_uploaded_file and move_uploaded_file
    if (!SG(rfc1867_uploaded_files))
    {
        ALLOC_HASHTABLE(SG(rfc1867_uploaded_files));
        zend_hash_init(SG(rfc1867_uploaded_files), 8, NULL, NULL, 0);
    }
}

http_context* php_swoole_http_request_get_and_check_context(zval *zobject)
{
    http_context *ctx = php_swoole_http_request_get_context(zobject);
    if (!ctx)
    {
        php_swoole_fatal_error(E_WARNING, "http request is unavailable (maybe it has been ended)");
    }
    return ctx;
}

http_context* php_swoole_http_response_get_and_check_context(zval *zobject, bool check_end)
{
    http_context *ctx = php_swoole_http_response_get_context(zobject);
    if (!ctx || (check_end && ctx->end))
    {
        php_swoole_fatal_error(E_WARNING, "http response is unavailable (maybe it has been ended or detached)");
        return NULL;
    }
    return ctx;
}

bool http_context_send_data(http_context* ctx, const char *data, size_t length)
{
    swServer *serv = (swServer *) ctx->private_data;
    zval *return_value = (zval *) ctx->private_data_2;
    ssize_t ret = serv->send(serv, ctx->fd, (void*) data, length);
    if (ret < 0 && SwooleG.error == SW_ERROR_OUTPUT_SEND_YIELD)
    {
        zval _yield_data;
        ZVAL_STRINGL(&_yield_data, swoole_http_buffer->str, swoole_http_buffer->length);
        php_swoole_server_send_yield(serv, ctx->fd, &_yield_data, return_value);
        if (Z_TYPE_P(return_value) == IS_FALSE)
        {
            ctx->chunk = 0;
            ctx->send_header = 0;
        }
    }
    return ret == SW_OK;
}

static bool http_context_send_file(http_context* ctx, const char *file, uint32_t l_file, off_t offset, size_t length)
{
    swServer *serv = (swServer *) ctx->private_data;
    return serv->sendfile(serv, ctx->fd, file, l_file, offset, length) == SW_OK;
}

static bool http_context_disconnect(http_context* ctx)
{
    swServer *serv = (swServer *) ctx->private_data;
    return serv->close(serv, ctx->fd, 0) == SW_OK;
}
<|endoftext|>


<commit_before>/*
 * C S O U N D
 *
 * L I C E N S E
 *
 * This software is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This software 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 software; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */
#include "MusicModel.hpp"
#include "Exception.hpp"
#include "Composition.hpp"
#include "System.hpp"

namespace csound
{
  MusicModel::MusicModel() :
    cppSound(&cppSound_),
    go(false)
  {
  }

  MusicModel::~MusicModel()
  {
    //clear();
  }

  void MusicModel::initialize()
  {
  }

  void MusicModel::generate()
  {
    cppSound->removeScore();
    if (children.size()) {
      score.clear();
    }
    traverse(getLocalCoordinates(), score);
    System::message("Generated %d events.\n", score.size());
  }

  void MusicModel::render()
  {
    generate();
    perform();
  }

  void MusicModel::createCsoundScore(std::string addToScore, double extendSeconds)
  {
    System::inform("addToScore.length(): %d\n", addToScore.length());
    if (addToScore.length() > 2) {
      cppSound->removeScore();
      cppSound->addScoreLine(addToScore);
    }
    cppSound->addScoreLine(score.getCsoundScore(tonesPerOctave, conformPitches));
    char buffer[0x100];
    std::sprintf(buffer, "\ns %9.3f", extendSeconds);
    cppSound->addScoreLine(buffer);
    std::sprintf(buffer, "\ne %9.3f", extendSeconds);
    cppSound->addScoreLine(buffer);
    cppSound->exportForPerformance();
  }

  void MusicModel::perform()
  {
    go = true;
    cppSound->setCommand(getCsoundCommand());
    createCsoundScore(csoundScoreHeader);
    cppSound->perform();
    // The Csound command is managed from MusicModel,
    // not from CppSound. So we clear out what we set.
    cppSound->setCommand("");
  }

  void MusicModel::clear()
  {
    Node::clear();
    Composition::clear();
    cppSound->removeScore();
  }

  void MusicModel::setCppSound(CppSound *cppSound)
  {
    if(!cppSound)
      {
        this->cppSound = &cppSound_;
      }
    else
      {
        this->cppSound = cppSound;
      }
  }

  CppSound *MusicModel::getCppSound()
  {
    return cppSound;
  }

  void MusicModel::setCsoundOrchestra(std::string orchestra)
  {
    cppSound->setOrchestra(orchestra);
  }

  std::string MusicModel::getCsoundOrchestra() const
  {
    return cppSound->getOrchestra();
  }

  void MusicModel::setCsoundScoreHeader(std::string header)
  {
    csoundScoreHeader = header;
  }

  std::string MusicModel::getCsoundScoreHeader() const
  {
    return csoundScoreHeader;
  }

  void MusicModel::arrange(int oldInstrumentNumber, int newInstrumentNumber)
  {
    score.arrange(oldInstrumentNumber, newInstrumentNumber);
  }

  void MusicModel::arrange(int oldInstrumentNumber,
			   int newInstrumentNumber,
			   double gain)
  {
    score.arrange(oldInstrumentNumber, newInstrumentNumber, gain);
  }

  void MusicModel::arrange(int oldInstrumentNumber,
			   int newInstrumentNumber,
			   double gain,
			   double pan)
  {
    score.arrange(oldInstrumentNumber, newInstrumentNumber, gain, pan);
  }

  void MusicModel::arrange(int silenceInstrumentNumber, std::string csoundInstrumentName)
  {
    int csoundInstrumentNumber = cppSound->getInstrumentNumber(csoundInstrumentName);
    arrange(silenceInstrumentNumber, csoundInstrumentNumber);
  }

  void MusicModel::arrange(int silenceInstrumentNumber, std::string csoundInstrumentName, double gain)
  {
    int csoundInstrumentNumber = cppSound->getInstrumentNumber(csoundInstrumentName);
    arrange(silenceInstrumentNumber, csoundInstrumentNumber, gain);
  }

  void MusicModel::arrange(int silenceInstrumentNumber, std::string csoundInstrumentName, double gain, double pan)
  {
    int csoundInstrumentNumber = cppSound->getInstrumentNumber(csoundInstrumentName);
    arrange(silenceInstrumentNumber, csoundInstrumentNumber, gain, pan);
  }

  void MusicModel::removeArrangement()
  {
    score.removeArrangement();
  }

  void MusicModel::setCsoundCommand(std::string command)
  {
    cppSound->setCommand(command);
  }

  std::string MusicModel::getCsoundCommand() const
  {
    std::string command_ = cppSound->getCommand();
    if (command_.size() == 0)
      {
	char buffer[0x200];
	std::sprintf(buffer,
		     "csound --midi-key=4 --midi-velocity=5 -m167 -RWdfo %s temp.orc temp.sco",
		     getOutputSoundfileName().c_str());
	command_ = buffer;
      }
    return command_;
  }

  long MusicModel::getThis()
  {
    return (long) this;
  }

  Node *MusicModel::getThisNode()
  {
    return (Node *)this;
  }

  void MusicModel::processArgs(const std::vector<std::string> &args)
  {
    std::map<std::string, std::string> argsmap;
    for (size_t i = 0, n = args.size(); i < n; )
      {
	if (args[i].find("--") == 0)
	  {
	    const std::string key = args[i];
	    ++i;
	    if (args[i].find("--") == std::string::npos)
	      {
		std::string value = args[i];
		++i;
		argsmap[key] = value;
	      }
	    else
	      {
		argsmap[key] = "";
	      }
	  }
      }
    char command[0x200];
    go = true;
    bool postPossible = false;
    if ((argsmap.find("--midi") != argsmap.end()) && go)
      {
	generate();
	cppSound->save(getMidiFilename().c_str());
      }
    if ((argsmap.find("--csound") != argsmap.end()) && go)
      {
	postPossible = true;
	render();
      }
    if ((argsmap.find("--pianoteq") != argsmap.end()) && go)
      {
	std::sprintf(command, "Pianoteq --midi %s", getMidiFilename().c_str());
	int result = std::system(command);
      }
    if ((argsmap.find("--pianoteq-wav") != argsmap.end()) && go)
      {
	postPossible = true;
	std::sprintf(command, "Pianoteq --headless --midi %s --rate 48000 --wav %s", getMidiFilename().c_str(), getOutputSoundfileName().c_str());
	int result = std::system(command);
      }
    if ((argsmap.find("--playmidi") != argsmap.end()) && go)
      {
	std::sprintf(command, "%s %s", argsmap["--playmidi"].c_str(), getMidiFilename().c_str());
	int result = std::system(command);
      }
    if ((argsmap.find("--playwav") != argsmap.end()) && go)
      {
	std::sprintf(command, "%s %s", argsmap["--playwav"].c_str(), getOutputSoundfileName().c_str());
	int result = std::system(command);
      }
    if ((argsmap.find("--post") != argsmap.end()) && go && postPossible)
      {
	translateMaster();
      }
  }
  void MusicModel::stop()
  {
    std::cout << "MusicModel::stop()..." << std::endl;
    go = false;
    cppSound->stop();
  }
}

<commit_msg>Less ambiguous file locations for Csound command.<commit_after>/*
 * C S O U N D
 *
 * L I C E N S E
 *
 * This software is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This software 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 software; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */
#include "MusicModel.hpp"
#include "Exception.hpp"
#include "Composition.hpp"
#include "System.hpp"
#include <cstdio>
#include <cstdlib>

namespace csound
{
  MusicModel::MusicModel() :
    cppSound(&cppSound_),
    go(false)
  {
  }

  MusicModel::~MusicModel()
  {
    //clear();
  }

  void MusicModel::initialize()
  {
  }

  void MusicModel::generate()
  {
    cppSound->removeScore();
    if (children.size()) {
      score.clear();
    }
    traverse(getLocalCoordinates(), score);
    System::message("Generated %d events.\n", score.size());
  }

  void MusicModel::render()
  {
    generate();
    perform();
  }

  void MusicModel::createCsoundScore(std::string addToScore, double extendSeconds)
  {
    System::inform("addToScore.length(): %d\n", addToScore.length());
    if (addToScore.length() > 2) {
      cppSound->removeScore();
      cppSound->addScoreLine(addToScore);
    }
    cppSound->addScoreLine(score.getCsoundScore(tonesPerOctave, conformPitches));
    char buffer[0x100];
    std::sprintf(buffer, "\ns %9.3f", extendSeconds);
    cppSound->addScoreLine(buffer);
    std::sprintf(buffer, "\ne %9.3f", extendSeconds);
    cppSound->addScoreLine(buffer);
    cppSound->exportForPerformance();
  }

  void MusicModel::perform()
  {
    go = true;
    cppSound->setCommand(getCsoundCommand());
    createCsoundScore(csoundScoreHeader);
    cppSound->perform();
    // The Csound command is managed from MusicModel,
    // not from CppSound. So we clear out what we set.
    cppSound->setCommand("");
  }

  void MusicModel::clear()
  {
    Node::clear();
    Composition::clear();
    cppSound->removeScore();
  }

  void MusicModel::setCppSound(CppSound *cppSound)
  {
    if(!cppSound)
      {
        this->cppSound = &cppSound_;
      }
    else
      {
        this->cppSound = cppSound;
      }
  }

  CppSound *MusicModel::getCppSound()
  {
    return cppSound;
  }

  void MusicModel::setCsoundOrchestra(std::string orchestra)
  {
    cppSound->setOrchestra(orchestra);
  }

  std::string MusicModel::getCsoundOrchestra() const
  {
    return cppSound->getOrchestra();
  }

  void MusicModel::setCsoundScoreHeader(std::string header)
  {
    csoundScoreHeader = header;
  }

  std::string MusicModel::getCsoundScoreHeader() const
  {
    return csoundScoreHeader;
  }

  void MusicModel::arrange(int oldInstrumentNumber, int newInstrumentNumber)
  {
    score.arrange(oldInstrumentNumber, newInstrumentNumber);
  }

  void MusicModel::arrange(int oldInstrumentNumber,
			   int newInstrumentNumber,
			   double gain)
  {
    score.arrange(oldInstrumentNumber, newInstrumentNumber, gain);
  }

  void MusicModel::arrange(int oldInstrumentNumber,
			   int newInstrumentNumber,
			   double gain,
			   double pan)
  {
    score.arrange(oldInstrumentNumber, newInstrumentNumber, gain, pan);
  }

  void MusicModel::arrange(int silenceInstrumentNumber, std::string csoundInstrumentName)
  {
    int csoundInstrumentNumber = cppSound->getInstrumentNumber(csoundInstrumentName);
    arrange(silenceInstrumentNumber, csoundInstrumentNumber);
  }

  void MusicModel::arrange(int silenceInstrumentNumber, std::string csoundInstrumentName, double gain)
  {
    int csoundInstrumentNumber = cppSound->getInstrumentNumber(csoundInstrumentName);
    arrange(silenceInstrumentNumber, csoundInstrumentNumber, gain);
  }

  void MusicModel::arrange(int silenceInstrumentNumber, std::string csoundInstrumentName, double gain, double pan)
  {
    int csoundInstrumentNumber = cppSound->getInstrumentNumber(csoundInstrumentName);
    arrange(silenceInstrumentNumber, csoundInstrumentNumber, gain, pan);
  }

  void MusicModel::removeArrangement()
  {
    score.removeArrangement();
  }

  void MusicModel::setCsoundCommand(std::string command)
  {
    cppSound->setCommand(command);
  }

  std::string MusicModel::getCsoundCommand() const
  {
    std::string command_ = cppSound->getCommand();
    if (command_.size() == 0)
      {
	const char *temp_path = std::getenv("TEMP");
	std::string orcname = std::tmpnam(0);
	std::string sconame = std::tmpnam(0);
	char buffer[0x200];
	std::sprintf(buffer,
		     "csound --midi-key=4 --midi-velocity=5 -m167 -RWdfo %s %s%s.orc %s%s.sco",
		     getOutputSoundfileName().c_str(), temp_path, orcname.c_str(), temp_path, sconame.c_str());
	command_ = buffer;
      }
    return command_;
  }

  long MusicModel::getThis()
  {
    return (long) this;
  }

  Node *MusicModel::getThisNode()
  {
    return (Node *)this;
  }

  void MusicModel::processArgs(const std::vector<std::string> &args)
  {
    std::map<std::string, std::string> argsmap;
    for (size_t i = 0, n = args.size(); i < n; )
      {
	if (args[i].find("--") == 0)
	  {
	    const std::string key = args[i];
	    ++i;
	    if (args[i].find("--") == std::string::npos)
	      {
		std::string value = args[i];
		++i;
		argsmap[key] = value;
	      }
	    else
	      {
		argsmap[key] = "";
	      }
	  }
      }
    char command[0x200];
    go = true;
    bool postPossible = false;
    if ((argsmap.find("--midi") != argsmap.end()) && go)
      {
	generate();
	cppSound->save(getMidiFilename().c_str());
      }
    if ((argsmap.find("--csound") != argsmap.end()) && go)
      {
	postPossible = true;
	render();
      }
    if ((argsmap.find("--pianoteq") != argsmap.end()) && go)
      {
	std::sprintf(command, "Pianoteq --midi %s", getMidiFilename().c_str());
	int result = std::system(command);
      }
    if ((argsmap.find("--pianoteq-wav") != argsmap.end()) && go)
      {
	postPossible = true;
	std::sprintf(command, "Pianoteq --headless --midi %s --rate 48000 --wav %s", getMidiFilename().c_str(), getOutputSoundfileName().c_str());
	int result = std::system(command);
      }
    if ((argsmap.find("--playmidi") != argsmap.end()) && go)
      {
	std::sprintf(command, "%s %s", argsmap["--playmidi"].c_str(), getMidiFilename().c_str());
	int result = std::system(command);
      }
    if ((argsmap.find("--playwav") != argsmap.end()) && go)
      {
	std::sprintf(command, "%s %s", argsmap["--playwav"].c_str(), getOutputSoundfileName().c_str());
	int result = std::system(command);
      }
    if ((argsmap.find("--post") != argsmap.end()) && go && postPossible)
      {
	translateMaster();
      }
  }
  void MusicModel::stop()
  {
    std::cout << "MusicModel::stop()..." << std::endl;
    go = false;
    cppSound->stop();
  }
}

<|endoftext|>


<commit_before>/***************************************************************************
**
** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (directui@nokia.com)
**
** This file is part of libmeegotouch.
**
** If you have questions regarding the use of this file, please contact
** Nokia at directui@nokia.com.
**
** 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
** and appearing in the file LICENSE.LGPL included in the packaging
** of this file.
**
****************************************************************************/

#include "mlabelview.h"
#include "mlabelview_p.h"
#include "mlabelmodel.h"
#include "mlabel.h"
#include "mviewcreator.h"

#include <QPainter>
#include <QTextDocument>
#include <QTextCursor>
#include <QTransform>
#include <QFontMetrics>
#include <QPixmapCache>
#include <QAbstractTextDocumentLayout>
#include <QGraphicsSceneMouseEvent>
#include <QGraphicsSceneResizeEvent>

MLabelViewSimple::MLabelViewSimple(MLabelViewPrivate *viewPrivate) :
    viewPrivate(viewPrivate), preferredSize(-1, -1), dirty(true), staticText()
{
    staticText.setTextFormat(Qt::PlainText);
}

MLabelViewSimple::~MLabelViewSimple()
{
}

void MLabelViewSimple::drawContents(QPainter *painter, const QSizeF &size)
{
    Q_UNUSED(size);

    initializeStaticText();

    const MLabelModel *model = viewPrivate->model();
    const MLabelStyle *style = viewPrivate->style();
    const QRectF paintingRect(viewPrivate->boundingRect().adjusted(style->paddingLeft(), style->paddingTop(), -style->paddingRight(), -style->paddingBottom()));

    painter->setPen(model->color().isValid() ? model->color() : style->color());
    painter->setFont(viewPrivate->controller->font());

    painter->setClipping(true);
    painter->setClipRect(paintingRect);
    painter->drawStaticText(textOffset, staticText);
    painter->setClipping(false);
}

bool MLabelViewSimple::resizeEvent(QGraphicsSceneResizeEvent *event)
{
    // There is no way to specify sizeHint for a text without knowing possible width.
    // 1st phase, when Qt calls sizeHint, view will return approximate values for
    // minimum and preferred size. When resizeEvent comes, layout already knows
    // sizes of components, and here comes
    // 2nd phase, when we identify widget's height, based on width. Our height will
    // change and we don't want to occupy more space then need, so we have to call
    // updateGeometry, to tell layout to update sizeHint cache. This function
    // return true if such update is needed.

    QFontMetricsF fm(viewPrivate->controller->font());

    QRectF bR = fm.boundingRect(QRectF(QPoint(0, 0), event->newSize()),
                                viewPrivate->textOptions.alignment() | wrap(), viewPrivate->model()->text());
    if (bR.height() > fm.height()) {
        preferredSize = QSizeF(bR.width(), bR.height());
        return true;
    } else
        return false;
}

QSizeF MLabelViewSimple::sizeHint(Qt::SizeHint which, const QSizeF &constraint) const
{
    switch (which) {
    case Qt::MinimumSize: {
        QFontMetricsF fm(viewPrivate->controller->font());
        QRectF r(0, 0, constraint.width(), constraint.height());

        if (r.width() < 0) {
            r.setWidth(QWIDGETSIZE_MAX);
        }
        if (r.height() < 0) {
            r.setHeight(QWIDGETSIZE_MAX);
        }

        QRectF bR(fm.boundingRect(r, viewPrivate->textOptions.alignment() | wrap(),
                                  viewPrivate->model()->text()));

        return QSizeF(fm.width("x"), bR.height());
    }
    case Qt::PreferredSize: {
        qreal w = constraint.width();
        qreal h = constraint.height();
        if (w < 0) {
            w = QWIDGETSIZE_MAX;
        }
        if (h < 0) {
            h = QWIDGETSIZE_MAX;
        }
        if (preferredSize.width() >= 0 && preferredSize.width() < w)
            w = preferredSize.width();
        if (preferredSize.height() >= 0 && preferredSize.height() < h)
            h = preferredSize.height();

        QFontMetricsF fm(viewPrivate->controller->font());

        QRectF bR(fm.boundingRect(QRectF(0, 0, w, h), viewPrivate->textOptions.alignment() | wrap(),
                                  viewPrivate->model()->text()));
        return bR.size().boundedTo(QSizeF(w, h));
    }
    case Qt::MaximumSize: {
        return QSizeF(QWIDGETSIZE_MAX, QWIDGETSIZE_MAX);
    }
    default:
        qWarning("MLabel::sizeHint() don't know how to handle the value of 'which' ");
    }

    return QSizeF(0, 0);
}

void MLabelViewSimple::setupModel()
{
    viewPrivate->textOptions.setTextDirection(viewPrivate->model()->textDirection());
    viewPrivate->textOptions.setAlignment(viewPrivate->model()->alignment());
}

bool MLabelViewSimple::updateData(const QList<const char *>& modifications)
{
    const char *member = NULL;
    bool needUpdate = false;

    const MLabelModel *model = viewPrivate->model();

    foreach(member, modifications) {
        if (member == MLabelModel::Text) {
            preferredSize = QSizeF(-1, -1);
            needUpdate = true;
        } else if(member == MLabelModel::WrapMode) {
            if (model->wordWrap()) {
                if (model->wrapMode() == QTextOption::NoWrap) {
                    //Note that NoWrap works incorrectly in Qt 4.6
                    viewPrivate->textOptions.setWrapMode(QTextOption::ManualWrap);
                } else {
                    viewPrivate->textOptions.setWrapMode(model->wrapMode());
                }
            }
            needUpdate = true;
        } else if (member == MLabelModel::WordWrap) {
            if (model->wordWrap()) {
                viewPrivate->textOptions.setWrapMode(model->wrapMode());
            } else {
                //Note that NoWrap works incorrectly in Qt 4.6
                viewPrivate->textOptions.setWrapMode(QTextOption::ManualWrap);
            }
            needUpdate = true;
        } else if (member == MLabelModel::TextDirection) {
            needUpdate = true;
            viewPrivate->textOptions.setTextDirection(viewPrivate->model()->textDirection());
        } else if (member == MLabelModel::Alignment) {
            viewPrivate->textOptions.setAlignment(viewPrivate->model()->alignment());
        } else if (member == MLabelModel::UseModelFont || member == MLabelModel::Font) {
            needUpdate = true;
        }
    }
    return needUpdate;
}

bool MLabelViewSimple::isRich()
{
    return false;
}

void MLabelViewSimple::mousePressEvent(QGraphicsSceneMouseEvent *event)
{
    event->ignore(); //propagate link up to owner of label
}

void MLabelViewSimple::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
{
    Q_UNUSED(event);
}

void MLabelViewSimple::cancelEvent(MCancelEvent *event)
{
    Q_UNUSED(event);
}

void MLabelViewSimple::longPressEvent(QGraphicsSceneContextMenuEvent *event)
{
    Q_UNUSED(event);
}

void MLabelViewSimple::applyStyle()
{
}

void MLabelViewSimple::initializeStaticText()
{
    if (!dirty) {
        return;
    }

    dirty = false;

    const MLabelModel *model = viewPrivate->model();
    const MLabelStyle *style = viewPrivate->style();

    const QRectF paintingRect(viewPrivate->boundingRect().adjusted(style->paddingLeft(), style->paddingTop(), -style->paddingRight(), -style->paddingBottom()));
    textOffset = paintingRect.topLeft().toPoint();

    QString textToRender = model->text();
    if (model->textElide() && textToRender.size() > 4) {
        QFontMetrics fm(viewPrivate->controller->font());
        textToRender = fm.elidedText(model->text(), Qt::ElideRight, paintingRect.width());
    }

    qreal textWidth = -1.0;
    if (viewPrivate->controller->wordWrap()) {
        textWidth = paintingRect.width();
    } else {
        // QStaticText uses QPainter::drawText(int x, int y, ...) internally, if the text width
        // is smaller than 0. In opposite to QPainter::drawText(const QRect &rectangle, ...) '\n'
        // characters are not replaced by spaces in this case. For MLabel '\n' characters should be
        // replaced by spaces too, when shown in a single line.
        textToRender.replace('\n', ' ');
    }
    staticText.setTextWidth(textWidth);
    staticText.setText(textToRender);
    staticText.prepare(QTransform(), viewPrivate->controller->font());

    Qt::Alignment alignment = viewPrivate->textOptions.alignment();
    if (model->textDirection() == Qt::RightToLeft) {
        // Mirror the horizontal alignment
        if (alignment & Qt::AlignLeft) {
            alignment = (alignment | Qt::AlignRight) & ~Qt::AlignLeft;
        } else if (alignment & Qt::AlignRight) {
            alignment = (alignment | Qt::AlignLeft) & ~Qt::AlignRight;
        }
    }

    // Adjust x-position dependent on the horizontal alignment
    if (alignment & Qt::AlignHCenter) {
        const qreal inc = (paintingRect.width() - staticText.size().width()) / 2.0;
        if (inc > 0.0) {
            textOffset.rx() += inc;
        }
    } else if (alignment & Qt::AlignRight) {
        textOffset.setX(paintingRect.right() - staticText.size().width());
    }

    // Adjust y-position dependent on the vertical alignment
    if (alignment & Qt::AlignVCenter) {
        const qreal inc = (paintingRect.height() - staticText.size().height()) / 2.0;
        if (inc > 0.0) {
            textOffset.ry() += inc;
        }
    } else if (alignment & Qt::AlignBottom) {
        textOffset.setY(paintingRect.bottom() - staticText.size().height());
    }
}

void MLabelViewSimple::markDirty()
{
    dirty = true;
}

Qt::TextFlag MLabelViewSimple::wrap() const
{
    if(!viewPrivate->controller->wordWrap()) {
        return Qt::TextSingleLine;
    }

    QTextOption::WrapMode wrapMode = viewPrivate->model()->wrapMode();
    if (wrapMode == QTextOption::WordWrap) {
        return Qt::TextWordWrap;
    } else if (wrapMode == QTextOption::WrapAnywhere || wrapMode == QTextOption::WrapAtWordBoundaryOrAnywhere) {
        return Qt::TextWrapAnywhere;
    }
    return Qt::TextSingleLine;
}

<commit_msg>Fixes: NB#175977 MLabelViewSimple - restore clipping state after setting it<commit_after>/***************************************************************************
**
** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (directui@nokia.com)
**
** This file is part of libmeegotouch.
**
** If you have questions regarding the use of this file, please contact
** Nokia at directui@nokia.com.
**
** 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
** and appearing in the file LICENSE.LGPL included in the packaging
** of this file.
**
****************************************************************************/

#include "mlabelview.h"
#include "mlabelview_p.h"
#include "mlabelmodel.h"
#include "mlabel.h"
#include "mviewcreator.h"

#include <QPainter>
#include <QTextDocument>
#include <QTextCursor>
#include <QTransform>
#include <QFontMetrics>
#include <QPixmapCache>
#include <QAbstractTextDocumentLayout>
#include <QGraphicsSceneMouseEvent>
#include <QGraphicsSceneResizeEvent>

MLabelViewSimple::MLabelViewSimple(MLabelViewPrivate *viewPrivate) :
    viewPrivate(viewPrivate), preferredSize(-1, -1), dirty(true), staticText()
{
    staticText.setTextFormat(Qt::PlainText);
}

MLabelViewSimple::~MLabelViewSimple()
{
}

void MLabelViewSimple::drawContents(QPainter *painter, const QSizeF &size)
{
    Q_UNUSED(size);

    initializeStaticText();

    const MLabelModel *model = viewPrivate->model();
    const MLabelStyle *style = viewPrivate->style();
    const QRectF paintingRect(viewPrivate->boundingRect().adjusted(style->paddingLeft(), style->paddingTop(), -style->paddingRight(), -style->paddingBottom()));

    painter->setPen(model->color().isValid() ? model->color() : style->color());
    painter->setFont(viewPrivate->controller->font());

    bool wasClipping = painter->hasClipping();
    QRegion oldClipRegion = painter->clipRegion();
    painter->setClipping(true);
    // IntersectClip is needed for the cases when widget has "clip children to parent" flag on
    painter->setClipRect(paintingRect, wasClipping?Qt::IntersectClip:Qt::ReplaceClip);
    painter->drawStaticText(textOffset, staticText);
    painter->setClipRegion(oldClipRegion);
    painter->setClipping(wasClipping);
}

bool MLabelViewSimple::resizeEvent(QGraphicsSceneResizeEvent *event)
{
    // There is no way to specify sizeHint for a text without knowing possible width.
    // 1st phase, when Qt calls sizeHint, view will return approximate values for
    // minimum and preferred size. When resizeEvent comes, layout already knows
    // sizes of components, and here comes
    // 2nd phase, when we identify widget's height, based on width. Our height will
    // change and we don't want to occupy more space then need, so we have to call
    // updateGeometry, to tell layout to update sizeHint cache. This function
    // return true if such update is needed.

    QFontMetricsF fm(viewPrivate->controller->font());

    QRectF bR = fm.boundingRect(QRectF(QPoint(0, 0), event->newSize()),
                                viewPrivate->textOptions.alignment() | wrap(), viewPrivate->model()->text());
    if (bR.height() > fm.height()) {
        preferredSize = QSizeF(bR.width(), bR.height());
        return true;
    } else
        return false;
}

QSizeF MLabelViewSimple::sizeHint(Qt::SizeHint which, const QSizeF &constraint) const
{
    switch (which) {
    case Qt::MinimumSize: {
        QFontMetricsF fm(viewPrivate->controller->font());
        QRectF r(0, 0, constraint.width(), constraint.height());

        if (r.width() < 0) {
            r.setWidth(QWIDGETSIZE_MAX);
        }
        if (r.height() < 0) {
            r.setHeight(QWIDGETSIZE_MAX);
        }

        QRectF bR(fm.boundingRect(r, viewPrivate->textOptions.alignment() | wrap(),
                                  viewPrivate->model()->text()));

        return QSizeF(fm.width("x"), bR.height());
    }
    case Qt::PreferredSize: {
        qreal w = constraint.width();
        qreal h = constraint.height();
        if (w < 0) {
            w = QWIDGETSIZE_MAX;
        }
        if (h < 0) {
            h = QWIDGETSIZE_MAX;
        }
        if (preferredSize.width() >= 0 && preferredSize.width() < w)
            w = preferredSize.width();
        if (preferredSize.height() >= 0 && preferredSize.height() < h)
            h = preferredSize.height();

        QFontMetricsF fm(viewPrivate->controller->font());

        QRectF bR(fm.boundingRect(QRectF(0, 0, w, h), viewPrivate->textOptions.alignment() | wrap(),
                                  viewPrivate->model()->text()));
        return bR.size().boundedTo(QSizeF(w, h));
    }
    case Qt::MaximumSize: {
        return QSizeF(QWIDGETSIZE_MAX, QWIDGETSIZE_MAX);
    }
    default:
        qWarning("MLabel::sizeHint() don't know how to handle the value of 'which' ");
    }

    return QSizeF(0, 0);
}

void MLabelViewSimple::setupModel()
{
    viewPrivate->textOptions.setTextDirection(viewPrivate->model()->textDirection());
    viewPrivate->textOptions.setAlignment(viewPrivate->model()->alignment());
}

bool MLabelViewSimple::updateData(const QList<const char *>& modifications)
{
    const char *member = NULL;
    bool needUpdate = false;

    const MLabelModel *model = viewPrivate->model();

    foreach(member, modifications) {
        if (member == MLabelModel::Text) {
            preferredSize = QSizeF(-1, -1);
            needUpdate = true;
        } else if(member == MLabelModel::WrapMode) {
            if (model->wordWrap()) {
                if (model->wrapMode() == QTextOption::NoWrap) {
                    //Note that NoWrap works incorrectly in Qt 4.6
                    viewPrivate->textOptions.setWrapMode(QTextOption::ManualWrap);
                } else {
                    viewPrivate->textOptions.setWrapMode(model->wrapMode());
                }
            }
            needUpdate = true;
        } else if (member == MLabelModel::WordWrap) {
            if (model->wordWrap()) {
                viewPrivate->textOptions.setWrapMode(model->wrapMode());
            } else {
                //Note that NoWrap works incorrectly in Qt 4.6
                viewPrivate->textOptions.setWrapMode(QTextOption::ManualWrap);
            }
            needUpdate = true;
        } else if (member == MLabelModel::TextDirection) {
            needUpdate = true;
            viewPrivate->textOptions.setTextDirection(viewPrivate->model()->textDirection());
        } else if (member == MLabelModel::Alignment) {
            viewPrivate->textOptions.setAlignment(viewPrivate->model()->alignment());
        } else if (member == MLabelModel::UseModelFont || member == MLabelModel::Font) {
            needUpdate = true;
        }
    }
    return needUpdate;
}

bool MLabelViewSimple::isRich()
{
    return false;
}

void MLabelViewSimple::mousePressEvent(QGraphicsSceneMouseEvent *event)
{
    event->ignore(); //propagate link up to owner of label
}

void MLabelViewSimple::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
{
    Q_UNUSED(event);
}

void MLabelViewSimple::cancelEvent(MCancelEvent *event)
{
    Q_UNUSED(event);
}

void MLabelViewSimple::longPressEvent(QGraphicsSceneContextMenuEvent *event)
{
    Q_UNUSED(event);
}

void MLabelViewSimple::applyStyle()
{
}

void MLabelViewSimple::initializeStaticText()
{
    if (!dirty) {
        return;
    }

    dirty = false;

    const MLabelModel *model = viewPrivate->model();
    const MLabelStyle *style = viewPrivate->style();

    const QRectF paintingRect(viewPrivate->boundingRect().adjusted(style->paddingLeft(), style->paddingTop(), -style->paddingRight(), -style->paddingBottom()));
    textOffset = paintingRect.topLeft().toPoint();

    QString textToRender = model->text();
    if (model->textElide() && textToRender.size() > 4) {
        QFontMetrics fm(viewPrivate->controller->font());
        textToRender = fm.elidedText(model->text(), Qt::ElideRight, paintingRect.width());
    }

    qreal textWidth = -1.0;
    if (viewPrivate->controller->wordWrap()) {
        textWidth = paintingRect.width();
    } else {
        // QStaticText uses QPainter::drawText(int x, int y, ...) internally, if the text width
        // is smaller than 0. In opposite to QPainter::drawText(const QRect &rectangle, ...) '\n'
        // characters are not replaced by spaces in this case. For MLabel '\n' characters should be
        // replaced by spaces too, when shown in a single line.
        textToRender.replace('\n', ' ');
    }
    staticText.setTextWidth(textWidth);
    staticText.setText(textToRender);
    staticText.prepare(QTransform(), viewPrivate->controller->font());

    Qt::Alignment alignment = viewPrivate->textOptions.alignment();
    if (model->textDirection() == Qt::RightToLeft) {
        // Mirror the horizontal alignment
        if (alignment & Qt::AlignLeft) {
            alignment = (alignment | Qt::AlignRight) & ~Qt::AlignLeft;
        } else if (alignment & Qt::AlignRight) {
            alignment = (alignment | Qt::AlignLeft) & ~Qt::AlignRight;
        }
    }

    // Adjust x-position dependent on the horizontal alignment
    if (alignment & Qt::AlignHCenter) {
        const qreal inc = (paintingRect.width() - staticText.size().width()) / 2.0;
        if (inc > 0.0) {
            textOffset.rx() += inc;
        }
    } else if (alignment & Qt::AlignRight) {
        textOffset.setX(paintingRect.right() - staticText.size().width());
    }

    // Adjust y-position dependent on the vertical alignment
    if (alignment & Qt::AlignVCenter) {
        const qreal inc = (paintingRect.height() - staticText.size().height()) / 2.0;
        if (inc > 0.0) {
            textOffset.ry() += inc;
        }
    } else if (alignment & Qt::AlignBottom) {
        textOffset.setY(paintingRect.bottom() - staticText.size().height());
    }
}

void MLabelViewSimple::markDirty()
{
    dirty = true;
}

Qt::TextFlag MLabelViewSimple::wrap() const
{
    if(!viewPrivate->controller->wordWrap()) {
        return Qt::TextSingleLine;
    }

    QTextOption::WrapMode wrapMode = viewPrivate->model()->wrapMode();
    if (wrapMode == QTextOption::WordWrap) {
        return Qt::TextWordWrap;
    } else if (wrapMode == QTextOption::WrapAnywhere || wrapMode == QTextOption::WrapAtWordBoundaryOrAnywhere) {
        return Qt::TextWrapAnywhere;
    }
    return Qt::TextSingleLine;
}

<|endoftext|>


<commit_before>#include <string>
#include <memory>
#include <vector>
#include <map>

#include <folly/futures/Future.h>
#include <folly/futures/Try.h>

#include <folly/Format.h>

#include <glog/logging.h>
#include "gen-cpp2/Relevanced.h"
#include "gen-cpp2/RelevancedProtocol_types.h"
#include "server/ThriftRelevanceServer.h"
#include "server/RelevanceServer.h"
#include "models/Centroid.h"
#include "models/ProcessedDocument.h"

namespace relevanced {
namespace server {

using namespace thrift_protocol;
using models::Centroid;
using models::ProcessedDocument;
using namespace std;
using namespace folly;

ThriftRelevanceServer::ThriftRelevanceServer(
    shared_ptr<RelevanceServerIf> server)
    : server_(server) {}

void ThriftRelevanceServer::ping() { server_->ping(); }

Future<double> ThriftRelevanceServer::future_getDocumentSimilarity(
    unique_ptr<string> centroidId, unique_ptr<string> docId) {
  return server_->getDocumentSimilarity(std::move(centroidId), std::move(docId))
      .then([this](Try<double> result) {
        result.throwIfFailed();
        return result.value();
      });
}

Future<double> ThriftRelevanceServer::future_getTextSimilarity(
    unique_ptr<string> centroidId, unique_ptr<string> text) {
  return server_->getTextSimilarity(std::move(centroidId), std::move(text))
      .then([this](Try<double> result) {
        result.throwIfFailed();
        return result.value();
      });
}

Future<double> ThriftRelevanceServer::future_getCentroidSimilarity(
    unique_ptr<string> centroid1Id, unique_ptr<string> centroid2Id) {
  return server_->getCentroidSimilarity(std::move(centroid1Id),
                                        std::move(centroid2Id))
      .then([this](Try<double> result) {
        result.throwIfFailed();
        return result.value();
      });
}

Future<unique_ptr<MultiSimilarityResponse>>
ThriftRelevanceServer::future_multiGetTextSimilarity(
    unique_ptr<vector<string>> centroidIds, unique_ptr<string> text) {
  return server_->multiGetTextSimilarity(std::move(centroidIds),
                                         std::move(text))
      .then([this](Try<unique_ptr<map<string, double>>> result) {
        result.throwIfFailed();
        auto response = folly::make_unique<MultiSimilarityResponse>();
        map<string, double> scores = *result.value();
        response->scores = std::move(scores);
        return std::move(response);
      });
}

Future<unique_ptr<MultiSimilarityResponse>>
ThriftRelevanceServer::future_multiGetDocumentSimilarity(
    unique_ptr<vector<string>> centroidIds, unique_ptr<string> docId) {
  return server_->multiGetDocumentSimilarity(std::move(centroidIds),
                                         std::move(docId))
      .then([this](Try<unique_ptr<map<string, double>>> result) {
        result.throwIfFailed();
        auto response = folly::make_unique<MultiSimilarityResponse>();
        map<string, double> scores = *result.value();
        response->scores = std::move(scores);
        return std::move(response);
      });
}

Future<unique_ptr<CreateDocumentResponse>>
ThriftRelevanceServer::future_createDocument(unique_ptr<string> text) {
  return server_->createDocument(std::move(text))
      .then([this](Try<unique_ptr<string>> result) {
        result.throwIfFailed();
        auto response = folly::make_unique<CreateDocumentResponse>();
        response->id = *result.value();
        return std::move(response);
      });
}

Future<unique_ptr<CreateDocumentResponse>>
ThriftRelevanceServer::future_createDocumentWithID(unique_ptr<string> id,
                                                   unique_ptr<string> text) {
  string docId = *id;
  return server_->createDocumentWithID(std::move(id), std::move(text))
      .then([this, docId](Try<unique_ptr<string>> result) {
        result.throwIfFailed();
        auto response = folly::make_unique<CreateDocumentResponse>();
        response->id = docId;
        return std::move(response);
      });
}

Future<unique_ptr<DeleteDocumentResponse>>
ThriftRelevanceServer::future_deleteDocument(unique_ptr<string> id) {
  string docId = *id;
  return server_->deleteDocument(std::move(id))
      .then([this, docId](Try<bool> result) {
        result.throwIfFailed();
        auto response = folly::make_unique<DeleteDocumentResponse>();
        response->id = docId;
        return std::move(response);
      });
}

Future<unique_ptr<CreateCentroidResponse>>
ThriftRelevanceServer::future_createCentroid(unique_ptr<string> centroidId) {
  string cId = *centroidId;
  return server_->createCentroid(std::move(centroidId))
      .then([cId](Try<bool> result) {
        result.throwIfFailed();
        auto response = folly::make_unique<CreateCentroidResponse>();
        response->id = cId;
        return std::move(response);
      });
}

Future<unique_ptr<DeleteCentroidResponse>>
ThriftRelevanceServer::future_deleteCentroid(unique_ptr<string> centroidId) {
  string cId = *centroidId;
  return server_->deleteCentroid(std::move(centroidId))
      .then([cId](Try<bool> result) {
        result.throwIfFailed();
        auto response = folly::make_unique<DeleteCentroidResponse>();
        response->id = cId;
        return std::move(response);
      });
}

Future<unique_ptr<ListCentroidDocumentsResponse>>
ThriftRelevanceServer::future_listAllDocumentsForCentroid(
    unique_ptr<string> centroidId) {
  auto cId = *centroidId;
  return server_->listAllDocumentsForCentroid(std::move(centroidId))
      .then([cId](Try<unique_ptr<vector<string>>> result) {
        result.throwIfFailed();
        auto response = folly::make_unique<ListCentroidDocumentsResponse>();
        vector<string> docIds = *result.value();
        response->documents = std::move(docIds);
        return std::move(response);
      });
}

Future<unique_ptr<ListCentroidDocumentsResponse>>
ThriftRelevanceServer::future_listCentroidDocumentRange(
    unique_ptr<string> centroidId, int64_t iOffset, int64_t iCount) {
  size_t offset = iOffset;
  size_t count = iCount;
  return server_->listCentroidDocumentRange(std::move(centroidId), offset, count)
      .then([](Try<unique_ptr<vector<string>>> result) {
        result.throwIfFailed();
        auto response = folly::make_unique<ListCentroidDocumentsResponse>();
        vector<string> docIds = *result.value();
        response->documents = std::move(docIds);
        return std::move(response);
      });
}

Future<unique_ptr<ListCentroidDocumentsResponse>>
ThriftRelevanceServer::future_listCentroidDocumentRangeFromID(
    unique_ptr<string> centroidId, unique_ptr<string> docId, int64_t iCount) {
  size_t count = iCount;
  return server_->listCentroidDocumentRangeFromID(std::move(centroidId), std::move(docId), count)
      .then([](Try<unique_ptr<vector<string>>> result) {
        result.throwIfFailed();
        auto response = folly::make_unique<ListCentroidDocumentsResponse>();
        vector<string> docIds = *result.value();
        response->documents = std::move(docIds);
        return std::move(response);
      });
}

Future<unique_ptr<AddDocumentToCentroidResponse>>
ThriftRelevanceServer::future_addDocumentToCentroid(
    unique_ptr<string> centroidId, unique_ptr<string> docId) {
  auto cId = *centroidId;
  auto dId = *docId;
  return server_->addDocumentToCentroid(std::move(centroidId), std::move(docId))
      .then([cId, dId](Try<bool> result) {
        result.throwIfFailed();
        auto response = folly::make_unique<AddDocumentToCentroidResponse>();
        response->documentId = dId;
        response->centroidId = cId;
        return std::move(response);
      });
}

Future<unique_ptr<RemoveDocumentFromCentroidResponse>>
ThriftRelevanceServer::future_removeDocumentFromCentroid(
    unique_ptr<string> centroidId, unique_ptr<string> docId) {
  auto cId = *centroidId;
  auto dId = *docId;
  return server_->removeDocumentFromCentroid(std::move(centroidId),
                                             std::move(docId))
      .then([cId, dId](Try<bool> result) {
        result.throwIfFailed();
        auto response =
            folly::make_unique<RemoveDocumentFromCentroidResponse>();
        response->documentId = dId;
        response->centroidId = cId;
        return std::move(response);
      });
}

Future<unique_ptr<JoinCentroidResponse>>
ThriftRelevanceServer::future_joinCentroid(unique_ptr<string> centroidId) {
  auto cId = *centroidId;
  return server_->joinCentroid(std::move(centroidId))
      .then([cId](Try<bool> result) {
        result.throwIfFailed();
        auto response = folly::make_unique<JoinCentroidResponse>();
        response->id = cId;
        response->recalculated = result.value();
        return std::move(response);
      });
}

Future<unique_ptr<ListCentroidsResponse>>
ThriftRelevanceServer::future_listAllCentroids() {
  return server_->listAllCentroids().then(
      [](unique_ptr<vector<string>> result) {
        auto response = folly::make_unique<ListCentroidsResponse>();
        response->centroids = *result;
        return std::move(response);
      });
}

Future<unique_ptr<ListCentroidsResponse>>
ThriftRelevanceServer::future_listCentroidRange(int64_t iOffset, int64_t iCount) {
  size_t offset = iOffset;
  size_t count = iCount;
  return server_->listCentroidRange(offset, count).then(
      [](unique_ptr<vector<string>> result) {
        auto response = folly::make_unique<ListCentroidsResponse>();
        response->centroids = *result;
        return std::move(response);
      });
}

Future<unique_ptr<ListCentroidsResponse>>
ThriftRelevanceServer::future_listCentroidRangeFromID(unique_ptr<string> centroidId, int64_t iCount) {
  size_t count = iCount;
  return server_->listCentroidRangeFromID(std::move(centroidId), count).then(
      [](unique_ptr<vector<string>> result) {
        auto response = folly::make_unique<ListCentroidsResponse>();
        response->centroids = *result;
        return std::move(response);
      });
}

Future<unique_ptr<ListDocumentsResponse>>
ThriftRelevanceServer::future_listAllDocuments() {
  return server_->listAllDocuments().then(
      [](unique_ptr<vector<string>> result) {
        auto response = folly::make_unique<ListDocumentsResponse>();
        response->documents = *result;
        return std::move(response);
      });
}

Future<unique_ptr<ListDocumentsResponse>>
ThriftRelevanceServer::future_listDocumentRange(int64_t iOffset, int64_t iCount) {
  size_t offset = iOffset;
  size_t count = iCount;
  return server_->listDocumentRange(offset, count).then(
      [](unique_ptr<vector<string>> result) {
        auto response = folly::make_unique<ListDocumentsResponse>();
        response->documents = *result;
        return std::move(response);
      });
}

Future<unique_ptr<ListDocumentsResponse>>
ThriftRelevanceServer::future_listDocumentRangeFromID(unique_ptr<string> docId, int64_t iCount) {
  size_t count = iCount;
  return server_->listDocumentRangeFromID(std::move(docId), count).then(
      [](unique_ptr<vector<string>> result) {
        auto response = folly::make_unique<ListDocumentsResponse>();
        response->documents = *result;
        return std::move(response);
      });
}

Future<unique_ptr<map<string, string>>>
ThriftRelevanceServer::future_getServerMetadata() {
  return server_->getServerMetadata();
}

Future<folly::Unit>
ThriftRelevanceServer::future_debugEraseAllData() {
  return server_->debugEraseAllData();
}

Future<unique_ptr<CentroidDTO>>
ThriftRelevanceServer::future_debugGetFullCentroid(unique_ptr<string> centroidId) {
  return server_->debugGetFullCentroid(std::move(centroidId)).then([](Try<shared_ptr<Centroid>> result) {
    result.throwIfFailed();
    auto centroid = result.value();
    auto response = folly::make_unique<CentroidDTO>();
    response->id = centroid->id;
    response->wordVector.magnitude = centroid->wordVector.magnitude;
    response->wordVector.documentWeight = centroid->wordVector.documentWeight;
    response->wordVector.scores = centroid->wordVector.scores;
    return std::move(response);
  });
}

Future<unique_ptr<ProcessedDocumentDTO>>
ThriftRelevanceServer::future_debugGetFullProcessedDocument(unique_ptr<string> documentId) {
  return server_->debugGetFullProcessedDocument(std::move(documentId)).then([](Try<shared_ptr<ProcessedDocument>> result) {
    result.throwIfFailed();
    auto document = result.value();
    auto response = folly::make_unique<ProcessedDocumentDTO>();
    response->metadata.id = document->id;
    response->metadata.created = document->created;
    response->metadata.updated = document->updated;
    if (document->sha1Hash.hasValue()) {
      response->metadata.sha1Hash = document->sha1Hash.value();
    }
    response->wordVector.magnitude = document->magnitude;
    for (auto &elem: document->scoredWords) {
      string k = elem.word;
      response->wordVector.scores[k] = elem.score;
    }
    // response->wordVector.documentWeight = document->wordVector.documentWeight;
    // response->wordVector.scores = document->wordVector.scores;
    return std::move(response);
  });
}

} // server
} // relevanced
<commit_msg>dead code<commit_after>#include <string>
#include <memory>
#include <vector>
#include <map>

#include <folly/futures/Future.h>
#include <folly/futures/Try.h>

#include <folly/Format.h>

#include <glog/logging.h>
#include "gen-cpp2/Relevanced.h"
#include "gen-cpp2/RelevancedProtocol_types.h"
#include "server/ThriftRelevanceServer.h"
#include "server/RelevanceServer.h"
#include "models/Centroid.h"
#include "models/ProcessedDocument.h"

namespace relevanced {
namespace server {

using namespace thrift_protocol;
using models::Centroid;
using models::ProcessedDocument;
using namespace std;
using namespace folly;

ThriftRelevanceServer::ThriftRelevanceServer(
    shared_ptr<RelevanceServerIf> server)
    : server_(server) {}

void ThriftRelevanceServer::ping() { server_->ping(); }

Future<double> ThriftRelevanceServer::future_getDocumentSimilarity(
    unique_ptr<string> centroidId, unique_ptr<string> docId) {
  return server_->getDocumentSimilarity(std::move(centroidId), std::move(docId))
      .then([this](Try<double> result) {
        result.throwIfFailed();
        return result.value();
      });
}

Future<double> ThriftRelevanceServer::future_getTextSimilarity(
    unique_ptr<string> centroidId, unique_ptr<string> text) {
  return server_->getTextSimilarity(std::move(centroidId), std::move(text))
      .then([this](Try<double> result) {
        result.throwIfFailed();
        return result.value();
      });
}

Future<double> ThriftRelevanceServer::future_getCentroidSimilarity(
    unique_ptr<string> centroid1Id, unique_ptr<string> centroid2Id) {
  return server_->getCentroidSimilarity(std::move(centroid1Id),
                                        std::move(centroid2Id))
      .then([this](Try<double> result) {
        result.throwIfFailed();
        return result.value();
      });
}

Future<unique_ptr<MultiSimilarityResponse>>
ThriftRelevanceServer::future_multiGetTextSimilarity(
    unique_ptr<vector<string>> centroidIds, unique_ptr<string> text) {
  return server_->multiGetTextSimilarity(std::move(centroidIds),
                                         std::move(text))
      .then([this](Try<unique_ptr<map<string, double>>> result) {
        result.throwIfFailed();
        auto response = folly::make_unique<MultiSimilarityResponse>();
        map<string, double> scores = *result.value();
        response->scores = std::move(scores);
        return std::move(response);
      });
}

Future<unique_ptr<MultiSimilarityResponse>>
ThriftRelevanceServer::future_multiGetDocumentSimilarity(
    unique_ptr<vector<string>> centroidIds, unique_ptr<string> docId) {
  return server_->multiGetDocumentSimilarity(std::move(centroidIds),
                                         std::move(docId))
      .then([this](Try<unique_ptr<map<string, double>>> result) {
        result.throwIfFailed();
        auto response = folly::make_unique<MultiSimilarityResponse>();
        map<string, double> scores = *result.value();
        response->scores = std::move(scores);
        return std::move(response);
      });
}

Future<unique_ptr<CreateDocumentResponse>>
ThriftRelevanceServer::future_createDocument(unique_ptr<string> text) {
  return server_->createDocument(std::move(text))
      .then([this](Try<unique_ptr<string>> result) {
        result.throwIfFailed();
        auto response = folly::make_unique<CreateDocumentResponse>();
        response->id = *result.value();
        return std::move(response);
      });
}

Future<unique_ptr<CreateDocumentResponse>>
ThriftRelevanceServer::future_createDocumentWithID(unique_ptr<string> id,
                                                   unique_ptr<string> text) {
  string docId = *id;
  return server_->createDocumentWithID(std::move(id), std::move(text))
      .then([this, docId](Try<unique_ptr<string>> result) {
        result.throwIfFailed();
        auto response = folly::make_unique<CreateDocumentResponse>();
        response->id = docId;
        return std::move(response);
      });
}

Future<unique_ptr<DeleteDocumentResponse>>
ThriftRelevanceServer::future_deleteDocument(unique_ptr<string> id) {
  string docId = *id;
  return server_->deleteDocument(std::move(id))
      .then([this, docId](Try<bool> result) {
        result.throwIfFailed();
        auto response = folly::make_unique<DeleteDocumentResponse>();
        response->id = docId;
        return std::move(response);
      });
}

Future<unique_ptr<CreateCentroidResponse>>
ThriftRelevanceServer::future_createCentroid(unique_ptr<string> centroidId) {
  string cId = *centroidId;
  return server_->createCentroid(std::move(centroidId))
      .then([cId](Try<bool> result) {
        result.throwIfFailed();
        auto response = folly::make_unique<CreateCentroidResponse>();
        response->id = cId;
        return std::move(response);
      });
}

Future<unique_ptr<DeleteCentroidResponse>>
ThriftRelevanceServer::future_deleteCentroid(unique_ptr<string> centroidId) {
  string cId = *centroidId;
  return server_->deleteCentroid(std::move(centroidId))
      .then([cId](Try<bool> result) {
        result.throwIfFailed();
        auto response = folly::make_unique<DeleteCentroidResponse>();
        response->id = cId;
        return std::move(response);
      });
}

Future<unique_ptr<ListCentroidDocumentsResponse>>
ThriftRelevanceServer::future_listAllDocumentsForCentroid(
    unique_ptr<string> centroidId) {
  auto cId = *centroidId;
  return server_->listAllDocumentsForCentroid(std::move(centroidId))
      .then([cId](Try<unique_ptr<vector<string>>> result) {
        result.throwIfFailed();
        auto response = folly::make_unique<ListCentroidDocumentsResponse>();
        vector<string> docIds = *result.value();
        response->documents = std::move(docIds);
        return std::move(response);
      });
}

Future<unique_ptr<ListCentroidDocumentsResponse>>
ThriftRelevanceServer::future_listCentroidDocumentRange(
    unique_ptr<string> centroidId, int64_t iOffset, int64_t iCount) {
  size_t offset = iOffset;
  size_t count = iCount;
  return server_->listCentroidDocumentRange(std::move(centroidId), offset, count)
      .then([](Try<unique_ptr<vector<string>>> result) {
        result.throwIfFailed();
        auto response = folly::make_unique<ListCentroidDocumentsResponse>();
        vector<string> docIds = *result.value();
        response->documents = std::move(docIds);
        return std::move(response);
      });
}

Future<unique_ptr<ListCentroidDocumentsResponse>>
ThriftRelevanceServer::future_listCentroidDocumentRangeFromID(
    unique_ptr<string> centroidId, unique_ptr<string> docId, int64_t iCount) {
  size_t count = iCount;
  return server_->listCentroidDocumentRangeFromID(std::move(centroidId), std::move(docId), count)
      .then([](Try<unique_ptr<vector<string>>> result) {
        result.throwIfFailed();
        auto response = folly::make_unique<ListCentroidDocumentsResponse>();
        vector<string> docIds = *result.value();
        response->documents = std::move(docIds);
        return std::move(response);
      });
}

Future<unique_ptr<AddDocumentToCentroidResponse>>
ThriftRelevanceServer::future_addDocumentToCentroid(
    unique_ptr<string> centroidId, unique_ptr<string> docId) {
  auto cId = *centroidId;
  auto dId = *docId;
  return server_->addDocumentToCentroid(std::move(centroidId), std::move(docId))
      .then([cId, dId](Try<bool> result) {
        result.throwIfFailed();
        auto response = folly::make_unique<AddDocumentToCentroidResponse>();
        response->documentId = dId;
        response->centroidId = cId;
        return std::move(response);
      });
}

Future<unique_ptr<RemoveDocumentFromCentroidResponse>>
ThriftRelevanceServer::future_removeDocumentFromCentroid(
    unique_ptr<string> centroidId, unique_ptr<string> docId) {
  auto cId = *centroidId;
  auto dId = *docId;
  return server_->removeDocumentFromCentroid(std::move(centroidId),
                                             std::move(docId))
      .then([cId, dId](Try<bool> result) {
        result.throwIfFailed();
        auto response =
            folly::make_unique<RemoveDocumentFromCentroidResponse>();
        response->documentId = dId;
        response->centroidId = cId;
        return std::move(response);
      });
}

Future<unique_ptr<JoinCentroidResponse>>
ThriftRelevanceServer::future_joinCentroid(unique_ptr<string> centroidId) {
  auto cId = *centroidId;
  return server_->joinCentroid(std::move(centroidId))
      .then([cId](Try<bool> result) {
        result.throwIfFailed();
        auto response = folly::make_unique<JoinCentroidResponse>();
        response->id = cId;
        response->recalculated = result.value();
        return std::move(response);
      });
}

Future<unique_ptr<ListCentroidsResponse>>
ThriftRelevanceServer::future_listAllCentroids() {
  return server_->listAllCentroids().then(
      [](unique_ptr<vector<string>> result) {
        auto response = folly::make_unique<ListCentroidsResponse>();
        response->centroids = *result;
        return std::move(response);
      });
}

Future<unique_ptr<ListCentroidsResponse>>
ThriftRelevanceServer::future_listCentroidRange(int64_t iOffset, int64_t iCount) {
  size_t offset = iOffset;
  size_t count = iCount;
  return server_->listCentroidRange(offset, count).then(
      [](unique_ptr<vector<string>> result) {
        auto response = folly::make_unique<ListCentroidsResponse>();
        response->centroids = *result;
        return std::move(response);
      });
}

Future<unique_ptr<ListCentroidsResponse>>
ThriftRelevanceServer::future_listCentroidRangeFromID(unique_ptr<string> centroidId, int64_t iCount) {
  size_t count = iCount;
  return server_->listCentroidRangeFromID(std::move(centroidId), count).then(
      [](unique_ptr<vector<string>> result) {
        auto response = folly::make_unique<ListCentroidsResponse>();
        response->centroids = *result;
        return std::move(response);
      });
}

Future<unique_ptr<ListDocumentsResponse>>
ThriftRelevanceServer::future_listAllDocuments() {
  return server_->listAllDocuments().then(
      [](unique_ptr<vector<string>> result) {
        auto response = folly::make_unique<ListDocumentsResponse>();
        response->documents = *result;
        return std::move(response);
      });
}

Future<unique_ptr<ListDocumentsResponse>>
ThriftRelevanceServer::future_listDocumentRange(int64_t iOffset, int64_t iCount) {
  size_t offset = iOffset;
  size_t count = iCount;
  return server_->listDocumentRange(offset, count).then(
      [](unique_ptr<vector<string>> result) {
        auto response = folly::make_unique<ListDocumentsResponse>();
        response->documents = *result;
        return std::move(response);
      });
}

Future<unique_ptr<ListDocumentsResponse>>
ThriftRelevanceServer::future_listDocumentRangeFromID(unique_ptr<string> docId, int64_t iCount) {
  size_t count = iCount;
  return server_->listDocumentRangeFromID(std::move(docId), count).then(
      [](unique_ptr<vector<string>> result) {
        auto response = folly::make_unique<ListDocumentsResponse>();
        response->documents = *result;
        return std::move(response);
      });
}

Future<unique_ptr<map<string, string>>>
ThriftRelevanceServer::future_getServerMetadata() {
  return server_->getServerMetadata();
}

Future<folly::Unit>
ThriftRelevanceServer::future_debugEraseAllData() {
  return server_->debugEraseAllData();
}

Future<unique_ptr<CentroidDTO>>
ThriftRelevanceServer::future_debugGetFullCentroid(unique_ptr<string> centroidId) {
  return server_->debugGetFullCentroid(std::move(centroidId)).then([](Try<shared_ptr<Centroid>> result) {
    result.throwIfFailed();
    auto centroid = result.value();
    auto response = folly::make_unique<CentroidDTO>();
    response->id = centroid->id;
    response->wordVector.magnitude = centroid->wordVector.magnitude;
    response->wordVector.documentWeight = centroid->wordVector.documentWeight;
    response->wordVector.scores = centroid->wordVector.scores;
    return std::move(response);
  });
}

Future<unique_ptr<ProcessedDocumentDTO>>
ThriftRelevanceServer::future_debugGetFullProcessedDocument(unique_ptr<string> documentId) {
  return server_->debugGetFullProcessedDocument(std::move(documentId)).then([](Try<shared_ptr<ProcessedDocument>> result) {
    result.throwIfFailed();
    auto document = result.value();
    auto response = folly::make_unique<ProcessedDocumentDTO>();
    response->metadata.id = document->id;
    response->metadata.created = document->created;
    response->metadata.updated = document->updated;
    if (document->sha1Hash.hasValue()) {
      response->metadata.sha1Hash = document->sha1Hash.value();
    }
    response->wordVector.magnitude = document->magnitude;
    for (auto &elem: document->scoredWords) {
      string k = elem.word;
      response->wordVector.scores[k] = elem.score;
    }
    return std::move(response);
  });
}

} // server
} // relevanced
<|endoftext|>


<commit_before>#include "stoptasksdialog.h"

WARNINGS_DISABLE
#include <QAction>
#include <QMenu>
#include <QPushButton>
WARNINGS_ENABLE

StopTasksDialog::StopTasksDialog(QWidget *parent)
    : QMessageBox(parent),
      _actionButton(new QPushButton(this)),
      _actionMenu(new QMenu(_actionButton)),
      _cancelButton(nullptr)
{
    // Set up text.
    setInformativeText(tr("What do you want to do?"));
    _actionButton->setText(tr("Choose action"));

    // Set up menu.
    _actionButton->setMenu(_actionMenu);
    addButton(_actionButton, QMessageBox::ActionRole);

    // Set up processing the result.
    connect(this, &QMessageBox::finished, this,
            &StopTasksDialog::processResult);
}

void StopTasksDialog::display(bool backupTaskRunning, int runningTasks,
                              int queuedTasks, bool aboutToQuit)
{
    _aboutToQuit = aboutToQuit;

    // Overall setup.
    setText(tr("There are %1 running tasks and %2 queued.")
                .arg(runningTasks)
                .arg(queuedTasks));
    _actionMenu->clear();

    // Ensure that we have a new cancel button, to avoid
    // clickedButton() carrying over from the previous display().
    QPushButton *cancel_orig = _cancelButton;
    if(_cancelButton != nullptr)
        removeButton(_cancelButton);
    _cancelButton = addButton(QMessageBox::Cancel);
    setDefaultButton(_cancelButton);
    if(cancel_orig != nullptr)
        delete cancel_orig;

    // interrupt
    _interruptBackup = nullptr;
    if(backupTaskRunning)
    {
        if(_aboutToQuit)
            _interruptBackup =
                _actionMenu->addAction(tr("Interrupt backup and clear queue"));
        else
            _interruptBackup = _actionMenu->addAction(tr("Interrupt backup"));
        _interruptBackup->setCheckable(true);
        connect(_interruptBackup, &QAction::triggered, this, &QDialog::accept,
                Qt::QueuedConnection);
    }
    // stopRunning
    _stopRunning = nullptr;
    if(runningTasks && !_aboutToQuit)
    {
        _stopRunning = _actionMenu->addAction(tr("Stop running"));
        _stopRunning->setCheckable(true);
        connect(_stopRunning, &QAction::triggered, this, &QDialog::accept,
                Qt::QueuedConnection);
    }
    // stopQueued
    _stopQueued = nullptr;
    if(queuedTasks && !_aboutToQuit)
    {
        _stopQueued = _actionMenu->addAction(tr("Cancel queued"));
        _stopQueued->setCheckable(true);
        connect(_stopQueued, &QAction::triggered, this, &QDialog::accept,
                Qt::QueuedConnection);
    }
    // stopAll
    _stopAll = nullptr;
    if(runningTasks || queuedTasks)
    {
        _stopAll = _actionMenu->addAction(tr("Stop all"));
        _stopAll->setCheckable(true);
        connect(_stopAll, &QAction::triggered, this, &QDialog::accept,
                Qt::QueuedConnection);
    }
    // proceedBackground
    _proceedBackground = nullptr;
    if((runningTasks || queuedTasks) && _aboutToQuit)
    {
        _proceedBackground =
            _actionMenu->addAction(tr("Proceed in background"));
        _proceedBackground->setCheckable(true);
        connect(_proceedBackground, &QAction::triggered, this, &QDialog::accept,
                Qt::QueuedConnection);
    }

    // Launch dialog.
    open();
}

void StopTasksDialog::processResult(int res)
{
    // Keep 'res' name to avoid shadowing QDialog::result().

    // Bail (if applicable).
    // QMessageBox::finished() is not documented as diverging from
    // QDialog::finished().  However, it does differ, similar to
    // QMessageBox::exec() -- it can return a QMessageBox::StandardButton
    // value.  That said, if the QMessageBox is closed with an
    // ->accept(), ->reject(), or ->close(), it will still provide a
    // QDialog::Accepted or QDialog::Rejected.
    if((res != QDialog::Accepted) || (clickedButton() == _cancelButton))
    {
        if(_aboutToQuit)
        {
            _aboutToQuit = false;
            emit cancelAboutToQuit();
        }
        return;
    }

    // Signal that we can quit now.
    if(_aboutToQuit)
    {
        emit quitOk();
    }

    // Stop tasks.
    if(_interruptBackup && _interruptBackup->isChecked())
        emit stopTasks(true, false, _aboutToQuit);
    else if(_stopQueued && _stopQueued->isChecked())
        emit stopTasks(false, false, true);
    else if(_stopRunning && _stopRunning->isChecked())
        emit stopTasks(false, true, false);
    else if(_stopAll && _stopAll->isChecked())
        emit stopTasks(false, true, true);
    else if(_proceedBackground && _proceedBackground->isChecked())
    {
        // Do nothing; it will happen due to code elsewhere
    }
}
<commit_msg>StopTasksDialog: sanity check<commit_after>#include "stoptasksdialog.h"

WARNINGS_DISABLE
#include <QAction>
#include <QMenu>
#include <QPushButton>
WARNINGS_ENABLE

StopTasksDialog::StopTasksDialog(QWidget *parent)
    : QMessageBox(parent),
      _actionButton(new QPushButton(this)),
      _actionMenu(new QMenu(_actionButton)),
      _cancelButton(nullptr)
{
    // Set up text.
    setInformativeText(tr("What do you want to do?"));
    _actionButton->setText(tr("Choose action"));

    // Set up menu.
    _actionButton->setMenu(_actionMenu);
    addButton(_actionButton, QMessageBox::ActionRole);

    // Set up processing the result.
    connect(this, &QMessageBox::finished, this,
            &StopTasksDialog::processResult);
}

void StopTasksDialog::display(bool backupTaskRunning, int runningTasks,
                              int queuedTasks, bool aboutToQuit)
{
    _aboutToQuit = aboutToQuit;

    // Sanity check.
    Q_ASSERT((runningTasks > 0) || (queuedTasks > 0));

    // Overall setup.
    setText(tr("There are %1 running tasks and %2 queued.")
                .arg(runningTasks)
                .arg(queuedTasks));
    _actionMenu->clear();

    // Ensure that we have a new cancel button, to avoid
    // clickedButton() carrying over from the previous display().
    QPushButton *cancel_orig = _cancelButton;
    if(_cancelButton != nullptr)
        removeButton(_cancelButton);
    _cancelButton = addButton(QMessageBox::Cancel);
    setDefaultButton(_cancelButton);
    if(cancel_orig != nullptr)
        delete cancel_orig;

    // interrupt
    _interruptBackup = nullptr;
    if(backupTaskRunning)
    {
        if(_aboutToQuit)
            _interruptBackup =
                _actionMenu->addAction(tr("Interrupt backup and clear queue"));
        else
            _interruptBackup = _actionMenu->addAction(tr("Interrupt backup"));
        _interruptBackup->setCheckable(true);
        connect(_interruptBackup, &QAction::triggered, this, &QDialog::accept,
                Qt::QueuedConnection);
    }
    // stopRunning
    _stopRunning = nullptr;
    if(runningTasks && !_aboutToQuit)
    {
        _stopRunning = _actionMenu->addAction(tr("Stop running"));
        _stopRunning->setCheckable(true);
        connect(_stopRunning, &QAction::triggered, this, &QDialog::accept,
                Qt::QueuedConnection);
    }
    // stopQueued
    _stopQueued = nullptr;
    if(queuedTasks && !_aboutToQuit)
    {
        _stopQueued = _actionMenu->addAction(tr("Cancel queued"));
        _stopQueued->setCheckable(true);
        connect(_stopQueued, &QAction::triggered, this, &QDialog::accept,
                Qt::QueuedConnection);
    }
    // stopAll
    _stopAll = nullptr;
    if(runningTasks || queuedTasks)
    {
        _stopAll = _actionMenu->addAction(tr("Stop all"));
        _stopAll->setCheckable(true);
        connect(_stopAll, &QAction::triggered, this, &QDialog::accept,
                Qt::QueuedConnection);
    }
    // proceedBackground
    _proceedBackground = nullptr;
    if((runningTasks || queuedTasks) && _aboutToQuit)
    {
        _proceedBackground =
            _actionMenu->addAction(tr("Proceed in background"));
        _proceedBackground->setCheckable(true);
        connect(_proceedBackground, &QAction::triggered, this, &QDialog::accept,
                Qt::QueuedConnection);
    }

    // Launch dialog.
    open();
}

void StopTasksDialog::processResult(int res)
{
    // Keep 'res' name to avoid shadowing QDialog::result().

    // Bail (if applicable).
    // QMessageBox::finished() is not documented as diverging from
    // QDialog::finished().  However, it does differ, similar to
    // QMessageBox::exec() -- it can return a QMessageBox::StandardButton
    // value.  That said, if the QMessageBox is closed with an
    // ->accept(), ->reject(), or ->close(), it will still provide a
    // QDialog::Accepted or QDialog::Rejected.
    if((res != QDialog::Accepted) || (clickedButton() == _cancelButton))
    {
        if(_aboutToQuit)
        {
            _aboutToQuit = false;
            emit cancelAboutToQuit();
        }
        return;
    }

    // Signal that we can quit now.
    if(_aboutToQuit)
    {
        emit quitOk();
    }

    // Stop tasks.
    if(_interruptBackup && _interruptBackup->isChecked())
        emit stopTasks(true, false, _aboutToQuit);
    else if(_stopQueued && _stopQueued->isChecked())
        emit stopTasks(false, false, true);
    else if(_stopRunning && _stopRunning->isChecked())
        emit stopTasks(false, true, false);
    else if(_stopAll && _stopAll->isChecked())
        emit stopTasks(false, true, true);
    else if(_proceedBackground && _proceedBackground->isChecked())
    {
        // Do nothing; it will happen due to code elsewhere
    }
}
<|endoftext|>