@Override
  public void render(
      Renderer renderer,
      StringOutput sb,
      Component source,
      URLBuilder ubu,
      Translator translator,
      RenderResult renderResult,
      String[] args) {

    FlexiTableComponent ftC = (FlexiTableComponent) source;
    FlexiTableElementImpl ftE = ftC.getFlexiTableElement();
    String id = ftC.getFormDispatchId();

    renderHeaderButtons(renderer, sb, ftE, ubu, translator, renderResult, args);

    if (ftE.getTableDataModel().getRowCount() == 0
        && StringHelper.containsNonWhitespace(ftE.getEmtpyTableMessageKey())) {
      String emptyMessageKey = ftE.getEmtpyTableMessageKey();
      sb.append("<div class='o_info'>")
          .append(translator.translate(emptyMessageKey))
          .append("</div>");
    } else {
      sb.append("<div class='o_table_wrapper o_table_flexi")
          .append(" o_table_edit", ftE.isEditMode());
      String css = ftE.getElementCssClass();
      if (css != null) {
        sb.append(" ").append(css);
      }
      switch (ftE.getRendererType()) {
        case custom:
          sb.append(" o_rendertype_custom");
          break;
        case classic:
          sb.append(" o_rendertype_classic");
          break;
      }
      sb.append("'");
      String wrapperSelector = ftE.getWrapperSelector();
      if (wrapperSelector != null) {
        sb.append(" id='").append(wrapperSelector).append("'");
      }
      sb.append("><table id=\"")
          .append(id)
          .append("\" class=\"table table-condensed table-striped table-hover\">");

      // render headers
      renderHeaders(sb, ftC, translator);
      // render body
      sb.append("<tbody>");
      renderBody(renderer, sb, ftC, ubu, translator, renderResult);
      sb.append("</tbody></table>");
      renderFooterButtons(sb, ftC, translator);
      // draggable
      if (ftE.getColumnIndexForDragAndDropLabel() > 0) {
        sb.append("<script type='text/javascript'>")
            .append("/* <![CDATA[ */ \n")
            .append("jQuery(function() {\n")
            .append(" jQuery('.o_table_flexi table tr').draggable({\n")
            .append("  containment: '#o_main',\n")
            .append("	 zIndex: 10000,\n")
            .append("	 cursorAt: {left: 0, top: 0},\n")
            .append("	 accept: function(event,ui){ return true; },\n")
            .append("	 helper: function(event,ui,zt) {\n")
            .append("    var helperText = jQuery(this).children('.o_dnd_label').text();\n")
            .append(
                "    return jQuery(\"<div class='ui-widget-header o_table_drag'>\" + helperText + \"</div>\").appendTo('body').css('zIndex',5).show();\n")
            .append("  }\n")
            .append("});\n")
            .append("});\n")
            .append("/* ]]> */\n")
            .append("</script>\n");
      }

      sb.append("</div>");
    }

    // source
    if (source.isEnabled()) {
      FormJSHelper.appendFlexiFormDirty(sb, ftE.getRootForm(), id);
    }
  }