<commit_before>#include "layouter.h"

#include "utf-8.h"

#include <harfbuzz/hb.h>
#include <harfbuzz/hb-ft.h>

#include <fribidi/fribidi.h>

#include <linebreak.h>

#include <vector>
#include <string>
#include <memory>
#include <algorithm>

typedef struct
{
  std::vector<textLayout_c::commandData> run;
  int dx, dy;
  FriBidiLevel embeddingLevel;
  char linebreak;
  std::shared_ptr<fontFace_c> font;
#ifdef _DEBUG_
  std::u32string text;
#endif
} runInfo;

// TODO create a sharing structure, where we only
// define structures for each configuration once
// and link to it
// but for now it is good as it is
typedef struct
{
  uint8_t r, g, b;
  std::shared_ptr<fontFace_c> font;
  std::string lang;
} codepointAttributes;

FriBidiLevel getBidiEmbeddingLevels(const std::u32string & txt32, std::vector<FriBidiLevel> & embedding_levels)
{
  std::vector<FriBidiCharType> bidiTypes(txt32.length());
  fribidi_get_bidi_types((uint32_t*)txt32.c_str(), txt32.length(), bidiTypes.data());
  FriBidiParType base_dir = FRIBIDI_TYPE_LTR_VAL; // TODO depends on main script of text
  embedding_levels.resize(txt32.length());
  FriBidiLevel max_level = fribidi_get_par_embedding_levels(bidiTypes.data(), txt32.length(),
                                                            &base_dir, embedding_levels.data());

  return max_level;
}

textLayout_c layoutParagraph(const std::u32string & txt32, const std::vector<codepointAttributes> & attr,
                             const shape_c & shape, const std::string & align)
{
  // calculate embedding types for the text
  std::vector<FriBidiLevel> embedding_levels;
  FriBidiLevel max_level = getBidiEmbeddingLevels(txt32, embedding_levels);

  // calculate the possible linebreak positions
  std::vector<char> linebreaks(txt32.length());
  set_linebreaks_utf32((utf32_t*)txt32.c_str(), txt32.length(), "", linebreaks.data());

  // Get our harfbuzz font structs, TODO we need to do that for all the fonts
  std::map<const std::shared_ptr<fontFace_c>, hb_font_t *> hb_ft_fonts;

  for (const auto & a : attr)
  {
    if (hb_ft_fonts.find(a.font) == hb_ft_fonts.end())
    {
      hb_ft_fonts[a.font] = hb_ft_font_create(a.font->getFace(), NULL);
    }
  }

  // Create a buffer for harfbuzz to use
  hb_buffer_t *buf = hb_buffer_create();

  std::string lan = attr[0].lang.substr(0, 2);
  std::string s = attr[0].lang.substr(3, 4);

  hb_script_t scr = hb_script_from_iso15924_tag(HB_TAG(s[0], s[1], s[2], s[3]));
  hb_buffer_set_script(buf, scr);
  // TODO must come either from text or from rules
  hb_buffer_set_language(buf, hb_language_from_string(lan.c_str(), lan.length()));

  size_t runstart = 0;

  std::vector<runInfo> runs;

  while (runstart < txt32.length())
  {
    size_t spos = runstart+1;
    // find end of current run
    while (   (spos < txt32.length())
           && (embedding_levels[runstart] == embedding_levels[spos])
           && (attr[runstart].font == attr[spos].font)
           && (   (linebreaks[spos-1] == LINEBREAK_NOBREAK)
               || (linebreaks[spos-1] == LINEBREAK_INSIDEACHAR)
              )
          )
    {
      spos++;
    }

    hb_buffer_add_utf32(buf, ((uint32_t*)txt32.c_str())+runstart, spos-runstart, 0, spos-runstart);

    if (embedding_levels[runstart] % 2 == 0)
    {
      hb_buffer_set_direction(buf, HB_DIRECTION_LTR);
    }
    else
    {
      hb_buffer_set_direction(buf, HB_DIRECTION_RTL);
    }

    hb_shape(hb_ft_fonts[attr[runstart].font], buf, NULL, 0);

    unsigned int         glyph_count;
    hb_glyph_info_t     *glyph_info   = hb_buffer_get_glyph_infos(buf, &glyph_count);
    hb_glyph_position_t *glyph_pos    = hb_buffer_get_glyph_positions(buf, &glyph_count);

    runInfo run;

    run.dx = run.dy = 0;
    run.embeddingLevel = embedding_levels[runstart];
    run.linebreak = linebreaks[spos-1];
    run.font = attr[runstart].font;
#ifdef _DEBUG_
    run.text = txt32.substr(runstart, spos-runstart);
#endif

    for (size_t j=0; j < glyph_count; ++j)
    {
      textLayout_c::commandData g;

      g.glyphIndex = glyph_info[j].codepoint;
      g.font = attr[runstart].font;
      // TODO the other parameters

      g.x = run.dx + (glyph_pos[j].x_offset/64);
      g.y = run.dy - (glyph_pos[j].y_offset/64);

      run.dx += glyph_pos[j].x_advance/64;
      run.dy -= glyph_pos[j].y_advance/64;

      g.r = attr[glyph_info[j].cluster + runstart].r;
      g.g = attr[glyph_info[j].cluster + runstart].g;
      g.b = attr[glyph_info[j].cluster + runstart].b;

      g.command = textLayout_c::commandData::CMD_GLYPH;

      run.run.push_back(g);
    }

    runs.push_back(run);
    runstart = spos;

    hb_buffer_reset(buf);
  }

  hb_buffer_destroy(buf);

  for (auto & a : hb_ft_fonts)
    hb_font_destroy(a.second);

  std::vector<size_t> runorder(runs.size());
  int n(0);
  std::generate(runorder.begin(), runorder.end(), [&]{ return n++; });

  // layout a run
  // TODO take care of different font sizes of the different runs
  runstart = 0;
  int32_t ypos = 0;
  textLayout_c l;

  while (runstart < runs.size())
  {
    int32_t curAscend = runs[runstart].font->getAscender()/64;
    int32_t curDescend = runs[runstart].font->getDescender()/64;
    uint32_t curWidth = runs[runstart].dx;
    size_t spos = runstart + 1;

    while (spos < runs.size())
    {
      // check, if we can add another run
      // TODO keep non break runs in mind
      // TODO take properly care of spaces at the end of lines (they must be left out)
      int32_t newAscend = std::max(curAscend, runs[spos].font->getAscender()/64);
      int32_t newDescend = std::min(curDescend, runs[spos].font->getDescender()/64);
      uint32_t newWidth = curWidth + runs[spos].dx;

      if (shape.getLeft(ypos, ypos+newAscend-newDescend)+newWidth >
          shape.getRight(ypos, ypos+newAscend-newDescend))
      {
        // next run would overrun
        break;
      }

      // additional run fits
      curAscend = newAscend;
      curDescend = newDescend;
      curWidth = newWidth;
      spos++;
    }

    // reorder runs for current line
    for (int i = max_level-1; i >= 0; i--)
    {
      // find starts of regions to reverse
      for (size_t j = runstart; j < spos; j++)
      {
        if (runs[runorder[j]].embeddingLevel > i)
        {
          // find the end of the current regions
          size_t k = j+1;
          while (k < spos && runs[runorder[k]].embeddingLevel > i)
          {
            k++;
          }

          std::reverse(runorder.begin()+j, runorder.begin()+k);
          j = k;
        }
      }
    }

    int32_t spaceLeft = shape.getRight(ypos, ypos+curAscend-curDescend) -
                        shape.getLeft(ypos, ypos+curAscend-curDescend);
    spaceLeft -= curWidth;

    int32_t xpos;
    double spaceadder = 0;

    if (align == "left")
    {
      xpos = shape.getLeft(ypos, ypos+curAscend-curDescend);
    }
    else if (align == "right")
    {
      xpos = shape.getLeft(ypos, ypos+curAscend-curDescend) + spaceLeft;
    }
    else if (align == "center")
    {
      xpos = shape.getLeft(ypos, ypos+curAscend-curDescend) + spaceLeft/2;
    }
    else if (align == "justify")
    {
      xpos = shape.getLeft(ypos, ypos+curAscend-curDescend);
      // don't justify last paragraph
      if (spos-runstart > 1 && spos < runs.size())
        spaceadder = 1.0 * spaceLeft / (spos-runstart - 1);
    }

    ypos += curAscend;

    for (size_t i = runstart; i < spos; i++)
    {
      l.addCommandVector(runs[runorder[i]].run, xpos+spaceadder*(i-runstart), ypos);
      xpos += runs[runorder[i]].dx;
    }

    ypos -= curDescend;
    runstart = spos;
  }

  // TODO proper font handling for multiple fonts in a line
  l.setHeight(ypos);

  return l;
}

static std::string normalizeHTML(const std::string & in, char prev)
{
  std::string out;

  for (auto a : in)
  {
    if (a == '\n' || a == '\r')
      a = ' ';

    if (a != ' ' || prev != ' ')
      out += a;

    prev = a;
  }

  return out;
}

void layoutXML_text(pugi::xml_node xml, const textStyleSheet_c & rules, std::u32string & txt,
               std::vector<codepointAttributes> & attr)
{
  for (const auto & i : xml)
  {
    if (i.type() == pugi::node_pcdata)
    {
      if (txt.length() == 0)
        txt = u8_convertToU32(normalizeHTML(i.value(), ' '));
      else
        txt += u8_convertToU32(normalizeHTML(i.value(), txt[txt.length()-1]));

      codepointAttributes a;

      evalColor(rules.getValue(xml, "color"), a.r, a.g, a.b);
      std::string fontFamily = rules.getValue(xml, "font-family");
      std::string fontStyle = rules.getValue(xml, "font-style");
      std::string fontVariant = rules.getValue(xml, "font-variant");
      std::string fontWeight = rules.getValue(xml, "font-weight");
      double fontSize = evalSize(rules.getValue(xml, "font-size"));

      a.font = rules.findFamily(fontFamily)->getFont(64*fontSize, fontStyle, fontVariant, fontWeight);
      a.lang = "en-eng";

      while (attr.size() < txt.length())
        attr.push_back(a);
    }
    else if (   (i.type() == pugi::node_element)
             && (   (std::string("i") == i.name())
                 || (std::string("div") == i.name())
                )
            )
    {
      layoutXML_text(i, rules, txt, attr);
    }
  }
}

// this whole stuff is a recursive descending parser of the XHTML stuff
textLayout_c layoutXML_P(const pugi::xml_node & xml, const textStyleSheet_c & rules, const shape_c & shape)
{
  std::u32string txt;
  std::vector<codepointAttributes> attr;

  layoutXML_text(xml, rules, txt, attr);

  return layoutParagraph(txt, attr, shape, rules.getValue(xml, "text-align"));
}

textLayout_c layoutXML_BODY(const pugi::xml_node & txt, const textStyleSheet_c & rules, const shape_c & shape)
{
  textLayout_c l;

  for (const auto & i : txt)
  {
    if (   (i.type() == pugi::node_element)
        && (   (std::string("p") == i.name())
            || (std::string("h1") == i.name())
            || (std::string("h2") == i.name())
            || (std::string("h3") == i.name())
            || (std::string("h4") == i.name())
            || (std::string("h5") == i.name())
            || (std::string("h6") == i.name())
           )
       )
    {
      // TODO rahmen und anderes beachten
      l.append(layoutXML_P(i, rules, shape), 0, l.getHeight());
    }
    else if (i.type() == pugi::node_element && std::string("table") == i.name())
    {
    }
    else
    {
      // TODO exception nothing else supported
    }
  }

  return l;
}

textLayout_c layoutXML_HTML(const pugi::xml_node & txt, const textStyleSheet_c & rules, const shape_c & shape)
{
  textLayout_c l;

  bool headfound = false;
  bool bodyfound = false;

  for (const auto & i : txt)
  {
    if (std::string("head") == i.name() && !headfound)
    {
      headfound = true;
    }
    else if (std::string("body") == i.name() && !bodyfound)
    {
      bodyfound = true;
      l = layoutXML_BODY(i, rules, shape);
    }
    else
    {
      // nothing else permitted -> exception TODO
    }
  }

  return l;
}

textLayout_c layoutXML(const pugi::xml_document & txt, const textStyleSheet_c & rules, const shape_c & shape)
{
  textLayout_c l;

  // we must have a HTML root node
  for (const auto & i : txt)
  {
    if (std::string("html") == i.name())
    {
      l = layoutXML_HTML(i, rules, shape);
    }
    else
    {
      // nothing else permitted -> exception TODO
    }
  }

  return l;
}

textLayout_c layoutXHTML(const std::string & txt, const textStyleSheet_c & rules, const shape_c & shape)
{
  pugi::xml_document doc;
  // TODO preprocess to get rid of linebreaks and multiple spaces

  // TODO handle parser errors
  doc.load_buffer(txt.c_str(), txt.length());
  return layoutXML(doc, rules, shape);
}

textLayout_c layoutRaw(const std::string & txt, const std::shared_ptr<fontFace_c> font, const shape_c & shape, const std::string & language)
{
  // when we layout raw text we
  // only have to convert the text to utf-32
  // and assign the given font and language to all the codepoints of that text

  std::u32string txt32 = u8_convertToU32(txt);
  std::vector<codepointAttributes> attr(txt32.size());

  for (auto & i : attr)
  {
    i.r = i.g = i.b = 255;
    i.font = font;
    i.lang = language;
  }

  return layoutParagraph(txt32, attr, shape, "left");
}
<commit_msg>only break lines where allowed<commit_after>#include "layouter.h"

#include "utf-8.h"

#include <harfbuzz/hb.h>
#include <harfbuzz/hb-ft.h>

#include <fribidi/fribidi.h>

#include <linebreak.h>

#include <vector>
#include <string>
#include <memory>
#include <algorithm>

typedef struct
{
  std::vector<textLayout_c::commandData> run;
  int dx, dy;
  FriBidiLevel embeddingLevel;
  char linebreak;
  std::shared_ptr<fontFace_c> font;
#ifdef _DEBUG_
  std::u32string text;
#endif
} runInfo;

// TODO create a sharing structure, where we only
// define structures for each configuration once
// and link to it
// but for now it is good as it is
typedef struct
{
  uint8_t r, g, b;
  std::shared_ptr<fontFace_c> font;
  std::string lang;
} codepointAttributes;

FriBidiLevel getBidiEmbeddingLevels(const std::u32string & txt32, std::vector<FriBidiLevel> & embedding_levels)
{
  std::vector<FriBidiCharType> bidiTypes(txt32.length());
  fribidi_get_bidi_types((uint32_t*)txt32.c_str(), txt32.length(), bidiTypes.data());
  FriBidiParType base_dir = FRIBIDI_TYPE_LTR_VAL; // TODO depends on main script of text
  embedding_levels.resize(txt32.length());
  FriBidiLevel max_level = fribidi_get_par_embedding_levels(bidiTypes.data(), txt32.length(),
                                                            &base_dir, embedding_levels.data());

  return max_level;
}

textLayout_c layoutParagraph(const std::u32string & txt32, const std::vector<codepointAttributes> & attr,
                             const shape_c & shape, const std::string & align)
{
  // calculate embedding types for the text
  std::vector<FriBidiLevel> embedding_levels;
  FriBidiLevel max_level = getBidiEmbeddingLevels(txt32, embedding_levels);

  // calculate the possible linebreak positions
  std::vector<char> linebreaks(txt32.length());
  set_linebreaks_utf32((utf32_t*)txt32.c_str(), txt32.length(), "", linebreaks.data());

  // Get our harfbuzz font structs, TODO we need to do that for all the fonts
  std::map<const std::shared_ptr<fontFace_c>, hb_font_t *> hb_ft_fonts;

  for (const auto & a : attr)
  {
    if (hb_ft_fonts.find(a.font) == hb_ft_fonts.end())
    {
      hb_ft_fonts[a.font] = hb_ft_font_create(a.font->getFace(), NULL);
    }
  }

  // Create a buffer for harfbuzz to use
  hb_buffer_t *buf = hb_buffer_create();

  std::string lan = attr[0].lang.substr(0, 2);
  std::string s = attr[0].lang.substr(3, 4);

  hb_script_t scr = hb_script_from_iso15924_tag(HB_TAG(s[0], s[1], s[2], s[3]));
  hb_buffer_set_script(buf, scr);
  // TODO must come either from text or from rules
  hb_buffer_set_language(buf, hb_language_from_string(lan.c_str(), lan.length()));

  size_t runstart = 0;

  std::vector<runInfo> runs;

  while (runstart < txt32.length())
  {
    size_t spos = runstart+1;
    // find end of current run
    while (   (spos < txt32.length())
           && (embedding_levels[runstart] == embedding_levels[spos])
           && (attr[runstart].font == attr[spos].font)
           && (   (linebreaks[spos-1] == LINEBREAK_NOBREAK)
               || (linebreaks[spos-1] == LINEBREAK_INSIDEACHAR)
              )
          )
    {
      spos++;
    }

    hb_buffer_add_utf32(buf, ((uint32_t*)txt32.c_str())+runstart, spos-runstart, 0, spos-runstart);

    if (embedding_levels[runstart] % 2 == 0)
    {
      hb_buffer_set_direction(buf, HB_DIRECTION_LTR);
    }
    else
    {
      hb_buffer_set_direction(buf, HB_DIRECTION_RTL);
    }

    hb_shape(hb_ft_fonts[attr[runstart].font], buf, NULL, 0);

    unsigned int         glyph_count;
    hb_glyph_info_t     *glyph_info   = hb_buffer_get_glyph_infos(buf, &glyph_count);
    hb_glyph_position_t *glyph_pos    = hb_buffer_get_glyph_positions(buf, &glyph_count);

    runInfo run;

    run.dx = run.dy = 0;
    run.embeddingLevel = embedding_levels[runstart];
    run.linebreak = linebreaks[spos-1];
    run.font = attr[runstart].font;
#ifdef _DEBUG_
    run.text = txt32.substr(runstart, spos-runstart);
#endif

    for (size_t j=0; j < glyph_count; ++j)
    {
      textLayout_c::commandData g;

      g.glyphIndex = glyph_info[j].codepoint;
      g.font = attr[runstart].font;
      // TODO the other parameters

      g.x = run.dx + (glyph_pos[j].x_offset/64);
      g.y = run.dy - (glyph_pos[j].y_offset/64);

      run.dx += glyph_pos[j].x_advance/64;
      run.dy -= glyph_pos[j].y_advance/64;

      g.r = attr[glyph_info[j].cluster + runstart].r;
      g.g = attr[glyph_info[j].cluster + runstart].g;
      g.b = attr[glyph_info[j].cluster + runstart].b;

      g.command = textLayout_c::commandData::CMD_GLYPH;

      run.run.push_back(g);
    }

    runs.push_back(run);
    runstart = spos;

    hb_buffer_reset(buf);
  }

  hb_buffer_destroy(buf);

  for (auto & a : hb_ft_fonts)
    hb_font_destroy(a.second);

  std::vector<size_t> runorder(runs.size());
  int n(0);
  std::generate(runorder.begin(), runorder.end(), [&]{ return n++; });

  // layout a run
  // TODO take care of different font sizes of the different runs
  runstart = 0;
  int32_t ypos = 0;
  textLayout_c l;

  while (runstart < runs.size())
  {
    int32_t curAscend = 0;
    int32_t curDescend = 0;
    uint32_t curWidth = 0;
    size_t spos = runstart;

    // add runs until we run out of runs
    while (spos < runs.size())
    {
      // check, if we can add another run
      // TODO keep non break runs in mind
      // TODO take properly care of spaces at the end of lines (they must be left out)

      int32_t newAscend = curAscend;
      int32_t newDescend = curDescend;
      uint32_t newWidth = curWidth;
      size_t newspos = spos;

      while (newspos < runs.size())
      {
        newAscend = std::max(newAscend, runs[newspos].font->getAscender()/64);
        newDescend = std::min(newDescend, runs[newspos].font->getDescender()/64);
        newWidth += runs[newspos].dx;
        if (   (runs[newspos].linebreak == LINEBREAK_ALLOWBREAK)
            || (runs[newspos].linebreak == LINEBREAK_MUSTBREAK)
           )
          break;
        newspos++;
      }

      newspos++;

      if (spos > runstart &&
          shape.getLeft(ypos, ypos+newAscend-newDescend)+newWidth >
          shape.getRight(ypos, ypos+newAscend-newDescend))
      {
        // next run would overrun
        break;
      }

      // additional run fits
      curAscend = newAscend;
      curDescend = newDescend;
      curWidth = newWidth;
      spos = newspos;
    }

    // reorder runs for current line
    for (int i = max_level-1; i >= 0; i--)
    {
      // find starts of regions to reverse
      for (size_t j = runstart; j < spos; j++)
      {
        if (runs[runorder[j]].embeddingLevel > i)
        {
          // find the end of the current regions
          size_t k = j+1;
          while (k < spos && runs[runorder[k]].embeddingLevel > i)
          {
            k++;
          }

          std::reverse(runorder.begin()+j, runorder.begin()+k);
          j = k;
        }
      }
    }

    int32_t spaceLeft = shape.getRight(ypos, ypos+curAscend-curDescend) -
                        shape.getLeft(ypos, ypos+curAscend-curDescend);
    spaceLeft -= curWidth;

    int32_t xpos;
    double spaceadder = 0;

    if (align == "left")
    {
      xpos = shape.getLeft(ypos, ypos+curAscend-curDescend);
    }
    else if (align == "right")
    {
      xpos = shape.getLeft(ypos, ypos+curAscend-curDescend) + spaceLeft;
    }
    else if (align == "center")
    {
      xpos = shape.getLeft(ypos, ypos+curAscend-curDescend) + spaceLeft/2;
    }
    else if (align == "justify")
    {
      xpos = shape.getLeft(ypos, ypos+curAscend-curDescend);
      // don't justify last paragraph
      if (spos-runstart > 1 && spos < runs.size())
        spaceadder = 1.0 * spaceLeft / (spos-runstart - 1);
    }

    ypos += curAscend;

    for (size_t i = runstart; i < spos; i++)
    {
      l.addCommandVector(runs[runorder[i]].run, xpos+spaceadder*(i-runstart), ypos);
      xpos += runs[runorder[i]].dx;
    }

    ypos -= curDescend;
    runstart = spos;
  }

  // TODO proper font handling for multiple fonts in a line
  l.setHeight(ypos);

  return l;
}

static std::string normalizeHTML(const std::string & in, char prev)
{
  std::string out;

  for (auto a : in)
  {
    if (a == '\n' || a == '\r')
      a = ' ';

    if (a != ' ' || prev != ' ')
      out += a;

    prev = a;
  }

  return out;
}

void layoutXML_text(pugi::xml_node xml, const textStyleSheet_c & rules, std::u32string & txt,
               std::vector<codepointAttributes> & attr)
{
  for (const auto & i : xml)
  {
    if (i.type() == pugi::node_pcdata)
    {
      if (txt.length() == 0)
        txt = u8_convertToU32(normalizeHTML(i.value(), ' '));
      else
        txt += u8_convertToU32(normalizeHTML(i.value(), txt[txt.length()-1]));

      codepointAttributes a;

      evalColor(rules.getValue(xml, "color"), a.r, a.g, a.b);
      std::string fontFamily = rules.getValue(xml, "font-family");
      std::string fontStyle = rules.getValue(xml, "font-style");
      std::string fontVariant = rules.getValue(xml, "font-variant");
      std::string fontWeight = rules.getValue(xml, "font-weight");
      double fontSize = evalSize(rules.getValue(xml, "font-size"));

      a.font = rules.findFamily(fontFamily)->getFont(64*fontSize, fontStyle, fontVariant, fontWeight);
      a.lang = "en-eng";

      while (attr.size() < txt.length())
        attr.push_back(a);
    }
    else if (   (i.type() == pugi::node_element)
             && (   (std::string("i") == i.name())
                 || (std::string("div") == i.name())
                )
            )
    {
      layoutXML_text(i, rules, txt, attr);
    }
  }
}

// this whole stuff is a recursive descending parser of the XHTML stuff
textLayout_c layoutXML_P(const pugi::xml_node & xml, const textStyleSheet_c & rules, const shape_c & shape)
{
  std::u32string txt;
  std::vector<codepointAttributes> attr;

  layoutXML_text(xml, rules, txt, attr);

  return layoutParagraph(txt, attr, shape, rules.getValue(xml, "text-align"));
}

textLayout_c layoutXML_BODY(const pugi::xml_node & txt, const textStyleSheet_c & rules, const shape_c & shape)
{
  textLayout_c l;

  for (const auto & i : txt)
  {
    if (   (i.type() == pugi::node_element)
        && (   (std::string("p") == i.name())
            || (std::string("h1") == i.name())
            || (std::string("h2") == i.name())
            || (std::string("h3") == i.name())
            || (std::string("h4") == i.name())
            || (std::string("h5") == i.name())
            || (std::string("h6") == i.name())
           )
       )
    {
      // TODO rahmen und anderes beachten
      l.append(layoutXML_P(i, rules, shape), 0, l.getHeight());
    }
    else if (i.type() == pugi::node_element && std::string("table") == i.name())
    {
    }
    else
    {
      // TODO exception nothing else supported
    }
  }

  return l;
}

textLayout_c layoutXML_HTML(const pugi::xml_node & txt, const textStyleSheet_c & rules, const shape_c & shape)
{
  textLayout_c l;

  bool headfound = false;
  bool bodyfound = false;

  for (const auto & i : txt)
  {
    if (std::string("head") == i.name() && !headfound)
    {
      headfound = true;
    }
    else if (std::string("body") == i.name() && !bodyfound)
    {
      bodyfound = true;
      l = layoutXML_BODY(i, rules, shape);
    }
    else
    {
      // nothing else permitted -> exception TODO
    }
  }

  return l;
}

textLayout_c layoutXML(const pugi::xml_document & txt, const textStyleSheet_c & rules, const shape_c & shape)
{
  textLayout_c l;

  // we must have a HTML root node
  for (const auto & i : txt)
  {
    if (std::string("html") == i.name())
    {
      l = layoutXML_HTML(i, rules, shape);
    }
    else
    {
      // nothing else permitted -> exception TODO
    }
  }

  return l;
}

textLayout_c layoutXHTML(const std::string & txt, const textStyleSheet_c & rules, const shape_c & shape)
{
  pugi::xml_document doc;
  // TODO preprocess to get rid of linebreaks and multiple spaces

  // TODO handle parser errors
  doc.load_buffer(txt.c_str(), txt.length());
  return layoutXML(doc, rules, shape);
}

textLayout_c layoutRaw(const std::string & txt, const std::shared_ptr<fontFace_c> font, const shape_c & shape, const std::string & language)
{
  // when we layout raw text we
  // only have to convert the text to utf-32
  // and assign the given font and language to all the codepoints of that text

  std::u32string txt32 = u8_convertToU32(txt);
  std::vector<codepointAttributes> attr(txt32.size());

  for (auto & i : attr)
  {
    i.r = i.g = i.b = 255;
    i.font = font;
    i.lang = language;
  }

  return layoutParagraph(txt32, attr, shape, "left");
}
<|endoftext|>


<commit_before>/****************************************************************************
**
** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the Qt Mobility Components.
**
** $QT_BEGIN_LICENSE:LGPL$
** No Commercial Usage
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
** contained in the Technology Preview License Agreement accompanying
** this package.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights.  These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** If you have questions regarding the use of this file, please contact
** Nokia at qt-info@nokia.com.
**
**
**
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/

#include "s60audioencodercontrol.h"
#include "s60audiocapturesession.h"

#include <QAudioFormat>

#include <QtCore/qdebug.h>

S60AudioEncoderControl::S60AudioEncoderControl(QObject *session, QObject *parent)
    :QAudioEncoderControl(parent), m_quality(QtMultimedia::NormalQuality)
{
    m_session = qobject_cast<S60AudioCaptureSession*>(session);
    QAudioFormat fmt = m_session->format();
    // medium, 22050Hz mono S16
    fmt.setSampleType(QAudioFormat::SignedInt);
    fmt.setSampleSize(16);
    fmt.setFrequency(22050);
    fmt.setChannels(1);
    m_session->setFormat(fmt);
}

S60AudioEncoderControl::~S60AudioEncoderControl()
{
}

QStringList S60AudioEncoderControl::supportedAudioCodecs() const
{
    return m_session->supportedAudioCodecs();
}

QString S60AudioEncoderControl::codecDescription(const QString &codecName) const
{
	return m_session->codecDescription(codecName);
}

QtMultimedia::EncodingQuality S60AudioEncoderControl::quality() const
{
    return m_quality;
}

void S60AudioEncoderControl::setQuality(QtMultimedia::EncodingQuality value)
{
    QAudioFormat fmt = m_session->format();
    switch (value) {
    case QtMultimedia::VeryLowQuality:
    case QtMultimedia::LowQuality:
        // low, 8000Hz mono U8
        fmt.setSampleType(QAudioFormat::UnSignedInt);
        fmt.setSampleSize(8);
        fmt.setFrequency(8000);
        fmt.setChannels(1);
        break;
    case QtMultimedia::NormalQuality:
        // medium, 22050Hz mono S16
        fmt.setSampleType(QAudioFormat::SignedInt);
        fmt.setSampleSize(16);
        fmt.setFrequency(22050);
        fmt.setChannels(1);
        break;
    case QtMultimedia::HighQuality:
    case QtMultimedia::VeryHighQuality:
        // high, 44100Hz mono S16
        fmt.setSampleType(QAudioFormat::SignedInt);
        fmt.setSampleSize(16);
        fmt.setFrequency(44100);
        fmt.setChannels(2);
        break;
    default:
        break;
    }
}

QStringList S60AudioEncoderControl::supportedEncodingOptions(const QString &codec) const
{
    Q_UNUSED(codec)
    QStringList list;
    if (codec == "PCM")
        list << "quality" << "channels" << "samplerate";
     return list;
}

QVariant S60AudioEncoderControl::encodingOption(const QString &codec, const QString &name) const
{
    if (codec == "PCM") {
        QAudioFormat fmt = m_session->format();

        if(qstrcmp(name.toLocal8Bit().constData(), "quality") == 0) {
            return QVariant(quality());
        }
        else if(qstrcmp(name.toLocal8Bit().constData(), "channels") == 0) {
            return QVariant(fmt.channels());
        }
        else if(qstrcmp(name.toLocal8Bit().constData(), "samplerate") == 0) {
            return QVariant(fmt.frequency());
        }
    }
    return QVariant();
}

void S60AudioEncoderControl::setEncodingOption(
        const QString &codec, const QString &name, const QVariant &value)
{
    if (codec == "PCM") {
        QAudioFormat fmt = m_session->format();

        if(qstrcmp(name.toLocal8Bit().constData(), "quality") == 0) {
            setQuality((QtMultimedia::EncodingQuality)value.toInt(), fmt);
        } else if(qstrcmp(name.toLocal8Bit().constData(), "channels") == 0) {
            fmt.setChannels(value.toInt());
        } else if(qstrcmp(name.toLocal8Bit().constData(), "samplerate") == 0) {
            fmt.setFrequency(value.toInt());
        }
        m_session->setFormat(fmt);
    }
}

QList<int> S60AudioEncoderControl::supportedSampleRates(const QAudioEncoderSettings &settings, bool *continuous) const
{
    if (continuous)
        *continuous = false;

    return m_session->supportedAudioSampleRates(settings);
}

QAudioEncoderSettings S60AudioEncoderControl::audioSettings() const
{
    return m_settings;
}

void S60AudioEncoderControl::setAudioSettings(const QAudioEncoderSettings &settings)
{
    QAudioFormat fmt = m_session->format();
    if (settings.encodingMode() == QtMultimedia::ConstantQualityEncoding) {
        fmt.setCodec(settings.codec());
        setQuality(settings.quality(), fmt);
        if (settings.sampleRate() > 0) {
            fmt.setFrequency(settings.sampleRate());
        }
        if (settings.channelCount() > 0)
            fmt.setChannels(settings.channelCount());
    }else {
        if (settings.sampleRate() == 8000) {
            fmt.setSampleType(QAudioFormat::UnSignedInt);
            fmt.setSampleSize(8);
        } else {
            fmt.setSampleType(QAudioFormat::SignedInt);
            fmt.setSampleSize(16);
        }
        fmt.setCodec(settings.codec());
        fmt.setFrequency(settings.sampleRate());
        fmt.setChannels(settings.channelCount());
    }
    m_session->setFormat(fmt);
    m_settings = settings;
}
<commit_msg>symbian: fix compile<commit_after>/****************************************************************************
**
** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the Qt Mobility Components.
**
** $QT_BEGIN_LICENSE:LGPL$
** No Commercial Usage
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
** contained in the Technology Preview License Agreement accompanying
** this package.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights.  These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** If you have questions regarding the use of this file, please contact
** Nokia at qt-info@nokia.com.
**
**
**
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/

#include "s60audioencodercontrol.h"
#include "s60audiocapturesession.h"

#include <QAudioFormat>

#include <QtCore/qdebug.h>

S60AudioEncoderControl::S60AudioEncoderControl(QObject *session, QObject *parent)
    :QAudioEncoderControl(parent), m_quality(QtMultimedia::NormalQuality)
{
    m_session = qobject_cast<S60AudioCaptureSession*>(session);
    QAudioFormat fmt = m_session->format();
    // medium, 22050Hz mono S16
    fmt.setSampleType(QAudioFormat::SignedInt);
    fmt.setSampleSize(16);
    fmt.setFrequency(22050);
    fmt.setChannels(1);
    m_session->setFormat(fmt);
}

S60AudioEncoderControl::~S60AudioEncoderControl()
{
}

QStringList S60AudioEncoderControl::supportedAudioCodecs() const
{
    return m_session->supportedAudioCodecs();
}

QString S60AudioEncoderControl::codecDescription(const QString &codecName) const
{
	return m_session->codecDescription(codecName);
}

QtMultimedia::EncodingQuality S60AudioEncoderControl::quality() const
{
    return m_quality;
}

void S60AudioEncoderControl::setQuality(QtMultimedia::EncodingQuality value, QAudioFormat &fmt)
{
    switch (value) {
    case QtMultimedia::VeryLowQuality:
    case QtMultimedia::LowQuality:
        // low, 8000Hz mono U8
        fmt.setSampleType(QAudioFormat::UnSignedInt);
        fmt.setSampleSize(8);
        fmt.setFrequency(8000);
        fmt.setChannels(1);
        break;
    case QtMultimedia::NormalQuality:
        // medium, 22050Hz mono S16
        fmt.setSampleType(QAudioFormat::SignedInt);
        fmt.setSampleSize(16);
        fmt.setFrequency(22050);
        fmt.setChannels(1);
        break;
    case QtMultimedia::HighQuality:
    case QtMultimedia::VeryHighQuality:
        // high, 44100Hz mono S16
        fmt.setSampleType(QAudioFormat::SignedInt);
        fmt.setSampleSize(16);
        fmt.setFrequency(44100);
        fmt.setChannels(2);
        break;
    default:
        break;
    }
}

QStringList S60AudioEncoderControl::supportedEncodingOptions(const QString &codec) const
{
    Q_UNUSED(codec)
    QStringList list;
    if (codec == "PCM")
        list << "quality" << "channels" << "samplerate";
     return list;
}

QVariant S60AudioEncoderControl::encodingOption(const QString &codec, const QString &name) const
{
    if (codec == "PCM") {
        QAudioFormat fmt = m_session->format();

        if(qstrcmp(name.toLocal8Bit().constData(), "quality") == 0) {
            return QVariant(quality());
        }
        else if(qstrcmp(name.toLocal8Bit().constData(), "channels") == 0) {
            return QVariant(fmt.channels());
        }
        else if(qstrcmp(name.toLocal8Bit().constData(), "samplerate") == 0) {
            return QVariant(fmt.frequency());
        }
    }
    return QVariant();
}

void S60AudioEncoderControl::setEncodingOption(
        const QString &codec, const QString &name, const QVariant &value)
{
    if (codec == "PCM") {
        QAudioFormat fmt = m_session->format();

        if(qstrcmp(name.toLocal8Bit().constData(), "quality") == 0) {
            setQuality((QtMultimedia::EncodingQuality)value.toInt(), fmt);
        } else if(qstrcmp(name.toLocal8Bit().constData(), "channels") == 0) {
            fmt.setChannels(value.toInt());
        } else if(qstrcmp(name.toLocal8Bit().constData(), "samplerate") == 0) {
            fmt.setFrequency(value.toInt());
        }
        m_session->setFormat(fmt);
    }
}

QList<int> S60AudioEncoderControl::supportedSampleRates(const QAudioEncoderSettings &settings, bool *continuous) const
{
    if (continuous)
        *continuous = false;

    return m_session->supportedAudioSampleRates(settings);
}

QAudioEncoderSettings S60AudioEncoderControl::audioSettings() const
{
    return m_settings;
}

void S60AudioEncoderControl::setAudioSettings(const QAudioEncoderSettings &settings)
{
    QAudioFormat fmt = m_session->format();
    if (settings.encodingMode() == QtMultimedia::ConstantQualityEncoding) {
        fmt.setCodec(settings.codec());
        setQuality(settings.quality(), fmt);
        if (settings.sampleRate() > 0) {
            fmt.setFrequency(settings.sampleRate());
        }
        if (settings.channelCount() > 0)
            fmt.setChannels(settings.channelCount());
    }else {
        if (settings.sampleRate() == 8000) {
            fmt.setSampleType(QAudioFormat::UnSignedInt);
            fmt.setSampleSize(8);
        } else {
            fmt.setSampleType(QAudioFormat::SignedInt);
            fmt.setSampleSize(16);
        }
        fmt.setCodec(settings.codec());
        fmt.setFrequency(settings.sampleRate());
        fmt.setChannels(settings.channelCount());
    }
    m_session->setFormat(fmt);
    m_settings = settings;
}
<|endoftext|>


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

#if defined(LIBPEERCONNECTION_LIB) || defined(LIBPEERCONNECTION_IMPLEMENTATION)

#include "talk/media/webrtc/webrtcmediaengine.h"
#include "talk/media/webrtc/webrtcvideoengine.h"
#include "talk/media/webrtc/webrtcvideoengine2.h"
#include "talk/media/webrtc/webrtcvoiceengine.h"
#include "webrtc/system_wrappers/interface/field_trial.h"

namespace cricket {

class WebRtcMediaEngine
    : public CompositeMediaEngine<WebRtcVoiceEngine, WebRtcVideoEngine> {
 public:
  WebRtcMediaEngine() {}
  WebRtcMediaEngine(webrtc::AudioDeviceModule* adm,
                    webrtc::AudioDeviceModule* adm_sc,
                    WebRtcVideoEncoderFactory* encoder_factory,
                    WebRtcVideoDecoderFactory* decoder_factory) {
    voice_.SetAudioDeviceModule(adm, adm_sc);
    video_.SetExternalEncoderFactory(encoder_factory);
    video_.SetExternalDecoderFactory(decoder_factory);
  }
};

class WebRtcMediaEngine2
    : public CompositeMediaEngine<WebRtcVoiceEngine, WebRtcVideoEngine2> {
 public:
  WebRtcMediaEngine2(webrtc::AudioDeviceModule* adm,
                     webrtc::AudioDeviceModule* adm_sc,
                     WebRtcVideoEncoderFactory* encoder_factory,
                     WebRtcVideoDecoderFactory* decoder_factory) {
    voice_.SetAudioDeviceModule(adm, adm_sc);
    video_.SetExternalDecoderFactory(decoder_factory);
    video_.SetExternalEncoderFactory(encoder_factory);
  }
};

}  // namespace cricket

WRME_EXPORT
cricket::MediaEngineInterface* CreateWebRtcMediaEngine(
    webrtc::AudioDeviceModule* adm,
    webrtc::AudioDeviceModule* adm_sc,
    cricket::WebRtcVideoEncoderFactory* encoder_factory,
    cricket::WebRtcVideoDecoderFactory* decoder_factory) {
  if (webrtc::field_trial::FindFullName("WebRTC-NewVideoAPI") == "Enabled") {
    return new cricket::WebRtcMediaEngine2(adm, adm_sc, encoder_factory,
                                           decoder_factory);
  }
  return new cricket::WebRtcMediaEngine(adm, adm_sc, encoder_factory,
                                        decoder_factory);
}

WRME_EXPORT
void DestroyWebRtcMediaEngine(cricket::MediaEngineInterface* media_engine) {
  delete media_engine;
}

namespace cricket {

// Used by ChannelManager when no media engine is passed in to it
// explicitly (acts as a default).
MediaEngineInterface* WebRtcMediaEngineFactory::Create() {
  return new cricket::WebRtcMediaEngine();
}

// Used by PeerConnectionFactory to create a media engine passed into
// ChannelManager.
MediaEngineInterface* WebRtcMediaEngineFactory::Create(
    webrtc::AudioDeviceModule* adm,
    webrtc::AudioDeviceModule* adm_sc,
    WebRtcVideoEncoderFactory* encoder_factory,
    WebRtcVideoDecoderFactory* decoder_factory) {
  return CreateWebRtcMediaEngine(adm, adm_sc, encoder_factory, decoder_factory);
}

}  // namespace cricket

#endif  // defined(LIBPEERCONNECTION_LIB) ||
        // defined(LIBPEERCONNECTION_IMPLEMENTATION)
<commit_msg>Set WebRtcVideoEngine2 as the WebRtcMediaEngine.<commit_after>/*
 * libjingle
 * Copyright 2014 Google Inc.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 *  1. Redistributions of source code must retain the above copyright notice,
 *     this list of conditions and the following disclaimer.
 *  2. Redistributions in binary form must reproduce the above copyright notice,
 *     this list of conditions and the following disclaimer in the documentation
 *     and/or other materials provided with the distribution.
 *  3. The name of the author may not be used to endorse or promote products
 *     derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
 * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#if defined(LIBPEERCONNECTION_LIB) || defined(LIBPEERCONNECTION_IMPLEMENTATION)

#include "talk/media/webrtc/webrtcmediaengine.h"
#include "talk/media/webrtc/webrtcvideoengine.h"
#include "talk/media/webrtc/webrtcvideoengine2.h"
#include "talk/media/webrtc/webrtcvoiceengine.h"
#include "webrtc/system_wrappers/interface/field_trial.h"

namespace cricket {

class WebRtcMediaEngine
    : public CompositeMediaEngine<WebRtcVoiceEngine, WebRtcVideoEngine> {
 public:
  WebRtcMediaEngine() {}
  WebRtcMediaEngine(webrtc::AudioDeviceModule* adm,
                    webrtc::AudioDeviceModule* adm_sc,
                    WebRtcVideoEncoderFactory* encoder_factory,
                    WebRtcVideoDecoderFactory* decoder_factory) {
    voice_.SetAudioDeviceModule(adm, adm_sc);
    video_.SetExternalEncoderFactory(encoder_factory);
    video_.SetExternalDecoderFactory(decoder_factory);
  }
};

class WebRtcMediaEngine2
    : public CompositeMediaEngine<WebRtcVoiceEngine, WebRtcVideoEngine2> {
 public:
  WebRtcMediaEngine2(webrtc::AudioDeviceModule* adm,
                     webrtc::AudioDeviceModule* adm_sc,
                     WebRtcVideoEncoderFactory* encoder_factory,
                     WebRtcVideoDecoderFactory* decoder_factory) {
    voice_.SetAudioDeviceModule(adm, adm_sc);
    video_.SetExternalDecoderFactory(decoder_factory);
    video_.SetExternalEncoderFactory(encoder_factory);
  }
};

}  // namespace cricket

WRME_EXPORT
cricket::MediaEngineInterface* CreateWebRtcMediaEngine(
    webrtc::AudioDeviceModule* adm,
    webrtc::AudioDeviceModule* adm_sc,
    cricket::WebRtcVideoEncoderFactory* encoder_factory,
    cricket::WebRtcVideoDecoderFactory* decoder_factory) {
  return new cricket::WebRtcMediaEngine2(adm, adm_sc, encoder_factory,
                                         decoder_factory);
}

WRME_EXPORT
void DestroyWebRtcMediaEngine(cricket::MediaEngineInterface* media_engine) {
  delete media_engine;
}

namespace cricket {

// Used by ChannelManager when no media engine is passed in to it
// explicitly (acts as a default).
MediaEngineInterface* WebRtcMediaEngineFactory::Create() {
  return new cricket::WebRtcMediaEngine();
}

// Used by PeerConnectionFactory to create a media engine passed into
// ChannelManager.
MediaEngineInterface* WebRtcMediaEngineFactory::Create(
    webrtc::AudioDeviceModule* adm,
    webrtc::AudioDeviceModule* adm_sc,
    WebRtcVideoEncoderFactory* encoder_factory,
    WebRtcVideoDecoderFactory* decoder_factory) {
  return CreateWebRtcMediaEngine(adm, adm_sc, encoder_factory, decoder_factory);
}

}  // namespace cricket

#endif  // defined(LIBPEERCONNECTION_LIB) ||
        // defined(LIBPEERCONNECTION_IMPLEMENTATION)
<|endoftext|>


<commit_before>/***********************************************************************
    created:    Sun May 25 2014
    author:     Timotei Dolean
*************************************************************************/
/***************************************************************************
 *   Copyright (C) 2004 - 2014 Paul D Turner & The CEGUI Development Team
 *
 *   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 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 "ModelView.h"
#include "CEGUI/CEGUI.h"

#include <iostream>
#include <sstream>

using namespace CEGUI;

ModelViewSample::ModelViewSample()
{
    d_name = "ModelViewSample";
    d_credits = "Timotei Dolean";
    d_summary = "";
    d_description = "";
}

/** This sample uses most of the code from the 'HelloWorld' sample.
    Thus, most of the clarifying comments have been removed for brevity. **/

/*************************************************************************
    Sample specific initialisation goes here.
*************************************************************************/
bool ModelViewSample::initialise(GUIContext* gui_context)
{
    d_usedFiles = String(__FILE__);

    SchemeManager::getSingleton().createFromFile("TaharezLook.scheme");
    SchemeManager::getSingleton().createFromFile("WindowsLook.scheme");

    gui_context->getPointerIndicator().setDefaultImage("TaharezLook/MouseArrow");

    WindowManager& win_mgr = WindowManager::getSingleton();
    d_root = win_mgr.loadLayoutFromFile("ModelViewSample.layout");

    ImageManager::getSingleton().loadImageset("DriveIcons.imageset");

    Font& defaultFont = FontManager::getSingleton().createFromFile("DejaVuSans-12.font");
    gui_context->setDefaultFont(&defaultFont);
    gui_context->setRootWindow(d_root);
    gui_context->setDefaultTooltipType("TaharezLook/Tooltip");

    d_inventoryModel.load();
    d_newItemsCount = 0;

    d_listView = static_cast<ListView*>(win_mgr.createWindow("TaharezLook/ListView", "listView"));
    d_listView->setModel(&d_inventoryModel);
    d_listView->setItemTooltipsEnabled(true);
    d_listView->setSelectionColourRect(ColourRect(Colour(1.0f, 0, 0, 1)));
    d_root->getChild("ListViewHolder")->addChild(d_listView);

    d_treeView = static_cast<TreeView*>(win_mgr.createWindow("TaharezLook/TreeView", "treeView"));
    d_treeView->setModel(&d_inventoryModel);
    d_treeView->setItemTooltipsEnabled(true);
    d_root->getChild("TreeViewHolder")->addChild(d_treeView);

    ListWidget* list_widget = static_cast<ListWidget*>(win_mgr.createWindow("TaharezLook/ListWidget", "listWidget"));
    d_root->getChild("ListWidgetHolder")->addChild(list_widget);
    initListWidgetItems(list_widget);

    d_root->getChild("btnAddRandomItem")->subscribeEvent(PushButton::EventClicked,
        Event::Subscriber(&ModelViewSample::handleAddRandomItem, this));

    d_root->getChild("btnAddRandomItemInList")->subscribeEvent(PushButton::EventClicked,
        Event::Subscriber(&ModelViewSample::handleAddItemInList, this));

    d_root->getChild("btnAddRandomItemInTree")->subscribeEvent(PushButton::EventClicked,
        Event::Subscriber(&ModelViewSample::handleAddItemInTree, this));

    d_root->getChild("btnRemoveSelectedListItem")->subscribeEvent(PushButton::EventClicked,
        Event::Subscriber(&ModelViewSample::handleRemoveSelectedListItems, this));

    d_root->getChild("btnRemoveSelectedTreeItem")->subscribeEvent(PushButton::EventClicked,
        Event::Subscriber(&ModelViewSample::handleRemoveSelectedTreeItems, this));

    d_root->getChild("btnClearAllItems")->subscribeEvent(PushButton::EventClicked,
        Event::Subscriber(&ModelViewSample::handleClearItems, this));

    d_root->getChild("btnUpdateListItemName")->subscribeEvent(PushButton::EventClicked,
        Event::Subscriber(&ModelViewSample::handleUpdateListItemName, this));

    d_root->getChild("btnUpdateTreeItemName")->subscribeEvent(PushButton::EventClicked,
        Event::Subscriber(&ModelViewSample::handleUpdateTreeItemName, this));

    d_root->getChild("chkMultiSelectEnabled")->subscribeEvent(
        ToggleButton::EventSelectStateChanged,
        Event::Subscriber(&ModelViewSample::toggleMultiSelect, this));

    d_root->getChild("btnSwitchSortingMode")->subscribeEvent(
        PushButton::EventClicked,
        Event::Subscriber(&ModelViewSample::toggleSorting, this));

    d_txtNewItemName = d_root->getChild("txtNewItemName");

    return true;

}

/*************************************************************************
    Cleans up resources allocated in the initialiseSample call.
*************************************************************************/
void ModelViewSample::deinitialise()
{
}

//----------------------------------------------------------------------------//
bool ModelViewSample::handleClearItems(const EventArgs& e)
{
    d_inventoryModel.clear();
    return true;
}

//----------------------------------------------------------------------------//
bool ModelViewSample::handleRemoveSelectedListItems(const EventArgs& e)
{
    removeSelectedItemsFromView(d_listView);
    return true;
}

//----------------------------------------------------------------------------//
bool ModelViewSample::handleRemoveSelectedTreeItems(const EventArgs& e)
{
    removeSelectedItemsFromView(d_treeView);
    return true;
}

//----------------------------------------------------------------------------//
bool ModelViewSample::handleAddRandomItem(const EventArgs& e)
{
    d_inventoryModel.addRandomItemWithChildren(d_inventoryModel.getRootIndex(), 0);
    return true;
}

//----------------------------------------------------------------------------//
bool ModelViewSample::handleAddItemInList(const EventArgs& e)
{
    const std::vector<ModelIndexSelectionState>& selections = d_listView->getIndexSelectionStates();
    if (selections.empty())
        return false;

    const ModelIndexSelectionState& selection = (*selections.begin());

    d_inventoryModel.addRandomItemWithChildren(selection.d_parentIndex, selection.d_childId + 1);
    return true;
}

//----------------------------------------------------------------------------//
bool ModelViewSample::handleAddItemInTree(const EventArgs& e)
{
    const std::vector<ModelIndexSelectionState>& selections = d_treeView->getIndexSelectionStates();
    if (selections.empty())
        return false;

    const ModelIndexSelectionState& selection = (*selections.begin());

    d_inventoryModel.addRandomItemWithChildren(selection.d_selectedIndex, 0);
    return true;
}

//----------------------------------------------------------------------------//
bool ModelViewSample::handleUpdateListItemName(const EventArgs& e)
{
    updateSelectedIndexText(d_listView, d_txtNewItemName->getText());
    return true;
}

//----------------------------------------------------------------------------//
bool ModelViewSample::handleUpdateTreeItemName(const EventArgs& e)
{
    updateSelectedIndexText(d_treeView, d_txtNewItemName->getText());
    return true;
}

//----------------------------------------------------------------------------//
void ModelViewSample::removeSelectedItemsFromView(ItemView* view)
{
    while(!view->getIndexSelectionStates().empty())
    {
        d_inventoryModel.removeItem(view->getIndexSelectionStates().back().d_selectedIndex);
    }
}

//----------------------------------------------------------------------------//
void ModelViewSample::updateSelectedIndexText(ItemView* view, const String& text)
{
    const std::vector<ModelIndexSelectionState>& selections = view->getIndexSelectionStates();
    if (selections.empty())
        return;

    const ModelIndexSelectionState& selection = (*selections.begin());

    d_inventoryModel.updateItemName(selection.d_selectedIndex, text);
}

//----------------------------------------------------------------------------//
bool ModelViewSample::toggleMultiSelect(const EventArgs& e)
{
    bool enabled = d_listView->isMultiSelectEnabled();

    d_listView->setMultiSelectEnabled(!enabled);
    d_treeView->setMultiSelectEnabled(!enabled);

    return true;
}

//----------------------------------------------------------------------------//
bool ModelViewSample::toggleSorting(const EventArgs& e)
{
    Window* switch_button = d_root->getChild("btnSwitchSortingMode");
    ViewSortMode sort_mode = d_listView->getSortMode();

    ViewSortMode next_sort_mode = static_cast<ViewSortMode>((sort_mode + 1) % 3);

    d_listView->setSortMode(next_sort_mode);
    d_treeView->setSortMode(next_sort_mode);

    switch_button->setText(
        "Current sort mode: " + PropertyHelper<ViewSortMode>::toString(next_sort_mode));

    return true;
}

//----------------------------------------------------------------------------//
void ModelViewSample::initListWidgetItems(ListWidget* list_widget)
{
    ImageManager::ImageIterator itor = ImageManager::getSingleton().getIterator();
    while (!itor.isAtEnd())
    {
        list_widget->addItem(new StandardItem(itor.getCurrentKey(), itor.getCurrentKey()));
        ++itor;
    }
}

/*************************************************************************
    Define the module function that returns an instance of the sample
*************************************************************************/
extern "C" SAMPLE_EXPORT Sample& getSampleInstance()
{
    static ModelViewSample sample;
    return sample;
}
<commit_msg>MOD: (SAMPLES) added summary and description to ModelView sample<commit_after>/***********************************************************************
    created:    Sun May 25 2014
    author:     Timotei Dolean
*************************************************************************/
/***************************************************************************
 *   Copyright (C) 2004 - 2014 Paul D Turner & The CEGUI Development Team
 *
 *   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 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 "ModelView.h"
#include "CEGUI/CEGUI.h"

#include <iostream>
#include <sstream>

using namespace CEGUI;

ModelViewSample::ModelViewSample()
{
    d_name = "ModelViewSample";
    d_credits = "Timotei Dolean";
    d_summary = "A demo that shows the usage of the new Model-View widgets.";
    d_description = "The demo uses the WindowManager to create from code a window with a listview, treeview and GridView.";
}

/** This sample uses most of the code from the 'HelloWorld' sample.
    Thus, most of the clarifying comments have been removed for brevity. **/

/*************************************************************************
    Sample specific initialisation goes here.
*************************************************************************/
bool ModelViewSample::initialise(GUIContext* gui_context)
{
    d_usedFiles = String(__FILE__);

    SchemeManager::getSingleton().createFromFile("TaharezLook.scheme");
    SchemeManager::getSingleton().createFromFile("WindowsLook.scheme");

    gui_context->getPointerIndicator().setDefaultImage("TaharezLook/MouseArrow");

    WindowManager& win_mgr = WindowManager::getSingleton();
    d_root = win_mgr.loadLayoutFromFile("ModelViewSample.layout");

    ImageManager::getSingleton().loadImageset("DriveIcons.imageset");

    Font& defaultFont = FontManager::getSingleton().createFromFile("DejaVuSans-12.font");
    gui_context->setDefaultFont(&defaultFont);
    gui_context->setRootWindow(d_root);
    gui_context->setDefaultTooltipType("TaharezLook/Tooltip");

    d_inventoryModel.load();
    d_newItemsCount = 0;

    d_listView = static_cast<ListView*>(win_mgr.createWindow("TaharezLook/ListView", "listView"));
    d_listView->setModel(&d_inventoryModel);
    d_listView->setItemTooltipsEnabled(true);
    d_listView->setSelectionColourRect(ColourRect(Colour(1.0f, 0, 0, 1)));
    d_root->getChild("ListViewHolder")->addChild(d_listView);

    d_treeView = static_cast<TreeView*>(win_mgr.createWindow("TaharezLook/TreeView", "treeView"));
    d_treeView->setModel(&d_inventoryModel);
    d_treeView->setItemTooltipsEnabled(true);
    d_root->getChild("TreeViewHolder")->addChild(d_treeView);

    ListWidget* list_widget = static_cast<ListWidget*>(win_mgr.createWindow("TaharezLook/ListWidget", "listWidget"));
    d_root->getChild("ListWidgetHolder")->addChild(list_widget);
    initListWidgetItems(list_widget);

    d_root->getChild("btnAddRandomItem")->subscribeEvent(PushButton::EventClicked,
        Event::Subscriber(&ModelViewSample::handleAddRandomItem, this));

    d_root->getChild("btnAddRandomItemInList")->subscribeEvent(PushButton::EventClicked,
        Event::Subscriber(&ModelViewSample::handleAddItemInList, this));

    d_root->getChild("btnAddRandomItemInTree")->subscribeEvent(PushButton::EventClicked,
        Event::Subscriber(&ModelViewSample::handleAddItemInTree, this));

    d_root->getChild("btnRemoveSelectedListItem")->subscribeEvent(PushButton::EventClicked,
        Event::Subscriber(&ModelViewSample::handleRemoveSelectedListItems, this));

    d_root->getChild("btnRemoveSelectedTreeItem")->subscribeEvent(PushButton::EventClicked,
        Event::Subscriber(&ModelViewSample::handleRemoveSelectedTreeItems, this));

    d_root->getChild("btnClearAllItems")->subscribeEvent(PushButton::EventClicked,
        Event::Subscriber(&ModelViewSample::handleClearItems, this));

    d_root->getChild("btnUpdateListItemName")->subscribeEvent(PushButton::EventClicked,
        Event::Subscriber(&ModelViewSample::handleUpdateListItemName, this));

    d_root->getChild("btnUpdateTreeItemName")->subscribeEvent(PushButton::EventClicked,
        Event::Subscriber(&ModelViewSample::handleUpdateTreeItemName, this));

    d_root->getChild("chkMultiSelectEnabled")->subscribeEvent(
        ToggleButton::EventSelectStateChanged,
        Event::Subscriber(&ModelViewSample::toggleMultiSelect, this));

    d_root->getChild("btnSwitchSortingMode")->subscribeEvent(
        PushButton::EventClicked,
        Event::Subscriber(&ModelViewSample::toggleSorting, this));

    d_txtNewItemName = d_root->getChild("txtNewItemName");

    return true;

}

/*************************************************************************
    Cleans up resources allocated in the initialiseSample call.
*************************************************************************/
void ModelViewSample::deinitialise()
{
}

//----------------------------------------------------------------------------//
bool ModelViewSample::handleClearItems(const EventArgs& e)
{
    d_inventoryModel.clear();
    return true;
}

//----------------------------------------------------------------------------//
bool ModelViewSample::handleRemoveSelectedListItems(const EventArgs& e)
{
    removeSelectedItemsFromView(d_listView);
    return true;
}

//----------------------------------------------------------------------------//
bool ModelViewSample::handleRemoveSelectedTreeItems(const EventArgs& e)
{
    removeSelectedItemsFromView(d_treeView);
    return true;
}

//----------------------------------------------------------------------------//
bool ModelViewSample::handleAddRandomItem(const EventArgs& e)
{
    d_inventoryModel.addRandomItemWithChildren(d_inventoryModel.getRootIndex(), 0);
    return true;
}

//----------------------------------------------------------------------------//
bool ModelViewSample::handleAddItemInList(const EventArgs& e)
{
    const std::vector<ModelIndexSelectionState>& selections = d_listView->getIndexSelectionStates();
    if (selections.empty())
        return false;

    const ModelIndexSelectionState& selection = (*selections.begin());

    d_inventoryModel.addRandomItemWithChildren(selection.d_parentIndex, selection.d_childId + 1);
    return true;
}

//----------------------------------------------------------------------------//
bool ModelViewSample::handleAddItemInTree(const EventArgs& e)
{
    const std::vector<ModelIndexSelectionState>& selections = d_treeView->getIndexSelectionStates();
    if (selections.empty())
        return false;

    const ModelIndexSelectionState& selection = (*selections.begin());

    d_inventoryModel.addRandomItemWithChildren(selection.d_selectedIndex, 0);
    return true;
}

//----------------------------------------------------------------------------//
bool ModelViewSample::handleUpdateListItemName(const EventArgs& e)
{
    updateSelectedIndexText(d_listView, d_txtNewItemName->getText());
    return true;
}

//----------------------------------------------------------------------------//
bool ModelViewSample::handleUpdateTreeItemName(const EventArgs& e)
{
    updateSelectedIndexText(d_treeView, d_txtNewItemName->getText());
    return true;
}

//----------------------------------------------------------------------------//
void ModelViewSample::removeSelectedItemsFromView(ItemView* view)
{
    while(!view->getIndexSelectionStates().empty())
    {
        d_inventoryModel.removeItem(view->getIndexSelectionStates().back().d_selectedIndex);
    }
}

//----------------------------------------------------------------------------//
void ModelViewSample::updateSelectedIndexText(ItemView* view, const String& text)
{
    const std::vector<ModelIndexSelectionState>& selections = view->getIndexSelectionStates();
    if (selections.empty())
        return;

    const ModelIndexSelectionState& selection = (*selections.begin());

    d_inventoryModel.updateItemName(selection.d_selectedIndex, text);
}

//----------------------------------------------------------------------------//
bool ModelViewSample::toggleMultiSelect(const EventArgs& e)
{
    bool enabled = d_listView->isMultiSelectEnabled();

    d_listView->setMultiSelectEnabled(!enabled);
    d_treeView->setMultiSelectEnabled(!enabled);

    return true;
}

//----------------------------------------------------------------------------//
bool ModelViewSample::toggleSorting(const EventArgs& e)
{
    Window* switch_button = d_root->getChild("btnSwitchSortingMode");
    ViewSortMode sort_mode = d_listView->getSortMode();

    ViewSortMode next_sort_mode = static_cast<ViewSortMode>((sort_mode + 1) % 3);

    d_listView->setSortMode(next_sort_mode);
    d_treeView->setSortMode(next_sort_mode);

    switch_button->setText(
        "Current sort mode: " + PropertyHelper<ViewSortMode>::toString(next_sort_mode));

    return true;
}

//----------------------------------------------------------------------------//
void ModelViewSample::initListWidgetItems(ListWidget* list_widget)
{
    ImageManager::ImageIterator itor = ImageManager::getSingleton().getIterator();
    while (!itor.isAtEnd())
    {
        list_widget->addItem(new StandardItem(itor.getCurrentKey(), itor.getCurrentKey()));
        ++itor;
    }
}

/*************************************************************************
    Define the module function that returns an instance of the sample
*************************************************************************/
extern "C" SAMPLE_EXPORT Sample& getSampleInstance()
{
    static ModelViewSample sample;
    return sample;
}
<|endoftext|>


<commit_before>// -*- Mode: C++; tab-width: 2; -*-
// vi: set ts=2:
//
// $Id: dataset.C,v 1.1.4.2 2007/05/10 21:40:37 amoll Exp $
//

#include <BALL/VIEW/DATATYPE/dataset.h>
#include <BALL/VIEW/WIDGETS/datasetControl.h>
#include <BALL/VIEW/KERNEL/common.h>
#include <BALL/VIEW/KERNEL/mainControl.h>
#include <BALL/VIEW/KERNEL/message.h>
#include <BALL/CONCEPT/molecularInformation.h>

#include <QtGui/QFileDialog>
#include <QtCore/QStringList>

using namespace std;

namespace BALL
{

	namespace VIEW
	{

		Dataset::Dataset()
			: composite_(0)
		{
		}

		Dataset::Dataset(const Dataset& ds)
			: composite_(ds.composite_),
				name_(ds.name_),
				type_(ds.type_)
		{
		}

		Dataset::~Dataset()
		{
			#ifdef BALL_VIEW_DEBUG
				cout << "Destructing object " << (void *)this << " of class " << RTTI::getName<Dataset>() << endl;
			#endif
		}

		void Dataset::clear()
		{
			composite_ = 0;
			name_ = "";
			type_ = "";
		}

		void Dataset::set(const Dataset& ds)
		{
			composite_ = ds.composite_;
			name_ = ds.name_;
			type_ = ds.type_;
		}

		const Dataset& Dataset::operator = (const Dataset& v)
		{
			set(v);
			return *this;
		}

		void Dataset::dump(std::ostream& s, Size depth) const
		{
			BALL_DUMP_STREAM_PREFIX(s);

			BALL_DUMP_DEPTH(s, depth);
			BALL_DUMP_HEADER(s, this, this);

			BALL_DUMP_STREAM_SUFFIX(s);
		}

		////////////////////////////////////////////////////////////////////////
		// Controller:

		DatasetController::DatasetController()
			: QObject(),
				Embeddable("DatasetController"),
				type_("undefined type"),
				file_formats_(),
				control_(0)
		{
			registerThis();
		}

		DatasetController::DatasetController(DatasetController& dc)
			: QObject(),
				Embeddable(dc),
				type_(dc.type_),
				file_formats_(dc.file_formats_),
				control_(dc.control_)
		{
			registerThis();
		}

		DatasetController::~DatasetController()
			throw()
		{
		}

		bool DatasetController::write(Dataset* /*set*/, String /*filetype*/, String /*filename*/)
		{
			Log.error() << "DatasetController::write() should have been overloaded in derived class!" <<std::endl;
			return false;
		}

		Dataset* DatasetController::open(String /*filetype*/, String /*filename*/)
		{
			Log.error() << "DatasetController::open() should have been overloaded in derived class!" <<std::endl;
			return 0;
		}

		bool DatasetController::insertDataset(Dataset* set)
		{
			if (getDatasetControl() == 0)
			{
				BALLVIEW_DEBUG
				Log.error() << "DatasetController not bound to Dataset!" << std::endl;
				return false;
			}

			if (set == 0)
			{
				BALLVIEW_DEBUG
				return false;
			}

			QStringList sl;
			sl << set->getName().c_str();
			if (set->getComposite() != 0)
			{
				MolecularInformation mi;
				mi.visit(*set->getComposite());
				sl << mi.getName().c_str();
			}
			else
			{
				sl << "";
			}
			sl << set->getType().c_str();

 			QTreeWidgetItem* item = getDatasetControl()->addRow(sl);
			item_to_dataset_[item] = set;
			dataset_to_item_[set]  = item;

			return true;
		}

		QMenu* DatasetController::buildContextMenu(QTreeWidgetItem* item)
		{
			if (!item_to_dataset_.has(item)) return 0;

			QMenu* menu = new QMenu(control_);
			menu->addAction("Save as...", this, SLOT(write()));
			menu->addAction("Delete", this, SLOT(deleteDataset()));
			return menu;
		}

		vector<Dataset*> DatasetController::getDatasets()
		{
			vector<Dataset*> result;
			HashMap<Dataset*, QTreeWidgetItem*>::Iterator it = dataset_to_item_.begin();
			for (; it != dataset_to_item_.end(); ++it)
			{
				result.push_back((*it).first);
			}

			return result;
		}

		vector<Dataset*> DatasetController::getSelectedDatasets()
		{
			vector<Dataset*> result;

			if (getDatasetControl() == 0)
			{
				BALLVIEW_DEBUG
				Log.error() << "DatasetController not bound to Dataset!" << std::endl;
				return result;
			}

			DatasetControl::ItemList il = getDatasetControl()->getSelectedItems();
			DatasetControl::ItemList::iterator it = il.begin();
			for (; it != il.end(); it++)
			{
				if (item_to_dataset_.has(*it))
				{
					result.push_back(item_to_dataset_[*it]);
				}
			}

			return result;
		}

		Dataset* DatasetController::getSelectedDataset()
		{
			vector<Dataset*> v = getSelectedDatasets();
			if (v.size() != 1) return 0;

			if (getDatasetControl()->getSelectedItems().size() == 1)
			{
				return v[0];
			}

			return 0;
		}

		bool DatasetController::deleteDatasets()
		{
			bool ok = true;

			vector<Dataset*> sets = getSelectedDatasets();
			for (Position p = 0; p < sets.size(); p++)
			{
				Dataset* dp = sets[p];
				if (dp == 0)
				{
					BALLVIEW_DEBUG
					return false;
				}

				ok &= deleteDataset(dp);
			}

			return ok;
		}

		bool DatasetController::deleteDataset()
		{
			bool ok = true;
			vector<Dataset*> v =  getSelectedDatasets();
			for (Position p = 0; p < v.size(); p++)
			{
				Dataset* set = v[p];
				if (set == 0) return false;

				ok &= deleteDataset(set);
			}

			return ok;
		}

		bool DatasetController::deleteDataset(Dataset* set)
		{
			if (getDatasetControl() == 0)
			{
				BALLVIEW_DEBUG
				Log.error() << "DatasetController not bound to Dataset!" << std::endl;
				return false;
			}

			if (set == 0)
			{
				BALLVIEW_DEBUG
				return false;
			}

			if (!dataset_to_item_.has(set))
			{
				return false;
			}

 			QTreeWidgetItem* item = dataset_to_item_[set];
			dataset_to_item_.erase(set);
			item_to_dataset_.erase(item);
			delete item;
			deleteDataset_(set);

			return true;
		}

		bool DatasetController::createMenuEntries()
		{
			if (getDatasetControl() == 0)
			{
				BALLVIEW_DEBUG
				Log.error() << "DatasetController not bound to Dataset!" << std::endl;
				return false;
			}

			QAction* action = getDatasetControl()->insertMenuEntry(MainControl::FILE_OPEN, type_, this,
												SLOT(open()), "Shortcut|File|Open|Dataset");
			actions_for_one_set_.insert(action);

			return true;
		}

		String DatasetController::getFileTypes_()
		{
			String result(type_);
			result += " (";
			for (Position p = 0; p < file_formats_.size(); p++)
			{
				result += "*.";
				result += file_formats_[p];
			}

			result += ")";
			return result;
		}

		bool DatasetController::write()
		{
			Dataset* set = getSelectedDataset();
			if (set == 0) return 0;

			QString file = QFileDialog::getSaveFileName(0,
													QString("Save as ") + type_.c_str(),
													getDatasetControl()->getWorkingDir().c_str(),
													getFileTypes_().c_str());

			if (file == QString::null) return false;

			vector<String> fields;
			String s(ascii(file));
			s.split(fields, ".");
			if (fields.size() == 0)
			{
				BALLVIEW_DEBUG
				return false;
			}

			return write(set, fields[fields.size() - 1], ascii(file));
		}

		bool DatasetController::open()
		{
			QString file = QFileDialog::getOpenFileName(0,
													QString("Open ") + type_.c_str(),
													getDatasetControl()->getWorkingDir().c_str(),
													getFileTypes_().c_str());

			if (file == QString::null) return false;

			vector<String> fields;
			String s(ascii(file));
			s.split(fields, ".");
			if (fields.size() == 0)
			{
				BALLVIEW_DEBUG
				return false;
			}

			Dataset* set = open(fields[fields.size() - 1], ascii(file));
			if (set == 0) return false;

			return insertDataset(set);
		}

		QAction* DatasetController::insertMenuEntry_(Position pid, const String& name,
																													const char* slot, const String& description,
																													QKeySequence accel)
		{
			if (getDatasetControl() == 0) return 0;
			QAction* action = getDatasetControl()->insertMenuEntry(pid, name, this, slot, description, accel);
			actions_.push_back(action);
			actions_for_one_set_.insert(action);
			return action;
		}

		String DatasetController::getNameFromFileName_(String filename)
		{
			Position pos = 0;
			for (Position p = 0; p < filename.size(); p++)
			{
				if (filename[p] == FileSystem::PATH_SEPARATOR) pos = p;
			}

			if (pos) pos++;
			return filename.getSubstring(pos);
		}

		void DatasetController::setStatusbarText(const String& text, bool important)
		{
			if (getDatasetControl() == 0) return;

			getDatasetControl()->setStatusbarText(text, important);
		}

		void DatasetController::checkMenu(MainControl& mc)
		{
			Size selected = getSelectedDatasets().size();
			Size all_selected = getDatasetControl()->getSelectionSize();

			bool other_selection = selected != all_selected;

			for (Position p = 0; p < actions_.size(); p++)
			{
				QAction& action = *actions_[p];

				if (other_selection || mc.isBusy() || selected == 0)
				{
					action.setEnabled(false);
					continue;
				}

				if (selected > 1 && actions_for_one_set_.has(&action))
				{
					action.setEnabled(false);
					continue;
				}

				action.setEnabled(true);
			}
		}

		bool DatasetController::handle(DatasetMessage* msg)
		{
			DatasetMessage::Type type = msg->getType();
			if (type == DatasetMessage::ADD)
			{
				insertDataset(msg->getDataset());
				return true;
			}

			if (type == DatasetMessage::REMOVE)
			{
				deleteDataset(msg->getDataset());
				return true;
			}

			return false;
		}

		bool DatasetController::hasDataset(Dataset* set)
		{
			return dataset_to_item_.has(set);
		}

		bool DatasetController::hasItem(QTreeWidgetItem* item)
		{
			return item_to_dataset_.has(item);
		}

		Dataset* DatasetController::getDataset(QTreeWidgetItem* item)
		{
			if (!item_to_dataset_.has(item)) return 0;
			return item_to_dataset_[item];
		}

	} // namespace VIEW
} // namespace BALL
<commit_msg>Fixed the "Double shortcut entry Shortcut|File|Open|Dataset" bug.<commit_after>// -*- Mode: C++; tab-width: 2; -*-
// vi: set ts=2:
//
// $Id: dataset.C,v 1.1.4.2 2007/05/10 21:40:37 amoll Exp $
//

#include <BALL/VIEW/DATATYPE/dataset.h>
#include <BALL/VIEW/WIDGETS/datasetControl.h>
#include <BALL/VIEW/KERNEL/common.h>
#include <BALL/VIEW/KERNEL/mainControl.h>
#include <BALL/VIEW/KERNEL/message.h>
#include <BALL/CONCEPT/molecularInformation.h>

#include <QtGui/QFileDialog>
#include <QtCore/QStringList>

using namespace std;

namespace BALL
{

	namespace VIEW
	{

		Dataset::Dataset()
			: composite_(0)
		{
		}

		Dataset::Dataset(const Dataset& ds)
			: composite_(ds.composite_),
				name_(ds.name_),
				type_(ds.type_)
		{
		}

		Dataset::~Dataset()
		{
			#ifdef BALL_VIEW_DEBUG
				cout << "Destructing object " << (void *)this << " of class " << RTTI::getName<Dataset>() << endl;
			#endif
		}

		void Dataset::clear()
		{
			composite_ = 0;
			name_ = "";
			type_ = "";
		}

		void Dataset::set(const Dataset& ds)
		{
			composite_ = ds.composite_;
			name_ = ds.name_;
			type_ = ds.type_;
		}

		const Dataset& Dataset::operator = (const Dataset& v)
		{
			set(v);
			return *this;
		}

		void Dataset::dump(std::ostream& s, Size depth) const
		{
			BALL_DUMP_STREAM_PREFIX(s);

			BALL_DUMP_DEPTH(s, depth);
			BALL_DUMP_HEADER(s, this, this);

			BALL_DUMP_STREAM_SUFFIX(s);
		}

		////////////////////////////////////////////////////////////////////////
		// Controller:

		DatasetController::DatasetController()
			: QObject(),
				Embeddable("DatasetController"),
				type_("undefined type"),
				file_formats_(),
				control_(0)
		{
			registerThis();
		}

		DatasetController::DatasetController(DatasetController& dc)
			: QObject(),
				Embeddable(dc),
				type_(dc.type_),
				file_formats_(dc.file_formats_),
				control_(dc.control_)
		{
			registerThis();
		}

		DatasetController::~DatasetController()
			throw()
		{
		}

		bool DatasetController::write(Dataset* /*set*/, String /*filetype*/, String /*filename*/)
		{
			Log.error() << "DatasetController::write() should have been overloaded in derived class!" <<std::endl;
			return false;
		}

		Dataset* DatasetController::open(String /*filetype*/, String /*filename*/)
		{
			Log.error() << "DatasetController::open() should have been overloaded in derived class!" <<std::endl;
			return 0;
		}

		bool DatasetController::insertDataset(Dataset* set)
		{
			if (getDatasetControl() == 0)
			{
				BALLVIEW_DEBUG
				Log.error() << "DatasetController not bound to Dataset!" << std::endl;
				return false;
			}

			if (set == 0)
			{
				BALLVIEW_DEBUG
				return false;
			}

			QStringList sl;
			sl << set->getName().c_str();
			if (set->getComposite() != 0)
			{
				MolecularInformation mi;
				mi.visit(*set->getComposite());
				sl << mi.getName().c_str();
			}
			else
			{
				sl << "";
			}
			sl << set->getType().c_str();

 			QTreeWidgetItem* item = getDatasetControl()->addRow(sl);
			item_to_dataset_[item] = set;
			dataset_to_item_[set]  = item;

			return true;
		}

		QMenu* DatasetController::buildContextMenu(QTreeWidgetItem* item)
		{
			if (!item_to_dataset_.has(item)) return 0;

			QMenu* menu = new QMenu(control_);
			menu->addAction("Save as...", this, SLOT(write()));
			menu->addAction("Delete", this, SLOT(deleteDataset()));
			return menu;
		}

		vector<Dataset*> DatasetController::getDatasets()
		{
			vector<Dataset*> result;
			HashMap<Dataset*, QTreeWidgetItem*>::Iterator it = dataset_to_item_.begin();
			for (; it != dataset_to_item_.end(); ++it)
			{
				result.push_back((*it).first);
			}

			return result;
		}

		vector<Dataset*> DatasetController::getSelectedDatasets()
		{
			vector<Dataset*> result;

			if (getDatasetControl() == 0)
			{
				BALLVIEW_DEBUG
				Log.error() << "DatasetController not bound to Dataset!" << std::endl;
				return result;
			}

			DatasetControl::ItemList il = getDatasetControl()->getSelectedItems();
			DatasetControl::ItemList::iterator it = il.begin();
			for (; it != il.end(); it++)
			{
				if (item_to_dataset_.has(*it))
				{
					result.push_back(item_to_dataset_[*it]);
				}
			}

			return result;
		}

		Dataset* DatasetController::getSelectedDataset()
		{
			vector<Dataset*> v = getSelectedDatasets();
			if (v.size() != 1) return 0;

			if (getDatasetControl()->getSelectedItems().size() == 1)
			{
				return v[0];
			}

			return 0;
		}

		bool DatasetController::deleteDatasets()
		{
			bool ok = true;

			vector<Dataset*> sets = getSelectedDatasets();
			for (Position p = 0; p < sets.size(); p++)
			{
				Dataset* dp = sets[p];
				if (dp == 0)
				{
					BALLVIEW_DEBUG
					return false;
				}

				ok &= deleteDataset(dp);
			}

			return ok;
		}

		bool DatasetController::deleteDataset()
		{
			bool ok = true;
			vector<Dataset*> v =  getSelectedDatasets();
			for (Position p = 0; p < v.size(); p++)
			{
				Dataset* set = v[p];
				if (set == 0) return false;

				ok &= deleteDataset(set);
			}

			return ok;
		}

		bool DatasetController::deleteDataset(Dataset* set)
		{
			if (getDatasetControl() == 0)
			{
				BALLVIEW_DEBUG
				Log.error() << "DatasetController not bound to Dataset!" << std::endl;
				return false;
			}

			if (set == 0)
			{
				BALLVIEW_DEBUG
				return false;
			}

			if (!dataset_to_item_.has(set))
			{
				return false;
			}

 			QTreeWidgetItem* item = dataset_to_item_[set];
			dataset_to_item_.erase(set);
			item_to_dataset_.erase(item);
			delete item;
			deleteDataset_(set);

			return true;
		}

		bool DatasetController::createMenuEntries()
		{
			if (getDatasetControl() == 0)
			{
				BALLVIEW_DEBUG
				Log.error() << "DatasetController not bound to Dataset!" << std::endl;
				return false;
			}

			String temp_type(type_);
			temp_type.substitute(" ", "_");
			String description = "Shortcut|File|Open|Dataset|" + temp_type;

			QAction* action = getDatasetControl()->insertMenuEntry(MainControl::FILE_OPEN, type_, this,
												SLOT(open()), description);
			actions_for_one_set_.insert(action);

			return true;
		}

		String DatasetController::getFileTypes_()
		{
			String result(type_);
			result += " (";
			for (Position p = 0; p < file_formats_.size(); p++)
			{
				result += "*.";
				result += file_formats_[p];
			}

			result += ")";
			return result;
		}

		bool DatasetController::write()
		{
			Dataset* set = getSelectedDataset();
			if (set == 0) return 0;

			QString file = QFileDialog::getSaveFileName(0,
													QString("Save as ") + type_.c_str(),
													getDatasetControl()->getWorkingDir().c_str(),
													getFileTypes_().c_str());

			if (file == QString::null) return false;

			vector<String> fields;
			String s(ascii(file));
			s.split(fields, ".");
			if (fields.size() == 0)
			{
				BALLVIEW_DEBUG
				return false;
			}

			return write(set, fields[fields.size() - 1], ascii(file));
		}

		bool DatasetController::open()
		{
			QString file = QFileDialog::getOpenFileName(0,
													QString("Open ") + type_.c_str(),
													getDatasetControl()->getWorkingDir().c_str(),
													getFileTypes_().c_str());

			if (file == QString::null) return false;

			vector<String> fields;
			String s(ascii(file));
			s.split(fields, ".");
			if (fields.size() == 0)
			{
				BALLVIEW_DEBUG
				return false;
			}

			Dataset* set = open(fields[fields.size() - 1], ascii(file));
			if (set == 0) return false;

			return insertDataset(set);
		}

		QAction* DatasetController::insertMenuEntry_(Position pid, const String& name,
																													const char* slot, const String& description,
																													QKeySequence accel)
		{
			if (getDatasetControl() == 0) return 0;
			QAction* action = getDatasetControl()->insertMenuEntry(pid, name, this, slot, description, accel);
			actions_.push_back(action);
			actions_for_one_set_.insert(action);
			return action;
		}

		String DatasetController::getNameFromFileName_(String filename)
		{
			Position pos = 0;
			for (Position p = 0; p < filename.size(); p++)
			{
				if (filename[p] == FileSystem::PATH_SEPARATOR) pos = p;
			}

			if (pos) pos++;
			return filename.getSubstring(pos);
		}

		void DatasetController::setStatusbarText(const String& text, bool important)
		{
			if (getDatasetControl() == 0) return;

			getDatasetControl()->setStatusbarText(text, important);
		}

		void DatasetController::checkMenu(MainControl& mc)
		{
			Size selected = getSelectedDatasets().size();
			Size all_selected = getDatasetControl()->getSelectionSize();

			bool other_selection = selected != all_selected;

			for (Position p = 0; p < actions_.size(); p++)
			{
				QAction& action = *actions_[p];

				if (other_selection || mc.isBusy() || selected == 0)
				{
					action.setEnabled(false);
					continue;
				}

				if (selected > 1 && actions_for_one_set_.has(&action))
				{
					action.setEnabled(false);
					continue;
				}

				action.setEnabled(true);
			}
		}

		bool DatasetController::handle(DatasetMessage* msg)
		{
			DatasetMessage::Type type = msg->getType();
			if (type == DatasetMessage::ADD)
			{
				insertDataset(msg->getDataset());
				return true;
			}

			if (type == DatasetMessage::REMOVE)
			{
				deleteDataset(msg->getDataset());
				return true;
			}

			return false;
		}

		bool DatasetController::hasDataset(Dataset* set)
		{
			return dataset_to_item_.has(set);
		}

		bool DatasetController::hasItem(QTreeWidgetItem* item)
		{
			return item_to_dataset_.has(item);
		}

		Dataset* DatasetController::getDataset(QTreeWidgetItem* item)
		{
			if (!item_to_dataset_.has(item)) return 0;
			return item_to_dataset_[item];
		}

	} // namespace VIEW
} // namespace BALL
<|endoftext|>