mirror of
https://github.com/RPCS3/rpcs3.git
synced 2025-04-22 04:25:19 +00:00
Qt: Exit And Save Log - toolbar action (#14212)
Fixup main_window::IsValidFile
This commit is contained in:
parent
db029ed29f
commit
ba988f1d3f
6 changed files with 230 additions and 1 deletions
|
@ -135,6 +135,7 @@ namespace gui
|
|||
const gui_save fd_insert_disc = gui_save(main_window, "lastExplorePathDISC", "");
|
||||
const gui_save fd_cfg_check = gui_save(main_window, "lastExplorePathCfgChk", "");
|
||||
const gui_save fd_save_elf = gui_save(main_window, "lastExplorePathSaveElf", "");
|
||||
const gui_save fd_save_log = gui_save(main_window, "lastExplorePathSaveLog", "");
|
||||
|
||||
const gui_save mw_debugger = gui_save(main_window, "debuggerVisible", false);
|
||||
const gui_save mw_logger = gui_save(main_window, "loggerVisible", true);
|
||||
|
|
|
@ -2347,6 +2347,124 @@ void main_window::CreateConnects()
|
|||
|
||||
connect(ui->bootInstallPkgAct, &QAction::triggered, this, [this] {InstallPackages(); });
|
||||
connect(ui->bootInstallPupAct, &QAction::triggered, this, [this] {InstallPup(); });
|
||||
|
||||
connect(this, &main_window::NotifyWindowCloseEvent, this, [this](bool closed)
|
||||
{
|
||||
if (!closed)
|
||||
{
|
||||
// Cancel the request
|
||||
m_requested_show_logs_on_exit = false;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!m_requested_show_logs_on_exit)
|
||||
{
|
||||
// Not requested
|
||||
return;
|
||||
}
|
||||
|
||||
const std::string archived_path = fs::get_cache_dir() + "RPCS3.log.gz";
|
||||
const std::string raw_file_path = fs::get_cache_dir() + "RPCS3.log";
|
||||
|
||||
fs::stat_t raw_stat{};
|
||||
fs::stat_t archived_stat{};
|
||||
|
||||
if ((!fs::stat(raw_file_path, raw_stat) || raw_stat.is_directory) || (!fs::stat(archived_path, archived_stat) || archived_stat.is_directory) || (raw_stat.size == 0 && archived_stat.size == 0))
|
||||
{
|
||||
QMessageBox::warning(this, tr("Failed to locate log"), tr("Failed to locate log files.\nMake sure that RPCS3.log and RPCS3.log.gz are writable and can be created without permission issues."));
|
||||
return;
|
||||
}
|
||||
|
||||
// Get new filename from title and title ID but simplified
|
||||
std::string log_filename = Emu.GetTitleID().empty() ? "RPCS3" : Emu.GetTitleAndTitleID();
|
||||
log_filename.erase(std::remove_if(log_filename.begin(), log_filename.end(), [](u8 c){ return !std::isalnum(c) && c != ' ' && c != '[' && ']'; }), log_filename.end());
|
||||
fmt::trim_back(log_filename);
|
||||
|
||||
QString path_last_log = m_gui_settings->GetValue(gui::fd_save_log).toString();
|
||||
|
||||
auto move_log = [](const std::string& from, const std::string& to)
|
||||
{
|
||||
if (from == to)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Test writablity here to avoid closing the log with no *chance* of success
|
||||
if (fs::file test_writable{to, fs::write + fs::create}; !test_writable)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Close and flush log file handle (!)
|
||||
// Cannot rename the file due to file management design
|
||||
logs::listener::close_all_prematurely();
|
||||
|
||||
// Try to move it
|
||||
if (fs::rename(from, to, true))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// Try to copy it if fails
|
||||
if (fs::copy_file(from, to, true))
|
||||
{
|
||||
fs::remove_file(from);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
};
|
||||
|
||||
if (archived_stat.size)
|
||||
{
|
||||
const QString dir_path = QFileDialog::getExistingDirectory(this, tr("Select RPCS3's log saving location (saving %0)").arg(qstr(log_filename + ".log.gz")), path_last_log, QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks);
|
||||
|
||||
if (dir_path.isEmpty())
|
||||
{
|
||||
// Aborted - view the current location
|
||||
gui::utils::open_dir(archived_path);
|
||||
return;
|
||||
}
|
||||
|
||||
const std::string dest_archived_path = dir_path.toStdString() + "/" + log_filename + ".log.gz";
|
||||
|
||||
if (!Emu.GetTitleID().empty() && !dest_archived_path.empty() && move_log(archived_path, dest_archived_path))
|
||||
{
|
||||
m_gui_settings->SetValue(gui::fd_save_log, dir_path);
|
||||
gui_log.success("Moved log file to '%s'!", dest_archived_path);
|
||||
return;
|
||||
}
|
||||
|
||||
gui::utils::open_dir(archived_path);
|
||||
return;
|
||||
}
|
||||
|
||||
const QString dir_path = QFileDialog::getExistingDirectory(this, tr("Select RPCS3's log saving location (saving %0)").arg(qstr(log_filename + ".log")), path_last_log, QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks);
|
||||
|
||||
if (dir_path.isEmpty())
|
||||
{
|
||||
// Aborted - view the current location
|
||||
gui::utils::open_dir(raw_file_path);
|
||||
return;
|
||||
}
|
||||
|
||||
const std::string dest_raw_file_path = dir_path.toStdString() + "/" + log_filename + ".log";
|
||||
|
||||
if (!Emu.GetTitleID().empty() && !dest_raw_file_path.empty() && move_log(raw_file_path, dest_raw_file_path))
|
||||
{
|
||||
m_gui_settings->SetValue(gui::fd_save_log, dir_path);
|
||||
gui_log.success("Moved log file to '%s'!", dest_raw_file_path);
|
||||
return;
|
||||
}
|
||||
|
||||
gui::utils::open_dir(raw_file_path);
|
||||
});
|
||||
|
||||
connect(ui->exitAndSaveLogAct, &QAction::triggered, this, [this]()
|
||||
{
|
||||
m_requested_show_logs_on_exit = true;
|
||||
close();
|
||||
});
|
||||
connect(ui->exitAct, &QAction::triggered, this, &QWidget::close);
|
||||
|
||||
connect(ui->batchCreatePPUCachesAct, &QAction::triggered, m_game_list_frame, &game_list_frame::BatchCreatePPUCaches);
|
||||
|
@ -3212,6 +3330,7 @@ void main_window::closeEvent(QCloseEvent* closeEvent)
|
|||
{
|
||||
if (!m_gui_settings->GetBootConfirmation(this, gui::ib_confirm_exit))
|
||||
{
|
||||
Q_EMIT NotifyWindowCloseEvent(false);
|
||||
closeEvent->ignore();
|
||||
return;
|
||||
}
|
||||
|
@ -3223,6 +3342,12 @@ void main_window::closeEvent(QCloseEvent* closeEvent)
|
|||
}
|
||||
|
||||
SaveWindowState();
|
||||
|
||||
// Flush logs here as well
|
||||
logs::listener::sync_all();
|
||||
|
||||
Q_EMIT NotifyWindowCloseEvent(true);
|
||||
|
||||
Emu.Quit(true);
|
||||
}
|
||||
|
||||
|
@ -3248,6 +3373,11 @@ Check data for valid file types and cache their paths if necessary
|
|||
*/
|
||||
main_window::drop_type main_window::IsValidFile(const QMimeData& md, QStringList* drop_paths)
|
||||
{
|
||||
if (drop_paths)
|
||||
{
|
||||
drop_paths->clear();
|
||||
}
|
||||
|
||||
drop_type type = drop_type::drop_error;
|
||||
|
||||
QList<QUrl> list = md.urls(); // get list of all the dropped file urls
|
||||
|
@ -3255,6 +3385,14 @@ main_window::drop_type main_window::IsValidFile(const QMimeData& md, QStringList
|
|||
// Try to cache the data for half a second
|
||||
if (m_drop_file_timestamp != umax && m_drop_file_url_list == list && get_system_time() - m_drop_file_timestamp < 500'000)
|
||||
{
|
||||
if (drop_paths)
|
||||
{
|
||||
for (auto&& url : m_drop_file_url_list)
|
||||
{
|
||||
drop_paths->append(url.toLocalFile());
|
||||
}
|
||||
}
|
||||
|
||||
return m_drop_file_cached_drop_type;
|
||||
}
|
||||
|
||||
|
|
|
@ -50,6 +50,7 @@ class main_window : public QMainWindow
|
|||
|
||||
bool m_is_list_mode = true;
|
||||
bool m_save_slider_pos = false;
|
||||
bool m_requested_show_logs_on_exit = false;
|
||||
int m_other_slider_pos = 0;
|
||||
|
||||
QIcon m_app_icon;
|
||||
|
@ -95,6 +96,7 @@ Q_SIGNALS:
|
|||
void RequestGlobalStylesheetChange();
|
||||
void RequestTrophyManagerRepaint();
|
||||
void NotifyEmuSettingsChange();
|
||||
void NotifyWindowCloseEvent(bool closed);
|
||||
|
||||
public Q_SLOTS:
|
||||
void OnEmuStop();
|
||||
|
|
|
@ -213,6 +213,7 @@
|
|||
<addaction name="menuBatch"/>
|
||||
<addaction name="menuFirmware"/>
|
||||
<addaction name="separator"/>
|
||||
<addaction name="exitAndSaveLogAct"/>
|
||||
<addaction name="exitAct"/>
|
||||
</widget>
|
||||
<widget class="QMenu" name="menuEmulation">
|
||||
|
@ -588,6 +589,17 @@
|
|||
<string>Configure Auto Pause</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="exitAndSaveLogAct">
|
||||
<property name="text">
|
||||
<string>Exit And Save Log</string>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Exit RPCS3, move the log file to a custom location</string>
|
||||
</property>
|
||||
<property name="statusTip">
|
||||
<string>Exit the application and save the log to a user-defined location</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="exitAct">
|
||||
<property name="text">
|
||||
<string>Exit</string>
|
||||
|
|
|
@ -107,6 +107,9 @@ namespace logs
|
|||
|
||||
// Ensure written to disk
|
||||
void sync();
|
||||
|
||||
// Close file handle after flushing to disk
|
||||
void close_prematurely();
|
||||
};
|
||||
|
||||
struct file_listener final : file_writer, public listener
|
||||
|
@ -121,6 +124,11 @@ namespace logs
|
|||
{
|
||||
file_writer::sync();
|
||||
}
|
||||
|
||||
void close_prematurely() override
|
||||
{
|
||||
file_writer::close_prematurely();
|
||||
}
|
||||
};
|
||||
|
||||
struct root_listener final : public listener
|
||||
|
@ -353,6 +361,10 @@ void logs::listener::sync()
|
|||
{
|
||||
}
|
||||
|
||||
void logs::listener::close_prematurely()
|
||||
{
|
||||
}
|
||||
|
||||
void logs::listener::sync_all()
|
||||
{
|
||||
for (listener* lis = get_logger(); lis; lis = lis->m_next)
|
||||
|
@ -361,6 +373,14 @@ void logs::listener::sync_all()
|
|||
}
|
||||
}
|
||||
|
||||
void logs::listener::close_all_prematurely()
|
||||
{
|
||||
for (listener* lis = get_logger(); lis; lis = lis->m_next)
|
||||
{
|
||||
lis->close_prematurely();
|
||||
}
|
||||
}
|
||||
|
||||
logs::registerer::registerer(channel& _ch)
|
||||
{
|
||||
std::lock_guard lock(g_mutex);
|
||||
|
@ -535,7 +555,7 @@ logs::file_writer::~file_writer()
|
|||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
// Cancel compressed log file autodeletion
|
||||
// Cancel compressed log file auto-deletion
|
||||
FILE_DISPOSITION_INFO disp;
|
||||
disp.DeleteFileW = false;
|
||||
SetFileInformationByHandle(m_fout2.get_handle(), FileDispositionInfo, &disp, sizeof(disp));
|
||||
|
@ -691,6 +711,56 @@ void logs::file_writer::sync()
|
|||
}
|
||||
}
|
||||
|
||||
void logs::file_writer::close_prematurely()
|
||||
{
|
||||
if (!m_fptr)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Ensure written to disk
|
||||
sync();
|
||||
|
||||
std::lock_guard lock(m_m);
|
||||
|
||||
if (m_fout2)
|
||||
{
|
||||
m_zs.avail_in = 0;
|
||||
m_zs.next_in = nullptr;
|
||||
|
||||
do
|
||||
{
|
||||
m_zs.avail_out = sizeof(m_zout);
|
||||
m_zs.next_out = m_zout;
|
||||
|
||||
if (deflate(&m_zs, Z_FINISH) == Z_STREAM_ERROR || m_fout2.write(m_zout, sizeof(m_zout) - m_zs.avail_out) != sizeof(m_zout) - m_zs.avail_out)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
while (m_zs.avail_out == 0);
|
||||
|
||||
deflateEnd(&m_zs);
|
||||
|
||||
#ifdef _WIN32
|
||||
// Cancel compressed log file auto-deletion
|
||||
FILE_DISPOSITION_INFO disp;
|
||||
disp.DeleteFileW = false;
|
||||
SetFileInformationByHandle(m_fout2.get_handle(), FileDispositionInfo, &disp, sizeof(disp));
|
||||
#else
|
||||
// Restore compressed log file permissions
|
||||
::fchmod(m_fout2.get_handle(), S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
|
||||
#endif
|
||||
|
||||
m_fout2.close();
|
||||
}
|
||||
|
||||
if (m_fout)
|
||||
{
|
||||
m_fout.close();
|
||||
}
|
||||
}
|
||||
|
||||
logs::file_listener::file_listener(const std::string& path, u64 max_size)
|
||||
: file_writer(path, max_size)
|
||||
, listener()
|
||||
|
|
|
@ -84,6 +84,9 @@ namespace logs
|
|||
// Flush contents (file writer)
|
||||
virtual void sync();
|
||||
|
||||
// Close file handle after flushing to disk (hazardous)
|
||||
virtual void close_prematurely();
|
||||
|
||||
// Add new listener
|
||||
static void add(listener*);
|
||||
|
||||
|
@ -92,6 +95,9 @@ namespace logs
|
|||
|
||||
// Flush log to disk
|
||||
static void sync_all();
|
||||
|
||||
// Close file handle after flushing to disk (hazardous)
|
||||
static void close_all_prematurely();
|
||||
};
|
||||
|
||||
struct alignas(16) channel : private message
|
||||
|
|
Loading…
Add table
Reference in a new issue