summaryrefslogblamecommitdiff
path: root/src/gui/setup_relations.cpp
blob: 04bfa234351ff3dc98c047fe3810df30fad6421c (plain) (tree)
1
2
3
4
5
6
7
  
                       
                                                            
                                               
  
                                             













                                                                         
                                




                               
                           







                                     
                                  

















                                                                                                                   
                  












































































































































































                                                                                    
                                            

                                                  
 
                                   
















                                                                          
                                                          
                                                           
                                                              
                                                                 
                  
 
                            

























































                                                                              


                                                                            



                                                                             



                                                            



                                                                      




                                              
                                                       



                                                       





                                                          
                                                

                                                       
                                                         




                                                 
                                   





                                          
                             

















                                                                               
                             














                                                                        
                                                   
                                                                     
                                                          
                                                             






                                                
                              









                                                           
                                                        
                                                            
                                                               
                                                                  
 
                                                           


























































                                                                              


                                                            












                                                                     


                                                                   


                                                                      
 
                                                                     








                                                                     
                                 
















                                                                              
                                       



                                                                 
 
/*
 *  The ManaPlus Client
 *  Copyright (C) 2008-2009  The Mana World Development Team
 *  Copyright (C) 2009-2010  The Mana Developers
 *  Copyright (C) 2011  The ManaPlus Developers
 *
 *  This file is part of The ManaPlus Client.
 *
 *  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; either version 2 of the License, or
 *  any later version.
 *
 *  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, see <http://www.gnu.org/licenses/>.
 */

#include "gui/setup_relations.h"

#include "actorspritemanager.h"
#include "configuration.h"
#include "localplayer.h"
#include "log.h"

#include "gui/editdialog.h"
#include "gui/okdialog.h"

#include "gui/widgets/button.h"
#include "gui/widgets/checkbox.h"
#include "gui/widgets/dropdown.h"
#include "gui/widgets/label.h"
#include "gui/widgets/layouthelper.h"
#include "gui/widgets/scrollarea.h"
#include "gui/widgets/table.h"
#include "gui/widgets/textfield.h"

#include "utils/dtor.h"
#include "utils/gettext.h"

#include <string>
#include <vector>

#define COLUMNS_NR 2 // name plus listbox
#define NAME_COLUMN 0
#define RELATION_CHOICE_COLUMN 1

#define ROW_HEIGHT 12
// The following column widths really shouldn't be hardcoded but should scale with the size of the widget... except
// that, right now, the widget doesn't exactly scale either.
#define NAME_COLUMN_WIDTH 230
#define RELATION_CHOICE_COLUMN_WIDTH 80

#define WIDGET_AT(row, column) (((row) * COLUMNS_NR) + column)

#include "debug.h"

static const char *table_titles[COLUMNS_NR] =
{
    N_("Name"),
    N_("Relation")
};

static const char *RELATION_NAMES[PlayerRelation::RELATIONS_NR] =
{
    N_("Neutral"),
    N_("Friend"),
    N_("Disregarded"),
    N_("Ignored"),
    N_("Erased")
};

class PlayerRelationListModel : public gcn::ListModel
{
public:
    virtual ~PlayerRelationListModel() { }

    virtual int getNumberOfElements()
    {
        return PlayerRelation::RELATIONS_NR;
    }

    virtual std::string getElementAt(int i)
    {
        if (i >= getNumberOfElements() || i < 0)
            return "";
        return gettext(RELATION_NAMES[i]);
    }
};

class PlayerTableModel : public TableModel
{
public:
    PlayerTableModel() :
        mPlayers(NULL),
        mListModel(new PlayerRelationListModel)
    {
        playerRelationsUpdated();
    }

    virtual ~PlayerTableModel()
    {
        freeWidgets();
        delete mListModel;
        mListModel = 0;
        delete mPlayers;
        mPlayers = 0;
    }

    virtual int getRows() const
    {
        if (mPlayers)
            return static_cast<int>(mPlayers->size());
        else
            return 0;
    }

    virtual int getColumns() const
    {
        return COLUMNS_NR;
    }

    virtual int getRowHeight() const
    {
        return ROW_HEIGHT;
    }

    virtual int getColumnWidth(int index) const
    {
        if (index == NAME_COLUMN)
            return NAME_COLUMN_WIDTH;
        else
            return RELATION_CHOICE_COLUMN_WIDTH;
    }

    virtual void playerRelationsUpdated()
    {
        signalBeforeUpdate();

        freeWidgets();
        std::vector<std::string> *player_names = player_relations.getPlayers();

        if (!player_names)
            return;

        delete mPlayers;
        mPlayers = player_names;

        // set up widgets
        for (unsigned int r = 0; r < player_names->size(); ++r)
        {
            std::string name = (*player_names)[r];
            gcn::Widget *widget = new Label(name);
            mWidgets.push_back(widget);

            gcn::DropDown *choicebox = new DropDown(mListModel);
            choicebox->setSelected(player_relations.getRelation(name));
            mWidgets.push_back(choicebox);
        }

        signalAfterUpdate();
    }

    virtual void updateModelInRow(int row)
    {
        gcn::DropDown *choicebox = static_cast<gcn::DropDown *>(
                                   getElementAt(row, RELATION_CHOICE_COLUMN));
        player_relations.setRelation(getPlayerAt(row),
                                   static_cast<PlayerRelation::Relation>(
                                   choicebox->getSelected()));
    }


    virtual gcn::Widget *getElementAt(int row, int column) const
    {
        return mWidgets[WIDGET_AT(row, column)];
    }

    virtual void freeWidgets()
    {
        delete mPlayers;
        mPlayers = 0;

        delete_all(mWidgets);
        mWidgets.clear();
    }

    std::string getPlayerAt(int index) const
    {
        return (*mPlayers)[index];
    }

protected:
    std::vector<std::string> *mPlayers;
    std::vector<gcn::Widget *> mWidgets;
    PlayerRelationListModel *mListModel;
};

/**
 * Class for choosing one of the various `what to do when ignoring a player' options
 */
class IgnoreChoicesListModel : public gcn::ListModel
{
public:
    virtual ~IgnoreChoicesListModel() { }

    virtual int getNumberOfElements()
    {
        return static_cast<int>(player_relations.getPlayerIgnoreStrategies()
                                ->size());
    }

    virtual std::string getElementAt(int i)
    {
        if (i >= getNumberOfElements() || i < 0)
            return _("???");

        return (*player_relations.getPlayerIgnoreStrategies())
            [i]->mDescription;
    }
};

#define ACTION_DELETE "delete"
#define ACTION_OLD "old"
#define ACTION_TABLE "table"
#define ACTION_STRATEGY "strategy"
#define ACTION_WHISPER_TAB "whisper tab"
#define ACTION_SHOW_GENDER "show gender"
#define ACTION_SHOW_LEVEL "show level"
#define ACTION_TARGET_DEAD "target dead"
#define ACTION_SHOW_OWN_NAME "show own name"
#define ACTION_SECURE_TRADES "secure trades"
#define ACTION_UNSECURE "unsecure"
#define ACTION_EDIT_UNSECURE "edit unsecure"
#define ACTION_EDIT_UNSECURE_OK "edit unsecure ok"

Setup_Relations::Setup_Relations():
    mPlayerTableTitleModel(new StaticTableModel(1, COLUMNS_NR)),
    mPlayerTableModel(new PlayerTableModel),
    mPlayerTable(new GuiTable(mPlayerTableModel)),
    mPlayerTitleTable(new GuiTable(mPlayerTableTitleModel)),
    mPlayerScrollArea(new ScrollArea(mPlayerTable)),
    mDefaultTrading(new CheckBox(_("Allow trading"),
                player_relations.getDefault() & PlayerRelation::TRADE)),
    mDefaultWhisper(new CheckBox(_("Allow whispers"),
                player_relations.getDefault() & PlayerRelation::WHISPER)),
    mDeleteButton(new Button(_("Delete"), ACTION_DELETE, this)),
    mOldButton(new Button(_("Old"), ACTION_OLD, this)),
    mWhisperTab(config.getBoolValue("whispertab")),
    mWhisperTabCheckBox(new CheckBox(_("Put all whispers in tabs"),
                        mWhisperTab)),
    mShowGender(config.getBoolValue("showgender")),
    mShowGenderCheckBox(new CheckBox(_("Show gender"), mShowGender)),
    mShowLevel(config.getBoolValue("showlevel")),
    mShowOwnName(config.getBoolValue("showownname")),
    mTargetDead(config.getBoolValue("targetDeadPlayers")),
    mSecureTrades(config.getBoolValue("securetrades")),
    mUnsecureChars(config.getStringValue("unsecureChars")),
    mVisibleNamesEnabled(config.getBoolValue("visiblenames")),
    mShowPlayersStatus(config.getBoolValue("showPlayersStatus")),
    mEditDialog(0)
{
    setName(_("Relations"));

    mPlayerTable->setOpaque(false);

    mPlayerTableTitleModel->fixColumnWidth(NAME_COLUMN, NAME_COLUMN_WIDTH);
    mPlayerTableTitleModel->fixColumnWidth(RELATION_CHOICE_COLUMN,
                                           RELATION_CHOICE_COLUMN_WIDTH);
    mPlayerTitleTable->setBackgroundColor(gcn::Color(0xbf, 0xbf, 0xbf));

    mIgnoreActionChoicesModel = new IgnoreChoicesListModel;
    mIgnoreActionChoicesBox = new DropDown(mIgnoreActionChoicesModel);

    for (int i = 0; i < COLUMNS_NR; i++)
    {
        mPlayerTableTitleModel->set(0, i,
                new Label(gettext(table_titles[i])));
    }

    mPlayerTitleTable->setLinewiseSelection(true);

    mPlayerScrollArea->setHorizontalScrollPolicy(gcn::ScrollArea::SHOW_NEVER);
    mPlayerTable->setActionEventId(ACTION_TABLE);
    mPlayerTable->setLinewiseSelection(true);
    mPlayerTable->addActionListener(this);

    gcn::Label *ignore_action_label = new Label(_("When ignoring:"));

    mIgnoreActionChoicesBox->setActionEventId(ACTION_STRATEGY);
    mIgnoreActionChoicesBox->addActionListener(this);

    int ignore_strategy_index = 0; // safe default

    if (player_relations.getPlayerIgnoreStrategy())
    {
        ignore_strategy_index = player_relations.getPlayerIgnoreStrategyIndex(
            player_relations.getPlayerIgnoreStrategy()->mShortName);
        if (ignore_strategy_index < 0)
            ignore_strategy_index = 0;
    }
    mIgnoreActionChoicesBox->setSelected(ignore_strategy_index);
    mIgnoreActionChoicesBox->adjustHeight();

    mWhisperTabCheckBox->setActionEventId(ACTION_WHISPER_TAB);
    mWhisperTabCheckBox->addActionListener(this);

    mShowGenderCheckBox->setActionEventId(ACTION_SHOW_GENDER);
    mShowGenderCheckBox->addActionListener(this);

    mShowLevelCheckBox = new CheckBox(_("Show level"), mShowLevel);
    mShowLevelCheckBox->setActionEventId(ACTION_SHOW_LEVEL);
    mShowLevelCheckBox->addActionListener(this);

    mShowOwnNameCheckBox = new CheckBox(_("Show own name"), mShowOwnName);
    mShowOwnNameCheckBox->setActionEventId(ACTION_SHOW_OWN_NAME);
    mShowOwnNameCheckBox->addActionListener(this);

    mTargetDeadCheckBox = new CheckBox(_("Target dead players"), mTargetDead);
    mTargetDeadCheckBox->setActionEventId(ACTION_TARGET_DEAD);
    mTargetDeadCheckBox->addActionListener(this);

    mSecureTradesCheckBox = new CheckBox(_("Secure trades"), mSecureTrades);
    mSecureTradesCheckBox->setActionEventId(ACTION_SECURE_TRADES);
    mSecureTradesCheckBox->addActionListener(this);

    mUnsecureCharsLabel = new Label(_("Unsecure chars in names"));
    mUnsecureCharsField = new TextField(mUnsecureChars,
        true, this, ACTION_UNSECURE);
    mUnsecureCharsButton = new Button(_("Edit"), ACTION_EDIT_UNSECURE, this);

    mVisibleNamesCheckBox = new CheckBox(_("Visible names"),
        mVisibleNamesEnabled);
    mVisibleNamesCheckBox->setActionEventId("visiblenames");
    mVisibleNamesCheckBox->addActionListener(this);

    mShowPlayersStatusCheckBox = new CheckBox(_("Show statuses"),
        mShowPlayersStatus);
    mShowPlayersStatusCheckBox->setActionEventId("showPlayersStatus");
    mShowPlayersStatusCheckBox->addActionListener(this);

    reset();

    // Do the layout
    LayoutHelper h(this);
    ContainerPlacer place = h.getPlacer(0, 0);

    place(0, 0, mPlayerTitleTable, 6);
    place(0, 1, mPlayerScrollArea, 6, 4).setPadding(2);
    place(0, 5, mDeleteButton);
    place(0, 6, mShowGenderCheckBox, 3).setPadding(2);
    place(0, 7, mShowLevelCheckBox, 3).setPadding(2);
    place(0, 8, mShowOwnNameCheckBox, 3).setPadding(2);
    place(1, 5, mOldButton, 1);
    place(3, 5, ignore_action_label, 1);
    place(4, 5, mIgnoreActionChoicesBox, 2).setPadding(2);
    place(3, 6, mDefaultTrading, 3);
    place(3, 7, mDefaultWhisper, 3);
    place(3, 8, mSecureTradesCheckBox, 3);
    place(3, 9, mUnsecureCharsLabel, 3);
    place(3, 10, mUnsecureCharsField, 2);
    place(3, 11, mShowPlayersStatusCheckBox, 2);
    place(5, 10, mUnsecureCharsButton, 1);
    place(0, 9, mWhisperTabCheckBox, 3).setPadding(4);
    place(0, 10, mTargetDeadCheckBox, 3).setPadding(4);
    place(0, 11, mVisibleNamesCheckBox, 3).setPadding(4);

    player_relations.addListener(this);

    setDimension(gcn::Rectangle(0, 0, 500, 350));
}

Setup_Relations::~Setup_Relations()
{
    player_relations.removeListener(this);
    delete mIgnoreActionChoicesModel;
    mIgnoreActionChoicesModel = 0;
}


void Setup_Relations::reset()
{
    // We now have to search through the list of ignore choices to find the
    // current selection. We could use an index into the table of config
    // options in player_relations instead of strategies to sidestep this.
    int selection = 0;
    for (unsigned int i = 0;
                      i < player_relations.getPlayerIgnoreStrategies()->size();
                      ++i)
        if ((*player_relations.getPlayerIgnoreStrategies())[i] ==
            player_relations.getPlayerIgnoreStrategy())
        {

            selection = i;
            break;
        }

    mIgnoreActionChoicesBox->setSelected(selection);
}

void Setup_Relations::apply()
{
    player_relations.store();

    unsigned int old_default_relations = player_relations.getDefault() &
                                         ~(PlayerRelation::TRADE |
                                           PlayerRelation::WHISPER);
    player_relations.setDefault(old_default_relations
                                | (mDefaultTrading->isSelected() ?
                                       PlayerRelation::TRADE : 0)
                                | (mDefaultWhisper->isSelected() ?
                                       PlayerRelation::WHISPER : 0));
    config.setValue("whispertab", mWhisperTab);
    config.setValue("showlevel", mShowLevel);
    config.setValue("showownname", mShowOwnName);
    config.setValue("targetDeadPlayers", mTargetDead);
    config.setValue("showgender", mShowGender);
    config.setValue("securetrades", mSecureTrades);
    config.setValue("unsecureChars", mUnsecureCharsField->getText());
    config.setValue("visiblenames", mVisibleNamesEnabled);
    config.setValue("showPlayersStatus", mShowPlayersStatus);

    if (actorSpriteManager)
        actorSpriteManager->updatePlayerNames();

    if (player_node)
        player_node->setCheckNameSetting(true);
}

void Setup_Relations::cancel()
{
    mWhisperTab = config.getBoolValue("whispertab");
    mWhisperTabCheckBox->setSelected(mWhisperTab);
    mShowGender = config.getBoolValue("showgender");
    mShowGenderCheckBox->setSelected(mShowGender);
    mShowLevel = config.getBoolValue("showlevel");
    mShowLevelCheckBox->setSelected(mShowLevel);
    mShowOwnName = config.getBoolValue("showownname");
    mShowOwnNameCheckBox->setSelected(mShowOwnName);
    mTargetDead = config.getBoolValue("targetDeadPlayers");
    mTargetDeadCheckBox->setSelected(mTargetDead);
    mSecureTrades = config.getBoolValue("securetrades");
    mSecureTradesCheckBox->setSelected(mSecureTrades);
    mUnsecureChars = config.getStringValue("unsecureChars");
    mUnsecureCharsField->setText(mUnsecureChars);
    mVisibleNamesEnabled = config.getBoolValue("visiblenames");
    mVisibleNamesCheckBox->setSelected(mVisibleNamesEnabled);
    mShowPlayersStatus = config.getBoolValue("showPlayersStatus");
    mShowPlayersStatusCheckBox->setSelected(mShowPlayersStatus);
}

void Setup_Relations::action(const gcn::ActionEvent &event)
{
    if (event.getId() == ACTION_TABLE)
    {
        // temporarily eliminate ourselves: we are fully aware of this change,
        // so there is no need for asynchronous updates.  (In fact, thouse
        // might destroy the widet that triggered them, which would be rather
        // embarrassing.)
        player_relations.removeListener(this);

        int row = mPlayerTable->getSelectedRow();
        if (row >= 0)
            mPlayerTableModel->updateModelInRow(row);

        player_relations.addListener(this);

    }
    else if (event.getId() == ACTION_DELETE)
    {
        int player_index = mPlayerTable->getSelectedRow();

        if (player_index < 0)
            return;

        std::string name = mPlayerTableModel->getPlayerAt(player_index);

        player_relations.removePlayer(name);
    }
    else if (event.getId() == ACTION_OLD)
    {
        player_relations.load(true);
        updateAll();
    }
    else if (event.getId() == ACTION_STRATEGY)
    {
        PlayerIgnoreStrategy *s =
            (*player_relations.getPlayerIgnoreStrategies())[
                mIgnoreActionChoicesBox->getSelected()];

        player_relations.setPlayerIgnoreStrategy(s);
    }
    else if (event.getId() == ACTION_WHISPER_TAB)
    {
        mWhisperTab = mWhisperTabCheckBox->isSelected();
    }
    else if (event.getId() == ACTION_SHOW_GENDER)
    {
        mShowGender = mShowGenderCheckBox->isSelected();
    }
    else if (event.getId() == ACTION_SHOW_LEVEL)
    {
        mShowLevel = mShowLevelCheckBox->isSelected();
    }
    else if (event.getId() == ACTION_SHOW_OWN_NAME)
    {
        mShowOwnName = mShowOwnNameCheckBox->isSelected();
    }
    else if (event.getId() == ACTION_TARGET_DEAD)
    {
        mTargetDead = mTargetDeadCheckBox->isSelected();
    }
    else if (event.getId() == ACTION_SECURE_TRADES)
    {
        mSecureTrades = mSecureTradesCheckBox->isSelected();
    }
    else if (event.getId() == ACTION_EDIT_UNSECURE)
    {
        mEditDialog = new EditDialog(_("Unsecure chars in names"),
            mUnsecureCharsField->getText(), ACTION_EDIT_UNSECURE_OK);
        mEditDialog->addActionListener(this);
    }
    else if (event.getId() == ACTION_EDIT_UNSECURE_OK)
    {
        mUnsecureCharsField->setText(mEditDialog->getMsg());
    }
    else if (event.getId() == ACTION_UNSECURE)
    {
        mUnsecureChars = mUnsecureCharsField->getText();
    }
    else if (event.getId() == "visiblenames")
    {
        mVisibleNamesEnabled = mVisibleNamesCheckBox->isSelected();
    }
    else if (event.getId() == "showPlayersStatus")
    {
        mShowPlayersStatus = mShowPlayersStatusCheckBox->isSelected();
    }
}

void Setup_Relations::updatedPlayer(const std::string &name A_UNUSED)
{
    mPlayerTableModel->playerRelationsUpdated();
    mDefaultTrading->setSelected(
            player_relations.getDefault() & PlayerRelation::TRADE);
    mDefaultWhisper->setSelected(
            player_relations.getDefault() & PlayerRelation::WHISPER);
    if (player_node)
        player_node->updateName();
}

void Setup_Relations::updateAll()
{
    PlayerTableModel *model = new PlayerTableModel();
    mPlayerTable->setModel(model);
    delete mPlayerTableModel;
    mPlayerTableModel = model;
    int ignore_strategy_index = 0; // safe default

    if (player_relations.getPlayerIgnoreStrategy())
    {
        ignore_strategy_index = player_relations.getPlayerIgnoreStrategyIndex(
                player_relations.getPlayerIgnoreStrategy()->mShortName);
        if (ignore_strategy_index < 0)
            ignore_strategy_index = 0;
    }
    mIgnoreActionChoicesBox->setSelected(ignore_strategy_index);
    mIgnoreActionChoicesBox->adjustHeight();
    reset();
}
void Setup_Relations::externalUpdated()
{
    mDefaultTrading->setSelected(
        player_relations.getDefault() & PlayerRelation::TRADE);
    mDefaultWhisper->setSelected(
        player_relations.getDefault() & PlayerRelation::WHISPER);
}