1 /*
2    Vimpc
3    Copyright (C) 2010 - 2012 Nathan Sweetman
4 
5    This program is free software: you can redistribute it and/or modify
6    it under the terms of the GNU General Public License as published by
7    the Free Software Foundation, either version 3 of the License, or
8    (at your option) any later version.
9 
10    This program is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13    GNU General Public License for more details.
14 
15    You should have received a copy of the GNU General Public License
16    along with this program.  If not, see <http://www.gnu.org/licenses/>.
17 
18    settings.hpp - handle configuration options via :set command
19    */
20 
21 #ifndef __MAIN__SETTINGS
22 #define __MAIN__SETTINGS
23 
24 #include "compiler.hpp"
25 
26 #include "colours.hpp"
27 #include "test.hpp"
28 
29 #include <string>
30 #include <map>
31 #include <vector>
32 
33 // Create an enum entry, name and value for each setting
34 // X(enum-entry, setting-name, default-value)
35 #define TOGGLE_SETTINGS \
36    X(AutoScroll,       "autoscroll",      true)  /* Automatically scroll to playing song */ \
37    X(AutoUpdate,       "autoupdate",      true)  /* Automatically update after file edits */ \
38    X(AutoLyrics,       "autolyrics",      false) /* Automatically get lyrics for the playing song */ \
39    X(AutoScrollLyrics, "autoscrolllyrics",false) /* Automatically scroll lyrics for the playing song */ \
40    X(AlbumArtist,      "albumartist",     true)  /* Use the album artist tag if there is one */ \
41    X(BrowseNumbers,    "browsenumbers",   false) /* Show numbers in the browse window */ \
42    X(ColourEnabled,    "colour",          true)  /* Determine if we should use colours */ \
43    X(ExpandArtists,    "expand-artists",  false) /* Expand artists in the library window by default */ \
44    X(HighlightSearch,  "hlsearch",        true)  /* Show search results in a different colour */ \
45    X(IgnoreTheGroup,   "groupignorethe",  false) /* Ignore 'the' when grouping the same artist into library */ \
46    X(IgnoreCaseSearch, "ignorecase",      false) /* Turn off case sensitivity on searching */ \
47    X(IgnoreCaseSort,   "sortignorecase",  true)  /* Turn off case sensitivity on sorting */\
48    X(IgnoreTheSort,    "sortignorethe",   false) /* Ignore 'the' when sorting */ \
49    X(IncrementalSearch,"incsearch",       false) /* Search for results whilst typing */ \
50    X(ListAllMeta,      "listallmeta",     true)  /* Get all meta data */ \
51    X(Mouse,            "mouse",           true)  /* Handle mouse keys */ \
52    X(Polling,          "polling",         false) /* Poll for status updates */ \
53    X(PlaylistNumbers,  "playlistnumbers", true)  /* Show id next to each song in the playlist */ \
54    X(PlayOnAdd,        "playonadd",       false) /* If mpd is stopped play after first add */ \
55    X(ProgressBar,      "progressbar",     true)  /* Show the progress bar */ \
56    X(Reconnect,        "reconnect",       true)  /* Reconnect to server when connection drops */ \
57    X(ScrollOnAdd,      "scrollonadd",     true)  /* Auto scroll down after song added */ \
58    X(ScrollOnDelete,   "scrollondelete",  true)  /* Auto scroll down after song delete */ \
59    X(ScrollStatus,     "scrollstatus",    true)  /* Scroll long status lines */ \
60    X(SearchWrap,       "searchwrap",      true)  /* Determine whether to wrap searching */ \
61    X(SeekBar,          "seekbar",         true)  /* Mouse click on progress bar causes a seek */ \
62    X(ShowPath,         "showpath",        true)  /* Show current path in directory window */ \
63    X(ShowPercent,      "showpercent",     true)  /* Show percentage on the progress bar */ \
64    X(ShowLists,        "showlists",       true)  /* Show playlists in directory window */ \
65    X(SingleQuit,       "singlequit",      false) /* Quit the entire application not just close a tab */ \
66    X(SongNumbers,      "songnumbers",     true)  /* Show id numbers next to songs in any window */ \
67    X(SmartCase,        "smartcase",       false) /* Case sensitivy enabled when upper case char is used */  \
68    X(StopOnQuit,       "stoponquit",      false) /* Stop playing when we quit */ \
69    X(TabBar,           "tabbar",          true)  /* Show the tab bar */ \
70    X(TimeRemaining,    "timeremaining",   false) /* Show time left rather than time elapsed */ \
71    X(WindowNumbers,    "windownumbers",   false) /* Window numbers next to each window in the tab list */
72 
73 // X(enum-entry, setting-name, default-value, regex-filter)
74 #define STRING_SETTINGS \
75    /* position to add songs */ \
76    X(AddPosition,      "add", "end", "next|end") \
77    /* Library format string */ \
78    X(AlbumFormat,      "albumformat", "%B",  ".*") \
79    /* Library format string */ \
80    X(ArtistFormat,     "artistformat", "%A",  ".*") \
81    /* Library format string */ \
82    X(LibraryFormat,    "libraryformat", "$I%n \\| $D$H[$H%l$H]$H {%t}|{%f}$E$R ", ".*") \
83    /* Library format string */ \
84    X(LocalMusicDir,    "local-music-dir", "", ".*") \
85    /* Lyrics strip regex */ \
86    X(LyricsStrip,      "lyricsstrip", "(\\s*(R|r)emaster\\w*)|(\\s+-.*)", ".*") \
87    /* Lists to show in the lists window */ \
88    X(Playlists,        "playlists", "mpd", "all|mpd|files") \
89    /* Song format string */ \
90    X(SongFormat,       "songformat", "{{%a - }%t}|{%f}$E$R $H[$H%l$H]$H", ".*") \
91    /* Song format fill character */ \
92    X(SongFillChar,       "songfillchar", " ", ".") \
93    /* Sort based on song format */ \
94    X(Sort,             "sort", "format", "format|library") \
95    /* Connection Timeout in seconds */ \
96    X(Timeout,          "timeout", "30", "\\d+") \
97    /* Startup window */ \
98    X(Window,           "window",  "help", ".*") \
99    /* Startup windows */ \
100    X(Windows,          "windows", "help,lists,library,browse,playlist", ".*")
101 
102 #define COLOUR_SETTINGS \
103    X(COLOR_DEFAULT, "default" ) \
104    X(COLOR_BLACK, "black" ) \
105    X(COLOR_RED, "red" ) \
106    X(COLOR_GREEN, "green" ) \
107    X(COLOR_YELLOW, "yellow" ) \
108    X(COLOR_BLUE, "blue" ) \
109    X(COLOR_MAGENTA, "magenta" ) \
110    X(COLOR_CYAN, "cyan" ) \
111    X(COLOR_WHITE, "white" ) \
112    X(BOLD(COLOR_BLACK), "bold_black" ) \
113    X(BOLD(COLOR_RED), "bold_red" ) \
114    X(BOLD(COLOR_GREEN), "bold_green" ) \
115    X(BOLD(COLOR_YELLOW), "bold_yellow" ) \
116    X(BOLD(COLOR_BLUE), "bold_blue" ) \
117    X(BOLD(COLOR_MAGENTA), "bold_magenta" ) \
118    X(BOLD(COLOR_CYAN), "bold_cyan" ) \
119    X(BOLD(COLOR_WHITE), "bold_white" )
120 
121 class Setting
122 {
123 public:
124    // Provide access to default values through settings table
125    static std::string Default;
126 
127    // Use for add position comparisons
128    static std::string AddEnd;
129    static std::string AddNext;
130 
131    // Use for playlists comparisons
132    static std::string PlaylistsMpd;
133    static std::string PlaylistsAll;
134    static std::string PlaylistsFiles;
135 
136 #define X(a, b, c) a,
137    typedef enum
138    {
139       TOGGLE_SETTINGS
140       ToggleCount
141    } ToggleSettings;
142 #undef X
143 
144 #define X(a, b, c, d) a,
145    typedef enum
146    {
147       StartString = ToggleCount,
148       STRING_SETTINGS
149       StringCount
150    } StringSettings;
151 #undef X
152 };
153 
154 namespace Main
155 {
156    //! Holds the value of an individual setting
157    template <typename T>
158    class SettingValue
159    {
160       public:
SettingValue(int32_t id)161          SettingValue(int32_t id) : id_(id) { }
SettingValue(int32_t id,T v)162          SettingValue(int32_t id, T v) : id_(id), value_(v) { }
~SettingValue()163          ~SettingValue() { }
164 
Id() const165          int32_t Id() const { return id_; }
Get() const166          T Get() const { return value_; }
Set(T v)167          void Set(T v) { value_ = v; }
168 
169       private:
170          int32_t const id_;
171          T             value_;
172    };
173 
174    //! Manages settings which are set via :set command
175    class Settings
176    {
177       public:
178          Colours colours;
179 
180       public:
181          static Settings & Instance();
182 
183       protected:
184          Settings();
185          ~Settings();
186 
187       public:
188          //! List all the available settings (including no versions);
189          std::vector<std::string> AvailableSettings() const;
190 
191          //! Calls the correct setter function based upon the given input
192          void Set(std::string const & input);
193 
194          //! Handles settings which are treated as an on/off setting
195          void SetSingleSetting(std::string setting);
196 
197          //! Get the value of a particular setting
198          bool Get(Setting::ToggleSettings setting) const;
199          std::string Get(Setting::StringSettings setting) const;
200 
201          //! Name of a particular setting
202          std::string Name(Setting::ToggleSettings setting) const;
203          std::string Name(Setting::StringSettings setting) const;
204 
205          //! Register a callback to be called when a setting is changed
206          void RegisterCallback(Setting::ToggleSettings setting, FUNCTION<void (bool)> callback);
207          void RegisterCallback(Setting::StringSettings setting, FUNCTION<void (std::string)> callback);
208 
209          //! Turn the callbacks on and off
210          void EnableCallbacks();
211          void DisableCallbacks();
212 
213       public:
214          //! Set/Get whether or not to connect if asked to in config
215          void SetSkipConfigConnects(bool val);
216          bool SkipConfigConnects() const;
217 
218          void SetColour(std::string property, std::string bg, std::string fg);
219 
220          //! Get the value for the given \p setting
221          template <typename T>
222          inline T Get(std::string setting) const;
223 
224          //! Set the value of a particular setting
225          void Set(Setting::ToggleSettings setting, bool value);
226          void Set(Setting::StringSettings setting, std::string value);
227 
228       protected:
229          //! Set the value for the given \p setting
SetValue(std::string setting,bool value)230          inline void SetValue(std::string setting, bool value)
231          {
232             SetValue(setting, value, toggleTable_);
233          }
234 
SetValue(std::string setting,std::string value)235          inline void SetValue(std::string setting, std::string value)
236          {
237             SetValue(setting, value, stringTable_);
238          }
239 
240       private:
241          template <class T>
GetValue(std::string setting,T table) const242          auto GetValue(std::string setting, T table) const -> decltype (table.at(Setting::Default)->Get())
243          {
244             mutex_.lock();
245             auto const it = table.find(setting);
246             auto const Result = (it != table.end()) ? (it->second->Get()) : table.at(Setting::Default)->Get();
247             mutex_.unlock();
248             return Result;
249          }
250 
251          template <class T, class U>
SetValue(std::string setting,T value,U const & table)252          void SetValue(std::string setting, T value, U const & table)
253          {
254             mutex_.lock();
255             auto const it = table.find(setting);
256             if (it != table.end()) { (it->second->Set(value)); }
257             mutex_.unlock();
258          }
259 
260          //! Used to handle settings that require very specific paramters
261          void SetSpecificSetting(std::string setting, std::string arguments);
262 
263       private:
264          typedef std::map<int, std::string> SettingNameTable;
265          SettingNameTable     settingName_;
266 
267          // Holds yes/no, on/off style settings
268          typedef std::map<std::string, SettingValue<bool> * > BoolSettingsTable;
269          BoolSettingsTable    toggleTable_;
270 
271          typedef std::vector<SettingValue<bool> * > BoolVector;
272          BoolVector           toggleVector_;
273 
274          // Callbacks for on/off settings
275          typedef std::map<Setting::ToggleSettings, std::vector<FUNCTION<void (bool)> > > BoolCallbackTable;
276          BoolCallbackTable    tCallbackTable_;
277 
278          // Used to validate string settings against a regex pattern
279          typedef std::map<std::string, std::string> SettingsFilterTable;
280          SettingsFilterTable  filterTable_;
281 
282          // Settings that are represented by a string value
283          typedef std::map<std::string, SettingValue<std::string> * > StringSettingsTable;
284          StringSettingsTable  stringTable_;
285 
286          typedef std::vector<SettingValue<std::string> * > StringVector;
287          StringVector         stringVector_;
288 
289          // Callbacks for string style settings
290          typedef std::map<Setting::StringSettings, std::vector<FUNCTION<void (std::string)> > > StringCallbackTable;
291          StringCallbackTable  sCallbackTable_;
292 
293          typedef std::map<std::string, int> ColorNameTable;
294          ColorNameTable       colourTable_;
295 
296          bool                 enabled_;
297 
298          mutable RecursiveMutex mutex_;
299    };
300 
301    template <>
Get(std::string setting) const302    inline bool Settings::Get<bool>(std::string setting) const
303    {
304       return GetValue(setting, toggleTable_);
305    }
306 
307    template <>
Get(std::string setting) const308    inline std::string Settings::Get<std::string>(std::string setting) const
309    {
310       return GetValue(setting, stringTable_);
311    }
312 }
313 
314 #endif
315 /* vim: set sw=3 ts=3: */
316