protected function getHtmlHeader(): string
  {
    $ret = '';

    if ($this->title)
    {
      $mode    = 1;
      $colspan = 0;

      $ret .= '<tr class="title">';
      foreach ($this->columns as $column)
      {
        $empty = $column->hasEmptyHeader();

        if ($mode==1)
        {
          if ($empty)
          {
            $ret .= '<th class="empty"></th>';
          }
          else
          {
            $mode = 2;
          }
        }

        if ($mode==2)
        {
          if ($empty)
          {
            $mode = 3;
          }
          else
          {
            $colspan++;
          }
        }

        if ($mode==3)
        {
          if ($colspan==1) $colspan = null;
          $ret  .= Html::generateElement('th', ['colspan' => $colspan], $this->title);
          $mode = 4;
        }

        if ($mode==4)
        {
          $ret .= '<th class="empty"></th>';
        }
      }

      if ($mode==2)
      {
        if ($colspan==1) $colspan = null;
        $ret .= Html::generateElement('th', ['colspan' => $colspan], $this->title);
      }

      $ret .= '</tr>';
    }

    $ret .= Html::generateTag('tr', ['class' => [self::$class, 'header']]);
    foreach ($this->columns as $column)
    {
      $ret .= $column->getHtmlColumnHeader();
    }
    $ret .= '</tr>';

    if ($this->filter)
    {
      $ret .= Html::generateTag('tr', ['class' => [self::$class, 'filter']]);
      foreach ($this->columns as $column)
      {
        $ret .= $column->getHtmlColumnFilter();
      }
      $ret .= '</tr>';
    }

    return $ret;
  }