2017-08-14 02:17:45 +02:00
# include "save_manager_dialog.h"
# include "save_data_info_dialog.h"
# include "Emu/System.h"
# include "Emu/VFS.h"
# include "Loader/PSF.h"
# include <QIcon>
# include <QHBoxLayout>
# include <QPushButton>
# include <QHeaderView>
# include <QMenu>
# include <QMessageBox>
2017-10-24 17:09:38 +02:00
# include <QDesktopWidget>
# include <QApplication>
# include <QUrl>
# include <QDesktopServices>
2017-08-14 02:17:45 +02:00
namespace
{
// Helper converters
2017-09-20 22:25:10 +02:00
constexpr auto qstr = QString : : fromStdString ;
2017-11-27 22:31:15 +01:00
inline std : : string sstr ( const QString & _in ) { return _in . toStdString ( ) ; }
2017-08-14 02:17:45 +02:00
/**
* This certainly isn ' t ideal for this code , as it essentially copies cellSaveData . But , I have no other choice without adding public methods to cellSaveData .
*/
std : : vector < SaveDataEntry > GetSaveEntries ( const std : : string & base_dir )
{
std : : vector < SaveDataEntry > save_entries ;
// get the saves matching the supplied prefix
for ( const auto & entry : fs : : dir ( base_dir ) )
{
if ( ! entry . is_directory )
{
continue ;
}
// PSF parameters
const auto & psf = psf : : load_object ( fs : : file ( base_dir + entry . name + " /PARAM.SFO " ) ) ;
if ( psf . empty ( ) )
{
continue ;
}
SaveDataEntry save_entry2 ;
save_entry2 . dirName = psf . at ( " SAVEDATA_DIRECTORY " ) . as_string ( ) ;
save_entry2 . listParam = psf . at ( " SAVEDATA_LIST_PARAM " ) . as_string ( ) ;
save_entry2 . title = psf . at ( " TITLE " ) . as_string ( ) ;
save_entry2 . subtitle = psf . at ( " SUB_TITLE " ) . as_string ( ) ;
save_entry2 . details = psf . at ( " DETAIL " ) . as_string ( ) ;
save_entry2 . size = 0 ;
2017-11-30 21:55:26 +01:00
for ( const auto & entry2 : fs : : dir ( base_dir + entry . name ) )
2017-08-14 02:17:45 +02:00
{
save_entry2 . size + = entry2 . size ;
}
save_entry2 . atime = entry . atime ;
save_entry2 . mtime = entry . mtime ;
save_entry2 . ctime = entry . ctime ;
if ( fs : : is_file ( base_dir + entry . name + " /ICON0.PNG " ) )
{
fs : : file icon = fs : : file ( base_dir + entry . name + " /ICON0.PNG " ) ;
u32 iconSize = icon . size ( ) ;
std : : vector < uchar > iconData ;
icon . read ( iconData , iconSize ) ;
save_entry2 . iconBuf = iconData ;
}
save_entry2 . isNew = false ;
save_entries . emplace_back ( save_entry2 ) ;
}
return save_entries ;
}
}
2017-11-22 12:11:59 +01:00
save_manager_dialog : : save_manager_dialog ( std : : shared_ptr < gui_settings > gui_settings , std : : string dir , QWidget * parent )
: QDialog ( parent ) , m_save_entries ( ) , m_dir ( dir ) , m_sort_column ( 1 ) , m_sort_ascending ( true ) , m_gui_settings ( gui_settings )
2017-08-14 02:17:45 +02:00
{
setWindowTitle ( tr ( " Save Manager " ) ) ;
setMinimumSize ( QSize ( 400 , 400 ) ) ;
Init ( dir ) ;
}
/*
* Future proofing . Makes it easier in future if I add ability to change directories
*/
void save_manager_dialog : : Init ( std : : string dir )
{
// Table
m_list = new QTableWidget ( this ) ;
//m_list->setItemDelegate(new table_item_delegate(this)); // to get rid of cell selection rectangles include "table_item_delegate.h"
2017-10-24 17:09:38 +02:00
m_list - > setSelectionMode ( QAbstractItemView : : SelectionMode : : ExtendedSelection ) ;
2017-08-14 02:17:45 +02:00
m_list - > setSelectionBehavior ( QAbstractItemView : : SelectRows ) ;
m_list - > setContextMenuPolicy ( Qt : : CustomContextMenu ) ;
m_list - > setColumnCount ( 4 ) ;
m_list - > setHorizontalHeaderLabels ( QStringList ( ) < < tr ( " Title " ) < < tr ( " Subtitle " ) < < tr ( " Save ID " ) < < tr ( " Entry Notes " ) ) ;
2017-10-24 17:09:38 +02:00
QPushButton * push_remove_entries = new QPushButton ( tr ( " Delete Selection " ) , this ) ;
2017-08-14 02:17:45 +02:00
QPushButton * push_close = new QPushButton ( tr ( " &Close " ) , this ) ;
push_close - > setAutoDefault ( true ) ;
2017-10-24 17:09:38 +02:00
// Button Layout
QHBoxLayout * hbox_buttons = new QHBoxLayout ( ) ;
hbox_buttons - > addWidget ( push_remove_entries ) ;
2017-08-14 02:17:45 +02:00
hbox_buttons - > addStretch ( ) ;
hbox_buttons - > addWidget ( push_close ) ;
// main layout
QVBoxLayout * vbox_main = new QVBoxLayout ( ) ;
vbox_main - > setAlignment ( Qt : : AlignCenter ) ;
vbox_main - > addWidget ( m_list ) ;
vbox_main - > addLayout ( hbox_buttons ) ;
setLayout ( vbox_main ) ;
UpdateList ( ) ;
2018-03-28 20:08:15 +02:00
if ( restoreGeometry ( m_gui_settings - > GetValue ( gui : : sd_geometry ) . toByteArray ( ) ) )
resize ( size ( ) . expandedTo ( QDesktopWidget ( ) . availableGeometry ( ) . size ( ) * 0.5 ) ) ;
2017-11-22 12:11:59 +01:00
2017-08-14 02:17:45 +02:00
// Connects and events
connect ( push_close , & QAbstractButton : : clicked , this , & save_manager_dialog : : close ) ;
2017-10-24 17:09:38 +02:00
connect ( push_remove_entries , & QAbstractButton : : clicked , this , & save_manager_dialog : : OnEntriesRemove ) ;
2017-09-06 19:32:33 +02:00
connect ( m_list - > horizontalHeader ( ) , & QHeaderView : : sectionClicked , this , & save_manager_dialog : : OnSort ) ;
connect ( m_list , & QTableWidget : : itemDoubleClicked , this , & save_manager_dialog : : OnEntryInfo ) ;
2017-08-14 02:17:45 +02:00
connect ( m_list , & QTableWidget : : customContextMenuRequested , this , & save_manager_dialog : : ShowContextMenu ) ;
2017-09-05 22:40:35 +02:00
connect ( m_list , & QTableWidget : : cellChanged , [ & ] ( int row , int col )
{
2017-08-14 02:17:45 +02:00
int originalIndex = m_list - > item ( row , 0 ) - > data ( Qt : : UserRole ) . toInt ( ) ;
SaveDataEntry originalEntry = m_save_entries [ originalIndex ] ;
QString originalDirName = qstr ( originalEntry . dirName ) ;
2017-11-22 12:11:59 +01:00
QVariantMap currNotes = m_gui_settings - > GetValue ( gui : : m_saveNotes ) . toMap ( ) ;
2017-08-14 02:17:45 +02:00
currNotes [ originalDirName ] = m_list - > item ( row , col ) - > text ( ) ;
2017-11-22 12:11:59 +01:00
m_gui_settings - > SetValue ( gui : : m_saveNotes , currNotes ) ;
2017-08-14 02:17:45 +02:00
} ) ;
}
void save_manager_dialog : : UpdateList ( )
{
if ( m_dir = = " " )
{
2018-03-17 07:17:27 +01:00
m_dir = Emu . GetHddDir ( ) + " home/ " + Emu . GetUsr ( ) + " /savedata/ " ;
2017-08-14 02:17:45 +02:00
}
m_save_entries = GetSaveEntries ( m_dir ) ;
m_list - > clearContents ( ) ;
2017-09-20 22:25:10 +02:00
m_list - > setRowCount ( static_cast < int > ( m_save_entries . size ( ) ) ) ;
2017-11-22 12:11:59 +01:00
QVariantMap currNotes = m_gui_settings - > GetValue ( gui : : m_saveNotes ) . toMap ( ) ;
2017-08-14 02:17:45 +02:00
int row = 0 ;
2017-11-30 21:55:26 +01:00
for ( const SaveDataEntry & entry : m_save_entries )
2017-08-14 02:17:45 +02:00
{
QString title = qstr ( entry . title ) ;
QString subtitle = qstr ( entry . subtitle ) ;
QString dirName = qstr ( entry . dirName ) ;
QTableWidgetItem * titleItem = new QTableWidgetItem ( title ) ;
titleItem - > setData ( Qt : : UserRole , row ) ; // For sorting to work properly
titleItem - > setFlags ( titleItem - > flags ( ) & ~ Qt : : ItemIsEditable ) ;
m_list - > setItem ( row , 0 , titleItem ) ;
QTableWidgetItem * subtitleItem = new QTableWidgetItem ( subtitle ) ;
subtitleItem - > setFlags ( subtitleItem - > flags ( ) & ~ Qt : : ItemIsEditable ) ;
m_list - > setItem ( row , 1 , subtitleItem ) ;
QTableWidgetItem * dirNameItem = new QTableWidgetItem ( dirName ) ;
dirNameItem - > setFlags ( dirNameItem - > flags ( ) & ~ Qt : : ItemIsEditable ) ;
m_list - > setItem ( row , 2 , dirNameItem ) ;
QTableWidgetItem * noteItem = new QTableWidgetItem ( ) ;
noteItem - > setFlags ( noteItem - > flags ( ) | Qt : : ItemIsEditable ) ;
2017-11-22 12:11:59 +01:00
2017-08-14 02:17:45 +02:00
if ( currNotes . contains ( dirName ) )
{
noteItem - > setText ( currNotes [ dirName ] . toString ( ) ) ;
}
2017-11-22 12:11:59 +01:00
2017-08-14 02:17:45 +02:00
m_list - > setItem ( row , 3 , noteItem ) ;
+ + row ;
}
m_list - > horizontalHeader ( ) - > resizeSections ( QHeaderView : : ResizeToContents ) ;
m_list - > verticalHeader ( ) - > resizeSections ( QHeaderView : : ResizeToContents ) ;
QSize tableSize = QSize (
m_list - > verticalHeader ( ) - > width ( ) + m_list - > horizontalHeader ( ) - > length ( ) + m_list - > frameWidth ( ) * 2 ,
m_list - > horizontalHeader ( ) - > height ( ) + m_list - > verticalHeader ( ) - > length ( ) + m_list - > frameWidth ( ) * 2 ) ;
2017-10-28 16:22:18 +02:00
QSize preferredSize = minimumSize ( ) . expandedTo ( sizeHint ( ) - m_list - > sizeHint ( ) + tableSize ) ;
2017-08-14 02:17:45 +02:00
2017-10-28 16:22:18 +02:00
QSize maxSize = QSize ( preferredSize . width ( ) , static_cast < int > ( QApplication : : desktop ( ) - > screenGeometry ( ) . height ( ) * .6 ) ) ;
resize ( preferredSize . boundedTo ( maxSize ) ) ;
2017-08-14 02:17:45 +02:00
}
/**
* Copied method to do sort from save_data_list_dialog
*/
2017-09-06 19:32:33 +02:00
void save_manager_dialog : : OnSort ( int logicalIndex )
2017-08-14 02:17:45 +02:00
{
2017-09-06 19:32:33 +02:00
if ( logicalIndex > = 0 )
2017-08-14 02:17:45 +02:00
{
2017-09-06 19:32:33 +02:00
if ( logicalIndex = = m_sort_column )
2017-08-14 02:17:45 +02:00
{
2017-09-06 19:32:33 +02:00
m_sort_ascending ^ = true ;
2017-08-14 02:17:45 +02:00
}
else
{
2017-09-06 19:32:33 +02:00
m_sort_ascending = true ;
2017-08-14 02:17:45 +02:00
}
2018-06-20 02:15:26 +02:00
m_sort_column = logicalIndex ;
2017-09-06 19:32:33 +02:00
Qt : : SortOrder sort_order = m_sort_ascending ? Qt : : AscendingOrder : Qt : : DescendingOrder ;
m_list - > sortByColumn ( m_sort_column , sort_order ) ;
2017-08-14 02:17:45 +02:00
}
}
/**
* Display info dialog directly . Copied from save_data_list_dialog
*/
void save_manager_dialog : : OnEntryInfo ( )
{
int idx = m_list - > currentRow ( ) ;
if ( idx ! = - 1 )
{
idx = m_list - > item ( idx , 0 ) - > data ( Qt : : UserRole ) . toInt ( ) ;
save_data_info_dialog * infoDialog = new save_data_info_dialog ( m_save_entries [ idx ] , this ) ;
infoDialog - > setModal ( true ) ;
infoDialog - > show ( ) ;
}
}
//Remove a save file, need to be confirmed.
void save_manager_dialog : : OnEntryRemove ( )
{
int idx = m_list - > currentRow ( ) ;
if ( idx ! = - 1 )
{
2017-08-14 04:35:40 +02:00
int idx_real = m_list - > item ( idx , 0 ) - > data ( Qt : : UserRole ) . toInt ( ) ;
2018-02-10 15:00:06 +01:00
if ( QMessageBox : : question ( this , tr ( " Delete Confirmation " ) , tr ( " Are you sure you want to delete: \n %1? " ) . arg ( qstr ( m_save_entries [ idx_real ] . title ) ) , QMessageBox : : Yes , QMessageBox : : No ) = = QMessageBox : : Yes )
2017-08-14 02:17:45 +02:00
{
2017-08-14 04:35:40 +02:00
fs : : remove_all ( m_dir + m_save_entries [ idx_real ] . dirName + " / " ) ;
m_list - > removeRow ( idx ) ;
2017-08-14 02:17:45 +02:00
}
}
}
2017-10-24 17:09:38 +02:00
void save_manager_dialog : : OnEntriesRemove ( )
{
QModelIndexList selection ( m_list - > selectionModel ( ) - > selectedRows ( ) ) ;
if ( selection . size ( ) = = 0 )
{
return ;
}
if ( selection . size ( ) = = 1 )
{
OnEntryRemove ( ) ;
return ;
}
2018-02-10 15:00:06 +01:00
if ( QMessageBox : : question ( this , tr ( " Delete Confirmation " ) , tr ( " Are you sure you want to delete these %1 items? " ) . arg ( selection . size ( ) ) , QMessageBox : : Yes , QMessageBox : : No ) = = QMessageBox : : Yes )
2017-10-24 17:09:38 +02:00
{
qSort ( selection . begin ( ) , selection . end ( ) , qGreater < QModelIndex > ( ) ) ;
for ( QModelIndex index : selection )
{
int idx_real = m_list - > item ( index . row ( ) , 0 ) - > data ( Qt : : UserRole ) . toInt ( ) ;
fs : : remove_all ( m_dir + m_save_entries [ idx_real ] . dirName + " / " ) ;
m_list - > removeRow ( index . row ( ) ) ;
}
}
}
2017-08-14 02:17:45 +02:00
//Pop-up a small context-menu, being a replacement for save_data_manage_dialog
void save_manager_dialog : : ShowContextMenu ( const QPoint & pos )
{
2017-10-26 19:02:35 +02:00
bool selectedItems = m_list - > selectionModel ( ) - > selectedRows ( ) . size ( ) > 1 ;
2017-10-24 17:09:38 +02:00
2017-08-14 02:17:45 +02:00
QPoint globalPos = m_list - > mapToGlobal ( pos ) ;
QMenu * menu = new QMenu ( ) ;
int idx = m_list - > currentRow ( ) ;
2017-10-24 17:09:38 +02:00
if ( idx = = - 1 )
{
return ;
}
2017-08-14 02:17:45 +02:00
2017-09-06 19:32:33 +02:00
QAction * saveIDAct = new QAction ( tr ( " SaveID " ) , this ) ;
QAction * titleAct = new QAction ( tr ( " Title " ) , this ) ;
QAction * subtitleAct = new QAction ( tr ( " Subtitle " ) , this ) ;
2017-10-24 17:09:38 +02:00
2017-09-06 19:32:33 +02:00
QAction * removeAct = new QAction ( tr ( " &Remove " ) , this ) ;
QAction * infoAct = new QAction ( tr ( " &Info " ) , this ) ;
2017-10-24 17:09:38 +02:00
QAction * showDirAct = new QAction ( tr ( " &Open Save Directory " ) , this ) ;
2017-08-14 02:17:45 +02:00
2017-10-24 17:09:38 +02:00
//This is also a stub for the sort setting. Ids are set accordingly to their sort-type integer.
// TODO: add more sorting types.
m_sort_options = new QMenu ( tr ( " &Sort By " ) ) ;
2017-08-14 02:17:45 +02:00
m_sort_options - > addAction ( titleAct ) ;
m_sort_options - > addAction ( subtitleAct ) ;
m_sort_options - > addAction ( saveIDAct ) ;
menu - > addMenu ( m_sort_options ) ;
menu - > addSeparator ( ) ;
menu - > addAction ( removeAct ) ;
menu - > addAction ( infoAct ) ;
2017-10-24 17:09:38 +02:00
menu - > addAction ( showDirAct ) ;
2017-08-14 02:17:45 +02:00
2017-10-24 17:09:38 +02:00
infoAct - > setEnabled ( ! selectedItems ) ;
showDirAct - > setEnabled ( ! selectedItems ) ;
2017-08-14 02:17:45 +02:00
removeAct - > setEnabled ( idx ! = - 1 ) ;
2017-10-24 17:09:38 +02:00
// Events
connect ( removeAct , & QAction : : triggered , this , & save_manager_dialog : : OnEntriesRemove ) ; // entriesremove handles case of one as well
2017-08-14 02:17:45 +02:00
connect ( infoAct , & QAction : : triggered , this , & save_manager_dialog : : OnEntryInfo ) ;
2018-02-10 15:00:06 +01:00
connect ( showDirAct , & QAction : : triggered , [ = ] ( )
{
2017-10-24 17:09:38 +02:00
int idx_real = m_list - > item ( idx , 0 ) - > data ( Qt : : UserRole ) . toInt ( ) ;
QString path = qstr ( m_dir + m_save_entries [ idx_real ] . dirName + " / " ) ;
QDesktopServices : : openUrl ( QUrl ( " file:/// " + path ) ) ;
} ) ;
2017-08-14 02:17:45 +02:00
connect ( titleAct , & QAction : : triggered , this , [ = ] { OnSort ( 0 ) ; } ) ;
connect ( subtitleAct , & QAction : : triggered , this , [ = ] { OnSort ( 1 ) ; } ) ;
connect ( saveIDAct , & QAction : : triggered , this , [ = ] { OnSort ( 2 ) ; } ) ;
menu - > exec ( globalPos ) ;
}
2017-11-22 12:11:59 +01:00
2018-05-18 09:58:04 +02:00
void save_manager_dialog : : closeEvent ( QCloseEvent * event )
2017-11-22 12:11:59 +01:00
{
m_gui_settings - > SetValue ( gui : : sd_geometry , saveGeometry ( ) ) ;
2018-05-18 09:58:04 +02:00
QDialog : : closeEvent ( event ) ;
2017-11-22 12:11:59 +01:00
}