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