]> git.lyx.org Git - features.git/blob - src/frontends/xforms/xforms_helpers.C
5a0271c9b4f6de579567b34d49cc6227771b760e
[features.git] / src / frontends / xforms / xforms_helpers.C
1 /** Collection of some useful xform helper functions
2  */
3
4 #include <config.h>
5
6 #include FORMS_H_LOCATION
7
8 #include <fstream> // ofstream
9 #include <vector>
10
11 #ifdef __GNUG_
12 #pragma implementation
13 #endif
14  
15 #include "xforms_helpers.h"
16 #include "lyxlex.h"
17 #include "support/FileInfo.h"
18 #include "support/filetools.h"
19 #include "support/lstrings.h" // frontStrip, strip
20 #include "gettext.h"
21 #include "support/LAssert.h"
22
23 using std::ofstream;
24 using std::pair;
25 using std::vector;
26
27 // Set an FL_OBJECT to activated or deactivated
28 void setEnabled(FL_OBJECT * ob, bool enable)
29 {
30         if (enable) {
31                 fl_activate_object(ob);
32                 fl_set_object_lcol(ob, FL_BLACK);
33         } else {
34                 fl_deactivate_object(ob);
35                 fl_set_object_lcol(ob, FL_INACTIVE);
36         }
37 }
38
39         
40 // Given an fl_choice, create a vector of its entries
41 vector<string> const getVectorFromChoice(FL_OBJECT * ob)
42 {
43         vector<string> vec;
44         if (!ob || ob->objclass != FL_CHOICE)
45                 return vec;
46
47         for(int i = 0; i < fl_get_choice_maxitems(ob); ++i) {
48                 string const text = fl_get_choice_item_text(ob, i+1);
49                 vec.push_back(strip(frontStrip(text)));
50         }
51
52         return vec;
53 }
54
55
56 // Given an fl_browser, create a vector of its entries
57 vector<string> const getVectorFromBrowser(FL_OBJECT * ob)
58 {
59         vector<string> vec;
60         if (!ob || ob->objclass != FL_BROWSER)
61                 return vec;
62
63         for(int i = 0; i < fl_get_browser_maxline(ob); ++i) {
64                 string const text = fl_get_browser_line(ob, i+1);
65                 vec.push_back(strip(frontStrip(text)));
66         }
67
68         return vec;
69 }
70
71
72 string getLengthFromWidgets(FL_OBJECT * input, FL_OBJECT * choice)
73 {
74         // Paranoia check
75         lyx::Assert(input  && input->objclass  == FL_INPUT &&
76                     choice && choice->objclass == FL_CHOICE);
77
78         string const length = strip(frontStrip(fl_get_input(input)));
79         if (length.empty())
80                 return string();
81
82         string unit = strip(frontStrip(fl_get_choice_text(choice)));
83         unit = subst(unit, "%%", "%");
84
85         return length + unit;
86 }
87         
88
89 void updateWidgetsFromLengthString(FL_OBJECT * input, FL_OBJECT * choice,
90                                    string const & str,
91                                    string const & default_unit)
92 {
93         // Paranoia check
94         lyx::Assert(input  && input->objclass  == FL_INPUT &&
95                     choice && choice->objclass == FL_CHOICE);
96
97         if (str.empty()) {
98                 fl_set_input(input, "");
99                 int unitpos = 1; // xforms has Fortran-style indexing
100                 for(int i = 0; i < fl_get_choice_maxitems(choice); ++i) {
101                         string const text = fl_get_choice_item_text(choice,i+1);
102                         if (default_unit ==
103                             lowercase(strip(frontStrip(text)))) {
104                                 unitpos = i+1;
105                                 break;
106                         }
107                 }
108                 fl_set_choice(choice, unitpos);
109                 return;
110         }
111
112         // The unit is presumed to begin at the first char a-z
113         string const tmp = lowercase(strip(frontStrip(str)));
114
115         string::const_iterator p = tmp.begin();
116         for (; p != tmp.end(); ++p) {
117                 if (*p >= 'a' && *p <= 'z')
118                         break;
119         }
120
121         string len = "0";
122         int unitpos = 1; // xforms has Fortran-style indexing
123
124         if (p == tmp.end()) {
125                 if (isStrDbl(tmp))
126                         len = tmp;
127
128         } else {
129                 string tmplen = string(tmp.begin(), p);
130                 if (isStrDbl(tmplen))
131                         len = tmplen;
132                 string unit = string(p, tmp.end());
133                 unit = subst(unit, "%", "%%");
134
135                 for(int i = 0; i < fl_get_choice_maxitems(choice); ++i) {
136                         string const text = fl_get_choice_item_text(choice,i+1);
137                         if (unit == lowercase(strip(frontStrip(text)))) {
138                                 unitpos = i+1;
139                                 break;
140                         }
141                 }
142         }
143         
144         fl_set_input(input,   len.c_str());
145         fl_set_choice(choice, unitpos);
146 }
147  
148 // Take a string and add breaks so that it fits into a desired label width, w
149 string formatted(string const & sin, int w, int size, int style)
150 {
151         // FIX: Q: Why cant this be done by a one pass algo? (Lgb)
152
153         string sout;
154         if (sin.empty()) return sout;
155
156         // breaks in up into a vector of individual words
157         vector<string> sentence;
158         string word;
159         for (string::const_iterator sit = sin.begin();
160              sit != sin.end(); ++sit) {
161                 if ((*sit) == ' ' || (*sit) == '\n') {
162                         if (!word.empty()) {
163                                 sentence.push_back(word);
164                                 word.erase();
165                         }
166                         if ((*sit) == '\n') word += '\n';
167                         
168                 } else {
169                         word += (*sit);
170                 }
171         }
172
173         // Flush remaining contents of word
174         if (!word.empty() ) sentence.push_back(word);
175
176         string line;
177         string line_plus_word;
178         for (vector<string>::const_iterator vit = sentence.begin();
179              vit != sentence.end(); ++vit) {
180                 string word(*vit);
181
182                 char c = word[0];
183                 if (c == '\n') {
184                         sout += line + '\n';
185                         word.erase(0,1);
186                         line_plus_word.erase();
187                         line.erase();
188                 }
189
190                 if (!line_plus_word.empty() ) line_plus_word += ' ';
191                 line_plus_word += word;
192
193                 int const length = fl_get_string_width(style, size,
194                                                        line_plus_word.c_str(),
195                                                        int(line_plus_word.length()));
196                 if (length >= w) {
197                         sout += line + '\n';
198                         line_plus_word = word;
199                 }
200
201                 line = line_plus_word;
202         }
203         // Flush remaining contents of line
204         if (!line.empty()) {
205                 sout += line;
206         }
207
208         if (sout[sout.length() - 1] == '\n')
209                 sout.erase(sout.length() - 1);
210
211         return sout;
212 }
213
214
215 namespace {
216
217 // sorted by hand to prevent LyXLex from complaining on read().
218 keyword_item xformTags[] = {
219         { "\\gui_background", FL_COL1 },
220         { "\\gui_buttonbottom", FL_BOTTOM_BCOL },
221         { "\\gui_buttonleft", FL_LEFT_BCOL },
222         { "\\gui_buttonright", FL_RIGHT_BCOL },
223         { "\\gui_buttontop", FL_TOP_BCOL },
224         { "\\gui_inactive", FL_INACTIVE },
225         { "\\gui_push_button", FL_YELLOW },
226         { "\\gui_selected", FL_MCOL },  
227         { "\\gui_text", FL_BLACK }
228 };
229
230
231 const int xformCount = sizeof(xformTags) / sizeof(keyword_item);
232
233 } // namespace anon
234
235
236 bool XformsColor::read(string const & filename)
237 {
238         LyXLex lexrc(xformTags, xformCount);
239         if (!lexrc.setFile(filename))
240                 return false;
241
242         while (lexrc.isOK()) {
243                 int const le = lexrc.lex();
244
245                 switch (le) {
246                 case LyXLex::LEX_UNDEF:
247                         lexrc.printError("Unknown tag `$$Token'");
248                         continue; 
249                 case LyXLex::LEX_FEOF:
250                         continue;
251                 default: break;
252                 }
253
254                 RGBColor col;
255
256                 if (!lexrc.next()) break;
257                 col.r = lexrc.getInteger();
258
259                 if (!lexrc.next()) break;
260                 col.g = lexrc.getInteger();
261
262                 if (!lexrc.next()) break;
263                 col.b = lexrc.getInteger();
264
265                 fl_mapcolor(le, col.r, col.g, col.b);
266         }
267                 
268         return true;
269 }
270
271
272 bool XformsColor::write(string const & filename)
273 {
274         ofstream os(filename.c_str());
275         if (!os)
276                 return false;
277
278         os << "### This file is part of\n"
279            << "### ========================================================\n"
280            << "###          LyX, The Document Processor\n"
281            << "###\n"
282            << "###          Copyright 1995 Matthias Ettrich\n"
283            << "###          Copyright 1995-2001 The LyX Team.\n"
284            << "###\n"
285            << "### ========================================================\n"
286            << "\n"
287            << "# This file is written by LyX, if you want to make your own\n"
288            << "# modifications you should do them from inside LyX and save\n"
289            << "\n";
290
291         for (int i = 0; i < xformCount; ++i) {
292                 string const tag  = xformTags[i].tag;
293                 int const colorID = xformTags[i].code;
294                 RGBColor color;
295
296                 fl_getmcolor(colorID, &color.r, &color.g, &color.b);
297
298                 os << tag << " "
299                    << color.r << " " << color.g << " " << color.b << "\n";
300         }
301
302         return true;
303 }
304
305
306 string  RWInfo::error_message;
307
308 bool RWInfo::WriteableDir(string const & name)
309 {
310         error_message.erase();
311
312         if (!AbsolutePath(name)) {
313                 error_message = N_("The absolute path is required.");
314                 return false;
315         }
316
317         FileInfo const tp(name);
318         if (!tp.isDir()) {
319                 error_message = N_("Directory does not exist.");
320                 return false;
321         }
322
323         if (!tp.writable()) {
324                 error_message = N_("Cannot write to this directory.");
325                 return false;
326         }
327
328         return true;
329 }
330
331
332 bool RWInfo::ReadableDir(string const & name)
333 {
334         error_message.erase();
335
336         if (!AbsolutePath(name)) {
337                 error_message = N_("The absolute path is required.");
338                 return false;
339         }
340
341         FileInfo const tp(name);
342         if (!tp.isDir()) {
343                 error_message = N_("Directory does not exist.");
344                 return false;
345         }
346
347         if (!tp.readable()) {
348                 error_message = N_("Cannot read this directory.");
349                 return false;
350         }
351
352         return true;
353 }
354
355
356 bool RWInfo::WriteableFile(string const & name)
357 {
358         // A writeable file is either:
359         // * An existing file to which we have write access, or
360         // * A file that doesn't yet exist but that would exist in a writeable
361         //   directory.
362
363         error_message.erase();
364
365         if (name.empty()) {
366                 error_message = N_("No file input.");
367                 return false;
368         }
369
370         string const dir = OnlyPath(name);
371         if (!AbsolutePath(dir)) {
372                 error_message = N_("The absolute path is required.");
373                 return false;
374         }
375
376         FileInfo d(name);
377         if (!d.isDir()) {
378                 d.newFile(dir);
379         }
380
381         if (!d.isDir()) {
382                 error_message = N_("Directory does not exist.");
383                 return false;
384         }
385         
386         if (!d.writable()) {
387                 error_message = N_("Cannot write to this directory.");
388                 return false;
389         }
390
391         FileInfo f(name);
392         if (dir == name || f.isDir()) {
393                 error_message = N_("A file is required, not a directory.");
394                 return false;
395         }
396
397         if (f.exist() && !f.writable()) {
398                 error_message = N_("Cannot write to this file.");
399                 return false;
400         }
401         
402         return true;
403 }
404
405
406 bool RWInfo::ReadableFile(string const & name)
407 {
408         error_message.erase();
409
410         if (name.empty()) {
411                 error_message = N_("No file input.");
412                 return false;
413         }
414
415         string const dir = OnlyPath(name);
416         if (!AbsolutePath(dir)) {
417                 error_message = N_("The absolute path is required.");
418                 return false;
419         }
420
421         FileInfo d(name);
422         if (!d.isDir()) {
423                 d.newFile(dir);
424         }
425
426         if (!d.isDir()) {
427                 error_message = N_("Directory does not exist.");
428                 return false;
429         }
430         
431         if (!d.readable()) {
432                 error_message = N_("Cannot read from this directory.");
433                 return false;
434         }
435
436         FileInfo f(name);
437         if (dir == name || f.isDir()) {
438                 error_message = N_("A file is required, not a directory.");
439                 return false;
440         }
441
442         if (!f.exist()) {
443                 error_message = N_("File does not exist.");
444                 return false;
445         }
446         
447         if (!f.readable()) {
448                 error_message = N_("Cannot read from this file.");
449                 return false;
450         }
451
452         return true;
453 }