1 //////////////////////////////////////////////////////////////////////////////
2 //
3 // Copyright : (C) 2015 Eran Ifrah
4 // File name : clKeyboardManager.h
5 //
6 // This program is free software; you can redistribute it and/or modify
7 // it under the terms of the GNU General Public License as published by
8 // the Free Software Foundation; either version 2 of the License, or
9 // (at your option) any later version.
10 //
11 //////////////////////////////////////////////////////////////////////////////
12 // Modifed for Code::Blocks by pecan
13
14 #include <wx/filename.h>
15 # if defined(LOGGING)
16 #include <wx/private/wxprintf.h>
17 #include <wx/textfile.h>
18 #endif
19
20 #include "manager.h"
21 #include "personalitymanager.h"
22 #include "configmanager.h"
23
24 #include "clKeyboardBindingConfig.h"
25 #include "json_node.h"
26
27 // ----------------------------------------------------------------------------
clKeyboardBindingConfig()28 clKeyboardBindingConfig::clKeyboardBindingConfig() {}
29 // ----------------------------------------------------------------------------
30
31 // ----------------------------------------------------------------------------
~clKeyboardBindingConfig()32 clKeyboardBindingConfig::~clKeyboardBindingConfig() {}
33 // ----------------------------------------------------------------------------
34
35 // ----------------------------------------------------------------------------
Load()36 clKeyboardBindingConfig& clKeyboardBindingConfig::Load()
37 // ----------------------------------------------------------------------------
38 {
39 wxFileName fn(ConfigManager::GetConfigFolder(), _T("cbKeyBinder20.conf"));
40 //-fn.AppendDir("config");
41 wxString personality = Manager::Get()->GetPersonalityManager()->GetPersonality();
42 fn.SetName(personality + _T(".") + fn.GetName());
43 if(not fn.FileExists()) return *this;
44
45 m_bindings.clear();
46 JSONRoot root(fn);
47 // unused typedef std::unordered_multimap<wxString, wxString> GlobalAccelMap_t; //(2019/04/3)
48 MenuItemDataMap_t globalBindings; //(2019/04/3)
49
50 {//Block
51 JSONElement menus = root.toElement().namedObject(_T("menus"));
52 int arrSize = menus.arraySize();
53 for(int i = 0; i < arrSize; ++i) {
54 JSONElement item = menus.arrayItem(i);
55 MenuItemData binding;
56 binding.action = item.namedObject(_T("description")).toString();
57 binding.accel = item.namedObject(_T("accelerator")).toString();
58 binding.parentMenu = item.namedObject(_T("parentMenu")).toString();
59 binding.resourceID = item.namedObject(_T("resourceID")).toString();
60 if (binding.parentMenu.empty()) //Empty parent menu means a <global> accelerator
61 {
62 // Hold global key bindings until later
63 globalBindings.insert(std::make_pair(binding.resourceID, binding));
64 continue;
65 }
66 // insert regular menu items before globals
67 m_bindings.insert(std::make_pair(binding.resourceID, binding));
68 }//endif for arrSize
69
70 // Append the global key bindings to the end of the menu bindings
71 for(MenuItemDataMap_t::const_iterator iter = globalBindings.begin(); iter != globalBindings.end(); ++iter)
72 {
73 #if defined(LOGGING) //debugging
74 wxString resourceID = iter->first;
75 MenuItemData binding = iter->second;
76 #endif
77 m_bindings.insert(std::make_pair(iter->first, iter->second) );
78 }
79
80 }//end Block
81 return *this;
82 }
83 // ----------------------------------------------------------------------------
Save()84 clKeyboardBindingConfig& clKeyboardBindingConfig::Save()
85 // ----------------------------------------------------------------------------
86 {
87 // ----------------------------------------------------------------------------
88 // Sort the bindings
89 // ----------------------------------------------------------------------------
90 std::vector<MenuItemDataMap_t::iterator> sortedIters;
91 SortBindings(sortedIters);
92
93 JSONRoot root(cJSON_Object);
94 JSONElement mainObj = root.toElement();
95 JSONElement menuArr = JSONElement::createArray(_T("menus"));
96 mainObj.append(menuArr);
97 //-for(MenuItemDataMap_t::iterator iter = m_bindings.begin(); iter != m_bindings.end(); ++iter) {
98 for (size_t ii=0; ii< sortedIters.size(); ++ii)
99 {
100 MenuItemDataMap_t::iterator iter = sortedIters[ii];
101 JSONElement binding = JSONElement::createObject();
102 binding.addProperty(_T("description"), iter->second.action);
103 binding.addProperty(_T("accelerator"), iter->second.accel);
104 binding.addProperty(_T("resourceID"), iter->second.resourceID);
105 binding.addProperty(_T("parentMenu"), iter->second.parentMenu);
106 menuArr.arrayAppend(binding);
107 }
108
109 wxString configDir = ConfigManager::GetConfigFolder();
110 wxFileName fn(configDir, _T("cbKeyBinder20.conf"));
111 wxString personality = Manager::Get()->GetPersonalityManager()->GetPersonality();
112 fn.SetName(personality + _T(".") + fn.GetName());
113
114 root.save(fn);
115 return *this;
116 }
117 // ----------------------------------------------------------------------------
SortBindings(std::vector<MenuItemDataMap_t::iterator> & sortedIters)118 bool clKeyboardBindingConfig::SortBindings( std::vector<MenuItemDataMap_t::iterator>& sortedIters)
119 // ----------------------------------------------------------------------------
120 {
121 // ----------------------------------------------------------------------------
122 // set a vector of iters sorted by parent menu strings
123 // ----------------------------------------------------------------------------
124 //-std::vector<MenuItemDataMap_t::iterator> sortedIters; //indexes to MenuItemData in sorted order
125 std::vector<MenuItemDataMap_t::iterator> bindGlobals; //indexes to globals in sorted order
126
127 for(MenuItemDataMap_t::iterator iter = m_bindings.begin(); iter != m_bindings.end(); ++iter)
128 {
129 wxString description = iter->second.action; //description
130 wxString accelerator = iter->second.accel; //accelerator
131 wxString resourceID = iter->second.resourceID; //menu resource ID
132 wxString parentMenu = iter->second.parentMenu; //parent menu
133 //-wxPrintf("parentMenu: \"%s\"\n", parentMenu.wx_str());
134
135 if (parentMenu.empty()) //global accelerator
136 {
137 bindGlobals.push_back(iter);
138 continue;
139 }
140
141 MenuItemDataMap_t::iterator iterOne;
142 MenuItemDataMap_t::iterator iterTwo;
143 wxString strOne;
144 wxString strTwo;
145
146 if (0 == sortedIters.size())
147 {
148 sortedIters.push_back(iter);
149 iterTwo = iterOne = iter;
150 strOne = strTwo = parentMenu;
151 continue;
152 }
153
154 strOne = parentMenu;
155 iterOne = iter;
156
157 bool inserted = false;
158 for (size_t ii=0; ii< sortedIters.size(); ++ii)
159 {
160 iterTwo = sortedIters[ii];
161 strTwo = iterTwo->second.parentMenu;
162 if (strOne <= strTwo)
163 {
164 sortedIters.insert(sortedIters.begin()+ii, iterOne );
165 //-wxPrintf(_T("Inserted [%s] above [%s]\n"), strOne.wx_str(), strTwo.wx_str());
166 inserted = true;
167 break; //breaks the for loop
168 }
169 }//endfor
170 if (not inserted)
171 {
172 sortedIters.push_back(iterOne);
173 //-wxPrintf(_T("Appended [%s]\n"), strOne.wx_str());
174 }
175 }
176 // append the global accelerator iters to the sortedIters vector
177 for (size_t ii=0; ii < bindGlobals.size(); ++ii)
178 sortedIters.push_back(bindGlobals[ii]);
179
180 #if defined(LOGGING) //debugging
181 // ----------------------------------------------------------------------------
182 // Debugging: write log file of the sorted sequence
183 // ----------------------------------------------------------------------------
184 wxString tempDir = wxFileName::GetTempDir();
185 wxString txtFilename = tempDir + _T("\\JsonSortLogFile.txt");
186 if (wxFileExists(txtFilename))
187 wxRemoveFile(txtFilename);
188 wxTextFile logFile(txtFilename);
189 logFile.Create();
190 for (size_t ii=0; ii< sortedIters.size(); ++ii)
191 {
192 MenuItemDataMap_t::iterator iterTwo = sortedIters[ii];
193 wxString strTwo = iterTwo->second.parentMenu;
194 if (not strTwo.empty())
195 {
196 logFile.AddLine(strTwo);
197 continue;
198 }
199 // must be a global
200 if (strTwo.empty())
201 {
202 wxString strTwo = iterTwo->second.action +_T(" ") + iterTwo->second.accel;
203 logFile.AddLine(strTwo);
204 }
205 }
206
207 logFile.Write();
208 logFile.Close();
209 #endif //defined logging
210
211 return (sortedIters.size() > 0);
212 }
213
214