1 /*
2 * Part of WCM Commander
3 * https://github.com/corporateshark/WCMCommander
4 * wcm@linderdaum.com
5 */
6
7 #include "nchistory.h"
8 #include "wcm-config.h"
9
10
11 #define MAX_FIELD_HISTORY_COUNT 50
12
13 static const char fieldHistSection[] = "FieldsHistory";
14
15 static cstrhash<HistCollect_t> g_FieldsHistHash;
16
17
LoadFieldsHistory()18 void LoadFieldsHistory()
19 {
20 IniHash iniHash;
21 IniHashLoad( iniHash, fieldHistSection );
22
23 g_FieldsHistHash.clear();
24 std::vector<const char*> SecList = iniHash.Keys();
25 char Name[64];
26
27 for ( int i = 0, count = SecList.size(); i < count; i++ )
28 {
29 const char* Section = SecList[i];
30 HistCollect_t& List = g_FieldsHistHash.get( Section );
31
32 for ( int j = 0; j < MAX_FIELD_HISTORY_COUNT; j++ )
33 {
34 Lsnprintf( Name, sizeof( Name ), "v%i", j );
35 const char* Value = iniHash.GetStrValue( Section, Name, nullptr );
36 if ( Value )
37 {
38 std::vector<unicode_t> Str = utf8_to_unicode( Value );
39 List.push_back( Str );
40 }
41 }
42 }
43 }
44
SaveFieldsHistory()45 void SaveFieldsHistory()
46 {
47 IniHash iniHash;
48 std::vector<const char*> SecList = g_FieldsHistHash.keys();
49 char Name[64];
50
51 for ( int i = 0, SecCount = SecList.size(); i < SecCount; i++ )
52 {
53 const char* Section = SecList[i];
54 HistCollect_t* List = g_FieldsHistHash.exist( Section );
55 if ( !List )
56 {
57 continue;
58 }
59
60 for ( int j = 0, ValCount = List->size(); j < ValCount; j++ )
61 {
62 Lsnprintf( Name, sizeof( Name ), "v%i", j );
63 std::string Val = unicode_to_utf8_string( List->at(j).data() );
64
65 iniHash.SetStrValue( Section, Name, Val.c_str());
66 }
67 }
68
69 IniHashSave( iniHash, fieldHistSection );
70 }
71
GetFieldHistCollect(const char * FieldName)72 HistCollect_t* GetFieldHistCollect( const char* FieldName )
73 {
74 if ( !FieldName || !FieldName[0] )
75 {
76 return nullptr;
77 }
78
79 HistCollect_t* List = g_FieldsHistHash.exist( FieldName );
80 return List ? List : nullptr;
81 }
82
83 // Returns index of element with the specified text, or -1 if no such found
FindHistElement(HistCollect_t * List,const unicode_t * Text)84 int FindHistElement( HistCollect_t* List, const unicode_t* Text )
85 {
86 for (int i = 0, count = List->size(); i < count; i++)
87 {
88 if (unicode_is_equal( Text, List->at(i).data() ))
89 {
90 return i;
91 }
92 }
93
94 return -1;
95 }
96
AddFieldTextToHistory(const char * FieldName,const unicode_t * Txt)97 void AddFieldTextToHistory( const char* FieldName, const unicode_t* Txt )
98 {
99 if ( !FieldName || !FieldName[0] || !Txt || !Txt[0] )
100 {
101 return;
102 }
103
104 std::vector<unicode_t> Str = new_unicode_str( Txt );
105
106 HistCollect_t& List = g_FieldsHistHash.get( FieldName );
107
108 // check if item already exists in the list
109 const int Index = FindHistElement( &List, Str.data() );
110 if ( Index != -1 )
111 {
112 // remove existing item
113 List.erase( List.begin() + Index );
114 }
115
116 // add item to the begining of the list
117 List.insert( List.begin(), Str );
118
119 // limit number of elements in the list
120 while ( List.size() > MAX_FIELD_HISTORY_COUNT )
121 {
122 List.erase( List.end() );
123 }
124 }
125
126
Clear()127 void NCHistory::Clear()
128 {
129 m_List.clear();
130 }
131
DeleteAll(const unicode_t * Str)132 void NCHistory::DeleteAll( const unicode_t* Str )
133 {
134 size_t i = 0;
135
136 while ( i < m_List.size() )
137 {
138 if ( unicode_is_equal( Str, m_List[i].data() ) )
139 {
140 m_List.erase( m_List.begin() + i );
141 continue;
142 }
143
144 i++;
145 }
146
147 // Maybe we need to keep m_Current pointing to specific command, if the latter survived?
148 m_Current = -1;
149 }
150
Put(const unicode_t * str)151 void NCHistory::Put( const unicode_t* str )
152 {
153 m_Current = -1;
154
155 for ( size_t i = 0; i < m_List.size(); i++ )
156 {
157 const unicode_t* s = str;
158 const unicode_t* t = m_List[i].data();
159
160 while ( *t && *s )
161 {
162 if ( *t != *s ) { break; }
163
164 s++;
165 t++;
166 }
167
168 if ( *t == *s )
169 {
170 std::vector<unicode_t> p = m_List[i];
171 m_List.erase( m_List.begin() + i );
172 m_List.insert( m_List.begin(), p );
173 return;
174 }
175 }
176
177 const size_t MaxHistorySize = 1000;
178
179 if ( m_List.size() > MaxHistorySize )
180 {
181 m_List.pop_back();
182 }
183
184 m_List.insert( m_List.begin(), new_unicode_str( str ) );
185 }
186
Count() const187 size_t NCHistory::Count() const
188 {
189 return m_List.size();
190 }
191
operator [](size_t n)192 const unicode_t* NCHistory::operator[] ( size_t n )
193 {
194 return n < m_List.size() ? m_List[n].data() : nullptr;
195 }
196
Prev()197 const unicode_t* NCHistory::Prev()
198 {
199 if ( !m_List.size() ) return nullptr;
200
201 if ( m_Current >= (int) m_List.size()-1 )
202 {
203 m_Current = (int) m_List.size()-1;
204 return m_List[m_Current].data();
205 }
206
207 return m_List[++m_Current].data();
208 }
209
Next()210 const unicode_t* NCHistory::Next()
211 {
212 if ( m_Current <= 0 )
213 {
214 m_Current = -1;
215 return nullptr;
216 }
217
218 return ( m_Current == 0 || m_Current > (int) m_List.size() )
219 ? nullptr
220 : m_List[--m_Current].data();
221 }
222