Basic recent files list in the File menu.
authorCarl Hetherington <cth@carlh.net>
Mon, 25 Aug 2014 15:33:55 +0000 (16:33 +0100)
committerCarl Hetherington <cth@carlh.net>
Mon, 25 Aug 2014 15:33:55 +0000 (16:33 +0100)
Suggested-by: Carsten Kurz
ChangeLog
src/lib/config.cc
src/lib/config.h
src/lib/util.h
src/tools/dcpomatic.cc

index 8b0a5cd3e990b7cdcdc2410db8cfedadc78cd98b..c3d8a77c4877479c5657c6ab756968faefa5f22d 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,7 @@
+2014-08-25  Carl Hetherington  <cth@carlh.net>
+
+       * Basic recent files list in the File menu.
+
 2014-08-23  Carl Hetherington  <cth@carlh.net>
 
        * Version 1.72.12 released.
index d11bcf983f5365a872027570d840b1c5ff92dc36..04f28579ba580ab927e9ac77a58958632e7fa8a9 100644 (file)
 #include "i18n.h"
 
 using std::vector;
+using std::cout;
 using std::ifstream;
 using std::string;
 using std::list;
 using std::max;
+using std::remove;
 using std::exception;
 using std::cerr;
 using boost::shared_ptr;
@@ -204,6 +206,11 @@ Config::read ()
        _allow_any_dcp_frame_rate = f.optional_bool_child ("AllowAnyDCPFrameRate");
 
        _log_types = f.optional_number_child<int> ("LogTypes").get_value_or (Log::TYPE_GENERAL | Log::TYPE_WARNING | Log::TYPE_ERROR);
+
+       list<cxml::NodePtr> his = f.node_children ("History");
+       for (list<cxml::NodePtr>::const_iterator i = his.begin(); i != his.end(); ++i) {
+               _history.push_back ((*i)->content ());
+       }
 }
 
 void
@@ -388,6 +395,10 @@ Config::write () const
        root->add_child("MaximumJ2KBandwidth")->add_child_text (raw_convert<string> (_maximum_j2k_bandwidth));
        root->add_child("AllowAnyDCPFrameRate")->add_child_text (_allow_any_dcp_frame_rate ? "1" : "0");
        root->add_child("LogTypes")->add_child_text (raw_convert<string> (_log_types));
+
+       for (vector<boost::filesystem::path>::const_iterator i = _history.begin(); i != _history.end(); ++i) {
+               root->add_child("History")->add_child_text (i->string ());
+       }
        
        doc.write_to_file_formatted (file(false).string ());
 }
@@ -434,3 +445,17 @@ Config::reset_kdm_email ()
                "Best regards,\nDCP-o-matic"
                );
 }
+
+void
+Config::add_to_history (boost::filesystem::path p)
+{
+       /* Remove existing instances of this path in the history */
+       _history.erase (remove (_history.begin(), _history.end(), p), _history.end ());
+       
+       _history.insert (_history.begin (), p);
+       if (_history.size() > HISTORY_SIZE) {
+               _history.pop_back ();
+       }
+
+       changed ();
+}
index 0ce6b8351a4b0a48d5fb3a0791112edd5edd2ba1..aa3c06356320cd28464b14b1e7e358a403f87df5 100644 (file)
@@ -208,7 +208,11 @@ public:
        int log_types () const {
                return _log_types;
        }
-       
+
+       std::vector<boost::filesystem::path> history () const {
+               return _history;
+       }
+
        /** @param n New number of local encoding threads */
        void set_num_local_encoding_threads (int n) {
                _num_local_encoding_threads = n;
@@ -386,6 +390,13 @@ public:
                _log_types = t;
                changed ();
        }
+
+       void clear_history () {
+               _history.clear ();
+               changed ();
+       }
+
+       void add_to_history (boost::filesystem::path p);
        
        boost::filesystem::path signer_chain_directory () const;
 
@@ -453,7 +464,8 @@ private:
        /** maximum allowed J2K bandwidth in bits per second */
        int _maximum_j2k_bandwidth;
        int _log_types;
-
+       std::vector<boost::filesystem::path> _history;
+       
        /** Singleton instance, or 0 */
        static Config* _instance;
 };
index 70bf495c682c42332ea22bf5294497c243ad5276..675c8d03e6304a42a56f4911e88eb4bdeeaa352d 100644 (file)
@@ -44,8 +44,8 @@ extern "C" {
 
 /** The maximum number of audio channels that we can have in a DCP */
 #define MAX_DCP_AUDIO_CHANNELS 12
-
 #define DCPOMATIC_HELLO "Boys, you gotta learn not to talk to nuns that way"
+#define HISTORY_SIZE 10
 
 namespace libdcp {
        class Signer;
index cf6be18f63c41d012b5dbb95944cdc298a4dbf1f..09aebd39ce3f953c48d3a2950117ab78f5957519 100644 (file)
@@ -63,6 +63,7 @@
 
 using std::cout;
 using std::string;
+using std::vector;
 using std::wstring;
 using std::map;
 using std::make_pair;
@@ -116,7 +117,9 @@ enum {
        ID_file_open,
        ID_file_save,
        ID_file_properties,
-       ID_content_scale_to_fit_width,
+       ID_file_history,
+       /* Allow spare IDs after _history for the recent files list */
+       ID_content_scale_to_fit_width = 100,
        ID_content_scale_to_fit_height,
        ID_jobs_make_dcp,
        ID_jobs_make_kdms,
@@ -135,6 +138,10 @@ public:
                , _hints_dialog (0)
                , _servers_list_dialog (0)
                , _config_dialog (0)
+               , _file_menu (0)
+               , _history_items (0)
+               , _history_position (0)
+               , _history_separator (0)
        {
 #if defined(DCPOMATIC_WINDOWS) && defined(DCPOMATIC_WINDOWS_CONSOLE)
                 AllocConsole();
@@ -156,10 +163,14 @@ public:
                setup_menu (bar);
                SetMenuBar (bar);
 
+               Config::instance()->Changed.connect (boost::bind (&Frame::config_changed, this));
+               config_changed ();
+
                Bind (wxEVT_COMMAND_MENU_SELECTED, boost::bind (&Frame::file_new, this),                ID_file_new);
                Bind (wxEVT_COMMAND_MENU_SELECTED, boost::bind (&Frame::file_open, this),               ID_file_open);
                Bind (wxEVT_COMMAND_MENU_SELECTED, boost::bind (&Frame::file_save, this),               ID_file_save);
                Bind (wxEVT_COMMAND_MENU_SELECTED, boost::bind (&Frame::file_properties, this),         ID_file_properties);
+               Bind (wxEVT_COMMAND_MENU_SELECTED, boost::bind (&Frame::file_history, this, _1),        ID_file_history, ID_file_history + HISTORY_SIZE);
                Bind (wxEVT_COMMAND_MENU_SELECTED, boost::bind (&Frame::file_exit, this),               wxID_EXIT);
                Bind (wxEVT_COMMAND_MENU_SELECTED, boost::bind (&Frame::edit_preferences, this),        wxID_PREFERENCES);
                Bind (wxEVT_COMMAND_MENU_SELECTED, boost::bind (&Frame::content_scale_to_fit_width, this), ID_content_scale_to_fit_width);
@@ -211,7 +222,10 @@ public:
        }
 
        void load_film (boost::filesystem::path file)
+       try
        {
+               maybe_save_then_delete_film ();
+               
                shared_ptr<Film> film (new Film (file));
                list<string> const notes = film->read_metadata ();
 
@@ -229,6 +243,11 @@ public:
                
                set_film (film);
        }
+       catch (std::exception& e) {
+               wxString p = std_to_wx (file.string ());
+               wxCharBuffer b = p.ToUTF8 ();
+               error_dialog (this, wxString::Format (_("Could not open film at %s (%s)"), p.data(), std_to_wx (e.what()).data()));
+       }
 
        void set_film (shared_ptr<Film> film)
        {
@@ -236,6 +255,7 @@ public:
                _film_viewer->set_film (_film);
                _film_editor->set_film (_film);
                set_menu_sensitivity ();
+               Config::instance()->add_to_history (_film->directory ());
        }
 
        shared_ptr<Film> film () const {
@@ -307,14 +327,7 @@ private:
                }
                        
                if (r == wxID_OK) {
-                       maybe_save_then_delete_film ();
-                       try {
-                               load_film (wx_to_std (c->GetPath ()));
-                       } catch (std::exception& e) {
-                               wxString p = c->GetPath ();
-                               wxCharBuffer b = p.ToUTF8 ();
-                               error_dialog (this, wxString::Format (_("Could not open film at %s (%s)"), p.data(), std_to_wx (e.what()).data()));
-                       }
+                       load_film (wx_to_std (c->GetPath ()));
                }
 
                c->Destroy ();
@@ -331,6 +344,15 @@ private:
                d->ShowModal ();
                d->Destroy ();
        }
+
+       void file_history (wxCommandEvent& event)
+       {
+               vector<boost::filesystem::path> history = Config::instance()->history ();
+               int n = event.GetId() - ID_file_history;
+               if (n >= 0 && n < static_cast<int> (history.size ())) {
+                       load_film (history[n]);
+               }
+       }
        
        void file_exit ()
        {
@@ -561,25 +583,28 @@ private:
        
        void setup_menu (wxMenuBar* m)
        {
-               wxMenu* file = new wxMenu;
-               add_item (file, _("New..."), ID_file_new, ALWAYS);
-               add_item (file, _("&Open..."), ID_file_open, ALWAYS);
-               file->AppendSeparator ();
-               add_item (file, _("&Save"), ID_file_save, NEEDS_FILM);
-               file->AppendSeparator ();
-               add_item (file, _("&Properties..."), ID_file_properties, NEEDS_FILM);
+               _file_menu = new wxMenu;
+               add_item (_file_menu, _("New..."), ID_file_new, ALWAYS);
+               add_item (_file_menu, _("&Open..."), ID_file_open, ALWAYS);
+               _file_menu->AppendSeparator ();
+               add_item (_file_menu, _("&Save"), ID_file_save, NEEDS_FILM);
+               _file_menu->AppendSeparator ();
+               add_item (_file_menu, _("&Properties..."), ID_file_properties, NEEDS_FILM);
+
+               _history_position = _file_menu->GetMenuItems().GetCount();
+
 #ifndef __WXOSX__      
-               file->AppendSeparator ();
+               _file_menu->AppendSeparator ();
 #endif
        
 #ifdef __WXOSX__       
-               add_item (file, _("&Exit"), wxID_EXIT, ALWAYS);
+               add_item (_file_menu, _("&Exit"), wxID_EXIT, ALWAYS);
 #else
-               add_item (file, _("&Quit"), wxID_EXIT, ALWAYS);
+               add_item (_file_menu, _("&Quit"), wxID_EXIT, ALWAYS);
 #endif 
        
 #ifdef __WXOSX__       
-               add_item (file, _("&Preferences..."), wxID_PREFERENCES, ALWAYS);
+               add_item (_file_menu, _("&Preferences..."), wxID_PREFERENCES, ALWAYS);
 #else
                wxMenu* edit = new wxMenu;
                add_item (edit, _("&Preferences..."), wxID_PREFERENCES, ALWAYS);
@@ -607,7 +632,7 @@ private:
                add_item (help, _("About"), wxID_ABOUT, ALWAYS);
 #endif 
                
-               m->Append (file, _("&File"));
+               m->Append (_file_menu, _("&File"));
 #ifndef __WXOSX__      
                m->Append (edit, _("&Edit"));
 #endif
@@ -616,13 +641,49 @@ private:
                m->Append (tools, _("&Tools"));
                m->Append (help, _("&Help"));
        }
+
+       void config_changed ()
+       {
+               for (int i = 0; i < _history_items; ++i) {
+                       delete _file_menu->Remove (ID_file_history + i);
+               }
+
+               if (_history_separator) {
+                       _file_menu->Remove (_history_separator);
+               }
+               delete _history_separator;
+               _history_separator = 0;
+               
+               int pos = _history_position;
+               
+               vector<boost::filesystem::path> history = Config::instance()->history ();
+               
+               if (!history.empty ()) {
+                       _history_separator = _file_menu->InsertSeparator (pos++);
+               }
+               
+               for (size_t i = 0; i < history.size(); ++i) {
+                       SafeStringStream s;
+                       if (i < 9) {
+                               s << "&" << (i + 1) << " ";
+                       }
+                       s << history[i].string();
+                       _file_menu->Insert (pos++, ID_file_history + i, std_to_wx (s.str ()));
+               }
+
+               _history_items = history.size ();
+       }
        
        FilmEditor* _film_editor;
        FilmViewer* _film_viewer;
        HintsDialog* _hints_dialog;
        ServersListDialog* _servers_list_dialog;
        wxPreferencesEditor* _config_dialog;
+       wxMenu* _file_menu;
        shared_ptr<Film> _film;
+       int _history_items;
+       int _history_position;
+       wxMenuItem* _history_separator;
 };
 
 static const wxCmdLineEntryDesc command_line_description[] = {