2 * \file xforms_helpers.C
3 * This file is part of LyX, the document processor.
4 * Licence details can be found in the file COPYING.
6 * \author Angus Leeming
8 * Full author contact details are available in file CREDITS
14 #pragma implementation
17 #include "xforms_helpers.h"
21 #include "lyxlength.h"
22 #include "lyxgluelength.h"
24 #include "support/LAssert.h"
25 #include "support/FileInfo.h"
26 #include "support/filetools.h"
27 #include "support/lstrings.h" // frontStrip, strip
33 #include FORMS_H_LOCATION
39 bool isActive(FL_OBJECT * ob)
41 return ob && ob->active > 0;
45 // Set an FL_OBJECT to activated or deactivated
46 void setEnabled(FL_OBJECT * ob, bool enable)
49 fl_activate_object(ob);
50 fl_set_object_lcol(ob, FL_LCOL);
52 fl_deactivate_object(ob);
53 fl_set_object_lcol(ob, FL_INACTIVE);
58 // Given an fl_choice or an fl_browser, create a vector of its entries
59 vector<string> const getVector(FL_OBJECT * ob)
63 switch (ob->objclass) {
65 for(int i = 0; i < fl_get_choice_maxitems(ob); ++i) {
66 string const text = fl_get_choice_item_text(ob, i+1);
67 vec.push_back(trim(text));
71 for(int i = 0; i < fl_get_browser_maxline(ob); ++i) {
72 string const text = fl_get_browser_line(ob, i+1);
73 vec.push_back(trim(text));
85 string const getString(FL_OBJECT * ob, int line)
87 // Negative line value does not make sense.
88 lyx::Assert(line >= 0);
91 switch (ob->objclass) {
93 tmp = fl_get_input(ob);
98 line = fl_get_browser(ob);
100 if (line >= 1 && line <= fl_get_browser_maxline(ob))
101 tmp = fl_get_browser_line(ob, line);
106 line = fl_get_choice(ob);
108 if (line >= 1 && line <= fl_get_choice_maxitems(ob))
109 tmp = fl_get_choice_item_text(ob, line);
116 return tmp ? trim(tmp) : string();
119 string getLengthFromWidgets(FL_OBJECT * input, FL_OBJECT * choice)
122 lyx::Assert(input && input->objclass == FL_INPUT &&
123 choice && choice->objclass == FL_CHOICE);
125 string const length = trim(fl_get_input(input));
129 // don't return unit-from-choice if the input(field) contains a unit
130 if (isValidGlueLength(length))
133 string unit = trim(fl_get_choice_text(choice));
134 unit = subst(unit, "%%", "%");
136 return length + unit;
140 void updateWidgetsFromLengthString(FL_OBJECT * input, FL_OBJECT * choice,
142 string const & default_unit)
144 // use input field only for gluelengths
145 if (!isValidLength(str) && !isStrDbl(str)) {
146 fl_set_input(input, str.c_str());
147 // we assume that "default_unit" is in the choice as "we"
148 // have control over that!
149 // No need to check for its presence in the choice, therefore.
150 fl_set_choice_text(choice, default_unit.c_str());
152 updateWidgetsFromLength(input, choice,
153 LyXLength(str), default_unit);
158 void updateWidgetsFromLength(FL_OBJECT * input, FL_OBJECT * choice,
159 LyXLength const & len,
160 string const & default_unit)
163 lyx::Assert(input && input->objclass == FL_INPUT &&
164 choice && choice->objclass == FL_CHOICE);
167 fl_set_input(input, "");
168 fl_set_choice_text(choice, default_unit.c_str());
170 ostringstream buffer;
171 buffer << len.value();
172 fl_set_input(input, buffer.str().c_str());
174 // Set the choice to the desired unit, if present in the choice.
175 // Else set the choice to the default unit.
176 string const unit = subst(stringFromUnit(len.unit()),"%","%%");
178 vector<string> const vec = getVector(choice);
179 vector<string>::const_iterator it =
180 std::find(vec.begin(), vec.end(), unit);
181 if (it != vec.end()) {
182 fl_set_choice_text(choice, unit.c_str());
184 fl_set_choice_text(choice, default_unit.c_str());
190 // Take a string and add breaks so that it fits into a desired label width, w
191 string formatted(string const & sin, int w, int size, int style)
194 if (sin.empty()) return sout;
196 string::size_type curpos = 0;
199 string::size_type const nxtpos1 = sin.find(' ', curpos);
200 string::size_type const nxtpos2 = sin.find('\n', curpos);
201 string::size_type const nxtpos = std::min(nxtpos1, nxtpos2);
203 string const word = nxtpos == string::npos ?
204 sin.substr(curpos) : sin.substr(curpos, nxtpos-curpos);
206 bool const newline = (nxtpos2 != string::npos &&
209 string const line_plus_word =
210 line.empty() ? word : line + ' ' + word;
213 fl_get_string_width(style, size,
214 line_plus_word.c_str(),
215 int(line_plus_word.length()));
226 } else if (newline) {
227 sout += line_plus_word + '\n';
236 if (nxtpos == string::npos) {
249 void setCursorColor(int color)
251 fl_set_cursor_color(FL_DEFAULT_CURSOR, color, FL_WHITE);
252 fl_set_cursor_color(XC_xterm, color, FL_WHITE);
253 fl_set_cursor_color(XC_watch, color, FL_WHITE);
254 fl_set_cursor_color(XC_sb_right_arrow, color, FL_WHITE);
260 // sorted by hand to prevent LyXLex from complaining on read().
261 keyword_item xformTags[] = {
262 { "\\gui_background", FL_COL1 },
263 { "\\gui_buttonbottom", FL_BOTTOM_BCOL },
264 { "\\gui_buttonleft", FL_LEFT_BCOL },
265 { "\\gui_buttonright", FL_RIGHT_BCOL },
266 { "\\gui_buttontop", FL_TOP_BCOL },
267 { "\\gui_inactive", FL_INACTIVE },
268 { "\\gui_pointer", FL_FREE_COL16 },
269 { "\\gui_push_button", FL_YELLOW },
270 { "\\gui_selected", FL_MCOL },
271 { "\\gui_text", FL_BLACK }
275 const int xformCount = sizeof(xformTags) / sizeof(keyword_item);
280 bool XformsColor::read(string const & filename)
282 LyXLex lexrc(xformTags, xformCount);
283 if (!lexrc.setFile(filename))
286 while (lexrc.isOK()) {
287 int const le = lexrc.lex();
290 case LyXLex::LEX_UNDEF:
291 lexrc.printError("Unknown tag `$$Token'");
293 case LyXLex::LEX_FEOF:
298 string const tag = lexrc.getString();
302 if (!lexrc.next()) break;
303 col.r = lexrc.getInteger();
305 if (!lexrc.next()) break;
306 col.g = lexrc.getInteger();
308 if (!lexrc.next()) break;
309 col.b = lexrc.getInteger();
311 fl_mapcolor(le, col.r, col.g, col.b);
313 if (tag == "\\gui_pointer") {
314 setCursorColor(FL_FREE_COL16);
322 bool XformsColor::write(string const & filename)
324 ofstream os(filename.c_str());
329 << "### file " << filename << "\n\n"
330 << "### This file is written by LyX, if you want to make your own\n"
331 << "### modifications you should do them from inside LyX and save\n"
334 for (int i = 0; i < xformCount; ++i) {
335 string const tag = xformTags[i].tag;
336 int const colorID = xformTags[i].code;
339 fl_getmcolor(colorID, &color.r, &color.g, &color.b);
342 << color.r << " " << color.g << " " << color.b << "\n";
349 string RWInfo::error_message;
351 bool RWInfo::WriteableDir(string const & name)
353 error_message.erase();
355 if (!AbsolutePath(name)) {
356 error_message = _("The absolute path is required.");
360 FileInfo const tp(name);
361 if (!tp.isOK() || !tp.isDir()) {
362 error_message = _("Directory does not exist.");
366 if (!tp.writable()) {
367 error_message = _("Cannot write to this directory.");
375 bool RWInfo::ReadableDir(string const & name)
377 error_message.erase();
379 if (!AbsolutePath(name)) {
380 error_message = _("The absolute path is required.");
384 FileInfo const tp(name);
385 if (!tp.isOK() || !tp.isDir()) {
386 error_message = _("Directory does not exist.");
390 if (!tp.readable()) {
391 error_message = _("Cannot read this directory.");
399 bool RWInfo::WriteableFile(string const & name)
401 // A writeable file is either:
402 // * An existing file to which we have write access, or
403 // * A file that doesn't yet exist but that would exist in a writeable
406 error_message.erase();
409 error_message = _("No file input.");
413 string const dir = OnlyPath(name);
414 if (!AbsolutePath(dir)) {
415 error_message = _("The absolute path is required.");
421 if (!d.isOK() || !d.isDir()) {
425 if (!d.isOK() || !d.isDir()) {
426 error_message = _("Directory does not exist.");
431 error_message = _("Cannot write to this directory.");
436 if (dir == name || (f.isOK() && f.isDir())) {
437 error_message = _("A file is required, not a directory.");
441 if (f.isOK() && f.exist() && !f.writable()) {
442 error_message = _("Cannot write to this file.");
450 bool RWInfo::ReadableFile(string const & name)
452 error_message.erase();
455 error_message = _("No file input.");
459 string const dir = OnlyPath(name);
460 if (!AbsolutePath(dir)) {
461 error_message = _("The absolute path is required.");
467 if (!d.isOK() && !d.isDir()) {
471 if (!d.isOK() || !d.isDir()) {
472 error_message = _("Directory does not exist.");
477 error_message = _("Cannot read from this directory.");
482 if (dir == name || (f.isOK() && f.isDir())) {
483 error_message = _("A file is required, not a directory.");
488 error_message = _("File does not exist.");
493 error_message = _("Cannot read from this file.");