Memory cards manager: allow custom file names (create/rename/copy), still without assigning arbitrary MCD files at the folder. TODO: 1. allow assigning arbitrary files at the folder. 2. GUI cleanups (text alignment on some messages, MCD list vertical stretch..) 3. code cleanups (remove all commented/unused code).

This is a relatively big change of the MCD manager, so I'd appreciate feedback (functionality, translations, bugs, etc).

git-svn-id: http://pcsx2.googlecode.com/svn/trunk@4423 96395faa-99c1-11dd-bbfe-3dabce05a288
This commit is contained in:
avihal@gmail.com 2011-03-12 22:58:28 +00:00
parent 0f2e588ba2
commit 2471c483bc
9 changed files with 423 additions and 128 deletions

View File

@ -129,6 +129,7 @@ bool isoFile::Detect( bool readType )
m_blockofs = 0;
m_type = ISOTYPE_AUDIO;
//BUG: This also detects a memory-card-file as a valid Audio-CD ISO... -avih
return true;
}

View File

@ -212,8 +212,9 @@ namespace Dialogs
uint m_slot;
wxDirName m_mcdpath;
wxString m_mcdfile;
wxTextCtrl* m_text_filenameInput;
wxFilePickerCtrl* m_filepicker;
//wxFilePickerCtrl* m_filepicker;
pxRadioPanel* m_radio_CardSize;
#ifdef __WXMSW__
@ -223,9 +224,10 @@ namespace Dialogs
public:
virtual ~CreateMemoryCardDialog() throw() {}
//CreateMemoryCardDialog( wxWindow* parent, uint port, uint slot, const wxString& filepath=wxEmptyString );
CreateMemoryCardDialog( wxWindow* parent, uint slot, const wxDirName& mcdpath, const wxString& mcdfile=wxEmptyString );
wxDirName GetPathToMcds() const;
CreateMemoryCardDialog( wxWindow* parent, uint slot, const wxDirName& mcdpath, const wxString& suggested_mcdfileName);
wxString result_createdMcdFilename;
//wxDirName GetPathToMcds() const;
protected:
void CreateControls();

View File

@ -18,14 +18,13 @@
#include "System.h"
#include "MemoryCardFile.h"
#include <wx/filepicker.h>
//#include <wx/filepicker.h>
#include <wx/ffile.h>
using namespace pxSizerFlags;
extern wxString GetMsg_McdNtfsCompress();
/*
wxFilePickerCtrl* CreateMemoryCardFilePicker( wxWindow* parent, uint portidx, uint slotidx, const wxString& filename=wxEmptyString )
{
return new wxFilePickerCtrl( parent, wxID_ANY, filename,
@ -36,14 +35,15 @@ wxFilePickerCtrl* CreateMemoryCardFilePicker( wxWindow* parent, uint portidx, ui
);
}
Dialogs::CreateMemoryCardDialog::CreateMemoryCardDialog( wxWindow* parent, uint slot, const wxDirName& mcdpath, const wxString& mcdfile )
: wxDialogWithHelpers( parent, _("Create new memory card") )
*/
Dialogs::CreateMemoryCardDialog::CreateMemoryCardDialog( wxWindow* parent, uint slot, const wxDirName& mcdpath, const wxString& suggested_mcdfileName)
: wxDialogWithHelpers( parent, _("Create a new memory card file") )
, m_mcdpath( mcdpath.IsOk() ? mcdpath : (wxDirName)g_Conf->Mcd[slot].Filename.GetPath() )
, m_mcdfile( mcdfile.IsEmpty() ? g_Conf->Mcd[slot].Filename.GetFullName() : mcdfile )
, m_mcdfile( suggested_mcdfileName )//suggested_and_result_mcdfileName.IsEmpty() ? g_Conf->Mcd[slot].Filename.GetFullName()
{
SetMinWidth( 472 );
m_filepicker = NULL;
//m_filepicker = NULL;
m_slot = slot;
CreateControls();
@ -65,12 +65,22 @@ Dialogs::CreateMemoryCardDialog::CreateMemoryCardDialog( wxWindow* parent, uint
//s_padding += Heading(_("Select the size for your new memory card."));
if( m_filepicker )
s_padding += m_filepicker | StdExpand();
else
// if( m_filepicker )
// s_padding += m_filepicker | StdExpand();
// else
{
s_padding += Heading( _( "New card will be saved to:" ) ) | StdExpand();
s_padding += Heading( (m_mcdpath + m_mcdfile).GetFullPath() ).Unwrapped() | StdExpand();
s_padding += Heading( _( "New memory card file:" ) ) | StdExpand();
s_padding += Heading( wxString(_("At folder: ")) + (m_mcdpath + m_mcdfile).GetPath() ).Unwrapped() | StdExpand();
wxBoxSizer& s_filename( *new wxBoxSizer(wxHORIZONTAL) );
s_filename += Heading( _("Select file name: ")).SetMinWidth(150);
m_text_filenameInput->SetMinSize(wxSize(150,20));
m_text_filenameInput->SetValue ((m_mcdpath + m_mcdfile).GetName());
s_filename += m_text_filenameInput;
s_filename += Heading( L".ps2" );
s_padding += s_filename | wxALIGN_LEFT;
}
s_padding += m_radio_CardSize | StdExpand();
@ -85,13 +95,16 @@ Dialogs::CreateMemoryCardDialog::CreateMemoryCardDialog( wxWindow* parent, uint
*this += s_padding | StdExpand();
Connect( wxID_OK, wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( CreateMemoryCardDialog::OnOk_Click ) );
}
m_text_filenameInput->SetFocus();
m_text_filenameInput->SelectAll();
}
/*
wxDirName Dialogs::CreateMemoryCardDialog::GetPathToMcds() const
{
return m_filepicker ? (wxDirName)m_filepicker->GetPath() : m_mcdpath;
}
*/
// When this GUI is moved into the FileMemoryCard plugin (where it eventually belongs),
// this function will be removed and the MemoryCardFile::Create() function will be used
// instead.
@ -102,7 +115,7 @@ static bool CreateIt( const wxString& mcdFile, uint sizeInMB )
u8 m_effeffs[528*16];
memset8<0xff>( m_effeffs );
Console.WriteLn( L"(FileMcd) Creating new %uMB memory card: " + mcdFile, sizeInMB );
Console.WriteLn( L"(FileMcd) Creating new %uMB memory card file: '%s'", sizeInMB, mcdFile.c_str() );
wxFFile fp( mcdFile, L"wb" );
if( !fp.IsOpened() ) return false;
@ -114,6 +127,7 @@ static bool CreateIt( const wxString& mcdFile, uint sizeInMB )
if( fp.Write( m_effeffs, sizeof(m_effeffs) ) == 0 )
return false;
}
return true;
}
@ -125,18 +139,34 @@ void Dialogs::CreateMemoryCardDialog::OnOk_Click( wxCommandEvent& evt )
#ifdef __WXMSW__
g_Conf->McdCompressNTFS = m_check_CompressNTFS->GetValue();
#endif
result_createdMcdFilename=L"_INVALID_FILE_NAME_";
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, _("Create memory card file") );
m_text_filenameInput->SetFocus();
m_text_filenameInput->SelectAll();
return;
}
wxString fullPath=(m_mcdpath + composedName).GetFullPath();
if( !CreateIt(
m_filepicker ? m_filepicker->GetPath() : (m_mcdpath + m_mcdfile).GetFullPath(),
fullPath,
m_radio_CardSize ? m_radio_CardSize->SelectedItem().SomeInt : 8
) )
{
Msgbox::Alert(
_("Error: The memory card could not be created."),
_("memory card creation error")
_("Error: The memory card file could not be created."),
_("Create memory card file")
);
return;
}
result_createdMcdFilename = composedName;
EndModal( wxID_OK );
}
@ -153,6 +183,8 @@ void Dialogs::CreateMemoryCardDialog::CreateControls()
)
);
m_text_filenameInput = new wxTextCtrl( this, wxID_ANY);
// Initial value of the checkbox is saved between calls to the dialog box. If the user checks
// the option, it remains checked for future dialog. If the user unchecks it, ditto.
m_check_CompressNTFS->SetValue( g_Conf->McdCompressNTFS );

View File

@ -48,7 +48,7 @@ Panels::McdConfigPanel_Toggles::McdConfigPanel_Toggles(wxWindow *parent)
for( uint i=0; i<2; ++i )
{
m_check_Multitap[i] = new pxCheckBox( this, pxsFmt(_("Enable Multitap on Port %u"), i+1) );
m_check_Multitap[i] = new pxCheckBox( this, pxsFmt(_("Use Multitap on Port %u"), i+1) );
m_check_Multitap[i]->SetClientData( (void*)i );
m_check_Multitap[i]->SetName(pxsFmt( L"CheckBox::Multitap%u", i ));
}
@ -100,8 +100,10 @@ Dialogs::McdConfigDialog::McdConfigDialog( wxWindow* parent )
// [TODO] : Plan here is to add an advanced tab which gives the user the ability
// to configure the names of each memory card slot.
*this += Heading(_("Drag items over other items in the list to swap or copy memory cards.")) | StdExpand();
wxString title=_("Drag card files in the list to swap or copy between ports.");
title+=_("\n\nNote: 'Rename' and 'Delete' require to apply pending changes first.");
title+=_("\nAlso, 'Create', 'Rename' and 'Delete' will NOT be reverted when clicking 'Cancel'.");
*this += Heading(title) | StdExpand();
*this += StdPadding;
*this += m_panel_mcdlist | StdExpand();

View File

@ -15,6 +15,7 @@
#include "PrecompiledHeader.h"
#include "Utilities/SafeArray.inl"
#include <wx/file.h>
#include "MemoryCardFile.h"
@ -75,9 +76,9 @@ protected:
wxString GetDisabledMessage( uint slot ) const
{
return pxE( "!Notice:Mcd:HasBeenDisabled", wxsFormat(
L"The memory card in slot %d has been automatically disabled. You can correct the problem\n"
L"and re-enable the memory card at any time using Config:Memory cards from the main menu.",
slot
L"The PS2-slot %d has been automatically disabled. You can correct the problem\n"
L"and re-enable it at any time using Config:Memory cards from the main menu.",
slot//TODO: translate internal slot index to human-readable slot description
) );
}
};
@ -272,7 +273,7 @@ s32 FileMemoryCard::Read( uint slot, u8 *dest, u32 adr, int size )
wxFFile& mcfp( m_file[slot] );
if( !mcfp.IsOpened() )
{
DevCon.Error( "(FileMcd) Ignoring attempted read from disabled card." );
DevCon.Error( "(FileMcd) Ignoring attempted read from disabled slot." );
memset(dest, 0, size);
return 1;
}
@ -286,7 +287,7 @@ s32 FileMemoryCard::Save( uint slot, const u8 *src, u32 adr, int size )
if( !mcfp.IsOpened() )
{
DevCon.Error( "(FileMcd) Ignoring attempted save/write to disabled card." );
DevCon.Error( "(FileMcd) Ignoring attempted save/write to disabled slot." );
return 1;
}
@ -311,7 +312,7 @@ s32 FileMemoryCard::EraseBlock( uint slot, u32 adr )
if( !mcfp.IsOpened() )
{
DevCon.Error( "MemoryCard: Ignoring erase for disabled card." );
DevCon.Error( "MemoryCard: Ignoring erase for disabled slot." );
return 1;
}
@ -509,3 +510,42 @@ struct superblock
u8 card_type; // 0x150
u8 card_flags; // 0x151
};
//Tests if a string is a valid name for a new file within a specified directory.
//returns true if:
// - the file name has a minimum length of minNumCharacters chars (default is 5 chars: at least 1 char + '.' + 3-chars extension)
// and - the file name is within the basepath directory (doesn't contain .. , / , \ , etc)
// and - file name doesn't already exist
// and - can be created on current system (it is actually created and deleted for this test).
bool isValidNewFilename( wxString filenameStringToTest, wxDirName atBasePath, wxString& out_errorMessage, uint minNumCharacters)
{
if ( filenameStringToTest.Length()<1 || filenameStringToTest.Length()<minNumCharacters )
{
out_errorMessage = _("File name empty or too short");
return false;
}
if( (atBasePath + wxFileName(filenameStringToTest)).GetFullPath() != (atBasePath + wxFileName(filenameStringToTest).GetFullName()).GetFullPath() ){
out_errorMessage = _("File name outside of required directory");
return false;
}
if ( wxFileExists( (atBasePath + wxFileName(filenameStringToTest)).GetFullPath() ))
{
out_errorMessage = _("File name already exists");
return false;
}
wxFile fp;
if( !fp.Create( (atBasePath + wxFileName(filenameStringToTest)).GetFullPath() ))
{
out_errorMessage = _("The Operating-System prevents this file from being created");
return false;
}
fp.Close();
wxRemoveFile( (atBasePath + wxFileName(filenameStringToTest)).GetFullPath() );
out_errorMessage = L"[OK - New file name is valid]"; //shouldn't be displayed on success, hence not translatable.
return true;
}

View File

@ -25,5 +25,6 @@
extern uint FileMcd_GetMtapPort(uint slot);
extern uint FileMcd_GetMtapSlot(uint slot);
extern bool FileMcd_IsMultitapSlot( uint slot );
extern wxFileName FileMcd_GetSimpleName(uint slot);
//extern wxFileName FileMcd_GetSimpleName(uint slot);
extern wxString FileMcd_GetDefaultName(uint slot);
extern bool isValidNewFilename( wxString filenameStringToTest, wxDirName atBasePath, wxString& out_errorMessage, uint minNumCharacters=5 );

View File

@ -43,7 +43,8 @@ static bool IsMcdFormatted( wxFFile& fhand )
return memcmp( formatted_string, dest, fmtstrlen ) == 0;
}
bool EnumerateMemoryCard( McdSlotItem& dest, const wxFileName& filename )
//sets IsPresent if the file is valid, and derived properties (filename, formatted, size, etc)
bool EnumerateMemoryCard( McdSlotItem& dest, const wxFileName& filename, const wxDirName basePath )
{
dest.IsFormatted = false;
dest.IsPresent = false;
@ -62,6 +63,9 @@ bool EnumerateMemoryCard( McdSlotItem& dest, const wxFileName& filename )
dest.IsPresent = true;
dest.Filename = filename;
if( filename.GetFullPath() == (basePath+filename.GetFullName()).GetFullPath() )
dest.Filename = filename.GetFullName();
dest.SizeInMB = (uint)(mcdFile.Length() / (1024 * 528 * 2));
dest.IsFormatted = IsMcdFormatted( mcdFile );
filename.GetTimes( NULL, &dest.DateModified, &dest.DateCreated );
@ -230,7 +234,7 @@ public:
uint GetViewIndex() const
{
pxAssumeDev( m_viewIndex >= 0, "memory card Index is uninitialized (invalid drag&drop object state)" );
pxAssumeDev( m_viewIndex >= 0, "memory card view-Index is uninitialized (invalid drag&drop object state)" );
return (uint)m_viewIndex;
}
@ -349,15 +353,13 @@ public:
m_listview->GetMcdProvider().RefreshMcds();
return result;
}
virtual wxDragResult OnDropMcd( McdSlotItem& src, McdSlotItem& dest, wxDragResult def )
{
if( src.Slot == dest.Slot ) return wxDragNone;
if( !pxAssert( (src.Slot >= 0) && (dest.Slot >= 0) ) ) return wxDragNone;
const wxDirName basepath( m_listview->GetMcdProvider().GetMcdPath() );
wxFileName srcfile( basepath + g_Conf->Mcd[src.Slot].Filename );
wxFileName destfile( basepath + g_Conf->Mcd[dest.Slot].Filename );
bool result = true;
@ -365,19 +367,56 @@ public:
{
// user is force invoking copy mode, which means we need to check the destination
// and prompt if it looks valuable (formatted).
if( !src.IsPresent )
{
Msgbox::Alert(_("Failed. Can only copy an existing card file."), _("Copy memory card file"));
return wxDragNone;
}
if ( !dest.IsPresent )
{
while (1){
wxString newFilename=L"";
newFilename = wxGetTextFromUser(_("Select a name for the new memory card file copy\n( '.ps2' will be added automatically)"), _("Copy memory card file"));
if( newFilename==L"" )
{
Msgbox::Alert( _("Copy canceled"), _("Copy memory card file") );
return wxDragNone;
}
newFilename += L".ps2";
//check that the name is valid for a new file
wxString errMsg;
if( !isValidNewFilename( newFilename, basepath, errMsg, 5 ) )
{
wxString message;
message.Printf(_("Error (%s)"), errMsg.c_str());
Msgbox::Alert( message, _("Copy memory card file") );
continue;
}
dest.Filename = newFilename;
break;
}
}
wxFileName srcfile( basepath + src.Filename);//g_Conf->Mcd[src.Slot].Filename );
wxFileName destfile( basepath + dest.Filename);//g_Conf->Mcd[dest.Slot].Filename );
if( dest.IsPresent && dest.IsFormatted )
{
wxString content;
content.Printf(
pxE( "!Notice:Mcd:Overwrite",
L"This will copy the entire contents of the memory card file '%s' (=slot %u) to the memory card file '%s' (=slot %u). "
L"All previous data on the memory card file '%s' will be lost. Are you sure?" ),
L"This will copy the entire contents of memory card file '%s' [=slot %u] to the memory card file '%s' [=slot %u]. "
L"All previous data on memory card file '%s' will be lost. Are you sure?" ),
src.Filename.GetFullName().c_str(), src.Slot,
dest.Filename.GetFullName().c_str(), dest.Slot,
dest.Filename.GetFullName().c_str(), dest.Slot
);
result = Msgbox::YesNo( content, _("Overwrite memory card?") );
result = Msgbox::YesNo( content, _("Overwrite memory card file?") );
if (!result)
return wxDragNone;
@ -388,7 +427,7 @@ public:
{
wxString heading;
heading.Printf( pxE( "!Notice:Mcd:Copy Failed",
L"Error! Could not copy the memory card into file '%s' (=slot %u). The destination file is in use." ),//xxx
L"Error! Copy failed. Destination memory card file '%s' [=slot %u] is in use." ),
dest.Filename.GetFullName().c_str(), dest.Slot
);
@ -399,10 +438,19 @@ public:
}
// Destination memcard isEnabled state is the same now as the source's
dest.IsEnabled = src.IsEnabled;
wxString success;
success.Printf(_("Memory card file '%s' copied to '%s'.\n\nBoth card files are now identical."),
src.Filename.GetFullName().c_str(),
dest.Filename.GetFullName().c_str()
);
Msgbox::Alert(success, _("Success"));
dest.IsPresent=true;
dest.IsEnabled = true;//src.IsEnabled;
}
else if( wxDragMove == def )
{
/*
// Move always performs a swap :)
const bool srcExists( srcfile.FileExists() );
@ -436,10 +484,32 @@ public:
{
// TODO : Popup an error to the user.
Console.Error( "(FileMcd) memory card swap failed." );
Console.Error( "(FileMcd) memory card files swap failed." );
Console.Indent().WriteLn( L"Src : " + srcfile.GetFullPath() );
Console.Indent().WriteLn( L"Dest: " + destfile.GetFullPath() );
}
*/
// avih: old implementation above was swapping file contents (by actually switching the file names of 2 files)
// New implementation just swaps the assigned file names at the slots.
//Note: each slot has 2 important properties: IsPresent (with Filename) and IsEnabled.
// For the sake of usability, when draggind src to dest, if src IsPresent, automatically enable dest.
// However, src slot keeps its old IsEnabled regardless of what happened.
if (src.IsPresent || dest.IsPresent)
{
//swap file names (along with IsPresent)
wxFileName tmpFilename = dest.Filename;
bool tmpPresent = dest.IsPresent;
dest.Filename = src.Filename;
dest.IsPresent = src.IsPresent;
if( src.IsPresent )
dest.IsEnabled = true;
src.Filename = tmpFilename;
src.IsPresent = tmpPresent;
}
}
return def;
@ -450,13 +520,20 @@ enum McdMenuId
{
McdMenuId_Create = 0x888,
McdMenuId_Mount,
McdMenuId_Relocate,
McdMenuId_Rename,
McdMenuId_RefreshList
};
// =====================================================================================================
// MemoryCardListPanel_Simple (implementations)
// =====================================================================================================
/* some code from cotton to enumerate files at a folder:
[21:07] <cotton> ScopedPtr<wxArrayString> memcardList(new wxArrayString());
[21:07] <cotton> wxDir::GetAllFiles(m_FolderPicker->GetPath().ToString(), memcardList, L"*.ps2*", wxDIR_FILES);
[21:07] <cotton> for(uint i = 0; i < memcardList->size(); i++) {
[21:07] <cotton> DevCon.WriteLn(L"hey - " + memcardList[0][i]);
[21:07] <cotton> }
*/
Panels::MemoryCardListPanel_Simple::MemoryCardListPanel_Simple( wxWindow* parent )
: _parent( parent )
{
@ -467,8 +544,9 @@ Panels::MemoryCardListPanel_Simple::MemoryCardListPanel_Simple( wxWindow* parent
m_listview->SetMinSize(wxSize(m_listview->GetMinWidth(), m_listview->GetCharHeight() * 13));
m_listview->SetDropTarget( new McdDropTarget(m_listview) );
m_button_Create = new wxButton(this, wxID_ANY, _("Create"));
m_button_Mount = new wxButton(this, wxID_ANY, _("Mount"));
m_button_Create = new wxButton(this, wxID_ANY, _("Create card file"));
m_button_Mount = new wxButton(this, wxID_ANY, _("Enable port"));
m_button_Rename = new wxButton(this, wxID_ANY, _("Rename card file"));
// ------------------------------------
// Sizer / Layout Section
@ -476,28 +554,33 @@ Panels::MemoryCardListPanel_Simple::MemoryCardListPanel_Simple( wxWindow* parent
CreateLayout();
*s_leftside_buttons += m_button_Create;
*s_leftside_buttons += 2;
*s_leftside_buttons += 20;
*s_leftside_buttons += m_button_Mount;
//*s_leftside_buttons += 2;
*s_leftside_buttons += 20;
*s_leftside_buttons += m_button_Rename;
*s_leftside_buttons += 2;
*s_leftside_buttons += m_button_Create;
parent->SetWindowStyle(parent->GetWindowStyle() | wxRESIZE_BORDER);
Connect( m_listview->GetId(), wxEVT_COMMAND_LIST_BEGIN_DRAG, wxListEventHandler(MemoryCardListPanel_Simple::OnListDrag));
Connect( m_listview->GetId(), wxEVT_COMMAND_LIST_ITEM_SELECTED, wxListEventHandler(MemoryCardListPanel_Simple::OnListSelectionChanged));
//Deselected is not working for some reason (e.g. when clicking an empty row at the table) - avih
Connect( m_listview->GetId(), wxEVT_COMMAND_LIST_ITEM_DESELECTED, wxListEventHandler(MemoryCardListPanel_Simple::OnListSelectionChanged));
Connect( m_listview->GetId(), wxEVT_COMMAND_LIST_ITEM_RIGHT_CLICK, wxListEventHandler(MemoryCardListPanel_Simple::OnOpenItemContextMenu) );
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::OnCreateCard));
Connect( m_button_Rename->GetId(), wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(MemoryCardListPanel_Simple::OnRenameFile));
// Popup Menu Connections!
Connect( McdMenuId_Create, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler(MemoryCardListPanel_Simple::OnCreateCard) );
Connect( McdMenuId_Mount, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler(MemoryCardListPanel_Simple::OnMountCard) );
Connect( McdMenuId_Relocate, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler(MemoryCardListPanel_Simple::OnRelocateCard) );
Connect( McdMenuId_Rename, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler(MemoryCardListPanel_Simple::OnRenameFile) );
Connect( McdMenuId_RefreshList, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler(MemoryCardListPanel_Simple::OnRefreshSelections) );
}
@ -511,25 +594,34 @@ void Panels::MemoryCardListPanel_Simple::UpdateUI()
{
m_button_Create->Disable();
m_button_Mount->Disable();
m_button_Rename->Disable();
return;
}
const McdSlotItem& item( GetCardForViewIndex(sel) );
const McdSlotItem& card( GetCardForViewIndex(sel) );
m_button_Rename->Enable( card.IsPresent );
wxString renameTip = _("Rename this memory card file.");
renameTip += wxString(L"\n") + _("Note: Port needs to be disabled first, and the change then needs to be applied." );
pxSetToolTip( m_button_Rename, renameTip );
m_button_Create->Enable();
m_button_Create->SetLabel( item.IsPresent ? _("Delete") : _("Create") );
m_button_Create->SetLabel( card.IsPresent ? _("Delete card file") : _("Create card file") );
wxString deleteTip = _("Permanently delete this memory card file from disk (all contents are lost)");
deleteTip += wxString(L"\n") + _("Note: Port needs to be disabled first, and the change then needs to be applied." );
pxSetToolTip( m_button_Create,
item.IsPresent
? _("Deletes the existing memory card from disk (all contents are lost)." )
: _("Creates a new memory card in the empty slot." )
card.IsPresent
? deleteTip
: _("Create a new memory card file and assign it to the selected PS2-Port." )
);
m_button_Mount->Enable( item.IsPresent );
m_button_Mount->SetLabel( item.IsEnabled ? _("Disable") : _("Enable") );
m_button_Mount->Enable( card.IsPresent );
m_button_Mount->SetLabel( card.IsEnabled ? _("Disable Port") : _("Enable Port") );
pxSetToolTip( m_button_Mount,
item.IsEnabled
? _("Disables the selected memory card, so that it will not be seen by games or BIOS.")
: _("Mounts the selected memory card, so that games can see it again.")
card.IsEnabled
? _("Disable the selected PS2-Port (this memory card will be invisible to games/BIOS).")
: _("Enable the selected PS2-Port (games/BIOS will see this memory card).")
);
}
@ -544,6 +636,10 @@ void Panels::MemoryCardListPanel_Simple::Apply()
for( uint slot=0; slot<8; ++slot )
{
g_Conf->Mcd[slot].Enabled = m_Cards[slot].IsEnabled && m_Cards[slot].IsPresent;
if (m_Cards[slot].IsPresent)
g_Conf->Mcd[slot].Filename = m_Cards[slot].Filename;
else
g_Conf->Mcd[slot].Filename = L"";
}
}
@ -552,11 +648,15 @@ void Panels::MemoryCardListPanel_Simple::AppStatusEvent_OnSettingsApplied()
for( uint slot=0; slot<8; ++slot )
{
m_Cards[slot].IsEnabled = g_Conf->Mcd[slot].Enabled;
m_Cards[slot].Filename = g_Conf->Mcd[slot].Filename;
}
_parent::AppStatusEvent_OnSettingsApplied();
}
//BUG: the next function is never reached because, for some reason, IsoDropTarget::OnDropFiles is called instead.
// Interestingly, IsoDropTarget::OnDropFiles actually "detects" a memory card file as a valid Audio-CD ISO... - avih
bool Panels::MemoryCardListPanel_Simple::OnDropFiles(wxCoord x, wxCoord y, const wxArrayString& filenames)
{
if( filenames.GetCount() == 1 && wxFileName(filenames[0]).IsDir() )
@ -577,10 +677,13 @@ void Panels::MemoryCardListPanel_Simple::DoRefresh()
{
for( uint slot=0; slot<8; ++slot )
{
if( FileMcd_IsMultitapSlot(slot) && !m_MultitapEnabled[FileMcd_GetMtapPort(slot)] ) continue;
if( FileMcd_IsMultitapSlot(slot) && !m_MultitapEnabled[FileMcd_GetMtapPort(slot)] )
continue;
//wxFileName fullpath( m_FolderPicker->GetPath() + g_Conf->Mcd[slot].Filename.GetFullName() );
wxFileName fullpath = m_FolderPicker->GetPath() + m_Cards[slot].Filename.GetFullName();
wxFileName fullpath( m_FolderPicker->GetPath() + g_Conf->Mcd[slot].Filename.GetFullName() );
EnumerateMemoryCard( m_Cards[slot], fullpath );
EnumerateMemoryCard( m_Cards[slot], fullpath, m_FolderPicker->GetPath());
m_Cards[slot].Slot = slot;
}
@ -598,34 +701,61 @@ void Panels::MemoryCardListPanel_Simple::OnCreateCard(wxCommandEvent& evt)
McdSlotItem& card( GetCardForViewIndex(selectedViewIndex) );
if( card.IsPresent )
{
{// called for "delete memory card"
if ( 0<=card.Slot && card.Slot<=7 && card.Filename != g_Conf->Mcd[card.Slot].Filename)
{
Msgbox::Alert( _("Error: Please apply pending changes before proceeding."), _("Delete memory card file") );
return;
}
if ( 0<=card.Slot && card.Slot<=7 && g_Conf->Mcd[card.Slot].Enabled )
{
Msgbox::Alert( _("Error: Memory card file currently in use.\n\n1. Disable this port (if not already disabled).\n2. Click 'Apply'.\n3. Proceed with Delete."), _("Delete memory card file") );
return;
}
bool result = true;
if( card.IsFormatted )
{
wxString content;
content.Printf(
pxE( "!Notice:Mcd:Delete",
L"You are about to delete the formatted memory card file '%s' (=slot %u). "
L"You are about to delete the formatted memory card file '%s' [=slot %u]. "
L"All data on this card will be lost! Are you absolutely and quite positively sure?"
), card.Filename.GetFullName().c_str()
, card.Slot
);
result = Msgbox::YesNo( content, _("Delete memory card?") );
result = Msgbox::YesNo( content, _("Delete memory card file?") );
}
if( result )
{
wxFileName fullpath( m_FolderPicker->GetPath() + g_Conf->Mcd[GetSlotIndexForViewIndex( selectedViewIndex )].Filename.GetFullName() );
wxFileName fullpath( m_FolderPicker->GetPath() + card.Filename.GetFullName());//g_Conf->Mcd[GetSlotIndexForViewIndex( selectedViewIndex )].Filename.GetFullName() );
wxRemoveFile( fullpath.GetFullPath() );
}
}
else
{
wxWindowID result = Dialogs::CreateMemoryCardDialog( this, GetSlotIndexForViewIndex( selectedViewIndex ), m_FolderPicker->GetPath() ).ShowModal();
card.IsEnabled = (result != wxID_CANCEL);
{// actually create a file
Dialogs::CreateMemoryCardDialog dialog( this, GetSlotIndexForViewIndex( selectedViewIndex ), m_FolderPicker->GetPath(), L"my memory card" );
wxWindowID result = dialog.ShowModal();
//card.IsEnabled = (result != wxID_CANCEL);
if (result != wxID_CANCEL)
{
card.IsEnabled = true;
card.Filename = dialog.result_createdMcdFilename;
card.IsPresent = true;
Console.WriteLn(L"setting new card to slot %u: '%s'", card.Slot, card.Filename.GetFullName().c_str());
}
else
{
card.IsEnabled=false;
}
}
this->AddPendingEvent(wxCommandEvent(pxEvt_SomethingChanged));//enable the apply button (the auto-trigger doesn't get triggered here...)
RefreshSelections();
closed_core.AllowResume();
}
@ -648,7 +778,8 @@ void Panels::MemoryCardListPanel_Simple::OnMountCard(wxCommandEvent& evt)
m_listview->RefreshItem(selectedViewIndex);
UpdateUI();
}
/*
//text dialog: can be used for rename: wxGetTextFromUser - avih
void Panels::MemoryCardListPanel_Simple::OnRelocateCard(wxCommandEvent& evt)
{
evt.Skip();
@ -664,6 +795,69 @@ void Panels::MemoryCardListPanel_Simple::OnRelocateCard(wxCommandEvent& evt)
m_listview->RefreshItem(slot);
UpdateUI();
}
*/
void Panels::MemoryCardListPanel_Simple::OnRenameFile(wxCommandEvent& evt)
{
//evt.Skip();//what is it used for? - avih
const wxDirName basepath( m_listview->GetMcdProvider().GetMcdPath() );
const int viewIndex = m_listview->GetFirstSelected();
if( wxNOT_FOUND == viewIndex )
return;
McdSlotItem& card( GetCardForViewIndex(viewIndex) );
if( !card.IsPresent ){
Console.WriteLn("Internal Error: rename mcd invoked but no file is associated. Aborting.");
return;
}
if ( 0<=card.Slot && card.Slot<=7 && card.Filename != g_Conf->Mcd[card.Slot].Filename)
{
Msgbox::Alert( _("Error: Please apply pending changes before proceeding."), _("Rename memory card file") );
return;
}
if ( 0<=card.Slot && card.Slot<=7 && g_Conf->Mcd[card.Slot].Enabled)
{
Msgbox::Alert( _("Error: Memory card file currently in use.\n\n1. Disable this port (if not already disabled).\n2. Click 'Apply'.\n3. Proceed with rename.\n4. Don't forget to re-enable this port."), _("Rename memory card file") );
return;
}
wxString newFilename;
while (1){
newFilename = wxGetTextFromUser(_("Select a new name for the memory card file\n( '.ps2' will be added automatically)"), _("Rename memory card file"));
if( newFilename==L"" )
{
Msgbox::Alert( _("Rename canceled"), _("Rename memory card file") );
return;
}
newFilename += L".ps2";
//check that the name is valid for a new file
wxString errMsg;
if( !isValidNewFilename( newFilename, basepath, errMsg, 5 ) )
{
wxString message;
message.Printf(_("Error (%s)"), errMsg.c_str());
Msgbox::Alert( message, _("Rename memory card file") );
continue;
}
break;
}
if( !wxRenameFile( (basepath + card.Filename).GetFullPath(), (basepath + wxFileName(newFilename)).GetFullPath(), false ) )
{
Msgbox::Alert( _("Error: Rename could not be completed.\n"), _("Rename memory card file") );
return;
}
card.Filename = newFilename;
this->DoRefresh();
this->AddPendingEvent(wxCommandEvent(pxEvt_SomethingChanged));//enable the apply button (the auto-trigger doesn't get triggered here...)
}
void Panels::MemoryCardListPanel_Simple::OnListDrag(wxListEvent& evt)
{
@ -692,9 +886,12 @@ void Panels::MemoryCardListPanel_Simple::OnOpenItemContextMenu(wxListEvent& evt)
{
const McdSlotItem& card( GetCardForViewIndex(idx) );
junk->Append( McdMenuId_Create, card.IsPresent ? _("Delete") : _("Create new...") );
junk->Append( McdMenuId_Mount, card.IsEnabled ? _("Disable") : _("Enable") );
junk->Append( McdMenuId_Relocate, _("Relocate file...") );
if (card.IsPresent){
junk->Append( McdMenuId_Mount, card.IsEnabled ? _("Disable Port") : _("Enable Port") );
junk->Append( McdMenuId_Rename, _("Rename card file...") );
}
junk->Append( McdMenuId_Create, card.IsPresent ? _("Delete card file") : _("Create a new card file...") );
junk->AppendSeparator();
}
@ -732,8 +929,10 @@ int Panels::MemoryCardListPanel_Simple::GetSlotIndexForViewIndex( int listViewIn
{
int targetSlot=-1;
//this list-view arrangement is mostly kept aligned with the slots indexes, and only takes care
/*
//this list-view arrangement is mostly kept aligned with the internal slots indexes, and only takes care
// of the case where MT1 is disabled (hence the MT2 slots 2,3,4 "move backwards" 3 places on the view-index)
// However, this arrangement it's not very intuitive to use...
if (!m_MultitapEnabled[0] && listViewIndex>=2)
{
//we got an MT2 slot.
@ -744,31 +943,30 @@ int Panels::MemoryCardListPanel_Simple::GetSlotIndexForViewIndex( int listViewIn
{
targetSlot=listViewIndex;//identical view-index and card slot.
}
*/
/* //alternative arrangement of list-view:
//mcd1(=MT1 slot 1)
//[MT1 slots 2,3,4 if MT1 is enabled]
//This arrangement of list-view is as follows:
//mcd1(=MT1 port 1)
//[MT1 port 2,3,4 if MT1 is enabled]
//mcd2(=MT2 slot 1)
//[MT2 slots 2,3,4 if MT2 is enabled]
//[MT2 port 2,3,4 if MT2 is enabled]
if (m_MultitapEnabled[0]){
//MT1 enabled:
if (1<=listViewIndex && idx<=3){//MT1 slots 2/3/4 move one place backwards
if (1<=listViewIndex && listViewIndex<=3){//MT1 ports 2/3/4 move one place backwards
targetSlot=listViewIndex+1;
}else if (listViewIndex==4){//mcd2 (=MT2 slot 1) moves 3 places forward
}else if (listViewIndex==4){//mcd2 (=MT2 port 1) moves 3 places forward
targetSlot=1;
} else {//mcd1 keeps it's pos as first, MT2 slots keep their pos at the end of the list.
} else {//mcd1 keeps it's pos as first, MT2 ports keep their pos at the end of the list.
targetSlot=listViewIndex;
}
} else {
//MT1 disabled: mcd1 and mcd2 stay put, MT2 slots 2,3,4 come next (move backwards 3 places)
//MT1 disabled: mcd1 and mcd2 stay put, MT2 ports 2,3,4 come next (move backwards 3 places)
if (2<=listViewIndex && listViewIndex<=4)
targetSlot=listViewIndex+3;
else
targetSlot=listViewIndex;
}
*/
assert(targetSlot>=0);
return targetSlot;

View File

@ -73,11 +73,11 @@ enum McdColumnType_Simple
{
McdColS_PortSlot, // port and slot of the card
McdColS_Status, // either Enabled/Disabled, or Missing (no card).
McdColS_Filename,
McdColS_Size,
McdColS_Formatted,
McdColS_DateModified,
McdColS_DateCreated,
McdColS_Filename,
McdColS_Count
};
@ -102,13 +102,13 @@ const ListViewColumnInfo& MemoryCardListView_Simple::GetDefaultColumnInfo( uint
{
static const ListViewColumnInfo columns[] =
{
{ _("PS2 Location") , 140 , wxLIST_FORMAT_CENTER },
{ _("Status") , 96 , wxLIST_FORMAT_CENTER },
{ _("Size") , 72 , wxLIST_FORMAT_LEFT },
{ _("Formatted") , 96 , wxLIST_FORMAT_CENTER },
{ _("Modified") , 120 , wxLIST_FORMAT_LEFT },
{ _("Created") , 120 , wxLIST_FORMAT_LEFT },
{ _("Filename") , 256 , wxLIST_FORMAT_LEFT },
{ _("PS2 Port") , 140 , wxLIST_FORMAT_LEFT },
{ _("Port status") , 96 , wxLIST_FORMAT_LEFT },
{ _("File name") , 256 , wxLIST_FORMAT_LEFT },
{ _("File size") , 72 , wxLIST_FORMAT_LEFT },
{ _("Formatted") , 96 , wxLIST_FORMAT_LEFT },
{ _("Last Modified"), 120 , wxLIST_FORMAT_LEFT },
{ _("Created on") , 120 , wxLIST_FORMAT_LEFT },
};
pxAssumeDev( idx < ArraySize(columns), "ListView column index is out of bounds." );
@ -128,29 +128,38 @@ wxString MemoryCardListView_Simple::OnGetItemText(long item, long column) const
{
if( !m_CardProvider ) return _parent::OnGetItemText(item, column);
const McdSlotItem& it( m_CardProvider->GetCardForViewIndex(item) );
wxString prefix=L" ";
switch( column )
{
// case McdColS_PortSlot: return pxsFmt( L"%u", item+1);
case McdColS_PortSlot:
if (!it.IsMultitapSlot())
return pxsFmt(L"Port-%u or Multitap-%u-Port-1", it.GetMtapPort()+1, it.GetMtapPort()+1);
return pxsFmt(L" Multitap-%u-Port-%u", it.GetMtapPort()+1, it.GetMtapSlot()+1);
return pxsFmt(wxString(L" ") + _("Port-%u / Multitap-%u--Port-1"), it.GetMtapPort()+1, it.GetMtapPort()+1);
return pxsFmt(wxString(L" ") + _("Multitap-%u--Port-%u"), it.GetMtapPort()+1, it.GetMtapSlot()+1);
case McdColS_Status: return it.IsPresent ? ( it.IsEnabled ? _("Enabled") : _("Disabled")) : _("Missing");
case McdColS_Size: return it.IsPresent ? pxsFmt( L"%u MB", it.SizeInMB ) : (wxString)_("N/A");
case McdColS_Formatted: return it.IsFormatted ? _("Yes") : _("No");
case McdColS_DateModified: return it.IsPresent ? it.DateModified.FormatDate() : (wxString)_("N/A");
case McdColS_DateCreated: return it.IsPresent ? it.DateCreated.FormatDate() : (wxString)_("N/A");
case McdColS_Status:
{
wxString res = prefix + (it.IsEnabled ? _("Enabled") : _("Disabled"));
if( !it.IsPresent )
res = prefix + _("Empty");
return prefix + res;
}
case McdColS_Size: return prefix + ( !it.IsPresent ? L"" : pxsFmt( L"%u MB", it.SizeInMB ) );
case McdColS_Formatted: return prefix + ( !it.IsPresent ? L"" : ( it.IsFormatted ? _("Yes") : _("No")) );
case McdColS_DateModified: return prefix + ( !it.IsPresent ? L"" : it.DateModified.FormatDate() );
case McdColS_DateCreated: return prefix + ( !it.IsPresent ? L"" : it.DateCreated.FormatDate() );
case McdColS_Filename:
{
if (!it.IsPresent) return L"";
wxDirName filepath( it.Filename.GetPath() );
if (filepath.SameAs(g_Conf->Folders.MemoryCards))
return it.Filename.GetFullName();
return prefix + it.Filename.GetFullName();
else
return it.Filename.GetFullPath();
return prefix + it.Filename.GetFullPath();
}
}
@ -185,11 +194,11 @@ wxListItemAttr* MemoryCardListView_Simple::OnGetItemAttr(long item) const
m_ItemAttr = wxListItemAttr(); // Wipe it clean!
if( !it.IsPresent )
if( !it.IsPresent || !it.IsEnabled)
m_ItemAttr.SetTextColour( *wxLIGHT_GREY );
/*
if( m_TargetedItem == item )
m_ItemAttr.SetBackgroundColour( wxColour(L"Wheat") );
*/
return &m_ItemAttr;
}

View File

@ -29,36 +29,43 @@ struct ListViewColumnInfo
// --------------------------------------------------------------------------------------
// McdListItem / IMcdList
//
// These are the items at the list-view.
// Each item holds:
// - An internal slot association (or -1 if it isn't associated with an internal slot)
// - Properties of the internal slot (when associated with one)
// - Properties of the file associated with this list item (when associated with one)
// --------------------------------------------------------------------------------------
struct McdSlotItem
{
bool IsPresent;
bool IsEnabled;
int Slot; //0-7: internal slot. -1: unrelated to an internal slot (the rest of the files at the folder).
bool IsPresent; //Whether or not a file is associated with this item (true/false when 0<=Slot<=7. Always true when Slot==-1)
//Only meaningful when IsPresent==true (a file exists for this item):
wxFileName Filename; // full pathname
bool IsFormatted;
uint SizeInMB; // size, in megabytes!
wxDateTime DateCreated;
wxDateTime DateModified;
int Slot;
wxFileName Filename; // full pathname (optional)
McdSlotItem()
{
//Port = -1;
Slot = -1;
IsPresent = false;
IsEnabled = false;
}
//Only meaningful when 0<=Slot<=7 (associated with an internal slot):
// Properties of an internal slot, and translation from internal slot index to ps2 physical port (0-based-indexes).
bool IsEnabled; //This slot is enabled/disabled
bool IsMultitapSlot() const;
uint GetMtapPort() const;
uint GetMtapSlot() const;
bool operator==( const McdSlotItem& right ) const;
bool operator!=( const McdSlotItem& right ) const;
McdSlotItem()
{
Slot = -1;
IsPresent = false;
IsEnabled = false;
}
};
typedef std::vector<McdSlotItem> McdList;
@ -84,7 +91,7 @@ protected:
IMcdList* m_CardProvider;
// specifies the target of a drag&drop operation
int m_TargetedItem;
int m_TargetedItem;
public:
virtual ~BaseMcdListView() throw() { }
@ -183,7 +190,9 @@ namespace Panels
typedef BaseMcdListPanel _parent;
protected:
McdSlotItem m_Cards[8];
McdSlotItem m_Cards[8];
wxButton* m_button_Rename;
// Doubles as Create and Delete buttons
wxButton* m_button_Create;
@ -206,7 +215,8 @@ namespace Panels
protected:
void OnCreateCard(wxCommandEvent& evt);
void OnMountCard(wxCommandEvent& evt);
void OnRelocateCard(wxCommandEvent& evt);
// void OnRelocateCard(wxCommandEvent& evt);
void OnRenameFile(wxCommandEvent& evt);
void OnListDrag(wxListEvent& evt);
void OnListSelectionChanged(wxListEvent& evt);