1 // Copyright (c) 2013, Thomas Goyne <plorkyeran@aegisub.org> 2 // 3 // Permission to use, copy, modify, and distribute this software for any 4 // purpose with or without fee is hereby granted, provided that the above 5 // copyright notice and this permission notice appear in all copies. 6 // 7 // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 8 // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 9 // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 10 // ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 11 // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 12 // ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 13 // OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 14 // 15 // Aegisub Project http://www.aegisub.org/ 16 17 #include <libaegisub/fs_fwd.h> 18 #include <libaegisub/signal.h> 19 20 #include <boost/container/list.hpp> 21 #include <boost/filesystem/path.hpp> 22 #include <wx/timer.h> 23 24 class SelectionController; 25 namespace agi { struct Context; } 26 struct AssFileCommit; 27 struct ProjectProperties; 28 29 class SubsController { 30 agi::Context *context; 31 agi::signal::Connection undo_connection; 32 agi::signal::Connection active_line_connection; 33 agi::signal::Connection selection_connection; 34 agi::signal::Connection text_selection_connection; 35 36 struct UndoInfo; 37 boost::container::list<UndoInfo> undo_stack; 38 boost::container::list<UndoInfo> redo_stack; 39 40 /// Revision counter for undo coalescing and modified state tracking 41 int commit_id = 0; 42 /// Last saved version of this file 43 int saved_commit_id = 0; 44 /// Last autosaved version of this file 45 int autosaved_commit_id = 0; 46 47 /// Timer for triggering autosaves 48 wxTimer autosave_timer; 49 50 /// A new file has been opened (filename) 51 agi::signal::Signal<agi::fs::path> FileOpen; 52 /// The file has been saved 53 agi::signal::Signal<> FileSave; 54 55 /// The filename of the currently open file, if any 56 agi::fs::path filename; 57 58 /// Set the filename, updating things like the MRU and last used path 59 void SetFileName(agi::fs::path const& file); 60 61 void OnCommit(AssFileCommit c); 62 void OnActiveLineChanged(); 63 void OnSelectionChanged(); 64 void OnTextSelectionChanged(); 65 66 public: 67 SubsController(agi::Context *context); 68 ~SubsController(); 69 70 /// Set the selection controller to use 71 /// 72 /// Required due to that the selection controller is the subtitles grid, and 73 /// so is created long after the subtitles controller 74 void SetSelectionController(SelectionController *selection_controller); 75 76 /// The file's path and filename if any, or platform-appropriate "untitled" 77 agi::fs::path Filename() const; 78 79 /// Does the file have unsaved changes? IsModified()80 bool IsModified() const { return commit_id != saved_commit_id; }; 81 82 /// @brief Load from a file 83 /// @param file File name 84 /// @param charset Character set of file 85 ProjectProperties Load(agi::fs::path const& file, std::string charset); 86 87 /// @brief Save to a file 88 /// @param file Path to save to 89 /// @param encoding Encoding to use, or empty to let the writer decide (which usually means "App/Save Charset") 90 void Save(agi::fs::path const& file, std::string const& encoding=""); 91 92 /// Close the currently open file (i.e. open a new blank file) 93 void Close(); 94 95 /// If there are unsaved changes, asl the user if they want to save them 96 /// @param allow_cancel Let the user cancel the closing 97 /// @return wxYES, wxNO or wxCANCEL (note: all three are true in a boolean context) 98 int TryToClose(bool allow_cancel = true) const; 99 100 /// @brief Autosave the file if there have been any chances since the last autosave 101 /// @return File name used or empty if no save was performed 102 agi::fs::path AutoSave(); 103 104 /// Can the file be saved in its current format? 105 bool CanSave() const; 106 107 /// The file is about to be saved 108 /// This signal is intended for adding metadata which is awkward or 109 /// expensive to always keep up to date 110 agi::signal::Signal<> UpdateProperties; 111 112 DEFINE_SIGNAL_ADDERS(FileOpen, AddFileOpenListener) 113 DEFINE_SIGNAL_ADDERS(FileSave, AddFileSaveListener) 114 115 /// @brief Undo the last set of changes to the file 116 void Undo(); 117 /// @brief Redo the last undone changes 118 void Redo(); 119 /// Check if undo stack is empty IsUndoStackEmpty()120 bool IsUndoStackEmpty() const { return undo_stack.size() <= 1; }; 121 /// Check if redo stack is empty IsRedoStackEmpty()122 bool IsRedoStackEmpty() const { return redo_stack.empty(); }; 123 /// Get the description of the first undoable change 124 wxString GetUndoDescription() const; 125 /// Get the description of the first redoable change 126 wxString GetRedoDescription() const; 127 }; 128