| GCC Code Coverage Report | |||||||||||||||||||||
| 
 | |||||||||||||||||||||
| Line | Branch | Exec | Source | 
| 1 | /* | ||
| 2 | * The ManaPlus Client | ||
| 3 | * Copyright (C) 2004-2009 The Mana World Development Team | ||
| 4 | * Copyright (C) 2009-2010 The Mana Developers | ||
| 5 | * Copyright (C) 2011-2019 The ManaPlus Developers | ||
| 6 | * Copyright (C) 2019-2021 Andrei Karas | ||
| 7 | * | ||
| 8 | * This file is part of The ManaPlus Client. | ||
| 9 | * | ||
| 10 | * This program is free software; you can redistribute it and/or modify | ||
| 11 | * it under the terms of the GNU General Public License as published by | ||
| 12 | * the Free Software Foundation; either version 2 of the License, or | ||
| 13 | * any later version. | ||
| 14 | * | ||
| 15 | * This program is distributed in the hope that it will be useful, | ||
| 16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 18 | * GNU General Public License for more details. | ||
| 19 | * | ||
| 20 | * You should have received a copy of the GNU General Public License | ||
| 21 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 22 | */ | ||
| 23 | |||
| 24 | #include "gui/windows/charselectdialog.h" | ||
| 25 | |||
| 26 | #include "client.h" | ||
| 27 | #include "configuration.h" | ||
| 28 | #include "pincodemanager.h" | ||
| 29 | |||
| 30 | #include "listeners/charrenamelistener.h" | ||
| 31 | |||
| 32 | #include "gui/windows/charcreatedialog.h" | ||
| 33 | #include "gui/windows/chardeleteconfirm.h" | ||
| 34 | #include "gui/windows/editdialog.h" | ||
| 35 | #include "gui/windows/logindialog.h" | ||
| 36 | #include "gui/windows/okdialog.h" | ||
| 37 | #include "gui/windows/textdialog.h" | ||
| 38 | |||
| 39 | #include "gui/widgets/button.h" | ||
| 40 | #include "gui/widgets/characterdisplay.h" | ||
| 41 | #include "gui/widgets/characterviewnormal.h" | ||
| 42 | #include "gui/widgets/characterviewsmall.h" | ||
| 43 | #include "gui/widgets/containerplacer.h" | ||
| 44 | #include "gui/widgets/createwidget.h" | ||
| 45 | |||
| 46 | #include "net/character.h" | ||
| 47 | #include "net/charserverhandler.h" | ||
| 48 | #include "net/logindata.h" | ||
| 49 | #ifdef TMWA_SUPPORT | ||
| 50 | #include "net/net.h" | ||
| 51 | #endif // TMWA_SUPPORT | ||
| 52 | #include "net/serverfeatures.h" | ||
| 53 | |||
| 54 | #include "utils/foreach.h" | ||
| 55 | |||
| 56 | #include "resources/db/unitsdb.h" | ||
| 57 | |||
| 58 | #include "debug.h" | ||
| 59 | |||
| 60 | // Character slots per row in the dialog | ||
| 61 | static const int SLOTS_PER_ROW = 5; | ||
| 62 | |||
| 63 | 1 | CharSelectDialog::CharSelectDialog(LoginData &data) : | |
| 64 | // TRANSLATORS: char select dialog name | ||
| 65 | ✓✗ | 4 |     Window(strprintf(_("Account %s (last login time %s)"), | 
| 66 | data.username.c_str(), data.lastLogin.c_str()), | ||
| 67 | Modal_false, | ||
| 68 | nullptr, | ||
| 69 | "char.xml"), | ||
| 70 | ActionListener(), | ||
| 71 | KeyListener(), | ||
| 72 | mLoginData(&data), | ||
| 73 | // TRANSLATORS: char select dialog. button. | ||
| 74 | 1 |     mSwitchLoginButton(new Button(this, _("Switch"), "switch", | |
| 75 | ✓✗✓✗ | 1 | BUTTON_SKIN, this)), | 
| 76 | // TRANSLATORS: char select dialog. button. | ||
| 77 | 1 |     mChangePasswordButton(new Button(this, _("Password"), "change_password", | |
| 78 | ✓✗✓✗ | 1 | BUTTON_SKIN, this)), | 
| 79 | // TRANSLATORS: char select dialog. button. | ||
| 80 | ✓✗✓✗ | 2 |     mPlayButton(new Button(this, _("Play"), "use", BUTTON_SKIN, this)), | 
| 81 | // TRANSLATORS: char select dialog. button. | ||
| 82 | ✓✗✓✗ | 2 |     mInfoButton(new Button(this, _("Info"), "info", BUTTON_SKIN, this)), | 
| 83 | // TRANSLATORS: char select dialog. button. | ||
| 84 | ✓✗✓✗ | 2 |     mDeleteButton(new Button(this, _("Delete"), "delete", BUTTON_SKIN, this)), | 
| 85 | // TRANSLATORS: char select dialog. button. | ||
| 86 | mRenameButton(nullptr), | ||
| 87 | mChangePinButton(nullptr), | ||
| 88 | mCharacterView(nullptr), | ||
| 89 | mCharacterEntries(0), | ||
| 90 | mCharServerHandler(charServerHandler), | ||
| 91 | mDeleteDialog(nullptr), | ||
| 92 | mDeleteIndex(-1), | ||
| 93 | mLocked(false), | ||
| 94 | ✓✗ | 1 | mSmallScreen(mainGraphics->getWidth() < 470 | 
| 95 | ✓✗✓✗ ✓✗✓✗ ✓✗✓✗ ✓✗✓✗ ✓✗✓✗ ✓✗✓✗ ✓✗✓✗ ✗✓ | 45 | || mainGraphics->getHeight() < 370) | 
| 96 | { | ||
| 97 | ✓✗ | 1 | setCloseButton(true); | 
| 98 | ✓✗ | 1 | setFocusable(true); | 
| 99 | |||
| 100 | 1 | ContainerPlacer placer(nullptr, nullptr); | |
| 101 | ✓✗ | 1 | placer = getPlacer(0, 0); | 
| 102 | |||
| 103 | ✓✗ | 1 | placer(0, 0, mSwitchLoginButton, 1, 1); | 
| 104 | |||
| 105 | 1 | int n = 1; | |
| 106 | ✓✗ | 1 | placer(n, 0, mChangePasswordButton, 1, 1); | 
| 107 | 1 | n ++; | |
| 108 | ✓✗ | 1 | placer(n, 0, mDeleteButton, 1, 1); | 
| 109 | 1 | n ++; | |
| 110 | #ifdef TMWA_SUPPORT | ||
| 111 | ✓✗✓✗ | 1 | if (Net::getNetworkType() != ServerType::TMWATHENA) | 
| 112 | #endif | ||
| 113 |     { | ||
| 114 | 1 | mRenameButton = new Button(this, | |
| 115 | // TRANSLATORS: character rename button | ||
| 116 | 1 |             _("Rename"), | |
| 117 | "rename", | ||
| 118 | BUTTON_SKIN, | ||
| 119 | ✓✗✓✗ ✓✗✓✗ | 7 | this); | 
| 120 | ✓✗ | 1 | placer(n, 0, mRenameButton, 1, 1); | 
| 121 | n ++; | ||
| 122 | } | ||
| 123 | #ifdef TMWA_SUPPORT | ||
| 124 | ✓✗✓✗ | 1 | if (serverFeatures->havePincode()) | 
| 125 | #endif | ||
| 126 |     { | ||
| 127 | 1 | mChangePinButton = new Button(this, | |
| 128 | // TRANSLATORS: change pincode button | ||
| 129 | 1 |             _("Change pin"), | |
| 130 | "changepin", | ||
| 131 | BUTTON_SKIN, | ||
| 132 | ✓✗✓✗ ✓✗✓✗ | 7 | this); | 
| 133 | ✓✗ | 1 | placer(n, 0, mChangePinButton, 1, 1); | 
| 134 | 1 | n ++; | |
| 135 | } | ||
| 136 | ✓✗ | 1 | placer(n, 0, mInfoButton, 1, 1); | 
| 137 | n ++; | ||
| 138 | |||
| 139 | ✓✓ | 19 | for (int i = 0; i < CAST_S32(mLoginData->characterSlots); i++) | 
| 140 |     { | ||
| 141 | ✓✗✓✗ | 9 | CharacterDisplay *const character = new CharacterDisplay(this, this); | 
| 142 | ✓✗ | 9 | character->setVisible(Visible_false); | 
| 143 | ✓✗ | 9 | mCharacterEntries.push_back(character); | 
| 144 | } | ||
| 145 | |||
| 146 | ✓✗ | 1 | placer(0, 2, mPlayButton, 1, 1); | 
| 147 | |||
| 148 | ✓✗ | 1 | if (!mSmallScreen) | 
| 149 |     { | ||
| 150 | 1 | mCharacterView = new CharacterViewNormal( | |
| 151 | ✓✗✓✗ | 1 | this, &mCharacterEntries, mPadding); | 
| 152 | ✓✗ | 1 | placer(0, 1, mCharacterView, 10, 1); | 
| 153 | 1 | int sz = 410 + 2 * mPadding; | |
| 154 | ✓✗✓✗ ✗✓ | 4 |         if (config.getIntValue("fontSize") > 18) | 
| 155 | sz = 500 + 2 * mPadding; | ||
| 156 | 2 | const int width = mCharacterView->getWidth() + 2 * mPadding; | |
| 157 | ✓✗ | 1 | if (sz < width) | 
| 158 | 1 | sz = width; | |
| 159 | ✓✗✗✓ | 1 | if (sz > mainGraphics->getWidth()) | 
| 160 | sz = mainGraphics->getWidth(); | ||
| 161 | ✓✗ | 1 | reflowLayout(sz, 0); | 
| 162 | } | ||
| 163 | else | ||
| 164 |     { | ||
| 165 | // TRANSLATORS: char select dialog name | ||
| 166 |         setCaption(strprintf(_("Account %s"), mLoginData->username.c_str())); | ||
| 167 | mCharacterView = new CharacterViewSmall( | ||
| 168 | this, &mCharacterEntries, mPadding); | ||
| 169 | mCharacterView->setWidth(mainGraphics->getWidth() | ||
| 170 | - 2 * getPadding()); | ||
| 171 | placer(0, 1, mCharacterView, 10, 1); | ||
| 172 | reflowLayout(0, 0); | ||
| 173 | } | ||
| 174 | ✓✗ | 1 | addKeyListener(this); | 
| 175 | ✓✗ | 1 | center(); | 
| 176 | |||
| 177 | ✓✗ | 1 | charServerHandler->setCharSelectDialog(this); | 
| 178 | ✓✗ | 1 | mCharacterView->show(0); | 
| 179 | ✓✗ | 1 | updateState(); | 
| 180 | 1 | } | |
| 181 | |||
| 182 | 6 | CharSelectDialog::~CharSelectDialog() | |
| 183 | { | ||
| 184 | 1 | mDeleteDialog = nullptr; | |
| 185 | 2 | } | |
| 186 | |||
| 187 | 1 | void CharSelectDialog::postInit() | |
| 188 | { | ||
| 189 | 1 | Window::postInit(); | |
| 190 | 1 | setVisible(Visible_true); | |
| 191 | 1 | requestFocus(); | |
| 192 | 1 | } | |
| 193 | |||
| 194 | void CharSelectDialog::action(const ActionEvent &event) | ||
| 195 | { | ||
| 196 | // Check if a button of a character was pressed | ||
| 197 | const Widget *const sourceParent = event.getSource()->getParent(); | ||
| 198 | int selected = -1; | ||
| 199 | for (unsigned int i = 0, fsz = CAST_U32( | ||
| 200 | mCharacterEntries.size()); | ||
| 201 | i < fsz; | ||
| 202 | ++i) | ||
| 203 |     { | ||
| 204 | if (mCharacterEntries[i] == sourceParent) | ||
| 205 |         { | ||
| 206 | selected = i; | ||
| 207 | mCharacterView->show(i); | ||
| 208 | updateState(); | ||
| 209 | break; | ||
| 210 | } | ||
| 211 | } | ||
| 212 | if (selected == -1) | ||
| 213 | selected = mCharacterView->getSelected(); | ||
| 214 | |||
| 215 | const std::string &eventId = event.getId(); | ||
| 216 | const bool blocked = pincodeManager.isBlocked(); | ||
| 217 | |||
| 218 | if (selected >= 0) | ||
| 219 |     { | ||
| 220 | if (blocked) | ||
| 221 | return; | ||
| 222 | if (eventId == "use") | ||
| 223 |         { | ||
| 224 | use(selected); | ||
| 225 | return; | ||
| 226 | } | ||
| 227 | else if (eventId == "delete" | ||
| 228 | && (mCharacterEntries[selected]->getCharacter() != nullptr)) | ||
| 229 |         { | ||
| 230 | CREATEWIDGET(CharDeleteConfirm, this, selected); | ||
| 231 | return; | ||
| 232 | } | ||
| 233 | else if (eventId == "rename" | ||
| 234 | && (mCharacterEntries[selected]->getCharacter() != nullptr)) | ||
| 235 |         { | ||
| 236 | const LocalPlayer *const player = mCharacterEntries[ | ||
| 237 | selected]->getCharacter()->dummy; | ||
| 238 | EditDialog *const dialog = CREATEWIDGETR(EditDialog, | ||
| 239 | // TRANSLATORS: character rename dialog header. | ||
| 240 |                 _("Please enter new name"), | ||
| 241 | player->getName(), | ||
| 242 | "OK", | ||
| 243 | 300, | ||
| 244 | nullptr, | ||
| 245 | Modal_true); | ||
| 246 | charRenameListener.setId(player->getId()); | ||
| 247 | charRenameListener.setDialog(dialog); | ||
| 248 | dialog->addActionListener(&charRenameListener); | ||
| 249 | } | ||
| 250 | else if (eventId == "info") | ||
| 251 |         { | ||
| 252 | Net::Character *const character = mCharacterEntries[ | ||
| 253 | selected]->getCharacter(); | ||
| 254 | if (character == nullptr) | ||
| 255 | return; | ||
| 256 | |||
| 257 | const LocalPlayer *const data = character->dummy; | ||
| 258 | if (data == nullptr) | ||
| 259 | return; | ||
| 260 | |||
| 261 | const std::string strExp = toString(CAST_U64( | ||
| 262 | character->data.mAttributes[Attributes::PLAYER_EXP])); | ||
| 263 | const std::string msg = strprintf( | ||
| 264 | // TRANSLATORS: char select dialog. player info message. | ||
| 265 |                 _("Hp: %u/%u\nMp: %u/%u\nLevel: %u\n" | ||
| 266 | "Experience: %s\nMoney: %s"), | ||
| 267 | CAST_U32( | ||
| 268 | character->data.mAttributes[Attributes::PLAYER_HP]), | ||
| 269 | CAST_U32( | ||
| 270 | character->data.mAttributes[Attributes::PLAYER_MAX_HP]), | ||
| 271 | CAST_U32( | ||
| 272 | character->data.mAttributes[Attributes::PLAYER_MP]), | ||
| 273 | CAST_U32( | ||
| 274 | character->data.mAttributes[Attributes::PLAYER_MAX_MP]), | ||
| 275 | CAST_U32( | ||
| 276 | character->data.mAttributes[Attributes::PLAYER_BASE_LEVEL]), | ||
| 277 | strExp.c_str(), | ||
| 278 | UnitsDb::formatCurrency(CAST_S32( | ||
| 279 | character->data.mAttributes[Attributes::MONEY])).c_str()); | ||
| 280 | CREATEWIDGET(OkDialog, data->getName(), msg, | ||
| 281 | // TRANSLATORS: ok dialog button | ||
| 282 |                 _("OK"), | ||
| 283 | DialogType::SILENCE, | ||
| 284 | Modal_true, | ||
| 285 | ShowCenter_true, | ||
| 286 | nullptr, | ||
| 287 | 260); | ||
| 288 | } | ||
| 289 | } | ||
| 290 | if (eventId == "switch") | ||
| 291 |     { | ||
| 292 | charServerHandler->clear(); | ||
| 293 | close(); | ||
| 294 | } | ||
| 295 | else if (eventId == "change_password") | ||
| 296 |     { | ||
| 297 | if (blocked) | ||
| 298 | return; | ||
| 299 | client->setState(State::CHANGEPASSWORD); | ||
| 300 | } | ||
| 301 | else if (eventId == "change_email") | ||
| 302 |     { | ||
| 303 | if (blocked) | ||
| 304 | return; | ||
| 305 | client->setState(State::CHANGEEMAIL); | ||
| 306 | } | ||
| 307 | else if (eventId == "try delete character") | ||
| 308 |     { | ||
| 309 | if (blocked) | ||
| 310 | return; | ||
| 311 | if ((mDeleteDialog != nullptr) && mDeleteIndex != -1) | ||
| 312 |         { | ||
| 313 | if (serverFeatures->haveEmailOnDelete()) | ||
| 314 |             { | ||
| 315 | attemptCharacterDelete(mDeleteIndex, mDeleteDialog->getText()); | ||
| 316 | mDeleteDialog = nullptr; | ||
| 317 | } | ||
| 318 | else if (mDeleteDialog->getText() == LoginDialog::savedPassword) | ||
| 319 |             { | ||
| 320 | attemptCharacterDelete(mDeleteIndex, ""); | ||
| 321 | mDeleteDialog = nullptr; | ||
| 322 | } | ||
| 323 | else | ||
| 324 |             { | ||
| 325 | CREATEWIDGET(OkDialog, | ||
| 326 | // TRANSLATORS: error header | ||
| 327 |                     _("Error"), | ||
| 328 | // TRANSLATORS: error message | ||
| 329 |                     _("Incorrect password"), | ||
| 330 | // TRANSLATORS: ok dialog button | ||
| 331 |                     _("OK"), | ||
| 332 | DialogType::ERROR, | ||
| 333 | Modal_true, | ||
| 334 | ShowCenter_true, | ||
| 335 | nullptr, | ||
| 336 | 260); | ||
| 337 | } | ||
| 338 | } | ||
| 339 | mDeleteIndex = -1; | ||
| 340 | } | ||
| 341 | else if (eventId == "changepin") | ||
| 342 |     { | ||
| 343 | if (blocked) | ||
| 344 | return; | ||
| 345 | pincodeManager.setState(PincodeState::Change); | ||
| 346 | pincodeManager.updateState(); | ||
| 347 | } | ||
| 348 | } | ||
| 349 | |||
| 350 | void CharSelectDialog::use(const int selected) | ||
| 351 | { | ||
| 352 | if ((mCharacterEntries[selected] != nullptr) | ||
| 353 | && (mCharacterEntries[selected]->getCharacter() != nullptr)) | ||
| 354 |     { | ||
| 355 | attemptCharacterSelect(selected); | ||
| 356 | } | ||
| 357 | else | ||
| 358 |     { | ||
| 359 | CharCreateDialog *const charCreateDialog = | ||
| 360 | CREATEWIDGETR(CharCreateDialog, this, selected); | ||
| 361 | mCharServerHandler->setCharCreateDialog(charCreateDialog); | ||
| 362 | } | ||
| 363 | } | ||
| 364 | |||
| 365 | void CharSelectDialog::keyPressed(KeyEvent &event) | ||
| 366 | { | ||
| 367 | const InputActionT actionId = event.getActionId(); | ||
| 368 | const bool blocked = pincodeManager.isBlocked(); | ||
| 369 | PRAGMA45(GCC diagnostic push) | ||
| 370 | PRAGMA45(GCC diagnostic ignored "-Wswitch-enum") | ||
| 371 | switch (actionId) | ||
| 372 |     { | ||
| 373 | case InputAction::GUI_CANCEL: | ||
| 374 | event.consume(); | ||
| 375 | action(ActionEvent(mSwitchLoginButton, | ||
| 376 | mSwitchLoginButton->getActionEventId())); | ||
| 377 | break; | ||
| 378 | |||
| 379 | case InputAction::GUI_RIGHT: | ||
| 380 |         { | ||
| 381 | event.consume(); | ||
| 382 | int idx = mCharacterView->getSelected(); | ||
| 383 | if (idx >= 0) | ||
| 384 |             { | ||
| 385 | if ((idx + 1) % SLOTS_PER_ROW == 0) | ||
| 386 | break; | ||
| 387 | idx ++; | ||
| 388 | mCharacterView->show(idx); | ||
| 389 | updateState(); | ||
| 390 | } | ||
| 391 | break; | ||
| 392 | } | ||
| 393 | |||
| 394 | case InputAction::GUI_LEFT: | ||
| 395 |         { | ||
| 396 | event.consume(); | ||
| 397 | int idx = mCharacterView->getSelected(); | ||
| 398 | if (idx >= 0) | ||
| 399 |             { | ||
| 400 | if (idx == 0 || idx % SLOTS_PER_ROW == 0) | ||
| 401 | break; | ||
| 402 | idx --; | ||
| 403 | mCharacterView->show(idx); | ||
| 404 | updateState(); | ||
| 405 | } | ||
| 406 | break; | ||
| 407 | } | ||
| 408 | |||
| 409 | case InputAction::GUI_UP: | ||
| 410 |         { | ||
| 411 | event.consume(); | ||
| 412 | int idx = mCharacterView->getSelected(); | ||
| 413 | if (idx >= 0) | ||
| 414 |             { | ||
| 415 | if (idx < SLOTS_PER_ROW) | ||
| 416 | break; | ||
| 417 | idx -= SLOTS_PER_ROW; | ||
| 418 | mCharacterView->show(idx); | ||
| 419 | updateState(); | ||
| 420 | } | ||
| 421 | break; | ||
| 422 | } | ||
| 423 | |||
| 424 | case InputAction::GUI_DOWN: | ||
| 425 |         { | ||
| 426 | event.consume(); | ||
| 427 | int idx = mCharacterView->getSelected(); | ||
| 428 | if (idx >= 0) | ||
| 429 |             { | ||
| 430 | if (idx >= mLoginData->characterSlots - SLOTS_PER_ROW) | ||
| 431 | break; | ||
| 432 | idx += SLOTS_PER_ROW; | ||
| 433 | mCharacterView->show(idx); | ||
| 434 | updateState(); | ||
| 435 | } | ||
| 436 | break; | ||
| 437 | } | ||
| 438 | |||
| 439 | case InputAction::GUI_DELETE: | ||
| 440 |         { | ||
| 441 | if (blocked) | ||
| 442 | return; | ||
| 443 | event.consume(); | ||
| 444 | const int idx = mCharacterView->getSelected(); | ||
| 445 | if (idx >= 0 && (mCharacterEntries[idx] != nullptr) | ||
| 446 | && (mCharacterEntries[idx]->getCharacter() != nullptr)) | ||
| 447 |             { | ||
| 448 | CREATEWIDGET(CharDeleteConfirm, this, idx); | ||
| 449 | } | ||
| 450 | break; | ||
| 451 | } | ||
| 452 | |||
| 453 | case InputAction::GUI_SELECT: | ||
| 454 |         { | ||
| 455 | if (blocked) | ||
| 456 | return; | ||
| 457 | event.consume(); | ||
| 458 | use(mCharacterView->getSelected()); | ||
| 459 | break; | ||
| 460 | } | ||
| 461 | default: | ||
| 462 | break; | ||
| 463 | } | ||
| 464 | PRAGMA45(GCC diagnostic pop) | ||
| 465 | } | ||
| 466 | |||
| 467 | /** | ||
| 468 | * Communicate character deletion to the server. | ||
| 469 | */ | ||
| 470 | void CharSelectDialog::attemptCharacterDelete(const int index, | ||
| 471 | const std::string &email) | ||
| 472 | { | ||
| 473 | if (mLocked) | ||
| 474 | return; | ||
| 475 | |||
| 476 | if (mCharacterEntries[index] != nullptr) | ||
| 477 |     { | ||
| 478 | mCharServerHandler->deleteCharacter( | ||
| 479 | mCharacterEntries[index]->getCharacter(), | ||
| 480 | email); | ||
| 481 | } | ||
| 482 | lock(); | ||
| 483 | } | ||
| 484 | |||
| 485 | void CharSelectDialog::askPasswordForDeletion(const int index) | ||
| 486 | { | ||
| 487 | mDeleteIndex = index; | ||
| 488 | if (serverFeatures->haveEmailOnDelete()) | ||
| 489 |     { | ||
| 490 | CREATEWIDGETV(mDeleteDialog, TextDialog, | ||
| 491 | // TRANSLATORS: char deletion question. | ||
| 492 |             _("Enter your email for deleting character"), | ||
| 493 | // TRANSLATORS: email label. | ||
| 494 |             _("Enter email:"), | ||
| 495 | this, | ||
| 496 | false); | ||
| 497 | } | ||
| 498 | else | ||
| 499 |     { | ||
| 500 | CREATEWIDGETV(mDeleteDialog, TextDialog, | ||
| 501 | // TRANSLATORS: char deletion question. | ||
| 502 |             _("Enter password for deleting character"), | ||
| 503 | // TRANSLATORS: email label. | ||
| 504 |             _("Enter password:"), | ||
| 505 | this, | ||
| 506 | true); | ||
| 507 | } | ||
| 508 |     mDeleteDialog->setActionEventId("try delete character"); | ||
| 509 | mDeleteDialog->addActionListener(this); | ||
| 510 | } | ||
| 511 | |||
| 512 | /** | ||
| 513 | * Communicate character selection to the server. | ||
| 514 | */ | ||
| 515 | void CharSelectDialog::attemptCharacterSelect(const int index) | ||
| 516 | { | ||
| 517 | if (mLocked || (mCharacterEntries[index] == nullptr)) | ||
| 518 | return; | ||
| 519 | |||
| 520 | setVisible(Visible_false); | ||
| 521 | if (mCharServerHandler != nullptr) | ||
| 522 |     { | ||
| 523 | mCharServerHandler->chooseCharacter( | ||
| 524 | mCharacterEntries[index]->getCharacter()); | ||
| 525 | } | ||
| 526 | lock(); | ||
| 527 | } | ||
| 528 | |||
| 529 | 1 | void CharSelectDialog::setCharacters(const Net::Characters &characters) | |
| 530 | { | ||
| 531 | // Reset previous characters | ||
| 532 | ✓✓ | 15 | FOR_EACH (STD_VECTOR<CharacterDisplay*>::const_iterator, | 
| 533 | iter, mCharacterEntries) | ||
| 534 |     { | ||
| 535 | ✓✗ | 9 | if (*iter != nullptr) | 
| 536 | 9 | (*iter)->setCharacter(nullptr); | |
| 537 | } | ||
| 538 | |||
| 539 | ✗✓ | 3 | FOR_EACH (Net::Characters::const_iterator, i, characters) | 
| 540 | setCharacter(*i); | ||
| 541 | 1 | updateState(); | |
| 542 | 1 | } | |
| 543 | |||
| 544 | void CharSelectDialog::setCharacter(Net::Character *const character) | ||
| 545 | { | ||
| 546 | if (character == nullptr) | ||
| 547 | return; | ||
| 548 | const int characterSlot = character->slot; | ||
| 549 | if (characterSlot >= CAST_S32(mCharacterEntries.size())) | ||
| 550 |     { | ||
| 551 |         logger->log("Warning: slot out of range: %d", character->slot); | ||
| 552 | return; | ||
| 553 | } | ||
| 554 | |||
| 555 | if (mCharacterEntries[characterSlot] != nullptr) | ||
| 556 | mCharacterEntries[characterSlot]->setCharacter(character); | ||
| 557 | } | ||
| 558 | |||
| 559 | void CharSelectDialog::lock() | ||
| 560 | { | ||
| 561 | if (!mLocked) | ||
| 562 | setLocked(true); | ||
| 563 | } | ||
| 564 | |||
| 565 | void CharSelectDialog::unlock() | ||
| 566 | { | ||
| 567 | setLocked(false); | ||
| 568 | } | ||
| 569 | |||
| 570 | void CharSelectDialog::setLocked(const bool locked) | ||
| 571 | { | ||
| 572 | mLocked = locked; | ||
| 573 | |||
| 574 | if (mSwitchLoginButton != nullptr) | ||
| 575 | mSwitchLoginButton->setEnabled(!locked); | ||
| 576 | if (mChangePasswordButton != nullptr) | ||
| 577 | mChangePasswordButton->setEnabled(!locked); | ||
| 578 | mPlayButton->setEnabled(!locked); | ||
| 579 | if (mDeleteButton != nullptr) | ||
| 580 | mDeleteButton->setEnabled(!locked); | ||
| 581 | |||
| 582 | for (size_t i = 0, sz = mCharacterEntries.size(); i < sz; ++i) | ||
| 583 |     { | ||
| 584 | if (mCharacterEntries[i] != nullptr) | ||
| 585 | mCharacterEntries[i]->setActive(!mLocked); | ||
| 586 | } | ||
| 587 | } | ||
| 588 | |||
| 589 | bool CharSelectDialog::selectByName(const std::string &name, | ||
| 590 | const SelectAction selAction) | ||
| 591 | { | ||
| 592 | if (mLocked) | ||
| 593 | return false; | ||
| 594 | |||
| 595 | for (size_t i = 0, sz = mCharacterEntries.size(); i < sz; ++i) | ||
| 596 |     { | ||
| 597 | if (mCharacterEntries[i] != nullptr) | ||
| 598 |         { | ||
| 599 | const Net::Character *const character | ||
| 600 | = mCharacterEntries[i]->getCharacter(); | ||
| 601 | if (character != nullptr) | ||
| 602 |             { | ||
| 603 | if (character->dummy != nullptr && | ||
| 604 | character->dummy->getName() == name) | ||
| 605 |                 { | ||
| 606 | mCharacterView->show(CAST_S32(i)); | ||
| 607 | updateState(); | ||
| 608 | if (selAction == Choose) | ||
| 609 | attemptCharacterSelect(CAST_S32(i)); | ||
| 610 | return true; | ||
| 611 | } | ||
| 612 | } | ||
| 613 | } | ||
| 614 | } | ||
| 615 | |||
| 616 | return false; | ||
| 617 | } | ||
| 618 | |||
| 619 | void CharSelectDialog::close() | ||
| 620 | { | ||
| 621 | client->setState(State::SWITCH_LOGIN); | ||
| 622 | Window::close(); | ||
| 623 | } | ||
| 624 | |||
| 625 | 1 | void CharSelectDialog::widgetResized(const Event &event) | |
| 626 | { | ||
| 627 | 1 | Window::widgetResized(event); | |
| 628 | 1 | mCharacterView->resize(); | |
| 629 | 1 | } | |
| 630 | |||
| 631 | 2 | void CharSelectDialog::updateState() | |
| 632 | { | ||
| 633 | 2 | const int idx = mCharacterView->getSelected(); | |
| 634 | ✗✓ | 2 | if (idx == -1) | 
| 635 |     { | ||
| 636 | mPlayButton->setEnabled(false); | ||
| 637 | return; | ||
| 638 | } | ||
| 639 | 4 | mPlayButton->setEnabled(true); | |
| 640 | |||
| 641 | ✓✗✓✗ ✗✓ | 6 | if (mCharacterEntries[idx] != nullptr && | 
| 642 | 2 | mCharacterEntries[idx]->getCharacter() != nullptr) | |
| 643 |     { | ||
| 644 | // TRANSLATORS: char select dialog. button. | ||
| 645 |         mPlayButton->setCaption(_("Play")); | ||
| 646 | |||
| 647 | const LocalPlayer *const player = mCharacterEntries[ | ||
| 648 | idx]->getCharacter()->dummy; | ||
| 649 | if ((player != nullptr) && (mRenameButton != nullptr)) | ||
| 650 | mRenameButton->setEnabled(player->getRename() ? true : false); | ||
| 651 | } | ||
| 652 | else | ||
| 653 |     { | ||
| 654 | // TRANSLATORS: char select dialog. button. | ||
| 655 | 10 |         mPlayButton->setCaption(_("Create")); | |
| 656 | } | ||
| 657 | } | ||
| 658 | |||
| 659 | void CharSelectDialog::setName(const BeingId id, const std::string &newName) | ||
| 660 | { | ||
| 661 | for (unsigned int i = 0, fsz = CAST_U32( | ||
| 662 | mCharacterEntries.size()); | ||
| 663 | i < fsz; | ||
| 664 | ++i) | ||
| 665 |     { | ||
| 666 | CharacterDisplay *const character = mCharacterEntries[i]; | ||
| 667 | if (character == nullptr) | ||
| 668 | continue; | ||
| 669 | LocalPlayer *const player = character->getCharacter()->dummy; | ||
| 670 | if ((player != nullptr) && player->getId() == id) | ||
| 671 |         { | ||
| 672 | player->setName(newName); | ||
| 673 | character->update(); | ||
| 674 | return; | ||
| 675 | } | ||
| 676 | } | ||
| 677 | ✓✗✓✗ | 3 | } | 
| Generated by: GCOVR (Version 3.3) |