QTfrontend/ui/page/pageeditteam.cpp
author Wuzzy <almikes@aol.com>
Mon, 25 Sep 2017 18:02:35 +0200
changeset 12519 d89dabfd07ce
parent 12510 82c75a317d48
child 12674 bc34fc75670e
permissions -rw-r--r--
Use EndTurn to replace TurnTimeLeft=0 in ASA campaign (fixes #225)

/*
 * Hedgewars, a free turn based strategy game
 * Copyright (c) 2004-2015 Andrey Korotaev <unC0Rr@gmail.com>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; version 2 of the License
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 */

#include <QGridLayout>
#include <QHBoxLayout>
#include <QPushButton>
#include <QComboBox>
#include <QLabel>
#include <QLineEdit>
#include <QTabWidget>
#include <QGroupBox>
#include <QToolBox>
#include <QMessageBox>
#include <QStandardItemModel>
#include <QDebug>
#include "SquareLabel.h"
#include "HWApplication.h"
#include "keybinder.h"

#include "DataManager.h"
#include "hatbutton.h"

#include "pageeditteam.h"

QLayout * PageEditTeam::bodyLayoutDefinition()
{
    QGridLayout * pageLayout = new QGridLayout();
    tbw = new QTabWidget();
    QWidget * page1 = new QWidget(this);
    binder = new KeyBinder(this, tr("Select an action to choose a custom key bind for this team"), tr("Use my default"), tr("Reset all binds"));
    connect(binder, SIGNAL(resetAllBinds()), this, SLOT(resetAllBinds()));
    tbw->addTab(page1, tr("General"));
    tbw->addTab(binder, tr("Custom Controls"));
    pageLayout->addWidget(tbw, 0, 0, 1, 3);

    QHBoxLayout * page1Layout = new QHBoxLayout(page1);
    page1Layout->setAlignment(Qt::AlignTop);

// ====== Page 1 ======
    QVBoxLayout * vbox1 = new QVBoxLayout();
    QVBoxLayout * vbox2 = new QVBoxLayout();
    page1Layout->addLayout(vbox1);
    page1Layout->addLayout(vbox2);

    GBoxHedgehogs = new QGroupBox(this);
    GBoxHedgehogs->setTitle(QGroupBox::tr("Team Members"));
    GBoxHedgehogs->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
    QGridLayout * GBHLayout = new QGridLayout(GBoxHedgehogs);


    GBHLayout->addWidget(new QLabel(tr("Hat")), 0, 0);
    GBHLayout->addWidget(new QLabel(tr("Name")), 0, 1);

    for(int i = 0; i < HEDGEHOGS_PER_TEAM; i++)
    {
        HHHats[i] = new HatButton(GBoxHedgehogs);
        GBHLayout->addWidget(HHHats[i], i + 1, 0);

        HHNameEdit[i] = new QLineEdit(GBoxHedgehogs);
        HHNameEdit[i]->setMaxLength(64);
        HHNameEdit[i]->setMinimumWidth(120);
        HHNameEdit[i]->setFixedHeight(36);
        HHNameEdit[i]->setWhatsThis(tr("This hedgehog's name"));
        HHNameEdit[i]->setStyleSheet("padding: 6px;");
        GBHLayout->addWidget(HHNameEdit[i], i + 1, 1, 1, 2);

        btnRandomHogName[i] = addButton(":/res/dice.png", GBHLayout, i + 1, 5, 1, 1, true);
        btnRandomHogName[i]->setFixedHeight(HHNameEdit[i]->height());
        btnRandomHogName[i]->setWhatsThis(tr("Randomize this hedgehog's name"));
    }

    btnRandomHats = new QPushButton();
    btnRandomHats->setText(tr("Random Hats"));
    btnRandomHats->setStyleSheet("padding: 6px 10px;");
    GBHLayout->addWidget(btnRandomHats, 9, 1, 1, 1, Qt::AlignCenter);
    btnRandomHats->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);

    btnRandomNames = new QPushButton();
    btnRandomNames->setText(tr("Random Names"));
    btnRandomNames->setStyleSheet("padding: 6px 10px;");
    GBHLayout->addWidget(btnRandomNames, 9, 2, 1, 1, Qt::AlignCenter);
    btnRandomNames->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);

    vbox1->addWidget(GBoxHedgehogs);

    btnRandomTeam = new QPushButton();
    btnRandomTeam->setText(tr("Random Team"));
    btnRandomTeam->setStyleSheet("padding: 6px 10px;");
    btnRandomTeam->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
    vbox1->addWidget(btnRandomTeam, 0, Qt::AlignCenter);

    GBoxTeam = new QGroupBox(this);
    GBoxTeam->setTitle(QGroupBox::tr("Team Settings"));
    GBoxTeam->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
    QGridLayout * GBTLayout = new QGridLayout(GBoxTeam);
    QLabel * tmpLabel = new QLabel(GBoxTeam);
    tmpLabel->setText(QLabel::tr("Name"));
    GBTLayout->addWidget(tmpLabel, 0, 0);
    tmpLabel = new QLabel(GBoxTeam);
    tmpLabel->setText(QLabel::tr("Player"));
    GBTLayout->addWidget(tmpLabel, 1, 0);
    tmpLabel = new QLabel(GBoxTeam);
    tmpLabel->setText(QLabel::tr("Grave"));
    GBTLayout->addWidget(tmpLabel, 2, 0);
    tmpLabel = new QLabel(GBoxTeam);
    tmpLabel->setText(QLabel::tr("Flag"));
    GBTLayout->addWidget(tmpLabel, 3, 0);
    tmpLabel = new QLabel(GBoxTeam);
    tmpLabel->setText(QLabel::tr("Voice"));
    GBTLayout->addWidget(tmpLabel, 4, 0);

    TeamNameEdit = new QLineEdit(GBoxTeam);
    TeamNameEdit->setMaxLength(64);
    TeamNameEdit->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
    GBTLayout->addWidget(TeamNameEdit, 0, 1, 1, 2);
    vbox2->addWidget(GBoxTeam);

    CBTeamLvl = new QComboBox(GBoxTeam);
    CBTeamLvl->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
    CBTeamLvl->setIconSize(QSize(32, 32));
    CBTeamLvl->addItem(QIcon(":/res/botlevels/small0.png"), QComboBox::tr("Human"));
    for(int i = 5; i > 0; i--)
        CBTeamLvl->addItem(
            QIcon(QString(":/res/botlevels/small%1.png").arg(6 - i)),
            QComboBox::tr("Computer (Level %1)").arg(i)
        );
    CBTeamLvl->setFixedHeight(38);
    GBTLayout->addWidget(CBTeamLvl, 1, 1, 1, 2);

    CBGrave = new QComboBox(GBoxTeam);
    CBGrave->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
    CBGrave->setMaxCount(65535);
    CBGrave->setMaxVisibleItems(20);
    CBGrave->setIconSize(QSize(32, 32));
    CBGrave->setFixedHeight(44);
    GBTLayout->addWidget(CBGrave, 2, 1, 1, 2);

    // Player flags, combobox to select flag
    CBFlag = new QComboBox(GBoxTeam);
    CBFlag->setMaxCount(65535);
    CBFlag->setMaxVisibleItems(50);
    CBFlag->setIconSize(QSize(22, 15));
    CBFlag->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
    GBTLayout->addWidget(CBFlag, 3, 1, 1, 2);

    // CPU level flag. Static image, only displayed when computer player is selected
    QImage imgBotlevels = QImage("physfs://Graphics/botlevels.png");

    int botlevelOffsets[5]= { 19, 14, 10, 6, 0 };   

    for(int i=0; i<5; i++) {
        QImage imgCPU = QImage("physfs://Graphics/Flags/cpu.png");
        QPainter painter(&imgCPU);
        painter.drawImage(botlevelOffsets[i], 0, imgBotlevels, botlevelOffsets[i]);

        pixCPU[i] = QPixmap::fromImage(imgCPU);
    }

    QHBoxLayout* hboxCPU = new QHBoxLayout();
    hboxCPU->setContentsMargins(0, 0, 0, 0);

    hboxCPUWidget = new QWidget();
    hboxCPUWidget->setLayout(hboxCPU);

    CPUFlag = new QLabel();
    CPUFlag->setPixmap(pixCPU[0]);
    CPUFlag->setFixedHeight(38);

    hboxCPU->addWidget(CPUFlag);

    CPUFlagLabel = new QLabel("CPU");
    CPUFlagLabel->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
    hboxCPU->addWidget(CPUFlagLabel);

    hboxCPUWidget->setHidden(true);
    GBTLayout->addWidget(hboxCPUWidget, 3, 1, 1, 1);

    btnRandomTeamName = addButton(":/res/dice.png", GBTLayout, 0, 3, 1, 1, true);
    btnRandomTeamName->setWhatsThis(tr("Randomize the team name"));

    btnRandomGrave = addButton(":/res/dice.png", GBTLayout, 2, 3, 1, 1, true);
    btnRandomGrave->setWhatsThis(tr("Randomize the grave"));

    btnRandomFlag = addButton(":/res/dice.png", GBTLayout, 3, 3, 1, 1, true);
    btnRandomFlag->setWhatsThis(tr("Randomize the flag"));

    CBVoicepack = new QComboBox(GBoxTeam);
    CBVoicepack->setMaxVisibleItems(50);
    CBVoicepack->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);

    GBTLayout->addWidget(CBVoicepack, 4, 1, 1, 1);

    btnTestSound = addSoundlessButton(":/res/PlaySound.png", GBTLayout, 4, 2, 1, 1, true);
    btnTestSound->setWhatsThis(tr("Play a random example of this voice"));

    btnRandomVoice = addButton(":/res/dice.png", GBTLayout, 4, 3, 1, 1, true);
    btnRandomVoice->setWhatsThis(tr("Randomize the voice"));

    GBoxFort = new QGroupBox(this);
    GBoxFort->setTitle(QGroupBox::tr("Fort"));
    QGridLayout * GBFLayout = new QGridLayout(GBoxFort);
    CBFort = new QComboBox(GBoxFort);
    CBFort->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
    CBFort->setMaxVisibleItems(25);
    CBFort->setMaxCount(65535);

    GBFLayout->addWidget(CBFort, 0, 0);

    btnRandomFort = addButton(":/res/dice.png", GBFLayout, 0, 2, 1, 1, true);
    btnRandomFort->setWhatsThis(tr("Randomize the fort"));

    FortPreview = new SquareLabel(GBoxFort);
    FortPreview->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
    FortPreview->setMinimumSize(128, 128);
    FortPreview->setPixmap(QPixmap());
    // perhaps due to handling its own paintevents, SquareLabel doesn't play nice with the stars
    //FortPreview->setAttribute(Qt::WA_PaintOnScreen, true);
    GBFLayout->addWidget(FortPreview, 1, 0, 1, 2);
    vbox2->addWidget(GBoxFort);

    vbox1->addStretch();
    vbox2->addStretch();

    return pageLayout;
}

QLayout * PageEditTeam::footerLayoutDefinition()
{
    return NULL;
}

void PageEditTeam::connectSignals()
{
    connect(this, SIGNAL(pageLeave()), this, SLOT(saveTeam()));

    signalMapper1 = new QSignalMapper(this);
    signalMapper2 = new QSignalMapper(this);

    connect(signalMapper1, SIGNAL(mapped(int)), this, SLOT(fixHHname(int)));
    connect(signalMapper2, SIGNAL(mapped(int)), this, SLOT(setRandomHogName(int)));

    for(int i = 0; i < HEDGEHOGS_PER_TEAM; i++)
    {
        connect(HHNameEdit[i], SIGNAL(editingFinished()), signalMapper1, SLOT(map()));
        signalMapper1->setMapping(HHNameEdit[i], i);

        connect(btnRandomHogName[i], SIGNAL(clicked()), signalMapper2, SLOT(map()));
        signalMapper2->setMapping(btnRandomHogName[i], i);
    }

    connect(btnRandomTeam, SIGNAL(clicked()), this, SLOT(setRandomTeam()));
    connect(btnRandomNames, SIGNAL(clicked()), this, SLOT(setRandomHogNames()));
    connect(btnRandomHats, SIGNAL(clicked()), this, SLOT(setRandomHats()));

    connect(CBTeamLvl, SIGNAL(currentIndexChanged(const int)), this, SLOT(CBTeamLvl_activated(const int)));

    connect(btnRandomTeamName, SIGNAL(clicked()), this, SLOT(setRandomTeamName()));
    connect(btnRandomGrave, SIGNAL(clicked()), this, SLOT(setRandomGrave()));
    connect(btnRandomFlag, SIGNAL(clicked()), this, SLOT(setRandomFlag()));
    connect(btnRandomVoice, SIGNAL(clicked()), this, SLOT(setRandomVoice()));
    connect(btnRandomFort, SIGNAL(clicked()), this, SLOT(setRandomFort()));

    connect(btnTestSound, SIGNAL(clicked()), this, SLOT(testSound()));

    connect(CBFort, SIGNAL(currentIndexChanged(const QString &)), this, SLOT(CBFort_activated(const QString &)));
}

PageEditTeam::PageEditTeam(QWidget* parent) :
    AbstractPage(parent)
{
    initPage();

    m_playerHash = "0000000000000000000000000000000000000000";
    m_loaded = false;
}

void PageEditTeam::lazyLoad()
{
    if(m_loaded) return;
    m_loaded = true;
    qDebug("[LAZINESS] PageEditTeam::lazyLoad()");

    HatModel * hatsModel = DataManager::instance().hatModel();
    for(int i = 0; i < HEDGEHOGS_PER_TEAM; i++)
        HHHats[i]->setModel(hatsModel);


    QRegExp pngSuffix("\\.png$");
    DataManager & dataMgr = DataManager::instance();
    QStringList list;


    // voicepacks
    list = dataMgr.entryList("Sounds/voices",
                             QDir::AllDirs | QDir::NoDotAndDotDot);

    CBVoicepack->addItems(list);


    // forts
    list = dataMgr.entryList("Forts", QDir::Files, QStringList("*L.png"));
    list.replaceInStrings(QRegExp("L\\.png$"), "");
    CBFort->addItems(list);


    // graves
    list =
        dataMgr.entryList("Graphics/Graves", QDir::Files, QStringList("*.png"));

    foreach (QString file, list)
    {
        QPixmap pix("physfs://Graphics/Graves/" + file);
        if ((pix.height() > 32) || pix.width() > 32)
            pix = pix.copy(0, 0, 32, 32);
        QIcon icon(pix);

        QString grave = file.remove(pngSuffix);

        CBGrave->addItem(icon, grave);
    }

    // flags

    list =
        dataMgr.entryList("Graphics/Flags", QDir::Files, QStringList("*.png"));

    // skip cpu and hedgewars flags
    int idx = list.indexOf("cpu.png");
    if (idx >= 0)
        list.removeAt(idx);
    idx = list.indexOf("cpu_plain.png");
    if (idx >= 0)
        list.removeAt(idx);
    idx = list.indexOf("hedgewars.png");
    if (idx >= 0)
        list.removeAt(idx);

    // add the default flag
    QPixmap hwFlag("physfs://Graphics/Flags/hedgewars.png");
    CBFlag->addItem(QIcon(hwFlag.copy(0, 0, 22, 15)), "Hedgewars", "hedgewars");

    // add seperator after
    CBFlag->insertSeparator(1);

    int insertAt = 2; // insert country flags after Hedgewars flag and seperator

    // add all country flags
    foreach (const QString & file, list)
    {
        QIcon icon(QPixmap("physfs://Graphics/Flags/" + file));

        QString flag = QString(file).remove(pngSuffix);

        bool isCountryFlag = !file.startsWith("cm_");

        if (isCountryFlag)
        {
            CBFlag->insertItem(insertAt, icon, flag.replace("_", " "), flag);
            insertAt++;
        }
        else // append community flags at end
            CBFlag->addItem(icon, flag.replace("cm_", QComboBox::tr("Community") + ": "), flag);
    }

    // add separator between country flags and community flags
    CBFlag->insertSeparator(insertAt);
}

void PageEditTeam::fixHHname(int idx)
{
    HHNameEdit[idx]->setText(HHNameEdit[idx]->text().trimmed());

    if (HHNameEdit[idx]->text().isEmpty())
        HHNameEdit[idx]->setText(QLineEdit::tr("hedgehog %1").arg(idx+1));
}

void PageEditTeam::CBFort_activated(const QString & fortname)
{
    QPixmap pix("physfs://Forts/" + fortname + "L.png");
    FortPreview->setPixmap(pix);
}

void PageEditTeam::CBTeamLvl_activated(const int index)
{
    CBFlag->setHidden(index != 0);
    btnRandomFlag->setHidden(index != 0);

    if(index > 0) 
    {
        int cpuLevel = 6 - index;
        CPUFlag->setPixmap(pixCPU[cpuLevel - 1]);
        //: Name of a flag for computer-controlled enemies. %1 is replaced with the computer level
        CPUFlagLabel->setText(tr("CPU %1").arg(cpuLevel));
    }
    hboxCPUWidget->setHidden(index == 0);
}

void PageEditTeam::testSound()
{
    DataManager & dataMgr = DataManager::instance();

    QString voiceDir = QString("Sounds/voices/") + CBVoicepack->currentText();

    QStringList list = dataMgr.entryList(
                           voiceDir,
                           QDir::Files,
                           QStringList() <<
                           "Illgetyou.ogg" <<
                           "Incoming.ogg" <<
                           "Stupid.ogg" <<
                           "Coward.ogg" <<
                           "Firstblood.ogg"
                       );

    if (!list.isEmpty())
        SDLInteraction::instance().playSoundFile("/" + voiceDir + "/" +
                                    list[rand() % list.size()]);
}

void PageEditTeam::createTeam(const QString & name, const QString & playerHash)
{
    m_playerHash = playerHash;
    lazyLoad();

    // Mostly create a default team, with 2 important exceptions:
    HWTeam newTeam(name);
    // Randomize grave to make it less likely that default teams have equal graves (important for resurrector)
    HWNamegen::teamRandomGrave(newTeam, false);
    // Randomize fort for greater variety in fort mode with default teams
    HWNamegen::teamRandomFort(newTeam, false);
    // DLC forts and graves intentionally filtered out to prevent desyncs and missing grave error
    // TODO: Remove DLC filter as soon it is not needed anymore
    loadTeam(newTeam);
}

void PageEditTeam::editTeam(const QString & name, const QString & playerHash)
{
    m_playerHash = playerHash;
    lazyLoad();

    HWTeam team(name);
    team.loadFromFile();
    loadTeam(team);
}

void PageEditTeam::deleteTeam(const QString & name)
{
    QMessageBox reallyDeleteMsg(this);
    reallyDeleteMsg.setIcon(QMessageBox::Question);
    reallyDeleteMsg.setWindowTitle(QMessageBox::tr("Teams - Are you sure?"));
    reallyDeleteMsg.setText(QMessageBox::tr("Do you really want to delete the team '%1'?").arg(name));
    reallyDeleteMsg.setWindowModality(Qt::WindowModal);
    reallyDeleteMsg.setStandardButtons(QMessageBox::Ok | QMessageBox::Cancel);

    if (reallyDeleteMsg.exec() == QMessageBox::Ok)
        HWTeam(name).deleteFile();
}

void PageEditTeam::setRandomTeam()
{
    HWTeam team = data();
    HWNamegen::teamRandomEverything(team);
    loadTeam(team);
}

void PageEditTeam::setRandomHogNames()
{
    HWTeam team = data();
    HWNamegen::teamRandomHogNames(team);
    loadTeam(team);
}

void PageEditTeam::setRandomHats()
{
    HWTeam team = data();
    HWNamegen::teamRandomHats(team);
    loadTeam(team);
}

void PageEditTeam::setRandomHogName(int hh_index)
{
    HWTeam team = data();
    HWNamegen::teamRandomHogName(team,hh_index);
    loadTeam(team);
}

void PageEditTeam::setRandomTeamName()
{
    HWTeam team = data();
    HWNamegen::teamRandomTeamName(team);
    loadTeam(team);
}

void PageEditTeam::setRandomGrave()
{
    HWTeam team = data();
    HWNamegen::teamRandomGrave(team);
    loadTeam(team);
}

void PageEditTeam::setRandomFlag()
{
    HWTeam team = data();
    HWNamegen::teamRandomFlag(team);
    loadTeam(team);
}

void PageEditTeam::setRandomVoice()
{
    HWTeam team = data();
    HWNamegen::teamRandomVoice(team);
    loadTeam(team);
}

void PageEditTeam::setRandomFort()
{
    HWTeam team = data();
    HWNamegen::teamRandomFort(team);
    loadTeam(team);
}

void PageEditTeam::loadTeam(const HWTeam & team)
{
    tbw->setCurrentIndex(0);
    binder->resetInterface();

    TeamNameEdit->setText(team.name());
    CBTeamLvl->setCurrentIndex(team.difficulty());

    for(int i = 0; i < HEDGEHOGS_PER_TEAM; i++)
    {
        HWHog hh = team.hedgehog(i);

        HHNameEdit[i]->setText(hh.Name);

        if (hh.Hat.startsWith("Reserved"))
            hh.Hat = "Reserved "+hh.Hat.remove(0,40);

        HHHats[i]->setCurrentHat(hh.Hat);
    }

    CBGrave->setCurrentIndex(CBGrave->findText(team.grave()));
    CBFlag->setCurrentIndex(CBFlag->findData(team.flag()));

    CBFort->setCurrentIndex(CBFort->findText(team.fort()));
    CBVoicepack->setCurrentIndex(CBVoicepack->findText(team.voicepack()));

    QStandardItemModel * binds = DataManager::instance().bindsModel();
    for(int i = 0; i < BINDS_NUMBER; i++)
    {
        if (team.keyBind(i).isEmpty()) continue;

        QModelIndexList mdl = binds->match(binds->index(0, 0), Qt::UserRole + 1, team.keyBind(i), 1, Qt::MatchExactly);

        if(mdl.size() == 1)
            binder->setBindIndex(i, mdl[0].row());
        else
            qDebug() << "Binds: cannot find" << team.keyBind(i);
    }
}

HWTeam PageEditTeam::data()
{
    HWTeam team(TeamNameEdit->text());
    team.setDifficulty(CBTeamLvl->currentIndex());

    for(int i = 0; i < HEDGEHOGS_PER_TEAM; i++)
    {
        HWHog hh;
        hh.Name = HHNameEdit[i]->text();
        hh.Hat = HHHats[i]->currentHat();

        if (hh.Hat.startsWith("Reserved"))
            hh.Hat = "Reserved"+m_playerHash+hh.Hat.remove(0,9);

        team.setHedgehog(i,hh);
    }

    team.setGrave(CBGrave->currentText());
    team.setFort(CBFort->currentText());
    team.setVoicepack(CBVoicepack->currentText());
    team.setFlag(CBFlag->itemData(CBFlag->currentIndex()).toString());

    QStandardItemModel * binds = DataManager::instance().bindsModel();
    for(int i = 0; i < BINDS_NUMBER; i++)
    {
        team.bindKey(i, binds->index(binder->bindIndex(i), 0).data(Qt::UserRole + 1).toString());
    }

    return team;
}

void PageEditTeam::saveTeam()
{
    data().saveToFile();
}

// When the "Use default for all binds" is pressed...
void PageEditTeam::resetAllBinds()
{
    for (int i = 0; i < BINDS_NUMBER; i++)
        binder->setBindIndex(i, 0);
}