MemoryCard: Add option to convert a memory card to another type in the Memory Card Manager.

This commit is contained in:
Admiral H. Curtiss 2015-05-30 14:09:47 +02:00
parent d19facfb43
commit 7e194f1a26
9 changed files with 279 additions and 0 deletions

View File

@ -272,6 +272,7 @@ set(pcsx2GuiSources
gui/Panels/ThemeSelectorPanel.cpp
gui/Dialogs/BaseConfigurationDialog.cpp
gui/Dialogs/ConfirmationDialogs.cpp
gui/Dialogs/ConvertMemoryCardDialog.cpp
gui/Dialogs/CreateMemoryCardDialog.cpp
gui/Dialogs/FirstTimeWizard.cpp
gui/Dialogs/GameDatabaseDialog.cpp

View File

@ -237,4 +237,26 @@ namespace Dialogs
void CreateControls();
void OnOk_Click( wxCommandEvent& evt );
};
// --------------------------------------------------------------------------------------
// ConvertMemoryCardDialog
// --------------------------------------------------------------------------------------
class ConvertMemoryCardDialog : public wxDialogWithHelpers
{
protected:
wxDirName m_mcdPath;
wxString m_mcdSourceFilename;
wxTextCtrl* m_text_filenameInput;
pxRadioPanel* m_radio_CardType;
public:
virtual ~ConvertMemoryCardDialog() throw() {}
ConvertMemoryCardDialog( wxWindow* parent, const wxDirName& mcdPath, const AppConfig::McdOptions& mcdSourceConfig );
protected:
void CreateControls( const MemoryCardType sourceType );
void OnOk_Click( wxCommandEvent& evt );
bool ConvertToFile( const wxFileName& sourcePath, const wxFileName& targetPath );
bool ConvertToFolder( const wxFileName& sourcePath, const wxFileName& targetPath );
};
}

View File

@ -0,0 +1,197 @@
/* PCSX2 - PS2 Emulator for PCs
* Copyright (C) 2002-2015 PCSX2 Dev Team
*
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
* of the GNU Lesser General Public License as published by the Free Software Found-
* ation, either version 3 of the License, or (at your option) any later version.
*
* PCSX2 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 PCSX2.
* If not, see <http://www.gnu.org/licenses/>.
*/
#include "PrecompiledHeader.h"
#include "ConfigurationDialog.h"
#include "System.h"
#include "MemoryCardFile.h"
#include "MemoryCardFolder.h"
#include <wx/ffile.h>
Dialogs::ConvertMemoryCardDialog::ConvertMemoryCardDialog( wxWindow* parent, const wxDirName& mcdPath, const AppConfig::McdOptions& mcdSourceConfig )
: wxDialogWithHelpers( parent, _( "Convert a memory card to a different format" ) )
, m_mcdPath( mcdPath )
, m_mcdSourceFilename( mcdSourceConfig.Filename.GetFullName() )
{
SetMinWidth( 472 );
CreateControls( mcdSourceConfig.Type );
if ( m_radio_CardType ) m_radio_CardType->Realize();
wxBoxSizer& s_buttons( *new wxBoxSizer( wxHORIZONTAL ) );
s_buttons += new wxButton( this, wxID_OK, _( "Convert" ) ) | pxProportion( 2 );
s_buttons += pxStretchSpacer( 3 );
s_buttons += new wxButton( this, wxID_CANCEL ) | pxProportion( 2 );
wxBoxSizer& s_padding( *new wxBoxSizer( wxVERTICAL ) );
s_padding += Heading( wxString( _( "Convert: " ) ) + ( mcdPath + m_mcdSourceFilename ).GetFullPath() ).Unwrapped() | pxSizerFlags::StdExpand();
wxBoxSizer& s_filename( *new wxBoxSizer( wxHORIZONTAL ) );
s_filename += Heading( _( "To: " ) ).SetMinWidth( 50 );
m_text_filenameInput->SetMinSize( wxSize( 250, 20 ) );
m_text_filenameInput->SetValue( wxFileName( m_mcdSourceFilename ).GetName() + L"_converted" );
s_filename += m_text_filenameInput;
s_filename += Heading( L".ps2" );
s_padding += s_filename | wxALIGN_LEFT;
s_padding += m_radio_CardType | pxSizerFlags::StdExpand();
s_padding += Heading( pxE( L"WARNING: Converting a memory card may take several minutes! Please do not close the emulator during the conversion process, even if the emulator is no longer responding to input." ) );
s_padding += 12;
s_padding += s_buttons | pxSizerFlags::StdCenter();
*this += s_padding | pxSizerFlags::StdExpand();
Connect( wxID_OK, wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( ConvertMemoryCardDialog::OnOk_Click ) );
Connect( m_text_filenameInput->GetId(), wxEVT_COMMAND_TEXT_ENTER, wxCommandEventHandler( ConvertMemoryCardDialog::OnOk_Click ) );
m_text_filenameInput->SetFocus();
m_text_filenameInput->SelectAll();
}
void Dialogs::ConvertMemoryCardDialog::CreateControls( const MemoryCardType sourceType ) {
m_text_filenameInput = new wxTextCtrl( this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxTE_PROCESS_ENTER );
RadioPanelItem toFile = RadioPanelItem( _( "File" ), pxE( L"Convert this memory card to a regular 8 MB .ps2 file. Please note that the resulting file may not actually contain all saves, depending on how many are in the source memory card." ) )
.SetInt( MemoryCardType::MemoryCard_File );
RadioPanelItem toFolder = RadioPanelItem( _( "Folder" ), _( "Convert this memory card to a folder of individual saves." ) )
.SetInt( MemoryCardType::MemoryCard_Folder );
const RadioPanelItem tblForFile[] = { toFolder };
const RadioPanelItem tblForFolder[] = { toFile };
switch ( sourceType ) {
case MemoryCardType::MemoryCard_File:
m_radio_CardType = new pxRadioPanel( this, tblForFile );
break;
case MemoryCardType::MemoryCard_Folder:
m_radio_CardType = new pxRadioPanel( this, tblForFolder );
break;
default:
Console.Error( L"Memory Card Conversion: Invalid source type!" );
return;
}
m_radio_CardType->SetDefaultItem( 0 );
}
void Dialogs::ConvertMemoryCardDialog::OnOk_Click( wxCommandEvent& evt ) {
wxString composedName = m_text_filenameInput->GetValue().Trim() + L".ps2";
wxString errMsg;
if ( !isValidNewFilename( composedName, m_mcdPath, errMsg, 5 ) ) {
wxString message;
message.Printf( _( "Error (%s)" ), errMsg.c_str() );
Msgbox::Alert( message, _( "Convert memory card" ) );
m_text_filenameInput->SetFocus();
m_text_filenameInput->SelectAll();
return;
}
bool success = false;
wxFileName sourcePath = ( m_mcdPath + m_mcdSourceFilename );
wxFileName targetPath = ( m_mcdPath + composedName );
if ( m_radio_CardType ) {
MemoryCardType targetType = (MemoryCardType)m_radio_CardType->SelectedItem().SomeInt;
switch ( targetType ) {
case MemoryCardType::MemoryCard_File:
success = ConvertToFile( sourcePath, targetPath );
break;
case MemoryCardType::MemoryCard_Folder:
success = ConvertToFolder( sourcePath, targetPath );
break;
}
}
if ( !success ) {
Msgbox::Alert( _( "Memory Card conversion failed for unknown reasons." ), _( "Convert memory card" ) );
return;
}
EndModal( wxID_OK );
}
bool Dialogs::ConvertMemoryCardDialog::ConvertToFile( const wxFileName& sourcePath, const wxFileName& targetPath ) {
// Conversion method: Open FolderMcd as usual, then read the raw data from it and write it to a file stream
wxFFile targetFile( targetPath.GetFullPath(), L"wb" );
if ( !targetFile.IsOpened() ) {
return false;
}
FolderMemoryCard sourceFolderMemoryCard;
AppConfig::McdOptions config;
config.Enabled = true;
config.Type = MemoryCardType::MemoryCard_Folder;
sourceFolderMemoryCard.Open( sourcePath.GetFullPath(), config, false, L"" );
u8 buffer[FolderMemoryCard::PageSizeRaw];
u32 adr = 0;
while ( adr < FolderMemoryCard::TotalSizeRaw ) {
sourceFolderMemoryCard.Read( buffer, adr, FolderMemoryCard::PageSizeRaw );
targetFile.Write( buffer, FolderMemoryCard::PageSizeRaw );
adr += FolderMemoryCard::PageSizeRaw;
}
targetFile.Close();
sourceFolderMemoryCard.Close();
return true;
}
bool Dialogs::ConvertMemoryCardDialog::ConvertToFolder( const wxFileName& sourcePath, const wxFileName& targetPath ) {
// Conversion method: Read all pages of the FileMcd into a FolderMcd, then just write that out with the regular methods
// TODO: Test if >8MB files don't super fuck up something
wxFFile sourceFile( sourcePath.GetFullPath(), L"rb" );
if ( !sourceFile.IsOpened() ) {
return false;
}
u8 buffer[FolderMemoryCard::PageSizeRaw];
FolderMemoryCard targetFolderMemoryCard;
AppConfig::McdOptions config;
config.Enabled = true;
config.Type = MemoryCardType::MemoryCard_Folder;
targetFolderMemoryCard.Open( targetPath.GetFullPath(), config, false, L"" );
u32 adr = 0;
while ( !sourceFile.Eof() ) {
int size = sourceFile.Read( buffer, FolderMemoryCard::PageSizeRaw );
if ( size > 0 ) {
targetFolderMemoryCard.Save( buffer, adr, size );
adr += size;
}
}
sourceFile.Close();
targetFolderMemoryCard.Close();
if ( adr != FolderMemoryCard::TotalSizeRaw ) {
// reset memory card metrics in superblock to the default 8MB, since the converted card was different
targetFolderMemoryCard.Open( targetPath.GetFullPath(), config, true, L"" );
targetFolderMemoryCard.SetSizeInMB( 8 );
targetFolderMemoryCard.Close();
}
return true;
}

View File

@ -466,6 +466,7 @@ enum McdMenuId
McdMenuId_RefreshList,
McdMenuId_AssignUnassign,
McdMenuId_Duplicate,
McdMenuId_Convert,
};
@ -492,6 +493,7 @@ Panels::MemoryCardListPanel_Simple::MemoryCardListPanel_Simple( wxWindow* parent
m_button_Duplicate = new wxButton(this, wxID_ANY, _("Duplicate ..."));
m_button_Rename = new wxButton(this, wxID_ANY, _("Rename ..."));
m_button_Create = new wxButton(this, wxID_ANY, _("Create ..."));
m_button_Convert = new wxButton(this, wxID_ANY, _("Convert ..."));
// ------------------------------------
// Sizer / Layout Section
@ -511,6 +513,8 @@ Panels::MemoryCardListPanel_Simple::MemoryCardListPanel_Simple( wxWindow* parent
*s_leftside_buttons += m_button_Rename;
*s_leftside_buttons += 2;
*s_leftside_buttons += m_button_Create;
*s_leftside_buttons += 2;
*s_leftside_buttons += m_button_Convert;
SetSizerAndFit(GetSizer());
parent->SetWindowStyle(parent->GetWindowStyle() | wxRESIZE_BORDER);
@ -526,12 +530,14 @@ Panels::MemoryCardListPanel_Simple::MemoryCardListPanel_Simple( wxWindow* parent
// Connect( m_button_Mount->GetId(), wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(MemoryCardListPanel_Simple::OnMountCard));
Connect( m_button_Create->GetId(), wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(MemoryCardListPanel_Simple::OnCreateOrDeleteCard));
Connect( m_button_Convert->GetId(), wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(MemoryCardListPanel_Simple::OnConvertCard));
Connect( m_button_Rename->GetId(), wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(MemoryCardListPanel_Simple::OnRenameFile));
Connect( m_button_Duplicate->GetId(), wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(MemoryCardListPanel_Simple::OnDuplicateFile));
Connect( m_button_AssignUnassign->GetId(), wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(MemoryCardListPanel_Simple::OnAssignUnassignFile));
// Popup Menu Connections!
Connect( McdMenuId_Create, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler(MemoryCardListPanel_Simple::OnCreateOrDeleteCard) );
Connect( McdMenuId_Convert, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler(MemoryCardListPanel_Simple::OnConvertCard) );
//Connect( McdMenuId_Mount, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler(MemoryCardListPanel_Simple::OnMountCard) );
Connect( McdMenuId_Rename, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler(MemoryCardListPanel_Simple::OnRenameFile) );
Connect( McdMenuId_AssignUnassign, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler(MemoryCardListPanel_Simple::OnAssignUnassignFile) );
@ -562,6 +568,7 @@ void Panels::MemoryCardListPanel_Simple::UpdateUI()
m_button_Rename->Disable();
m_button_Duplicate->Disable();
m_button_AssignUnassign->Disable();
m_button_Convert->Disable();
return;
}
@ -581,6 +588,8 @@ void Panels::MemoryCardListPanel_Simple::UpdateUI()
wxString dupTip = _("Create a duplicate of this memory card ...");
pxSetToolTip( m_button_Duplicate, dupTip );
m_button_Convert->Enable( card.IsPresent && card.IsFormatted && !card.IsPSX );
//m_button_Create->Enable( card.Slot>=0 || card.IsPresent);
m_button_Create->SetLabel( card.IsPresent ? _("Delete") : _("Create ...") );
@ -747,6 +756,29 @@ void Panels::MemoryCardListPanel_Simple::UiCreateNewCard( McdSlotItem& card )
closed_core.AllowResume();
}
void Panels::MemoryCardListPanel_Simple::UiConvertCard( McdSlotItem& card ) {
if ( !card.IsPresent ) {
Console.WriteLn( "Error: Aborted: Convert mcd invoked but but a file is not associated." );
return;
}
ScopedCoreThreadClose closed_core;
AppConfig::McdOptions config;
config.Filename = card.Filename.GetFullName();
config.Enabled = card.IsEnabled;
config.Type = card.Type;
Dialogs::ConvertMemoryCardDialog dialog( this, m_FolderPicker->GetPath(), config );
wxWindowID result = dialog.ShowModal();
if ( result != wxID_CANCEL ) {
Apply();
RefreshSelections();
}
closed_core.AllowResume();
}
bool CopyDirectory( const wxString& from, const wxString& to ) {
wxDir src( from );
if ( !src.IsOpened() ) {
@ -1009,6 +1041,18 @@ void Panels::MemoryCardListPanel_Simple::OnCreateOrDeleteCard(wxCommandEvent& ev
UiCreateNewCard( card );
}
void Panels::MemoryCardListPanel_Simple::OnConvertCard(wxCommandEvent& evt) {
int selectedViewIndex = m_listview->GetFirstSelected();
if ( wxNOT_FOUND == selectedViewIndex ) {
return;
}
McdSlotItem& card( GetCardForViewIndex( selectedViewIndex ) );
if ( card.IsPresent ) {
UiConvertCard( card );
}
}
//enable/disapbe port
/*
void Panels::MemoryCardListPanel_Simple::OnMountCard(wxCommandEvent& evt)
@ -1168,6 +1212,9 @@ void Panels::MemoryCardListPanel_Simple::OnOpenItemContextMenu(wxListEvent& evt)
junk->Append( McdMenuId_Duplicate, _("Duplicate card ...") );
junk->Append( McdMenuId_Rename, _("Rename card ...") );
junk->Append( McdMenuId_Create, _("Delete card") );
if (card.IsFormatted && !card.IsPSX) {
junk->Append( McdMenuId_Convert, _("Convert card") );
}
}
else
junk->Append( McdMenuId_Create, _("Create a new card ...") );

View File

@ -213,6 +213,8 @@ namespace Panels
// Doubles as Create and Delete buttons
wxButton* m_button_Create;
wxButton* m_button_Convert;
// Doubles as Mount and Unmount buttons ("Enable"/"Disable" port)
// wxButton* m_button_Mount;
@ -237,6 +239,7 @@ namespace Panels
protected:
void OnCreateOrDeleteCard(wxCommandEvent& evt);
void OnConvertCard(wxCommandEvent& evt);
void OnMountCard(wxCommandEvent& evt);
// void OnRelocateCard(wxCommandEvent& evt);
void OnRenameFile(wxCommandEvent& evt);
@ -270,6 +273,7 @@ namespace Panels
virtual void UiRenameCard( McdSlotItem& card );
virtual void UiCreateNewCard( McdSlotItem& card );
virtual void UiConvertCard( McdSlotItem& card );
virtual void UiDeleteCard( McdSlotItem& card );
virtual void UiAssignUnassignFile( McdSlotItem& card );

View File

@ -646,6 +646,7 @@
<ClCompile Include="..\..\gui\Dialogs\AssertionDialog.cpp" />
<ClCompile Include="..\..\gui\Dialogs\BaseConfigurationDialog.cpp" />
<ClCompile Include="..\..\gui\Dialogs\ConfirmationDialogs.cpp" />
<ClCompile Include="..\..\gui\Dialogs\ConvertMemoryCardDialog.cpp" />
<ClCompile Include="..\..\gui\Dialogs\CreateMemoryCardDialog.cpp" />
<ClCompile Include="..\..\gui\Dialogs\FirstTimeWizard.cpp" />
<ClCompile Include="..\..\gui\Dialogs\ImportSettingsDialog.cpp" />

View File

@ -665,6 +665,9 @@
<ClCompile Include="..\..\gui\Dialogs\ConfirmationDialogs.cpp">
<Filter>AppHost\Dialogs</Filter>
</ClCompile>
<ClCompile Include="..\..\gui\Dialogs\ConvertMemoryCardDialog.cpp">
<Filter>AppHost\Dialogs</Filter>
</ClCompile>
<ClCompile Include="..\..\gui\Dialogs\CreateMemoryCardDialog.cpp">
<Filter>AppHost\Dialogs</Filter>
</ClCompile>

View File

@ -646,6 +646,7 @@
<ClCompile Include="..\..\gui\Dialogs\AssertionDialog.cpp" />
<ClCompile Include="..\..\gui\Dialogs\BaseConfigurationDialog.cpp" />
<ClCompile Include="..\..\gui\Dialogs\ConfirmationDialogs.cpp" />
<ClCompile Include="..\..\gui\Dialogs\ConvertMemoryCardDialog.cpp" />
<ClCompile Include="..\..\gui\Dialogs\CreateMemoryCardDialog.cpp" />
<ClCompile Include="..\..\gui\Dialogs\FirstTimeWizard.cpp" />
<ClCompile Include="..\..\gui\Dialogs\ImportSettingsDialog.cpp" />

View File

@ -665,6 +665,9 @@
<ClCompile Include="..\..\gui\Dialogs\ConfirmationDialogs.cpp">
<Filter>AppHost\Dialogs</Filter>
</ClCompile>
<ClCompile Include="..\..\gui\Dialogs\ConvertMemoryCardDialog.cpp">
<Filter>AppHost\Dialogs</Filter>
</ClCompile>
<ClCompile Include="..\..\gui\Dialogs\CreateMemoryCardDialog.cpp">
<Filter>AppHost\Dialogs</Filter>
</ClCompile>