Allow to delete savegames (shift + click)

actorid
scrawl 11 years ago
parent 7f37f2c2be
commit 7a0aeeaa38

@ -55,6 +55,8 @@ namespace MWBase
virtual void endGame() = 0; virtual void endGame() = 0;
virtual void deleteGame (const MWState::Character *character, const MWState::Slot *slot) = 0;
virtual void saveGame (const std::string& description, const MWState::Slot *slot = 0) = 0; virtual void saveGame (const std::string& description, const MWState::Slot *slot = 0) = 0;
///< Write a saved game to \a slot or create a new slot if \a slot == 0. ///< Write a saved game to \a slot or create a new slot if \a slot == 0.
/// ///

@ -23,6 +23,7 @@ namespace MWGui
: WindowModal("openmw_savegame_dialog.layout") : WindowModal("openmw_savegame_dialog.layout")
, mSaving(true) , mSaving(true)
, mCurrentCharacter(NULL) , mCurrentCharacter(NULL)
, mCurrentSlot(NULL)
{ {
getWidget(mScreenshot, "Screenshot"); getWidget(mScreenshot, "Screenshot");
getWidget(mCharacterSelection, "SelectCharacter"); getWidget(mCharacterSelection, "SelectCharacter");
@ -36,6 +37,7 @@ namespace MWGui
mCancelButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SaveGameDialog::onCancelButtonClicked); mCancelButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SaveGameDialog::onCancelButtonClicked);
mCharacterSelection->eventComboChangePosition += MyGUI::newDelegate(this, &SaveGameDialog::onCharacterSelected); mCharacterSelection->eventComboChangePosition += MyGUI::newDelegate(this, &SaveGameDialog::onCharacterSelected);
mSaveList->eventListChangePosition += MyGUI::newDelegate(this, &SaveGameDialog::onSlotSelected); mSaveList->eventListChangePosition += MyGUI::newDelegate(this, &SaveGameDialog::onSlotSelected);
mSaveList->eventListMouseItemActivate += MyGUI::newDelegate(this, &SaveGameDialog::onSlotMouseClick);
mSaveList->eventListSelectAccept += MyGUI::newDelegate(this, &SaveGameDialog::onSlotActivated); mSaveList->eventListSelectAccept += MyGUI::newDelegate(this, &SaveGameDialog::onSlotActivated);
mSaveNameEdit->eventEditSelectAccept += MyGUI::newDelegate(this, &SaveGameDialog::onEditSelectAccept); mSaveNameEdit->eventEditSelectAccept += MyGUI::newDelegate(this, &SaveGameDialog::onEditSelectAccept);
mSaveNameEdit->eventEditTextChange += MyGUI::newDelegate(this, &SaveGameDialog::onSaveNameChanged); mSaveNameEdit->eventEditTextChange += MyGUI::newDelegate(this, &SaveGameDialog::onSaveNameChanged);
@ -47,6 +49,37 @@ namespace MWGui
accept(); accept();
} }
void SaveGameDialog::onSlotMouseClick(MyGUI::ListBox* sender, size_t pos)
{
onSlotSelected(sender, pos);
if (MyGUI::InputManager::getInstance().isShiftPressed())
{
ConfirmationDialog* dialog = MWBase::Environment::get().getWindowManager()->getConfirmationDialog();
dialog->open("#{sMessage3}");
dialog->eventOkClicked.clear();
dialog->eventOkClicked += MyGUI::newDelegate(this, &SaveGameDialog::onDeleteSlotConfirmed);
dialog->eventCancelClicked.clear();
}
}
void SaveGameDialog::onDeleteSlotConfirmed()
{
MWBase::Environment::get().getStateManager()->deleteGame (mCurrentCharacter, mCurrentSlot);
mSaveList->removeItemAt(mSaveList->getIndexSelected());
onSlotSelected(mSaveList, MyGUI::ITEM_NONE);
// The character might be deleted now
size_t previousIndex = mCharacterSelection->getIndexSelected();
open();
if (mCharacterSelection->getItemCount())
{
size_t nextCharacter = std::min(previousIndex, mCharacterSelection->getItemCount()-1);
mCharacterSelection->setIndexSelected(nextCharacter);
onCharacterSelected(mCharacterSelection, nextCharacter);
}
}
void SaveGameDialog::onSaveNameChanged(MyGUI::EditBox *sender) void SaveGameDialog::onSaveNameChanged(MyGUI::EditBox *sender)
{ {
// This might have previously been a save slot from the list. If so, that is no longer the case // This might have previously been a save slot from the list. If so, that is no longer the case
@ -69,6 +102,12 @@ namespace MWGui
center(); center();
mCharacterSelection->setCaption("");
mCharacterSelection->removeAllItems();
mCurrentCharacter = NULL;
mCurrentSlot = NULL;
mSaveList->removeAllItems();
MWBase::StateManager* mgr = MWBase::Environment::get().getStateManager(); MWBase::StateManager* mgr = MWBase::Environment::get().getStateManager();
if (mgr->characterBegin() == mgr->characterEnd()) if (mgr->characterBegin() == mgr->characterEnd())
return; return;
@ -78,8 +117,6 @@ namespace MWGui
std::string directory = std::string directory =
Misc::StringUtils::lowerCase (Settings::Manager::getString ("character", "Saves")); Misc::StringUtils::lowerCase (Settings::Manager::getString ("character", "Saves"));
mCharacterSelection->removeAllItems();
int selectedIndex = MyGUI::ITEM_NONE; int selectedIndex = MyGUI::ITEM_NONE;
for (MWBase::StateManager::CharacterIterator it = mgr->characterBegin(); it != mgr->characterEnd(); ++it) for (MWBase::StateManager::CharacterIterator it = mgr->characterBegin(); it != mgr->characterEnd(); ++it)
@ -152,23 +189,10 @@ namespace MWGui
{ {
MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(NULL); MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(NULL);
// Get the selected slot, if any
unsigned int i=0;
const MWState::Slot* slot = NULL;
if (mCurrentCharacter)
{
for (MWState::Character::SlotIterator it = mCurrentCharacter->begin(); it != mCurrentCharacter->end(); ++it,++i)
{
if (i == mSaveList->getIndexSelected())
slot = &*it;
}
}
if (mSaving) if (mSaving)
{ {
// If overwriting an existing slot, ask for confirmation first // If overwriting an existing slot, ask for confirmation first
if (slot != NULL && !reallySure) if (mCurrentSlot != NULL && !reallySure)
{ {
ConfirmationDialog* dialog = MWBase::Environment::get().getWindowManager()->getConfirmationDialog(); ConfirmationDialog* dialog = MWBase::Environment::get().getWindowManager()->getConfirmationDialog();
dialog->open("#{sMessage4}"); dialog->open("#{sMessage4}");
@ -182,13 +206,13 @@ namespace MWGui
MWBase::Environment::get().getWindowManager()->messageBox("#{sNotifyMessage65}"); MWBase::Environment::get().getWindowManager()->messageBox("#{sNotifyMessage65}");
return; return;
} }
MWBase::Environment::get().getStateManager()->saveGame (mSaveNameEdit->getCaption(), slot); MWBase::Environment::get().getStateManager()->saveGame (mSaveNameEdit->getCaption(), mCurrentSlot);
} }
else else
{ {
if (mCurrentCharacter && slot) if (mCurrentCharacter && mCurrentSlot)
{ {
MWBase::Environment::get().getStateManager()->loadGame (mCurrentCharacter, slot); MWBase::Environment::get().getStateManager()->loadGame (mCurrentCharacter, mCurrentSlot);
MWBase::Environment::get().getWindowManager()->removeGuiMode (MWGui::GM_MainMenu); MWBase::Environment::get().getWindowManager()->removeGuiMode (MWGui::GM_MainMenu);
} }
} }
@ -221,6 +245,7 @@ namespace MWGui
assert(character && "Can't find selected character"); assert(character && "Can't find selected character");
mCurrentCharacter = character; mCurrentCharacter = character;
mCurrentSlot = NULL;
fillSaveList(); fillSaveList();
} }
@ -240,6 +265,7 @@ namespace MWGui
{ {
if (pos == MyGUI::ITEM_NONE) if (pos == MyGUI::ITEM_NONE)
{ {
mCurrentSlot = NULL;
mInfoText->setCaption(""); mInfoText->setCaption("");
mScreenshot->setImageTexture(""); mScreenshot->setImageTexture("");
return; return;
@ -248,17 +274,17 @@ namespace MWGui
if (mSaving) if (mSaving)
mSaveNameEdit->setCaption(sender->getItemNameAt(pos)); mSaveNameEdit->setCaption(sender->getItemNameAt(pos));
const MWState::Slot* slot = NULL; mCurrentSlot = NULL;
unsigned int i=0; unsigned int i=0;
for (MWState::Character::SlotIterator it = mCurrentCharacter->begin(); it != mCurrentCharacter->end(); ++it, ++i) for (MWState::Character::SlotIterator it = mCurrentCharacter->begin(); it != mCurrentCharacter->end(); ++it, ++i)
{ {
if (i == pos) if (i == pos)
slot = &*it; mCurrentSlot = &*it;
} }
assert(slot && "Can't find selected slot"); assert(mCurrentSlot && "Can't find selected slot");
std::stringstream text; std::stringstream text;
time_t time = slot->mTimeStamp; time_t time = mCurrentSlot->mTimeStamp;
struct tm* timeinfo; struct tm* timeinfo;
timeinfo = localtime(&time); timeinfo = localtime(&time);
@ -269,24 +295,24 @@ namespace MWGui
char buffer[size]; char buffer[size];
if (std::strftime(buffer, size, "%x %X", timeinfo) > 0) if (std::strftime(buffer, size, "%x %X", timeinfo) > 0)
text << buffer << "\n"; text << buffer << "\n";
text << "Level " << slot->mProfile.mPlayerLevel << "\n"; text << "Level " << mCurrentSlot->mProfile.mPlayerLevel << "\n";
text << slot->mProfile.mPlayerCell << "\n"; text << mCurrentSlot->mProfile.mPlayerCell << "\n";
// text << "Time played: " << slot->mProfile.mTimePlayed << "\n"; // text << "Time played: " << slot->mProfile.mTimePlayed << "\n";
int hour = int(slot->mProfile.mInGameTime.mGameHour); int hour = int(mCurrentSlot->mProfile.mInGameTime.mGameHour);
bool pm = hour >= 12; bool pm = hour >= 12;
if (hour >= 13) hour -= 12; if (hour >= 13) hour -= 12;
if (hour == 0) hour = 12; if (hour == 0) hour = 12;
text text
<< slot->mProfile.mInGameTime.mDay << " " << mCurrentSlot->mProfile.mInGameTime.mDay << " "
<< MWBase::Environment::get().getWorld()->getMonthName(slot->mProfile.mInGameTime.mMonth) << MWBase::Environment::get().getWorld()->getMonthName(mCurrentSlot->mProfile.mInGameTime.mMonth)
<< " " << hour << " " << (pm ? "#{sSaveMenuHelp05}" : "#{sSaveMenuHelp04}"); << " " << hour << " " << (pm ? "#{sSaveMenuHelp05}" : "#{sSaveMenuHelp04}");
mInfoText->setCaptionWithReplacing(text.str()); mInfoText->setCaptionWithReplacing(text.str());
// Decode screenshot // Decode screenshot
std::vector<char> data = slot->mProfile.mScreenshot; // MemoryDataStream doesn't work with const data :( std::vector<char> data = mCurrentSlot->mProfile.mScreenshot; // MemoryDataStream doesn't work with const data :(
Ogre::DataStreamPtr stream(new Ogre::MemoryDataStream(&data[0], data.size())); Ogre::DataStreamPtr stream(new Ogre::MemoryDataStream(&data[0], data.size()));
Ogre::Image image; Ogre::Image image;
image.load(stream, "jpg"); image.load(stream, "jpg");

@ -6,6 +6,7 @@
namespace MWState namespace MWState
{ {
class Character; class Character;
class Slot;
} }
namespace MWGui namespace MWGui
@ -24,8 +25,15 @@ namespace MWGui
void onCancelButtonClicked (MyGUI::Widget* sender); void onCancelButtonClicked (MyGUI::Widget* sender);
void onOkButtonClicked (MyGUI::Widget* sender); void onOkButtonClicked (MyGUI::Widget* sender);
void onCharacterSelected (MyGUI::ComboBox* sender, size_t pos); void onCharacterSelected (MyGUI::ComboBox* sender, size_t pos);
// Slot selected (mouse click or arrow keys)
void onSlotSelected (MyGUI::ListBox* sender, size_t pos); void onSlotSelected (MyGUI::ListBox* sender, size_t pos);
// Slot activated (double click or enter key)
void onSlotActivated (MyGUI::ListBox* sender, size_t pos); void onSlotActivated (MyGUI::ListBox* sender, size_t pos);
// Slot clicked with mouse
void onSlotMouseClick(MyGUI::ListBox* sender, size_t pos);
void onDeleteSlotConfirmed();
void onEditSelectAccept (MyGUI::EditBox* sender); void onEditSelectAccept (MyGUI::EditBox* sender);
void onSaveNameChanged (MyGUI::EditBox* sender); void onSaveNameChanged (MyGUI::EditBox* sender);
void onConfirmationGiven(); void onConfirmationGiven();
@ -46,6 +54,7 @@ namespace MWGui
MyGUI::Widget* mSpacer; MyGUI::Widget* mSpacer;
const MWState::Character* mCurrentCharacter; const MWState::Character* mCurrentCharacter;
const MWState::Slot* mCurrentSlot;
}; };

@ -95,6 +95,21 @@ MWState::Character::Character (const boost::filesystem::path& saves, const std::
} }
} }
void MWState::Character::cleanup()
{
if (mSlots.size() == 0)
{
// All slots are gone, no need to keep the empty directory
if (boost::filesystem::is_directory (mPath))
{
// Extra safety check to make sure the directory is empty (e.g. slots failed to parse header)
boost::filesystem::directory_iterator it(mPath);
if (it == boost::filesystem::directory_iterator())
boost::filesystem::remove_all(mPath);
}
}
}
const MWState::Slot *MWState::Character::createSlot (const ESM::SavedGame& profile) const MWState::Slot *MWState::Character::createSlot (const ESM::SavedGame& profile)
{ {
addSlot (profile); addSlot (profile);
@ -102,6 +117,21 @@ const MWState::Slot *MWState::Character::createSlot (const ESM::SavedGame& profi
return &mSlots.back(); return &mSlots.back();
} }
void MWState::Character::deleteSlot (const Slot *slot)
{
int index = slot - &mSlots[0];
if (index<0 || index>=static_cast<int> (mSlots.size()))
{
// sanity check; not entirely reliable
throw std::logic_error ("slot not found");
}
boost::filesystem::remove(slot->mPath);
mSlots.erase (mSlots.begin()+index);
}
const MWState::Slot *MWState::Character::updateSlot (const Slot *slot, const ESM::SavedGame& profile) const MWState::Slot *MWState::Character::updateSlot (const Slot *slot, const ESM::SavedGame& profile)
{ {
int index = slot - &mSlots[0]; int index = slot - &mSlots[0];
@ -150,4 +180,4 @@ ESM::SavedGame MWState::Character::getSignature() const
slot = *iter; slot = *iter;
return slot.mProfile; return slot.mProfile;
} }

@ -36,11 +36,19 @@ namespace MWState
Character (const boost::filesystem::path& saves, const std::string& game); Character (const boost::filesystem::path& saves, const std::string& game);
void cleanup();
///< Delete the directory we used, if it is empty
const Slot *createSlot (const ESM::SavedGame& profile); const Slot *createSlot (const ESM::SavedGame& profile);
///< Create new slot. ///< Create new slot.
/// ///
/// \attention The ownership of the slot is not transferred. /// \attention The ownership of the slot is not transferred.
/// \note Slot must belong to this character.
///
/// \attention The \a slot pointer will be invalidated by this call.
void deleteSlot (const Slot *slot);
const Slot *updateSlot (const Slot *slot, const ESM::SavedGame& profile); const Slot *updateSlot (const Slot *slot, const ESM::SavedGame& profile);
/// \note Slot must belong to this character. /// \note Slot must belong to this character.
/// ///

@ -47,6 +47,25 @@ MWState::Character *MWState::CharacterManager::getCurrentCharacter (bool create)
return mCurrent; return mCurrent;
} }
void MWState::CharacterManager::deleteSlot(const MWState::Character *character, const MWState::Slot *slot)
{
int index = character - &mCharacters[0];
if (index<0 || index>=static_cast<int> (mCharacters.size()))
throw std::logic_error ("invalid character");
mCharacters[index].deleteSlot(slot);
if (mCharacters[index].begin() == mCharacters[index].end())
{
// All slots deleted, cleanup and remove this character
mCharacters[index].cleanup();
if (character == mCurrent)
mCurrent = NULL;
mCharacters.erase(mCharacters.begin() + index);
}
}
void MWState::CharacterManager::createCharacter() void MWState::CharacterManager::createCharacter()
{ {
std::ostringstream stream; std::ostringstream stream;

@ -30,6 +30,8 @@ namespace MWState
Character *getCurrentCharacter (bool create = true); Character *getCurrentCharacter (bool create = true);
///< \param create Create a new character, if there is no current character. ///< \param create Create a new character, if there is no current character.
void deleteSlot(const MWState::Character *character, const MWState::Slot *slot);
void createCharacter(); void createCharacter();
///< Create new character within saved game management ///< Create new character within saved game management

@ -374,6 +374,11 @@ void MWState::StateManager::quickLoad()
} }
} }
void MWState::StateManager::deleteGame(const MWState::Character *character, const MWState::Slot *slot)
{
mCharacterManager.deleteSlot(character, slot);
}
MWState::Character *MWState::StateManager::getCurrentCharacter (bool create) MWState::Character *MWState::StateManager::getCurrentCharacter (bool create)
{ {
return mCharacterManager.getCurrentCharacter (create); return mCharacterManager.getCurrentCharacter (create);

@ -44,6 +44,9 @@ namespace MWState
virtual void endGame(); virtual void endGame();
virtual void deleteGame (const MWState::Character *character, const MWState::Slot *slot);
///< Delete a saved game slot from this character. If all save slots are deleted, the character will be deleted too.
virtual void saveGame (const std::string& description, const Slot *slot = 0); virtual void saveGame (const std::string& description, const Slot *slot = 0);
///< Write a saved game to \a slot or create a new slot if \a slot == 0. ///< Write a saved game to \a slot or create a new slot if \a slot == 0.
/// ///

Loading…
Cancel
Save