You are here

function sheetnode_plugin_style::render_sheet in Sheetnode 7.2

Same name and namespace in other branches
  1. 6 views/sheetnode_plugin_style.inc \sheetnode_plugin_style::render_sheet()
  2. 7 views/sheetnode_plugin_style.inc \sheetnode_plugin_style::render_sheet()

Render views plugin style.

3 calls to sheetnode_plugin_style::render_sheet()
sheetnode_phpexcel_plugin_style::render in modules/sheetnode_phpexcel/sheetnode_phpexcel_plugin_style.inc
Render sheetnode plugin style.
sheetnode_plugin_style::render in views/sheetnode_plugin_style.inc
Render sheetnode plugin style.
sheetnode_raw_plugin_style::render in views/sheetnode_raw_plugin_style.inc
Render plugin style.

File

views/sheetnode_plugin_style.inc, line 71

Class

sheetnode_plugin_style
Extentions for sheetnode plugin style.

Code

function render_sheet() {
  $tangent = $this->options['expansion'];
  $normal = 1 - $tangent;
  if ($this->options['use_template']) {
    $socialcalc = socialcalc_parse($this->options['template']);
    $lastpos = array(
      0,
      0,
    );

    // Iterate through cells, gathering placeholder values.
    if (!empty($socialcalc['sheet']['cells'])) {
      foreach ($socialcalc['sheet']['cells'] as $coord => $cell) {

        // Field placeholder?
        $matches = array();
        if (isset($cell['datavalue']) && $cell['datatype'] == 't') {
          if (preg_match('/^\\${(.*?)\\}$/', $cell['datavalue'], $matches)) {
            $field_name = $this
              ->find_field($matches[1]);
            if (isset($cell['comment']) && preg_match('/^\\${(.*?)\\}$/', $cell['comment'], $comment_matches)) {
              $comment_field_name = $this
                ->find_field($comment_matches[1]);
            }
            else {
              $comment_field_name = FALSE;
            }
            if ($field_name && !$this->view->field[$field_name]->options['exclude']) {

              // it's a field expansion.
              $fields[$field_name] = array(
                'coord' => $coord,
                'cell' => $cell,
                'info' => $this->view->field[$field_name],
                'comment' => $comment_field_name,
              );
            }
            else {

              // it's a formula expansion.
              $formula_expansions[] = array(
                'coord' => $coord,
                'cell' => $cell,
                'expression' => $matches[1],
                'comment' => $comment_field_name,
              );
            }
          }
          elseif (preg_match('/^\\$\\[(.*?)]$/', $cell['datavalue'], $matches)) {

            // it's a formula placement.
            $formulas[] = array(
              'coord' => $coord,
              'cell' => $cell,
              'expression' => $matches[1],
            );
          }
        }
        $lastpos = array(
          max($lastpos[0], $cell['pos'][0]),
          max($lastpos[1], $cell['pos'][1]),
        );
      }
    }

    // Replace field placeholders with actual values.
    $tangent_increment = array(
      SHEETNODE_EXPANSION_VERTICAL => 0,
      SHEETNODE_EXPANSION_HORIZONTAL => 1,
    );
    if (!empty($fields)) {
      foreach ($fields as $field_name => $field) {
        unset($socialcalc['sheet']['cells'][$field['coord']]);
        $newcell = $field['cell'];
        $pos = $maxpos = $newcell['pos'];
        $this->view->row_index = 0;
        foreach ($this->view->result as $j => $result) {
          $this->view->row_index = $j;

          // Get comment value if any.
          if ($field['comment']) {
            $comment_field = $this->view->field[$field['comment']];
            $newcell['comment'] = strip_tags($comment_field
              ->theme($result));
          }

          // Get cell value.
          $value = $field['info']
            ->theme($result);
          if (is_array($value)) {

            // Expand an array of values into consecutive cells.
            $itempos = $pos;
            foreach ($value as $item) {
              $itemcell = $newcell;
              $itemcell['pos'] = $itempos;
              $itemcell['datavalue'] = $item;
              $itemcell['datatype'] = is_numeric($item) ? 'v' : 't';
              $itemcell['valuetype'] = is_numeric($item) ? 'n' : 'th';
              $newcells[socialcalc_cr_to_coord($itempos[0], $itempos[1])] = $itemcell;
              $itempos[$tangent]++;
              $maxpos[$tangent] = max($maxpos[$tangent], $itempos[$tangent]);
            }
          }
          else {

            // Expand a single value into the current cell.
            $newcell['pos'] = $pos;
            $newcell['datavalue'] = $value;
            $newcell['datatype'] = is_numeric($value) ? 'v' : 't';
            $newcell['valuetype'] = is_numeric($value) ? 'n' : 'th';
            $newcells[socialcalc_cr_to_coord($pos[0], $pos[1])] = $newcell;
          }
          $pos[$normal]++;
        }
        $maxpos[$normal] = $pos[$normal];
        $fields[$field_name]['endpos'] = array(
          $maxpos[0] - $tangent_increment[$tangent],
          $maxpos[1] - $tangent_increment[$normal],
        );
        $lastpos = array(
          max($lastpos[0], $maxpos[0]),
          max($lastpos[1], $maxpos[1]),
        );
      }
    }

    // Replace formula expansions with actual values.
    if (!empty($formula_expansions) && !empty($fields)) {
      foreach ($formula_expansions as $fe) {
        unset($socialcalc['sheet']['cells'][$fe['coord']]);
        $newcell = $fe['cell'];
        $pos = $newcell['pos'];
        $matches = array();
        $count = preg_match_all('/@(.*?)@|\\$(.*?)\\$/', $fe['expression'], $matches);
        $this->view->row_index = 0;
        foreach ($this->view->result as $j => $result) {
          $this->view->row_index = $j;

          // Get comment value if any.
          if ($fe['comment']) {
            $comment_field = $this->view->field[$fe['comment']];
            $newcell['comment'] = strip_tags($comment_field
              ->theme($result));
          }

          // Expand formula.
          $expression = $fe['expression'];
          $newcell['pos'] = $pos;
          for ($i = 0; $i < $count; $i++) {
            $replace = NULL;
            $match = !empty($matches[1][$i]) ? $matches[1][$i] : $matches[2][$i];
            $field_name = $this
              ->find_field($match);
            if (!$field_name) {

              // Not a field: try a cell coordinate.
              if (preg_match('/^\\$?\\w\\w?\\$?\\d+$/', $match)) {
                $refpos = socialcalc_coord_to_cr($match);
                foreach ($fields as $field) {
                  if ($refpos == $field['cell']['pos']) {
                    $replace = socialcalc_cr_to_coord($field['cell']['pos'][0] + $j * $tangent_increment[$tangent], $field['cell']['pos'][1] + $j * $tangent_increment[$normal]);
                    break;
                  }
                }
              }
            }
            elseif ($matches[0][$i][0] == '@' && isset($fields[$field_name])) {
              $replace = socialcalc_cr_to_coord($fields[$field_name]['cell']['pos'][0] + $j * $tangent_increment[$tangent], $fields[$field_name]['cell']['pos'][1] + $j * $tangent_increment[$normal]);
            }
            elseif ($matches[0][$i][0] == '$') {
              $field = $this->view->field[$field_name];
              $replace = $field
                ->get_value($result);

              // Special case: empty array == NULL.
              if (is_array($replace) && empty($replace)) {
                $replace = NULL;
              }
              elseif (!is_scalar($replace) && isset($field->field_info) && isset($result->_field_data[$field->field_alias])) {
                $field_data = $result->_field_data[$field->field_alias];
                $output = '';
                foreach ($replace as $item) {
                  $element = field_view_value($field_data['entity_type'], $field_data['entity'], $field_name, $item);
                  $output .= drupal_render($element);
                }
                $replace = $output;
              }
            }
            if (!is_null($replace)) {
              $expression = str_replace($matches[0][$i], $replace, $expression);
            }
            else {
              $expression = NULL;
            }
          }
          if (!is_null($expression)) {
            $newcell['formula'] = $expression;
            $newcell['datatype'] = 'f';
            $newcell['valuetype'] = 'n';
            $newcell['datavalue'] = 0;
            $newcells[socialcalc_cr_to_coord($pos[0], $pos[1])] = $newcell;
          }
          $pos[$normal]++;
        }
        $fields[] = array(
          'cell' => $fe['cell'],
          'coord' => $fe['coord'],
          'endpos' => array(
            $pos[0] - $tangent_increment[$tangent],
            $pos[1] - $tangent_increment[$normal],
          ),
        );
        $lastpos = array(
          max($lastpos[0], $pos[0]),
          max($lastpos[1], $pos[1]),
        );
      }
    }

    // Replace formula placeholders with actual values.
    if (!empty($formulas)) {
      foreach ($formulas as $formula) {
        $newcell = $formula['cell'];
        $expression = $formula['expression'];
        $matches = array();
        $count = (int) preg_match_all('/@(.*?)@/', $expression, $matches);
        for ($i = 0; $i < $count; $i++) {
          $field_name = $this
            ->find_field($matches[1][$i]);
          if (!$field_name || !isset($fields[$field_name])) {

            // Not a field: try a cell coordinate.
            if (preg_match('/^\\$?\\w\\w?\\$?\\d+$/', $matches[1][$i])) {
              $replace = '@' . $matches[1][$i] . '@';
              $references[$formula['coord']][] = socialcalc_coord_to_cr(str_replace('$', '', $matches[1][$i]));
            }
            else {
              $replace = NULL;
            }
          }
          else {
            $field = $fields[$field_name];
            $replace = socialcalc_cr_to_coord($field['cell']['pos'][0], $field['cell']['pos'][1]) . ':' . socialcalc_cr_to_coord($field['endpos'][0], $field['endpos'][1]);
          }
          if (!is_null($replace)) {
            $expression = str_replace($matches[0][$i], $replace, $expression);
          }
          else {
            $expression = NULL;
          }
        }
        if (!is_null($expression)) {
          $newcell['formula'] = $expression;
          $newcell['datatype'] = 'f';
          $newcell['valuetype'] = 'n';
          $newcell['datavalue'] = 0;
          $socialcalc['sheet']['cells'][$formula['coord']] = $newcell;
        }
      }
    }

    // Adjust positions of all cells based on expanded values.
    if (!empty($fields)) {
      foreach ($socialcalc['sheet']['cells'] as $coord => $cell) {
        $pos = $cell['pos'];
        foreach ($fields as $field) {
          if ($pos[$tangent] == $field['cell']['pos'][$tangent] && $pos[$normal] > $field['cell']['pos'][$normal]) {
            $pos[$normal] += $field['endpos'][$normal] - $field['cell']['pos'][$normal];
            unset($socialcalc['sheet']['cells'][$coord]);
            $cell['pos'] = $pos;
            $newcoord = socialcalc_cr_to_coord($pos[0], $pos[1]);
            $socialcalc['sheet']['cells'][$newcoord] = $cell;
            if (isset($references[$coord])) {
              $references[$newcoord] = $references[$coord];
              unset($references[$coord]);
            }
            $lastpos = array(
              max($lastpos[0], $pos[0]),
              max($lastpos[1], $pos[1]),
            );
            break;
          }
        }
      }
    }

    // Adjust references in formulas based on expanded values.
    if (!empty($fields) && !empty($references)) {
      foreach ($references as $coord => $positions) {
        $cell = $socialcalc['sheet']['cells'][$coord];
        $expression = $cell['formula'];
        $matches = array();
        $count = (int) preg_match_all('/@\\$?\\w\\w?\\$?\\d+@/', $expression, $matches);
        for ($i = 0; $i < $count; $i++) {
          $pos = $positions[$i];
          foreach ($fields as $field) {
            if ($pos[$tangent] == $field['cell']['pos'][$tangent]) {
              if ($pos[$normal] == $field['cell']['pos'][$normal]) {

                // Referencing a field cell.
                $refrange = socialcalc_cr_to_coord($field['cell']['pos'][0], $field['cell']['pos'][1]) . ':' . socialcalc_cr_to_coord($field['endpos'][0], $field['endpos'][1]);
                $expression = str_replace($matches[0][$i], $refrange, $expression);
                break;
              }
              elseif ($pos[$normal] > $field['cell']['pos'][$normal]) {

                // Referencing a cell below a field.
                $pos[$normal] += $field['endpos'][$normal] - $field['cell']['pos'][$normal];
                $refcoord = socialcalc_cr_to_coord($pos[0], $pos[1], TRUE);
                $expression = preg_replace('/@(\\$?)\\w\\w?(\\$?)\\d+@/', '${1}' . $refcoord[0] . '${2}' . $refcoord[1], $expression, 1);
                break;
              }
            }
          }
        }
        $cell['formula'] = $expression;
        $socialcalc['sheet']['cells'][$coord] = $cell;
      }
    }

    // Replace values inside the sheet.
    if (!empty($newcells)) {
      $socialcalc['sheet']['cells'] += $newcells;
    }
    $socialcalc['sheet']['attribs']['lastcol'] = $lastpos[0];
    $socialcalc['sheet']['attribs']['lastrow'] = $lastpos[1];

    // Adjust starting cell in editor.
    $pos = $socialcalc['edit']['ecell']['pos'];
    if (!empty($fields)) {
      foreach ($fields as $field) {
        if ($pos[$tangent] == $field['cell']['pos'][$tangent] && $pos[$normal] > $field['cell']['pos'][$normal]) {
          $pos[$normal] += $field['endpos'][$normal] - $field['cell']['pos'][$normal];
          $ecell_changed = TRUE;
          break;
        }
      }
    }
    $socialcalc['edit']['ecell']['pos'] = $pos;
    $socialcalc['edit']['ecell']['coord'] = socialcalc_cr_to_coord($pos[0], $pos[1]);

    // Adjust row and column panes.
    $panes = $tangent == SHEETNODE_EXPANSION_VERTICAL ? 'rowpanes' : 'colpanes';
    foreach ($socialcalc['edit'][$panes] as $i => $pane) {
      $delta = 0;
      if (!empty($fields)) {
        foreach ($fields as $field) {
          if ($pane['last'] > $field['cell']['pos'][$normal]) {
            $delta = max($delta, $field['endpos'][$normal] - $field['cell']['pos'][$normal]);
          }
        }
      }
      if (!empty($ecell_changed)) {
        $socialcalc['edit'][$panes][$i]['first'] += $delta;
        $socialcalc['edit'][$panes][$i]['last'] += $delta;
      }
    }
  }
  else {

    // Hand-make default SocialCalc structure based on views results.
    $pos = array(
      1,
      1,
    );
    foreach ($this->view->field as $field => $info) {
      if ($info->options['exclude']) {
        continue;
      }
      $cell['pos'] = $pos;
      $cell['datavalue'] = $info
        ->label();
      $cell['datatype'] = 't';
      $cell['valuetype'] = 't';
      $sheet['cells'][socialcalc_cr_to_coord($pos[0], $pos[1])] = $cell;
      $pos[$tangent]++;
    }
    $pos[$normal] = 2;
    $this->view->row_index = 0;
    foreach ($this->view->result as $j => $result) {
      $this->view->row_index = $j;
      $pos[$tangent] = 1;
      foreach ($this->view->field as $field => $info) {
        if ($info->options['exclude']) {
          continue;
        }
        $value = $info
          ->theme($result);
        if (is_array($value)) {
          foreach ($value as $item) {
            $cell['pos'] = $pos;
            $cell['datavalue'] = $item;
            $cell['datatype'] = is_numeric($item) ? 'v' : 't';
            $cell['valuetype'] = is_numeric($item) ? 'n' : 'th';
            $sheet['cells'][socialcalc_cr_to_coord($pos[0], $pos[1])] = $cell;
            $pos[$tangent]++;
          }
        }
        else {
          $cell['pos'] = $pos;
          $cell['datavalue'] = $value;
          $cell['datatype'] = is_numeric($value) ? 'v' : 't';
          $cell['valuetype'] = is_numeric($value) ? 'n' : 'th';
          $sheet['cells'][socialcalc_cr_to_coord($pos[0], $pos[1])] = $cell;
          $pos[$tangent]++;
        }
      }
      $pos[$normal]++;
    }
    $sheet['attribs']['lastcol'] = $pos[0] - 1;
    $sheet['attribs']['lastrow'] = $pos[1] - 1;
    if ($tangent == SHEETNODE_EXPANSION_VERTICAL) {
      $edit['rowpanes'] = array(
        0 => array(
          'first' => 1,
          'last' => 1,
        ),
        1 => array(
          'first' => 2,
          'last' => $sheet['attribs']['lastrow'],
        ),
      );
      $edit['colpanes'] = array(
        0 => array(
          'first' => 1,
          'last' => $sheet['attribs']['lastcol'],
        ),
      );
    }
    else {
      $edit['colpanes'] = array(
        0 => array(
          'first' => 1,
          'last' => 1,
        ),
        1 => array(
          'first' => 2,
          'last' => $sheet['attribs']['lastcol'],
        ),
      );
      $edit['rowpanes'] = array(
        0 => array(
          'first' => 1,
          'last' => $sheet['attribs']['lastrow'],
        ),
      );
    }
    $edit['ecell'] = array(
      'coord' => 'A1',
    );

    // Inject the Sheetnode code.
    $socialcalc = array(
      'sheet' => $sheet,
      'edit' => $edit,
      'audit' => socialcalc_default_audit($sheet),
    );
  }

  // Merge with saved version if any.
  $this
    ->merge_annotation($socialcalc);
  unset($this->view->row_index);
  return $socialcalc;
}