Load Shift Times settings from history on double-click

Redesign how shift times history is saved. Previously it stored the
localized strings in the history file, which are not particularly
parsable as the format may differ between locales. Rather than doing
this, store the raw settings in a json file, and generate the history
strings on display. In addition to making it much easier to load old
settings, this makes it so that the history is always displayed using
the current locale, rather than the locale in which the shifting was
done.

Closes #1427.

Originally committed to SVN as r6363.
This commit is contained in:
Thomas Goyne 2012-01-25 23:09:45 +00:00
parent 2094814077
commit 214079af58
2 changed files with 121 additions and 49 deletions

View file

@ -40,7 +40,10 @@
#include <libaegisub/io.h>
#include <libaegisub/log.h>
#include <libaegisub/scoped_ptr.h>
#include <libaegisub/cajun/elements.h>
#include <libaegisub/cajun/reader.h>
#include <libaegisub/cajun/writer.h>
#include "ass_dialogue.h"
#include "ass_file.h"
@ -55,10 +58,53 @@
#include "utils.h"
#include "video_context.h"
static wxString get_history_string(json::Object &obj) {
wxString filename = lagi_wxString(obj["filename"]);
if (filename.empty())
filename = _("unsaved");
wxString shift_amount(lagi_wxString(obj["amount"]));
if (!obj["is by time"])
shift_amount = wxString::Format(_("%s frames"), shift_amount);
wxString shift_direction = obj["is backward"] ? _("backward") : _("forward");
int64_t time_field = obj["fields"];
wxString fields =
time_field == 0 ? _("s+e") :
time_field == 1 ? _("s") :
_("e") ;
json::Array const& sel = obj["selection"];
wxString lines;
int64_t sel_mode = obj["mode"];
if (sel_mode == 0)
lines = _("all");
else if (sel_mode == 2)
lines = wxString::Format(_("from %d onward"), (int)(int64_t)sel.front()["start"]);
else {
lines += _("sel ");
for (json::Array::const_iterator it = sel.begin(); it != sel.end(); ++it) {
int beg = (int64_t)(*it)["start"];
int end = (int64_t)(*it)["end"];
if (beg == end)
lines += wxString::Format("%d", beg);
else
lines += wxString::Format("%d-%d", beg, end);
if (it + 1 != sel.end())
lines += ";";
}
}
return wxString::Format("%s, %s %s, %s, %s", filename, shift_amount, shift_direction, fields, lines);
}
DialogShiftTimes::DialogShiftTimes(agi::Context *context)
: wxDialog(context->parent, -1, _("Shift Times"))
, context(context)
, history_filename(STD_STR(StandardPaths::DecodePath("?user/shift_history.txt")))
, history_filename(STD_STR(StandardPaths::DecodePath("?user/shift_history.json")))
, history(new json::Array)
, timecodes_loaded_slot(context->videoController->AddTimecodesListener(&DialogShiftTimes::OnTimecodesLoaded, this))
{
SetIcon(BitmapToIcon(GETIMAGE(shift_times_toolbutton_24)));
@ -90,7 +136,7 @@ DialogShiftTimes::DialogShiftTimes(agi::Context *context)
wxString time_field_vals[] = { _("Start a&nd End times"), _("&Start times only"), _("&End times only") };
time_fields = new wxRadioBox(this, -1, _("Times"), wxDefaultPosition, wxDefaultSize, 3, time_field_vals, 1);
history = new wxListBox(this, -1, wxDefaultPosition, wxSize(350, 100), 0, NULL, wxLB_HSCROLL);
history_box = new wxListBox(this, -1, wxDefaultPosition, wxSize(350, 100), 0, NULL, wxLB_HSCROLL);
wxButton *clear_button = new wxButton(this, -1, _("&Clear"));
clear_button->Bind(wxEVT_COMMAND_BUTTON_CLICKED, &DialogShiftTimes::OnClear, this);
@ -134,7 +180,7 @@ DialogShiftTimes::DialogShiftTimes(agi::Context *context)
left_sizer->Add(time_fields, wxSizerFlags().Expand());
wxSizer *history_sizer = new wxStaticBoxSizer(wxVERTICAL, this, _("History"));
history_sizer->Add(history, wxSizerFlags(1).Expand());
history_sizer->Add(history_box, wxSizerFlags(1).Expand());
history_sizer->Add(clear_button, wxSizerFlags().Expand().Border(wxTOP));
wxSizer *top_sizer = new wxBoxSizer(wxHORIZONTAL);
@ -150,6 +196,7 @@ DialogShiftTimes::DialogShiftTimes(agi::Context *context)
Bind(wxEVT_COMMAND_BUTTON_CLICKED, &DialogShiftTimes::Process, this, wxID_OK);
Bind(wxEVT_COMMAND_BUTTON_CLICKED, &DialogShiftTimes::OnClose, this, wxID_CANCEL);
Bind(wxEVT_COMMAND_BUTTON_CLICKED, std::tr1::bind(&HelpButton::OpenPage, "Shift Times"), wxID_HELP);
history_box->Bind(wxEVT_COMMAND_LISTBOX_DOUBLECLICKED, &DialogShiftTimes::OnHistoryClick, this);
context->selectionController->AddSelectionListener(this);
}
@ -185,7 +232,8 @@ void DialogShiftTimes::OnSelectedSetChanged(Selection const&, Selection const&)
void DialogShiftTimes::OnClear(wxCommandEvent &) {
wxRemoveFile(lagi_wxString(history_filename));
history->Clear();
history_box->Clear();
history->clear();
}
void DialogShiftTimes::OnClose(wxCommandEvent &) {
@ -212,39 +260,47 @@ void DialogShiftTimes::OnByFrames(wxCommandEvent &) {
shift_frames->Enable(true);
}
void DialogShiftTimes::SaveHistory(std::vector<std::pair<int, int> > const& shifted_blocks) {
wxString filename = wxFileName(context->ass->filename).GetFullName();
int fields = time_fields->GetSelection();
void DialogShiftTimes::OnHistoryClick(wxCommandEvent &evt) {
size_t entry = evt.GetInt();
if (entry >= history->size()) return;
wxString new_line = wxString::Format("%s, %s %s, %s, ",
filename.empty() ? _("unsaved") : filename,
shift_by_time->GetValue() ? shift_time->GetValue() : shift_frames->GetValue() + _(" frames"),
shift_backward->GetValue() ? _("backward") : _("forward"),
fields == 0 ? _("s+e") : fields == 1 ? _("s") : _("e"));
int sel_mode = selection_mode->GetSelection();
if (sel_mode == 0)
new_line += _("all");
else if (sel_mode == 2)
new_line += wxString::Format(_("from %d onward"), shifted_blocks.front().first);
json::Object& obj = (*history)[entry];
if (obj["is by time"]) {
shift_time->SetValue(lagi_wxString(obj["amount"]));
shift_by_time->SetValue(true);
OnByTime(evt);
}
else {
new_line += _("sel ");
for (size_t i = 0; i < shifted_blocks.size(); ++i) {
std::pair<int, int> const& b = shifted_blocks[i];
wxString term = i == shifted_blocks.size() - 1 ? "" : ";";
if (b.first == b.second)
new_line += wxString::Format("%d%s", b.first, term);
else
new_line += wxString::Format("%d-%d%s", b.first, b.second, term);
shift_frames->SetValue(lagi_wxString(obj["amount"]));
if (shift_by_frames->IsEnabled()) {
shift_by_frames->SetValue(true);
OnByFrames(evt);
}
}
try {
agi::io::Save file(history_filename);
if (obj["is backward"])
shift_backward->SetValue(true);
else
shift_forward->SetValue(true);
for (size_t i = 0; i < history->GetCount(); ++i)
file.Get() << history->GetString(i).utf8_str() << std::endl;
file.Get() << new_line.utf8_str() << std::endl;
selection_mode->SetSelection((int64_t)obj["mode"]);
time_fields->SetSelection((int64_t)obj["fields"]);
}
void DialogShiftTimes::SaveHistory(json::Array const& shifted_blocks) {
json::Object new_entry;
new_entry["filename"] = STD_STR(wxFileName(context->ass->filename).GetFullName());
new_entry["is by time"] = shift_by_time->GetValue();
new_entry["is backward"] = shift_backward->GetValue();
new_entry["amount"] = STD_STR(shift_by_time->GetValue() ? shift_time->GetValue() : shift_frames->GetValue());
new_entry["fields"] = time_fields->GetSelection();
new_entry["mode"] = selection_mode->GetSelection();
new_entry["selection"] = shifted_blocks;
history->push_front(new_entry);
try {
json::Writer::Write(*history, agi::io::Save(history_filename).Get());
}
catch (agi::FileSystemError const& e) {
LOG_E("dialog_shift_times/save_history") << "Cannot save shift times history: " << e.GetChainedMessage();
@ -252,27 +308,27 @@ void DialogShiftTimes::SaveHistory(std::vector<std::pair<int, int> > const& shif
}
void DialogShiftTimes::LoadHistory() {
history->Clear();
history->Freeze();
history_box->Clear();
history_box->Freeze();
try {
agi::scoped_ptr<std::istream> file(agi::io::Open(history_filename));
std::string buffer;
while(!file->eof()) {
getline(*file, buffer);
if (buffer.size())
history->Insert(lagi_wxString(buffer), 0);
}
json::UnknownElement root;
json::Reader::Read(root, *file);
*history = root;
for (json::Array::iterator it = history->begin(); it != history->end(); ++it)
history_box->Append(get_history_string(*it));
}
catch (agi::FileSystemError const& e) {
LOG_E("dialog_shift_times/save_history") << "Cannot load shift times history: " << e.GetChainedMessage();
LOG_D("dialog_shift_times/load_history") << "Cannot load shift times history: " << e.GetChainedMessage();
}
catch (...) {
history->Thaw();
history_box->Thaw();
throw;
}
history->Thaw();
history_box->Thaw();
}
void DialogShiftTimes::Process(wxCommandEvent &) {
@ -303,7 +359,7 @@ void DialogShiftTimes::Process(wxCommandEvent &) {
// Track which rows were shifted for the log
int row_number = 0;
int block_start = 0;
std::vector<std::pair<int, int> > shifted_blocks;
json::Array shifted_blocks;
for (entryIter it = context->ass->Line.begin(); it != context->ass->Line.end(); ++it) {
AssDialogue *line = dynamic_cast<AssDialogue*>(*it);
@ -312,7 +368,10 @@ void DialogShiftTimes::Process(wxCommandEvent &) {
if (!sel.count(line)) {
if (block_start) {
shifted_blocks.push_back(std::make_pair(block_start, row_number - 1));
json::Object block;
block["start"] = block_start;
block["end"] = row_number - 1;
shifted_blocks.push_back(block);
block_start = 0;
}
if (mode == 1) continue;
@ -329,8 +388,12 @@ void DialogShiftTimes::Process(wxCommandEvent &) {
context->ass->Commit(_("shifting"), AssFile::COMMIT_DIAG_TIME);
if (block_start)
shifted_blocks.push_back(std::make_pair(block_start, row_number - 1));
if (block_start) {
json::Object block;
block["start"] = block_start;
block["end"] = row_number - 1;
shifted_blocks.push_back(block);
}
SaveHistory(shifted_blocks);
Close();

View file

@ -22,9 +22,12 @@
///
#ifndef AGI_PRE
#include <deque>
#include <wx/dialog.h>
#endif
#include <libaegisub/scoped_ptr.h>
#include <libaegisub/signal.h>
#include <libaegisub/vfr.h>
@ -37,6 +40,10 @@ class wxRadioBox;
class wxRadioButton;
class wxTextCtrl;
namespace agi { struct Context; }
namespace json {
class UnknownElement;
typedef std::deque<UnknownElement> Array;
}
/// DOCME
/// @class DialogShiftTimes
@ -47,6 +54,7 @@ class DialogShiftTimes : public wxDialog, private SelectionListener<AssDialogue>
agi::Context *context;
std::string history_filename;
agi::scoped_ptr<json::Array> history;
agi::vfr::Framerate fps;
agi::signal::Connection timecodes_loaded_slot;
@ -58,9 +66,9 @@ class DialogShiftTimes : public wxDialog, private SelectionListener<AssDialogue>
wxRadioButton *shift_backward;
wxRadioBox *selection_mode;
wxRadioBox *time_fields;
wxListBox *history;
wxListBox *history_box;
void SaveHistory(std::vector<std::pair<int, int> > const& shifted_blocks);
void SaveHistory(json::Array const& shifted_blocks);
void LoadHistory();
void Process(wxCommandEvent&);
int Shift(int initial_time, int shift, bool by_time, agi::vfr::Time type);
@ -69,6 +77,7 @@ class DialogShiftTimes : public wxDialog, private SelectionListener<AssDialogue>
void OnClose(wxCommandEvent&);
void OnByTime(wxCommandEvent&);
void OnByFrames(wxCommandEvent&);
void OnHistoryClick(wxCommandEvent&);
void OnActiveLineChanged(AssDialogue*) { }
void OnSelectedSetChanged(Selection const&, Selection const&);