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