<commit_before>#include <ast/all.hh>
#include <ast/new-clone.hh>
#include <ast/parametric-ast.hh>
#include <object/symbols.hh>
#include <parser/ast-factory.hh>
#include <parser/event-match.hh>
#include <parser/parse.hh>
#include <parser/parse-result.hh>
#include <rewrite/pattern-binder.hh>
#include <rewrite/rewrite.hh>

namespace std
{
  ostream&
  operator<< (ostream& o, const parser::case_type& c)
  {
    return o << "/* " << (const void*) &c << " */ "
             << "case "
             << libport::deref << c.first
             << " => "
             << libport::deref << c.second;
  }

  ostream&
  operator<< (ostream& o, const parser::cases_type& cs)
  {
    o << "/* " << (const void*) &cs << " */ "
      << "{" << endl;
    foreach (const parser::case_type& c, cs)
      o << "  " << c << endl;
    return o << "}";
  }

}

namespace parser
{
  ast::rExp
  ast_at(const yy::location& loc,
         ast::rExp cond,
         ast::rExp body, ast::rExp onleave,
         ast::rExp duration)
  {
    if (!onleave)
      onleave = new ast::Noop(loc, 0);

    if (duration)
    {
      PARAMETRIC_AST(desugar,
                     "var '$at' = persist(%exp:1, %exp:2) |"
                     "at ('$at') %exp:3 onleave %exp:4");

      return exp(desugar % cond % duration % body % onleave);
    }
    else
    {
      PARAMETRIC_AST(desugar,
        "Control.at_(%exp:1, detach(%exp:2), detach(%exp:3))");

      return exp(desugar % cond % body % onleave);
    }
  }

  ast::rExp
  ast_event_catcher(const ast::loc& loc,
                    EventMatch& event,
                    ast::rExp body, ast::rExp onleave)
  {
    if (onleave)
    {
      PARAMETRIC_AST(a, "%exp:1 | %exp:2");
      body = exp(a % body % onleave);
    }

    if (event.guard)
    {
      PARAMETRIC_AST(desugar_guard,
                     "if (%exp:1) %exp:2;");
      body = exp(desugar_guard % event.guard % body);
    }

    if (event.pattern)
    {
      ast::rExp pattern = new ast::List(loc, event.pattern);
      rewrite::PatternBinder bind(ast_call(loc, SYMBOL(DOLLAR_pattern)), loc);
      bind(pattern.get());
      PARAMETRIC_AST(desugar,
                     "detach("
                     "{"
                     "  %exp:1.onEvent("
                     "  closure ('$evt')"
                     "  {"
                     "    var '$pattern' = Pattern.new(%exp:2) |"
                     "    if ('$pattern'.match('$evt'.payload))"
                     "    {"
                     "      %exp: 3 |"
                     "      %exp: 4 |"
                     "    }"
                     "  })"
                     "})");
      return exp(desugar
                 % event.event
                 % bind.result_get().unchecked_cast<ast::Exp>()
                 % bind.bindings_get()
                 % body);
    }
    else
    {
      PARAMETRIC_AST(desugar_no_pattern,
                     "detach("
                     "{"
                     "  %exp:1.onEvent(closure ('$evt')"
                     "  {"
                     "    %exp: 2 |"
                     "  })"
                     "})");
      return exp(desugar_no_pattern % event.event % body);
    }
  }

  ast::rExp
  ast_at_event(const ast::loc& loc,
               EventMatch& event,
               ast::rExp body, ast::rExp onleave)
  {
    PARAMETRIC_AST(desugar_body,
                   "%exp:1 |"
                   "waituntil(!'$evt'.active)");
    body = exp(desugar_body % body);
    return ast_event_catcher(loc, event, body, onleave);
  }

  /// Create a new Tree node composing \c Lhs and \c Rhs with \c Op.
  /// \param op must be & or |.
  ast::rExp
  ast_bin(const yy::location& l,
          ast::flavor_type op, ast::rExp lhs, ast::rExp rhs)
  {
    ast::rExp res = 0;
    assert (lhs);
    assert (rhs);
    switch (op)
    {
    case ast::flavor_pipe:
    {
      ast::rPipe pipe;
      if (pipe = lhs.unsafe_cast<ast::Pipe>())
        pipe->children_get().push_back(rhs);
      else
      {
        pipe = new ast::Pipe(l, ast::exps_type());
        pipe->children_get().push_back(lhs);
        pipe->children_get().push_back(rhs);
      }
      res = pipe;
      break;
    }
    case ast::flavor_and:
    {
      ast::rAnd rand;
      if (rand = lhs.unsafe_cast<ast::And>())
        rand->children_get().push_back(rhs);
      else
      {
        rand = new ast::And(l, ast::exps_type());
        rand->children_get().push_back(lhs);
        rand->children_get().push_back(rhs);
      }
      res = rand;
      break;
    }
    case ast::flavor_comma:
    case ast::flavor_semicolon:
    {
      ast::rNary nary = new ast::Nary(l);
      nary->push_back(lhs, op);
      nary->push_back(rhs);
      res = nary;
      break;
    }
    case ast::flavor_none:
      pabort(op);
    }
    return res;
  }

  /// "<method> (args)".
  ast::rCall
  ast_call (const yy::location& l,
            libport::Symbol method)
  {
    return ast_call(l, new ast::Implicit(l), method);
  }

  /// "<target> . <method> (args)".
  ast::rCall
  ast_call(const yy::location& l,
           ast::rExp target, libport::Symbol method, ast::exps_type* args)
  {
    return new ast::Call(l, args, target, method);
  }

  /// "<target> . <method> ()".
  ast::rCall
  ast_call(const yy::location& l, ast::rExp target, libport::Symbol method)
  {
    return ast_call(l, target, method, 0);
  }

  /// "<target> . <method> (<arg1>)".
  ast::rCall
  ast_call(const yy::location& l,
           ast::rExp target, libport::Symbol method, ast::rExp arg1)
  {
    ast::rCall res = ast_call(l, target, method, new ast::exps_type);
    res->arguments_get()->push_back(arg1);
    return res;
  }

  /// "<target> . <method> (<arg1>, <arg2>)".
  /// "<target> . <method> (<arg1>, <arg2>, <arg3>)".
  ast::rCall
  ast_call(const yy::location& l,
           ast::rExp target, libport::Symbol method,
           ast::rExp arg1, ast::rExp arg2, ast::rExp arg3)
  {
    ast::rCall res = ast_call(l, target, method, new ast::exps_type);
    res->arguments_get()->push_back(arg1);
    res->arguments_get()->push_back(arg2);
    if (arg3)
      res->arguments_get()->push_back(arg3);
    return res;
  }

  ast::rExp
  ast_closure(ast::rExp value)
  {
    PARAMETRIC_AST(a, "closure () { %exp:1 }");
    return exp(a % value);
  }

  /// Build a for loop.
  // The increment is included directly in the condition to make sure
  // it is executed on `continue'.
  ast::rExp
  ast_for(const yy::location&, ast::flavor_type,
          ast::rExp init, ast::rExp test, ast::rExp inc,
          ast::rExp body)
  {
    // FIXME: for| is handled as a simple for
    PARAMETRIC_AST(desugar,
      "{"
      "  %exp:1 |"
      "  var '$tmp-for-first' = true |"
      "  while ({ if ('$tmp-for-first') '$tmp-for-first' = false else %exp:2 | %exp:3})"
      "    %exp:4 |"
      "}"
      );
    return exp(desugar % init % inc % test % body);
  }

  ast::rExp
  ast_if(const yy::location& l,
         ast::rExp cond, ast::rExp iftrue, ast::rExp iffalse)
  {
    return new ast::If(l, ast_strip(cond),
                       ast_scope(l, iftrue),
		       iffalse ? ast_scope(l, iffalse) : new ast::Noop(l, 0));
  }

  ast::rLValue
  ast_lvalue_once(const ast::rLValue& lvalue)
  {
    ast::rCall tmp = ast_call(lvalue->location_get(), SYMBOL(DOLLAR_tmp));

    if (lvalue->call()->target_implicit())
      return lvalue.get();
    else
      return ast_call(lvalue->location_get(), tmp, lvalue->call()->name_get());
  }

  ast::rExp
  ast_lvalue_wrap(const ast::rLValue& lvalue, const ast::rExp& e)
  {
    PARAMETRIC_AST(wrap,
                   "{"
                   "var '$tmp' = %exp:1;"
                   "%exp:2;"
                   "}"
      );

    if (lvalue->call()->target_implicit())
      return e;
    else
    {
      wrap % lvalue->call()->target_get() % e;
      return exp(wrap);
    }
  }

  ast::rExp
  ast_nil()
  {
    PARAMETRIC_AST(nil, "nil");
    return exp(nil);
  }

  /// Return \a e in a ast::Scope unless it is already one.
  ast::rScope
  ast_scope(const yy::location& l, ast::rExp target, ast::rExp e)
  {
    if (ast::rScope res = e.unsafe_cast<ast::Scope>())
      return res;
    else if (target)
      return new ast::Do(l, e, target);
    else
      return new ast::Scope(l, e);
  }

  ast::rScope
  ast_scope(const yy::location& l, ast::rExp e)
  {
    return ast_scope(l, 0, e);
  }

  ast::rExp
  ast_string(const yy::location& l, libport::Symbol s)
  {
    return new ast::String(l, s);
  }

  /*------------.
  | ast_strip.  |
  `------------*/

  ast::rExp
  ast_strip(ast::rNary nary)
  {
    ast::rExp res = nary;
    // Remove useless nary and statement if there's only one child.
    if (nary->children_get().size() == 1)
      res = (nary->children_get().front()
             .unchecked_cast<ast::Stmt>()
             ->expression_get());
    return res;
  }

  ast::rExp
  ast_strip(ast::rExp e)
  {
    if (ast::rNary nary = e.unsafe_cast<ast::Nary>())
      return ast_strip(nary);
    else
      return e;
  }

  ast::rExp
  ast_switch(const yy::location&, ast::rExp cond,
             const cases_type& cases, ast::rExp def)
  {
    const ast::loc& loc = cond->location_get();
    ast::rExp inner = def ? def : ast_nil();
    rforeach (const case_type& c, cases)
    {
      PARAMETRIC_AST(desugar,
                     "var '$pattern' = Pattern.new(%exp:1) |"
                     "if (if ('$pattern'.match('$switch'))"
                     "    {"
                     "      %exp:2 |"
                     "      %exp:3"
                     "    }"
                     "    else"
                     "      false)"
                     "{"
                     "  %exp:4 |"
                     "  %exp:5"
                     "}"
                     "else"
                     "  %exp:6"
        );

      PARAMETRIC_AST(cond,
                     "true");

      ast::rExp condition = c.first->guard_get();
      if (!condition)
        condition = exp(cond);

      rewrite::PatternBinder bind(ast_call(loc, SYMBOL(DOLLAR_pattern)), loc);
      bind(c.first->pattern_get().get());

      desugar
        % bind.result_get().unchecked_cast<ast::Exp>()
        % bind.bindings_get()
        % condition
        % bind.bindings_get()
        % c.second
        % inner;
      inner = ast::exp(desugar);
    }

    PARAMETRIC_AST(sw, "{ var '$switch' = %exp:1 | %exp:2 }");
    return exp(sw % cond % inner);
  }

  ast::rExp
  ast_timeout(const ast::rExp& duration, const ast::rExp& body)
  {
    PARAMETRIC_AST(desugar,
		   "{"
		   " var '$tag' = Tag.new |"
		   " '$tag':"
		   "   {"
		   "      {"
		   "        sleep(%exp:1) | '$tag'.stop"
		   "      },"
		   "     %exp:2 | '$tag'.stop"
		   "   }"
		   "}");
    return exp(desugar % duration % body);
  }

  ast::rExp
  ast_waituntil(const yy::location&,
                const ast::rExp& cond, ast::rExp duration)
  {
    if (duration)
    {
      PARAMETRIC_AST(desugar,
        "{"
        "  var '$waituntil' = persist(%exp:1, %exp:2) |"
        "  waituntil('$waituntil'())"
        "}"
        );
      return exp(desugar % cond % duration);
    }
    else
    {
      PARAMETRIC_AST(desugar,
                     "{var '$tag' = Tag.new |"
                     "'$tag': {at (%exp:1) '$tag'.stop | sleep(inf)}}");
      return exp(desugar % cond);
    }
  }

  ast::rExp
  ast_waituntil_event(const ast::loc& loc,
                      ast::rExp event,
                      ast::exps_type* payload)
  {
    if (!payload)
    {
      PARAMETRIC_AST
        (desugar,
         "  %exp:1.'waituntil'(nil)");
      return exp(desugar % event);
    }

    PARAMETRIC_AST
      (desugar,
       "{"
       "  var '$pattern' = Pattern.new(%exp:1) |"
       "  %exp:2.'waituntil'('$pattern') |"
       "  {"
       "    %unscope: 2 |"
       "    %exp:3 |"
       "  }"
       "}");

    ast::rList d_payload = new ast::List(loc, payload);

    rewrite::PatternBinder bind(ast_call(loc, SYMBOL(DOLLAR_pattern)), loc);
    bind(d_payload.get());

    return exp(desugar
               % bind.result_get().unchecked_cast<ast::Exp>()
               % event
               % bind.bindings_get());
  }

  ast::rExp
  ast_whenever_event(const ast::loc& loc,
                     EventMatch& event,
                     ast::rExp body, ast::rExp onleave)
  {
    PARAMETRIC_AST(desugar_body,
                   "while (true)"
                   "{"
                   "  %exp:1 |"
                   "  if(!'$evt'.active)"
                   "    break"
                   "}");
    body = exp(desugar_body % body);
    return ast_event_catcher(loc, event, body, onleave);
  }

  ast::rExp
  ast_whenever(const yy::location&,
               ast::rExp cond,
               ast::rExp body, ast::rExp else_stmt,
               ast::rExp duration)
  {
    // FIXME: Be smarter on empty else_stmt.
    if (!else_stmt)
      else_stmt = ast_nil();
    if (duration)
    {
      PARAMETRIC_AST(desugar,
        "var '$whenever' = persist(%exp:1, %exp:2) |"
        "Control.whenever_('$whenever'.val, %exp:3, %exp:4) |'"
        );
      return exp(desugar % cond % duration % body % else_stmt);
    }
    else
    {
      PARAMETRIC_AST(desugar,
        "Control.whenever_(%exp:1, %exp:2, %exp:3)");
      return exp(desugar % cond % body % else_stmt);
    }
  }

}
<commit_msg>parser: avoid unary naries in scopes.<commit_after>#include <ast/all.hh>
#include <ast/new-clone.hh>
#include <ast/parametric-ast.hh>
#include <object/symbols.hh>
#include <parser/ast-factory.hh>
#include <parser/event-match.hh>
#include <parser/parse.hh>
#include <parser/parse-result.hh>
#include <rewrite/pattern-binder.hh>
#include <rewrite/rewrite.hh>

namespace std
{
  ostream&
  operator<< (ostream& o, const parser::case_type& c)
  {
    return o << "/* " << (const void*) &c << " */ "
             << "case "
             << libport::deref << c.first
             << " => "
             << libport::deref << c.second;
  }

  ostream&
  operator<< (ostream& o, const parser::cases_type& cs)
  {
    o << "/* " << (const void*) &cs << " */ "
      << "{" << endl;
    foreach (const parser::case_type& c, cs)
      o << "  " << c << endl;
    return o << "}";
  }

}

namespace parser
{
  ast::rExp
  ast_at(const yy::location& loc,
         ast::rExp cond,
         ast::rExp body, ast::rExp onleave,
         ast::rExp duration)
  {
    if (!onleave)
      onleave = new ast::Noop(loc, 0);

    if (duration)
    {
      PARAMETRIC_AST(desugar,
                     "var '$at' = persist(%exp:1, %exp:2) |"
                     "at ('$at') %exp:3 onleave %exp:4");

      return exp(desugar % cond % duration % body % onleave);
    }
    else
    {
      PARAMETRIC_AST(desugar,
        "Control.at_(%exp:1, detach(%exp:2), detach(%exp:3))");

      return exp(desugar % cond % body % onleave);
    }
  }

  ast::rExp
  ast_event_catcher(const ast::loc& loc,
                    EventMatch& event,
                    ast::rExp body, ast::rExp onleave)
  {
    if (onleave)
    {
      PARAMETRIC_AST(a, "%exp:1 | %exp:2");
      body = exp(a % body % onleave);
    }

    if (event.guard)
    {
      PARAMETRIC_AST(desugar_guard,
                     "if (%exp:1) %exp:2;");
      body = exp(desugar_guard % event.guard % body);
    }

    if (event.pattern)
    {
      ast::rExp pattern = new ast::List(loc, event.pattern);
      rewrite::PatternBinder bind(ast_call(loc, SYMBOL(DOLLAR_pattern)), loc);
      bind(pattern.get());
      PARAMETRIC_AST(desugar,
                     "detach("
                     "{"
                     "  %exp:1.onEvent("
                     "  closure ('$evt')"
                     "  {"
                     "    var '$pattern' = Pattern.new(%exp:2) |"
                     "    if ('$pattern'.match('$evt'.payload))"
                     "    {"
                     "      %exp: 3 |"
                     "      %exp: 4 |"
                     "    }"
                     "  })"
                     "})");
      return exp(desugar
                 % event.event
                 % bind.result_get().unchecked_cast<ast::Exp>()
                 % bind.bindings_get()
                 % body);
    }
    else
    {
      PARAMETRIC_AST(desugar_no_pattern,
                     "detach("
                     "{"
                     "  %exp:1.onEvent(closure ('$evt')"
                     "  {"
                     "    %exp: 2 |"
                     "  })"
                     "})");
      return exp(desugar_no_pattern % event.event % body);
    }
  }

  ast::rExp
  ast_at_event(const ast::loc& loc,
               EventMatch& event,
               ast::rExp body, ast::rExp onleave)
  {
    PARAMETRIC_AST(desugar_body,
                   "%exp:1 |"
                   "waituntil(!'$evt'.active)");
    body = exp(desugar_body % body);
    return ast_event_catcher(loc, event, body, onleave);
  }

  /// Create a new Tree node composing \c Lhs and \c Rhs with \c Op.
  /// \param op must be & or |.
  ast::rExp
  ast_bin(const yy::location& l,
          ast::flavor_type op, ast::rExp lhs, ast::rExp rhs)
  {
    ast::rExp res = 0;
    assert (lhs);
    assert (rhs);
    switch (op)
    {
    case ast::flavor_pipe:
    {
      ast::rPipe pipe;
      if (pipe = lhs.unsafe_cast<ast::Pipe>())
        pipe->children_get().push_back(rhs);
      else
      {
        pipe = new ast::Pipe(l, ast::exps_type());
        pipe->children_get().push_back(lhs);
        pipe->children_get().push_back(rhs);
      }
      res = pipe;
      break;
    }
    case ast::flavor_and:
    {
      ast::rAnd rand;
      if (rand = lhs.unsafe_cast<ast::And>())
        rand->children_get().push_back(rhs);
      else
      {
        rand = new ast::And(l, ast::exps_type());
        rand->children_get().push_back(lhs);
        rand->children_get().push_back(rhs);
      }
      res = rand;
      break;
    }
    case ast::flavor_comma:
    case ast::flavor_semicolon:
    {
      ast::rNary nary = new ast::Nary(l);
      nary->push_back(lhs, op);
      nary->push_back(rhs);
      res = nary;
      break;
    }
    case ast::flavor_none:
      pabort(op);
    }
    return res;
  }

  /// "<method> (args)".
  ast::rCall
  ast_call (const yy::location& l,
            libport::Symbol method)
  {
    return ast_call(l, new ast::Implicit(l), method);
  }

  /// "<target> . <method> (args)".
  ast::rCall
  ast_call(const yy::location& l,
           ast::rExp target, libport::Symbol method, ast::exps_type* args)
  {
    return new ast::Call(l, args, target, method);
  }

  /// "<target> . <method> ()".
  ast::rCall
  ast_call(const yy::location& l, ast::rExp target, libport::Symbol method)
  {
    return ast_call(l, target, method, 0);
  }

  /// "<target> . <method> (<arg1>)".
  ast::rCall
  ast_call(const yy::location& l,
           ast::rExp target, libport::Symbol method, ast::rExp arg1)
  {
    ast::rCall res = ast_call(l, target, method, new ast::exps_type);
    res->arguments_get()->push_back(arg1);
    return res;
  }

  /// "<target> . <method> (<arg1>, <arg2>)".
  /// "<target> . <method> (<arg1>, <arg2>, <arg3>)".
  ast::rCall
  ast_call(const yy::location& l,
           ast::rExp target, libport::Symbol method,
           ast::rExp arg1, ast::rExp arg2, ast::rExp arg3)
  {
    ast::rCall res = ast_call(l, target, method, new ast::exps_type);
    res->arguments_get()->push_back(arg1);
    res->arguments_get()->push_back(arg2);
    if (arg3)
      res->arguments_get()->push_back(arg3);
    return res;
  }

  ast::rExp
  ast_closure(ast::rExp value)
  {
    PARAMETRIC_AST(a, "closure () { %exp:1 }");
    return exp(a % value);
  }

  /// Build a for loop.
  // The increment is included directly in the condition to make sure
  // it is executed on `continue'.
  ast::rExp
  ast_for(const yy::location&, ast::flavor_type,
          ast::rExp init, ast::rExp test, ast::rExp inc,
          ast::rExp body)
  {
    // FIXME: for| is handled as a simple for
    PARAMETRIC_AST(desugar,
      "{"
      "  %exp:1 |"
      "  var '$tmp-for-first' = true |"
      "  while ({ if ('$tmp-for-first') '$tmp-for-first' = false else %exp:2 | %exp:3})"
      "    %exp:4 |"
      "}"
      );
    return exp(desugar % init % inc % test % body);
  }

  ast::rExp
  ast_if(const yy::location& l,
         ast::rExp cond, ast::rExp iftrue, ast::rExp iffalse)
  {
    return new ast::If(l, ast_strip(cond),
                       ast_scope(l, iftrue),
		       iffalse ? ast_scope(l, iffalse) : new ast::Noop(l, 0));
  }

  ast::rLValue
  ast_lvalue_once(const ast::rLValue& lvalue)
  {
    ast::rCall tmp = ast_call(lvalue->location_get(), SYMBOL(DOLLAR_tmp));

    if (lvalue->call()->target_implicit())
      return lvalue.get();
    else
      return ast_call(lvalue->location_get(), tmp, lvalue->call()->name_get());
  }

  ast::rExp
  ast_lvalue_wrap(const ast::rLValue& lvalue, const ast::rExp& e)
  {
    PARAMETRIC_AST(wrap,
                   "{"
                   "var '$tmp' = %exp:1;"
                   "%exp:2;"
                   "}"
      );

    if (lvalue->call()->target_implicit())
      return e;
    else
    {
      wrap % lvalue->call()->target_get() % e;
      return exp(wrap);
    }
  }

  ast::rExp
  ast_nil()
  {
    PARAMETRIC_AST(nil, "nil");
    return exp(nil);
  }

  /// Return \a e in a ast::Scope unless it is already one.
  ast::rScope
  ast_scope(const yy::location& l, ast::rExp target, ast::rExp e)
  {
    if (ast::rScope res = e.unsafe_cast<ast::Scope>())
      return res;
    else if (target)
      return new ast::Do(l, ast_strip(e), ast_strip(target));
    else
      return new ast::Scope(l, ast_strip(e));
  }

  ast::rScope
  ast_scope(const yy::location& l, ast::rExp e)
  {
    return ast_scope(l, 0, e);
  }

  ast::rExp
  ast_string(const yy::location& l, libport::Symbol s)
  {
    return new ast::String(l, s);
  }

  /*------------.
  | ast_strip.  |
  `------------*/

  ast::rExp
  ast_strip(ast::rNary nary)
  {
    ast::rExp res = nary;
    // Remove useless nary and statement if there's only one child.
    if (nary->children_get().size() == 1)
      res = (nary->children_get().front()
             .unchecked_cast<ast::Stmt>()
             ->expression_get());
    return res;
  }

  ast::rExp
  ast_strip(ast::rExp e)
  {
    if (ast::rNary nary = e.unsafe_cast<ast::Nary>())
      return ast_strip(nary);
    else
      return e;
  }

  ast::rExp
  ast_switch(const yy::location&, ast::rExp cond,
             const cases_type& cases, ast::rExp def)
  {
    const ast::loc& loc = cond->location_get();
    ast::rExp inner = def ? def : ast_nil();
    rforeach (const case_type& c, cases)
    {
      PARAMETRIC_AST(desugar,
                     "var '$pattern' = Pattern.new(%exp:1) |"
                     "if (if ('$pattern'.match('$switch'))"
                     "    {"
                     "      %exp:2 |"
                     "      %exp:3"
                     "    }"
                     "    else"
                     "      false)"
                     "{"
                     "  %exp:4 |"
                     "  %exp:5"
                     "}"
                     "else"
                     "  %exp:6"
        );

      PARAMETRIC_AST(cond,
                     "true");

      ast::rExp condition = c.first->guard_get();
      if (!condition)
        condition = exp(cond);

      rewrite::PatternBinder bind(ast_call(loc, SYMBOL(DOLLAR_pattern)), loc);
      bind(c.first->pattern_get().get());

      desugar
        % bind.result_get().unchecked_cast<ast::Exp>()
        % bind.bindings_get()
        % condition
        % bind.bindings_get()
        % c.second
        % inner;
      inner = ast::exp(desugar);
    }

    PARAMETRIC_AST(sw, "{ var '$switch' = %exp:1 | %exp:2 }");
    return exp(sw % cond % inner);
  }

  ast::rExp
  ast_timeout(const ast::rExp& duration, const ast::rExp& body)
  {
    PARAMETRIC_AST(desugar,
		   "{"
		   " var '$tag' = Tag.new |"
		   " '$tag':"
		   "   {"
		   "      {"
		   "        sleep(%exp:1) | '$tag'.stop"
		   "      },"
		   "     %exp:2 | '$tag'.stop"
		   "   }"
		   "}");
    return exp(desugar % duration % body);
  }

  ast::rExp
  ast_waituntil(const yy::location&,
                const ast::rExp& cond, ast::rExp duration)
  {
    if (duration)
    {
      PARAMETRIC_AST(desugar,
        "{"
        "  var '$waituntil' = persist(%exp:1, %exp:2) |"
        "  waituntil('$waituntil'())"
        "}"
        );
      return exp(desugar % cond % duration);
    }
    else
    {
      PARAMETRIC_AST(desugar,
                     "{var '$tag' = Tag.new |"
                     "'$tag': {at (%exp:1) '$tag'.stop | sleep(inf)}}");
      return exp(desugar % cond);
    }
  }

  ast::rExp
  ast_waituntil_event(const ast::loc& loc,
                      ast::rExp event,
                      ast::exps_type* payload)
  {
    if (!payload)
    {
      PARAMETRIC_AST
        (desugar,
         "  %exp:1.'waituntil'(nil)");
      return exp(desugar % event);
    }

    PARAMETRIC_AST
      (desugar,
       "{"
       "  var '$pattern' = Pattern.new(%exp:1) |"
       "  %exp:2.'waituntil'('$pattern') |"
       "  {"
       "    %unscope: 2 |"
       "    %exp:3 |"
       "  }"
       "}");

    ast::rList d_payload = new ast::List(loc, payload);

    rewrite::PatternBinder bind(ast_call(loc, SYMBOL(DOLLAR_pattern)), loc);
    bind(d_payload.get());

    return exp(desugar
               % bind.result_get().unchecked_cast<ast::Exp>()
               % event
               % bind.bindings_get());
  }

  ast::rExp
  ast_whenever_event(const ast::loc& loc,
                     EventMatch& event,
                     ast::rExp body, ast::rExp onleave)
  {
    PARAMETRIC_AST(desugar_body,
                   "while (true)"
                   "{"
                   "  %exp:1 |"
                   "  if(!'$evt'.active)"
                   "    break"
                   "}");
    body = exp(desugar_body % body);
    return ast_event_catcher(loc, event, body, onleave);
  }

  ast::rExp
  ast_whenever(const yy::location&,
               ast::rExp cond,
               ast::rExp body, ast::rExp else_stmt,
               ast::rExp duration)
  {
    // FIXME: Be smarter on empty else_stmt.
    if (!else_stmt)
      else_stmt = ast_nil();
    if (duration)
    {
      PARAMETRIC_AST(desugar,
        "var '$whenever' = persist(%exp:1, %exp:2) |"
        "Control.whenever_('$whenever'.val, %exp:3, %exp:4) |'"
        );
      return exp(desugar % cond % duration % body % else_stmt);
    }
    else
    {
      PARAMETRIC_AST(desugar,
        "Control.whenever_(%exp:1, %exp:2, %exp:3)");
      return exp(desugar % cond % body % else_stmt);
    }
  }

}
<|endoftext|>


<commit_before>//
//  libavg - Media Playback Engine.
//  Copyright (C) 2003-2008 Ulrich von Zadow
//
//  This library 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 of the License, or (at your option) any later version.
//
//  This library is distributed in the hope that it will be useful,
//  but WITHOUT ANY WARRANTY; without even the implied warranty of
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
//  Lesser General Public License for more details.
//
//  You should have received a copy of the GNU Lesser General Public
//  License along with this library; if not, write to the Free Software
//  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
//
//  Current versions can be found at www.libavg.de
//

#include "TextEngine.h"

#include "../base/Logger.h"
#include "../base/OSHelper.h"
#include "../base/Exception.h"
#include "../base/FileHelper.h"
#include "../base/StringHelper.h"

#include <assert.h>
#include <algorithm>

namespace avg {

using namespace std;

static void
text_subst_func_hint(FcPattern *pattern, gpointer data)
{
    FcPatternAddBool(pattern, FC_HINTING, true);
    FcPatternAddInteger(pattern, FC_HINT_STYLE, FC_HINT_MEDIUM);
    FcPatternAddInteger(pattern, FC_RGBA, FC_RGBA_NONE);
    FcPatternAddBool(pattern, FC_ANTIALIAS, true);
}

static void
text_subst_func_nohint(FcPattern *pattern, gpointer data)
{
    FcPatternAddBool(pattern, FC_HINTING, false);
    FcPatternAddBool(pattern, FC_AUTOHINT, false);
    FcPatternAddInteger(pattern, FC_HINT_STYLE, FC_HINT_NONE);
    FcPatternAddInteger(pattern, FC_RGBA, FC_RGBA_NONE);
    FcPatternAddBool(pattern, FC_ANTIALIAS, true);
}

TextEngine& TextEngine::get(bool bHint)
{
    if (bHint) {
        static TextEngine s_Instance(true);
        return s_Instance;
    } else {
        static TextEngine s_Instance(false);
        return s_Instance;
    }
}

TextEngine::TextEngine(bool bHint)
    : m_bHint(bHint)
{
    m_sFontDirs.push_back("fonts/");
    init();
}

TextEngine::~TextEngine()
{
    deinit();
}

void TextEngine::init()
{
    g_type_init();
    m_pFontMap = PANGO_FT2_FONT_MAP(pango_ft2_font_map_new());
    pango_ft2_font_map_set_resolution(m_pFontMap, 72, 72);
    if (m_bHint) {
        pango_ft2_font_map_set_default_substitute(m_pFontMap, text_subst_func_hint,
                0, 0);
    } else {
        pango_ft2_font_map_set_default_substitute(m_pFontMap, text_subst_func_nohint,
                0, 0);
    }
    m_pPangoContext = pango_font_map_create_context(PANGO_FONT_MAP(m_pFontMap));

    pango_context_set_language(m_pPangoContext,
            pango_language_from_string ("en_US"));
    pango_context_set_base_dir(m_pPangoContext, PANGO_DIRECTION_LTR);

    initFonts();

    string sOldLang = "";
    getEnv("LC_CTYPE", sOldLang);
    setEnv("LC_CTYPE", "en-us");
    pango_font_map_list_families(PANGO_FONT_MAP(m_pFontMap), &m_ppFontFamilies,
            &m_NumFontFamilies);
    setEnv("LC_CTYPE", sOldLang);
    for (int i=0; i<m_NumFontFamilies; ++i) {
        m_sFonts.push_back(pango_font_family_get_name(m_ppFontFamilies[i]));
    }
    sort(m_sFonts.begin(), m_sFonts.end());
}

void TextEngine::deinit()
{
    g_object_unref(m_pFontMap);
    g_free(m_ppFontFamilies);
    g_object_unref(m_pPangoContext);
    m_sFonts.clear();
}

void TextEngine::addFontDir(const std::string& sDir)
{
    deinit();
    m_sFontDirs.push_back(sDir);
    init();
}

PangoContext * TextEngine::getPangoContext()
{
    return m_pPangoContext;
}

const vector<string>& TextEngine::getFontFamilies()
{
    return m_sFonts;
}

const vector<string>& TextEngine::getFontVariants(const string& sFontName)
{
    PangoFontFamily * pCurFamily = getFontFamily(sFontName);
    PangoFontFace ** ppFaces;
    int numFaces;
    pango_font_family_list_faces (pCurFamily, &ppFaces, &numFaces);
    static vector<string> sVariants;
    for (int i=0; i<numFaces; ++i) {
        sVariants.push_back(pango_font_face_get_face_name(ppFaces[i]));
    }
    g_free(ppFaces);
    return sVariants;
}

PangoFontDescription * TextEngine::getFontDescription(const string& sFamily,
        const string& sVariant)
{
    PangoFontDescription* pDescription;
    FontDescriptionCache::iterator it;
    it = m_FontDescriptionCache.find(pair<string, string>(sFamily, sVariant));
    if (it == m_FontDescriptionCache.end()) {
        PangoFontFamily * pFamily;
        bool bFamilyFound = true;
        try {
            pFamily = getFontFamily(sFamily);
        } catch (Exception&) {
            if (m_sFontsNotFound.find(sFamily) == m_sFontsNotFound.end()) {
                AVG_TRACE(Logger::WARNING, "Could not find font face " << sFamily <<
                        ". Using sans instead.");
                m_sFontsNotFound.insert(sFamily);
            }
            bFamilyFound = false;
            pFamily = getFontFamily("sans");
        }
        PangoFontFace ** ppFaces;
        int numFaces;
        pango_font_family_list_faces(pFamily, &ppFaces, &numFaces);
        PangoFontFace * pFace = 0;
        if (sVariant == "") {
            pFace = ppFaces[0];
        } else {
            for (int i=0; i<numFaces; ++i) {
                if (equalIgnoreCase(pango_font_face_get_face_name(ppFaces[i]), sVariant)) {
                    pFace = ppFaces[i];
                }
            }
        }
        if (!pFace) {
            pFace = ppFaces[0];
            if (bFamilyFound) {
                pair<string, string> variant(sFamily, sVariant);
                if (m_VariantsNotFound.find(variant) == m_VariantsNotFound.end()) {
                    m_VariantsNotFound.insert(variant);
                    AVG_TRACE(Logger::WARNING, "Could not find font variant "
                            << sFamily << ":" << sVariant << ". Using " <<
                            pango_font_face_get_face_name(pFace) << " instead.");
                }
            }
        }
        g_free(ppFaces);
        pDescription = pango_font_face_describe(pFace);
        m_FontDescriptionCache[pair<string, string>(sFamily, sVariant)] =
                pDescription;
    } else {
        pDescription = it->second;
    }
    return pango_font_description_copy(pDescription);
}

void GLibLogFunc(const gchar *log_domain, GLogLevelFlags log_level,
        const gchar *message, gpointer unused_data)
{
#ifndef WIN32
    string s = "Pango ";
    if (log_level & G_LOG_LEVEL_ERROR) {
        s += "error: ";
    } else if (log_level & G_LOG_LEVEL_CRITICAL) {
        s += string("critical: ")+message;
        AVG_TRACE(Logger::ERROR, s);
        assert(false);
    } else if (log_level & G_LOG_LEVEL_WARNING) {
        s += "warning: ";
    } else if (log_level & G_LOG_LEVEL_MESSAGE) {
        s += "message: ";
    } else if (log_level & G_LOG_LEVEL_INFO) {
        s += "info: ";
    } else if (log_level & G_LOG_LEVEL_DEBUG) {
        s += "debug: ";
    }
    s += message;
    AVG_TRACE(Logger::WARNING, s);
#endif
}

void TextEngine::initFonts()
{
    g_type_init();
    std::string sFontConfPath = "/etc/fonts/fonts.conf";
    if (!fileExists(sFontConfPath)) {
        sFontConfPath = getAvgLibPath()+"etc/fonts/fonts.conf";
    }
    FcConfig * pConfig = FcConfigCreate();
    int Ok = (int)FcConfigParseAndLoad(pConfig,
            (const FcChar8 *)(sFontConfPath.c_str()), true);
    checkFontError(Ok, string("Font error: could not load config file ")+sFontConfPath);
    Ok = (int)FcConfigBuildFonts(pConfig);
    checkFontError(Ok, string("Font error: FcConfigBuildFonts failed."));
    Ok = (int)FcConfigSetCurrent(pConfig);
    checkFontError(Ok, string("Font error: FcConfigSetCurrent failed."));
    for(std::vector<std::string>::const_iterator it = m_sFontDirs.begin();
            it != m_sFontDirs.end(); ++it) {
        Ok = (int)FcConfigAppFontAddDir(pConfig, (const FcChar8 *)it->c_str());
        checkFontError(Ok, string("Font error: FcConfigAppFontAddDir("
                    + *it + ") failed."));
    }
    /*
       FcStrList * pCacheDirs = FcConfigGetCacheDirs(pConfig);
       FcChar8 * pDir;
       do {
       pDir = FcStrListNext(pCacheDirs);
       if (pDir) {
       cerr << pDir << endl;
       }
       } while (pDir);
     */
    g_log_set_default_handler(GLibLogFunc, 0);
}

PangoFontFamily * TextEngine::getFontFamily(const string& sFamily)
{
    PangoFontFamily * pFamily = 0;
    assert(m_NumFontFamilies != 0);
    for (int i=0; i<m_NumFontFamilies; ++i) {
        if (equalIgnoreCase(pango_font_family_get_name(m_ppFontFamilies[i]), sFamily)) {
            pFamily = m_ppFontFamilies[i];
        }
    }
    if (!pFamily) {
        throw(Exception(AVG_ERR_INVALID_ARGS,
                "getFontFamily: Font family "+sFamily+" not found."));
    }
    return pFamily;
}

void TextEngine::checkFontError(int Ok, const string& sMsg)
{
    if (Ok == 0) {
        throw Exception(AVG_ERR_FONT_INIT_FAILED, sMsg);
    }
}

}
<commit_msg>Fixed windows unresolved external.<commit_after>//
//  libavg - Media Playback Engine.
//  Copyright (C) 2003-2008 Ulrich von Zadow
//
//  This library 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 of the License, or (at your option) any later version.
//
//  This library is distributed in the hope that it will be useful,
//  but WITHOUT ANY WARRANTY; without even the implied warranty of
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
//  Lesser General Public License for more details.
//
//  You should have received a copy of the GNU Lesser General Public
//  License along with this library; if not, write to the Free Software
//  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
//
//  Current versions can be found at www.libavg.de
//

#include "TextEngine.h"

#include "../base/Logger.h"
#include "../base/OSHelper.h"
#include "../base/Exception.h"
#include "../base/FileHelper.h"
#include "../base/StringHelper.h"

#include <assert.h>
#include <algorithm>

namespace avg {

using namespace std;

static void
text_subst_func_hint(FcPattern *pattern, gpointer data)
{
    FcPatternAddBool(pattern, FC_HINTING, true);
    FcPatternAddInteger(pattern, FC_HINT_STYLE, FC_HINT_MEDIUM);
    FcPatternAddInteger(pattern, FC_RGBA, FC_RGBA_NONE);
    FcPatternAddBool(pattern, FC_ANTIALIAS, true);
}

static void
text_subst_func_nohint(FcPattern *pattern, gpointer data)
{
    FcPatternAddBool(pattern, FC_HINTING, false);
    FcPatternAddBool(pattern, FC_AUTOHINT, false);
    FcPatternAddInteger(pattern, FC_HINT_STYLE, FC_HINT_NONE);
    FcPatternAddInteger(pattern, FC_RGBA, FC_RGBA_NONE);
    FcPatternAddBool(pattern, FC_ANTIALIAS, true);
}

TextEngine& TextEngine::get(bool bHint)
{
    if (bHint) {
        static TextEngine s_Instance(true);
        return s_Instance;
    } else {
        static TextEngine s_Instance(false);
        return s_Instance;
    }
}

TextEngine::TextEngine(bool bHint)
    : m_bHint(bHint)
{
    m_sFontDirs.push_back("fonts/");
    init();
}

TextEngine::~TextEngine()
{
    deinit();
}

void TextEngine::init()
{
    g_type_init();
    m_pFontMap = PANGO_FT2_FONT_MAP(pango_ft2_font_map_new());
    pango_ft2_font_map_set_resolution(m_pFontMap, 72, 72);
    if (m_bHint) {
        pango_ft2_font_map_set_default_substitute(m_pFontMap, text_subst_func_hint,
                0, 0);
    } else {
        pango_ft2_font_map_set_default_substitute(m_pFontMap, text_subst_func_nohint,
                0, 0);
    }
    m_pPangoContext = pango_ft2_font_map_create_context(m_pFontMap);

    pango_context_set_language(m_pPangoContext,
            pango_language_from_string ("en_US"));
    pango_context_set_base_dir(m_pPangoContext, PANGO_DIRECTION_LTR);

    initFonts();

    string sOldLang = "";
    getEnv("LC_CTYPE", sOldLang);
    setEnv("LC_CTYPE", "en-us");
    pango_font_map_list_families(PANGO_FONT_MAP(m_pFontMap), &m_ppFontFamilies,
            &m_NumFontFamilies);
    setEnv("LC_CTYPE", sOldLang);
    for (int i=0; i<m_NumFontFamilies; ++i) {
        m_sFonts.push_back(pango_font_family_get_name(m_ppFontFamilies[i]));
    }
    sort(m_sFonts.begin(), m_sFonts.end());
}

void TextEngine::deinit()
{
    g_object_unref(m_pFontMap);
    g_free(m_ppFontFamilies);
    g_object_unref(m_pPangoContext);
    m_sFonts.clear();
}

void TextEngine::addFontDir(const std::string& sDir)
{
    deinit();
    m_sFontDirs.push_back(sDir);
    init();
}

PangoContext * TextEngine::getPangoContext()
{
    return m_pPangoContext;
}

const vector<string>& TextEngine::getFontFamilies()
{
    return m_sFonts;
}

const vector<string>& TextEngine::getFontVariants(const string& sFontName)
{
    PangoFontFamily * pCurFamily = getFontFamily(sFontName);
    PangoFontFace ** ppFaces;
    int numFaces;
    pango_font_family_list_faces (pCurFamily, &ppFaces, &numFaces);
    static vector<string> sVariants;
    for (int i=0; i<numFaces; ++i) {
        sVariants.push_back(pango_font_face_get_face_name(ppFaces[i]));
    }
    g_free(ppFaces);
    return sVariants;
}

PangoFontDescription * TextEngine::getFontDescription(const string& sFamily,
        const string& sVariant)
{
    PangoFontDescription* pDescription;
    FontDescriptionCache::iterator it;
    it = m_FontDescriptionCache.find(pair<string, string>(sFamily, sVariant));
    if (it == m_FontDescriptionCache.end()) {
        PangoFontFamily * pFamily;
        bool bFamilyFound = true;
        try {
            pFamily = getFontFamily(sFamily);
        } catch (Exception&) {
            if (m_sFontsNotFound.find(sFamily) == m_sFontsNotFound.end()) {
                AVG_TRACE(Logger::WARNING, "Could not find font face " << sFamily <<
                        ". Using sans instead.");
                m_sFontsNotFound.insert(sFamily);
            }
            bFamilyFound = false;
            pFamily = getFontFamily("sans");
        }
        PangoFontFace ** ppFaces;
        int numFaces;
        pango_font_family_list_faces(pFamily, &ppFaces, &numFaces);
        PangoFontFace * pFace = 0;
        if (sVariant == "") {
            pFace = ppFaces[0];
        } else {
            for (int i=0; i<numFaces; ++i) {
                if (equalIgnoreCase(pango_font_face_get_face_name(ppFaces[i]), sVariant)) {
                    pFace = ppFaces[i];
                }
            }
        }
        if (!pFace) {
            pFace = ppFaces[0];
            if (bFamilyFound) {
                pair<string, string> variant(sFamily, sVariant);
                if (m_VariantsNotFound.find(variant) == m_VariantsNotFound.end()) {
                    m_VariantsNotFound.insert(variant);
                    AVG_TRACE(Logger::WARNING, "Could not find font variant "
                            << sFamily << ":" << sVariant << ". Using " <<
                            pango_font_face_get_face_name(pFace) << " instead.");
                }
            }
        }
        g_free(ppFaces);
        pDescription = pango_font_face_describe(pFace);
        m_FontDescriptionCache[pair<string, string>(sFamily, sVariant)] =
                pDescription;
    } else {
        pDescription = it->second;
    }
    return pango_font_description_copy(pDescription);
}

void GLibLogFunc(const gchar *log_domain, GLogLevelFlags log_level,
        const gchar *message, gpointer unused_data)
{
#ifndef WIN32
    string s = "Pango ";
    if (log_level & G_LOG_LEVEL_ERROR) {
        s += "error: ";
    } else if (log_level & G_LOG_LEVEL_CRITICAL) {
        s += string("critical: ")+message;
        AVG_TRACE(Logger::ERROR, s);
        assert(false);
    } else if (log_level & G_LOG_LEVEL_WARNING) {
        s += "warning: ";
    } else if (log_level & G_LOG_LEVEL_MESSAGE) {
        s += "message: ";
    } else if (log_level & G_LOG_LEVEL_INFO) {
        s += "info: ";
    } else if (log_level & G_LOG_LEVEL_DEBUG) {
        s += "debug: ";
    }
    s += message;
    AVG_TRACE(Logger::WARNING, s);
#endif
}

void TextEngine::initFonts()
{
    g_type_init();
    std::string sFontConfPath = "/etc/fonts/fonts.conf";
    if (!fileExists(sFontConfPath)) {
        sFontConfPath = getAvgLibPath()+"etc/fonts/fonts.conf";
    }
    FcConfig * pConfig = FcConfigCreate();
    int Ok = (int)FcConfigParseAndLoad(pConfig,
            (const FcChar8 *)(sFontConfPath.c_str()), true);
    checkFontError(Ok, string("Font error: could not load config file ")+sFontConfPath);
    Ok = (int)FcConfigBuildFonts(pConfig);
    checkFontError(Ok, string("Font error: FcConfigBuildFonts failed."));
    Ok = (int)FcConfigSetCurrent(pConfig);
    checkFontError(Ok, string("Font error: FcConfigSetCurrent failed."));
    for(std::vector<std::string>::const_iterator it = m_sFontDirs.begin();
            it != m_sFontDirs.end(); ++it) {
        Ok = (int)FcConfigAppFontAddDir(pConfig, (const FcChar8 *)it->c_str());
        checkFontError(Ok, string("Font error: FcConfigAppFontAddDir("
                    + *it + ") failed."));
    }
    /*
       FcStrList * pCacheDirs = FcConfigGetCacheDirs(pConfig);
       FcChar8 * pDir;
       do {
       pDir = FcStrListNext(pCacheDirs);
       if (pDir) {
       cerr << pDir << endl;
       }
       } while (pDir);
     */
    g_log_set_default_handler(GLibLogFunc, 0);
}

PangoFontFamily * TextEngine::getFontFamily(const string& sFamily)
{
    PangoFontFamily * pFamily = 0;
    assert(m_NumFontFamilies != 0);
    for (int i=0; i<m_NumFontFamilies; ++i) {
        if (equalIgnoreCase(pango_font_family_get_name(m_ppFontFamilies[i]), sFamily)) {
            pFamily = m_ppFontFamilies[i];
        }
    }
    if (!pFamily) {
        throw(Exception(AVG_ERR_INVALID_ARGS,
                "getFontFamily: Font family "+sFamily+" not found."));
    }
    return pFamily;
}

void TextEngine::checkFontError(int Ok, const string& sMsg)
{
    if (Ok == 0) {
        throw Exception(AVG_ERR_FONT_INIT_FAILED, sMsg);
    }
}

}
<|endoftext|>


<commit_before>////////////////////////////////////////////////////////////
//
// The MIT License (MIT)
//
// Copyright (c) 2014 stevehalliwell
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
//
////////////////////////////////////////////////////////////

#include <ResourceManager/ResourceManager.hpp>
#include <ResourceManager/BaseResource.hpp>
#include <ResourceManager/LuaParser.hpp>
#include <string>
namespace rm
{

////////////////////////////////////////////////////////////
/// Initialise static members
////////////////////////////////////////////////////////////
ResourceLookup ResourceManager::resources = {};
ResourceLookup ResourceManager::errorResources = {};
ResourceQueue ResourceManager::loadingQueue = {};
ResourceQueue ResourceManager::unloadQueue = {};
ResourceQueue ResourceManager::reloadQueue = {};
bool ResourceManager::useNullForErrorRes = true;

LoadCompleteCallback ResourceManager::loadCompleteCallback = nullptr;

enum class LoadMode
{
    Queue,
    Block,
};
////////////////////////////////////////////////////////////
/// Function definitions
////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////
/// \brief ResourceManager loads this single resource and
///     assigns the mode for the queue.
///
/// \param name Either a path to where the resource is located or
///     the resource's alias
///
/// \param mode If the resource hasn't been loaded yet, mode determines
///     whether it should queue it for loading or load it immediately
///
/// \returns A shared_ptr to the resource, upcasted to type T
///
////////////////////////////////////////////////////////////
std::shared_ptr<BaseResource>  ResourceManager::loadResource(const std::string& name, LoadMode mode)
{
    // Checking if resource exists in resources
    if (resources.find(name) != resources.end())
    {
        // Assigns a new pointer to the key for the resource
        ResourcePtr pointer = resources.find(name)->second;

        // Checking if the resource is not loaded
        if (pointer->isLoaded == false)
        {
           // If the resource has to be loaded immediately
           if (mode == LoadMode::Block)
           {
               // Change the status of the BaseResource
               pointer->setIsLoaded(true);
               // Unload the BaseResource
               pointer->load;
           }
           else
           {
               // Change the status of the BaseResource
               pointer->setIsLoaded(true);
               // Send to unloadQueue list
               loadingQueue.push(pointer);
            }
        }
        return;
    }

    throw("Not implemented");

    return;
}

/////////////////////////////////////////////////////////////
/// \brief ResourceManager unloads this single resource and
///     assigns the mode for the queue.
///
/// \param name The resource's alias
///
/// \param mode If the resource hasn't been unloaded yet, mode determines
///     whether it should queue it for unloading or unload it immediately
///
////////////////////////////////////////////////////////////
void ResourceManager::unloadResource(const std::string& name, LoadMode mode)
{
    // Setting a new Resource pointer to append to &name if found
    ResourcePtr pointer;

    // Checking if resource exists in resources
   if (resources.find(name) != resources.end())
   {
       // Assigns a new pointer to the key for the resource
       pointer = resources.find(name)->second;

       // If the resource has to be removed immediately
       if(mode == LoadMode::Block)
       {
           // Change the status of the BaseResource
           pointer->setIsLoaded(false);
           // Unload the BaseResource
           pointer->unload;
       }
       else
       {
           // Change the status of the BaseResource
           pointer->setIsLoaded(false);
           // Send to unloadQueue list
           unloadQueue.push(pointer);
       }
       return;
    }

    throw("Not implemented");

    return;

}

void ResourceManager::reloadResource(const std::string& name)
{
    throw("Not implemented");
    // Must appropriately set isLoaded in resource
}

void ResourceManager::initResource(const std::string& path)
{
	//How do you check if a string is a valid file path? Does this even need to be checked?
	/*
	if(path is not a valid filepath)
	{
		return error?
	}
	*/

	bool exists = false;

	//Check if resource with file path already exists.
	for(ResourceLookup::iterator iter = resources.begin(); iter != resources.end(); iter++)
	{
		if(resources[iter].second->getFilePath() == path)
		{
			exists = true;
		}
	}

	//If it does not already exist then create and add to resources.
	if(!exists)
	{
		ResourcePtr res = ResourceFactory::createResource(path, /*type?*/);
		resources.insert({path, res});

		//return success?
	}
	else
	{
		//return error (already exists)?
	}
}

void ResourceManager::initPack(const std::string& path)
{
    //How do you check if a string is a valid file path? Does this even need to be checked?
	/*
	if(path is not a valid filepath)
	{
		return error?
	}
	*/

	//Get a list of data from the resource pack lua table
	ResourceDataList list = LuaParser::parsePack(path);

	//iterate through the list and create a new resource if one does not already exist.
	for(ResourceDataList::iterator iter = list.begin(); iter != list.end(); iter++)
	{
		//is this supposed to call initResource()? It seems like initResource() will not set an alias as it only takes a path, whereas this function can set the alias and type returned from the luaparser.
		//initResource(list[iter].path);

		//If it does not call initResource()
		bool exists = false;
		for(ResourceLookup::iterator iter2 = resources.begin(); iter2 != resources.end(); iter2++)
		{
			if(resources[iter2].second->getFilePath() == path)
			{
				exists = true;
			}
		}

		if(!exists)
		{
			ResourcePtr res = ResourceFactory::createResource(list[iter]->path, list[iter]->type);
			res->setAlias(list[iter]->alias);
			resources.insert({list[iter]->alias, res});

			//return success?
		}
		else
		{
			//return error (already exists)?
		}
	}
}

////////////////////////////////////////////////////////////
/// \brief ResourceManager will load this Pack of resources
///     assigning each resource a mode for the queue.
///
/// \param path The resource packs's path
///
/// \param mode Determines the load mode for each resource
///
////////////////////////////////////////////////////////////

void ResourceManager::loadPack(const std::string& path, LoadMode mode)
{
    throw("Not implemented");

}

void ResourceManager::unloadPack(const std::string& path, LoadMode mode)
{
    throw("Not implemented");

}

void ResourceManager::reloadPack(const std::string& path)
{
    throw("Not implemented");

}

void ResourceManager::switchPack(const std::string& fromPath, const std::string& toPath)
{
    throw("Not implemented");

}

void ResourceManager::init(bool _useNullForErrorRes)
{
    useNullForErrorRes = _useNullForErrorRes;

    if(!useNullForErrorRes)
    {
        // Init default resources
        // but we don't have any yet
    }
}

void ResourceManager::update()
{
    loadFromQueue();
    unloadFromQueue();
    reloadFromQueue();
}

void ResourceManager::cleanupUnused()
{
   for(ResourcePtr r : resources)
   {
      if(r.unique())
      {
          r->setIsLoaded(false);
          r->unload();
      }
   }
}

}

bool ResourceManager::isLoading()
{
    return getNumToLoad() > 0;
}

size_t ResourceManager::getNumToLoad()
{
    return loadingQueue.size();
}

ResourceList ResourceManager::listAll()
{
    throw("Not implemented");
    return ResourceList();
}

size_t ResourceManager::getMemUsage()
{
    throw("Not implemented");

}

size_t ResourceManager::getNumResources()
{
    return resources.size();
}

void ResourceManager::setLoadCompleteCallback(LoadCompleteCallback callback)
{
    loadCompleteCallback = callback;
}

void ResourceManager::loadFromQueue()
{
    throw("Not implemented");
    // Must appropriately set isLoaded in resource

    // bail if queue empty
    // load
    // pop
    // if queue empty call loadCompleteCallback
}

void ResourceManager::unloadFromQueue()
{
    throw("Not implemented");
    // Must appropriately set isLoaded in resource
}

void ResourceManager::reloadFromQueue()
{
    throw("Not implemented");

}

} // rm
<commit_msg>loadPack completed<commit_after>////////////////////////////////////////////////////////////
//
// The MIT License (MIT)
//
// Copyright (c) 2014 stevehalliwell
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
//
////////////////////////////////////////////////////////////

#include <ResourceManager/ResourceManager.hpp>
#include <ResourceManager/BaseResource.hpp>
#include <ResourceManager/LuaParser.hpp>
#include <string>
namespace rm
{

////////////////////////////////////////////////////////////
/// Initialise static members
////////////////////////////////////////////////////////////
ResourceLookup ResourceManager::resources = {};
ResourceLookup ResourceManager::errorResources = {};
ResourceQueue ResourceManager::loadingQueue = {};
ResourceQueue ResourceManager::unloadQueue = {};
ResourceQueue ResourceManager::reloadQueue = {};
bool ResourceManager::useNullForErrorRes = true;

LoadCompleteCallback ResourceManager::loadCompleteCallback = nullptr;

enum class LoadMode
{
    Queue,
    Block,
};
////////////////////////////////////////////////////////////
/// Function definitions
////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////
/// \brief ResourceManager loads this single resource and
///     assigns the mode for the queue.
///
/// \param name Either a path to where the resource is located or
///     the resource's alias
///
/// \param mode If the resource hasn't been loaded yet, mode determines
///     whether it should queue it for loading or load it immediately
///
/// \returns A shared_ptr to the resource, upcasted to type T
///
////////////////////////////////////////////////////////////
std::shared_ptr<BaseResource>  ResourceManager::loadResource(const std::string& name, LoadMode mode)
{
    // Checking if resource exists in resources
    if (resources.find(name) != resources.end())
    {
        // Assigns a new pointer to the key for the resource
        ResourcePtr pointer = resources.find(name)->second;

        // Checking if the resource is not loaded
        if (pointer->isLoaded == false)
        {
           // If the resource has to be loaded immediately
           if (mode == LoadMode::Block)
           {
               // Change the status of the BaseResource
               pointer->setIsLoaded(true);
               // Unload the BaseResource
               pointer->load;
           }
           else
           {
               // Change the status of the BaseResource
               pointer->setIsLoaded(true);
               // Send to unloadQueue list
               loadingQueue.push(pointer);
            }
        }
        return;
    }

    throw("Not implemented");

    return;
}

/////////////////////////////////////////////////////////////
/// \brief ResourceManager unloads this single resource and
///     assigns the mode for the queue.
///
/// \param name The resource's alias
///
/// \param mode If the resource hasn't been unloaded yet, mode determines
///     whether it should queue it for unloading or unload it immediately
///
////////////////////////////////////////////////////////////
void ResourceManager::unloadResource(const std::string& name, LoadMode mode)
{
    // Setting a new Resource pointer to append to &name if found
    ResourcePtr pointer;

    // Checking if resource exists in resources
   if (resources.find(name) != resources.end())
   {
       // Assigns a new pointer to the key for the resource
       pointer = resources.find(name)->second;

       // If the resource has to be removed immediately
       if(mode == LoadMode::Block)
       {
           // Change the status of the BaseResource
           pointer->setIsLoaded(false);
           // Unload the BaseResource
           pointer->unload;
       }
       else
       {
           // Change the status of the BaseResource
           pointer->setIsLoaded(false);
           // Send to unloadQueue list
           unloadQueue.push(pointer);
       }
       return;
    }

    throw("Not implemented");

    return;

}

void ResourceManager::reloadResource(const std::string& name)
{
    throw("Not implemented");
    // Must appropriately set isLoaded in resource
}

void ResourceManager::initResource(const std::string& path)
{
	//How do you check if a string is a valid file path? Does this even need to be checked?
	/*
	if(path is not a valid filepath)
	{
		return error?
	}
	*/

	bool exists = false;

	//Check if resource with file path already exists.
	for(ResourceLookup::iterator iter = resources.begin(); iter != resources.end(); iter++)
	{
		if(resources[iter].second->getFilePath() == path)
		{
			exists = true;
		}
	}

	//If it does not already exist then create and add to resources.
	if(!exists)
	{
		ResourcePtr res = ResourceFactory::createResource(path, /*type?*/);
		resources.insert({path, res});

		//return success?
	}
	else
	{
		//return error (already exists)?
	}
}

void ResourceManager::initPack(const std::string& path)
{
    //How do you check if a string is a valid file path? Does this even need to be checked?
	/*
	if(path is not a valid filepath)
	{
		return error?
	}
	*/

	//Get a list of data from the resource pack lua table
	ResourceDataList list = LuaParser::parsePack(path);

	//iterate through the list and create a new resource if one does not already exist.
	for(ResourceDataList::iterator iter = list.begin(); iter != list.end(); iter++)
	{
		//is this supposed to call initResource()? It seems like initResource() will not set an alias as it only takes a path, whereas this function can set the alias and type returned from the luaparser.
		//initResource(list[iter].path);

		//If it does not call initResource()
		bool exists = false;
		for(ResourceLookup::iterator iter2 = resources.begin(); iter2 != resources.end(); iter2++)
		{
			if(resources[iter2].second->getFilePath() == path)
			{
				exists = true;
			}
		}

		if(!exists)
		{
			ResourcePtr res = ResourceFactory::createResource(list[iter]->path, list[iter]->type);
			res->setAlias(list[iter]->alias);
			resources.insert({list[iter]->alias, res});

			//return success?
		}
		else
		{
			//return error (already exists)?
		}
	}
}

////////////////////////////////////////////////////////////
/// \brief ResourceManager will load this Pack of resources
///     assigning each resource a mode for the queue.
///
/// \param path The resource packs's path
///
/// \param mode Determines the load mode for each resource
///
////////////////////////////////////////////////////////////

void ResourceManager::loadPack(const std::string& path, LoadMode mode)
{
    // Create a list from the parsePack
    ResourceDataList list = LuaParser::parsePack(path);

    // Iterate through the list
    for (ResourceDataList::iterator var = list.begin; var != list.end; ++var)
    {
        // Assign the alias to a throw-away string
        std::string name = var->alias;

        // Checking if resource exists in resources
        if (resources.find(name) != resources.end())
        {
            // Assigns a new pointer to the key for the resource
            ResourcePtr pointer = resources.find(name)->second;

            // Checking if the resource is not loaded
            if (pointer->isLoaded == false)
            {
                // If the resource has to be loaded immediately
                if (mode == LoadMode::Block)
                {
                    // Change the status of the BaseResource
                    pointer->setIsLoaded(true);
                    // Unload the BaseResource
                    pointer->load;
                }
                else
                {
                    // Change the status of the BaseResource
                    pointer->setIsLoaded(true);
                    // Send to unloadQueue list
                    loadingQueue.push(pointer);
                }
            }
        }

    }

    throw("Not implemented");
    return;
}

void ResourceManager::unloadPack(const std::string& path, LoadMode mode)
{
    throw("Not implemented");

}

void ResourceManager::reloadPack(const std::string& path)
{
    throw("Not implemented");

}

void ResourceManager::switchPack(const std::string& fromPath, const std::string& toPath)
{
    throw("Not implemented");

}

void ResourceManager::init(bool _useNullForErrorRes)
{
    useNullForErrorRes = _useNullForErrorRes;

    if(!useNullForErrorRes)
    {
        // Init default resources
        // but we don't have any yet
    }
}

void ResourceManager::update()
{
    loadFromQueue();
    unloadFromQueue();
    reloadFromQueue();
}

void ResourceManager::cleanupUnused()
{
   for(ResourcePtr r : resources)
   {
      if(r.unique())
      {
          r->setIsLoaded(false);
          r->unload();
      }
   }
}

}

bool ResourceManager::isLoading()
{
    return getNumToLoad() > 0;
}

size_t ResourceManager::getNumToLoad()
{
    return loadingQueue.size();
}

ResourceList ResourceManager::listAll()
{
    throw("Not implemented");
    return ResourceList();
}

size_t ResourceManager::getMemUsage()
{
    throw("Not implemented");

}

size_t ResourceManager::getNumResources()
{
    return resources.size();
}

void ResourceManager::setLoadCompleteCallback(LoadCompleteCallback callback)
{
    loadCompleteCallback = callback;
}

void ResourceManager::loadFromQueue()
{
    throw("Not implemented");
    // Must appropriately set isLoaded in resource

    // bail if queue empty
    // load
    // pop
    // if queue empty call loadCompleteCallback
}

void ResourceManager::unloadFromQueue()
{

    /////////////////////////////////////////////
    // I thought Steve said that we could not remove anything from the queue..
    /////////////////////////////////////////////

    throw("Not implemented");
    // Must appropriately set isLoaded in resource
}

void ResourceManager::reloadFromQueue()
{
    throw("Not implemented");

}

} // rm
<|endoftext|>


<commit_before>// Copyright (c) 2015-2018 The Gulden developers
// Authored by: Malcolm MacLeod (mmacleod@webmail.co.za)
// Distributed under the GULDEN software license, see the accompanying
// file COPYING

#include "clientversion.h"
#include "ticker.h"
#include "utilmoneystr.h"
#include "arith_uint256.h"
#include "units.h"

#include <QNetworkRequest>
#include <QNetworkAccessManager>
#include <QNetworkReply>
#include <QString>
#include <QJsonDocument>
#include <QJsonArray>
#include <QJsonObject>
#include <QTimer>
#include <QVariant>
#include <QModelIndex>

#include <ostream>
#include <iomanip>
#include <sstream>

#include <openssl/x509_vfy.h>

CurrencyTableModel::CurrencyTableModel(QObject *parent, CurrencyTicker* ticker)
: QAbstractTableModel( parent )
, m_ticker( ticker )
, m_currenciesMap( NULL )
{
}

int CurrencyTableModel::rowCount(const QModelIndex& parent) const
{
    if (m_currenciesMap)
        return m_currenciesMap->size();

    return 0;
}

int CurrencyTableModel::columnCount(const QModelIndex & parent) const
{
    return 3;
}

QVariant CurrencyTableModel::data(const QModelIndex& index, int role) const
{
    if (!m_currenciesMap)
        return QVariant();

    if (index.row() < 0 || index.row() >= (int)m_currenciesMap->size() || role != Qt::DisplayRole)
    {
        return QVariant();
    }

    auto iter = m_currenciesMap->begin();
    std::advance(iter, index.row());

    if (index.column() == 0)
    {
        return QString::fromStdString(iter->first);
    }
    if (index.column() == 1)
    {
        return QString("rate
balance");
    }
    if (index.column() == 2)
    {
        CAmount temp;
        ParseMoney(iter->second,temp);
        //fixme: (2.1) Truncates - we should instead round here...
        QString rate = GuldenUnits::format(GuldenUnits::NLG, temp, false, GuldenUnits::separatorAlways, 4);
        QString balance = GuldenUnits::format(GuldenUnits::NLG, m_ticker->convertGuldenToForex(m_balanceNLG, iter->first), false, GuldenUnits::separatorAlways, 2);
        return rate + QString("
") + balance;
    }

    return QVariant();
}

void CurrencyTableModel::setBalance(CAmount balanceNLG)
{
    m_balanceNLG = balanceNLG;
}

void CurrencyTableModel::balanceChanged(const CAmount& availableBalance, const CAmount& unconfirmedBalance, const CAmount& immatureBalance, const CAmount& watchOnlyBalance, const CAmount& watchUnconfBalance, const CAmount& watchImmatureBalance, const CAmount& lockedBalance)
{
    setBalance(availableBalance + unconfirmedBalance + immatureBalance);
    //fixme: (2.1) Only emit if data actually changes.
    Q_EMIT dataChanged(index(0, 0, QModelIndex()), index(rowCount()-1, columnCount()-1, QModelIndex()));
}

CurrencyTicker::CurrencyTicker( QObject* parent )
: count(0)
{
    netManager = new QNetworkAccessManager( this );
    netManager->setObjectName("currency_ticker_net_manager");

    connect( netManager, SIGNAL( finished( QNetworkReply* ) ), this, SLOT( netRequestFinished( QNetworkReply* ) ) );
    connect( netManager, SIGNAL( sslErrors( QNetworkReply*, const QList<QSslError>& ) ), this, SLOT( reportSslErrors( QNetworkReply*, const QList<QSslError>& ) ) );
}

CurrencyTicker::~CurrencyTicker()
{
    disconnect( netManager, SIGNAL( finished( QNetworkReply* ) ), this, SLOT( netRequestFinished( QNetworkReply* ) ) );
    disconnect( netManager, SIGNAL( sslErrors( QNetworkReply*, const QList<QSslError>& ) ), this, SLOT( reportSslErrors( QNetworkReply*, const QList<QSslError>& ) ) );
}

CAmount CurrencyTicker::convertGuldenToForex(CAmount guldenAmount, std::string forexCurrencyCode)
{
    if (m_ExchangeRates.find(forexCurrencyCode) != m_ExchangeRates.end())
    {
        CAmount exchangeRate;
        if ( ParseMoney(m_ExchangeRates[forexCurrencyCode], exchangeRate) )
        {
            arith_uint256 forexAmountBN = guldenAmount;
            forexAmountBN *= exchangeRate;
            forexAmountBN /= COIN;
            return forexAmountBN.GetLow64();
        }
    }
    return CAmount(0);
}

CAmount CurrencyTicker::convertForexToGulden(CAmount forexAmount, std::string forexCurrencyCode)
{
    if (m_ExchangeRates.find(forexCurrencyCode) != m_ExchangeRates.end())
    {
        CAmount exchangeRate;
        if ( ParseMoney(m_ExchangeRates[forexCurrencyCode], exchangeRate) )
        {
            arith_uint256 forexAmountBN = forexAmount;
            forexAmountBN *= COIN;
            forexAmountBN /= exchangeRate;
            return forexAmountBN.GetLow64();
        }
    }
    return CAmount(0);
}

CurrencyTableModel* CurrencyTicker::GetCurrencyTableModel()
{
    CurrencyTableModel* model = new CurrencyTableModel(this, this);
    model->setObjectName("ticker_currency_table_model");
    model->setMap(&m_ExchangeRates);
    model->setBalance(CAmount(0));
    return model;
}

void CurrencyTicker::pollTicker()
{
    QNetworkRequest netRequest;
    netRequest.setUrl( QString::fromStdString( "https://api.gulden.com/api/v1/ticker" ) );
    netRequest.setRawHeader( "User-Agent", QByteArray(UserAgent().c_str()));
    netRequest.setRawHeader( "Accept", "application/json" );

    QSslConfiguration config( QSslConfiguration::defaultConfiguration() );
    netRequest.setSslConfiguration( config );

    netManager->get( netRequest );
}

void CurrencyTicker::netRequestFinished( QNetworkReply* reply )
{
    bool signalUpdates = false;

    if ( reply->error() != QNetworkReply::NetworkError::NoError )
    {
        //fixme: (2.1) Error handling code here.
        //Note - it is possible the ticker has temporary outages etc. and these are not a major issue
        //We update every ~10s but if we miss a few updates it has no ill-effects
        //So if we do anything here, it should only be after multiple failiures...
    }
    else
    {
        int statusCode = reply->attribute( QNetworkRequest::HttpStatusCodeAttribute ).toInt();

        if ( statusCode != 200 )
        {
            //fixme: (2.1) Error handling code here.
            //Note - it is possible the ticker has temporary outages etc. and these are not a major issue
            //We update every ~10s but if we miss a few updates it has no ill-effects
            //So if we do anything here, it should only be after multiple failiures...
        }
        else
        {
            QByteArray jsonReply = reply->readAll();
            QString temp = QString::fromStdString( jsonReply.data() );
            QJsonDocument jsonDoc = QJsonDocument::fromJson( jsonReply );
            QJsonArray jsonArray = jsonDoc.object().value( "data" ).toArray();

            for ( auto jsonVal : jsonArray )
            {
                QJsonObject jsonObject = jsonVal.toObject();
                std::string currencyName = jsonObject.value( "name" ).toString().toStdString();
                std::string currencyCode = jsonObject.value( "code" ).toString().toStdString();
                //NB! Possible precision loss here - but in this case it is probably acceptible.
                std::string currencyRate;
                std::ostringstream bufstream;
                bufstream << std::fixed << std::setprecision(8) << jsonObject.value( "rate" ).toDouble();
                currencyRate = bufstream.str();

                m_ExchangeRates[currencyCode] = currencyRate;
                signalUpdates = true;
            }
        }
    }

    if ( signalUpdates )
    {
        Q_EMIT exchangeRatesUpdated();
        if(++count % 20 == 0)
        {
            Q_EMIT exchangeRatesUpdatedLongPoll();
        }
    }

    // Call again every ~10 seconds
    QTimer::singleShot( 10000, this, SLOT(pollTicker()) );
}

void CurrencyTicker::reportSslErrors( QNetworkReply* reply, const QList<QSslError>& errorList )
{
    //fixme: (2.1) In future (I guess) we should signal in UI somehow that ticker is unavailable - need to decide how to do this in a user friendly way.
    //Note - it is possible the ticker has temporary outages - is switching hosts or whatever other minor thing
    //We update every ~10s but if we miss a few updates it has no ill-effects
    //So if we do anything here, it should only be after multiple failiures...
}

<commit_msg>Fix crash on forex amount entry with invalid exchangerate<commit_after>// Copyright (c) 2015-2018 The Gulden developers
// Authored by: Malcolm MacLeod (mmacleod@webmail.co.za)
// Distributed under the GULDEN software license, see the accompanying
// file COPYING

#include "clientversion.h"
#include "ticker.h"
#include "utilmoneystr.h"
#include "arith_uint256.h"
#include "units.h"

#include <QNetworkRequest>
#include <QNetworkAccessManager>
#include <QNetworkReply>
#include <QString>
#include <QJsonDocument>
#include <QJsonArray>
#include <QJsonObject>
#include <QTimer>
#include <QVariant>
#include <QModelIndex>

#include <ostream>
#include <iomanip>
#include <sstream>

#include <openssl/x509_vfy.h>

CurrencyTableModel::CurrencyTableModel(QObject *parent, CurrencyTicker* ticker)
: QAbstractTableModel( parent )
, m_ticker( ticker )
, m_currenciesMap( NULL )
{
}

int CurrencyTableModel::rowCount(const QModelIndex& parent) const
{
    if (m_currenciesMap)
        return m_currenciesMap->size();

    return 0;
}

int CurrencyTableModel::columnCount(const QModelIndex & parent) const
{
    return 3;
}

QVariant CurrencyTableModel::data(const QModelIndex& index, int role) const
{
    if (!m_currenciesMap)
        return QVariant();

    if (index.row() < 0 || index.row() >= (int)m_currenciesMap->size() || role != Qt::DisplayRole)
    {
        return QVariant();
    }

    auto iter = m_currenciesMap->begin();
    std::advance(iter, index.row());

    if (index.column() == 0)
    {
        return QString::fromStdString(iter->first);
    }
    if (index.column() == 1)
    {
        return QString("rate
balance");
    }
    if (index.column() == 2)
    {
        CAmount temp;
        ParseMoney(iter->second,temp);
        //fixme: (2.1) Truncates - we should instead round here...
        QString rate = GuldenUnits::format(GuldenUnits::NLG, temp, false, GuldenUnits::separatorAlways, 4);
        QString balance = GuldenUnits::format(GuldenUnits::NLG, m_ticker->convertGuldenToForex(m_balanceNLG, iter->first), false, GuldenUnits::separatorAlways, 2);
        return rate + QString("
") + balance;
    }

    return QVariant();
}

void CurrencyTableModel::setBalance(CAmount balanceNLG)
{
    m_balanceNLG = balanceNLG;
}

void CurrencyTableModel::balanceChanged(const CAmount& availableBalance, const CAmount& unconfirmedBalance, const CAmount& immatureBalance, const CAmount& watchOnlyBalance, const CAmount& watchUnconfBalance, const CAmount& watchImmatureBalance, const CAmount& lockedBalance)
{
    setBalance(availableBalance + unconfirmedBalance + immatureBalance);
    //fixme: (2.1) Only emit if data actually changes.
    Q_EMIT dataChanged(index(0, 0, QModelIndex()), index(rowCount()-1, columnCount()-1, QModelIndex()));
}

CurrencyTicker::CurrencyTicker( QObject* parent )
: count(0)
{
    netManager = new QNetworkAccessManager( this );
    netManager->setObjectName("currency_ticker_net_manager");

    connect( netManager, SIGNAL( finished( QNetworkReply* ) ), this, SLOT( netRequestFinished( QNetworkReply* ) ) );
    connect( netManager, SIGNAL( sslErrors( QNetworkReply*, const QList<QSslError>& ) ), this, SLOT( reportSslErrors( QNetworkReply*, const QList<QSslError>& ) ) );
}

CurrencyTicker::~CurrencyTicker()
{
    disconnect( netManager, SIGNAL( finished( QNetworkReply* ) ), this, SLOT( netRequestFinished( QNetworkReply* ) ) );
    disconnect( netManager, SIGNAL( sslErrors( QNetworkReply*, const QList<QSslError>& ) ), this, SLOT( reportSslErrors( QNetworkReply*, const QList<QSslError>& ) ) );
}

CAmount CurrencyTicker::convertGuldenToForex(CAmount guldenAmount, std::string forexCurrencyCode)
{
    if (m_ExchangeRates.find(forexCurrencyCode) != m_ExchangeRates.end())
    {
        CAmount exchangeRate;
        if ( ParseMoney(m_ExchangeRates[forexCurrencyCode], exchangeRate) )
        {
            arith_uint256 forexAmountBN = guldenAmount;
            forexAmountBN *= exchangeRate;
            forexAmountBN /= COIN;
            return forexAmountBN.GetLow64();
        }
    }
    return CAmount(0);
}

CAmount CurrencyTicker::convertForexToGulden(CAmount forexAmount, std::string forexCurrencyCode)
{
    if (m_ExchangeRates.find(forexCurrencyCode) != m_ExchangeRates.end())
    {
        CAmount exchangeRate;
        if ( ParseMoney(m_ExchangeRates[forexCurrencyCode], exchangeRate) )
        {
            arith_uint256 forexAmountBN = forexAmount;
            forexAmountBN *= COIN;
            if (exchangeRate != 0)
            {
                forexAmountBN /= exchangeRate;
                return forexAmountBN.GetLow64();
            }
        }
    }
    return CAmount(0);
}

CurrencyTableModel* CurrencyTicker::GetCurrencyTableModel()
{
    CurrencyTableModel* model = new CurrencyTableModel(this, this);
    model->setObjectName("ticker_currency_table_model");
    model->setMap(&m_ExchangeRates);
    model->setBalance(CAmount(0));
    return model;
}

void CurrencyTicker::pollTicker()
{
    QNetworkRequest netRequest;
    netRequest.setUrl( QString::fromStdString( "https://api.gulden.com/api/v1/ticker" ) );
    netRequest.setRawHeader( "User-Agent", QByteArray(UserAgent().c_str()));
    netRequest.setRawHeader( "Accept", "application/json" );

    QSslConfiguration config( QSslConfiguration::defaultConfiguration() );
    netRequest.setSslConfiguration( config );

    netManager->get( netRequest );
}

void CurrencyTicker::netRequestFinished( QNetworkReply* reply )
{
    bool signalUpdates = false;

    if ( reply->error() != QNetworkReply::NetworkError::NoError )
    {
        //fixme: (2.1) Error handling code here.
        //Note - it is possible the ticker has temporary outages etc. and these are not a major issue
        //We update every ~10s but if we miss a few updates it has no ill-effects
        //So if we do anything here, it should only be after multiple failiures...
    }
    else
    {
        int statusCode = reply->attribute( QNetworkRequest::HttpStatusCodeAttribute ).toInt();

        if ( statusCode != 200 )
        {
            //fixme: (2.1) Error handling code here.
            //Note - it is possible the ticker has temporary outages etc. and these are not a major issue
            //We update every ~10s but if we miss a few updates it has no ill-effects
            //So if we do anything here, it should only be after multiple failiures...
        }
        else
        {
            QByteArray jsonReply = reply->readAll();
            QString temp = QString::fromStdString( jsonReply.data() );
            QJsonDocument jsonDoc = QJsonDocument::fromJson( jsonReply );
            QJsonArray jsonArray = jsonDoc.object().value( "data" ).toArray();

            for ( auto jsonVal : jsonArray )
            {
                QJsonObject jsonObject = jsonVal.toObject();
                std::string currencyName = jsonObject.value( "name" ).toString().toStdString();
                std::string currencyCode = jsonObject.value( "code" ).toString().toStdString();
                //NB! Possible precision loss here - but in this case it is probably acceptible.
                std::string currencyRate;
                std::ostringstream bufstream;
                bufstream << std::fixed << std::setprecision(8) << jsonObject.value( "rate" ).toDouble();
                currencyRate = bufstream.str();

                m_ExchangeRates[currencyCode] = currencyRate;
                signalUpdates = true;
            }
        }
    }

    if ( signalUpdates )
    {
        Q_EMIT exchangeRatesUpdated();
        if(++count % 20 == 0)
        {
            Q_EMIT exchangeRatesUpdatedLongPoll();
        }
    }

    // Call again every ~10 seconds
    QTimer::singleShot( 10000, this, SLOT(pollTicker()) );
}

void CurrencyTicker::reportSslErrors( QNetworkReply* reply, const QList<QSslError>& errorList )
{
    //fixme: (2.1) In future (I guess) we should signal in UI somehow that ticker is unavailable - need to decide how to do this in a user friendly way.
    //Note - it is possible the ticker has temporary outages - is switching hosts or whatever other minor thing
    //We update every ~10s but if we miss a few updates it has no ill-effects
    //So if we do anything here, it should only be after multiple failiures...
}

<|endoftext|>


<commit_before>// Copyright (c) 2011-2013 The Bitcoin developers
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include "sendcoinsentry.h"
#include "ui_sendcoinsentry.h"

#include "addressbookpage.h"
#include "addresstablemodel.h"
#include "guiutil.h"
#include "optionsmodel.h"
#include "walletmodel.h"

#include <QApplication>
#include <QClipboard>

SendCoinsEntry::SendCoinsEntry(QWidget *parent) :
    QStackedWidget(parent),
    ui(new Ui::SendCoinsEntry),
    model(0)
{
    ui->setupUi(this);

    setCurrentWidget(ui->SendCoins);

#ifdef Q_OS_MAC
    ui->payToLayout->setSpacing(4);
#endif
#if QT_VERSION >= 0x040700
    ui->addAsLabel->setPlaceholderText(tr("Enter a label for this address to add it to your address book"));
#endif

    // normal bitcoin address field
    GUIUtil::setupAddressWidget(ui->payTo, this);
    // just a label for displaying bitcoin address(es)
    ui->payTo_is->setFont(GUIUtil::bitcoinAddressFont());
}

SendCoinsEntry::~SendCoinsEntry()
{
    delete ui;
}

void SendCoinsEntry::on_pasteButton_clicked()
{
    // Paste text from clipboard into recipient field
    ui->payTo->setText(QApplication::clipboard()->text());
}

void SendCoinsEntry::on_addressBookButton_clicked()
{
    if(!model)
        return;
    AddressBookPage dlg(AddressBookPage::ForSelection, AddressBookPage::SendingTab, this);
    dlg.setModel(model->getAddressTableModel());
    if(dlg.exec())
    {
        ui->payTo->setText(dlg.getReturnValue());
        ui->payAmount->setFocus();
    }
}

void SendCoinsEntry::on_payTo_textChanged(const QString &address)
{
    updateLabel(address);
}

void SendCoinsEntry::setModel(WalletModel *model)
{
    this->model = model;

    if (model && model->getOptionsModel())
        connect(model->getOptionsModel(), SIGNAL(displayUnitChanged(int)), this, SLOT(updateDisplayUnit()));

    connect(ui->payAmount, SIGNAL(textChanged()), this, SIGNAL(payAmountChanged()));
    connect(ui->deleteButton, SIGNAL(clicked()), this, SLOT(deleteClicked()));
    connect(ui->deleteButton_is, SIGNAL(clicked()), this, SLOT(deleteClicked()));
    connect(ui->deleteButton_s, SIGNAL(clicked()), this, SLOT(deleteClicked()));

    clear();
}

void SendCoinsEntry::clear()
{
    // clear UI elements for normal payment
    ui->payTo->clear();
    ui->addAsLabel->clear();
    ui->payAmount->clear();
    ui->messageTextLabel->clear();
    ui->messageTextLabel->hide();
    ui->messageLabel->hide();
    // clear UI elements for insecure payment request
    ui->payTo_is->clear();
    ui->memoTextLabel_is->clear();
    ui->payAmount_is->clear();
    // clear UI elements for secure payment request
    ui->payTo_s->clear();
    ui->memoTextLabel_s->clear();
    ui->payAmount_s->clear();

    // update the display unit, to not use the default ("BTC")
    updateDisplayUnit();
}

void SendCoinsEntry::deleteClicked()
{
    emit removeEntry(this);
}

bool SendCoinsEntry::validate()
{
    if (!model)
        return false;

    // Check input validity
    bool retval = true;

    // Skip checks for payment request
    if (recipient.paymentRequest.IsInitialized())
        return retval;

    if (!model->validateAddress(ui->payTo->text()))
    {
        ui->payTo->setValid(false);
        retval = false;
    }

    if (!ui->payAmount->validate())
    {
        retval = false;
    }

    // Reject dust outputs:
    if (retval && GUIUtil::isDust(ui->payTo->text(), ui->payAmount->value())) {
        ui->payAmount->setValid(false);
        retval = false;
    }

    return retval;
}

SendCoinsRecipient SendCoinsEntry::getValue()
{
    // Payment request
    if (recipient.paymentRequest.IsInitialized())
        return recipient;

    // Normal payment
    recipient.address = ui->payTo->text();
    recipient.label = ui->addAsLabel->text();
    recipient.amount = ui->payAmount->value();
    recipient.message = ui->messageTextLabel->text();

    return recipient;
}

QWidget *SendCoinsEntry::setupTabChain(QWidget *prev)
{
    QWidget::setTabOrder(prev, ui->payTo);
    QWidget::setTabOrder(ui->payTo, ui->addAsLabel);
    QWidget *w = ui->payAmount->setupTabChain(ui->addAsLabel);
    QWidget::setTabOrder(w, ui->addressBookButton);
    QWidget::setTabOrder(ui->addressBookButton, ui->pasteButton);
    QWidget::setTabOrder(ui->pasteButton, ui->deleteButton);
    return ui->deleteButton;
}

void SendCoinsEntry::setValue(const SendCoinsRecipient &value)
{
    recipient = value;

    if (recipient.paymentRequest.IsInitialized()) // payment request
    {
        if (recipient.authenticatedMerchant.isEmpty()) // insecure
        {
            ui->payTo_is->setText(recipient.address);
            ui->memoTextLabel_is->setText(recipient.message);
            ui->payAmount_is->setValue(recipient.amount);
            ui->payAmount_is->setReadOnly(true);
            setCurrentWidget(ui->SendCoins_InsecurePaymentRequest);
        }
        else // secure
        {
            ui->payTo_s->setText(recipient.authenticatedMerchant);
            ui->memoTextLabel_s->setText(recipient.message);
            ui->payAmount_s->setValue(recipient.amount);
            ui->payAmount_s->setReadOnly(true);
            setCurrentWidget(ui->SendCoins_SecurePaymentRequest);
        }
    }
    else // normal payment
    {
        // message
        ui->messageTextLabel->setText(recipient.message);
        ui->messageTextLabel->setVisible(!recipient.message.isEmpty());
        ui->messageLabel->setVisible(!recipient.message.isEmpty());

        ui->payTo->setText(recipient.address);
        ui->addAsLabel->setText(recipient.label);
        ui->payAmount->setValue(recipient.amount);
    }
}

void SendCoinsEntry::setAddress(const QString &address)
{
    ui->payTo->setText(address);
    ui->payAmount->setFocus();
}

bool SendCoinsEntry::isClear()
{
    return ui->payTo->text().isEmpty() && ui->payTo_is->text().isEmpty() && ui->payTo_s->text().isEmpty();
}

void SendCoinsEntry::setFocus()
{
    ui->payTo->setFocus();
}

void SendCoinsEntry::updateDisplayUnit()
{
    if(model && model->getOptionsModel())
    {
        // Update payAmount with the current unit
        ui->payAmount->setDisplayUnit(model->getOptionsModel()->getDisplayUnit());
        ui->payAmount_is->setDisplayUnit(model->getOptionsModel()->getDisplayUnit());
        ui->payAmount_s->setDisplayUnit(model->getOptionsModel()->getDisplayUnit());
    }
}

bool SendCoinsEntry::updateLabel(const QString &address)
{
    if(!model)
        return false;

    // Fill in label from address book, if address has an associated label
    QString associatedLabel = model->getAddressTableModel()->labelForAddress(address);
    if(!associatedLabel.isEmpty())
    {
        ui->addAsLabel->setText(associatedLabel);
        return true;
    }

    return false;
}
<commit_msg>[Qt] Fill in label from address book also for URIs<commit_after>// Copyright (c) 2011-2013 The Bitcoin developers
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include "sendcoinsentry.h"
#include "ui_sendcoinsentry.h"

#include "addressbookpage.h"
#include "addresstablemodel.h"
#include "guiutil.h"
#include "optionsmodel.h"
#include "walletmodel.h"

#include <QApplication>
#include <QClipboard>

SendCoinsEntry::SendCoinsEntry(QWidget *parent) :
    QStackedWidget(parent),
    ui(new Ui::SendCoinsEntry),
    model(0)
{
    ui->setupUi(this);

    setCurrentWidget(ui->SendCoins);

#ifdef Q_OS_MAC
    ui->payToLayout->setSpacing(4);
#endif
#if QT_VERSION >= 0x040700
    ui->addAsLabel->setPlaceholderText(tr("Enter a label for this address to add it to your address book"));
#endif

    // normal bitcoin address field
    GUIUtil::setupAddressWidget(ui->payTo, this);
    // just a label for displaying bitcoin address(es)
    ui->payTo_is->setFont(GUIUtil::bitcoinAddressFont());
}

SendCoinsEntry::~SendCoinsEntry()
{
    delete ui;
}

void SendCoinsEntry::on_pasteButton_clicked()
{
    // Paste text from clipboard into recipient field
    ui->payTo->setText(QApplication::clipboard()->text());
}

void SendCoinsEntry::on_addressBookButton_clicked()
{
    if(!model)
        return;
    AddressBookPage dlg(AddressBookPage::ForSelection, AddressBookPage::SendingTab, this);
    dlg.setModel(model->getAddressTableModel());
    if(dlg.exec())
    {
        ui->payTo->setText(dlg.getReturnValue());
        ui->payAmount->setFocus();
    }
}

void SendCoinsEntry::on_payTo_textChanged(const QString &address)
{
    updateLabel(address);
}

void SendCoinsEntry::setModel(WalletModel *model)
{
    this->model = model;

    if (model && model->getOptionsModel())
        connect(model->getOptionsModel(), SIGNAL(displayUnitChanged(int)), this, SLOT(updateDisplayUnit()));

    connect(ui->payAmount, SIGNAL(textChanged()), this, SIGNAL(payAmountChanged()));
    connect(ui->deleteButton, SIGNAL(clicked()), this, SLOT(deleteClicked()));
    connect(ui->deleteButton_is, SIGNAL(clicked()), this, SLOT(deleteClicked()));
    connect(ui->deleteButton_s, SIGNAL(clicked()), this, SLOT(deleteClicked()));

    clear();
}

void SendCoinsEntry::clear()
{
    // clear UI elements for normal payment
    ui->payTo->clear();
    ui->addAsLabel->clear();
    ui->payAmount->clear();
    ui->messageTextLabel->clear();
    ui->messageTextLabel->hide();
    ui->messageLabel->hide();
    // clear UI elements for insecure payment request
    ui->payTo_is->clear();
    ui->memoTextLabel_is->clear();
    ui->payAmount_is->clear();
    // clear UI elements for secure payment request
    ui->payTo_s->clear();
    ui->memoTextLabel_s->clear();
    ui->payAmount_s->clear();

    // update the display unit, to not use the default ("BTC")
    updateDisplayUnit();
}

void SendCoinsEntry::deleteClicked()
{
    emit removeEntry(this);
}

bool SendCoinsEntry::validate()
{
    if (!model)
        return false;

    // Check input validity
    bool retval = true;

    // Skip checks for payment request
    if (recipient.paymentRequest.IsInitialized())
        return retval;

    if (!model->validateAddress(ui->payTo->text()))
    {
        ui->payTo->setValid(false);
        retval = false;
    }

    if (!ui->payAmount->validate())
    {
        retval = false;
    }

    // Reject dust outputs:
    if (retval && GUIUtil::isDust(ui->payTo->text(), ui->payAmount->value())) {
        ui->payAmount->setValid(false);
        retval = false;
    }

    return retval;
}

SendCoinsRecipient SendCoinsEntry::getValue()
{
    // Payment request
    if (recipient.paymentRequest.IsInitialized())
        return recipient;

    // Normal payment
    recipient.address = ui->payTo->text();
    recipient.label = ui->addAsLabel->text();
    recipient.amount = ui->payAmount->value();
    recipient.message = ui->messageTextLabel->text();

    return recipient;
}

QWidget *SendCoinsEntry::setupTabChain(QWidget *prev)
{
    QWidget::setTabOrder(prev, ui->payTo);
    QWidget::setTabOrder(ui->payTo, ui->addAsLabel);
    QWidget *w = ui->payAmount->setupTabChain(ui->addAsLabel);
    QWidget::setTabOrder(w, ui->addressBookButton);
    QWidget::setTabOrder(ui->addressBookButton, ui->pasteButton);
    QWidget::setTabOrder(ui->pasteButton, ui->deleteButton);
    return ui->deleteButton;
}

void SendCoinsEntry::setValue(const SendCoinsRecipient &value)
{
    recipient = value;

    if (recipient.paymentRequest.IsInitialized()) // payment request
    {
        if (recipient.authenticatedMerchant.isEmpty()) // insecure
        {
            ui->payTo_is->setText(recipient.address);
            ui->memoTextLabel_is->setText(recipient.message);
            ui->payAmount_is->setValue(recipient.amount);
            ui->payAmount_is->setReadOnly(true);
            setCurrentWidget(ui->SendCoins_InsecurePaymentRequest);
        }
        else // secure
        {
            ui->payTo_s->setText(recipient.authenticatedMerchant);
            ui->memoTextLabel_s->setText(recipient.message);
            ui->payAmount_s->setValue(recipient.amount);
            ui->payAmount_s->setReadOnly(true);
            setCurrentWidget(ui->SendCoins_SecurePaymentRequest);
        }
    }
    else // normal payment
    {
        // message
        ui->messageTextLabel->setText(recipient.message);
        ui->messageTextLabel->setVisible(!recipient.message.isEmpty());
        ui->messageLabel->setVisible(!recipient.message.isEmpty());

        ui->addAsLabel->clear();
        ui->payTo->setText(recipient.address); // this may set a label from addressbook
        if (!recipient.label.isEmpty()) // if a label had been set from the addressbook, dont overwrite with an empty label
            ui->addAsLabel->setText(recipient.label);
        ui->payAmount->setValue(recipient.amount);
    }
}

void SendCoinsEntry::setAddress(const QString &address)
{
    ui->payTo->setText(address);
    ui->payAmount->setFocus();
}

bool SendCoinsEntry::isClear()
{
    return ui->payTo->text().isEmpty() && ui->payTo_is->text().isEmpty() && ui->payTo_s->text().isEmpty();
}

void SendCoinsEntry::setFocus()
{
    ui->payTo->setFocus();
}

void SendCoinsEntry::updateDisplayUnit()
{
    if(model && model->getOptionsModel())
    {
        // Update payAmount with the current unit
        ui->payAmount->setDisplayUnit(model->getOptionsModel()->getDisplayUnit());
        ui->payAmount_is->setDisplayUnit(model->getOptionsModel()->getDisplayUnit());
        ui->payAmount_s->setDisplayUnit(model->getOptionsModel()->getDisplayUnit());
    }
}

bool SendCoinsEntry::updateLabel(const QString &address)
{
    if(!model)
        return false;

    // Fill in label from address book, if address has an associated label
    QString associatedLabel = model->getAddressTableModel()->labelForAddress(address);
    if(!associatedLabel.isEmpty())
    {
        ui->addAsLabel->setText(associatedLabel);
        return true;
    }

    return false;
}
<|endoftext|>


<commit_before><commit_msg>Fix HTTPServer::GetNextLoop compile error for libevent2.0 version<commit_after><|endoftext|>


<commit_before><commit_msg>Update sensorflare.cpp<commit_after><|endoftext|>