1 #include "Browser.h"
2
3 ArrayMap<String, TopicEditor::FileInfo> TopicEditor::editstate;
4 VectorMap<String, String> TopicEditor::grouptopic; // the last topic edited in group
5
6 String TopicEditor::lasttemplate;
7 int TopicEditor::lastlang;
8 bool TopicEditor::allfonts;
9
10 struct ListOrder : FileList::Order {
11 public:
operator ()ListOrder12 virtual bool operator()(const FileList::File& a, const FileList::File& b) const {
13 return ToUpper(a.name) < ToUpper(b.name);
14 }
15 };
16
LoadTopics(Vector<String> & topics,const String & grouppath)17 bool LoadTopics(Vector<String>& topics, const String& grouppath)
18 {
19 bool renamed = false;
20
21 for(int pass = 0; pass < 2; pass++) {
22 topics.Clear();
23
24 FindFile ff(AppendFileName(grouppath, "*.*"));
25 for(; ff; ff.Next()) {
26 if(ff.IsFile() && GetFileExt(ff.GetName()) == ".tppi") {
27 String n = ff.GetName();
28 int q = n.ReverseFind('$');
29 if(q < 0)
30 q = n.ReverseFind('@');
31 if(q >= 0 && q > n.GetLength() - 12) {
32 String nn = n;
33 n.Set(q, '_');
34 FileMove(AppendFileName(grouppath, nn), AppendFileName(grouppath, n));
35 renamed = true;
36 }
37 }
38 if(ff.IsFile() && GetFileExt(ff.GetName()) == ".tpp") {
39 String n = ff.GetName();
40 int q = n.ReverseFind('$');
41 if(q < 0)
42 q = n.ReverseFind('@');
43 if(q >= 0 && q > n.GetLength() - 12) {
44 String nn = n;
45 n.Set(q, '_');
46 FileMove(AppendFileName(grouppath, nn), AppendFileName(grouppath, n));
47 renamed = true;
48 }
49
50 topics.Add(GetFileTitle(n));
51 }
52 }
53 if(!renamed)
54 break;
55 }
56
57 return renamed;
58 }
59
FillTopicsList(FileList & list,const Vector<String> & topics)60 void FillTopicsList(FileList& list, const Vector<String>& topics)
61 {
62 list.Clear();
63
64 for (const auto& topic : topics)
65 list.Add(topic, TopicImg::Topic());
66
67 list.Sort(ListOrder());
68 list.Enable();
69
70 }
71
Open(const String & group_path)72 void TopicEditor::Open(const String& group_path)
73 {
74
75 topics_search.Clear();
76
77 grouppath = group_path;
78 if(FileExists(grouppath))
79 DeleteFile(grouppath);
80 DirectoryCreate(grouppath);
81
82 if(LoadTopics(topics, grouppath))
83 SaveInc();
84 FillTopicsList(topics_list, topics);
85
86 int q = grouptopic.Find(grouppath);
87 if(q >= 0)
88 topics_list.FindSetCursor(grouptopic[q]);
89 else
90 topics_list.SetCursor(0);
91 }
92
OpenFile(const String & path)93 void TopicEditor::OpenFile(const String& path)
94 {
95 grouppath.Clear();
96 singlefilepath = path;
97 topics_list.Clear();
98 topics_list.Add(GetFileTitle(path), TopicImg::Topic());
99 topics_list.Enable();
100 topics_list.SetCursor(0);
101 }
102
OnSearch()103 void TopicEditor::OnSearch()
104 {
105 auto current_topic = topics_list.GetCurrentName();
106 auto topic_list_sel_callback = topics_list.WhenSel;
107 topics_list.WhenSel = {};
108
109 DoSearch();
110
111 auto idx = topics_list.Find(current_topic);
112 if (idx >= 0) {
113 topics_list.SetCursor(idx);
114 }
115
116 topics_list.WhenSel = topic_list_sel_callback;
117 }
118
DoSearch()119 void TopicEditor::DoSearch()
120 {
121 auto search_phase = ToLower(topics_search.GetData().ToString());
122
123 auto found_topics = Vector<String>();
124 for (const auto& topic : topics) {
125 const auto normalized_topic = ToLower(topic);
126 if (normalized_topic.Find(search_phase) >= 0) {
127 found_topics.Add(topic);
128 }
129 }
130 FillTopicsList(topics_list, found_topics);
131 }
132
GetCurrentTopicPath()133 String TopicEditor::GetCurrentTopicPath()
134 {
135 if(topics_list.IsCursor())
136 return NormalizePath(AppendFileName(grouppath, topics_list.GetCurrentName() + ".tpp"));
137 else
138 return Null;
139 }
140
ShowTopic(bool b)141 void TopicEditor::ShowTopic(bool b)
142 {
143 title.Enable(b);
144 title.Show(b);
145 editor.Enable(b);
146 editor.Show(b);
147 }
148
TopicCursor()149 void TopicEditor::TopicCursor()
150 {
151 String h;
152 HideTopic();
153 if(IsNull(grouppath)) {
154 ShowTopic();
155 h = singlefilepath;
156 }
157 else {
158 if(!topics_list.IsCursor())
159 return;
160 h = GetCurrentTopicPath();
161 }
162 if(h != topicpath)
163 Load(h);
164 else
165 ShowTopic();
166 }
167
Load(const String & fn)168 void TopicEditor::Load(const String& fn)
169 {
170 Flush();
171
172 Topic t = ReadTopic(LoadFile(fn));
173 if(t.text.IsVoid()) {
174 Exclamation("Error loading the topic file:&[* " + DeQtf(fn));
175 topics_list.KillCursor();
176 return;
177 }
178
179 title <<= t.title;
180 editor <<= t.text;
181 topicpath = fn;
182
183 int q = editstate.Find(fn);
184 if(q >= 0) {
185 FileInfo& fi = editstate[q];
186 if(fi.time == FileGetTime(fn)) {
187 editor.SetPickUndoInfo(pick(fi.undo));
188 fi.time = Time(1, 1, 1);
189 editor.SetPosInfo(fi.pos);
190 }
191 }
192
193 grouptopic.GetAdd(grouppath) = GetFileTitle(fn);
194
195 ShowTopic();
196
197 editor.SetFocus();
198 editor.ClearModify();
199 title.ClearModify();
200 }
201
202 int TopicEditor::serial;
203
GetSerial()204 int TopicEditor::GetSerial()
205 {
206 return serial;
207 }
208
SaveTopic()209 void TopicEditor::SaveTopic()
210 {
211 if(IsNull(topicpath))
212 return;
213 if(IsNull(~title)) {
214 const RichText& txt = editor.Get();
215 if(txt.IsPara(0)) {
216 RichPara para = txt.Get(0);
217 WString t;
218 for(int i = 0; i < para.GetCount(); i++)
219 if(para[i].IsText())
220 for(const wchar *s = para[i].text; *s; s++) {
221 if(*s == '\t' || *s == 160)
222 t.Cat(' ');
223 else
224 if(*s >= ' ')
225 t.Cat(*s);
226 }
227 if(!IsNull(t))
228 title <<= t;
229 }
230 }
231 if(!editor.IsModified() && !title.IsModified())
232 return;
233 String r = WriteTopic((String)~title, editor.Get());
234 if(LoadFile(topicpath) != r) {
235 serial++;
236 SaveFile(topicpath, r);
237 if(FileExists(AppendFileName(grouppath, "all.i")))
238 SaveFile(ForceExt(topicpath, ".tppi"), WriteTopicI((String)~title, editor.Get()));
239 TopicLink tl = ParseTopicFilePath(topicpath);
240 if(tl)
241 SyncTopicFile(editor.Get(), TopicLinkString(tl), topicpath, ~title);
242 }
243 }
244
Flush()245 void TopicEditor::Flush()
246 {
247 if(IsNull(topicpath))
248 return;
249 SaveTopic();
250 FileInfo& fi = editstate.GetAdd(topicpath);
251 fi.time = FileGetTime(topicpath);
252 fi.pos = editor.GetPosInfo();
253 fi.undo = editor.PickUndoInfo();
254 topicpath.Clear();
255 editor.Clear();
256 HideTopic();
257 }
258
SaveInc()259 void TopicEditor::SaveInc()
260 {
261 SaveGroupInc(grouppath);
262 }
263
ParseTopicFilePath(const String & path)264 TopicLink ParseTopicFilePath(const String& path)
265 {
266 TopicLink tl;
267 tl.topic = GetFileTitle(path);
268 String q = GetFileFolder(path);
269 tl.group = GetFileTitle(q);
270 q = GetFileFolder(q);
271 const Workspace& wspc = GetIdeWorkspace();
272 for(int i = 0; i < wspc.GetCount(); i++)
273 if(PathIsEqual(PackageDirectory(wspc[i]), q)) {
274 tl.package = wspc[i];
275 return tl;
276 }
277 return TopicLink();
278 }
279
TopicFilePath(const TopicLink & tl)280 String TopicFilePath(const TopicLink& tl)
281 {
282 return AppendFileName(AppendFileName(PackageDirectory(tl.package), tl.group + ".tpp"),
283 tl.topic + ".tpp");
284 }
285